mirror of
https://github.com/ansible/awx.git
synced 2026-05-06 08:57:35 -02:30
AC-1040 Work on unified job serializers.
This commit is contained in:
@@ -33,9 +33,6 @@ from awx.main.utils import update_scm_url, camelcase_to_underscore
|
||||
|
||||
logger = logging.getLogger('awx.api.serializers')
|
||||
|
||||
BASE_FIELDS = ('id', 'type', 'url', 'related', 'summary_fields', 'created',
|
||||
'modified', 'name', 'description')
|
||||
|
||||
# Fields that should be summarized regardless of object type.
|
||||
DEFAULT_SUMMARY_FIELDS = ('name', 'description',)
|
||||
|
||||
@@ -65,13 +62,15 @@ SUMMARIZABLE_FK_FIELDS = {
|
||||
'has_inventory_sources'),
|
||||
'project': DEFAULT_SUMMARY_FIELDS + ('status',),
|
||||
'credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud'),
|
||||
'cloud_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud'),
|
||||
'permission': DEFAULT_SUMMARY_FIELDS,
|
||||
'job': DEFAULT_SUMMARY_FIELDS + ('status', 'failed',),
|
||||
'job_template': DEFAULT_SUMMARY_FIELDS,
|
||||
'last_job': DEFAULT_SUMMARY_FIELDS + ('status', 'failed',),
|
||||
'last_job': DEFAULT_SUMMARY_FIELDS + ('status', 'failed', 'license_error'),
|
||||
'last_job_host_summary': DEFAULT_SUMMARY_FIELDS + ('failed',),
|
||||
'last_update': DEFAULT_SUMMARY_FIELDS + ('status', 'failed', 'license_error'),
|
||||
'current_update': DEFAULT_SUMMARY_FIELDS + ('status', 'failed', 'license_error'),
|
||||
'current_job': DEFAULT_SUMMARY_FIELDS + ('status', 'failed', 'license_error'),
|
||||
'inventory_source': ('source', 'last_updated', 'status'),
|
||||
}
|
||||
|
||||
@@ -98,13 +97,87 @@ class ChoiceField(fields.ChoiceField):
|
||||
serializers.ChoiceField = ChoiceField
|
||||
|
||||
|
||||
class BaseSerializerMetaclass(serializers.SerializerMetaclass):
|
||||
'''
|
||||
Custom metaclass to enable attribute inheritance from Meta objects on
|
||||
serializer base classes.
|
||||
|
||||
Also allows for inheriting or updating field lists from base class(es):
|
||||
|
||||
class Meta:
|
||||
|
||||
# Inherit all fields from base class.
|
||||
fields = ('*',)
|
||||
|
||||
# Inherit all fields from base class and add 'foo'.
|
||||
fields = ('*', 'foo')
|
||||
|
||||
# Inherit all fields from base class except 'bar'.
|
||||
fields = ('*', '-bar')
|
||||
|
||||
# Define fields as 'foo' and 'bar'; ignore base class fields.
|
||||
fields = ('foo', 'bar')
|
||||
|
||||
'''
|
||||
|
||||
@classmethod
|
||||
def _update_meta(self, base, meta, other=None):
|
||||
for attr in dir(other):
|
||||
if attr.startswith('_'):
|
||||
continue
|
||||
val = getattr(other, attr)
|
||||
# Special handling for lists of strings (field names).
|
||||
if isinstance(val, (list, tuple)) and all([isinstance(x, basestring) for x in val]):
|
||||
new_vals = []
|
||||
except_vals = []
|
||||
if base: # Merge values from all bases.
|
||||
new_vals.extend([x for x in getattr(meta, attr, [])])
|
||||
for v in val:
|
||||
if not base and v == '*': # Inherit all values from previous base(es).
|
||||
new_vals.extend([x for x in getattr(meta, attr, [])])
|
||||
elif not base and v.startswith('-'): # Except these values.
|
||||
except_vals.append(v[1:])
|
||||
else:
|
||||
new_vals.append(v)
|
||||
val = []
|
||||
for v in new_vals:
|
||||
if v not in except_vals and v not in val:
|
||||
val.append(v)
|
||||
setattr(meta, attr, val)
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
meta = type('Meta', (object,), {})
|
||||
for base in bases:
|
||||
cls._update_meta(base, meta, getattr(base, 'Meta', None))
|
||||
cls._update_meta(None, meta, attrs.get('Meta', None))
|
||||
attrs['Meta'] = meta
|
||||
return super(BaseSerializerMetaclass, cls).__new__(cls, name, bases, attrs)
|
||||
|
||||
|
||||
class BaseSerializerOptions(serializers.ModelSerializerOptions):
|
||||
|
||||
def __init__(self, meta):
|
||||
super(BaseSerializerOptions, self).__init__(meta)
|
||||
self.summary_fields = getattr(meta, 'summary_fields', ())
|
||||
self.summarizable_fields = getattr(meta, 'summarizable_fields', ())
|
||||
|
||||
|
||||
class BaseSerializer(serializers.ModelSerializer):
|
||||
|
||||
__metaclass__ = BaseSerializerMetaclass
|
||||
_options_class = BaseSerializerOptions
|
||||
|
||||
class Meta:
|
||||
fields = ('id', 'type', 'url', 'related', 'summary_fields', 'created',
|
||||
'modified', 'name', 'description')
|
||||
summary_fields = () # FIXME: List of field names from this serializer that should be used when included as part of another's summary_fields.
|
||||
summarizable_fields = () # FIXME: List of field names on this serializer that should be included in summary_fields.
|
||||
|
||||
# add the URL and related resources
|
||||
type = serializers.SerializerMethodField('get_type')
|
||||
url = serializers.SerializerMethodField('get_url')
|
||||
related = serializers.SerializerMethodField('get_related')
|
||||
summary_fields = serializers.SerializerMethodField('get_summary_fields')
|
||||
related = serializers.SerializerMethodField('_get_related')
|
||||
summary_fields = serializers.SerializerMethodField('_get_summary_fields')
|
||||
|
||||
# make certain fields read only
|
||||
created = serializers.SerializerMethodField('get_created')
|
||||
@@ -149,6 +222,9 @@ class BaseSerializer(serializers.ModelSerializer):
|
||||
else:
|
||||
return obj.get_absolute_url()
|
||||
|
||||
def _get_related(self, obj):
|
||||
return {} if obj is None else self.get_related(obj)
|
||||
|
||||
def get_related(self, obj):
|
||||
res = SortedDict()
|
||||
if getattr(obj, 'created_by', None) and obj.created_by.is_active:
|
||||
@@ -157,6 +233,9 @@ class BaseSerializer(serializers.ModelSerializer):
|
||||
res['modified_by'] = reverse('api:user_detail', args=(obj.modified_by.pk,))
|
||||
return res
|
||||
|
||||
def _get_summary_fields(self, obj):
|
||||
return {} if obj is None else self.get_summary_fields(obj)
|
||||
|
||||
def get_summary_fields(self, obj):
|
||||
# Return values for certain fields on related objects, to simplify
|
||||
# displaying lists of items without additional API requests.
|
||||
@@ -166,6 +245,8 @@ class BaseSerializer(serializers.ModelSerializer):
|
||||
fkval = getattr(obj, fk, None)
|
||||
if fkval is None:
|
||||
continue
|
||||
if fkval == obj:
|
||||
continue
|
||||
if hasattr(fkval, 'active') and not fkval.active:
|
||||
continue
|
||||
if hasattr(fkval, 'is_active') and not fkval.is_active:
|
||||
@@ -205,6 +286,43 @@ class BaseSerializer(serializers.ModelSerializer):
|
||||
return obj.active
|
||||
|
||||
|
||||
class UnifiedJobTemplateSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = UnifiedJobTemplate
|
||||
fields = ('*', 'last_job_run', 'last_job_failed', 'has_schedules',
|
||||
'next_job_run', 'status')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(UnifiedJobTemplateSerializer, self).get_related(obj)
|
||||
if obj.current_job and obj.current_job.active:
|
||||
res['current_job'] = obj.current_job.get_absolute_url()
|
||||
if obj.last_job and obj.last_job.active:
|
||||
res['last_job'] = obj.last_job.get_absolute_url()
|
||||
if obj.next_schedule and obj.next_schedule.active:
|
||||
res['next_schedule'] = obj.next_schedule.get_absolute_url()
|
||||
return res
|
||||
|
||||
|
||||
class UnifiedJobSerializer(BaseSerializer):
|
||||
|
||||
result_stdout = serializers.Field(source='result_stdout')
|
||||
|
||||
class Meta:
|
||||
model = UnifiedJob
|
||||
fields = ('*', 'unified_job_template', 'launch_type', 'status',
|
||||
'failed', 'started', 'finished', 'elapsed', 'job_args',
|
||||
'job_cwd', 'job_env', 'result_stdout', 'result_traceback')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(UnifiedJobSerializer, self).get_related(obj)
|
||||
if obj.unified_job_template and obj.unified_job_template.active:
|
||||
res['unified_job_template'] = obj.unified_job_template.get_absolute_url()
|
||||
if obj.schedule and obj.schedule.active:
|
||||
res['schedule'] = obj.schedule.get_absolute_url()
|
||||
return res
|
||||
|
||||
|
||||
class BaseTaskSerializer(BaseSerializer):
|
||||
|
||||
job_env = serializers.SerializerMethodField('get_job_env')
|
||||
@@ -224,9 +342,9 @@ class UserSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('id', 'type', 'url', 'related', 'created', 'username',
|
||||
'first_name', 'last_name', 'email', 'is_superuser',
|
||||
'password', 'ldap_dn')
|
||||
fields = ('*', '-name', '-description', '-modified',
|
||||
'-summary_fields', 'username', 'first_name', 'last_name',
|
||||
'email', 'is_superuser', 'password', 'ldap_dn')
|
||||
|
||||
def to_native(self, obj):
|
||||
ret = super(UserSerializer, self).to_native(obj)
|
||||
@@ -261,8 +379,6 @@ class UserSerializer(BaseSerializer):
|
||||
return super(UserSerializer, self).save_object(obj, **kwargs)
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(UserSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
teams = reverse('api:user_teams_list', args=(obj.pk,)),
|
||||
@@ -309,69 +425,32 @@ class OrganizationSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Organization
|
||||
fields = BASE_FIELDS
|
||||
fields = ('*',)
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(OrganizationSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
#audit_trail = reverse('api:organization_audit_trail_list', args=(obj.pk,)),
|
||||
projects = reverse('api:organization_projects_list', args=(obj.pk,)),
|
||||
inventories = reverse('api:organization_inventories_list', args=(obj.pk,)),
|
||||
users = reverse('api:organization_users_list', args=(obj.pk,)),
|
||||
admins = reverse('api:organization_admins_list', args=(obj.pk,)),
|
||||
#tags = reverse('api:organization_tags_list', args=(obj.pk,)),
|
||||
teams = reverse('api:organization_teams_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:organization_activity_stream_list', args=(obj.pk,))
|
||||
))
|
||||
return res
|
||||
|
||||
|
||||
class ProjectSerializer(BaseSerializer):
|
||||
|
||||
playbooks = serializers.Field(source='playbooks', help_text='Array of playbooks available within this project.')
|
||||
scm_delete_on_next_update = serializers.Field(source='scm_delete_on_next_update')
|
||||
last_update_failed = serializers.Field(source='last_update_failed')
|
||||
last_updated = serializers.Field(source='last_updated')
|
||||
|
||||
class ProjectOptionsSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Project
|
||||
fields = BASE_FIELDS + ('local_path', 'scm_type', 'scm_url',
|
||||
'scm_branch', 'scm_clean',
|
||||
'scm_delete_on_update', 'scm_delete_on_next_update',
|
||||
'scm_update_on_launch', 'credential',
|
||||
'last_job_failed', 'status', 'last_job_run') +\
|
||||
('last_update_failed', 'last_updated',) # Backwards compatibility
|
||||
fields = ('*', 'local_path', 'scm_type', 'scm_url', 'scm_branch',
|
||||
'scm_clean', 'scm_delete_on_update', 'credential')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(ProjectSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
organizations = reverse('api:project_organizations_list', args=(obj.pk,)),
|
||||
teams = reverse('api:project_teams_list', args=(obj.pk,)),
|
||||
playbooks = reverse('api:project_playbooks', args=(obj.pk,)),
|
||||
update = reverse('api:project_update_view', args=(obj.pk,)),
|
||||
project_updates = reverse('api:project_updates_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:project_activity_stream_list', args=(obj.pk,)),
|
||||
))
|
||||
res = super(ProjectOptionsSerializer, self).get_related(obj)
|
||||
if obj.credential and obj.credential.active:
|
||||
res['credential'] = reverse('api:credential_detail',
|
||||
args=(obj.credential.pk,))
|
||||
if obj.current_job:
|
||||
res['current_job'] = reverse('api:project_update_detail',
|
||||
args=(obj.current_job.pk,))
|
||||
if obj.last_job:
|
||||
res['last_job'] = reverse('api:project_update_detail',
|
||||
args=(obj.last_job.pk,))
|
||||
# Backwards compatibility.
|
||||
if obj.current_update:
|
||||
res['current_update'] = reverse('api:project_update_detail',
|
||||
args=(obj.current_update.pk,))
|
||||
if obj.last_update:
|
||||
res['last_update'] = reverse('api:project_update_detail',
|
||||
args=(obj.last_update.pk,))
|
||||
return res
|
||||
|
||||
def validate_local_path(self, attrs, source):
|
||||
@@ -391,12 +470,44 @@ class ProjectSerializer(BaseSerializer):
|
||||
return attrs
|
||||
|
||||
def to_native(self, obj):
|
||||
ret = super(ProjectSerializer, self).to_native(obj)
|
||||
ret = super(ProjectOptionsSerializer, self).to_native(obj)
|
||||
if obj is not None and 'credential' in ret and (not obj.credential or not obj.credential.active):
|
||||
ret['credential'] = None
|
||||
return ret
|
||||
|
||||
|
||||
class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer):
|
||||
|
||||
playbooks = serializers.Field(source='playbooks', help_text='Array of playbooks available within this project.')
|
||||
scm_delete_on_next_update = serializers.Field(source='scm_delete_on_next_update')
|
||||
last_update_failed = serializers.Field(source='last_update_failed')
|
||||
last_updated = serializers.Field(source='last_updated')
|
||||
|
||||
class Meta:
|
||||
model = Project
|
||||
fields = ('*', 'scm_delete_on_next_update', 'scm_update_on_launch') + \
|
||||
('last_update_failed', 'last_updated') # Backwards compatibility
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(ProjectSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
organizations = reverse('api:project_organizations_list', args=(obj.pk,)),
|
||||
teams = reverse('api:project_teams_list', args=(obj.pk,)),
|
||||
playbooks = reverse('api:project_playbooks', args=(obj.pk,)),
|
||||
update = reverse('api:project_update_view', args=(obj.pk,)),
|
||||
project_updates = reverse('api:project_updates_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:project_activity_stream_list', args=(obj.pk,)),
|
||||
))
|
||||
# Backwards compatibility.
|
||||
if obj.current_update:
|
||||
res['current_update'] = reverse('api:project_update_detail',
|
||||
args=(obj.current_update.pk,))
|
||||
if obj.last_update:
|
||||
res['last_update'] = reverse('api:project_update_detail',
|
||||
args=(obj.last_update.pk,))
|
||||
return res
|
||||
|
||||
|
||||
class ProjectPlaybooksSerializer(ProjectSerializer):
|
||||
|
||||
class Meta:
|
||||
@@ -408,19 +519,13 @@ class ProjectPlaybooksSerializer(ProjectSerializer):
|
||||
return ret.get('playbooks', [])
|
||||
|
||||
|
||||
class ProjectUpdateSerializer(BaseTaskSerializer):
|
||||
|
||||
result_stdout = serializers.Field(source='result_stdout')
|
||||
class ProjectUpdateSerializer(UnifiedJobSerializer, ProjectOptionsSerializer):
|
||||
|
||||
class Meta:
|
||||
model = ProjectUpdate
|
||||
fields = ('id', 'type', 'url', 'related', 'summary_fields', 'created',
|
||||
'modified', 'project', 'status', 'failed', 'result_stdout',
|
||||
'result_traceback', 'job_args', 'job_cwd', 'job_env')
|
||||
fields = ('*', 'project')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(ProjectUpdateSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
project = reverse('api:project_detail', args=(obj.project.pk,)),
|
||||
@@ -446,17 +551,12 @@ class InventorySerializer(BaseSerializerWithVariables):
|
||||
|
||||
class Meta:
|
||||
model = Inventory
|
||||
fields = BASE_FIELDS + ('organization', 'variables',
|
||||
'has_active_failures', 'total_hosts',
|
||||
'hosts_with_active_failures', 'total_groups',
|
||||
'groups_with_active_failures',
|
||||
'has_inventory_sources',
|
||||
'total_inventory_sources',
|
||||
'inventory_sources_with_failures',)
|
||||
fields = ('*', 'organization', 'variables', 'has_active_failures',
|
||||
'total_hosts', 'hosts_with_active_failures', 'total_groups',
|
||||
'groups_with_active_failures', 'has_inventory_sources',
|
||||
'total_inventory_sources', 'inventory_sources_with_failures')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(InventorySerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
hosts = reverse('api:inventory_hosts_list', args=(obj.pk,)),
|
||||
@@ -481,19 +581,14 @@ class InventorySerializer(BaseSerializerWithVariables):
|
||||
|
||||
class HostSerializer(BaseSerializerWithVariables):
|
||||
|
||||
# Allow the serializer to treat these fields as read-only
|
||||
last_job = serializers.PrimaryKeyRelatedField(read_only=True)
|
||||
last_job_host_summary = serializers.PrimaryKeyRelatedField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Host
|
||||
fields = BASE_FIELDS + ('inventory', 'enabled', 'instance_id', 'variables',
|
||||
'has_active_failures', 'has_inventory_sources',
|
||||
'last_job', 'last_job_host_summary')
|
||||
fields = ('*', 'inventory', 'enabled', 'instance_id', 'variables',
|
||||
'has_active_failures', 'has_inventory_sources', 'last_job',
|
||||
'last_job_host_summary')
|
||||
readonly_fields = ('last_job', 'last_job_host_summary')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(HostSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
variable_data = reverse('api:host_variable_data', args=(obj.pk,)),
|
||||
@@ -513,8 +608,6 @@ class HostSerializer(BaseSerializerWithVariables):
|
||||
return res
|
||||
|
||||
def get_summary_fields(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
d = super(HostSerializer, self).get_summary_fields(obj)
|
||||
try:
|
||||
d['last_job']['job_template_id'] = obj.last_job.job_template.id
|
||||
@@ -600,14 +693,11 @@ class GroupSerializer(BaseSerializerWithVariables):
|
||||
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = BASE_FIELDS + ('inventory', 'variables', 'has_active_failures',
|
||||
'total_hosts', 'hosts_with_active_failures',
|
||||
'total_groups', 'groups_with_active_failures',
|
||||
'has_inventory_sources')
|
||||
fields = ('*', 'inventory', 'variables', 'has_active_failures',
|
||||
'total_hosts', 'hosts_with_active_failures', 'total_groups',
|
||||
'groups_with_active_failures', 'has_inventory_sources')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(GroupSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
variable_data = reverse('api:group_variable_data', args=(obj.pk,)),
|
||||
@@ -645,10 +735,7 @@ class GroupTreeSerializer(GroupSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = BASE_FIELDS + ('inventory', 'variables', 'has_active_failures',
|
||||
'total_hosts', 'hosts_with_active_failures',
|
||||
'total_groups', 'groups_with_active_failures',
|
||||
'has_inventory_sources', 'children')
|
||||
fields = ('*', 'children')
|
||||
|
||||
def get_children(self, obj):
|
||||
if obj is None:
|
||||
@@ -661,6 +748,9 @@ class GroupTreeSerializer(GroupSerializer):
|
||||
|
||||
class BaseVariableDataSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
fields = ('variables',)
|
||||
|
||||
def to_native(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
@@ -679,78 +769,33 @@ class InventoryVariableDataSerializer(BaseVariableDataSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Inventory
|
||||
fields = ('variables',)
|
||||
|
||||
|
||||
class HostVariableDataSerializer(BaseVariableDataSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Host
|
||||
fields = ('variables',)
|
||||
|
||||
|
||||
class GroupVariableDataSerializer(BaseVariableDataSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = ('variables',)
|
||||
|
||||
|
||||
class InventorySourceSerializer(BaseSerializer):
|
||||
class InventorySourceOptionsSerializer(BaseSerializer):
|
||||
|
||||
#source_password = serializers.WritableField(required=False, default='')
|
||||
last_update_failed = serializers.Field(source='last_update_failed')
|
||||
last_updated = serializers.Field(source='last_updated')
|
||||
|
||||
class Meta:
|
||||
model = InventorySource
|
||||
fields = ('id', 'type', 'url', 'related', 'summary_fields', 'created',
|
||||
'modified', 'inventory', 'group', 'source', 'source_path',
|
||||
'source_vars', 'credential', 'source_regions', 'overwrite',
|
||||
'overwrite_vars', 'update_on_launch', 'last_job_failed',
|
||||
'status', 'last_job_run') + \
|
||||
('last_update_failed', 'last_updated') # Backwards compatibility.
|
||||
read_only_fields = ('inventory', 'group')
|
||||
fields = ('*', 'source', 'source_path', 'source_vars', 'credential',
|
||||
'source_regions', 'overwrite', 'overwrite_vars')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(InventorySourceSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
update = reverse('api:inventory_source_update_view', args=(obj.pk,)),
|
||||
inventory_updates = reverse('api:inventory_source_updates_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:inventory_activity_stream_list', args=(obj.pk,)),
|
||||
#hosts = reverse('api:inventory_source_hosts_list', args=(obj.pk,)),
|
||||
#groups = reverse('api:inventory_source_groups_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj.inventory and obj.inventory.active:
|
||||
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
|
||||
if obj.group and obj.group.active:
|
||||
res['group'] = reverse('api:group_detail', args=(obj.group.pk,))
|
||||
res = super(InventorySourceOptionsSerializer, self).get_related(obj)
|
||||
if obj.credential and obj.credential.active:
|
||||
res['credential'] = reverse('api:credential_detail',
|
||||
args=(obj.credential.pk,))
|
||||
if obj.current_job:
|
||||
res['current_job'] = reverse('api:inventory_update_detail',
|
||||
args=(obj.current_job.pk,))
|
||||
if obj.last_job:
|
||||
res['last_job'] = reverse('api:inventory_update_detail',
|
||||
args=(obj.last_job.pk,))
|
||||
# Backwards compatibility.
|
||||
if obj.current_update:
|
||||
res['current_update'] = reverse('api:inventory_update_detail',
|
||||
args=(obj.current_update.pk,))
|
||||
if obj.last_update:
|
||||
res['last_update'] = reverse('api:inventory_update_detail',
|
||||
args=(obj.last_update.pk,))
|
||||
return res
|
||||
|
||||
def get_summary_fields(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
d = super(InventorySourceSerializer, self).get_summary_fields(obj)
|
||||
return d
|
||||
|
||||
def validate_source(self, attrs, source):
|
||||
src = attrs.get(source, '')
|
||||
obj = self.object
|
||||
@@ -777,12 +822,55 @@ class InventorySourceSerializer(BaseSerializer):
|
||||
return attrs
|
||||
|
||||
def metadata(self):
|
||||
metadata = super(InventorySourceSerializer, self).metadata()
|
||||
metadata = super(InventorySourceOptionsSerializer, self).metadata()
|
||||
field_opts = metadata.get('source_regions', {})
|
||||
field_opts['ec2_region_choices'] = self.opts.model.get_ec2_region_choices()
|
||||
field_opts['rax_region_choices'] = self.opts.model.get_rax_region_choices()
|
||||
return metadata
|
||||
|
||||
def to_native(self, obj):
|
||||
ret = super(InventorySourceOptionsSerializer, self).to_native(obj)
|
||||
if obj is None:
|
||||
return ret
|
||||
if 'credential' in ret and (not obj.credential or not obj.credential.active):
|
||||
ret['credential'] = None
|
||||
return ret
|
||||
|
||||
|
||||
class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOptionsSerializer):
|
||||
|
||||
last_update_failed = serializers.Field(source='last_update_failed')
|
||||
last_updated = serializers.Field(source='last_updated')
|
||||
|
||||
class Meta:
|
||||
model = InventorySource
|
||||
fields = ('*', 'inventory', 'group', 'update_on_launch',
|
||||
'update_cache_timeout') + \
|
||||
('last_update_failed', 'last_updated') # Backwards compatibility.
|
||||
read_only_fields = ('*', 'name', 'inventory', 'group')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(InventorySourceSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
update = reverse('api:inventory_source_update_view', args=(obj.pk,)),
|
||||
inventory_updates = reverse('api:inventory_source_updates_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:inventory_activity_stream_list', args=(obj.pk,)),
|
||||
#hosts = reverse('api:inventory_source_hosts_list', args=(obj.pk,)),
|
||||
#groups = reverse('api:inventory_source_groups_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj.inventory and obj.inventory.active:
|
||||
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
|
||||
if obj.group and obj.group.active:
|
||||
res['group'] = reverse('api:group_detail', args=(obj.group.pk,))
|
||||
# Backwards compatibility.
|
||||
if obj.current_update:
|
||||
res['current_update'] = reverse('api:inventory_update_detail',
|
||||
args=(obj.current_update.pk,))
|
||||
if obj.last_update:
|
||||
res['last_update'] = reverse('api:inventory_update_detail',
|
||||
args=(obj.last_update.pk,))
|
||||
return res
|
||||
|
||||
def to_native(self, obj):
|
||||
ret = super(InventorySourceSerializer, self).to_native(obj)
|
||||
if obj is None:
|
||||
@@ -791,25 +879,16 @@ class InventorySourceSerializer(BaseSerializer):
|
||||
ret['inventory'] = None
|
||||
if 'group' in ret and (not obj.group or not obj.group.active):
|
||||
ret['group'] = None
|
||||
if 'credential' in ret and (not obj.credential or not obj.credential.active):
|
||||
ret['credential'] = None
|
||||
return ret
|
||||
|
||||
|
||||
class InventoryUpdateSerializer(BaseTaskSerializer):
|
||||
|
||||
result_stdout = serializers.Field(source='result_stdout')
|
||||
class InventoryUpdateSerializer(UnifiedJobSerializer, InventorySourceOptionsSerializer):
|
||||
|
||||
class Meta:
|
||||
model = InventoryUpdate
|
||||
fields = ('id', 'type', 'url', 'related', 'summary_fields', 'created',
|
||||
'modified', 'inventory_source', 'status', 'failed',
|
||||
'result_stdout', 'result_traceback', 'job_args', 'job_cwd',
|
||||
'job_env', 'license_error')
|
||||
fields = ('*', 'inventory_source', 'license_error')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(InventoryUpdateSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
inventory_source = reverse('api:inventory_source_detail', args=(obj.inventory_source.pk,)),
|
||||
@@ -822,11 +901,9 @@ class TeamSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Team
|
||||
fields = BASE_FIELDS + ('organization',)
|
||||
fields = ('*', 'organization')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(TeamSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
projects = reverse('api:team_projects_list', args=(obj.pk,)),
|
||||
@@ -835,7 +912,7 @@ class TeamSerializer(BaseSerializer):
|
||||
permissions = reverse('api:team_permissions_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:team_activity_stream_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj.organization:
|
||||
if obj.organization and obj.organization.active:
|
||||
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
|
||||
return res
|
||||
|
||||
@@ -850,20 +927,18 @@ class PermissionSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Permission
|
||||
fields = BASE_FIELDS + ('user', 'team', 'project', 'inventory',
|
||||
'permission_type',)
|
||||
fields = ('*', 'user', 'team', 'project', 'inventory',
|
||||
'permission_type')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(PermissionSerializer, self).get_related(obj)
|
||||
if obj.user:
|
||||
if obj.user and obj.user.is_active:
|
||||
res['user'] = reverse('api:user_detail', args=(obj.user.pk,))
|
||||
if obj.team:
|
||||
if obj.team and obj.team.active:
|
||||
res['team'] = reverse('api:team_detail', args=(obj.team.pk,))
|
||||
if obj.project:
|
||||
if obj.project and obj.project.active:
|
||||
res['project'] = reverse('api:project_detail', args=(obj.project.pk,))
|
||||
if obj.inventory:
|
||||
if obj.inventory and obj.inventory.active:
|
||||
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
|
||||
return res
|
||||
|
||||
@@ -908,9 +983,9 @@ class CredentialSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Credential
|
||||
fields = BASE_FIELDS + ('user', 'team', 'kind', 'cloud', 'username',
|
||||
'password', 'ssh_key_data', 'ssh_key_unlock',
|
||||
'sudo_username', 'sudo_password',)
|
||||
fields = ('*', 'user', 'team', 'kind', 'cloud', 'username',
|
||||
'password', 'ssh_key_data', 'ssh_key_unlock',
|
||||
'sudo_username', 'sudo_password')
|
||||
|
||||
def to_native(self, obj):
|
||||
ret = super(CredentialSerializer, self).to_native(obj)
|
||||
@@ -933,8 +1008,6 @@ class CredentialSerializer(BaseSerializer):
|
||||
return instance
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(CredentialSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
activity_stream = reverse('api:credential_activity_stream_list', args=(obj.pk,))
|
||||
@@ -946,25 +1019,15 @@ class CredentialSerializer(BaseSerializer):
|
||||
return res
|
||||
|
||||
|
||||
class JobTemplateSerializer(BaseSerializer):
|
||||
class JobOptionsSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = JobTemplate
|
||||
fields = BASE_FIELDS + ('job_type', 'inventory', 'project', 'playbook',
|
||||
'credential', 'cloud_credential', 'forks',
|
||||
'limit', 'verbosity', 'extra_vars', 'job_tags',
|
||||
'host_config_key')
|
||||
fields = ('*', 'job_type', 'inventory', 'project', 'playbook',
|
||||
'credential', 'cloud_credential', 'forks', 'limit',
|
||||
'verbosity', 'extra_vars', 'job_tags')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(JobTemplateSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
jobs = reverse('api:job_template_jobs_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:job_template_activity_stream_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj is None:
|
||||
return ret
|
||||
res = super(JobOptionsSerializer, self).get_related(obj)
|
||||
if obj.inventory and obj.inventory.active:
|
||||
res['inventory'] = reverse('api:inventory_detail', args=(obj.inventory.pk,))
|
||||
if obj.project and obj.project.active:
|
||||
@@ -974,12 +1037,10 @@ class JobTemplateSerializer(BaseSerializer):
|
||||
if obj.cloud_credential and obj.cloud_credential.active:
|
||||
res['cloud_credential'] = reverse('api:credential_detail',
|
||||
args=(obj.cloud_credential.pk,))
|
||||
if obj.host_config_key:
|
||||
res['callback'] = reverse('api:job_template_callback', args=(obj.pk,))
|
||||
return res
|
||||
|
||||
def to_native(self, obj):
|
||||
ret = super(JobTemplateSerializer, self).to_native(obj)
|
||||
ret = super(JobOptionsSerializer, self).to_native(obj)
|
||||
if obj is None:
|
||||
return ret
|
||||
if 'inventory' in ret and (not obj.inventory or not obj.inventory.active):
|
||||
@@ -1002,24 +1063,32 @@ class JobTemplateSerializer(BaseSerializer):
|
||||
return attrs
|
||||
|
||||
|
||||
class JobSerializer(BaseTaskSerializer):
|
||||
class JobTemplateSerializer(UnifiedJobTemplateSerializer, JobOptionsSerializer):
|
||||
|
||||
class Meta:
|
||||
model = JobTemplate
|
||||
fields = ('*', 'host_config_key')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(JobTemplateSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
jobs = reverse('api:job_template_jobs_list', args=(obj.pk,)),
|
||||
activity_stream = reverse('api:job_template_activity_stream_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj.host_config_key:
|
||||
res['callback'] = reverse('api:job_template_callback', args=(obj.pk,))
|
||||
return res
|
||||
|
||||
|
||||
class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
|
||||
|
||||
passwords_needed_to_start = serializers.Field(source='passwords_needed_to_start')
|
||||
result_stdout = serializers.Field(source='result_stdout')
|
||||
|
||||
class Meta:
|
||||
model = Job
|
||||
fields = ('id', 'type', 'url', 'related', 'summary_fields', 'created',
|
||||
'modified', 'job_template', 'job_type', 'inventory',
|
||||
'project', 'playbook', 'credential', 'cloud_credential',
|
||||
'forks', 'limit', 'verbosity', 'extra_vars',
|
||||
'job_tags', 'launch_type', 'status', 'failed', 'result_stdout',
|
||||
'result_traceback', 'passwords_needed_to_start', 'job_args',
|
||||
'job_cwd', 'job_env')
|
||||
fields = ('*', 'job_template', 'passwords_needed_to_start')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(JobSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
job_events = reverse('api:job_job_events_list', args=(obj.pk,)),
|
||||
@@ -1029,18 +1098,6 @@ class JobSerializer(BaseTaskSerializer):
|
||||
if obj.job_template and obj.job_template.active:
|
||||
res['job_template'] = reverse('api:job_template_detail',
|
||||
args=(obj.job_template.pk,))
|
||||
if obj.inventory and obj.inventory.active:
|
||||
res['inventory'] = reverse('api:inventory_detail',
|
||||
args=(obj.inventory.pk,))
|
||||
if obj.project and obj.project.active:
|
||||
res['project'] = reverse('api:project_detail',
|
||||
args=(obj.project.pk,))
|
||||
if obj.credential and obj.credential.active:
|
||||
res['credential'] = reverse('api:credential_detail',
|
||||
args=(obj.credential.pk,))
|
||||
if obj.cloud_credential and obj.cloud_credential.active:
|
||||
res['cloud_credential'] = reverse('api:credential_detail',
|
||||
args=(obj.cloud_credential.pk,))
|
||||
if obj.can_start or True:
|
||||
res['start'] = reverse('api:job_start', args=(obj.pk,))
|
||||
if obj.can_cancel or True:
|
||||
@@ -1080,16 +1137,6 @@ class JobSerializer(BaseTaskSerializer):
|
||||
return ret
|
||||
if 'job_template' in ret and (not obj.job_template or not obj.job_template.active):
|
||||
ret['job_template'] = None
|
||||
if 'inventory' in ret and (not obj.inventory or not obj.inventory.active):
|
||||
ret['inventory'] = None
|
||||
if 'project' in ret and (not obj.project or not obj.project.active):
|
||||
ret['project'] = None
|
||||
if 'playbook' in ret:
|
||||
ret['playbook'] = ''
|
||||
if 'credential' in ret and (not obj.credential or not obj.credential.active):
|
||||
ret['credential'] = None
|
||||
if 'cloud_credential' in ret and (not obj.cloud_credential or not obj.cloud_credential.active):
|
||||
ret['cloud_credential'] = None
|
||||
return ret
|
||||
|
||||
|
||||
@@ -1097,26 +1144,17 @@ class JobListSerializer(JobSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Job
|
||||
fields = ('id', 'type', 'url', 'related', 'summary_fields', 'created',
|
||||
'modified', 'job_template', 'job_type', 'inventory',
|
||||
'project', 'playbook', 'credential', 'cloud_credential',
|
||||
'forks', 'limit', 'verbosity', 'extra_vars',
|
||||
'job_tags', 'launch_type', 'status', 'failed',
|
||||
'result_traceback', 'passwords_needed_to_start', 'job_args',
|
||||
'job_cwd', 'job_env')
|
||||
fields = ('*', '-result_stdout')
|
||||
|
||||
|
||||
class JobHostSummarySerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = JobHostSummary
|
||||
fields = ('id', 'type', 'url', 'job', 'host', 'created', 'modified',
|
||||
'summary_fields', 'related', 'changed', 'dark', 'failures',
|
||||
'ok', 'processed', 'skipped', 'failed')
|
||||
fields = ('*', '-name', '-description', 'job', 'host', 'changed',
|
||||
'dark', 'failures', 'ok', 'processed', 'skipped', 'failed')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(JobHostSummarySerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
job=reverse('api:job_detail', args=(obj.job.pk,)),
|
||||
@@ -1125,8 +1163,6 @@ class JobHostSummarySerializer(BaseSerializer):
|
||||
return res
|
||||
|
||||
def get_summary_fields(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
d = super(JobHostSummarySerializer, self).get_summary_fields(obj)
|
||||
try:
|
||||
d['job']['job_template_id'] = obj.job.job_template.id
|
||||
@@ -1143,14 +1179,11 @@ class JobEventSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = JobEvent
|
||||
fields = ('id', 'type', 'url', 'created', 'modified', 'job', 'event',
|
||||
fields = ('*', '-name', '-description', 'job', 'event',
|
||||
'event_display', 'event_data', 'event_level', 'failed',
|
||||
'changed', 'host', 'related', 'summary_fields', 'parent',
|
||||
'play', 'task')
|
||||
'changed', 'host', 'parent', 'play', 'task')
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
res = super(JobEventSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
job = reverse('api:job_detail', args=(obj.job.pk,)),
|
||||
@@ -1167,8 +1200,6 @@ class JobEventSerializer(BaseSerializer):
|
||||
return res
|
||||
|
||||
def get_summary_fields(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
d = super(JobEventSerializer, self).get_summary_fields(obj)
|
||||
try:
|
||||
d['job']['job_template_id'] = obj.job.job_template.id
|
||||
@@ -1177,13 +1208,31 @@ class JobEventSerializer(BaseSerializer):
|
||||
pass
|
||||
return d
|
||||
|
||||
|
||||
class ScheduleSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Schedule
|
||||
fields = ('*', 'unified_job_template', 'enabled', 'dtstart', 'dtend',
|
||||
'rrule', 'next_run')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(ScheduleSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
#unified_jobs = reverse('api:schedule_unified_jobs_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj.unified_job_template and obj.unified_job_template.active:
|
||||
res['unified_job_template'] = obj.unified_job_template.get_absolute_url()
|
||||
return res
|
||||
|
||||
|
||||
class ActivityStreamSerializer(BaseSerializer):
|
||||
|
||||
changes = serializers.SerializerMethodField('get_changes')
|
||||
|
||||
class Meta:
|
||||
model = ActivityStream
|
||||
fields = ('id', 'type', 'url', 'related', 'summary_fields',
|
||||
fields = ('*', '-name', '-description', '-created', '-modified',
|
||||
'timestamp', 'operation', 'changes', 'object1', 'object2')
|
||||
|
||||
def get_fields(self):
|
||||
@@ -1197,10 +1246,8 @@ class ActivityStreamSerializer(BaseSerializer):
|
||||
field.help_text = 'Unpopulated for create, update, and delete events. For associate and disassociate events this is the object type that object1 is being associated with'
|
||||
if key == 'operation':
|
||||
field.help_text = 'The action taken with respect to the given object(s).'
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def get_changes(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
@@ -1214,8 +1261,6 @@ class ActivityStreamSerializer(BaseSerializer):
|
||||
return {}
|
||||
|
||||
def get_related(self, obj):
|
||||
if obj is None:
|
||||
return {}
|
||||
rel = {}
|
||||
if obj.actor is not None:
|
||||
rel['actor'] = reverse('api:user_detail', args=(obj.actor.pk,))
|
||||
@@ -1267,6 +1312,7 @@ class ActivityStreamSerializer(BaseSerializer):
|
||||
last_name = obj.actor.last_name)
|
||||
return summary_fields
|
||||
|
||||
|
||||
class AuthTokenSerializer(serializers.Serializer):
|
||||
|
||||
username = serializers.CharField()
|
||||
|
||||
Reference in New Issue
Block a user