mirror of
https://github.com/ansible/awx.git
synced 2026-02-01 09:38:10 -03:30
Split out RBAC and can_user_* methods from models into access.py. Moved list/item permissions checks from the base views into RBAC. Added serializers/views/tests for jobs REST API.
This commit is contained in:
@@ -14,33 +14,91 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible Commander. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Django
|
||||
from django.contrib.auth.models import User
|
||||
from lib.main.models import *
|
||||
from rest_framework import serializers, pagination
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.serializers import json
|
||||
|
||||
# Django REST framework
|
||||
from rest_framework import serializers, pagination
|
||||
from rest_framework.templatetags.rest_framework import replace_query_param
|
||||
|
||||
# Ansible Commander
|
||||
from lib.main.models import *
|
||||
|
||||
BASE_FIELDS = ('id', 'url', 'related', 'creation_date', 'name', 'description')
|
||||
|
||||
class NextPageField(pagination.NextPageField):
|
||||
|
||||
def to_native(self, value):
|
||||
if not value.has_next():
|
||||
return None
|
||||
page = value.next_page_number()
|
||||
request = self.context.get('request')
|
||||
url = request and request.get_full_path() or ''
|
||||
return replace_query_param(url, self.page_field, page)
|
||||
|
||||
class PreviousPageField(pagination.NextPageField):
|
||||
|
||||
def to_native(self, value):
|
||||
if not value.has_previous():
|
||||
return None
|
||||
page = value.previous_page_number()
|
||||
request = self.context.get('request')
|
||||
url = request and request.get_full_path() or ''
|
||||
return replace_query_param(url, self.page_field, page)
|
||||
|
||||
class PaginationSerializer(pagination.BasePaginationSerializer):
|
||||
'''
|
||||
Custom pagination serializer to output only URL path (without host/port).
|
||||
'''
|
||||
|
||||
count = serializers.Field(source='paginator.count')
|
||||
next = NextPageField(source='*')
|
||||
previous = PreviousPageField(source='*')
|
||||
|
||||
class BaseSerializer(serializers.ModelSerializer):
|
||||
pass
|
||||
|
||||
class OrganizationSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
url = serializers.SerializerMethodField('get_absolute_url')
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
# make certain fields read only
|
||||
creation_date = serializers.DateTimeField(read_only=True) # FIXME: is model Date or DateTime, fix model
|
||||
active = serializers.BooleanField(read_only=True)
|
||||
creation_date = serializers.SerializerMethodField('get_creation_date') # FIXME: is model Date or DateTime, fix model
|
||||
active = serializers.SerializerMethodField('get_active')
|
||||
|
||||
def get_absolute_url(self, obj):
|
||||
if isinstance(obj, User):
|
||||
return reverse('main:users_detail', args=(obj.pk,))
|
||||
else:
|
||||
return obj.get_absolute_url()
|
||||
|
||||
def get_related(self, obj):
|
||||
res = dict()
|
||||
if getattr(obj, 'created_by', None):
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
return res
|
||||
|
||||
def get_creation_date(self, obj):
|
||||
if isinstance(obj, User):
|
||||
return obj.date_joined.date()
|
||||
else:
|
||||
return obj.creation_date
|
||||
|
||||
def get_active(self, obj):
|
||||
if isinstance(obj, User):
|
||||
return obj.is_active
|
||||
else:
|
||||
return obj.active
|
||||
|
||||
class OrganizationSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Organization
|
||||
fields = ('url', 'id', 'name', 'description', 'creation_date', 'related') # whitelist
|
||||
fields = BASE_FIELDS
|
||||
|
||||
def get_related(self, obj):
|
||||
''' related resource URLs '''
|
||||
|
||||
res = dict(
|
||||
res = super(OrganizationSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
audit_trail = reverse('main:organizations_audit_trail_list', args=(obj.pk,)),
|
||||
projects = reverse('main:organizations_projects_list', args=(obj.pk,)),
|
||||
inventories = reverse('main:organizations_inventories_list', args=(obj.pk,)),
|
||||
@@ -48,181 +106,137 @@ class OrganizationSerializer(BaseSerializer):
|
||||
admins = reverse('main:organizations_admins_list', args=(obj.pk,)),
|
||||
tags = reverse('main:organizations_tags_list', args=(obj.pk,)),
|
||||
teams = reverse('main:organizations_teams_list', args=(obj.pk,)),
|
||||
)
|
||||
if obj.created_by:
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
|
||||
))
|
||||
return res
|
||||
|
||||
class AuditTrailSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
class Meta:
|
||||
model = AuditTrail
|
||||
fields = ('url', 'id', 'modified_by', 'delta', 'detail', 'comment')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = dict()
|
||||
res = super(AuditTrailSerializer, self).get_related(obj)
|
||||
if obj.modified_by:
|
||||
res['modified_by'] = reverse('main:users_detail', args=(obj.modified_by.pk,))
|
||||
return res
|
||||
|
||||
class ProjectSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
available_playbooks = serializers.Field(source='available_playbooks')
|
||||
|
||||
class Meta:
|
||||
model = Project
|
||||
fields = ('url', 'id', 'name', 'description', 'creation_date', 'local_path')#, 'default_playbook', 'scm_type')
|
||||
fields = BASE_FIELDS + ('local_path', 'available_playbooks')
|
||||
# 'default_playbook', 'scm_type')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = dict(
|
||||
res = super(ProjectSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
organizations = reverse('main:projects_organizations_list', args=(obj.pk,)),
|
||||
)
|
||||
if obj.created_by:
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
))
|
||||
return res
|
||||
|
||||
|
||||
class InventorySerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
class Meta:
|
||||
model = Inventory
|
||||
fields = ('url', 'id', 'name', 'description', 'creation_date', 'related', 'organization')
|
||||
fields = BASE_FIELDS + ('organization',)
|
||||
|
||||
def get_related(self, obj):
|
||||
res = dict(
|
||||
res = super(InventorySerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
hosts = reverse('main:inventory_hosts_list', args=(obj.pk,)),
|
||||
groups = reverse('main:inventory_groups_list', args=(obj.pk,)),
|
||||
organization = reverse('main:organizations_detail', args=(obj.organization.pk,)),
|
||||
)
|
||||
if obj.created_by:
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
))
|
||||
return res
|
||||
|
||||
class HostSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
class Meta:
|
||||
model = Host
|
||||
fields = ('url', 'id', 'name', 'description', 'creation_date', 'related', 'inventory')
|
||||
fields = BASE_FIELDS + ('inventory',)
|
||||
|
||||
def get_related(self, obj):
|
||||
res = dict(
|
||||
res = super(HostSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
variable_data = reverse('main:hosts_variable_detail', args=(obj.pk,)),
|
||||
inventory = reverse('main:inventory_detail', args=(obj.inventory.pk,)),
|
||||
)
|
||||
job_events = reverse('main:host_job_event_list', args=(obj.pk,)),
|
||||
))
|
||||
# NICE TO HAVE: possible reverse resource to show what groups the host is in
|
||||
if obj.created_by:
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
return res
|
||||
|
||||
class GroupSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = ('url', 'id', 'name', 'description', 'creation_date', 'inventory')
|
||||
fields = BASE_FIELDS + ('inventory',)
|
||||
|
||||
def get_related(self, obj):
|
||||
res = dict(
|
||||
res = super(GroupSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
variable_data = reverse('main:groups_variable_detail', args=(obj.pk,)),
|
||||
hosts = reverse('main:groups_hosts_list', args=(obj.pk,)),
|
||||
children = reverse('main:groups_children_list', args=(obj.pk,)),
|
||||
all_hosts = reverse('main:groups_all_hosts_list', args=(obj.pk,)),
|
||||
inventory = reverse('main:inventory_detail', args=(obj.inventory.pk,)),
|
||||
)
|
||||
if obj.created_by:
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
))
|
||||
return res
|
||||
|
||||
class TeamSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
class Meta:
|
||||
model = Team
|
||||
fields = ('url', 'id', 'related', 'name', 'description', 'organization', 'creation_date')
|
||||
|
||||
# FIXME: TODO: include related collections but also related FK urls
|
||||
fields = BASE_FIELDS + ('organization',)
|
||||
|
||||
def get_related(self, obj):
|
||||
res = dict(
|
||||
res = super(TeamSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
projects = reverse('main:teams_projects_list', args=(obj.pk,)),
|
||||
users = reverse('main:teams_users_list', args=(obj.pk,)),
|
||||
credentials = reverse('main:teams_credentials_list', args=(obj.pk,)),
|
||||
organization = reverse('main:organizations_detail', args=(obj.organization.pk,)),
|
||||
permissions = reverse('main:teams_permissions_list', args=(obj.pk,)),
|
||||
)
|
||||
if obj.created_by:
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
))
|
||||
return res
|
||||
|
||||
class PermissionSerializer(BaseSerializer):
|
||||
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
class Meta:
|
||||
model = Permission
|
||||
fields = ( 'url', 'id', 'user', 'team', 'name', 'description', 'creation_date',
|
||||
'project', 'inventory', 'permission_type' )
|
||||
fields = BASE_FIELDS + ('user', 'team', 'project', 'inventory',
|
||||
'permission_type',)
|
||||
|
||||
def get_related(self, obj):
|
||||
res = dict()
|
||||
res = super(PermissionSerializer, self).get_related(obj)
|
||||
if obj.user:
|
||||
res['user'] = reverse('main:users_detail', args=(obj.user.pk,))
|
||||
if obj.team:
|
||||
res['team'] = reverse('main:teams_detail', args=(obj.team.pk,))
|
||||
if self.project:
|
||||
if obj.project:
|
||||
res['project'] = reverse('main:projects_detail', args=(obj.project.pk,))
|
||||
if self.inventory:
|
||||
if obj.inventory:
|
||||
res['inventory'] = reverse('main:inventory_detail', args=(obj.inventory.pk,))
|
||||
if self.created_by:
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
return res
|
||||
|
||||
class CredentialSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
# FIXME: may want to make some of these filtered based on user accessing
|
||||
|
||||
class Meta:
|
||||
model = Credential
|
||||
fields = (
|
||||
'url', 'id', 'related', 'name', 'description', 'creation_date',
|
||||
'ssh_username', 'ssh_password', 'ssh_key_data', 'ssh_key_unlock',
|
||||
'sudo_username', 'sudo_password', 'user', 'team',
|
||||
)
|
||||
fields = BASE_FIELDS + ('ssh_username', 'ssh_password', 'ssh_key_data',
|
||||
'ssh_key_unlock', 'sudo_username',
|
||||
'sudo_password', 'user', 'team',)
|
||||
|
||||
def get_related(self, obj):
|
||||
# FIXME: no related collections, do want to add user and team if defined
|
||||
res = dict(
|
||||
)
|
||||
res = super(CredentialSerializer, self).get_related(obj)
|
||||
if obj.user:
|
||||
res['user'] = reverse('main:users_detail', args=(obj.user.pk,))
|
||||
res['user'] = reverse('main:users_detail', args=(obj.user.pk,))
|
||||
if obj.team:
|
||||
res['team'] = reverse('main:teams_detail', args=(obj.team.pk,))
|
||||
if obj.created_by:
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
res['team'] = reverse('main:teams_detail', args=(obj.team.pk,))
|
||||
return res
|
||||
|
||||
def validate(self, attrs):
|
||||
@@ -237,97 +251,122 @@ class CredentialSerializer(BaseSerializer):
|
||||
|
||||
class UserSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.SerializerMethodField('get_absolute_url_override')
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('url', 'id', 'username', 'first_name', 'last_name', 'email', 'is_active', 'is_superuser', 'related')
|
||||
fields = ('id', 'url', 'related', 'creation_date', 'username',
|
||||
'first_name', 'last_name', 'email', 'is_active',
|
||||
'is_superuser',)
|
||||
|
||||
def get_related(self, obj):
|
||||
return dict(
|
||||
res = super(UserSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
teams = reverse('main:users_teams_list', args=(obj.pk,)),
|
||||
organizations = reverse('main:users_organizations_list', args=(obj.pk,)),
|
||||
admin_of_organizations = reverse('main:users_admin_organizations_list', args=(obj.pk,)),
|
||||
projects = reverse('main:users_projects_list', args=(obj.pk,)),
|
||||
credentials = reverse('main:users_credentials_list', args=(obj.pk,)),
|
||||
permissions = reverse('main:users_permissions_list', args=(obj.pk,)),
|
||||
)
|
||||
|
||||
def get_absolute_url_override(self, obj):
|
||||
return reverse('main:users_detail', args=(obj.pk,))
|
||||
|
||||
))
|
||||
return res
|
||||
|
||||
class TagSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
class Meta:
|
||||
model = Tag
|
||||
fields = ('url', 'id', 'name')
|
||||
fields = ('id', 'url', 'name')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = dict()
|
||||
res = super(TagSerializer, self).get_related(obj)
|
||||
res.pop('created_by', None)
|
||||
return res
|
||||
|
||||
class VariableDataSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
class Meta:
|
||||
model = VariableData
|
||||
fields = ('url', 'id', 'data', 'related', 'name', 'description', 'creation_date')
|
||||
fields = BASE_FIELDS + ('data',)
|
||||
|
||||
def get_related(self, obj):
|
||||
# FIXME: add host or group if defined
|
||||
res = dict(
|
||||
)
|
||||
if obj.created_by:
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
res = super(VariableDataSerializer, self).get_related(obj)
|
||||
try:
|
||||
res['host'] = reverse('main:hosts_detail', args=(obj.host.pk,))
|
||||
except Host.DoesNotExist:
|
||||
pass
|
||||
try:
|
||||
res['group'] = reverse('main:groups_detail', args=(obj.group.pk,))
|
||||
except Group.DoesNotExist:
|
||||
pass
|
||||
return res
|
||||
|
||||
class JobTemplateSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
|
||||
class Meta:
|
||||
model = JobTemplate
|
||||
fields = ('url', 'id', 'related', 'name', 'description', 'job_type', 'credential', 'project', 'inventory', 'created_by', 'creation_date')
|
||||
fields = BASE_FIELDS + ('job_type', 'inventory', 'project', 'playbook',
|
||||
'credential', 'use_sudo', 'forks', 'limit',
|
||||
'verbosity', 'extra_vars')
|
||||
|
||||
def get_related(self, obj):
|
||||
# FIXME: fill in once further defined. related resources, credential, project, inventory, etc
|
||||
res = dict(
|
||||
credential = reverse('main:credentials_detail', args=(obj.credential.pk,)),
|
||||
project = reverse('main:projects_detail', args=(obj.project.pk,)),
|
||||
res = super(JobTemplateSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
inventory = reverse('main:inventory_detail', args=(obj.inventory.pk,)),
|
||||
)
|
||||
if obj.created_by:
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
project = reverse('main:projects_detail', args=(obj.project.pk,)),
|
||||
jobs = reverse('main:job_template_job_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj.credential:
|
||||
res['credential'] = reverse('main:credentials_detail', args=(obj.credential.pk,))
|
||||
return res
|
||||
|
||||
class JobSerializer(BaseSerializer):
|
||||
|
||||
# add the URL and related resources
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
passwords_needed_to_start = serializers.Field(source='get_passwords_needed_to_start')
|
||||
|
||||
class Meta:
|
||||
model = Job
|
||||
fields = ('url', 'id', 'related', 'name', 'description', 'job_type', 'credential', 'project', 'inventory', 'created_by', 'creation_date')
|
||||
fields = BASE_FIELDS + ('job_template', 'job_type', 'inventory',
|
||||
'project', 'playbook', 'credential',
|
||||
'use_sudo', 'forks', 'limit', 'verbosity',
|
||||
'extra_vars', 'status', 'result_stdout',
|
||||
'result_traceback', 'passwords_needed_to_start')
|
||||
|
||||
def get_related(self, obj):
|
||||
# FIXME: fill in once further defined. related resources, credential, project, inventory, etc
|
||||
res = dict(
|
||||
)
|
||||
if obj.created_by:
|
||||
res['created_by'] = reverse('main:users_detail', args=(obj.created_by.pk,))
|
||||
res = super(JobSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
inventory = reverse('main:inventory_detail', args=(obj.inventory.pk,)),
|
||||
project = reverse('main:projects_detail', args=(obj.project.pk,)),
|
||||
credential = reverse('main:credentials_detail', args=(obj.credential.pk,)),
|
||||
job_events = reverse('main:job_job_event_list', args=(obj.pk,)),
|
||||
#hosts = reverse('main:job_???', args=(obj.pk,)),
|
||||
))
|
||||
if obj.job_template:
|
||||
res['job_template'] = reverse('main:job_template_detail', args=(obj.job_template.pk,))
|
||||
return res
|
||||
|
||||
|
||||
class JobHostSummarySerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = JobHostSummary
|
||||
fields = ('id', 'url', 'job', 'host', 'changed', 'dark', 'failures',
|
||||
'ok', 'processed', 'skipped', 'related')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(JobHostSummarySerializer, self).get_related(obj)
|
||||
res['job'] = reverse('main:job_detail', args=(obj.job.pk,))
|
||||
if obj.host:
|
||||
res['host'] = reverse('main:hosts_detail', args=(obj.host.pk,))
|
||||
return res
|
||||
|
||||
class JobEventSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = JobEvent
|
||||
fields = ('id', 'url', 'job', 'event', 'event_data', 'host', 'related')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(JobEventSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
job = reverse('main:job_detail', args=(obj.job.pk,)),
|
||||
))
|
||||
if obj.host:
|
||||
res['host'] = reverse('main:hosts_detail', args=(obj.host.pk,))
|
||||
return res
|
||||
|
||||
Reference in New Issue
Block a user