wmglobalqueue 2.3.10rc10__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.
Potentially problematic release.
This version of wmglobalqueue might be problematic. Click here for more details.
- Utils/CPMetrics.py +270 -0
- Utils/CertTools.py +62 -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/ProcessStats.py +103 -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 +308 -0
- Utils/__init__.py +11 -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 +651 -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 +1349 -0
- WMCore/Database/ConfigDBMap.py +29 -0
- WMCore/Database/CouchUtils.py +118 -0
- WMCore/Database/DBCore.py +198 -0
- WMCore/Database/DBCreator.py +113 -0
- WMCore/Database/DBExceptionHandler.py +57 -0
- WMCore/Database/DBFactory.py +110 -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 +623 -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 +113 -0
- WMCore/Services/DBS/DBSReader.py +23 -0
- WMCore/Services/DBS/DBSUtils.py +139 -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/PyCondorUtils.py +105 -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 +1287 -0
- WMCore/Services/Rucio/RucioUtils.py +74 -0
- WMCore/Services/Rucio/__init__.py +0 -0
- WMCore/Services/RucioConMon/RucioConMon.py +128 -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 +228 -0
- WMCore/WMLogging.py +108 -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 +1980 -0
- WMCore/WMSpec/WMWorkload.py +2288 -0
- WMCore/WMSpec/WMWorkloadTools.py +370 -0
- WMCore/WMSpec/__init__.py +9 -0
- WMCore/WorkQueue/DataLocationMapper.py +269 -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 +741 -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.3.10rc10.data/data/bin/wmc-dist-patch +15 -0
- wmglobalqueue-2.3.10rc10.data/data/bin/wmc-dist-unpatch +8 -0
- wmglobalqueue-2.3.10rc10.data/data/bin/wmc-httpd +3 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/.couchapprc +1 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/README.md +40 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/_attachments/index.html +264 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/_attachments/js/ElementInfoByWorkflow.js +96 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/_attachments/js/StuckElementInfo.js +57 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/_attachments/js/WorkloadInfoTable.js +80 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/_attachments/js/dataTable.js +70 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/_attachments/js/namespace.js +23 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/_attachments/style/main.css +75 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/couchapp.json +4 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/filters/childQueueFilter.js +13 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/filters/filterDeletedDocs.js +3 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/filters/queueFilter.js +11 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/language +1 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/lib/mustache.js +333 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/lib/validate.js +27 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/lib/workqueue_utils.js +61 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/lists/elementsDetail.js +28 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/lists/filter.js +86 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/lists/stuckElements.js +38 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/lists/workRestrictions.js +153 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/lists/workflowSummary.js +28 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/rewrites.json +73 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/shows/redirect.js +23 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/shows/status.js +40 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/templates/ElementSummaryByWorkflow.html +27 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/templates/StuckElementSummary.html +26 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/templates/TaskStatus.html +23 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/templates/WorkflowSummary.html +27 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/templates/partials/workqueue-common-lib.html +2 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib-remote.html +16 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib.html +18 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/updates/in-place.js +50 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/validate_doc_update.js +8 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.couch.app.js +235 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.pathbinder.js +173 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/activeData/map.js +8 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/activeData/reduce.js +2 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/activeParentData/map.js +8 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/activeParentData/reduce.js +2 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/activePileupData/map.js +8 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/activePileupData/reduce.js +2 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/analyticsData/map.js +11 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/analyticsData/reduce.js +1 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/availableByPriority/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/conflicts/map.js +5 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/elements/map.js +5 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/elementsByData/map.js +8 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/elementsByParent/map.js +8 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/elementsByParentData/map.js +8 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/elementsByPileupData/map.js +8 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/elementsByStatus/map.js +8 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/elementsBySubscription/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/map.js +8 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/reduce.js +3 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/elementsDetailByWorkflowAndStatus/map.js +26 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/map.js +10 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/reduce.js +1 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/reduce.js +1 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobsByRequest/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobsByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobsByStatus/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobsByStatus/reduce.js +1 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/reduce.js +1 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/openRequests/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/recent-items/map.js +5 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/specsByWorkflow/map.js +5 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/stuckElements/map.js +38 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/map.js +12 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/reduce.js +3 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/wmbsUrl/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/wmbsUrl/reduce.js +2 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/map.js +6 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/reduce.js +2 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/workflowSummary/map.js +9 -0
- wmglobalqueue-2.3.10rc10.data/data/data/couchapps/WorkQueue/views/workflowSummary/reduce.js +10 -0
- wmglobalqueue-2.3.10rc10.dist-info/METADATA +26 -0
- wmglobalqueue-2.3.10rc10.dist-info/RECORD +345 -0
- wmglobalqueue-2.3.10rc10.dist-info/WHEEL +5 -0
- wmglobalqueue-2.3.10rc10.dist-info/licenses/LICENSE +202 -0
- wmglobalqueue-2.3.10rc10.dist-info/licenses/NOTICE +16 -0
- wmglobalqueue-2.3.10rc10.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: ISO-8859-1 -*-
|
|
3
|
+
# pylint: disable=R0913,W0702,R0914,R0912,R0201
|
|
4
|
+
"""
|
|
5
|
+
File: pycurl_manager.py
|
|
6
|
+
Author: Valentin Kuznetsov <vkuznet@gmail.com>
|
|
7
|
+
Description: a basic wrapper around pycurl library.
|
|
8
|
+
The RequestHandler class provides basic APIs to get data
|
|
9
|
+
from a single resource or submit mutliple requests to
|
|
10
|
+
underlying data-services.
|
|
11
|
+
|
|
12
|
+
Examples:
|
|
13
|
+
# CERN SSO: http://linux.web.cern.ch/linux/docs/cernssocookie.shtml
|
|
14
|
+
# use RequestHandler with CERN SSO enabled site
|
|
15
|
+
mgr = RequestHandler()
|
|
16
|
+
url = "https://cms-gwmsmon.cern.ch/prodview/json/site_summary"
|
|
17
|
+
params = {}
|
|
18
|
+
tfile = tempfile.NamedTemporaryFile()
|
|
19
|
+
cern_sso_cookie(url, tfile.name, cert, ckey)
|
|
20
|
+
cookie = {url: tfile.name}
|
|
21
|
+
header, data = mgr.request(url3, params, cookie=cookie)
|
|
22
|
+
if header.status != 200:
|
|
23
|
+
print "ERROR"
|
|
24
|
+
|
|
25
|
+
# fetch multiple urls at onces from various urls
|
|
26
|
+
tfile = tempfile.NamedTemporaryFile()
|
|
27
|
+
ckey = os.path.join(os.environ['HOME'], '.globus/userkey.pem')
|
|
28
|
+
cert = os.path.join(os.environ['HOME'], '.globus/usercert.pem')
|
|
29
|
+
url1 = "https://cmsweb-prod.cern.ch/dbs/prod/global/DBSReader/help"
|
|
30
|
+
url2 = "https://cmsweb-prod.cern.ch/dbs/prod/global/DBSReader/datatiers"
|
|
31
|
+
url3 = "https://cms-gwmsmon.cern.ch/prodview/json/site_summary"
|
|
32
|
+
cern_sso_cookie(url3, tfile.name, cert, ckey)
|
|
33
|
+
cookie = {url3: tfile.name}
|
|
34
|
+
urls = [url1, url2, url3]
|
|
35
|
+
data = getdata(urls, ckey, cert, cookie=cookie)
|
|
36
|
+
for row in data:
|
|
37
|
+
print(row)
|
|
38
|
+
"""
|
|
39
|
+
from __future__ import print_function
|
|
40
|
+
from future import standard_library
|
|
41
|
+
standard_library.install_aliases()
|
|
42
|
+
|
|
43
|
+
from builtins import str, range, object
|
|
44
|
+
from past.builtins import basestring
|
|
45
|
+
from future.utils import viewitems
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# system modules
|
|
49
|
+
import copy
|
|
50
|
+
import json
|
|
51
|
+
import gzip
|
|
52
|
+
import logging
|
|
53
|
+
import os
|
|
54
|
+
import re
|
|
55
|
+
import subprocess
|
|
56
|
+
import pycurl
|
|
57
|
+
from io import BytesIO
|
|
58
|
+
import http.client
|
|
59
|
+
from urllib.parse import urlencode
|
|
60
|
+
|
|
61
|
+
from Utils.Utilities import encodeUnicodeToBytes, decodeBytesToUnicode
|
|
62
|
+
from Utils.PortForward import portForward, PortForward
|
|
63
|
+
from Utils.TokenManager import TokenManager
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def getException(url, params, headers, header, data):
|
|
67
|
+
"""
|
|
68
|
+
Return HTTP exception for a given set of parameters:
|
|
69
|
+
:param url: string
|
|
70
|
+
:param params: dict
|
|
71
|
+
:param headers: dict
|
|
72
|
+
:param header: ResponseHeader
|
|
73
|
+
:param data: HTTP body
|
|
74
|
+
"""
|
|
75
|
+
msg = 'url=%s, code=%s, reason=%s, headers=%s, result=%s' \
|
|
76
|
+
% (url, header.status, header.reason, header.header, data)
|
|
77
|
+
exc = http.client.HTTPException(msg)
|
|
78
|
+
setattr(exc, 'req_data', params)
|
|
79
|
+
setattr(exc, 'req_headers', headers)
|
|
80
|
+
setattr(exc, 'url', url)
|
|
81
|
+
setattr(exc, 'result', data)
|
|
82
|
+
setattr(exc, 'status', header.status)
|
|
83
|
+
setattr(exc, 'reason', header.reason)
|
|
84
|
+
setattr(exc, 'headers', header.header)
|
|
85
|
+
return exc
|
|
86
|
+
|
|
87
|
+
def decompress(body, headers):
|
|
88
|
+
"""
|
|
89
|
+
Helper function to decompress given body if HTTP headers contains gzip encoding
|
|
90
|
+
:param body: bytes
|
|
91
|
+
:param headers: dict
|
|
92
|
+
:return: decode body
|
|
93
|
+
"""
|
|
94
|
+
encoding = ""
|
|
95
|
+
for header, value in headers.items():
|
|
96
|
+
if header.lower() == 'content-encoding' and 'gzip' in value.lower():
|
|
97
|
+
encoding = 'gzip'
|
|
98
|
+
break
|
|
99
|
+
if encoding != 'gzip':
|
|
100
|
+
return body
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
return gzip.decompress(body)
|
|
104
|
+
except Exception as exc:
|
|
105
|
+
logger = logging.getLogger()
|
|
106
|
+
msg = "While processing decompress function with headers: %s, " % headers
|
|
107
|
+
msg += "we were unable to decompress gzip content. Details: %s. " % str(exc)
|
|
108
|
+
msg += "Considering response body as uncompressed."
|
|
109
|
+
logger.exception(msg)
|
|
110
|
+
return body
|
|
111
|
+
|
|
112
|
+
class ResponseHeader(object):
|
|
113
|
+
"""ResponseHeader parses HTTP response header"""
|
|
114
|
+
|
|
115
|
+
def __init__(self, response):
|
|
116
|
+
super(ResponseHeader, self).__init__()
|
|
117
|
+
self.header = {}
|
|
118
|
+
self.reason = ''
|
|
119
|
+
self.fromcache = False
|
|
120
|
+
self.parse(response)
|
|
121
|
+
|
|
122
|
+
def parse(self, response):
|
|
123
|
+
"""Parse response header and assign class member data"""
|
|
124
|
+
startRegex = r"^HTTP/(\d|\d.\d) \d{3}" # to match "HTTP/1.1 200" and "HTTP/2 200"
|
|
125
|
+
continueRegex = r"^HTTP/(\d|\d.\d) 100" # Continue: client should continue its request
|
|
126
|
+
|
|
127
|
+
response = decodeBytesToUnicode(response)
|
|
128
|
+
|
|
129
|
+
for row in response.split('\r'):
|
|
130
|
+
row = row.replace('\n', '')
|
|
131
|
+
if not row:
|
|
132
|
+
continue
|
|
133
|
+
if re.search(startRegex, row):
|
|
134
|
+
if re.search(continueRegex, row):
|
|
135
|
+
continue
|
|
136
|
+
# split HTTP header row on empty space
|
|
137
|
+
# for HTTP/proto STATUS REASON
|
|
138
|
+
arr = row.split(' ')
|
|
139
|
+
self.status = int(arr[1])
|
|
140
|
+
self.reason = ' '.join(arr[2:])
|
|
141
|
+
continue
|
|
142
|
+
try:
|
|
143
|
+
key, val = row.split(':', 1)
|
|
144
|
+
self.header[key.strip()] = val.strip()
|
|
145
|
+
except:
|
|
146
|
+
pass
|
|
147
|
+
|
|
148
|
+
def getReason(self):
|
|
149
|
+
"""
|
|
150
|
+
Return the HTTP request reason
|
|
151
|
+
"""
|
|
152
|
+
return self.reason
|
|
153
|
+
|
|
154
|
+
def getHeader(self):
|
|
155
|
+
"""
|
|
156
|
+
Return the header dictionary object
|
|
157
|
+
"""
|
|
158
|
+
return self.header
|
|
159
|
+
|
|
160
|
+
def getHeaderKey(self, keyName):
|
|
161
|
+
"""
|
|
162
|
+
Provided a key name, return it from the HTTP header.
|
|
163
|
+
Note that - by design - header keys are meant to be
|
|
164
|
+
case insensitive
|
|
165
|
+
:param keyName: a header key name to be looked up
|
|
166
|
+
:return: the value for that header key, or None if not found
|
|
167
|
+
"""
|
|
168
|
+
for keyHea, valHea in self.header.items():
|
|
169
|
+
if keyHea.lower() == keyName.lower():
|
|
170
|
+
return valHea
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class RequestHandler(object):
|
|
174
|
+
"""
|
|
175
|
+
RequestHandler provides APIs to fetch single/multiple
|
|
176
|
+
URL requests based on pycurl library
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
def __init__(self, config=None, logger=None):
|
|
180
|
+
super(RequestHandler, self).__init__()
|
|
181
|
+
if not config:
|
|
182
|
+
config = {}
|
|
183
|
+
defaultOpts = pycurl_options()
|
|
184
|
+
self.nosignal = config.get('nosignal', defaultOpts['NOSIGNAL'])
|
|
185
|
+
self.timeout = config.get('timeout', defaultOpts['TIMEOUT'])
|
|
186
|
+
self.connecttimeout = config.get('connecttimeout', defaultOpts['CONNECTTIMEOUT'])
|
|
187
|
+
self.followlocation = config.get('followlocation', defaultOpts['FOLLOWLOCATION'])
|
|
188
|
+
self.maxredirs = config.get('maxredirs', defaultOpts['MAXREDIRS'])
|
|
189
|
+
self.logger = logger if logger else logging.getLogger()
|
|
190
|
+
self.tokenLocation = config.get('iam_token_file', '')
|
|
191
|
+
if self.tokenLocation:
|
|
192
|
+
self.tmgr = TokenManager(self.tokenLocation)
|
|
193
|
+
else:
|
|
194
|
+
self.tmgr = None
|
|
195
|
+
|
|
196
|
+
def encode_params(self, params, verb, doseq, encode):
|
|
197
|
+
""" Encode request parameters for usage with the 4 verbs.
|
|
198
|
+
Assume params is already encoded if it is a string and
|
|
199
|
+
uses a different encoding depending on the HTTP verb
|
|
200
|
+
(either json.dumps or urllib.urlencode)
|
|
201
|
+
"""
|
|
202
|
+
if not encode:
|
|
203
|
+
return params
|
|
204
|
+
# data is already encoded, just return it
|
|
205
|
+
if isinstance(params, basestring):
|
|
206
|
+
return params
|
|
207
|
+
|
|
208
|
+
# data is not encoded, we need to do that
|
|
209
|
+
if verb in ['GET', 'HEAD']:
|
|
210
|
+
if params:
|
|
211
|
+
encoded_data = urlencode(params, doseq=doseq)
|
|
212
|
+
else:
|
|
213
|
+
return ''
|
|
214
|
+
else:
|
|
215
|
+
if params:
|
|
216
|
+
encoded_data = json.dumps(params)
|
|
217
|
+
else:
|
|
218
|
+
return {}
|
|
219
|
+
|
|
220
|
+
return encoded_data
|
|
221
|
+
|
|
222
|
+
def set_opts(self, curl, url, params, headers,
|
|
223
|
+
ckey=None, cert=None, capath=None, verbose=None,
|
|
224
|
+
verb='GET', doseq=True, encode=False, cainfo=None, cookie=None):
|
|
225
|
+
"""Set options for given curl object, params should be a dictionary"""
|
|
226
|
+
if not (isinstance(params, (dict, basestring)) or params is None):
|
|
227
|
+
raise TypeError("pycurl parameters should be passed as dictionary or an (encoded) string")
|
|
228
|
+
# ensure the original headers object remains unchanged
|
|
229
|
+
headers = headers or {} # if it's None, then make it a dict
|
|
230
|
+
thisHeaders = copy.deepcopy(headers)
|
|
231
|
+
curl.setopt(pycurl.NOSIGNAL, self.nosignal)
|
|
232
|
+
curl.setopt(pycurl.TIMEOUT, self.timeout)
|
|
233
|
+
curl.setopt(pycurl.CONNECTTIMEOUT, self.connecttimeout)
|
|
234
|
+
curl.setopt(pycurl.FOLLOWLOCATION, self.followlocation)
|
|
235
|
+
curl.setopt(pycurl.MAXREDIRS, self.maxredirs)
|
|
236
|
+
|
|
237
|
+
if cookie and url in cookie:
|
|
238
|
+
curl.setopt(pycurl.COOKIEFILE, cookie[url])
|
|
239
|
+
curl.setopt(pycurl.COOKIEJAR, cookie[url])
|
|
240
|
+
|
|
241
|
+
encoded_data = self.encode_params(params, verb, doseq, encode)
|
|
242
|
+
|
|
243
|
+
if verb == 'GET':
|
|
244
|
+
if encoded_data:
|
|
245
|
+
url = url + '?' + encoded_data
|
|
246
|
+
elif verb == 'HEAD':
|
|
247
|
+
if encoded_data:
|
|
248
|
+
url = url + '?' + encoded_data
|
|
249
|
+
curl.setopt(pycurl.CUSTOMREQUEST, verb)
|
|
250
|
+
curl.setopt(pycurl.HEADER, 1)
|
|
251
|
+
curl.setopt(pycurl.NOBODY, True)
|
|
252
|
+
elif verb == 'POST':
|
|
253
|
+
curl.setopt(pycurl.POST, 1)
|
|
254
|
+
if encoded_data:
|
|
255
|
+
curl.setopt(pycurl.POSTFIELDS, encoded_data)
|
|
256
|
+
elif verb == 'DELETE' or verb == 'PUT':
|
|
257
|
+
curl.setopt(pycurl.CUSTOMREQUEST, verb)
|
|
258
|
+
curl.setopt(pycurl.HTTPHEADER, ['Transfer-Encoding: chunked'])
|
|
259
|
+
if encoded_data:
|
|
260
|
+
curl.setopt(pycurl.POSTFIELDS, encoded_data)
|
|
261
|
+
else:
|
|
262
|
+
raise Exception('Unsupported HTTP method "%s"' % verb)
|
|
263
|
+
|
|
264
|
+
if self.tmgr:
|
|
265
|
+
token = self.tmgr.getToken()
|
|
266
|
+
if token:
|
|
267
|
+
thisHeaders['Authorization'] = 'Bearer {}'.format(token)
|
|
268
|
+
|
|
269
|
+
if verb in ('POST', 'PUT'):
|
|
270
|
+
# only these methods (and PATCH) require this header
|
|
271
|
+
thisHeaders["Content-Length"] = str(len(encoded_data))
|
|
272
|
+
|
|
273
|
+
# we must pass url as a bytes data-type, otherwise pycurl will fail with error
|
|
274
|
+
# TypeError: invalid arguments to setopt
|
|
275
|
+
# see https://curl.haxx.se/mail/curlpython-2007-07/0001.html
|
|
276
|
+
curl.setopt(pycurl.URL, encodeUnicodeToBytes(url))
|
|
277
|
+
# In order to enable service intercommunication with compressed HTTP body,
|
|
278
|
+
# we need to enable this header here, in case it has not been provided by upstream.
|
|
279
|
+
thisHeaders.setdefault("Accept-Encoding", "gzip")
|
|
280
|
+
curl.setopt(pycurl.HTTPHEADER, [encodeUnicodeToBytes("%s: %s" % (k, v)) for k, v in viewitems(thisHeaders)])
|
|
281
|
+
|
|
282
|
+
bbuf = BytesIO()
|
|
283
|
+
hbuf = BytesIO()
|
|
284
|
+
curl.setopt(pycurl.WRITEFUNCTION, bbuf.write)
|
|
285
|
+
curl.setopt(pycurl.HEADERFUNCTION, hbuf.write)
|
|
286
|
+
if capath:
|
|
287
|
+
curl.setopt(pycurl.CAPATH, capath)
|
|
288
|
+
curl.setopt(pycurl.SSL_VERIFYPEER, True)
|
|
289
|
+
if cainfo:
|
|
290
|
+
curl.setopt(pycurl.CAINFO, cainfo)
|
|
291
|
+
else:
|
|
292
|
+
curl.setopt(pycurl.SSL_VERIFYPEER, False)
|
|
293
|
+
if ckey:
|
|
294
|
+
curl.setopt(pycurl.SSLKEY, ckey)
|
|
295
|
+
if cert:
|
|
296
|
+
curl.setopt(pycurl.SSLCERT, cert)
|
|
297
|
+
if verbose:
|
|
298
|
+
curl.setopt(pycurl.VERBOSE, True)
|
|
299
|
+
curl.setopt(pycurl.DEBUGFUNCTION, self.debug)
|
|
300
|
+
return bbuf, hbuf
|
|
301
|
+
|
|
302
|
+
def debug(self, debug_type, debug_msg):
|
|
303
|
+
"""Debug callback implementation"""
|
|
304
|
+
print("debug(%d): %s" % (debug_type, debug_msg))
|
|
305
|
+
|
|
306
|
+
def parse_body(self, data, decode=False):
|
|
307
|
+
"""
|
|
308
|
+
Parse body part of URL request (by default use json).
|
|
309
|
+
This method can be overwritten.
|
|
310
|
+
"""
|
|
311
|
+
if decode:
|
|
312
|
+
try:
|
|
313
|
+
res = json.loads(data)
|
|
314
|
+
return res
|
|
315
|
+
except ValueError as exc:
|
|
316
|
+
msg = 'Unable to load JSON data, %s, data type=%s, pass as is' \
|
|
317
|
+
% (str(exc), type(data))
|
|
318
|
+
logging.debug(msg)
|
|
319
|
+
return data
|
|
320
|
+
else:
|
|
321
|
+
return data
|
|
322
|
+
|
|
323
|
+
def parse_header(self, header):
|
|
324
|
+
"""
|
|
325
|
+
Parse response header.
|
|
326
|
+
This method can be overwritten.
|
|
327
|
+
"""
|
|
328
|
+
return ResponseHeader(header)
|
|
329
|
+
|
|
330
|
+
@portForward(8443)
|
|
331
|
+
def request(self, url, params, headers=None, verb='GET',
|
|
332
|
+
verbose=0, ckey=None, cert=None, capath=None,
|
|
333
|
+
doseq=True, encode=False, decode=False, cainfo=None, cookie=None):
|
|
334
|
+
"""Fetch data for given set of parameters"""
|
|
335
|
+
curl = pycurl.Curl()
|
|
336
|
+
bbuf, hbuf = self.set_opts(curl, url, params, headers, ckey, cert, capath,
|
|
337
|
+
verbose, verb, doseq, encode, cainfo, cookie)
|
|
338
|
+
curl.perform()
|
|
339
|
+
if verbose:
|
|
340
|
+
print(verb, url, params, headers)
|
|
341
|
+
header = self.parse_header(hbuf.getvalue())
|
|
342
|
+
data = bbuf.getvalue()
|
|
343
|
+
data = decompress(data, header.header)
|
|
344
|
+
if header.status < 300:
|
|
345
|
+
if verb == 'HEAD':
|
|
346
|
+
data = ''
|
|
347
|
+
else:
|
|
348
|
+
data = self.parse_body(data, decode)
|
|
349
|
+
else:
|
|
350
|
+
exc = getException(url, params, headers, header, data)
|
|
351
|
+
bbuf.flush()
|
|
352
|
+
hbuf.flush()
|
|
353
|
+
raise exc
|
|
354
|
+
|
|
355
|
+
bbuf.flush()
|
|
356
|
+
hbuf.flush()
|
|
357
|
+
return header, data
|
|
358
|
+
|
|
359
|
+
def getdata(self, url, params, headers=None, verb='GET',
|
|
360
|
+
verbose=0, ckey=None, cert=None, doseq=True,
|
|
361
|
+
encode=False, decode=False, cookie=None):
|
|
362
|
+
"""Fetch data for given set of parameters"""
|
|
363
|
+
_, data = self.request(url=url, params=params, headers=headers, verb=verb,
|
|
364
|
+
verbose=verbose, ckey=ckey, cert=cert, doseq=doseq,
|
|
365
|
+
encode=encode, decode=decode, cookie=cookie)
|
|
366
|
+
return data
|
|
367
|
+
|
|
368
|
+
def getheader(self, url, params, headers=None, verb='GET',
|
|
369
|
+
verbose=0, ckey=None, cert=None, doseq=True):
|
|
370
|
+
"""Fetch HTTP header"""
|
|
371
|
+
header, _ = self.request(url, params, headers, verb,
|
|
372
|
+
verbose, ckey, cert, doseq=doseq)
|
|
373
|
+
return header
|
|
374
|
+
|
|
375
|
+
@portForward(8443)
|
|
376
|
+
def multirequest(self, url, parray, headers=None, verb='GET',
|
|
377
|
+
ckey=None, cert=None, verbose=None, cookie=None,
|
|
378
|
+
encode=False, decode=False):
|
|
379
|
+
"""Fetch data for given set of parameters"""
|
|
380
|
+
multi = pycurl.CurlMulti()
|
|
381
|
+
for params in parray:
|
|
382
|
+
curl = pycurl.Curl()
|
|
383
|
+
bbuf, hbuf = \
|
|
384
|
+
self.set_opts(curl, url, params, headers, ckey=ckey, cert=cert,
|
|
385
|
+
verbose=verbose, cookie=cookie, encode=encode)
|
|
386
|
+
multi.add_handle(curl)
|
|
387
|
+
while True:
|
|
388
|
+
ret, num_handles = multi.perform()
|
|
389
|
+
if ret != pycurl.E_CALL_MULTI_PERFORM:
|
|
390
|
+
break
|
|
391
|
+
while num_handles:
|
|
392
|
+
ret = multi.select(1.0)
|
|
393
|
+
if ret == -1:
|
|
394
|
+
continue
|
|
395
|
+
while True:
|
|
396
|
+
ret, num_handles = multi.perform()
|
|
397
|
+
if ret != pycurl.E_CALL_MULTI_PERFORM:
|
|
398
|
+
break
|
|
399
|
+
dummyNumq, response, dummyErr = multi.info_read()
|
|
400
|
+
for _respItem in response:
|
|
401
|
+
header = self.parse_header(hbuf.getvalue())
|
|
402
|
+
data = bbuf.getvalue()
|
|
403
|
+
data = decompress(data, header.header)
|
|
404
|
+
data = decodeBytesToUnicode(data)
|
|
405
|
+
if header.status < 300:
|
|
406
|
+
if verb == 'HEAD':
|
|
407
|
+
data = ''
|
|
408
|
+
else:
|
|
409
|
+
data = self.parse_body(data, decode)
|
|
410
|
+
else:
|
|
411
|
+
exc = getException(url, params, headers, header, data)
|
|
412
|
+
bbuf.flush()
|
|
413
|
+
hbuf.flush()
|
|
414
|
+
raise exc
|
|
415
|
+
if isinstance(data, dict):
|
|
416
|
+
data.update(params)
|
|
417
|
+
yield data
|
|
418
|
+
if isinstance(data, list):
|
|
419
|
+
for item in data:
|
|
420
|
+
if isinstance(item, dict):
|
|
421
|
+
item.update(params)
|
|
422
|
+
yield item
|
|
423
|
+
else:
|
|
424
|
+
err = 'Unsupported data format: data=%s, type=%s' \
|
|
425
|
+
% (item, type(item))
|
|
426
|
+
raise Exception(err)
|
|
427
|
+
bbuf.flush()
|
|
428
|
+
hbuf.flush()
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
HTTP_PAT = re.compile( \
|
|
432
|
+
"(https|http)://[-A-Za-z0-9_+&@#/%?=~_|!:,.;]*[-A-Za-z0-9+&@#/%=~_|]")
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def validate_url(url):
|
|
436
|
+
"Validate URL"
|
|
437
|
+
if HTTP_PAT.match(url):
|
|
438
|
+
return True
|
|
439
|
+
return False
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def pycurl_options():
|
|
443
|
+
"Default set of options for pycurl"
|
|
444
|
+
opts = {
|
|
445
|
+
'FOLLOWLOCATION': 1,
|
|
446
|
+
'CONNECTTIMEOUT': 270,
|
|
447
|
+
'MAXREDIRS': 5,
|
|
448
|
+
'NOSIGNAL': 1,
|
|
449
|
+
'TIMEOUT': 270,
|
|
450
|
+
'SSL_VERIFYPEER': False,
|
|
451
|
+
'VERBOSE': 0
|
|
452
|
+
}
|
|
453
|
+
return opts
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
def cern_sso_cookie(url, fname, cert, ckey):
|
|
457
|
+
"Obtain cern SSO cookie and store it in given file name"
|
|
458
|
+
cmd = 'cern-get-sso-cookie -cert %s -key %s -r -u %s -o %s' \
|
|
459
|
+
% (cert, ckey, url, fname)
|
|
460
|
+
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, env=os.environ)
|
|
461
|
+
proc.wait()
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def getdata(urls, ckey, cert, headers=None, options=None, num_conn=50, cookie=None):
|
|
465
|
+
"""
|
|
466
|
+
Get data for given list of urls, using provided number of connections
|
|
467
|
+
and user credentials
|
|
468
|
+
"""
|
|
469
|
+
|
|
470
|
+
if not options:
|
|
471
|
+
options = pycurl_options()
|
|
472
|
+
|
|
473
|
+
portForwarder = PortForward(8443)
|
|
474
|
+
|
|
475
|
+
# Make a queue with urls
|
|
476
|
+
queue = [portForwarder(u) for u in urls if validate_url(u)]
|
|
477
|
+
|
|
478
|
+
# Check args
|
|
479
|
+
num_urls = len(queue)
|
|
480
|
+
num_conn = min(num_conn, num_urls)
|
|
481
|
+
|
|
482
|
+
# Pre-allocate a list of curl objects
|
|
483
|
+
mcurl = pycurl.CurlMulti()
|
|
484
|
+
mcurl.handles = []
|
|
485
|
+
for _ in range(num_conn):
|
|
486
|
+
curl = pycurl.Curl()
|
|
487
|
+
curl.fp = None
|
|
488
|
+
for key, val in viewitems(options):
|
|
489
|
+
curl.setopt(getattr(pycurl, key), val)
|
|
490
|
+
curl.setopt(pycurl.SSLKEY, ckey)
|
|
491
|
+
curl.setopt(pycurl.SSLCERT, cert)
|
|
492
|
+
mcurl.handles.append(curl)
|
|
493
|
+
if headers:
|
|
494
|
+
curl.setopt(pycurl.HTTPHEADER, \
|
|
495
|
+
["%s: %s" % (k, v) for k, v in viewitems(headers)])
|
|
496
|
+
|
|
497
|
+
# Main loop
|
|
498
|
+
freelist = mcurl.handles[:]
|
|
499
|
+
num_processed = 0
|
|
500
|
+
while num_processed < num_urls:
|
|
501
|
+
# If there is an url to process and a free curl object,
|
|
502
|
+
# add to multi-stack
|
|
503
|
+
while queue and freelist:
|
|
504
|
+
url = queue.pop(0)
|
|
505
|
+
curl = freelist.pop()
|
|
506
|
+
curl.setopt(pycurl.URL, url.encode('ascii', 'ignore'))
|
|
507
|
+
if cookie and url in cookie:
|
|
508
|
+
curl.setopt(pycurl.COOKIEFILE, cookie[url])
|
|
509
|
+
curl.setopt(pycurl.COOKIEJAR, cookie[url])
|
|
510
|
+
bbuf = BytesIO()
|
|
511
|
+
hbuf = BytesIO()
|
|
512
|
+
curl.setopt(pycurl.WRITEFUNCTION, bbuf.write)
|
|
513
|
+
curl.setopt(pycurl.HEADERFUNCTION, hbuf.write)
|
|
514
|
+
mcurl.add_handle(curl)
|
|
515
|
+
# store some info
|
|
516
|
+
curl.hbuf = hbuf
|
|
517
|
+
curl.bbuf = bbuf
|
|
518
|
+
curl.url = url
|
|
519
|
+
# Run the internal curl state machine for the multi stack
|
|
520
|
+
while True:
|
|
521
|
+
ret, _ = mcurl.perform()
|
|
522
|
+
if ret != pycurl.E_CALL_MULTI_PERFORM:
|
|
523
|
+
break
|
|
524
|
+
# Check for curl objects which have terminated, and add them to the
|
|
525
|
+
# freelist
|
|
526
|
+
while True:
|
|
527
|
+
num_q, ok_list, err_list = mcurl.info_read()
|
|
528
|
+
for curl in ok_list:
|
|
529
|
+
hdrs = decodeBytesToUnicode(curl.hbuf.getvalue())
|
|
530
|
+
data = decompress(decodeBytesToUnicode(curl.bbuf.getvalue()), ResponseHeader(hdrs).getHeader())
|
|
531
|
+
url = curl.url
|
|
532
|
+
curl.bbuf.flush()
|
|
533
|
+
curl.bbuf.close()
|
|
534
|
+
curl.hbuf.close()
|
|
535
|
+
curl.hbuf = None
|
|
536
|
+
curl.bbuf = None
|
|
537
|
+
mcurl.remove_handle(curl)
|
|
538
|
+
freelist.append(curl)
|
|
539
|
+
yield {'url': url, 'data': data, 'headers': hdrs}
|
|
540
|
+
for curl, errno, errmsg in err_list:
|
|
541
|
+
hdrs = curl.hbuf.getvalue()
|
|
542
|
+
data = curl.bbuf.getvalue()
|
|
543
|
+
url = curl.url
|
|
544
|
+
curl.bbuf.flush()
|
|
545
|
+
curl.bbuf.close()
|
|
546
|
+
curl.hbuf.close()
|
|
547
|
+
curl.hbuf = None
|
|
548
|
+
curl.bbuf = None
|
|
549
|
+
mcurl.remove_handle(curl)
|
|
550
|
+
freelist.append(curl)
|
|
551
|
+
yield {'url': url, 'data': None, 'headers': hdrs, \
|
|
552
|
+
'error': errmsg, 'code': errno}
|
|
553
|
+
num_processed = num_processed + len(ok_list) + len(err_list)
|
|
554
|
+
if num_q == 0:
|
|
555
|
+
break
|
|
556
|
+
# Currently no more I/O is pending, could do something in the meantime
|
|
557
|
+
# (display a progress bar, etc.).
|
|
558
|
+
# We just call select() to sleep until some more data is available.
|
|
559
|
+
mcurl.select(1.0)
|
|
560
|
+
|
|
561
|
+
cleanup(mcurl)
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def cleanup(mcurl):
|
|
565
|
+
"Clean-up MultiCurl handles"
|
|
566
|
+
for curl in mcurl.handles:
|
|
567
|
+
if curl.hbuf is not None:
|
|
568
|
+
curl.hbuf.close()
|
|
569
|
+
curl.hbuf = None
|
|
570
|
+
if curl.bbuf is not None:
|
|
571
|
+
curl.bbuf.close()
|
|
572
|
+
curl.bbuf = None
|
|
573
|
+
curl.close()
|
|
574
|
+
mcurl.close()
|
WMCore/WMBase.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
"""
|
|
4
|
+
WMBase.py
|
|
5
|
+
|
|
6
|
+
Created by Dave Evans on 2011-05-20.
|
|
7
|
+
Copyright (c) 2011 Fermilab. All rights reserved.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
import os
|
|
12
|
+
import os.path
|
|
13
|
+
import inspect
|
|
14
|
+
|
|
15
|
+
def getWMBASE():
|
|
16
|
+
""" returns the root of WMCore install """
|
|
17
|
+
if __file__.find("src/python") != -1:
|
|
18
|
+
return os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
|
19
|
+
else:
|
|
20
|
+
return os.path.normpath(os.path.join(os.path.dirname(__file__), '..'))
|
|
21
|
+
|
|
22
|
+
def getTestBase(importFlag = True):
|
|
23
|
+
"""
|
|
24
|
+
_getTestBase_
|
|
25
|
+
|
|
26
|
+
Returns a base that can be used for testing. Defaults to
|
|
27
|
+
getWMBase if no environment variables WMCORE_TEST_ROOT is defined
|
|
28
|
+
"""
|
|
29
|
+
basePath = os.path.normpath(os.path.join(getWMBASE(), 'test/python'))
|
|
30
|
+
envPath = os.environ.get("WMCORE_TEST_ROOT", None)
|
|
31
|
+
|
|
32
|
+
# First, try getting things from the environment
|
|
33
|
+
if envPath != None:
|
|
34
|
+
try:
|
|
35
|
+
if os.path.isdir(envPath):
|
|
36
|
+
return envPath
|
|
37
|
+
except:
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
if importFlag:
|
|
41
|
+
# Then try importing things from WMCore_t and see if we can
|
|
42
|
+
# find the directory
|
|
43
|
+
try:
|
|
44
|
+
import WMCore_t.__init__ as testImport
|
|
45
|
+
testPath = os.path.dirname(inspect.getsourcefile(testImport))
|
|
46
|
+
return os.path.normpath(os.path.join(testPath, '../'))
|
|
47
|
+
except ImportError:
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
return basePath
|