Initial implicit role / resource field additions into models

"Completes" #731 until we find out what I missed
This commit is contained in:
Akita Noek 2016-01-28 16:58:19 -05:00
parent 68d8299689
commit 6dad0406b8
7 changed files with 213 additions and 17 deletions

View File

@ -45,7 +45,8 @@ class AutoOneToOneField(models.OneToOneField):
def resolve_field(obj, field):
for f in field.split('.'):
obj = getattr(obj, f)
if obj:
obj = getattr(obj, f)
return obj
class ResourceFieldDescriptor(ReverseSingleRelatedObjectDescriptor):
@ -61,7 +62,16 @@ class ResourceFieldDescriptor(ReverseSingleRelatedObjectDescriptor):
return resource
resource = Resource._default_manager.create()
if self.parent_resource:
resource.parent = resolve_field(instance, self.parent_resource)
# Take first non null parent resource
parent = None
if type(self.parent_resource) is list:
for path in self.parent_resource:
parent = resolve_field(instance, path)
if parent:
break
else:
parent = resolve_field(instance, self.parent_resource)
resource.parent = parent
resource.save()
setattr(instance, self.field.name, resource)
instance.save(update_fields=[self.field.name,])
@ -102,25 +112,43 @@ class ImplicitRoleDescriptor(ReverseSingleRelatedObjectDescriptor):
if not self.role_name:
raise FieldError('Implicit role missing `role_name`')
if not self.resource_field:
raise FieldError('Implicit role missing `resource_field` specification')
if not self.permissions:
raise FieldError('Implicit role missing `permissions`')
role = Role._default_manager.create(name=self.role_name)
role.save()
if self.parent_role:
role.parents.add(resolve_field(instance, self.parent_role))
# Add all non-null parent roles as parents
if type(self.parent_role) is list:
for path in self.parent_role:
parent = resolve_field(instance, path)
if parent:
role.parents.add(parent)
else:
parent = resolve_field(instance, self.parent_role)
if parent:
role.parents.add(parent)
setattr(instance, self.field.name, role)
instance.save(update_fields=[self.field.name,])
permissions = RolePermission(
role=role,
resource=getattr(instance, self.resource_field)
)
for k,v in self.permissions.items():
setattr(permissions, k, v)
permissions.save()
if self.resource_field and self.permissions:
permissions = RolePermission(
role=role,
resource=getattr(instance, self.resource_field)
)
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()
return role

View File

@ -11,6 +11,7 @@ from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
from django.core.urlresolvers import reverse
# AWX
from awx.main.fields import ImplicitResourceField, ImplicitRoleField
from awx.main.constants import CLOUD_PROVIDERS
from awx.main.utils import decrypt_field
from awx.main.models.base import * # noqa
@ -153,6 +154,27 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
default='',
help_text=_('Vault password (or "ASK" to prompt the user).'),
)
resource = ImplicitResourceField(
parent_resource=[
'user.resource',
'team.resource'
]
)
owner_role = ImplicitRoleField(
role_name='Credential Owner',
parent_role=[
'user.user_role',
'team.admin_role'
],
resource_field='resource',
permissions = { 'all': True }
)
usage_role = ImplicitRoleField(
role_name='Credential User',
resource_field='resource',
parent_role= 'team.member_role',
permissions = { 'usage': True }
)
@property
def needs_ssh_password(self):

View File

@ -18,7 +18,7 @@ from django.utils.timezone import now
# AWX
from awx.main.constants import CLOUD_PROVIDERS
from awx.main.fields import AutoOneToOneField
from awx.main.fields import AutoOneToOneField, ImplicitResourceField, ImplicitRoleField
from awx.main.managers import HostManager
from awx.main.models.base import * # noqa
from awx.main.models.jobs import Job
@ -92,6 +92,21 @@ class Inventory(CommonModel):
editable=False,
help_text=_('Number of external inventory sources in this inventory with failures.'),
)
resource = ImplicitResourceField(
parent_resource='organization.resource'
)
admin_role = ImplicitRoleField(
role_name='Inventory Administrator',
parent_role='organization.admin_role',
resource_field='resource',
permissions = { 'all': True }
)
auditor_role = ImplicitRoleField(
role_name='Inventory Auditor',
parent_role='organization.auditor_role',
resource_field='resource',
permissions = { 'read': True }
)
def get_absolute_url(self):
return reverse('api:inventory_detail', args=(self.pk,))
@ -523,6 +538,21 @@ class Group(CommonModelNameNotUnique):
editable=False,
help_text=_('Inventory source(s) that created or modified this group.'),
)
resource = ImplicitResourceField(
parent_resource='inventory.resource'
)
admin_role = ImplicitRoleField(
role_name='Inventory Group Administrator',
parent_role='inventory.admin_role',
resource_field='resource',
permissions = { 'all': True }
)
auditor_role = ImplicitRoleField(
role_name='Inventory Group Auditor',
parent_role='inventory.auditor_role',
resource_field='resource',
permissions = { 'read': True }
)
def __unicode__(self):
return self.name
@ -1093,6 +1123,30 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions):
update_cache_timeout = models.PositiveIntegerField(
default=0,
)
resource = ImplicitResourceField(
parent_resource=[
'group.resource',
'inventory.resource'
]
)
admin_role = ImplicitRoleField(
role_name='Inventory Group Administrator',
parent_role=[
'group.admin_role',
'inventory.admin_role',
],
resource_field='resource',
permissions = { 'all': True }
)
auditor_role = ImplicitRoleField(
role_name='Inventory Group Auditor',
parent_role=[
'group.auditor_role',
'inventory.auditor_role',
],
resource_field='resource',
permissions = { 'read': True }
)
@classmethod
def _get_unified_job_class(cls):

View File

@ -26,6 +26,7 @@ from awx.main.utils import decrypt_field, ignore_inventory_computed_fields
from awx.main.utils import emit_websocket_notification
from awx.main.redact import PlainTextCleaner
from awx.main.conf import tower_settings
from awx.main.fields import ImplicitResourceField, ImplicitRoleField
logger = logging.getLogger('awx.main.models.jobs')
@ -178,6 +179,25 @@ class JobTemplate(UnifiedJobTemplate, JobOptions):
blank=True,
default={},
)
resource = ImplicitResourceField()
admin_role = ImplicitRoleField(
role_name='Job Template Administrator',
parent_role='project.admin_role',
resource_field='resource',
permissions = { 'all': True }
)
auditor_role = ImplicitRoleField(
role_name='Job Template Auditor',
parent_role='project.auditor_role',
resource_field='resource',
permissions = { 'read': True }
)
executor_role = ImplicitRoleField(
role_name='Job Template Executor',
parent_role='project.auditor_role',
resource_field='resource',
permissions = { 'execute': True }
)
@classmethod
def _get_unified_job_class(cls):

View File

@ -16,7 +16,7 @@ from django.utils.timezone import now as tz_now
from django.utils.translation import ugettext_lazy as _
# AWX
from awx.main.fields import AutoOneToOneField
from awx.main.fields import AutoOneToOneField, ImplicitResourceField, ImplicitRoleField
from awx.main.models.base import * # noqa
from awx.main.conf import tower_settings
@ -42,11 +42,27 @@ class Organization(CommonModel):
blank=True,
related_name='admin_of_organizations',
)
# TODO: This field is deprecated. In 3.0 all projects will have exactly one
# organization parent, the foreign key field representing that has been
# moved to the Project model.
projects = models.ManyToManyField(
'Project',
blank=True,
related_name='organizations',
)
resource = ImplicitResourceField()
admin_role = ImplicitRoleField(
role_name='Organization Administrator',
resource_field='resource',
permissions = { 'all': True }
)
auditor_role = ImplicitRoleField(
role_name='Organization Auditor',
resource_field='resource',
permissions = { 'read': True }
)
def get_absolute_url(self):
return reverse('api:organization_detail', args=(self.pk,))
@ -88,6 +104,23 @@ class Team(CommonModelNameNotUnique):
blank=True,
related_name='teams',
)
resource = ImplicitResourceField()
admin_role = ImplicitRoleField(
role_name='Team Administrator',
parent_role='organization.admin_role',
resource_field='resource',
permissions = { 'all': True }
)
auditor_role = ImplicitRoleField(
role_name='Team Auditor',
parent_role='organization.auditor_role',
resource_field='resource',
permissions = { 'read': True }
)
member_role = ImplicitRoleField(
role_name='Team Member',
parent_role='admin_role',
)
def get_absolute_url(self):
return reverse('api:team_detail', args=(self.pk,))
@ -103,6 +136,10 @@ class Team(CommonModelNameNotUnique):
class Permission(CommonModelNameNotUnique):
'''
A permission allows a user, project, or team to be able to use an inventory source.
NOTE: This class is deprecated, permissions and access is to be handled by
our new RBAC system. This class should be able to be safely removed after a 3.0.0
migration. - anoek 2016-01-28
'''
class Meta:

View File

@ -22,6 +22,7 @@ from awx.main.models.base import * # noqa
from awx.main.models.jobs import Job
from awx.main.models.unified_jobs import * # noqa
from awx.main.utils import update_scm_url
from awx.main.fields import ImplicitResourceField, ImplicitRoleField
__all__ = ['Project', 'ProjectUpdate']
@ -194,6 +195,14 @@ class Project(UnifiedJobTemplate, ProjectOptions):
app_label = 'main'
ordering = ('id',)
organization = models.ForeignKey(
'Organization',
blank=False,
null=True,
on_delete=models.SET_NULL,
related_name='project_list', # TODO: this should eventually be refactored
# back to 'projects' - anoek 2016-01-28
)
scm_delete_on_next_update = models.BooleanField(
default=False,
editable=False,
@ -205,6 +214,31 @@ class Project(UnifiedJobTemplate, ProjectOptions):
default=0,
blank=True,
)
resource = ImplicitResourceField()
admin_role = ImplicitRoleField(
role_name='Project Administrator',
parent_role='organization.admin_role',
resource_field='resource',
permissions = { 'all': True }
)
auditor_role = ImplicitRoleField(
role_name='Project Auditor',
parent_role='organization.auditor_role',
resource_field='resource',
permissions = { 'read': True }
)
member_role = ImplicitRoleField(
role_name='Project Member',
parent_role='admin',
resource_field='resource',
permissions = { 'usage': True }
)
scm_update_role = ImplicitRoleField(
role_name='Project Updater',
parent_role='admin',
resource_field='resource',
permissions = { 'scm_update': True }
)
@classmethod
def _get_unified_job_class(cls):

View File

@ -11,7 +11,6 @@ from django.db.models.signals import pre_save, post_save, pre_delete, post_delet
# AWX
from awx.main.models.base import * # noqa
from awx.main.fields import * # noqa
__all__ = ['Role', 'RolePermission', 'Resource', 'RoleHierarchy', 'ResourceHierarchy']
@ -158,6 +157,8 @@ class RolePermission(CreatedModifiedModel):
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)