Skip to content

Commit

Permalink
add clone test and fix assignment permission
Browse files Browse the repository at this point in the history
  • Loading branch information
ticoann committed Aug 23, 2013
1 parent cc187d0 commit fdeacde
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 112 deletions.
11 changes: 7 additions & 4 deletions src/couchapps/ReqMgr/updates/updaterequest.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// update function
// input: valueKey (what to change), value - new value
function(doc, req)
{
log(req);

function(doc, req) {

if (doc === null) {
log("Error: missing doc id - " + req.id);
return [null, "ERROR: request not found - " + req.id];
}

function updateTransition() {
var currentTS = Math.round((new Date()).getTime() / 1000);
var statusObj = {"Status": doc.RequestStatus, "UpdateTime": currentTS};
Expand Down
32 changes: 17 additions & 15 deletions src/python/WMCore/ReqMgr/DataStructs/Request.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import cherrypy
from WMCore.ReqMgr.DataStructs.RequestStatus import REQUEST_START_STATE

def initialize_request_args(request, config):
def initialize_request_args(request, config, clone = False):
"""
Request data class request is a dictionary representing
a being injected / created request. This method initializes
Expand All @@ -31,33 +31,35 @@ def initialize_request_args(request, config):
request is changed here.
"""
#update the information from config
request["CouchURL"] = config.couch_host
request["CouchWorkloadDBName"] = config.couch_reqmgr_db
request["CouchDBName"] = config.couch_config_cache_db

#user information for cert. (which is converted to cherry py log in)
request["Requestor"] = cherrypy.request.user["login"]
request["RequestorDN"] = cherrypy.request.user.get("dn", "unknown")

# assign first starting status, should be 'new'
request["RequestStatus"] = REQUEST_START_STATE
request["RequestTransition"] = [{"Status": request["RequestStatus"], "UpdateTime": int(time.time())}]
request["RequestDate"] = list(time.gmtime()[:6])

#TODO: generate this automatically from the spec
# generate request name using request
generateRequestName(request)

request["RequestDate"] = list(time.gmtime()[:6])

request.setdefault("SoftwareVersions", [])
if request["CMSSWVersion"] and (request["CMSSWVersion"] not in request["SoftwareVersions"]):
request["SoftwareVersions"].append(request["CMSSWVersion"])
if not clone:
#update the information from config
request["CouchURL"] = config.couch_host
request["CouchWorkloadDBName"] = config.couch_reqmgr_db
request["CouchDBName"] = config.couch_config_cache_db

# TODO
# do we need InputDataset and InputDatasets? when one is just a list
# containing the other? ; could be related to #3743 problem
if request.has_key("InputDataset"):
request["InputDatasets"] = [request["InputDataset"]]
request.setdefault("SoftwareVersions", [])
if request["CMSSWVersion"] and (request["CMSSWVersion"] not in request["SoftwareVersions"]):
request["SoftwareVersions"].append(request["CMSSWVersion"])

# TODO
# do we need InputDataset and InputDatasets? when one is just a list
# containing the other? ; could be related to #3743 problem
if request.has_key("InputDataset"):
request["InputDatasets"] = [request["InputDataset"]]

def generateRequestName(request):

Expand Down
42 changes: 27 additions & 15 deletions src/python/WMCore/ReqMgr/Service/Request.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def __init__(self, app, api, config, mount):
self.reqmgr_db = api.db_handler.get_db(config.couch_reqmgr_db)
# this need for the post validtiaon
self.reqmgr_aux_db = api.db_handler.get_db(config.couch_reqmgr_aux_db)

def validate(self, apiobj, method, api, param, safe):
# to make validate successful
# move the validated argument to safe
Expand Down Expand Up @@ -70,8 +70,12 @@ def validate_request_update_args(self, param, safe):
TODO: rasie right kind of error with clear message
"""
#convert request.body to json (python dict)
request_args = JsonWrapper.loads(cherrypy.request.body.read())

data = cherrypy.request.body.read()
if data:
request_args = JsonWrapper.loads(data)
else:
request_args = {}

if len(param.args) == 2:
#validate clone case
if param.args[0] == "clone":
Expand Down Expand Up @@ -111,7 +115,7 @@ def validate_request_update_args(self, param, safe):
args_without_status = request_args
# validate the arguments against the spec argumentSpecdefinition
workload.validateArgument(args_without_status)
# after validtion clear the param

safe.kwargs['workload'] = workload
safe.kwargs['request_args'] = request_args
return
Expand Down Expand Up @@ -156,9 +160,9 @@ def validate_state_transition(self, request_name, new_state) :

def initialize_clone(self, request_name):
requests = self._get_request_by_name(request_name)
clone_args = requests.values()
clone_args = requests.values()[0]
# overwrite the name and time stamp.
generateRequestName(clone_args)
initialize_request_args(clone_args, self.config, clone=True)
# timestamp status update

spec = loadSpecByType(clone_args["RequestType"])
Expand Down Expand Up @@ -205,7 +209,7 @@ def get(self, **kwargs):
if status and not team:
request_info.append(self.get_reqmgr_view("bystatus" , option, status))
if status and team:
request_info.append(self.get_reqmgr_view("byteamandstatus", option, team))
request_info.append(self.get_reqmgr_view("byteamandstatus", option, [[team, status]]))
if name:
request_info.append(self._get_request_by_name(name))
if prep_id:
Expand Down Expand Up @@ -250,9 +254,17 @@ def _get_couch_view(self, couchdb, couchapp, view, options, keys):
request_info = {}
for item in result["rows"]:
request_info[item["id"]] = item.get('doc', None)
if request_info[item["id"]] != None:
self.filterCouchInfo(request_info[item["id"]])
return request_info


#TODO move this out of this class
def filterCouchInfo(self, couchInfo):
del couchInfo["_rev"]
del couchInfo["_id"]
del couchInfo["_attachments"]

def get_reqmgr_view(self, view, options, keys):
return self._get_couch_view(self.reqmgr_db, "ReqMgr", view,
options, keys)
Expand All @@ -267,6 +279,7 @@ def _get_request_by_name(self, name, stale="update_after"):
TODO: names can be regular expression or list of names
"""
request_doc = self.reqmgr_db.document(name)
self.filterCouchInfo(request_doc)
return {name: request_doc}

def _combine_request(self, request_info, requestAgentUrl, cache):
Expand All @@ -287,20 +300,19 @@ def _combine_request(self, request_info, requestAgentUrl, cache):
@restcall
def put(self, workload, request_args):

if workload == 0:
if workload == None:
(workload, request_args) = self.initialize_clone(request_args["OriginalRequestName"])
self.post(workload, request_args)
return
return self.post(workload, request_args)

cherrypy.log("INFO: '%s -- %s' ..." % (workload.name(), request_args))
# if is not just updating status
if len(request_args) > 1 or not request_args.has_key("RequestStatus"):
workload.updateArguments(request_args)
workload.saveCouchUrl(self.config.couch_host, self.config.couch_reqmgr_db)
# set the worklaad helper using paramenter
# save back to spec and ouch
return self.reqmgr_db.updateDocument(workload.name(), "ReqMgr", "updaterequest",
# trailing / is needed for the savecouchUrl function
workload.saveCouch(self.config.couch_host, self.config.couch_reqmgr_db)

report = self.reqmgr_db.updateDocument(workload.name(), "ReqMgr", "updaterequest",
fields=request_args)
return report

@restcall
def delete(self, request_name):
Expand Down
10 changes: 6 additions & 4 deletions src/python/WMCore/WMSpec/StdSpecs/StdBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -922,21 +922,23 @@ def getWorkloadArguments():

# dashboard activity
"DashboardActivity" : {"default" : "", "type" : str},
# team name
"Team" : {"default" : "", "type" : str},

# this is specified automatically by reqmgr.
# "RequestName" : {"default" : "AnotherRequest", "type" : str,
# "optional" : False, "validate" : None,
# "attr" : "requestName", "null" : False},
"CouchURL" : {"default" : "http://localhost:5984", "type" : str,
"CouchURL" : {"default" : "http://localhost:5984", "type" : str,
"optional" : False, "validate" : couchurl,
"attr" : "couchURL", "null" : False},
"CouchDBName" : {"default" : "dp_configcache", "type" : str,
"CouchDBName" : {"default" : "dp_configcache", "type" : str,
"optional" : True, "validate" : identifier,
"attr" : "couchDBName", "null" : False},
"ConfigCacheUrl" : {"default" : None, "type" : str,
"ConfigCacheUrl" : {"default" : None, "type" : str,
"optional" : True, "validate" : None,
"attr" : "configCacheUrl", "null" : True},
"CouchWorkloadDBName" : {"default" : "reqmgr_workload_cache", "type" : str,
"CouchWorkloadDBName" : {"default" : "reqmgr_workload_cache", "type" : str,
"optional" : False, "validate" : identifier,
"attr" : "couchWorkloadDBName", "null" : False}}

Expand Down
112 changes: 64 additions & 48 deletions src/python/WMCore/WMSpec/WMWorkload.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
from WMCore.Configuration import ConfigSection
from WMCore.WMSpec.ConfigSectionTree import findTop
from WMCore.WMSpec.Persistency import PersistencyHelper
from WMCore.WMSpec.WMWorkloadTools import validateArgumentsUpdate, loadSpecClassByType
from WMCore.WMSpec.WMWorkloadTools import validateArgumentsUpdate, \
loadSpecClassByType, setArgumentsNoneValueWithDefault
from WMCore.WMSpec.WMTask import WMTask, WMTaskHelper
from WMCore.Lexicon import lfnBase, sanitizeURL
from WMCore.WMException import WMException
Expand Down Expand Up @@ -1641,77 +1642,92 @@ def validateArgument(self, schema):
raise WMSpecFactoryException(message = msg)
return

def updateArguments(self, kwargs):
def _checkKeys(self, kwargs, keys):
"""
check whether list of keys exist in the kwargs
if no keys exist return False
if all keys exist return True
if partial keys exsit raise Exception
"""
if type(keys) == str:
keys = [keys]
validKey = 0
for key in keys:
if kwargs.has_key(key):
validKey += 1
if validKey == 0:
return False
elif validKey == len(keys):
return True
else:
#TODO raise proper exception
raise Exception("not all the key is specified %s" % keys)

def updateArguments(self, kwargs, wildcardSites = {}):
"""
set up all the argument related to assigning request.
args are validated before update.
assignment is common for all different types spec.
"""

if kwargs.get("SiteWhitelist") or kwargs.get("SiteBlacklist"):
specClass = loadSpecClassByType(self.requestType())
argumentDefinition = specClass.getWorkloadArguments()
setArgumentsNoneValueWithDefault(kwargs, argumentDefinition)

if self._checkKeys(kwargs, ["SiteWhitelist", "SiteBlacklist"]):
self.setSiteWildcardsLists(siteWhitelist = kwargs["SiteWhitelist"],
siteBlacklist = kwargs["SiteBlacklist"],
wildcardDict = self.wildcardSites)
wildcardDict = wildcardSites)
# Set ProcessingVersion and AcquisitionEra, which could be json encoded dicts
if kwargs.get("ProcessingVersion"):
if self._checkKeys(kwargs, "ProcessingVersion"):
self.setProcessingVersion(kwargs["ProcessingVersion"])
if kwargs.get("AcquisitionEra"):
if self._checkKeys(kwargs, "AcquisitionEra"):
self.setAcquisitionEra(kwargs["AcquisitionEra"])
if kwargs.get("ProcessingString"):
if self._checkKeys(kwargs, "ProcessingString"):
self.setProcessingString(kwargs["ProcessingString"])

#FIXME not validated
if kwargs.get("MergedLFNBase") or kwargs.get("MergedLFNBase"):
if self._checkKeys(kwargs, ["MergedLFNBase", "MergedLFNBase"]):
self.setLFNBase(kwargs["MergedLFNBase"], kwargs["UnmergedLFNBase"])

self.setMergeParameters(int(kwargs.get("MinMergeSize", 2147483648)),
int(kwargs.get("MaxMergeSize", 4294967296)),
int(kwargs.get("MaxMergeEvents", 50000)))
self.setupPerformanceMonitoring(int(kwargs.get("MaxRSS", 2411724)),
int(kwargs.get("MaxVSize", 20411724)),
int(kwargs.get("SoftTimeout", 129600)),
int(kwargs.get("GracePeriod", 300)))
if self._checkKeys(kwargs, ["MinMergeSize", "MaxMergeSize", "MaxMergeEvents"]):
self.setMergeParameters(int(kwargs["MinMergeSize"]),
int(kwargs["MaxMergeSize"]),
int(kwargs["MaxMergeEvents"]))

if self._checkKeys(kwargs, ["MaxRSS", "MaxVSize", "SoftTimeout", "GracePeriod"]):
self.setupPerformanceMonitoring(int(kwargs["MaxRSS"]),
int(kwargs["MaxVSize"]),
int(kwargs["SoftTimeout"]),
int(kwargs["GracePeriod"]))

# Check whether we should check location for the data
if kwargs.get("useSiteListAsLocation"):
if self._checkKeys(kwargs, "useSiteListAsLocation"):
self.setLocationDataSourceFlag()

# Set phedex subscription information
custodialList = kwargs.get("CustodialSites", [])
nonCustodialList = kwargs.get("NonCustodialSites", [])
autoApproveList = kwargs.get("AutoApproveSubscriptionSites", [])
subscriptionPriority = kwargs.get("SubscriptionPriority", "Low")
subscriptionType = kwargs.get("CustodialSubType", "Move")

self.setSubscriptionInformationWildCards(wildcardDict = self.wildcardSites,
custodialSites = custodialList,
nonCustodialSites = nonCustodialList,
autoApproveSites = autoApproveList,
custodialSubType = subscriptionType,
priority = subscriptionPriority)
if self._checkKeys(kwargs, ["CustodialSites", "NonCustodialSites",
"AutoApproveSubscriptionSites",
"CustodialSubType", "SubscriptionPriority"]):
self.setSubscriptionInformationWildCards(wildcardDict = wildcardSites,
custodialSites = kwargs["CustodialSites"],
nonCustodialSites = kwargs["NonCustodialSites"],
autoApproveSites = kwargs["AutoApproveSubscriptionSites"],
custodialSubType = kwargs["CustodialSubType"],
priority = kwargs["SubscriptionPriority"])

# Block closing information
blockCloseMaxWaitTime = int(kwargs.get("BlockCloseMaxWaitTime", self.getBlockCloseMaxWaitTime()))
blockCloseMaxFiles = int(kwargs.get("BlockCloseMaxFiles", self.getBlockCloseMaxFiles()))
blockCloseMaxEvents = int(kwargs.get("BlockCloseMaxEvents", self.getBlockCloseMaxEvents()))
blockCloseMaxSize = int(kwargs.get("BlockCloseMaxSize", self.getBlockCloseMaxSize()))

self.setBlockCloseSettings(blockCloseMaxWaitTime, blockCloseMaxFiles,
blockCloseMaxEvents, blockCloseMaxSize)

self.setDashboardActivity(kwargs.get("DashboardActivity", ""))
if self._checkKeys(kwargs, ["BlockCloseMaxWaitTime", "BlockCloseMaxFiles",
"BlockCloseMaxEvents", "BlockCloseMaxSize"]):
self.setBlockCloseSettings(kwargs["BlockCloseMaxWaitTime"],
kwargs["BlockCloseMaxFiles"],
kwargs["BlockCloseMaxEvents"],
kwargs["BlockCloseMaxSize"])

if self._checkKeys(kwargs, "DashboardActivity"):
self.setDashboardActivity(kwargs["DashboardActivity"])


## this needs to be done outside the function
# Utilities.saveWorkload(helper, request['RequestWorkflow'], self.wmstatWriteURL)
#
# # update AcquisitionEra in the Couch document (#4380)
# # request object returned above from Oracle doesn't have information Couch
# # database
# reqDetails = Utilities.requestDetails(request["RequestName"])
# couchDb = Database(reqDetails["CouchWorkloadDBName"], reqDetails["CouchURL"])
# couchDb.updateDocument(request["RequestName"], "ReqMgr", "updaterequest",
# fields={"AcquisitionEra": reqDetails["AcquisitionEra"]})


return kwargs

Expand Down
9 changes: 9 additions & 0 deletions src/python/WMCore/WMSpec/WMWorkloadTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,15 @@ def validateArgumentsUpdate(arguments, argumentDefinition):
_validateArgument(argument, arguments[argument], argumentDefinition)
return

def setArgumentsNoneValueWithDefault(arguments, argumentDefinition):
"""
sets the default value if arguments value is specified as None
"""
for argument in arguments:
if arguments[argument] == None:
argumentDefinition[argument]["default"]
return

def loadSpecClassByType(specType):
factoryName = "%sWorkloadFactory" % specType
mod = __import__("WMCore.WMSpec.StdSpecs.%s" % specType,
Expand Down
6 changes: 3 additions & 3 deletions test/data/ReqMgr/requests/ReReco.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@
"AcquisitionEra": "AcquisitionEra-OVERRIDE-ME",
"ProcessingVersion": 1,
"ProcessingString" : "ProcessingString-OVERRIDE-ME",
"maxRSS": 4294967296,
"maxVSize": 4294967296,
"MaxRSS": 4294967296,
"MaxVSize": 4294967296,
"SoftTimeout": 129600,
"GracePeriod": 300,
"dashboard": "dashboard-OVERRIDE-ME",
"DashboardActivity": "dashboard-OVERRIDE-ME",
"Team": "Team--OVERRIDE-ME",
"CustodialSites": [],
"NonCustodialSites": [],
Expand Down
Loading

0 comments on commit fdeacde

Please sign in to comment.