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,300 @@
|
|
|
1
|
+
from builtins import object
|
|
2
|
+
from future.utils import viewitems, viewvalues
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class JobSummary(object):
|
|
6
|
+
"""
|
|
7
|
+
job summary data structure from job format in couchdb
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, jobStatus=None):
|
|
11
|
+
self.jobStatus = {
|
|
12
|
+
"success": 0,
|
|
13
|
+
"canceled": 0,
|
|
14
|
+
"transition": 0,
|
|
15
|
+
"queued": {"first": 0, "retry": 0},
|
|
16
|
+
"submitted": {"first": 0, "retry": 0, "pending": 0, "running": 0},
|
|
17
|
+
"failure": {"create": 0, "submit": 0, "exception": 0},
|
|
18
|
+
"cooloff": {"create": 0, "submit": 0, "job": 0},
|
|
19
|
+
"paused": {"create": 0, "submit": 0, "job": 0},
|
|
20
|
+
}
|
|
21
|
+
if jobStatus != None:
|
|
22
|
+
self.addJobStatusInfo(jobStatus)
|
|
23
|
+
|
|
24
|
+
def addJobStatusInfo(self, jobStatus):
|
|
25
|
+
|
|
26
|
+
# TODO need to validate the structure.
|
|
27
|
+
for key, value in viewitems(self.jobStatus):
|
|
28
|
+
if isinstance(value, int):
|
|
29
|
+
self.jobStatus[key] += jobStatus.get(key, 0)
|
|
30
|
+
elif isinstance(value, dict):
|
|
31
|
+
for secondKey in value:
|
|
32
|
+
if key in jobStatus and secondKey in jobStatus[key]:
|
|
33
|
+
self.jobStatus[key][secondKey] += jobStatus[key][secondKey]
|
|
34
|
+
|
|
35
|
+
def addJobSummary(self, jobSummary):
|
|
36
|
+
self.addJobStatusInfo(jobSummary.jobStatus)
|
|
37
|
+
|
|
38
|
+
def getTotalJobs(self):
|
|
39
|
+
return (self.getSuccess() +
|
|
40
|
+
self.jobStatus["canceled"] +
|
|
41
|
+
self.jobStatus["transition"] +
|
|
42
|
+
self.getFailure() +
|
|
43
|
+
self.getCooloff() +
|
|
44
|
+
self.getPaused() +
|
|
45
|
+
self.getQueued() +
|
|
46
|
+
self.getRunning() +
|
|
47
|
+
self.getPending())
|
|
48
|
+
|
|
49
|
+
def getSuccess(self):
|
|
50
|
+
return self.jobStatus["success"]
|
|
51
|
+
|
|
52
|
+
def getFailure(self):
|
|
53
|
+
|
|
54
|
+
return (self.jobStatus["failure"]["create"] +
|
|
55
|
+
self.jobStatus["failure"]["submit"] +
|
|
56
|
+
self.jobStatus["failure"]["exception"])
|
|
57
|
+
|
|
58
|
+
def getCompleted(self):
|
|
59
|
+
return self.getSuccess() + self.getFailure()
|
|
60
|
+
|
|
61
|
+
def getSubmitted(self):
|
|
62
|
+
return (self.jobStatus["submitted"]["first"] +
|
|
63
|
+
self.jobStatus["submitted"]["retry"])
|
|
64
|
+
|
|
65
|
+
def getRunning(self):
|
|
66
|
+
return self.jobStatus["submitted"]["running"]
|
|
67
|
+
|
|
68
|
+
def getPending(self):
|
|
69
|
+
return self.jobStatus["submitted"]["pending"]
|
|
70
|
+
|
|
71
|
+
def getCooloff(self):
|
|
72
|
+
return (self.jobStatus["cooloff"]["create"] +
|
|
73
|
+
self.jobStatus["cooloff"]["submit"] +
|
|
74
|
+
self.jobStatus["cooloff"]["job"])
|
|
75
|
+
|
|
76
|
+
def getPaused(self):
|
|
77
|
+
return (self.jobStatus["paused"]["create"] +
|
|
78
|
+
self.jobStatus["paused"]["submit"] +
|
|
79
|
+
self.jobStatus["paused"]["job"])
|
|
80
|
+
|
|
81
|
+
def getQueued(self):
|
|
82
|
+
return (self.jobStatus["queued"]["first"] +
|
|
83
|
+
self.jobStatus["queued"]["retry"])
|
|
84
|
+
|
|
85
|
+
def getJSONStatus(self):
|
|
86
|
+
return {'success': self.getSuccess(),
|
|
87
|
+
'failure': self.getFailure(),
|
|
88
|
+
'cooloff': self.getCooloff(),
|
|
89
|
+
'running': self.getRunning(),
|
|
90
|
+
'queued': self.getQueued(),
|
|
91
|
+
'pending': self.getPending(),
|
|
92
|
+
'paused': self.getPaused(),
|
|
93
|
+
'created': self.getTotalJobs()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class ProgressSummary(object):
|
|
98
|
+
|
|
99
|
+
def __init__(self, progressReport=None):
|
|
100
|
+
self.progress = {
|
|
101
|
+
"totalLumis": 0,
|
|
102
|
+
"events": 0,
|
|
103
|
+
"size": 0
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if progressReport != None:
|
|
107
|
+
self.addProgressReport(progressReport)
|
|
108
|
+
|
|
109
|
+
def addProgressReport(self, progressReport):
|
|
110
|
+
|
|
111
|
+
# TODO need to validate the structure.
|
|
112
|
+
for key in self.progress:
|
|
113
|
+
self.progress[key] += progressReport.get(key, 0)
|
|
114
|
+
|
|
115
|
+
def getReport(self):
|
|
116
|
+
return self.progress
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class TaskInfo(object):
|
|
120
|
+
|
|
121
|
+
def __init__(self, requestName, taskName, data):
|
|
122
|
+
self.requestName = requestName
|
|
123
|
+
self.taskName = taskName
|
|
124
|
+
self.taskType = data.get('jobtype', "N/A")
|
|
125
|
+
self.jobSummary = JobSummary(data.get('status', {}))
|
|
126
|
+
|
|
127
|
+
def addTaskInfo(self, taskInfo):
|
|
128
|
+
if not (self.requestName == taskInfo.requestName and
|
|
129
|
+
self.taskName == taskInfo.taskName):
|
|
130
|
+
msg = "%s: %s, %s: %s, %s: %s" % (self.requestName, taskInfo.requestName,
|
|
131
|
+
self.taskName, taskInfo.taskName,
|
|
132
|
+
self.taskType, taskInfo.taskType)
|
|
133
|
+
raise Exception("task doesn't match %s" % msg)
|
|
134
|
+
|
|
135
|
+
self.jobSummary.addJobSummary(taskInfo.jobSummary)
|
|
136
|
+
|
|
137
|
+
def getRequestName(self):
|
|
138
|
+
return self.requestName
|
|
139
|
+
|
|
140
|
+
def getTaskName(self):
|
|
141
|
+
return self.taskName
|
|
142
|
+
|
|
143
|
+
def getTaskType(self):
|
|
144
|
+
return self.taskType
|
|
145
|
+
|
|
146
|
+
def getJobSummary(self):
|
|
147
|
+
return self.jobSummary
|
|
148
|
+
|
|
149
|
+
def isTaskCompleted(self):
|
|
150
|
+
totalJobs = self.jobSummary.getTotalJobs()
|
|
151
|
+
completedJobs = self.jobSummary.getCompleted()
|
|
152
|
+
return (totalJobs != 0 and totalJobs == completedJobs)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class RequestInfo(object):
|
|
156
|
+
|
|
157
|
+
def __init__(self, data):
|
|
158
|
+
"""
|
|
159
|
+
data structure is
|
|
160
|
+
{'request_name1':
|
|
161
|
+
{'agent_url1': {'status'
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
"""
|
|
165
|
+
self.setData(data)
|
|
166
|
+
|
|
167
|
+
def setData(self, data):
|
|
168
|
+
# If RequestName doesn't exist, try legacy format (workflow)
|
|
169
|
+
if 'RequestName' in data:
|
|
170
|
+
self.requestName = data['RequestName']
|
|
171
|
+
else:
|
|
172
|
+
self.requestName = data['workflow']
|
|
173
|
+
self.data = data
|
|
174
|
+
self.jobSummaryByAgent = {}
|
|
175
|
+
self.tasks = {}
|
|
176
|
+
self.tasksByAgent = {}
|
|
177
|
+
self.jobSummary = JobSummary()
|
|
178
|
+
if 'AgentJobInfo' in data:
|
|
179
|
+
for agentUrl, agentRequestInfo in viewitems(data['AgentJobInfo']):
|
|
180
|
+
self.jobSummary.addJobStatusInfo(agentRequestInfo.get('status', {}))
|
|
181
|
+
self.jobSummaryByAgent[agentUrl] = JobSummary(agentRequestInfo.get('status', {}))
|
|
182
|
+
|
|
183
|
+
if 'tasks' in agentRequestInfo:
|
|
184
|
+
self.tasksByAgent[agentUrl] = {}
|
|
185
|
+
for taskName, taskData in viewitems(agentRequestInfo['tasks']):
|
|
186
|
+
if taskName not in self.tasks:
|
|
187
|
+
self.tasks[taskName] = TaskInfo(self.requestName, taskName, taskData)
|
|
188
|
+
else:
|
|
189
|
+
self.tasks[taskName].addTaskInfo(TaskInfo(self.requestName, taskName, taskData))
|
|
190
|
+
# only one task by one agent - don't need to combine
|
|
191
|
+
self.tasksByAgent[agentUrl][taskName] = TaskInfo(self.requestName, taskName, taskData)
|
|
192
|
+
|
|
193
|
+
def getJobSummary(self):
|
|
194
|
+
return self.jobSummary
|
|
195
|
+
|
|
196
|
+
def getJobSummaryByAgent(self, agentUrl=None):
|
|
197
|
+
if agentUrl:
|
|
198
|
+
return self.jobSummaryByAgent[agentUrl]
|
|
199
|
+
return self.jobSummaryByAgent
|
|
200
|
+
|
|
201
|
+
def getTasksByAgent(self, agentUrl=None):
|
|
202
|
+
if agentUrl:
|
|
203
|
+
return self.tasksByAgent[agentUrl]
|
|
204
|
+
return self.tasksByAgent
|
|
205
|
+
|
|
206
|
+
def getTasks(self):
|
|
207
|
+
return self.tasks
|
|
208
|
+
|
|
209
|
+
def getTotalTopLevelJobs(self):
|
|
210
|
+
return self.data.get("total_jobs", "N/A")
|
|
211
|
+
|
|
212
|
+
def getTotalTopLevelJobsInWMBS(self):
|
|
213
|
+
inWMBS = 0
|
|
214
|
+
if "AgentJobInfo" in self.data:
|
|
215
|
+
for agentRequestInfo in viewvalues(self.data["AgentJobInfo"]):
|
|
216
|
+
inWMBS += agentRequestInfo['status'].get('inWMBS', 0)
|
|
217
|
+
return inWMBS
|
|
218
|
+
|
|
219
|
+
def getTotalInputLumis(self):
|
|
220
|
+
return self.data.get("input_lumis", "N/A")
|
|
221
|
+
|
|
222
|
+
def getTotalInputEvents(self):
|
|
223
|
+
return self.data.get("input_events", "N/A")
|
|
224
|
+
|
|
225
|
+
def getProgressSummaryByOutputDataset(self):
|
|
226
|
+
"""
|
|
227
|
+
check sampleResult.json for datastructure
|
|
228
|
+
"""
|
|
229
|
+
datasets = {}
|
|
230
|
+
|
|
231
|
+
if "AgentJobInfo" not in self.data:
|
|
232
|
+
# ther is no report yet (no agent has reported)
|
|
233
|
+
return datasets
|
|
234
|
+
|
|
235
|
+
for agentRequestInfo in viewvalues(self.data["AgentJobInfo"]):
|
|
236
|
+
|
|
237
|
+
tasks = agentRequestInfo.get("tasks", [])
|
|
238
|
+
for task in tasks:
|
|
239
|
+
for site in tasks[task].get("sites", []):
|
|
240
|
+
for outputDS in tasks[task]["sites"][site].get("dataset", {}):
|
|
241
|
+
# TODO: need update the record instead of replacing.
|
|
242
|
+
datasets.setdefault(outputDS, ProgressSummary())
|
|
243
|
+
datasets[outputDS].addProgressReport(tasks[task]["sites"][site]["dataset"][outputDS])
|
|
244
|
+
|
|
245
|
+
return datasets
|
|
246
|
+
|
|
247
|
+
def filterRequest(self, conditionFunc):
|
|
248
|
+
return conditionFunc(self.data)
|
|
249
|
+
|
|
250
|
+
def getRequestTransition(self):
|
|
251
|
+
return self.data["request_status"]
|
|
252
|
+
|
|
253
|
+
def getRequestStatus(self, timeFlag=False):
|
|
254
|
+
if timeFlag:
|
|
255
|
+
return self.data["request_status"][-1]
|
|
256
|
+
return self.data["request_status"][-1]['status']
|
|
257
|
+
|
|
258
|
+
def isWorkflowFinished(self):
|
|
259
|
+
"""
|
|
260
|
+
check whether workflow is completed including LogCollect and CleanUp tasks
|
|
261
|
+
TODO: If the parent task all failed and next task are not created at all,
|
|
262
|
+
It can't detect complete status.
|
|
263
|
+
If the one of the task doesn't contain any jobs, it will return False
|
|
264
|
+
"""
|
|
265
|
+
if not self.tasks:
|
|
266
|
+
return False
|
|
267
|
+
|
|
268
|
+
for taskInfo in viewvalues(self.tasks):
|
|
269
|
+
if not taskInfo.isTaskCompleted():
|
|
270
|
+
return False
|
|
271
|
+
return True
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
class RequestInfoCollection(object):
|
|
275
|
+
|
|
276
|
+
def __init__(self, data):
|
|
277
|
+
self.collection = {}
|
|
278
|
+
self.setData(data)
|
|
279
|
+
|
|
280
|
+
def setData(self, data):
|
|
281
|
+
for requestName, requestInfo in viewitems(data):
|
|
282
|
+
self.collection[requestName] = RequestInfo(requestInfo)
|
|
283
|
+
|
|
284
|
+
def getData(self):
|
|
285
|
+
return self.collection
|
|
286
|
+
|
|
287
|
+
def filterRequests(self, conditionFunc):
|
|
288
|
+
filtered = {}
|
|
289
|
+
for name, reqInfo in viewitems(self.collection):
|
|
290
|
+
if reqInfo.filterRequest(conditionFunc):
|
|
291
|
+
filtered[name] = reqInfo
|
|
292
|
+
return filtered
|
|
293
|
+
|
|
294
|
+
def getJSONData(self):
|
|
295
|
+
result = {}
|
|
296
|
+
for requestInfo in viewvalues(self.collection):
|
|
297
|
+
result[requestInfo.requestName] = {}
|
|
298
|
+
for agentUrl, jobSummary in viewitems(requestInfo.getJobSummaryByAgent()):
|
|
299
|
+
result[requestInfo.requestName][agentUrl] = jobSummary.getJSONStatus()
|
|
300
|
+
return result
|
|
File without changes
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides some functions to create concurrent HTTP requests
|
|
3
|
+
for CouchDB, as an alternative to the sequential modules available under:
|
|
4
|
+
* WMCore/Services/WMStats/WMStatsReader.getTaskJobSummaryByRequest
|
|
5
|
+
* WMCore/Services/WMStats/WMStatsReader.jobDetailByTasks
|
|
6
|
+
|
|
7
|
+
Documentation for the parameters supported in views query can be found at:
|
|
8
|
+
https://docs.couchdb.org/en/stable/api/ddoc/views.html#get--db-_design-ddoc-_view-view
|
|
9
|
+
"""
|
|
10
|
+
import json
|
|
11
|
+
|
|
12
|
+
from urllib.parse import urljoin, urlencode
|
|
13
|
+
from Utils.CertTools import ckey, cert
|
|
14
|
+
from WMCore.Services.pycurl_manager import getdata as multi_getdata
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def getTaskJobSummaryByRequestPycurl(rowsSummary, sampleSize, serviceOpts):
|
|
18
|
+
"""
|
|
19
|
+
Pycurl-based implementation of WMStatsReader.getTaskJobSummaryByRequest
|
|
20
|
+
:param rowsSummary: a dictionary with rows from CouchDB
|
|
21
|
+
:param sampleSize: integer with number of documents to retrieve
|
|
22
|
+
:param serviceOpts: dictionary with CouchDB options (url, db name and couchapp name)
|
|
23
|
+
:return: a dictionary with job detail
|
|
24
|
+
"""
|
|
25
|
+
paramQueries = []
|
|
26
|
+
for row in rowsSummary['rows']:
|
|
27
|
+
thisQuery = {"startkey": [], "endkey": [], "numOfError": 0}
|
|
28
|
+
# row["key"] = ['workflow', 'task', 'jobstatus', 'exitCode', 'site']
|
|
29
|
+
thisQuery["startkey"] = row["key"][:4]
|
|
30
|
+
if row["key"][4]:
|
|
31
|
+
thisQuery["startkey"].append(row["key"][4]) # site
|
|
32
|
+
|
|
33
|
+
thisQuery["endkey"] = []
|
|
34
|
+
thisQuery["endkey"].extend(thisQuery["startkey"])
|
|
35
|
+
thisQuery["endkey"].append({})
|
|
36
|
+
# append amount of errors matching the 5 keys above
|
|
37
|
+
thisQuery["numOfError"] = row["value"]
|
|
38
|
+
# add query to the pool
|
|
39
|
+
paramQueries.append(thisQuery)
|
|
40
|
+
|
|
41
|
+
return jobDetailByTasksPycurl(paramQueries, sampleSize, serviceOpts)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def jobDetailByTasksPycurl(queries, limit, serviceOpts):
|
|
45
|
+
"""
|
|
46
|
+
Pycurl-based implementation of WMStatsReader.jobDetailByTasks.
|
|
47
|
+
In short, for each tuple of errors, it returns "limit" number of documents.
|
|
48
|
+
:param queries: list of CouchDB query parameters
|
|
49
|
+
:param limit: number of documents to retrieve from CouchDB
|
|
50
|
+
:param serviceOpts: dictionary with CouchDB options (url, db name and couchapp name)
|
|
51
|
+
:return: dictionary with job detail information, in a format like:
|
|
52
|
+
{"WORKFLOW_NAME":
|
|
53
|
+
{"/WORKFLOW_NAME/TASK_NAME":
|
|
54
|
+
{"JOB_STATE":
|
|
55
|
+
{"EXIT_CODE":
|
|
56
|
+
{"SITE_NAME":
|
|
57
|
+
"samples": [
|
|
58
|
+
{"_id": "123abc",
|
|
59
|
+
"_rev": "12-abc",
|
|
60
|
+
"wmbsid": 2006208,
|
|
61
|
+
"type": "jobsummary",
|
|
62
|
+
"retrycount": 3,
|
|
63
|
+
"errors": {"JobSubmit": [{
|
|
64
|
+
"type": "SubmitFailed",
|
|
65
|
+
"details": "The job can blah blah",
|
|
66
|
+
"exitCode": 71103}]
|
|
67
|
+
},
|
|
68
|
+
"timestamp": 1698749157,
|
|
69
|
+
... etc etc}],
|
|
70
|
+
"errorCount": 1}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
{"/WORKFLOW_NAME/TASK_NAME-2":
|
|
75
|
+
{"JOB_STATE": {... etc etc
|
|
76
|
+
|
|
77
|
+
A decoded example of this query would be:
|
|
78
|
+
scurl "https://cmsweb-test9.cern.ch/couchdb/wmstats/_design/WMStatsErl3/_view/jobsByStatusWorkflow?reduce=false&include_docs=true&startkey=["WORKFLOW_NAME","/WORKFLOW_NAME/TASK_NAME","JOB_STATE",EXIT_CODE,"SITE_NAME"]&endkey=["WORKFLOW_NAME","/WORKFLOW_NAME/TASK_NAME","JOB_STATE",EXIT_CODE,"SITE_NAME",{}]&limit=1&stale=update_after"
|
|
79
|
+
while encoding the url would result in:
|
|
80
|
+
scurl "https://****.cern.ch/couchdb/wmstats/_design/WMStatsErl3/_view/jobsByStatusWorkflow?reduce=false&include_docs=true&startkey=%5B%22WORKFLOW_NAME%22%2C+%22%2FWORKFLOW_NAME%2FTASK_NAME%22%2C+%22JOB_STATE%22%2C+EXIT_CODE%2C+%22SITE_NAME%22%5D&endkey=%5B%22WORKFLOW_NAME%22%2C+%22%2FWORKFLOW_NAME%2FTASK_NAME%22%2C+%22JOB_STATE%22%2C+EXIT_CODE%2C+%22SITE_NAME%22%2C+%7B%7D%5D&limit=1&stale=update_after"
|
|
81
|
+
|
|
82
|
+
Example of output is:
|
|
83
|
+
{"total_rows":4764135,"offset":4056263,"rows":[
|
|
84
|
+
{"id":"12703ce5-xxx","key":["WORKFLOW_NAME","/WORKFLOW_NAME/TASK_NAME","jobfailed",8006,"SITE_NAME","https://xxx.cern.ch/couchdb/acdcserver","vocms0255.cern.ch",["Fatal Exception"]],
|
|
85
|
+
"value":{"id":"12703ce5-xxx","rev":"4-xxx"},
|
|
86
|
+
"doc":{"_id":"12703ce5-xx","_rev":"4-xxx","wmbsid":2709786,"type":"jobsummary", ...
|
|
87
|
+
|
|
88
|
+
where (for the examples above):
|
|
89
|
+
WORKFLOW_NAME is, e.g.: pdmvserv_Run2017G_DoubleMuon_UL2017_MiniAODv2_BParking_230917_124108_9876
|
|
90
|
+
TASK_NAME is, e.g.: DataProcessing
|
|
91
|
+
SITE_NAME is, e.g.: T2_US_Wisconsin
|
|
92
|
+
JOB_STATE is, e.g.: jobfailed
|
|
93
|
+
EXIT_CODE is, e.g.: 8006
|
|
94
|
+
"""
|
|
95
|
+
uri = f"couchdb/{serviceOpts['dbName']}/_design/{serviceOpts['couchapp']}/_view/jobsByStatusWorkflow"
|
|
96
|
+
baseUrl = urljoin(serviceOpts['couchURL'], uri)
|
|
97
|
+
|
|
98
|
+
encoder = json.JSONEncoder()
|
|
99
|
+
urlsPool = []
|
|
100
|
+
for query in queries:
|
|
101
|
+
options = {'include_docs': encoder.encode(True),
|
|
102
|
+
'reduce': encoder.encode(False),
|
|
103
|
+
'startkey': encoder.encode(query["startkey"]),
|
|
104
|
+
'endkey': encoder.encode(query["endkey"]),
|
|
105
|
+
'limit': encoder.encode(limit)}
|
|
106
|
+
# we cannot encode the 'stale' parameter
|
|
107
|
+
options.setdefault("stale", "update_after")
|
|
108
|
+
# encode url data for the GET request
|
|
109
|
+
thisUrl = f"{baseUrl}?{urlencode(options, doseq=True)}"
|
|
110
|
+
urlsPool.append(thisUrl)
|
|
111
|
+
|
|
112
|
+
jobInfoDoc = {}
|
|
113
|
+
# now run all of these calls in parallel
|
|
114
|
+
for response in multi_getdata(urlsPool, ckey(), cert()):
|
|
115
|
+
if 'error' in response:
|
|
116
|
+
raise RuntimeError(f"Unexpected error in HTTP call. Details: {response}")
|
|
117
|
+
data = json.loads(response.get('data', ''))
|
|
118
|
+
if 'error' in data:
|
|
119
|
+
raise RuntimeError(f"CouchDB query failed. Details: {data}")
|
|
120
|
+
|
|
121
|
+
for row in data.get('rows', []):
|
|
122
|
+
keys = row['key']
|
|
123
|
+
workflow = keys[0]
|
|
124
|
+
task = keys[1]
|
|
125
|
+
jobStatus = keys[2]
|
|
126
|
+
exitCode = keys[3]
|
|
127
|
+
site = keys[4]
|
|
128
|
+
|
|
129
|
+
jobInfoDoc.setdefault(workflow, {})
|
|
130
|
+
jobInfoDoc[workflow].setdefault(task, {})
|
|
131
|
+
jobInfoDoc[workflow][task].setdefault(jobStatus, {})
|
|
132
|
+
jobInfoDoc[workflow][task][jobStatus].setdefault(exitCode, {})
|
|
133
|
+
jobInfoDoc[workflow][task][jobStatus][exitCode].setdefault(site, {})
|
|
134
|
+
finalStruct = jobInfoDoc[workflow][task][jobStatus][exitCode][site]
|
|
135
|
+
finalStruct.setdefault("samples", [])
|
|
136
|
+
finalStruct["samples"].append(row["doc"])
|
|
137
|
+
# now painfully find out the number of errors based on the original query
|
|
138
|
+
finalStruct.setdefault("errorCount", 0)
|
|
139
|
+
keysJson = json.dumps(keys[:5])
|
|
140
|
+
for query in queries:
|
|
141
|
+
if json.dumps(query["startkey"]) in keysJson:
|
|
142
|
+
finalStruct["errorCount"] = query["numOfError"]
|
|
143
|
+
break
|
|
144
|
+
|
|
145
|
+
return jobInfoDoc
|