From ec59330465d5f904991e5a2d2b716edee4b29418 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Wed, 9 Mar 2016 13:51:17 -0500 Subject: [PATCH 1/9] Active flag removed from Primordial Base Class --- awx/main/models/base.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/awx/main/models/base.py b/awx/main/models/base.py index c4edfbd8ba..677e48e92d 100644 --- a/awx/main/models/base.py +++ b/awx/main/models/base.py @@ -273,29 +273,9 @@ class PrimordialModel(CreatedModifiedModel): editable=False, on_delete=models.SET_NULL, ) - active = models.BooleanField( - default=True, - editable=False, - ) tags = TaggableManager(blank=True) - def mark_inactive(self, save=True, update_fields=None, skip_active_check=False): - '''Use instead of delete to rename and mark inactive.''' - update_fields = update_fields or [] - if skip_active_check or self.active: - dtnow = now() - if 'name' in self._meta.get_all_field_names(): - self.name = "_deleted_%s_%s" % (dtnow.isoformat(), self.name) - if 'name' not in update_fields: - update_fields.append('name') - self.active = False - if 'active' not in update_fields: - update_fields.append('active') - if save: - self.save(update_fields=update_fields) - return update_fields - def save(self, *args, **kwargs): update_fields = kwargs.get('update_fields', []) user = get_current_user() From 4825b2a6fcb8fb325dbbc8190eb5195637b3e677 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Wed, 9 Mar 2016 15:38:57 -0500 Subject: [PATCH 2/9] Do cleanup_deleted on migrate. Re-ordered active flag removal to be before system job template creation. Also removed active flag deletes from remaining cleanup_deleted management command as they will no longer be needed - but the deletes of the authentication tokens as well as potentially disabled users are still necessary, so the cleanup_deleted command will continue to exist. Reordering of the active flag removal to happen before the system job template creation is necessary since the system job template creation hits the license checker which at some point runs queries that depend on the active flag, and with that code changing to not use the active flag, we need to do the removal before we run this code. --- .../management/commands/cleanup_deleted.py | 2 - .../0005_v300_active_flag_removal.py | 65 ++++++++++++++ .../0006_v300_active_flag_removal.py | 16 ---- ...5_v300_changes.py => 0006_v300_changes.py} | 2 +- awx/main/migrations/0007_v300_rbac_changes.py | 2 +- awx/main/migrations/_cleanup_deleted.py | 85 +++++++++++++++++++ 6 files changed, 152 insertions(+), 20 deletions(-) create mode 100644 awx/main/migrations/0005_v300_active_flag_removal.py delete mode 100644 awx/main/migrations/0006_v300_active_flag_removal.py rename awx/main/migrations/{0005_v300_changes.py => 0006_v300_changes.py} (98%) create mode 100644 awx/main/migrations/_cleanup_deleted.py diff --git a/awx/main/management/commands/cleanup_deleted.py b/awx/main/management/commands/cleanup_deleted.py index b6fd5360e5..7fd726be7f 100644 --- a/awx/main/management/commands/cleanup_deleted.py +++ b/awx/main/management/commands/cleanup_deleted.py @@ -111,8 +111,6 @@ class Command(BaseCommand): n_deleted_items = 0 n_deleted_items += self.cleanup_model(User) - for model in self.get_models(PrimordialModel): - n_deleted_items += self.cleanup_model(model) if not self.dry_run: self.logger.log(99, "Removed %d items", n_deleted_items) diff --git a/awx/main/migrations/0005_v300_active_flag_removal.py b/awx/main/migrations/0005_v300_active_flag_removal.py new file mode 100644 index 0000000000..adc6a0cddf --- /dev/null +++ b/awx/main/migrations/0005_v300_active_flag_removal.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from awx.main.migrations import _cleanup_deleted as cleanup_deleted +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0004_v300_changes'), + ] + + operations = [ + migrations.RunPython(cleanup_deleted.cleanup_deleted), + + migrations.RemoveField( + model_name='credential', + name='active', + ), + migrations.RemoveField( + model_name='custominventoryscript', + name='active', + ), + migrations.RemoveField( + model_name='group', + name='active', + ), + migrations.RemoveField( + model_name='host', + name='active', + ), + migrations.RemoveField( + model_name='inventory', + name='active', + ), + migrations.RemoveField( + model_name='notifier', + name='active', + ), + migrations.RemoveField( + model_name='organization', + name='active', + ), + migrations.RemoveField( + model_name='permission', + name='active', + ), + migrations.RemoveField( + model_name='schedule', + name='active', + ), + migrations.RemoveField( + model_name='team', + name='active', + ), + migrations.RemoveField( + model_name='unifiedjob', + name='active', + ), + migrations.RemoveField( + model_name='unifiedjobtemplate', + name='active', + ), + ] diff --git a/awx/main/migrations/0006_v300_active_flag_removal.py b/awx/main/migrations/0006_v300_active_flag_removal.py deleted file mode 100644 index 795db642b2..0000000000 --- a/awx/main/migrations/0006_v300_active_flag_removal.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from awx.main.migrations import _rbac as rbac -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('main', '0005_v300_changes'), - ] - - operations = [ - # This is a placeholder for our future active flag removal work - ] diff --git a/awx/main/migrations/0005_v300_changes.py b/awx/main/migrations/0006_v300_changes.py similarity index 98% rename from awx/main/migrations/0005_v300_changes.py rename to awx/main/migrations/0006_v300_changes.py index e350c881f2..4162ff3bd1 100644 --- a/awx/main/migrations/0005_v300_changes.py +++ b/awx/main/migrations/0006_v300_changes.py @@ -107,7 +107,7 @@ def create_system_job_templates(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('main', '0004_v300_changes'), + ('main', '0005_v300_active_flag_removal'), ] operations = [ diff --git a/awx/main/migrations/0007_v300_rbac_changes.py b/awx/main/migrations/0007_v300_rbac_changes.py index f77d4c026a..b1aae399d3 100644 --- a/awx/main/migrations/0007_v300_rbac_changes.py +++ b/awx/main/migrations/0007_v300_rbac_changes.py @@ -14,7 +14,7 @@ class Migration(migrations.Migration): ('taggit', '0002_auto_20150616_2121'), ('contenttypes', '0002_remove_content_type_name'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('main', '0006_v300_active_flag_removal'), + ('main', '0006_v300_changes'), ] operations = [ diff --git a/awx/main/migrations/_cleanup_deleted.py b/awx/main/migrations/_cleanup_deleted.py new file mode 100644 index 0000000000..db187efeb4 --- /dev/null +++ b/awx/main/migrations/_cleanup_deleted.py @@ -0,0 +1,85 @@ +# Copyright (c) 2016 Ansible, Inc. +# All Rights Reserved. + +# Python +import logging + +# Django +from django.db import transaction +from django.utils.dateparse import parse_datetime + +def cleanup_deleted(apps, schema_editor): + logger = logging.getLogger('awx.main.migrations.cleanup_deleted') + + def cleanup_model(model): + + ''' + Presume the '_deleted_' string to be in the 'name' field unless considering the User model. + When considering the User model, presume the '_d_' string to be in the 'username' field. + ''' + logger.debug('cleaning up model %s', model) + + name_field = 'name' + name_prefix = '_deleted_' + active_field = None + n_deleted_items = 0 + for field in model._meta.fields: + if field.name in ('is_active', 'active'): + active_field = field.name + if field.name == 'is_active': # is User model + name_field = 'username' + name_prefix = '_d_' + if not active_field: + logger.warning('skipping model %s, no active field', model) + return n_deleted_items + qs = model.objects.filter(**{ + active_field: False, + '%s__startswith' % name_field: name_prefix, + }) + pks_to_delete = set() + for instance in qs.iterator(): + dt = parse_datetime(getattr(instance, name_field).split('_')[2]) + if not dt: + logger.warning('unable to find deleted timestamp in %s field', name_field) + else: + action_text = 'deleting' + logger.info('%s %s', action_text, instance) + n_deleted_items += 1 + instance.delete() + + # Cleanup objects in batches instead of deleting each one individually. + if len(pks_to_delete) >= 50: + model.objects.filter(pk__in=pks_to_delete).delete() + pks_to_delete.clear() + if len(pks_to_delete): + model.objects.filter(pk__in=pks_to_delete).delete() + return n_deleted_items + + logger = logging.getLogger('awx.main.commands.cleanup_deleted') + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter('%(message)s')) + logger.addHandler(handler) + logger.propagate = False + + with transaction.atomic(): + n_deleted_items = 0 + + models = [ + apps.get_model('auth', "User"), + apps.get_model('main', 'Credential'), + apps.get_model('main', 'CustomInventoryScript'), + apps.get_model('main', 'Group'), + apps.get_model('main', 'Host'), + apps.get_model('main', 'Inventory'), + apps.get_model('main', 'Notifier'), + apps.get_model('main', 'Organization'), + apps.get_model('main', 'Permission'), + apps.get_model('main', 'Schedule'), + apps.get_model('main', 'Team'), + apps.get_model('main', 'UnifiedJob'), + apps.get_model('main', 'UnifiedJobTemplate'), + ] + + for model in models: + n_deleted_items += cleanup_model(model) + logger.log(99, "Removed %d items", n_deleted_items) From 26f73fa68eb90e0bbc8dc1ce3258e0c4f93aed1e Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Wed, 9 Mar 2016 15:44:16 -0500 Subject: [PATCH 3/9] Remove active flag from ever getting created in the rbac models --- awx/main/migrations/0007_v300_rbac_changes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/awx/main/migrations/0007_v300_rbac_changes.py b/awx/main/migrations/0007_v300_rbac_changes.py index b1aae399d3..1d8f9cf2c5 100644 --- a/awx/main/migrations/0007_v300_rbac_changes.py +++ b/awx/main/migrations/0007_v300_rbac_changes.py @@ -41,7 +41,6 @@ class Migration(migrations.Migration): ('created', models.DateTimeField(default=None, editable=False)), ('modified', models.DateTimeField(default=None, editable=False)), ('description', models.TextField(default=b'', blank=True)), - ('active', models.BooleanField(default=True, editable=False)), ('name', models.CharField(max_length=512)), ('singleton_name', models.TextField(default=None, unique=True, null=True, db_index=True)), ('object_id', models.PositiveIntegerField(default=None, null=True)), From ddf3265bd277481a18f0bb4654a69e49743679bc Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Wed, 9 Mar 2016 16:03:57 -0500 Subject: [PATCH 4/9] Reordered system job template migration to happen after rbac migrations The system job template migration creates SystemJobTemplate instances, which necessarily depend on the RBAC modifications. --- .../{0007_v300_rbac_changes.py => 0006_v300_rbac_changes.py} | 2 +- ...8_v300_rbac_migrations.py => 0007_v300_rbac_migrations.py} | 2 +- .../migrations/{0006_v300_changes.py => 0009_v300_changes.py} | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename awx/main/migrations/{0007_v300_rbac_changes.py => 0006_v300_rbac_changes.py} (99%) rename awx/main/migrations/{0008_v300_rbac_migrations.py => 0007_v300_rbac_migrations.py} (92%) rename awx/main/migrations/{0006_v300_changes.py => 0009_v300_changes.py} (97%) diff --git a/awx/main/migrations/0007_v300_rbac_changes.py b/awx/main/migrations/0006_v300_rbac_changes.py similarity index 99% rename from awx/main/migrations/0007_v300_rbac_changes.py rename to awx/main/migrations/0006_v300_rbac_changes.py index 1d8f9cf2c5..d9313fe8aa 100644 --- a/awx/main/migrations/0007_v300_rbac_changes.py +++ b/awx/main/migrations/0006_v300_rbac_changes.py @@ -14,7 +14,7 @@ class Migration(migrations.Migration): ('taggit', '0002_auto_20150616_2121'), ('contenttypes', '0002_remove_content_type_name'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('main', '0006_v300_changes'), + ('main', '0005_v300_active_flag_removal'), ] operations = [ diff --git a/awx/main/migrations/0008_v300_rbac_migrations.py b/awx/main/migrations/0007_v300_rbac_migrations.py similarity index 92% rename from awx/main/migrations/0008_v300_rbac_migrations.py rename to awx/main/migrations/0007_v300_rbac_migrations.py index 7226c31e1b..d50069ab48 100644 --- a/awx/main/migrations/0008_v300_rbac_migrations.py +++ b/awx/main/migrations/0007_v300_rbac_migrations.py @@ -8,7 +8,7 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('main', '0007_v300_rbac_changes'), + ('main', '0006_v300_rbac_changes'), ] operations = [ diff --git a/awx/main/migrations/0006_v300_changes.py b/awx/main/migrations/0009_v300_changes.py similarity index 97% rename from awx/main/migrations/0006_v300_changes.py rename to awx/main/migrations/0009_v300_changes.py index 4162ff3bd1..578dc10653 100644 --- a/awx/main/migrations/0006_v300_changes.py +++ b/awx/main/migrations/0009_v300_changes.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations from django.utils.timezone import now from awx.api.license import feature_enabled @@ -107,7 +107,7 @@ def create_system_job_templates(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('main', '0005_v300_active_flag_removal'), + ('main', '0008_v300_rbac_drop_fields'), ] operations = [ From 1e7c71edfbbcaad3349f06c60cb775be4954a390 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Wed, 9 Mar 2016 16:05:34 -0500 Subject: [PATCH 5/9] active flag removal in migration functions --- awx/main/migrations/_old_access.py | 110 ++++++++++++----------------- awx/main/migrations/_rbac.py | 5 +- 2 files changed, 48 insertions(+), 67 deletions(-) diff --git a/awx/main/migrations/_old_access.py b/awx/main/migrations/_old_access.py index c662f0ddd0..e670f5e8e5 100644 --- a/awx/main/migrations/_old_access.py +++ b/awx/main/migrations/_old_access.py @@ -199,16 +199,16 @@ class UserAccess(BaseAccess): model = User def get_queryset(self): - qs = self.model.objects.filter(is_active=True).distinct() + qs = self.model.objects.distinct() if self.user.is_superuser: return qs - if tower_settings.ORG_ADMINS_CAN_SEE_ALL_USERS and self.user.admin_of_organizations.filter(active=True).exists(): + if tower_settings.ORG_ADMINS_CAN_SEE_ALL_USERS and self.user.admin_of_organizations.all().exists(): return qs return qs.filter( Q(pk=self.user.pk) | - Q(organizations__in=self.user.admin_of_organizations.filter(active=True)) | - Q(organizations__in=self.user.organizations.filter(active=True)) | - Q(teams__in=self.user.teams.filter(active=True)) + Q(organizations__in=self.user.admin_of_organizations) | + Q(organizations__in=self.user.organizations) | + Q(teams__in=self.user.teams) ).distinct() def can_add(self, data): @@ -216,7 +216,7 @@ class UserAccess(BaseAccess): if to_python_boolean(data['is_superuser'], allow_none=True) and not self.user.is_superuser: return False return bool(self.user.is_superuser or - self.user.admin_of_organizations.filter(active=True).exists()) + self.user.admin_of_organizations.exists()) def can_change(self, obj, data): if data is not None and 'is_superuser' in data: @@ -231,18 +231,18 @@ class UserAccess(BaseAccess): # Admin implies changing all user fields. if self.user.is_superuser: return True - return bool(obj.organizations.filter(active=True, deprecated_admins__in=[self.user]).exists()) + return bool(obj.organizations.filter(deprecated_admins__in=[self.user]).exists()) def can_delete(self, obj): if obj == self.user: # cannot delete yourself return False - super_users = User.objects.filter(is_active=True, is_superuser=True) + super_users = User.objects.filter(is_superuser=True) if obj.is_superuser and super_users.count() == 1: # cannot delete the last active superuser return False return bool(self.user.is_superuser or - obj.organizations.filter(active=True, deprecated_admins__in=[self.user]).exists()) + obj.organizations.filter(deprecated_admins__in=[self.user]).exists()) class OrganizationAccess(BaseAccess): ''' @@ -257,7 +257,7 @@ class OrganizationAccess(BaseAccess): model = Organization def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by') if self.user.is_superuser: return qs @@ -295,25 +295,21 @@ class InventoryAccess(BaseAccess): def get_queryset(self, allowed=None, ad_hoc=None): allowed = allowed or PERMISSION_TYPES_ALLOWING_INVENTORY_READ - qs = Inventory.objects.filter(active=True).distinct() + qs = Inventory.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'organization') if self.user.is_superuser: return qs - qs = qs.filter(organization__active=True) admin_of = qs.filter(organization__deprecated_admins__in=[self.user]).distinct() has_user_kw = dict( permissions__user__in=[self.user], permissions__permission_type__in=allowed, - permissions__active=True, ) if ad_hoc is not None: has_user_kw['permissions__run_ad_hoc_commands'] = ad_hoc has_user_perms = qs.filter(**has_user_kw).distinct() has_team_kw = dict( permissions__team__deprecated_users__in=[self.user], - permissions__team__active=True, permissions__permission_type__in=allowed, - permissions__active=True, ) if ad_hoc is not None: has_team_kw['permissions__run_ad_hoc_commands'] = ad_hoc @@ -330,7 +326,7 @@ class InventoryAccess(BaseAccess): # If no data is specified, just checking for generic add permission? if not data: return bool(self.user.is_superuser or - self.user.admin_of_organizations.filter(active=True).exists()) + self.user.admin_of_organizations.exists()) # Otherwise, verify that the user has access to change the parent # organization of this inventory. if self.user.is_superuser: @@ -379,7 +375,7 @@ class HostAccess(BaseAccess): model = Host def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'inventory', 'last_job__job_template', 'last_job_host_summary__job') @@ -435,7 +431,7 @@ class GroupAccess(BaseAccess): model = Group def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'inventory') qs = qs.prefetch_related('parents', 'children', 'inventory_source') inventory_ids = set(self.user.get_queryset(Inventory).values_list('id', flat=True)) @@ -466,9 +462,6 @@ class GroupAccess(BaseAccess): if not super(GroupAccess, self).can_attach(obj, sub_obj, relationship, data, skip_sub_obj_read_check): return False - # Don't allow attaching if the sub obj is not active - if not obj.active: - return False # Prevent assignments between different inventories. if obj.inventory != sub_obj.inventory: raise ParseError('Cannot associate two items from different inventories') @@ -495,7 +488,7 @@ class InventorySourceAccess(BaseAccess): model = InventorySource def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'group', 'inventory') inventory_ids = set(self.user.get_queryset(Inventory).values_list('id', flat=True)) return qs.filter(Q(inventory_id__in=inventory_ids) | @@ -535,7 +528,7 @@ class InventoryUpdateAccess(BaseAccess): model = InventoryUpdate def get_queryset(self): - qs = InventoryUpdate.objects.filter(active=True).distinct() + qs = InventoryUpdate.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'inventory_source__group', 'inventory_source__inventory') inventory_sources_qs = self.user.get_queryset(InventorySource) @@ -569,19 +562,19 @@ class CredentialAccess(BaseAccess): # Create a base queryset. # If the user is a superuser, and therefore can see everything, this # is also sufficient, and we are done. - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'user', 'team') if self.user.is_superuser: return qs # Get the list of organizations for which the user is an admin - orgs_as_admin_ids = set(self.user.admin_of_organizations.filter(active=True).values_list('id', flat=True)) + orgs_as_admin_ids = set(self.user.admin_of_organizations.values_list('id', flat=True)) return qs.filter( Q(user=self.user) | Q(user__organizations__id__in=orgs_as_admin_ids) | Q(user__admin_of_organizations__id__in=orgs_as_admin_ids) | - Q(team__organization__id__in=orgs_as_admin_ids, team__active=True) | - Q(team__deprecated_users__in=[self.user], team__active=True) + Q(team__organization__id__in=orgs_as_admin_ids) | + Q(team__deprecated_users__in=[self.user]) ) def can_add(self, data): @@ -607,12 +600,12 @@ class CredentialAccess(BaseAccess): if obj.user: if self.user == obj.user: return True - if obj.user.organizations.filter(active=True, deprecated_admins__in=[self.user]).exists(): + if obj.user.organizations.filter(deprecated_admins__in=[self.user]).exists(): return True - if obj.user.admin_of_organizations.filter(active=True, deprecated_admins__in=[self.user]).exists(): + if obj.user.admin_of_organizations.filter(deprecated_admins__in=[self.user]).exists(): return True if obj.team: - if self.user in obj.team.organization.deprecated_admins.filter(is_active=True): + if self.user in obj.team.organization.deprecated_admins.all(): return True return False @@ -637,12 +630,12 @@ class TeamAccess(BaseAccess): model = Team def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'organization') if self.user.is_superuser: return qs return qs.filter( - Q(organization__deprecated_admins__in=[self.user], organization__active=True) | + Q(organization__deprecated_admins__in=[self.user]) | Q(deprecated_users__in=[self.user]) ) @@ -689,26 +682,24 @@ class ProjectAccess(BaseAccess): model = Project def get_queryset(self): - qs = Project.objects.filter(active=True).distinct() + qs = Project.objects.distinct() qs = qs.select_related('modified_by', 'credential', 'current_job', 'last_job') if self.user.is_superuser: return qs team_ids = set(Team.objects.filter(deprecated_users__in=[self.user]).values_list('id', flat=True)) qs = qs.filter(Q(created_by=self.user, deprecated_organizations__isnull=True) | - Q(deprecated_organizations__deprecated_admins__in=[self.user], deprecated_organizations__active=True) | - Q(deprecated_organizations__deprecated_users__in=[self.user], deprecated_organizations__active=True) | + Q(deprecated_organizations__deprecated_admins__in=[self.user]) | + Q(deprecated_organizations__deprecated_users__in=[self.user]) | Q(teams__in=team_ids)) allowed_deploy = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY] allowed_check = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY, PERM_INVENTORY_CHECK] deploy_permissions_ids = set(Permission.objects.filter( Q(user=self.user) | Q(team_id__in=team_ids), - active=True, permission_type__in=allowed_deploy, ).values_list('id', flat=True)) check_permissions_ids = set(Permission.objects.filter( Q(user=self.user) | Q(team_id__in=team_ids), - active=True, permission_type__in=allowed_check, ).values_list('id', flat=True)) @@ -719,16 +710,16 @@ class ProjectAccess(BaseAccess): def can_add(self, data): if self.user.is_superuser: return True - if self.user.admin_of_organizations.filter(active=True).exists(): + if self.user.admin_of_organizations.exists(): return True return False def can_change(self, obj, data): if self.user.is_superuser: return True - if obj.created_by == self.user and not obj.deprecated_organizations.filter(active=True).count(): + if obj.created_by == self.user and not obj.deprecated_organizations.count(): return True - if obj.deprecated_organizations.filter(active=True, deprecated_admins__in=[self.user]).exists(): + if obj.deprecated_organizations.filter(deprecated_admins__in=[self.user]).exists(): return True return False @@ -748,7 +739,7 @@ class ProjectUpdateAccess(BaseAccess): model = ProjectUpdate def get_queryset(self): - qs = ProjectUpdate.objects.filter(active=True).distinct() + qs = ProjectUpdate.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'project') project_ids = set(self.user.get_queryset(Project).values_list('id', flat=True)) return qs.filter(project_id__in=project_ids) @@ -776,18 +767,18 @@ class PermissionAccess(BaseAccess): model = Permission def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'user', 'team', 'inventory', 'project') if self.user.is_superuser: return qs - orgs_as_admin_ids = set(self.user.admin_of_organizations.filter(active=True).values_list('id', flat=True)) + orgs_as_admin_ids = set(self.user.admin_of_organizations.values_list('id', flat=True)) return qs.filter( Q(user__organizations__in=orgs_as_admin_ids) | Q(user__admin_of_organizations__in=orgs_as_admin_ids) | - Q(team__organization__in=orgs_as_admin_ids, team__active=True) | + Q(team__organization__in=orgs_as_admin_ids) | Q(user=self.user) | - Q(team__deprecated_users__in=[self.user], team__active=True) + Q(team__deprecated_users__in=[self.user]) ) def can_add(self, data): @@ -868,7 +859,7 @@ class JobTemplateAccess(BaseAccess): model = JobTemplate def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'inventory', 'project', 'credential', 'cloud_credential', 'next_schedule') if self.user.is_superuser: @@ -892,12 +883,10 @@ class JobTemplateAccess(BaseAccess): # TODO: I think the below queries can be combined deploy_permissions_ids = Permission.objects.filter( Q(user=self.user) | Q(team_id__in=team_ids), - active=True, permission_type__in=allowed_deploy, ) check_permissions_ids = Permission.objects.filter( Q(user=self.user) | Q(team_id__in=team_ids), - active=True, permission_type__in=allowed_check, ) @@ -986,7 +975,6 @@ class JobTemplateAccess(BaseAccess): Q(user=self.user) | Q(team__deprecated_users__in=[self.user]), inventory=inventory, project=project, - active=True, #permission_type__in=[PERM_INVENTORY_CHECK, PERM_INVENTORY_DEPLOY], permission_type=PERM_JOBTEMPLATE_CREATE, ) @@ -1044,7 +1032,6 @@ class JobTemplateAccess(BaseAccess): Q(user=self.user) | Q(team__deprecated_users__in=[self.user]), inventory=obj.inventory, project=obj.project, - active=True, permission_type__in=[PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_CHECK, PERM_INVENTORY_DEPLOY], ) @@ -1086,7 +1073,7 @@ class JobAccess(BaseAccess): model = Job def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'job_template', 'inventory', 'project', 'credential', 'cloud_credential', 'job_template') qs = qs.prefetch_related('unified_job_template') @@ -1108,12 +1095,10 @@ class JobAccess(BaseAccess): # TODO: I think the below queries can be combined deploy_permissions_ids = Permission.objects.filter( Q(user=self.user) | Q(team__in=team_ids), - active=True, permission_type__in=allowed_deploy, ) check_permissions_ids = Permission.objects.filter( Q(user=self.user) | Q(team__in=team_ids), - active=True, permission_type__in=allowed_check, ) @@ -1212,18 +1197,17 @@ class AdHocCommandAccess(BaseAccess): model = AdHocCommand def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'inventory', 'credential') if self.user.is_superuser: return qs credential_ids = set(self.user.get_queryset(Credential).values_list('id', flat=True)) - team_ids = set(Team.objects.filter(active=True, deprecated_users__in=[self.user]).values_list('id', flat=True)) + team_ids = set(Team.objects.filter(deprecated_users__in=[self.user]).values_list('id', flat=True)) permission_ids = set(Permission.objects.filter( Q(user=self.user) | Q(team__in=team_ids), - active=True, permission_type__in=PERMISSION_TYPES_ALLOWING_INVENTORY_READ, run_ad_hoc_commands=True, ).values_list('id', flat=True)) @@ -1247,7 +1231,7 @@ class AdHocCommandAccess(BaseAccess): # If a credential is provided, the user should have read access to it. credential_pk = get_pk_from_dict(data, 'credential') if credential_pk: - credential = get_object_or_400(Credential, pk=credential_pk, active=True) + credential = get_object_or_400(Credential, pk=credential_pk) if not check_user_access(self.user, Credential, 'read', credential): return False @@ -1255,7 +1239,7 @@ class AdHocCommandAccess(BaseAccess): # given inventory. inventory_pk = get_pk_from_dict(data, 'inventory') if inventory_pk: - inventory = get_object_or_400(Inventory, pk=inventory_pk, active=True) + inventory = get_object_or_400(Inventory, pk=inventory_pk) if not check_user_access(self.user, Inventory, 'run_ad_hoc_commands', inventory): return False @@ -1375,7 +1359,7 @@ class UnifiedJobTemplateAccess(BaseAccess): model = UnifiedJobTemplate def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() project_qs = self.user.get_queryset(Project).filter(scm_type__in=[s[0] for s in Project.SCM_TYPE_CHOICES]) inventory_source_qs = self.user.get_queryset(InventorySource).filter(source__in=CLOUD_INVENTORY_SOURCES) job_template_qs = self.user.get_queryset(JobTemplate) @@ -1405,7 +1389,7 @@ class UnifiedJobAccess(BaseAccess): model = UnifiedJob def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() project_update_qs = self.user.get_queryset(ProjectUpdate) inventory_update_qs = self.user.get_queryset(InventoryUpdate).filter(source__in=CLOUD_INVENTORY_SOURCES) job_qs = self.user.get_queryset(Job) @@ -1442,7 +1426,7 @@ class ScheduleAccess(BaseAccess): model = Schedule def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by') qs = qs.prefetch_related('unified_job_template') if self.user.is_superuser: @@ -1614,7 +1598,7 @@ class CustomInventoryScriptAccess(BaseAccess): model = CustomInventoryScript def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() if not self.user.is_superuser: qs = qs.filter(Q(organization__deprecated_admins__in=[self.user]) | Q(organization__deprecated_users__in=[self.user])) return qs @@ -1622,8 +1606,6 @@ class CustomInventoryScriptAccess(BaseAccess): def can_read(self, obj): if self.user.is_superuser: return True - if not obj.active: - return False return bool(obj.organization in self.user.organizations.all() or obj.organization in self.user.admin_of_organizations.all()) def can_add(self, data): diff --git a/awx/main/migrations/_rbac.py b/awx/main/migrations/_rbac.py index 8bd2a91f50..33bcb82b4a 100644 --- a/awx/main/migrations/_rbac.py +++ b/awx/main/migrations/_rbac.py @@ -73,7 +73,7 @@ def migrate_inventory(apps, schema_editor): for inventory in Inventory.objects.all(): teams, users = [], [] - for perm in Permission.objects.filter(inventory=inventory, active=True): + for perm in Permission.objects.filter(inventory=inventory): role = None execrole = None if perm.permission_type == 'admin': @@ -186,7 +186,7 @@ def migrate_projects(apps, schema_editor): project.member_role.members.add(user) migrations[project.name]['users'].add(user) - for perm in Permission.objects.filter(project=project, active=True): + for perm in Permission.objects.filter(project=project): # All perms at this level just imply a user or team can read if perm.team: perm.team.member_role.children.add(project.member_role) @@ -253,7 +253,6 @@ def migrate_job_templates(apps, schema_editor): permission = Permission.objects.filter( inventory=jt.inventory, project=jt.project, - active=True, permission_type__in=['create', 'check', 'run'] if jt.job_type == 'check' else ['create', 'run'], ) From ba833d683ef1af6b3c15649e8581dd01ab37ff38 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Thu, 10 Mar 2016 13:58:00 -0500 Subject: [PATCH 6/9] Active flag removal: switched from using mark_inactive to delete calls --- awx/api/generics.py | 15 +-- awx/api/views.py | 14 +- .../management/commands/inventory_import.py | 23 ++-- awx/main/models/base.py | 9 -- awx/main/models/inventory.py | 58 +-------- awx/main/models/organization.py | 29 ----- awx/main/models/unified_jobs.py | 11 -- awx/main/signals.py | 2 +- awx/main/tasks.py | 11 -- awx/main/tests/old/ad_hoc.py | 6 +- awx/main/tests/old/commands/age_deleted.py | 34 ----- .../tests/old/commands/commands_monolithic.py | 121 ------------------ awx/main/tests/old/inventory.py | 13 +- awx/main/tests/old/jobs/job_launch.py | 17 +-- awx/main/tests/old/projects.py | 2 +- awx/main/tests/old/scripts.py | 12 +- awx/main/tests/old/tasks.py | 49 +------ awx/main/tests/old/users.py | 6 +- 18 files changed, 55 insertions(+), 377 deletions(-) delete mode 100644 awx/main/tests/old/commands/age_deleted.py diff --git a/awx/api/generics.py b/awx/api/generics.py index a660b2acba..3c1321300c 100644 --- a/awx/api/generics.py +++ b/awx/api/generics.py @@ -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): diff --git a/awx/api/views.py b/awx/api/views.py index 4883342003..7d54f9dd56 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -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): diff --git a/awx/main/management/commands/inventory_import.py b/awx/main/management/commands/inventory_import.py index 187a04af7e..76898af111 100644 --- a/awx/main/management/commands/inventory_import.py +++ b/awx/main/management/commands/inventory_import.py @@ -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: diff --git a/awx/main/models/base.py b/awx/main/models/base.py index 677e48e92d..a25dd1d154 100644 --- a/awx/main/models/base.py +++ b/awx/main/models/base.py @@ -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, diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 32175b19d9..44f1a404f6 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -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): ''' diff --git a/awx/main/models/organization.py b/awx/main/models/organization.py index 1362b23f37..d83c68832e 100644 --- a/awx/main/models/organization.py +++ b/awx/main/models/organization.py @@ -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): diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index 3750ccf41e..5b9949dbe9 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -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. diff --git a/awx/main/signals.py b/awx/main/signals.py index 797296ef13..dbccf61dd6 100644 --- a/awx/main/signals.py +++ b/awx/main/signals.py @@ -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) diff --git a/awx/main/tasks.py b/awx/main/tasks.py index b8bb60905b..49589a6e3b 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -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(): diff --git a/awx/main/tests/old/ad_hoc.py b/awx/main/tests/old/ad_hoc.py index 52e22faf21..95b8130664 100644 --- a/awx/main/tests/old/ad_hoc.py +++ b/awx/main/tests/old/ad_hoc.py @@ -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'], []) diff --git a/awx/main/tests/old/commands/age_deleted.py b/awx/main/tests/old/commands/age_deleted.py deleted file mode 100644 index ec5591d28e..0000000000 --- a/awx/main/tests/old/commands/age_deleted.py +++ /dev/null @@ -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) diff --git a/awx/main/tests/old/commands/commands_monolithic.py b/awx/main/tests/old/commands/commands_monolithic.py index c658f6411c..c3de826259 100644 --- a/awx/main/tests/old/commands/commands_monolithic.py +++ b/awx/main/tests/old/commands/commands_monolithic.py @@ -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') diff --git a/awx/main/tests/old/inventory.py b/awx/main/tests/old/inventory.py index a3f3b63794..a47807e62b 100644 --- a/awx/main/tests/old/inventory.py +++ b/awx/main/tests/old/inventory.py @@ -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'])): diff --git a/awx/main/tests/old/jobs/job_launch.py b/awx/main/tests/old/jobs/job_launch.py index 0beb3a9546..5cd9f9e7e0 100644 --- a/awx/main/tests/old/jobs/job_launch.py +++ b/awx/main/tests/old/jobs/job_launch.py @@ -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']) diff --git a/awx/main/tests/old/projects.py b/awx/main/tests/old/projects.py index 9834356860..416ad41327 100644 --- a/awx/main/tests/old/projects.py +++ b/awx/main/tests/old/projects.py @@ -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']) diff --git a/awx/main/tests/old/scripts.py b/awx/main/tests/old/scripts.py index 1b5295d0bd..735d0f0197 100644 --- a/awx/main/tests/old/scripts.py +++ b/awx/main/tests/old/scripts.py @@ -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}) diff --git a/awx/main/tests/old/tasks.py b/awx/main/tests/old/tasks.py index a57202a958..30f58353c2 100644 --- a/awx/main/tests/old/tasks.py +++ b/awx/main/tests/old/tasks.py @@ -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) diff --git a/awx/main/tests/old/users.py b/awx/main/tests/old/users.py index 2fa89402f9..75377037da 100644 --- a/awx/main/tests/old/users.py +++ b/awx/main/tests/old/users.py @@ -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) From 6ea99583daee80ee104cf199a0ba3470c276506a Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Thu, 10 Mar 2016 16:44:55 -0500 Subject: [PATCH 7/9] Mass active flag code removal --- awx/api/filters.py | 17 +-- awx/api/permissions.py | 10 +- awx/api/serializers.py | 135 ++++++++---------- awx/api/views.py | 33 +++-- awx/main/access.py | 21 ++- .../management/commands/create_default_org.py | 2 +- .../management/commands/inventory_import.py | 26 ++-- awx/main/managers.py | 4 +- awx/main/models/ad_hoc_commands.py | 8 +- awx/main/models/inventory.py | 69 ++++----- awx/main/models/jobs.py | 8 +- awx/main/models/projects.py | 6 +- awx/main/models/schedules.py | 2 +- awx/main/signals.py | 105 ++------------ awx/main/south_migrations/0018_v14_changes.py | 10 +- .../south_migrations/0044_v1411_changes.py | 2 +- .../south_migrations/0070_v221_changes.py | 2 +- awx/main/tasks.py | 8 +- awx/main/tests/job_base.py | 36 +++-- .../tests/old/commands/commands_monolithic.py | 49 ++++--- awx/main/tests/old/inventory.py | 59 ++++---- awx/main/tests/old/jobs/job_launch.py | 2 +- awx/main/tests/old/organizations.py | 4 +- awx/main/tests/old/projects.py | 8 +- awx/main/tests/old/scripts.py | 58 +++----- awx/settings/defaults.py | 1 - awx/sso/pipeline.py | 4 +- 27 files changed, 272 insertions(+), 417 deletions(-) diff --git a/awx/api/filters.py b/awx/api/filters.py index 73afbc178b..367fd0eda5 100644 --- a/awx/api/filters.py +++ b/awx/api/filters.py @@ -26,19 +26,6 @@ class MongoFilterBackend(BaseFilterBackend): def filter_queryset(self, request, queryset, view): return queryset -class ActiveOnlyBackend(BaseFilterBackend): - ''' - Filter to show only objects where is_active/active is True. - ''' - - def filter_queryset(self, request, queryset, view): - for field in queryset.model._meta.fields: - if field.name == 'is_active': - queryset = queryset.filter(is_active=True) - elif field.name == 'active': - queryset = queryset.filter(active=True) - return queryset - class TypeFilterBackend(BaseFilterBackend): ''' Filter on type field now returned with all objects. @@ -166,12 +153,12 @@ class FieldLookupBackend(BaseFilterBackend): for key, values in request.query_params.lists(): if key in self.RESERVED_NAMES: continue - + # HACK: Make job event filtering by host name mostly work even # when not capturing job event hosts M2M. if queryset.model._meta.object_name == 'JobEvent' and key.startswith('hosts__name'): key = key.replace('hosts__name', 'or__host__name') - or_filters.append((False, 'host__name__isnull', True)) + or_filters.append((False, 'host__name__isnull', True)) # Custom __int filter suffix (internal use only). q_int = False diff --git a/awx/api/permissions.py b/awx/api/permissions.py index 8f535f7adf..bc1447ba03 100644 --- a/awx/api/permissions.py +++ b/awx/api/permissions.py @@ -103,11 +103,7 @@ class ModelAccessPermission(permissions.BasePermission): if not request.user or request.user.is_anonymous(): return False - # Don't allow inactive users (and respond with a 403). - if not request.user.is_active: - raise PermissionDenied('your account is inactive') - - # Always allow superusers (as long as they are active). + # Always allow superusers if getattr(view, 'always_allow_superuser', True) and request.user.is_superuser: return True @@ -161,8 +157,6 @@ class JobTemplateCallbackPermission(ModelAccessPermission): raise PermissionDenied() elif not host_config_key: raise PermissionDenied() - elif obj and not obj.active: - raise PermissionDenied() elif obj and obj.host_config_key != host_config_key: raise PermissionDenied() else: @@ -182,7 +176,7 @@ class TaskPermission(ModelAccessPermission): # Verify that the ID present in the auth token is for a valid, active # unified job. try: - unified_job = UnifiedJob.objects.get(active=True, status='running', + unified_job = UnifiedJob.objects.get(status='running', pk=int(request.auth.split('-')[0])) except (UnifiedJob.DoesNotExist, TypeError): return False diff --git a/awx/api/serializers.py b/awx/api/serializers.py index aea7ad0c7e..f549e1c768 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -252,7 +252,6 @@ class BaseSerializer(serializers.ModelSerializer): # make certain fields read only created = serializers.SerializerMethodField() modified = serializers.SerializerMethodField() - active = serializers.SerializerMethodField() def get_type(self, obj): @@ -288,9 +287,9 @@ class BaseSerializer(serializers.ModelSerializer): def get_related(self, obj): res = OrderedDict() - if getattr(obj, 'created_by', None) and obj.created_by.is_active: + if getattr(obj, 'created_by', None): res['created_by'] = reverse('api:user_detail', args=(obj.created_by.pk,)) - if getattr(obj, 'modified_by', None) and obj.modified_by.is_active: + if getattr(obj, 'modified_by', None): res['modified_by'] = reverse('api:user_detail', args=(obj.modified_by.pk,)) return res @@ -315,10 +314,6 @@ class BaseSerializer(serializers.ModelSerializer): continue if fkval == obj: continue - if hasattr(fkval, 'active') and not fkval.active: - continue - if hasattr(fkval, 'is_active') and not fkval.is_active: - continue summary_fields[fk] = OrderedDict() for field in related_fields: fval = getattr(fkval, field, None) @@ -334,11 +329,11 @@ class BaseSerializer(serializers.ModelSerializer): # Can be raised by the reverse accessor for a OneToOneField. except ObjectDoesNotExist: pass - if getattr(obj, 'created_by', None) and obj.created_by.is_active: + if getattr(obj, 'created_by', None): summary_fields['created_by'] = OrderedDict() for field in SUMMARIZABLE_FK_FIELDS['user']: summary_fields['created_by'][field] = getattr(obj.created_by, field) - if getattr(obj, 'modified_by', None) and obj.modified_by.is_active: + if getattr(obj, 'modified_by', None): summary_fields['modified_by'] = OrderedDict() for field in SUMMARIZABLE_FK_FIELDS['user']: summary_fields['modified_by'][field] = getattr(obj.modified_by, field) @@ -378,14 +373,6 @@ class BaseSerializer(serializers.ModelSerializer): else: return obj.modified - def get_active(self, obj): - if obj is None: - return False - elif isinstance(obj, User): - return obj.is_active - else: - return obj.active - def build_standard_field(self, field_name, model_field): # DRF 3.3 serializers.py::build_standard_field() -> utils/field_mapping.py::get_field_kwargs() short circuits @@ -564,11 +551,11 @@ class UnifiedJobTemplateSerializer(BaseSerializer): def get_related(self, obj): res = super(UnifiedJobTemplateSerializer, self).get_related(obj) - if obj.current_job and obj.current_job.active: + if obj.current_job: res['current_job'] = obj.current_job.get_absolute_url() - if obj.last_job and obj.last_job.active: + if obj.last_job: res['last_job'] = obj.last_job.get_absolute_url() - if obj.next_schedule and obj.next_schedule.active: + if obj.next_schedule: res['next_schedule'] = obj.next_schedule.get_absolute_url() return res @@ -623,9 +610,9 @@ class UnifiedJobSerializer(BaseSerializer): def get_related(self, obj): res = super(UnifiedJobSerializer, self).get_related(obj) - if obj.unified_job_template and obj.unified_job_template.active: + if obj.unified_job_template: res['unified_job_template'] = obj.unified_job_template.get_absolute_url() - if obj.schedule and obj.schedule.active: + if obj.schedule: res['schedule'] = obj.schedule.get_absolute_url() if isinstance(obj, ProjectUpdate): res['stdout'] = reverse('api:project_update_stdout', args=(obj.pk,)) @@ -874,7 +861,7 @@ class ProjectOptionsSerializer(BaseSerializer): def get_related(self, obj): res = super(ProjectOptionsSerializer, self).get_related(obj) - if obj.credential and obj.credential.active: + if obj.credential: res['credential'] = reverse('api:credential_detail', args=(obj.credential.pk,)) return res @@ -903,7 +890,7 @@ class ProjectOptionsSerializer(BaseSerializer): def to_representation(self, obj): ret = super(ProjectOptionsSerializer, self).to_representation(obj) - if obj is not None and 'credential' in ret and (not obj.credential or not obj.credential.active): + if obj is not None and 'credential' in ret and not obj.credential: ret['credential'] = None return ret @@ -1039,13 +1026,13 @@ class InventorySerializer(BaseSerializerWithVariables): access_list = reverse('api:inventory_access_list', args=(obj.pk,)), #single_fact = reverse('api:inventory_single_fact_view', args=(obj.pk,)), )) - if obj.organization and obj.organization.active: + if obj.organization: res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,)) return res def to_representation(self, obj): ret = super(InventorySerializer, self).to_representation(obj) - if obj is not None and 'organization' in ret and (not obj.organization or not obj.organization.active): + if obj is not None and 'organization' in ret and not obj.organization: ret['organization'] = None return ret @@ -1100,11 +1087,11 @@ class HostSerializer(BaseSerializerWithVariables): fact_versions = reverse('api:host_fact_versions_list', args=(obj.pk,)), #single_fact = reverse('api:host_single_fact_view', args=(obj.pk,)), )) - if obj.inventory and obj.inventory.active: + if obj.inventory: res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,)) - if obj.last_job and obj.last_job.active: + if obj.last_job: res['last_job'] = reverse('api:job_detail', args=(obj.last_job.pk,)) - if obj.last_job_host_summary and obj.last_job_host_summary.job.active: + if obj.last_job_host_summary: res['last_job_host_summary'] = reverse('api:job_host_summary_detail', args=(obj.last_job_host_summary.pk,)) return res @@ -1120,7 +1107,7 @@ class HostSerializer(BaseSerializerWithVariables): 'name': j.job.job_template.name if j.job.job_template is not None else "", 'status': j.job.status, 'finished': j.job.finished, - } for j in obj.job_host_summaries.filter(job__active=True).select_related('job__job_template').order_by('-created')[:5]]}) + } for j in obj.job_host_summaries.select_related('job__job_template').order_by('-created')[:5]]}) return d def _get_host_port_from_name(self, name): @@ -1169,11 +1156,11 @@ class HostSerializer(BaseSerializerWithVariables): ret = super(HostSerializer, self).to_representation(obj) if not obj: return ret - if 'inventory' in ret and (not obj.inventory or not obj.inventory.active): + if 'inventory' in ret and not obj.inventory: ret['inventory'] = None - if 'last_job' in ret and (not obj.last_job or not obj.last_job.active): + if 'last_job' in ret and not obj.last_job: ret['last_job'] = None - if 'last_job_host_summary' in ret and (not obj.last_job_host_summary or not obj.last_job_host_summary.job.active): + if 'last_job_host_summary' in ret and not obj.last_job_host_summary: ret['last_job_host_summary'] = None return ret @@ -1210,7 +1197,7 @@ class GroupSerializer(BaseSerializerWithVariables): access_list = reverse('api:group_access_list', args=(obj.pk,)), #single_fact = reverse('api:group_single_fact_view', args=(obj.pk,)), )) - if obj.inventory and obj.inventory.active: + if obj.inventory: res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,)) if obj.inventory_source: res['inventory_source'] = reverse('api:inventory_source_detail', args=(obj.inventory_source.pk,)) @@ -1223,7 +1210,7 @@ class GroupSerializer(BaseSerializerWithVariables): def to_representation(self, obj): ret = super(GroupSerializer, self).to_representation(obj) - if obj is not None and 'inventory' in ret and (not obj.inventory or not obj.inventory.active): + if obj is not None and 'inventory' in ret and not obj.inventory: ret['inventory'] = None return ret @@ -1239,7 +1226,7 @@ class GroupTreeSerializer(GroupSerializer): def get_children(self, obj): if obj is None: return {} - children_qs = obj.children.filter(active=True) + children_qs = obj.children children_qs = children_qs.select_related('inventory') children_qs = children_qs.prefetch_related('inventory_source') return GroupTreeSerializer(children_qs, many=True).data @@ -1304,7 +1291,7 @@ class CustomInventoryScriptSerializer(BaseSerializer): def get_related(self, obj): res = super(CustomInventoryScriptSerializer, self).get_related(obj) - if obj.organization and obj.organization.active: + if obj.organization: res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,)) return res @@ -1317,10 +1304,10 @@ class InventorySourceOptionsSerializer(BaseSerializer): def get_related(self, obj): res = super(InventorySourceOptionsSerializer, self).get_related(obj) - if obj.credential and obj.credential.active: + if obj.credential: res['credential'] = reverse('api:credential_detail', args=(obj.credential.pk,)) - if obj.source_script and obj.source_script.active: + if obj.source_script: res['source_script'] = reverse('api:inventory_script_detail', args=(obj.source_script.pk,)) return res @@ -1365,7 +1352,7 @@ class InventorySourceOptionsSerializer(BaseSerializer): ret = super(InventorySourceOptionsSerializer, self).to_representation(obj) if obj is None: return ret - if 'credential' in ret and (not obj.credential or not obj.credential.active): + if 'credential' in ret and not obj.credential: ret['credential'] = None return ret @@ -1396,9 +1383,9 @@ class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOpt notifiers_success = reverse('api:inventory_source_notifiers_success_list', args=(obj.pk,)), notifiers_error = reverse('api:inventory_source_notifiers_error_list', args=(obj.pk,)), )) - if obj.inventory and obj.inventory.active: + if obj.inventory: res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,)) - if obj.group and obj.group.active: + if obj.group: res['group'] = reverse('api:group_detail', args=(obj.group.pk,)) # Backwards compatibility. if obj.current_update: @@ -1413,9 +1400,9 @@ class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOpt ret = super(InventorySourceSerializer, self).to_representation(obj) if obj is None: return ret - if 'inventory' in ret and (not obj.inventory or not obj.inventory.active): + if 'inventory' in ret and not obj.inventory: ret['inventory'] = None - if 'group' in ret and (not obj.group or not obj.group.active): + if 'group' in ret and not obj.group: ret['group'] = None return ret @@ -1473,13 +1460,13 @@ class TeamSerializer(BaseSerializer): activity_stream = reverse('api:team_activity_stream_list', args=(obj.pk,)), access_list = reverse('api:team_access_list', args=(obj.pk,)), )) - if obj.organization and obj.organization.active: + if obj.organization: res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,)) return res def to_representation(self, obj): ret = super(TeamSerializer, self).to_representation(obj) - if obj is not None and 'organization' in ret and (not obj.organization or not obj.organization.active): + if obj is not None and 'organization' in ret and not obj.organization: ret['organization'] = None return ret @@ -1563,9 +1550,9 @@ class CredentialSerializer(BaseSerializer): def to_representation(self, obj): ret = super(CredentialSerializer, self).to_representation(obj) - if obj is not None and 'user' in ret and (not obj.user or not obj.user.is_active): + if obj is not None and 'user' in ret and not obj.user: ret['user'] = None - if obj is not None and 'team' in ret and (not obj.team or not obj.team.active): + if obj is not None and 'team' in ret and not obj.team: ret['team'] = None return ret @@ -1604,13 +1591,13 @@ class JobOptionsSerializer(BaseSerializer): def get_related(self, obj): res = super(JobOptionsSerializer, self).get_related(obj) - if obj.inventory and obj.inventory.active: + if obj.inventory: res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,)) - if obj.project and obj.project.active: + if obj.project: res['project'] = reverse('api:project_detail', args=(obj.project.pk,)) - if obj.credential and obj.credential.active: + if obj.credential: res['credential'] = reverse('api:credential_detail', args=(obj.credential.pk,)) - if obj.cloud_credential and obj.cloud_credential.active: + if obj.cloud_credential: res['cloud_credential'] = reverse('api:credential_detail', args=(obj.cloud_credential.pk,)) return res @@ -1619,15 +1606,15 @@ class JobOptionsSerializer(BaseSerializer): ret = super(JobOptionsSerializer, self).to_representation(obj) if obj is None: return ret - if 'inventory' in ret and (not obj.inventory or not obj.inventory.active): + if 'inventory' in ret and not obj.inventory: ret['inventory'] = None - if 'project' in ret and (not obj.project or not obj.project.active): + if 'project' in ret and not obj.project: ret['project'] = None if 'playbook' in ret: ret['playbook'] = '' - if 'credential' in ret and (not obj.credential or not obj.credential.active): + if 'credential' in ret and not obj.credential: ret['credential'] = None - if 'cloud_credential' in ret and (not obj.cloud_credential or not obj.cloud_credential.active): + if 'cloud_credential' in ret and not obj.cloud_credential: ret['cloud_credential'] = None return ret @@ -1690,7 +1677,7 @@ class JobTemplateSerializer(UnifiedJobTemplateSerializer, JobOptionsSerializer): else: d['can_copy'] = False d['can_edit'] = False - d['recent_jobs'] = [{'id': x.id, 'status': x.status, 'finished': x.finished} for x in obj.jobs.filter(active=True).order_by('-created')[:10]] + d['recent_jobs'] = [{'id': x.id, 'status': x.status, 'finished': x.finished} for x in obj.jobs.order_by('-created')[:10]] return d def validate(self, attrs): @@ -1721,7 +1708,7 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer): activity_stream = reverse('api:job_activity_stream_list', args=(obj.pk,)), notifications = reverse('api:job_notifications_list', args=(obj.pk,)), )) - if obj.job_template and obj.job_template.active: + if obj.job_template: res['job_template'] = reverse('api:job_template_detail', args=(obj.job_template.pk,)) if obj.can_start or True: @@ -1766,7 +1753,7 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer): ret = super(JobSerializer, self).to_representation(obj) if obj is None: return ret - if 'job_template' in ret and (not obj.job_template or not obj.job_template.active): + if 'job_template' in ret and not obj.job_template: ret['job_template'] = None if obj.job_template and obj.job_template.survey_enabled: @@ -1830,11 +1817,11 @@ class JobRelaunchSerializer(JobSerializer): def validate(self, attrs): obj = self.context.get('obj') - if not obj.credential or obj.credential.active is False: + if not obj.credential: raise serializers.ValidationError(dict(credential=["Credential not found or deleted."])) - if obj.job_type != PERM_INVENTORY_SCAN and (obj.project is None or not obj.project.active): + if obj.job_type != PERM_INVENTORY_SCAN and obj.project is None: raise serializers.ValidationError(dict(errors=["Job Template Project is missing or undefined"])) - if obj.inventory is None or not obj.inventory.active: + if obj.inventory is None: raise serializers.ValidationError(dict(errors=["Job Template Inventory is missing or undefined"])) attrs = super(JobRelaunchSerializer, self).validate(attrs) return attrs @@ -1874,9 +1861,9 @@ class AdHocCommandSerializer(UnifiedJobSerializer): def get_related(self, obj): res = super(AdHocCommandSerializer, self).get_related(obj) - if obj.inventory and obj.inventory.active: + if obj.inventory: res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,)) - if obj.credential and obj.credential.active: + if obj.credential: res['credential'] = reverse('api:credential_detail', args=(obj.credential.pk,)) res.update(dict( events = reverse('api:ad_hoc_command_ad_hoc_command_events_list', args=(obj.pk,)), @@ -1888,9 +1875,9 @@ class AdHocCommandSerializer(UnifiedJobSerializer): def to_representation(self, obj): ret = super(AdHocCommandSerializer, self).to_representation(obj) - if 'inventory' in ret and (not obj.inventory or not obj.inventory.active): + if 'inventory' in ret and not obj.inventory: ret['inventory'] = None - if 'credential' in ret and (not obj.credential or not obj.credential.active): + if 'credential' in ret and not obj.credential: ret['credential'] = None # For the UI, only module_name is returned for name, instead of the # longer module name + module_args format. @@ -1942,7 +1929,7 @@ class SystemJobSerializer(UnifiedJobSerializer): def get_related(self, obj): res = super(SystemJobSerializer, self).get_related(obj) - if obj.system_job_template and obj.system_job_template.active: + if obj.system_job_template: res['system_job_template'] = reverse('api:system_job_template_detail', args=(obj.system_job_template.pk,)) if obj.can_cancel or True: @@ -2080,7 +2067,7 @@ class JobLaunchSerializer(BaseSerializer): } def get_credential_needed_to_start(self, obj): - return not (obj and obj.credential and obj.credential.active) + return not (obj and obj.credential) def get_survey_enabled(self, obj): if obj: @@ -2093,7 +2080,7 @@ class JobLaunchSerializer(BaseSerializer): data = self.context.get('data') credential = attrs.get('credential', obj and obj.credential or None) - if not credential or not credential.active: + if not credential: errors['credential'] = 'Credential not provided' # fill passwords dict with request data passwords @@ -2124,9 +2111,9 @@ class JobLaunchSerializer(BaseSerializer): if validation_errors: errors['variables_needed_to_start'] = validation_errors - if obj.job_type != PERM_INVENTORY_SCAN and (obj.project is None or not obj.project.active): + if obj.job_type != PERM_INVENTORY_SCAN and (obj.project is None): errors['project'] = 'Job Template Project is missing or undefined' - if obj.inventory is None or not obj.inventory.active: + if obj.inventory is None: errors['inventory'] = 'Job Template Inventory is missing or undefined' if errors: @@ -2162,7 +2149,7 @@ class NotifierSerializer(BaseSerializer): test = reverse('api:notifier_test', args=(obj.pk,)), notifications = reverse('api:notifier_notification_list', args=(obj.pk,)), )) - if obj.organization and obj.organization.active: + if obj.organization: res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,)) return res @@ -2220,7 +2207,7 @@ class ScheduleSerializer(BaseSerializer): res.update(dict( unified_jobs = reverse('api:schedule_unified_jobs_list', args=(obj.pk,)), )) - if obj.unified_job_template and obj.unified_job_template.active: + if obj.unified_job_template: res['unified_job_template'] = obj.unified_job_template.get_absolute_url() return res @@ -2447,8 +2434,6 @@ class AuthTokenSerializer(serializers.Serializer): if username and password: user = authenticate(username=username, password=password) if user: - if not user.is_active: - raise serializers.ValidationError('User account is disabled.') attrs['user'] = user return attrs else: diff --git a/awx/api/views.py b/awx/api/views.py index 7d54f9dd56..af32ffd0a9 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -214,7 +214,7 @@ class ApiV1ConfigView(APIView): user_ldap_fields.extend(getattr(settings, 'AUTH_LDAP_USER_FLAGS_BY_GROUP', {}).keys()) data['user_ldap_fields'] = user_ldap_fields - if request.user.is_superuser or request.user.admin_of_organizations.filter(active=True).count(): + if request.user.is_superuser or request.user.admin_of_organizations.count(): data.update(dict( project_base_dir = settings.PROJECTS_ROOT, project_local_paths = Project.get_local_path_choices(), @@ -609,7 +609,7 @@ class OrganizationList(ListCreateAPIView): # by the license, then we are only willing to create this organization # if no organizations exist in the system. if (not feature_enabled('multiple_organizations') and - self.model.objects.filter(active=True).count() > 0): + self.model.objects.count() > 0): raise LicenseForbids('Your Tower license only permits a single ' 'organization to exist.') @@ -804,7 +804,7 @@ class ProjectList(ListCreateAPIView): def get(self, request, *args, **kwargs): # Not optimal, but make sure the project status and last_updated fields # are up to date here... - projects_qs = Project.objects.filter(active=True) + projects_qs = Project.objects projects_qs = projects_qs.select_related('current_job', 'last_job') for project in projects_qs: project._set_status_and_last_job_run() @@ -1421,7 +1421,7 @@ class GroupChildrenList(SubListCreateAttachDetachAPIView): sub, self.relationship): raise PermissionDenied() - if sub.parents.filter(active=True).exclude(pk=parent.pk).count() == 0: + if sub.parents.exclude(pk=parent.pk).count() == 0: sub.delete() else: relationship.remove(sub) @@ -1593,9 +1593,9 @@ class InventoryScriptView(RetrieveAPIView): hostvars = bool(request.query_params.get('hostvars', '')) show_all = bool(request.query_params.get('all', '')) if show_all: - hosts_q = dict(active=True) + hosts_q = dict() else: - hosts_q = dict(active=True, enabled=True) + hosts_q = dict(enabled=True) if hostname: host = get_object_or_404(obj.hosts, name=hostname, **hosts_q) data = host.variables_dict @@ -1613,8 +1613,7 @@ class InventoryScriptView(RetrieveAPIView): all_group['hosts'] = groupless_hosts # Build in-memory mapping of groups and their hosts. - group_hosts_kw = dict(group__inventory_id=obj.id, group__active=True, - host__inventory_id=obj.id, host__active=True) + group_hosts_kw = dict(group__inventory_id=obj.id, host__inventory_id=obj.id) if 'enabled' in hosts_q: group_hosts_kw['host__enabled'] = hosts_q['enabled'] group_hosts_qs = Group.hosts.through.objects.filter(**group_hosts_kw) @@ -1627,8 +1626,8 @@ class InventoryScriptView(RetrieveAPIView): # Build in-memory mapping of groups and their children. group_parents_qs = Group.parents.through.objects.filter( - from_group__inventory_id=obj.id, from_group__active=True, - to_group__inventory_id=obj.id, to_group__active=True, + from_group__inventory_id=obj.id, + to_group__inventory_id=obj.id, ) group_parents_qs = group_parents_qs.order_by('from_group__name') group_parents_qs = group_parents_qs.values_list('from_group_id', 'from_group__name', 'to_group_id') @@ -1638,7 +1637,7 @@ class InventoryScriptView(RetrieveAPIView): group_children.append(from_group_name) # Now use in-memory maps to build up group info. - for group in obj.groups.filter(active=True): + for group in obj.groups: group_info = OrderedDict() group_info['hosts'] = group_hosts_map.get(group.id, []) group_info['children'] = group_children_map.get(group.id, []) @@ -1684,9 +1683,9 @@ class InventoryTreeView(RetrieveAPIView): def retrieve(self, request, *args, **kwargs): inventory = self.get_object() - group_children_map = inventory.get_group_children_map(active=True) - root_group_pks = inventory.root_groups.filter(active=True).order_by('name').values_list('pk', flat=True) - groups_qs = inventory.groups.filter(active=True) + group_children_map = inventory.get_group_children_map() + root_group_pks = inventory.root_groups.order_by('name').values_list('pk', flat=True) + groups_qs = inventory.groups groups_qs = groups_qs.select_related('inventory') groups_qs = groups_qs.prefetch_related('inventory_source') all_group_data = GroupSerializer(groups_qs, many=True).data @@ -1890,7 +1889,7 @@ class JobTemplateLaunch(RetrieveAPIView, GenericAPIView): if obj: for p in obj.passwords_needed_to_start: data[p] = u'' - if obj.credential and obj.credential.active: + if obj.credential: data.pop('credential', None) else: data['credential'] = None @@ -2087,7 +2086,7 @@ class JobTemplateCallback(GenericAPIView): return set() # Find the host objects to search for a match. obj = self.get_object() - qs = obj.inventory.hosts.filter(active=True) + qs = obj.inventory.hosts # First try for an exact match on the name. try: return set([qs.get(name__in=remote_hosts)]) @@ -2147,7 +2146,7 @@ class JobTemplateCallback(GenericAPIView): # match again. inventory_sources_already_updated = [] if len(matching_hosts) != 1: - inventory_sources = job_template.inventory.inventory_sources.filter(active=True, update_on_launch=True) + inventory_sources = job_template.inventory.inventory_sources.filter( update_on_launch=True) inventory_update_pks = set() for inventory_source in inventory_sources: if inventory_source.needs_update_on_launch: diff --git a/awx/main/access.py b/awx/main/access.py index 91d78fc849..6dcff91d5e 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -245,7 +245,7 @@ class UserAccess(BaseAccess): return False if self.user.is_superuser: return True - return Organization.accessible_objects(self.user, ALL_PERMISSIONS).filter(active=True).exists() + return Organization.accessible_objects(self.user, ALL_PERMISSIONS).exists() def can_change(self, obj, data): if data is not None and 'is_superuser' in data: @@ -266,7 +266,7 @@ class UserAccess(BaseAccess): if obj == self.user: # cannot delete yourself return False - super_users = User.objects.filter(is_active=True, is_superuser=True) + super_users = User.objects.filter(is_superuser=True) if obj.is_superuser and super_users.count() == 1: # cannot delete the last active superuser return False @@ -525,7 +525,7 @@ class InventoryUpdateAccess(BaseAccess): model = InventoryUpdate def get_queryset(self): - qs = InventoryUpdate.objects.filter(active=True).distinct() + qs = InventoryUpdate.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'inventory_source__group', 'inventory_source__inventory') inventory_sources_qs = self.user.get_queryset(InventorySource) @@ -675,7 +675,7 @@ class ProjectUpdateAccess(BaseAccess): model = ProjectUpdate def get_queryset(self): - qs = ProjectUpdate.objects.filter(active=True).distinct() + qs = ProjectUpdate.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'project') project_ids = set(self.user.get_queryset(Project).values_list('id', flat=True)) return qs.filter(project_id__in=project_ids) @@ -819,7 +819,7 @@ class JobAccess(BaseAccess): model = Job def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'job_template', 'inventory', 'project', 'credential', 'cloud_credential', 'job_template') qs = qs.prefetch_related('unified_job_template') @@ -841,12 +841,10 @@ class JobAccess(BaseAccess): # TODO: I think the below queries can be combined deploy_permissions_ids = Permission.objects.filter( Q(user=self.user) | Q(team__in=team_ids), - active=True, permission_type__in=allowed_deploy, ) check_permissions_ids = Permission.objects.filter( Q(user=self.user) | Q(team__in=team_ids), - active=True, permission_type__in=allowed_check, ) @@ -945,18 +943,17 @@ class AdHocCommandAccess(BaseAccess): model = AdHocCommand def get_queryset(self): - qs = self.model.objects.filter(active=True).distinct() + qs = self.model.objects.distinct() qs = qs.select_related('created_by', 'modified_by', 'inventory', 'credential') if self.user.is_superuser: return qs credential_ids = set(self.user.get_queryset(Credential).values_list('id', flat=True)) - team_ids = set(Team.objects.filter(active=True, users__in=[self.user]).values_list('id', flat=True)) + team_ids = set(Team.objects.filter( users__in=[self.user]).values_list('id', flat=True)) permission_ids = set(Permission.objects.filter( Q(user=self.user) | Q(team__in=team_ids), - active=True, permission_type__in=PERMISSION_TYPES_ALLOWING_INVENTORY_READ, run_ad_hoc_commands=True, ).values_list('id', flat=True)) @@ -980,7 +977,7 @@ class AdHocCommandAccess(BaseAccess): # If a credential is provided, the user should have read access to it. credential_pk = get_pk_from_dict(data, 'credential') if credential_pk: - credential = get_object_or_400(Credential, pk=credential_pk, active=True) + credential = get_object_or_400(Credential, pk=credential_pk) if not credential.accessible_by(self.user, {'read':True}): return False @@ -988,7 +985,7 @@ class AdHocCommandAccess(BaseAccess): # given inventory. inventory_pk = get_pk_from_dict(data, 'inventory') if inventory_pk: - inventory = get_object_or_400(Inventory, pk=inventory_pk, active=True) + inventory = get_object_or_400(Inventory, pk=inventory_pk) if not inventory.accessible_by(self.user, {'execute': True}): return False diff --git a/awx/main/management/commands/create_default_org.py b/awx/main/management/commands/create_default_org.py index a6fb99f826..dbdb64ef85 100644 --- a/awx/main/management/commands/create_default_org.py +++ b/awx/main/management/commands/create_default_org.py @@ -19,7 +19,7 @@ class Command(BaseCommand): # Create a default organization as the first superuser found. try: - superuser = User.objects.filter(is_superuser=True, is_active=True).order_by('pk')[0] + superuser = User.objects.filter(is_superuser=True).order_by('pk')[0] except IndexError: superuser = None with impersonate(superuser): diff --git a/awx/main/management/commands/inventory_import.py b/awx/main/management/commands/inventory_import.py index 76898af111..47b333f75c 100644 --- a/awx/main/management/commands/inventory_import.py +++ b/awx/main/management/commands/inventory_import.py @@ -633,7 +633,7 @@ class Command(NoArgsCommand): else: q = dict(name=self.inventory_name) try: - self.inventory = Inventory.objects.filter(active=True).get(**q) + self.inventory = Inventory.objects.get(**q) except Inventory.DoesNotExist: raise CommandError('Inventory with %s = %s cannot be found' % q.items()[0]) except Inventory.MultipleObjectsReturned: @@ -648,8 +648,7 @@ class Command(NoArgsCommand): if inventory_source_id: try: self.inventory_source = InventorySource.objects.get(pk=inventory_source_id, - inventory=self.inventory, - active=True) + inventory=self.inventory) except InventorySource.DoesNotExist: raise CommandError('Inventory source with id=%s not found' % inventory_source_id) @@ -669,7 +668,6 @@ class Command(NoArgsCommand): source_path=os.path.abspath(self.source), overwrite=self.overwrite, overwrite_vars=self.overwrite_vars, - active=True, ) self.inventory_update = self.inventory_source.create_inventory_update( job_args=json.dumps(sys.argv), @@ -703,7 +701,7 @@ class Command(NoArgsCommand): host_qs = self.inventory_source.group.all_hosts else: host_qs = self.inventory.hosts.all() - host_qs = host_qs.filter(active=True, instance_id='', + host_qs = host_qs.filter(instance_id='', variables__contains=self.instance_id_var.split('.')[0]) for host in host_qs: instance_id = self._get_instance_id(host.variables_dict) @@ -740,7 +738,7 @@ class Command(NoArgsCommand): hosts_qs = self.inventory_source.group.all_hosts # FIXME: Also include hosts from inventory_source.managed_hosts? else: - hosts_qs = self.inventory.hosts.filter(active=True) + hosts_qs = self.inventory.hosts # Build list of all host pks, remove all that should not be deleted. del_host_pks = set(hosts_qs.values_list('pk', flat=True)) if self.instance_id_var: @@ -785,7 +783,7 @@ class Command(NoArgsCommand): groups_qs = self.inventory_source.group.all_children # FIXME: Also include groups from inventory_source.managed_groups? else: - groups_qs = self.inventory.groups.filter(active=True) + groups_qs = self.inventory.groups # Build list of all group pks, remove those that should not be deleted. del_group_pks = set(groups_qs.values_list('pk', flat=True)) all_group_names = self.all_group.all_groups.keys() @@ -822,10 +820,10 @@ class Command(NoArgsCommand): if self.inventory_source.group: db_groups = self.inventory_source.group.all_children else: - db_groups = self.inventory.groups.filter(active=True) + db_groups = self.inventory.groups for db_group in db_groups: # Delete child group relationships not present in imported data. - db_children = db_group.children.filter(active=True) + db_children = db_group.children db_children_name_pk_map = dict(db_children.values_list('name', 'pk')) mem_children = self.all_group.all_groups[db_group.name].children for mem_group in mem_children: @@ -840,7 +838,7 @@ class Command(NoArgsCommand): db_child.name, db_group.name) # FIXME: Inventory source group relationships # Delete group/host relationships not present in imported data. - db_hosts = db_group.hosts.filter(active=True) + db_hosts = db_group.hosts del_host_pks = set(db_hosts.values_list('pk', flat=True)) mem_hosts = self.all_group.all_groups[db_group.name].hosts all_mem_host_names = [h.name for h in mem_hosts if not h.instance_id] @@ -861,7 +859,7 @@ class Command(NoArgsCommand): del_pks = del_host_pks[offset:(offset + self._batch_size)] for db_host in db_hosts.filter(pk__in=del_pks): group_host_count += 1 - if db_host not in db_group.hosts.filter(active=True): + if db_host not in db_group.hosts: continue db_group.hosts.remove(db_host) self.logger.info('Host "%s" removed from group "%s"', @@ -1037,7 +1035,7 @@ class Command(NoArgsCommand): all_host_pks = sorted(mem_host_pk_map.keys()) for offset in xrange(0, len(all_host_pks), self._batch_size): host_pks = all_host_pks[offset:(offset + self._batch_size)] - for db_host in self.inventory.hosts.filter(active=True, pk__in=host_pks): + for db_host in self.inventory.hosts.filter( pk__in=host_pks): if db_host.pk in host_pks_updated: continue mem_host = mem_host_pk_map[db_host.pk] @@ -1049,7 +1047,7 @@ class Command(NoArgsCommand): all_instance_ids = sorted(mem_host_instance_id_map.keys()) for offset in xrange(0, len(all_instance_ids), self._batch_size): instance_ids = all_instance_ids[offset:(offset + self._batch_size)] - for db_host in self.inventory.hosts.filter(active=True, instance_id__in=instance_ids): + for db_host in self.inventory.hosts.filter( instance_id__in=instance_ids): if db_host.pk in host_pks_updated: continue mem_host = mem_host_instance_id_map[db_host.instance_id] @@ -1061,7 +1059,7 @@ class Command(NoArgsCommand): all_host_names = sorted(mem_host_name_map.keys()) for offset in xrange(0, len(all_host_names), self._batch_size): host_names = all_host_names[offset:(offset + self._batch_size)] - for db_host in self.inventory.hosts.filter(active=True, name__in=host_names): + for db_host in self.inventory.hosts.filter( name__in=host_names): if db_host.pk in host_pks_updated: continue mem_host = mem_host_name_map[db_host.name] diff --git a/awx/main/managers.py b/awx/main/managers.py index 355f616dac..4825a74cf8 100644 --- a/awx/main/managers.py +++ b/awx/main/managers.py @@ -13,9 +13,9 @@ class HostManager(models.Manager): def active_count(self): """Return count of active, unique hosts for licensing.""" try: - return self.filter(active=True, inventory__active=True).order_by('name').distinct('name').count() + return self.order_by('name').distinct('name').count() except NotImplementedError: # For unit tests only, SQLite doesn't support distinct('name') - return len(set(self.filter(active=True, inventory__active=True).values_list('name', flat=True))) + return len(set(self.values_list('name', flat=True))) class InstanceManager(models.Manager): """A custom manager class for the Instance model. diff --git a/awx/main/models/ad_hoc_commands.py b/awx/main/models/ad_hoc_commands.py index c5ab627046..c97c484c5e 100644 --- a/awx/main/models/ad_hoc_commands.py +++ b/awx/main/models/ad_hoc_commands.py @@ -87,7 +87,7 @@ class AdHocCommand(UnifiedJob): def clean_inventory(self): inv = self.inventory - if not inv or not inv.active: + if not inv: raise ValidationError('Inventory is no longer available.') return inv @@ -123,7 +123,7 @@ class AdHocCommand(UnifiedJob): @property def passwords_needed_to_start(self): '''Return list of password field names needed to start the job.''' - if self.credential and self.credential.active: + if self.credential: return self.credential.passwords_needed else: return [] @@ -164,14 +164,14 @@ class AdHocCommand(UnifiedJob): def task_impact(self): # NOTE: We sorta have to assume the host count matches and that forks default to 5 from awx.main.models.inventory import Host - count_hosts = Host.objects.filter(active=True, enabled=True, inventory__ad_hoc_commands__pk=self.pk).count() + count_hosts = Host.objects.filter( enabled=True, inventory__ad_hoc_commands__pk=self.pk).count() return min(count_hosts, 5 if self.forks == 0 else self.forks) * 10 def generate_dependencies(self, active_tasks): from awx.main.models import InventoryUpdate if not self.inventory: return [] - inventory_sources = self.inventory.inventory_sources.filter(active=True, update_on_launch=True) + inventory_sources = self.inventory.inventory_sources.filter( update_on_launch=True) inventory_sources_found = [] dependencies = [] for obj in active_tasks: diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 44f1a404f6..50d0fd58bd 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -123,15 +123,12 @@ class Inventory(CommonModel, ResourceMixin): variables_dict = VarsDictProperty('variables') - def get_group_hosts_map(self, active=None): + def get_group_hosts_map(self): ''' Return dictionary mapping group_id to set of child host_id's. ''' # FIXME: Cache this mapping? group_hosts_kw = dict(group__inventory_id=self.pk, host__inventory_id=self.pk) - if active is not None: - group_hosts_kw['group__active'] = active - group_hosts_kw['host__active'] = active group_hosts_qs = Group.hosts.through.objects.filter(**group_hosts_kw) group_hosts_qs = group_hosts_qs.values_list('group_id', 'host_id') group_hosts_map = {} @@ -140,15 +137,12 @@ class Inventory(CommonModel, ResourceMixin): group_host_ids.add(host_id) return group_hosts_map - def get_group_parents_map(self, active=None): + def get_group_parents_map(self): ''' Return dictionary mapping group_id to set of parent group_id's. ''' # FIXME: Cache this mapping? group_parents_kw = dict(from_group__inventory_id=self.pk, to_group__inventory_id=self.pk) - if active is not None: - group_parents_kw['from_group__active'] = active - group_parents_kw['to_group__active'] = active group_parents_qs = Group.parents.through.objects.filter(**group_parents_kw) group_parents_qs = group_parents_qs.values_list('from_group_id', 'to_group_id') group_parents_map = {} @@ -157,15 +151,12 @@ class Inventory(CommonModel, ResourceMixin): group_parents.add(to_group_id) return group_parents_map - def get_group_children_map(self, active=None): + def get_group_children_map(self): ''' Return dictionary mapping group_id to set of child group_id's. ''' # FIXME: Cache this mapping? group_parents_kw = dict(from_group__inventory_id=self.pk, to_group__inventory_id=self.pk) - if active is not None: - group_parents_kw['from_group__active'] = active - group_parents_kw['to_group__active'] = active group_parents_qs = Group.parents.through.objects.filter(**group_parents_kw) group_parents_qs = group_parents_qs.values_list('from_group_id', 'to_group_id') group_children_map = {} @@ -176,12 +167,12 @@ class Inventory(CommonModel, ResourceMixin): def update_host_computed_fields(self): ''' - Update computed fields for all active hosts in this inventory. + Update computed fields for all hosts in this inventory. ''' hosts_to_update = {} - hosts_qs = self.hosts.filter(active=True) + hosts_qs = self.hosts # Define queryset of all hosts with active failures. - hosts_with_active_failures = hosts_qs.filter(last_job_host_summary__isnull=False, last_job_host_summary__job__active=True, last_job_host_summary__failed=True).values_list('pk', flat=True) + hosts_with_active_failures = hosts_qs.filter(last_job_host_summary__isnull=False, last_job_host_summary__failed=True).values_list('pk', flat=True) # Find all hosts that need the has_active_failures flag set. hosts_to_set = hosts_qs.filter(has_active_failures=False, pk__in=hosts_with_active_failures) for host_pk in hosts_to_set.values_list('pk', flat=True): @@ -193,7 +184,7 @@ class Inventory(CommonModel, ResourceMixin): host_updates = hosts_to_update.setdefault(host_pk, {}) host_updates['has_active_failures'] = False # Define queryset of all hosts with cloud inventory sources. - hosts_with_cloud_inventory = hosts_qs.filter(inventory_sources__active=True, inventory_sources__source__in=CLOUD_INVENTORY_SOURCES).values_list('pk', flat=True) + hosts_with_cloud_inventory = hosts_qs.filter(inventory_sources__source__in=CLOUD_INVENTORY_SOURCES).values_list('pk', flat=True) # Find all hosts that need the has_inventory_sources flag set. hosts_to_set = hosts_qs.filter(has_inventory_sources=False, pk__in=hosts_with_cloud_inventory) for host_pk in hosts_to_set.values_list('pk', flat=True): @@ -218,13 +209,13 @@ class Inventory(CommonModel, ResourceMixin): ''' Update computed fields for all active groups in this inventory. ''' - group_children_map = self.get_group_children_map(active=True) - group_hosts_map = self.get_group_hosts_map(active=True) - active_host_pks = set(self.hosts.filter(active=True).values_list('pk', flat=True)) - failed_host_pks = set(self.hosts.filter(active=True, last_job_host_summary__job__active=True, last_job_host_summary__failed=True).values_list('pk', flat=True)) - # active_group_pks = set(self.groups.filter(active=True).values_list('pk', flat=True)) + group_children_map = self.get_group_children_map() + group_hosts_map = self.get_group_hosts_map() + active_host_pks = set(self.hosts.values_list('pk', flat=True)) + failed_host_pks = set(self.hosts.filter(last_job_host_summary__failed=True).values_list('pk', flat=True)) + # active_group_pks = set(self.groups.values_list('pk', flat=True)) failed_group_pks = set() # Update below as we check each group. - groups_with_cloud_pks = set(self.groups.filter(active=True, inventory_sources__active=True, inventory_sources__source__in=CLOUD_INVENTORY_SOURCES).values_list('pk', flat=True)) + groups_with_cloud_pks = set(self.groups.filter(inventory_sources__source__in=CLOUD_INVENTORY_SOURCES).values_list('pk', flat=True)) groups_to_update = {} # Build list of group pks to check, starting with the groups at the @@ -296,11 +287,11 @@ class Inventory(CommonModel, ResourceMixin): self.update_host_computed_fields() if update_groups: self.update_group_computed_fields() - active_hosts = self.hosts.filter(active=True) + active_hosts = self.hosts failed_hosts = active_hosts.filter(has_active_failures=True) - active_groups = self.groups.filter(active=True) + active_groups = self.groups failed_groups = active_groups.filter(has_active_failures=True) - active_inventory_sources = self.inventory_sources.filter(active=True, source__in=CLOUD_INVENTORY_SOURCES) + active_inventory_sources = self.inventory_sources.filter( source__in=CLOUD_INVENTORY_SOURCES) failed_inventory_sources = active_inventory_sources.filter(last_job_failed=True) computed_fields = { 'has_active_failures': bool(failed_hosts.count()), @@ -405,10 +396,8 @@ class Host(CommonModelNameNotUnique, ResourceMixin): Update model fields that are computed from database relationships. ''' has_active_failures = bool(self.last_job_host_summary and - self.last_job_host_summary.job.active and self.last_job_host_summary.failed) - active_inventory_sources = self.inventory_sources.filter(active=True, - source__in=CLOUD_INVENTORY_SOURCES) + active_inventory_sources = self.inventory_sources.filter(source__in=CLOUD_INVENTORY_SOURCES) computed_fields = { 'has_active_failures': has_active_failures, 'has_inventory_sources': bool(active_inventory_sources.count()), @@ -424,7 +413,7 @@ class Host(CommonModelNameNotUnique, ResourceMixin): # change. # NOTE: I think this is no longer needed # if update_groups: - # for group in self.all_groups.filter(active=True): + # for group in self.all_groups: # group.update_computed_fields() # if update_inventory: # self.inventory.update_computed_fields(update_groups=False, @@ -620,14 +609,12 @@ class Group(CommonModelNameNotUnique, ResourceMixin): ''' Update model fields that are computed from database relationships. ''' - active_hosts = self.all_hosts.filter(active=True) - failed_hosts = active_hosts.filter(last_job_host_summary__job__active=True, - last_job_host_summary__failed=True) - active_groups = self.all_children.filter(active=True) + active_hosts = self.all_hosts + failed_hosts = active_hosts.filter(last_job_host_summary__failed=True) + active_groups = self.all_children # FIXME: May not be accurate unless we always update groups depth-first. failed_groups = active_groups.filter(has_active_failures=True) - active_inventory_sources = self.inventory_sources.filter(active=True, - source__in=CLOUD_INVENTORY_SOURCES) + active_inventory_sources = self.inventory_sources.filter(source__in=CLOUD_INVENTORY_SOURCES) computed_fields = { 'total_hosts': active_hosts.count(), 'has_active_failures': bool(failed_hosts.count()), @@ -1154,7 +1141,7 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions, ResourceMixin) def _can_update(self): if self.source == 'custom': - return bool(self.source_script and self.source_script.active) + return bool(self.source_script) else: return bool(self.source in CLOUD_INVENTORY_SOURCES) @@ -1171,7 +1158,7 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions, ResourceMixin) @property def needs_update_on_launch(self): - if self.active and self.source and self.update_on_launch: + if self.source and self.update_on_launch: if not self.last_job_run: return True if (self.last_job_run + datetime.timedelta(seconds=self.update_cache_timeout)) <= now(): @@ -1180,7 +1167,7 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions, ResourceMixin) @property def notifiers(self): - base_notifiers = Notifier.objects.filter(active=True) + base_notifiers = Notifier.objects error_notifiers = list(base_notifiers.filter(organization_notifiers_for_errors=self.inventory.organization)) success_notifiers = list(base_notifiers.filter(organization_notifiers_for_success=self.inventory.organization)) any_notifiers = list(base_notifiers.filter(organization_notifiers_for_any=self.inventory.organization)) @@ -1189,7 +1176,7 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions, ResourceMixin) def clean_source(self): source = self.source if source and self.group: - qs = self.group.inventory_sources.filter(source__in=CLOUD_INVENTORY_SOURCES, active=True, group__active=True) + qs = self.group.inventory_sources.filter(source__in=CLOUD_INVENTORY_SOURCES) existing_sources = qs.exclude(pk=self.pk) if existing_sources.count(): s = u', '.join([x.group.name for x in existing_sources]) @@ -1233,7 +1220,7 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions): def save(self, *args, **kwargs): update_fields = kwargs.get('update_fields', []) inventory_source = self.inventory_source - if self.active and inventory_source.inventory and self.name == inventory_source.name: + if inventory_source.inventory and self.name == inventory_source.name: if inventory_source.group: self.name = '%s (%s)' % (inventory_source.group.name, inventory_source.inventory.name) else: @@ -1269,7 +1256,7 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions): return False if (self.source not in ('custom', 'ec2') and - not (self.credential and self.credential.active)): + not (self.credential)): return False return True diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index 410f3c0392..82d1060fa5 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -149,7 +149,7 @@ class JobOptions(BaseModel): @property def passwords_needed_to_start(self): '''Return list of password field names needed to start the job.''' - if self.credential and self.credential.active: + if self.credential: return self.credential.passwords_needed else: return [] @@ -357,7 +357,7 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, ResourceMixin): # Return all notifiers defined on the Job Template, on the Project, and on the Organization for each trigger type # TODO: Currently there is no org fk on project so this will need to be added once that is # available after the rbac pr - base_notifiers = Notifier.objects.filter(active=True) + base_notifiers = Notifier.objects error_notifiers = list(base_notifiers.filter(unifiedjobtemplate_notifiers_for_errors__in=[self, self.project])) success_notifiers = list(base_notifiers.filter(unifiedjobtemplate_notifiers_for_success__in=[self, self.project])) any_notifiers = list(base_notifiers.filter(unifiedjobtemplate_notifiers_for_any__in=[self, self.project])) @@ -493,7 +493,7 @@ class Job(UnifiedJob, JobOptions): from awx.main.models import InventoryUpdate, ProjectUpdate if self.inventory is None or self.project is None: return [] - inventory_sources = self.inventory.inventory_sources.filter(active=True, update_on_launch=True) + inventory_sources = self.inventory.inventory_sources.filter( update_on_launch=True) project_found = False inventory_sources_found = [] dependencies = [] @@ -592,7 +592,7 @@ class Job(UnifiedJob, JobOptions): if not super(Job, self).can_start: return False - if not (self.credential and self.credential.active): + if not (self.credential): return False return True diff --git a/awx/main/models/projects.py b/awx/main/models/projects.py index aa416bb95a..fb08f6bcfd 100644 --- a/awx/main/models/projects.py +++ b/awx/main/models/projects.py @@ -53,7 +53,7 @@ class ProjectOptions(models.Model): paths = [x.decode('utf-8') for x in os.listdir(settings.PROJECTS_ROOT) if (os.path.isdir(os.path.join(settings.PROJECTS_ROOT, x)) and not x.startswith('.') and not x.startswith('_'))] - qs = Project.objects.filter(active=True) + qs = Project.objects used_paths = qs.values_list('local_path', flat=True) return [x for x in paths if x not in used_paths] else: @@ -336,7 +336,7 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin): @property def needs_update_on_launch(self): - if self.active and self.scm_type and self.scm_update_on_launch: + if self.scm_type and self.scm_update_on_launch: if not self.last_job_run: return True if (self.last_job_run + datetime.timedelta(seconds=self.scm_update_cache_timeout)) <= now(): @@ -345,7 +345,7 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin): @property def notifiers(self): - base_notifiers = Notifier.objects.filter(active=True) + base_notifiers = Notifier.objects error_notifiers = list(base_notifiers.filter(unifiedjobtemplate_notifiers_for_errors=self)) success_notifiers = list(base_notifiers.filter(unifiedjobtemplate_notifiers_for_success=self)) any_notifiers = list(base_notifiers.filter(unifiedjobtemplate_notifiers_for_any=self)) diff --git a/awx/main/models/schedules.py b/awx/main/models/schedules.py index 8af6da3be3..d9de8b394e 100644 --- a/awx/main/models/schedules.py +++ b/awx/main/models/schedules.py @@ -27,7 +27,7 @@ __all__ = ['Schedule'] class ScheduleFilterMethods(object): def enabled(self, enabled=True): - return self.filter(enabled=enabled, active=enabled) + return self.filter(enabled=enabled) def before(self, dt): return self.filter(next_run__lt=dt) diff --git a/awx/main/signals.py b/awx/main/signals.py index dbccf61dd6..ddfc792f2a 100644 --- a/awx/main/signals.py +++ b/awx/main/signals.py @@ -8,7 +8,7 @@ import threading import json # Django -from django.db.models.signals import pre_save, post_save, pre_delete, post_delete, m2m_changed +from django.db.models.signals import post_save, pre_delete, post_delete, m2m_changed from django.dispatch import receiver # Django-CRUM @@ -27,9 +27,8 @@ __all__ = [] logger = logging.getLogger('awx.main.signals') -# Update has_active_failures for inventory/groups when a Host/Group is deleted -# or marked inactive, when a Host-Group or Group-Group relationship is updated, -# or when a Job is deleted or marked inactive. +# Update has_active_failures for inventory/groups when a Host/Group is deleted, +# when a Host-Group or Group-Group relationship is updated, or when a Job is deleted def emit_job_event_detail(sender, **kwargs): instance = kwargs['instance'] @@ -69,7 +68,7 @@ def emit_update_inventory_computed_fields(sender, **kwargs): else: sender_name = unicode(sender._meta.verbose_name) if kwargs['signal'] == post_save: - if sender == Job and instance.active: + if sender == Job: return sender_action = 'saved' elif kwargs['signal'] == post_delete: @@ -92,7 +91,6 @@ def emit_update_inventory_on_created_or_deleted(sender, **kwargs): return instance = kwargs['instance'] if ('created' in kwargs and kwargs['created']) or \ - (hasattr(instance, '_saved_active_state') and instance._saved_active_state != instance.active) or \ kwargs['signal'] == post_delete: pass else: @@ -108,13 +106,6 @@ def emit_update_inventory_on_created_or_deleted(sender, **kwargs): if inventory is not None: update_inventory_computed_fields.delay(inventory.id, True) -def store_initial_active_state(sender, **kwargs): - instance = kwargs['instance'] - if instance.id is not None: - instance._saved_active_state = sender.objects.get(id=instance.id).active - else: - instance._saved_active_state = True - def rebuild_role_ancestor_list(reverse, model, instance, pk_set, **kwargs): 'When a role parent is added or removed, update our role hierarchy list' if reverse: @@ -161,20 +152,16 @@ def org_admin_edit_members(instance, action, model, reverse, pk_set, **kwargs): if action == 'pre_remove': instance.content_object.admin_role.children.remove(user.admin_role) -pre_save.connect(store_initial_active_state, sender=Host) post_save.connect(emit_update_inventory_on_created_or_deleted, sender=Host) post_delete.connect(emit_update_inventory_on_created_or_deleted, sender=Host) -pre_save.connect(store_initial_active_state, sender=Group) post_save.connect(emit_update_inventory_on_created_or_deleted, sender=Group) post_delete.connect(emit_update_inventory_on_created_or_deleted, sender=Group) m2m_changed.connect(emit_update_inventory_computed_fields, sender=Group.hosts.through) m2m_changed.connect(emit_update_inventory_computed_fields, sender=Group.parents.through) m2m_changed.connect(emit_update_inventory_computed_fields, sender=Host.inventory_sources.through) m2m_changed.connect(emit_update_inventory_computed_fields, sender=Group.inventory_sources.through) -pre_save.connect(store_initial_active_state, sender=InventorySource) post_save.connect(emit_update_inventory_on_created_or_deleted, sender=InventorySource) post_delete.connect(emit_update_inventory_on_created_or_deleted, sender=InventorySource) -pre_save.connect(store_initial_active_state, sender=Job) post_save.connect(emit_update_inventory_on_created_or_deleted, sender=Job) post_delete.connect(emit_update_inventory_on_created_or_deleted, sender=Job) post_save.connect(emit_job_event_detail, sender=JobEvent) @@ -184,8 +171,8 @@ m2m_changed.connect(org_admin_edit_members, Role.members.through) post_save.connect(sync_superuser_status_to_rbac, sender=User) post_save.connect(create_user_role, sender=User) -# Migrate hosts, groups to parent group(s) whenever a group is deleted or -# marked as inactive. + +# Migrate hosts, groups to parent group(s) whenever a group is deleted @receiver(pre_delete, sender=Group) def save_related_pks_before_group_delete(sender, **kwargs): @@ -208,80 +195,28 @@ def migrate_children_from_deleted_group_to_parent_groups(sender, **kwargs): with ignore_inventory_group_removal(): with ignore_inventory_computed_fields(): if parents_pks: - for parent_group in Group.objects.filter(pk__in=parents_pks, active=True): - for child_host in Host.objects.filter(pk__in=hosts_pks, active=True): + for parent_group in Group.objects.filter(pk__in=parents_pks): + for child_host in Host.objects.filter(pk__in=hosts_pks): logger.debug('adding host %s to parent %s after group deletion', child_host, parent_group) parent_group.hosts.add(child_host) - for child_group in Group.objects.filter(pk__in=children_pks, active=True): + for child_group in Group.objects.filter(pk__in=children_pks): logger.debug('adding group %s to parent %s after group deletion', child_group, parent_group) parent_group.children.add(child_group) inventory_pk = getattr(instance, '_saved_inventory_pk', None) if inventory_pk: try: - inventory = Inventory.objects.get(pk=inventory_pk, active=True) + inventory = Inventory.objects.get(pk=inventory_pk) inventory.update_computed_fields() except Inventory.DoesNotExist: pass -@receiver(pre_save, sender=Group) -def save_related_pks_before_group_marked_inactive(sender, **kwargs): - if getattr(_inventory_updates, 'is_removing', False): - return - instance = kwargs['instance'] - if not instance.pk or instance.active: - return - instance._saved_inventory_pk = instance.inventory.pk - instance._saved_parents_pks = set(instance.parents.values_list('pk', flat=True)) - instance._saved_hosts_pks = set(instance.hosts.values_list('pk', flat=True)) - instance._saved_children_pks = set(instance.children.values_list('pk', flat=True)) - instance._saved_inventory_source_pk = instance.inventory_source.pk -@receiver(post_save, sender=Group) -def migrate_children_from_inactive_group_to_parent_groups(sender, **kwargs): - if getattr(_inventory_updates, 'is_removing', False): - return - instance = kwargs['instance'] - if instance.active: - return - parents_pks = getattr(instance, '_saved_parents_pks', []) - hosts_pks = getattr(instance, '_saved_hosts_pks', []) - children_pks = getattr(instance, '_saved_children_pks', []) - with ignore_inventory_group_removal(): - with ignore_inventory_computed_fields(): - if parents_pks: - for parent_group in Group.objects.filter(pk__in=parents_pks, active=True): - for child_host in Host.objects.filter(pk__in=hosts_pks, active=True): - logger.debug('moving host %s to parent %s after marking group %s inactive', - child_host, parent_group, instance) - parent_group.hosts.add(child_host) - for child_group in Group.objects.filter(pk__in=children_pks, active=True): - logger.debug('moving group %s to parent %s after marking group %s inactive', - child_group, parent_group, instance) - parent_group.children.add(child_group) - parent_group.children.remove(instance) - inventory_source_pk = getattr(instance, '_saved_inventory_source_pk', None) - if inventory_source_pk: - try: - inventory_source = InventorySource.objects.get(pk=inventory_source_pk, active=True) - inventory_source.delete() - except InventorySource.DoesNotExist: - pass - inventory_pk = getattr(instance, '_saved_inventory_pk', None) - if not getattr(_inventory_updates, 'is_updating', False): - if inventory_pk: - try: - inventory = Inventory.objects.get(pk=inventory_pk, active=True) - inventory.update_computed_fields() - except Inventory.DoesNotExist: - pass - -# Update host pointers to last_job and last_job_host_summary when a job is -# marked inactive or deleted. +# Update host pointers to last_job and last_job_host_summary when a job is deleted def _update_host_last_jhs(host): - jhs_qs = JobHostSummary.objects.filter(job__active=True, host__pk=host.pk) + jhs_qs = JobHostSummary.objects.filter(host__pk=host.pk) try: jhs = jhs_qs.order_by('-job__pk')[0] except IndexError: @@ -297,19 +232,10 @@ def _update_host_last_jhs(host): if update_fields: host.save(update_fields=update_fields) -@receiver(post_save, sender=Job) -def update_host_last_job_when_job_marked_inactive(sender, **kwargs): - instance = kwargs['instance'] - if instance.active: - return - hosts_qs = Host.objects.filter(active=True, last_job__pk=instance.pk) - for host in hosts_qs: - _update_host_last_jhs(host) - @receiver(pre_delete, sender=Job) def save_host_pks_before_job_delete(sender, **kwargs): instance = kwargs['instance'] - hosts_qs = Host.objects.filter(active=True, last_job__pk=instance.pk) + hosts_qs = Host.objects.filter( last_job__pk=instance.pk) instance._saved_hosts_pks = set(hosts_qs.values_list('pk', flat=True)) @receiver(post_delete, sender=Job) @@ -388,11 +314,6 @@ def activity_stream_update(sender, instance, **kwargs): except sender.DoesNotExist: return - # Handle the AWX mark-inactive for delete event - if hasattr(instance, 'active') and not instance.active: - activity_stream_delete(sender, instance, **kwargs) - return - new = instance changes = model_instance_diff(old, new, model_serializer_mapping) if changes is None: diff --git a/awx/main/south_migrations/0018_v14_changes.py b/awx/main/south_migrations/0018_v14_changes.py index ea4fde18ab..980c4293d6 100644 --- a/awx/main/south_migrations/0018_v14_changes.py +++ b/awx/main/south_migrations/0018_v14_changes.py @@ -13,7 +13,7 @@ class Migration(DataMigration): # and orm['appname.ModelName'] for models in other applications. # Refresh has_active_failures for all hosts. - for host in orm.Host.objects.filter(active=True): + for host in orm.Host.objects: has_active_failures = bool(host.last_job_host_summary and host.last_job_host_summary.job.active and host.last_job_host_summary.failed) @@ -30,9 +30,9 @@ class Migration(DataMigration): for subgroup in group.children.exclude(pk__in=except_group_pks): qs = qs | get_all_hosts_for_group(subgroup, except_group_pks) return qs - for group in orm.Group.objects.filter(active=True): + for group in orm.Group.objects: all_hosts = get_all_hosts_for_group(group) - failed_hosts = all_hosts.filter(active=True, + failed_hosts = all_hosts.filter( last_job_host_summary__job__active=True, last_job_host_summary__failed=True) hosts_with_active_failures = failed_hosts.count() @@ -49,8 +49,8 @@ class Migration(DataMigration): # Now update has_active_failures and hosts_with_active_failures for all # inventories. - for inventory in orm.Inventory.objects.filter(active=True): - failed_hosts = inventory.hosts.filter(active=True, has_active_failures=True) + for inventory in orm.Inventory.objects: + failed_hosts = inventory.hosts.filter( has_active_failures=True) hosts_with_active_failures = failed_hosts.count() has_active_failures = bool(hosts_with_active_failures) changed = False diff --git a/awx/main/south_migrations/0044_v1411_changes.py b/awx/main/south_migrations/0044_v1411_changes.py index 137f4cb220..c58dc8d155 100644 --- a/awx/main/south_migrations/0044_v1411_changes.py +++ b/awx/main/south_migrations/0044_v1411_changes.py @@ -8,7 +8,7 @@ from django.db import models class Migration(DataMigration): def forwards(self, orm): - for iu in orm.InventoryUpdate.objects.filter(active=True): + for iu in orm.InventoryUpdate.objects: if iu.inventory_source is None or iu.inventory_source.group is None or iu.inventory_source.inventory is None: continue iu.name = "%s (%s)" % (iu.inventory_source.group.name, iu.inventory_source.inventory.name) diff --git a/awx/main/south_migrations/0070_v221_changes.py b/awx/main/south_migrations/0070_v221_changes.py index 0bc36f27ac..c27edf8e9c 100644 --- a/awx/main/south_migrations/0070_v221_changes.py +++ b/awx/main/south_migrations/0070_v221_changes.py @@ -12,7 +12,7 @@ from django.conf import settings class Migration(DataMigration): def forwards(self, orm): - for j in orm.UnifiedJob.objects.filter(active=True): + for j in orm.UnifiedJob.objects: cur = connection.cursor() stdout_filename = os.path.join(settings.JOBOUTPUT_ROOT, "%d-%s.out" % (j.pk, str(uuid.uuid1()))) fd = open(stdout_filename, 'w') diff --git a/awx/main/tasks.py b/awx/main/tasks.py index 49589a6e3b..d397b6fbeb 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -51,7 +51,7 @@ from awx.main.queue import FifoQueue from awx.main.conf import tower_settings from awx.main.task_engine import TaskSerializer, TASK_TIMEOUT_INTERVAL from awx.main.utils import (get_ansible_version, get_ssh_version, decrypt_field, update_scm_url, - ignore_inventory_computed_fields, emit_websocket_notification, + emit_websocket_notification, check_proot_installed, build_proot_temp_dir, wrap_args_with_proot) __all__ = ['RunJob', 'RunSystemJob', 'RunProjectUpdate', 'RunInventoryUpdate', @@ -883,12 +883,12 @@ class RunJob(BaseTask): 'tower_job_id': job.pk, 'tower_job_launch_type': job.launch_type, } - if job.job_template and job.job_template.active: + if job.job_template: extra_vars.update({ 'tower_job_template_id': job.job_template.pk, 'tower_job_template_name': job.job_template.name, }) - if job.created_by and job.created_by.is_active: + if job.created_by: extra_vars.update({ 'tower_user_id': job.created_by.pk, 'tower_user_name': job.created_by.username, @@ -1381,7 +1381,7 @@ class RunInventoryUpdate(BaseTask): runpath = tempfile.mkdtemp(prefix='ansible_tower_launch_') handle, path = tempfile.mkstemp(dir=runpath) f = os.fdopen(handle, 'w') - if inventory_update.source_script is None or not inventory_update.source_script.active: + if inventory_update.source_script is None: raise RuntimeError('Inventory Script does not exist') f.write(inventory_update.source_script.script.encode('utf-8')) f.close() diff --git a/awx/main/tests/job_base.py b/awx/main/tests/job_base.py index 5b7408d19d..54c3462fbc 100644 --- a/awx/main/tests/job_base.py +++ b/awx/main/tests/job_base.py @@ -229,13 +229,18 @@ class BaseJobTestMixin(BaseTestMixin): self.team_ops_west.users.add(self.user_iris) # The south team is no longer active having been folded into the east team - self.team_ops_south = self.org_ops.teams.create( - name='southerners', - created_by=self.user_sue, - active=False, - ) - self.team_ops_south.projects.add(self.proj_prod) - self.team_ops_south.users.add(self.user_greg) + # FIXME: This code can be removed (probably) + # - this case has been removed as we've gotten rid of the active flag, keeping + # code around in case this has ramifications on some test failures.. if + # you find this message and all tests are passing, then feel free to remove this + # - anoek 2016-03-10 + #self.team_ops_south = self.org_ops.teams.create( + # name='southerners', + # created_by=self.user_sue, + # active=False, + #) + #self.team_ops_south.projects.add(self.proj_prod) + #self.team_ops_south.users.add(self.user_greg) # The north team is going to be deleted self.team_ops_north = self.org_ops.teams.create( @@ -337,11 +342,18 @@ class BaseJobTestMixin(BaseTestMixin): password='Heading270', created_by = self.user_sue, ) - self.cred_ops_south = self.team_ops_south.credentials.create( - username='south', - password='Heading180', - created_by = self.user_sue, - ) + + + # FIXME: This code can be removed (probably) + # - this case has been removed as we've gotten rid of the active flag, keeping + # code around in case this has ramifications on some test failures.. if + # you find this message and all tests are passing, then feel free to remove this + # - anoek 2016-03-10 + #self.cred_ops_south = self.team_ops_south.credentials.create( + # username='south', + # password='Heading180', + # created_by = self.user_sue, + #) self.cred_ops_north = self.team_ops_north.credentials.create( username='north', diff --git a/awx/main/tests/old/commands/commands_monolithic.py b/awx/main/tests/old/commands/commands_monolithic.py index c3de826259..02fad6a199 100644 --- a/awx/main/tests/old/commands/commands_monolithic.py +++ b/awx/main/tests/old/commands/commands_monolithic.py @@ -520,12 +520,12 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): self.assertEqual(inventory_source.inventory_updates.count(), 1) inventory_update = inventory_source.inventory_updates.all()[0] self.assertEqual(inventory_update.status, 'successful') - for host in inventory.hosts.filter(active=True): + for host in inventory.hosts: if host.pk in (except_host_pks or []): continue source_pks = host.inventory_sources.values_list('pk', flat=True) self.assertTrue(inventory_source.pk in source_pks) - for group in inventory.groups.filter(active=True): + for group in inventory.groups: if group.pk in (except_group_pks or []): continue source_pks = group.inventory_sources.values_list('pk', flat=True) @@ -693,7 +693,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): 'lbservers', 'others']) if overwrite: expected_group_names.remove('lbservers') - group_names = set(new_inv.groups.filter(active=True).values_list('name', flat=True)) + group_names = set(new_inv.groups.values_list('name', flat=True)) self.assertEqual(expected_group_names, group_names) expected_host_names = set(['web1.example.com', 'web2.example.com', 'web3.example.com', 'db1.example.com', @@ -703,13 +703,13 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): 'fe80::1610:9fff:fedd:b654', '::1']) if overwrite: expected_host_names.remove('lb.example.com') - host_names = set(new_inv.hosts.filter(active=True).values_list('name', flat=True)) + host_names = set(new_inv.hosts.values_list('name', flat=True)) self.assertEqual(expected_host_names, host_names) expected_inv_vars = {'vara': 'A', 'varc': 'C'} if overwrite_vars: expected_inv_vars.pop('varc') self.assertEqual(new_inv.variables_dict, expected_inv_vars) - for host in new_inv.hosts.filter(active=True): + for host in new_inv.hosts: if host.name == 'web1.example.com': self.assertEqual(host.variables_dict, {'ansible_ssh_host': 'w1.example.net'}) @@ -721,35 +721,35 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): self.assertEqual(host.variables_dict, {'lbvar': 'ni!'}) else: self.assertEqual(host.variables_dict, {}) - for group in new_inv.groups.filter(active=True): + for group in new_inv.groups: if group.name == 'servers': expected_vars = {'varb': 'B', 'vard': 'D'} if overwrite_vars: expected_vars.pop('vard') self.assertEqual(group.variables_dict, expected_vars) - children = set(group.children.filter(active=True).values_list('name', flat=True)) + children = set(group.children.values_list('name', flat=True)) expected_children = set(['dbservers', 'webservers', 'lbservers']) if overwrite: expected_children.remove('lbservers') self.assertEqual(children, expected_children) - self.assertEqual(group.hosts.filter(active=True).count(), 0) + self.assertEqual(group.hosts.count(), 0) elif group.name == 'dbservers': self.assertEqual(group.variables_dict, {'dbvar': 'ugh'}) - self.assertEqual(group.children.filter(active=True).count(), 0) - hosts = set(group.hosts.filter(active=True).values_list('name', flat=True)) + self.assertEqual(group.children.count(), 0) + hosts = set(group.hosts.values_list('name', flat=True)) host_names = set(['db1.example.com','db2.example.com']) self.assertEqual(hosts, host_names) elif group.name == 'webservers': self.assertEqual(group.variables_dict, {'webvar': 'blah'}) - self.assertEqual(group.children.filter(active=True).count(), 0) - hosts = set(group.hosts.filter(active=True).values_list('name', flat=True)) + self.assertEqual(group.children.count(), 0) + hosts = set(group.hosts.values_list('name', flat=True)) host_names = set(['web1.example.com','web2.example.com', 'web3.example.com']) self.assertEqual(hosts, host_names) elif group.name == 'lbservers': self.assertEqual(group.variables_dict, {}) - self.assertEqual(group.children.filter(active=True).count(), 0) - hosts = set(group.hosts.filter(active=True).values_list('name', flat=True)) + self.assertEqual(group.children.count(), 0) + hosts = set(group.hosts.values_list('name', flat=True)) host_names = set(['lb.example.com']) self.assertEqual(hosts, host_names) if overwrite: @@ -799,7 +799,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): # Check hosts in dotcom group. group = new_inv.groups.get(name='dotcom') self.assertEqual(group.hosts.count(), 65) - for host in group.hosts.filter(active=True, name__startswith='web'): + for host in group.hosts.filter( name__startswith='web'): self.assertEqual(host.variables_dict.get('ansible_ssh_user', ''), 'example') # Check hosts in dotnet group. group = new_inv.groups.get(name='dotnet') @@ -807,7 +807,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): # Check hosts in dotorg group. group = new_inv.groups.get(name='dotorg') self.assertEqual(group.hosts.count(), 61) - for host in group.hosts.filter(active=True): + for host in group.hosts: if host.name.startswith('mx.'): continue self.assertEqual(host.variables_dict.get('ansible_ssh_user', ''), 'example') @@ -815,7 +815,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): # Check hosts in dotus group. group = new_inv.groups.get(name='dotus') self.assertEqual(group.hosts.count(), 10) - for host in group.hosts.filter(active=True): + for host in group.hosts: if int(host.name[2:4]) % 2 == 0: self.assertEqual(host.variables_dict.get('even_odd', ''), 'even') else: @@ -969,7 +969,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): else: return 0 - def _check_largeinv_import(self, new_inv, nhosts, nhosts_inactive=0): + def _check_largeinv_import(self, new_inv, nhosts): self._start_time = time.time() inv_file = os.path.join(os.path.dirname(__file__), '..', '..', 'data', 'largeinv.py') ngroups = self._get_ngroups_for_nhosts(nhosts) @@ -982,9 +982,8 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): # Check that inventory is populated as expected within a reasonable # amount of time. Computed fields should also be updated. new_inv = Inventory.objects.get(pk=new_inv.pk) - self.assertEqual(new_inv.hosts.filter(active=True).count(), nhosts) - self.assertEqual(new_inv.groups.filter(active=True).count(), ngroups) - self.assertEqual(new_inv.hosts.filter(active=False).count(), nhosts_inactive) + self.assertEqual(new_inv.hosts.count(), nhosts) + self.assertEqual(new_inv.groups.count(), ngroups) self.assertEqual(new_inv.total_hosts, nhosts) self.assertEqual(new_inv.total_groups, ngroups) self.assertElapsedLessThan(120) @@ -998,10 +997,10 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): self.assertEqual(new_inv.groups.count(), 0) nhosts = 2000 # Test initial import into empty inventory. - self._check_largeinv_import(new_inv, nhosts, 0) + self._check_largeinv_import(new_inv, nhosts) # Test re-importing and overwriting. - self._check_largeinv_import(new_inv, nhosts, 0) + self._check_largeinv_import(new_inv, nhosts) # Test re-importing with only half as many hosts. - self._check_largeinv_import(new_inv, nhosts / 2, nhosts / 2) + self._check_largeinv_import(new_inv, nhosts / 2) # Test re-importing that clears all hosts. - self._check_largeinv_import(new_inv, 0, nhosts) + self._check_largeinv_import(new_inv, 0) diff --git a/awx/main/tests/old/inventory.py b/awx/main/tests/old/inventory.py index a47807e62b..dda615e79e 100644 --- a/awx/main/tests/old/inventory.py +++ b/awx/main/tests/old/inventory.py @@ -69,7 +69,7 @@ class InventoryTest(BaseTest): def test_get_inventory_list(self): url = reverse('api:inventory_list') - qs = Inventory.objects.filter(active=True).distinct() + qs = Inventory.objects.distinct() # Check list view with invalid authentication. self.check_invalid_auth(url) @@ -226,6 +226,8 @@ class InventoryTest(BaseTest): self.inventory_a.groups.create(name='group-a') self.inventory_b.hosts.create(name='host-b') self.inventory_b.groups.create(name='group-b') + a_pk = self.inventory_a.pk + b_pk = self.inventory_b.pk # Check put to detail view with invalid authentication. self.check_invalid_auth(url_a, methods=('delete',)) @@ -248,24 +250,16 @@ class InventoryTest(BaseTest): self.delete(url_a, expect=204) self.delete(url_b, expect=403) - # Verify that the inventory is marked inactive, along with all its - # hosts and groups. - self.inventory_a = Inventory.objects.get(pk=self.inventory_a.pk) - self.assertFalse(self.inventory_a.active) - self.assertFalse(self.inventory_a.hosts.filter(active=True).count()) - self.assertFalse(self.inventory_a.groups.filter(active=True).count()) + # Verify that the inventory was deleted + assert Inventory.objects.filter(pk=a_pk).count() == 0 # a super user can delete inventory records with self.current_user(self.super_django_user): self.delete(url_a, expect=404) self.delete(url_b, expect=204) - # Verify that the inventory is marked inactive, along with all its - # hosts and groups. - self.inventory_b = Inventory.objects.get(pk=self.inventory_b.pk) - self.assertFalse(self.inventory_b.active) - self.assertFalse(self.inventory_b.hosts.filter(active=True).count()) - self.assertFalse(self.inventory_b.groups.filter(active=True).count()) + # Verify that the inventory was deleted + assert Inventory.objects.filter(pk=b_pk).count() == 0 def test_inventory_access_deleted_permissions(self): temp_org = self.make_organizations(self.super_django_user, 1)[0] @@ -747,13 +741,11 @@ class InventoryTest(BaseTest): # removed group should be automatically marked inactive once it no longer has any parents. removed_group = Group.objects.get(pk=result['id']) self.assertTrue(removed_group.parents.count()) - self.assertTrue(removed_group.active) for parent in removed_group.parents.all(): parent_children_url = reverse('api:group_children_list', args=(parent.pk,)) data = {'id': removed_group.pk, 'disassociate': 1} self.post(parent_children_url, data, expect=204, auth=self.get_super_credentials()) removed_group = Group.objects.get(pk=result['id']) - #self.assertFalse(removed_group.active) # FIXME: Disabled for now because automatically deleting group with no parents is also disabled. # Removing a group from a hierarchy should migrate its children to the # parent. The group itself will be deleted (marked inactive), and all @@ -766,7 +758,6 @@ class InventoryTest(BaseTest): with self.current_user(self.super_django_user): self.post(url, data, expect=204) gx3 = Group.objects.get(pk=gx3.pk) - #self.assertFalse(gx3.active) # FIXME: Disabled for now.... self.assertFalse(gx3 in gx2.children.all()) #self.assertTrue(gx4 in gx2.children.all()) @@ -1265,7 +1256,7 @@ class InventoryUpdatesTest(BaseTransactionTest): url = reverse('api:inventory_source_hosts_list', args=(inventory_source.pk,)) response = self.get(url, expect=200) self.assertNotEqual(response['count'], 0) - for host in inventory.hosts.filter(active=True): + for host in inventory.hosts: source_pks = host.inventory_sources.values_list('pk', flat=True) self.assertTrue(inventory_source.pk in source_pks) self.assertTrue(host.has_inventory_sources) @@ -1279,12 +1270,12 @@ class InventoryUpdatesTest(BaseTransactionTest): url = reverse('api:host_inventory_sources_list', args=(host.pk,)) response = self.get(url, expect=200) self.assertNotEqual(response['count'], 0) - for group in inventory.groups.filter(active=True): + for group in inventory.groups: source_pks = group.inventory_sources.values_list('pk', flat=True) self.assertTrue(inventory_source.pk in source_pks) self.assertTrue(group.has_inventory_sources) - self.assertTrue(group.children.filter(active=True).exists() or - group.hosts.filter(active=True).exists()) + self.assertTrue(group.children.exists() or + group.hosts.exists()) # Make sure EC2 instance ID groups and RDS groups are excluded. if inventory_source.source == 'ec2' and not instance_id_group_ok: self.assertFalse(re.match(r'^i-[0-9a-f]{8}$', group.name, re.I), @@ -1302,7 +1293,7 @@ class InventoryUpdatesTest(BaseTransactionTest): self.assertNotEqual(response['count'], 0) # Try to set a source on a child group that was imported. Should not # be allowed. - for group in inventory_source.group.children.filter(active=True): + for group in inventory_source.group.children: inv_src_2 = group.inventory_source inv_src_url2 = reverse('api:inventory_source_detail', args=(inv_src_2.pk,)) with self.current_user(self.super_django_user): @@ -1658,7 +1649,7 @@ class InventoryUpdatesTest(BaseTransactionTest): inventory_source.overwrite = True inventory_source.save() self.check_inventory_source(inventory_source, initial=False) - for host in self.inventory.hosts.filter(active=True): + for host in self.inventory.hosts: self.assertEqual(host.variables_dict['ec2_instance_type'], instance_type) # Try invalid instance filters that should be ignored: @@ -1792,12 +1783,12 @@ class InventoryUpdatesTest(BaseTransactionTest): inventory_source.save() self.check_inventory_source(inventory_source, initial=False) # Verify that only the desired groups are returned. - child_names = self.group.children.filter(active=True).values_list('name', flat=True) + child_names = self.group.children.values_list('name', flat=True) self.assertTrue('ec2' in child_names) self.assertTrue('regions' in child_names) - self.assertTrue(self.group.children.get(name='regions').children.filter(active=True).count()) + self.assertTrue(self.group.children.get(name='regions').children.count()) self.assertTrue('types' in child_names) - self.assertTrue(self.group.children.get(name='types').children.filter(active=True).count()) + self.assertTrue(self.group.children.get(name='types').children.count()) self.assertFalse('keys' in child_names) self.assertFalse('security_groups' in child_names) self.assertFalse('tags' in child_names) @@ -1814,27 +1805,27 @@ class InventoryUpdatesTest(BaseTransactionTest): self.check_inventory_source(inventory_source, initial=False, instance_id_group_ok=True) # Verify that only the desired groups are returned. # Skip vpcs as selected inventory may or may not have any. - child_names = self.group.children.filter(active=True).values_list('name', flat=True) + child_names = self.group.children.values_list('name', flat=True) self.assertTrue('ec2' in child_names) self.assertFalse('tag_none' in child_names) self.assertTrue('regions' in child_names) - self.assertTrue(self.group.children.get(name='regions').children.filter(active=True).count()) + self.assertTrue(self.group.children.get(name='regions').children.count()) self.assertTrue('types' in child_names) - self.assertTrue(self.group.children.get(name='types').children.filter(active=True).count()) + self.assertTrue(self.group.children.get(name='types').children.count()) self.assertTrue('keys' in child_names) - self.assertTrue(self.group.children.get(name='keys').children.filter(active=True).count()) + self.assertTrue(self.group.children.get(name='keys').children.count()) self.assertTrue('security_groups' in child_names) - self.assertTrue(self.group.children.get(name='security_groups').children.filter(active=True).count()) + self.assertTrue(self.group.children.get(name='security_groups').children.count()) self.assertTrue('tags' in child_names) - self.assertTrue(self.group.children.get(name='tags').children.filter(active=True).count()) + self.assertTrue(self.group.children.get(name='tags').children.count()) # Only check for tag_none as a child of tags if there is a tag_none group; # the test inventory *may* have tags set for all hosts. if self.inventory.groups.filter(name='tag_none').exists(): self.assertTrue('tag_none' in self.group.children.get(name='tags').children.values_list('name', flat=True)) self.assertTrue('images' in child_names) - self.assertTrue(self.group.children.get(name='images').children.filter(active=True).count()) + self.assertTrue(self.group.children.get(name='images').children.count()) self.assertTrue('instances' in child_names) - self.assertTrue(self.group.children.get(name='instances').children.filter(active=True).count()) + self.assertTrue(self.group.children.get(name='instances').children.count()) # Sync again with overwrite set to False after renaming a group that # was created by the sync. With overwrite false, the renamed group and # the original group (created again by the sync) will both exist. @@ -1848,7 +1839,7 @@ class InventoryUpdatesTest(BaseTransactionTest): inventory_source.overwrite = False inventory_source.save() self.check_inventory_source(inventory_source, initial=False, instance_id_group_ok=True) - child_names = self.group.children.filter(active=True).values_list('name', flat=True) + child_names = self.group.children.values_list('name', flat=True) self.assertTrue(region_group_original_name in self.group.children.get(name='regions').children.values_list('name', flat=True)) self.assertTrue(region_group.name in self.group.children.get(name='regions').children.values_list('name', flat=True)) # Replacement text should not be left in inventory source name. diff --git a/awx/main/tests/old/jobs/job_launch.py b/awx/main/tests/old/jobs/job_launch.py index 5cd9f9e7e0..c0997607ee 100644 --- a/awx/main/tests/old/jobs/job_launch.py +++ b/awx/main/tests/old/jobs/job_launch.py @@ -137,7 +137,7 @@ class JobTemplateLaunchTest(BaseJobTestMixin, django.test.TransactionTestCase): 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) - doug_pk = self.cred_doug.pk + cred_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) diff --git a/awx/main/tests/old/organizations.py b/awx/main/tests/old/organizations.py index ef3b3ac77f..c5b1569513 100644 --- a/awx/main/tests/old/organizations.py +++ b/awx/main/tests/old/organizations.py @@ -436,10 +436,8 @@ class OrganizationsTest(BaseTest): self.delete(urls[0], expect=204, auth=self.get_super_credentials()) # check that when we have deleted an object it comes back 404 via GET - # but that it's still in the database as inactive self.get(urls[1], expect=404, auth=self.get_normal_credentials()) - org1 = Organization.objects.get(pk=urldata1['id']) - self.assertEquals(org1.active, False) + assert Organization.objects.filter(pk=urldata1['id']).count() == 0 # also check that DELETE on the collection doesn't work self.delete(self.collection(), expect=405, auth=self.get_super_credentials()) diff --git a/awx/main/tests/old/projects.py b/awx/main/tests/old/projects.py index 416ad41327..2c715e312a 100644 --- a/awx/main/tests/old/projects.py +++ b/awx/main/tests/old/projects.py @@ -162,7 +162,7 @@ class ProjectsTest(BaseTransactionTest): set(Project.get_local_path_choices())) # return local paths are only the ones not used by any active project. - qs = Project.objects.filter(active=True) + qs = Project.objects used_paths = qs.values_list('local_path', flat=True) self.assertFalse(set(response['project_local_paths']) & set(used_paths)) for project in self.projects: @@ -402,7 +402,7 @@ class ProjectsTest(BaseTransactionTest): # ===================================================================== # TEAM PROJECTS - team = Team.objects.filter(active=True, organization__pk=self.organizations[1].pk)[0] + team = Team.objects.filter( organization__pk=self.organizations[1].pk)[0] team_projects = reverse('api:team_projects_list', args=(team.pk,)) p1 = self.projects[0] @@ -419,7 +419,7 @@ class ProjectsTest(BaseTransactionTest): # ===================================================================== # TEAMS USER MEMBERSHIP - team = Team.objects.filter(active=True, organization__pk=self.organizations[1].pk)[0] + team = Team.objects.filter( organization__pk=self.organizations[1].pk)[0] team_users = reverse('api:team_users_list', args=(team.pk,)) for x in team.deprecated_users.all(): team.deprecated_users.remove(x) @@ -1262,7 +1262,7 @@ class ProjectUpdatesTest(BaseTransactionTest): else: self.check_project_update(project, should_fail=should_still_fail) # Test that we can delete project updates. - for pu in project.project_updates.filter(active=True): + for pu in project.project_updates: pu_url = reverse('api:project_update_detail', args=(pu.pk,)) with self.current_user(self.super_django_user): self.delete(pu_url, expect=204) diff --git a/awx/main/tests/old/scripts.py b/awx/main/tests/old/scripts.py index 735d0f0197..7f1d62161a 100644 --- a/awx/main/tests/old/scripts.py +++ b/awx/main/tests/old/scripts.py @@ -146,12 +146,11 @@ class InventoryScriptTest(BaseScriptTest): def test_list_with_inventory_id_as_argument(self): inventory = self.inventories[0] - self.assertTrue(inventory.active) rc, stdout, stderr = self.run_inventory_script(list=True, inventory=inventory.pk) self.assertEqual(rc, 0, stderr) data = json.loads(stdout) - groups = inventory.groups.filter(active=True) + groups = inventory.groups groupnames = [ x for x in groups.values_list('name', flat=True)] # it's ok for all to be here because due to an Ansible inventory workaround @@ -167,16 +166,13 @@ class InventoryScriptTest(BaseScriptTest): self.assertTrue(isinstance(v['children'], (list,tuple))) self.assertTrue(isinstance(v['hosts'], (list,tuple))) self.assertTrue(isinstance(v['vars'], (dict))) - group = inventory.groups.get(active=True, name=k) - hosts = group.hosts.filter(active=True) + group = inventory.groups.get(name=k) + hosts = group.hosts hostnames = hosts.values_list('name', flat=True) self.assertEqual(set(v['hosts']), set(hostnames)) else: self.assertTrue(v['hosts'] == ['localhost']) - for group in inventory.groups.filter(active=False): - self.assertFalse(group.name in data.keys(), - 'deleted group %s should not be in data' % group) # Command line argument for inventory ID should take precedence over # environment variable. inventory_pks = set(map(lambda x: x.pk, self.inventories)) @@ -189,12 +185,11 @@ class InventoryScriptTest(BaseScriptTest): def test_list_with_inventory_id_in_environment(self): inventory = self.inventories[1] - self.assertTrue(inventory.active) os.environ['INVENTORY_ID'] = str(inventory.pk) rc, stdout, stderr = self.run_inventory_script(list=True) self.assertEqual(rc, 0, stderr) data = json.loads(stdout) - groups = inventory.groups.filter(active=True) + groups = inventory.groups groupnames = list(groups.values_list('name', flat=True)) + ['all'] self.assertEqual(set(data.keys()), set(groupnames)) # Groups for this inventory should have hosts, variable data, and one @@ -204,14 +199,14 @@ class InventoryScriptTest(BaseScriptTest): if k == 'all': self.assertEqual(v.get('vars', {}), inventory.variables_dict) continue - group = inventory.groups.get(active=True, name=k) - hosts = group.hosts.filter(active=True) + group = inventory.groups.get(name=k) + hosts = group.hosts hostnames = hosts.values_list('name', flat=True) self.assertEqual(set(v.get('hosts', [])), set(hostnames)) if group.variables: self.assertEqual(v.get('vars', {}), group.variables_dict) if k == 'group-3': - children = group.children.filter(active=True) + children = group.children childnames = children.values_list('name', flat=True) self.assertEqual(set(v.get('children', [])), set(childnames)) else: @@ -219,13 +214,12 @@ class InventoryScriptTest(BaseScriptTest): def test_list_with_hostvars_inline(self): inventory = self.inventories[1] - self.assertTrue(inventory.active) rc, stdout, stderr = self.run_inventory_script(list=True, inventory=inventory.pk, hostvars=True) self.assertEqual(rc, 0, stderr) data = json.loads(stdout) - groups = inventory.groups.filter(active=True) + groups = inventory.groups groupnames = list(groups.values_list('name', flat=True)) groupnames.extend(['all', '_meta']) self.assertEqual(set(data.keys()), set(groupnames)) @@ -239,15 +233,15 @@ class InventoryScriptTest(BaseScriptTest): continue if k == '_meta': continue - group = inventory.groups.get(active=True, name=k) - hosts = group.hosts.filter(active=True) + group = inventory.groups.get(name=k) + hosts = group.hosts hostnames = hosts.values_list('name', flat=True) all_hostnames.update(hostnames) self.assertEqual(set(v.get('hosts', [])), set(hostnames)) if group.variables: self.assertEqual(v.get('vars', {}), group.variables_dict) if k == 'group-3': - children = group.children.filter(active=True) + children = group.children childnames = children.values_list('name', flat=True) self.assertEqual(set(v.get('children', [])), set(childnames)) else: @@ -269,8 +263,7 @@ class InventoryScriptTest(BaseScriptTest): def test_valid_host(self): # Host without variable data. inventory = self.inventories[0] - self.assertTrue(inventory.active) - host = inventory.hosts.filter(active=True)[2] + host = inventory.hosts[2] os.environ['INVENTORY_ID'] = str(inventory.pk) rc, stdout, stderr = self.run_inventory_script(host=host.name) self.assertEqual(rc, 0, stderr) @@ -278,8 +271,7 @@ class InventoryScriptTest(BaseScriptTest): self.assertEqual(data, {}) # Host with variable data. inventory = self.inventories[1] - self.assertTrue(inventory.active) - host = inventory.hosts.filter(active=True)[4] + host = inventory.hosts[4] os.environ['INVENTORY_ID'] = str(inventory.pk) rc, stdout, stderr = self.run_inventory_script(host=host.name) self.assertEqual(rc, 0, stderr) @@ -289,8 +281,7 @@ class InventoryScriptTest(BaseScriptTest): def test_invalid_host(self): # Valid host, but not part of the specified inventory. inventory = self.inventories[0] - self.assertTrue(inventory.active) - host = Host.objects.filter(active=True).exclude(inventory=inventory)[0] + host = Host.objects.exclude(inventory=inventory)[0] os.environ['INVENTORY_ID'] = str(inventory.pk) rc, stdout, stderr = self.run_inventory_script(host=host.name) self.assertNotEqual(rc, 0, stderr) @@ -331,7 +322,6 @@ class InventoryScriptTest(BaseScriptTest): def test_without_list_or_host_argument(self): inventory = self.inventories[0] - self.assertTrue(inventory.active) os.environ['INVENTORY_ID'] = str(inventory.pk) rc, stdout, stderr = self.run_inventory_script() self.assertNotEqual(rc, 0, stderr) @@ -339,7 +329,6 @@ class InventoryScriptTest(BaseScriptTest): def test_with_both_list_and_host_arguments(self): inventory = self.inventories[0] - self.assertTrue(inventory.active) os.environ['INVENTORY_ID'] = str(inventory.pk) rc, stdout, stderr = self.run_inventory_script(list=True, host='blah') self.assertNotEqual(rc, 0, stderr) @@ -347,8 +336,7 @@ class InventoryScriptTest(BaseScriptTest): def test_with_disabled_hosts(self): inventory = self.inventories[1] - self.assertTrue(inventory.active) - for host in inventory.hosts.filter(active=True, enabled=True): + for host in inventory.hosts.filter(enabled=True): host.enabled = False host.save(update_fields=['enabled']) os.environ['INVENTORY_ID'] = str(inventory.pk) @@ -356,7 +344,7 @@ class InventoryScriptTest(BaseScriptTest): rc, stdout, stderr = self.run_inventory_script(list=True) self.assertEqual(rc, 0, stderr) data = json.loads(stdout) - groups = inventory.groups.filter(active=True) + groups = inventory.groups groupnames = list(groups.values_list('name', flat=True)) + ['all'] self.assertEqual(set(data.keys()), set(groupnames)) for k,v in data.items(): @@ -364,15 +352,15 @@ class InventoryScriptTest(BaseScriptTest): if k == 'all': self.assertEqual(v.get('vars', {}), inventory.variables_dict) continue - group = inventory.groups.get(active=True, name=k) - hosts = group.hosts.filter(active=True, enabled=True) + group = inventory.groups.get(name=k) + hosts = group.hosts.filter(enabled=True) hostnames = hosts.values_list('name', flat=True) self.assertEqual(set(v.get('hosts', [])), set(hostnames)) self.assertFalse(hostnames) if group.variables: self.assertEqual(v.get('vars', {}), group.variables_dict) if k == 'group-3': - children = group.children.filter(active=True) + children = group.children childnames = children.values_list('name', flat=True) self.assertEqual(set(v.get('children', [])), set(childnames)) else: @@ -381,7 +369,7 @@ class InventoryScriptTest(BaseScriptTest): rc, stdout, stderr = self.run_inventory_script(list=True, all=True) self.assertEqual(rc, 0, stderr) data = json.loads(stdout) - groups = inventory.groups.filter(active=True) + groups = inventory.groups groupnames = list(groups.values_list('name', flat=True)) + ['all'] self.assertEqual(set(data.keys()), set(groupnames)) for k,v in data.items(): @@ -389,15 +377,15 @@ class InventoryScriptTest(BaseScriptTest): if k == 'all': self.assertEqual(v.get('vars', {}), inventory.variables_dict) continue - group = inventory.groups.get(active=True, name=k) - hosts = group.hosts.filter(active=True) + group = inventory.groups.get(name=k) + hosts = group.hosts hostnames = hosts.values_list('name', flat=True) self.assertEqual(set(v.get('hosts', [])), set(hostnames)) self.assertTrue(hostnames) if group.variables: self.assertEqual(v.get('vars', {}), group.variables_dict) if k == 'group-3': - children = group.children.filter(active=True) + children = group.children childnames = children.values_list('name', flat=True) self.assertEqual(set(v.get('children', [])), set(childnames)) else: diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index 76381e5ac0..f663bab11b 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -209,7 +209,6 @@ REST_FRAMEWORK = { 'awx.api.permissions.ModelAccessPermission', ), 'DEFAULT_FILTER_BACKENDS': ( - 'awx.api.filters.ActiveOnlyBackend', 'awx.api.filters.TypeFilterBackend', 'awx.api.filters.FieldLookupBackend', 'rest_framework.filters.SearchFilter', diff --git a/awx/sso/pipeline.py b/awx/sso/pipeline.py index 7000d050ee..f3e8987d17 100644 --- a/awx/sso/pipeline.py +++ b/awx/sso/pipeline.py @@ -90,7 +90,7 @@ def update_user_orgs(backend, details, user=None, *args, **kwargs): org = Organization.objects.get_or_create(name=org_name)[0] else: try: - org = Organization.objects.filter(active=True).order_by('pk')[0] + org = Organization.objects.order_by('pk')[0] except IndexError: continue @@ -126,7 +126,7 @@ def update_user_teams(backend, details, user=None, *args, **kwargs): org = Organization.objects.get_or_create(name=team_opts['organization'])[0] else: try: - org = Organization.objects.filter(active=True).order_by('pk')[0] + org = Organization.objects.order_by('pk')[0] except IndexError: continue From a845d5c0bb94396159a9139df44dcb63d1ec85c5 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Tue, 15 Mar 2016 09:34:50 -0400 Subject: [PATCH 8/9] we removed our previous 0008 migration, so moving 0009 -> 0008 --- .../migrations/{0009_v300_changes.py => 0008_v300_changes.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename awx/main/migrations/{0009_v300_changes.py => 0008_v300_changes.py} (98%) diff --git a/awx/main/migrations/0009_v300_changes.py b/awx/main/migrations/0008_v300_changes.py similarity index 98% rename from awx/main/migrations/0009_v300_changes.py rename to awx/main/migrations/0008_v300_changes.py index 578dc10653..fe6c67f48d 100644 --- a/awx/main/migrations/0009_v300_changes.py +++ b/awx/main/migrations/0008_v300_changes.py @@ -107,7 +107,7 @@ def create_system_job_templates(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('main', '0008_v300_rbac_drop_fields'), + ('main', '0007_v300_rbac_migrations'), ] operations = [ From d6429eb1e817161d24df97f486ec4190b27f0fdf Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Tue, 15 Mar 2016 09:47:53 -0400 Subject: [PATCH 9/9] Active flag removal fix for .filter->all --- awx/api/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/api/views.py b/awx/api/views.py index af32ffd0a9..96c3bf396e 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -1637,7 +1637,7 @@ class InventoryScriptView(RetrieveAPIView): group_children.append(from_group_name) # Now use in-memory maps to build up group info. - for group in obj.groups: + for group in obj.groups.all(): group_info = OrderedDict() group_info['hosts'] = group_hosts_map.get(group.id, []) group_info['children'] = group_children_map.get(group.id, [])