mirror of
https://github.com/ansible/awx.git
synced 2026-01-13 11:00:03 -03:30
Merge pull request #1560 from anoek/11th-hour
RBAC RolePermission removal updates
This commit is contained in:
commit
969782fdca
@ -13,6 +13,7 @@ from django.shortcuts import get_object_or_404
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.encoding import smart_text
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
# Django REST Framework
|
||||
from rest_framework.authentication import get_authorization_header
|
||||
@ -475,7 +476,9 @@ class ResourceAccessList(ListAPIView):
|
||||
resource_model = getattr(self, 'resource_model')
|
||||
obj = resource_model.objects.get(pk=self.object_id)
|
||||
|
||||
roles = set([p.role for p in obj.role_permissions.all()])
|
||||
content_type = ContentType.objects.get_for_model(obj)
|
||||
roles = set(Role.objects.filter(content_type=content_type, object_id=obj.id))
|
||||
|
||||
ancestors = set()
|
||||
for r in roles:
|
||||
ancestors.update(set(r.ancestors.all()))
|
||||
|
||||
@ -1485,7 +1485,7 @@ class ResourceAccessListElementSerializer(UserSerializer):
|
||||
|
||||
if 'summary_fields' not in ret:
|
||||
ret['summary_fields'] = {}
|
||||
ret['summary_fields']['permissions'] = get_user_permissions_on_resource(obj, user)
|
||||
ret['summary_fields']['permissions'] = get_roles_on_resource(obj, user)
|
||||
|
||||
def format_role_perm(role):
|
||||
role_dict = { 'id': role.id, 'name': role.name, 'description': role.description}
|
||||
@ -1495,7 +1495,7 @@ class ResourceAccessListElementSerializer(UserSerializer):
|
||||
role_dict['related'] = reverse_gfk(role.content_object)
|
||||
except:
|
||||
pass
|
||||
return { 'role': role_dict, 'permissions': get_role_permissions_on_resource(obj, role)}
|
||||
return { 'role': role_dict, 'permissions': get_roles_on_resource(obj, role)}
|
||||
|
||||
def format_team_role_perm(team_role, permissive_role_ids):
|
||||
role = team_role.children.filter(id__in=permissive_role_ids)[0]
|
||||
@ -1513,13 +1513,15 @@ class ResourceAccessListElementSerializer(UserSerializer):
|
||||
role_dict['related'] = reverse_gfk(role.content_object)
|
||||
except:
|
||||
pass
|
||||
return { 'role': role_dict, 'permissions': get_role_permissions_on_resource(obj, team_role)}
|
||||
return { 'role': role_dict, 'permissions': get_roles_on_resource(obj, team_role)}
|
||||
|
||||
team_content_type = ContentType.objects.get_for_model(Team)
|
||||
content_type = ContentType.objects.get_for_model(obj)
|
||||
|
||||
direct_permissive_role_ids = RolePermission.objects.filter(content_type=content_type, object_id=obj.id).values_list('role__id')
|
||||
all_permissive_role_ids = RolePermission.objects.filter(content_type=content_type, object_id=obj.id).values_list('role__ancestors__id')
|
||||
|
||||
content_type = ContentType.objects.get_for_model(obj)
|
||||
direct_permissive_role_ids = Role.objects.filter(content_type=content_type, object_id=obj.id).values_list('id', flat=True)
|
||||
all_permissive_role_ids = Role.objects.filter(content_type=content_type, object_id=obj.id).values_list('ancestors__id', flat=True)
|
||||
|
||||
direct_access_roles = user.roles \
|
||||
.filter(id__in=direct_permissive_role_ids).all()
|
||||
|
||||
@ -220,7 +220,7 @@ class ApiV1ConfigView(APIView):
|
||||
user_ldap_fields.extend(getattr(settings, 'AUTH_LDAP_USER_FLAGS_BY_GROUP', {}).keys())
|
||||
data['user_ldap_fields'] = user_ldap_fields
|
||||
|
||||
if request.user.is_superuser or Organization.accessible_objects(request.user, {'write': True}).exists():
|
||||
if request.user.is_superuser or Organization.accessible_objects(request.user, 'admin_role').exists():
|
||||
data.update(dict(
|
||||
project_base_dir = settings.PROJECTS_ROOT,
|
||||
project_local_paths = Project.get_local_path_choices(),
|
||||
@ -566,7 +566,7 @@ class OrganizationList(ListCreateAPIView):
|
||||
serializer_class = OrganizationSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Organization.accessible_objects(self.request.user, {'read': True})
|
||||
qs = Organization.accessible_objects(self.request.user, 'read_role')
|
||||
qs = qs.select_related('admin_role', 'auditor_role', 'member_role')
|
||||
return qs
|
||||
|
||||
@ -595,27 +595,27 @@ class OrganizationList(ListCreateAPIView):
|
||||
return full_context
|
||||
|
||||
db_results = {}
|
||||
org_qs = self.model.accessible_objects(self.request.user, {"read": True})
|
||||
org_qs = self.model.accessible_objects(self.request.user, 'read_role')
|
||||
org_id_list = org_qs.values('id')
|
||||
if len(org_id_list) == 0:
|
||||
if self.request.method == 'POST':
|
||||
full_context['related_field_counts'] = {}
|
||||
return full_context
|
||||
|
||||
inv_qs = Inventory.accessible_objects(self.request.user, {"read": True})
|
||||
project_qs = Project.accessible_objects(self.request.user, {"read": True})
|
||||
inv_qs = Inventory.accessible_objects(self.request.user, 'read_role')
|
||||
project_qs = Project.accessible_objects(self.request.user, 'read_role')
|
||||
|
||||
# Produce counts of Foreign Key relationships
|
||||
db_results['inventories'] = inv_qs\
|
||||
.values('organization').annotate(Count('organization')).order_by('organization')
|
||||
|
||||
db_results['teams'] = Team.accessible_objects(
|
||||
self.request.user, {"read": True}).values('organization').annotate(
|
||||
self.request.user, 'read_role').values('organization').annotate(
|
||||
Count('organization')).order_by('organization')
|
||||
|
||||
JT_reference = 'project__organization'
|
||||
db_results['job_templates'] = JobTemplate.accessible_objects(
|
||||
self.request.user, {"read": True}).values(JT_reference).annotate(
|
||||
self.request.user, 'read_role').values(JT_reference).annotate(
|
||||
Count(JT_reference)).order_by(JT_reference)
|
||||
|
||||
db_results['projects'] = project_qs\
|
||||
@ -667,7 +667,7 @@ class OrganizationDetail(RetrieveUpdateDestroyAPIView):
|
||||
org_id = int(self.kwargs['pk'])
|
||||
|
||||
org_counts = {}
|
||||
access_kwargs = {'accessor': self.request.user, 'permissions': {"read": True}}
|
||||
access_kwargs = {'accessor': self.request.user, 'role_field': 'read_role'}
|
||||
direct_counts = Organization.objects.filter(id=org_id).annotate(
|
||||
users=Count('member_role__members', distinct=True),
|
||||
admins=Count('admin_role__members', distinct=True)
|
||||
@ -784,8 +784,8 @@ class TeamList(ListCreateAPIView):
|
||||
serializer_class = TeamSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Team.accessible_objects(self.request.user, {'read': True})
|
||||
qs = qs.select_related('admin_role', 'auditor_role', 'member_role')
|
||||
qs = Team.accessible_objects(self.request.user, 'read_role').order_by()
|
||||
qs = qs.select_related('admin_role', 'auditor_role', 'member_role', 'organization')
|
||||
return qs
|
||||
|
||||
class TeamDetail(RetrieveUpdateDestroyAPIView):
|
||||
@ -831,8 +831,8 @@ class TeamProjectsList(SubListAPIView):
|
||||
def get_queryset(self):
|
||||
team = self.get_parent_object()
|
||||
self.check_parent_access(team)
|
||||
team_qs = Project.objects.filter(Q(member_role__parents=team.member_role) | Q(admin_role__parents=team.member_role))
|
||||
user_qs = Project.accessible_objects(self.request.user, {'read': True})
|
||||
team_qs = Project.objects.filter(Q(member_role__parents=team.member_role) | Q(admin_role__parents=team.member_role)).distinct()
|
||||
user_qs = Project.accessible_objects(self.request.user, 'read_role').distinct()
|
||||
return team_qs & user_qs
|
||||
|
||||
|
||||
@ -860,8 +860,8 @@ class TeamActivityStreamList(SubListAPIView):
|
||||
|
||||
qs = self.request.user.get_queryset(self.model)
|
||||
return qs.filter(Q(team=parent) |
|
||||
Q(project__in=Project.accessible_objects(parent, {'read':True})) |
|
||||
Q(credential__in=Credential.accessible_objects(parent, {'read':True})))
|
||||
Q(project__in=Project.accessible_objects(parent, 'read_role')) |
|
||||
Q(credential__in=Credential.accessible_objects(parent, 'read_role')))
|
||||
|
||||
class TeamAccessList(ResourceAccessList):
|
||||
|
||||
@ -875,7 +875,7 @@ class ProjectList(ListCreateAPIView):
|
||||
serializer_class = ProjectSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
projects_qs = Project.accessible_objects(self.request.user, {'read': True})
|
||||
projects_qs = Project.accessible_objects(self.request.user, 'read_role')
|
||||
projects_qs = projects_qs.select_related(
|
||||
'organization',
|
||||
'admin_role',
|
||||
@ -1065,7 +1065,7 @@ class UserTeamsList(ListAPIView):
|
||||
u = get_object_or_404(User, pk=self.kwargs['pk'])
|
||||
if not self.request.user.can_access(User, 'read', u):
|
||||
raise PermissionDenied()
|
||||
return Team.accessible_objects(self.request.user, {'read': True}).filter(member_role__members=u)
|
||||
return Team.accessible_objects(self.request.user, 'read_role').filter(member_role__members=u)
|
||||
|
||||
class UserRolesList(SubListCreateAttachDetachAPIView):
|
||||
|
||||
@ -1103,8 +1103,8 @@ class UserProjectsList(SubListAPIView):
|
||||
def get_queryset(self):
|
||||
parent = self.get_parent_object()
|
||||
self.check_parent_access(parent)
|
||||
my_qs = Project.accessible_objects(self.request.user, {'read': True})
|
||||
user_qs = Project.accessible_objects(parent, {'read': True})
|
||||
my_qs = Project.accessible_objects(self.request.user, 'read_role')
|
||||
user_qs = Project.accessible_objects(parent, 'read_role')
|
||||
return my_qs & user_qs
|
||||
|
||||
class UserOrganizationsList(SubListAPIView):
|
||||
@ -1117,7 +1117,7 @@ class UserOrganizationsList(SubListAPIView):
|
||||
def get_queryset(self):
|
||||
parent = self.get_parent_object()
|
||||
self.check_parent_access(parent)
|
||||
my_qs = Organization.accessible_objects(self.request.user, {'read': True})
|
||||
my_qs = Organization.accessible_objects(self.request.user, 'read_role')
|
||||
user_qs = Organization.objects.filter(member_role__members=parent)
|
||||
return my_qs & user_qs
|
||||
|
||||
@ -1131,7 +1131,7 @@ class UserAdminOfOrganizationsList(SubListAPIView):
|
||||
def get_queryset(self):
|
||||
parent = self.get_parent_object()
|
||||
self.check_parent_access(parent)
|
||||
my_qs = Organization.accessible_objects(self.request.user, {'read': True})
|
||||
my_qs = Organization.accessible_objects(self.request.user, 'read_role')
|
||||
user_qs = Organization.objects.filter(admin_role__members=parent)
|
||||
return my_qs & user_qs
|
||||
|
||||
@ -1217,7 +1217,7 @@ class CredentialList(ListCreateAPIView):
|
||||
organization = Organization.objects.get(pk=request.data['organization'])
|
||||
obj = organization
|
||||
|
||||
if not obj.accessible_by(self.request.user, {'write': True}):
|
||||
if self.request.user not in obj.admin_role:
|
||||
raise PermissionDenied()
|
||||
|
||||
ret = super(CredentialList, self).post(request, *args, **kwargs)
|
||||
@ -1242,8 +1242,8 @@ class UserCredentialsList(CredentialList):
|
||||
if not self.request.user.can_access(User, 'read', user):
|
||||
raise PermissionDenied()
|
||||
|
||||
visible_creds = Credential.accessible_objects(self.request.user, {'read': True})
|
||||
user_creds = Credential.accessible_objects(user, {'read': True})
|
||||
visible_creds = Credential.accessible_objects(self.request.user, 'read_role')
|
||||
user_creds = Credential.accessible_objects(user, 'read_role')
|
||||
return user_creds & visible_creds
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
@ -1262,7 +1262,7 @@ class TeamCredentialsList(CredentialList):
|
||||
if not self.request.user.can_access(Team, 'read', team):
|
||||
raise PermissionDenied()
|
||||
|
||||
visible_creds = Credential.accessible_objects(self.request.user, {'read': True})
|
||||
visible_creds = Credential.accessible_objects(self.request.user, 'read_role')
|
||||
team_creds = Credential.objects.filter(owner_role__parents=team.member_role)
|
||||
return team_creds & visible_creds
|
||||
|
||||
@ -1282,8 +1282,8 @@ class OrganizationCredentialList(CredentialList):
|
||||
if not self.request.user.can_access(Organization, 'read', organization):
|
||||
raise PermissionDenied()
|
||||
|
||||
user_visible = Credential.accessible_objects(self.request.user, {'read': True}).all()
|
||||
org_set = Credential.accessible_objects(organization.admin_role, {'read': True}).all()
|
||||
user_visible = Credential.accessible_objects(self.request.user, 'read_role').all()
|
||||
org_set = Credential.accessible_objects(organization.admin_role, 'read_role').all()
|
||||
|
||||
if self.request.user.is_superuser:
|
||||
return org_set
|
||||
@ -1353,8 +1353,8 @@ class InventoryList(ListCreateAPIView):
|
||||
serializer_class = InventorySerializer
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Inventory.accessible_objects(self.request.user, {'read': True})
|
||||
qs = qs.select_related('admin_role', 'auditor_role', 'updater_role', 'executor_role')
|
||||
qs = Inventory.accessible_objects(self.request.user, 'read_role')
|
||||
qs = qs.select_related('admin_role', 'auditor_role', 'update_role', 'execute_role')
|
||||
return qs
|
||||
|
||||
class InventoryDetail(RetrieveUpdateDestroyAPIView):
|
||||
@ -2120,12 +2120,12 @@ class JobTemplateLaunch(RetrieveAPIView, GenericAPIView):
|
||||
|
||||
if 'credential' in prompted_fields and prompted_fields['credential'] != getattrd(obj, 'credential.pk', None):
|
||||
new_credential = Credential.objects.get(pk=prompted_fields['credential'])
|
||||
if not request.user.can_access(Credential, 'use', new_credential):
|
||||
if request.user not in new_credential.use_role:
|
||||
raise PermissionDenied()
|
||||
|
||||
if 'inventory' in prompted_fields and prompted_fields['inventory'] != getattrd(obj, 'inventory.pk', None):
|
||||
new_inventory = Inventory.objects.get(pk=prompted_fields['inventory'])
|
||||
if not request.user.can_access(Inventory, 'use', new_inventory):
|
||||
if request.user not in new_inventory.use_role:
|
||||
raise PermissionDenied()
|
||||
|
||||
kv = prompted_fields
|
||||
|
||||
@ -18,13 +18,12 @@ from rest_framework.exceptions import ParseError, PermissionDenied
|
||||
from awx.main.utils import * # noqa
|
||||
from awx.main.models import * # noqa
|
||||
from awx.main.models.mixins import ResourceMixin
|
||||
from awx.main.models.rbac import ALL_PERMISSIONS
|
||||
from awx.api.license import LicenseForbids
|
||||
from awx.main.task_engine import TaskSerializer
|
||||
from awx.main.conf import tower_settings
|
||||
|
||||
__all__ = ['get_user_queryset', 'check_user_access',
|
||||
'user_accessible_objects', 'user_accessible_by',
|
||||
'user_accessible_objects',
|
||||
'user_admin_role',]
|
||||
|
||||
PERMISSION_TYPES = [
|
||||
@ -64,19 +63,14 @@ def register_access(model_class, access_class):
|
||||
|
||||
@property
|
||||
def user_admin_role(self):
|
||||
return Role.objects.get(content_type=ContentType.objects.get_for_model(User), object_id=self.id)
|
||||
return Role.objects.get(
|
||||
content_type=ContentType.objects.get_for_model(User),
|
||||
object_id=self.id,
|
||||
role_field='admin_role'
|
||||
)
|
||||
|
||||
def user_accessible_objects(user, permissions):
|
||||
return ResourceMixin._accessible_objects(User, user, permissions)
|
||||
|
||||
def user_accessible_by(instance, user, permissions):
|
||||
perms = get_user_permissions_on_resource(instance, user)
|
||||
if perms is None:
|
||||
return False
|
||||
for k in permissions:
|
||||
if k not in perms or perms[k] < permissions[k]:
|
||||
return False
|
||||
return True
|
||||
def user_accessible_objects(user, role_name):
|
||||
return ResourceMixin._accessible_objects(User, user, role_name)
|
||||
|
||||
def get_user_queryset(user, model_class):
|
||||
'''
|
||||
@ -218,11 +212,18 @@ class UserAccess(BaseAccess):
|
||||
if tower_settings.ORG_ADMINS_CAN_SEE_ALL_USERS and self.user.admin_of_organizations.exists():
|
||||
return User.objects.all()
|
||||
|
||||
viewable_users_set = set()
|
||||
viewable_users_set.update(self.user.roles.values_list('ancestors__members__id', flat=True))
|
||||
viewable_users_set.update(self.user.roles.values_list('descendents__members__id', flat=True))
|
||||
return (
|
||||
User.objects.filter(
|
||||
pk__in=Organization.accessible_objects(self.user, 'read_role').values('member_role__members')
|
||||
) |
|
||||
User.objects.filter(
|
||||
pk=self.user.id
|
||||
) |
|
||||
User.objects.filter(
|
||||
pk__in=Role.objects.filter(singleton_name__in = [ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, ROLE_SINGLETON_SYSTEM_AUDITOR]).values('members')
|
||||
)
|
||||
).distinct()
|
||||
|
||||
return User.objects.filter(id__in=viewable_users_set)
|
||||
|
||||
def can_add(self, data):
|
||||
if data is not None and 'is_superuser' in data:
|
||||
@ -230,7 +231,7 @@ class UserAccess(BaseAccess):
|
||||
return False
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return Organization.accessible_objects(self.user, ALL_PERMISSIONS).exists()
|
||||
return Organization.accessible_objects(self.user, 'admin_role').exists()
|
||||
|
||||
def can_change(self, obj, data):
|
||||
if data is not None and 'is_superuser' in data:
|
||||
@ -257,7 +258,7 @@ class UserAccess(BaseAccess):
|
||||
return False
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return obj.accessible_by(self.user, {'delete': True})
|
||||
return False
|
||||
|
||||
|
||||
class OrganizationAccess(BaseAccess):
|
||||
@ -273,13 +274,13 @@ class OrganizationAccess(BaseAccess):
|
||||
model = Organization
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.accessible_objects(self.user, {'read':True})
|
||||
qs = self.model.accessible_objects(self.user, 'read_role')
|
||||
return qs.select_related('created_by', 'modified_by').all()
|
||||
|
||||
def can_change(self, obj, data):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return obj.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
return self.user in obj.admin_role
|
||||
|
||||
def can_delete(self, obj):
|
||||
self.check_license(feature='multiple_organizations', check_expiration=False)
|
||||
@ -308,29 +309,29 @@ class InventoryAccess(BaseAccess):
|
||||
model = Inventory
|
||||
|
||||
def get_queryset(self, allowed=None, ad_hoc=None):
|
||||
qs = self.model.accessible_objects(self.user, {'read': True})
|
||||
qs = self.model.accessible_objects(self.user, 'read_role')
|
||||
return qs.select_related('created_by', 'modified_by', 'organization').all()
|
||||
|
||||
def can_read(self, obj):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return obj.accessible_by(self.user, {'read': True})
|
||||
return self.user in obj.read_role
|
||||
|
||||
def can_use(self, obj):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return obj.accessible_by(self.user, {'use': True})
|
||||
return self.user in obj.use_role
|
||||
|
||||
def can_add(self, data):
|
||||
# If no data is specified, just checking for generic add permission?
|
||||
if not data:
|
||||
return Organization.accessible_objects(self.user, ALL_PERMISSIONS).exists()
|
||||
return Organization.accessible_objects(self.user, 'admin_role').exists()
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
|
||||
org_pk = get_pk_from_dict(data, 'organization')
|
||||
org = get_object_or_400(Organization, pk=org_pk)
|
||||
return org.accessible_by(self.user, {'read': True, 'create':True, 'update': True, 'delete': True})
|
||||
return self.user in org.admin_role
|
||||
|
||||
def can_change(self, obj, data):
|
||||
# Verify that the user has access to the new organization if moving an
|
||||
@ -338,10 +339,10 @@ class InventoryAccess(BaseAccess):
|
||||
org_pk = get_pk_from_dict(data, 'organization')
|
||||
if obj and org_pk and obj.organization.pk != org_pk:
|
||||
org = get_object_or_400(Organization, pk=org_pk)
|
||||
if not org.accessible_by(self.user, {'read': True, 'create':True, 'update': True, 'delete': True}):
|
||||
if self.user not in org.admin_role:
|
||||
return False
|
||||
# Otherwise, just check for write permission.
|
||||
return obj.accessible_by(self.user, {'read': True, 'create':True, 'update': True, 'delete': True})
|
||||
return self.user in obj.admin_role
|
||||
|
||||
def can_admin(self, obj, data):
|
||||
# Verify that the user has access to the new organization if moving an
|
||||
@ -349,16 +350,16 @@ class InventoryAccess(BaseAccess):
|
||||
org_pk = get_pk_from_dict(data, 'organization')
|
||||
if obj and org_pk and obj.organization.pk != org_pk:
|
||||
org = get_object_or_400(Organization, pk=org_pk)
|
||||
if not org.accessible_by(self.user, ALL_PERMISSIONS):
|
||||
if self.user not in org.admin_role:
|
||||
return False
|
||||
# Otherwise, just check for admin permission.
|
||||
return obj.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
return self.user in obj.admin_role
|
||||
|
||||
def can_delete(self, obj):
|
||||
return self.can_admin(obj, None)
|
||||
|
||||
def can_run_ad_hoc_commands(self, obj):
|
||||
return obj.accessible_by(self.user, {'execute': True})
|
||||
return self.user in obj.adhoc_role
|
||||
|
||||
class HostAccess(BaseAccess):
|
||||
'''
|
||||
@ -369,14 +370,17 @@ class HostAccess(BaseAccess):
|
||||
model = Host
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.accessible_objects(self.user, {'read':True})
|
||||
qs = qs.select_related('created_by', 'modified_by', 'inventory',
|
||||
'last_job__job_template',
|
||||
'last_job_host_summary__job')
|
||||
return qs.prefetch_related('groups').all()
|
||||
inv_qs = Inventory.accessible_objects(self.user, 'read_role')
|
||||
group_qs = Group.accessible_objects(self.user, 'read_role')
|
||||
qs = (self.model.objects.filter(inventory=inv_qs) | self.model.objects.filter(groups=group_qs)).distinct()
|
||||
#qs = qs.select_related('created_by', 'modified_by', 'inventory',
|
||||
# 'last_job__job_template',
|
||||
# 'last_job_host_summary__job')
|
||||
#return qs.prefetch_related('groups').all()
|
||||
return qs
|
||||
|
||||
def can_read(self, obj):
|
||||
return obj and obj.inventory.accessible_by(self.user, {'read':True})
|
||||
return obj and any(self.user in grp.read_role for grp in obj.groups.all()) or self.user in obj.inventory.read_role
|
||||
|
||||
def can_add(self, data):
|
||||
if not data or 'inventory' not in data:
|
||||
@ -385,7 +389,7 @@ class HostAccess(BaseAccess):
|
||||
# Checks for admin or change permission on inventory.
|
||||
inventory_pk = get_pk_from_dict(data, 'inventory')
|
||||
inventory = get_object_or_400(Inventory, pk=inventory_pk)
|
||||
if not inventory.accessible_by(self.user, {'read':True, 'create':True}):
|
||||
if self.user not in inventory.admin_role:
|
||||
return False
|
||||
|
||||
# Check to see if we have enough licenses
|
||||
@ -399,7 +403,7 @@ class HostAccess(BaseAccess):
|
||||
raise PermissionDenied('Unable to change inventory on a host')
|
||||
# Checks for admin or change permission on inventory, controls whether
|
||||
# the user can edit variable data.
|
||||
return obj and obj.inventory.accessible_by(self.user, {'read':True, 'update':True, 'write':True})
|
||||
return obj and self.user in obj.inventory.admin_role
|
||||
|
||||
def can_attach(self, obj, sub_obj, relationship, data,
|
||||
skip_sub_obj_read_check=False):
|
||||
@ -412,7 +416,7 @@ class HostAccess(BaseAccess):
|
||||
return True
|
||||
|
||||
def can_delete(self, obj):
|
||||
return obj and obj.inventory.accessible_by(self.user, {'delete':True})
|
||||
return obj and self.user in obj.inventory.admin_role
|
||||
|
||||
class GroupAccess(BaseAccess):
|
||||
'''
|
||||
@ -423,12 +427,12 @@ class GroupAccess(BaseAccess):
|
||||
model = Group
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.accessible_objects(self.user, {'read':True})
|
||||
qs = self.model.accessible_objects(self.user, 'read_role')
|
||||
qs = qs.select_related('created_by', 'modified_by', 'inventory')
|
||||
return qs.prefetch_related('parents', 'children', 'inventory_source').all()
|
||||
|
||||
def can_read(self, obj):
|
||||
return obj and obj.inventory.accessible_by(self.user, {'read':True})
|
||||
return obj and self.user in obj.inventory.read_role
|
||||
|
||||
def can_add(self, data):
|
||||
if not data or 'inventory' not in data:
|
||||
@ -436,7 +440,7 @@ class GroupAccess(BaseAccess):
|
||||
# Checks for admin or change permission on inventory.
|
||||
inventory_pk = get_pk_from_dict(data, 'inventory')
|
||||
inventory = get_object_or_400(Inventory, pk=inventory_pk)
|
||||
return inventory.accessible_by(self.user, {'read':True, 'create':True})
|
||||
return self.user in inventory.admin_role
|
||||
|
||||
def can_change(self, obj, data):
|
||||
# Prevent moving a group to a different inventory.
|
||||
@ -445,7 +449,7 @@ class GroupAccess(BaseAccess):
|
||||
raise PermissionDenied('Unable to change inventory on a group')
|
||||
# Checks for admin or change permission on inventory, controls whether
|
||||
# the user can attach subgroups or edit variable data.
|
||||
return obj and obj.inventory.accessible_by(self.user, {'read':True, 'update':True, 'write':True})
|
||||
return obj and self.user in obj.inventory.admin_role
|
||||
|
||||
def can_attach(self, obj, sub_obj, relationship, data,
|
||||
skip_sub_obj_read_check=False):
|
||||
@ -466,7 +470,7 @@ class GroupAccess(BaseAccess):
|
||||
return True
|
||||
|
||||
def can_delete(self, obj):
|
||||
return obj and obj.inventory.accessible_by(self.user, {'delete':True})
|
||||
return obj and self.user in obj.inventory.admin_role
|
||||
|
||||
class InventorySourceAccess(BaseAccess):
|
||||
'''
|
||||
@ -485,9 +489,9 @@ class InventorySourceAccess(BaseAccess):
|
||||
|
||||
def can_read(self, obj):
|
||||
if obj and obj.group:
|
||||
return obj.group.accessible_by(self.user, {'read':True})
|
||||
return self.user in obj.group.read_role
|
||||
elif obj and obj.inventory:
|
||||
return obj.inventory.accessible_by(self.user, {'read':True})
|
||||
return self.user in obj.inventory.read_role
|
||||
else:
|
||||
return False
|
||||
|
||||
@ -498,7 +502,7 @@ class InventorySourceAccess(BaseAccess):
|
||||
def can_change(self, obj, data):
|
||||
# Checks for admin or change permission on group.
|
||||
if obj and obj.group:
|
||||
return obj.group.accessible_by(self.user, {'read':True, 'update':True, 'write':True})
|
||||
return self.user in obj.group.admin_role
|
||||
# Can't change inventory sources attached to only the inventory, since
|
||||
# these are created automatically from the management command.
|
||||
else:
|
||||
@ -548,11 +552,11 @@ class CredentialAccess(BaseAccess):
|
||||
"""Return the queryset for credentials, based on what the user is
|
||||
permitted to see.
|
||||
"""
|
||||
qs = self.model.accessible_objects(self.user, {'read':True})
|
||||
qs = self.model.accessible_objects(self.user, 'read_role')
|
||||
return qs.select_related('created_by', 'modified_by').all()
|
||||
|
||||
def can_read(self, obj):
|
||||
return obj.accessible_by(self.user, {'read': True})
|
||||
return self.user in obj.read_role
|
||||
|
||||
def can_add(self, data):
|
||||
# Access enforced in our view where we have context enough to make a decision
|
||||
@ -561,12 +565,12 @@ class CredentialAccess(BaseAccess):
|
||||
def can_use(self, obj):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return obj.accessible_by(self.user, {'use': True})
|
||||
return self.user in obj.use_role
|
||||
|
||||
def can_change(self, obj, data):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return obj.accessible_by(self.user, {'read':True, 'update': True, 'delete':True})
|
||||
return self.user in obj.owner_role
|
||||
|
||||
def can_delete(self, obj):
|
||||
# Unassociated credentials may be marked deleted by anyone, though we
|
||||
@ -579,17 +583,17 @@ class TeamAccess(BaseAccess):
|
||||
'''
|
||||
I can see a team when:
|
||||
- I'm a superuser.
|
||||
- I'm an admin of the team's organization.
|
||||
- I'm an admin of the team
|
||||
- I'm a member of that team.
|
||||
I can create/change a team when:
|
||||
- I'm a superuser.
|
||||
- I'm an org admin for the team's org.
|
||||
- I'm an admin for the team
|
||||
'''
|
||||
|
||||
model = Team
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.accessible_objects(self.user, {'read':True})
|
||||
qs = self.model.accessible_objects(self.user, 'read_role')
|
||||
return qs.select_related('created_by', 'modified_by', 'organization').all()
|
||||
|
||||
def can_add(self, data):
|
||||
@ -598,7 +602,7 @@ class TeamAccess(BaseAccess):
|
||||
else:
|
||||
org_pk = get_pk_from_dict(data, 'organization')
|
||||
org = get_object_or_400(Organization, pk=org_pk)
|
||||
if org.accessible_by(self.user, {'read':True, 'update':True, 'write':True}):
|
||||
if self.user in org.admin_role:
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -607,7 +611,7 @@ class TeamAccess(BaseAccess):
|
||||
org_pk = get_pk_from_dict(data, 'organization')
|
||||
if obj and org_pk and obj.organization.pk != org_pk:
|
||||
raise PermissionDenied('Unable to change organization on a team')
|
||||
return obj.organization.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
return self.user in obj.admin_role
|
||||
|
||||
def can_delete(self, obj):
|
||||
return self.can_change(obj, None)
|
||||
@ -633,19 +637,19 @@ class ProjectAccess(BaseAccess):
|
||||
def get_queryset(self):
|
||||
if self.user.is_superuser:
|
||||
return self.model.objects.all()
|
||||
qs = self.model.accessible_objects(self.user, {'read':True})
|
||||
qs = self.model.accessible_objects(self.user, 'read_role')
|
||||
return qs.select_related('modified_by', 'credential', 'current_job', 'last_job').all()
|
||||
|
||||
def can_add(self, data):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
qs = Organization.accessible_objects(self.user, ALL_PERMISSIONS)
|
||||
qs = Organization.accessible_objects(self.user, 'admin_role')
|
||||
return qs.exists()
|
||||
|
||||
def can_change(self, obj, data):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return obj.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
return self.user in obj.admin_role
|
||||
|
||||
def can_delete(self, obj):
|
||||
return self.can_change(obj, None)
|
||||
@ -674,7 +678,7 @@ class ProjectUpdateAccess(BaseAccess):
|
||||
return self.can_change(obj, {}) and obj.can_cancel
|
||||
|
||||
def can_delete(self, obj):
|
||||
return obj and obj.project.accessible_by(self.user, {'delete':True})
|
||||
return obj and self.user in obj.project.admin_role
|
||||
|
||||
class JobTemplateAccess(BaseAccess):
|
||||
'''
|
||||
@ -695,7 +699,7 @@ class JobTemplateAccess(BaseAccess):
|
||||
if self.user.is_superuser:
|
||||
qs = self.model.objects.all()
|
||||
else:
|
||||
qs = self.model.accessible_objects(self.user, {'read':True})
|
||||
qs = self.model.accessible_objects(self.user, 'read_role')
|
||||
return qs.select_related('created_by', 'modified_by', 'inventory', 'project',
|
||||
'credential', 'cloud_credential', 'next_schedule').all()
|
||||
|
||||
@ -727,7 +731,7 @@ class JobTemplateAccess(BaseAccess):
|
||||
credential_pk = get_pk_from_dict(data, 'credential')
|
||||
if credential_pk:
|
||||
credential = get_object_or_400(Credential, pk=credential_pk)
|
||||
if not credential.accessible_by(self.user, {'read':True}):
|
||||
if self.user not in credential.read_role:
|
||||
return False
|
||||
|
||||
# If a cloud credential is provided, the user should have read access.
|
||||
@ -735,7 +739,7 @@ class JobTemplateAccess(BaseAccess):
|
||||
if cloud_credential_pk:
|
||||
cloud_credential = get_object_or_400(Credential,
|
||||
pk=cloud_credential_pk)
|
||||
if not cloud_credential.accessible_by(self.user, {'read':True}):
|
||||
if self.user not in cloud_credential.read_role:
|
||||
return False
|
||||
|
||||
# Check that the given inventory ID is valid.
|
||||
@ -747,7 +751,7 @@ class JobTemplateAccess(BaseAccess):
|
||||
project_pk = get_pk_from_dict(data, 'project')
|
||||
if 'job_type' in data and data['job_type'] == PERM_INVENTORY_SCAN:
|
||||
org = inventory[0].organization
|
||||
accessible = org.accessible_by(self.user, {'read':True, 'update':True, 'write':True})
|
||||
accessible = self.user in org.admin_role
|
||||
if not project_pk and accessible:
|
||||
return True
|
||||
elif not accessible:
|
||||
@ -755,10 +759,10 @@ class JobTemplateAccess(BaseAccess):
|
||||
# If the user has admin access to the project (as an org admin), should
|
||||
# be able to proceed without additional checks.
|
||||
project = get_object_or_400(Project, pk=project_pk)
|
||||
if project.accessible_by(self.user, ALL_PERMISSIONS):
|
||||
if self.user in project.admin_role:
|
||||
return True
|
||||
|
||||
return project.accessible_by(self.user, ALL_PERMISSIONS) and inventory.accessible_by(self.user, {'read':True})
|
||||
return self.user in project.admin_role and self.user in inventory.read_role
|
||||
|
||||
def can_start(self, obj, validate_license=True):
|
||||
# Check license.
|
||||
@ -776,10 +780,10 @@ class JobTemplateAccess(BaseAccess):
|
||||
if obj.job_type == PERM_INVENTORY_SCAN:
|
||||
# Scan job with default project, must have JT execute or be org admin
|
||||
if obj.project is None and obj.inventory:
|
||||
return (obj.accessible_by(self.user, {'execute': True}) or
|
||||
obj.inventory.organization.accessible_by(self.user, ALL_PERMISSIONS))
|
||||
return (self.user in obj.execute_role or
|
||||
self.user in obj.inventory.organization.admin_role)
|
||||
|
||||
return obj.accessible_by(self.user, {'execute':True})
|
||||
return self.user in obj.execute_role
|
||||
|
||||
def can_change(self, obj, data):
|
||||
data_for_change = data
|
||||
@ -814,7 +818,7 @@ class JobAccess(BaseAccess):
|
||||
credential_ids = self.user.get_queryset(Credential)
|
||||
return qs.filter(
|
||||
credential_id__in=credential_ids,
|
||||
job_template__in=JobTemplate.accessible_objects(self.user, {'read': True})
|
||||
job_template__in=JobTemplate.accessible_objects(self.user, 'read_role')
|
||||
)
|
||||
|
||||
def can_add(self, data):
|
||||
@ -847,7 +851,7 @@ class JobAccess(BaseAccess):
|
||||
# Allow org admins and superusers to delete jobs
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return obj.inventory.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
return self.user in obj.inventory.admin_role
|
||||
|
||||
def can_start(self, obj):
|
||||
self.check_license()
|
||||
@ -859,12 +863,12 @@ class JobAccess(BaseAccess):
|
||||
# If a user can launch the job template then they can relaunch a job from that
|
||||
# job template
|
||||
if obj.job_template is not None:
|
||||
return obj.job_template.accessible_by(self.user, {'execute': True})
|
||||
return self.user in obj.job_template.execute_role
|
||||
|
||||
inventory_access = obj.inventory.accessible_by(self.user, {'use':True})
|
||||
inventory_access = self.user in obj.inventory.use_role
|
||||
|
||||
org_access = obj.inventory.organization.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
project_access = obj.project is None or obj.project.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
org_access = self.user in obj.inventory.organization.admin_role
|
||||
project_access = obj.project is None or self.user in obj.project.admin_role
|
||||
|
||||
return inventory_access and (org_access or project_access)
|
||||
|
||||
@ -906,7 +910,7 @@ class AdHocCommandAccess(BaseAccess):
|
||||
return qs.all()
|
||||
|
||||
credential_ids = set(self.user.get_queryset(Credential).values_list('id', flat=True))
|
||||
inventory_qs = Inventory.accessible_objects(self.user, {'read': True, 'execute': True})
|
||||
inventory_qs = Inventory.accessible_objects(self.user, 'execute_role')
|
||||
|
||||
return qs.filter(credential_id__in=credential_ids,
|
||||
inventory__in=inventory_qs)
|
||||
@ -921,7 +925,7 @@ class AdHocCommandAccess(BaseAccess):
|
||||
credential_pk = get_pk_from_dict(data, 'credential')
|
||||
if credential_pk:
|
||||
credential = get_object_or_400(Credential, pk=credential_pk)
|
||||
if not credential.accessible_by(self.user, {'read':True}):
|
||||
if self.user not in credential.read_role:
|
||||
return False
|
||||
|
||||
# Check that the user has the run ad hoc command permission on the
|
||||
@ -929,7 +933,7 @@ class AdHocCommandAccess(BaseAccess):
|
||||
inventory_pk = get_pk_from_dict(data, 'inventory')
|
||||
if inventory_pk:
|
||||
inventory = get_object_or_400(Inventory, pk=inventory_pk)
|
||||
if not inventory.accessible_by(self.user, {'execute': True}):
|
||||
if self.user not in inventory.execute_role:
|
||||
return False
|
||||
|
||||
return True
|
||||
@ -1189,23 +1193,23 @@ class NotifierAccess(BaseAccess):
|
||||
qs = self.model.objects.all()
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
return self.model.objects.filter(organization__in=Organization.accessible_objects(self.user, ALL_PERMISSIONS).all())
|
||||
return self.model.objects.filter(organization__in=Organization.accessible_objects(self.user, 'admin_role').all())
|
||||
|
||||
def can_read(self, obj):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
if obj.organization is not None:
|
||||
return obj.organization.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
return self.user in obj.organization.admin_role
|
||||
return False
|
||||
|
||||
def can_add(self, data):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
if not data:
|
||||
return Organization.accessible_objects(self.user, ALL_PERMISSIONS).exists()
|
||||
return Organization.accessible_objects(self.user, 'admin_role').exists()
|
||||
org_pk = get_pk_from_dict(data, 'organization')
|
||||
org = get_object_or_400(Organization, pk=org_pk)
|
||||
return org.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
return self.user in org.admin_role
|
||||
|
||||
def can_change(self, obj, data):
|
||||
if self.user.is_superuser:
|
||||
@ -1213,10 +1217,10 @@ class NotifierAccess(BaseAccess):
|
||||
org_pk = get_pk_from_dict(data, 'organization')
|
||||
if obj and org_pk and obj.organization.pk != org_pk:
|
||||
org = get_object_or_400(Organization, pk=org_pk)
|
||||
if not org.accessible_by(self.user, ALL_PERMISSIONS):
|
||||
if self.user not in org.admin_role:
|
||||
return False
|
||||
if obj.organization is not None:
|
||||
return obj.organization.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
return self.user in obj.organization.admin_role
|
||||
return False
|
||||
|
||||
def can_admin(self, obj, data):
|
||||
@ -1235,7 +1239,7 @@ class NotificationAccess(BaseAccess):
|
||||
qs = self.model.objects.all()
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
return self.model.objects.filter(notifier__organization__in=Organization.accessible_objects(self.user, ALL_PERMISSIONS))
|
||||
return self.model.objects.filter(notifier__organization__in=Organization.accessible_objects(self.user, 'admin_role'))
|
||||
|
||||
def can_read(self, obj):
|
||||
return self.user.can_access(Notifier, 'read', obj.notifier)
|
||||
@ -1253,13 +1257,13 @@ class LabelAccess(BaseAccess):
|
||||
if self.user.is_superuser:
|
||||
return self.model.objects.all()
|
||||
return self.model.objects.filter(
|
||||
organization__in=Organization.accessible_objects(self.user, {'read': True})
|
||||
organization__in=Organization.accessible_objects(self.user, 'read_role')
|
||||
)
|
||||
|
||||
def can_read(self, obj):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return obj.organization.accessible_by(self.user, {'read': True})
|
||||
return self.user in obj.organization.read_role
|
||||
|
||||
def can_add(self, data):
|
||||
if self.user.is_superuser:
|
||||
@ -1270,7 +1274,7 @@ class LabelAccess(BaseAccess):
|
||||
|
||||
org_pk = get_pk_from_dict(data, 'organization')
|
||||
org = get_object_or_400(Organization, pk=org_pk)
|
||||
return org.accessible_by(self.user, {'read': True})
|
||||
return self.user in org.read_role
|
||||
|
||||
def can_change(self, obj, data):
|
||||
if self.user.is_superuser:
|
||||
@ -1279,7 +1283,7 @@ class LabelAccess(BaseAccess):
|
||||
if self.can_add(data) is False:
|
||||
return False
|
||||
|
||||
return obj.organization.accessible_by(self.user, ALL_PERMISSIONS)
|
||||
return self.user in obj.organization.admin_role
|
||||
|
||||
def can_delete(self, obj):
|
||||
return self.can_change(obj, None)
|
||||
@ -1370,12 +1374,12 @@ class CustomInventoryScriptAccess(BaseAccess):
|
||||
def get_queryset(self):
|
||||
if self.user.is_superuser:
|
||||
return self.model.objects.distinct().all()
|
||||
return self.model.accessible_objects(self.user, {'read':True}).all()
|
||||
return self.model.accessible_objects(self.user, 'read_role').all()
|
||||
|
||||
def can_read(self, obj):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
return obj.accessible_by(self.user, {'read':True})
|
||||
return self.user in obj.read_role
|
||||
|
||||
def can_add(self, data):
|
||||
if self.user.is_superuser:
|
||||
@ -1464,7 +1468,7 @@ class RoleAccess(BaseAccess):
|
||||
return True
|
||||
if obj.object_id and \
|
||||
isinstance(obj.content_object, ResourceMixin) and \
|
||||
obj.content_object.accessible_by(self.user, {'write': True}):
|
||||
self.user in obj.content_object.admin_role:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@ -93,10 +93,9 @@ class ImplicitRoleDescriptor(ReverseSingleRelatedObjectDescriptor):
|
||||
class ImplicitRoleField(models.ForeignKey):
|
||||
"""Implicitly creates a role entry for a resource"""
|
||||
|
||||
def __init__(self, role_name=None, role_description=None, permissions=None, parent_role=None, *args, **kwargs):
|
||||
def __init__(self, role_name=None, role_description=None, parent_role=None, *args, **kwargs):
|
||||
self.role_name = role_name
|
||||
self.role_description = role_description if role_description else ""
|
||||
self.permissions = permissions
|
||||
self.parent_role = parent_role
|
||||
|
||||
kwargs.setdefault('to', 'Role')
|
||||
@ -108,7 +107,6 @@ class ImplicitRoleField(models.ForeignKey):
|
||||
name, path, args, kwargs = super(ImplicitRoleField, self).deconstruct()
|
||||
kwargs['role_name'] = self.role_name
|
||||
kwargs['role_description'] = self.role_description
|
||||
kwargs['permissions'] = self.permissions
|
||||
kwargs['parent_role'] = self.parent_role
|
||||
return name, path, args, kwargs
|
||||
|
||||
@ -185,45 +183,17 @@ class ImplicitRoleField(models.ForeignKey):
|
||||
role = Role_.objects.create(
|
||||
created=now(),
|
||||
modified=now(),
|
||||
role_field=self.name,
|
||||
name=self.role_name,
|
||||
description=self.role_description
|
||||
)
|
||||
setattr(instance, self.name, role)
|
||||
|
||||
def _patch_role_content_object_and_grant_permissions(self, instance):
|
||||
def _patch_role_content_object(self, instance):
|
||||
role = getattr(instance, self.name)
|
||||
role.content_object = instance
|
||||
role.save()
|
||||
|
||||
if self.permissions is not None:
|
||||
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,
|
||||
content_type=instance_content_type,
|
||||
object_id=instance.id,
|
||||
auto_generated=True
|
||||
)
|
||||
|
||||
if 'all' in self.permissions and self.permissions['all']:
|
||||
del self.permissions['all']
|
||||
self.permissions['create'] = True
|
||||
self.permissions['read'] = True
|
||||
self.permissions['write'] = True
|
||||
self.permissions['update'] = True
|
||||
self.permissions['delete'] = True
|
||||
self.permissions['scm_update'] = True
|
||||
self.permissions['use'] = True
|
||||
self.permissions['execute'] = True
|
||||
|
||||
for k,v in self.permissions.items():
|
||||
setattr(permissions, k, v)
|
||||
permissions.save()
|
||||
|
||||
def _pre_save(self, instance, *args, **kwargs):
|
||||
for implicit_role_field in getattr(instance.__class__, '__implicit_role_fields'):
|
||||
implicit_role_field._create_role_instance_if_not_exists(instance)
|
||||
@ -231,7 +201,7 @@ class ImplicitRoleField(models.ForeignKey):
|
||||
def _post_save(self, instance, created, *args, **kwargs):
|
||||
if created:
|
||||
for implicit_role_field in getattr(instance.__class__, '__implicit_role_fields'):
|
||||
implicit_role_field._patch_role_content_object_and_grant_permissions(instance)
|
||||
implicit_role_field._patch_role_content_object(instance)
|
||||
|
||||
with batch_role_ancestor_rebuilding():
|
||||
for implicit_role_field in getattr(instance.__class__, '__implicit_role_fields'):
|
||||
@ -264,6 +234,7 @@ class ImplicitRoleField(models.ForeignKey):
|
||||
else:
|
||||
role = Role_.objects.create(created=now(),
|
||||
modified=now(),
|
||||
role_field=path,
|
||||
singleton_name=singleton_name,
|
||||
name=singleton_name,
|
||||
description=singleton_name)
|
||||
|
||||
@ -1,354 +0,0 @@
|
||||
# Copyright (c) 2016 Ansible, Inc.
|
||||
# All Rights Reserved
|
||||
|
||||
# Python
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from optparse import make_option
|
||||
|
||||
|
||||
# Django
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils.timezone import now
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import transaction
|
||||
|
||||
# awx
|
||||
from awx.main.models import * # noqa
|
||||
|
||||
|
||||
|
||||
class Rollback(Exception):
|
||||
pass
|
||||
|
||||
class Command(BaseCommand):
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--organizations', action='store', type='int', default=3,
|
||||
help='Number of organizations to create'),
|
||||
make_option('--users', action='store', type='int', default=10,
|
||||
help='Number of users to create'),
|
||||
make_option('--teams', action='store', type='int', default=5,
|
||||
help='Number of teams to create'),
|
||||
make_option('--projects', action='store', type='int', default=10,
|
||||
help='Number of projects to create'),
|
||||
make_option('--job-templates', action='store', type='int', default=20,
|
||||
help='Number of job templates to create'),
|
||||
make_option('--credentials', action='store', type='int', default=5,
|
||||
help='Number of credentials to create'),
|
||||
make_option('--inventories', action='store', type='int', default=5,
|
||||
help='Number of credentials to create'),
|
||||
make_option('--inventory-groups', action='store', type='int', default=10,
|
||||
help='Number of credentials to create'),
|
||||
make_option('--inventory-hosts', action='store', type='int', default=40,
|
||||
help='number of credentials to create'),
|
||||
make_option('--jobs', action='store', type='int', default=200,
|
||||
help='number of job entries to create'),
|
||||
make_option('--job-events', action='store', type='int', default=500,
|
||||
help='number of job event entries to create'),
|
||||
make_option('--pretend', action='store_true',
|
||||
help="Don't commit the data to the database"),
|
||||
make_option('--prefix', action='store', type='string', default='',
|
||||
help="Prefix generated names with this string"),
|
||||
#make_option('--spread-bias', action='store', type='string', default='exponential',
|
||||
# help='"exponential" to bias associations exponentially front loaded for - for ex'),
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
n_organizations = int(options['organizations'])
|
||||
n_users = int(options['users'])
|
||||
n_teams = int(options['teams'])
|
||||
n_projects = int(options['projects'])
|
||||
n_job_templates = int(options['job_templates'])
|
||||
n_credentials = int(options['credentials'])
|
||||
n_inventories = int(options['inventories'])
|
||||
n_inventory_groups = int(options['inventory_groups'])
|
||||
n_inventory_hosts = int(options['inventory_hosts'])
|
||||
n_jobs = int(options['jobs'])
|
||||
n_job_events = int(options['job_events'])
|
||||
prefix = options['prefix']
|
||||
|
||||
organizations = []
|
||||
users = []
|
||||
teams = []
|
||||
projects = []
|
||||
job_templates = []
|
||||
credentials = []
|
||||
inventories = []
|
||||
inventory_groups = []
|
||||
inventory_hosts = []
|
||||
jobs = []
|
||||
#job_events = []
|
||||
|
||||
def spread(n, m):
|
||||
ret = []
|
||||
# At least one in each slot, split up the rest exponentially so the first
|
||||
# buckets contain a lot of entries
|
||||
for i in xrange(m):
|
||||
if n > 0:
|
||||
ret.append(1)
|
||||
n -= 1
|
||||
else:
|
||||
ret.append(0)
|
||||
|
||||
for i in xrange(m):
|
||||
n_in_this_slot = n // 2
|
||||
n-= n_in_this_slot
|
||||
ret[i] += n_in_this_slot
|
||||
if n > 0 and len(ret):
|
||||
ret[0] += n
|
||||
return ret
|
||||
|
||||
ids = defaultdict(lambda: 0)
|
||||
|
||||
|
||||
try:
|
||||
|
||||
with transaction.atomic():
|
||||
with batch_role_ancestor_rebuilding():
|
||||
|
||||
print('# Creating %d organizations' % n_organizations)
|
||||
for i in xrange(n_organizations):
|
||||
sys.stdout.write('\r%d ' % (i + 1))
|
||||
sys.stdout.flush()
|
||||
organizations.append(Organization.objects.create(name='%s Organization %d' % (prefix, i)))
|
||||
print('')
|
||||
|
||||
print('# Creating %d users' % n_users)
|
||||
org_idx = 0
|
||||
for n in spread(n_users, n_organizations):
|
||||
for i in range(n):
|
||||
ids['user'] += 1
|
||||
user_id = ids['user']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, organizations[org_idx].name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
user = User.objects.create(username='%suser-%d' % (prefix, user_id))
|
||||
organizations[org_idx].member_role.members.add(user)
|
||||
users.append(user)
|
||||
org_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Creating %d teams' % n_teams)
|
||||
org_idx = 0
|
||||
for n in spread(n_teams, n_organizations):
|
||||
org = organizations[org_idx]
|
||||
for i in range(n):
|
||||
ids['team'] += 1
|
||||
team_id = ids['team']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, org.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
team = Team.objects.create(name='%s Team %d Org %d' % (prefix, team_id, org_idx), organization=org)
|
||||
teams.append(team)
|
||||
org_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Adding users to teams')
|
||||
for org in organizations:
|
||||
org_teams = [t for t in org.teams.all()]
|
||||
org_users = [u for u in org.member_role.members.all()]
|
||||
print(' Spreading %d users accross %d teams for %s' % (len(org_users), len(org_teams), org.name))
|
||||
# Our normal spread for most users
|
||||
cur_user_idx = 0
|
||||
cur_team_idx = 0
|
||||
for n in spread(len(org_users), len(org_teams)):
|
||||
team = org_teams[cur_team_idx]
|
||||
for i in range(n):
|
||||
if cur_user_idx < len(org_users):
|
||||
user = org_users[cur_user_idx]
|
||||
team.member_role.members.add(user)
|
||||
cur_user_idx += 1
|
||||
cur_team_idx += 1
|
||||
|
||||
# First user gets added to all teams
|
||||
for team in org_teams:
|
||||
team.member_role.members.add(org_users[0])
|
||||
|
||||
|
||||
print('# Creating %d credentials for users' % (n_credentials - n_credentials // 2))
|
||||
user_idx = 0
|
||||
for n in spread(n_credentials - n_credentials // 2, n_users):
|
||||
user = users[user_idx]
|
||||
for i in range(n):
|
||||
ids['credential'] += 1
|
||||
sys.stdout.write('\r %d ' % (ids['credential']))
|
||||
sys.stdout.flush()
|
||||
credential_id = ids['credential']
|
||||
credential = Credential.objects.create(name='%s Credential %d User %d' % (prefix, credential_id, user_idx))
|
||||
credential.owner_role.members.add(user)
|
||||
credentials.append(credential)
|
||||
user_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Creating %d credentials for teams' % (n_credentials // 2))
|
||||
team_idx = 0
|
||||
starting_credential_id = ids['credential']
|
||||
for n in spread(n_credentials - n_credentials // 2, n_teams):
|
||||
team = teams[team_idx]
|
||||
for i in range(n):
|
||||
ids['credential'] += 1
|
||||
sys.stdout.write('\r %d ' % (ids['credential'] - starting_credential_id))
|
||||
sys.stdout.flush()
|
||||
credential_id = ids['credential']
|
||||
credential = Credential.objects.create(name='%s Credential %d team %d' % (prefix, credential_id, team_idx))
|
||||
credential.owner_role.parents.add(team.member_role)
|
||||
credentials.append(credential)
|
||||
team_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Creating %d projects' % n_projects)
|
||||
org_idx = 0
|
||||
for n in spread(n_projects, n_organizations):
|
||||
org = organizations[org_idx]
|
||||
for i in range(n):
|
||||
ids['project'] += 1
|
||||
project_id = ids['project']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, org.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
project = Project.objects.create(name='%s Project %d Org %d' % (prefix, project_id, org_idx), organization=org)
|
||||
projects.append(project)
|
||||
|
||||
org_idx += 1
|
||||
print('')
|
||||
|
||||
|
||||
print('# Creating %d inventories' % n_inventories)
|
||||
org_idx = 0
|
||||
for n in spread(n_inventories, min(n_inventories // 4 + 1, n_organizations)):
|
||||
org = organizations[org_idx]
|
||||
for i in range(n):
|
||||
ids['inventory'] += 1
|
||||
inventory_id = ids['inventory']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, org.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
inventory = Inventory.objects.create(name='%s Inventory %d Org %d' % (prefix, inventory_id, org_idx), organization=org)
|
||||
inventories.append(inventory)
|
||||
|
||||
org_idx += 1
|
||||
print('')
|
||||
|
||||
|
||||
print('# Creating %d inventory_groups' % n_inventory_groups)
|
||||
inv_idx = 0
|
||||
for n in spread(n_inventory_groups, n_inventories):
|
||||
inventory = inventories[inv_idx]
|
||||
parent_list = [None] * 3
|
||||
for i in range(n):
|
||||
ids['group'] += 1
|
||||
group_id = ids['group']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, inventory.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
group = Group.objects.create(
|
||||
name='%s Group %d Inventory %d' % (prefix, group_id, inv_idx),
|
||||
inventory=inventory,
|
||||
)
|
||||
# Have each group have up to 3 parent groups
|
||||
for parent_n in range(3):
|
||||
if i // 4 + parent_n < len(parent_list) and parent_list[i // 4 + parent_n]:
|
||||
group.parents.add(parent_list[i // 4 + parent_n])
|
||||
if parent_list[i // 4] is None:
|
||||
parent_list[i // 4] = group
|
||||
else:
|
||||
parent_list.append(group)
|
||||
inventory_groups.append(group)
|
||||
|
||||
inv_idx += 1
|
||||
print('')
|
||||
|
||||
|
||||
print('# Creating %d inventory_hosts' % n_inventory_hosts)
|
||||
group_idx = 0
|
||||
for n in spread(n_inventory_hosts, n_inventory_groups):
|
||||
group = inventory_groups[group_idx]
|
||||
for i in range(n):
|
||||
ids['host'] += 1
|
||||
host_id = ids['host']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, group.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
host = Host.objects.create(name='%s Host %d Group %d' % (prefix, host_id, group_idx), inventory=group.inventory)
|
||||
# Add the host to up to 3 groups
|
||||
host.groups.add(group)
|
||||
for m in range(2):
|
||||
if group_idx + m < len(inventory_groups) and group.inventory.id == inventory_groups[group_idx + m].inventory.id:
|
||||
host.groups.add(inventory_groups[group_idx + m])
|
||||
|
||||
inventory_hosts.append(host)
|
||||
|
||||
group_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Creating %d job_templates' % n_job_templates)
|
||||
project_idx = 0
|
||||
inv_idx = 0
|
||||
for n in spread(n_job_templates, n_projects):
|
||||
project = projects[project_idx]
|
||||
for i in range(n):
|
||||
ids['job_template'] += 1
|
||||
job_template_id = ids['job_template']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, project.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
|
||||
inventory = None
|
||||
org_inv_count = project.organization.inventories.count()
|
||||
if org_inv_count > 0:
|
||||
inventory = project.organization.inventories.all()[inv_idx % org_inv_count]
|
||||
|
||||
job_template = JobTemplate.objects.create(
|
||||
name='%s Job Template %d Project %d' % (prefix, job_template_id, project_idx),
|
||||
inventory=inventory,
|
||||
project=project,
|
||||
)
|
||||
job_templates.append(job_template)
|
||||
inv_idx += 1
|
||||
project_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Creating %d jobs' % n_jobs)
|
||||
group_idx = 0
|
||||
job_template_idx = 0
|
||||
for n in spread(n_jobs, n_job_templates):
|
||||
job_template = job_templates[job_template_idx]
|
||||
for i in range(n):
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, job_template.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
job = Job.objects.create(job_template=job_template)
|
||||
jobs.append(job)
|
||||
|
||||
if job_template.inventory:
|
||||
inv_groups = [g for g in job_template.inventory.groups.all()]
|
||||
if len(inv_groups):
|
||||
JobHostSummary.objects.bulk_create([
|
||||
JobHostSummary(
|
||||
job=job, host=h, host_name=h.name, processed=1,
|
||||
created=now(), modified=now()
|
||||
)
|
||||
for h in inv_groups[group_idx % len(inv_groups)].hosts.all()[:100]
|
||||
])
|
||||
group_idx += 1
|
||||
job_template_idx += 1
|
||||
if n:
|
||||
print('')
|
||||
|
||||
print('# Creating %d job events' % n_job_events)
|
||||
job_idx = 0
|
||||
for n in spread(n_job_events, n_jobs):
|
||||
job = jobs[job_idx]
|
||||
sys.stdout.write('\r Creating %d job events for job %d' % (n, job.id))
|
||||
sys.stdout.flush()
|
||||
JobEvent.objects.bulk_create([
|
||||
JobEvent(
|
||||
created=now(),
|
||||
modified=now(),
|
||||
job=job,
|
||||
event='runner_on_ok'
|
||||
)
|
||||
for i in range(n)
|
||||
])
|
||||
job_idx += 1
|
||||
if n:
|
||||
print('')
|
||||
|
||||
if options['pretend']:
|
||||
raise Rollback()
|
||||
except Rollback:
|
||||
print('Rolled back changes')
|
||||
pass
|
||||
return
|
||||
@ -780,10 +780,10 @@ class Command(NoArgsCommand):
|
||||
if settings.SQL_DEBUG:
|
||||
queries_before = len(connection.queries)
|
||||
if self.inventory_source.group:
|
||||
groups_qs = self.inventory_source.group.all_children
|
||||
groups_qs = self.inventory_source.group.all_children.all()
|
||||
# FIXME: Also include groups from inventory_source.managed_groups?
|
||||
else:
|
||||
groups_qs = self.inventory.groups
|
||||
groups_qs = self.inventory.groups.all()
|
||||
# Build list of all group pks, remove those that should not be deleted.
|
||||
del_group_pks = set(groups_qs.values_list('pk', flat=True))
|
||||
all_group_names = self.all_group.all_groups.keys()
|
||||
@ -1273,42 +1273,43 @@ class Command(NoArgsCommand):
|
||||
self.is_custom)
|
||||
self.all_group.debug_tree()
|
||||
|
||||
# Ensure that this is managed as an atomic SQL transaction,
|
||||
# and thus properly rolled back if there is an issue.
|
||||
with transaction.atomic():
|
||||
# Merge/overwrite inventory into database.
|
||||
if settings.SQL_DEBUG:
|
||||
self.logger.warning('loading into database...')
|
||||
with ignore_inventory_computed_fields():
|
||||
if getattr(settings, 'ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC', True):
|
||||
self.load_into_database()
|
||||
else:
|
||||
with disable_activity_stream():
|
||||
with batch_role_ancestor_rebuilding():
|
||||
# Ensure that this is managed as an atomic SQL transaction,
|
||||
# and thus properly rolled back if there is an issue.
|
||||
with transaction.atomic():
|
||||
# Merge/overwrite inventory into database.
|
||||
if settings.SQL_DEBUG:
|
||||
self.logger.warning('loading into database...')
|
||||
with ignore_inventory_computed_fields():
|
||||
if getattr(settings, 'ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC', True):
|
||||
self.load_into_database()
|
||||
if settings.SQL_DEBUG:
|
||||
queries_before2 = len(connection.queries)
|
||||
self.inventory.update_computed_fields()
|
||||
if settings.SQL_DEBUG:
|
||||
self.logger.warning('update computed fields took %d queries',
|
||||
len(connection.queries) - queries_before2)
|
||||
try:
|
||||
self.check_license()
|
||||
except CommandError as e:
|
||||
self.mark_license_failure(save=True)
|
||||
raise e
|
||||
else:
|
||||
with disable_activity_stream():
|
||||
self.load_into_database()
|
||||
if settings.SQL_DEBUG:
|
||||
queries_before2 = len(connection.queries)
|
||||
self.inventory.update_computed_fields()
|
||||
if settings.SQL_DEBUG:
|
||||
self.logger.warning('update computed fields took %d queries',
|
||||
len(connection.queries) - queries_before2)
|
||||
try:
|
||||
self.check_license()
|
||||
except CommandError as e:
|
||||
self.mark_license_failure(save=True)
|
||||
raise e
|
||||
|
||||
if self.inventory_source.group:
|
||||
inv_name = 'group "%s"' % (self.inventory_source.group.name)
|
||||
else:
|
||||
inv_name = '"%s" (id=%s)' % (self.inventory.name,
|
||||
self.inventory.id)
|
||||
if settings.SQL_DEBUG:
|
||||
self.logger.warning('Inventory import completed for %s in %0.1fs',
|
||||
inv_name, time.time() - begin)
|
||||
else:
|
||||
self.logger.info('Inventory import completed for %s in %0.1fs',
|
||||
inv_name, time.time() - begin)
|
||||
status = 'successful'
|
||||
if self.inventory_source.group:
|
||||
inv_name = 'group "%s"' % (self.inventory_source.group.name)
|
||||
else:
|
||||
inv_name = '"%s" (id=%s)' % (self.inventory.name,
|
||||
self.inventory.id)
|
||||
if settings.SQL_DEBUG:
|
||||
self.logger.warning('Inventory import completed for %s in %0.1fs',
|
||||
inv_name, time.time() - begin)
|
||||
else:
|
||||
self.logger.info('Inventory import completed for %s in %0.1fs',
|
||||
inv_name, time.time() - begin)
|
||||
status = 'successful'
|
||||
|
||||
# If we're in debug mode, then log the queries and time
|
||||
# used to do the operation.
|
||||
|
||||
@ -48,6 +48,19 @@ class Migration(migrations.Migration):
|
||||
field=models.ManyToManyField(related_name='deprecated_teams', to='main.Project', blank=True),
|
||||
),
|
||||
|
||||
migrations.CreateModel(
|
||||
name='RoleAncestorEntry',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('role_field', models.TextField()),
|
||||
('content_type_id', models.PositiveIntegerField(null=False)),
|
||||
('object_id', models.PositiveIntegerField(null=False)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'main_rbac_role_ancestors',
|
||||
'verbose_name_plural': 'role_ancestors',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Role',
|
||||
fields=[
|
||||
@ -58,7 +71,7 @@ class Migration(migrations.Migration):
|
||||
('name', models.CharField(max_length=512)),
|
||||
('singleton_name', models.TextField(default=None, unique=True, null=True, db_index=True)),
|
||||
('object_id', models.PositiveIntegerField(default=None, null=True)),
|
||||
('ancestors', models.ManyToManyField(related_name='descendents', to='main.Role')),
|
||||
('ancestors', models.ManyToManyField(related_name='descendents', through='main.RoleAncestorEntry', to='main.Role')),
|
||||
('content_type', models.ForeignKey(default=None, to='contenttypes.ContentType', null=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)),
|
||||
@ -72,177 +85,262 @@ class Migration(migrations.Migration):
|
||||
'verbose_name_plural': 'roles',
|
||||
},
|
||||
),
|
||||
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)),
|
||||
('auto_generated', models.BooleanField(default=False)),
|
||||
('object_id', models.PositiveIntegerField(default=None)),
|
||||
('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)),
|
||||
('content_type', models.ForeignKey(default=None, to='contenttypes.ContentType')),
|
||||
('role', models.ForeignKey(related_name='permissions', to='main.Role')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'main_rbac_permissions',
|
||||
'verbose_name_plural': 'permissions',
|
||||
},
|
||||
migrations.AddField(
|
||||
model_name='roleancestorentry',
|
||||
name='ancestor',
|
||||
field=models.ForeignKey(related_name='+', to='main.Role'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='roleancestorentry',
|
||||
name='descendent',
|
||||
field=models.ForeignKey(related_name='+', to='main.Role'),
|
||||
),
|
||||
migrations.AlterIndexTogether(
|
||||
name='roleancestorentry',
|
||||
index_together=set([('ancestor', 'content_type_id', 'object_id'), ('ancestor', 'content_type_id', 'role_field')]),
|
||||
),
|
||||
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Auditor of the credential', parent_role=[b'singleton:System Auditor'], to='main.Role', role_name=b'Credential Auditor', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Auditor of the credential', parent_role=[b'singleton:System Auditor'], to='main.Role', role_name=b'Credential Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='owner_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Owner of the credential', parent_role=[b'singleton:System Administrator'], to='main.Role', role_name=b'Credential Owner', null=b'True', permissions={b'all': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Owner of the credential', parent_role=[b'singleton:System Administrator'], to='main.Role', role_name=b'Credential Owner', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='usage_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May use this credential, but not read sensitive portions or modify it', parent_role=None, to='main.Role', role_name=b'Credential User', null=b'True', permissions={b'use': True}),
|
||||
name='use_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May use this credential, but not read sensitive portions or modify it', parent_role=None, to='main.Role', role_name=b'Credential User', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this inventory', parent_role=b'organization.admin_role', to='main.Role', role_name=b'CustomInventory Administrator', null=b'True', permissions={b'all': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this inventory', parent_role=b'organization.admin_role', to='main.Role', role_name=b'CustomInventory Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view but not modify this inventory', parent_role=b'organization.auditor_role', to='main.Role', role_name=b'CustomInventory Auditor', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view but not modify this inventory', parent_role=b'organization.auditor_role', to='main.Role', role_name=b'CustomInventory Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view but not modify this inventory', parent_role=b'organization.member_role', to='main.Role', role_name=b'CustomInventory Member', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view but not modify this inventory', parent_role=b'organization.member_role', to='main.Role', role_name=b'CustomInventory Member', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.admin_role', b'parents.admin_role'], to='main.Role', role_name=b'Inventory Group Administrator', null=b'True', permissions={b'all': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.admin_role', b'parents.admin_role'], to='main.Role', role_name=b'Inventory Group Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.auditor_role', b'parents.auditor_role'], to='main.Role', role_name=b'Inventory Group Auditor', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.auditor_role', b'parents.auditor_role'], to='main.Role', role_name=b'Inventory Group Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='executor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.executor_role', b'parents.executor_role'], to='main.Role', role_name=b'Inventory Group Executor', null=b'True', permissions={b'read': True, b'execute': True}),
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.execute_role', b'parents.executor_role'], to='main.Role', role_name=b'Inventory Group Executor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='updater_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.updater_role', b'parents.updater_role'], to='main.Role', role_name=b'Inventory Group Updater', null=b'True', permissions={b'read': True, b'write': True, b'create': True, b'use': True}),
|
||||
name='update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.update_role', b'parents.updater_role'], to='main.Role', role_name=b'Inventory Group Updater', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this inventory', parent_role=b'organization.admin_role', to='main.Role', role_name=b'Inventory Administrator', null=b'True', permissions={b'all': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this inventory', parent_role=b'organization.admin_role', to='main.Role', role_name=b'Inventory Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view but not modify this inventory', parent_role=b'organization.auditor_role', to='main.Role', role_name=b'Inventory Auditor', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view but not modify this inventory', parent_role=b'organization.auditor_role', to='main.Role', role_name=b'Inventory Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='executor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May execute jobs against this inventory', parent_role=None, to='main.Role', role_name=b'Inventory Executor', null=b'True', permissions={b'read': True, b'execute': True}),
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May execute jobs against this inventory', parent_role=None, to='main.Role', role_name=b'Inventory Executor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='updater_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May update the inventory', parent_role=None, to='main.Role', role_name=b'Inventory Updater', null=b'True', permissions={b'read': True, b'update': True}),
|
||||
name='update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May update the inventory', parent_role=None, to='main.Role', role_name=b'Inventory Updater', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='usage_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May use this inventory, but not read sensitive portions or modify it', parent_role=None, to='main.Role', role_name=b'Inventory User', null=b'True', permissions={b'use': True}),
|
||||
name='use_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May use this inventory, but not read sensitive portions or modify it', parent_role=None, to='main.Role', role_name=b'Inventory User', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Full access to all settings', parent_role=b'project.admin_role', to='main.Role', role_name=b'Job Template Administrator', null=b'True', permissions={b'all': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Full access to all settings', parent_role=b'project.admin_role', to='main.Role', role_name=b'Job Template Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Read-only access to all settings', parent_role=b'project.auditor_role', to='main.Role', role_name=b'Job Template Auditor', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Read-only access to all settings', parent_role=b'project.auditor_role', to='main.Role', role_name=b'Job Template Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='executor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May run the job template', parent_role=None, to='main.Role', role_name=b'Job Template Runner', null=b'True', permissions={b'read': True, b'execute': True}),
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May run the job template', parent_role=None, to='main.Role', role_name=b'Job Template Runner', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage all aspects of this organization', parent_role=b'singleton:System Administrator', to='main.Role', role_name=b'Organization Administrator', null=b'True', permissions={b'write': True, b'use': True, b'scm_update': True, b'execute': True, b'read': True, b'create': True, b'update': True, b'delete': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage all aspects of this organization', parent_role=b'singleton:System Administrator', to='main.Role', role_name=b'Organization Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May read all settings associated with this organization', parent_role=b'singleton:System Auditor', to='main.Role', role_name=b'Organization Auditor', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May read all settings associated with this organization', parent_role=b'singleton:System Auditor', to='main.Role', role_name=b'Organization Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'A member of this organization', parent_role=b'admin_role', to='main.Role', role_name=b'Organization Member', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'A member of this organization', parent_role=b'admin_role', to='main.Role', role_name=b'Organization Member', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this project', parent_role=[b'organization.admin_role', b'singleton:System Administrator'], to='main.Role', role_name=b'Project Administrator', null=b'True', permissions={b'all': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this project', parent_role=[b'organization.admin_role', b'singleton:System Administrator'], to='main.Role', role_name=b'Project Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May read all settings associated with this project', parent_role=[b'organization.auditor_role', b'singleton:System Auditor'], to='main.Role', role_name=b'Project Auditor', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May read all settings associated with this project', parent_role=[b'organization.auditor_role', b'singleton:System Auditor'], to='main.Role', role_name=b'Project Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Implies membership within this project', parent_role=None, to='main.Role', role_name=b'Project Member', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Implies membership within this project', parent_role=None, to='main.Role', role_name=b'Project Member', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='scm_update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May update this project from the source control management system', parent_role=b'admin_role', to='main.Role', role_name=b'Project Updater', null=b'True', permissions={b'scm_update': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May update this project from the source control management system', parent_role=b'admin_role', to='main.Role', role_name=b'Project Updater', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this team', parent_role=b'organization.admin_role', to='main.Role', role_name=b'Team Administrator', null=b'True', permissions={b'write': True, b'use': True, b'scm_update': True, b'execute': True, b'read': True, b'create': True, b'update': True, b'delete': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this team', parent_role=b'organization.admin_role', to='main.Role', role_name=b'Team Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May read all settings associated with this team', parent_role=b'organization.auditor_role', to='main.Role', role_name=b'Team Auditor', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May read all settings associated with this team', parent_role=b'organization.auditor_role', to='main.Role', role_name=b'Team Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'A member of this team', parent_role=b'admin_role', to='main.Role', role_name=b'Team Member', null=b'True', permissions={b'read': True}),
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'A member of this team', to='main.Role', role_name=b'Team Member', null=b'True'),
|
||||
),
|
||||
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May read this credential', parent_role=[b'use_role', b'auditor_role', b'owner_role'], to='main.Role', role_name=b'Credential REad', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view but not modify this inventory', parent_role=[b'auditor_role', b'member_role', b'admin_role'], to='main.Role', role_name=b'CustomInventory Read', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='adhoc_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May execute ad hoc commands against this inventory', parent_role=[b'inventory.adhoc_role', b'parents.adhoc_role', b'admin_role'], to='main.Role', role_name=b'Inventory Ad Hoc', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'execute_role', b'update_role', b'auditor_role', b'admin_role'], to='main.Role', role_name=b'Inventory Group Executor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='adhoc_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May execute ad hoc commands against this inventory', parent_role=[b'admin_role'], to='main.Role', role_name=b'Inventory Ad Hoc', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view this inventory', parent_role=[b'auditor_role', b'execute_role', b'update_role', b'use_role', b'admin_role'], to='main.Role', role_name=b'Read', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May run the job template', parent_role=[b'execute_role', b'auditor_role', b'admin_role'], to='main.Role', role_name=b'Job Template Runner', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Read an organization', parent_role=[b'member_role', b'auditor_role'], to='main.Role', role_name=b'Organization Read Access', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Read access to this project', parent_role=[b'member_role', b'auditor_role', b'scm_update_role'], to='main.Role', role_name=b'Project Read Access', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='role_field',
|
||||
field=models.TextField(default=b''),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Can view this team', parent_role=[b'admin_role', b'auditor_role', b'member_role'], to='main.Role', role_name=b'Read', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='credential',
|
||||
name='use_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May use this credential, but not read sensitive portions or modify it', parent_role=[b'owner_role'], to='main.Role', role_name=b'Credential User', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='group',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.execute_role', b'parents.execute_role', b'adhoc_role'], to='main.Role', role_name=b'Inventory Group Executor', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='group',
|
||||
name='update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.update_role', b'parents.update_role', b'admin_role'], to='main.Role', role_name=b'Inventory Group Updater', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventory',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May execute jobs against this inventory', parent_role=b'adhoc_role', to='main.Role', role_name=b'Inventory Executor', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventory',
|
||||
name='update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May update the inventory', parent_role=[b'admin_role'], to='main.Role', role_name=b'Inventory Updater', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventory',
|
||||
name='use_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May use this inventory, but not read sensitive portions or modify it', parent_role=[b'admin_role'], to='main.Role', role_name=b'Inventory User', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='jobtemplate',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May run the job template', parent_role=[b'admin_role'], to='main.Role', role_name=b'Job Template Runner', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='project',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Implies membership within this project', parent_role=b'admin_role', to='main.Role', role_name=b'Project Member', null=b'True'),
|
||||
),
|
||||
|
||||
|
||||
migrations.AlterIndexTogether(
|
||||
name='rolepermission',
|
||||
index_together=set([('content_type', 'object_id')]),
|
||||
),
|
||||
|
||||
|
||||
|
||||
migrations.RenameField(
|
||||
model_name='organization',
|
||||
old_name='projects',
|
||||
|
||||
18
awx/main/migrations/0018_v300_host_ordering.py
Normal file
18
awx/main/migrations/0018_v300_host_ordering.py
Normal file
@ -0,0 +1,18 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0017_v300_prompting_migrations'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='host',
|
||||
options={'ordering': ('name',)},
|
||||
),
|
||||
]
|
||||
@ -34,7 +34,6 @@ def init_rbac_migration(apps, schema_editor):
|
||||
def migrate_users(apps, schema_editor):
|
||||
User = apps.get_model('auth', "User")
|
||||
Role = apps.get_model('main', "Role")
|
||||
RolePermission = apps.get_model('main', "RolePermission")
|
||||
ContentType = apps.get_model('contenttypes', "ContentType")
|
||||
user_content_type = ContentType.objects.get_for_model(User)
|
||||
|
||||
@ -52,15 +51,6 @@ def migrate_users(apps, schema_editor):
|
||||
object_id = user.id
|
||||
)
|
||||
role.members.add(user)
|
||||
RolePermission.objects.create(
|
||||
created=now(),
|
||||
modified=now(),
|
||||
role = role,
|
||||
content_type = user_content_type,
|
||||
object_id = user.id,
|
||||
create=1, read=1, write=1, delete=1, update=1,
|
||||
execute=1, scm_update=1, use=1,
|
||||
)
|
||||
logger.info(smart_text(u"migrating to new role for user: {}".format(user.username)))
|
||||
|
||||
if user.is_superuser:
|
||||
@ -113,7 +103,7 @@ def attrfunc(attr_path):
|
||||
|
||||
def _update_credential_parents(org, cred):
|
||||
org.admin_role.children.add(cred.owner_role)
|
||||
org.member_role.children.add(cred.usage_role)
|
||||
org.member_role.children.add(cred.use_role)
|
||||
cred.deprecated_user, cred.deprecated_team = None, None
|
||||
cred.save()
|
||||
|
||||
@ -147,7 +137,7 @@ def _discover_credentials(instances, cred, orgfunc):
|
||||
|
||||
# Unlink the old information from the new credential
|
||||
cred.deprecated_user, cred.deprecated_team = None, None
|
||||
cred.owner_role, cred.usage_role = None, None
|
||||
cred.owner_role, cred.use_role = None, None
|
||||
cred.save()
|
||||
|
||||
for i in orgs[org]:
|
||||
@ -189,7 +179,7 @@ def migrate_credential(apps, schema_editor):
|
||||
|
||||
if cred.deprecated_team is not None:
|
||||
cred.deprecated_team.admin_role.children.add(cred.owner_role)
|
||||
cred.deprecated_team.member_role.children.add(cred.usage_role)
|
||||
cred.deprecated_team.member_role.children.add(cred.use_role)
|
||||
cred.deprecated_user, cred.deprecated_team = None, None
|
||||
cred.save()
|
||||
logger.info(smart_text(u"added Credential(name={}, kind={}, host={}) at user level".format(cred.name, cred.kind, cred.host)))
|
||||
@ -214,7 +204,7 @@ def migrate_inventory(apps, schema_editor):
|
||||
elif perm.permission_type == 'read':
|
||||
return inventory.auditor_role
|
||||
elif perm.permission_type == 'write':
|
||||
return inventory.updater_role
|
||||
return inventory.update_role
|
||||
elif perm.permission_type == 'check' or perm.permission_type == 'run':
|
||||
# These permission types are handled differntly in RBAC now, nothing to migrate.
|
||||
return False
|
||||
@ -232,7 +222,7 @@ def migrate_inventory(apps, schema_editor):
|
||||
raise Exception(smart_text(u'Unhandled permission type for inventory: {}'.format( perm.permission_type)))
|
||||
|
||||
if perm.run_ad_hoc_commands:
|
||||
execrole = inventory.executor_role
|
||||
execrole = inventory.execute_role
|
||||
|
||||
if perm.team:
|
||||
if role:
|
||||
@ -392,20 +382,20 @@ def migrate_job_templates(apps, schema_editor):
|
||||
|
||||
for team in Team.objects.iterator():
|
||||
if permission.filter(team=team).exists():
|
||||
team.member_role.children.add(jt.executor_role)
|
||||
team.member_role.children.add(jt.execute_role)
|
||||
logger.info(smart_text(u'adding Team({}) access to JobTemplate({})'.format(team.name, jt.name)))
|
||||
|
||||
for user in User.objects.iterator():
|
||||
if permission.filter(user=user).exists():
|
||||
jt.executor_role.members.add(user)
|
||||
jt.execute_role.members.add(user)
|
||||
logger.info(smart_text(u'adding User({}) access to JobTemplate({})'.format(user.username, jt.name)))
|
||||
|
||||
if jt.accessible_by(user, {'execute': True}):
|
||||
if 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.executor_role.members.add(user)
|
||||
jt.execute_role.members.add(user)
|
||||
logger.info(smart_text(u'adding User({}) access to JobTemplate({})'.format(user.username, jt.name)))
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
|
||||
# Django
|
||||
from django.conf import settings # noqa
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
|
||||
# AWX
|
||||
from awx.main.models.base import * # noqa
|
||||
@ -43,10 +42,8 @@ from awx.main.access import * # noqa
|
||||
|
||||
User.add_to_class('get_queryset', get_user_queryset)
|
||||
User.add_to_class('can_access', check_user_access)
|
||||
User.add_to_class('accessible_by', user_accessible_by)
|
||||
User.add_to_class('accessible_objects', user_accessible_objects)
|
||||
User.add_to_class('admin_role', user_admin_role)
|
||||
User.add_to_class('role_permissions', GenericRelation('main.RolePermission'))
|
||||
|
||||
@property
|
||||
def user_get_organizations(user):
|
||||
|
||||
@ -174,7 +174,6 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
|
||||
parent_role=[
|
||||
'singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
|
||||
],
|
||||
permissions = {'all': True}
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Credential Auditor',
|
||||
@ -182,12 +181,18 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
|
||||
parent_role=[
|
||||
'singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,
|
||||
],
|
||||
permissions = {'read': True}
|
||||
)
|
||||
usage_role = ImplicitRoleField(
|
||||
use_role = ImplicitRoleField(
|
||||
role_name='Credential User',
|
||||
role_description='May use this credential, but not read sensitive portions or modify it',
|
||||
permissions = {'use': True}
|
||||
parent_role=['owner_role']
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Credential REad',
|
||||
role_description='May read this credential',
|
||||
parent_role=[
|
||||
'use_role', 'auditor_role', 'owner_role'
|
||||
],
|
||||
)
|
||||
|
||||
@property
|
||||
|
||||
@ -100,28 +100,36 @@ class Inventory(CommonModel, ResourceMixin):
|
||||
role_name='Inventory Administrator',
|
||||
role_description='May manage this inventory',
|
||||
parent_role='organization.admin_role',
|
||||
permissions = {'all': True}
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Inventory Auditor',
|
||||
role_description='May view but not modify this inventory',
|
||||
parent_role='organization.auditor_role',
|
||||
permissions = {'read': True}
|
||||
)
|
||||
updater_role = ImplicitRoleField(
|
||||
update_role = ImplicitRoleField(
|
||||
role_name='Inventory Updater',
|
||||
role_description='May update the inventory',
|
||||
permissions = {'read': True, 'update': True}
|
||||
parent_role=['admin_role'],
|
||||
)
|
||||
usage_role = ImplicitRoleField(
|
||||
use_role = ImplicitRoleField(
|
||||
role_name='Inventory User',
|
||||
role_description='May use this inventory, but not read sensitive portions or modify it',
|
||||
permissions = {'use': True}
|
||||
parent_role=['admin_role'],
|
||||
)
|
||||
executor_role = ImplicitRoleField(
|
||||
adhoc_role = ImplicitRoleField(
|
||||
role_name='Inventory Ad Hoc',
|
||||
role_description='May execute ad hoc commands against this inventory',
|
||||
parent_role=['admin_role'],
|
||||
)
|
||||
execute_role = ImplicitRoleField(
|
||||
role_name='Inventory Executor',
|
||||
role_description='May execute jobs against this inventory',
|
||||
permissions = {'read': True, 'execute': True}
|
||||
parent_role='adhoc_role',
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Read',
|
||||
parent_role=['auditor_role', 'execute_role', 'update_role', 'use_role', 'admin_role'],
|
||||
role_description='May view this inventory',
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
@ -335,7 +343,7 @@ class Host(CommonModelNameNotUnique, ResourceMixin):
|
||||
class Meta:
|
||||
app_label = 'main'
|
||||
unique_together = (("name", "inventory"),) # FIXME: Add ('instance_id', 'inventory') after migration.
|
||||
ordering = ('inventory', 'name')
|
||||
ordering = ('name',)
|
||||
|
||||
inventory = models.ForeignKey(
|
||||
'Inventory',
|
||||
@ -525,22 +533,27 @@ class Group(CommonModelNameNotUnique, ResourceMixin):
|
||||
admin_role = ImplicitRoleField(
|
||||
role_name='Inventory Group Administrator',
|
||||
parent_role=['inventory.admin_role', 'parents.admin_role'],
|
||||
permissions = {'all': True}
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Inventory Group Auditor',
|
||||
parent_role=['inventory.auditor_role', 'parents.auditor_role'],
|
||||
permissions = {'read': True}
|
||||
)
|
||||
updater_role = ImplicitRoleField(
|
||||
update_role = ImplicitRoleField(
|
||||
role_name='Inventory Group Updater',
|
||||
parent_role=['inventory.updater_role', 'parents.updater_role'],
|
||||
permissions = {'read': True, 'write': True, 'create': True, 'use': True},
|
||||
parent_role=['inventory.update_role', 'parents.update_role', 'admin_role'],
|
||||
)
|
||||
executor_role = ImplicitRoleField(
|
||||
adhoc_role = ImplicitRoleField(
|
||||
role_name='Inventory Ad Hoc',
|
||||
parent_role=['inventory.adhoc_role', 'parents.adhoc_role', 'admin_role'],
|
||||
role_description='May execute ad hoc commands against this inventory',
|
||||
)
|
||||
execute_role = ImplicitRoleField(
|
||||
role_name='Inventory Group Executor',
|
||||
parent_role=['inventory.executor_role', 'parents.executor_role'],
|
||||
permissions = {'read':True, 'execute':True},
|
||||
parent_role=['inventory.execute_role', 'parents.execute_role', 'adhoc_role'],
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Inventory Group Executor',
|
||||
parent_role=['execute_role', 'update_role', 'auditor_role', 'admin_role'],
|
||||
)
|
||||
|
||||
def __unicode__(self):
|
||||
@ -1296,21 +1309,23 @@ class CustomInventoryScript(CommonModelNameNotUnique, ResourceMixin):
|
||||
role_name='CustomInventory Administrator',
|
||||
role_description='May manage this inventory',
|
||||
parent_role='organization.admin_role',
|
||||
permissions = {'all': True}
|
||||
)
|
||||
|
||||
member_role = ImplicitRoleField(
|
||||
role_name='CustomInventory Member',
|
||||
role_description='May view but not modify this inventory',
|
||||
parent_role='organization.member_role',
|
||||
permissions = {'read': True}
|
||||
)
|
||||
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='CustomInventory Auditor',
|
||||
role_description='May view but not modify this inventory',
|
||||
parent_role='organization.auditor_role',
|
||||
permissions = {'read': True}
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='CustomInventory Read',
|
||||
role_description='May view but not modify this inventory',
|
||||
parent_role=['auditor_role', 'member_role', 'admin_role'],
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
|
||||
@ -229,18 +229,21 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, ResourceMixin):
|
||||
role_name='Job Template Administrator',
|
||||
role_description='Full access to all settings',
|
||||
parent_role='project.admin_role',
|
||||
permissions = {'all': True}
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Job Template Auditor',
|
||||
role_description='Read-only access to all settings',
|
||||
parent_role='project.auditor_role',
|
||||
permissions = {'read': True}
|
||||
)
|
||||
executor_role = ImplicitRoleField(
|
||||
execute_role = ImplicitRoleField(
|
||||
role_name='Job Template Runner',
|
||||
role_description='May run the job template',
|
||||
permissions = {'read': True, 'execute': True}
|
||||
parent_role=['admin_role'],
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Job Template Runner',
|
||||
role_description='May run the job template',
|
||||
parent_role=['execute_role', 'auditor_role', 'admin_role'],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
||||
@ -1,15 +1,11 @@
|
||||
# Django
|
||||
from django.db import models
|
||||
from django.db.models.aggregates import Max
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.auth.models import User # noqa
|
||||
|
||||
# AWX
|
||||
from awx.main.models.rbac import (
|
||||
get_user_permissions_on_resource,
|
||||
get_role_permissions_on_resource,
|
||||
Role,
|
||||
Role, RoleAncestorEntry, get_roles_on_resource
|
||||
)
|
||||
|
||||
|
||||
@ -20,88 +16,47 @@ class ResourceMixin(models.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
role_permissions = GenericRelation('main.RolePermission')
|
||||
|
||||
@classmethod
|
||||
def accessible_objects(cls, accessor, permissions):
|
||||
def accessible_objects(cls, accessor, role_field):
|
||||
'''
|
||||
Use instead of `MyModel.objects` when you want to only consider
|
||||
resources that a user has specific permissions for. For example:
|
||||
|
||||
MyModel.accessible_objects(user, {'read': True}).filter(name__istartswith='bar');
|
||||
MyModel.accessible_objects(user, 'read_role').filter(name__istartswith='bar');
|
||||
|
||||
NOTE: This should only be used for list type things. If you have a
|
||||
specific resource you want to check permissions on, it is more
|
||||
performant to resolve the resource in question then call
|
||||
`myresource.get_permissions(user)`.
|
||||
'''
|
||||
return ResourceMixin._accessible_objects(cls, accessor, permissions)
|
||||
return ResourceMixin._accessible_objects(cls, accessor, role_field)
|
||||
|
||||
@staticmethod
|
||||
def _accessible_objects(cls, accessor, permissions):
|
||||
def _accessible_objects(cls, accessor, role_field):
|
||||
if type(accessor) == User:
|
||||
qs = cls.objects.filter(
|
||||
role_permissions__role__ancestors__members=accessor
|
||||
)
|
||||
ancestor_roles = accessor.roles.all()
|
||||
elif type(accessor) == Role:
|
||||
qs = cls.objects.filter(
|
||||
role_permissions__role__ancestors=accessor
|
||||
)
|
||||
ancestor_roles = [accessor]
|
||||
else:
|
||||
accessor_type = ContentType.objects.get_for_model(accessor)
|
||||
roles = Role.objects.filter(content_type__pk=accessor_type.id,
|
||||
object_id=accessor.id)
|
||||
qs = cls.objects.filter(
|
||||
role_permissions__role__ancestors__in=roles
|
||||
)
|
||||
|
||||
for perm in permissions:
|
||||
qs = qs.annotate(**{'max_' + perm: Max('role_permissions__' + perm)})
|
||||
qs = qs.filter(**{'max_' + perm: int(permissions[perm])})
|
||||
|
||||
#return cls.objects.filter(resource__in=qs)
|
||||
ancestor_roles = Role.objects.filter(content_type__pk=accessor_type.id,
|
||||
object_id=accessor.id)
|
||||
qs = cls.objects.filter(pk__in =
|
||||
RoleAncestorEntry.objects.filter(
|
||||
ancestor__in=ancestor_roles,
|
||||
content_type_id = ContentType.objects.get_for_model(cls).id,
|
||||
role_field = role_field
|
||||
).values_list('object_id').distinct()
|
||||
)
|
||||
return qs
|
||||
|
||||
|
||||
def get_permissions(self, user):
|
||||
def get_permissions(self, accessor):
|
||||
'''
|
||||
Returns a dict (or None) of the permissions a user has for a given
|
||||
resource.
|
||||
|
||||
Note: Each field in the dict is the `or` of all respective permissions
|
||||
that have been granted to the roles that are applicable for the given
|
||||
user.
|
||||
|
||||
In example, if a user has been granted read access through a permission
|
||||
on one role and write access through a permission on a separate role,
|
||||
the returned dict will denote that the user has both read and write
|
||||
access.
|
||||
Returns a dict (or None) of the roles a accessor has for a given resource.
|
||||
An accessor can be either a User, Role, or an arbitrary resource that
|
||||
contains one or more Roles associated with it.
|
||||
'''
|
||||
|
||||
return get_user_permissions_on_resource(self, user)
|
||||
return get_roles_on_resource(self, accessor)
|
||||
|
||||
|
||||
def get_role_permissions(self, role):
|
||||
'''
|
||||
Returns a dict (or None) of the permissions a role has for a given
|
||||
resource.
|
||||
|
||||
Note: Each field in the dict is the `or` of all respective permissions
|
||||
that have been granted to either the role or any descendents of that role.
|
||||
'''
|
||||
|
||||
return get_role_permissions_on_resource(self, role)
|
||||
|
||||
|
||||
def accessible_by(self, user, permissions):
|
||||
'''
|
||||
Returns true if the user has all of the specified permissions
|
||||
'''
|
||||
|
||||
perms = self.get_permissions(user)
|
||||
if perms is None:
|
||||
return False
|
||||
for k in permissions:
|
||||
if k not in perms or perms[k] < permissions[k]:
|
||||
return False
|
||||
return True
|
||||
|
||||
@ -19,7 +19,6 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from awx.main.fields import AutoOneToOneField, ImplicitRoleField
|
||||
from awx.main.models.base import * # noqa
|
||||
from awx.main.models.rbac import (
|
||||
ALL_PERMISSIONS,
|
||||
ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
|
||||
ROLE_SINGLETON_SYSTEM_AUDITOR,
|
||||
)
|
||||
@ -57,19 +56,21 @@ class Organization(CommonModel, NotificationFieldsModel, ResourceMixin):
|
||||
role_name='Organization Administrator',
|
||||
role_description='May manage all aspects of this organization',
|
||||
parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
|
||||
permissions = ALL_PERMISSIONS,
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Organization Auditor',
|
||||
role_description='May read all settings associated with this organization',
|
||||
parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,
|
||||
permissions = {'read': True}
|
||||
)
|
||||
member_role = ImplicitRoleField(
|
||||
role_name='Organization Member',
|
||||
role_description='A member of this organization',
|
||||
parent_role='admin_role',
|
||||
permissions = {'read': True}
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Organization Read Access',
|
||||
role_description='Read an organization',
|
||||
parent_role=['member_role', 'auditor_role'],
|
||||
)
|
||||
|
||||
|
||||
@ -112,19 +113,20 @@ class Team(CommonModelNameNotUnique, ResourceMixin):
|
||||
role_name='Team Administrator',
|
||||
role_description='May manage this team',
|
||||
parent_role='organization.admin_role',
|
||||
permissions = ALL_PERMISSIONS,
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Team Auditor',
|
||||
role_description='May read all settings associated with this team',
|
||||
parent_role='organization.auditor_role',
|
||||
permissions = {'read': True}
|
||||
)
|
||||
member_role = ImplicitRoleField(
|
||||
role_name='Team Member',
|
||||
role_description='A member of this team',
|
||||
parent_role='admin_role',
|
||||
permissions = {'read':True},
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Read',
|
||||
role_description='Can view this team',
|
||||
parent_role=['admin_role', 'auditor_role', 'member_role'],
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
|
||||
@ -227,7 +227,6 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin):
|
||||
'organization.admin_role',
|
||||
'singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
|
||||
],
|
||||
permissions = {'all': True}
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Project Auditor',
|
||||
@ -236,18 +235,21 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin):
|
||||
'organization.auditor_role',
|
||||
'singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,
|
||||
],
|
||||
permissions = {'read': True}
|
||||
)
|
||||
member_role = ImplicitRoleField(
|
||||
role_name='Project Member',
|
||||
role_description='Implies membership within this project',
|
||||
permissions = {'read': True}
|
||||
parent_role='admin_role',
|
||||
)
|
||||
scm_update_role = ImplicitRoleField(
|
||||
role_name='Project Updater',
|
||||
role_description='May update this project from the source control management system',
|
||||
parent_role='admin_role',
|
||||
permissions = {'scm_update': True}
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Project Read Access',
|
||||
role_description='Read access to this project',
|
||||
parent_role=['member_role', 'auditor_role', 'scm_update_role'],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
||||
@ -7,24 +7,22 @@ import threading
|
||||
import contextlib
|
||||
|
||||
# Django
|
||||
from django.db import models, transaction
|
||||
from django.db import models, transaction, connection
|
||||
from django.db.models import Q
|
||||
from django.db.models.aggregates import Max
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
|
||||
|
||||
# AWX
|
||||
from django.contrib.auth.models import User # noqa
|
||||
from awx.main.models.base import * # noqa
|
||||
|
||||
__all__ = [
|
||||
'Role',
|
||||
'RolePermission',
|
||||
'batch_role_ancestor_rebuilding',
|
||||
'get_user_permissions_on_resource',
|
||||
'get_role_permissions_on_resource',
|
||||
'get_roles_on_resource',
|
||||
'ROLE_SINGLETON_SYSTEM_ADMINISTRATOR',
|
||||
'ROLE_SINGLETON_SYSTEM_AUDITOR',
|
||||
]
|
||||
@ -34,10 +32,6 @@ logger = logging.getLogger('awx.main.models.rbac')
|
||||
ROLE_SINGLETON_SYSTEM_ADMINISTRATOR='System Administrator'
|
||||
ROLE_SINGLETON_SYSTEM_AUDITOR='System Auditor'
|
||||
|
||||
ALL_PERMISSIONS = {'create': True, 'read': True, 'update': True, 'delete': True,
|
||||
'write': True, 'scm_update': True, 'use': True, 'execute': True}
|
||||
|
||||
|
||||
tls = threading.local() # thread local storage
|
||||
|
||||
@contextlib.contextmanager
|
||||
@ -65,9 +59,11 @@ def batch_role_ancestor_rebuilding(allow_nesting=False):
|
||||
if not batch_role_rebuilding:
|
||||
rebuild_set = getattr(tls, 'roles_needing_rebuilding')
|
||||
with transaction.atomic():
|
||||
for role in Role.objects.filter(id__in=list(rebuild_set)).all():
|
||||
# TODO: We can reduce this to one rebuild call with our new upcoming rebuild method.. do this
|
||||
role.rebuild_role_ancestor_list()
|
||||
Role._simultaneous_ancestry_rebuild(list(rebuild_set))
|
||||
|
||||
#for role in Role.objects.filter(id__in=list(rebuild_set)).all():
|
||||
# # TODO: We can reduce this to one rebuild call with our new upcoming rebuild method.. do this
|
||||
# role.rebuild_role_ancestor_list()
|
||||
delattr(tls, 'roles_needing_rebuilding')
|
||||
|
||||
|
||||
@ -82,9 +78,15 @@ class Role(CommonModelNameNotUnique):
|
||||
db_table = 'main_rbac_roles'
|
||||
|
||||
singleton_name = models.TextField(null=True, default=None, db_index=True, unique=True)
|
||||
role_field = models.TextField(null=False, default='')
|
||||
parents = models.ManyToManyField('Role', related_name='children')
|
||||
implicit_parents = models.TextField(null=False, default='[]')
|
||||
ancestors = models.ManyToManyField('Role', related_name='descendents') # auto-generated by `rebuild_role_ancestor_list`
|
||||
ancestors = models.ManyToManyField(
|
||||
'Role',
|
||||
through='RoleAncestorEntry',
|
||||
through_fields=('descendent', 'ancestor'),
|
||||
related_name='descendents'
|
||||
) # auto-generated by `rebuild_role_ancestor_list`
|
||||
members = models.ManyToManyField('auth.User', related_name='roles')
|
||||
content_type = models.ForeignKey(ContentType, null=True, default=None)
|
||||
object_id = models.PositiveIntegerField(null=True, default=None)
|
||||
@ -97,6 +99,18 @@ class Role(CommonModelNameNotUnique):
|
||||
def get_absolute_url(self):
|
||||
return reverse('api:role_detail', args=(self.pk,))
|
||||
|
||||
def __contains__(self, accessor):
|
||||
if type(accessor) == User:
|
||||
return self.ancestors.filter(members=accessor).exists()
|
||||
elif accessor.__class__.__name__ == 'Team':
|
||||
return self.ancestors.filter(pk=accessor.member_role.id).exists()
|
||||
elif type(accessor) == Role:
|
||||
return self.ancestors.filter(pk=accessor).exists()
|
||||
else:
|
||||
accessor_type = ContentType.objects.get_for_model(accessor)
|
||||
roles = Role.objects.filter(content_type__pk=accessor_type.id,
|
||||
object_id=accessor.id)
|
||||
return self.ancestors.filter(pk__in=roles).exists()
|
||||
|
||||
def rebuild_role_ancestor_list(self):
|
||||
'''
|
||||
@ -115,21 +129,191 @@ class Role(CommonModelNameNotUnique):
|
||||
roles_needing_rebuilding.add(self.id)
|
||||
return
|
||||
|
||||
actual_ancestors = set(Role.objects.filter(id=self.id).values_list('parents__ancestors__id', flat=True))
|
||||
actual_ancestors.add(self.id)
|
||||
if None in actual_ancestors:
|
||||
actual_ancestors.remove(None)
|
||||
stored_ancestors = set(self.ancestors.all().values_list('id', flat=True))
|
||||
Role._simultaneous_ancestry_rebuild([self.id])
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _simultaneous_ancestry_rebuild(role_ids_to_rebuild):
|
||||
#
|
||||
# The simple version of what this function is doing
|
||||
# =================================================
|
||||
#
|
||||
# When something changes in our role "hierarchy", we need to update
|
||||
# the `Role.ancestors` mapping to reflect these changes. The basic
|
||||
# idea, which the code in this method is modeled after, is to do
|
||||
# this: When a change happens to a role's parents list, we update
|
||||
# that role's ancestry list, then we recursively update any child
|
||||
# roles ancestry lists. Because our role relationships are not
|
||||
# strictly hierarchical, and can even have loops, this process may
|
||||
# necessarily visit the same nodes more than once. To handle this
|
||||
# without having to keep track of what should be updated (again) and
|
||||
# in what order, we simply use the termination condition of stopping
|
||||
# when our stored ancestry list matches what our list should be, eg,
|
||||
# when nothing changes. This can be simply implemented:
|
||||
#
|
||||
# if actual_ancestors != stored_ancestors:
|
||||
# for id in actual_ancestors - stored_ancestors:
|
||||
# self.ancestors.add(id)
|
||||
# for id in stored_ancestors - actual_ancestors:
|
||||
# self.ancestors.remove(id)
|
||||
#
|
||||
# for child in self.children.all():
|
||||
# child.rebuild_role_ancestor_list()
|
||||
#
|
||||
# However this results in a lot of calls to the database, so the
|
||||
# optimized implementation below effectively does this same thing,
|
||||
# but we update all children at once, so effectively we sweep down
|
||||
# through our hierarchy one layer at a time instead of one node at a
|
||||
# time. Because of how this method works, we can also start from many
|
||||
# roots at once and sweep down a large set of roles, which we take
|
||||
# advantage of when performing bulk operations.
|
||||
#
|
||||
#
|
||||
# SQL Breakdown
|
||||
# =============
|
||||
# The Role ancestors has three columns, (id, from_role_id, to_role_id)
|
||||
#
|
||||
# id: Unqiue row ID
|
||||
# from_role_id: Descendent role ID
|
||||
# to_role_id: Ancestor role ID
|
||||
#
|
||||
# *NOTE* In addition to mapping roles to parents, there also
|
||||
# always exists must exist an entry where
|
||||
#
|
||||
# from_role_id == role_id == to_role_id
|
||||
#
|
||||
# this makes our joins simple when we go to derive permissions or
|
||||
# accessible objects.
|
||||
#
|
||||
#
|
||||
# We operate under the assumption that our parent's ancestor list is
|
||||
# correct, thus we can always compute what our ancestor list should
|
||||
# be by taking the union of our parent's ancestor lists and adding
|
||||
# our self reference entry from_role_id == role_id == to_role_id
|
||||
#
|
||||
# The inner query for the two SQL statements compute this union,
|
||||
# the union of the parent's ancestors and the self referncing entry,
|
||||
# for all roles in the current set of roles to rebuild.
|
||||
#
|
||||
# The DELETE query uses this to select all entries on disk for the
|
||||
# roles we're dealing with, and removes the entries that are not in
|
||||
# this list.
|
||||
#
|
||||
# The INSERT query uses this to select all entries in the list that
|
||||
# are not in the database yet, and inserts all of the missing
|
||||
# records.
|
||||
#
|
||||
# Once complete, we select all of the children for the roles we are
|
||||
# working with, this list becomes the new role list we are working
|
||||
# with.
|
||||
#
|
||||
# When our delete or insert query return that they have not performed
|
||||
# any work, then we know that our children will also not need to be
|
||||
# updated, and so we can terminate our loop.
|
||||
#
|
||||
#
|
||||
|
||||
if len(role_ids_to_rebuild) == 0:
|
||||
return
|
||||
|
||||
cursor = connection.cursor()
|
||||
loop_ct = 0
|
||||
|
||||
sql_params = {
|
||||
'ancestors_table': Role.ancestors.through._meta.db_table,
|
||||
'parents_table': Role.parents.through._meta.db_table,
|
||||
'roles_table': Role._meta.db_table,
|
||||
}
|
||||
|
||||
|
||||
def split_ids_for_sqlite(role_ids):
|
||||
for i in xrange(0, len(role_ids), 999):
|
||||
yield role_ids[i:i + 999]
|
||||
|
||||
for ids in split_ids_for_sqlite(role_ids_to_rebuild):
|
||||
sql_params['ids'] = ','.join(str(x) for x in ids)
|
||||
cursor.execute('''
|
||||
DELETE FROM %(ancestors_table)s
|
||||
WHERE ancestor_id IN (%(ids)s)
|
||||
''' % sql_params)
|
||||
|
||||
|
||||
while role_ids_to_rebuild:
|
||||
if loop_ct > 1000:
|
||||
raise Exception('Ancestry role rebuilding error: infinite loop detected')
|
||||
loop_ct += 1
|
||||
|
||||
delete_ct = 0
|
||||
for ids in split_ids_for_sqlite(role_ids_to_rebuild):
|
||||
sql_params['ids'] = ','.join(str(x) for x in ids)
|
||||
cursor.execute('''
|
||||
DELETE FROM %(ancestors_table)s
|
||||
WHERE descendent_id IN (%(ids)s)
|
||||
AND
|
||||
id NOT IN (
|
||||
SELECT %(ancestors_table)s.id FROM (
|
||||
SELECT parents.from_role_id from_id, ancestors.ancestor_id to_id
|
||||
FROM %(parents_table)s as parents
|
||||
LEFT JOIN %(ancestors_table)s as ancestors
|
||||
ON (parents.to_role_id = ancestors.descendent_id)
|
||||
WHERE parents.from_role_id IN (%(ids)s) AND ancestors.ancestor_id IS NOT NULL
|
||||
|
||||
UNION
|
||||
|
||||
SELECT id from_id, id to_id from %(roles_table)s WHERE id IN (%(ids)s)
|
||||
) new_ancestry_list
|
||||
LEFT JOIN %(ancestors_table)s ON (new_ancestry_list.from_id = %(ancestors_table)s.descendent_id
|
||||
AND new_ancestry_list.to_id = %(ancestors_table)s.ancestor_id)
|
||||
WHERE %(ancestors_table)s.id IS NOT NULL
|
||||
)
|
||||
''' % sql_params)
|
||||
delete_ct += cursor.rowcount
|
||||
|
||||
insert_ct = 0
|
||||
for ids in split_ids_for_sqlite(role_ids_to_rebuild):
|
||||
sql_params['ids'] = ','.join(str(x) for x in ids)
|
||||
cursor.execute('''
|
||||
INSERT INTO %(ancestors_table)s (descendent_id, ancestor_id, role_field, content_type_id, object_id)
|
||||
SELECT from_id, to_id, new_ancestry_list.role_field, new_ancestry_list.content_type_id, new_ancestry_list.object_id FROM (
|
||||
SELECT parents.from_role_id from_id,
|
||||
ancestors.ancestor_id to_id,
|
||||
roles.role_field,
|
||||
COALESCE(roles.content_type_id, 0) content_type_id,
|
||||
COALESCE(roles.object_id, 0) object_id
|
||||
FROM %(parents_table)s as parents
|
||||
INNER JOIN %(roles_table)s as roles ON (parents.from_role_id = roles.id)
|
||||
LEFT OUTER JOIN %(ancestors_table)s as ancestors
|
||||
ON (parents.to_role_id = ancestors.descendent_id)
|
||||
WHERE parents.from_role_id IN (%(ids)s) AND ancestors.ancestor_id IS NOT NULL
|
||||
|
||||
UNION
|
||||
|
||||
SELECT id from_id,
|
||||
id to_id,
|
||||
role_field,
|
||||
COALESCE(content_type_id, 0) content_type_id,
|
||||
COALESCE(object_id, 0) object_id
|
||||
from %(roles_table)s WHERE id IN (%(ids)s)
|
||||
) new_ancestry_list
|
||||
LEFT JOIN %(ancestors_table)s ON (new_ancestry_list.from_id = %(ancestors_table)s.descendent_id
|
||||
AND new_ancestry_list.to_id = %(ancestors_table)s.ancestor_id)
|
||||
WHERE %(ancestors_table)s.id IS NULL
|
||||
''' % sql_params)
|
||||
insert_ct += cursor.rowcount
|
||||
|
||||
if insert_ct == 0 and delete_ct == 0:
|
||||
break
|
||||
|
||||
new_role_ids_to_rebuild = set()
|
||||
for ids in split_ids_for_sqlite(role_ids_to_rebuild):
|
||||
sql_params['ids'] = ','.join(str(x) for x in ids)
|
||||
new_role_ids_to_rebuild.update(set(Role.objects.distinct()
|
||||
.filter(id__in=ids, children__id__isnull=False)
|
||||
.values_list('children__id', flat=True)))
|
||||
role_ids_to_rebuild = list(new_role_ids_to_rebuild)
|
||||
|
||||
|
||||
# If it differs, update, and then update all of our children
|
||||
if actual_ancestors != stored_ancestors:
|
||||
for id in actual_ancestors - stored_ancestors:
|
||||
self.ancestors.add(id)
|
||||
for id in stored_ancestors - actual_ancestors:
|
||||
self.ancestors.remove(id)
|
||||
|
||||
for child in self.children.all():
|
||||
child.rebuild_role_ancestor_list()
|
||||
|
||||
@staticmethod
|
||||
def visible_roles(user):
|
||||
@ -143,109 +327,48 @@ class Role(CommonModelNameNotUnique):
|
||||
def is_ancestor_of(self, role):
|
||||
return role.ancestors.filter(id=self.id).exists()
|
||||
|
||||
|
||||
class RolePermission(CreatedModifiedModel):
|
||||
'''
|
||||
Defines the permissions a role has
|
||||
'''
|
||||
class RoleAncestorEntry(models.Model):
|
||||
|
||||
class Meta:
|
||||
app_label = 'main'
|
||||
verbose_name_plural = _('permissions')
|
||||
db_table = 'main_rbac_permissions'
|
||||
verbose_name_plural = _('role_ancestors')
|
||||
db_table = 'main_rbac_role_ancestors'
|
||||
index_together = [
|
||||
('content_type', 'object_id')
|
||||
("ancestor", "content_type_id", "object_id"), # used by get_roles_on_resource
|
||||
("ancestor", "content_type_id", "role_field"), # used by accessible_objects
|
||||
]
|
||||
|
||||
role = models.ForeignKey(
|
||||
Role,
|
||||
null=False,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='permissions',
|
||||
)
|
||||
content_type = models.ForeignKey(ContentType, null=False, default=None)
|
||||
object_id = models.PositiveIntegerField(null=False, default=None)
|
||||
resource = GenericForeignKey('content_type', 'object_id')
|
||||
auto_generated = models.BooleanField(default=False)
|
||||
|
||||
create = models.IntegerField(default = 0)
|
||||
read = models.IntegerField(default = 0)
|
||||
write = models.IntegerField(default = 0)
|
||||
delete = models.IntegerField(default = 0)
|
||||
update = models.IntegerField(default = 0)
|
||||
execute = models.IntegerField(default = 0)
|
||||
scm_update = models.IntegerField(default = 0)
|
||||
use = models.IntegerField(default = 0)
|
||||
descendent = models.ForeignKey(Role, null=False, on_delete=models.CASCADE, related_name='+')
|
||||
ancestor = models.ForeignKey(Role, null=False, on_delete=models.CASCADE, related_name='+')
|
||||
role_field = models.TextField(null=False)
|
||||
#content_type_id = models.PositiveIntegerField(null=False)
|
||||
#object_id = models.PositiveIntegerField(null=False)
|
||||
content_type_id = models.PositiveIntegerField(null=False)
|
||||
object_id = models.PositiveIntegerField(null=False)
|
||||
|
||||
|
||||
|
||||
def get_user_permissions_on_resource(resource, user):
|
||||
def get_roles_on_resource(resource, accessor):
|
||||
'''
|
||||
Returns a dict (or None) of the permissions a user has for a given
|
||||
resource.
|
||||
|
||||
Note: Each field in the dict is the `or` of all respective permissions
|
||||
that have been granted to the roles that are applicable for the given
|
||||
user.
|
||||
|
||||
In example, if a user has been granted read access through a permission
|
||||
on one role and write access through a permission on a separate role,
|
||||
the returned dict will denote that the user has both read and write
|
||||
access.
|
||||
Returns a dict (or None) of the roles a accessor has for a given resource.
|
||||
An accessor can be either a User, Role, or an arbitrary resource that
|
||||
contains one or more Roles associated with it.
|
||||
'''
|
||||
|
||||
if type(user) == User:
|
||||
roles = user.roles.all()
|
||||
if type(accessor) == User:
|
||||
roles = accessor.roles.all()
|
||||
elif type(accessor) == Role:
|
||||
roles = [accessor]
|
||||
else:
|
||||
accessor_type = ContentType.objects.get_for_model(user)
|
||||
accessor_type = ContentType.objects.get_for_model(accessor)
|
||||
roles = Role.objects.filter(content_type__pk=accessor_type.id,
|
||||
object_id=user.id)
|
||||
object_id=accessor.id)
|
||||
|
||||
qs = RolePermission.objects.filter(
|
||||
content_type=ContentType.objects.get_for_model(resource),
|
||||
object_id=resource.id,
|
||||
role__ancestors__in=roles,
|
||||
)
|
||||
return {
|
||||
role_field: True for role_field in
|
||||
RoleAncestorEntry.objects.filter(
|
||||
ancestor__in=roles,
|
||||
content_type_id=ContentType.objects.get_for_model(resource).id,
|
||||
object_id=resource.id
|
||||
).values_list('role_field', flat=True)
|
||||
}
|
||||
|
||||
res = qs = qs.aggregate(
|
||||
create = Max('create'),
|
||||
read = Max('read'),
|
||||
write = Max('write'),
|
||||
update = Max('update'),
|
||||
delete = Max('delete'),
|
||||
scm_update = Max('scm_update'),
|
||||
execute = Max('execute'),
|
||||
use = Max('use')
|
||||
)
|
||||
if res['read'] is None:
|
||||
return None
|
||||
return res
|
||||
|
||||
def get_role_permissions_on_resource(resource, role):
|
||||
'''
|
||||
Returns a dict (or None) of the permissions a role has for a given
|
||||
resource.
|
||||
|
||||
Note: Each field in the dict is the `or` of all respective permissions
|
||||
that have been granted to either the role or any descendents of that role.
|
||||
'''
|
||||
|
||||
qs = RolePermission.objects.filter(
|
||||
content_type=ContentType.objects.get_for_model(resource),
|
||||
object_id=resource.id,
|
||||
role__ancestors=role
|
||||
)
|
||||
|
||||
res = qs = qs.aggregate(
|
||||
create = Max('create'),
|
||||
read = Max('read'),
|
||||
write = Max('write'),
|
||||
update = Max('update'),
|
||||
delete = Max('delete'),
|
||||
scm_update = Max('scm_update'),
|
||||
execute = Max('execute'),
|
||||
use = Max('use')
|
||||
)
|
||||
if res['read'] is None:
|
||||
return None
|
||||
return res
|
||||
|
||||
@ -106,13 +106,14 @@ def emit_update_inventory_on_created_or_deleted(sender, **kwargs):
|
||||
if inventory is not None:
|
||||
update_inventory_computed_fields.delay(inventory.id, True)
|
||||
|
||||
def rebuild_role_ancestor_list(reverse, model, instance, pk_set, **kwargs):
|
||||
def rebuild_role_ancestor_list(reverse, model, instance, pk_set, action, **kwargs):
|
||||
'When a role parent is added or removed, update our role hierarchy list'
|
||||
if reverse:
|
||||
for id in pk_set:
|
||||
model.objects.get(id=id).rebuild_role_ancestor_list()
|
||||
else:
|
||||
instance.rebuild_role_ancestor_list()
|
||||
if action in ['post_add', 'post_remove', 'post_clear']:
|
||||
if reverse:
|
||||
for id in pk_set:
|
||||
model.objects.get(id=id).rebuild_role_ancestor_list()
|
||||
else:
|
||||
instance.rebuild_role_ancestor_list()
|
||||
|
||||
def sync_superuser_status_to_rbac(instance, **kwargs):
|
||||
'When the is_superuser flag is changed on a user, reflect that in the membership of the System Admnistrator role'
|
||||
@ -126,21 +127,15 @@ def create_user_role(instance, **kwargs):
|
||||
Role.objects.get(
|
||||
content_type=ContentType.objects.get_for_model(instance),
|
||||
object_id=instance.id,
|
||||
name = 'Owner'
|
||||
name = 'User Admin'
|
||||
)
|
||||
except Role.DoesNotExist:
|
||||
role = Role.objects.create(
|
||||
name = 'Owner',
|
||||
name = 'User Admin',
|
||||
role_field='admin_role',
|
||||
content_object = instance,
|
||||
)
|
||||
role.members.add(instance)
|
||||
RolePermission.objects.create(
|
||||
role = role,
|
||||
resource = instance,
|
||||
auto_generated = True,
|
||||
create=1, read=1, write=1, delete=1, update=1,
|
||||
execute=1, scm_update=1, use=1,
|
||||
)
|
||||
|
||||
def org_admin_edit_members(instance, action, model, reverse, pk_set, **kwargs):
|
||||
content_type = ContentType.objects.get_for_model(Organization)
|
||||
@ -157,101 +152,6 @@ def org_admin_edit_members(instance, action, model, reverse, pk_set, **kwargs):
|
||||
if action == 'pre_remove':
|
||||
instance.content_object.admin_role.children.remove(user.admin_role)
|
||||
|
||||
def grant_host_access_to_group_roles(instance, action, model, reverse, pk_set, **kwargs):
|
||||
'Add/remove RolePermission entries for Group roles that contain this host'
|
||||
|
||||
if action == 'post_add':
|
||||
def grant(host, group):
|
||||
RolePermission.objects.create(
|
||||
resource=host,
|
||||
role=group.admin_role,
|
||||
auto_generated=True,
|
||||
create=1,
|
||||
read=1, write=1,
|
||||
delete=1,
|
||||
update=1,
|
||||
execute=1,
|
||||
scm_update=1,
|
||||
use=1,
|
||||
)
|
||||
RolePermission.objects.create(
|
||||
resource=host,
|
||||
role=group.auditor_role,
|
||||
auto_generated=True,
|
||||
read=1,
|
||||
)
|
||||
RolePermission.objects.create(
|
||||
resource=host,
|
||||
role=group.updater_role,
|
||||
auto_generated=True,
|
||||
read=1,
|
||||
write=1,
|
||||
create=1,
|
||||
use=1
|
||||
)
|
||||
RolePermission.objects.create(
|
||||
resource=host,
|
||||
role=group.executor_role,
|
||||
auto_generated=True,
|
||||
read=1,
|
||||
execute=1
|
||||
)
|
||||
|
||||
if reverse:
|
||||
host = instance
|
||||
for group_id in pk_set:
|
||||
grant(host, Group.objects.get(id=group_id))
|
||||
else:
|
||||
group = instance
|
||||
for host_id in pk_set:
|
||||
grant(Host.objects.get(id=host_id), group)
|
||||
|
||||
if action == 'pre_remove':
|
||||
host_content_type = ContentType.objects.get_for_model(Host)
|
||||
|
||||
def remove_grant(host, group):
|
||||
RolePermission.objects.filter(
|
||||
content_type = host_content_type,
|
||||
object_id = host.id,
|
||||
auto_generated = True,
|
||||
role__in = [group.admin_role, group.updater_role, group.auditor_role, group.executor_role]
|
||||
).delete()
|
||||
|
||||
if reverse:
|
||||
host = instance
|
||||
for group_id in pk_set:
|
||||
remove_grant(host, Group.objects.get(id=group_id))
|
||||
else:
|
||||
group = instance
|
||||
for host_id in pk_set:
|
||||
remove_grant(Host.objects.get(id=host_id), group)
|
||||
|
||||
|
||||
def grant_host_access_to_inventory(instance, **kwargs):
|
||||
'Add/remove RolePermission entries for the Inventory that contains this host'
|
||||
host_content_type = ContentType.objects.get_for_model(Host)
|
||||
inventory_content_type = ContentType.objects.get_for_model(Inventory)
|
||||
|
||||
# Clear out any existing perms.. in case we switched inventory or something
|
||||
qs = RolePermission.objects.filter(
|
||||
content_type=host_content_type,
|
||||
object_id=instance.id,
|
||||
auto_generated=True,
|
||||
role__content_type=inventory_content_type
|
||||
)
|
||||
if qs.count() == 1 and qs[0].role.object_id == instance.inventory.id:
|
||||
# No change
|
||||
return
|
||||
qs.delete()
|
||||
|
||||
RolePermission.objects.create(
|
||||
resource=instance,
|
||||
role=instance.inventory.admin_role,
|
||||
auto_generated=True,
|
||||
create=1, read=1, write=1, delete=1, update=1,
|
||||
execute=1, scm_update=1, use=1,
|
||||
)
|
||||
|
||||
|
||||
post_save.connect(emit_update_inventory_on_created_or_deleted, sender=Host)
|
||||
post_delete.connect(emit_update_inventory_on_created_or_deleted, sender=Host)
|
||||
@ -269,8 +169,6 @@ post_save.connect(emit_job_event_detail, sender=JobEvent)
|
||||
post_save.connect(emit_ad_hoc_command_event_detail, sender=AdHocCommandEvent)
|
||||
m2m_changed.connect(rebuild_role_ancestor_list, Role.parents.through)
|
||||
m2m_changed.connect(org_admin_edit_members, Role.members.through)
|
||||
m2m_changed.connect(grant_host_access_to_group_roles, Group.hosts.through)
|
||||
post_save.connect(grant_host_access_to_inventory, Host)
|
||||
post_save.connect(sync_superuser_status_to_rbac, sender=User)
|
||||
post_save.connect(create_user_role, sender=User)
|
||||
|
||||
|
||||
@ -661,4 +661,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -340,4 +340,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -270,4 +270,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -255,4 +255,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -268,4 +268,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -257,4 +257,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -405,4 +405,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -518,4 +518,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -327,4 +327,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -331,4 +331,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -336,4 +336,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -335,4 +335,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -427,4 +427,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -388,4 +388,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -497,4 +497,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -451,4 +451,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -501,4 +501,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -464,4 +464,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -395,4 +395,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -417,4 +417,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -427,4 +427,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -442,4 +442,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -1408,4 +1408,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -792,4 +792,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -497,4 +497,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -449,4 +449,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -436,4 +436,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -437,4 +437,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -440,4 +440,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -450,4 +450,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -493,4 +493,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -510,4 +510,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -572,4 +572,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -519,4 +519,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -520,4 +520,4 @@ class Migration(SchemaMigration):
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
complete_apps = ['main']
|
||||
|
||||
@ -3,6 +3,7 @@ import yaml
|
||||
|
||||
from awx.api.serializers import JobLaunchSerializer
|
||||
from awx.main.models.credential import Credential
|
||||
from awx.main.models.inventory import Inventory
|
||||
from awx.main.models.jobs import Job, JobTemplate
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
@ -93,8 +94,7 @@ def test_job_accept_prompted_vars(runtime_data, job_template_prompts, post, user
|
||||
job_template = job_template_prompts(True)
|
||||
admin_user = user('admin', True)
|
||||
|
||||
job_template.inventory.executor_role.members.add(admin_user)
|
||||
job_template.inventory.save()
|
||||
job_template.inventory.execute_role.members.add(admin_user)
|
||||
|
||||
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
|
||||
runtime_data, admin_user)
|
||||
@ -112,20 +112,19 @@ def test_job_accept_prompted_vars(runtime_data, job_template_prompts, post, user
|
||||
assert job_obj.job_tags == runtime_data['job_tags']
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.skip(reason="JT can_start without inventory needs to be fixed before passing")
|
||||
@pytest.mark.job_runtime_vars
|
||||
def test_job_accept_prompted_vars_null(runtime_data, job_template_prompts_null, post, user):
|
||||
job_template = job_template_prompts_null
|
||||
common_user = user('admin', False)
|
||||
common_user = user('not-admin', False)
|
||||
|
||||
job_template.executor_role.members.add(common_user)
|
||||
job_template.save()
|
||||
job_template.project.member_role.members.add(common_user)
|
||||
job_template.project.save()
|
||||
# Give user permission to execute the job template
|
||||
job_template.execute_role.members.add(common_user)
|
||||
|
||||
# Give user permission to use inventory and credential at runtime
|
||||
credential = Credential.objects.get(pk=runtime_data['credential'])
|
||||
credential.usage_role.members.add(common_user)
|
||||
credential.save()
|
||||
credential.use_role.members.add(common_user)
|
||||
inventory = Inventory.objects.get(pk=runtime_data['inventory'])
|
||||
inventory.use_role.members.add(common_user)
|
||||
|
||||
response = post(reverse('api:job_template_launch', args=[job_template.pk]),
|
||||
runtime_data, common_user)
|
||||
@ -186,15 +185,12 @@ def test_job_launch_fails_without_inventory(deploy_jobtemplate, post, user):
|
||||
def test_job_launch_fails_without_inventory_access(deploy_jobtemplate, machine_credential, post, user):
|
||||
deploy_jobtemplate.ask_inventory_on_launch = True
|
||||
deploy_jobtemplate.credential = machine_credential
|
||||
common_user = user('test-user', False)
|
||||
deploy_jobtemplate.executor_role.members.add(common_user)
|
||||
deploy_jobtemplate.save()
|
||||
deploy_jobtemplate.inventory.usage_role.members.add(common_user)
|
||||
deploy_jobtemplate.inventory.save()
|
||||
common_user = user('test-user', False)
|
||||
deploy_jobtemplate.execute_role.members.add(common_user)
|
||||
deploy_jobtemplate.inventory.use_role.members.add(common_user)
|
||||
deploy_jobtemplate.project.member_role.members.add(common_user)
|
||||
deploy_jobtemplate.project.save()
|
||||
deploy_jobtemplate.credential.usage_role.members.add(common_user)
|
||||
deploy_jobtemplate.credential.save()
|
||||
deploy_jobtemplate.credential.use_role.members.add(common_user)
|
||||
|
||||
# Assure that the base job template can be launched to begin with
|
||||
response = post(reverse('api:job_template_launch',
|
||||
|
||||
@ -3,72 +3,118 @@ import pytest
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
@pytest.fixture
|
||||
def resourced_organization(organization, project, team, inventory, user):
|
||||
admin_user = user('test-admin', True)
|
||||
member_user = user('org-member')
|
||||
def organization_resource_creator(organization, user):
|
||||
def rf(users, admins, job_templates, projects, inventories, teams):
|
||||
|
||||
# Associate one resource of every type with the organization
|
||||
organization.member_role.members.add(member_user)
|
||||
organization.admin_role.members.add(admin_user)
|
||||
# organization.teams.create(name='org-team')
|
||||
# inventory = organization.inventories.create(name="associated-inv")
|
||||
project.jobtemplates.create(name="test-jt",
|
||||
description="test-job-template-desc",
|
||||
inventory=inventory,
|
||||
playbook="test_playbook.yml")
|
||||
# Associate one resource of every type with the organization
|
||||
for i in range(users):
|
||||
member_user = user('org-member %s' % i)
|
||||
organization.member_role.members.add(member_user)
|
||||
for i in range(admins):
|
||||
admin_user = user('org-admin %s' % i)
|
||||
organization.admin_role.members.add(admin_user)
|
||||
for i in range(teams):
|
||||
organization.teams.create(name='org-team %s' % i)
|
||||
for i in range(inventories):
|
||||
inventory = organization.inventories.create(name="associated-inv %s" % i)
|
||||
for i in range(projects):
|
||||
organization.projects.create(name="test-proj %s" % i,
|
||||
description="test-proj-desc",
|
||||
scm_type="git",
|
||||
scm_url="https://github.com/jlaska/ansible-playbooks")
|
||||
# Mix up the inventories and projects used by the job templates
|
||||
i_proj = 0
|
||||
i_inv = 0
|
||||
for i in range(job_templates):
|
||||
project = organization.projects.all()[i_proj]
|
||||
inventory = organization.inventories.all()[i_inv]
|
||||
project.jobtemplates.create(name="test-jt %s" % i,
|
||||
description="test-job-template-desc",
|
||||
inventory=inventory,
|
||||
playbook="test_playbook.yml")
|
||||
i_proj += 1
|
||||
i_inv += 1
|
||||
if i_proj >= organization.projects.count():
|
||||
i_proj = 0
|
||||
if i_inv >= organization.inventories.count():
|
||||
i_inv = 0
|
||||
|
||||
return organization
|
||||
return organization
|
||||
return rf
|
||||
|
||||
COUNTS_PRIMES = {
|
||||
'users': 11,
|
||||
'admins': 5,
|
||||
'job_templates': 3,
|
||||
'projects': 3,
|
||||
'inventories': 7,
|
||||
'teams': 5
|
||||
}
|
||||
COUNTS_ZEROS = {
|
||||
'users': 0,
|
||||
'admins': 0,
|
||||
'job_templates': 0,
|
||||
'projects': 0,
|
||||
'inventories': 0,
|
||||
'teams': 0
|
||||
}
|
||||
|
||||
@pytest.fixture
|
||||
def resourced_organization(organization_resource_creator):
|
||||
return organization_resource_creator(**COUNTS_PRIMES)
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_org_counts_detail_view(resourced_organization, user, get):
|
||||
def test_org_counts_detail_admin(resourced_organization, user, get):
|
||||
# Check that all types of resources are counted by a superuser
|
||||
external_admin = user('admin', True)
|
||||
response = get(reverse('api:organization_detail',
|
||||
args=[resourced_organization.pk]), external_admin)
|
||||
assert response.status_code == 200
|
||||
|
||||
counts = response.data['summary_fields']['related_field_counts']
|
||||
assert counts == COUNTS_PRIMES
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_org_counts_detail_member(resourced_organization, user, get):
|
||||
# Check that a non-admin org member can only see users / admin in detail view
|
||||
member_user = resourced_organization.member_role.members.get(username='org-member 1')
|
||||
response = get(reverse('api:organization_detail',
|
||||
args=[resourced_organization.pk]), member_user)
|
||||
assert response.status_code == 200
|
||||
|
||||
counts = response.data['summary_fields']['related_field_counts']
|
||||
assert counts == {
|
||||
'users': 1,
|
||||
'admins': 1,
|
||||
'job_templates': 1,
|
||||
'projects': 1,
|
||||
'inventories': 1,
|
||||
'teams': 1
|
||||
'users': COUNTS_PRIMES['users'], # Policy is that members can see other users and admins
|
||||
'admins': COUNTS_PRIMES['admins'],
|
||||
'job_templates': 0,
|
||||
'projects': 0,
|
||||
'inventories': 0,
|
||||
'teams': 0
|
||||
}
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.skipif("True") # XXX: This needs to be implemented
|
||||
def test_org_counts_admin(resourced_organization, user, get):
|
||||
def test_org_counts_list_admin(resourced_organization, user, get):
|
||||
# Check that all types of resources are counted by a superuser
|
||||
external_admin = user('admin', True)
|
||||
response = get(reverse('api:organization_list', args=[]), external_admin)
|
||||
assert response.status_code == 200
|
||||
|
||||
counts = response.data['results'][0]['summary_fields']['related_field_counts']
|
||||
assert counts == {
|
||||
'users': 1,
|
||||
'admins': 1,
|
||||
'job_templates': 1,
|
||||
'projects': 1,
|
||||
'inventories': 1,
|
||||
'teams': 1
|
||||
}
|
||||
assert counts == COUNTS_PRIMES
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_org_counts_member(resourced_organization, get):
|
||||
def test_org_counts_list_member(resourced_organization, user, get):
|
||||
# Check that a non-admin user can only see the full project and
|
||||
# user count, consistent with the RBAC rules
|
||||
member_user = resourced_organization.member_role.members.get(username='org-member')
|
||||
member_user = resourced_organization.member_role.members.get(username='org-member 1')
|
||||
response = get(reverse('api:organization_list', args=[]), member_user)
|
||||
assert response.status_code == 200
|
||||
|
||||
counts = response.data['results'][0]['summary_fields']['related_field_counts']
|
||||
|
||||
assert counts == {
|
||||
'users': 1, # Policy is that members can see other users and admins
|
||||
'admins': 1,
|
||||
'users': COUNTS_PRIMES['users'], # Policy is that members can see other users and admins
|
||||
'admins': COUNTS_PRIMES['admins'],
|
||||
'job_templates': 0,
|
||||
'projects': 0,
|
||||
'inventories': 0,
|
||||
@ -86,17 +132,9 @@ def test_new_org_zero_counts(user, post):
|
||||
|
||||
new_org_list = post_response.render().data
|
||||
counts_dict = new_org_list['summary_fields']['related_field_counts']
|
||||
assert counts_dict == {
|
||||
'users': 0,
|
||||
'admins': 0,
|
||||
'job_templates': 0,
|
||||
'projects': 0,
|
||||
'inventories': 0,
|
||||
'teams': 0
|
||||
}
|
||||
assert counts_dict == COUNTS_ZEROS
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.skipif("True") # XXX: This needs to be implemented
|
||||
def test_two_organizations(resourced_organization, organizations, user, get):
|
||||
# Check correct results for two organizations are returned
|
||||
external_admin = user('admin', True)
|
||||
@ -111,26 +149,10 @@ def test_two_organizations(resourced_organization, organizations, user, get):
|
||||
org_id = response.data['results'][i]['id']
|
||||
counts[org_id] = response.data['results'][i]['summary_fields']['related_field_counts']
|
||||
|
||||
assert counts[org_id_full] == {
|
||||
'users': 1,
|
||||
'admins': 1,
|
||||
'job_templates': 1,
|
||||
'projects': 1,
|
||||
'inventories': 1,
|
||||
'teams': 1
|
||||
}
|
||||
assert counts[org_id_zero] == {
|
||||
'users': 0,
|
||||
'admins': 0,
|
||||
'job_templates': 0,
|
||||
'projects': 0,
|
||||
'inventories': 0,
|
||||
'teams': 0
|
||||
}
|
||||
assert counts[org_id_full] == COUNTS_PRIMES
|
||||
assert counts[org_id_zero] == COUNTS_ZEROS
|
||||
|
||||
@pytest.mark.skip(reason="resolution planned for after RBAC merge")
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.skipif("True") # XXX: This needs to be implemented
|
||||
def test_JT_associated_with_project(organizations, project, user, get):
|
||||
# Check that adding a project to an organization gets the project's JT
|
||||
# included in the organization's JT count
|
||||
@ -163,4 +185,3 @@ def test_JT_associated_with_project(organizations, project, user, get):
|
||||
'inventories': 0,
|
||||
'teams': 0
|
||||
}
|
||||
|
||||
|
||||
@ -11,9 +11,11 @@ from awx.main.models import Project
|
||||
#
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_user_project_list(get, project_factory, admin, alice, bob):
|
||||
def test_user_project_list(get, project_factory, organization, admin, alice, bob):
|
||||
'List of projects a user has access to, filtered by projects you can also see'
|
||||
|
||||
organization.member_role.members.add(alice, bob)
|
||||
|
||||
alice_project = project_factory('alice project')
|
||||
alice_project.admin_role.members.add(alice)
|
||||
|
||||
|
||||
@ -176,8 +176,9 @@ def test_get_teams_roles_list(get, team, organization, admin):
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
roles = response.data
|
||||
assert roles['count'] == 1
|
||||
assert roles['results'][0]['id'] == organization.admin_role.id
|
||||
|
||||
assert roles['count'] == 2
|
||||
assert roles['results'][0]['id'] == organization.admin_role.id or roles['results'][1]['id'] == organization.admin_role.id
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@ -272,13 +273,11 @@ def test_org_admin_add_user_to_job_template(post, organization, check_jobtemplat
|
||||
joe = user('joe')
|
||||
organization.admin_role.members.add(org_admin)
|
||||
|
||||
assert check_jobtemplate.accessible_by(org_admin, {'write': True}) is True
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is False
|
||||
assert org_admin in check_jobtemplate.admin_role
|
||||
assert joe not in check_jobtemplate.execute_role
|
||||
|
||||
res =post(reverse('api:role_users_list', args=(check_jobtemplate.executor_role.id,)), {'id': joe.id}, org_admin)
|
||||
|
||||
print(res.data)
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is True
|
||||
post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'id': joe.id}, org_admin)
|
||||
assert joe in check_jobtemplate.execute_role
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
@ -287,14 +286,14 @@ def test_org_admin_remove_user_to_job_template(post, organization, check_jobtemp
|
||||
org_admin = user('org-admin')
|
||||
joe = user('joe')
|
||||
organization.admin_role.members.add(org_admin)
|
||||
check_jobtemplate.executor_role.members.add(joe)
|
||||
check_jobtemplate.execute_role.members.add(joe)
|
||||
|
||||
assert check_jobtemplate.accessible_by(org_admin, {'write': True}) is True
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is True
|
||||
assert org_admin in check_jobtemplate.admin_role
|
||||
assert joe in check_jobtemplate.execute_role
|
||||
|
||||
post(reverse('api:role_users_list', args=(check_jobtemplate.executor_role.id,)), {'disassociate': True, 'id': joe.id}, org_admin)
|
||||
post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'disassociate': True, 'id': joe.id}, org_admin)
|
||||
assert joe not in check_jobtemplate.execute_role
|
||||
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is False
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_user_fail_to_add_user_to_job_template(post, organization, check_jobtemplate, user):
|
||||
@ -302,14 +301,13 @@ def test_user_fail_to_add_user_to_job_template(post, organization, check_jobtemp
|
||||
rando = user('rando')
|
||||
joe = user('joe')
|
||||
|
||||
assert check_jobtemplate.accessible_by(rando, {'write': True}) is False
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is False
|
||||
assert rando not in check_jobtemplate.admin_role
|
||||
assert joe not in check_jobtemplate.execute_role
|
||||
|
||||
res = post(reverse('api:role_users_list', args=(check_jobtemplate.executor_role.id,)), {'id': joe.id}, rando)
|
||||
print(res.data)
|
||||
res = post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'id': joe.id}, rando)
|
||||
assert res.status_code == 403
|
||||
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is False
|
||||
assert joe not in check_jobtemplate.execute_role
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
@ -317,16 +315,15 @@ def test_user_fail_to_remove_user_to_job_template(post, organization, check_jobt
|
||||
'Tests that a user without permissions to assign/revoke membership to a particular role cannot do so'
|
||||
rando = user('rando')
|
||||
joe = user('joe')
|
||||
check_jobtemplate.executor_role.members.add(joe)
|
||||
check_jobtemplate.execute_role.members.add(joe)
|
||||
|
||||
assert check_jobtemplate.accessible_by(rando, {'write': True}) is False
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is True
|
||||
assert rando not in check_jobtemplate.admin_role
|
||||
assert joe in check_jobtemplate.execute_role
|
||||
|
||||
res = post(reverse('api:role_users_list', args=(check_jobtemplate.executor_role.id,)), {'disassociate': True, 'id': joe.id}, rando)
|
||||
res = post(reverse('api:role_users_list', args=(check_jobtemplate.execute_role.id,)), {'disassociate': True, 'id': joe.id}, rando)
|
||||
assert res.status_code == 403
|
||||
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is True
|
||||
|
||||
assert joe in check_jobtemplate.execute_role
|
||||
|
||||
#
|
||||
# /roles/<id>/teams/
|
||||
@ -384,8 +381,8 @@ def test_role_children(get, team, admin, role):
|
||||
url = reverse('api:role_children_list', args=(team.member_role.id,))
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
assert response.data['count'] == 1
|
||||
assert response.data['results'][0]['id'] == role.id
|
||||
assert response.data['count'] == 2
|
||||
assert response.data['results'][0]['id'] == role.id or response.data['results'][1]['id'] == role.id
|
||||
|
||||
|
||||
|
||||
@ -421,7 +418,7 @@ def test_ensure_permissions_is_present(organization, get, user):
|
||||
|
||||
assert 'summary_fields' in org
|
||||
assert 'permissions' in org['summary_fields']
|
||||
assert org['summary_fields']['permissions']['read'] > 0
|
||||
assert org['summary_fields']['permissions']['read_role'] > 0
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_ensure_role_summary_is_present(organization, get, user):
|
||||
|
||||
@ -2,7 +2,6 @@ import pytest
|
||||
|
||||
from awx.main.models import (
|
||||
Role,
|
||||
RolePermission,
|
||||
Organization,
|
||||
Project,
|
||||
)
|
||||
@ -10,27 +9,25 @@ from awx.main.models import (
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_auto_inheritance_by_children(organization, alice):
|
||||
A = Role.objects.create(name='A')
|
||||
B = Role.objects.create(name='B')
|
||||
A = Role.objects.create(name='A', role_field='')
|
||||
B = Role.objects.create(name='B', role_field='')
|
||||
A.members.add(alice)
|
||||
|
||||
|
||||
|
||||
assert organization.accessible_by(alice, {'read': True}) is False
|
||||
assert Organization.accessible_objects(alice, {'read': True}).count() == 0
|
||||
assert alice not in organization.admin_role
|
||||
assert Organization.accessible_objects(alice, 'admin_role').count() == 0
|
||||
A.children.add(B)
|
||||
assert organization.accessible_by(alice, {'read': True}) is False
|
||||
assert Organization.accessible_objects(alice, {'read': True}).count() == 0
|
||||
assert alice not in organization.admin_role
|
||||
assert Organization.accessible_objects(alice, 'admin_role').count() == 0
|
||||
A.children.add(organization.admin_role)
|
||||
assert organization.accessible_by(alice, {'read': True}) is True
|
||||
assert Organization.accessible_objects(alice, {'read': True}).count() == 1
|
||||
assert alice in organization.admin_role
|
||||
assert Organization.accessible_objects(alice, 'admin_role').count() == 1
|
||||
A.children.remove(organization.admin_role)
|
||||
assert organization.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in organization.admin_role
|
||||
B.children.add(organization.admin_role)
|
||||
assert organization.accessible_by(alice, {'read': True}) is True
|
||||
assert alice in organization.admin_role
|
||||
B.children.remove(organization.admin_role)
|
||||
assert organization.accessible_by(alice, {'read': True}) is False
|
||||
assert Organization.accessible_objects(alice, {'read': True}).count() == 0
|
||||
assert alice not in organization.admin_role
|
||||
assert Organization.accessible_objects(alice, 'admin_role').count() == 0
|
||||
|
||||
# We've had the case where our pre/post save init handlers in our field descriptors
|
||||
# end up creating a ton of role objects because of various not-so-obvious issues
|
||||
@ -43,32 +40,19 @@ def test_auto_inheritance_by_parents(organization, alice):
|
||||
B = Role.objects.create(name='B')
|
||||
A.members.add(alice)
|
||||
|
||||
assert organization.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in organization.admin_role
|
||||
B.parents.add(A)
|
||||
assert organization.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in organization.admin_role
|
||||
organization.admin_role.parents.add(A)
|
||||
assert organization.accessible_by(alice, {'read': True}) is True
|
||||
assert alice in organization.admin_role
|
||||
organization.admin_role.parents.remove(A)
|
||||
assert organization.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in organization.admin_role
|
||||
organization.admin_role.parents.add(B)
|
||||
assert organization.accessible_by(alice, {'read': True}) is True
|
||||
assert alice in organization.admin_role
|
||||
organization.admin_role.parents.remove(B)
|
||||
assert organization.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in organization.admin_role
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_permission_union(organization, alice):
|
||||
A = Role.objects.create(name='A')
|
||||
A.members.add(alice)
|
||||
B = Role.objects.create(name='B')
|
||||
B.members.add(alice)
|
||||
|
||||
assert organization.accessible_by(alice, {'read': True, 'write': True}) is False
|
||||
RolePermission.objects.create(role=A, resource=organization, read=True)
|
||||
assert organization.accessible_by(alice, {'read': True, 'write': True}) is False
|
||||
RolePermission.objects.create(role=A, resource=organization, write=True)
|
||||
assert organization.accessible_by(alice, {'read': True, 'write': True}) is True
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_accessible_objects(organization, alice, bob):
|
||||
@ -78,57 +62,54 @@ def test_accessible_objects(organization, alice, bob):
|
||||
B.members.add(alice)
|
||||
B.members.add(bob)
|
||||
|
||||
assert Organization.accessible_objects(alice, {'read': True, 'write': True}).count() == 0
|
||||
RolePermission.objects.create(role=A, resource=organization, read=True)
|
||||
assert Organization.accessible_objects(alice, {'read': True, 'write': True}).count() == 0
|
||||
assert Organization.accessible_objects(bob, {'read': True, 'write': True}).count() == 0
|
||||
RolePermission.objects.create(role=B, resource=organization, write=True)
|
||||
assert Organization.accessible_objects(alice, {'read': True, 'write': True}).count() == 1
|
||||
assert Organization.accessible_objects(bob, {'read': True, 'write': True}).count() == 0
|
||||
assert Organization.accessible_objects(bob, {'read': True, 'write': True}).count() == 0
|
||||
assert Organization.accessible_objects(alice, 'admin_role').count() == 0
|
||||
assert Organization.accessible_objects(bob, 'admin_role').count() == 0
|
||||
A.children.add(organization.admin_role)
|
||||
assert Organization.accessible_objects(alice, 'admin_role').count() == 1
|
||||
assert Organization.accessible_objects(bob, 'admin_role').count() == 0
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_team_symantics(organization, team, alice):
|
||||
assert organization.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in organization.auditor_role
|
||||
team.member_role.children.add(organization.auditor_role)
|
||||
assert organization.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in organization.auditor_role
|
||||
team.member_role.members.add(alice)
|
||||
assert organization.accessible_by(alice, {'read': True}) is True
|
||||
assert alice in organization.auditor_role
|
||||
team.member_role.members.remove(alice)
|
||||
assert organization.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in organization.auditor_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_auto_m2m_adjuments(organization, inventory, group, alice):
|
||||
def test_auto_m2m_adjustments(organization, inventory, group, alice):
|
||||
'Ensures the auto role reparenting is working correctly through m2m maps'
|
||||
g1 = group(name='g1')
|
||||
g1.admin_role.members.add(alice)
|
||||
assert g1.accessible_by(alice, {'read': True}) is True
|
||||
assert alice in g1.admin_role
|
||||
g2 = group(name='g2')
|
||||
assert g2.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in g2.admin_role
|
||||
|
||||
g2.parents.add(g1)
|
||||
assert g2.accessible_by(alice, {'read': True}) is True
|
||||
assert alice in g2.admin_role
|
||||
g2.parents.remove(g1)
|
||||
assert g2.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in g2.admin_role
|
||||
|
||||
g1.children.add(g2)
|
||||
assert g2.accessible_by(alice, {'read': True}) is True
|
||||
assert alice in g2.admin_role
|
||||
g1.children.remove(g2)
|
||||
assert g2.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in g2.admin_role
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_auto_field_adjuments(organization, inventory, team, alice):
|
||||
def test_auto_field_adjustments(organization, inventory, team, alice):
|
||||
'Ensures the auto role reparenting is working correctly through non m2m fields'
|
||||
org2 = Organization.objects.create(name='Org 2', description='org 2')
|
||||
org2.admin_role.members.add(alice)
|
||||
assert inventory.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in inventory.admin_role
|
||||
inventory.organization = org2
|
||||
inventory.save()
|
||||
assert inventory.accessible_by(alice, {'read': True}) is True
|
||||
assert alice in inventory.admin_role
|
||||
inventory.organization = organization
|
||||
inventory.save()
|
||||
assert inventory.accessible_by(alice, {'read': True}) is False
|
||||
assert alice not in inventory.admin_role
|
||||
#assert False
|
||||
|
||||
@pytest.mark.django_db
|
||||
@ -147,14 +128,12 @@ def test_implicit_deletes(alice):
|
||||
assert Role.objects.filter(id=auditor_role_id).count() == 1
|
||||
n_alice_roles = alice.roles.count()
|
||||
n_system_admin_children = Role.singleton('System Administrator').children.count()
|
||||
rp = RolePermission.objects.create(role=delorg.admin_role, resource=delorg, read=True)
|
||||
|
||||
delorg.delete()
|
||||
|
||||
assert Role.objects.filter(id=admin_role_id).count() == 0
|
||||
assert Role.objects.filter(id=auditor_role_id).count() == 0
|
||||
assert alice.roles.count() == (n_alice_roles - 1)
|
||||
assert RolePermission.objects.filter(id=rp.id).count() == 0
|
||||
assert Role.singleton('System Administrator').children.count() == (n_system_admin_children - 1)
|
||||
assert child.ancestors.count() == 1
|
||||
assert child.ancestors.all()[0] == child
|
||||
@ -168,8 +147,8 @@ def test_content_object(user):
|
||||
assert org.admin_role.content_object.id == org.id
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_hierarchy_rebuilding():
|
||||
'Tests some subdtle cases around role hierarchy rebuilding'
|
||||
def test_hierarchy_rebuilding_multi_path():
|
||||
'Tests a subdtle cases around role hierarchy rebuilding when you have multiple paths to the same role of different length'
|
||||
|
||||
X = Role.objects.create(name='X')
|
||||
A = Role.objects.create(name='A')
|
||||
@ -196,6 +175,100 @@ def test_hierarchy_rebuilding():
|
||||
assert X.is_ancestor_of(D) is False
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_hierarchy_rebuilding_loops1(organization, team):
|
||||
'Tests ancestry rebuilding loops are involved'
|
||||
|
||||
|
||||
assert team.admin_role.is_ancestor_of(organization.admin_role) is False
|
||||
assert organization.admin_role.is_ancestor_of(team.admin_role)
|
||||
|
||||
team.admin_role.children.add(organization.admin_role)
|
||||
|
||||
assert team.admin_role.is_ancestor_of(organization.admin_role)
|
||||
assert organization.admin_role.is_ancestor_of(team.admin_role)
|
||||
|
||||
team.admin_role.children.remove(organization.admin_role)
|
||||
|
||||
assert team.admin_role.is_ancestor_of(organization.admin_role) is False
|
||||
assert organization.admin_role.is_ancestor_of(team.admin_role)
|
||||
|
||||
team.admin_role.children.add(organization.admin_role)
|
||||
|
||||
|
||||
X = Role.objects.create(name='X')
|
||||
X.children.add(organization.admin_role)
|
||||
assert X.is_ancestor_of(team.admin_role)
|
||||
assert X.is_ancestor_of(organization.admin_role)
|
||||
assert organization.admin_role.is_ancestor_of(X) is False
|
||||
assert team.admin_role.is_ancestor_of(X) is False
|
||||
|
||||
#print(X.descendents.filter(id=organization.admin_role.id).count())
|
||||
#print(X.children.filter(id=organization.admin_role.id).count())
|
||||
X.children.remove(organization.admin_role)
|
||||
X.rebuild_role_ancestor_list()
|
||||
#print(X.descendents.filter(id=organization.admin_role.id).count())
|
||||
#print(X.children.filter(id=organization.admin_role.id).count())
|
||||
|
||||
assert X.is_ancestor_of(team.admin_role) is False
|
||||
assert X.is_ancestor_of(organization.admin_role) is False
|
||||
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_hierarchy_rebuilding_loops():
|
||||
'Tests ancestry rebuilding loops are involved'
|
||||
|
||||
X = Role.objects.create(name='X')
|
||||
A = Role.objects.create(name='A')
|
||||
B = Role.objects.create(name='B')
|
||||
C = Role.objects.create(name='C')
|
||||
|
||||
A.children.add(B)
|
||||
B.children.add(C)
|
||||
C.children.add(A)
|
||||
X.children.add(A)
|
||||
|
||||
assert X.is_ancestor_of(A)
|
||||
assert X.is_ancestor_of(B)
|
||||
assert X.is_ancestor_of(C)
|
||||
|
||||
assert A.is_ancestor_of(B)
|
||||
assert A.is_ancestor_of(C)
|
||||
assert B.is_ancestor_of(C)
|
||||
assert B.is_ancestor_of(A)
|
||||
assert C.is_ancestor_of(A)
|
||||
assert C.is_ancestor_of(B)
|
||||
|
||||
X.children.remove(A)
|
||||
X.rebuild_role_ancestor_list()
|
||||
|
||||
assert X.is_ancestor_of(A) is False
|
||||
assert X.is_ancestor_of(B) is False
|
||||
assert X.is_ancestor_of(C) is False
|
||||
|
||||
X.children.add(A)
|
||||
|
||||
assert X.is_ancestor_of(A)
|
||||
assert X.is_ancestor_of(B)
|
||||
assert X.is_ancestor_of(C)
|
||||
|
||||
C.children.remove(A)
|
||||
|
||||
assert A.is_ancestor_of(B)
|
||||
assert A.is_ancestor_of(C)
|
||||
assert B.is_ancestor_of(C)
|
||||
assert B.is_ancestor_of(A) is False
|
||||
assert C.is_ancestor_of(A) is False
|
||||
assert C.is_ancestor_of(B) is False
|
||||
|
||||
assert X.is_ancestor_of(A)
|
||||
assert X.is_ancestor_of(B)
|
||||
assert X.is_ancestor_of(C)
|
||||
|
||||
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_auto_parenting():
|
||||
org1 = Organization.objects.create(name='org1')
|
||||
|
||||
@ -16,13 +16,13 @@ def test_credential_migration_user(credential, user, permissions):
|
||||
|
||||
rbac.migrate_credential(apps, None)
|
||||
|
||||
assert credential.accessible_by(u, permissions['admin'])
|
||||
assert u in credential.owner_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_credential_usage_role(credential, user, permissions):
|
||||
def test_credential_use_role(credential, user, permissions):
|
||||
u = user('user', False)
|
||||
credential.usage_role.members.add(u)
|
||||
assert credential.accessible_by(u, permissions['usage'])
|
||||
credential.use_role.members.add(u)
|
||||
assert u in credential.use_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_credential_migration_team_member(credential, team, user, permissions):
|
||||
@ -34,13 +34,13 @@ def test_credential_migration_team_member(credential, team, user, permissions):
|
||||
|
||||
# No permissions pre-migration (this happens automatically so we patch this)
|
||||
team.admin_role.children.remove(credential.owner_role)
|
||||
team.member_role.children.remove(credential.usage_role)
|
||||
assert not credential.accessible_by(u, permissions['admin'])
|
||||
team.member_role.children.remove(credential.use_role)
|
||||
assert u not in credential.owner_role
|
||||
|
||||
rbac.migrate_credential(apps, None)
|
||||
|
||||
# Admin permissions post migration
|
||||
assert credential.accessible_by(u, permissions['admin'])
|
||||
assert u in credential.owner_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_credential_migration_team_admin(credential, team, user, permissions):
|
||||
@ -49,11 +49,11 @@ def test_credential_migration_team_admin(credential, team, user, permissions):
|
||||
credential.deprecated_team = team
|
||||
credential.save()
|
||||
|
||||
assert not credential.accessible_by(u, permissions['usage'])
|
||||
assert u not in credential.use_role
|
||||
|
||||
# Usage permissions post migration
|
||||
rbac.migrate_credential(apps, None)
|
||||
assert credential.accessible_by(u, permissions['usage'])
|
||||
assert u in credential.use_role
|
||||
|
||||
def test_credential_access_superuser():
|
||||
u = User(username='admin', is_superuser=True)
|
||||
@ -166,10 +166,10 @@ def test_cred_inventory_source(user, inventory, credential):
|
||||
inventory=inventory,
|
||||
)
|
||||
|
||||
assert not credential.accessible_by(u, {'use':True})
|
||||
assert u not in credential.use_role
|
||||
|
||||
rbac.migrate_credential(apps, None)
|
||||
assert credential.accessible_by(u, {'use':True})
|
||||
assert u in credential.use_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_cred_project(user, credential, project):
|
||||
@ -178,10 +178,10 @@ def test_cred_project(user, credential, project):
|
||||
project.credential = credential
|
||||
project.save()
|
||||
|
||||
assert not credential.accessible_by(u, {'use':True})
|
||||
assert u not in credential.use_role
|
||||
|
||||
rbac.migrate_credential(apps, None)
|
||||
assert credential.accessible_by(u, {'use':True})
|
||||
assert u in credential.use_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_cred_no_org(user, credential):
|
||||
@ -196,7 +196,7 @@ def test_cred_team(user, team, credential):
|
||||
credential.deprecated_team = team
|
||||
credential.save()
|
||||
|
||||
assert not credential.accessible_by(u, {'use':True})
|
||||
assert u not in credential.use_role
|
||||
|
||||
rbac.migrate_credential(apps, None)
|
||||
assert credential.accessible_by(u, {'use':True})
|
||||
assert u in credential.use_role
|
||||
|
||||
@ -6,7 +6,7 @@ from awx.main.models import (
|
||||
Host,
|
||||
CustomInventoryScript,
|
||||
)
|
||||
from awx.main.access import InventoryAccess
|
||||
from awx.main.access import InventoryAccess, HostAccess
|
||||
from django.apps import apps
|
||||
|
||||
@pytest.mark.django_db
|
||||
@ -16,10 +16,10 @@ def test_custom_inv_script_access(organization, user):
|
||||
custom_inv = CustomInventoryScript.objects.create(name='test', script='test', description='test')
|
||||
custom_inv.organization = organization
|
||||
custom_inv.save()
|
||||
assert not custom_inv.accessible_by(u, {'read':True})
|
||||
assert u not in custom_inv.read_role
|
||||
|
||||
organization.member_role.members.add(u)
|
||||
assert custom_inv.accessible_by(u, {'read':True})
|
||||
assert u in custom_inv.read_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_inventory_admin_user(inventory, permissions, user):
|
||||
@ -27,13 +27,13 @@ def test_inventory_admin_user(inventory, permissions, user):
|
||||
perm = Permission(user=u, inventory=inventory, permission_type='admin')
|
||||
perm.save()
|
||||
|
||||
assert inventory.accessible_by(u, permissions['admin']) is False
|
||||
assert u not in inventory.admin_role
|
||||
|
||||
rbac.migrate_inventory(apps, None)
|
||||
|
||||
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
|
||||
assert u in inventory.admin_role
|
||||
assert inventory.execute_role.members.filter(id=u.id).exists() is False
|
||||
assert inventory.update_role.members.filter(id=u.id).exists() is False
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_inventory_auditor_user(inventory, permissions, user):
|
||||
@ -41,15 +41,15 @@ def test_inventory_auditor_user(inventory, permissions, user):
|
||||
perm = Permission(user=u, inventory=inventory, permission_type='read')
|
||||
perm.save()
|
||||
|
||||
assert inventory.accessible_by(u, permissions['admin']) is False
|
||||
assert inventory.accessible_by(u, permissions['auditor']) is False
|
||||
assert u not in inventory.admin_role
|
||||
assert u not in inventory.auditor_role
|
||||
|
||||
rbac.migrate_inventory(apps, None)
|
||||
|
||||
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
|
||||
assert inventory.updater_role.members.filter(id=u.id).exists() is False
|
||||
assert u not in inventory.admin_role
|
||||
assert u in inventory.auditor_role
|
||||
assert inventory.execute_role.members.filter(id=u.id).exists() is False
|
||||
assert inventory.update_role.members.filter(id=u.id).exists() is False
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_inventory_updater_user(inventory, permissions, user):
|
||||
@ -57,14 +57,14 @@ def test_inventory_updater_user(inventory, permissions, user):
|
||||
perm = Permission(user=u, inventory=inventory, permission_type='write')
|
||||
perm.save()
|
||||
|
||||
assert inventory.accessible_by(u, permissions['admin']) is False
|
||||
assert inventory.accessible_by(u, permissions['auditor']) is False
|
||||
assert u not in inventory.admin_role
|
||||
assert u not in inventory.auditor_role
|
||||
|
||||
rbac.migrate_inventory(apps, None)
|
||||
|
||||
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()
|
||||
assert u not in inventory.admin_role
|
||||
assert inventory.execute_role.members.filter(id=u.id).exists() is False
|
||||
assert inventory.update_role.members.filter(id=u.id).exists()
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_inventory_executor_user(inventory, permissions, user):
|
||||
@ -72,15 +72,15 @@ def test_inventory_executor_user(inventory, permissions, user):
|
||||
perm = Permission(user=u, inventory=inventory, permission_type='read', run_ad_hoc_commands=True)
|
||||
perm.save()
|
||||
|
||||
assert inventory.accessible_by(u, permissions['admin']) is False
|
||||
assert inventory.accessible_by(u, permissions['auditor']) is False
|
||||
assert u not in inventory.admin_role
|
||||
assert u not in inventory.auditor_role
|
||||
|
||||
rbac.migrate_inventory(apps, None)
|
||||
|
||||
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()
|
||||
assert inventory.updater_role.members.filter(id=u.id).exists() is False
|
||||
assert u not in inventory.admin_role
|
||||
assert u in inventory.read_role
|
||||
assert inventory.execute_role.members.filter(id=u.id).exists()
|
||||
assert inventory.update_role.members.filter(id=u.id).exists() is False
|
||||
|
||||
|
||||
|
||||
@ -91,7 +91,7 @@ def test_inventory_admin_team(inventory, permissions, user, team):
|
||||
perm.save()
|
||||
team.deprecated_users.add(u)
|
||||
|
||||
assert inventory.accessible_by(u, permissions['admin']) is False
|
||||
assert u not in inventory.admin_role
|
||||
|
||||
rbac.migrate_team(apps, None)
|
||||
rbac.migrate_inventory(apps, None)
|
||||
@ -99,10 +99,10 @@ def test_inventory_admin_team(inventory, permissions, user, team):
|
||||
assert team.member_role.members.count() == 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
|
||||
assert inventory.updater_role.members.filter(id=u.id).exists() is False
|
||||
assert inventory.accessible_by(u, permissions['auditor'])
|
||||
assert inventory.accessible_by(u, permissions['admin'])
|
||||
assert inventory.execute_role.members.filter(id=u.id).exists() is False
|
||||
assert inventory.update_role.members.filter(id=u.id).exists() is False
|
||||
assert u in inventory.read_role
|
||||
assert u in inventory.admin_role
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@ -112,8 +112,8 @@ def test_inventory_auditor(inventory, permissions, user, team):
|
||||
perm.save()
|
||||
team.deprecated_users.add(u)
|
||||
|
||||
assert inventory.accessible_by(u, permissions['admin']) is False
|
||||
assert inventory.accessible_by(u, permissions['auditor']) is False
|
||||
assert u not in inventory.admin_role
|
||||
assert u not in inventory.auditor_role
|
||||
|
||||
rbac.migrate_team(apps,None)
|
||||
rbac.migrate_inventory(apps, None)
|
||||
@ -121,10 +121,10 @@ def test_inventory_auditor(inventory, permissions, user, team):
|
||||
assert team.member_role.members.count() == 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
|
||||
assert inventory.updater_role.members.filter(id=u.id).exists() is False
|
||||
assert inventory.accessible_by(u, permissions['auditor'])
|
||||
assert inventory.accessible_by(u, permissions['admin']) is False
|
||||
assert inventory.execute_role.members.filter(id=u.id).exists() is False
|
||||
assert inventory.update_role.members.filter(id=u.id).exists() is False
|
||||
assert u in inventory.read_role
|
||||
assert u not in inventory.admin_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_inventory_updater(inventory, permissions, user, team):
|
||||
@ -133,8 +133,8 @@ def test_inventory_updater(inventory, permissions, user, team):
|
||||
perm.save()
|
||||
team.deprecated_users.add(u)
|
||||
|
||||
assert inventory.accessible_by(u, permissions['admin']) is False
|
||||
assert inventory.accessible_by(u, permissions['auditor']) is False
|
||||
assert u not in inventory.admin_role
|
||||
assert u not in inventory.auditor_role
|
||||
|
||||
rbac.migrate_team(apps,None)
|
||||
rbac.migrate_inventory(apps, None)
|
||||
@ -142,10 +142,10 @@ def test_inventory_updater(inventory, permissions, user, team):
|
||||
assert team.member_role.members.count() == 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
|
||||
assert inventory.updater_role.members.filter(id=u.id).exists() is False
|
||||
assert team.member_role.is_ancestor_of(inventory.updater_role)
|
||||
assert team.member_role.is_ancestor_of(inventory.executor_role) is False
|
||||
assert inventory.execute_role.members.filter(id=u.id).exists() is False
|
||||
assert inventory.update_role.members.filter(id=u.id).exists() is False
|
||||
assert team.member_role.is_ancestor_of(inventory.update_role)
|
||||
assert team.member_role.is_ancestor_of(inventory.execute_role) is False
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@ -155,8 +155,8 @@ def test_inventory_executor(inventory, permissions, user, team):
|
||||
perm.save()
|
||||
team.deprecated_users.add(u)
|
||||
|
||||
assert inventory.accessible_by(u, permissions['admin']) is False
|
||||
assert inventory.accessible_by(u, permissions['auditor']) is False
|
||||
assert u not in inventory.admin_role
|
||||
assert u not in inventory.auditor_role
|
||||
|
||||
rbac.migrate_team(apps, None)
|
||||
rbac.migrate_inventory(apps, None)
|
||||
@ -164,10 +164,10 @@ def test_inventory_executor(inventory, permissions, user, team):
|
||||
assert team.member_role.members.count() == 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
|
||||
assert inventory.updater_role.members.filter(id=u.id).exists() is False
|
||||
assert team.member_role.is_ancestor_of(inventory.updater_role) is False
|
||||
assert team.member_role.is_ancestor_of(inventory.executor_role)
|
||||
assert inventory.execute_role.members.filter(id=u.id).exists() is False
|
||||
assert inventory.update_role.members.filter(id=u.id).exists() is False
|
||||
assert team.member_role.is_ancestor_of(inventory.update_role) is False
|
||||
assert team.member_role.is_ancestor_of(inventory.execute_role)
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_group_parent_admin(group, permissions, user):
|
||||
@ -177,21 +177,21 @@ def test_group_parent_admin(group, permissions, user):
|
||||
childA = group('child-1')
|
||||
|
||||
parent1.admin_role.members.add(u)
|
||||
assert parent1.accessible_by(u, permissions['admin'])
|
||||
assert not parent2.accessible_by(u, permissions['admin'])
|
||||
assert not childA.accessible_by(u, permissions['admin'])
|
||||
assert u in parent1.admin_role
|
||||
assert u not in parent2.admin_role
|
||||
assert u not in childA.admin_role
|
||||
|
||||
childA.parents.add(parent1)
|
||||
assert childA.accessible_by(u, permissions['admin'])
|
||||
assert u in childA.admin_role
|
||||
|
||||
childA.parents.remove(parent1)
|
||||
assert not childA.accessible_by(u, permissions['admin'])
|
||||
assert u not in childA.admin_role
|
||||
|
||||
parent2.children.add(childA)
|
||||
assert not childA.accessible_by(u, permissions['admin'])
|
||||
assert u not in childA.admin_role
|
||||
|
||||
parent2.admin_role.members.add(u)
|
||||
assert childA.accessible_by(u, permissions['admin'])
|
||||
assert u in childA.admin_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_access_admin(organization, inventory, user):
|
||||
@ -237,33 +237,35 @@ def test_host_access(organization, inventory, user, group):
|
||||
not_my_group = group('not-my-group')
|
||||
group_admin = user('group_admin', False)
|
||||
|
||||
inventory_admin_access = HostAccess(inventory_admin)
|
||||
group_admin_access = HostAccess(group_admin)
|
||||
|
||||
h1 = Host.objects.create(inventory=inventory, name='host1')
|
||||
h2 = Host.objects.create(inventory=inventory, name='host2')
|
||||
h1.groups.add(my_group)
|
||||
h2.groups.add(not_my_group)
|
||||
|
||||
assert h1.accessible_by(inventory_admin, {'read': True}) is False
|
||||
assert h1.accessible_by(group_admin, {'read': True}) is False
|
||||
assert inventory_admin_access.can_read(h1) is False
|
||||
assert group_admin_access.can_read(h1) is False
|
||||
|
||||
inventory.admin_role.members.add(inventory_admin)
|
||||
my_group.admin_role.members.add(group_admin)
|
||||
|
||||
assert h1.accessible_by(inventory_admin, {'read': True})
|
||||
assert h2.accessible_by(inventory_admin, {'read': True})
|
||||
assert h1.accessible_by(group_admin, {'read': True})
|
||||
assert h2.accessible_by(group_admin, {'read': True}) is False
|
||||
assert inventory_admin_access.can_read(h1)
|
||||
assert inventory_admin_access.can_read(h2)
|
||||
assert group_admin_access.can_read(h1)
|
||||
assert group_admin_access.can_read(h2) is False
|
||||
|
||||
my_group.hosts.remove(h1)
|
||||
|
||||
assert h1.accessible_by(inventory_admin, {'read': True})
|
||||
assert h1.accessible_by(group_admin, {'read': True}) is False
|
||||
assert inventory_admin_access.can_read(h1)
|
||||
assert group_admin_access.can_read(h1) is False
|
||||
|
||||
h1.inventory = other_inventory
|
||||
h1.save()
|
||||
|
||||
assert h1.accessible_by(inventory_admin, {'read': True}) is False
|
||||
assert h1.accessible_by(group_admin, {'read': True}) is False
|
||||
assert inventory_admin_access.can_read(h1) is False
|
||||
assert group_admin_access.can_read(h1) is False
|
||||
|
||||
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ def test_admin_executing_permissions(deploy_jobtemplate, inventory, machine_cred
|
||||
def test_job_template_start_access(deploy_jobtemplate, user):
|
||||
|
||||
common_user = user('test-user', False)
|
||||
deploy_jobtemplate.executor_role.members.add(common_user)
|
||||
deploy_jobtemplate.execute_role.members.add(common_user)
|
||||
|
||||
assert common_user.can_access(JobTemplate, 'start', deploy_jobtemplate)
|
||||
|
||||
@ -33,7 +33,7 @@ def test_job_template_start_access(deploy_jobtemplate, user):
|
||||
def test_credential_use_access(machine_credential, user):
|
||||
|
||||
common_user = user('test-user', False)
|
||||
machine_credential.usage_role.members.add(common_user)
|
||||
machine_credential.use_role.members.add(common_user)
|
||||
|
||||
assert common_user.can_access(Credential, 'use', machine_credential)
|
||||
|
||||
@ -42,6 +42,6 @@ def test_credential_use_access(machine_credential, user):
|
||||
def test_inventory_use_access(inventory, user):
|
||||
|
||||
common_user = user('test-user', False)
|
||||
inventory.usage_role.members.add(common_user)
|
||||
inventory.use_role.members.add(common_user)
|
||||
|
||||
assert common_user.can_access(Inventory, 'use', inventory)
|
||||
|
||||
@ -27,16 +27,16 @@ def test_job_template_migration_check(deploy_jobtemplate, check_jobtemplate, use
|
||||
rbac.migrate_projects(apps, None)
|
||||
rbac.migrate_inventory(apps, None)
|
||||
|
||||
assert check_jobtemplate.project.accessible_by(joe, {'read': True})
|
||||
assert check_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is False
|
||||
assert joe in check_jobtemplate.project.read_role
|
||||
assert admin in check_jobtemplate.execute_role
|
||||
assert joe not in check_jobtemplate.execute_role
|
||||
|
||||
rbac.migrate_job_templates(apps, None)
|
||||
|
||||
assert check_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is True
|
||||
assert deploy_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert deploy_jobtemplate.accessible_by(joe, {'execute': True}) is False
|
||||
assert admin in check_jobtemplate.execute_role
|
||||
assert joe in check_jobtemplate.execute_role
|
||||
assert admin in deploy_jobtemplate.execute_role
|
||||
assert joe not in deploy_jobtemplate.execute_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_job_template_migration_deploy(deploy_jobtemplate, check_jobtemplate, user):
|
||||
@ -55,16 +55,16 @@ def test_job_template_migration_deploy(deploy_jobtemplate, check_jobtemplate, us
|
||||
rbac.migrate_projects(apps, None)
|
||||
rbac.migrate_inventory(apps, None)
|
||||
|
||||
assert deploy_jobtemplate.project.accessible_by(joe, {'read': True})
|
||||
assert deploy_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert deploy_jobtemplate.accessible_by(joe, {'execute': True}) is False
|
||||
assert joe in deploy_jobtemplate.project.read_role
|
||||
assert admin in deploy_jobtemplate.execute_role
|
||||
assert joe not in deploy_jobtemplate.execute_role
|
||||
|
||||
rbac.migrate_job_templates(apps, None)
|
||||
|
||||
assert deploy_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert deploy_jobtemplate.accessible_by(joe, {'execute': True}) is True
|
||||
assert check_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is True
|
||||
assert admin in deploy_jobtemplate.execute_role
|
||||
assert joe in deploy_jobtemplate.execute_role
|
||||
assert admin in check_jobtemplate.execute_role
|
||||
assert joe in check_jobtemplate.execute_role
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@ -87,17 +87,17 @@ def test_job_template_team_migration_check(deploy_jobtemplate, check_jobtemplate
|
||||
rbac.migrate_projects(apps, None)
|
||||
rbac.migrate_inventory(apps, None)
|
||||
|
||||
assert check_jobtemplate.project.accessible_by(joe, {'read': True})
|
||||
assert check_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is False
|
||||
assert joe in check_jobtemplate.read_role
|
||||
assert admin in check_jobtemplate.execute_role
|
||||
assert joe not in check_jobtemplate.execute_role
|
||||
|
||||
rbac.migrate_job_templates(apps, None)
|
||||
|
||||
assert check_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is True
|
||||
assert admin in check_jobtemplate.execute_role
|
||||
assert joe in check_jobtemplate.execute_role
|
||||
|
||||
assert deploy_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert deploy_jobtemplate.accessible_by(joe, {'execute': True}) is False
|
||||
assert admin in deploy_jobtemplate.execute_role
|
||||
assert joe not in deploy_jobtemplate.execute_role
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@ -120,17 +120,17 @@ def test_job_template_team_deploy_migration(deploy_jobtemplate, check_jobtemplat
|
||||
rbac.migrate_projects(apps, None)
|
||||
rbac.migrate_inventory(apps, None)
|
||||
|
||||
assert deploy_jobtemplate.project.accessible_by(joe, {'read': True})
|
||||
assert deploy_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert deploy_jobtemplate.accessible_by(joe, {'execute': True}) is False
|
||||
assert joe in deploy_jobtemplate.read_role
|
||||
assert admin in deploy_jobtemplate.execute_role
|
||||
assert joe not in deploy_jobtemplate.execute_role
|
||||
|
||||
rbac.migrate_job_templates(apps, None)
|
||||
|
||||
assert deploy_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert deploy_jobtemplate.accessible_by(joe, {'execute': True}) is True
|
||||
assert admin in deploy_jobtemplate.execute_role
|
||||
assert joe in deploy_jobtemplate.execute_role
|
||||
|
||||
assert check_jobtemplate.accessible_by(admin, {'execute': True}) is True
|
||||
assert check_jobtemplate.accessible_by(joe, {'execute': True}) is True
|
||||
assert admin in check_jobtemplate.execute_role
|
||||
assert joe in check_jobtemplate.execute_role
|
||||
|
||||
|
||||
@mock.patch.object(BaseAccess, 'check_license', return_value=None)
|
||||
|
||||
@ -16,11 +16,11 @@ def test_organization_migration_admin(organization, permissions, user):
|
||||
|
||||
# Undo some automatic work that we're supposed to be testing with our migration
|
||||
organization.admin_role.members.remove(u)
|
||||
assert not organization.accessible_by(u, permissions['admin'])
|
||||
assert u not in organization.admin_role
|
||||
|
||||
rbac.migrate_organization(apps, None)
|
||||
|
||||
assert organization.accessible_by(u, permissions['admin'])
|
||||
assert u in organization.admin_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_organization_migration_user(organization, permissions, user):
|
||||
@ -29,11 +29,11 @@ def test_organization_migration_user(organization, permissions, user):
|
||||
|
||||
# Undo some automatic work that we're supposed to be testing with our migration
|
||||
organization.member_role.members.remove(u)
|
||||
assert not organization.accessible_by(u, permissions['auditor'])
|
||||
assert u not in organization.read_role
|
||||
|
||||
rbac.migrate_organization(apps, None)
|
||||
|
||||
assert organization.accessible_by(u, permissions['auditor'])
|
||||
assert u in organization.read_role
|
||||
|
||||
|
||||
@mock.patch.object(BaseAccess, 'check_license', return_value=None)
|
||||
|
||||
@ -138,11 +138,11 @@ def test_project_user_project(user_project, project, user):
|
||||
assert old_access.check_user_access(u, user_project.__class__, 'read', user_project)
|
||||
assert old_access.check_user_access(u, project.__class__, 'read', project) is False
|
||||
|
||||
assert user_project.accessible_by(u, {'read': True}) is False
|
||||
assert project.accessible_by(u, {'read': True}) is False
|
||||
assert u not in user_project.read_role
|
||||
assert u not in project.read_role
|
||||
rbac.migrate_projects(apps, None)
|
||||
assert user_project.accessible_by(u, {'read': True}) is True
|
||||
assert project.accessible_by(u, {'read': True}) is False
|
||||
assert u in user_project.read_role
|
||||
assert u not in project.read_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_project_accessible_by_sa(user, project):
|
||||
@ -150,21 +150,21 @@ def test_project_accessible_by_sa(user, project):
|
||||
# This gets setup by a signal, but we want to test the migration which will set this up too, so remove it
|
||||
Role.singleton('System Administrator').members.remove(u)
|
||||
|
||||
assert project.accessible_by(u, {'read': True}) is False
|
||||
assert u not in project.read_role
|
||||
rbac.migrate_organization(apps, None)
|
||||
rbac.migrate_users(apps, None)
|
||||
rbac.migrate_projects(apps, None)
|
||||
print(project.admin_role.ancestors.all())
|
||||
print(project.admin_role.ancestors.all())
|
||||
assert project.accessible_by(u, {'read': True, 'write': True}) is True
|
||||
assert u in project.admin_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_project_org_members(user, organization, project):
|
||||
admin = user('orgadmin')
|
||||
member = user('orgmember')
|
||||
|
||||
assert project.accessible_by(admin, {'read': True}) is False
|
||||
assert project.accessible_by(member, {'read': True}) is False
|
||||
assert admin not in project.read_role
|
||||
assert member not in project.read_role
|
||||
|
||||
organization.deprecated_admins.add(admin)
|
||||
organization.deprecated_users.add(member)
|
||||
@ -172,8 +172,8 @@ def test_project_org_members(user, organization, project):
|
||||
rbac.migrate_organization(apps, None)
|
||||
rbac.migrate_projects(apps, None)
|
||||
|
||||
assert project.accessible_by(admin, {'read': True, 'write': True}) is True
|
||||
assert project.accessible_by(member, {'read': True})
|
||||
assert admin in project.admin_role
|
||||
assert member in project.read_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_project_team(user, team, project):
|
||||
@ -183,15 +183,15 @@ def test_project_team(user, team, project):
|
||||
team.deprecated_users.add(member)
|
||||
project.deprecated_teams.add(team)
|
||||
|
||||
assert project.accessible_by(nonmember, {'read': True}) is False
|
||||
assert project.accessible_by(member, {'read': True}) is False
|
||||
assert nonmember not in project.read_role
|
||||
assert member not in project.read_role
|
||||
|
||||
rbac.migrate_team(apps, None)
|
||||
rbac.migrate_organization(apps, None)
|
||||
rbac.migrate_projects(apps, None)
|
||||
|
||||
assert project.accessible_by(member, {'read': True}) is True
|
||||
assert project.accessible_by(nonmember, {'read': True}) is False
|
||||
assert member in project.read_role
|
||||
assert nonmember not in project.read_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_project_explicit_permission(user, team, project, organization):
|
||||
@ -203,9 +203,9 @@ def test_project_explicit_permission(user, team, project, organization):
|
||||
p = Permission(user=u, project=project, permission_type='create', name='Perm name')
|
||||
p.save()
|
||||
|
||||
assert project.accessible_by(u, {'read': True}) is False
|
||||
assert u not in project.read_role
|
||||
|
||||
rbac.migrate_organization(apps, None)
|
||||
rbac.migrate_projects(apps, None)
|
||||
|
||||
assert project.accessible_by(u, {'read': True}) is True
|
||||
assert u in project.read_role
|
||||
|
||||
@ -54,20 +54,20 @@ def test_team_accessible_by(team, user, project):
|
||||
u = user('team_member', False)
|
||||
|
||||
team.member_role.children.add(project.member_role)
|
||||
assert project.accessible_by(team, {'read':True})
|
||||
assert not project.accessible_by(u, {'read':True})
|
||||
assert team in project.read_role
|
||||
assert u not in project.read_role
|
||||
|
||||
team.member_role.members.add(u)
|
||||
assert project.accessible_by(u, {'read':True})
|
||||
assert u in project.read_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_team_accessible_objects(team, user, project):
|
||||
u = user('team_member', False)
|
||||
|
||||
team.member_role.children.add(project.member_role)
|
||||
assert len(Project.accessible_objects(team, {'read':True})) == 1
|
||||
assert not Project.accessible_objects(u, {'read':True})
|
||||
assert len(Project.accessible_objects(team, 'read_role')) == 1
|
||||
assert not Project.accessible_objects(u, 'read_role')
|
||||
|
||||
team.member_role.members.add(u)
|
||||
assert len(Project.accessible_objects(u, {'read':True})) == 1
|
||||
assert len(Project.accessible_objects(u, 'read_role')) == 1
|
||||
|
||||
|
||||
@ -40,14 +40,14 @@ def test_user_queryset(user):
|
||||
def test_user_accessible_objects(user, organization):
|
||||
admin = user('admin', False)
|
||||
u = user('john', False)
|
||||
assert User.accessible_objects(admin, {'read':True}).count() == 1
|
||||
assert User.accessible_objects(admin, 'admin_role').count() == 1
|
||||
|
||||
organization.member_role.members.add(u)
|
||||
organization.admin_role.members.add(admin)
|
||||
assert User.accessible_objects(admin, {'read':True}).count() == 2
|
||||
assert User.accessible_objects(admin, 'admin_role').count() == 2
|
||||
|
||||
organization.member_role.members.remove(u)
|
||||
assert User.accessible_objects(admin, {'read':True}).count() == 1
|
||||
assert User.accessible_objects(admin, 'admin_role').count() == 1
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_org_user_admin(user, organization):
|
||||
@ -55,13 +55,13 @@ def test_org_user_admin(user, organization):
|
||||
member = user('orgmember')
|
||||
|
||||
organization.member_role.members.add(member)
|
||||
assert not member.accessible_by(admin, {'write':True})
|
||||
assert admin not in member.admin_role
|
||||
|
||||
organization.admin_role.members.add(admin)
|
||||
assert member.accessible_by(admin, {'write':True})
|
||||
assert admin in member.admin_role
|
||||
|
||||
organization.admin_role.members.remove(admin)
|
||||
assert not member.accessible_by(admin, {'write':True})
|
||||
assert admin not in member.admin_role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_org_user_removed(user, organization):
|
||||
@ -71,7 +71,7 @@ def test_org_user_removed(user, organization):
|
||||
organization.admin_role.members.add(admin)
|
||||
organization.member_role.members.add(member)
|
||||
|
||||
assert member.accessible_by(admin, {'write':True})
|
||||
assert admin in member.admin_role
|
||||
|
||||
organization.member_role.members.remove(member)
|
||||
assert not member.accessible_by(admin, {'write':True})
|
||||
assert admin not in member.admin_role
|
||||
|
||||
10
awx/main/tests/functional/test_teams.py
Normal file
10
awx/main/tests/functional/test_teams.py
Normal file
@ -0,0 +1,10 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.django_db()
|
||||
def test_admin_not_member(team):
|
||||
"Test to ensure we don't add admin_role as a parent to team.member_role, as "
|
||||
"this creates a cycle with organization administration, which we've decided "
|
||||
"to remove support for"
|
||||
|
||||
assert team.admin_role.is_ancestor_of(team.member_role) is False
|
||||
@ -295,14 +295,14 @@ class BaseJobTestMixin(BaseTestMixin):
|
||||
password='ASK',
|
||||
created_by=self.user_sue,
|
||||
)
|
||||
self.cred_bob.usage_role.members.add(self.user_bob)
|
||||
self.cred_bob.use_role.members.add(self.user_bob)
|
||||
|
||||
self.cred_chuck = Credential.objects.create(
|
||||
username='chuck',
|
||||
ssh_key_data=TEST_SSH_KEY_DATA,
|
||||
created_by=self.user_sue,
|
||||
)
|
||||
self.cred_chuck.usage_role.members.add(self.user_chuck)
|
||||
self.cred_chuck.use_role.members.add(self.user_chuck)
|
||||
|
||||
self.cred_doug = Credential.objects.create(
|
||||
username='doug',
|
||||
@ -310,7 +310,7 @@ class BaseJobTestMixin(BaseTestMixin):
|
||||
'is why we dont\'t let doug actually run jobs.',
|
||||
created_by=self.user_sue,
|
||||
)
|
||||
self.cred_doug.usage_role.members.add(self.user_doug)
|
||||
self.cred_doug.use_role.members.add(self.user_doug)
|
||||
|
||||
self.cred_eve = Credential.objects.create(
|
||||
username='eve',
|
||||
@ -320,14 +320,14 @@ class BaseJobTestMixin(BaseTestMixin):
|
||||
become_password='ASK',
|
||||
created_by=self.user_sue,
|
||||
)
|
||||
self.cred_eve.usage_role.members.add(self.user_eve)
|
||||
self.cred_eve.use_role.members.add(self.user_eve)
|
||||
|
||||
self.cred_frank = Credential.objects.create(
|
||||
username='frank',
|
||||
password='fr@nk the t@nk',
|
||||
created_by=self.user_sue,
|
||||
)
|
||||
self.cred_frank.usage_role.members.add(self.user_frank)
|
||||
self.cred_frank.use_role.members.add(self.user_frank)
|
||||
|
||||
self.cred_greg = Credential.objects.create(
|
||||
username='greg',
|
||||
@ -335,21 +335,21 @@ class BaseJobTestMixin(BaseTestMixin):
|
||||
ssh_key_unlock='ASK',
|
||||
created_by=self.user_sue,
|
||||
)
|
||||
self.cred_greg.usage_role.members.add(self.user_greg)
|
||||
self.cred_greg.use_role.members.add(self.user_greg)
|
||||
|
||||
self.cred_holly = Credential.objects.create(
|
||||
username='holly',
|
||||
password='holly rocks',
|
||||
created_by=self.user_sue,
|
||||
)
|
||||
self.cred_holly.usage_role.members.add(self.user_holly)
|
||||
self.cred_holly.use_role.members.add(self.user_holly)
|
||||
|
||||
self.cred_iris = Credential.objects.create(
|
||||
username='iris',
|
||||
password='ASK',
|
||||
created_by=self.user_sue,
|
||||
)
|
||||
self.cred_iris.usage_role.members.add(self.user_iris)
|
||||
self.cred_iris.use_role.members.add(self.user_iris)
|
||||
|
||||
# Each operations team also has shared credentials they can use.
|
||||
self.cred_ops_east = Credential.objects.create(
|
||||
@ -358,14 +358,14 @@ class BaseJobTestMixin(BaseTestMixin):
|
||||
ssh_key_unlock=TEST_SSH_KEY_DATA_UNLOCK,
|
||||
created_by = self.user_sue,
|
||||
)
|
||||
self.team_ops_east.member_role.children.add(self.cred_ops_east.usage_role)
|
||||
self.team_ops_east.member_role.children.add(self.cred_ops_east.use_role)
|
||||
|
||||
self.cred_ops_west = Credential.objects.create(
|
||||
username='west',
|
||||
password='Heading270',
|
||||
created_by = self.user_sue,
|
||||
)
|
||||
self.team_ops_west.member_role.children.add(self.cred_ops_west.usage_role)
|
||||
self.team_ops_west.member_role.children.add(self.cred_ops_west.use_role)
|
||||
|
||||
|
||||
# FIXME: This code can be removed (probably)
|
||||
@ -391,7 +391,7 @@ class BaseJobTestMixin(BaseTestMixin):
|
||||
password='HeadingNone',
|
||||
created_by = self.user_sue,
|
||||
)
|
||||
self.team_ops_testers.member_role.children.add(self.cred_ops_test.usage_role)
|
||||
self.team_ops_testers.member_role.children.add(self.cred_ops_test.use_role)
|
||||
|
||||
self.ops_east_permission = Permission.objects.create(
|
||||
inventory = self.inv_ops_east,
|
||||
|
||||
@ -463,7 +463,7 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
# not allowed to run ad hoc commands).
|
||||
user_roles_list_url = reverse('api:user_roles_list', args=(self.other_django_user.pk,))
|
||||
with self.current_user('admin'):
|
||||
response = self.post(user_roles_list_url, {"id": self.inventory.updater_role.id}, expect=204)
|
||||
response = self.post(user_roles_list_url, {"id": self.inventory.update_role.id}, expect=204)
|
||||
with self.current_user('other'):
|
||||
self.run_test_ad_hoc_command(expect=403)
|
||||
self.check_get_list(url, 'other', qs)
|
||||
@ -471,7 +471,7 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
# Add executor role permissions to other. Fails
|
||||
# when other user can't read credential.
|
||||
with self.current_user('admin'):
|
||||
response = self.post(user_roles_list_url, {"id": self.inventory.executor_role.id}, expect=204)
|
||||
response = self.post(user_roles_list_url, {"id": self.inventory.execute_role.id}, expect=204)
|
||||
with self.current_user('other'):
|
||||
self.run_test_ad_hoc_command(expect=403)
|
||||
|
||||
@ -504,7 +504,7 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
# Give the nobody user the run_ad_hoc_commands flag, and can now see
|
||||
# the one ad hoc command previously run.
|
||||
with self.current_user('admin'):
|
||||
response = self.post(nobody_roles_list_url, {"id": self.inventory.executor_role.id}, expect=204)
|
||||
response = self.post(nobody_roles_list_url, {"id": self.inventory.execute_role.id}, expect=204)
|
||||
qs = AdHocCommand.objects.filter(credential_id=nobody_cred.pk)
|
||||
self.assertEqual(qs.count(), 1)
|
||||
self.check_get_list(url, 'nobody', qs)
|
||||
@ -1006,7 +1006,7 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
# can_run_ad_hoc_commands = True when we shouldn't.
|
||||
nobody_roles_list_url = reverse('api:user_roles_list', args=(self.nobody_django_user.pk,))
|
||||
with self.current_user('admin'):
|
||||
response = self.post(nobody_roles_list_url, {"id": self.inventory.executor_role.id}, expect=204)
|
||||
response = self.post(nobody_roles_list_url, {"id": self.inventory.execute_role.id}, expect=204)
|
||||
|
||||
# Create a credential for the other user and explicitly give other
|
||||
# user admin permission on the inventory (still not allowed to run ad
|
||||
@ -1014,7 +1014,7 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
other_cred = self.create_test_credential(user=self.other_django_user)
|
||||
user_roles_list_url = reverse('api:user_roles_list', args=(self.other_django_user.pk,))
|
||||
with self.current_user('admin'):
|
||||
response = self.post(user_roles_list_url, {"id": self.inventory.updater_role.id}, expect=204)
|
||||
response = self.post(user_roles_list_url, {"id": self.inventory.update_role.id}, expect=204)
|
||||
with self.current_user('other'):
|
||||
response = self.get(url, expect=200)
|
||||
self.assertEqual(response['count'], 0)
|
||||
@ -1025,7 +1025,7 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
# Update permission to allow other user to run ad hoc commands. Can
|
||||
# only see his own ad hoc commands (because of credential permission).
|
||||
with self.current_user('admin'):
|
||||
response = self.post(user_roles_list_url, {"id": self.inventory.executor_role.id}, expect=204)
|
||||
response = self.post(user_roles_list_url, {"id": self.inventory.adhoc_role.id}, expect=204)
|
||||
with self.current_user('other'):
|
||||
response = self.get(url, expect=200)
|
||||
self.assertEqual(response['count'], 0)
|
||||
|
||||
@ -952,7 +952,8 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest):
|
||||
self.assertNotEqual(new_inv.groups.count(), 0)
|
||||
self.assertNotEqual(new_inv.total_hosts, 0)
|
||||
self.assertNotEqual(new_inv.total_groups, 0)
|
||||
self.assertElapsedLessThan(600)
|
||||
self.assertElapsedLessThan(1800) # TODO: We need to revisit this again to see if we can optimize this back to the sub-600 second range - anoek 2016-04-18
|
||||
|
||||
|
||||
def _get_ngroups_for_nhosts(self, n):
|
||||
if n > 0:
|
||||
@ -977,7 +978,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest):
|
||||
self.assertEqual(new_inv.groups.count(), ngroups)
|
||||
self.assertEqual(new_inv.total_hosts, nhosts)
|
||||
self.assertEqual(new_inv.total_groups, ngroups)
|
||||
self.assertElapsedLessThan(1200) # FIXME: This should be < 120, will drop back down next sprint during our performance tuning work - anoek 2016-03-22
|
||||
self.assertElapsedLessThan(180) # TODO: We need to revisit this again to see if we can optimize this back to the sub-120 second range - anoek 2016-04-18
|
||||
|
||||
@unittest.skipIf(getattr(settings, 'LOCAL_DEVELOPMENT', False),
|
||||
'Skip this test in local development environments, '
|
||||
|
||||
@ -77,7 +77,7 @@ class InventoryTest(BaseTest):
|
||||
self.check_get_list(url, self.normal_django_user, normal_qs)
|
||||
|
||||
# a user who is on a team who has a read permissions on an inventory can see filtered inventories
|
||||
other_qs = Inventory.accessible_objects(self.other_django_user, {'read': True}).distinct()
|
||||
other_qs = Inventory.accessible_objects(self.other_django_user, 'read_role').distinct()
|
||||
self.check_get_list(url, self.other_django_user, other_qs)
|
||||
|
||||
# a regular user not part of anything cannot see any inventories
|
||||
@ -401,7 +401,7 @@ class InventoryTest(BaseTest):
|
||||
del_children_url = reverse('api:group_children_list', args=(del_group.pk,))
|
||||
nondel_url = reverse('api:group_detail',
|
||||
args=(Group.objects.get(name='nondel').pk,))
|
||||
assert(inv.accessible_by(self.normal_django_user, {'read': True}))
|
||||
assert self.normal_django_user in inv.read_role
|
||||
del_group.delete()
|
||||
nondel_detail = self.get(nondel_url, expect=200, auth=self.get_normal_credentials())
|
||||
self.post(del_children_url, data=nondel_detail, expect=400, auth=self.get_normal_credentials())
|
||||
|
||||
@ -289,7 +289,7 @@ class OrganizationsTest(BaseTest):
|
||||
|
||||
# post a completely new user to verify we can add users to the subcollection directly
|
||||
new_user = dict(username='NewUser9000', password='NewPassword9000')
|
||||
which_org = Organization.accessible_objects(self.normal_django_user, {'read': True, 'write': True})[0]
|
||||
which_org = Organization.accessible_objects(self.normal_django_user, 'admin_role')[0]
|
||||
url = reverse('api:organization_users_list', args=(which_org.pk,))
|
||||
self.post(url, new_user, expect=201, auth=self.get_normal_credentials())
|
||||
|
||||
|
||||
@ -420,10 +420,10 @@ class UsersTest(BaseTest):
|
||||
self.assertEquals(data1['count'], 3)
|
||||
# Normal user can no longer see all users after the organization he
|
||||
# admins is marked inactive, nor can he see any other users that were
|
||||
# in that org, so he only sees himself.
|
||||
# in that org, so he only sees himself and the system admin.
|
||||
self.organizations[0].delete()
|
||||
data3 = self.get(url, expect=200, auth=self.get_normal_credentials())
|
||||
self.assertEquals(data3['count'], 1)
|
||||
self.assertEquals(data3['count'], 2)
|
||||
|
||||
# Test no longer relevant since we've moved away from active / inactive.
|
||||
# However there was talk about keeping is_active for users, so this test will
|
||||
|
||||
@ -9,4 +9,3 @@ Alias /munin /var/www/html/munin/
|
||||
require valid-user
|
||||
|
||||
</Directory>
|
||||
ScriptAlias /munin-cgi/munin-cgi-graph /var/www/cgi-bin/munin-cgi-graph
|
||||
402
tools/data_generators/rbac_dummy_data_generator.py
Executable file
402
tools/data_generators/rbac_dummy_data_generator.py
Executable file
@ -0,0 +1,402 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2016 Ansible, Inc.
|
||||
# All Rights Reserved
|
||||
import os
|
||||
import sys
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "awx.settings.development") # noqa
|
||||
|
||||
import django
|
||||
django.setup() # noqa
|
||||
|
||||
|
||||
# Python
|
||||
from collections import defaultdict
|
||||
from optparse import make_option, OptionParser
|
||||
|
||||
|
||||
# Django
|
||||
|
||||
from django.utils.timezone import now
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import transaction
|
||||
|
||||
# awx
|
||||
from awx.main.models import * # noqa
|
||||
|
||||
|
||||
|
||||
|
||||
option_list = [
|
||||
make_option('--organizations', action='store', type='int', default=3,
|
||||
help='Number of organizations to create'),
|
||||
make_option('--users', action='store', type='int', default=10,
|
||||
help='Number of users to create'),
|
||||
make_option('--teams', action='store', type='int', default=5,
|
||||
help='Number of teams to create'),
|
||||
make_option('--projects', action='store', type='int', default=10,
|
||||
help='Number of projects to create'),
|
||||
make_option('--job-templates', action='store', type='int', default=20,
|
||||
help='Number of job templates to create'),
|
||||
make_option('--credentials', action='store', type='int', default=5,
|
||||
help='Number of credentials to create'),
|
||||
make_option('--inventories', action='store', type='int', default=5,
|
||||
help='Number of credentials to create'),
|
||||
make_option('--inventory-groups', action='store', type='int', default=10,
|
||||
help='Number of credentials to create'),
|
||||
make_option('--inventory-hosts', action='store', type='int', default=40,
|
||||
help='number of credentials to create'),
|
||||
make_option('--jobs', action='store', type='int', default=200,
|
||||
help='number of job entries to create'),
|
||||
make_option('--job-events', action='store', type='int', default=500,
|
||||
help='number of job event entries to create'),
|
||||
make_option('--pretend', action='store_true',
|
||||
help="Don't commit the data to the database"),
|
||||
make_option('--prefix', action='store', type='string', default='',
|
||||
help="Prefix generated names with this string"),
|
||||
#make_option('--spread-bias', action='store', type='string', default='exponential',
|
||||
# help='"exponential" to bias associations exponentially front loaded for - for ex'),
|
||||
]
|
||||
parser = OptionParser(option_list=option_list)
|
||||
options, remainder = parser.parse_args()
|
||||
options = vars(options)
|
||||
|
||||
|
||||
n_organizations = int(options['organizations'])
|
||||
n_users = int(options['users'])
|
||||
n_teams = int(options['teams'])
|
||||
n_projects = int(options['projects'])
|
||||
n_job_templates = int(options['job_templates'])
|
||||
n_credentials = int(options['credentials'])
|
||||
n_inventories = int(options['inventories'])
|
||||
n_inventory_groups = int(options['inventory_groups'])
|
||||
n_inventory_hosts = int(options['inventory_hosts'])
|
||||
n_jobs = int(options['jobs'])
|
||||
n_job_events = int(options['job_events'])
|
||||
prefix = options['prefix']
|
||||
|
||||
organizations = []
|
||||
users = []
|
||||
teams = []
|
||||
projects = []
|
||||
job_templates = []
|
||||
credentials = []
|
||||
inventories = []
|
||||
inventory_groups = []
|
||||
inventory_hosts = []
|
||||
jobs = []
|
||||
#job_events = []
|
||||
|
||||
def spread(n, m):
|
||||
ret = []
|
||||
# At least one in each slot, split up the rest exponentially so the first
|
||||
# buckets contain a lot of entries
|
||||
for i in xrange(m):
|
||||
if n > 0:
|
||||
ret.append(1)
|
||||
n -= 1
|
||||
else:
|
||||
ret.append(0)
|
||||
|
||||
for i in xrange(m):
|
||||
n_in_this_slot = n // 2
|
||||
n-= n_in_this_slot
|
||||
ret[i] += n_in_this_slot
|
||||
if n > 0 and len(ret):
|
||||
ret[0] += n
|
||||
return ret
|
||||
|
||||
ids = defaultdict(lambda: 0)
|
||||
|
||||
|
||||
class Rollback(Exception):
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
|
||||
with batch_role_ancestor_rebuilding():
|
||||
with transaction.atomic():
|
||||
admin, _ = User.objects.get_or_create(username = 'admin', is_superuser=True)
|
||||
org_admin, _ = User.objects.get_or_create(username = 'org_admin')
|
||||
org_member, _ = User.objects.get_or_create(username = 'org_member')
|
||||
prj_admin, _ = User.objects.get_or_create(username = 'prj_admin')
|
||||
jt_admin, _ = User.objects.get_or_create(username = 'jt_admin')
|
||||
inv_admin, _ = User.objects.get_or_create(username = 'inv_admin')
|
||||
|
||||
admin.is_superuser = True
|
||||
admin.save()
|
||||
admin.set_password('test')
|
||||
admin.save()
|
||||
org_admin.set_password('test')
|
||||
org_admin.save()
|
||||
org_member.set_password('test')
|
||||
org_member.save()
|
||||
prj_admin.set_password('test')
|
||||
prj_admin.save()
|
||||
jt_admin.set_password('test')
|
||||
jt_admin.save()
|
||||
inv_admin.set_password('test')
|
||||
inv_admin.save()
|
||||
|
||||
|
||||
|
||||
print('# Creating %d organizations' % n_organizations)
|
||||
for i in xrange(n_organizations):
|
||||
sys.stdout.write('\r%d ' % (i + 1))
|
||||
sys.stdout.flush()
|
||||
org = Organization.objects.create(name='%s Organization %d' % (prefix, i))
|
||||
organizations.append(org)
|
||||
if i == 0:
|
||||
org.admin_role.members.add(org_admin)
|
||||
org.member_role.members.add(org_admin)
|
||||
org.member_role.members.add(org_member)
|
||||
org.member_role.members.add(prj_admin)
|
||||
org.member_role.members.add(jt_admin)
|
||||
org.member_role.members.add(inv_admin)
|
||||
|
||||
print('')
|
||||
|
||||
print('# Creating %d users' % n_users)
|
||||
org_idx = 0
|
||||
for n in spread(n_users, n_organizations):
|
||||
for i in range(n):
|
||||
ids['user'] += 1
|
||||
user_id = ids['user']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, organizations[org_idx].name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
user = User.objects.create(username='%suser-%d' % (prefix, user_id))
|
||||
organizations[org_idx].member_role.members.add(user)
|
||||
users.append(user)
|
||||
org_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Creating %d teams' % n_teams)
|
||||
org_idx = 0
|
||||
for n in spread(n_teams, n_organizations):
|
||||
org = organizations[org_idx]
|
||||
for i in range(n):
|
||||
ids['team'] += 1
|
||||
team_id = ids['team']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, org.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
team = Team.objects.create(name='%s Team %d Org %d' % (prefix, team_id, org_idx), organization=org)
|
||||
teams.append(team)
|
||||
org_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Adding users to teams')
|
||||
for org in organizations:
|
||||
org_teams = [t for t in org.teams.all()]
|
||||
org_users = [u for u in org.member_role.members.all()]
|
||||
print(' Spreading %d users accross %d teams for %s' % (len(org_users), len(org_teams), org.name))
|
||||
# Our normal spread for most users
|
||||
cur_user_idx = 0
|
||||
cur_team_idx = 0
|
||||
for n in spread(len(org_users), len(org_teams)):
|
||||
team = org_teams[cur_team_idx]
|
||||
for i in range(n):
|
||||
if cur_user_idx < len(org_users):
|
||||
user = org_users[cur_user_idx]
|
||||
team.member_role.members.add(user)
|
||||
cur_user_idx += 1
|
||||
cur_team_idx += 1
|
||||
|
||||
# First user gets added to all teams
|
||||
for team in org_teams:
|
||||
team.member_role.members.add(org_users[0])
|
||||
|
||||
|
||||
print('# Creating %d credentials for users' % (n_credentials - n_credentials // 2))
|
||||
user_idx = 0
|
||||
for n in spread(n_credentials - n_credentials // 2, n_users):
|
||||
user = users[user_idx]
|
||||
for i in range(n):
|
||||
ids['credential'] += 1
|
||||
sys.stdout.write('\r %d ' % (ids['credential']))
|
||||
sys.stdout.flush()
|
||||
credential_id = ids['credential']
|
||||
credential = Credential.objects.create(name='%s Credential %d User %d' % (prefix, credential_id, user_idx))
|
||||
credential.owner_role.members.add(user)
|
||||
credentials.append(credential)
|
||||
user_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Creating %d credentials for teams' % (n_credentials // 2))
|
||||
team_idx = 0
|
||||
starting_credential_id = ids['credential']
|
||||
for n in spread(n_credentials - n_credentials // 2, n_teams):
|
||||
team = teams[team_idx]
|
||||
for i in range(n):
|
||||
ids['credential'] += 1
|
||||
sys.stdout.write('\r %d ' % (ids['credential'] - starting_credential_id))
|
||||
sys.stdout.flush()
|
||||
credential_id = ids['credential']
|
||||
credential = Credential.objects.create(name='%s Credential %d team %d' % (prefix, credential_id, team_idx))
|
||||
credential.owner_role.parents.add(team.member_role)
|
||||
credentials.append(credential)
|
||||
team_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Creating %d projects' % n_projects)
|
||||
org_idx = 0
|
||||
for n in spread(n_projects, n_organizations):
|
||||
org = organizations[org_idx]
|
||||
for i in range(n):
|
||||
ids['project'] += 1
|
||||
project_id = ids['project']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, org.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
project = Project.objects.create(name='%s Project %d Org %d' % (prefix, project_id, org_idx), organization=org)
|
||||
projects.append(project)
|
||||
if org_idx == 0 and i == 0:
|
||||
project.admin_role.members.add(prj_admin)
|
||||
|
||||
org_idx += 1
|
||||
print('')
|
||||
|
||||
|
||||
print('# Creating %d inventories' % n_inventories)
|
||||
org_idx = 0
|
||||
for n in spread(n_inventories, min(n_inventories // 4 + 1, n_organizations)):
|
||||
org = organizations[org_idx]
|
||||
for i in range(n):
|
||||
ids['inventory'] += 1
|
||||
inventory_id = ids['inventory']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, org.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
inventory = Inventory.objects.create(name='%s Inventory %d Org %d' % (prefix, inventory_id, org_idx), organization=org)
|
||||
inventories.append(inventory)
|
||||
if org_idx == 0 and i == 0:
|
||||
inventory.admin_role.members.add(inv_admin)
|
||||
|
||||
org_idx += 1
|
||||
print('')
|
||||
|
||||
|
||||
print('# Creating %d inventory_groups' % n_inventory_groups)
|
||||
inv_idx = 0
|
||||
for n in spread(n_inventory_groups, n_inventories):
|
||||
inventory = inventories[inv_idx]
|
||||
parent_list = [None] * 3
|
||||
for i in range(n):
|
||||
ids['group'] += 1
|
||||
group_id = ids['group']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, inventory.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
group = Group.objects.create(
|
||||
name='%s Group %d Inventory %d' % (prefix, group_id, inv_idx),
|
||||
inventory=inventory,
|
||||
)
|
||||
# Have each group have up to 3 parent groups
|
||||
for parent_n in range(3):
|
||||
if i // 4 + parent_n < len(parent_list) and parent_list[i // 4 + parent_n]:
|
||||
group.parents.add(parent_list[i // 4 + parent_n])
|
||||
if parent_list[i // 4] is None:
|
||||
parent_list[i // 4] = group
|
||||
else:
|
||||
parent_list.append(group)
|
||||
inventory_groups.append(group)
|
||||
|
||||
inv_idx += 1
|
||||
print('')
|
||||
|
||||
|
||||
print('# Creating %d inventory_hosts' % n_inventory_hosts)
|
||||
group_idx = 0
|
||||
for n in spread(n_inventory_hosts, n_inventory_groups):
|
||||
group = inventory_groups[group_idx]
|
||||
for i in range(n):
|
||||
ids['host'] += 1
|
||||
host_id = ids['host']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, group.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
host = Host.objects.create(name='%s.host-%06d.group-%05d.dummy' % (prefix, host_id, group_idx), inventory=group.inventory)
|
||||
# Add the host to up to 3 groups
|
||||
host.groups.add(group)
|
||||
for m in range(2):
|
||||
if group_idx + m < len(inventory_groups) and group.inventory.id == inventory_groups[group_idx + m].inventory.id:
|
||||
host.groups.add(inventory_groups[group_idx + m])
|
||||
|
||||
inventory_hosts.append(host)
|
||||
|
||||
group_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Creating %d job_templates' % n_job_templates)
|
||||
project_idx = 0
|
||||
inv_idx = 0
|
||||
for n in spread(n_job_templates, n_projects):
|
||||
project = projects[project_idx]
|
||||
for i in range(n):
|
||||
ids['job_template'] += 1
|
||||
job_template_id = ids['job_template']
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, project.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
|
||||
inventory = None
|
||||
org_inv_count = project.organization.inventories.count()
|
||||
if org_inv_count > 0:
|
||||
inventory = project.organization.inventories.all()[inv_idx % org_inv_count]
|
||||
|
||||
job_template = JobTemplate.objects.create(
|
||||
name='%s Job Template %d Project %d' % (prefix, job_template_id, project_idx),
|
||||
inventory=inventory,
|
||||
project=project,
|
||||
)
|
||||
job_templates.append(job_template)
|
||||
inv_idx += 1
|
||||
if project_idx == 0 and i == 0:
|
||||
job_template.admin_role.members.add(jt_admin)
|
||||
project_idx += 1
|
||||
print('')
|
||||
|
||||
print('# Creating %d jobs' % n_jobs)
|
||||
group_idx = 0
|
||||
job_template_idx = 0
|
||||
for n in spread(n_jobs, n_job_templates):
|
||||
job_template = job_templates[job_template_idx]
|
||||
for i in range(n):
|
||||
sys.stdout.write('\r Assigning %d to %s: %d ' % (n, job_template.name, i+ 1))
|
||||
sys.stdout.flush()
|
||||
job = Job.objects.create(job_template=job_template)
|
||||
jobs.append(job)
|
||||
|
||||
if job_template.inventory:
|
||||
inv_groups = [g for g in job_template.inventory.groups.all()]
|
||||
if len(inv_groups):
|
||||
JobHostSummary.objects.bulk_create([
|
||||
JobHostSummary(
|
||||
job=job, host=h, host_name=h.name, processed=1,
|
||||
created=now(), modified=now()
|
||||
)
|
||||
for h in inv_groups[group_idx % len(inv_groups)].hosts.all()[:100]
|
||||
])
|
||||
group_idx += 1
|
||||
job_template_idx += 1
|
||||
if n:
|
||||
print('')
|
||||
|
||||
print('# Creating %d job events' % n_job_events)
|
||||
job_idx = 0
|
||||
for n in spread(n_job_events, n_jobs):
|
||||
job = jobs[job_idx]
|
||||
sys.stdout.write('\r Creating %d job events for job %d' % (n, job.id))
|
||||
sys.stdout.flush()
|
||||
JobEvent.objects.bulk_create([
|
||||
JobEvent(
|
||||
created=now(),
|
||||
modified=now(),
|
||||
job=job,
|
||||
event='runner_on_ok'
|
||||
)
|
||||
for i in range(n)
|
||||
])
|
||||
job_idx += 1
|
||||
if n:
|
||||
print('')
|
||||
|
||||
if options['pretend']:
|
||||
raise Rollback()
|
||||
except Rollback:
|
||||
print('Rolled back changes')
|
||||
pass
|
||||
Loading…
x
Reference in New Issue
Block a user