wmglobalqueue 2.4.5.1__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.
- Utils/CPMetrics.py +270 -0
- Utils/CertTools.py +100 -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/ProcFS.py +112 -0
- Utils/ProcessStats.py +194 -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 +318 -0
- Utils/__init__.py +11 -0
- Utils/wmcoreDTools.py +707 -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 +659 -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 +1430 -0
- WMCore/Database/ConfigDBMap.py +29 -0
- WMCore/Database/CouchMonitoring.py +450 -0
- WMCore/Database/CouchUtils.py +118 -0
- WMCore/Database/DBCore.py +198 -0
- WMCore/Database/DBCreator.py +113 -0
- WMCore/Database/DBExceptionHandler.py +59 -0
- WMCore/Database/DBFactory.py +117 -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 +636 -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 +112 -0
- WMCore/Services/DBS/DBSReader.py +23 -0
- WMCore/Services/DBS/DBSUtils.py +166 -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/__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 +1290 -0
- WMCore/Services/Rucio/RucioUtils.py +74 -0
- WMCore/Services/Rucio/__init__.py +0 -0
- WMCore/Services/RucioConMon/RucioConMon.py +121 -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 +377 -0
- WMCore/WMLogging.py +104 -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 +1997 -0
- WMCore/WMSpec/WMWorkload.py +2288 -0
- WMCore/WMSpec/WMWorkloadTools.py +382 -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.4.5.1.data/data/bin/wmc-dist-patch +15 -0
- wmglobalqueue-2.4.5.1.data/data/bin/wmc-dist-unpatch +8 -0
- wmglobalqueue-2.4.5.1.data/data/bin/wmc-httpd +3 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/.couchapprc +1 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/README.md +40 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/index.html +264 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/js/ElementInfoByWorkflow.js +96 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/js/StuckElementInfo.js +57 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/js/WorkloadInfoTable.js +80 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/js/dataTable.js +70 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/js/namespace.js +23 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/style/main.css +75 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/couchapp.json +4 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/filters/childQueueFilter.js +13 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/filters/filterDeletedDocs.js +3 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/filters/queueFilter.js +11 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/language +1 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lib/mustache.js +333 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lib/validate.js +27 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lib/workqueue_utils.js +61 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lists/elementsDetail.js +28 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lists/filter.js +86 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lists/stuckElements.js +38 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lists/workRestrictions.js +153 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lists/workflowSummary.js +28 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/rewrites.json +73 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/shows/redirect.js +23 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/shows/status.js +40 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/ElementSummaryByWorkflow.html +27 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/StuckElementSummary.html +26 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/TaskStatus.html +23 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/WorkflowSummary.html +27 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/partials/workqueue-common-lib.html +2 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib-remote.html +16 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib.html +18 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/updates/in-place.js +50 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/validate_doc_update.js +8 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.couch.app.js +235 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.pathbinder.js +173 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activeData/map.js +8 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activeData/reduce.js +2 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activeParentData/map.js +8 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activeParentData/reduce.js +2 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activePileupData/map.js +8 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activePileupData/reduce.js +2 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/analyticsData/map.js +11 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/analyticsData/reduce.js +1 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/availableByPriority/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/conflicts/map.js +5 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elements/map.js +5 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByData/map.js +8 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByParent/map.js +8 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByParentData/map.js +8 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByPileupData/map.js +8 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByStatus/map.js +8 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsBySubscription/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/map.js +8 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/reduce.js +3 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsDetailByWorkflowAndStatus/map.js +26 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/map.js +10 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/reduce.js +1 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/reduce.js +1 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/reduce.js +1 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/reduce.js +1 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByRequest/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByRequest/reduce.js +1 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByStatus/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByStatus/reduce.js +1 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/reduce.js +1 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/openRequests/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/recent-items/map.js +5 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/reduce.js +1 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/specsByWorkflow/map.js +5 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/stuckElements/map.js +38 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/map.js +12 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/reduce.js +3 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsUrl/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsUrl/reduce.js +2 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/map.js +6 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/reduce.js +2 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/workflowSummary/map.js +9 -0
- wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/workflowSummary/reduce.js +10 -0
- wmglobalqueue-2.4.5.1.dist-info/METADATA +26 -0
- wmglobalqueue-2.4.5.1.dist-info/RECORD +347 -0
- wmglobalqueue-2.4.5.1.dist-info/WHEEL +5 -0
- wmglobalqueue-2.4.5.1.dist-info/licenses/LICENSE +202 -0
- wmglobalqueue-2.4.5.1.dist-info/licenses/NOTICE +16 -0
- wmglobalqueue-2.4.5.1.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Set of rules and functions
|
|
3
|
+
Handling resubmission Block construction
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from builtins import object
|
|
7
|
+
|
|
8
|
+
ACDC_PREFIX = "acdc"
|
|
9
|
+
|
|
10
|
+
class ACDCBlock(object):
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def name(wmspecName, taskName, offset, numOfFile):
|
|
14
|
+
taskName = taskName.replace('/', ':')
|
|
15
|
+
return "/%s/%s/%s/%s/%s" % (ACDC_PREFIX, wmspecName, taskName, offset,
|
|
16
|
+
numOfFile)
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def checkBlockName(blockName):
|
|
20
|
+
if blockName.split('/')[1] == ACDC_PREFIX:
|
|
21
|
+
return True
|
|
22
|
+
else:
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def splitBlockName(blockName):
|
|
27
|
+
""" return False if the blockName is not acdc Block
|
|
28
|
+
return original elements of block name in order as a dict
|
|
29
|
+
{'SpecName': blockSplit[1],
|
|
30
|
+
'TaskName': blockSplit[2],
|
|
31
|
+
'Offset': int(blockSplit[3]),
|
|
32
|
+
'NumOfFiles': int(blockSplit[4])},
|
|
33
|
+
if it is acdc Block
|
|
34
|
+
raise ValueError if the block is has wrong format
|
|
35
|
+
"""
|
|
36
|
+
blockSplit = blockName.split('/')
|
|
37
|
+
if blockSplit[1] != ACDC_PREFIX:
|
|
38
|
+
return False
|
|
39
|
+
elif len(blockSplit) != 6:
|
|
40
|
+
msg = """blockName should contain prefix, wmspec name, task name,
|
|
41
|
+
offset and number of files %s""" % blockName
|
|
42
|
+
raise ValueError(msg)
|
|
43
|
+
else:
|
|
44
|
+
return {'SpecName': str(blockSplit[2]),
|
|
45
|
+
'TaskName': str(blockSplit[3]).replace(':', '/'),
|
|
46
|
+
'Offset': int(blockSplit[4]),
|
|
47
|
+
'NumOfFiles': int(blockSplit[5])}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
_Block_
|
|
3
|
+
|
|
4
|
+
A dictionary based object meant to represent a row in the active_block/block table.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Block(dict):
|
|
11
|
+
"""
|
|
12
|
+
_Block_
|
|
13
|
+
|
|
14
|
+
A dictionary based object meant to represent subset of dbs block.
|
|
15
|
+
Which will just need for workQueue update.
|
|
16
|
+
It contains the following keys:
|
|
17
|
+
Name
|
|
18
|
+
Size
|
|
19
|
+
NumEvent
|
|
20
|
+
NumFiles
|
|
21
|
+
"""
|
|
22
|
+
def __init__(self, **args):
|
|
23
|
+
"""
|
|
24
|
+
___init___
|
|
25
|
+
|
|
26
|
+
Initialize all attributes.
|
|
27
|
+
"""
|
|
28
|
+
dict.__init__(self)
|
|
29
|
+
|
|
30
|
+
self.setdefault("Name", None)
|
|
31
|
+
self.setdefault("Size", None)
|
|
32
|
+
self.setdefault("NumEvents", None)
|
|
33
|
+
self.setdefault("NumFiles", None)
|
|
34
|
+
self.update(args)
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def getBlock(blockInfo):
|
|
38
|
+
"""
|
|
39
|
+
convert to the Block structure from db column format
|
|
40
|
+
"""
|
|
41
|
+
block = Block()
|
|
42
|
+
|
|
43
|
+
block["Name"] = blockInfo[0]["name"]
|
|
44
|
+
block["NumFiles"] = blockInfo[0]["num_files"]
|
|
45
|
+
block["NumEvents"] = blockInfo[0]["num_events"]
|
|
46
|
+
block["Size"] = blockInfo[0]["block_size"]
|
|
47
|
+
|
|
48
|
+
return block
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
"""
|
|
4
|
+
CouchWorkQueueElement.py
|
|
5
|
+
|
|
6
|
+
Created by Dave Evans on 2010-10-12.
|
|
7
|
+
Copyright (c) 2010 Fermilab. All rights reserved.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from future.utils import viewitems
|
|
11
|
+
|
|
12
|
+
import unittest
|
|
13
|
+
import time
|
|
14
|
+
import logging
|
|
15
|
+
|
|
16
|
+
from WMCore.Database.CMSCouch import Document
|
|
17
|
+
from WMCore.WorkQueue.DataStructs.WorkQueueElement import WorkQueueElement
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CouchWorkQueueElement(WorkQueueElement):
|
|
22
|
+
"""
|
|
23
|
+
_CouchWorkQueueElement_
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, couchDB, id = None, elementParams = None):
|
|
27
|
+
elementParams = elementParams or {}
|
|
28
|
+
WorkQueueElement.__init__(self, **elementParams)
|
|
29
|
+
if id:
|
|
30
|
+
self._id = id
|
|
31
|
+
self._document = Document(id = id)
|
|
32
|
+
self._couch = couchDB
|
|
33
|
+
|
|
34
|
+
rev = property(
|
|
35
|
+
lambda x: str(x._document[u'_rev']) if u'_rev' in x._document else x._document.__getitem__('_rev'),
|
|
36
|
+
lambda x, newid: x._document.__setitem__('_rev', newid))
|
|
37
|
+
timestamp = property(
|
|
38
|
+
lambda x: str(x._document[u'timestamp']) if u'timestamp' in x._document else x._document.__getitem__('timestamp')
|
|
39
|
+
)
|
|
40
|
+
updatetime = property(
|
|
41
|
+
lambda x: str(x._document[u'updatetime']) if u'updatetime' in x._document else 0
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def fromDocument(cls, couchDB, doc):
|
|
47
|
+
"""Create element from couch document"""
|
|
48
|
+
elementParams = doc.pop('WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement')
|
|
49
|
+
elementParams["CreationTime"] = doc.pop('timestamp')
|
|
50
|
+
element = CouchWorkQueueElement(couchDB = couchDB,
|
|
51
|
+
id = doc['_id'],
|
|
52
|
+
elementParams = elementParams)
|
|
53
|
+
element._document['_rev'] = doc.pop('_rev')
|
|
54
|
+
element._document['timestamp'] = elementParams["CreationTime"]
|
|
55
|
+
element._document['updatetime'] = doc.pop('updatetime')
|
|
56
|
+
return element
|
|
57
|
+
|
|
58
|
+
def save(self):
|
|
59
|
+
"""
|
|
60
|
+
_save
|
|
61
|
+
"""
|
|
62
|
+
self.populateDocument()
|
|
63
|
+
self._couch.queue(self._document)
|
|
64
|
+
|
|
65
|
+
def load(self):
|
|
66
|
+
"""
|
|
67
|
+
_load_
|
|
68
|
+
|
|
69
|
+
Load the document representing this WQE
|
|
70
|
+
"""
|
|
71
|
+
document = self._couch.document(self._document['_id'])
|
|
72
|
+
self.update(document.pop('WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement'))
|
|
73
|
+
self._document['_rev'] = document.pop('_rev')
|
|
74
|
+
self._document['timestamp'] = document.pop('timestamp', None)
|
|
75
|
+
self._document['updatetime'] = document.pop('updatetime', None)
|
|
76
|
+
return self
|
|
77
|
+
|
|
78
|
+
def delete(self):
|
|
79
|
+
"""Delete element"""
|
|
80
|
+
self.populateDocument()
|
|
81
|
+
self._document.delete()
|
|
82
|
+
self._couch.queue(self._document)
|
|
83
|
+
|
|
84
|
+
def populateDocument(self):
|
|
85
|
+
"""Certain attributed shouldn't be stored"""
|
|
86
|
+
self._document.update(self.__to_json__(None))
|
|
87
|
+
now = time.time()
|
|
88
|
+
self._document['updatetime'] = now
|
|
89
|
+
self._document.setdefault('timestamp', now)
|
|
90
|
+
if not self._document.get('_id') and self.id:
|
|
91
|
+
self._document['_id'] = self.id
|
|
92
|
+
attrs = ['WMSpec', 'Task']
|
|
93
|
+
for attr in attrs:
|
|
94
|
+
self._document['WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement'].pop(attr, None)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def fixElementConflicts(*elements):
|
|
99
|
+
"""Take conflicting elements, fix conflicts and return
|
|
100
|
+
First element returned will contain the merged results,
|
|
101
|
+
the others will be losing revisions
|
|
102
|
+
"""
|
|
103
|
+
ordered_states = ['Available', 'Negotiating', 'Acquired', 'Running',
|
|
104
|
+
'Done', 'Failed', 'CancelRequested', 'Canceled']
|
|
105
|
+
allowed_keys = ['Status', 'EventsWritten', 'FilesProcessed',
|
|
106
|
+
'PercentComplete', 'PercentSuccess', 'Inputs', 'NumOfFilesAdded',
|
|
107
|
+
'SubscriptionId', 'Priority', 'SiteWhitelist', 'SiteBlacklist']
|
|
108
|
+
merged_value = None
|
|
109
|
+
updated = set()
|
|
110
|
+
for ele in elements:
|
|
111
|
+
if not merged_value: # 1st will contain merged result and become winner
|
|
112
|
+
merged_value = ele
|
|
113
|
+
continue
|
|
114
|
+
|
|
115
|
+
# print differences
|
|
116
|
+
from WMCore.Algorithms.MiscAlgos import dict_diff
|
|
117
|
+
logging.info("Conflict between %s revs %s & %s: %s",
|
|
118
|
+
ele.id, merged_value.rev, ele.rev,
|
|
119
|
+
"; ".join("%s=%s" % (x,y) for x,y in viewitems(dict_diff(merged_value, ele)))
|
|
120
|
+
)
|
|
121
|
+
for key in merged_value:
|
|
122
|
+
if merged_value[key] == ele.get(key):
|
|
123
|
+
continue
|
|
124
|
+
# we need to merge: Take elements from both that seem most advanced, e.g. status & progress stats
|
|
125
|
+
if key not in allowed_keys:
|
|
126
|
+
msg = 'Unable to merge conflicting element %s: field "%s" value 1 "%s" value2 "%s"'
|
|
127
|
+
raise RuntimeError(msg % (ele.id, key, merged_value.get(key), ele.get(key)))
|
|
128
|
+
elif key == 'Status':
|
|
129
|
+
if ordered_states.index(ele[key]) > ordered_states.index(merged_value[key]):
|
|
130
|
+
merged_value[key] = ele[key]
|
|
131
|
+
elif key == 'Inputs':
|
|
132
|
+
for item in merged_value[key]:
|
|
133
|
+
# take larger locations list
|
|
134
|
+
if merged_value[key][item] < ele[key].get(item, []):
|
|
135
|
+
merged_value[key][item] = ele[key][item]
|
|
136
|
+
elif ele[key] is not None and ele[key] > merged_value[key]:
|
|
137
|
+
merged_value[key] = ele[key]
|
|
138
|
+
updated.add(key)
|
|
139
|
+
# once losing element has been merged - queue for deletion
|
|
140
|
+
ele._document.delete()
|
|
141
|
+
|
|
142
|
+
msg = 'Resolving conflict for wf "%s", id "%s": Remove rev(s): %s: Updates: (%s)'
|
|
143
|
+
logging.info(msg, str(merged_value['RequestName']),
|
|
144
|
+
str(merged_value.id),
|
|
145
|
+
", ".join([x._document['_rev'] for x in elements[1:]]),
|
|
146
|
+
"; ".join("%s=%s" % (x, merged_value[x]) for x in updated)
|
|
147
|
+
)
|
|
148
|
+
return elements
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
"""
|
|
2
|
+
WorkQueueElement
|
|
3
|
+
|
|
4
|
+
A dictionary based object meant to represent a WorkQueue element
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from future.utils import viewitems, viewvalues
|
|
8
|
+
import time
|
|
9
|
+
from hashlib import md5
|
|
10
|
+
|
|
11
|
+
from Utils.Utilities import encodeUnicodeToBytesConditional
|
|
12
|
+
from Utils.PythonVersion import PY3
|
|
13
|
+
|
|
14
|
+
STATES = ('Available', 'Negotiating', 'Acquired', 'Running',
|
|
15
|
+
'Done', 'Failed', 'CancelRequested', 'Canceled')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def possibleSites(element):
|
|
19
|
+
"""
|
|
20
|
+
_possibleSites_
|
|
21
|
+
|
|
22
|
+
Checks the site and data restrictions and return a list of possible sites
|
|
23
|
+
to work on this element.
|
|
24
|
+
"""
|
|
25
|
+
# check if the whole document was provide
|
|
26
|
+
elem = element.get('WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement', element)
|
|
27
|
+
|
|
28
|
+
if elem['NoInputUpdate'] and elem['NoPileupUpdate']:
|
|
29
|
+
return elem['SiteWhitelist']
|
|
30
|
+
|
|
31
|
+
commonSites = set(elem['SiteWhitelist']) - set(elem['SiteBlacklist'])
|
|
32
|
+
|
|
33
|
+
if elem['Inputs'] and elem['NoInputUpdate'] is False:
|
|
34
|
+
commonSites = commonSites.intersection(set([y for x in viewvalues(elem['Inputs']) for y in x]))
|
|
35
|
+
if elem['ParentFlag'] and elem['NoInputUpdate'] is False:
|
|
36
|
+
commonSites = commonSites.intersection(set([y for x in viewvalues(elem['ParentData']) for y in x]))
|
|
37
|
+
if elem['PileupData'] and elem['NoPileupUpdate'] is False:
|
|
38
|
+
commonSites = commonSites.intersection(set([y for x in viewvalues(elem['PileupData']) for y in x]))
|
|
39
|
+
|
|
40
|
+
return list(commonSites)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class WorkQueueElement(dict):
|
|
44
|
+
"""Class to represent a WorkQueue element"""
|
|
45
|
+
|
|
46
|
+
def __init__(self, **kwargs):
|
|
47
|
+
dict.__init__(self)
|
|
48
|
+
|
|
49
|
+
if 'Status' in kwargs and kwargs['Status'] not in STATES:
|
|
50
|
+
msg = 'Invalid Status: %s' % kwargs['Status']
|
|
51
|
+
raise ValueError(msg)
|
|
52
|
+
|
|
53
|
+
self.update(kwargs)
|
|
54
|
+
|
|
55
|
+
self._id = None
|
|
56
|
+
|
|
57
|
+
# XXX If adding or modifying any new parameter which affects the
|
|
58
|
+
# XXX workflow or data run over, the id function must be updated
|
|
59
|
+
|
|
60
|
+
self.setdefault('Inputs', {})
|
|
61
|
+
self.setdefault('ProcessedInputs', [])
|
|
62
|
+
self.setdefault('RejectedInputs', [])
|
|
63
|
+
# Some workflows require additional datasets for PileUp
|
|
64
|
+
# Track their locations
|
|
65
|
+
self.setdefault('PileupData', {})
|
|
66
|
+
# both ParentData and ParentFlag is needed in case there Dataset split,
|
|
67
|
+
# even though ParentFlag is True it will have empty ParentData
|
|
68
|
+
self.setdefault('ParentData', {})
|
|
69
|
+
self.setdefault('ParentFlag', False)
|
|
70
|
+
# 0 jobs are valid where we need to accept all blocks (only dqm etc subscriptions will run)
|
|
71
|
+
self.setdefault('Jobs', 0)
|
|
72
|
+
self.setdefault('WMSpec', None)
|
|
73
|
+
self.setdefault('SiteWhitelist', [])
|
|
74
|
+
self.setdefault('SiteBlacklist', [])
|
|
75
|
+
self.setdefault('Dbs', None)
|
|
76
|
+
self.setdefault('Task', None)
|
|
77
|
+
self.setdefault('ParentQueueId', None)
|
|
78
|
+
self.setdefault('Priority', 0)
|
|
79
|
+
self.setdefault('SubscriptionId', None)
|
|
80
|
+
self.setdefault('Status', None)
|
|
81
|
+
self.setdefault('EventsWritten', 0)
|
|
82
|
+
self.setdefault('FilesProcessed', 0)
|
|
83
|
+
self.setdefault('PercentComplete', 0)
|
|
84
|
+
self.setdefault('PercentSuccess', 0)
|
|
85
|
+
self.setdefault('RequestName', None)
|
|
86
|
+
self.setdefault('TaskName', None)
|
|
87
|
+
self.setdefault('TeamName', None)
|
|
88
|
+
self.setdefault('StartPolicy', {})
|
|
89
|
+
self.setdefault('EndPolicy', {})
|
|
90
|
+
self.setdefault('ACDC', {})
|
|
91
|
+
self.setdefault('ChildQueueUrl', None)
|
|
92
|
+
self.setdefault('ParentQueueUrl', None)
|
|
93
|
+
self.setdefault('WMBSUrl', None)
|
|
94
|
+
self.setdefault('NumberOfLumis', 0)
|
|
95
|
+
self.setdefault('NumberOfEvents', 0)
|
|
96
|
+
self.setdefault('NumberOfFiles', 0)
|
|
97
|
+
# Number of files added to WMBS including parent files for this element. used only for monitoring purpose
|
|
98
|
+
self.setdefault('NumOfFilesAdded', 0)
|
|
99
|
+
# Mask used to constrain MC run/lumi ranges
|
|
100
|
+
self.setdefault('Mask', None)
|
|
101
|
+
# is new data being added to the workflow (e.g., growing input datasets)
|
|
102
|
+
self.setdefault('OpenForNewData', False)
|
|
103
|
+
# EPOCH time for when the last block was found and added to the workflow
|
|
104
|
+
self.setdefault('TimestampFoundNewData', int(time.time()))
|
|
105
|
+
# Trust initial input dataset location only or not
|
|
106
|
+
self.setdefault('NoInputUpdate', False)
|
|
107
|
+
# Trust initial pileup dataset location only or not
|
|
108
|
+
self.setdefault('NoPileupUpdate', False)
|
|
109
|
+
# EPOCH time with the creation time for this wq element, needed for sorting
|
|
110
|
+
self.setdefault('CreationTime', int(time.time()))
|
|
111
|
+
# set to true when updated from a WorkQueueElementResult
|
|
112
|
+
self.modified = False
|
|
113
|
+
|
|
114
|
+
def __to_json__(self, thunker):
|
|
115
|
+
"""Strip unthunkable"""
|
|
116
|
+
# result = WorkQueueElement(thunker_encoded_json = True,
|
|
117
|
+
result = dict(thunker_encoded_json=True,
|
|
118
|
+
type='WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement')
|
|
119
|
+
result['WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement'] = {}
|
|
120
|
+
result['WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement'].update(self)
|
|
121
|
+
# Do we need this 'Subscription' or can we not store this at all?
|
|
122
|
+
result['WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement'].pop('Subscription', None)
|
|
123
|
+
result['WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement'].pop('WMSpec', None)
|
|
124
|
+
# if self.get('Id'):
|
|
125
|
+
# result['_id'] = result['WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement'].pop('Id')
|
|
126
|
+
# if self.get('_rev'):
|
|
127
|
+
# result['_rev'] = result['WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement'].pop('_rev')
|
|
128
|
+
# result['Mask'] = thunker._thunk(result['Mask'])
|
|
129
|
+
return result
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def id(self):
|
|
133
|
+
"""Generate id for element
|
|
134
|
+
|
|
135
|
+
id is deterministic and can be used to identify duplicate elements.
|
|
136
|
+
Calculation only includes fields which affect the workflow and input data.
|
|
137
|
+
Result is an md5 hash of a ';' separated list of:
|
|
138
|
+
workflow name, task name, list of inputs, mask, ACDC info, Dbs instance.
|
|
139
|
+
|
|
140
|
+
Parent file info not accounted.
|
|
141
|
+
|
|
142
|
+
Example:
|
|
143
|
+
>>> WorkQueueElement(RequestName = 'a', TaskName = 'b').id
|
|
144
|
+
'9ef03a6ad8f16d74fb5ba44df92bf1ef'
|
|
145
|
+
|
|
146
|
+
Warning: Any change to this function may prevent identical existing and
|
|
147
|
+
new elements from appearing equivalent, thus in the case of expanding
|
|
148
|
+
work subscriptions work duplication can occur. Care must be taken
|
|
149
|
+
if any modification is made.
|
|
150
|
+
"""
|
|
151
|
+
if self._id:
|
|
152
|
+
return self._id
|
|
153
|
+
# Assume md5 is good enough for now
|
|
154
|
+
myhash = md5()
|
|
155
|
+
spacer = ';' # character not present in any field
|
|
156
|
+
myhash.update(encodeUnicodeToBytesConditional(self['RequestName'] + spacer, condition=PY3))
|
|
157
|
+
# Task will be None in global inbox
|
|
158
|
+
myhash.update(encodeUnicodeToBytesConditional(repr(self['TaskName']) + spacer, condition=PY3))
|
|
159
|
+
myhash.update(encodeUnicodeToBytesConditional(",".join(sorted(self['Inputs'].keys())) + spacer, condition=PY3))
|
|
160
|
+
# Check repr is reproducible - should be
|
|
161
|
+
if self['Mask']:
|
|
162
|
+
myhash.update(encodeUnicodeToBytesConditional(",".join(["%s=%s" % (x, y) for x, y in viewitems(self['Mask'])]) + spacer, condition=PY3))
|
|
163
|
+
else:
|
|
164
|
+
myhash.update(encodeUnicodeToBytesConditional("None" + spacer, condition=PY3))
|
|
165
|
+
# Check ACDC is deterministic and all params relevant
|
|
166
|
+
myhash.update(encodeUnicodeToBytesConditional(",".join(["%s=%s" % (x, y) for x, y in viewitems(self['ACDC'])]) + spacer, condition=PY3))
|
|
167
|
+
myhash.update(encodeUnicodeToBytesConditional(repr(self['Dbs']) + spacer, condition=PY3))
|
|
168
|
+
self._id = myhash.hexdigest()
|
|
169
|
+
return self._id
|
|
170
|
+
|
|
171
|
+
@id.setter
|
|
172
|
+
def id(self, value):
|
|
173
|
+
"""Set id - use to override built-in id calculation"""
|
|
174
|
+
self._id = value
|
|
175
|
+
|
|
176
|
+
def __from_json__(self, jsondata, thunker):
|
|
177
|
+
""""""
|
|
178
|
+
self.update(jsondata)
|
|
179
|
+
return self
|
|
180
|
+
|
|
181
|
+
# self.update(jsondata['WMCore.WorkQueue.DataStructs.WorkQueueElement.WorkQueueElement'])
|
|
182
|
+
# self.pop('type', None)
|
|
183
|
+
# self.pop('thunker_encoded_json', None)
|
|
184
|
+
## self['Id'] = jsondata['_id']
|
|
185
|
+
# self['_rev'] = jsondata['_rev'] # what to do here???
|
|
186
|
+
# return self
|
|
187
|
+
|
|
188
|
+
def inEndState(self):
|
|
189
|
+
"""Have we finished processing"""
|
|
190
|
+
return self.isComplete() or self.isFailed() or self.isCanceled()
|
|
191
|
+
|
|
192
|
+
def isComplete(self):
|
|
193
|
+
return self['Status'] == 'Done'
|
|
194
|
+
|
|
195
|
+
def isFailed(self):
|
|
196
|
+
return self['Status'] == 'Failed'
|
|
197
|
+
|
|
198
|
+
def isRunning(self):
|
|
199
|
+
return self['Status'] == 'Running'
|
|
200
|
+
|
|
201
|
+
def isAcquired(self):
|
|
202
|
+
return self['Status'] == 'Acquired'
|
|
203
|
+
|
|
204
|
+
def isAvailable(self):
|
|
205
|
+
return self['Status'] == 'Available'
|
|
206
|
+
|
|
207
|
+
def isCanceled(self):
|
|
208
|
+
return self['Status'] == 'Canceled'
|
|
209
|
+
|
|
210
|
+
def isCancelRequested(self):
|
|
211
|
+
return self['Status'] == 'CancelRequested'
|
|
212
|
+
|
|
213
|
+
def updateFromSubscription(self, wmbsStatus):
|
|
214
|
+
"""Get subscription status"""
|
|
215
|
+
mapping = {'EventsWritten': 'events_written',
|
|
216
|
+
'FilesProcessed': 'files_processed',
|
|
217
|
+
'PercentComplete': 'percent_complete',
|
|
218
|
+
'PercentSuccess': 'percent_success'}
|
|
219
|
+
for ourkey, wmbskey in viewitems(mapping):
|
|
220
|
+
if wmbskey in wmbsStatus and self[ourkey] != wmbsStatus[wmbskey]:
|
|
221
|
+
self['Modified'] = True
|
|
222
|
+
self[ourkey] = wmbsStatus[wmbskey]
|
|
223
|
+
|
|
224
|
+
def updateWithResult(self, progressReport):
|
|
225
|
+
"""Take a progress report and update ourself
|
|
226
|
+
Return True if progress updated"""
|
|
227
|
+
progressValues = ('Status', 'EventsWritten', 'FilesProcessed',
|
|
228
|
+
'PercentComplete', 'PercentSuccess')
|
|
229
|
+
modified = False
|
|
230
|
+
for val in progressValues:
|
|
231
|
+
# ignore if values the same
|
|
232
|
+
if self[val] == progressReport[val]:
|
|
233
|
+
continue
|
|
234
|
+
# ignore new state if it is lower than the current state
|
|
235
|
+
if val == 'Status' and self[val] and STATES.index(progressReport[val]) <= STATES.index(self[val]):
|
|
236
|
+
continue
|
|
237
|
+
|
|
238
|
+
self[val] = progressReport[val]
|
|
239
|
+
modified = True
|
|
240
|
+
self.modified = modified
|
|
241
|
+
|
|
242
|
+
def statusMetrics(self):
|
|
243
|
+
"""Returns the status & performance metrics"""
|
|
244
|
+
return dict(Status=self['Status'],
|
|
245
|
+
PercentComplete=self['PercentComplete'],
|
|
246
|
+
PercentSuccess=self['PercentSuccess'])
|
|
247
|
+
|
|
248
|
+
def passesSiteRestriction(self, site):
|
|
249
|
+
"""
|
|
250
|
+
_passesSiteRestriction_
|
|
251
|
+
|
|
252
|
+
Given a site name, checks whether it passes the site and data restrictions.
|
|
253
|
+
"""
|
|
254
|
+
# Site list restrictions
|
|
255
|
+
if site in self['SiteBlacklist'] or site not in self['SiteWhitelist']:
|
|
256
|
+
return False
|
|
257
|
+
|
|
258
|
+
# input data restrictions (TrustSitelists flag)
|
|
259
|
+
if self['NoInputUpdate'] is False:
|
|
260
|
+
for locations in viewvalues(self['Inputs']):
|
|
261
|
+
if site not in locations:
|
|
262
|
+
return False
|
|
263
|
+
if self['ParentFlag']:
|
|
264
|
+
for locations in viewvalues(self['ParentData']):
|
|
265
|
+
if site not in locations:
|
|
266
|
+
return False
|
|
267
|
+
|
|
268
|
+
# pileup data restrictions (TrustPUSitelists flag)
|
|
269
|
+
if self['NoPileupUpdate'] is False:
|
|
270
|
+
for locations in viewvalues(self['PileupData']):
|
|
271
|
+
if site not in locations:
|
|
272
|
+
return False
|
|
273
|
+
|
|
274
|
+
return True
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""
|
|
2
|
+
WorkQueueElementResult
|
|
3
|
+
|
|
4
|
+
A dictionary based object meant to represent a WorkQueue block
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import division
|
|
7
|
+
|
|
8
|
+
#Can we re-use WorkQueueElement for this?
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class WorkQueueElementResult(dict):
|
|
14
|
+
"""Class to hold the status of a related group of WorkQueueElements"""
|
|
15
|
+
def __init__(self, **kwargs):
|
|
16
|
+
dict.__init__(self)
|
|
17
|
+
self.update(kwargs)
|
|
18
|
+
|
|
19
|
+
self.setdefault('WMSpec', None)
|
|
20
|
+
self.setdefault('Elements', [])
|
|
21
|
+
self.setdefault('Status', self.status())
|
|
22
|
+
if self['Elements']:
|
|
23
|
+
self.setdefault('EventsWritten',
|
|
24
|
+
sum([x['EventsWritten'] for x in self['Elements']]))
|
|
25
|
+
self.setdefault('FilesProcessed',
|
|
26
|
+
sum([x['FilesProcessed'] for x in self['Elements']]))
|
|
27
|
+
self.setdefault('Jobs', sum([x['Jobs'] for x in self['Elements']]))
|
|
28
|
+
self.setdefault('PercentComplete',
|
|
29
|
+
int(sum([x['PercentComplete'] for x in self['Elements']],
|
|
30
|
+
0.0) / len(self['Elements'])))
|
|
31
|
+
self.setdefault('PercentSuccess',
|
|
32
|
+
int(sum([x['PercentSuccess'] for x in self['Elements']],
|
|
33
|
+
0.0) / len(self['Elements'])))
|
|
34
|
+
self.setdefault('RequestName', self['Elements'][0]['RequestName'])
|
|
35
|
+
self.setdefault('TeamName', self['Elements'][0]['TeamName'])
|
|
36
|
+
self.setdefault('Priority', self['Elements'][0]['Priority'])
|
|
37
|
+
self.setdefault('ParentQueueId', self['Elements'][0]['ParentQueueId'])
|
|
38
|
+
elif self.get('ParentQueueElement'):
|
|
39
|
+
self.setdefault('EventsWritten', self['ParentQueueElement']['EventsWritten'])
|
|
40
|
+
self.setdefault('FilesProcessed', self['ParentQueueElement']['FilesProcessed'])
|
|
41
|
+
self.setdefault('Jobs', self['ParentQueueElement']['Jobs'])
|
|
42
|
+
self.setdefault('PercentComplete', self['ParentQueueElement']['PercentComplete'])
|
|
43
|
+
self.setdefault('PercentSuccess', self['ParentQueueElement']['PercentSuccess'])
|
|
44
|
+
self.setdefault('RequestName', self['ParentQueueElement']['RequestName'])
|
|
45
|
+
self.setdefault('TeamName', self['ParentQueueElement']['TeamName'])
|
|
46
|
+
self.setdefault('Priority', self['ParentQueueElement']['Priority'])
|
|
47
|
+
self.setdefault('ParentQueueId', self['ParentQueueElement'].id)
|
|
48
|
+
else:
|
|
49
|
+
raise RuntimeError("Can create WQEResult: No elements or parent provided")
|
|
50
|
+
|
|
51
|
+
# some cross checks
|
|
52
|
+
for i in self['Elements']:
|
|
53
|
+
assert(i['RequestName'] == self['RequestName'])
|
|
54
|
+
assert(i['TeamName'] == self['TeamName'])
|
|
55
|
+
|
|
56
|
+
def fractionComplete(self):
|
|
57
|
+
"""Return fraction successful"""
|
|
58
|
+
return len(self.completeItems()) / float(len(self['Elements']))
|
|
59
|
+
|
|
60
|
+
def completeItems(self):
|
|
61
|
+
"""Return complete items"""
|
|
62
|
+
return [x for x in self['Elements'] if x.isComplete()]
|
|
63
|
+
|
|
64
|
+
def failedItems(self):
|
|
65
|
+
"""Return failed items"""
|
|
66
|
+
return [x for x in self['Elements'] if x.isFailed()]
|
|
67
|
+
|
|
68
|
+
def runningItems(self):
|
|
69
|
+
"""Return acquired items"""
|
|
70
|
+
return [x for x in self['Elements'] if x.isRunning()]
|
|
71
|
+
|
|
72
|
+
def acquiredItems(self):
|
|
73
|
+
"""Return available items"""
|
|
74
|
+
return [x for x in self['Elements'] if x.isAcquired()]
|
|
75
|
+
|
|
76
|
+
def availableItems(self):
|
|
77
|
+
"""Return available items"""
|
|
78
|
+
return [x for x in self['Elements'] if x.isAvailable()]
|
|
79
|
+
|
|
80
|
+
def canceledItems(self):
|
|
81
|
+
"""Return canceled items"""
|
|
82
|
+
return [x for x in self['Elements'] if x.isCanceled()]
|
|
83
|
+
|
|
84
|
+
def cancelRequestedItems(self):
|
|
85
|
+
"""Return CancelRequested Items"""
|
|
86
|
+
return [x for x in self['Elements'] if x.isCancelRequested()]
|
|
87
|
+
|
|
88
|
+
def status(self):
|
|
89
|
+
"""Compute status of elements"""
|
|
90
|
+
if not self['Elements'] and self.get('ParentQueueElement'):
|
|
91
|
+
return self['ParentQueueElement']['Status']
|
|
92
|
+
elif not self['Elements']:
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
if not self.inEndState():
|
|
96
|
+
if self.cancelRequestedItems():
|
|
97
|
+
return 'CancelRequested'
|
|
98
|
+
elif self.runningItems():
|
|
99
|
+
return 'Running'
|
|
100
|
+
elif self.acquiredItems() or self.availableItems():
|
|
101
|
+
# available in local queue is acquired to parent
|
|
102
|
+
return 'Acquired'
|
|
103
|
+
else:
|
|
104
|
+
if self.canceledItems():
|
|
105
|
+
return "Canceled"
|
|
106
|
+
elif self.failedItems():
|
|
107
|
+
return "Failed"
|
|
108
|
+
|
|
109
|
+
# if all elements have same status take that
|
|
110
|
+
status = self['Elements'][0]['Status']
|
|
111
|
+
for element in self['Elements']:
|
|
112
|
+
if element['Status'] != status:
|
|
113
|
+
msg = "Unable to compute overall status of elements: %s"
|
|
114
|
+
raise RuntimeError(msg % str(self['Elements']))
|
|
115
|
+
return status
|
|
116
|
+
|
|
117
|
+
def inEndState(self):
|
|
118
|
+
"""Are all requests complete (either success or failure)"""
|
|
119
|
+
if 'Status' in self:
|
|
120
|
+
return self['Status'] in ('Done', 'Failed', 'Canceled')
|
|
121
|
+
for element in self['Elements']:
|
|
122
|
+
if not element.inEndState():
|
|
123
|
+
return False
|
|
124
|
+
return True
|
|
125
|
+
|
|
126
|
+
def statusMetrics(self):
|
|
127
|
+
"""Returns the status & performance metrics"""
|
|
128
|
+
keys = ['Status', 'PercentComplete', 'PercentSuccess']
|
|
129
|
+
return self.fromkeys(keys)
|
|
130
|
+
|
|
131
|
+
def formatForWire(self):
|
|
132
|
+
"""Format used to send data over network
|
|
133
|
+
"""
|
|
134
|
+
to_remove = ['Elements', 'WMSpec']
|
|
135
|
+
result = dict(self)
|
|
136
|
+
for item in to_remove:
|
|
137
|
+
result.pop(item)
|
|
138
|
+
return result
|
|
139
|
+
|
|
140
|
+
def getMaxJobElement(self):
|
|
141
|
+
maxJobElement = self['Elements'][0]
|
|
142
|
+
for x in self['Elements']:
|
|
143
|
+
if x['Jobs'] > maxJobElement['Jobs']:
|
|
144
|
+
maxJobElement = x
|
|
145
|
+
return maxJobElement
|
|
146
|
+
|
|
147
|
+
def getMinJobElement(self):
|
|
148
|
+
minJobElement = self['Elements'][0]
|
|
149
|
+
for x in self['Elements']:
|
|
150
|
+
if x['Jobs'] < minJobElement['Jobs']:
|
|
151
|
+
minJobElement = x
|
|
152
|
+
return minJobElement
|