diff --git a/awx/main/fields.py b/awx/main/fields.py index 650edb55e0..90f94b734c 100644 --- a/awx/main/fields.py +++ b/awx/main/fields.py @@ -17,10 +17,11 @@ from django.db.models.fields.related import ( ReverseManyRelatedObjectsDescriptor, ) from django.utils.encoding import smart_text +from django.utils.timezone import now # AWX -from awx.main.models.rbac import RolePermission, Role, batch_role_ancestor_rebuilding - +from awx.main.models.rbac import Role, batch_role_ancestor_rebuilding +from awx.main.utils import get_current_apps __all__ = ['AutoOneToOneField', 'ImplicitRoleField'] @@ -65,8 +66,12 @@ def resolve_role_field(obj, field): else: return [] + if obj is None: + return [] + if len(field_components) == 1: - if type(obj) is not ImplicitRoleDescriptor and type(obj) is not Role: + Role_ = get_current_apps().get_model('main', 'Role') + if type(obj) is not ImplicitRoleDescriptor and type(obj) is not Role_: raise Exception(smart_text('{} refers to a {}, not an ImplicitRoleField or Role'.format(field, type(obj)))) ret.append(obj) else: @@ -174,7 +179,10 @@ class ImplicitRoleField(models.ForeignKey): role = getattr(instance, self.name, None) if role: return role - role = Role.objects.create( + Role_ = get_current_apps().get_model('main', 'Role') + role = Role_.objects.create( + created=now(), + modified=now(), name=self.role_name, description=self.role_description ) @@ -186,9 +194,16 @@ class ImplicitRoleField(models.ForeignKey): role.save() if self.permissions is not None: - permissions = RolePermission( + RolePermission_ = get_current_apps().get_model('main', 'RolePermission') + ContentType = get_current_apps().get_model('contenttypes', "ContentType") + instance_content_type = ContentType.objects.get_for_model(instance) + + permissions = RolePermission_( + created=now(), + modified=now(), role=role, - resource=instance, + content_type=instance_content_type, + object_id=instance.id, auto_generated=True ) @@ -253,7 +268,20 @@ class ImplicitRoleField(models.ForeignKey): parent_roles = set() for path in paths: if path.startswith("singleton:"): - parents = [Role.singleton(path[10:])] + singleton_name = path[10:] + Role_ = get_current_apps().get_model('main', 'Role') + qs = Role_.objects.filter(singleton_name=singleton_name) + if qs.count() >= 1: + role = qs[0] + else: + role = Role_.objects.create( + created=now(), + modified=now(), + singleton_name=singleton_name, + name=singleton_name, + description=singleton_name + ) + parents = [role] else: parents = resolve_role_field(instance, path) for parent in parents: diff --git a/awx/main/migrations/0009_v300_rbac_migrations.py b/awx/main/migrations/0009_v300_rbac_migrations.py index b652c1067a..9c7f7d8dd7 100644 --- a/awx/main/migrations/0009_v300_rbac_migrations.py +++ b/awx/main/migrations/0009_v300_rbac_migrations.py @@ -12,6 +12,7 @@ class Migration(migrations.Migration): ] operations = [ + migrations.RunPython(rbac.init_rbac_migration), migrations.RunPython(rbac.migrate_users), migrations.RunPython(rbac.migrate_organization), migrations.RunPython(rbac.migrate_team), diff --git a/awx/main/migrations/_rbac.py b/awx/main/migrations/_rbac.py index 85f2d3fd7d..de09d06fd1 100644 --- a/awx/main/migrations/_rbac.py +++ b/awx/main/migrations/_rbac.py @@ -5,7 +5,7 @@ from django.db.models import Q from django.utils.timezone import now from collections import defaultdict -from awx.main.utils import getattrd +from awx.main.utils import getattrd, set_current_apps import _old_access as old_access logger = logging.getLogger(__name__) @@ -26,6 +26,10 @@ def log_migration(wrapped): return wrapped(*args, **kwargs) return wrapper +@log_migration +def init_rbac_migration(apps, schema_editor): + set_current_apps(apps) + @log_migration def migrate_users(apps, schema_editor): User = apps.get_model('auth', "User") diff --git a/awx/main/utils.py b/awx/main/utils.py index dea2155597..f1d85f72b2 100644 --- a/awx/main/utils.py +++ b/awx/main/utils.py @@ -20,6 +20,7 @@ import tempfile from rest_framework.exceptions import ParseError, PermissionDenied from django.utils.encoding import smart_str from django.core.urlresolvers import reverse +from django.apps import apps # PyCrypto from Crypto.Cipher import AES @@ -30,7 +31,8 @@ __all__ = ['get_object_or_400', 'get_object_or_403', 'camelcase_to_underscore', 'get_ansible_version', 'get_ssh_version', 'get_awx_version', 'update_scm_url', 'get_type_for_model', 'get_model_for_type', 'to_python_boolean', 'ignore_inventory_computed_fields', 'ignore_inventory_group_removal', - '_inventory_updates', 'get_pk_from_dict', 'getattrd', 'NoDefaultProvided'] + '_inventory_updates', 'get_pk_from_dict', 'getattrd', 'NoDefaultProvided', + 'get_current_apps', 'set_current_apps'] def get_object_or_400(klass, *args, **kwargs): @@ -556,3 +558,11 @@ def getattrd(obj, name, default=NoDefaultProvided): return default raise +current_apps = apps +def set_current_apps(apps): + global current_apps + current_apps = apps + +def get_current_apps(): + global current_apps + return current_apps