mirror of
https://github.com/ansible/awx.git
synced 2026-01-12 10:30:03 -03:30
Active flag removal: switched from using mark_inactive to delete calls
This commit is contained in:
parent
1e7c71edfb
commit
ba833d683e
@ -7,7 +7,6 @@ import logging
|
||||
import time
|
||||
|
||||
# Django
|
||||
from django.http import Http404
|
||||
from django.conf import settings
|
||||
from django.db import connection
|
||||
from django.shortcuts import get_object_or_404
|
||||
@ -415,9 +414,7 @@ class SubListCreateAttachDetachAPIView(SubListCreateAPIView):
|
||||
raise PermissionDenied()
|
||||
|
||||
if parent_key:
|
||||
# sub object has a ForeignKey to the parent, so we can't remove it
|
||||
# from the set, only mark it as inactive.
|
||||
sub.mark_inactive()
|
||||
sub.delete()
|
||||
else:
|
||||
relationship.remove(sub)
|
||||
|
||||
@ -457,17 +454,9 @@ class RetrieveDestroyAPIView(RetrieveAPIView, generics.RetrieveDestroyAPIView):
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
# somewhat lame that delete has to call it's own permissions check
|
||||
obj = self.get_object()
|
||||
# FIXME: Why isn't the active check being caught earlier by RBAC?
|
||||
if not getattr(obj, 'active', True):
|
||||
raise Http404()
|
||||
if not getattr(obj, 'is_active', True):
|
||||
raise Http404()
|
||||
if not request.user.can_access(self.model, 'delete', obj):
|
||||
raise PermissionDenied()
|
||||
if hasattr(obj, 'mark_inactive'):
|
||||
obj.mark_inactive()
|
||||
else:
|
||||
raise NotImplementedError('destroy() not implemented yet for %s' % obj)
|
||||
obj.delete()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
class RetrieveUpdateDestroyAPIView(RetrieveUpdateAPIView, RetrieveDestroyAPIView):
|
||||
|
||||
@ -1093,8 +1093,6 @@ class UserDetail(RetrieveUpdateDestroyAPIView):
|
||||
can_delete = request.user.can_access(User, 'delete', obj)
|
||||
if not can_delete:
|
||||
raise PermissionDenied('Cannot delete user')
|
||||
for own_credential in Credential.objects.filter(user=obj):
|
||||
own_credential.mark_inactive()
|
||||
return super(UserDetail, self).destroy(request, *args, **kwargs)
|
||||
|
||||
class UserAccessList(ResourceAccessList):
|
||||
@ -1400,7 +1398,7 @@ class GroupChildrenList(SubListCreateAttachDetachAPIView):
|
||||
if sub_id is not None:
|
||||
return super(GroupChildrenList, self).unattach(request, *args, **kwargs)
|
||||
parent = self.get_parent_object()
|
||||
parent.mark_inactive()
|
||||
parent.delete()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
def _unattach(self, request, *args, **kwargs): # FIXME: Disabled for now for UI support.
|
||||
@ -1424,7 +1422,7 @@ class GroupChildrenList(SubListCreateAttachDetachAPIView):
|
||||
raise PermissionDenied()
|
||||
|
||||
if sub.parents.filter(active=True).exclude(pk=parent.pk).count() == 0:
|
||||
sub.mark_inactive()
|
||||
sub.delete()
|
||||
else:
|
||||
relationship.remove(sub)
|
||||
|
||||
@ -1526,15 +1524,9 @@ class GroupDetail(RetrieveUpdateDestroyAPIView):
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
# FIXME: Why isn't the active check being caught earlier by RBAC?
|
||||
if not getattr(obj, 'active', True):
|
||||
raise Http404()
|
||||
if not getattr(obj, 'is_active', True):
|
||||
raise Http404()
|
||||
if not request.user.can_access(self.model, 'delete', obj):
|
||||
raise PermissionDenied()
|
||||
if hasattr(obj, 'mark_inactive'):
|
||||
obj.mark_inactive_recursive()
|
||||
obj.delete_recursive()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
class GroupAccessList(ResourceAccessList):
|
||||
|
||||
@ -53,13 +53,13 @@ class MemObject(object):
|
||||
'''
|
||||
Common code shared between in-memory groups and hosts.
|
||||
'''
|
||||
|
||||
|
||||
def __init__(self, name, source_dir):
|
||||
assert name, 'no name'
|
||||
assert source_dir, 'no source dir'
|
||||
self.name = name
|
||||
self.source_dir = source_dir
|
||||
|
||||
|
||||
def load_vars(self, base_path):
|
||||
all_vars = {}
|
||||
files_found = 0
|
||||
@ -107,7 +107,7 @@ class MemGroup(MemObject):
|
||||
group_vars = os.path.join(source_dir, 'group_vars', self.name)
|
||||
self.variables = self.load_vars(group_vars)
|
||||
logger.debug('Loaded group: %s', self.name)
|
||||
|
||||
|
||||
def child_group_by_name(self, name, loader):
|
||||
if name == 'all':
|
||||
return
|
||||
@ -266,7 +266,7 @@ class BaseLoader(object):
|
||||
logger.debug('Filtering group %s', name)
|
||||
return None
|
||||
if name not in self.all_group.all_groups:
|
||||
group = MemGroup(name, self.source_dir)
|
||||
group = MemGroup(name, self.source_dir)
|
||||
if not child:
|
||||
all_group.add_child_group(group)
|
||||
self.all_group.all_groups[name] = group
|
||||
@ -315,7 +315,7 @@ class IniLoader(BaseLoader):
|
||||
for t in tokens[1:]:
|
||||
k,v = t.split('=', 1)
|
||||
host.variables[k] = v
|
||||
group.add_host(host)
|
||||
group.add_host(host)
|
||||
elif input_mode == 'children':
|
||||
group.child_group_by_name(line, self)
|
||||
elif input_mode == 'vars':
|
||||
@ -328,7 +328,7 @@ class IniLoader(BaseLoader):
|
||||
# from API documentation:
|
||||
#
|
||||
# if called with --list, inventory outputs like so:
|
||||
#
|
||||
#
|
||||
# {
|
||||
# "databases" : {
|
||||
# "hosts" : [ "host1.example.com", "host2.example.com" ],
|
||||
@ -581,7 +581,7 @@ class Command(NoArgsCommand):
|
||||
def _get_instance_id(self, from_dict, default=''):
|
||||
'''
|
||||
Retrieve the instance ID from the given dict of host variables.
|
||||
|
||||
|
||||
The instance ID variable may be specified as 'foo.bar', in which case
|
||||
the lookup will traverse into nested dicts, equivalent to:
|
||||
|
||||
@ -765,7 +765,7 @@ class Command(NoArgsCommand):
|
||||
del_pks = all_del_pks[offset:(offset + self._batch_size)]
|
||||
for host in hosts_qs.filter(pk__in=del_pks):
|
||||
host_name = host.name
|
||||
host.mark_inactive()
|
||||
host.delete()
|
||||
self.logger.info('Deleted host "%s"', host_name)
|
||||
if settings.SQL_DEBUG:
|
||||
self.logger.warning('host deletions took %d queries for %d hosts',
|
||||
@ -799,7 +799,8 @@ class Command(NoArgsCommand):
|
||||
del_pks = all_del_pks[offset:(offset + self._batch_size)]
|
||||
for group in groups_qs.filter(pk__in=del_pks):
|
||||
group_name = group.name
|
||||
group.mark_inactive(recompute=False)
|
||||
with ignore_inventory_computed_fields():
|
||||
group.delete()
|
||||
self.logger.info('Group "%s" deleted', group_name)
|
||||
if settings.SQL_DEBUG:
|
||||
self.logger.warning('group deletions took %d queries for %d groups',
|
||||
@ -1297,7 +1298,7 @@ class Command(NoArgsCommand):
|
||||
except CommandError as e:
|
||||
self.mark_license_failure(save=True)
|
||||
raise e
|
||||
|
||||
|
||||
if self.inventory_source.group:
|
||||
inv_name = 'group "%s"' % (self.inventory_source.group.name)
|
||||
else:
|
||||
@ -1336,7 +1337,7 @@ class Command(NoArgsCommand):
|
||||
self.inventory_update.result_traceback = tb
|
||||
self.inventory_update.status = status
|
||||
self.inventory_update.save(update_fields=['status', 'result_traceback'])
|
||||
|
||||
|
||||
if exc and isinstance(exc, CommandError):
|
||||
sys.exit(1)
|
||||
elif exc:
|
||||
|
||||
@ -203,15 +203,6 @@ class PasswordFieldsModel(BaseModel):
|
||||
def _password_field_allows_ask(self, field):
|
||||
return False # Override in subclasses if needed.
|
||||
|
||||
def mark_inactive(self, save=True):
|
||||
'''
|
||||
When marking a password model inactive we'll clear sensitive fields
|
||||
'''
|
||||
for sensitive_field in self.PASSWORD_FIELDS:
|
||||
setattr(self, sensitive_field, "")
|
||||
self.save()
|
||||
super(PasswordFieldsModel, self).mark_inactive(save=save)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
new_instance = not bool(self.pk)
|
||||
# If update_fields has been specified, add our field names to it,
|
||||
|
||||
@ -26,7 +26,7 @@ from awx.main.models.jobs import Job
|
||||
from awx.main.models.unified_jobs import * # noqa
|
||||
from awx.main.models.mixins import ResourceMixin
|
||||
from awx.main.models.notifications import Notifier
|
||||
from awx.main.utils import ignore_inventory_computed_fields, _inventory_updates
|
||||
from awx.main.utils import _inventory_updates
|
||||
from awx.main.conf import tower_settings
|
||||
|
||||
__all__ = ['Inventory', 'Host', 'Group', 'InventorySource', 'InventoryUpdate', 'CustomInventoryScript']
|
||||
@ -120,18 +120,6 @@ class Inventory(CommonModel, ResourceMixin):
|
||||
def get_absolute_url(self):
|
||||
return reverse('api:inventory_detail', args=(self.pk,))
|
||||
|
||||
def mark_inactive(self, save=True):
|
||||
'''
|
||||
When marking inventory inactive, also mark hosts and groups inactive.
|
||||
'''
|
||||
with ignore_inventory_computed_fields():
|
||||
for host in self.hosts.filter(active=True):
|
||||
host.mark_inactive()
|
||||
for group in self.groups.filter(active=True):
|
||||
group.mark_inactive(recompute=False)
|
||||
for inventory_source in self.inventory_sources.filter(active=True):
|
||||
inventory_source.mark_inactive()
|
||||
super(Inventory, self).mark_inactive(save=save)
|
||||
|
||||
variables_dict = VarsDictProperty('variables')
|
||||
|
||||
@ -412,15 +400,6 @@ class Host(CommonModelNameNotUnique, ResourceMixin):
|
||||
def get_absolute_url(self):
|
||||
return reverse('api:host_detail', args=(self.pk,))
|
||||
|
||||
def mark_inactive(self, save=True, from_inventory_import=False, skip_active_check=False):
|
||||
'''
|
||||
When marking hosts inactive, remove all associations to related
|
||||
inventory sources.
|
||||
'''
|
||||
super(Host, self).mark_inactive(save=save, skip_active_check=skip_active_check)
|
||||
if not from_inventory_import:
|
||||
self.inventory_sources.clear()
|
||||
|
||||
def update_computed_fields(self, update_inventory=True, update_groups=True):
|
||||
'''
|
||||
Update model fields that are computed from database relationships.
|
||||
@ -575,11 +554,11 @@ class Group(CommonModelNameNotUnique, ResourceMixin):
|
||||
return reverse('api:group_detail', args=(self.pk,))
|
||||
|
||||
@transaction.atomic
|
||||
def mark_inactive_recursive(self):
|
||||
from awx.main.tasks import bulk_inventory_element_delete
|
||||
def delete_recursive(self):
|
||||
from awx.main.utils import ignore_inventory_computed_fields
|
||||
from awx.main.signals import disable_activity_stream
|
||||
|
||||
|
||||
def mark_actual():
|
||||
all_group_hosts = Group.hosts.through.objects.select_related("host", "group").filter(group__inventory=self.inventory)
|
||||
group_hosts = {'groups': {}, 'hosts': {}}
|
||||
@ -629,38 +608,13 @@ class Group(CommonModelNameNotUnique, ResourceMixin):
|
||||
for direct_child in group_children[group]:
|
||||
linked_children.append((group, direct_child))
|
||||
marked_groups.append(group)
|
||||
Group.objects.filter(id__in=marked_groups).update(active=False)
|
||||
Host.objects.filter(id__in=marked_hosts).update(active=False)
|
||||
Group.parents.through.objects.filter(to_group__id__in=marked_groups)
|
||||
Group.hosts.through.objects.filter(group__id__in=marked_groups)
|
||||
Group.inventory_sources.through.objects.filter(group__id__in=marked_groups).delete()
|
||||
bulk_inventory_element_delete.delay(self.inventory.id, groups=marked_groups, hosts=marked_hosts)
|
||||
Group.objects.filter(id__in=marked_groups).delete()
|
||||
Host.objects.filter(id__in=marked_hosts).delete()
|
||||
update_inventory_computed_fields.delay(self.inventory.id)
|
||||
with ignore_inventory_computed_fields():
|
||||
with disable_activity_stream():
|
||||
mark_actual()
|
||||
|
||||
def mark_inactive(self, save=True, recompute=True, from_inventory_import=False, skip_active_check=False):
|
||||
'''
|
||||
When marking groups inactive, remove all associations to related
|
||||
groups/hosts/inventory_sources.
|
||||
'''
|
||||
def mark_actual():
|
||||
super(Group, self).mark_inactive(save=save, skip_active_check=skip_active_check)
|
||||
self.inventory_source.mark_inactive(save=save)
|
||||
self.inventory_sources.clear()
|
||||
self.parents.clear()
|
||||
self.children.clear()
|
||||
self.hosts.clear()
|
||||
i = self.inventory
|
||||
|
||||
if from_inventory_import:
|
||||
super(Group, self).mark_inactive(save=save, skip_active_check=skip_active_check)
|
||||
elif recompute:
|
||||
with ignore_inventory_computed_fields():
|
||||
mark_actual()
|
||||
i.update_computed_fields()
|
||||
else:
|
||||
mark_actual()
|
||||
|
||||
def update_computed_fields(self):
|
||||
'''
|
||||
|
||||
@ -79,11 +79,6 @@ class Organization(CommonModel, NotificationFieldsModel, ResourceMixin):
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
def mark_inactive(self, save=True):
|
||||
for script in self.custom_inventory_scripts.all():
|
||||
script.organization = None
|
||||
script.save()
|
||||
super(Organization, self).mark_inactive(save=save)
|
||||
|
||||
|
||||
class Team(CommonModelNameNotUnique, ResourceMixin):
|
||||
@ -135,14 +130,6 @@ class Team(CommonModelNameNotUnique, ResourceMixin):
|
||||
def get_absolute_url(self):
|
||||
return reverse('api:team_detail', args=(self.pk,))
|
||||
|
||||
def mark_inactive(self, save=True):
|
||||
'''
|
||||
When marking a team inactive we'll wipe out its credentials also
|
||||
'''
|
||||
for cred in self.credentials.all():
|
||||
cred.mark_inactive()
|
||||
super(Team, self).mark_inactive(save=save)
|
||||
|
||||
|
||||
class Permission(CommonModelNameNotUnique):
|
||||
'''
|
||||
@ -351,22 +338,6 @@ class AuthToken(BaseModel):
|
||||
return self.key
|
||||
|
||||
|
||||
# Add mark_inactive method to User model.
|
||||
def user_mark_inactive(user, save=True):
|
||||
'''Use instead of delete to rename and mark users inactive.'''
|
||||
if user.is_active:
|
||||
# Set timestamp to datetime.isoformat() but without the time zone
|
||||
# offset to stay withint the 30 character username limit.
|
||||
dtnow = tz_now()
|
||||
deleted_ts = dtnow.strftime('%Y-%m-%dT%H:%M:%S.%f')
|
||||
user.username = '_d_%s' % deleted_ts
|
||||
user.is_active = False
|
||||
if save:
|
||||
user.save()
|
||||
|
||||
User.add_to_class('mark_inactive', user_mark_inactive)
|
||||
|
||||
|
||||
# Add get_absolute_url method to User model if not present.
|
||||
if not hasattr(User, 'get_absolute_url'):
|
||||
def user_get_absolute_url(user):
|
||||
|
||||
@ -210,17 +210,6 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique, Notificatio
|
||||
self.next_job_run = related_schedules[0].next_run
|
||||
self.save(update_fields=['next_schedule', 'next_job_run'])
|
||||
|
||||
def mark_inactive(self, save=True):
|
||||
'''
|
||||
When marking a unified job template inactive, also mark its schedules
|
||||
inactive.
|
||||
'''
|
||||
for schedule in self.schedules.filter(active=True):
|
||||
schedule.mark_inactive()
|
||||
schedule.enabled = False
|
||||
schedule.save()
|
||||
super(UnifiedJobTemplate, self).mark_inactive(save=save)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# If update_fields has been specified, add our field names to it,
|
||||
# if it hasn't been specified, then we're just doing a normal save.
|
||||
|
||||
@ -265,7 +265,7 @@ def migrate_children_from_inactive_group_to_parent_groups(sender, **kwargs):
|
||||
if inventory_source_pk:
|
||||
try:
|
||||
inventory_source = InventorySource.objects.get(pk=inventory_source_pk, active=True)
|
||||
inventory_source.mark_inactive()
|
||||
inventory_source.delete()
|
||||
except InventorySource.DoesNotExist:
|
||||
pass
|
||||
inventory_pk = getattr(instance, '_saved_inventory_pk', None)
|
||||
|
||||
@ -110,17 +110,6 @@ def run_administrative_checks(self):
|
||||
tower_admin_emails,
|
||||
fail_silently=True)
|
||||
|
||||
@task()
|
||||
def bulk_inventory_element_delete(inventory, hosts=[], groups=[]):
|
||||
from awx.main.signals import disable_activity_stream
|
||||
with ignore_inventory_computed_fields():
|
||||
with disable_activity_stream():
|
||||
for group in groups:
|
||||
Group.objects.get(id=group).mark_inactive(skip_active_check=True)
|
||||
for host in hosts:
|
||||
Host.objects.get(id=host).mark_inactive(skip_active_check=True)
|
||||
update_inventory_computed_fields(inventory)
|
||||
|
||||
@task(bind=True)
|
||||
def tower_periodic_scheduler(self):
|
||||
def get_last_run():
|
||||
|
||||
@ -637,8 +637,8 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
# Verify that the credential and inventory are null when they have
|
||||
# been deleted, can delete an ad hoc command without inventory or
|
||||
# credential.
|
||||
self.credential.mark_inactive()
|
||||
self.inventory.mark_inactive()
|
||||
self.credential.delete()
|
||||
self.inventory.delete()
|
||||
with self.current_user('admin'):
|
||||
response = self.get(url, expect=200)
|
||||
self.assertEqual(response['credential'], None)
|
||||
@ -758,7 +758,7 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
tower_settings.AD_HOC_COMMANDS = ad_hoc_commands
|
||||
|
||||
# Try to relaunch after the inventory has been marked inactive.
|
||||
self.inventory.mark_inactive()
|
||||
self.inventory.delete()
|
||||
with self.current_user('admin'):
|
||||
response = self.get(url, expect=200)
|
||||
self.assertEqual(response['passwords_needed_to_start'], [])
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
# Copyright (c) 2015 Ansible, Inc.
|
||||
# All Rights Reserved
|
||||
|
||||
# AWX
|
||||
from awx.main.tests.base import BaseTest
|
||||
from command_base import BaseCommandMixin
|
||||
|
||||
__all__ = ['AgeDeletedCommandFunctionalTest']
|
||||
|
||||
class AgeDeletedCommandFunctionalTest(BaseCommandMixin, BaseTest):
|
||||
def setUp(self):
|
||||
super(AgeDeletedCommandFunctionalTest, self).setUp()
|
||||
self.create_test_license_file()
|
||||
self.setup_instances()
|
||||
self.setup_users()
|
||||
self.organization = self.make_organization(self.super_django_user)
|
||||
self.credential = self.make_credential()
|
||||
self.credential2 = self.make_credential()
|
||||
self.credential.mark_inactive(True)
|
||||
self.credential2.mark_inactive(True)
|
||||
self.credential_active = self.make_credential()
|
||||
self.super_django_user.mark_inactive(True)
|
||||
|
||||
def test_default(self):
|
||||
result, stdout, stderr = self.run_command('age_deleted')
|
||||
self.assertEqual(stdout, 'Aged %d items\n' % 3)
|
||||
|
||||
def test_type(self):
|
||||
result, stdout, stderr = self.run_command('age_deleted', type='Credential')
|
||||
self.assertEqual(stdout, 'Aged %d items\n' % 2)
|
||||
|
||||
def test_id_type(self):
|
||||
result, stdout, stderr = self.run_command('age_deleted', type='Credential', id=self.credential.pk)
|
||||
self.assertEqual(stdout, 'Aged %d items\n' % 1)
|
||||
@ -15,7 +15,6 @@ import unittest2 as unittest
|
||||
|
||||
# Django
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.management import call_command
|
||||
from django.core.management.base import CommandError
|
||||
from django.utils.timezone import now
|
||||
@ -232,126 +231,6 @@ class DumpDataTest(BaseCommandMixin, BaseTest):
|
||||
self.assertEqual(result, None)
|
||||
json.loads(stdout)
|
||||
|
||||
class CleanupDeletedTest(BaseCommandMixin, BaseTest):
|
||||
'''
|
||||
Test cases for cleanup_deleted management command.
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
self.start_redis()
|
||||
super(CleanupDeletedTest, self).setUp()
|
||||
self.create_test_inventories()
|
||||
|
||||
def tearDown(self):
|
||||
super(CleanupDeletedTest, self).tearDown()
|
||||
self.stop_redis()
|
||||
|
||||
def get_model_counts(self):
|
||||
def get_models(m):
|
||||
if not m._meta.abstract:
|
||||
yield m
|
||||
for sub in m.__subclasses__():
|
||||
for subm in get_models(sub):
|
||||
yield subm
|
||||
counts = {}
|
||||
for model in get_models(PrimordialModel):
|
||||
active = model.objects.filter(active=True).count()
|
||||
inactive = model.objects.filter(active=False).count()
|
||||
counts[model] = (active, inactive)
|
||||
return counts
|
||||
|
||||
def test_cleanup_our_models(self):
|
||||
# Test with nothing to be deleted.
|
||||
counts_before = self.get_model_counts()
|
||||
self.assertFalse(sum(x[1] for x in counts_before.values()))
|
||||
result, stdout, stderr = self.run_command('cleanup_deleted')
|
||||
self.assertEqual(result, None)
|
||||
counts_after = self.get_model_counts()
|
||||
self.assertEqual(counts_before, counts_after)
|
||||
# "Delete" some hosts.
|
||||
for host in Host.objects.all():
|
||||
host.mark_inactive()
|
||||
# With no parameters, "days" defaults to 90, which won't cleanup any of
|
||||
# the hosts we just removed.
|
||||
counts_before = self.get_model_counts()
|
||||
self.assertTrue(sum(x[1] for x in counts_before.values()))
|
||||
result, stdout, stderr = self.run_command('cleanup_deleted')
|
||||
self.assertEqual(result, None)
|
||||
counts_after = self.get_model_counts()
|
||||
self.assertEqual(counts_before, counts_after)
|
||||
# Even with days=1, the hosts will remain.
|
||||
counts_before = self.get_model_counts()
|
||||
self.assertTrue(sum(x[1] for x in counts_before.values()))
|
||||
result, stdout, stderr = self.run_command('cleanup_deleted', days=1)
|
||||
self.assertEqual(result, None)
|
||||
counts_after = self.get_model_counts()
|
||||
self.assertEqual(counts_before, counts_after)
|
||||
# With days=0, the hosts will be deleted.
|
||||
counts_before = self.get_model_counts()
|
||||
self.assertTrue(sum(x[1] for x in counts_before.values()))
|
||||
result, stdout, stderr = self.run_command('cleanup_deleted', days=0)
|
||||
self.assertEqual(result, None)
|
||||
counts_after = self.get_model_counts()
|
||||
self.assertNotEqual(counts_before, counts_after)
|
||||
self.assertFalse(sum(x[1] for x in counts_after.values()))
|
||||
return # Don't test how long it takes (for now).
|
||||
|
||||
# Create lots of hosts already marked as deleted.
|
||||
t = time.time()
|
||||
dtnow = now()
|
||||
for x in xrange(1000):
|
||||
hostname = "_deleted_%s_host-%d" % (dtnow.isoformat(), x)
|
||||
host = self.inventories[0].hosts.create(name=hostname, active=False)
|
||||
create_elapsed = time.time() - t
|
||||
|
||||
# Time how long it takes to cleanup deleted items, should be no more
|
||||
# then the time taken to create them.
|
||||
counts_before = self.get_model_counts()
|
||||
self.assertTrue(sum(x[1] for x in counts_before.values()))
|
||||
t = time.time()
|
||||
result, stdout, stderr = self.run_command('cleanup_deleted', days=0)
|
||||
cleanup_elapsed = time.time() - t
|
||||
self.assertEqual(result, None)
|
||||
counts_after = self.get_model_counts()
|
||||
self.assertNotEqual(counts_before, counts_after)
|
||||
self.assertFalse(sum(x[1] for x in counts_after.values()))
|
||||
self.assertTrue(cleanup_elapsed < create_elapsed,
|
||||
'create took %0.3fs, cleanup took %0.3fs, expected < %0.3fs' % (create_elapsed, cleanup_elapsed, create_elapsed))
|
||||
|
||||
def get_user_counts(self):
|
||||
active = User.objects.filter(is_active=True).count()
|
||||
inactive = User.objects.filter(is_active=False).count()
|
||||
return active, inactive
|
||||
|
||||
def test_cleanup_user_model(self):
|
||||
# Test with nothing to be deleted.
|
||||
counts_before = self.get_user_counts()
|
||||
self.assertFalse(counts_before[1])
|
||||
result, stdout, stderr = self.run_command('cleanup_deleted')
|
||||
self.assertEqual(result, None)
|
||||
counts_after = self.get_user_counts()
|
||||
self.assertEqual(counts_before, counts_after)
|
||||
# "Delete some users".
|
||||
for user in User.objects.all():
|
||||
user.mark_inactive()
|
||||
self.assertTrue(len(user.username) <= 30,
|
||||
'len(%r) == %d' % (user.username, len(user.username)))
|
||||
# With days=1, no users will be deleted.
|
||||
counts_before = self.get_user_counts()
|
||||
self.assertTrue(counts_before[1])
|
||||
result, stdout, stderr = self.run_command('cleanup_deleted', days=1)
|
||||
self.assertEqual(result, None)
|
||||
counts_after = self.get_user_counts()
|
||||
self.assertEqual(counts_before, counts_after)
|
||||
# With days=0, inactive users will be deleted.
|
||||
counts_before = self.get_user_counts()
|
||||
self.assertTrue(counts_before[1])
|
||||
result, stdout, stderr = self.run_command('cleanup_deleted', days=0)
|
||||
self.assertEqual(result, None)
|
||||
counts_after = self.get_user_counts()
|
||||
self.assertNotEqual(counts_before, counts_after)
|
||||
self.assertFalse(counts_after[1])
|
||||
|
||||
@override_settings(CELERY_ALWAYS_EAGER=True,
|
||||
CELERY_EAGER_PROPAGATES_EXCEPTIONS=True,
|
||||
ANSIBLE_TRANSPORT='local')
|
||||
|
||||
@ -423,7 +423,7 @@ class InventoryTest(BaseTest):
|
||||
del_children_url = reverse('api:group_children_list', args=(del_group.pk,))
|
||||
nondel_url = reverse('api:group_detail',
|
||||
args=(Group.objects.get(name='nondel').pk,))
|
||||
del_group.mark_inactive()
|
||||
del_group.delete()
|
||||
nondel_detail = self.get(nondel_url, expect=200, auth=self.get_normal_credentials())
|
||||
self.post(del_children_url, data=nondel_detail, expect=403, auth=self.get_normal_credentials())
|
||||
|
||||
@ -944,13 +944,10 @@ class InventoryTest(BaseTest):
|
||||
# Mark group C inactive. Its child groups and hosts should now also be
|
||||
# attached to group A. Group D hosts should be unchanged. Group C
|
||||
# should also no longer have any group or host relationships.
|
||||
g_c.mark_inactive()
|
||||
g_c.delete()
|
||||
self.assertTrue(g_d in g_a.children.all())
|
||||
self.assertTrue(h_c in g_a.hosts.all())
|
||||
self.assertFalse(h_d in g_a.hosts.all())
|
||||
self.assertFalse(g_c.parents.all())
|
||||
self.assertFalse(g_c.children.all())
|
||||
self.assertFalse(g_c.hosts.all())
|
||||
|
||||
def test_safe_delete_recursion(self):
|
||||
# First hierarchy
|
||||
@ -989,11 +986,9 @@ class InventoryTest(BaseTest):
|
||||
self.assertTrue(other_sub_group in sub_group.children.all())
|
||||
|
||||
# Now recursively remove its parent and the reference from subgroup should remain
|
||||
other_top_group.mark_inactive_recursive()
|
||||
other_top_group = Group.objects.get(pk=other_top_group.pk)
|
||||
other_top_group.delete_recursive()
|
||||
self.assertTrue(s2 in sub_group.all_hosts.all())
|
||||
self.assertTrue(other_sub_group in sub_group.children.all())
|
||||
self.assertFalse(other_top_group.active)
|
||||
|
||||
def test_group_parents_and_children(self):
|
||||
# Test for various levels of group parent/child relations, with hosts,
|
||||
@ -1173,7 +1168,7 @@ class InventoryTest(BaseTest):
|
||||
# Delete recently added hosts and verify the count drops.
|
||||
hostnames4 = list('defg')
|
||||
for host in Host.objects.filter(name__in=hostnames4):
|
||||
host.mark_inactive()
|
||||
host.delete()
|
||||
with self.current_user(self.super_django_user):
|
||||
response = self.get(url)
|
||||
for n, d in enumerate(reversed(response['hosts'])):
|
||||
|
||||
@ -96,7 +96,7 @@ class JobTemplateLaunchTest(BaseJobTestMixin, django.test.TransactionTestCase):
|
||||
def test_credential_explicit(self):
|
||||
# Explicit, credential
|
||||
with self.current_user(self.user_sue):
|
||||
self.cred_sue.mark_inactive()
|
||||
self.cred_sue.delete()
|
||||
response = self.post(self.launch_url, {'credential': self.cred_doug.pk}, expect=202)
|
||||
j = Job.objects.get(pk=response['job'])
|
||||
self.assertEqual(j.status, 'new')
|
||||
@ -105,7 +105,7 @@ class JobTemplateLaunchTest(BaseJobTestMixin, django.test.TransactionTestCase):
|
||||
def test_credential_explicit_via_credential_id(self):
|
||||
# Explicit, credential
|
||||
with self.current_user(self.user_sue):
|
||||
self.cred_sue.mark_inactive()
|
||||
self.cred_sue.delete()
|
||||
response = self.post(self.launch_url, {'credential_id': self.cred_doug.pk}, expect=202)
|
||||
j = Job.objects.get(pk=response['job'])
|
||||
self.assertEqual(j.status, 'new')
|
||||
@ -131,15 +131,16 @@ class JobTemplateLaunchTest(BaseJobTestMixin, django.test.TransactionTestCase):
|
||||
# Can't launch a job template without a credential defined (or if we
|
||||
# pass an invalid/inactive credential value).
|
||||
with self.current_user(self.user_sue):
|
||||
self.cred_sue.mark_inactive()
|
||||
self.cred_sue.delete()
|
||||
self.post(self.launch_url, {}, expect=400)
|
||||
self.post(self.launch_url, {'credential': 0}, expect=400)
|
||||
self.post(self.launch_url, {'credential_id': 0}, expect=400)
|
||||
self.post(self.launch_url, {'credential': 'one'}, expect=400)
|
||||
self.post(self.launch_url, {'credential_id': 'one'}, expect=400)
|
||||
self.cred_doug.mark_inactive()
|
||||
self.post(self.launch_url, {'credential': self.cred_doug.pk}, expect=400)
|
||||
self.post(self.launch_url, {'credential_id': self.cred_doug.pk}, expect=400)
|
||||
doug_pk = self.cred_doug.pk
|
||||
self.cred_doug.delete()
|
||||
self.post(self.launch_url, {'credential': cred_doug_pk}, expect=400)
|
||||
self.post(self.launch_url, {'credential_id': cred_doug_pk}, expect=400)
|
||||
|
||||
def test_explicit_unowned_cred(self):
|
||||
# Explicitly specify a credential that we don't have access to
|
||||
@ -174,7 +175,7 @@ class JobTemplateLaunchTest(BaseJobTestMixin, django.test.TransactionTestCase):
|
||||
|
||||
def test_deleted_credential_fail(self):
|
||||
# Job Templates with deleted credentials cannot be launched.
|
||||
self.cred_sue.mark_inactive()
|
||||
self.cred_sue.delete()
|
||||
with self.current_user(self.user_sue):
|
||||
self.post(self.launch_url, {}, expect=400)
|
||||
|
||||
@ -202,7 +203,7 @@ class JobTemplateLaunchPasswordsTest(BaseJobTestMixin, django.test.TransactionTe
|
||||
passwords_required = ['ssh_password', 'become_password', 'ssh_key_unlock']
|
||||
# Job Templates with deleted credentials cannot be launched.
|
||||
with self.current_user(self.user_sue):
|
||||
self.cred_sue_ask.mark_inactive()
|
||||
self.cred_sue_ask.delete()
|
||||
response = self.post(self.launch_url, {'credential_id': self.cred_sue_ask_many.pk}, expect=400)
|
||||
for p in passwords_required:
|
||||
self.assertIn(p, response['passwords_needed_to_start'])
|
||||
|
||||
@ -169,7 +169,7 @@ class ProjectsTest(BaseTransactionTest):
|
||||
local_path = project.local_path
|
||||
response = self.get(url, expect=200, auth=self.get_super_credentials())
|
||||
self.assertTrue(local_path not in response['project_local_paths'])
|
||||
project.mark_inactive()
|
||||
project.delete()
|
||||
response = self.get(url, expect=200, auth=self.get_super_credentials())
|
||||
self.assertTrue(local_path in response['project_local_paths'])
|
||||
|
||||
|
||||
@ -88,7 +88,8 @@ class InventoryScriptTest(BaseScriptTest):
|
||||
inventory=inventory,
|
||||
variables=variables)
|
||||
if x in (3, 7):
|
||||
host.mark_inactive()
|
||||
host.delete()
|
||||
continue
|
||||
hosts.append(host)
|
||||
|
||||
# add localhost just to make sure it's thrown into all (Ansible github bug)
|
||||
@ -106,7 +107,8 @@ class InventoryScriptTest(BaseScriptTest):
|
||||
inventory=inventory,
|
||||
variables=variables)
|
||||
if x == 2:
|
||||
group.mark_inactive()
|
||||
group.delete()
|
||||
continue
|
||||
groups.append(group)
|
||||
group.hosts.add(hosts[x])
|
||||
group.hosts.add(hosts[x + 5])
|
||||
@ -320,9 +322,9 @@ class InventoryScriptTest(BaseScriptTest):
|
||||
|
||||
def test_with_deleted_inventory(self):
|
||||
inventory = self.inventories[0]
|
||||
inventory.mark_inactive()
|
||||
self.assertFalse(inventory.active)
|
||||
os.environ['INVENTORY_ID'] = str(inventory.pk)
|
||||
pk = inventory.pk
|
||||
inventory.delete()
|
||||
os.environ['INVENTORY_ID'] = str(pk)
|
||||
rc, stdout, stderr = self.run_inventory_script(list=True)
|
||||
self.assertNotEqual(rc, 0, stderr)
|
||||
self.assertEqual(json.loads(stdout), {'failed': True})
|
||||
|
||||
@ -592,26 +592,8 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
new_group.children.remove(self.group)
|
||||
new_group = Group.objects.get(pk=new_group.pk)
|
||||
self.assertFalse(new_group.has_active_failures)
|
||||
# Mark host inactive (should clear flag on parent group and inventory)
|
||||
self.host.mark_inactive()
|
||||
self.group = Group.objects.get(pk=self.group.pk)
|
||||
self.assertFalse(self.group.has_active_failures)
|
||||
self.inventory = Inventory.objects.get(pk=self.inventory.pk)
|
||||
self.assertFalse(self.inventory.has_active_failures)
|
||||
# Un-mark host as inactive (need to force update of flag on group and
|
||||
# inventory)
|
||||
host = self.host
|
||||
host.name = '_'.join(host.name.split('_')[3:]) or 'undeleted host'
|
||||
host.active = True
|
||||
host.save()
|
||||
host.update_computed_fields()
|
||||
self.group = Group.objects.get(pk=self.group.pk)
|
||||
self.assertTrue(self.group.has_active_failures)
|
||||
self.inventory = Inventory.objects.get(pk=self.inventory.pk)
|
||||
self.assertTrue(self.inventory.has_active_failures)
|
||||
# Delete host. (should clear flag)
|
||||
# Delete host (should clear flag on parent group and inventory)
|
||||
self.host.delete()
|
||||
self.host = None
|
||||
self.group = Group.objects.get(pk=self.group.pk)
|
||||
self.assertFalse(self.group.has_active_failures)
|
||||
self.inventory = Inventory.objects.get(pk=self.inventory.pk)
|
||||
@ -619,30 +601,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
|
||||
def test_update_has_active_failures_when_job_removed(self):
|
||||
job = self.test_run_job_that_fails()
|
||||
# Mark job as inactive (should clear flags).
|
||||
job.mark_inactive()
|
||||
self.host = Host.objects.get(pk=self.host.pk)
|
||||
self.assertFalse(self.host.has_active_failures)
|
||||
self.group = Group.objects.get(pk=self.group.pk)
|
||||
self.assertFalse(self.group.has_active_failures)
|
||||
self.inventory = Inventory.objects.get(pk=self.inventory.pk)
|
||||
self.assertFalse(self.inventory.has_active_failures)
|
||||
# Un-mark job as inactive (need to force update of flag)
|
||||
job.active = True
|
||||
job.save()
|
||||
# Need to manually update last_job on host...
|
||||
host = Host.objects.get(pk=self.host.pk)
|
||||
host.last_job = job
|
||||
host.last_job_host_summary = JobHostSummary.objects.get(job=job, host=host)
|
||||
host.save()
|
||||
self.inventory.update_computed_fields()
|
||||
self.host = Host.objects.get(pk=self.host.pk)
|
||||
self.assertTrue(self.host.has_active_failures)
|
||||
self.group = Group.objects.get(pk=self.group.pk)
|
||||
self.assertTrue(self.group.has_active_failures)
|
||||
self.inventory = Inventory.objects.get(pk=self.inventory.pk)
|
||||
self.assertTrue(self.inventory.has_active_failures)
|
||||
# Delete job entirely.
|
||||
# Delete (should clear flags).
|
||||
job.delete()
|
||||
self.host = Host.objects.get(pk=self.host.pk)
|
||||
self.assertFalse(self.host.has_active_failures)
|
||||
@ -662,8 +621,8 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self.host = Host.objects.get(pk=self.host.pk)
|
||||
self.assertEqual(self.host.last_job, job1)
|
||||
self.assertEqual(self.host.last_job_host_summary.job, job1)
|
||||
# Mark job1 inactive (should update host.last_job to None).
|
||||
job1.mark_inactive()
|
||||
# Delete job1 (should update host.last_job to None).
|
||||
job1.delete()
|
||||
self.host = Host.objects.get(pk=self.host.pk)
|
||||
self.assertEqual(self.host.last_job, None)
|
||||
self.assertEqual(self.host.last_job_host_summary, None)
|
||||
|
||||
@ -196,7 +196,7 @@ class UsersTest(BaseTest):
|
||||
self.post(url, expect=201, data=new_user2, auth=self.get_normal_credentials())
|
||||
self.post(url, expect=400, data=new_user2, auth=self.get_normal_credentials())
|
||||
# Normal user cannot add users after his org is marked inactive.
|
||||
self.organizations[0].mark_inactive()
|
||||
self.organizations[0].delete()
|
||||
new_user3 = dict(username='blippy3')
|
||||
self.post(url, expect=403, data=new_user3, auth=self.get_normal_credentials())
|
||||
|
||||
@ -316,7 +316,7 @@ class UsersTest(BaseTest):
|
||||
remote_addr=remote_addr)
|
||||
|
||||
# Token auth should be denied if the user is inactive.
|
||||
self.normal_django_user.mark_inactive()
|
||||
self.normal_django_user.delete()
|
||||
response = self.get(user_me_url, expect=401, auth=auth_token2,
|
||||
remote_addr=remote_addr)
|
||||
self.assertEqual(response['detail'], 'User inactive or deleted')
|
||||
@ -422,7 +422,7 @@ class UsersTest(BaseTest):
|
||||
# Normal user can no longer see all users after the organization he
|
||||
# admins is marked inactive, nor can he see any other users that were
|
||||
# in that org, so he only sees himself.
|
||||
self.organizations[0].mark_inactive()
|
||||
self.organizations[0].delete()
|
||||
data3 = self.get(url, expect=200, auth=self.get_normal_credentials())
|
||||
self.assertEquals(data3['count'], 1)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user