From 994a72967dab5ef8d6f35159985ea44f3b335a15 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Wed, 13 Jul 2016 17:23:00 -0400 Subject: [PATCH 1/2] Cascade delete teams when their organization is deleted --- .../migrations/0027_v300_team_migrations.py | 20 +++++++++++++ .../migrations/0028_v300_org_team_cascade.py | 20 +++++++++++++ awx/main/migrations/_team_cleanup.py | 30 +++++++++++++++++++ awx/main/models/organization.py | 2 +- 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 awx/main/migrations/0027_v300_team_migrations.py create mode 100644 awx/main/migrations/0028_v300_org_team_cascade.py create mode 100644 awx/main/migrations/_team_cleanup.py diff --git a/awx/main/migrations/0027_v300_team_migrations.py b/awx/main/migrations/0027_v300_team_migrations.py new file mode 100644 index 0000000000..b53fd8a969 --- /dev/null +++ b/awx/main/migrations/0027_v300_team_migrations.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from awx.main.migrations import _rbac as rbac +from awx.main.migrations import _team_cleanup as team_cleanup +from awx.main.migrations import _migration_utils as migration_utils +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0026_v300_credential_unique'), + ] + + operations = [ + migrations.RunPython(migration_utils.set_current_apps_for_migrations), + migrations.RunPython(team_cleanup.migrate_team), + migrations.RunPython(rbac.rebuild_role_hierarchy), + ] diff --git a/awx/main/migrations/0028_v300_org_team_cascade.py b/awx/main/migrations/0028_v300_org_team_cascade.py new file mode 100644 index 0000000000..bf798df3c3 --- /dev/null +++ b/awx/main/migrations/0028_v300_org_team_cascade.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import awx.main.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0027_v300_team_migrations'), + ] + + operations = [ + migrations.AlterField( + model_name='team', + name='organization', + field=models.ForeignKey(related_name='teams', to='main.Organization', null=True), + ), + ] diff --git a/awx/main/migrations/_team_cleanup.py b/awx/main/migrations/_team_cleanup.py new file mode 100644 index 0000000000..1a937d1f88 --- /dev/null +++ b/awx/main/migrations/_team_cleanup.py @@ -0,0 +1,30 @@ +# Python +import logging +from django.utils.encoding import smart_text + +logger = logging.getLogger(__name__) + +def log_migration(wrapped): + '''setup the logging mechanism for each migration method + as it runs, Django resets this, so we use a decorator + to re-add the handler for each method. + ''' + handler = logging.FileHandler("/tmp/tower_rbac_migrations.log", mode="a", encoding="UTF-8") + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + handler.setLevel(logging.DEBUG) + handler.setFormatter(formatter) + + def wrapper(*args, **kwargs): + logger.handlers = [] + logger.addHandler(handler) + return wrapped(*args, **kwargs) + return wrapper + +@log_migration +def migrate_team(apps, schema_editor): + '''If an orphan team exists that is still active, delete it.''' + Team = apps.get_model('main', 'Team') + for team in Team.objects.iterator(): + if team.organization is None: + logger.info(smart_text(u"Deleting orphaned team: {}".format(team.name))) + team.delete() diff --git a/awx/main/models/organization.py b/awx/main/models/organization.py index 3717171411..79cb3facdc 100644 --- a/awx/main/models/organization.py +++ b/awx/main/models/organization.py @@ -93,7 +93,7 @@ class Team(CommonModelNameNotUnique, ResourceMixin): 'Organization', blank=False, null=True, - on_delete=models.SET_NULL, + on_delete=models.CASCADE, related_name='teams', ) deprecated_projects = models.ManyToManyField( From 68d5a702af292d2bf958422fed742b39b4757b0f Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Thu, 14 Jul 2016 14:38:43 -0400 Subject: [PATCH 2/2] Team organization field made non-null --- awx/main/migrations/0028_v300_org_team_cascade.py | 3 ++- awx/main/models/organization.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/awx/main/migrations/0028_v300_org_team_cascade.py b/awx/main/migrations/0028_v300_org_team_cascade.py index bf798df3c3..80378c5729 100644 --- a/awx/main/migrations/0028_v300_org_team_cascade.py +++ b/awx/main/migrations/0028_v300_org_team_cascade.py @@ -15,6 +15,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='team', name='organization', - field=models.ForeignKey(related_name='teams', to='main.Organization', null=True), + field=models.ForeignKey(related_name='teams', to='main.Organization'), + preserve_default=False, ), ] diff --git a/awx/main/models/organization.py b/awx/main/models/organization.py index 79cb3facdc..5f3dc9d7c9 100644 --- a/awx/main/models/organization.py +++ b/awx/main/models/organization.py @@ -92,7 +92,7 @@ class Team(CommonModelNameNotUnique, ResourceMixin): organization = models.ForeignKey( 'Organization', blank=False, - null=True, + null=False, on_delete=models.CASCADE, related_name='teams', )