1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-31 15:21:13 +03:00

Make use of 'current' apps so RBAC ImplicitRoleField can work during migrations

While a migration is taking place, we can't juse use normal model
references like Role and RolePermission, nor can we use generic foreign
keys without manually referring to the content type and object id
fields.
This commit is contained in:
Akita Noek 2016-04-10 11:57:39 -04:00
parent 682552d9b0
commit 7d2e660749
4 changed files with 52 additions and 9 deletions

View File

@ -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:

View File

@ -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),

View File

@ -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")

View File

@ -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