Merge pull request #1904 from anoek/migration-fixes

Job template migration fixes
This commit is contained in:
Akita Noek 2016-05-12 16:33:24 -04:00
commit 6d871afd4a
4 changed files with 100 additions and 40 deletions

View File

@ -813,6 +813,8 @@ class JobTemplateAccess(BaseAccess):
def can_change(self, obj, data):
data_for_change = data
if self.user not in obj.admin_role:
return False
if data is not None:
data_for_change = dict(data)
for required_field in ('credential', 'cloud_credential', 'inventory', 'project'):
@ -822,12 +824,7 @@ class JobTemplateAccess(BaseAccess):
return self.can_read(obj) and self.can_add(data_for_change)
def can_delete(self, obj):
add_obj = dict(credential=obj.credential.id if obj.credential is not None else None,
cloud_credential=obj.cloud_credential.id if obj.cloud_credential is not None else None,
inventory=obj.inventory.id if obj.inventory is not None else None,
project=obj.project.id if obj.project is not None else None,
job_type=obj.job_type)
return self.can_add(add_obj)
return self.user in obj.admin_role
class JobAccess(BaseAccess):
@ -841,9 +838,7 @@ class JobAccess(BaseAccess):
if self.user.is_superuser:
return qs.all()
credential_ids = self.user.get_queryset(Credential)
return qs.filter(
credential_id__in=credential_ids,
job_template__in=JobTemplate.accessible_objects(self.user, 'read_role')
)

View File

@ -686,7 +686,7 @@ class ProjectAccess(BaseAccess):
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))
team_ids = Team.objects.filter(deprecated_users__in=[self.user])
qs = qs.filter(Q(created_by=self.user, deprecated_organizations__isnull=True) |
Q(deprecated_organizations__deprecated_admins__in=[self.user]) |
Q(deprecated_organizations__deprecated_users__in=[self.user]) |
@ -694,17 +694,17 @@ class ProjectAccess(BaseAccess):
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(
deploy_permissions = Permission.objects.filter(
Q(user=self.user) | Q(team_id__in=team_ids),
permission_type__in=allowed_deploy,
).values_list('id', flat=True))
check_permissions_ids = set(Permission.objects.filter(
)
check_permissions = Permission.objects.filter(
Q(user=self.user) | Q(team_id__in=team_ids),
permission_type__in=allowed_check,
).values_list('id', flat=True))
)
perm_deploy_qs = qs.filter(permissions__in=deploy_permissions_ids)
perm_check_qs = qs.filter(permissions__in=check_permissions_ids)
perm_deploy_qs = qs.filter(permissions__in=deploy_permissions)
perm_check_qs = qs.filter(permissions__in=check_permissions)
return qs | perm_deploy_qs | perm_check_qs
def can_add(self, data):
@ -1047,8 +1047,10 @@ class JobTemplateAccess(BaseAccess):
obj.job_type == PERM_INVENTORY_CHECK:
has_perm = True
dep_access = check_user_access(self.user, Inventory, 'read', obj.inventory) and check_user_access(self.user, Project, 'read', obj.project)
return dep_access and has_perm
return \
has_perm and \
check_user_access(self.user, Inventory, 'read', obj.inventory) and \
check_user_access(self.user, Project, 'read', obj.project)
def can_change(self, obj, data):
data_for_change = data

View File

@ -8,7 +8,6 @@ from collections import defaultdict
from awx.main.utils import getattrd
from awx.main.models.rbac import Role, batch_role_ancestor_rebuilding
import _old_access as old_access
logger = logging.getLogger(__name__)
def log_migration(wrapped):
@ -150,7 +149,12 @@ def _discover_credentials(instances, cred, orgfunc):
pass
if len(orgs) == 1:
_update_credential_parents(orgfunc(instances[0]), cred)
try:
_update_credential_parents(orgfunc(instances[0]), cred)
except AttributeError:
# JobTemplate.inventory can be NULL sometimes, eg when an inventory
# has been deleted. This protects against that.
pass
else:
for pos, org in enumerate(orgs):
if pos == 0:
@ -382,33 +386,81 @@ def migrate_job_templates(apps, schema_editor):
JobTemplate = apps.get_model('main', 'JobTemplate')
Team = apps.get_model('main', 'Team')
Permission = apps.get_model('main', 'Permission')
Credential = apps.get_model('main', 'Credential')
for jt in JobTemplate.objects.iterator():
permission = Permission.objects.filter(
jt_queryset = JobTemplate.objects.select_related('inventory', 'project', 'inventory__organization', 'execute_role')
for jt in jt_queryset.iterator():
jt_permission_qs = Permission.objects.filter(
inventory=jt.inventory,
project=jt.project,
permission_type__in=['create', 'check', 'run'] if jt.job_type == 'check' else ['create', 'run'],
)
for team in Team.objects.iterator():
if permission.filter(team=team).exists():
inventory_permission_qs = Permission.objects.filter(
inventory=jt.inventory,
project__isnull=True,
)
team_create_permissions = set(
jt_permission_qs
.filter(permission_type__in=['create'] if jt.job_type == 'check' else ['create'])
.values_list('team__id', flat=True)
)
team_run_permissions = set(
jt_permission_qs
.filter(permission_type__in=['check', 'run'] if jt.job_type == 'check' else ['run'])
.values_list('team__id', flat=True)
)
user_create_permissions = set(
jt_permission_qs
.filter(permission_type__in=['create'] if jt.job_type == 'check' else ['run'])
.values_list('user__id', flat=True)
)
user_run_permissions = set(
jt_permission_qs
.filter(permission_type__in=['check', 'run'] if jt.job_type == 'check' else ['create'])
.values_list('user__id', flat=True)
)
team_inv_permissions = defaultdict(set)
user_inv_permissions = defaultdict(set)
for user_id, team_id, inventory_id in inventory_permission_qs.values_list('user_id', 'team_id', 'inventory_id'):
if user_id:
user_inv_permissions[user_id].add(inventory_id)
if team_id:
team_inv_permissions[team_id].add(inventory_id)
for team in Team.objects.filter(id__in=team_create_permissions).iterator():
if jt.inventory.id in team_inv_permissions[team.id] and \
((not jt.credential and not jt.cloud_credential) or
Credential.objects.filter(deprecated_team=team, jobtemplates=jt).exists()):
team.member_role.children.add(jt.admin_role)
logger.info(smart_text(u'transfering admin access on JobTemplate({}) to Team({})'.format(jt.name, team.name)))
for team in Team.objects.filter(id__in=team_run_permissions).iterator():
if jt.inventory.id in team_inv_permissions[team.id] and \
((not jt.credential and not jt.cloud_credential) or
Credential.objects.filter(deprecated_team=team, jobtemplates=jt).exists()):
team.member_role.children.add(jt.execute_role)
logger.info(smart_text(u'adding Team({}) access to JobTemplate({})'.format(team.name, jt.name)))
logger.info(smart_text(u'transfering execute access on JobTemplate({}) to Team({})'.format(jt.name, team.name)))
for user in User.objects.iterator():
if permission.filter(user=user).exists():
for user in User.objects.filter(id__in=user_create_permissions).iterator():
if (jt.inventory.id in user_inv_permissions[user.id] or
any([jt.inventory.id in team_inv_permissions[team.id] for team in user.deprecated_teams.all()])) and \
((not jt.credential and not jt.cloud_credential) or
Credential.objects.filter(Q(deprecated_user=user) | Q(deprecated_team__deprecated_users=user), jobtemplates=jt).exists()):
jt.admin_role.members.add(user)
logger.info(smart_text(u'transfering admin access on JobTemplate({}) to User({})'.format(jt.name, user.username)))
for user in User.objects.filter(id__in=user_run_permissions).iterator():
if (jt.inventory.id in user_inv_permissions[user.id] or
any([jt.inventory.id in team_inv_permissions[team.id] for team in user.deprecated_teams.all()])) and \
((not jt.credential and not jt.cloud_credential) or
Credential.objects.filter(Q(deprecated_user=user) | Q(deprecated_team__deprecated_users=user), jobtemplates=jt).exists()):
jt.execute_role.members.add(user)
logger.info(smart_text(u'adding User({}) access to JobTemplate({})'.format(user.username, jt.name)))
logger.info(smart_text(u'transfering execute access on JobTemplate({}) to User({})'.format(jt.name, user.username)))
if jt.execute_role.ancestors.filter(members=user).exists(): # aka "user in jt.execute_role"
# If the job template is already accessible by the user, because they
# are a sytem, organization, or project admin, then don't add an explicit
# role entry for them
continue
if old_access.check_user_access(user, jt.__class__, 'start', jt, False):
jt.execute_role.members.add(user)
logger.info(smart_text(u'adding User({}) access to JobTemplate({})'.format(user.username, jt.name)))
@log_migration
def rebuild_role_hierarchy(apps, schema_editor):

View File

@ -11,10 +11,12 @@ from django.apps import apps
@pytest.mark.django_db
def test_job_template_migration_check(deploy_jobtemplate, check_jobtemplate, user):
def test_job_template_migration_check(credential, deploy_jobtemplate, check_jobtemplate, user):
admin = user('admin', is_superuser=True)
joe = user('joe')
credential.deprecated_user = joe
credential.save()
check_jobtemplate.project.organization.deprecated_users.add(joe)
@ -22,6 +24,7 @@ def test_job_template_migration_check(deploy_jobtemplate, check_jobtemplate, use
Permission(user=joe, inventory=check_jobtemplate.inventory,
project=check_jobtemplate.project, permission_type='check').save()
rbac.migrate_users(apps, None)
rbac.migrate_organization(apps, None)
rbac.migrate_projects(apps, None)
@ -39,10 +42,12 @@ def test_job_template_migration_check(deploy_jobtemplate, check_jobtemplate, use
assert joe not in deploy_jobtemplate.execute_role
@pytest.mark.django_db
def test_job_template_migration_deploy(deploy_jobtemplate, check_jobtemplate, user):
def test_job_template_migration_deploy(credential, deploy_jobtemplate, check_jobtemplate, user):
admin = user('admin', is_superuser=True)
joe = user('joe')
credential.deprecated_user = joe
credential.save()
deploy_jobtemplate.project.organization.deprecated_users.add(joe)
@ -68,13 +73,16 @@ def test_job_template_migration_deploy(deploy_jobtemplate, check_jobtemplate, us
@pytest.mark.django_db
def test_job_template_team_migration_check(deploy_jobtemplate, check_jobtemplate, organization, team, user):
def test_job_template_team_migration_check(credential, deploy_jobtemplate, check_jobtemplate, organization, team, user):
admin = user('admin', is_superuser=True)
joe = user('joe')
team.deprecated_users.add(joe)
team.organization = organization
team.save()
credential.deprecated_team = team
credential.save()
check_jobtemplate.project.organization.deprecated_users.add(joe)
Permission(team=team, inventory=check_jobtemplate.inventory, permission_type='read').save()
@ -101,13 +109,16 @@ def test_job_template_team_migration_check(deploy_jobtemplate, check_jobtemplate
@pytest.mark.django_db
def test_job_template_team_deploy_migration(deploy_jobtemplate, check_jobtemplate, organization, team, user):
def test_job_template_team_deploy_migration(credential, deploy_jobtemplate, check_jobtemplate, organization, team, user):
admin = user('admin', is_superuser=True)
joe = user('joe')
team.deprecated_users.add(joe)
team.organization = organization
team.save()
credential.deprecated_team = team
credential.save()
deploy_jobtemplate.project.organization.deprecated_users.add(joe)
Permission(team=team, inventory=deploy_jobtemplate.inventory, permission_type='read').save()