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,327 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Script to create a dedicated DAOFactory and execute a single DAO.
|
|
5
|
+
|
|
6
|
+
This script is intended to be used by developers and experts only.
|
|
7
|
+
The execution environment should be under any of the WMAgents we have. And the full set
|
|
8
|
+
of agent management and initialisation scripts need to be sourced in advance i.e.:
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
|
|
12
|
+
For production:
|
|
13
|
+
source /data/admin/wmagent/env.sh
|
|
14
|
+
source /data/srv/wmagent/current/apps/wmagent/etc/profile.d/init.sh
|
|
15
|
+
python3 ExecuteDAO.py [--options] -- [SQL Query Arguments]
|
|
16
|
+
|
|
17
|
+
For tier0:
|
|
18
|
+
source /data/tier0/admin/env.sh
|
|
19
|
+
source /data/tier0/srv/wmagent/current/apps/t0/etc/profile.d/init.sh
|
|
20
|
+
python3 ExecuteDAO.py [--options] -- [SQL Query Arguments]
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import sys
|
|
25
|
+
import os
|
|
26
|
+
import re
|
|
27
|
+
|
|
28
|
+
import threading
|
|
29
|
+
import logging
|
|
30
|
+
import argparse
|
|
31
|
+
import pickle
|
|
32
|
+
from pprint import pformat
|
|
33
|
+
|
|
34
|
+
from WMCore.DAOFactory import DAOFactory
|
|
35
|
+
from WMCore.WMInit import WMInit
|
|
36
|
+
from WMCore.Agent.Configuration import Configuration, loadConfigurationFile
|
|
37
|
+
from Utils.FileTools import loadEnvFile
|
|
38
|
+
|
|
39
|
+
def parseArgs():
|
|
40
|
+
"""
|
|
41
|
+
Generic Argument Parser function
|
|
42
|
+
"""
|
|
43
|
+
parser = argparse.ArgumentParser(
|
|
44
|
+
prog='ExecuteDAO',
|
|
45
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
46
|
+
description=__doc__)
|
|
47
|
+
|
|
48
|
+
parser.add_argument('-c', '--config', required=False,
|
|
49
|
+
default=os.environ.get("WMA_CONFIG_FILE", None),
|
|
50
|
+
help="""\
|
|
51
|
+
The WMAgent config file to be used for the this execution. Default is taken from
|
|
52
|
+
the current's shell environment variable $WMA_CONFIG_FILE
|
|
53
|
+
""")
|
|
54
|
+
parser.add_argument('-e', '--envFile', required=False,
|
|
55
|
+
default=os.environ.get("WMA_ENV_FILE", None),
|
|
56
|
+
help="""
|
|
57
|
+
The WMAgent environment file to be used for the this execution. Default is taken from
|
|
58
|
+
the current's shell environment variable $WMA_ENV_FILE
|
|
59
|
+
""")
|
|
60
|
+
parser.add_argument('-p', '--package', required=True,
|
|
61
|
+
help="""\
|
|
62
|
+
The package from which the DAO factory to be created for this execution, e.g. WMCore.WMBS or WMComponent.DBS3Buffer""")
|
|
63
|
+
parser.add_argument('-m', '--module', required=True,
|
|
64
|
+
help="""\
|
|
65
|
+
The DAO Module to be executed, e.g. Workflow.GetDeletableWorkflows or CountUndeletedBlocksByWorkflow""")
|
|
66
|
+
parser.add_argument('-d', '--debug', action='store_true', default=False,
|
|
67
|
+
help="""\
|
|
68
|
+
Set logging to debug mode.""")
|
|
69
|
+
parser.add_argument('--dryRun', action='store_true', default=False,
|
|
70
|
+
help="""\
|
|
71
|
+
Simulation mode only""")
|
|
72
|
+
parser.add_argument('-s', '--sqlKwArgs', default={},
|
|
73
|
+
help="""\
|
|
74
|
+
Named paramaters to be forwarded to the DAO execute method and used as SQL arguments in the query.
|
|
75
|
+
Should be formatted as a dictionary e.g.:
|
|
76
|
+
-s "{'workflowName': name, injected: True}"
|
|
77
|
+
""")
|
|
78
|
+
parser.add_argument('sqlArgs', nargs=argparse.REMAINDER, default=(),
|
|
79
|
+
help="""\
|
|
80
|
+
-- Positional parameters to be forwarded to the DAO execute method and used as SQL arguments in the query.""")
|
|
81
|
+
parser.add_argument('-f', '--pklFile', default=None,
|
|
82
|
+
help="""\
|
|
83
|
+
An extra *.pkl file containing any additional python objects needed for the given dao
|
|
84
|
+
e.g. WMCore.WMBS.Files.AddRunLumi.
|
|
85
|
+
The object is always loaded under the name `pklFile`. One can access the contents of the so loaded pkl file
|
|
86
|
+
during the dao execution trough the -s arguent e.g.:
|
|
87
|
+
ExecuteDAO.py -p WMCore.WMBS -m Files.AddRunLumi -c $WMA_CONFIG_FILE -f runLumiBinds_2035-4016.pkl -s "{'file': pklFile['data']}
|
|
88
|
+
""")
|
|
89
|
+
currArgs = parser.parse_args()
|
|
90
|
+
|
|
91
|
+
return currArgs
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def loggerSetup(logLevel=logging.INFO):
|
|
95
|
+
"""
|
|
96
|
+
Return a logger which writes everything to stdout.
|
|
97
|
+
"""
|
|
98
|
+
currLogger = logging.getLogger()
|
|
99
|
+
outHandler = logging.StreamHandler(sys.stdout)
|
|
100
|
+
outHandler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(module)s: %(message)s"))
|
|
101
|
+
outHandler.setLevel(logLevel)
|
|
102
|
+
if currLogger.handlers:
|
|
103
|
+
currLogger.handlers.clear()
|
|
104
|
+
currLogger.addHandler(outHandler)
|
|
105
|
+
currLogger.setLevel(logLevel)
|
|
106
|
+
return currLogger
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def getBackendFromDbURL(dburl):
|
|
110
|
+
"""
|
|
111
|
+
Auxiliary function for determining sql dialect from a connection Url
|
|
112
|
+
:param dbUrl: The connection Url to be parsed.
|
|
113
|
+
:return: A string pointing to the correct dialect.
|
|
114
|
+
"""
|
|
115
|
+
dialectPart = dburl.split(":")[0]
|
|
116
|
+
if dialectPart == 'mysql':
|
|
117
|
+
return 'MySQL'
|
|
118
|
+
elif dialectPart == 'oracle':
|
|
119
|
+
return 'Oracle'
|
|
120
|
+
else:
|
|
121
|
+
raise RuntimeError("Unrecognized dialect %s" % dialectPart)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class ExecuteDAO():
|
|
125
|
+
"""
|
|
126
|
+
A generic class to create the DAO Factory and execute the DAO module.
|
|
127
|
+
"""
|
|
128
|
+
def __init__(self, connectUrl=None, socket=None, configFile=None,
|
|
129
|
+
package=None, daoModule=None, logger=None):
|
|
130
|
+
"""
|
|
131
|
+
__init__
|
|
132
|
+
The ExecuteDAO constructor method.
|
|
133
|
+
:param package: The Package from which the DAO factory to be initialised.
|
|
134
|
+
:param connectUrl: Database connection URL (overwrites the connectUrl param from configFile if both present)
|
|
135
|
+
:param socket: Database connection URL (overwrites the socket param from configFile if both present)
|
|
136
|
+
:param module: The DAO module to be executed.
|
|
137
|
+
"""
|
|
138
|
+
# Get the current thread:
|
|
139
|
+
myThread = threading.currentThread()
|
|
140
|
+
|
|
141
|
+
# Create default WMCore Init thread and configs:
|
|
142
|
+
self.init = WMInit()
|
|
143
|
+
|
|
144
|
+
if logger is None:
|
|
145
|
+
self.init.setLogging()
|
|
146
|
+
self.logger = logging.getLogger()
|
|
147
|
+
else:
|
|
148
|
+
self.logger = logger
|
|
149
|
+
|
|
150
|
+
if configFile is not None:
|
|
151
|
+
self.logger.info("Loading configFile: %s", configFile)
|
|
152
|
+
config = loadConfigurationFile(configFile)
|
|
153
|
+
else:
|
|
154
|
+
config = Configuration()
|
|
155
|
+
|
|
156
|
+
# Overwrite database config parameters from configFile if present as init arguments:
|
|
157
|
+
config.section_("CoreDatabase")
|
|
158
|
+
if connectUrl is not None:
|
|
159
|
+
config.CoreDatabase.connectUrl = connectUrl
|
|
160
|
+
|
|
161
|
+
if socket is not None:
|
|
162
|
+
config.CoreDatabase.socket = socket
|
|
163
|
+
|
|
164
|
+
# If still no proper database connection parameters provided,
|
|
165
|
+
# last resort - try fetching them from the environment:
|
|
166
|
+
if getattr(config.CoreDatabase, "connectUrl", None) is None and os.getenv('DATABASE', None):
|
|
167
|
+
config.CoreDatabase.connectUrl = os.getenv('DATABASE')
|
|
168
|
+
config.CoreDatabase.dialect = getBackendFromDbURL(os.getenv("DATABASE"))
|
|
169
|
+
config.CoreDatabase.socket = os.getenv("DBSOCK", None)
|
|
170
|
+
|
|
171
|
+
# always try to determine the dialect from the URL
|
|
172
|
+
if getattr(config.CoreDatabase, "connectUrl", None):
|
|
173
|
+
config.CoreDatabase.dialect = getBackendFromDbURL(config.CoreDatabase.connectUrl)
|
|
174
|
+
|
|
175
|
+
# finally if no socket is provided, set it to None and let WMInit to create it.
|
|
176
|
+
config.CoreDatabase.socket = getattr(config.CoreDatabase, "socket", None)
|
|
177
|
+
|
|
178
|
+
# check if all database connection parameters are provided:
|
|
179
|
+
if not all([getattr(config.CoreDatabase, "connectUrl", None),
|
|
180
|
+
getattr(config.CoreDatabase, "dialect", None)]):
|
|
181
|
+
raise RuntimeError("You must set proper DATABASE parameters: connectUrl, dialect, socket!")
|
|
182
|
+
|
|
183
|
+
# Connecting to database:
|
|
184
|
+
self.init.setDatabaseConnection(config.CoreDatabase.connectUrl,
|
|
185
|
+
config.CoreDatabase.dialect,
|
|
186
|
+
socketLoc=config.CoreDatabase.socket)
|
|
187
|
+
|
|
188
|
+
self.dbi = myThread.dbi
|
|
189
|
+
self.package = package
|
|
190
|
+
self.daoModule = daoModule
|
|
191
|
+
|
|
192
|
+
# Avoid any name that starts with _
|
|
193
|
+
self.sqlRegEx = re.compile("^(?!_.*)", re.IGNORECASE)
|
|
194
|
+
|
|
195
|
+
self.daoFactory = DAOFactory(package=package,
|
|
196
|
+
logger=self.logger,
|
|
197
|
+
dbinterface=self.dbi)
|
|
198
|
+
self.logger.info("DAO Factory initialised from package: %s", self.package)
|
|
199
|
+
|
|
200
|
+
self.dao = self.daoFactory(classname=daoModule)
|
|
201
|
+
self.logger.info("DAO Module initialised as: %s", self.daoModule)
|
|
202
|
+
|
|
203
|
+
def __call__(self, *sqlArgs, dryRun=False, daoHelp=False, **sqlKwArgs):
|
|
204
|
+
"""
|
|
205
|
+
__call__
|
|
206
|
+
The ExecuteDAO call method. This is the method to forward all provided
|
|
207
|
+
arguments to the execute method of the DAO and return the result from the query
|
|
208
|
+
:param dryRun: Bool flag to indicate dryrun method
|
|
209
|
+
:param *sqlArgs: All positional arguments to be forwarded to the DAO's execute method.
|
|
210
|
+
:param **sqlKwArgs: All named arguments to be forwarded to the DAO's execute method.
|
|
211
|
+
:return: The result from the DAO. Depending on the DAO itself it Could be one of:
|
|
212
|
+
* A dictionary
|
|
213
|
+
* A list
|
|
214
|
+
* A generator
|
|
215
|
+
"""
|
|
216
|
+
if dryRun:
|
|
217
|
+
results = []
|
|
218
|
+
if daoHelp:
|
|
219
|
+
self.getHelp()
|
|
220
|
+
self.logger.info("DAO SQL queries to be executed:")
|
|
221
|
+
sqlQueries = self.getSqlQuery()
|
|
222
|
+
for sqlName, sqlStr in sqlQueries.items():
|
|
223
|
+
msg = "\n----------------------------------------------------------------------\n"
|
|
224
|
+
msg += "%s: %s"
|
|
225
|
+
msg += "\n----------------------------------------------------------------------\n"
|
|
226
|
+
self.logger.info(msg, sqlName, sqlStr)
|
|
227
|
+
self.logger.info("DAO SQL arguments provided:\n%s, %s", pformat(sqlArgs), pformat(sqlKwArgs))
|
|
228
|
+
else:
|
|
229
|
+
results = self.dao.execute(*sqlArgs, **sqlKwArgs)
|
|
230
|
+
# self.logger.info("DAO Results:\n%s", pformat(results if isinstance(results, dict) else list(results)))
|
|
231
|
+
if isinstance(results, dict):
|
|
232
|
+
self.logger.info("DAO Results:\n%s", pformat(results))
|
|
233
|
+
elif isinstance(results, bool):
|
|
234
|
+
self.logger.info("DAO Results:\n%s", results)
|
|
235
|
+
else:
|
|
236
|
+
self.logger.info("DAO Results:\n%s", list(results))
|
|
237
|
+
return results
|
|
238
|
+
|
|
239
|
+
def getSqlQuery(self):
|
|
240
|
+
"""
|
|
241
|
+
A simple method to inspect all DAO object attributes and accumulate any sql query it finds in a simple list
|
|
242
|
+
:return: A list of all sql queries it finds in the object.
|
|
243
|
+
"""
|
|
244
|
+
# NOTE: Use this method with caution because it may also return an object which is not an sql query.
|
|
245
|
+
# This may happen if there is a DAO attribute which is of type string and satisfies self.sqlRegEx
|
|
246
|
+
sqlQueries = {}
|
|
247
|
+
for attr in dir(self.dao):
|
|
248
|
+
if self.sqlRegEx.match(attr) and isinstance(getattr(self.dao, attr), (str, bytes)):
|
|
249
|
+
sqlQueries[attr] = getattr(self.dao, attr)
|
|
250
|
+
return sqlQueries
|
|
251
|
+
|
|
252
|
+
def getHelp(self):
|
|
253
|
+
"""
|
|
254
|
+
A simple method to generate interactive DAO help message from the DAO source.
|
|
255
|
+
"""
|
|
256
|
+
help(self.dao)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def strToDict(dString, logger=None):
|
|
260
|
+
"""
|
|
261
|
+
A simple Function to parse a string and produce a dictionary out of it.
|
|
262
|
+
:param dString: The dictionary string to be parsed. Possible formats are either a string
|
|
263
|
+
of multiple space separated named values of the form 'name=value':
|
|
264
|
+
or a srting fully defining the dictionary itself.
|
|
265
|
+
:return: The constructed dictionary
|
|
266
|
+
"""
|
|
267
|
+
if not logger:
|
|
268
|
+
logger = logging.getLogger()
|
|
269
|
+
# result = ast.literal_eval(dString)
|
|
270
|
+
result = eval(dString)
|
|
271
|
+
if not isinstance(result, dict):
|
|
272
|
+
logger.error("The Query named arguments need to be provided as a dictionary. WRONG option: %s", pformat(dString))
|
|
273
|
+
raise TypeError(pformat(dString))
|
|
274
|
+
return result
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
if __name__ == '__main__':
|
|
278
|
+
args = parseArgs()
|
|
279
|
+
|
|
280
|
+
if args.debug:
|
|
281
|
+
logger = loggerSetup(logging.DEBUG)
|
|
282
|
+
else:
|
|
283
|
+
logger = loggerSetup()
|
|
284
|
+
|
|
285
|
+
# Create an instance of the *.pkl file provided with the dao call, if any.
|
|
286
|
+
if args.pklFile:
|
|
287
|
+
pklFilePath = os.path.normpath(args.pklFile)
|
|
288
|
+
if not os.path.exists(pklFilePath):
|
|
289
|
+
logger.error("Cannot find the pkl file: %s. Exit!", pklFilePath)
|
|
290
|
+
sys.exit(1)
|
|
291
|
+
with open(pklFilePath, 'rb') as fd:
|
|
292
|
+
pklFile = pickle.load(fd)
|
|
293
|
+
logger.info('PklFile: %s loaded as: `pklFile`. You can refer to its content through the -s argument.', pklFilePath)
|
|
294
|
+
# logger.info(pformat(pklFile))
|
|
295
|
+
|
|
296
|
+
# Remove leading double slash if present:
|
|
297
|
+
if args.sqlArgs and args.sqlArgs[0] == '--':
|
|
298
|
+
args.sqlArgs = args.sqlArgs[1:]
|
|
299
|
+
|
|
300
|
+
# Convert the positional arguments to a tuple:
|
|
301
|
+
if not isinstance(args.sqlArgs, tuple):
|
|
302
|
+
args.sqlArgs = tuple(args.sqlArgs)
|
|
303
|
+
|
|
304
|
+
# Parse named arguments to a proper dictionary:
|
|
305
|
+
if not isinstance(args.sqlKwArgs, dict):
|
|
306
|
+
args.sqlKwArgs = strToDict(args.sqlKwArgs)
|
|
307
|
+
|
|
308
|
+
# Trying to load WMA_ENV_FILE
|
|
309
|
+
if not args.envFile or not os.path.exists(args.envFile):
|
|
310
|
+
logger.warning("Missing WMAgent environment file! One may expect DAO misbehavior!")
|
|
311
|
+
else:
|
|
312
|
+
logger.info("Trying to source explicitely the WMAgent environment file: %s", args.envFile)
|
|
313
|
+
try:
|
|
314
|
+
loadEnvFile(args.envFile)
|
|
315
|
+
except Exception as ex:
|
|
316
|
+
logger.error("Failed to load wmaEnvFile: %s", args.envFile)
|
|
317
|
+
raise
|
|
318
|
+
|
|
319
|
+
if not args.config or not os.path.exists(args.config):
|
|
320
|
+
logger.warning("Missing WMAgent config file! One may expect DAO failure")
|
|
321
|
+
else:
|
|
322
|
+
# resetting the configuration file in the env (if the default is overwritten through args)
|
|
323
|
+
os.environ['WMAGENT_CONFIG'] = args.config
|
|
324
|
+
os.environ['WMA_CONFIG_FILE'] = args.config
|
|
325
|
+
|
|
326
|
+
daoObject = ExecuteDAO(package=args.package, daoModule=args.module, configFile=args.config)
|
|
327
|
+
daoObject(*args.sqlArgs, dryRun=args.dryRun, daoHelp=True, **args.sqlKwArgs)
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""
|
|
2
|
+
File : MongoDB.py
|
|
3
|
+
Description: Provides a wrapper class for MongoDB
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# futures
|
|
7
|
+
from __future__ import division, print_function
|
|
8
|
+
from builtins import str, object
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
import mongomock
|
|
12
|
+
except ImportError:
|
|
13
|
+
# this library should only be required by unit tests
|
|
14
|
+
mongomock = None
|
|
15
|
+
|
|
16
|
+
from pymongo import MongoClient, errors, IndexModel
|
|
17
|
+
from pymongo.errors import ConnectionFailure
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MongoDB(object):
|
|
21
|
+
"""
|
|
22
|
+
A simple wrapper class for creating a connection to a MongoDB instance
|
|
23
|
+
"""
|
|
24
|
+
def __init__(self, database=None, server=None,
|
|
25
|
+
create=False, collections=None, testIndexes=False,
|
|
26
|
+
logger=None, mockMongoDB=False, **kwargs):
|
|
27
|
+
"""
|
|
28
|
+
:databases: A database Name to connect to
|
|
29
|
+
:server: The server url or a list of (server:port) pairs (see https://docs.mongodb.com/manual/reference/connection-string/)
|
|
30
|
+
:create: A flag to trigger a database creation (if missing) during
|
|
31
|
+
object construction, together with collections if present.
|
|
32
|
+
:collections: A list of tuples describing collections with indexes -
|
|
33
|
+
the first element is considered the collection name, all
|
|
34
|
+
the rest elements are considered as indexes
|
|
35
|
+
:testIndexes: A flag to trigger index test and eventually to create them
|
|
36
|
+
if missing (TODO)
|
|
37
|
+
:mockMongoDB: A flag to trigger a database simulation instead of trying
|
|
38
|
+
to connect to a real database server.
|
|
39
|
+
:logger: Logger
|
|
40
|
+
|
|
41
|
+
Here follows a short list of usefull optional parameters accepted by the
|
|
42
|
+
MongoClient which may be passed as keyword arguments to the current module:
|
|
43
|
+
|
|
44
|
+
:replicaSet: The name of the replica set to connect to. The driver will verify
|
|
45
|
+
that all servers it connects to match this name. Implies that the
|
|
46
|
+
hosts specified are a seed list and the driver should attempt to
|
|
47
|
+
find all members of the set. Defaults to None.
|
|
48
|
+
:port: The port number on which to connect. It is overwritten by the ports
|
|
49
|
+
defined in the Url string or from the tuples listed in the server list
|
|
50
|
+
:connect: If True, immediately begin connecting to MongoDB in the background.
|
|
51
|
+
Otherwise connect on the first operation.
|
|
52
|
+
:directConnection: If True, forces the client to connect directly to the specified MongoDB
|
|
53
|
+
host as a standalone. If False, the client connects to the entire
|
|
54
|
+
replica set of which the given MongoDB host(s) is a part.
|
|
55
|
+
If this is True and a mongodb+srv:// URI or a URI containing multiple
|
|
56
|
+
seeds is provided, an exception will be raised.
|
|
57
|
+
:username: A string
|
|
58
|
+
:password: A string
|
|
59
|
+
Although username and password must be percent-escaped in a MongoDB URI,
|
|
60
|
+
they must not be percent-escaped when passed as parameters. In this example,
|
|
61
|
+
both the space and slash special characters are passed as-is:
|
|
62
|
+
MongoClient(username="user name", password="pass/word")
|
|
63
|
+
"""
|
|
64
|
+
self.server = server
|
|
65
|
+
self.logger = logger
|
|
66
|
+
self.mockMongoDB = mockMongoDB
|
|
67
|
+
if mockMongoDB and mongomock is None:
|
|
68
|
+
msg = "You are trying to mock MongoDB, but you do not have mongomock in the python path."
|
|
69
|
+
self.logger.critical(msg)
|
|
70
|
+
raise ImportError(msg)
|
|
71
|
+
|
|
72
|
+
# NOTE: We need to explicitely check for server availiability.
|
|
73
|
+
# From pymongo Documentation: https://pymongo.readthedocs.io/en/stable/api/pymongo/mongo_client.html
|
|
74
|
+
# """
|
|
75
|
+
# ...
|
|
76
|
+
# Starting with version 3.0 the :class:`MongoClient`
|
|
77
|
+
# constructor no longer blocks while connecting to the server or
|
|
78
|
+
# servers, and it no longer raises
|
|
79
|
+
# :class:`~pymongo.errors.ConnectionFailure` if they are
|
|
80
|
+
# unavailable, nor :class:`~pymongo.errors.ConfigurationError`
|
|
81
|
+
# if the user's credentials are wrong. Instead, the constructor
|
|
82
|
+
# returns immediately and launches the connection process on
|
|
83
|
+
# background threads.
|
|
84
|
+
# ...
|
|
85
|
+
# """
|
|
86
|
+
try:
|
|
87
|
+
if mockMongoDB:
|
|
88
|
+
self.client = mongomock.MongoClient()
|
|
89
|
+
self.logger.info("NOTICE: MongoDB is set to use mongomock, instead of real database.")
|
|
90
|
+
else:
|
|
91
|
+
self.client = MongoClient(host=self.server, **kwargs)
|
|
92
|
+
self.client.server_info()
|
|
93
|
+
self.client.admin.command('ping')
|
|
94
|
+
except ConnectionFailure as ex:
|
|
95
|
+
msg = "Could not connect to MongoDB server: %s. Server not available. \n"
|
|
96
|
+
msg += "Giving up Now."
|
|
97
|
+
self.logger.error(msg, self.server)
|
|
98
|
+
raise ex from None
|
|
99
|
+
except Exception as ex:
|
|
100
|
+
msg = "Could not connect to MongoDB server: %s. Due to unknown reason: %s\n"
|
|
101
|
+
msg += "Giving up Now."
|
|
102
|
+
self.logger.error(msg, self.server, str(ex))
|
|
103
|
+
raise ex from None
|
|
104
|
+
self.create = create
|
|
105
|
+
self.testIndexes = testIndexes
|
|
106
|
+
self.dbName = database
|
|
107
|
+
self.collections = collections or []
|
|
108
|
+
|
|
109
|
+
self._dbConnect(database)
|
|
110
|
+
|
|
111
|
+
if self.create and self.collections:
|
|
112
|
+
for collection in self.collections:
|
|
113
|
+
self._collCreate(collection, database)
|
|
114
|
+
|
|
115
|
+
if self.testIndexes and self.collections:
|
|
116
|
+
for collection in self.collections:
|
|
117
|
+
self._indexTest(collection[0], collection[1])
|
|
118
|
+
|
|
119
|
+
def _indexTest(self, collection, index):
|
|
120
|
+
pass
|
|
121
|
+
|
|
122
|
+
def _collTest(self, coll, db):
|
|
123
|
+
# self[db].list_collection_names()
|
|
124
|
+
pass
|
|
125
|
+
|
|
126
|
+
def collCreate(self, coll):
|
|
127
|
+
"""
|
|
128
|
+
A public method for _collCreate
|
|
129
|
+
"""
|
|
130
|
+
self._collCreate(coll, self.database)
|
|
131
|
+
|
|
132
|
+
def _collCreate(self, coll, db):
|
|
133
|
+
"""
|
|
134
|
+
A function used to explicitly create a collection with the relevant
|
|
135
|
+
indexes - used to avoid the Lazy Creating from MongoDB and eventual issues
|
|
136
|
+
in case we end up with no indexed collection, especially ones missing
|
|
137
|
+
the (`unique` index parameter)
|
|
138
|
+
:coll: A tuple describing one collection with indexes -
|
|
139
|
+
The first element is considered to be the collection name, and all
|
|
140
|
+
the rest of the elements are considered to be indexes.
|
|
141
|
+
The indexes must be of type IndexModel. See pymongo documentation:
|
|
142
|
+
|
|
143
|
+
https://api.mongodb.com/python/current/api/pymongo/collection.html#pymongo.collection.Collection.create_index
|
|
144
|
+
|
|
145
|
+
:db: The database name for the collection
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
collName = coll[0]
|
|
149
|
+
collIndexes = list(coll[1:])
|
|
150
|
+
try:
|
|
151
|
+
self.client[db].create_collection(collName)
|
|
152
|
+
except errors.CollectionInvalid:
|
|
153
|
+
# this error is thrown in case of an already existing collection
|
|
154
|
+
msg = "Collection '{}' Already exists in database '{}'".format(coll, db)
|
|
155
|
+
self.logger.warning(msg)
|
|
156
|
+
|
|
157
|
+
if collIndexes:
|
|
158
|
+
for index in collIndexes:
|
|
159
|
+
if not isinstance(index, IndexModel):
|
|
160
|
+
msg = "ERR: Bad Index type for collection %s" % collName
|
|
161
|
+
raise errors.InvalidName
|
|
162
|
+
try:
|
|
163
|
+
self.client[db][collName].create_indexes(collIndexes)
|
|
164
|
+
except Exception as ex:
|
|
165
|
+
msg = "Failed to create indexes on collection: %s\n%s" % (collName, str(ex))
|
|
166
|
+
self.logger.error(msg)
|
|
167
|
+
raise ex
|
|
168
|
+
|
|
169
|
+
def _dbTest(self, db):
|
|
170
|
+
"""
|
|
171
|
+
Tests database connection.
|
|
172
|
+
"""
|
|
173
|
+
# Test connection (from mongoDB documentation):
|
|
174
|
+
# https://api.mongodb.com/python/3.4.0/api/pymongo/mongo_client.html
|
|
175
|
+
try:
|
|
176
|
+
# The 'ismaster' command is cheap and does not require auth.
|
|
177
|
+
self.client.admin.command('ismaster')
|
|
178
|
+
except errors.ConnectionFailure as ex:
|
|
179
|
+
msg = "Server not available: %s" % str(ex)
|
|
180
|
+
self.logger.error(msg)
|
|
181
|
+
raise ex
|
|
182
|
+
|
|
183
|
+
# Test for database existence
|
|
184
|
+
if db not in self.client.list_database_names():
|
|
185
|
+
msg = "Missing MongoDB databases: %s" % db
|
|
186
|
+
self.logger.error(msg)
|
|
187
|
+
raise errors.InvalidName
|
|
188
|
+
|
|
189
|
+
def _dbCreate(self, db):
|
|
190
|
+
# creating an empty collection in order to create the database
|
|
191
|
+
_initColl = self.client[db].create_collection('_initCollection')
|
|
192
|
+
_initColl.insert_one({})
|
|
193
|
+
# NOTE: never delete the _initCollection if you want the database to persist
|
|
194
|
+
# self.client[db].drop_collection('_initCollection')
|
|
195
|
+
|
|
196
|
+
def dbConnect(self):
|
|
197
|
+
"""
|
|
198
|
+
A public method for _dbConnect
|
|
199
|
+
"""
|
|
200
|
+
self._dbConnect(self.database)
|
|
201
|
+
|
|
202
|
+
def _dbConnect(self, db):
|
|
203
|
+
"""
|
|
204
|
+
The function to be used for the initial database connection creation and testing
|
|
205
|
+
"""
|
|
206
|
+
try:
|
|
207
|
+
setattr(self, db, self.client[db])
|
|
208
|
+
if not self.mockMongoDB:
|
|
209
|
+
self._dbTest(db)
|
|
210
|
+
except errors.ConnectionFailure as ex:
|
|
211
|
+
msg = "Could not connect to MongoDB server for database: %s\n%s\n" % (db, str(ex))
|
|
212
|
+
msg += "Giving up Now."
|
|
213
|
+
self.logger.error(msg)
|
|
214
|
+
raise ex
|
|
215
|
+
except errors.InvalidName as ex:
|
|
216
|
+
msg = "Could not connect to a missing MongoDB databases: %s\n%s" % (db, str(ex))
|
|
217
|
+
self.logger.error(msg)
|
|
218
|
+
if self.create:
|
|
219
|
+
msg = "Trying to create: %s" % db
|
|
220
|
+
self.logger.error(msg)
|
|
221
|
+
try:
|
|
222
|
+
# self._dbCreate(getattr(self, db))
|
|
223
|
+
self._dbCreate(db)
|
|
224
|
+
except Exception as exc:
|
|
225
|
+
msg = "Could not create MongoDB databases: %s\n%s\n" % (db, str(exc))
|
|
226
|
+
msg += "Giving up Now."
|
|
227
|
+
self.logger.error(msg)
|
|
228
|
+
raise exc
|
|
229
|
+
try:
|
|
230
|
+
self._dbTest(db)
|
|
231
|
+
except Exception as exc:
|
|
232
|
+
msg = "Second failure while testing %s\n%s\n" % (db, str(exc))
|
|
233
|
+
msg += "Giving up Now."
|
|
234
|
+
self.logger.error(msg)
|
|
235
|
+
raise exc
|
|
236
|
+
msg = "Database %s successfully created" % db
|
|
237
|
+
self.logger.error(msg)
|
|
238
|
+
except Exception as ex:
|
|
239
|
+
msg = "General Exception while trying to connect to : %s\n%s" % (db, str(ex))
|
|
240
|
+
self.logger.error(msg)
|
|
241
|
+
raise ex
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""
|
|
2
|
+
_Destroy_
|
|
3
|
+
|
|
4
|
+
Implementation of Destroy for MySQL
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from WMCore.Database.DBFormatter import DBFormatter
|
|
9
|
+
|
|
10
|
+
class Destroy(DBFormatter):
|
|
11
|
+
|
|
12
|
+
def execute(self, subscription = None, conn = None, transaction = False):
|
|
13
|
+
|
|
14
|
+
sql = """SELECT DATABASE() AS dbname"""
|
|
15
|
+
|
|
16
|
+
results = self.dbi.processData(sql, {}, conn = conn,
|
|
17
|
+
transaction = transaction)
|
|
18
|
+
|
|
19
|
+
dbName = self.formatDict(results)[0]['dbname']
|
|
20
|
+
|
|
21
|
+
if dbName == None or dbName == 'None':
|
|
22
|
+
# Then we have no database.
|
|
23
|
+
# This presents us with a problem. We've been asked to clear a
|
|
24
|
+
# non-existant DB.
|
|
25
|
+
# Obviously we can't drop it, so what we have to do is try
|
|
26
|
+
# to pull the URL from the threaded dbi and use that
|
|
27
|
+
# to create the proper db
|
|
28
|
+
dbName = self.dbi.engine.url.database
|
|
29
|
+
else:
|
|
30
|
+
sql = """DROP DATABASE %s""" % dbName
|
|
31
|
+
self.dbi.processData(sql, {}, conn = conn,
|
|
32
|
+
transaction = transaction)
|
|
33
|
+
|
|
34
|
+
sql = """CREATE DATABASE %s""" % dbName
|
|
35
|
+
self.dbi.processData(sql, {}, conn = conn,
|
|
36
|
+
transaction = transaction)
|
|
37
|
+
|
|
38
|
+
sql = """USE %s""" % dbName
|
|
39
|
+
self.dbi.processData(sql, {}, conn = conn,
|
|
40
|
+
transaction = transaction)
|
|
41
|
+
|
|
42
|
+
return
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
_ListUserContent_
|
|
3
|
+
|
|
4
|
+
Implementation of ListUserContent for MySQL
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from WMCore.Database.DBFormatter import DBFormatter
|
|
9
|
+
|
|
10
|
+
class ListUserContent(DBFormatter):
|
|
11
|
+
|
|
12
|
+
def execute(self, subscription = None, conn = None, transaction = False):
|
|
13
|
+
|
|
14
|
+
sql = """SELECT table_name FROM information_schema.tables
|
|
15
|
+
WHERE table_schema = (SELECT DATABASE())"""
|
|
16
|
+
|
|
17
|
+
result = self.dbi.processData(sql, {}, conn = conn,
|
|
18
|
+
transaction = transaction)
|
|
19
|
+
|
|
20
|
+
return self.formatDict(result)
|