diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 1d2589db30..52cd775658 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1503,16 +1503,40 @@ 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): - if obj: - return dict([(p, u'') for p in obj.passwords_needed_to_start]) - else: - return {} + res = super(JobRelaunchSerializer, self).to_native(obj) + view = self.context.get('view', None) + if hasattr(view, '_raw_data_form_marker'): + password_keys = dict([(p, u'') for p in self.get_passwords_needed_to_start(obj)]) + res.update(password_keys) + return res + def get_passwords_needed_to_start(self, obj): + if obj: + 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) + return attrs + + def validate(self, attrs): + obj = self.context.get('obj') + if not obj.credential or obj.credential.active is 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 81914427f9..b66f49bb4e 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -1833,7 +1833,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 @@ -1844,23 +1844,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)