def validateOutputDatasets(outDsets, dbsUrl): """ Validate output datasets after all the other arguments have been locally update during assignment. """ if len(outDsets) != len(set(outDsets)): msg = "Output dataset contains duplicates and it has to be fixed! %s" % outDsets raise InvalidSpecParameterValue(msg) datatier = [] for dataset in outDsets: procds, tier = dataset.split("/")[2:] datatier.append(tier) try: procdataset(procds) except AssertionError as ex: msg = "Bad output dataset name, check the processed dataset name.\n %s" % str( ex) raise InvalidSpecParameterValue(msg) # TODO: this url conversion below can be removed in one year from now, thus March 2022 dbsUrl = dbsUrl.replace("cmsweb.cern.ch", "cmsweb-prod.cern.ch") # Verify whether the output datatiers are available in DBS _validateDatatier(datatier, dbsUrl)
def _handleAssignmentStateTransition(self, workload, request_args, dn): if ('SoftTimeout' in request_args) and ('GracePeriod' in request_args): request_args['HardTimeout'] = request_args['SoftTimeout'] + request_args['GracePeriod'] # Only allow extra value update for assigned status cherrypy.log("INFO: Assign request %s, input args: %s ..." % (workload.name(), request_args)) try: workload.updateArguments(request_args) except Exception as ex: msg = traceback.format_exc() cherrypy.log("Error for request args %s: %s" % (request_args, msg)) raise InvalidSpecParameterValue(str(ex)) # validate/update OutputDatasets after ProcessingString and AcquisionEra is updated request_args['OutputDatasets'] = workload.listOutputDatasets() validateOutputDatasets(request_args['OutputDatasets'], workload.getDbsUrl()) # by default, it contains all unmerged LFNs (used by sites to protect the unmerged area) request_args['OutputModulesLFNBases'] = workload.listAllOutputModulesLFNBases() # FIXME: remove it on HG1710, when this #7355 is complete fixed if not request_args['Team'] or not isinstance(request_args['Team'], basestring): raise InvalidSpecParameterValue("Team MUST be a non-empty string") # legacy update schema to support ops script loadRequestSchema(workload, request_args) # save the spec first before update the reqmgr request status to prevent race condition # when workflow is pulled to GQ before site white list is updated workload.saveCouch(self.config.couch_host, self.config.couch_reqmgr_db) report = self.reqmgr_db_service.updateRequestProperty(workload.name(), request_args, dn) return report
def _handleAssignmentStateTransition(self, workload, request_args, dn): req_status = request_args["RequestStatus"] if req_status == "assigned" and not request_args.get('Team', '').strip(): raise InvalidSpecParameterValue( "Team must be set during workflow assignment: %s" % request_args) if ('SoftTimeout' in request_args) and ('GracePeriod' in request_args): request_args['SoftTimeout'] = int(request_args['SoftTimeout']) #TODO: not sure why GracePeriod when passed from web ingerface but convert here request_args['GracePeriod'] = int(request_args['GracePeriod']) request_args['HardTimeout'] = request_args[ 'SoftTimeout'] + request_args['GracePeriod'] #Only allow extra value update for assigned status try: workload.updateArguments(request_args) except Exception as ex: msg = traceback.format_exc() cherrypy.log("Error for request args %s: %s" % (request_args, msg)) raise InvalidSpecParameterValue(str(ex)) # legacy update schema to support ops script loadRequestSchema(workload, request_args) #update OutputDatasets after ProcessingString and AcquisionEra is updated request_args['OutputDatasets'] = workload.listOutputDatasets() report = self.reqmgr_db_service.updateRequestProperty( workload.name(), request_args, dn) workload.saveCouch(self.config.couch_host, self.config.couch_reqmgr_db) return report
def _updateRequest(self, workload, request_args): if workload == None: (workload, request_args) = self.initialize_clone( request_args["OriginalRequestName"]) return self.post(workload, request_args) dn = cherrypy.request.user.get("dn", "unknown") if "total_jobs" in request_args: # only GQ update this stats # request_args should contain only 4 keys 'total_jobs', 'input_lumis', 'input_events', 'input_num_files'} report = self.reqmgr_db_service.updateRequestStats( workload.name(), request_args) # if is not just updating status else: if len(request_args) > 1 or "RequestStatus" not in request_args: try: workload.updateArguments(request_args) except Exception as ex: msg = traceback.format_exc() cherrypy.log("Error for request args %s: %s" % (request_args, msg)) raise InvalidSpecParameterValue(str(ex)) # trailing / is needed for the savecouchUrl function workload.saveCouch(self.config.couch_host, self.config.couch_reqmgr_db) report = self.reqmgr_db_service.updateRequestProperty( workload.name(), request_args, dn) return report
def _updateRequest(self, workload, request_args): dn = cherrypy.request.user.get("dn", "unknown") if "RequestStatus" not in request_args: report = self._handleNoStatusUpdate(workload, request_args) else: req_status = request_args["RequestStatus"] # assignment-approved only allow Priority update if len(request_args) == 2 and req_status == "assignment-approved": report = self._handleAssignmentApprovedTransition( workload, request_args, dn) elif len(request_args) > 1 and req_status == "assigned": report = self._handleAssignmentStateTransition( workload, request_args, dn) elif len(request_args) == 1 or (len(request_args) == 2 and "cascade" in request_args): report = self._handleOnlyStateTransition( workload, request_args, dn) else: raise InvalidSpecParameterValue( "can't update value except transition to assigned status: %s" % request_args) if report == 'OK': return {workload.name(): "OK"} else: return {workload.name(): "ERROR"}
def _updateRequest(self, workload, request_args): dn = cherrypy.request.user.get("dn", "unknown") if workload is None: (workload, request_args) = self.initialize_clone( request_args["OriginalRequestName"]) return self.post([workload, request_args]) if "RequestStatus" not in request_args: report = self._handleNoStatusUpdate(workload, request_args) else: req_status = request_args["RequestStatus"] if len(request_args) > 1 and req_status == "assigned": report = self._handleAssignmentStateTransition( workload, request_args, dn) elif len(request_args) == 2 and req_status in ["closed-out", "announced"] and \ "cascade" in request_args: report = self._handleCascadeUpdate(workload, request_args, dn) elif len(request_args) == 1: report = self._handleOnlyStateTransition( workload, req_status, dn) else: raise InvalidSpecParameterValue( "can't update value except transition to assigned status: %s" % request_args) if report == 'OK': return {workload.name(): "OK"} else: return {workload.name(): "ERROR"}
def _handleNoStatusUpdate(self, workload, request_args, dn): """ For no-status update, we only support the following parameters: 1. RequestPriority 2. Global workqueue statistics, while acquiring a workflow """ if 'RequestPriority' in request_args: # Yes, we completely ignore any other arguments posted by the user (web UI case) request_args = {'RequestPriority': request_args['RequestPriority']} # must update three places: GQ elements, workload_cache and workload spec self.gq_service.updatePriority(workload.name(), request_args['RequestPriority']) report = self.reqmgr_db_service.updateRequestProperty( workload.name(), request_args, dn) workload.setPriority(request_args['RequestPriority']) workload.saveCouchUrl(workload.specUrl()) cherrypy.log('Updated priority of "%s" to %s' % (workload.name(), request_args['RequestPriority'])) elif workqueue_stat_validation(request_args): report = self.reqmgr_db_service.updateRequestStats( workload.name(), request_args) else: msg = "There are invalid arguments for no-status update: %s" % request_args raise InvalidSpecParameterValue(msg) return report
def generateRequestName(request): currentTime = time.strftime('%y%m%d_%H%M%S', time.localtime(time.time())) seconds = int(10000 * (time.time() % 1.0)) if "RequestString" not in request: raise InvalidSpecParameterValue("RequestString need to be specified") # TODO change to lexicon when we have exact format of RequestString if '@' in request["RequestString"]: raise InvalidSpecParameterValue("RequestString cannot contain @: %s" % request["RequestString"]) request["RequestName"] = "%s_%s" % (request["Requestor"], request["RequestString"]) # add time info request["RequestName"] += "_%s_%s" % (currentTime, seconds)
def _updateRequest(self, workload, request_args): dn = get_user_info().get("dn", "unknown") if "RequestStatus" not in request_args: report = self._handleNoStatusUpdate(workload, request_args, dn) else: req_status = request_args["RequestStatus"] if len(request_args) == 2 and req_status == "assignment-approved": report = self._handleAssignmentApprovedTransition( workload, request_args, dn) elif len(request_args) > 1 and req_status == "assigned": report = self._handleAssignmentStateTransition( workload, request_args, dn) elif len(request_args) == 1 or (len(request_args) == 2 and "cascade" in request_args): report = self._handleOnlyStateTransition( workload, request_args, dn) else: msg = "There are invalid arguments with this status transition: %s" % request_args raise InvalidSpecParameterValue(msg) if report == 'OK': return {workload.name(): "OK"} else: return {workload.name(): "ERROR"}
def validate_request_priority(reqArgs): """ Validate the RequestPriority argument against its definition in StdBase :param reqArgs: dictionary of user request arguments :return: nothing, but raises an exception in case of an invalid value """ if 'RequestPriority' in reqArgs: reqPrioDefin = StdBase.getWorkloadCreateArgs()['RequestPriority'] if not isinstance(reqArgs['RequestPriority'], reqPrioDefin['type']): msg = "RequestPriority must be of integer type, not: {}".format( type(reqArgs['RequestPriority'])) raise InvalidSpecParameterValue(msg) if reqPrioDefin['validate'](reqArgs['RequestPriority']) is False: raise InvalidSpecParameterValue( "RequestPriority must be an integer between 0 and 999999")
def _validateGET(self, param, safe): # TODO: need proper validation but for now pass everything args_length = len(param.args) if args_length == 1: safe.kwargs["name"] = param.args[0] param.args.pop() return if "status" in param.kwargs and isinstance(param.kwargs["status"], basestring): param.kwargs["status"] = [param.kwargs["status"]] if "status" in param.kwargs: for status in param.kwargs["status"]: if status.endswith("-archived"): raise InvalidSpecParameterValue( "Can't retrieve bulk archived status requests, use other search arguments" ) for prop in param.kwargs: safe.kwargs[prop] = param.kwargs[prop] for prop in safe.kwargs: del param.kwargs[prop] return
def _validateGET(self, param, safe): # TODO: need proper validation but for now pass everything args_length = len(param.args) if args_length == 1: safe.kwargs["name"] = param.args[0] param.args.pop() return no_multi_key = ["detail", "_nostale", "date_range", "common_dict"] for key, value in param.kwargs.items(): # convert string to list if key not in no_multi_key and isinstance(value, basestring): param.kwargs[key] = [value] detail = param.kwargs.get('detail', True) if detail in (False, "false", "False", "FALSE"): detail = False if "status" in param.kwargs and detail: for status in param.kwargs["status"]: if status.endswith("-archived"): raise InvalidSpecParameterValue( """Can't retrieve bulk archived status requests with detail option True, set detail=false or use other search arguments""") for prop in param.kwargs.keys(): safe.kwargs[prop] = param.kwargs.pop(prop) return
def _handleAssignmentStateTransition(self, workload, request_args, dn): if ('SoftTimeout' in request_args) and ('GracePeriod' in request_args): request_args['HardTimeout'] = request_args['SoftTimeout'] + request_args['GracePeriod'] # Only allow extra value update for assigned status cherrypy.log("Assign request %s, input args: %s ..." % (workload.name(), request_args)) try: workload.updateArguments(request_args) except Exception as ex: msg = traceback.format_exc() cherrypy.log("Error for request args %s: %s" % (request_args, msg)) raise InvalidSpecParameterValue(str(ex)) # validate/update OutputDatasets after ProcessingString and AcquisionEra is updated request_args['OutputDatasets'] = workload.listOutputDatasets() validateOutputDatasets(request_args['OutputDatasets'], workload.getDbsUrl()) # by default, it contains all unmerged LFNs (used by sites to protect the unmerged area) request_args['OutputModulesLFNBases'] = workload.listAllOutputModulesLFNBases() # Add parentage relation for step chain, task chain: chainMap = workload.getChainParentageSimpleMapping() if chainMap: request_args["ChainParentageMap"] = chainMap # save the spec first before update the reqmgr request status to prevent race condition # when workflow is pulled to GQ before site white list is updated workload.saveCouch(self.config.couch_host, self.config.couch_reqmgr_db) report = self.reqmgr_db_service.updateRequestProperty(workload.name(), request_args, dn) return report
def validate(self, apiobj, method, api, param, safe): """ Validate request input data. Has to be implemented, otherwise the service fails to start. If it's not implemented correctly (e.g. just pass), the arguments are not passed in the method at all. """ try: if method == 'GET': self._validate_get_args(param, safe) if method == 'POST': args_length = len(param.args) if args_length == 1: safe.kwargs["name"] = param.args[0] param.args.pop() except InvalidSpecParameterValue as ex: raise ex except Exception as ex: msg = traceback.format_exc() cherrypy.log("Error: %s" % msg) if hasattr(ex, "message"): if hasattr(ex.message, '__call__'): msg = ex.message() else: msg = str(ex) else: msg = str(ex) raise InvalidSpecParameterValue(msg)
def _updateRequest(self, workload, request_args): if workload == None: (workload, request_args) = self.initialize_clone( request_args["OriginalRequestName"]) return self.post(workload, request_args) dn = cherrypy.request.user.get("dn", "unknown") if ('SoftTimeout' in request_args) and ('GracePeriod' in request_args): request_args['HardTimeout'] = request_args[ 'SoftTimeout'] + request_args['GracePeriod'] if 'RequestPriority' in request_args: self.gq_service.updatePriority(workload.name(), request_args['RequestPriority']) if "total_jobs" in request_args: # only GQ update this stats # request_args should contain only 4 keys 'total_jobs', 'input_lumis', 'input_events', 'input_num_files'} report = self.reqmgr_db_service.updateRequestStats( workload.name(), request_args) # if is not just updating status else: req_status = request_args.get("RequestStatus", None) if len(request_args) >= 1 and req_status == None: try: workload.updateArguments(request_args) except Exception as ex: msg = traceback.format_exc() cherrypy.log("Error for request args %s: %s" % (request_args, msg)) raise InvalidSpecParameterValue(str(ex)) # trailing / is needed for the savecouchUrl function workload.saveCouch(self.config.couch_host, self.config.couch_reqmgr_db) elif (req_status in ["closed-out" "announced"]) and request_args.get( "cascade", False): cascade_list = self._retrieveResubmissionChildren( workload.name) for req_name in cascade_list: report = self.reqmgr_db_service.updateRequestStatus( req_name, req_status) # If it is aborted or force-complete transition call workqueue to cancel the request else: if req_status == "aborted" or req_status == "force-complete": self.gq_service.cancelWorkflow(workload.name()) report = self.reqmgr_db_service.updateRequestProperty( workload.name(), request_args, dn) if report == 'OK': return {workload.name(): "OK"} else: return {workload.name(): "ERROR"}
def validate(self, apiobj, method, api, param, safe): # to make validate successful # move the validated argument to safe # make param empty # other wise raise the error try: if method == 'GET': self._validateGET(param, safe) elif method == 'PUT': args_length = len(param.args) if args_length == 1: requestName = param.args[0] param.args.pop() else: requestName = None self._validateRequestBase(param, safe, validate_request_update_args, requestName) elif method == 'POST': args_length = len(param.args) if args_length == 2 and param.args[0] == "clone": # handles clone workflow.- don't validtate args here param.kwargs['OriginalRequestName'] = param.args[1] param.args.pop() param.args.pop() self._validateRequestBase(param, safe, validate_clone_create_args) elif args_length == 1 and param.args[0] == "multi_update": # special case for multi update from browser. param.args.pop() self._validateMultiRequests(param, safe, validate_request_update_args) elif args_length == 1 and param.args[0] == "bynames": # special case for multi update from browser. param.args.pop() self._getRequestNamesFromBody(safe) else: self._validateRequestBase(param, safe, validate_request_create_args) except InvalidSpecParameterValue as ex: raise ex except Exception as ex: # TODO add proper error message instead of trace back msg = traceback.format_exc() cherrypy.log("Error: %s" % msg) if hasattr(ex, "message"): if hasattr(ex.message, '__call__'): msg = ex.message() else: msg = str(ex) else: msg = str(ex) raise InvalidSpecParameterValue(msg)
def _handleAssignmentApprovedTransition(self, workload, request_args, dn): """ Allows only two arguments: RequestStatus and RequestPriority """ if "RequestPriority" not in request_args: msg = "There are invalid arguments for assignment-approved transition: %s" % request_args raise InvalidSpecParameterValue(msg) report = self.reqmgr_db_service.updateRequestProperty(workload.name(), request_args, dn) return report
def _validateDatatier(datatier, dbsUrl): """ _validateDatatier_ Provided a list of datatiers extracted from the outputDatasets, checks whether they all exist in DBS already. """ dbsTiers = DBSReader.listDatatiers(dbsUrl) badTiers = list(set(datatier) - set(dbsTiers)) if badTiers: raise InvalidSpecParameterValue("Bad datatier(s): %s not available in DBS." % badTiers)
def validateOutputDatasets(outDsets, dbsUrl): """ Validate output datasets after all the other arguments have been locally update during assignment. """ if len(outDsets) != len(set(outDsets)): msg = "Output dataset contains duplicates and it has to be fixed! %s" % outDsets raise InvalidSpecParameterValue(msg) datatier = [] for dataset in outDsets: procds, tier = dataset.split("/")[2:] datatier.append(tier) try: procdataset(procds) except AssertionError as ex: msg = "Bad output dataset name, check the processed dataset name.\n %s" % str(ex) raise InvalidSpecParameterValue(msg) # Verify whether the output datatiers are available in DBS _validateDatatier(datatier, dbsUrl)
def validate_request_update_args(request_args, config, reqmgr_db_service, param): """ param and safe structure is RESTArgs structure: named tuple RESTArgs(args=[], kwargs={}) validate post/put request 1. read data from body 2. validate the permission (authentication) 3. validate state transition (against previous state from couchdb) 2. validate using workload validation 3. convert data from body to arguments (spec instance, argument with default setting) TODO: raise right kind of error with clear message """ # this needs to be deleted for validation request_name = request_args.pop("RequestName") couchurl = '%s/%s' % (config.couch_host, config.couch_reqmgr_db) workload = WMWorkloadHelper() workload.loadSpecFromCouch(couchurl, request_name) # first validate the permission by status and request type. # if the status is not set only ReqMgr Admin can change the values # TODO for each step, assigned, approved, announce find out what other values # can be set request_args["RequestType"] = workload.requestType() permission = getWritePermission(request_args) authz_match(permission['role'], permission['group']) del request_args["RequestType"] # validate the status if "RequestStatus" in request_args: validate_state_transition(reqmgr_db_service, request_name, request_args["RequestStatus"]) if request_args["RequestStatus"] in STATES_ALLOW_ONLY_STATE_TRANSITION: # if state change doesn't allow other transition nothing else to validate args_only_status = {} args_only_status["RequestStatus"] = request_args["RequestStatus"] args_only_status["cascade"] = request_args.get("cascade", False) return workload, args_only_status elif request_args["RequestStatus"] == 'assigned': workload.validateArgumentForAssignment(request_args) # TODO: fetch it from the assignment arg definition if 'RequestPriority' in request_args: request_args['RequestPriority'] = int(request_args['RequestPriority']) if (lambda x: (x >= 0 and x < 1e6))(request_args['RequestPriority']) is False: raise InvalidSpecParameterValue( "RequestPriority must be an integer between 0 and 1e6") return workload, request_args
def generateRequestName(request): currentTime = time.strftime('%y%m%d_%H%M%S', time.localtime(time.time())) seconds = int(10000 * (time.time() % 1.0)) if "RequestString" not in request: raise InvalidSpecParameterValue("RequestString need to be specified") request["RequestName"] = "%s_%s" % (request["Requestor"], request["RequestString"]) # add time info request["RequestName"] += "_%s_%s" % (currentTime, seconds) # then validate the final request name identifier(request["RequestName"])
def validate(self, apiobj, method, api, param, safe): # to make validate successful # move the validated argument to safe # make param empty # other wise raise the error try: if method in ['GET']: self._validateGET(param, safe) if method == 'PUT': args_length = len(param.args) if args_length == 1: requestName = param.args[0] param.args.pop() else: requestName = None self._validateRequestBase(param, safe, validate_request_update_args, requestName) #TO: handle multiple clone # if len(param.args) == 2: # #validate clone case # if param.args[0] == "clone": # param.args.pop() # return None, request_args if method == 'POST': args_length = len(param.args) if args_length == 1 and param.args[0] == "multi_update": #special case for multi update from browser. param.args.pop() self._validateMultiRequests(param, safe, validate_request_update_args) else: self._validateRequestBase(param, safe, validate_request_create_args) except Exception as ex: #TODO add proper error message instead of trace back msg = traceback.format_exc() cherrypy.log("Error: %s" % msg) if hasattr(ex, "message"): if hasattr(ex.message, '__call__'): msg = ex.message() else: msg = str(ex) else: msg = str(ex) raise InvalidSpecParameterValue(msg)
def validateOutputDatasets(outDsets, dbsUrl): """ Validate output datasets after all the other arguments have been locally update during assignment """ datatier = [] for dataset in outDsets: tokens = dataset.split("/") procds = tokens[2] datatier.append(tokens[3]) try: procdataset(procds) except AssertionError as ex: msg = "Bad output dataset name, check the processed dataset.\n %s" % str(ex) raise InvalidSpecParameterValue(msg) # Verify whether the output datatiers are available in DBS _validateDatatier(datatier, dbsUrl)
def _handleNoStatusUpdate(self, workload, request_args): """ only few values can be updated without state transition involved currently 'RequestPriority' and 'total_jobs', 'input_lumis', 'input_events', 'input_num_files' """ if 'RequestPriority' in request_args: # must update three places: GQ elements, workload_cache and workload spec self.gq_service.updatePriority(workload.name(), request_args['RequestPriority']) report = self.reqmgr_db_service.updateRequestProperty(workload.name(), request_args) workload.setPriority(request_args['RequestPriority']) workload.saveCouchUrl(workload.specUrl()) elif "total_jobs" in request_args: # only GQ update this stats # request_args should contain only 4 keys 'total_jobs', 'input_lumis', 'input_events', 'input_num_files'} report = self.reqmgr_db_service.updateRequestStats(workload.name(), request_args) else: raise InvalidSpecParameterValue("can't update value without state transition: %s" % request_args) return report
def _validateDatatier(datatier, dbsUrl, expiration=3600): """ _validateDatatier_ Provided a list of datatiers extracted from the outputDatasets, checks whether they all exist in DBS. """ cacheName = "dataTierList_" + md5(dbsUrl).hexdigest() if not GenericDataCache.cacheExists(cacheName): mc = MemoryCacheStruct(expiration, getDataTiers, kwargs={'dbsUrl': dbsUrl}) GenericDataCache.registerCache(cacheName, mc) cacheData = GenericDataCache.getCacheData(cacheName) dbsTiers = cacheData.getData() badTiers = list(set(datatier) - set(dbsTiers)) if badTiers: raise InvalidSpecParameterValue( "Bad datatier(s): %s not available in DBS." % badTiers)
def validate_request_update_args(request_args, config, reqmgr_db_service, param): """ param and safe structure is RESTArgs structure: named tuple RESTArgs(args=[], kwargs={}) validate post/put request 1. read data from body 2. validate the permission (authentication) 3. validate state transition (against previous state from couchdb) 2. validate using workload validation 3. convert data from body to arguments (spec instance, argument with default setting) TODO: rasie right kind of error with clear message """ # this needs to be deleted for validation request_name = request_args.pop("RequestName") couchurl = '%s/%s' % (config.couch_host, config.couch_reqmgr_db) workload = WMWorkloadHelper() workload.loadSpecFromCouch(couchurl, request_name) # first validate the permission by status and request type. # if the status is not set only ReqMgr Admin can change the values # TODO for each step, assigned, approved, announce find out what other values # can be set request_args["RequestType"] = workload.requestType() permission = getWritePermission(request_args) authz_match(permission['role'], permission['group']) del request_args["RequestType"] #validate the status if "RequestStatus" in request_args: validate_state_transition(reqmgr_db_service, request_name, request_args["RequestStatus"]) # delete request_args since it is not part of spec argument and validation args_without_status = {} args_without_status.update(request_args) del args_without_status["RequestStatus"] else: args_without_status = request_args if len(args_without_status) == 1: if 'RequestPriority' in args_without_status: args_without_status['RequestPriority'] = int( args_without_status['RequestPriority']) if (lambda x: (x >= 0 and x < 1e6))( args_without_status['RequestPriority']) is False: raise InvalidSpecParameterValue( "RequestPriority must be an integer between 0 and 1e6") return workload, args_without_status elif 'cascade' in args_without_status: # status was already validated return workload, request_args elif len(args_without_status) > 0 and not workqueue_stat_validation( args_without_status): # validate the arguments against the spec argumentSpecdefinition #TODO: currently only assigned status allows any update other then Status update workload.validateArgumentForAssignment(args_without_status) # to update request_args with type conversion request_args.update(args_without_status) return workload, request_args