From b8a7ad17ea7cd706f322d567c2e6ef82f95c1e75 Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Mon, 8 Feb 2016 15:33:59 -0500 Subject: [PATCH 1/5] Added initial rbac migrations --- awx/main/migrations/0003_rbac_changes.py | 256 +++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 awx/main/migrations/0003_rbac_changes.py diff --git a/awx/main/migrations/0003_rbac_changes.py b/awx/main/migrations/0003_rbac_changes.py new file mode 100644 index 0000000000..f26aee850d --- /dev/null +++ b/awx/main/migrations/0003_rbac_changes.py @@ -0,0 +1,256 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +from django.conf import settings +import taggit.managers +import awx.main.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('taggit', '0002_auto_20150616_2121'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('main', '0002_v300_changes'), + ] + + operations = [ + migrations.CreateModel( + name='Resource', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('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)), + ('created_by', models.ForeignKey(related_name="{u'class': 'resource', u'app_label': 'main'}(class)s_created+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)), + ('modified_by', models.ForeignKey(related_name="{u'class': 'resource', u'app_label': 'main'}(class)s_modified+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)), + ('parent', models.ForeignKey(related_name='children', default=None, to='main.Resource', null=True)), + ('tags', taggit.managers.TaggableManager(to='taggit.Tag', through='taggit.TaggedItem', blank=True, help_text='A comma-separated list of tags.', verbose_name='Tags')), + ], + options={ + 'db_table': 'main_rbac_resources', + 'verbose_name_plural': 'resources', + }, + ), + migrations.CreateModel( + name='Role', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('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)), + ('created_by', models.ForeignKey(related_name="{u'class': 'role', u'app_label': 'main'}(class)s_created+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)), + ('members', models.ManyToManyField(related_name='roles', to=settings.AUTH_USER_MODEL)), + ('modified_by', models.ForeignKey(related_name="{u'class': 'role', u'app_label': 'main'}(class)s_modified+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)), + ('parents', models.ManyToManyField(related_name='children', to='main.Role')), + ('tags', taggit.managers.TaggableManager(to='taggit.Tag', through='taggit.TaggedItem', blank=True, help_text='A comma-separated list of tags.', verbose_name='Tags')), + ], + options={ + 'db_table': 'main_rbac_roles', + 'verbose_name_plural': 'roles', + }, + ), + migrations.CreateModel( + name='RoleHierarchy', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('created', models.DateTimeField(default=None, editable=False)), + ('modified', models.DateTimeField(default=None, editable=False)), + ('ancestor', models.ForeignKey(related_name='+', to='main.Role')), + ('role', models.ForeignKey(related_name='+', to='main.Role')), + ], + options={ + 'db_table': 'main_rbac_role_hierarchy', + 'verbose_name_plural': 'role_ancestors', + }, + ), + migrations.CreateModel( + name='RolePermission', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('created', models.DateTimeField(default=None, editable=False)), + ('modified', models.DateTimeField(default=None, editable=False)), + ('create', models.IntegerField(default=0)), + ('read', models.IntegerField(default=0)), + ('write', models.IntegerField(default=0)), + ('update', models.IntegerField(default=0)), + ('delete', models.IntegerField(default=0)), + ('execute', models.IntegerField(default=0)), + ('scm_update', models.IntegerField(default=0)), + ('use', models.IntegerField(default=0)), + ('resource', models.ForeignKey(related_name='permissions', to='main.Resource')), + ('role', models.ForeignKey(related_name='permissions', to='main.Role')), + ], + options={ + 'db_table': 'main_rbac_permissions', + 'verbose_name_plural': 'permissions', + }, + ), + migrations.AddField( + model_name='project', + name='organization', + field=models.ForeignKey(related_name='project_list', on_delete=django.db.models.deletion.SET_NULL, to='main.Organization', null=True), + ), + migrations.AddField( + model_name='credential', + name='owner_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='credential', + name='resource', + field=awx.main.fields.ImplicitResourceField(related_name='+', to='main.Resource', null=b'True'), + ), + migrations.AddField( + model_name='credential', + name='usage_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='group', + name='admin_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='group', + name='auditor_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='group', + name='executor_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='group', + name='resource', + field=awx.main.fields.ImplicitResourceField(related_name='+', to='main.Resource', null=b'True'), + ), + migrations.AddField( + model_name='group', + name='updater_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='host', + name='resource', + field=awx.main.fields.ImplicitResourceField(related_name='+', to='main.Resource', null=b'True'), + ), + migrations.AddField( + model_name='inventory', + name='admin_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='inventory', + name='auditor_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='inventory', + name='executor_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='inventory', + name='resource', + field=awx.main.fields.ImplicitResourceField(related_name='+', to='main.Resource', null=b'True'), + ), + migrations.AddField( + model_name='inventory', + name='updater_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='inventorysource', + name='resource', + field=awx.main.fields.ImplicitResourceField(related_name='+', to='main.Resource', null=b'True'), + ), + migrations.AddField( + model_name='jobtemplate', + name='admin_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='jobtemplate', + name='auditor_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='jobtemplate', + name='executor_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='jobtemplate', + name='resource', + field=awx.main.fields.ImplicitResourceField(related_name='+', to='main.Resource', null=b'True'), + ), + migrations.AddField( + model_name='organization', + name='admin_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='organization', + name='auditor_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='organization', + name='resource', + field=awx.main.fields.ImplicitResourceField(related_name='+', to='main.Resource', null=b'True'), + ), + migrations.AddField( + model_name='project', + name='admin_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='project', + name='auditor_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='project', + name='member_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='project', + name='resource', + field=awx.main.fields.ImplicitResourceField(related_name='+', to='main.Resource', null=b'True'), + ), + migrations.AddField( + model_name='project', + name='scm_update_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='team', + name='admin_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='team', + name='auditor_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='team', + name='member_role', + field=awx.main.fields.ImplicitRoleField(related_name='+', to='main.Role', null=b'True'), + ), + migrations.AddField( + model_name='team', + name='resource', + field=awx.main.fields.ImplicitResourceField(related_name='+', to='main.Resource', null=b'True'), + ), + ] From 1ed18e4561d7fa2aee4a93ee73720ea62e3ef068 Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Mon, 8 Feb 2016 15:35:39 -0500 Subject: [PATCH 2/5] convert Organization to django migration --- awx/main/migrations/0004_rbac_migrations.py | 16 ++++++++++++++++ awx/main/migrations/_rbac.py | 17 +++++++++++++++++ awx/main/models/organization.py | 10 ---------- .../tests/functional/test_rbac_organization.py | 13 +++++++++---- 4 files changed, 42 insertions(+), 14 deletions(-) create mode 100644 awx/main/migrations/0004_rbac_migrations.py create mode 100644 awx/main/migrations/_rbac.py diff --git a/awx/main/migrations/0004_rbac_migrations.py b/awx/main/migrations/0004_rbac_migrations.py new file mode 100644 index 0000000000..e6c221272d --- /dev/null +++ b/awx/main/migrations/0004_rbac_migrations.py @@ -0,0 +1,16 @@ +# -*- 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', '0003_rbac_changes'), + ] + + operations = [ + migrations.RunPython(rbac.migrate_organization, rbac.unmigrate_organization), + ] diff --git a/awx/main/migrations/_rbac.py b/awx/main/migrations/_rbac.py new file mode 100644 index 0000000000..3c2a176b69 --- /dev/null +++ b/awx/main/migrations/_rbac.py @@ -0,0 +1,17 @@ +from collections import defaultdict + +def migrate_organization(apps, schema_editor): + migrations = defaultdict(list) + organization = apps.get_model('main', "Organization") + for org in organization.objects.all(): + for admin in org.admins.all(): + org.admin_role.members.add(admin) + migrations[org.name].append(admin) + for user in org.users.all(): + org.auditor_role.members.add(user) + migrations[org.name].append(user) + return migrations + + +def unmigrate_organization(apps, schema_editor): + pass diff --git a/awx/main/models/organization.py b/awx/main/models/organization.py index 306a4ff42b..62636e42e6 100644 --- a/awx/main/models/organization.py +++ b/awx/main/models/organization.py @@ -76,16 +76,6 @@ class Organization(CommonModel, ResourceMixin): script.save() super(Organization, self).mark_inactive(save=save) - def migrate_to_rbac(self): - migrated_users = [] - for admin in self.admins.all(): - self.admin_role.members.add(admin) - migrated_users.append(admin) - for user in self.users.all(): - self.auditor_role.members.add(user) - migrated_users.append(user) - return migrated_users - class Team(CommonModelNameNotUnique, ResourceMixin): ''' diff --git a/awx/main/tests/functional/test_rbac_organization.py b/awx/main/tests/functional/test_rbac_organization.py index 1eadd5a866..67422208aa 100644 --- a/awx/main/tests/functional/test_rbac_organization.py +++ b/awx/main/tests/functional/test_rbac_organization.py @@ -1,6 +1,9 @@ import pytest +from awx.main.migrations import _rbac as rbac from awx.main.access import OrganizationAccess +from django.apps import apps + @pytest.mark.django_db def test_organization_migration_admin(organization, permissions, user): @@ -9,8 +12,9 @@ def test_organization_migration_admin(organization, permissions, user): assert not organization.accessible_by(u, permissions['admin']) - migrated_users = organization.migrate_to_rbac() - assert len(migrated_users) == 1 + migrations = rbac.migrate_organization(apps, None) + + assert len(migrations) == 1 assert organization.accessible_by(u, permissions['admin']) @pytest.mark.django_db @@ -20,8 +24,9 @@ def test_organization_migration_user(organization, permissions, user): assert not organization.accessible_by(u, permissions['auditor']) - migrated_users = organization.migrate_to_rbac() - assert len(migrated_users) == 1 + migrations = rbac.migrate_organization(apps, None) + + assert len(migrations) == 1 assert organization.accessible_by(u, permissions['auditor']) @pytest.mark.django_db From 8cf0ba0da71d0ddec06bb5a1ee601fb2e6b019bf Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Mon, 8 Feb 2016 15:54:11 -0500 Subject: [PATCH 3/5] convert Credential to django migration --- awx/main/migrations/0004_rbac_migrations.py | 3 ++- awx/main/migrations/_rbac.py | 14 ++++++++++++-- awx/main/models/credential.py | 8 -------- awx/main/tests/functional/test_rbac_credential.py | 15 ++++++++++++--- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/awx/main/migrations/0004_rbac_migrations.py b/awx/main/migrations/0004_rbac_migrations.py index e6c221272d..5d02d6bd00 100644 --- a/awx/main/migrations/0004_rbac_migrations.py +++ b/awx/main/migrations/0004_rbac_migrations.py @@ -12,5 +12,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(rbac.migrate_organization, rbac.unmigrate_organization), + migrations.RunPython(rbac.migrate_organization), + migrations.RunPython(rbac.migrate_credential), ] diff --git a/awx/main/migrations/_rbac.py b/awx/main/migrations/_rbac.py index 3c2a176b69..b0403b1a0d 100644 --- a/awx/main/migrations/_rbac.py +++ b/awx/main/migrations/_rbac.py @@ -13,5 +13,15 @@ def migrate_organization(apps, schema_editor): return migrations -def unmigrate_organization(apps, schema_editor): - pass +def migrate_credential(apps, schema_editor): + migrations = defaultdict(list) + credential = apps.get_model('main', "Credential") + for cred in credential.objects.all(): + if cred.user: + cred.owner_role.members.add(cred.user) + migrations[cred.name].append(cred.user) + elif cred.team: + cred.owner_role.parents.add(cred.team.admin_role) + cred.usage_role.parents.add(cred.team.member_role) + migrations[cred.name].append(cred.team) + return migrations diff --git a/awx/main/models/credential.py b/awx/main/models/credential.py index 462cf35249..5d1c0cab96 100644 --- a/awx/main/models/credential.py +++ b/awx/main/models/credential.py @@ -363,14 +363,6 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin): update_fields.append('cloud') super(Credential, self).save(*args, **kwargs) - def migrate_to_rbac(self): - if self.user: - self.owner_role.members.add(self.user) - return [self.user] - elif self.team: - self.owner_role.parents.add(self.team.admin_role) - self.usage_role.parents.add(self.team.member_role) - return [self.team] def validate_ssh_private_key(data): """Validate that the given SSH private key or certificate is, diff --git a/awx/main/tests/functional/test_rbac_credential.py b/awx/main/tests/functional/test_rbac_credential.py index 173467f258..9de46f8115 100644 --- a/awx/main/tests/functional/test_rbac_credential.py +++ b/awx/main/tests/functional/test_rbac_credential.py @@ -1,10 +1,16 @@ import pytest +from awx.main.migrations import _rbac as rbac +from django.apps import apps + @pytest.mark.django_db def test_credential_migration_user(credential, user, permissions): u = user('user', False) credential.user = u - migrated = credential.migrate_to_rbac() + credential.save() + + migrated = rbac.migrate_credential(apps, None) + assert len(migrated) == 1 assert credential.accessible_by(u, permissions['admin']) @@ -19,11 +25,13 @@ def test_credential_migration_team_member(credential, team, user, permissions): u = user('user', False) team.admin_role.members.add(u) credential.team = team + credential.save() # No permissions pre-migration assert not credential.accessible_by(u, permissions['admin']) - migrated = credential.migrate_to_rbac() + migrated = rbac.migrate_credential(apps, None) + # Admin permissions post migration assert len(migrated) == 1 assert credential.accessible_by(u, permissions['admin']) @@ -33,12 +41,13 @@ def test_credential_migration_team_admin(credential, team, user, permissions): u = user('user', False) team.member_role.members.add(u) credential.team = team + credential.save() # No permissions pre-migration assert not credential.accessible_by(u, permissions['usage']) # Usage permissions post migration - migrated = credential.migrate_to_rbac() + migrated = rbac.migrate_credential(apps, None) assert len(migrated) == 1 assert credential.accessible_by(u, permissions['usage']) From f29fdf694f4983ffdb16d6ff622684b75a940340 Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Mon, 8 Feb 2016 16:05:05 -0500 Subject: [PATCH 4/5] convert Team to django migrations --- awx/main/migrations/0004_rbac_migrations.py | 1 + awx/main/migrations/_rbac.py | 8 ++++++++ awx/main/models/organization.py | 6 ------ awx/main/tests/functional/test_rbac_inventory.py | 10 ++++++---- awx/main/tests/functional/test_rbac_team.py | 8 ++++++-- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/awx/main/migrations/0004_rbac_migrations.py b/awx/main/migrations/0004_rbac_migrations.py index 5d02d6bd00..1f9757139a 100644 --- a/awx/main/migrations/0004_rbac_migrations.py +++ b/awx/main/migrations/0004_rbac_migrations.py @@ -14,4 +14,5 @@ class Migration(migrations.Migration): operations = [ migrations.RunPython(rbac.migrate_organization), migrations.RunPython(rbac.migrate_credential), + migrations.RunPython(rbac.migrate_team), ] diff --git a/awx/main/migrations/_rbac.py b/awx/main/migrations/_rbac.py index b0403b1a0d..05b056c0cd 100644 --- a/awx/main/migrations/_rbac.py +++ b/awx/main/migrations/_rbac.py @@ -12,6 +12,14 @@ def migrate_organization(apps, schema_editor): migrations[org.name].append(user) return migrations +def migrate_team(apps, schema_editor): + migrations = defaultdict(list) + team = apps.get_model('main', 'Team') + for t in team.objects.all(): + for user in t.users.all(): + t.member_role.members.add(user) + migrations[t.name].append(user) + return migrations def migrate_credential(apps, schema_editor): migrations = defaultdict(list) diff --git a/awx/main/models/organization.py b/awx/main/models/organization.py index 62636e42e6..5b24b304bd 100644 --- a/awx/main/models/organization.py +++ b/awx/main/models/organization.py @@ -134,12 +134,6 @@ class Team(CommonModelNameNotUnique, ResourceMixin): cred.mark_inactive() super(Team, self).mark_inactive(save=save) - def migrate_to_rbac(self): - migrated = [] - for user in self.users.all(): - self.member_role.members.add(user) - migrated.append(user) - return migrated class Permission(CommonModelNameNotUnique): ''' diff --git a/awx/main/tests/functional/test_rbac_inventory.py b/awx/main/tests/functional/test_rbac_inventory.py index 478de37d18..7297aaa2a5 100644 --- a/awx/main/tests/functional/test_rbac_inventory.py +++ b/awx/main/tests/functional/test_rbac_inventory.py @@ -1,6 +1,8 @@ import pytest +from awx.main.migrations import _rbac as rbac from awx.main.models import Permission +from django.apps import apps @pytest.mark.django_db def test_inventory_admin_user(inventory, permissions, user): @@ -82,7 +84,7 @@ def test_inventory_admin_team(inventory, permissions, user, team): assert inventory.accessible_by(u, permissions['admin']) is False - team_migrations = team.migrate_to_rbac() + team_migrations = rbac.migrate_team(apps, None) migrations = inventory.migrate_to_rbac() assert len(team_migrations) == 1 @@ -107,7 +109,7 @@ def test_inventory_auditor(inventory, permissions, user, team): assert inventory.accessible_by(u, permissions['admin']) is False assert inventory.accessible_by(u, permissions['auditor']) is False - team_migrations = team.migrate_to_rbac() + team_migrations = rbac.migrate_team(apps,None) migrations = inventory.migrate_to_rbac() assert len(team_migrations) == 1 @@ -131,7 +133,7 @@ def test_inventory_updater(inventory, permissions, user, team): assert inventory.accessible_by(u, permissions['admin']) is False assert inventory.accessible_by(u, permissions['auditor']) is False - team_migrations = team.migrate_to_rbac() + team_migrations = rbac.migrate_team(apps,None) migrations = inventory.migrate_to_rbac() assert len(team_migrations) == 1 @@ -156,7 +158,7 @@ def test_inventory_executor(inventory, permissions, user, team): assert inventory.accessible_by(u, permissions['admin']) is False assert inventory.accessible_by(u, permissions['auditor']) is False - team_migrations = team.migrate_to_rbac() + team_migrations = rbac.migrate_team(apps, None) migrations = inventory.migrate_to_rbac() assert len(team_migrations) == 1 diff --git a/awx/main/tests/functional/test_rbac_team.py b/awx/main/tests/functional/test_rbac_team.py index 42356783f3..72e26d0c37 100644 --- a/awx/main/tests/functional/test_rbac_team.py +++ b/awx/main/tests/functional/test_rbac_team.py @@ -1,13 +1,17 @@ import pytest +from awx.main.migrations import _rbac as rbac +from django.apps import apps + @pytest.mark.django_db def test_team_migration_user(team, user, permissions): u = user('user', False) team.users.add(u) + team.save() assert not team.accessible_by(u, permissions['auditor']) - migrated = team.migrate_to_rbac() + migrated = rbac.migrate_team(apps, None) + assert len(migrated) == 1 assert team.accessible_by(u, permissions['auditor']) - From e71de34cc1304e03434c3a8b566fae4787a2920b Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Mon, 8 Feb 2016 16:22:41 -0500 Subject: [PATCH 5/5] convert Inventory to django migrations --- awx/main/migrations/0004_rbac_migrations.py | 1 + awx/main/migrations/_rbac.py | 43 +++++++++++++++++ awx/main/models/inventory.py | 42 ---------------- .../tests/functional/test_rbac_inventory.py | 48 +++++++++---------- 4 files changed, 68 insertions(+), 66 deletions(-) diff --git a/awx/main/migrations/0004_rbac_migrations.py b/awx/main/migrations/0004_rbac_migrations.py index 1f9757139a..31bb92af98 100644 --- a/awx/main/migrations/0004_rbac_migrations.py +++ b/awx/main/migrations/0004_rbac_migrations.py @@ -15,4 +15,5 @@ class Migration(migrations.Migration): migrations.RunPython(rbac.migrate_organization), migrations.RunPython(rbac.migrate_credential), migrations.RunPython(rbac.migrate_team), + migrations.RunPython(rbac.migrate_inventory), ] diff --git a/awx/main/migrations/_rbac.py b/awx/main/migrations/_rbac.py index 05b056c0cd..d2bddc8302 100644 --- a/awx/main/migrations/_rbac.py +++ b/awx/main/migrations/_rbac.py @@ -33,3 +33,46 @@ def migrate_credential(apps, schema_editor): cred.usage_role.parents.add(cred.team.member_role) migrations[cred.name].append(cred.team) return migrations + +def migrate_inventory(apps, schema_editor): + migrations = defaultdict(dict) + + Inventory = apps.get_model('main', 'Inventory') + Permission = apps.get_model('main', 'Permission') + + for inventory in Inventory.objects.all(): + teams, users = [], [] + for perm in Permission.objects.filter(inventory=inventory): + role = None + execrole = None + if perm.permission_type == 'admin': + role = inventory.admin_role + pass + elif perm.permission_type == 'read': + role = inventory.auditor_role + pass + elif perm.permission_type == 'write': + role = inventory.updater_role + pass + else: + raise Exception('Unhandled permission type for inventory: %s' % perm.permission_type) + if perm.run_ad_hoc_commands: + execrole = inventory.executor_role + + if perm.team: + if role: + perm.team.member_role.children.add(role) + if execrole: + perm.team.member_role.children.add(execrole) + + teams.append(perm.team) + + if perm.user: + if role: + role.members.add(perm.user) + if execrole: + execrole.members.add(perm.user) + users.append(perm.user) + migrations[inventory.name]['teams'] = teams + migrations[inventory.name]['users'] = users + return migrations diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index a31dd76bb9..ead6104870 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -113,48 +113,6 @@ class Inventory(CommonModel, ResourceMixin): role_name='Inventory Executor', ) - def migrate_to_rbac(self): - migrated_users = [] - migrated_teams = [] - - for perm in Permission.objects.filter(inventory=self): - role = None - execrole = None - if perm.permission_type == 'admin': - role = self.admin_role - pass - elif perm.permission_type == 'read': - role = self.auditor_role - pass - elif perm.permission_type == 'write': - role = self.updater_role - pass - else: - raise Exception('Unhandled permission type for inventory: %s' % perm.permission_type) - if perm.run_ad_hoc_commands: - execrole = self.executor_role - - if perm.team: - if role: - perm.team.member_role.children.add(role) - if execrole: - perm.team.member_role.children.add(execrole) - - migrated_teams.append(perm.team) - - if perm.user: - if role: - role.members.add(perm.user) - if execrole: - execrole.members.add(perm.user) - migrated_users.append(perm.user) - - return { - 'migrated_users': migrated_users, - 'migrated_teams': migrated_teams, - } - - def get_absolute_url(self): return reverse('api:inventory_detail', args=(self.pk,)) diff --git a/awx/main/tests/functional/test_rbac_inventory.py b/awx/main/tests/functional/test_rbac_inventory.py index 7297aaa2a5..3d15584afd 100644 --- a/awx/main/tests/functional/test_rbac_inventory.py +++ b/awx/main/tests/functional/test_rbac_inventory.py @@ -12,10 +12,10 @@ def test_inventory_admin_user(inventory, permissions, user): assert inventory.accessible_by(u, permissions['admin']) is False - migrations = inventory.migrate_to_rbac() + migrations = rbac.migrate_inventory(apps, None) - assert len(migrations['migrated_users']) == 1 - assert len(migrations['migrated_teams']) == 0 + assert len(migrations[inventory.name]['users']) == 1 + assert len(migrations[inventory.name]['teams']) == 0 assert inventory.accessible_by(u, permissions['admin']) assert inventory.executor_role.members.filter(id=u.id).exists() is False assert inventory.updater_role.members.filter(id=u.id).exists() is False @@ -29,10 +29,10 @@ def test_inventory_auditor_user(inventory, permissions, user): assert inventory.accessible_by(u, permissions['admin']) is False assert inventory.accessible_by(u, permissions['auditor']) is False - migrations = inventory.migrate_to_rbac() + migrations = rbac.migrate_inventory(apps, None) - assert len(migrations['migrated_users']) == 1 - assert len(migrations['migrated_teams']) == 0 + assert len(migrations[inventory.name]['users']) == 1 + assert len(migrations[inventory.name]['teams']) == 0 assert inventory.accessible_by(u, permissions['admin']) is False assert inventory.accessible_by(u, permissions['auditor']) is True assert inventory.executor_role.members.filter(id=u.id).exists() is False @@ -47,10 +47,10 @@ def test_inventory_updater_user(inventory, permissions, user): assert inventory.accessible_by(u, permissions['admin']) is False assert inventory.accessible_by(u, permissions['auditor']) is False - migrations = inventory.migrate_to_rbac() + migrations = rbac.migrate_inventory(apps, None) - assert len(migrations['migrated_users']) == 1 - assert len(migrations['migrated_teams']) == 0 + assert len(migrations[inventory.name]['users']) == 1 + assert len(migrations[inventory.name]['teams']) == 0 assert inventory.accessible_by(u, permissions['admin']) is False assert inventory.executor_role.members.filter(id=u.id).exists() is False assert inventory.updater_role.members.filter(id=u.id).exists() @@ -64,10 +64,10 @@ def test_inventory_executor_user(inventory, permissions, user): assert inventory.accessible_by(u, permissions['admin']) is False assert inventory.accessible_by(u, permissions['auditor']) is False - migrations = inventory.migrate_to_rbac() + migrations = rbac.migrate_inventory(apps, None) - assert len(migrations['migrated_users']) == 1 - assert len(migrations['migrated_teams']) == 0 + assert len(migrations[inventory.name]['users']) == 1 + assert len(migrations[inventory.name]['teams']) == 0 assert inventory.accessible_by(u, permissions['admin']) is False assert inventory.accessible_by(u, permissions['auditor']) is True assert inventory.executor_role.members.filter(id=u.id).exists() @@ -85,12 +85,12 @@ def test_inventory_admin_team(inventory, permissions, user, team): assert inventory.accessible_by(u, permissions['admin']) is False team_migrations = rbac.migrate_team(apps, None) - migrations = inventory.migrate_to_rbac() + migrations = rbac.migrate_inventory(apps, None) assert len(team_migrations) == 1 assert team.member_role.members.count() == 1 - assert len(migrations['migrated_users']) == 0 - assert len(migrations['migrated_teams']) == 1 + assert len(migrations[inventory.name]['users']) == 0 + assert len(migrations[inventory.name]['teams']) == 1 assert inventory.admin_role.members.filter(id=u.id).exists() is False assert inventory.auditor_role.members.filter(id=u.id).exists() is False assert inventory.executor_role.members.filter(id=u.id).exists() is False @@ -110,12 +110,12 @@ def test_inventory_auditor(inventory, permissions, user, team): assert inventory.accessible_by(u, permissions['auditor']) is False team_migrations = rbac.migrate_team(apps,None) - migrations = inventory.migrate_to_rbac() + migrations = rbac.migrate_inventory(apps, None) assert len(team_migrations) == 1 assert team.member_role.members.count() == 1 - assert len(migrations['migrated_users']) == 0 - assert len(migrations['migrated_teams']) == 1 + assert len(migrations[inventory.name]['users']) == 0 + assert len(migrations[inventory.name]['teams']) == 1 assert inventory.admin_role.members.filter(id=u.id).exists() is False assert inventory.auditor_role.members.filter(id=u.id).exists() is False assert inventory.executor_role.members.filter(id=u.id).exists() is False @@ -134,12 +134,12 @@ def test_inventory_updater(inventory, permissions, user, team): assert inventory.accessible_by(u, permissions['auditor']) is False team_migrations = rbac.migrate_team(apps,None) - migrations = inventory.migrate_to_rbac() + migrations = rbac.migrate_inventory(apps, None) assert len(team_migrations) == 1 assert team.member_role.members.count() == 1 - assert len(migrations['migrated_users']) == 0 - assert len(migrations['migrated_teams']) == 1 + assert len(migrations[inventory.name]['users']) == 0 + assert len(migrations[inventory.name]['teams']) == 1 assert inventory.admin_role.members.filter(id=u.id).exists() is False assert inventory.auditor_role.members.filter(id=u.id).exists() is False assert inventory.executor_role.members.filter(id=u.id).exists() is False @@ -159,12 +159,12 @@ def test_inventory_executor(inventory, permissions, user, team): assert inventory.accessible_by(u, permissions['auditor']) is False team_migrations = rbac.migrate_team(apps, None) - migrations = inventory.migrate_to_rbac() + migrations = rbac.migrate_inventory(apps, None) assert len(team_migrations) == 1 assert team.member_role.members.count() == 1 - assert len(migrations['migrated_users']) == 0 - assert len(migrations['migrated_teams']) == 1 + assert len(migrations[inventory.name]['users']) == 0 + assert len(migrations[inventory.name]['teams']) == 1 assert inventory.admin_role.members.filter(id=u.id).exists() is False assert inventory.auditor_role.members.filter(id=u.id).exists() is False assert inventory.executor_role.members.filter(id=u.id).exists() is False