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
Utils/CPMetrics.py
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
File : CPMetrics.py
|
|
4
|
+
Author : Valentin Kuznetsov <vkuznet AT gmail dot com>
|
|
5
|
+
Description: This module provide functions to flatten cherrypy stats
|
|
6
|
+
and provide them in Prometheus format for scraping.
|
|
7
|
+
|
|
8
|
+
Below we present three different outputs:
|
|
9
|
+
- CherryPy stats default output
|
|
10
|
+
- flatten structure of stats
|
|
11
|
+
- prometheus output for stats
|
|
12
|
+
|
|
13
|
+
### Defautl CherryPy metrics output
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
"Cheroot HTTPServer 4388603856": {
|
|
17
|
+
"Accepts": 0,
|
|
18
|
+
"Accepts/sec": 0.0,
|
|
19
|
+
"Bind Address": "('127.0.0.1', 8080)",
|
|
20
|
+
"Bytes Read": -1,
|
|
21
|
+
"Bytes Written": -1,
|
|
22
|
+
"Enabled": false,
|
|
23
|
+
"Queue": 0,
|
|
24
|
+
"Read Throughput": -1,
|
|
25
|
+
"Requests": -1,
|
|
26
|
+
"Run time": -1,
|
|
27
|
+
"Socket Errors": 0,
|
|
28
|
+
"Threads": 20,
|
|
29
|
+
"Threads Idle": 19,
|
|
30
|
+
"Work Time": -1,
|
|
31
|
+
"Worker Threads": {
|
|
32
|
+
"CP Server Thread-10": {
|
|
33
|
+
"Bytes Read": 0,
|
|
34
|
+
"Bytes Written": 0,
|
|
35
|
+
"Read Throughput": 0.0,
|
|
36
|
+
"Requests": 0,
|
|
37
|
+
"Work Time": 0,
|
|
38
|
+
"Write Throughput": 0.0
|
|
39
|
+
},
|
|
40
|
+
.....
|
|
41
|
+
},
|
|
42
|
+
"Write Throughput": -1
|
|
43
|
+
},
|
|
44
|
+
"CherryPy Applications": {
|
|
45
|
+
"Bytes Read/Request": 0.0,
|
|
46
|
+
"Bytes Read/Second": 0.0,
|
|
47
|
+
"Bytes Written/Request": 0.0,
|
|
48
|
+
"Bytes Written/Second": 0.0,
|
|
49
|
+
"Current Requests": 0,
|
|
50
|
+
"Current Time": 1601039589.916887,
|
|
51
|
+
"Enabled": true,
|
|
52
|
+
"Requests": {},
|
|
53
|
+
"Requests/Second": 0.0,
|
|
54
|
+
"Server Version": "17.4.2",
|
|
55
|
+
"Start Time": 1601039576.541158,
|
|
56
|
+
"Total Bytes Read": 0,
|
|
57
|
+
"Total Bytes Written": 0,
|
|
58
|
+
"Total Requests": 0,
|
|
59
|
+
"Total Time": 0,
|
|
60
|
+
"Uptime": 13.375718116760254
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
### flatten structure via flattenStats function
|
|
65
|
+
{
|
|
66
|
+
"cherrypy_app_requests_second": 0.0,
|
|
67
|
+
"cherrypy_app_uptime": 1.7454230785369873,
|
|
68
|
+
"cherrypy_app_total_time": 0,
|
|
69
|
+
"cherrypy_app_current_time": 1601040713.369842,
|
|
70
|
+
"cherrypy_app_bytes_read_second": 0.0,
|
|
71
|
+
"cherrypy_app_requests": {},
|
|
72
|
+
"cherrypy_http_server_queue": 0,
|
|
73
|
+
"cherrypy_app_bytes_written_second": 0.0,
|
|
74
|
+
"cherrypy_app_total_requests": 0,
|
|
75
|
+
"cherrypy_http_server_write_throughput": -1,
|
|
76
|
+
"cherrypy_app_enabled": true,
|
|
77
|
+
"cherrypy_app_start_time": 1601040711.624408,
|
|
78
|
+
"cherrypy_http_server_threads": 20,
|
|
79
|
+
"cherrypy_http_server_work_time": -1,
|
|
80
|
+
"cherrypy_app_bytes_read_request": 0.0,
|
|
81
|
+
"cherrypy_http_server_bytes_read": -1,
|
|
82
|
+
"cherrypy_http_server_accepts_sec": 0.0,
|
|
83
|
+
"cherrypy_server_worker_threads": [
|
|
84
|
+
{"thread_name": "cp_server_thread_3", "read_throughput": 0.0,
|
|
85
|
+
"work_time": 0, "write_throughput": 0.0, "bytes_written": 0,
|
|
86
|
+
"bytes_read": 0, "requests": 0}, ....],
|
|
87
|
+
"cherrypy_http_server_run_time": -1,
|
|
88
|
+
"cherrypy_http_server_bind_address": "('127.0.0.1', 8080)",
|
|
89
|
+
"cherrypy_app_server_version": "17.4.2",
|
|
90
|
+
"cherrypy_http_server_enabled": false,
|
|
91
|
+
"cherrypy_http_server_socket_errors": 0,
|
|
92
|
+
"cherrypy_app_bytes_written_request": 0.0,
|
|
93
|
+
"cherrypy_app_current_requests": 0,
|
|
94
|
+
"cherrypy_app_total_bytes_read": 0,
|
|
95
|
+
"cherrypy_http_server_bytes_written": -1,
|
|
96
|
+
"cherrypy_http_server_threads_idle": 19,
|
|
97
|
+
"cherrypy_http_server_requests": -1,
|
|
98
|
+
"cherrypy_app_total_bytes_written": 0,
|
|
99
|
+
"cherrypy_http_server_read_throughput": -1,
|
|
100
|
+
"cherrypy_http_server_accepts": 0}
|
|
101
|
+
|
|
102
|
+
### prometheus exporter structure provided via promMetrics function
|
|
103
|
+
|
|
104
|
+
# HELP cherrypy_app_requests_second
|
|
105
|
+
# TYPE cherrypy_app_requests_second gauge
|
|
106
|
+
cherrypy_app_requests_second 0.0
|
|
107
|
+
# HELP cherrypy_app_uptime
|
|
108
|
+
# TYPE cherrypy_app_uptime gauge
|
|
109
|
+
cherrypy_app_uptime 2.03766894341
|
|
110
|
+
# HELP cherrypy_app_total_time
|
|
111
|
+
# TYPE cherrypy_app_total_time counter
|
|
112
|
+
cherrypy_app_total_time 0
|
|
113
|
+
# HELP cherrypy_app_current_time
|
|
114
|
+
# TYPE cherrypy_app_current_time gauge
|
|
115
|
+
cherrypy_app_current_time 1601043839.47
|
|
116
|
+
# HELP cherrypy_app_bytes_read_second
|
|
117
|
+
# TYPE cherrypy_app_bytes_read_second gauge
|
|
118
|
+
cherrypy_app_bytes_read_second 0.0
|
|
119
|
+
# HELP cherrypy_http_server_queue
|
|
120
|
+
# TYPE cherrypy_http_server_queue counter
|
|
121
|
+
cherrypy_http_server_queue 0
|
|
122
|
+
# HELP cherrypy_app_bytes_written_second
|
|
123
|
+
# TYPE cherrypy_app_bytes_written_second gauge
|
|
124
|
+
cherrypy_app_bytes_written_second 0.0
|
|
125
|
+
# HELP cherrypy_app_total_requests
|
|
126
|
+
# TYPE cherrypy_app_total_requests counter
|
|
127
|
+
cherrypy_app_total_requests 0
|
|
128
|
+
# HELP cherrypy_http_server_write_throughput
|
|
129
|
+
# TYPE cherrypy_http_server_write_throughput counter
|
|
130
|
+
cherrypy_http_server_write_throughput -1
|
|
131
|
+
# HELP cherrypy_server_worker_threads
|
|
132
|
+
# TYPE cherrypy_server_worker_threads histogram
|
|
133
|
+
cherrypy_server_worker_threads{thread_name="cp_server_thread_3",...} 1
|
|
134
|
+
# HELP cherrypy_app_start_time
|
|
135
|
+
# TYPE cherrypy_app_start_time gauge
|
|
136
|
+
cherrypy_app_start_time 1601043837.44
|
|
137
|
+
# HELP cherrypy_http_server_threads
|
|
138
|
+
# TYPE cherrypy_http_server_threads counter
|
|
139
|
+
cherrypy_http_server_threads 20
|
|
140
|
+
# HELP cherrypy_http_server_work_time
|
|
141
|
+
# TYPE cherrypy_http_server_work_time counter
|
|
142
|
+
cherrypy_http_server_work_time -1
|
|
143
|
+
# HELP cherrypy_app_bytes_read_request
|
|
144
|
+
# TYPE cherrypy_app_bytes_read_request gauge
|
|
145
|
+
cherrypy_app_bytes_read_request 0.0
|
|
146
|
+
# HELP cherrypy_http_server_bytes_read
|
|
147
|
+
# TYPE cherrypy_http_server_bytes_read counter
|
|
148
|
+
cherrypy_http_server_bytes_read -1
|
|
149
|
+
# HELP cherrypy_http_server_accepts_sec
|
|
150
|
+
# TYPE cherrypy_http_server_accepts_sec gauge
|
|
151
|
+
cherrypy_http_server_accepts_sec 0.0
|
|
152
|
+
# HELP cherrypy_http_server_run_time
|
|
153
|
+
# TYPE cherrypy_http_server_run_time counter
|
|
154
|
+
cherrypy_http_server_run_time -1
|
|
155
|
+
# HELP cherrypy_http_server_socket_errors
|
|
156
|
+
# TYPE cherrypy_http_server_socket_errors counter
|
|
157
|
+
cherrypy_http_server_socket_errors 0
|
|
158
|
+
# HELP cherrypy_app_bytes_written_request
|
|
159
|
+
# TYPE cherrypy_app_bytes_written_request gauge
|
|
160
|
+
cherrypy_app_bytes_written_request 0.0
|
|
161
|
+
# HELP cherrypy_app_current_requests
|
|
162
|
+
# TYPE cherrypy_app_current_requests counter
|
|
163
|
+
cherrypy_app_current_requests 0
|
|
164
|
+
# HELP cherrypy_app_total_bytes_read
|
|
165
|
+
# TYPE cherrypy_app_total_bytes_read counter
|
|
166
|
+
cherrypy_app_total_bytes_read 0
|
|
167
|
+
# HELP cherrypy_http_server_bytes_written
|
|
168
|
+
# TYPE cherrypy_http_server_bytes_written counter
|
|
169
|
+
cherrypy_http_server_bytes_written -1
|
|
170
|
+
# HELP cherrypy_http_server_threads_idle
|
|
171
|
+
# TYPE cherrypy_http_server_threads_idle counter
|
|
172
|
+
cherrypy_http_server_threads_idle 19
|
|
173
|
+
# HELP cherrypy_http_server_requests
|
|
174
|
+
# TYPE cherrypy_http_server_requests counter
|
|
175
|
+
cherrypy_http_server_requests -1
|
|
176
|
+
# HELP cherrypy_app_total_bytes_written
|
|
177
|
+
# TYPE cherrypy_app_total_bytes_written counter
|
|
178
|
+
cherrypy_app_total_bytes_written 0
|
|
179
|
+
# HELP cherrypy_http_server_read_throughput
|
|
180
|
+
# TYPE cherrypy_http_server_read_throughput counter
|
|
181
|
+
cherrypy_http_server_read_throughput -1
|
|
182
|
+
# HELP cherrypy_http_server_accepts
|
|
183
|
+
# TYPE cherrypy_http_server_accepts counter
|
|
184
|
+
cherrypy_http_server_accepts 0
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
# system modules
|
|
188
|
+
import json
|
|
189
|
+
|
|
190
|
+
# WMCore dependencies
|
|
191
|
+
from Utils.Utilities import decodeBytesToUnicode
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def promMetrics(data, exporter):
|
|
195
|
+
"""
|
|
196
|
+
Provide cherrypy stats prometheus metrics for given exporter name.
|
|
197
|
+
"""
|
|
198
|
+
# exporter name should not contain dashes, see
|
|
199
|
+
# https://its.cern.ch/jira/browse/CMSMONIT-514
|
|
200
|
+
exporter = exporter.replace("-", "_")
|
|
201
|
+
metrics = flattenStats(data)
|
|
202
|
+
if isinstance(metrics, str):
|
|
203
|
+
metrics = json.loads(metrics)
|
|
204
|
+
# the following keys will be skipped
|
|
205
|
+
skip = [
|
|
206
|
+
'cherrypy_app_enabled',
|
|
207
|
+
'cherrypy_http_server_bind_address',
|
|
208
|
+
'cherrypy_app_requests',
|
|
209
|
+
'cherrypy_app_server_version',
|
|
210
|
+
'cherrypy_http_server_enabled']
|
|
211
|
+
# our prometheus data representation
|
|
212
|
+
pdata = ""
|
|
213
|
+
for key, val in list(metrics.items()):
|
|
214
|
+
if key in skip:
|
|
215
|
+
continue
|
|
216
|
+
# add exporter name as a prefix for each key
|
|
217
|
+
key = '{}_{}'.format(exporter, key)
|
|
218
|
+
mhelp = "# HELP {}\n".format(key)
|
|
219
|
+
if isinstance(val, list):
|
|
220
|
+
mtype = "# TYPE {} histogram\n".format(key)
|
|
221
|
+
pdata += mhelp
|
|
222
|
+
pdata += mtype
|
|
223
|
+
for wdict in val:
|
|
224
|
+
entries = []
|
|
225
|
+
for kkk, vvv in list(wdict.items()):
|
|
226
|
+
entries.append('{}="{}"'.format(kkk, vvv))
|
|
227
|
+
entry = "{%s}" % ','.join(entries)
|
|
228
|
+
pdata += "{}{} 1\n".format(key, entry)
|
|
229
|
+
elif isinstance(val, (str, tuple)):
|
|
230
|
+
continue
|
|
231
|
+
else:
|
|
232
|
+
pdata += mhelp
|
|
233
|
+
if isinstance(val, int):
|
|
234
|
+
mtype = "# TYPE {} counter\n".format(key)
|
|
235
|
+
if isinstance(val, float):
|
|
236
|
+
mtype = "# TYPE {} gauge\n".format(key)
|
|
237
|
+
pdata += mtype
|
|
238
|
+
pdata += "{} {}\n".format(key, val)
|
|
239
|
+
return pdata
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def flattenStats(cpdata):
|
|
243
|
+
"Flatten cherrypy stats to make them suitable for monitoring"
|
|
244
|
+
if isinstance(cpdata, str) or isinstance(cpdata, bytes):
|
|
245
|
+
cpdata = json.loads(decodeBytesToUnicode(cpdata))
|
|
246
|
+
data = {}
|
|
247
|
+
for cpKey, cpVal in list(cpdata.items()):
|
|
248
|
+
if cpKey.lower().find('cherrypy') != -1:
|
|
249
|
+
for cpnKey, cpnVal in list(cpVal.items()):
|
|
250
|
+
nkey = 'cherrypy_app_%s' % cpnKey
|
|
251
|
+
nkey = nkey.lower().replace(" ", "_").replace("/", "_")
|
|
252
|
+
data[nkey] = cpnVal
|
|
253
|
+
if cpKey.lower().find('cheroot') != -1:
|
|
254
|
+
for cpnKey, cpnVal in list(cpVal.items()):
|
|
255
|
+
if cpnKey == 'Worker Threads':
|
|
256
|
+
wdata = []
|
|
257
|
+
for workerKey, threadValue in list(cpnVal.items()):
|
|
258
|
+
workerKey = workerKey.lower().replace(" ", "_").replace("/", "_").replace("-", "_")
|
|
259
|
+
threadValue['thread_name'] = workerKey
|
|
260
|
+
nval = {}
|
|
261
|
+
for tkey, tval in list(threadValue.items()):
|
|
262
|
+
tkey = tkey.lower().replace(" ", "_").replace("/", "_")
|
|
263
|
+
nval[tkey] = tval
|
|
264
|
+
wdata.append(nval)
|
|
265
|
+
data["cherrypy_server_worker_threads"] = wdata
|
|
266
|
+
else:
|
|
267
|
+
nkey = 'cherrypy_http_server_%s' % cpnKey
|
|
268
|
+
nkey = nkey.lower().replace(" ", "_").replace("/", "_")
|
|
269
|
+
data[nkey] = cpnVal
|
|
270
|
+
return data
|
Utils/CertTools.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module to deal with user certificates and CAs
|
|
3
|
+
"""
|
|
4
|
+
from builtins import str
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def ckey():
|
|
9
|
+
"Return user CA key either from proxy or userkey.pem"
|
|
10
|
+
pair = getKeyCertFromEnv()
|
|
11
|
+
return pair[0]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def cert():
|
|
15
|
+
"Return user CA cert either from proxy or usercert.pem"
|
|
16
|
+
pair = getKeyCertFromEnv()
|
|
17
|
+
return pair[1]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def getKeyCertFromEnv():
|
|
21
|
+
"""
|
|
22
|
+
gets key and certificate from environment variables
|
|
23
|
+
If no env variable is set return None, None for key, cert tuple
|
|
24
|
+
|
|
25
|
+
First preference to HOST Certificate, This is how it set in Tier0
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
envPairs = [('X509_HOST_KEY', 'X509_HOST_CERT'), # First preference to HOST Certificate,
|
|
29
|
+
('X509_USER_PROXY', 'X509_USER_PROXY'), # Second preference to User Proxy, very common
|
|
30
|
+
('X509_USER_KEY', 'X509_USER_CERT')] # Third preference to User Cert/Proxy combinition
|
|
31
|
+
|
|
32
|
+
for keyEnv, certEnv in envPairs:
|
|
33
|
+
localKey = os.environ.get(keyEnv)
|
|
34
|
+
localCert = os.environ.get(certEnv)
|
|
35
|
+
if localKey and localCert and os.path.exists(localKey) and os.path.exists(localCert):
|
|
36
|
+
# if it is found in env return key, cert
|
|
37
|
+
return localKey, localCert
|
|
38
|
+
|
|
39
|
+
# TODO: only in linux, unix case, add other os case
|
|
40
|
+
# look for proxy at default location /tmp/x509up_u$uid
|
|
41
|
+
localKey = localCert = '/tmp/x509up_u' + str(os.getuid())
|
|
42
|
+
if os.path.exists(localKey):
|
|
43
|
+
return localKey, localCert
|
|
44
|
+
|
|
45
|
+
# Finary look for globaus location
|
|
46
|
+
if (os.environ.get('HOME') and
|
|
47
|
+
os.path.exists(os.environ['HOME'] + '/.globus/usercert.pem') and
|
|
48
|
+
os.path.exists(os.environ['HOME'] + '/.globus/userkey.pem')):
|
|
49
|
+
|
|
50
|
+
localKey = os.environ['HOME'] + '/.globus/userkey.pem'
|
|
51
|
+
localCert = os.environ['HOME'] + '/.globus/usercert.pem'
|
|
52
|
+
return localKey, localCert
|
|
53
|
+
# couldn't find the key, cert files
|
|
54
|
+
return None, None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def getCAPathFromEnv():
|
|
58
|
+
"""
|
|
59
|
+
_getCAPathFromEnv_
|
|
60
|
+
|
|
61
|
+
Return the path of the CA certificates. The check is loose in the pycurl_manager:
|
|
62
|
+
is capath == None then the server identity is not verified. To enable this check
|
|
63
|
+
you need to set either the X509_CERT_DIR variable or the cacert key of the request.
|
|
64
|
+
"""
|
|
65
|
+
return os.environ.get("X509_CERT_DIR")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def caBundle(caPath="/etc/grid-security/certificates"):
|
|
69
|
+
"""
|
|
70
|
+
Load all PEM certificates from the given caPath and write them as single CA bundle PEM.
|
|
71
|
+
|
|
72
|
+
:param caPath: Path to directory containing .pem certificate files.
|
|
73
|
+
:return: A single string containing all concatenated PEM pemCertificates which may be
|
|
74
|
+
written to a caBundleFile if necessary (used by requests library)
|
|
75
|
+
"""
|
|
76
|
+
if not os.path.isdir(caPath):
|
|
77
|
+
raise ValueError(f"Invalid caPath: {caPath} is not a directory")
|
|
78
|
+
|
|
79
|
+
pemCertificates = []
|
|
80
|
+
|
|
81
|
+
for fileName in sorted(os.listdir(caPath)):
|
|
82
|
+
filePath = os.path.join(caPath, fileName)
|
|
83
|
+
|
|
84
|
+
# Only consider readable files that look like PEM certificates
|
|
85
|
+
if not os.path.isfile(filePath):
|
|
86
|
+
continue
|
|
87
|
+
if not fileName.endswith(".pem"):
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
with open(filePath, "r", encoding="utf-8") as istream:
|
|
92
|
+
certData = istream.read()
|
|
93
|
+
if "BEGIN CERTIFICATE" in certData:
|
|
94
|
+
pemCertificates.append(certData)
|
|
95
|
+
except Exception as e:
|
|
96
|
+
print(f"Warning: Could not read {filePath}: {e}")
|
|
97
|
+
|
|
98
|
+
if len(pemCertificates) == 0:
|
|
99
|
+
raise ValueError(f"No PEM files found in {caPath}")
|
|
100
|
+
return "\n".join(pemCertificates)
|
Utils/EmailAlert.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
EmailAlert - send alerts via email
|
|
3
|
+
|
|
4
|
+
NOTICE:
|
|
5
|
+
This class does not work from kubernetes pods. The AlertManagerAPI class should be used for alerting from k8s.
|
|
6
|
+
More details at: https://github.com/dmwm/WMCore/issues/10234
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
from builtins import str, object
|
|
11
|
+
import smtplib
|
|
12
|
+
import logging
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class EmailAlert(object):
|
|
16
|
+
"""
|
|
17
|
+
A simple class to send alerts via email
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
EMAIL_HEADER = "From: %s\r\nSubject: %s\r\nTo: %s\r\n\r\n"
|
|
21
|
+
|
|
22
|
+
def __init__(self, configDict):
|
|
23
|
+
self.serverName = configDict.get("smtpServer", "localhost")
|
|
24
|
+
self.fromAddr = configDict.get("fromAddr", "noreply@cern.ch")
|
|
25
|
+
self.toAddr = configDict.get("toAddr", "cms-service-production-admins@cern.ch")
|
|
26
|
+
if not isinstance(self.toAddr, (list, set)):
|
|
27
|
+
self.toAddr = [self.toAddr]
|
|
28
|
+
|
|
29
|
+
def send(self, subject, message):
|
|
30
|
+
"""
|
|
31
|
+
Send an email
|
|
32
|
+
:param subject: Email subject
|
|
33
|
+
:param message: Email body
|
|
34
|
+
"""
|
|
35
|
+
msg = self.EMAIL_HEADER % (self.fromAddr, subject, ", ".join(self.toAddr))
|
|
36
|
+
msg += message
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
smtp = smtplib.SMTP(self.serverName)
|
|
40
|
+
smtp.sendmail(self.fromAddr, self.toAddr, msg)
|
|
41
|
+
except Exception as ex:
|
|
42
|
+
logging.exception("Error sending alert email.\nDetails: %s", str(ex))
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
# clean up smtp connection
|
|
46
|
+
smtp.quit()
|
|
47
|
+
except UnboundLocalError:
|
|
48
|
+
# it means our client failed connecting to the SMTP server
|
|
49
|
+
pass
|
|
50
|
+
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#! /usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Unit testing base class with our extensions
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import copy
|
|
7
|
+
import unittest
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ExtendedUnitTestCase(unittest.TestCase):
|
|
11
|
+
"""
|
|
12
|
+
Class that can be imported to switch to 'mock'ed versions of
|
|
13
|
+
services.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def assertContentsEqual(self, expected_obj, actual_obj, msg=None):
|
|
17
|
+
"""
|
|
18
|
+
A nested object comparison without regard for the ordering of contents. It asserts that
|
|
19
|
+
expected_obj and actual_obj contain the same elements and that their sub-elements are the same.
|
|
20
|
+
However, all sequences are allowed to contain the same elements, but in different orders.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def traverse_dict(dictionary):
|
|
24
|
+
for key, value in list(dictionary.items()):
|
|
25
|
+
if isinstance(value, dict):
|
|
26
|
+
traverse_dict(value)
|
|
27
|
+
elif isinstance(value, list):
|
|
28
|
+
traverse_list(value)
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
def get_dict_sortkey(x):
|
|
32
|
+
if isinstance(x, dict):
|
|
33
|
+
return list(x.keys())
|
|
34
|
+
else:
|
|
35
|
+
return x
|
|
36
|
+
|
|
37
|
+
def traverse_list(theList):
|
|
38
|
+
for value in theList:
|
|
39
|
+
if isinstance(value, dict):
|
|
40
|
+
traverse_dict(value)
|
|
41
|
+
elif isinstance(value, list):
|
|
42
|
+
traverse_list(value)
|
|
43
|
+
theList.sort(key=get_dict_sortkey)
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
if not isinstance(expected_obj, type(actual_obj)):
|
|
47
|
+
self.fail(msg="The two objects are different type and cannot be compared: %s and %s" % (
|
|
48
|
+
type(expected_obj), type(actual_obj)))
|
|
49
|
+
|
|
50
|
+
expected = copy.deepcopy(expected_obj)
|
|
51
|
+
actual = copy.deepcopy(actual_obj)
|
|
52
|
+
|
|
53
|
+
if isinstance(expected, dict):
|
|
54
|
+
traverse_dict(expected)
|
|
55
|
+
traverse_dict(actual)
|
|
56
|
+
elif isinstance(expected, list):
|
|
57
|
+
traverse_list(expected)
|
|
58
|
+
traverse_list(actual)
|
|
59
|
+
else:
|
|
60
|
+
self.fail(msg="The two objects are different type (%s) and cannot be compared." % type(expected_obj))
|
|
61
|
+
|
|
62
|
+
return self.assertEqual(expected, actual)
|
Utils/FileTools.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Utilities related to file handling
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
import io
|
|
8
|
+
import os
|
|
9
|
+
import glob
|
|
10
|
+
import stat
|
|
11
|
+
import subprocess
|
|
12
|
+
import time
|
|
13
|
+
import zlib
|
|
14
|
+
import logging
|
|
15
|
+
|
|
16
|
+
from Utils.Utilities import decodeBytesToUnicode
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def findFiles(path, pat):
|
|
20
|
+
"""
|
|
21
|
+
Find files within given path and matching given pattern.
|
|
22
|
+
:param path: starting directory path (string)
|
|
23
|
+
:param pat: match pattern (string), e.g. *.py or name of the file
|
|
24
|
+
:return: matched file names
|
|
25
|
+
"""
|
|
26
|
+
files = []
|
|
27
|
+
for idir, _, _ in os.walk(path):
|
|
28
|
+
files.extend(glob.glob(os.path.join(idir, pat)))
|
|
29
|
+
return files
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def tarMode(tfile, opMode):
|
|
33
|
+
"""
|
|
34
|
+
Extract proper mode of operation for given tar file. For instance,
|
|
35
|
+
if op='r' and tfile name is file.tar.gz we should get 'r:gz',
|
|
36
|
+
while if tfile name is file.tar.bz2 we should get 'r':bz2', while
|
|
37
|
+
if tfile name is file.tar we should get 'r', etc.
|
|
38
|
+
:param opMode: mode of operation (string), e.g. 'r', or 'w'
|
|
39
|
+
:param tfile: sandbox tar file name (string)
|
|
40
|
+
:return: mode of operation
|
|
41
|
+
"""
|
|
42
|
+
ext = tfile.split(".")[-1]
|
|
43
|
+
if ext == 'tar':
|
|
44
|
+
return opMode
|
|
45
|
+
mode = opMode + ':' + ext
|
|
46
|
+
return mode
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def calculateChecksums(filename):
|
|
50
|
+
"""
|
|
51
|
+
_calculateChecksums_
|
|
52
|
+
|
|
53
|
+
Get the adler32 and crc32 checksums of a file. Return None on error
|
|
54
|
+
|
|
55
|
+
Process line by line and adjust for known signed vs. unsigned issues
|
|
56
|
+
http://docs.python.org/library/zlib.html
|
|
57
|
+
|
|
58
|
+
The cksum UNIX command line tool implements a CRC32 checksum that is
|
|
59
|
+
different than any of the python algorithms, therefore open cksum
|
|
60
|
+
in a subprocess and feed it the same chunks of data that are used
|
|
61
|
+
to calculate the adler32 checksum.
|
|
62
|
+
|
|
63
|
+
"""
|
|
64
|
+
adler32Checksum = 1 # adler32 of an empty string
|
|
65
|
+
cksumProcess = subprocess.Popen("cksum", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
|
66
|
+
|
|
67
|
+
# the lambda basically creates an iterator function with zero
|
|
68
|
+
# arguments that steps through the file in 4096 byte chunks
|
|
69
|
+
with open(filename, 'rb') as f:
|
|
70
|
+
for chunk in iter((lambda: f.read(4096)), b''):
|
|
71
|
+
adler32Checksum = zlib.adler32(chunk, adler32Checksum)
|
|
72
|
+
cksumProcess.stdin.write(chunk)
|
|
73
|
+
|
|
74
|
+
cksumProcess.stdin.close()
|
|
75
|
+
cksumProcess.wait()
|
|
76
|
+
|
|
77
|
+
cksumStdout = cksumProcess.stdout.read().split()
|
|
78
|
+
cksumProcess.stdout.close()
|
|
79
|
+
|
|
80
|
+
# consistency check on the cksum output
|
|
81
|
+
filesize = os.stat(filename)[stat.ST_SIZE]
|
|
82
|
+
if len(cksumStdout) != 2 or int(cksumStdout[1]) != filesize:
|
|
83
|
+
raise RuntimeError("Something went wrong with the cksum calculation !")
|
|
84
|
+
|
|
85
|
+
cksumStdout[0] = decodeBytesToUnicode(cksumStdout[0])
|
|
86
|
+
return (format(adler32Checksum & 0xffffffff, '08x'), cksumStdout[0])
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def tail(filename, nLines=20):
|
|
90
|
+
"""
|
|
91
|
+
_tail_
|
|
92
|
+
|
|
93
|
+
A version of tail
|
|
94
|
+
Adapted from code on http://stackoverflow.com/questions/136168/get-last-n-lines-of-a-file-with-python-similar-to-tail
|
|
95
|
+
"""
|
|
96
|
+
assert nLines >= 0
|
|
97
|
+
pos, lines = nLines + 1, []
|
|
98
|
+
|
|
99
|
+
# make sure only valid utf8 encoded chars will be passed along
|
|
100
|
+
with io.open(filename, 'r', encoding='utf8', errors='ignore') as f:
|
|
101
|
+
while len(lines) <= nLines:
|
|
102
|
+
try:
|
|
103
|
+
f.seek(-pos, 2)
|
|
104
|
+
except IOError:
|
|
105
|
+
f.seek(0)
|
|
106
|
+
break
|
|
107
|
+
finally:
|
|
108
|
+
lines = list(f)
|
|
109
|
+
pos *= 2
|
|
110
|
+
|
|
111
|
+
text = "".join(lines[-nLines:])
|
|
112
|
+
|
|
113
|
+
return text
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def getFileInfo(filename):
|
|
117
|
+
"""
|
|
118
|
+
_getFileInfo_
|
|
119
|
+
|
|
120
|
+
Return file info in a friendly format
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
filestats = os.stat(filename)
|
|
124
|
+
|
|
125
|
+
fileInfo = {'Name': filename,
|
|
126
|
+
'Size': filestats[stat.ST_SIZE],
|
|
127
|
+
'LastModification': time.strftime("%m/%d/%Y %I:%M:%S %p", time.localtime(filestats[stat.ST_MTIME])),
|
|
128
|
+
'LastAccess': time.strftime("%m/%d/%Y %I:%M:%S %p", time.localtime(filestats[stat.ST_ATIME]))}
|
|
129
|
+
return fileInfo
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def findMagicStr(filename, matchString):
|
|
133
|
+
"""
|
|
134
|
+
_findMagicStr_
|
|
135
|
+
|
|
136
|
+
Parse a log file looking for a pattern string
|
|
137
|
+
"""
|
|
138
|
+
with io.open(filename, 'r', encoding='utf8', errors='ignore') as logfile:
|
|
139
|
+
# TODO: can we avoid reading the whole file
|
|
140
|
+
for line in logfile:
|
|
141
|
+
if matchString in line:
|
|
142
|
+
yield line
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def getFullPath(name, envPath="PATH"):
|
|
146
|
+
"""
|
|
147
|
+
:param name: file name
|
|
148
|
+
:param envPath: any environment variable specified for path (PATH, PYTHONPATH, etc)
|
|
149
|
+
:return: full path if it is under PATH env
|
|
150
|
+
"""
|
|
151
|
+
for path in os.getenv(envPath).split(os.path.pathsep):
|
|
152
|
+
fullPath = os.path.join(path, name)
|
|
153
|
+
if os.path.exists(fullPath):
|
|
154
|
+
return fullPath
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def loadEnvFile(wmaEnvFilePath, logger=None):
|
|
159
|
+
"""
|
|
160
|
+
_loadEnvFile_
|
|
161
|
+
A simple function to load an additional bash env file into the current script
|
|
162
|
+
runtime environment
|
|
163
|
+
:param wmaEnvFilePath: The path to the environment file to be loaded
|
|
164
|
+
:return: True if the script has loaded successfully, False otherwise.
|
|
165
|
+
"""
|
|
166
|
+
if not logger:
|
|
167
|
+
logger = logging.getLogger()
|
|
168
|
+
subProc = subprocess.run(['bash', '-c', f'source {wmaEnvFilePath} && python -c "import os; print(repr(os.environ.copy()))" '],
|
|
169
|
+
capture_output=True, check=False)
|
|
170
|
+
if subProc.returncode == 0:
|
|
171
|
+
newEnv = eval(subProc.stdout)
|
|
172
|
+
os.environ.update(newEnv)
|
|
173
|
+
if subProc.stderr:
|
|
174
|
+
logger.warning("Environment file: %s loaded with errors:", wmaEnvFilePath)
|
|
175
|
+
logger.warning(subProc.stderr.decode())
|
|
176
|
+
else:
|
|
177
|
+
logger.info("Environment file: %s loaded successfully", wmaEnvFilePath)
|
|
178
|
+
return True
|
|
179
|
+
else:
|
|
180
|
+
logger.error("Failed to load environment file: %s", wmaEnvFilePath)
|
|
181
|
+
logger.error(subProc.stderr.decode())
|
|
182
|
+
return False
|