mirror of
https://github.com/ZwareBear/awx.git
synced 2026-05-03 13:21:48 -05:00
Workflow RBAC and prompting basic changes
This commit is contained in:
@@ -110,6 +110,20 @@ def reverse_gfk(content_object):
|
||||
camelcase_to_underscore(content_object.__class__.__name__): content_object.get_absolute_url()
|
||||
}
|
||||
|
||||
def vars_validate_or_raise(vars_str):
|
||||
# vars must be blank, a valid JSON or YAML dict, or ...
|
||||
try:
|
||||
json.loads((vars_str or '').strip() or '{}')
|
||||
return vars_str
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
yaml.safe_load(vars_str)
|
||||
return vars_str
|
||||
except yaml.YAMLError:
|
||||
pass
|
||||
raise serializers.ValidationError('Must be valid JSON or YAML.')
|
||||
|
||||
|
||||
class BaseSerializerMetaclass(serializers.SerializerMetaclass):
|
||||
'''
|
||||
@@ -996,14 +1010,7 @@ class ProjectUpdateCancelSerializer(ProjectUpdateSerializer):
|
||||
class BaseSerializerWithVariables(BaseSerializer):
|
||||
|
||||
def validate_variables(self, value):
|
||||
try:
|
||||
json.loads(value.strip() or '{}')
|
||||
except ValueError:
|
||||
try:
|
||||
yaml.safe_load(value)
|
||||
except yaml.YAMLError:
|
||||
raise serializers.ValidationError('Must be valid JSON or YAML.')
|
||||
return value
|
||||
return vars_validate_or_raise(value)
|
||||
|
||||
|
||||
class InventorySerializer(BaseSerializerWithVariables):
|
||||
@@ -1326,18 +1333,7 @@ class InventorySourceOptionsSerializer(BaseSerializer):
|
||||
return res
|
||||
|
||||
def validate_source_vars(self, value):
|
||||
# source_env must be blank, a valid JSON or YAML dict, or ...
|
||||
try:
|
||||
json.loads((value or '').strip() or '{}')
|
||||
return value
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
yaml.safe_load(value)
|
||||
return value
|
||||
except yaml.YAMLError:
|
||||
pass
|
||||
raise serializers.ValidationError('Must be valid JSON or YAML.')
|
||||
return vars_validate_or_raise(value)
|
||||
|
||||
def validate(self, attrs):
|
||||
# TODO: Validate source, validate source_regions
|
||||
@@ -1900,18 +1896,7 @@ class JobTemplateSerializer(UnifiedJobTemplateSerializer, JobOptionsSerializer):
|
||||
return super(JobTemplateSerializer, self).validate(attrs)
|
||||
|
||||
def validate_extra_vars(self, value):
|
||||
# extra_vars must be blank, a valid JSON or YAML dict, or ...
|
||||
try:
|
||||
json.loads((value or '').strip() or '{}')
|
||||
return value
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
yaml.safe_load(value)
|
||||
return value
|
||||
except yaml.YAMLError:
|
||||
pass
|
||||
raise serializers.ValidationError('Must be valid JSON or YAML.')
|
||||
return vars_validate_or_raise(value)
|
||||
|
||||
|
||||
class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
|
||||
@@ -2178,7 +2163,7 @@ class SystemJobCancelSerializer(SystemJobSerializer):
|
||||
class WorkflowJobTemplateSerializer(UnifiedJobTemplateSerializer):
|
||||
class Meta:
|
||||
model = WorkflowJobTemplate
|
||||
fields = ('*',)
|
||||
fields = ('*', 'extra_vars', 'organization')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(WorkflowJobTemplateSerializer, self).get_related(obj)
|
||||
@@ -2195,6 +2180,9 @@ class WorkflowJobTemplateSerializer(UnifiedJobTemplateSerializer):
|
||||
))
|
||||
return res
|
||||
|
||||
def validate_extra_vars(self, value):
|
||||
return vars_validate_or_raise(value)
|
||||
|
||||
# TODO:
|
||||
class WorkflowJobTemplateListSerializer(WorkflowJobTemplateSerializer):
|
||||
pass
|
||||
@@ -2226,10 +2214,15 @@ class WorkflowJobListSerializer(WorkflowJobSerializer, UnifiedJobListSerializer)
|
||||
pass
|
||||
|
||||
class WorkflowNodeBaseSerializer(BaseSerializer):
|
||||
job_type = serializers.SerializerMethodField()
|
||||
job_tags = serializers.SerializerMethodField()
|
||||
limit = serializers.SerializerMethodField()
|
||||
skip_tags = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
# TODO: workflow_job and job read-only
|
||||
fields = ('id', 'url', 'related', 'unified_job_template', 'success_nodes', 'failure_nodes', 'always_nodes',)
|
||||
fields = ('id', 'url', 'related', 'unified_job_template',
|
||||
'inventory', 'credential', 'job_type', 'job_tags', 'skip_tags', 'limit', 'skip_tags')
|
||||
read_only_fields = ('success_nodes', 'failure_nodes', 'always_nodes')
|
||||
|
||||
def get_related(self, obj):
|
||||
res = super(WorkflowNodeBaseSerializer, self).get_related(obj)
|
||||
@@ -2237,6 +2230,19 @@ class WorkflowNodeBaseSerializer(BaseSerializer):
|
||||
res['unified_job_template'] = obj.unified_job_template.get_absolute_url()
|
||||
return res
|
||||
|
||||
def get_job_type(self, obj):
|
||||
return obj.char_prompts.get('job_type', None)
|
||||
|
||||
def get_job_tags(self, obj):
|
||||
return obj.char_prompts.get('job_tags', None)
|
||||
|
||||
def get_skip_tags(self, obj):
|
||||
return obj.char_prompts.get('skip_tags', None)
|
||||
|
||||
def get_limit(self, obj):
|
||||
return obj.char_prompts.get('limit', None)
|
||||
|
||||
|
||||
class WorkflowJobTemplateNodeSerializer(WorkflowNodeBaseSerializer):
|
||||
class Meta:
|
||||
model = WorkflowJobTemplateNode
|
||||
@@ -2251,9 +2257,36 @@ class WorkflowJobTemplateNodeSerializer(WorkflowNodeBaseSerializer):
|
||||
res['workflow_job_template'] = reverse('api:workflow_job_template_detail', args=(obj.workflow_job_template.pk,))
|
||||
return res
|
||||
|
||||
def to_internal_value(self, data):
|
||||
internal_value = super(WorkflowNodeBaseSerializer, self).to_internal_value(data)
|
||||
char_prompts = self.extract_char_prompts(data)
|
||||
internal_value['char_prompts'] = char_prompts
|
||||
return internal_value
|
||||
|
||||
def extract_char_prompts(self, data):
|
||||
char_prompts = {}
|
||||
for fd in ['job_type', 'job_tags', 'skip_tags', 'limit', 'skip_tags']:
|
||||
if data.get(fd, None):
|
||||
char_prompts[fd] = data[fd]
|
||||
return char_prompts
|
||||
|
||||
def validate(self, attrs):
|
||||
if 'char_prompts' in attrs:
|
||||
if 'job_type' in attrs['char_prompts']:
|
||||
job_types = [t for t, v in JOB_TYPE_CHOICES]
|
||||
if attrs['char_prompts']['job_type'] not in job_types:
|
||||
raise serializers.ValidationError({
|
||||
"job_type": "%s is not a valid job type. The choices are %s." % (
|
||||
attrs['char_prompts']['job_type'], job_types)})
|
||||
ujt_obj = attrs.get('unified_job_template', None)
|
||||
if isinstance(ujt_obj, WorkflowJobTemplate):
|
||||
raise serializers.ValidationError({"unified_job_template": "Can not nest Workflow Job Templates inside of Workflow Job Templates"})
|
||||
return super(WorkflowJobTemplateNodeSerializer, self).validate(attrs)
|
||||
|
||||
class WorkflowJobNodeSerializer(WorkflowNodeBaseSerializer):
|
||||
class Meta:
|
||||
model = WorkflowJobTemplateNode
|
||||
# TODO: workflow_job and job read-only
|
||||
model = WorkflowJobNode
|
||||
fields = ('*', 'job', 'workflow_job',)
|
||||
|
||||
def get_related(self, obj):
|
||||
|
||||
@@ -2613,34 +2613,45 @@ class JobTemplateObjectRolesList(SubListAPIView):
|
||||
content_type = ContentType.objects.get_for_model(self.parent_model)
|
||||
return Role.objects.filter(content_type=content_type, object_id=po.pk)
|
||||
|
||||
# TODO:
|
||||
class WorkflowJobNodeList(ListCreateAPIView):
|
||||
class WorkflowJobNodeList(ListAPIView):
|
||||
|
||||
model = WorkflowJobNode
|
||||
serializer_class = WorkflowJobNodeListSerializer
|
||||
new_in_310 = True
|
||||
|
||||
# TODO:
|
||||
class WorkflowJobNodeDetail(RetrieveUpdateDestroyAPIView):
|
||||
class WorkflowJobNodeDetail(RetrieveAPIView):
|
||||
|
||||
model = WorkflowJobNode
|
||||
serializer_class = WorkflowJobNodeDetailSerializer
|
||||
new_in_310 = True
|
||||
|
||||
# TODO:
|
||||
class WorkflowJobTemplateNodeList(ListCreateAPIView):
|
||||
|
||||
model = WorkflowJobTemplateNode
|
||||
serializer_class = WorkflowJobTemplateNodeListSerializer
|
||||
new_in_310 = True
|
||||
|
||||
# TODO:
|
||||
def update_raw_data(self, data):
|
||||
for fd in ['job_type', 'job_tags', 'skip_tags', 'limit', 'skip_tags']:
|
||||
data[fd] = None
|
||||
return super(WorkflowJobTemplateNodeList, self).update_raw_data(data)
|
||||
|
||||
class WorkflowJobTemplateNodeDetail(RetrieveUpdateDestroyAPIView):
|
||||
|
||||
model = WorkflowJobTemplateNode
|
||||
serializer_class = WorkflowJobTemplateNodeDetailSerializer
|
||||
new_in_310 = True
|
||||
|
||||
def update_raw_data(self, data):
|
||||
for fd in ['job_type', 'job_tags', 'skip_tags', 'limit', 'skip_tags']:
|
||||
data[fd] = None
|
||||
try:
|
||||
obj = self.get_object()
|
||||
data.update(obj.char_prompts)
|
||||
except:
|
||||
pass
|
||||
return super(WorkflowJobTemplateNodeDetail, self).update_raw_data(data)
|
||||
|
||||
|
||||
class WorkflowJobTemplateNodeChildrenBaseList(EnforceParentRelationshipMixin, SubListCreateAttachDetachAPIView):
|
||||
|
||||
@@ -2732,7 +2743,10 @@ class WorkflowJobTemplateLaunch(GenericAPIView):
|
||||
serializer_class = EmptySerializer
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
return Response({})
|
||||
data = {}
|
||||
obj = self.get_object()
|
||||
data['warnings'] = obj.get_warnings()
|
||||
return Response(data)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
@@ -2749,7 +2763,6 @@ class WorkflowJobTemplateWorkflowNodesList(SubListCreateAPIView):
|
||||
|
||||
model = WorkflowJobTemplateNode
|
||||
serializer_class = WorkflowJobTemplateNodeListSerializer
|
||||
always_allow_superuser = True # TODO: RBAC
|
||||
parent_model = WorkflowJobTemplate
|
||||
relationship = 'workflow_job_template_nodes'
|
||||
parent_key = 'workflow_job_template'
|
||||
@@ -2763,17 +2776,11 @@ class WorkflowJobTemplateJobsList(SubListAPIView):
|
||||
relationship = 'jobs'
|
||||
parent_key = 'workflow_job_template'
|
||||
|
||||
# TODO:
|
||||
class WorkflowJobList(ListCreateAPIView):
|
||||
|
||||
model = WorkflowJob
|
||||
serializer_class = WorkflowJobListSerializer
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if not request.user.is_superuser and not request.user.is_system_auditor:
|
||||
raise PermissionDenied("Superuser privileges needed.")
|
||||
return super(WorkflowJobList, self).get(request, *args, **kwargs)
|
||||
|
||||
# TODO:
|
||||
class WorkflowJobDetail(RetrieveDestroyAPIView):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user