mirror of
https://github.com/ansible/awx.git
synced 2026-02-25 15:06:02 -03:30
Initial implicit role / resource field additions into models
"Completes" #731 until we find out what I missed
This commit is contained in:
@@ -45,7 +45,8 @@ class AutoOneToOneField(models.OneToOneField):
|
|||||||
|
|
||||||
def resolve_field(obj, field):
|
def resolve_field(obj, field):
|
||||||
for f in field.split('.'):
|
for f in field.split('.'):
|
||||||
obj = getattr(obj, f)
|
if obj:
|
||||||
|
obj = getattr(obj, f)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
class ResourceFieldDescriptor(ReverseSingleRelatedObjectDescriptor):
|
class ResourceFieldDescriptor(ReverseSingleRelatedObjectDescriptor):
|
||||||
@@ -61,7 +62,16 @@ class ResourceFieldDescriptor(ReverseSingleRelatedObjectDescriptor):
|
|||||||
return resource
|
return resource
|
||||||
resource = Resource._default_manager.create()
|
resource = Resource._default_manager.create()
|
||||||
if self.parent_resource:
|
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()
|
resource.save()
|
||||||
setattr(instance, self.field.name, resource)
|
setattr(instance, self.field.name, resource)
|
||||||
instance.save(update_fields=[self.field.name,])
|
instance.save(update_fields=[self.field.name,])
|
||||||
@@ -102,25 +112,43 @@ class ImplicitRoleDescriptor(ReverseSingleRelatedObjectDescriptor):
|
|||||||
|
|
||||||
if not self.role_name:
|
if not self.role_name:
|
||||||
raise FieldError('Implicit role missing `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 = Role._default_manager.create(name=self.role_name)
|
||||||
role.save()
|
role.save()
|
||||||
if self.parent_role:
|
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)
|
setattr(instance, self.field.name, role)
|
||||||
instance.save(update_fields=[self.field.name,])
|
instance.save(update_fields=[self.field.name,])
|
||||||
|
|
||||||
permissions = RolePermission(
|
if self.resource_field and self.permissions:
|
||||||
role=role,
|
permissions = RolePermission(
|
||||||
resource=getattr(instance, self.resource_field)
|
role=role,
|
||||||
)
|
resource=getattr(instance, self.resource_field)
|
||||||
for k,v in self.permissions.items():
|
)
|
||||||
setattr(permissions, k, v)
|
|
||||||
permissions.save()
|
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
|
return role
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
|
|||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.main.fields import ImplicitResourceField, ImplicitRoleField
|
||||||
from awx.main.constants import CLOUD_PROVIDERS
|
from awx.main.constants import CLOUD_PROVIDERS
|
||||||
from awx.main.utils import decrypt_field
|
from awx.main.utils import decrypt_field
|
||||||
from awx.main.models.base import * # noqa
|
from awx.main.models.base import * # noqa
|
||||||
@@ -153,6 +154,27 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
|
|||||||
default='',
|
default='',
|
||||||
help_text=_('Vault password (or "ASK" to prompt the user).'),
|
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
|
@property
|
||||||
def needs_ssh_password(self):
|
def needs_ssh_password(self):
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from django.utils.timezone import now
|
|||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.constants import CLOUD_PROVIDERS
|
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.managers import HostManager
|
||||||
from awx.main.models.base import * # noqa
|
from awx.main.models.base import * # noqa
|
||||||
from awx.main.models.jobs import Job
|
from awx.main.models.jobs import Job
|
||||||
@@ -92,6 +92,21 @@ class Inventory(CommonModel):
|
|||||||
editable=False,
|
editable=False,
|
||||||
help_text=_('Number of external inventory sources in this inventory with failures.'),
|
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):
|
def get_absolute_url(self):
|
||||||
return reverse('api:inventory_detail', args=(self.pk,))
|
return reverse('api:inventory_detail', args=(self.pk,))
|
||||||
@@ -523,6 +538,21 @@ class Group(CommonModelNameNotUnique):
|
|||||||
editable=False,
|
editable=False,
|
||||||
help_text=_('Inventory source(s) that created or modified this group.'),
|
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):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@@ -1093,6 +1123,30 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions):
|
|||||||
update_cache_timeout = models.PositiveIntegerField(
|
update_cache_timeout = models.PositiveIntegerField(
|
||||||
default=0,
|
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
|
@classmethod
|
||||||
def _get_unified_job_class(cls):
|
def _get_unified_job_class(cls):
|
||||||
|
|||||||
@@ -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.utils import emit_websocket_notification
|
||||||
from awx.main.redact import PlainTextCleaner
|
from awx.main.redact import PlainTextCleaner
|
||||||
from awx.main.conf import tower_settings
|
from awx.main.conf import tower_settings
|
||||||
|
from awx.main.fields import ImplicitResourceField, ImplicitRoleField
|
||||||
|
|
||||||
logger = logging.getLogger('awx.main.models.jobs')
|
logger = logging.getLogger('awx.main.models.jobs')
|
||||||
|
|
||||||
@@ -178,6 +179,25 @@ class JobTemplate(UnifiedJobTemplate, JobOptions):
|
|||||||
blank=True,
|
blank=True,
|
||||||
default={},
|
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
|
@classmethod
|
||||||
def _get_unified_job_class(cls):
|
def _get_unified_job_class(cls):
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from django.utils.timezone import now as tz_now
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
# AWX
|
# 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.models.base import * # noqa
|
||||||
from awx.main.conf import tower_settings
|
from awx.main.conf import tower_settings
|
||||||
|
|
||||||
@@ -42,11 +42,27 @@ class Organization(CommonModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
related_name='admin_of_organizations',
|
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(
|
projects = models.ManyToManyField(
|
||||||
'Project',
|
'Project',
|
||||||
blank=True,
|
blank=True,
|
||||||
related_name='organizations',
|
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):
|
def get_absolute_url(self):
|
||||||
return reverse('api:organization_detail', args=(self.pk,))
|
return reverse('api:organization_detail', args=(self.pk,))
|
||||||
@@ -88,6 +104,23 @@ class Team(CommonModelNameNotUnique):
|
|||||||
blank=True,
|
blank=True,
|
||||||
related_name='teams',
|
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):
|
def get_absolute_url(self):
|
||||||
return reverse('api:team_detail', args=(self.pk,))
|
return reverse('api:team_detail', args=(self.pk,))
|
||||||
@@ -103,6 +136,10 @@ class Team(CommonModelNameNotUnique):
|
|||||||
class Permission(CommonModelNameNotUnique):
|
class Permission(CommonModelNameNotUnique):
|
||||||
'''
|
'''
|
||||||
A permission allows a user, project, or team to be able to use an inventory source.
|
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:
|
class Meta:
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from awx.main.models.base import * # noqa
|
|||||||
from awx.main.models.jobs import Job
|
from awx.main.models.jobs import Job
|
||||||
from awx.main.models.unified_jobs import * # noqa
|
from awx.main.models.unified_jobs import * # noqa
|
||||||
from awx.main.utils import update_scm_url
|
from awx.main.utils import update_scm_url
|
||||||
|
from awx.main.fields import ImplicitResourceField, ImplicitRoleField
|
||||||
|
|
||||||
__all__ = ['Project', 'ProjectUpdate']
|
__all__ = ['Project', 'ProjectUpdate']
|
||||||
|
|
||||||
@@ -194,6 +195,14 @@ class Project(UnifiedJobTemplate, ProjectOptions):
|
|||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
ordering = ('id',)
|
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(
|
scm_delete_on_next_update = models.BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
editable=False,
|
editable=False,
|
||||||
@@ -205,6 +214,31 @@ class Project(UnifiedJobTemplate, ProjectOptions):
|
|||||||
default=0,
|
default=0,
|
||||||
blank=True,
|
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
|
@classmethod
|
||||||
def _get_unified_job_class(cls):
|
def _get_unified_job_class(cls):
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ from django.db.models.signals import pre_save, post_save, pre_delete, post_delet
|
|||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.models.base import * # noqa
|
from awx.main.models.base import * # noqa
|
||||||
from awx.main.fields import * # noqa
|
|
||||||
|
|
||||||
__all__ = ['Role', 'RolePermission', 'Resource', 'RoleHierarchy', 'ResourceHierarchy']
|
__all__ = ['Role', 'RolePermission', 'Resource', 'RoleHierarchy', 'ResourceHierarchy']
|
||||||
|
|
||||||
@@ -158,6 +157,8 @@ class RolePermission(CreatedModifiedModel):
|
|||||||
write = models.IntegerField(default = 0)
|
write = models.IntegerField(default = 0)
|
||||||
update = models.IntegerField(default = 0)
|
update = models.IntegerField(default = 0)
|
||||||
delete = models.IntegerField(default = 0)
|
delete = models.IntegerField(default = 0)
|
||||||
|
execute = models.IntegerField(default = 0)
|
||||||
scm_update = models.IntegerField(default = 0)
|
scm_update = models.IntegerField(default = 0)
|
||||||
|
use = models.IntegerField(default = 0)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user