diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 25317c33de..734ce2709f 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1493,16 +1493,35 @@ class JobCancelSerializer(JobSerializer): class JobRelaunchSerializer(JobSerializer): + passwords_needed_to_start = serializers.SerializerMethodField('get_passwords_needed_to_start') class Meta: - fields = () + fields = ('passwords_needed_to_start',) - def to_native(self, obj): + def get_passwords_needed_to_start(self, obj): if obj: - return dict([(p, u'') for p in obj.passwords_needed_to_start]) - else: - return {} + return obj.passwords_needed_to_start + return '' + def validate_passwords_needed_to_start(self, attrs, source): + obj = self.context.get('obj') + data = self.context.get('data') + + # Check for passwords needed + needed = self.get_passwords_needed_to_start(obj) + provided = dict([(field, data.get(field, '')) for field in needed]) + if not all(provided.values()): + raise serializers.ValidationError(needed) + + data.clear() + data.update(provided) + return attrs + + def validate(self, attrs): + obj = self.context.get('obj') + if not obj.credential or obj.credential.active == False: + raise serializers.ValidationError(dict(credential=["Credential not found or deleted."])) + return attrs class AdHocCommandSerializer(UnifiedJobSerializer): diff --git a/awx/api/views.py b/awx/api/views.py index d18c5ae6ea..e01125e1a2 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -1843,7 +1843,7 @@ class JobCancel(RetrieveAPIView): else: return self.http_method_not_allowed(request, *args, **kwargs) -class JobRelaunch(GenericAPIView): +class JobRelaunch(RetrieveAPIView, GenericAPIView): model = Job serializer_class = JobRelaunchSerializer @@ -1854,23 +1854,16 @@ class JobRelaunch(GenericAPIView): def dispatch(self, *args, **kwargs): return super(JobRelaunch, self).dispatch(*args, **kwargs) - def get(self, request, *args, **kwargs): - obj = self.get_object() - data = {} - data['passwords_needed_to_start'] = obj.passwords_needed_to_start - return Response(data) - def post(self, request, *args, **kwargs): obj = self.get_object() if not request.user.can_access(self.model, 'start', obj): raise PermissionDenied() - # Check for passwords needed before copying job. - needed = obj.passwords_needed_to_start - provided = dict([(field, request.DATA.get(field, '')) for field in needed]) - if not all(provided.values()): - data = dict(passwords_needed_to_start=needed) - return Response(data, status=status.HTTP_400_BAD_REQUEST) + # Note: is_valid() may modify request.DATA + # It will remove any key/value pair who's key is not in the 'passwords_needed_to_start' list + serializer = self.serializer_class(data=request.DATA, context={'obj': obj, 'data': request.DATA}) + if not serializer.is_valid(): + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) new_job = obj.copy() result = new_job.signal_start(**request.DATA)