mirror of
https://github.com/ZwareBear/awx.git
synced 2026-05-05 16:01:50 -05:00
* Populate browsable API raw data form with submitted request data in response to an update.
* Remove fields from browsable API raw data that are set implicitly based on URL / parent object. * Fix issue where a group/host could be assigned to a different inventory. * Update validation to load values from existing instance if not present in new data; allows PATCH requests to succeed. * Remove job_args, job_cwd, job_env, result_stdout and result_traceback fields from job listings.
This commit is contained in:
@@ -463,24 +463,6 @@ class BaseSerializer(serializers.ModelSerializer):
|
||||
raise ValidationError(d)
|
||||
return attrs
|
||||
|
||||
def to_representation(self, obj):
|
||||
# FIXME: Doesn't get called anymore for an new raw data form!
|
||||
# When rendering the raw data form, create an instance of the model so
|
||||
# that the model defaults will be filled in.
|
||||
view = self.context.get('view', None)
|
||||
parent_key = getattr(view, 'parent_key', None)
|
||||
if not obj and hasattr(view, '_raw_data_form_marker'):
|
||||
obj = self.Meta.model()
|
||||
# FIXME: Would be nice to include any posted data for the raw data
|
||||
# form, so that a submission with errors can be modified in place
|
||||
# and resubmitted.
|
||||
ret = super(BaseSerializer, self).to_representation(obj)
|
||||
# Remove parent key from raw form data, since it will be automatically
|
||||
# set by the sub list create view.
|
||||
if parent_key and hasattr(view, '_raw_data_form_marker'):
|
||||
ret.pop(parent_key, None)
|
||||
return ret
|
||||
|
||||
|
||||
class BaseFactSerializer(DocumentSerializer):
|
||||
|
||||
@@ -611,6 +593,12 @@ class UnifiedJobListSerializer(UnifiedJobSerializer):
|
||||
class Meta:
|
||||
fields = ('*', '-job_args', '-job_cwd', '-job_env', '-result_traceback', '-result_stdout')
|
||||
|
||||
def get_field_names(self, declared_fields, info):
|
||||
field_names = super(UnifiedJobListSerializer, self).get_field_names(declared_fields, info)
|
||||
# Meta multiple inheritance and -field_name options don't seem to be
|
||||
# taking effect above, so remove the undesired fields here.
|
||||
return tuple(x for x in field_names if x not in ('job_args', 'job_cwd', 'job_env', 'result_traceback', 'result_stdout'))
|
||||
|
||||
def get_types(self):
|
||||
if type(self) is UnifiedJobListSerializer:
|
||||
return ['project_update', 'inventory_update', 'job', 'ad_hoc_command', 'system_job']
|
||||
@@ -995,6 +983,14 @@ class HostSerializer(BaseSerializerWithVariables):
|
||||
'last_job_host_summary')
|
||||
read_only_fields = ('last_job', 'last_job_host_summary')
|
||||
|
||||
def build_relational_field(self, field_name, relation_info):
|
||||
field_class, field_kwargs = super(HostSerializer, self).build_relational_field(field_name, relation_info)
|
||||
# Inventory is read-only unless creating a new host.
|
||||
if self.instance and field_name == 'inventory':
|
||||
field_kwargs['read_only'] = True
|
||||
field_kwargs.pop('queryset', None)
|
||||
return field_class, field_kwargs
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(HostSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
@@ -1053,15 +1049,12 @@ class HostSerializer(BaseSerializerWithVariables):
|
||||
return value
|
||||
|
||||
def validate(self, attrs):
|
||||
name = force_text(attrs.get('name', ''))
|
||||
name = force_text(attrs.get('name', self.instance and self.instance.name or ''))
|
||||
host, port = self._get_host_port_from_name(name)
|
||||
|
||||
if port:
|
||||
attrs['name'] = host
|
||||
if self.instance:
|
||||
variables = force_text(attrs.get('variables', self.instance.variables) or '')
|
||||
else:
|
||||
variables = force_text(attrs.get('variables', ''))
|
||||
variables = force_text(attrs.get('variables', self.instance and self.instance.variables or ''))
|
||||
try:
|
||||
vars_dict = json.loads(variables.strip() or '{}')
|
||||
vars_dict['ansible_ssh_port'] = port
|
||||
@@ -1099,6 +1092,14 @@ class GroupSerializer(BaseSerializerWithVariables):
|
||||
'total_hosts', 'hosts_with_active_failures', 'total_groups',
|
||||
'groups_with_active_failures', 'has_inventory_sources')
|
||||
|
||||
def build_relational_field(self, field_name, relation_info):
|
||||
field_class, field_kwargs = super(GroupSerializer, self).build_relational_field(field_name, relation_info)
|
||||
# Inventory is read-only unless creating a new group.
|
||||
if self.instance and field_name == 'inventory':
|
||||
field_kwargs['read_only'] = True
|
||||
field_kwargs.pop('queryset', None)
|
||||
return field_class, field_kwargs
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(GroupSerializer, self).get_related(obj)
|
||||
res.update(dict(
|
||||
@@ -1247,9 +1248,10 @@ class InventorySourceOptionsSerializer(BaseSerializer):
|
||||
# TODO: Validate source, validate source_regions
|
||||
errors = {}
|
||||
|
||||
source_script = attrs.get('source_script', None)
|
||||
if 'source' in attrs and attrs.get('source', '') == 'custom':
|
||||
if source_script is None or source_script == '':
|
||||
source = attrs.get('source', self.instance and self.instance.source or '')
|
||||
source_script = attrs.get('source_script', self.instance and self.instance.source_script or '')
|
||||
if source == 'custom':
|
||||
if not source_script is None or source_script == '':
|
||||
errors['source_script'] = 'source_script must be provided'
|
||||
else:
|
||||
try:
|
||||
@@ -1403,15 +1405,19 @@ class PermissionSerializer(BaseSerializer):
|
||||
|
||||
def validate(self, attrs):
|
||||
# Can only set either user or team.
|
||||
if attrs.get('user', None) and attrs.get('team', None):
|
||||
user = attrs.get('user', self.instance and self.instance.user or None)
|
||||
team = attrs.get('team', self.instance and self.instance.team or None)
|
||||
if user and team:
|
||||
raise serializers.ValidationError('permission can only be assigned'
|
||||
' to a user OR a team, not both')
|
||||
# Cannot assign admit/read/write permissions for a project.
|
||||
if attrs.get('permission_type', None) in ('admin', 'read', 'write') and attrs.get('project', None):
|
||||
permission_type = attrs.get('permission_type', self.instance and self.instance.permission_type or None)
|
||||
project = attrs.get('project', self.instance and self.instance.project or None)
|
||||
if permission_type in ('admin', 'read', 'write') and project:
|
||||
raise serializers.ValidationError('project cannot be assigned for '
|
||||
'inventory-only permissions')
|
||||
# Project is required when setting deployment permissions.
|
||||
if attrs.get('permission_type', None) in ('run', 'check') and not attrs.get('project', None):
|
||||
if permission_type in ('run', 'check') and not project:
|
||||
raise serializers.ValidationError('project is required when '
|
||||
'assigning deployment permissions')
|
||||
|
||||
@@ -1522,9 +1528,10 @@ class JobOptionsSerializer(BaseSerializer):
|
||||
|
||||
def validate(self, attrs):
|
||||
if 'project' in self.fields and 'playbook' in self.fields:
|
||||
project = attrs.get('project', None)
|
||||
playbook = attrs.get('playbook', '')
|
||||
if not project and attrs.get('job_type') != PERM_INVENTORY_SCAN:
|
||||
project = attrs.get('project', self.instance and self.instance.project or None)
|
||||
playbook = attrs.get('playbook', self.instance and self.instance.playbook or '')
|
||||
job_type = attrs.get('job_type', self.instance and self.instance.job_type or None)
|
||||
if not project and job_type != PERM_INVENTORY_SCAN:
|
||||
raise serializers.ValidationError({'project': 'This field is required.'})
|
||||
if project and playbook and force_text(playbook) not in project.playbooks:
|
||||
raise serializers.ValidationError({'playbook': 'Playbook not found for project'})
|
||||
@@ -1578,8 +1585,8 @@ class JobTemplateSerializer(UnifiedJobTemplateSerializer, JobOptionsSerializer):
|
||||
return d
|
||||
|
||||
def validate(self, attrs):
|
||||
survey_enabled = attrs.get('survey_enabled', False)
|
||||
job_type = attrs.get('job_type', None)
|
||||
survey_enabled = attrs.get('survey_enabled', self.instance and self.instance.survey_enabled or False)
|
||||
job_type = attrs.get('job_type', self.instance and self.instance.job_type or None)
|
||||
if survey_enabled and job_type == PERM_INVENTORY_SCAN:
|
||||
raise serializers.ValidationError({'survey_enabled': 'Survey Enabled can not be used with scan jobs'})
|
||||
|
||||
@@ -1737,8 +1744,8 @@ class AdHocCommandSerializer(UnifiedJobSerializer):
|
||||
|
||||
def get_field_names(self, declared_fields, info):
|
||||
field_names = super(AdHocCommandSerializer, self).get_field_names(declared_fields, info)
|
||||
# Meta inheritance and -field_name options don't seem to be taking
|
||||
# effect above, so remove the undesired fields here.
|
||||
# Meta multiple inheritance and -field_name options don't seem to be
|
||||
# taking effect above, so remove the undesired fields here.
|
||||
return tuple(x for x in field_names if x not in ('unified_job_template', 'description'))
|
||||
|
||||
def build_standard_field(self, field_name, model_field):
|
||||
@@ -1770,19 +1777,7 @@ class AdHocCommandSerializer(UnifiedJobSerializer):
|
||||
return res
|
||||
|
||||
def to_representation(self, obj):
|
||||
# In raw data form, populate limit field from host/group name.
|
||||
view = self.context.get('view', None)
|
||||
parent_model = getattr(view, 'parent_model', None)
|
||||
if not (obj and obj.pk) and view and hasattr(view, '_raw_data_form_marker'):
|
||||
if not obj:
|
||||
obj = self.Meta.model()
|
||||
ret = super(AdHocCommandSerializer, self).to_representation(obj)
|
||||
# Hide inventory and limit fields from raw data, since they will be set
|
||||
# automatically by sub list create view.
|
||||
if not (obj and obj.pk) and view and hasattr(view, '_raw_data_form_marker'):
|
||||
if parent_model in (Host, Group):
|
||||
ret.pop('inventory', None)
|
||||
ret.pop('limit', None)
|
||||
if 'inventory' in ret and (not obj.inventory or not obj.inventory.active):
|
||||
ret['inventory'] = None
|
||||
if 'credential' in ret and (not obj.credential or not obj.credential.active):
|
||||
@@ -1993,7 +1988,7 @@ class JobLaunchSerializer(BaseSerializer):
|
||||
obj = self.context.get('obj')
|
||||
data = self.context.get('data')
|
||||
|
||||
credential = attrs.get('credential', None) or (obj and obj.credential)
|
||||
credential = attrs.get('credential', obj and obj.credential or None)
|
||||
if not credential or not credential.active:
|
||||
errors['credential'] = 'Credential not provided'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user