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,29 @@
|
|
|
1
|
+
from builtins import object
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ConfigDBMapInterface(object):
|
|
5
|
+
"""
|
|
6
|
+
Interface for converting the configuration to
|
|
7
|
+
db url string and option dictionary for DBFactory parameters
|
|
8
|
+
|
|
9
|
+
the implementation of this class should create db url string.
|
|
10
|
+
and option for DBFactory creation.
|
|
11
|
+
For details of options, reference WMCore.Database.DBFactory
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, config):
|
|
15
|
+
self.config = config
|
|
16
|
+
|
|
17
|
+
def getDBUrl(self):
|
|
18
|
+
"""
|
|
19
|
+
this should return db string
|
|
20
|
+
i.e. mysql://username@hostname.fnal.gov:3306/TestDB
|
|
21
|
+
"""
|
|
22
|
+
raise NotImplementedError("getDBUrl is not implemented")
|
|
23
|
+
|
|
24
|
+
def getOption(self):
|
|
25
|
+
"""
|
|
26
|
+
this should return options of dict format
|
|
27
|
+
i.e. {'engine_parameters': {'pool_size': 10}}
|
|
28
|
+
"""
|
|
29
|
+
raise NotImplementedError("getOption is not implemented")
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
This module provides helper functions to obtain and handle CouchDB Replication data:
|
|
4
|
+
- getSchedulerJobDocs get replication status based on scheduler information
|
|
5
|
+
- getReplicatorDocs get replication status based on replicator information
|
|
6
|
+
- compareReplicationStatus compares previous and current statuses
|
|
7
|
+
- formatPrometheusMetrics format status metrics in Prometheus format
|
|
8
|
+
- createAlerts create alerts from given status dict
|
|
9
|
+
- checkStatus perform all checks for couchdb replication
|
|
10
|
+
|
|
11
|
+
Example of using Flask framework to serve prometheus metrics about CouchDB replication
|
|
12
|
+
|
|
13
|
+
import requests
|
|
14
|
+
from flask import Flask, Response
|
|
15
|
+
import threading
|
|
16
|
+
import time
|
|
17
|
+
|
|
18
|
+
app = Flask(__name__)
|
|
19
|
+
status_cache = {}
|
|
20
|
+
|
|
21
|
+
@app.route("/metrics")
|
|
22
|
+
def metrics():
|
|
23
|
+
return Response(formatPrometheusMetrics(status_cache), mimetype="text/plain")
|
|
24
|
+
|
|
25
|
+
def daemonCouchReplicationStatus(interval=30):
|
|
26
|
+
global status_cache
|
|
27
|
+
while True:
|
|
28
|
+
new_status = getSchedulerJobDocs(COUCHDB_URL, USERNAME, PASSWORD)
|
|
29
|
+
status_cache = new_status
|
|
30
|
+
time.sleep(interval)
|
|
31
|
+
|
|
32
|
+
if __name__ == "__main__":
|
|
33
|
+
# Start the background thread to update replication status periodically
|
|
34
|
+
threading.Thread(target=daemonCouchReplicationStatus, daemon=True).start()
|
|
35
|
+
# Run the Flask app
|
|
36
|
+
app.run(host="0.0.0.0", port=8000)
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
import os
|
|
40
|
+
import json
|
|
41
|
+
import requests
|
|
42
|
+
import tempfile
|
|
43
|
+
|
|
44
|
+
# WMCore modules
|
|
45
|
+
from Utils.CertTools import cert, ckey, caBundle
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def getSchedulerJobDocs(couchdbUrl):
|
|
49
|
+
"""
|
|
50
|
+
Fetch CouchDB replication statuses. The logic is based on /_scheduler/jobs CouchDB end-point
|
|
51
|
+
see https://docs.couchdb.org/en/stable/api/server/common.html#api-server-scheduler-jobs
|
|
52
|
+
:param couchdbUrl: url of couch db
|
|
53
|
+
:return: dictionary of statuses for all found replication documents
|
|
54
|
+
"""
|
|
55
|
+
username, password = couchCredentials()
|
|
56
|
+
auth = (username, password) if username and password else None
|
|
57
|
+
try:
|
|
58
|
+
response = requests.get(f"{couchdbUrl}/_scheduler/jobs", auth=auth)
|
|
59
|
+
response.raise_for_status()
|
|
60
|
+
data = response.json()
|
|
61
|
+
|
|
62
|
+
statuses = {}
|
|
63
|
+
for job in data.get('jobs', []):
|
|
64
|
+
doc_id = job.get('doc_id') or job.get('id')
|
|
65
|
+
source = job.get('source')
|
|
66
|
+
target = job.get('target')
|
|
67
|
+
history = job.get('history', [])
|
|
68
|
+
info = job.get('info', {})
|
|
69
|
+
|
|
70
|
+
# Determine current state from latest history item
|
|
71
|
+
state = history[0]['type'] if history else 'unknown'
|
|
72
|
+
|
|
73
|
+
# Detect error if 'crashed' exists in any history entry
|
|
74
|
+
error = None
|
|
75
|
+
for h in history:
|
|
76
|
+
if h.get('type') == 'crashed':
|
|
77
|
+
error = f"Job previous crashed at {h.get('timestamp')} due to {h.get('reason')}"
|
|
78
|
+
break
|
|
79
|
+
|
|
80
|
+
# check info document
|
|
81
|
+
if info and info.get('doc_write_failures', 0) != 0:
|
|
82
|
+
error = f"found failure of replication jobs in {couchdbUrl}/_scheduler/jobs "
|
|
83
|
+
state = "error"
|
|
84
|
+
# try to get more info about the error
|
|
85
|
+
try:
|
|
86
|
+
response = requests.get(f"{couchdbUrl}/_scheduler/docs/_replicator/{doc_id}", auth=auth)
|
|
87
|
+
response.raise_for_status()
|
|
88
|
+
data = response.json()
|
|
89
|
+
error += f" Replicator state for {doc_id}: "
|
|
90
|
+
error += json.dumps(data)
|
|
91
|
+
except:
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
statuses[doc_id] = {
|
|
95
|
+
'state': state,
|
|
96
|
+
'source': source,
|
|
97
|
+
'target': target,
|
|
98
|
+
'error': error,
|
|
99
|
+
'history': history
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return statuses
|
|
103
|
+
except requests.RequestException as e:
|
|
104
|
+
print(f"Error fetching scheduler jobs: {e}")
|
|
105
|
+
return {}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def getReplicatorDocs(url=None):
|
|
109
|
+
"""
|
|
110
|
+
Helper function to get all replicator docs and return summary dictionary
|
|
111
|
+
:param url: url of the couchdb
|
|
112
|
+
:return: replication summary dictionary
|
|
113
|
+
"""
|
|
114
|
+
username, password = couchCredentials()
|
|
115
|
+
auth = (username, password) if username and password else None
|
|
116
|
+
if not url:
|
|
117
|
+
url = "http://localhost:5984"
|
|
118
|
+
headers = {"Accept": "application/json"}
|
|
119
|
+
|
|
120
|
+
# Get list of all documents in _replicator
|
|
121
|
+
r = requests.get(f"{url}/_replicator/_all_docs?include_docs=true",
|
|
122
|
+
headers=headers, auth=auth)
|
|
123
|
+
|
|
124
|
+
if r.status_code != 200:
|
|
125
|
+
raise Exception(f"Failed to fetch replication docs: {r.text}")
|
|
126
|
+
|
|
127
|
+
data = r.json()
|
|
128
|
+
result = {}
|
|
129
|
+
|
|
130
|
+
for row in data.get("rows", []):
|
|
131
|
+
doc = row.get("doc", {})
|
|
132
|
+
doc_id = doc.get("_id")
|
|
133
|
+
if doc_id.startswith("_design/"):
|
|
134
|
+
continue # skip design docs
|
|
135
|
+
|
|
136
|
+
summary = {
|
|
137
|
+
"state": doc.get("_replication_state"),
|
|
138
|
+
"source": doc.get("source"),
|
|
139
|
+
"target": doc.get("target"),
|
|
140
|
+
"error": doc.get("_replication_state_reason"),
|
|
141
|
+
"history": []
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
history = doc.get("_replication_history", [])
|
|
145
|
+
for h in history:
|
|
146
|
+
entry = {
|
|
147
|
+
"timestamp": h.get("start_time") or h.get("end_time"),
|
|
148
|
+
"type": h.get("type") or "unknown"
|
|
149
|
+
}
|
|
150
|
+
summary["history"].append(entry)
|
|
151
|
+
|
|
152
|
+
result[doc_id] = summary
|
|
153
|
+
|
|
154
|
+
return result
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def compareReplicationStatus(prev, curr):
|
|
158
|
+
"""
|
|
159
|
+
Helper function to compare replication status from previous to current state
|
|
160
|
+
:param prev: previous replication status dictionary
|
|
161
|
+
:param curr: current replication status dictionary
|
|
162
|
+
:return: dictionary of changes
|
|
163
|
+
"""
|
|
164
|
+
changes = {}
|
|
165
|
+
for key in curr:
|
|
166
|
+
if key not in prev or prev[key] != curr[key]:
|
|
167
|
+
changes[key] = {
|
|
168
|
+
'old': prev.get(key),
|
|
169
|
+
'new': curr[key]
|
|
170
|
+
}
|
|
171
|
+
return changes
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def formatPrometheusMetrics(statuses):
|
|
175
|
+
"""
|
|
176
|
+
Helper function to provide Prometheus metrics from given status dictionary
|
|
177
|
+
:param statuses: replication status dictionary
|
|
178
|
+
:return: prometheus metrics
|
|
179
|
+
"""
|
|
180
|
+
states = {'error': -1, 'completed': 0, 'started': 1, 'added': 2, 'waiting': 3, 'triggered': 4, 'failed': 5}
|
|
181
|
+
lines = [
|
|
182
|
+
f'# HELP couchdb_replication_state Replication state: {states}',
|
|
183
|
+
'# TYPE couchdb_replication_state gauge'
|
|
184
|
+
]
|
|
185
|
+
for key, status in statuses.items():
|
|
186
|
+
label = f'replId="{key}",source="{status["source"]}",target="{status["target"]}"'
|
|
187
|
+
value = 0 # default error/other
|
|
188
|
+
for k, v in states.items():
|
|
189
|
+
if status['state'] == k:
|
|
190
|
+
value = v
|
|
191
|
+
break
|
|
192
|
+
lines.append(f'couchdb_replication_state{{{label}}} {value}')
|
|
193
|
+
return '\n'.join(lines)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def createAlerts(statuses):
|
|
197
|
+
"""
|
|
198
|
+
Helper function to check alerts of replication status dictionary
|
|
199
|
+
:param statuses: replication status dictionary
|
|
200
|
+
:return: alerts dictionary
|
|
201
|
+
"""
|
|
202
|
+
alerts = {}
|
|
203
|
+
for key, status in statuses.items():
|
|
204
|
+
if status['state'] != 'completed':
|
|
205
|
+
alerts[key] = f"Replication state for {key} is '{status['state']}', error: {status['error']}"
|
|
206
|
+
return alerts
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def couchCredentials():
|
|
210
|
+
"""
|
|
211
|
+
Select CouchDB credentials from provided secrets file
|
|
212
|
+
:return: tuple of (user, password)
|
|
213
|
+
"""
|
|
214
|
+
fname = os.getenv('WMAGENT_SECRETS_LOCATION', '')
|
|
215
|
+
if fname == "":
|
|
216
|
+
raise Exception("No WMAGENT_SECRETS_LOCATION in environment")
|
|
217
|
+
user = ''
|
|
218
|
+
password = ''
|
|
219
|
+
data = ''
|
|
220
|
+
with open(fname, 'r', encoding="utf-8") as istream:
|
|
221
|
+
data = istream.read()
|
|
222
|
+
for item in data.split('\n'):
|
|
223
|
+
if 'COUCH_USER' in item:
|
|
224
|
+
user = item.split('=')[-1]
|
|
225
|
+
if 'COUCH_PASS' in item:
|
|
226
|
+
password = item.split('=')[-1]
|
|
227
|
+
return user, password
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def checkStatus(url=None, prevStatus=None, kind="scheduler"):
|
|
231
|
+
"""
|
|
232
|
+
Perform check of replication statuses
|
|
233
|
+
:param url: couchdb URL
|
|
234
|
+
:param prevStatus: previous status dictionary
|
|
235
|
+
:param kind: kind of data look-up, e.g. scheduler or replicator
|
|
236
|
+
:return: dictionary of current couchdb replication
|
|
237
|
+
|
|
238
|
+
Here is an example of such dictionary structure:
|
|
239
|
+
{'current_status': currStatus (dictionary),
|
|
240
|
+
'previous_status': prevStatus (dictionary),
|
|
241
|
+
'changes': changes (dictionary),
|
|
242
|
+
'metrics': metrics (string),
|
|
243
|
+
'alerts': alerts (dictionary)}
|
|
244
|
+
|
|
245
|
+
Then, current and previous status dictionaries have the following form:
|
|
246
|
+
{
|
|
247
|
+
"14843c24643f8960eb159f5912f0f938": {
|
|
248
|
+
"state": "started",
|
|
249
|
+
"source": "https://xxx.cern.ch/couchdb/workqueue/",
|
|
250
|
+
"target": "http://127.0.0.1:5984/workqueue_inbox/",
|
|
251
|
+
"error": "Job previously crashed at 2025-05-05T18:47:11Z due to {changes_reader_died,{timeout,ibrowse_stream_cleanup}}",
|
|
252
|
+
"history": [
|
|
253
|
+
{
|
|
254
|
+
"timestamp": "2025-05-05T18:47:11Z",
|
|
255
|
+
"type": "started"
|
|
256
|
+
},
|
|
257
|
+
...
|
|
258
|
+
]
|
|
259
|
+
},
|
|
260
|
+
"14843c24643f8960eb159f5912f0e51e": {
|
|
261
|
+
"state": "started",
|
|
262
|
+
"source": "http://127.0.0.1:5984/wmagent_summary/",
|
|
263
|
+
"target": "https://xxx.cern.ch/couchdb/wmstats/",
|
|
264
|
+
"error": null,
|
|
265
|
+
"history": [
|
|
266
|
+
{
|
|
267
|
+
"timestamp": "2025-04-09T11:19:36Z",
|
|
268
|
+
"type": "started"
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"timestamp": "2025-04-09T11:19:36Z",
|
|
272
|
+
"type": "added"
|
|
273
|
+
}
|
|
274
|
+
]
|
|
275
|
+
},
|
|
276
|
+
...
|
|
277
|
+
}
|
|
278
|
+
"""
|
|
279
|
+
if not prevStatus:
|
|
280
|
+
prevStatus = {}
|
|
281
|
+
if not url:
|
|
282
|
+
url = "http://localhost:5984"
|
|
283
|
+
|
|
284
|
+
# first let's get statuses of documents
|
|
285
|
+
if kind == "scheduler":
|
|
286
|
+
currStatus = getSchedulerJobDocs(url)
|
|
287
|
+
elif kind == "replicator":
|
|
288
|
+
currStatus = getReplicatorDocs(url)
|
|
289
|
+
else:
|
|
290
|
+
raise Exception("Unsupported kind of documents '{kind}', should be either scheduler or replicator")
|
|
291
|
+
|
|
292
|
+
# now we can find out changes from previous statuses
|
|
293
|
+
changes = compareReplicationStatus(prevStatus, currStatus)
|
|
294
|
+
|
|
295
|
+
# construct prometheus metrics with current statuses
|
|
296
|
+
metrics = formatPrometheusMetrics(currStatus)
|
|
297
|
+
|
|
298
|
+
# construct alerts with current statuses
|
|
299
|
+
alerts = createAlerts(currStatus)
|
|
300
|
+
|
|
301
|
+
# build final dictionary to return upstream
|
|
302
|
+
sdict = {'current_status': currStatus,
|
|
303
|
+
'previous_status': prevStatus,
|
|
304
|
+
'changes': changes,
|
|
305
|
+
'metrics': metrics,
|
|
306
|
+
'alerts': alerts}
|
|
307
|
+
return sdict
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def getDocCount(url, auth, certTuple, caCert):
|
|
311
|
+
"""
|
|
312
|
+
helper function to get document counts
|
|
313
|
+
:param url: url of the couchdb
|
|
314
|
+
:param auth: couchdb authentication credentials tuple
|
|
315
|
+
:param caCert: ca bundle file name
|
|
316
|
+
:return: document count
|
|
317
|
+
"""
|
|
318
|
+
resp = requests.get(url, auth=auth, cert=certTuple, verify=caCert or True)
|
|
319
|
+
resp.raise_for_status()
|
|
320
|
+
return resp.json().get('doc_count', -1)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def getReplicationState(url, auth, certTuple, caCert):
|
|
324
|
+
"""
|
|
325
|
+
helper function to get replication state from given couchdb url
|
|
326
|
+
:param url: url of the couchdb
|
|
327
|
+
:param auth: couchdb authentication credentials tuple
|
|
328
|
+
:param caCert: ca bundle file name
|
|
329
|
+
:return: tuple of replication state and its time
|
|
330
|
+
"""
|
|
331
|
+
resp = requests.get(url, auth=auth, cert=certTuple, verify=caCert or True)
|
|
332
|
+
resp.raise_for_status()
|
|
333
|
+
doc = resp.json()
|
|
334
|
+
return doc.get('_replication_state'), doc.get('_replication_state_time')
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def compareCouchInstances(sourceUrl, targetUrl, replUrl):
|
|
338
|
+
"""
|
|
339
|
+
Compare the number of documents between source and destination CouchDB databases.
|
|
340
|
+
Monitor replication if the counts differ but replication status is OK.
|
|
341
|
+
|
|
342
|
+
Parameters:
|
|
343
|
+
:param sourceUrl: str, e.g. http://localhost:5984/source_db
|
|
344
|
+
:param targetUrl: str, e.g. http://localhost:5984/dest_db
|
|
345
|
+
:param replUrl: str, e.g. http://localhost:5984/_replicator/<replId>
|
|
346
|
+
"""
|
|
347
|
+
user, password = couchCredentials()
|
|
348
|
+
auth = (user, password)
|
|
349
|
+
sdict = {}
|
|
350
|
+
userCert = cert() if cert() else ''
|
|
351
|
+
userCkey = ckey() if ckey() else ''
|
|
352
|
+
if userCkey == '' or userCert == '':
|
|
353
|
+
return sdict
|
|
354
|
+
certTuple = (userCert, userCkey)
|
|
355
|
+
with tempfile.NamedTemporaryFile(mode='w+', suffix=".pem", delete=True) as tfile:
|
|
356
|
+
capath = os.environ.get("X509_CERT_DIR", '/etc/grid-security/certificates')
|
|
357
|
+
cacerts = caBundle(capath)
|
|
358
|
+
tfile.write(cacerts)
|
|
359
|
+
tfile.flush()
|
|
360
|
+
|
|
361
|
+
sourceCount = getDocCount(sourceUrl, auth, certTuple, tfile.name)
|
|
362
|
+
targetCount = getDocCount(targetUrl, auth, certTuple, tfile.name)
|
|
363
|
+
state, stateTime = getReplicationState(replUrl, auth, certTuple, tfile.name)
|
|
364
|
+
|
|
365
|
+
sdict = {
|
|
366
|
+
"source": sourceUrl,
|
|
367
|
+
"target": targetUrl,
|
|
368
|
+
"source_count": sourceCount,
|
|
369
|
+
"target_count": targetCount,
|
|
370
|
+
"state": state,
|
|
371
|
+
"state_timestamp": stateTime
|
|
372
|
+
}
|
|
373
|
+
return sdict
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def exampleReplicationStatus(sourceUrl=None):
|
|
377
|
+
"""
|
|
378
|
+
Example function to test replication status either based on scheduler or replicator info
|
|
379
|
+
This function should run on a node with local CouchDB access as all of its logic
|
|
380
|
+
relies on using localhost:5984 URL
|
|
381
|
+
"""
|
|
382
|
+
|
|
383
|
+
try:
|
|
384
|
+
print(f"checking {sourceUrl}")
|
|
385
|
+
|
|
386
|
+
# let's first test scheduler info
|
|
387
|
+
sdict = checkStatus(url=sourceUrl, kind="scheduler")
|
|
388
|
+
print('--- status based on scheduler info ---')
|
|
389
|
+
print(sdict['current_status'])
|
|
390
|
+
print('--- metrics ---')
|
|
391
|
+
print(sdict['metrics'])
|
|
392
|
+
if sdict.get('alerts', None):
|
|
393
|
+
print('--- alerts ---')
|
|
394
|
+
for k, msg in sdict['alerts'].items():
|
|
395
|
+
print(f"{k}: {msg}")
|
|
396
|
+
|
|
397
|
+
print()
|
|
398
|
+
|
|
399
|
+
# now let's test replicator info
|
|
400
|
+
rdict = checkStatus(url=sourceUrl, kind="replicator")
|
|
401
|
+
print('--- status based on replicator info ---')
|
|
402
|
+
print(rdict['current_status'])
|
|
403
|
+
print('--- metrics ---')
|
|
404
|
+
print(rdict['metrics'])
|
|
405
|
+
if rdict.get('alerts', None):
|
|
406
|
+
print('--- alerts ---')
|
|
407
|
+
for k, msg in rdict['alerts'].items():
|
|
408
|
+
print(f"{k}: {msg}")
|
|
409
|
+
|
|
410
|
+
except Exception as exp:
|
|
411
|
+
print(str(exp))
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def exampleIndividualDocument(sourceUrl, targetUrl, replUrl):
|
|
415
|
+
"""
|
|
416
|
+
Example function how to test check status of particular replication document
|
|
417
|
+
This function should run through CMSWEB frontend URLs as we need to compare
|
|
418
|
+
documents in both source and target CouchDB instances
|
|
419
|
+
:param sourceUrl: source couchdb URL, e.g. https://xxx.cern.ch/couchdb/test_db
|
|
420
|
+
:param targetUrl: target couchdb URL, e.g. https://xxx.cern.ch/couchdb/test_db
|
|
421
|
+
:param replUrl: replication URL, e.g. https://xxx.cern.ch/couchdb/test_db/_replicator/bla
|
|
422
|
+
"""
|
|
423
|
+
try:
|
|
424
|
+
result = compareCouchInstances(sourceUrl, targetUrl, replUrl)
|
|
425
|
+
print('--- compare CouchDB Instances ---')
|
|
426
|
+
print('source: ', sourceUrl)
|
|
427
|
+
print('target: ', targetUrl)
|
|
428
|
+
print(result)
|
|
429
|
+
except:
|
|
430
|
+
pass
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def test():
|
|
434
|
+
"""
|
|
435
|
+
test functions
|
|
436
|
+
"""
|
|
437
|
+
import sys
|
|
438
|
+
if len(sys.argv) > 1:
|
|
439
|
+
sourceUrl = sys.argv[1]
|
|
440
|
+
exampleReplicationStatus(sourceUrl)
|
|
441
|
+
else:
|
|
442
|
+
print("Cannot run tests, please provide at least CouchDB source URL, or <srcUrl> <targetUrl> <replicationId>")
|
|
443
|
+
if len(sys.argv) == 4:
|
|
444
|
+
sourceUrl = sys.argv[1]
|
|
445
|
+
targetUrl = sys.argv[2]
|
|
446
|
+
replUrl = sys.argv[3]
|
|
447
|
+
exampleIndividualDocument(sourceUrl, targetUrl, replUrl)
|
|
448
|
+
|
|
449
|
+
if __name__ == '__main__':
|
|
450
|
+
test()
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
"""
|
|
4
|
+
CouchUtils.py
|
|
5
|
+
|
|
6
|
+
Created by Dave Evans on 2010-03-11.
|
|
7
|
+
Copyright (c) 2010 Fermilab. All rights reserved.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import print_function
|
|
10
|
+
|
|
11
|
+
from future import standard_library
|
|
12
|
+
standard_library.install_aliases()
|
|
13
|
+
|
|
14
|
+
from http.client import HTTPException
|
|
15
|
+
|
|
16
|
+
import functools
|
|
17
|
+
|
|
18
|
+
import WMCore.Database.CMSCouch as CMSCouch
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CouchConnectionError(Exception):
|
|
22
|
+
"""docstring for CouchConnectionError"""
|
|
23
|
+
def __init__(self, arg):
|
|
24
|
+
super(CouchConnectionError, self).__init__(arg)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def initialiseCouch(objectRef):
|
|
30
|
+
if objectRef.couchdb != None:
|
|
31
|
+
return
|
|
32
|
+
if objectRef.url == None:
|
|
33
|
+
msg = "url for couch service not provided"
|
|
34
|
+
raise CouchConnectionError(msg)
|
|
35
|
+
if objectRef.database == None:
|
|
36
|
+
msg = "database name for couch service not provided"
|
|
37
|
+
raise CouchConnectionError(msg)
|
|
38
|
+
try:
|
|
39
|
+
objectRef.server = CMSCouch.CouchServer(objectRef.url)
|
|
40
|
+
objectRef.couchdb = objectRef.server.connectDatabase(objectRef.database)
|
|
41
|
+
except HTTPException as e:
|
|
42
|
+
msg = "%s with status: %s, reason: %s and result: %s" % (repr(e),
|
|
43
|
+
getattr(e, 'status', ""),
|
|
44
|
+
getattr(e, 'reason', ""),
|
|
45
|
+
getattr(e, 'result', ""))
|
|
46
|
+
raise CouchConnectionError(msg)
|
|
47
|
+
except Exception as e:
|
|
48
|
+
msg = "Exception instantiating couch services for :\n"
|
|
49
|
+
msg += " url = %s\n database = %s\n" % (objectRef.url, objectRef.database)
|
|
50
|
+
msg += " Exception: %s" % str(e)
|
|
51
|
+
print(msg)
|
|
52
|
+
raise CouchConnectionError(msg)
|
|
53
|
+
|
|
54
|
+
def connectToCouch(funcRef):
|
|
55
|
+
"""
|
|
56
|
+
_connectToCouch_
|
|
57
|
+
|
|
58
|
+
Decorator method to connect the function's class object to couch
|
|
59
|
+
"""
|
|
60
|
+
@functools.wraps(funcRef)
|
|
61
|
+
def wrapper(x, *args, **opts):
|
|
62
|
+
initialiseCouch(x)
|
|
63
|
+
return funcRef(x, *args, **opts)
|
|
64
|
+
return wrapper
|
|
65
|
+
|
|
66
|
+
def requireOwner(func):
|
|
67
|
+
"""
|
|
68
|
+
_requireOwner_
|
|
69
|
+
|
|
70
|
+
Decorator to ensure that the owner attribute of a couch ACDC object is not None
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
def wrapper(self, *args, **opts):
|
|
74
|
+
if self.owner == None:
|
|
75
|
+
msg = "Owner not provided for Collection"
|
|
76
|
+
raise RuntimeError(msg)
|
|
77
|
+
return func(self, *args, **opts)
|
|
78
|
+
return wrapper
|
|
79
|
+
|
|
80
|
+
def requireCollection(func):
|
|
81
|
+
"""
|
|
82
|
+
_requireCollection_
|
|
83
|
+
|
|
84
|
+
Decorator to ensure that the collection attribute of a couch ACDC object is not None
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def wrapper(self, *args, **opts):
|
|
88
|
+
if self.collection == None:
|
|
89
|
+
msg = "Collection not provided for Collection"
|
|
90
|
+
raise RuntimeError(msg)
|
|
91
|
+
return func(self, *args, **opts)
|
|
92
|
+
return wrapper
|
|
93
|
+
|
|
94
|
+
def requireFilesetName(func):
|
|
95
|
+
"""
|
|
96
|
+
_requireFilesetName_
|
|
97
|
+
|
|
98
|
+
Decorator to require that a fileset has a name that is not None
|
|
99
|
+
|
|
100
|
+
"""
|
|
101
|
+
def wrapper(self, *args, **opts):
|
|
102
|
+
if not 'name' in self or self['name'] == None:
|
|
103
|
+
raise RuntimeError("Filesets must be named")
|
|
104
|
+
return func(self, *args, **opts)
|
|
105
|
+
return wrapper
|
|
106
|
+
|
|
107
|
+
def requireCollectionName(func):
|
|
108
|
+
"""
|
|
109
|
+
_requireCollectionName_
|
|
110
|
+
|
|
111
|
+
Decorator to require that a collection has a name that is not None
|
|
112
|
+
|
|
113
|
+
"""
|
|
114
|
+
def wrapper(self, *args, **opts):
|
|
115
|
+
if not 'name' in self or self['name'] == None:
|
|
116
|
+
raise RuntimeError("Filesets must be named")
|
|
117
|
+
return func(self, *args, **opts)
|
|
118
|
+
return wrapper
|