wmglobalqueue 2.3.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of wmglobalqueue might be problematic. Click here for more details.
- Utils/CPMetrics.py +270 -0
- Utils/CertTools.py +62 -0
- Utils/EmailAlert.py +50 -0
- Utils/ExtendedUnitTestCase.py +62 -0
- Utils/FileTools.py +182 -0
- Utils/IteratorTools.py +80 -0
- Utils/MathUtils.py +31 -0
- Utils/MemoryCache.py +119 -0
- Utils/Patterns.py +24 -0
- Utils/Pipeline.py +137 -0
- Utils/PortForward.py +97 -0
- Utils/ProcessStats.py +103 -0
- Utils/PythonVersion.py +17 -0
- Utils/Signals.py +36 -0
- Utils/TemporaryEnvironment.py +27 -0
- Utils/Throttled.py +227 -0
- Utils/Timers.py +130 -0
- Utils/Timestamps.py +86 -0
- Utils/TokenManager.py +143 -0
- Utils/Tracing.py +60 -0
- Utils/TwPrint.py +98 -0
- Utils/Utilities.py +308 -0
- Utils/__init__.py +11 -0
- WMCore/ACDC/Collection.py +57 -0
- WMCore/ACDC/CollectionTypes.py +12 -0
- WMCore/ACDC/CouchCollection.py +67 -0
- WMCore/ACDC/CouchFileset.py +238 -0
- WMCore/ACDC/CouchService.py +73 -0
- WMCore/ACDC/DataCollectionService.py +485 -0
- WMCore/ACDC/Fileset.py +94 -0
- WMCore/ACDC/__init__.py +11 -0
- WMCore/Algorithms/Alarm.py +39 -0
- WMCore/Algorithms/MathAlgos.py +274 -0
- WMCore/Algorithms/MiscAlgos.py +67 -0
- WMCore/Algorithms/ParseXMLFile.py +115 -0
- WMCore/Algorithms/Permissions.py +27 -0
- WMCore/Algorithms/Singleton.py +58 -0
- WMCore/Algorithms/SubprocessAlgos.py +129 -0
- WMCore/Algorithms/__init__.py +7 -0
- WMCore/Cache/GenericDataCache.py +98 -0
- WMCore/Cache/WMConfigCache.py +572 -0
- WMCore/Cache/__init__.py +0 -0
- WMCore/Configuration.py +651 -0
- WMCore/DAOFactory.py +47 -0
- WMCore/DataStructs/File.py +177 -0
- WMCore/DataStructs/Fileset.py +140 -0
- WMCore/DataStructs/Job.py +182 -0
- WMCore/DataStructs/JobGroup.py +142 -0
- WMCore/DataStructs/JobPackage.py +49 -0
- WMCore/DataStructs/LumiList.py +734 -0
- WMCore/DataStructs/Mask.py +219 -0
- WMCore/DataStructs/MathStructs/ContinuousSummaryHistogram.py +197 -0
- WMCore/DataStructs/MathStructs/DiscreteSummaryHistogram.py +92 -0
- WMCore/DataStructs/MathStructs/SummaryHistogram.py +117 -0
- WMCore/DataStructs/MathStructs/__init__.py +0 -0
- WMCore/DataStructs/Pickleable.py +24 -0
- WMCore/DataStructs/Run.py +256 -0
- WMCore/DataStructs/Subscription.py +175 -0
- WMCore/DataStructs/WMObject.py +47 -0
- WMCore/DataStructs/WorkUnit.py +112 -0
- WMCore/DataStructs/Workflow.py +60 -0
- WMCore/DataStructs/__init__.py +8 -0
- WMCore/Database/CMSCouch.py +1349 -0
- WMCore/Database/ConfigDBMap.py +29 -0
- WMCore/Database/CouchUtils.py +118 -0
- WMCore/Database/DBCore.py +198 -0
- WMCore/Database/DBCreator.py +113 -0
- WMCore/Database/DBExceptionHandler.py +57 -0
- WMCore/Database/DBFactory.py +110 -0
- WMCore/Database/DBFormatter.py +177 -0
- WMCore/Database/Dialects.py +13 -0
- WMCore/Database/ExecuteDAO.py +327 -0
- WMCore/Database/MongoDB.py +241 -0
- WMCore/Database/MySQL/Destroy.py +42 -0
- WMCore/Database/MySQL/ListUserContent.py +20 -0
- WMCore/Database/MySQL/__init__.py +9 -0
- WMCore/Database/MySQLCore.py +132 -0
- WMCore/Database/Oracle/Destroy.py +56 -0
- WMCore/Database/Oracle/ListUserContent.py +19 -0
- WMCore/Database/Oracle/__init__.py +9 -0
- WMCore/Database/ResultSet.py +44 -0
- WMCore/Database/Transaction.py +91 -0
- WMCore/Database/__init__.py +9 -0
- WMCore/Database/ipy_profile_couch.py +438 -0
- WMCore/GlobalWorkQueue/CherryPyThreads/CleanUpTask.py +29 -0
- WMCore/GlobalWorkQueue/CherryPyThreads/HeartbeatMonitor.py +105 -0
- WMCore/GlobalWorkQueue/CherryPyThreads/LocationUpdateTask.py +28 -0
- WMCore/GlobalWorkQueue/CherryPyThreads/ReqMgrInteractionTask.py +35 -0
- WMCore/GlobalWorkQueue/CherryPyThreads/__init__.py +0 -0
- WMCore/GlobalWorkQueue/__init__.py +0 -0
- WMCore/GroupUser/CouchObject.py +127 -0
- WMCore/GroupUser/Decorators.py +51 -0
- WMCore/GroupUser/Group.py +33 -0
- WMCore/GroupUser/Interface.py +73 -0
- WMCore/GroupUser/User.py +96 -0
- WMCore/GroupUser/__init__.py +11 -0
- WMCore/Lexicon.py +836 -0
- WMCore/REST/Auth.py +202 -0
- WMCore/REST/CherryPyPeriodicTask.py +166 -0
- WMCore/REST/Error.py +333 -0
- WMCore/REST/Format.py +642 -0
- WMCore/REST/HeartbeatMonitorBase.py +90 -0
- WMCore/REST/Main.py +623 -0
- WMCore/REST/Server.py +2435 -0
- WMCore/REST/Services.py +24 -0
- WMCore/REST/Test.py +120 -0
- WMCore/REST/Tools.py +38 -0
- WMCore/REST/Validation.py +250 -0
- WMCore/REST/__init__.py +1 -0
- WMCore/ReqMgr/DataStructs/RequestStatus.py +209 -0
- WMCore/ReqMgr/DataStructs/RequestType.py +13 -0
- WMCore/ReqMgr/DataStructs/__init__.py +0 -0
- WMCore/ReqMgr/__init__.py +1 -0
- WMCore/Services/AlertManager/AlertManagerAPI.py +111 -0
- WMCore/Services/AlertManager/__init__.py +0 -0
- WMCore/Services/CRIC/CRIC.py +238 -0
- WMCore/Services/CRIC/__init__.py +0 -0
- WMCore/Services/DBS/DBS3Reader.py +1044 -0
- WMCore/Services/DBS/DBSConcurrency.py +44 -0
- WMCore/Services/DBS/DBSErrors.py +113 -0
- WMCore/Services/DBS/DBSReader.py +23 -0
- WMCore/Services/DBS/DBSUtils.py +139 -0
- WMCore/Services/DBS/DBSWriterObjects.py +381 -0
- WMCore/Services/DBS/ProdException.py +133 -0
- WMCore/Services/DBS/__init__.py +8 -0
- WMCore/Services/FWJRDB/FWJRDBAPI.py +118 -0
- WMCore/Services/FWJRDB/__init__.py +0 -0
- WMCore/Services/HTTPS/HTTPSAuthHandler.py +66 -0
- WMCore/Services/HTTPS/__init__.py +0 -0
- WMCore/Services/LogDB/LogDB.py +201 -0
- WMCore/Services/LogDB/LogDBBackend.py +191 -0
- WMCore/Services/LogDB/LogDBExceptions.py +11 -0
- WMCore/Services/LogDB/LogDBReport.py +85 -0
- WMCore/Services/LogDB/__init__.py +0 -0
- WMCore/Services/MSPileup/__init__.py +0 -0
- WMCore/Services/MSUtils/MSUtils.py +54 -0
- WMCore/Services/MSUtils/__init__.py +0 -0
- WMCore/Services/McM/McM.py +173 -0
- WMCore/Services/McM/__init__.py +8 -0
- WMCore/Services/MonIT/Grafana.py +133 -0
- WMCore/Services/MonIT/__init__.py +0 -0
- WMCore/Services/PyCondor/PyCondorAPI.py +154 -0
- WMCore/Services/PyCondor/PyCondorUtils.py +105 -0
- WMCore/Services/PyCondor/__init__.py +0 -0
- WMCore/Services/ReqMgr/ReqMgr.py +261 -0
- WMCore/Services/ReqMgr/__init__.py +0 -0
- WMCore/Services/ReqMgrAux/ReqMgrAux.py +419 -0
- WMCore/Services/ReqMgrAux/__init__.py +0 -0
- WMCore/Services/RequestDB/RequestDBReader.py +267 -0
- WMCore/Services/RequestDB/RequestDBWriter.py +39 -0
- WMCore/Services/RequestDB/__init__.py +0 -0
- WMCore/Services/Requests.py +624 -0
- WMCore/Services/Rucio/Rucio.py +1287 -0
- WMCore/Services/Rucio/RucioUtils.py +74 -0
- WMCore/Services/Rucio/__init__.py +0 -0
- WMCore/Services/RucioConMon/RucioConMon.py +128 -0
- WMCore/Services/RucioConMon/__init__.py +0 -0
- WMCore/Services/Service.py +400 -0
- WMCore/Services/StompAMQ/__init__.py +0 -0
- WMCore/Services/TagCollector/TagCollector.py +155 -0
- WMCore/Services/TagCollector/XMLUtils.py +98 -0
- WMCore/Services/TagCollector/__init__.py +0 -0
- WMCore/Services/UUIDLib.py +13 -0
- WMCore/Services/UserFileCache/UserFileCache.py +160 -0
- WMCore/Services/UserFileCache/__init__.py +8 -0
- WMCore/Services/WMAgent/WMAgent.py +63 -0
- WMCore/Services/WMAgent/__init__.py +0 -0
- WMCore/Services/WMArchive/CMSSWMetrics.py +526 -0
- WMCore/Services/WMArchive/DataMap.py +463 -0
- WMCore/Services/WMArchive/WMArchive.py +33 -0
- WMCore/Services/WMArchive/__init__.py +0 -0
- WMCore/Services/WMBS/WMBS.py +97 -0
- WMCore/Services/WMBS/__init__.py +0 -0
- WMCore/Services/WMStats/DataStruct/RequestInfoCollection.py +300 -0
- WMCore/Services/WMStats/DataStruct/__init__.py +0 -0
- WMCore/Services/WMStats/WMStatsPycurl.py +145 -0
- WMCore/Services/WMStats/WMStatsReader.py +445 -0
- WMCore/Services/WMStats/WMStatsWriter.py +273 -0
- WMCore/Services/WMStats/__init__.py +0 -0
- WMCore/Services/WMStatsServer/WMStatsServer.py +134 -0
- WMCore/Services/WMStatsServer/__init__.py +0 -0
- WMCore/Services/WorkQueue/WorkQueue.py +492 -0
- WMCore/Services/WorkQueue/__init__.py +0 -0
- WMCore/Services/__init__.py +8 -0
- WMCore/Services/pycurl_manager.py +574 -0
- WMCore/WMBase.py +50 -0
- WMCore/WMConnectionBase.py +164 -0
- WMCore/WMException.py +183 -0
- WMCore/WMExceptions.py +269 -0
- WMCore/WMFactory.py +76 -0
- WMCore/WMInit.py +228 -0
- WMCore/WMLogging.py +108 -0
- WMCore/WMSpec/ConfigSectionTree.py +442 -0
- WMCore/WMSpec/Persistency.py +135 -0
- WMCore/WMSpec/Steps/BuildMaster.py +87 -0
- WMCore/WMSpec/Steps/BuildTools.py +201 -0
- WMCore/WMSpec/Steps/Builder.py +97 -0
- WMCore/WMSpec/Steps/Diagnostic.py +89 -0
- WMCore/WMSpec/Steps/Emulator.py +62 -0
- WMCore/WMSpec/Steps/ExecuteMaster.py +208 -0
- WMCore/WMSpec/Steps/Executor.py +210 -0
- WMCore/WMSpec/Steps/StepFactory.py +213 -0
- WMCore/WMSpec/Steps/TaskEmulator.py +75 -0
- WMCore/WMSpec/Steps/Template.py +204 -0
- WMCore/WMSpec/Steps/Templates/AlcaHarvest.py +76 -0
- WMCore/WMSpec/Steps/Templates/CMSSW.py +613 -0
- WMCore/WMSpec/Steps/Templates/DQMUpload.py +59 -0
- WMCore/WMSpec/Steps/Templates/DeleteFiles.py +70 -0
- WMCore/WMSpec/Steps/Templates/LogArchive.py +84 -0
- WMCore/WMSpec/Steps/Templates/LogCollect.py +105 -0
- WMCore/WMSpec/Steps/Templates/StageOut.py +105 -0
- WMCore/WMSpec/Steps/Templates/__init__.py +10 -0
- WMCore/WMSpec/Steps/WMExecutionFailure.py +21 -0
- WMCore/WMSpec/Steps/__init__.py +8 -0
- WMCore/WMSpec/Utilities.py +63 -0
- WMCore/WMSpec/WMSpecErrors.py +12 -0
- WMCore/WMSpec/WMStep.py +347 -0
- WMCore/WMSpec/WMTask.py +1980 -0
- WMCore/WMSpec/WMWorkload.py +2288 -0
- WMCore/WMSpec/WMWorkloadTools.py +370 -0
- WMCore/WMSpec/__init__.py +9 -0
- WMCore/WorkQueue/DataLocationMapper.py +273 -0
- WMCore/WorkQueue/DataStructs/ACDCBlock.py +47 -0
- WMCore/WorkQueue/DataStructs/Block.py +48 -0
- WMCore/WorkQueue/DataStructs/CouchWorkQueueElement.py +148 -0
- WMCore/WorkQueue/DataStructs/WorkQueueElement.py +274 -0
- WMCore/WorkQueue/DataStructs/WorkQueueElementResult.py +152 -0
- WMCore/WorkQueue/DataStructs/WorkQueueElementsSummary.py +185 -0
- WMCore/WorkQueue/DataStructs/__init__.py +0 -0
- WMCore/WorkQueue/Policy/End/EndPolicyInterface.py +44 -0
- WMCore/WorkQueue/Policy/End/SingleShot.py +22 -0
- WMCore/WorkQueue/Policy/End/__init__.py +32 -0
- WMCore/WorkQueue/Policy/PolicyInterface.py +17 -0
- WMCore/WorkQueue/Policy/Start/Block.py +258 -0
- WMCore/WorkQueue/Policy/Start/Dataset.py +180 -0
- WMCore/WorkQueue/Policy/Start/MonteCarlo.py +131 -0
- WMCore/WorkQueue/Policy/Start/ResubmitBlock.py +171 -0
- WMCore/WorkQueue/Policy/Start/StartPolicyInterface.py +316 -0
- WMCore/WorkQueue/Policy/Start/__init__.py +34 -0
- WMCore/WorkQueue/Policy/__init__.py +57 -0
- WMCore/WorkQueue/WMBSHelper.py +772 -0
- WMCore/WorkQueue/WorkQueue.py +1237 -0
- WMCore/WorkQueue/WorkQueueBackend.py +750 -0
- WMCore/WorkQueue/WorkQueueBase.py +39 -0
- WMCore/WorkQueue/WorkQueueExceptions.py +44 -0
- WMCore/WorkQueue/WorkQueueReqMgrInterface.py +278 -0
- WMCore/WorkQueue/WorkQueueUtils.py +130 -0
- WMCore/WorkQueue/__init__.py +13 -0
- WMCore/Wrappers/JsonWrapper/JSONThunker.py +342 -0
- WMCore/Wrappers/JsonWrapper/__init__.py +7 -0
- WMCore/Wrappers/__init__.py +6 -0
- WMCore/__init__.py +10 -0
- wmglobalqueue-2.3.10.data/data/bin/wmc-dist-patch +15 -0
- wmglobalqueue-2.3.10.data/data/bin/wmc-dist-unpatch +8 -0
- wmglobalqueue-2.3.10.data/data/bin/wmc-httpd +3 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/.couchapprc +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/README.md +40 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/index.html +264 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/ElementInfoByWorkflow.js +96 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/StuckElementInfo.js +57 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/WorkloadInfoTable.js +80 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/dataTable.js +70 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/namespace.js +23 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/style/main.css +75 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/couchapp.json +4 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/filters/childQueueFilter.js +13 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/filters/filterDeletedDocs.js +3 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/filters/queueFilter.js +11 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/language +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lib/mustache.js +333 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lib/validate.js +27 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lib/workqueue_utils.js +61 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/elementsDetail.js +28 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/filter.js +86 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/stuckElements.js +38 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/workRestrictions.js +153 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/workflowSummary.js +28 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/rewrites.json +73 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/shows/redirect.js +23 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/shows/status.js +40 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/ElementSummaryByWorkflow.html +27 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/StuckElementSummary.html +26 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/TaskStatus.html +23 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/WorkflowSummary.html +27 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/partials/workqueue-common-lib.html +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib-remote.html +16 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib.html +18 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/updates/in-place.js +50 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/validate_doc_update.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.couch.app.js +235 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.pathbinder.js +173 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeData/reduce.js +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeParentData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeParentData/reduce.js +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activePileupData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activePileupData/reduce.js +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/analyticsData/map.js +11 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/analyticsData/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/availableByPriority/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/conflicts/map.js +5 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elements/map.js +5 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByParent/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByParentData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByPileupData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByStatus/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsBySubscription/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/reduce.js +3 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsDetailByWorkflowAndStatus/map.js +26 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/map.js +10 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByRequest/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatus/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatus/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/openRequests/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/recent-items/map.js +5 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/specsByWorkflow/map.js +5 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/stuckElements/map.js +38 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/map.js +12 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/reduce.js +3 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrl/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrl/reduce.js +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/reduce.js +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/workflowSummary/map.js +9 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/workflowSummary/reduce.js +10 -0
- wmglobalqueue-2.3.10.dist-info/LICENSE +202 -0
- wmglobalqueue-2.3.10.dist-info/METADATA +24 -0
- wmglobalqueue-2.3.10.dist-info/NOTICE +16 -0
- wmglobalqueue-2.3.10.dist-info/RECORD +345 -0
- wmglobalqueue-2.3.10.dist-info/WHEEL +5 -0
- wmglobalqueue-2.3.10.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
"""
|
|
2
|
+
_WMWorkloadTools_
|
|
3
|
+
|
|
4
|
+
Define some generic tools used by the StdSpecs and WMWorkload
|
|
5
|
+
to validate arguments that modify a WMWorkload and/or WMTask.
|
|
6
|
+
|
|
7
|
+
Created on Jun 13, 2013
|
|
8
|
+
|
|
9
|
+
@author: dballest
|
|
10
|
+
"""
|
|
11
|
+
from builtins import str, bytes
|
|
12
|
+
from future.utils import viewitems, viewvalues
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import re
|
|
16
|
+
import inspect
|
|
17
|
+
|
|
18
|
+
from Utils.Utilities import makeList
|
|
19
|
+
from WMCore.DataStructs.LumiList import LumiList
|
|
20
|
+
from WMCore.WMSpec.WMSpecErrors import WMSpecFactoryException
|
|
21
|
+
|
|
22
|
+
def checkMemCore(paramInfo, minValue=1):
|
|
23
|
+
"""
|
|
24
|
+
Spec validation function for the Memory/Multicore parameters
|
|
25
|
+
:param memInfo: memory provided by the user (can be an int/float/dict)
|
|
26
|
+
:param minValue: base value to be used to validate user's values
|
|
27
|
+
:return: True if validation is successful, raise an exception otherwise
|
|
28
|
+
"""
|
|
29
|
+
try:
|
|
30
|
+
if isinstance(paramInfo, dict):
|
|
31
|
+
for value in viewvalues(paramInfo):
|
|
32
|
+
assert value >= minValue
|
|
33
|
+
else:
|
|
34
|
+
assert paramInfo >= minValue
|
|
35
|
+
except Exception:
|
|
36
|
+
return False
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def checkEventStreams(streamsInfo):
|
|
41
|
+
"""
|
|
42
|
+
Spec validation function for the EventStreams parameter
|
|
43
|
+
:param streamsInfo: event streams provided by the user (can be either int or a dict)
|
|
44
|
+
:return: True if validation is successful, raise an exception otherwise
|
|
45
|
+
"""
|
|
46
|
+
return checkMemCore(streamsInfo, 0)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def checkTimePerEvent(tpEvtInfo):
|
|
50
|
+
"""
|
|
51
|
+
Spec validation function for the TimePerEvent parameter
|
|
52
|
+
:param tpEvtInfo: time per event provided by the user (can be either float or a dict)
|
|
53
|
+
:return: True if validation is successful, raise an exception otherwise
|
|
54
|
+
"""
|
|
55
|
+
return checkMemCore(tpEvtInfo, 0)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def makeLumiList(lumiDict):
|
|
59
|
+
try:
|
|
60
|
+
if isinstance(lumiDict, (str, bytes)):
|
|
61
|
+
lumiDict = json.loads(lumiDict)
|
|
62
|
+
ll = LumiList(compactList=lumiDict)
|
|
63
|
+
return ll.getCompactList()
|
|
64
|
+
except:
|
|
65
|
+
raise WMSpecFactoryException("Could not parse LumiList, %s: %s" % (type(lumiDict), lumiDict))
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def parsePileupConfig(mcPileup, dataPileup):
|
|
69
|
+
"""
|
|
70
|
+
_parsePileupConfig_
|
|
71
|
+
|
|
72
|
+
If the pileup config is defined as MCPileup and DataPileup
|
|
73
|
+
then make sure we get the usual dictionary as
|
|
74
|
+
PileupConfig : {'mc': ['/mc_pd/procds/tier'], 'data': ['/data_pd/procds/tier']}
|
|
75
|
+
"""
|
|
76
|
+
pileUpConfig = {}
|
|
77
|
+
if mcPileup is not None:
|
|
78
|
+
pileUpConfig['mc'] = [mcPileup]
|
|
79
|
+
if dataPileup is not None:
|
|
80
|
+
pileUpConfig['data'] = [dataPileup]
|
|
81
|
+
return pileUpConfig
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _validateArgument(argument, value, argumentDefinition):
|
|
85
|
+
"""
|
|
86
|
+
Validate a single argument against its definition in the spec
|
|
87
|
+
"""
|
|
88
|
+
validNull = argumentDefinition["null"]
|
|
89
|
+
if not validNull and value is None:
|
|
90
|
+
raise WMSpecFactoryException("Argument '%s' cannot be None" % argument)
|
|
91
|
+
elif value is None:
|
|
92
|
+
return value
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
value = argumentDefinition["type"](value)
|
|
96
|
+
except Exception:
|
|
97
|
+
msg = "Argument '%s' with value %r, has an incorrect data type: " % (argument, value)
|
|
98
|
+
msg += "%s. It must be %s" % (type(value), argumentDefinition["type"])
|
|
99
|
+
raise WMSpecFactoryException(msg)
|
|
100
|
+
|
|
101
|
+
_validateArgFunction(argument, value, argumentDefinition["validate"])
|
|
102
|
+
return value
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _validateArgumentDict(argument, argValue, argumentDefinition):
|
|
106
|
+
"""
|
|
107
|
+
Validate only the basic structure of dict arguments, we anyways
|
|
108
|
+
don't have the definition of the internal arguments.
|
|
109
|
+
"""
|
|
110
|
+
# make sure we're not going to cast a dict to string and let that unnoticed
|
|
111
|
+
if isinstance(argumentDefinition["type"], type(dict)) and not isinstance(argValue, dict):
|
|
112
|
+
msg = "Argument '%s' with value %r, has an incorrect data type: " % (argument, argValue)
|
|
113
|
+
msg += "%s. It must be %s" % (type(argValue), argumentDefinition["type"])
|
|
114
|
+
raise WMSpecFactoryException(msg)
|
|
115
|
+
|
|
116
|
+
# still an exception, make sure it has the correct format
|
|
117
|
+
if argument == "LumiList":
|
|
118
|
+
argValue = argumentDefinition["type"](argValue)
|
|
119
|
+
|
|
120
|
+
_validateArgFunction(argument, argValue, argumentDefinition["validate"])
|
|
121
|
+
return argValue
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _validateArgFunction(argument, value, valFunction):
|
|
125
|
+
"""
|
|
126
|
+
Perform the validation function as in the argument definition
|
|
127
|
+
"""
|
|
128
|
+
if valFunction:
|
|
129
|
+
try:
|
|
130
|
+
if not valFunction(value):
|
|
131
|
+
msg = "Argument '%s' with value %r, doesn't pass the validate function." % (argument, value)
|
|
132
|
+
msg += "\nIt's definition is:\n%s" % inspect.getsource(valFunction)
|
|
133
|
+
raise WMSpecFactoryException(msg)
|
|
134
|
+
except WMSpecFactoryException:
|
|
135
|
+
# just re-raise it to keep the error message clear
|
|
136
|
+
raise
|
|
137
|
+
except Exception as ex:
|
|
138
|
+
# Some validation functions (e.g. Lexicon) will raise errors instead of returning False
|
|
139
|
+
raise WMSpecFactoryException(str(ex))
|
|
140
|
+
return
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _validateArgumentOptions(arguments, argumentDefinition, optionKey=None):
|
|
144
|
+
"""
|
|
145
|
+
Check whether create or assign mandatory parameters were properly
|
|
146
|
+
set in the request schema.
|
|
147
|
+
"""
|
|
148
|
+
for arg, argDef in viewitems(argumentDefinition):
|
|
149
|
+
optional = argDef.get(optionKey, True)
|
|
150
|
+
if not optional and arg not in arguments:
|
|
151
|
+
msg = "Argument '{}' is mandatory and must be provided by the user.".format(arg)
|
|
152
|
+
msg += " Its definition is: {}".format(argDef)
|
|
153
|
+
raise WMSpecFactoryException(msg)
|
|
154
|
+
# specific case when user GUI returns empty string for optional arguments
|
|
155
|
+
elif arg not in arguments:
|
|
156
|
+
continue
|
|
157
|
+
elif isinstance(arguments[arg], dict):
|
|
158
|
+
arguments[arg] = _validateArgumentDict(arg, arguments[arg], argDef)
|
|
159
|
+
else:
|
|
160
|
+
arguments[arg] = _validateArgument(arg, arguments[arg], argDef)
|
|
161
|
+
return
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def validateInputDatasSetAndParentFlag(arguments):
|
|
165
|
+
"""
|
|
166
|
+
Check if the InputDataset value provided corresponds to an actual dataset in DBS.
|
|
167
|
+
If parent flag is provided, then check whether the input dataset has a parent.
|
|
168
|
+
the InputDataset existence in DBS and its parent, if needed.
|
|
169
|
+
"""
|
|
170
|
+
inputdataset = _getChainKey(arguments, "InputDataset")
|
|
171
|
+
mcpileup = _getChainKey(arguments, "MCPileup")
|
|
172
|
+
datapileup = _getChainKey(arguments, "DataPileup")
|
|
173
|
+
includeParents = _getChainKey(arguments, "IncludeParents")
|
|
174
|
+
# TODO: this replace can be removed in one year from now, thus March 2022
|
|
175
|
+
dbsURL = arguments.get("DbsUrl")
|
|
176
|
+
if dbsURL:
|
|
177
|
+
dbsURL = dbsURL.replace("cmsweb.cern.ch", "cmsweb-prod.cern.ch")
|
|
178
|
+
dbsURL = dbsURL.rstrip("/")
|
|
179
|
+
|
|
180
|
+
if includeParents and not inputdataset:
|
|
181
|
+
msg = "IncludeParents flag is True but InputDataset value has not been provided"
|
|
182
|
+
raise WMSpecFactoryException(msg)
|
|
183
|
+
|
|
184
|
+
if dbsURL and inputdataset or mcpileup or datapileup:
|
|
185
|
+
# import DBS3Reader here, since Runtime code import this module and worker
|
|
186
|
+
# node doesn't have dbs3 client
|
|
187
|
+
from WMCore.Services.DBS.DBS3Reader import DBS3Reader
|
|
188
|
+
from WMCore.Services.DBS.DBSErrors import DBSReaderError
|
|
189
|
+
dbsInst = DBS3Reader(dbsURL)
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
_datasetExists(dbsInst, inputdataset)
|
|
193
|
+
_datasetExists(dbsInst, mcpileup)
|
|
194
|
+
_datasetExists(dbsInst, datapileup)
|
|
195
|
+
except DBSReaderError as ex:
|
|
196
|
+
# we need to Wrap the exception to WMSpecFactoryException to be caught in reqmgr validation
|
|
197
|
+
raise WMSpecFactoryException(str(ex))
|
|
198
|
+
|
|
199
|
+
if includeParents:
|
|
200
|
+
try:
|
|
201
|
+
result = dbsInst.listDatasetParents(inputdataset)
|
|
202
|
+
if len(result) == 0:
|
|
203
|
+
msg = "IncludeParents flag is True but the input dataset %s has no parents" % inputdataset
|
|
204
|
+
raise DBSReaderError(msg)
|
|
205
|
+
except DBSReaderError as ex:
|
|
206
|
+
raise WMSpecFactoryException(str(ex))
|
|
207
|
+
|
|
208
|
+
return
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _datasetExists(dbsInst, inputData):
|
|
212
|
+
"""
|
|
213
|
+
__datasetExists_
|
|
214
|
+
|
|
215
|
+
Check if dataset exists in DBS. Exception is raised in case it does not exist.
|
|
216
|
+
"""
|
|
217
|
+
if inputData is None:
|
|
218
|
+
return
|
|
219
|
+
dbsInst.checkDatasetPath(inputData)
|
|
220
|
+
return
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _getChainKey(arguments, keyName):
|
|
224
|
+
"""
|
|
225
|
+
Given a request arguments dictionary and a key name, properly returns its
|
|
226
|
+
value regardless of the request type.
|
|
227
|
+
"""
|
|
228
|
+
if "TaskChain" in arguments:
|
|
229
|
+
value = arguments['Task1'].get(keyName)
|
|
230
|
+
elif "StepChain" in arguments:
|
|
231
|
+
value = arguments['Step1'].get(keyName)
|
|
232
|
+
else:
|
|
233
|
+
value = arguments.get(keyName)
|
|
234
|
+
return value
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _validateMoveSubscription(subType, sites):
|
|
238
|
+
"""
|
|
239
|
+
Move subscriptions are only allowed to T0 or T1s, see #7760
|
|
240
|
+
"""
|
|
241
|
+
invalidSites = [site for site in sites if re.match("^T[2-3]", site)]
|
|
242
|
+
if invalidSites:
|
|
243
|
+
msg = "Move subscription (%s) not allowed to T2/T3 sites: %s" % (subType, invalidSites)
|
|
244
|
+
raise WMSpecFactoryException(msg)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def validateSiteLists(arguments):
|
|
248
|
+
whiteList = arguments.get("SiteWhitelist", [])
|
|
249
|
+
blackList = arguments.get("SiteBlacklist", [])
|
|
250
|
+
whiteList = makeList(whiteList)
|
|
251
|
+
blackList = makeList(blackList)
|
|
252
|
+
res = (set(whiteList) & set(blackList))
|
|
253
|
+
if len(res):
|
|
254
|
+
msg = "Validation failed: The same site cannot be white and blacklisted: %s" % list(res)
|
|
255
|
+
raise WMSpecFactoryException(msg)
|
|
256
|
+
# store the properly formatted values (list instead of string)
|
|
257
|
+
arguments["SiteWhitelist"] = whiteList
|
|
258
|
+
arguments["SiteBlacklist"] = blackList
|
|
259
|
+
return
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def validateArgumentsCreate(arguments, argumentDefinition, checkInputDset=True):
|
|
263
|
+
"""
|
|
264
|
+
_validateArguments_
|
|
265
|
+
|
|
266
|
+
Validate a set of arguments - for spec creation - against their
|
|
267
|
+
definition in StdBase.getWorkloadCreateArgs.
|
|
268
|
+
|
|
269
|
+
When validating Step/Task dictionary, checkInputDset should be usually
|
|
270
|
+
false since the input dataset validation already happened at top level.
|
|
271
|
+
|
|
272
|
+
It returns an error message if the validation went wrong,
|
|
273
|
+
otherwise returns None.
|
|
274
|
+
"""
|
|
275
|
+
validateUnknownArgs(arguments, argumentDefinition)
|
|
276
|
+
_validateArgumentOptions(arguments, argumentDefinition, "optional")
|
|
277
|
+
if checkInputDset:
|
|
278
|
+
validateInputDatasSetAndParentFlag(arguments)
|
|
279
|
+
return
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def validateArgumentsUpdate(arguments, argumentDefinition, optionKey="assign_optional"):
|
|
283
|
+
"""
|
|
284
|
+
_validateArgumentsUpdate_
|
|
285
|
+
|
|
286
|
+
Validate a set of arguments - for spec assignment/update - against
|
|
287
|
+
their definition in StdBase.getWorkloadAssignArgs.
|
|
288
|
+
|
|
289
|
+
It returns an error message if the validation went wrong,
|
|
290
|
+
otherwise returns None.
|
|
291
|
+
"""
|
|
292
|
+
validateUnknownArgs(arguments, argumentDefinition)
|
|
293
|
+
_validateArgumentOptions(arguments, argumentDefinition, optionKey)
|
|
294
|
+
validateSiteLists(arguments)
|
|
295
|
+
|
|
296
|
+
return
|
|
297
|
+
|
|
298
|
+
def validateUnknownArgs(arguments, argumentDefinition):
|
|
299
|
+
"""
|
|
300
|
+
Make sure user is sending only arguments that are known by
|
|
301
|
+
StdBase.getWorkloadCreateArgs, otherwise fail spec creation.
|
|
302
|
+
|
|
303
|
+
It returns an error message if the validation went wrong,
|
|
304
|
+
otherwise returns None.
|
|
305
|
+
"""
|
|
306
|
+
unknownArgs = set(arguments) - set(argumentDefinition.keys())
|
|
307
|
+
if unknownArgs:
|
|
308
|
+
# now onto the exceptions...
|
|
309
|
+
if arguments.get("RequestType") == "ReReco":
|
|
310
|
+
unknownArgs = unknownArgs - set([x for x in unknownArgs if x.startswith("Skim")])
|
|
311
|
+
elif arguments.get("RequestType") == "StepChain":
|
|
312
|
+
unknownArgs = unknownArgs - set([x for x in unknownArgs if x.startswith("Step")])
|
|
313
|
+
elif arguments.get("RequestType") == "TaskChain":
|
|
314
|
+
unknownArgs = unknownArgs - set([x for x in unknownArgs if x.startswith("Task")])
|
|
315
|
+
elif arguments.get("RequestType") == "Resubmission":
|
|
316
|
+
# oh well, then we have to skip all possible obscure arguments
|
|
317
|
+
unknownArgs = unknownArgs - set([x for x in unknownArgs if x.startswith("Skim")])
|
|
318
|
+
unknownArgs = unknownArgs - set([x for x in unknownArgs if x.startswith("Step")])
|
|
319
|
+
unknownArgs = unknownArgs - set([x for x in unknownArgs if x.startswith("Task")])
|
|
320
|
+
|
|
321
|
+
if unknownArgs:
|
|
322
|
+
msg = "There are unknown/unsupported arguments in your request spec: %s" % list(unknownArgs)
|
|
323
|
+
raise WMSpecFactoryException(msg)
|
|
324
|
+
return
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def setArgumentsWithDefault(arguments, argumentDefinition):
|
|
328
|
+
"""
|
|
329
|
+
Set arguments not provided by the user with a default spec value
|
|
330
|
+
"""
|
|
331
|
+
for argument in argumentDefinition:
|
|
332
|
+
if argument not in arguments:
|
|
333
|
+
arguments[argument] = argumentDefinition[argument]["default"]
|
|
334
|
+
|
|
335
|
+
# set the Campaign default value to the same as AcquisitionEra if Campaign is not specified
|
|
336
|
+
if "Campaign" in argumentDefinition and not arguments.get("Campaign"):
|
|
337
|
+
if "AcquisitionEra" in arguments and isinstance(arguments["AcquisitionEra"], (str, bytes)):
|
|
338
|
+
arguments["Campaign"] = arguments["AcquisitionEra"]
|
|
339
|
+
|
|
340
|
+
return
|
|
341
|
+
|
|
342
|
+
def setAssignArgumentsWithDefault(arguments, argumentDefinition):
|
|
343
|
+
"""
|
|
344
|
+
Set arguments not provided by the user with a default assign spec value,
|
|
345
|
+
unless the default value is None (read don't set default).
|
|
346
|
+
"""
|
|
347
|
+
for argument in argumentDefinition:
|
|
348
|
+
if argument not in arguments and argumentDefinition[argument]["default"] is not None:
|
|
349
|
+
arguments[argument] = argumentDefinition[argument]["default"]
|
|
350
|
+
|
|
351
|
+
return
|
|
352
|
+
|
|
353
|
+
def loadSpecClassByType(specType):
|
|
354
|
+
factoryName = "%sWorkloadFactory" % specType
|
|
355
|
+
mod = __import__("WMCore.WMSpec.StdSpecs.%s" % specType,
|
|
356
|
+
globals(), locals(), [factoryName])
|
|
357
|
+
specClass = getattr(mod, factoryName)
|
|
358
|
+
|
|
359
|
+
return specClass
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def loadSpecByType(specType):
|
|
363
|
+
specClass = loadSpecClassByType(specType)
|
|
364
|
+
return specClass()
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def checkDBSURL(url):
|
|
368
|
+
# import DBS3Reader here, since Runtime code import this module and worker node doesn't have dbs3 client
|
|
369
|
+
from WMCore.Services.DBS.DBS3Reader import DBS3Reader
|
|
370
|
+
return DBS3Reader(url).checkDBSServer()
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Map data to locations for WorkQueue"""
|
|
3
|
+
|
|
4
|
+
from future.utils import viewitems, viewvalues, listvalues
|
|
5
|
+
from builtins import object
|
|
6
|
+
from future import standard_library
|
|
7
|
+
standard_library.install_aliases()
|
|
8
|
+
|
|
9
|
+
from collections import defaultdict
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
from urllib.parse import urlparse
|
|
13
|
+
|
|
14
|
+
from WMCore.Services.DBS.DBSReader import DBSReader
|
|
15
|
+
from WMCore.Services.MSUtils.MSUtils import getPileupDocs
|
|
16
|
+
from WMCore.WorkQueue.DataStructs.ACDCBlock import ACDCBlock
|
|
17
|
+
|
|
18
|
+
# TODO: Combine with existing dls so DBSreader can do this kind of thing transparently
|
|
19
|
+
# TODO: Known Issue: Can't have same item in multiple dbs's at the same time.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def isGlobalDBS(dbs):
|
|
23
|
+
"""
|
|
24
|
+
Receives a DBSReader object and finds out whether it's
|
|
25
|
+
pointing to Global DBS (no matter whether it's production
|
|
26
|
+
or the pre-production instance).
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
url = urlparse(dbs.dbsURL)
|
|
30
|
+
if url.hostname.startswith('cmsweb'):
|
|
31
|
+
if url.path.startswith('/dbs/prod/global') or url.path.startswith('/dbs/int/global'):
|
|
32
|
+
return True
|
|
33
|
+
except Exception as ex:
|
|
34
|
+
logging.error("Failed to find out whether DBS is Global or not. Error: %s", str(ex))
|
|
35
|
+
return False
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def isDataset(inputData):
|
|
39
|
+
"""Check whether we're handling a block or a dataset"""
|
|
40
|
+
if '#' in inputData.split('/')[-1]:
|
|
41
|
+
return False
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class DataLocationMapper(object):
|
|
46
|
+
"""Map data to locations for WorkQueue"""
|
|
47
|
+
|
|
48
|
+
def __init__(self, logger=None, **kwargs):
|
|
49
|
+
self.params = kwargs
|
|
50
|
+
self.logger = logger or logging.getLogger()
|
|
51
|
+
self.params.setdefault('locationFrom', 'subscription')
|
|
52
|
+
self.params.setdefault('incompleteBlocks', False)
|
|
53
|
+
self.params.setdefault('requireBlocksSubscribed', True)
|
|
54
|
+
self.params.setdefault('rucioAccount', "wmcore_transferor")
|
|
55
|
+
self.params.setdefault('rucioAccountPU', "wmcore_pileup")
|
|
56
|
+
|
|
57
|
+
validLocationFrom = ('subscription', 'location')
|
|
58
|
+
if self.params['locationFrom'] not in validLocationFrom:
|
|
59
|
+
msg = "Invalid value for locationFrom: '%s'. Valid values are: %s" % (
|
|
60
|
+
self.params['locationFrom'], validLocationFrom)
|
|
61
|
+
raise ValueError(msg)
|
|
62
|
+
|
|
63
|
+
self.rucio = self.params.get('rucio')
|
|
64
|
+
if self.params.get('cric'):
|
|
65
|
+
self.cric = self.params['cric']
|
|
66
|
+
|
|
67
|
+
# save each DBSReader instance in the class object, such that
|
|
68
|
+
# the same object is not shared amongst multiple threads
|
|
69
|
+
self.dbses = {}
|
|
70
|
+
|
|
71
|
+
def __call__(self, dataItems, rucioAcct=None):
|
|
72
|
+
rucioAcct = rucioAcct or self.params['rucioAccount']
|
|
73
|
+
result = {}
|
|
74
|
+
|
|
75
|
+
dataByDbs = self.organiseByDbs(dataItems)
|
|
76
|
+
|
|
77
|
+
for dbs, dataItems in viewitems(dataByDbs):
|
|
78
|
+
# if global use Rucio, else use dbs
|
|
79
|
+
if "pileup" in rucioAcct:
|
|
80
|
+
output = self.locationsFromMSPileup(dataItems, dbs.dbsURL)
|
|
81
|
+
elif isGlobalDBS(dbs):
|
|
82
|
+
output = self.locationsFromRucio(dataItems, rucioAcct)
|
|
83
|
+
else:
|
|
84
|
+
output = self.locationsFromDBS(dbs, dataItems)
|
|
85
|
+
result[dbs] = output
|
|
86
|
+
|
|
87
|
+
return result
|
|
88
|
+
|
|
89
|
+
def locationsFromRucio(self, dataItems, rucioAcct):
|
|
90
|
+
"""
|
|
91
|
+
Get data location from Rucio. Location is mapped to the actual
|
|
92
|
+
sites associated with them, so PSNs are actually returned
|
|
93
|
+
:param dataItems: list of datasets/blocks names
|
|
94
|
+
:param rucioAcct: string with the Rucio account name to check the rules against
|
|
95
|
+
:return: dictionary key'ed by the dataset/block, with a list of PSNs as value
|
|
96
|
+
"""
|
|
97
|
+
result = defaultdict(set)
|
|
98
|
+
self.logger.info("Fetching location from Rucio for account: %s", rucioAcct)
|
|
99
|
+
for dataItem in dataItems:
|
|
100
|
+
try:
|
|
101
|
+
dataLocations = self.rucio.getDataLockedAndAvailable(name=dataItem,
|
|
102
|
+
account=rucioAcct)
|
|
103
|
+
# resolve the PNNs into PSNs
|
|
104
|
+
result[dataItem] = self.cric.PNNstoPSNs(dataLocations)
|
|
105
|
+
except Exception as ex:
|
|
106
|
+
self.logger.error('Error getting block location from Rucio for %s: %s', dataItem, str(ex))
|
|
107
|
+
|
|
108
|
+
return result
|
|
109
|
+
|
|
110
|
+
def locationsFromDBS(self, dbs, dataItems):
|
|
111
|
+
"""Get data location from dbs"""
|
|
112
|
+
result = defaultdict(set)
|
|
113
|
+
for dataItem in dataItems:
|
|
114
|
+
try:
|
|
115
|
+
if isDataset(dataItem):
|
|
116
|
+
phedexNodeNames = dbs.listDatasetLocation(dataItem)
|
|
117
|
+
else:
|
|
118
|
+
phedexNodeNames = dbs.listFileBlockLocation(dataItem)
|
|
119
|
+
result[dataItem].update(phedexNodeNames)
|
|
120
|
+
except Exception as ex:
|
|
121
|
+
self.logger.error('Error getting block location from dbs for %s: %s', dataItem, str(ex))
|
|
122
|
+
|
|
123
|
+
# convert the sets to lists
|
|
124
|
+
for name, nodes in viewitems(result):
|
|
125
|
+
psns = set()
|
|
126
|
+
psns.update(self.cric.PNNstoPSNs(nodes))
|
|
127
|
+
result[name] = list(psns)
|
|
128
|
+
|
|
129
|
+
return result
|
|
130
|
+
|
|
131
|
+
def locationsFromMSPileup(self, dataItems, dbsUrl):
|
|
132
|
+
"""
|
|
133
|
+
Get data location from MSPileup.
|
|
134
|
+
|
|
135
|
+
:param dataItems: list, list of pileup names to query
|
|
136
|
+
:param dbsUrl: str, dbs url to check which dbs server
|
|
137
|
+
:return: dict, dict of pileup name keys with location set values
|
|
138
|
+
"""
|
|
139
|
+
self.logger.info(f'Fetching locations from MSPileup for {len(dataItems)} containers')
|
|
140
|
+
|
|
141
|
+
result = defaultdict(set)
|
|
142
|
+
# TODO: Fetch multiple pileups in single request
|
|
143
|
+
for dataItem in dataItems:
|
|
144
|
+
try:
|
|
145
|
+
queryDict = {'query': {'pileupName': dataItem},
|
|
146
|
+
'filters': ['currentRSEs', 'pileupName', 'containerFraction', 'ruleIds']}
|
|
147
|
+
pileupInstance = '-testbed' if 'cmsweb-testbed' in dbsUrl else '-prod'
|
|
148
|
+
msPileupUrl = f"https://cmsweb{pileupInstance}.cern.ch/ms-pileup/data/pileup"
|
|
149
|
+
doc = getPileupDocs(msPileupUrl, queryDict, method='POST')[0]
|
|
150
|
+
self.logger.info(f'locationsFromPileup - name: {dataItem}, currentRSEs: {doc["currentRSEs"]}, containerFraction: {doc["containerFraction"]}')
|
|
151
|
+
# resolve PNNs into PSNs
|
|
152
|
+
result[dataItem] = self.cric.PNNstoPSNs(doc['currentRSEs'])
|
|
153
|
+
except IndexError:
|
|
154
|
+
self.logger.error('Did not find any pileup document for query: %s', queryDict['query'])
|
|
155
|
+
except Exception as ex:
|
|
156
|
+
self.logger.error('Error getting block location from MSPileup for %s: %s', dataItem, str(ex))
|
|
157
|
+
|
|
158
|
+
return result
|
|
159
|
+
|
|
160
|
+
def organiseByDbs(self, dataItems):
|
|
161
|
+
"""Sort items by dbs instances - return dict with DBSReader as key & data items as values"""
|
|
162
|
+
itemsByDbs = defaultdict(list)
|
|
163
|
+
for item in dataItems:
|
|
164
|
+
if ACDCBlock.checkBlockName(item['name']):
|
|
165
|
+
# if it is acdc block don't update location. location should be
|
|
166
|
+
# inserted when block is queued and not supposed to change
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
if item['dbs_url'] not in self.dbses:
|
|
170
|
+
self.dbses[item['dbs_url']] = DBSReader(item['dbs_url'])
|
|
171
|
+
itemsByDbs[self.dbses[item['dbs_url']]].append(item['name'])
|
|
172
|
+
|
|
173
|
+
return itemsByDbs
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class WorkQueueDataLocationMapper(DataLocationMapper):
|
|
177
|
+
"""WorkQueue data location functionality"""
|
|
178
|
+
|
|
179
|
+
def __init__(self, logger, backend, **kwargs):
|
|
180
|
+
self.backend = backend
|
|
181
|
+
self.logger = logger
|
|
182
|
+
super(WorkQueueDataLocationMapper, self).__init__(logger, **kwargs)
|
|
183
|
+
|
|
184
|
+
def __call__(self):
|
|
185
|
+
elemUpdated = 0
|
|
186
|
+
elemUpdated += self.updatePrimaryLocation()
|
|
187
|
+
elemUpdated += self.updateParentLocation()
|
|
188
|
+
elemUpdated += self.updatePileupLocation()
|
|
189
|
+
|
|
190
|
+
return elemUpdated
|
|
191
|
+
|
|
192
|
+
def updatePrimaryLocation(self):
|
|
193
|
+
dataItems = self.backend.getActiveData()
|
|
194
|
+
dataLocations = super(WorkQueueDataLocationMapper, self).__call__(dataItems)
|
|
195
|
+
self.logger.info("Found %d unique input data to update location", len(dataItems))
|
|
196
|
+
|
|
197
|
+
# elements with multiple changed data items will fail fix this, or move to store data outside element
|
|
198
|
+
modified = []
|
|
199
|
+
for dataMapping in viewvalues(dataLocations):
|
|
200
|
+
for data, locations in viewitems(dataMapping):
|
|
201
|
+
elements = self.backend.getElementsForData(data)
|
|
202
|
+
for element in elements:
|
|
203
|
+
if element.get('NoInputUpdate', False):
|
|
204
|
+
continue
|
|
205
|
+
if sorted(locations) != sorted(element['Inputs'][data]):
|
|
206
|
+
self.logger.info("%s, setting location to: %s", data, locations)
|
|
207
|
+
element['Inputs'][data] = locations
|
|
208
|
+
modified.append(element)
|
|
209
|
+
self.logger.info("Updating %d elements for Input location update", len(modified))
|
|
210
|
+
self.backend.saveElements(*modified)
|
|
211
|
+
|
|
212
|
+
return len(modified)
|
|
213
|
+
|
|
214
|
+
def updateParentLocation(self):
|
|
215
|
+
dataItems = self.backend.getActiveParentData()
|
|
216
|
+
|
|
217
|
+
# fullResync incorrect with multiple dbs's - fix!!!
|
|
218
|
+
dataLocations = DataLocationMapper.__call__(self, dataItems)
|
|
219
|
+
self.logger.info("Found %d unique parent data to update location", len(dataItems))
|
|
220
|
+
|
|
221
|
+
# Given that there might be multiple data items to be updated
|
|
222
|
+
# handle it like a dict such that element lookup becomes easier
|
|
223
|
+
modified = {}
|
|
224
|
+
for dataMapping in viewvalues(dataLocations):
|
|
225
|
+
for data, locations in viewitems(dataMapping):
|
|
226
|
+
elements = self.backend.getElementsForParentData(data)
|
|
227
|
+
for element in elements:
|
|
228
|
+
if element.get('NoInputUpdate', False):
|
|
229
|
+
continue
|
|
230
|
+
if element.id in modified:
|
|
231
|
+
element = modified[element.id]
|
|
232
|
+
for pData in element['ParentData']:
|
|
233
|
+
if pData == data:
|
|
234
|
+
if sorted(locations) != sorted(element['ParentData'][pData]):
|
|
235
|
+
self.logger.info("%s, setting location to: %s", data, locations)
|
|
236
|
+
element['ParentData'][pData] = locations
|
|
237
|
+
modified[element.id] = element
|
|
238
|
+
break
|
|
239
|
+
self.logger.info("Updating %d elements for Parent location update", len(modified))
|
|
240
|
+
self.backend.saveElements(*listvalues(modified))
|
|
241
|
+
|
|
242
|
+
return len(modified)
|
|
243
|
+
|
|
244
|
+
def updatePileupLocation(self):
|
|
245
|
+
dataItems = self.backend.getActivePileupData()
|
|
246
|
+
|
|
247
|
+
# fullResync incorrect with multiple dbs's - fix!!!
|
|
248
|
+
dataLocations = DataLocationMapper.__call__(self, dataItems, self.params['rucioAccountPU'])
|
|
249
|
+
self.logger.info("Found %d unique pileup data to update location", len(dataItems))
|
|
250
|
+
|
|
251
|
+
# Given that there might be multiple data items to be updated
|
|
252
|
+
# handle it like a dict such that element lookup becomes easier
|
|
253
|
+
modified = {}
|
|
254
|
+
for dataMapping in listvalues(dataLocations):
|
|
255
|
+
for data, locations in viewitems(dataMapping):
|
|
256
|
+
elements = self.backend.getElementsForPileupData(data)
|
|
257
|
+
self.logger.info("Found %d elements using pileup: %s", len(elements), data)
|
|
258
|
+
for element in elements:
|
|
259
|
+
if element.get('NoPileupUpdate', False):
|
|
260
|
+
continue
|
|
261
|
+
if element.id in modified:
|
|
262
|
+
element = modified[element.id]
|
|
263
|
+
for pData in element['PileupData']:
|
|
264
|
+
if pData == data:
|
|
265
|
+
if sorted(locations) != sorted(element['PileupData'][pData]):
|
|
266
|
+
self.logger.info("%s, setting location to: %s", data, locations)
|
|
267
|
+
element['PileupData'][pData] = locations
|
|
268
|
+
modified[element.id] = element
|
|
269
|
+
break
|
|
270
|
+
self.logger.info("Updating %d elements for Pileup location update", len(modified))
|
|
271
|
+
self.backend.saveElements(*listvalues(modified))
|
|
272
|
+
|
|
273
|
+
return len(modified)
|