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,624 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# pylint: disable=C0103,R0913,W0102
|
|
3
|
+
"""
|
|
4
|
+
_Requests_
|
|
5
|
+
|
|
6
|
+
A set of classes to handle making http and https requests to a remote server and
|
|
7
|
+
deserialising the response.
|
|
8
|
+
|
|
9
|
+
The response from the remote server is cached if expires/etags are set.
|
|
10
|
+
Note that the cache can have two different behaviors:
|
|
11
|
+
1. when WMCORE_CACHE_DIR is defined: it defines one specific path to be used for the
|
|
12
|
+
cache files. Cache files are never automatically cleaned up and it's up to the user/
|
|
13
|
+
maintainer to do so. Note that cache directories are named after the base class.
|
|
14
|
+
2. otherwise, the system will use the Operating System temp dir to store the cache files,
|
|
15
|
+
which uses `/tmp` as default for Linux systems. When using these temporary areas, the
|
|
16
|
+
cache files are automatically cleaned up when the object using it is destroyed and
|
|
17
|
+
garbage collected. Cache directories carry a random name.
|
|
18
|
+
|
|
19
|
+
By default, all of the WMCore central services define the CACHE_DIR (to use /data/srv/state).
|
|
20
|
+
"""
|
|
21
|
+
from __future__ import division, print_function
|
|
22
|
+
|
|
23
|
+
from future import standard_library
|
|
24
|
+
standard_library.install_aliases()
|
|
25
|
+
|
|
26
|
+
from builtins import str, bytes, object
|
|
27
|
+
from future.utils import viewvalues
|
|
28
|
+
|
|
29
|
+
import base64
|
|
30
|
+
import logging
|
|
31
|
+
import os
|
|
32
|
+
import shutil
|
|
33
|
+
import socket
|
|
34
|
+
import stat
|
|
35
|
+
import tempfile
|
|
36
|
+
import traceback
|
|
37
|
+
import types
|
|
38
|
+
|
|
39
|
+
from urllib.parse import urlparse, urlencode
|
|
40
|
+
from io import BytesIO
|
|
41
|
+
from http.client import HTTPException
|
|
42
|
+
from json import JSONEncoder, JSONDecoder
|
|
43
|
+
|
|
44
|
+
from Utils.CertTools import getKeyCertFromEnv, getCAPathFromEnv
|
|
45
|
+
from Utils.Utilities import encodeUnicodeToBytes, decodeBytesToUnicode
|
|
46
|
+
from Utils.PythonVersion import PY3
|
|
47
|
+
from WMCore.Algorithms import Permissions
|
|
48
|
+
from WMCore.Lexicon import sanitizeURL
|
|
49
|
+
from WMCore.WMException import WMException
|
|
50
|
+
from WMCore.Wrappers.JsonWrapper.JSONThunker import JSONThunker
|
|
51
|
+
from Utils.PortForward import portForward
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
from WMCore.Services.pycurl_manager import RequestHandler, ResponseHeader
|
|
55
|
+
except ImportError:
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
from httplib2 import ServerNotFoundError
|
|
60
|
+
except ImportError:
|
|
61
|
+
# Mock ServerNotFoundError since we don't want that WMCore depend on httplib2 using pycurl
|
|
62
|
+
class ServerNotFoundError(Exception):
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def check_server_url(srvurl):
|
|
67
|
+
"""Check given url for correctness"""
|
|
68
|
+
good_name = srvurl.startswith('http://') or srvurl.startswith('https://')
|
|
69
|
+
if not good_name:
|
|
70
|
+
msg = "You must include "
|
|
71
|
+
msg += "http(s):// in your server's address, %s doesn't" % srvurl
|
|
72
|
+
raise ValueError(msg)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class Requests(dict):
|
|
76
|
+
"""
|
|
77
|
+
Generic class for sending different types of HTTP Request to a given URL
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
@portForward(8443)
|
|
81
|
+
def __init__(self, url='http://localhost', idict=None):
|
|
82
|
+
"""
|
|
83
|
+
url should really be host - TODO fix that when have sufficient code
|
|
84
|
+
coverage and change _getURLOpener if needed
|
|
85
|
+
"""
|
|
86
|
+
if not idict:
|
|
87
|
+
idict = {}
|
|
88
|
+
dict.__init__(self, idict)
|
|
89
|
+
self.pycurl = idict.get('pycurl', True)
|
|
90
|
+
self.capath = idict.get('capath', None)
|
|
91
|
+
if self.pycurl:
|
|
92
|
+
self.reqmgr = RequestHandler()
|
|
93
|
+
|
|
94
|
+
# set up defaults
|
|
95
|
+
self.setdefault("accept_type", 'text/html')
|
|
96
|
+
self.setdefault("content_type", 'application/x-www-form-urlencoded')
|
|
97
|
+
self.additionalHeaders = {}
|
|
98
|
+
|
|
99
|
+
# check for basic auth early, as if found this changes the url
|
|
100
|
+
urlComponent = sanitizeURL(url)
|
|
101
|
+
if urlComponent['username'] is not None:
|
|
102
|
+
self.addBasicAuth(urlComponent['username'], urlComponent['password'])
|
|
103
|
+
# CouchDB 3.x requires user/passwd in the source/target of replication docs
|
|
104
|
+
# More info in: https://github.com/dmwm/WMCore/pull/11001
|
|
105
|
+
url = urlComponent['url'] # remove user, password from url
|
|
106
|
+
|
|
107
|
+
self.setdefault("host", url)
|
|
108
|
+
|
|
109
|
+
# then update with the incoming dict
|
|
110
|
+
self.update(idict)
|
|
111
|
+
|
|
112
|
+
self['endpoint_components'] = urlparse(self['host'])
|
|
113
|
+
|
|
114
|
+
# If cachepath = None disable caching
|
|
115
|
+
if 'cachepath' in idict and idict['cachepath'] is None:
|
|
116
|
+
self["req_cache_path"] = None
|
|
117
|
+
else:
|
|
118
|
+
cache_dir = (self.cachePath(idict.get('cachepath'), idict.get('service_name')))
|
|
119
|
+
self["cachepath"] = cache_dir
|
|
120
|
+
self["req_cache_path"] = os.path.join(cache_dir, '.cache')
|
|
121
|
+
|
|
122
|
+
# Try to resolve the key/cert pair path in the constructor:
|
|
123
|
+
# NOTE: Calling self.getKeyCert() assures that if the pair is already provided by
|
|
124
|
+
# the caller (e.g. the higher level Service class) through the `idict' argument
|
|
125
|
+
# during construction time, no additional os.environ calls would be made.
|
|
126
|
+
# If the pair is not provided anywhere: not by the higher level class
|
|
127
|
+
# nor from the environment, Exception will be raised early during construction
|
|
128
|
+
# time rather than later during an internel method call.
|
|
129
|
+
self.setdefault("cert", None)
|
|
130
|
+
self.setdefault("key", None)
|
|
131
|
+
self['key'], self['cert'] = self.getKeyCert()
|
|
132
|
+
|
|
133
|
+
self.setdefault('capath', None)
|
|
134
|
+
self['capath'] = self.getCAPath()
|
|
135
|
+
|
|
136
|
+
self.setdefault("timeout", 300)
|
|
137
|
+
self.setdefault("logger", logging)
|
|
138
|
+
|
|
139
|
+
check_server_url(self['host'])
|
|
140
|
+
|
|
141
|
+
def get(self, uri=None, data={}, incoming_headers={},
|
|
142
|
+
encode=True, decode=True, contentType=None):
|
|
143
|
+
"""
|
|
144
|
+
GET some data
|
|
145
|
+
"""
|
|
146
|
+
return self.makeRequest(uri, data, 'GET', incoming_headers,
|
|
147
|
+
encode, decode, contentType)
|
|
148
|
+
|
|
149
|
+
def post(self, uri=None, data={}, incoming_headers={},
|
|
150
|
+
encode=True, decode=True, contentType=None):
|
|
151
|
+
"""
|
|
152
|
+
POST some data
|
|
153
|
+
"""
|
|
154
|
+
return self.makeRequest(uri, data, 'POST', incoming_headers,
|
|
155
|
+
encode, decode, contentType)
|
|
156
|
+
|
|
157
|
+
def put(self, uri=None, data={}, incoming_headers={},
|
|
158
|
+
encode=True, decode=True, contentType=None):
|
|
159
|
+
"""
|
|
160
|
+
PUT some data
|
|
161
|
+
"""
|
|
162
|
+
return self.makeRequest(uri, data, 'PUT', incoming_headers,
|
|
163
|
+
encode, decode, contentType)
|
|
164
|
+
|
|
165
|
+
def delete(self, uri=None, data={}, incoming_headers={},
|
|
166
|
+
encode=True, decode=True, contentType=None):
|
|
167
|
+
"""
|
|
168
|
+
DELETE some data
|
|
169
|
+
"""
|
|
170
|
+
return self.makeRequest(uri, data, 'DELETE', incoming_headers,
|
|
171
|
+
encode, decode, contentType)
|
|
172
|
+
|
|
173
|
+
def makeRequest(self, uri=None, data=None, verb='GET', incoming_headers=None,
|
|
174
|
+
encoder=True, decoder=True, contentType=None):
|
|
175
|
+
"""
|
|
176
|
+
Wrapper around request helper functions.
|
|
177
|
+
"""
|
|
178
|
+
data = data or {}
|
|
179
|
+
incoming_headers = incoming_headers or {}
|
|
180
|
+
data, headers = self.encodeParams(data, verb, incoming_headers, encoder, contentType)
|
|
181
|
+
|
|
182
|
+
# both httpib2/pycurl require absolute url
|
|
183
|
+
uri = self['host'] + uri
|
|
184
|
+
if self.pycurl:
|
|
185
|
+
result, response = self.makeRequest_pycurl(uri, data, verb, headers)
|
|
186
|
+
else:
|
|
187
|
+
result, response = self.makeRequest_httplib(uri, data, verb, headers)
|
|
188
|
+
|
|
189
|
+
result = self.decodeResult(result, decoder)
|
|
190
|
+
return result, response.status, response.reason, response.fromcache
|
|
191
|
+
|
|
192
|
+
def makeRequest_pycurl(self, uri, data, verb, headers):
|
|
193
|
+
"""
|
|
194
|
+
Make HTTP(s) request via pycurl library. Stay complaint with
|
|
195
|
+
makeRequest_httplib method.
|
|
196
|
+
"""
|
|
197
|
+
ckey, cert = self.getKeyCert()
|
|
198
|
+
capath = self.getCAPath()
|
|
199
|
+
|
|
200
|
+
headers["Accept-Encoding"] = "gzip,deflate,identity"
|
|
201
|
+
|
|
202
|
+
response, result = self.reqmgr.request(uri, data, headers, verb=verb,
|
|
203
|
+
ckey=ckey, cert=cert, capath=capath)
|
|
204
|
+
return result, response
|
|
205
|
+
|
|
206
|
+
def makeRequest_httplib(self, uri, data, verb, headers):
|
|
207
|
+
"""
|
|
208
|
+
Make a request to the remote database. for a give URI. The type of
|
|
209
|
+
request will determine the action take by the server (be careful with
|
|
210
|
+
DELETE!). Data should be a dictionary of {dataname: datavalue}.
|
|
211
|
+
|
|
212
|
+
Returns a tuple of the data from the server, decoded using the
|
|
213
|
+
appropriate method the response status and the response reason, to be
|
|
214
|
+
used in error handling.
|
|
215
|
+
|
|
216
|
+
You can override the method to encode/decode your data by passing in an
|
|
217
|
+
encoding/decoding function to this method. Your encoded data must end up
|
|
218
|
+
as a string.
|
|
219
|
+
|
|
220
|
+
"""
|
|
221
|
+
if verb == 'GET' and data:
|
|
222
|
+
uri = "%s?%s" % (uri, data)
|
|
223
|
+
|
|
224
|
+
assert isinstance(data, (str, bytes)), \
|
|
225
|
+
"Data in makeRequest is %s and not encoded to a string" % type(data)
|
|
226
|
+
|
|
227
|
+
# And now overwrite any headers that have been passed into the call:
|
|
228
|
+
# WARNING: doesn't work with deplate so only accept gzip
|
|
229
|
+
headers["Accept-Encoding"] = "gzip,identity"
|
|
230
|
+
|
|
231
|
+
# httplib2 will allow sockets to close on remote end without retrying
|
|
232
|
+
# try to send request - if this fails try again - should then succeed
|
|
233
|
+
try:
|
|
234
|
+
conn = self._getURLOpener()
|
|
235
|
+
response, result = conn.request(uri, method=verb, body=data, headers=headers)
|
|
236
|
+
if response.status == 408: # timeout can indicate a socket error
|
|
237
|
+
raise socket.error
|
|
238
|
+
except ServerNotFoundError as ex:
|
|
239
|
+
# DNS cannot resolve this domain name, let's call it 'Service Unavailable'
|
|
240
|
+
e = HTTPException()
|
|
241
|
+
setattr(e, 'url', uri)
|
|
242
|
+
setattr(e, 'status', 503)
|
|
243
|
+
setattr(e, 'reason', 'Service Unavailable')
|
|
244
|
+
setattr(e, 'result', str(ex))
|
|
245
|
+
raise e from None
|
|
246
|
+
except (socket.error, AttributeError):
|
|
247
|
+
self['logger'].warning("Http request failed, retrying once again..")
|
|
248
|
+
# AttributeError implies initial connection error - need to close
|
|
249
|
+
# & retry. httplib2 doesn't clear httplib state before next request
|
|
250
|
+
# if this is threaded this may spoil things
|
|
251
|
+
# only have one endpoint so don't need to determine which to shut
|
|
252
|
+
for con in viewvalues(conn.connections):
|
|
253
|
+
con.close()
|
|
254
|
+
conn = self._getURLOpener()
|
|
255
|
+
# ... try again... if this fails propagate error to client
|
|
256
|
+
try:
|
|
257
|
+
response, result = conn.request(uri, method=verb, body=data, headers=headers)
|
|
258
|
+
except AttributeError:
|
|
259
|
+
msg = 'Error contacting: {}: {}'.format(self.getDomainName(), traceback.format_exc())
|
|
260
|
+
# socket/httplib really screwed up - nuclear option
|
|
261
|
+
conn.connections = {}
|
|
262
|
+
raise socket.error(msg) from None
|
|
263
|
+
if response.status >= 400:
|
|
264
|
+
e = HTTPException()
|
|
265
|
+
setattr(e, 'req_data', data)
|
|
266
|
+
setattr(e, 'req_headers', headers)
|
|
267
|
+
setattr(e, 'url', uri)
|
|
268
|
+
setattr(e, 'result', result)
|
|
269
|
+
setattr(e, 'status', response.status)
|
|
270
|
+
setattr(e, 'reason', response.reason)
|
|
271
|
+
setattr(e, 'headers', response)
|
|
272
|
+
raise e
|
|
273
|
+
|
|
274
|
+
return result, response
|
|
275
|
+
|
|
276
|
+
def encodeParams(self, data, verb, incomingHeaders, encoder, contentType):
|
|
277
|
+
"""
|
|
278
|
+
Encode request parameters for usage with the 4 verbs.
|
|
279
|
+
Assume params is already encoded if it is a string and
|
|
280
|
+
uses a different encoding depending on the HTTP verb
|
|
281
|
+
(either json.dumps or urllib.urlencode)
|
|
282
|
+
"""
|
|
283
|
+
# TODO: User agent should be:
|
|
284
|
+
# $client/$client_version (CMS)
|
|
285
|
+
# $http_lib/$http_lib_version $os/$os_version ($arch)
|
|
286
|
+
headers = {"Content-type": contentType if contentType else self['content_type'],
|
|
287
|
+
"User-Agent": "WMCore.Services.Requests/v002",
|
|
288
|
+
"Accept": self['accept_type']}
|
|
289
|
+
|
|
290
|
+
for key in self.additionalHeaders:
|
|
291
|
+
headers[key] = self.additionalHeaders[key]
|
|
292
|
+
# And now overwrite any headers that have been passed into the call:
|
|
293
|
+
# WARNING: doesn't work with deplate so only accept gzip
|
|
294
|
+
incomingHeaders["Accept-Encoding"] = "gzip,identity"
|
|
295
|
+
headers.update(incomingHeaders)
|
|
296
|
+
|
|
297
|
+
# If you're posting an attachment, the data might not be a dict
|
|
298
|
+
# please test against ConfigCache_t if you're unsure.
|
|
299
|
+
# assert type(data) == type({}), \
|
|
300
|
+
# "makeRequest input data must be a dict (key/value pairs)"
|
|
301
|
+
encoded_data = ''
|
|
302
|
+
if verb != 'GET' and data:
|
|
303
|
+
if isinstance(encoder, (types.MethodType, types.FunctionType)):
|
|
304
|
+
encoded_data = encoder(data)
|
|
305
|
+
elif encoder is False:
|
|
306
|
+
# Don't encode the data more than we have to
|
|
307
|
+
# we don't want to URL encode the data blindly,
|
|
308
|
+
# that breaks POSTing attachments... ConfigCache_t
|
|
309
|
+
# encoded_data = urllib.urlencode(data)
|
|
310
|
+
# -- Andrew Melo 25/7/09
|
|
311
|
+
encoded_data = data
|
|
312
|
+
else:
|
|
313
|
+
# Either the encoder is set to True or it's junk, so use
|
|
314
|
+
# self.encode
|
|
315
|
+
encoded_data = self.encode(data)
|
|
316
|
+
headers["Content-Length"] = len(encoded_data)
|
|
317
|
+
elif verb != 'GET':
|
|
318
|
+
# delete requests might not have any body
|
|
319
|
+
headers["Content-Length"] = 0
|
|
320
|
+
elif verb == 'GET' and data:
|
|
321
|
+
# encode the data as a get string
|
|
322
|
+
encoded_data = urlencode(data, doseq=True)
|
|
323
|
+
|
|
324
|
+
return encoded_data, headers
|
|
325
|
+
|
|
326
|
+
def decodeResult(self, result, decoder):
|
|
327
|
+
"""
|
|
328
|
+
Decode the http/pycurl request result
|
|
329
|
+
NOTE: if decoder is provided with a False value, then it means no
|
|
330
|
+
decoding is applied on the results at all
|
|
331
|
+
"""
|
|
332
|
+
if isinstance(decoder, (types.MethodType, types.FunctionType)):
|
|
333
|
+
result = decoder(result)
|
|
334
|
+
elif decoder is not False:
|
|
335
|
+
result = self.decode(result)
|
|
336
|
+
return result
|
|
337
|
+
|
|
338
|
+
def encode(self, data):
|
|
339
|
+
"""
|
|
340
|
+
encode data into some appropriate format, for now make it a string...
|
|
341
|
+
"""
|
|
342
|
+
return urlencode(data, doseq=True)
|
|
343
|
+
|
|
344
|
+
def decode(self, data):
|
|
345
|
+
"""
|
|
346
|
+
decode data to some appropriate format, for now make it a string...
|
|
347
|
+
"""
|
|
348
|
+
if PY3:
|
|
349
|
+
return decodeBytesToUnicode(data)
|
|
350
|
+
return data.__str__()
|
|
351
|
+
|
|
352
|
+
def cachePath(self, given_path, service_name):
|
|
353
|
+
"""Return cache location"""
|
|
354
|
+
if not service_name:
|
|
355
|
+
service_name = 'REQUESTS'
|
|
356
|
+
top = self.cacheTopPath(given_path, service_name)
|
|
357
|
+
|
|
358
|
+
# deal with multiple Services that have the same service running and
|
|
359
|
+
# with multiple users for a given Service
|
|
360
|
+
if self.getUserName() is None:
|
|
361
|
+
cachepath = os.path.join(top, self['endpoint_components'].netloc)
|
|
362
|
+
else:
|
|
363
|
+
cachepath = os.path.join(top, '%s-%s' % (self.getUserName(), self.getDomainName()))
|
|
364
|
+
|
|
365
|
+
try:
|
|
366
|
+
# only we should be able to write to this dir
|
|
367
|
+
os.makedirs(cachepath, stat.S_IRWXU)
|
|
368
|
+
except OSError:
|
|
369
|
+
if not os.path.isdir(cachepath):
|
|
370
|
+
raise
|
|
371
|
+
Permissions.owner_readwriteexec(cachepath)
|
|
372
|
+
|
|
373
|
+
return cachepath
|
|
374
|
+
|
|
375
|
+
def cacheTopPath(self, given_path, service_name):
|
|
376
|
+
"""Where to cache results?
|
|
377
|
+
|
|
378
|
+
Logic:
|
|
379
|
+
o If passed in take that
|
|
380
|
+
o Is the environment variable "SERVICE_NAME"_CACHE_DIR defined?
|
|
381
|
+
o Is WMCORE_CACHE_DIR set
|
|
382
|
+
o Generate a temporary directory
|
|
383
|
+
"""
|
|
384
|
+
if given_path:
|
|
385
|
+
return given_path
|
|
386
|
+
user = str(os.getuid())
|
|
387
|
+
# append user id so users don't clobber each other
|
|
388
|
+
lastbit = os.path.join('.wmcore_cache_%s' % user, service_name.lower())
|
|
389
|
+
for var in ('%s_CACHE_DIR' % service_name.upper(),
|
|
390
|
+
'WMCORE_CACHE_DIR'):
|
|
391
|
+
if os.environ.get(var):
|
|
392
|
+
firstbit = os.environ[var]
|
|
393
|
+
break
|
|
394
|
+
else:
|
|
395
|
+
idir = tempfile.mkdtemp(prefix='.wmcore_cache_')
|
|
396
|
+
# Alan Malta in 29 Mar 2022: this seems to prematurely remove the cache
|
|
397
|
+
# directory. For details, see: https://github.com/dmwm/WMCore/pull/10915
|
|
398
|
+
self['deleteCacheOnExit'] = TempDirectory(idir)
|
|
399
|
+
return idir
|
|
400
|
+
|
|
401
|
+
return os.path.join(firstbit, lastbit)
|
|
402
|
+
|
|
403
|
+
def getDomainName(self):
|
|
404
|
+
"""Parse netloc info to get hostname"""
|
|
405
|
+
return self['endpoint_components'].hostname
|
|
406
|
+
|
|
407
|
+
def getUserName(self):
|
|
408
|
+
"""Parse netloc to get user"""
|
|
409
|
+
return self['endpoint_components'].username
|
|
410
|
+
|
|
411
|
+
def _getURLOpener(self):
|
|
412
|
+
"""
|
|
413
|
+
method getting a secure (HTTPS) connection
|
|
414
|
+
"""
|
|
415
|
+
import httplib2
|
|
416
|
+
key, cert = None, None
|
|
417
|
+
if self['endpoint_components'].scheme == 'https':
|
|
418
|
+
# only add certs to https requests
|
|
419
|
+
# if we have a key/cert add to request,
|
|
420
|
+
# if not proceed as not all https connections require them
|
|
421
|
+
try:
|
|
422
|
+
key, cert = self.getKeyCert()
|
|
423
|
+
except Exception as ex:
|
|
424
|
+
msg = 'No certificate or key found, authentication may fail'
|
|
425
|
+
self['logger'].info(msg)
|
|
426
|
+
self['logger'].debug(str(ex))
|
|
427
|
+
|
|
428
|
+
try:
|
|
429
|
+
# disable validation as we don't have a single PEM with all ca's
|
|
430
|
+
http = httplib2.Http(self['req_cache_path'], self['timeout'],
|
|
431
|
+
disable_ssl_certificate_validation=True)
|
|
432
|
+
except TypeError:
|
|
433
|
+
# old httplib2 versions disable validation by default
|
|
434
|
+
http = httplib2.Http(self['req_cache_path'], self['timeout'])
|
|
435
|
+
|
|
436
|
+
# Domain must be just a hostname and port. self[host] is a URL currently
|
|
437
|
+
if key or cert:
|
|
438
|
+
http.add_certificate(key=key, cert=cert, domain='')
|
|
439
|
+
return http
|
|
440
|
+
|
|
441
|
+
def addBasicAuth(self, username, password):
|
|
442
|
+
"""Add basic auth headers to request"""
|
|
443
|
+
username = encodeUnicodeToBytes(username)
|
|
444
|
+
password = encodeUnicodeToBytes(password)
|
|
445
|
+
encodedauth = base64.encodebytes(b'%s:%s' % (username, password)).strip()
|
|
446
|
+
if PY3:
|
|
447
|
+
encodedauth = decodeBytesToUnicode(encodedauth)
|
|
448
|
+
auth_string = "Basic %s" % encodedauth
|
|
449
|
+
self.additionalHeaders["Authorization"] = auth_string
|
|
450
|
+
|
|
451
|
+
def getKeyCert(self):
|
|
452
|
+
"""
|
|
453
|
+
_getKeyCert_
|
|
454
|
+
|
|
455
|
+
Get the user credentials if they exist, otherwise throw an exception.
|
|
456
|
+
This code was modified from DBSAPI/dbsHttpService.py
|
|
457
|
+
"""
|
|
458
|
+
|
|
459
|
+
# Zeroth case is if the class has over ridden the key/cert and has it
|
|
460
|
+
# stored in self
|
|
461
|
+
if self['cert'] and self['key']:
|
|
462
|
+
key = self['key']
|
|
463
|
+
cert = self['cert']
|
|
464
|
+
else:
|
|
465
|
+
key, cert = getKeyCertFromEnv()
|
|
466
|
+
|
|
467
|
+
# Set but not found
|
|
468
|
+
if key is None or cert is None:
|
|
469
|
+
raise WMException('Request requires a host certificate and key',
|
|
470
|
+
"WMCORE-11")
|
|
471
|
+
|
|
472
|
+
# All looks OK, still doesn't guarantee proxy's validity etc.
|
|
473
|
+
return key, cert
|
|
474
|
+
|
|
475
|
+
def getCAPath(self):
|
|
476
|
+
"""
|
|
477
|
+
_getCAPath_
|
|
478
|
+
|
|
479
|
+
Return the path of the CA certificates. The check is loose in the pycurl_manager:
|
|
480
|
+
is capath == None then the server identity is not verified. To enable this check
|
|
481
|
+
you need to set either the X509_CERT_DIR variable or the cacert key of the request.
|
|
482
|
+
"""
|
|
483
|
+
capath = self['capath']
|
|
484
|
+
if not capath:
|
|
485
|
+
capath = getCAPathFromEnv()
|
|
486
|
+
return capath
|
|
487
|
+
|
|
488
|
+
def uploadFile(self, fileName, url, fieldName='file1', params=[], verb='POST'):
|
|
489
|
+
"""
|
|
490
|
+
Upload a file with curl streaming it directly from disk
|
|
491
|
+
|
|
492
|
+
:rtype: bytes (both py2 and py3)
|
|
493
|
+
"""
|
|
494
|
+
ckey, cert = self.getKeyCert()
|
|
495
|
+
capath = self.getCAPath()
|
|
496
|
+
import pycurl
|
|
497
|
+
c = pycurl.Curl()
|
|
498
|
+
if verb == 'POST':
|
|
499
|
+
c.setopt(c.POST, 1)
|
|
500
|
+
elif verb == 'PUT':
|
|
501
|
+
c.setopt(pycurl.CUSTOMREQUEST, 'PUT')
|
|
502
|
+
else:
|
|
503
|
+
raise HTTPException("Verb %s not supported for upload." % verb)
|
|
504
|
+
c.setopt(c.URL, url)
|
|
505
|
+
fullParams = [(fieldName, (c.FORM_FILE, fileName))]
|
|
506
|
+
fullParams.extend(params)
|
|
507
|
+
c.setopt(c.HTTPPOST, fullParams)
|
|
508
|
+
bbuf = BytesIO()
|
|
509
|
+
hbuf = BytesIO()
|
|
510
|
+
c.setopt(pycurl.WRITEFUNCTION, bbuf.write)
|
|
511
|
+
c.setopt(pycurl.HEADERFUNCTION, hbuf.write)
|
|
512
|
+
if capath:
|
|
513
|
+
c.setopt(pycurl.CAPATH, capath)
|
|
514
|
+
c.setopt(pycurl.SSL_VERIFYPEER, True)
|
|
515
|
+
else:
|
|
516
|
+
c.setopt(pycurl.SSL_VERIFYPEER, False)
|
|
517
|
+
if ckey:
|
|
518
|
+
c.setopt(pycurl.SSLKEY, ckey)
|
|
519
|
+
if cert:
|
|
520
|
+
c.setopt(pycurl.SSLCERT, cert)
|
|
521
|
+
c.perform()
|
|
522
|
+
hres = hbuf.getvalue()
|
|
523
|
+
bres = bbuf.getvalue()
|
|
524
|
+
rh = ResponseHeader(hres)
|
|
525
|
+
c.close()
|
|
526
|
+
if rh.status < 200 or rh.status >= 300:
|
|
527
|
+
exc = HTTPException(bres)
|
|
528
|
+
setattr(exc, 'req_data', fullParams)
|
|
529
|
+
setattr(exc, 'url', url)
|
|
530
|
+
setattr(exc, 'result', bres)
|
|
531
|
+
setattr(exc, 'status', rh.status)
|
|
532
|
+
setattr(exc, 'reason', rh.reason)
|
|
533
|
+
setattr(exc, 'headers', rh.header)
|
|
534
|
+
raise exc
|
|
535
|
+
|
|
536
|
+
return bres
|
|
537
|
+
|
|
538
|
+
def downloadFile(self, fileName, url):
|
|
539
|
+
"""
|
|
540
|
+
Download a file with curl streaming it directly to disk
|
|
541
|
+
"""
|
|
542
|
+
ckey, cert = self.getKeyCert()
|
|
543
|
+
capath = self.getCAPath()
|
|
544
|
+
import pycurl
|
|
545
|
+
|
|
546
|
+
hbuf = BytesIO()
|
|
547
|
+
|
|
548
|
+
with open(fileName, "wb") as fp:
|
|
549
|
+
curl = pycurl.Curl()
|
|
550
|
+
curl.setopt(pycurl.URL, url)
|
|
551
|
+
curl.setopt(pycurl.WRITEDATA, fp)
|
|
552
|
+
curl.setopt(pycurl.HEADERFUNCTION, hbuf.write)
|
|
553
|
+
if capath:
|
|
554
|
+
curl.setopt(pycurl.CAPATH, capath)
|
|
555
|
+
curl.setopt(pycurl.SSL_VERIFYPEER, True)
|
|
556
|
+
else:
|
|
557
|
+
curl.setopt(pycurl.SSL_VERIFYPEER, False)
|
|
558
|
+
if ckey:
|
|
559
|
+
curl.setopt(pycurl.SSLKEY, ckey)
|
|
560
|
+
if cert:
|
|
561
|
+
curl.setopt(pycurl.SSLCERT, cert)
|
|
562
|
+
curl.setopt(pycurl.FOLLOWLOCATION, 1)
|
|
563
|
+
curl.perform()
|
|
564
|
+
curl.close()
|
|
565
|
+
|
|
566
|
+
header = ResponseHeader(hbuf.getvalue())
|
|
567
|
+
if header.status < 200 or header.status >= 300:
|
|
568
|
+
raise RuntimeError('Reading %s failed with code %s' % (url, header.status))
|
|
569
|
+
return fileName, header
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
class JSONRequests(Requests):
|
|
573
|
+
"""
|
|
574
|
+
Example implementation of Requests that encodes data to/from JSON.
|
|
575
|
+
"""
|
|
576
|
+
|
|
577
|
+
def __init__(self, url='http://localhost:8080', idict={}):
|
|
578
|
+
Requests.__init__(self, url, idict)
|
|
579
|
+
self['accept_type'] = "application/json"
|
|
580
|
+
self['content_type'] = "application/json"
|
|
581
|
+
|
|
582
|
+
def encode(self, data):
|
|
583
|
+
"""
|
|
584
|
+
encode data as json
|
|
585
|
+
"""
|
|
586
|
+
encoder = JSONEncoder()
|
|
587
|
+
thunker = JSONThunker()
|
|
588
|
+
thunked = thunker.thunk(data)
|
|
589
|
+
return encoder.encode(thunked)
|
|
590
|
+
|
|
591
|
+
def decode(self, data):
|
|
592
|
+
"""
|
|
593
|
+
decode the data to python from json
|
|
594
|
+
"""
|
|
595
|
+
if data:
|
|
596
|
+
decoder = JSONDecoder()
|
|
597
|
+
thunker = JSONThunker()
|
|
598
|
+
if PY3:
|
|
599
|
+
data = decodeBytesToUnicode(data)
|
|
600
|
+
data = decoder.decode(data)
|
|
601
|
+
unthunked = thunker.unthunk(data)
|
|
602
|
+
return unthunked
|
|
603
|
+
return {}
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
class TempDirectory(object):
|
|
607
|
+
"""
|
|
608
|
+
Directory that cleans up after itself
|
|
609
|
+
|
|
610
|
+
Except this doesn't work, python __del__ is NOT a destructor
|
|
611
|
+
|
|
612
|
+
Leaving it anyways, since it might work sometimes
|
|
613
|
+
|
|
614
|
+
"""
|
|
615
|
+
|
|
616
|
+
def __init__(self, idir):
|
|
617
|
+
self.dir = idir
|
|
618
|
+
|
|
619
|
+
def __del__(self):
|
|
620
|
+
try:
|
|
621
|
+
# it'll likely fail, but give it a try
|
|
622
|
+
shutil.rmtree(self.dir, ignore_errors=True)
|
|
623
|
+
except Exception:
|
|
624
|
+
pass
|