wmglobalqueue 2.3.10__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 +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.3.10.data/data/bin/wmc-dist-patch +15 -0
- wmglobalqueue-2.3.10.data/data/bin/wmc-dist-unpatch +8 -0
- wmglobalqueue-2.3.10.data/data/bin/wmc-httpd +3 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/.couchapprc +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/README.md +40 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/index.html +264 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/ElementInfoByWorkflow.js +96 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/StuckElementInfo.js +57 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/WorkloadInfoTable.js +80 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/dataTable.js +70 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/namespace.js +23 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/style/main.css +75 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/couchapp.json +4 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/filters/childQueueFilter.js +13 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/filters/filterDeletedDocs.js +3 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/filters/queueFilter.js +11 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/language +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lib/mustache.js +333 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lib/validate.js +27 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lib/workqueue_utils.js +61 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/elementsDetail.js +28 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/filter.js +86 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/stuckElements.js +38 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/workRestrictions.js +153 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/workflowSummary.js +28 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/rewrites.json +73 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/shows/redirect.js +23 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/shows/status.js +40 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/ElementSummaryByWorkflow.html +27 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/StuckElementSummary.html +26 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/TaskStatus.html +23 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/WorkflowSummary.html +27 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/partials/workqueue-common-lib.html +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib-remote.html +16 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib.html +18 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/updates/in-place.js +50 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/validate_doc_update.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.couch.app.js +235 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.pathbinder.js +173 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeData/reduce.js +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeParentData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeParentData/reduce.js +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activePileupData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activePileupData/reduce.js +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/analyticsData/map.js +11 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/analyticsData/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/availableByPriority/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/conflicts/map.js +5 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elements/map.js +5 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByParent/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByParentData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByPileupData/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByStatus/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsBySubscription/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/map.js +8 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/reduce.js +3 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsDetailByWorkflowAndStatus/map.js +26 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/map.js +10 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByRequest/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatus/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatus/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/openRequests/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/recent-items/map.js +5 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/reduce.js +1 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/specsByWorkflow/map.js +5 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/stuckElements/map.js +38 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/map.js +12 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/reduce.js +3 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrl/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrl/reduce.js +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/map.js +6 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/reduce.js +2 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/workflowSummary/map.js +9 -0
- wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/workflowSummary/reduce.js +10 -0
- wmglobalqueue-2.3.10.dist-info/LICENSE +202 -0
- wmglobalqueue-2.3.10.dist-info/METADATA +24 -0
- wmglobalqueue-2.3.10.dist-info/NOTICE +16 -0
- wmglobalqueue-2.3.10.dist-info/RECORD +345 -0
- wmglobalqueue-2.3.10.dist-info/WHEEL +5 -0
- wmglobalqueue-2.3.10.dist-info/top_level.txt +2 -0
WMCore/Lexicon.py
ADDED
|
@@ -0,0 +1,836 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
_Lexicon_
|
|
4
|
+
|
|
5
|
+
A set of regular expressions and other tests that we can use to validate input
|
|
6
|
+
to other classes. If a test fails an AssertionError should be raised, and
|
|
7
|
+
handled appropriately by the client methods, on success returns True.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import print_function, division
|
|
10
|
+
|
|
11
|
+
from future import standard_library
|
|
12
|
+
standard_library.install_aliases()
|
|
13
|
+
from builtins import str, bytes
|
|
14
|
+
from future.utils import viewvalues, viewkeys
|
|
15
|
+
|
|
16
|
+
import io
|
|
17
|
+
import re
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
from urllib.parse import urlparse, urlunparse
|
|
21
|
+
|
|
22
|
+
from WMCore.WMException import WMException, WMEXCEPTION_START_STR, WMEXCEPTION_END_STR
|
|
23
|
+
|
|
24
|
+
# restriction enforced by DBS. for different types blocks.
|
|
25
|
+
# It could have a strict restriction
|
|
26
|
+
# i.e production should end with v[number]
|
|
27
|
+
PRIMARY_DS = {'re': '^[a-zA-Z][a-zA-Z0-9\-_]*$', 'maxLength': 99}
|
|
28
|
+
PROCESSED_DS = {'re': '[a-zA-Z0-9\.\-_]+', 'maxLength': 199}
|
|
29
|
+
TIER = {'re': '[A-Z0-9\-_]+', 'maxLength': 99}
|
|
30
|
+
BLOCK_STR = {'re': '#[a-zA-Z0-9\.\-_]+', 'maxLength': 100}
|
|
31
|
+
|
|
32
|
+
lfnParts = {
|
|
33
|
+
'era': '([a-zA-Z0-9\-_]+)',
|
|
34
|
+
'primDS': '([a-zA-Z][a-zA-Z0-9\-_]*)',
|
|
35
|
+
'tier': '(%(re)s)' % TIER,
|
|
36
|
+
'version': '([a-zA-Z0-9\-_]+)',
|
|
37
|
+
'procDS': '([a-zA-Z0-9\-_]+)', # Processed dataset = Processing string + Processing version
|
|
38
|
+
'counter': '([0-9]+)',
|
|
39
|
+
'root': '([a-zA-Z0-9\-_]+).root',
|
|
40
|
+
'hnName': '([a-zA-Z0-9\.]+)',
|
|
41
|
+
'subdir': '([a-zA-Z0-9\-_]+)',
|
|
42
|
+
'file': '([a-zA-Z0-9\-\._]+)',
|
|
43
|
+
'workflow': '([a-zA-Z0-9\-_]+)',
|
|
44
|
+
'physics_group': '([a-zA-Z0-9\-_]+)'
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
userProcDSParts = {
|
|
48
|
+
'groupuser': '([a-zA-Z0-9\.\-_])+',
|
|
49
|
+
'publishdataname': '([a-zA-Z0-9\-_])+',
|
|
50
|
+
'psethash': '([a-f0-9]){32}'
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
STORE_RESULTS_LFN = '/store/results/%(physics_group)s/%(era)s/%(primDS)s/%(tier)s/%(procDS)s' % lfnParts
|
|
54
|
+
|
|
55
|
+
# condor log filtering lexicons
|
|
56
|
+
WMEXCEPTION_FILTER = "(?P<WMException>\%s(?!<@).*?\%s)" % (WMEXCEPTION_START_STR, WMEXCEPTION_END_STR)
|
|
57
|
+
WMEXCEPTION_FILTER += "|(?P<ERROR>(ERROR:root:.*?This is a CRITICAL error))"
|
|
58
|
+
WMEXCEPTION_REGEXP = re.compile(r"%s" % WMEXCEPTION_FILTER, re.DOTALL)
|
|
59
|
+
|
|
60
|
+
CONDOR_LOG_REASON_FILTER = '<a n="Reason"><s>(?P<Reason>(?!</s></a>).*?)</s></a>'
|
|
61
|
+
CONDOR_LOG_SITE_FILTER = '<a n="MachineAttrGLIDEIN_CMSSite0"><s>(?P<Site>(?!</s></a>).*?)</s></a>'
|
|
62
|
+
|
|
63
|
+
CONDOR_LOG_FILTER_REGEXP = re.compile(r"%s|%s" % (CONDOR_LOG_REASON_FILTER, CONDOR_LOG_SITE_FILTER),
|
|
64
|
+
re.DOTALL)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def DBSUser(candidate):
|
|
68
|
+
"""
|
|
69
|
+
create_by and last_modified_by in DBS are in several formats. The major ones are:
|
|
70
|
+
1. DN that was mostly used in DBS2: example /DC=org/DC=doegrids/OU=People/CN=Lothar A.T. Bauerdick 301799;
|
|
71
|
+
2. CERN HN account name that used in DBS3/CMSWEB if the HN is assocated with DN: example giffels ;
|
|
72
|
+
3. username with host name: example cmsprod@vocms39.cern.ch;
|
|
73
|
+
"""
|
|
74
|
+
if candidate == '' or not candidate:
|
|
75
|
+
return candidate
|
|
76
|
+
r1 = r'^/[a-zA-Z][a-zA-Z0-9/\=\s()\']*\=[a-zA-Z0-9/\=\.\-_/#:\s\']*$'
|
|
77
|
+
r2 = r'^[a-zA-Z0-9/][a-zA-Z0-9/\.\-_\']*$'
|
|
78
|
+
r3 = r'^[a-zA-Z0-9/][a-zA-Z0-9/\.\-_]*@[a-zA-Z0-9/][a-zA-Z0-9/\.\-_]*$'
|
|
79
|
+
|
|
80
|
+
errorMsg = "DBSUser candidate: %s doesn't match any of the following regular expressions:\n" % candidate
|
|
81
|
+
try:
|
|
82
|
+
return check(r1, candidate)
|
|
83
|
+
except AssertionError:
|
|
84
|
+
errorMsg += " %s\n" % r1
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
return check(r2, candidate)
|
|
88
|
+
except AssertionError:
|
|
89
|
+
errorMsg += " %s\n" % r2
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
return check(r3, candidate)
|
|
93
|
+
except AssertionError:
|
|
94
|
+
errorMsg += " %s\n" % r3
|
|
95
|
+
raise AssertionError(errorMsg)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def searchblock(candidate):
|
|
99
|
+
"""
|
|
100
|
+
A block name with a * wildcard one or more times in it.
|
|
101
|
+
"""
|
|
102
|
+
regexp = r"^/(\*|[a-zA-Z\*][a-zA-Z0-9_\*]{0,100})(/(\*|[a-zA-Z0-9_\.\-\*]{1,199})){0,1}(/(\*|[A-Z0-9\-\*]{1,99})(#(\*|[a-zA-Z0-9\.\-_\*]){0,100}){0,1}){0,1}$"
|
|
103
|
+
return check(regexp, candidate)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
SEARCHDATASET_RE = r'^/(\*|[a-zA-Z\*][a-zA-Z0-9_\*\-]{0,100})(/(\*|[a-zA-Z0-9_\.\-\*]{1,199})){0,1}(/(\*|[A-Z0-9\-\*]{1,99})){0,1}$'
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def searchdataset(candidate):
|
|
110
|
+
"""
|
|
111
|
+
A dataset name with a * wildcard one or more times in it. Only the first '/' is mandatory to use.
|
|
112
|
+
"""
|
|
113
|
+
return check(SEARCHDATASET_RE, candidate)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def searchstr(candidate):
|
|
117
|
+
"""
|
|
118
|
+
Used to check a DBS input that searches for names in dbs. Note block name, dataset name, file name have their own
|
|
119
|
+
searching string.
|
|
120
|
+
No white space found in names in DBS production and allowed to elimate input like "Drop table table1".
|
|
121
|
+
letters, numbers, periods, dashes, underscores
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
if candidate == '':
|
|
125
|
+
return candidate
|
|
126
|
+
return check(r'^[a-zA-Z0-9/%*][a-zA-Z0-9/\.\-_%*/#]*$', candidate)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def namestr(candidate):
|
|
130
|
+
"""
|
|
131
|
+
Any input used in DBS and not defined here should pass namestr check.
|
|
132
|
+
No white space found in names in DBS production and allowed to elimate input like "Drop table table1".
|
|
133
|
+
letters, numbers, periods, dashes, underscores,#,/
|
|
134
|
+
|
|
135
|
+
"""
|
|
136
|
+
if candidate == '' or not candidate:
|
|
137
|
+
return candidate
|
|
138
|
+
return check(r'^[a-zA-Z0-9/][a-zA-Z0-9/\.\-_/#]*$', candidate)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def sitetier(candidate):
|
|
142
|
+
return check("^T[0-3]", candidate)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def jobrange(candidate):
|
|
146
|
+
""" Specifies a numbers/range of jobs separated by a comma.
|
|
147
|
+
A range is composed by two numbers separated my minus
|
|
148
|
+
For example valid candidates are either 1 or 1,2 or 3-6,5,7-8
|
|
149
|
+
It is like when you specifies which pages to print in Word
|
|
150
|
+
"""
|
|
151
|
+
return check("^\d+(-\d+)?(,\d+(-\d+)?)*$", candidate)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def cmsname(candidate):
|
|
155
|
+
"""
|
|
156
|
+
Candidate must pass the CMS name pattern. Thus:
|
|
157
|
+
* good candidates: T2_UK_SGrid or T2_UK_SGrid_Bristol
|
|
158
|
+
* bad candidates: T2, T2_UK
|
|
159
|
+
"""
|
|
160
|
+
candidate = candidate.rstrip('_')
|
|
161
|
+
return check("^T[0-3]_[A-Z]{2}((_[A-Za-z0-9]+)+)$", candidate)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def countrycode(candidate):
|
|
165
|
+
# TODO: do properly with a look up table
|
|
166
|
+
return check("^[A-Z]{2}$", candidate)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _blockStructCheck(candidate):
|
|
170
|
+
"""
|
|
171
|
+
Basic block structure check
|
|
172
|
+
/primary/process/tier#uuid
|
|
173
|
+
"""
|
|
174
|
+
assert candidate.count('/') == 3, "need to have / between the 3 parts which construct block name"
|
|
175
|
+
parts = candidate.split('/')
|
|
176
|
+
assert parts[3].count('#') == 1, "need to have # in the last parts of block"
|
|
177
|
+
# should be empty string for the first part
|
|
178
|
+
check(r"", parts[0])
|
|
179
|
+
return parts
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def block(candidate):
|
|
183
|
+
"""assert if not a valid block name"""
|
|
184
|
+
|
|
185
|
+
parts = _blockStructCheck(candidate)
|
|
186
|
+
|
|
187
|
+
primDSCheck = check(r"%s" % PRIMARY_DS['re'], parts[1], PRIMARY_DS['maxLength'])
|
|
188
|
+
procDSCheck = check(r"%s" % PROCESSED_DS['re'], parts[2], PROCESSED_DS['maxLength'])
|
|
189
|
+
lastParts = parts[3].split("#")
|
|
190
|
+
tierCheck = check(r"%s" % TIER['re'], lastParts[0], TIER['maxLength'])
|
|
191
|
+
blockCheck = check(r"%s" % BLOCK_STR['re'], "#%s" % lastParts[1], BLOCK_STR['maxLength'])
|
|
192
|
+
return (primDSCheck and procDSCheck and tierCheck and blockCheck)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def identifier(candidate):
|
|
196
|
+
""" letters, numbers, whitespace, periods, dashes, underscores """
|
|
197
|
+
return check(r'[a-zA-Z0-9\s\.\-_]{1,100}$', candidate)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def globalTag(candidate):
|
|
201
|
+
""" Identifier plus colons """
|
|
202
|
+
return check(r'[a-zA-Z0-9\s\.\-_:]{1,100}$', candidate)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
DATASET_RE = r'^/[a-zA-Z0-9\-_]{1,99}/[a-zA-Z0-9\.\-_]{1,199}/[A-Z0-9\-]{1,99}$'
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def dataset(candidate):
|
|
209
|
+
""" A slash followed by an identifier,x3 """
|
|
210
|
+
return check(DATASET_RE, candidate)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
PROCDATASET_RE = r'[a-zA-Z][a-zA-Z0-9_]*(\-[a-zA-Z0-9_]+){0,2}-v[0-9]*$'
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def procdataset(candidate):
|
|
217
|
+
"""
|
|
218
|
+
Check for processed dataset name.
|
|
219
|
+
letters, numbers, dashes, underscores.
|
|
220
|
+
"""
|
|
221
|
+
if not candidate or candidate.startswith('None'):
|
|
222
|
+
raise AssertionError("ProcDataset cannot be empty or start with None.")
|
|
223
|
+
|
|
224
|
+
commonCheck = check(r"%s" % PROCESSED_DS['re'], candidate, PROCESSED_DS['maxLength'])
|
|
225
|
+
prodCheck = check(PROCDATASET_RE, candidate)
|
|
226
|
+
return (commonCheck and prodCheck)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def publishdatasetname(candidate):
|
|
230
|
+
if candidate == '' or not candidate:
|
|
231
|
+
return candidate
|
|
232
|
+
return check(r'%(publishdataname)s$' % userProcDSParts, candidate, 100)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
USERPROCDATASET_RE = r'%(groupuser)s-%(publishdataname)s-%(psethash)s$' % userProcDSParts
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def userprocdataset(candidate):
|
|
239
|
+
"""
|
|
240
|
+
Check for processed dataset name of users.
|
|
241
|
+
letters, numbers, dashes, underscores.
|
|
242
|
+
"""
|
|
243
|
+
if candidate == '' or not candidate:
|
|
244
|
+
return candidate
|
|
245
|
+
|
|
246
|
+
commonCheck = check(r"%s" % PROCESSED_DS['re'], candidate, PROCESSED_DS['maxLength'])
|
|
247
|
+
anlaysisCheck = check(USERPROCDATASET_RE, candidate)
|
|
248
|
+
return (commonCheck and anlaysisCheck)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def physicsgroup(candidate):
|
|
252
|
+
"""
|
|
253
|
+
Check for Physics Group string which is added to StoreResults
|
|
254
|
+
merged LFN base. Up to 30 letters, numbers, dashes, underscores.
|
|
255
|
+
"""
|
|
256
|
+
return check(r'%(physics_group)s$' % lfnParts, candidate, 30)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def procversion(candidate):
|
|
260
|
+
""" Integers """
|
|
261
|
+
if isinstance(candidate, dict):
|
|
262
|
+
for candi in viewvalues(candidate):
|
|
263
|
+
check(r'^[0-9]+$', str(candi))
|
|
264
|
+
return True
|
|
265
|
+
else:
|
|
266
|
+
return check(r'^[0-9]+$', str(candidate))
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def procstring(candidate):
|
|
270
|
+
""" Identifier """
|
|
271
|
+
if not candidate:
|
|
272
|
+
raise AssertionError("ProcStr cannot be empty or None.")
|
|
273
|
+
if isinstance(candidate, dict):
|
|
274
|
+
for candi in viewvalues(candidate):
|
|
275
|
+
check(r'[a-zA-Z0-9_]{1,100}$', candi)
|
|
276
|
+
return True
|
|
277
|
+
else:
|
|
278
|
+
return check(r'[a-zA-Z0-9_]{1,100}$', candidate)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def procstringT0(candidate):
|
|
282
|
+
"""
|
|
283
|
+
ProcessingString validation function for T0 specs
|
|
284
|
+
"""
|
|
285
|
+
if isinstance(candidate, dict):
|
|
286
|
+
for candi in viewvalues(candidate):
|
|
287
|
+
check(r'^$|[a-zA-Z0-9_]{1,100}$', candi)
|
|
288
|
+
return True
|
|
289
|
+
else:
|
|
290
|
+
return check(r'^$|[a-zA-Z0-9_]{1,100}$', candidate)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def acqname(candidate):
|
|
294
|
+
"""
|
|
295
|
+
Check for acquisition name.
|
|
296
|
+
letters, numbers, underscores.
|
|
297
|
+
"""
|
|
298
|
+
if not candidate:
|
|
299
|
+
raise AssertionError("AcqEra cannot be empty or None.")
|
|
300
|
+
if isinstance(candidate, dict):
|
|
301
|
+
for candi in viewvalues(candidate):
|
|
302
|
+
check(r'[a-zA-Z][a-zA-Z0-9_]*$', candi)
|
|
303
|
+
return True
|
|
304
|
+
else:
|
|
305
|
+
return check(r'[a-zA-Z][a-zA-Z0-9_]*$', candidate)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def campaign(candidate):
|
|
309
|
+
"""
|
|
310
|
+
Check for Campaign name.
|
|
311
|
+
letters, numbers, underscores and dashes are allowed, up to 60 chars.
|
|
312
|
+
"""
|
|
313
|
+
if not candidate:
|
|
314
|
+
return True
|
|
315
|
+
return check(r'^[a-zA-Z0-9-_]{1,80}$', candidate)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def primdataset(candidate):
|
|
319
|
+
"""
|
|
320
|
+
Check for primary dataset name.
|
|
321
|
+
letters, numbers, dashes, underscores.
|
|
322
|
+
"""
|
|
323
|
+
if candidate == '' or not candidate:
|
|
324
|
+
return candidate
|
|
325
|
+
return check(r"%s" % PRIMARY_DS['re'], candidate, PRIMARY_DS['maxLength'])
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
TASK_STEP_NAME = {'re': '^[a-zA-Z][a-zA-Z0-9\-_]*$', 'maxLength': 50}
|
|
329
|
+
def taskStepName(candidate):
|
|
330
|
+
"""
|
|
331
|
+
Validate the TaskName and/or StepName field.
|
|
332
|
+
Letters, numbers, dashes and underscores are allowed.
|
|
333
|
+
"""
|
|
334
|
+
return check(r"%s" % TASK_STEP_NAME['re'], candidate, TASK_STEP_NAME['maxLength'])
|
|
335
|
+
|
|
336
|
+
def hnName(candidate):
|
|
337
|
+
"""
|
|
338
|
+
Use lfn parts definitions to validate a simple HN name
|
|
339
|
+
"""
|
|
340
|
+
|
|
341
|
+
validName = '^%(hnName)s$' % lfnParts
|
|
342
|
+
return check(validName, candidate)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def lfn(candidate):
|
|
346
|
+
"""
|
|
347
|
+
Should be of the following form:
|
|
348
|
+
/store/data/acquisition_era/primary-dataset/data_tier/processing_version/lfn_counter/filename.root
|
|
349
|
+
See https://twiki.cern.ch/twiki/bin/viewauth/CMS/DMWMPG_Namespace for details
|
|
350
|
+
|
|
351
|
+
NOTE:Because of the way we do lustre, we have to have two separate checks for this:
|
|
352
|
+
/store/data
|
|
353
|
+
/store/data/lustre
|
|
354
|
+
|
|
355
|
+
Add for LHE files: /data/lhe/...
|
|
356
|
+
"""
|
|
357
|
+
regexp1 = '/([a-z]+)/([a-z0-9]+)/(%(era)s)/([a-zA-Z0-9\-_]+)/([A-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)((/[0-9]+){3}){0,1}/([0-9]+)/([a-zA-Z0-9\-_]+).root' % lfnParts
|
|
358
|
+
regexp2 = '/([a-z]+)/([a-z0-9]+)/([a-z0-9]+)/([a-zA-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)/([A-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)((/[0-9]+){3}){0,1}/([0-9]+)/([a-zA-Z0-9\-_]+).root'
|
|
359
|
+
regexp3 = '/store/(temp/)*(user|group)/(%(hnName)s|%(physics_group)s)/%(primDS)s/%(procDS)s/%(version)s/%(counter)s/%(root)s' % lfnParts
|
|
360
|
+
regexp4 = '/store/(temp/)*(user|group)/(%(hnName)s|%(physics_group)s)/%(primDS)s/(%(subdir)s/)+%(root)s' % lfnParts
|
|
361
|
+
|
|
362
|
+
oldStyleTier0LFN = '/store/data/%(era)s/%(primDS)s/%(tier)s/%(version)s/%(counter)s/%(counter)s/%(counter)s/%(root)s' % lfnParts
|
|
363
|
+
tier0LFN = '/store/(backfill/[0-9]/){0,1}(t0temp/|unmerged/){0,1}(data|express|hidata)/%(era)s/%(primDS)s/%(tier)s/%(version)s/%(counter)s/%(counter)s/%(counter)s(/%(counter)s)?/%(root)s' % lfnParts
|
|
364
|
+
|
|
365
|
+
storeMcLFN = '/store/mc/(%(era)s)/([a-zA-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)(/([a-zA-Z0-9\-_]+))*/([a-zA-Z0-9\-_]+).root' % lfnParts
|
|
366
|
+
|
|
367
|
+
storeResults2LFN = '/store/results/%(physics_group)s/%(primDS)s/%(procDS)s/%(primDS)s/%(tier)s/%(procDS)s/%(counter)s/%(root)s' % lfnParts
|
|
368
|
+
|
|
369
|
+
storeResultRootPart = '%(counter)s/%(root)s' % lfnParts
|
|
370
|
+
storeResultsLFN = "%s/%s" % (STORE_RESULTS_LFN, storeResultRootPart)
|
|
371
|
+
|
|
372
|
+
lheLFN1 = '/store/lhe/([0-9]+)/([a-zA-Z0-9\-_]+).lhe(.xz){0,1}'
|
|
373
|
+
# This is for future lhe LFN structure. Need to be tested.
|
|
374
|
+
lheLFN2 = '/store/lhe/%(era)s/%(primDS)s/([0-9]+)/([a-zA-Z0-9\-_]+).lhe(.xz){0,1}' % lfnParts
|
|
375
|
+
|
|
376
|
+
errorMsg = "LFN candidate: %s doesn't match any of the following regular expressions:\n" % candidate
|
|
377
|
+
|
|
378
|
+
try:
|
|
379
|
+
return check(regexp1, candidate)
|
|
380
|
+
except AssertionError:
|
|
381
|
+
errorMsg += " %s\n" % regexp1
|
|
382
|
+
|
|
383
|
+
try:
|
|
384
|
+
return check(regexp2, candidate)
|
|
385
|
+
except AssertionError:
|
|
386
|
+
errorMsg += " %s\n" % regexp2
|
|
387
|
+
|
|
388
|
+
try:
|
|
389
|
+
return check(regexp3, candidate)
|
|
390
|
+
except AssertionError:
|
|
391
|
+
errorMsg += " %s\n" % regexp3
|
|
392
|
+
|
|
393
|
+
try:
|
|
394
|
+
return check(regexp4, candidate)
|
|
395
|
+
except AssertionError:
|
|
396
|
+
errorMsg += " %s\n" % regexp4
|
|
397
|
+
|
|
398
|
+
try:
|
|
399
|
+
return check(tier0LFN, candidate)
|
|
400
|
+
except AssertionError:
|
|
401
|
+
errorMsg += " %s\n" % tier0LFN
|
|
402
|
+
|
|
403
|
+
try:
|
|
404
|
+
return check(oldStyleTier0LFN, candidate)
|
|
405
|
+
except AssertionError:
|
|
406
|
+
errorMsg += " %s\n" % oldStyleTier0LFN
|
|
407
|
+
|
|
408
|
+
try:
|
|
409
|
+
return check(storeMcLFN, candidate)
|
|
410
|
+
except AssertionError:
|
|
411
|
+
errorMsg += " %s\n" % storeMcLFN
|
|
412
|
+
|
|
413
|
+
try:
|
|
414
|
+
return check(lheLFN1, candidate)
|
|
415
|
+
except AssertionError:
|
|
416
|
+
errorMsg += " %s\n" % lheLFN1
|
|
417
|
+
|
|
418
|
+
try:
|
|
419
|
+
return check(lheLFN2, candidate)
|
|
420
|
+
except AssertionError:
|
|
421
|
+
errorMsg += " %s\n" % lheLFN2
|
|
422
|
+
|
|
423
|
+
try:
|
|
424
|
+
return check(storeResults2LFN, candidate)
|
|
425
|
+
except AssertionError:
|
|
426
|
+
errorMsg += " %s\n" % storeResults2LFN
|
|
427
|
+
|
|
428
|
+
try:
|
|
429
|
+
return check(storeResultsLFN, candidate)
|
|
430
|
+
except AssertionError:
|
|
431
|
+
errorMsg += " %s\n" % storeResultsLFN
|
|
432
|
+
raise AssertionError(errorMsg)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def lfnBase(candidate):
|
|
436
|
+
"""
|
|
437
|
+
As lfn above, but for doing the lfnBase
|
|
438
|
+
i.e., for use in spec generation and parsing
|
|
439
|
+
"""
|
|
440
|
+
regexp1 = '/([a-z]+)/([a-z0-9]+)/([a-zA-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)/([A-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)'
|
|
441
|
+
regexp2 = '/([a-z]+)/([a-z0-9]+)/([a-z0-9]+)/([a-zA-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)/([A-Z0-9\-_]+)/([a-zA-Z0-9\-_]+)((/[0-9]+){3}){0,1}'
|
|
442
|
+
regexp3 = '/(store)/(temp/)*(user|group)/(%(hnName)s|%(physics_group)s)/%(primDS)s/%(procDS)s/%(version)s' % lfnParts
|
|
443
|
+
|
|
444
|
+
tier0LFN = '/store/(backfill/[0-9]/){0,1}(t0temp/|unmerged/){0,1}(data|express|hidata)/%(era)s/%(primDS)s/%(tier)s/%(version)s/%(counter)s/%(counter)s/%(counter)s' % lfnParts
|
|
445
|
+
|
|
446
|
+
errorMsg = "LFN candidate: %s doesn't match any of the following regular expressions:\n" % candidate
|
|
447
|
+
|
|
448
|
+
try:
|
|
449
|
+
return check(regexp1, candidate)
|
|
450
|
+
except AssertionError:
|
|
451
|
+
errorMsg += " %s\n" % regexp1
|
|
452
|
+
|
|
453
|
+
try:
|
|
454
|
+
return check(regexp2, candidate)
|
|
455
|
+
except AssertionError:
|
|
456
|
+
errorMsg += " %s\n" % regexp2
|
|
457
|
+
|
|
458
|
+
try:
|
|
459
|
+
return check(regexp3, candidate)
|
|
460
|
+
except AssertionError:
|
|
461
|
+
errorMsg += " %s\n" % regexp3
|
|
462
|
+
|
|
463
|
+
try:
|
|
464
|
+
return check(tier0LFN, candidate)
|
|
465
|
+
except AssertionError:
|
|
466
|
+
errorMsg += " %s\n" % tier0LFN
|
|
467
|
+
|
|
468
|
+
try:
|
|
469
|
+
return check(STORE_RESULTS_LFN, candidate)
|
|
470
|
+
except AssertionError:
|
|
471
|
+
errorMsg += " %s\n" % STORE_RESULTS_LFN
|
|
472
|
+
raise AssertionError(errorMsg)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def userLfn(candidate):
|
|
476
|
+
"""
|
|
477
|
+
Check LFNs in /store/{temp}/user that are not EDM data
|
|
478
|
+
"""
|
|
479
|
+
regexp = '/store/(temp/)*(user|group)/(%(hnName)s|%(physics_group)s)/%(subdir)s/%(workflow)s/%(subdir)s/%(file)s' % lfnParts
|
|
480
|
+
return check(regexp, candidate)
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def userLfnBase(candidate):
|
|
484
|
+
"""
|
|
485
|
+
As above but for the base part of the file
|
|
486
|
+
"""
|
|
487
|
+
regexp = '/store/(temp/)*(user|group)/(%(hnName)s|%(physics_group)s)/%(subdir)s/%(workflow)s/%(subdir)s' % lfnParts
|
|
488
|
+
return check(regexp, candidate)
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def cmsswversion(candidate):
|
|
492
|
+
return check('CMSSW(_\d+){3}(_[a-zA-Z0-9_]+)?$', candidate)
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def couchurl(candidate):
|
|
496
|
+
return check('https?://(([a-zA-Z0-9:@\.\-_]){0,100})([a-z0-9\.]+)(:\d+|/couchdb)', candidate)
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def requestName(candidate):
|
|
500
|
+
return check(r'[a-zA-Z0-9\.\-_]{1,150}$', candidate)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def validateUrl(candidate):
|
|
504
|
+
"""
|
|
505
|
+
Basic input validation for http(s) urls
|
|
506
|
+
"""
|
|
507
|
+
# regex taken from django https://github.com/django/django/blob/master/django/core/validators.py#L47
|
|
508
|
+
# Copyright (c) Django Software Foundation and individual contributors
|
|
509
|
+
protocol = r"^https?://" # http:// or https://
|
|
510
|
+
domain = r'?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}\.?'
|
|
511
|
+
localhost = r'localhost'
|
|
512
|
+
ipv4 = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
|
|
513
|
+
ipv6 = r'\[?[a-fA-F0-9]*:[a-fA-F0-9:]+\]?'
|
|
514
|
+
port = r'(?::\d+)?' # optional port
|
|
515
|
+
path = r'(?:/?|[/?]\S+)$'
|
|
516
|
+
regex_url = r'%s(%s|%s|%s|%s)%s%s' % (protocol, domain, localhost, ipv4, ipv6, port, path)
|
|
517
|
+
return check(regex_url, candidate)
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
def check(regexp, candidate, maxLength=None):
|
|
521
|
+
if maxLength is not None:
|
|
522
|
+
assert len(candidate) <= maxLength, \
|
|
523
|
+
"%s is longer than max length (%s) allowed" % (candidate, maxLength)
|
|
524
|
+
assert re.compile(regexp).match(candidate) is not None, \
|
|
525
|
+
"'%s' does not match regular expression %s" % (candidate, regexp)
|
|
526
|
+
return True
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def parseLFN(candidate):
|
|
530
|
+
"""
|
|
531
|
+
_parseLFN_
|
|
532
|
+
|
|
533
|
+
Take an LFN, return the component parts
|
|
534
|
+
"""
|
|
535
|
+
separator = "/"
|
|
536
|
+
|
|
537
|
+
# First, make sure what we've gotten is a real LFN
|
|
538
|
+
lfn(candidate)
|
|
539
|
+
|
|
540
|
+
parts = candidate.split('/')
|
|
541
|
+
final = {}
|
|
542
|
+
|
|
543
|
+
if parts[0] == '':
|
|
544
|
+
parts.remove('')
|
|
545
|
+
if 'user' in parts[1:3] or 'group' in parts[1:3]:
|
|
546
|
+
if parts[1] in ['user', 'group']:
|
|
547
|
+
final['baseLocation'] = '/%s' % separator.join(parts[:2])
|
|
548
|
+
parts = parts[2:]
|
|
549
|
+
else:
|
|
550
|
+
final['baseLocation'] = '/%s' % separator.join(parts[:3])
|
|
551
|
+
parts = parts[3:]
|
|
552
|
+
|
|
553
|
+
final['hnName'] = parts[0]
|
|
554
|
+
final['primaryDataset'] = parts[1]
|
|
555
|
+
final['secondaryDataset'] = parts[2]
|
|
556
|
+
final['processingVersion'] = parts[3]
|
|
557
|
+
final['lfnCounter'] = parts[4]
|
|
558
|
+
final['filename'] = parts[5]
|
|
559
|
+
|
|
560
|
+
return final
|
|
561
|
+
|
|
562
|
+
if len(parts) == 8:
|
|
563
|
+
# Then we have only two locations
|
|
564
|
+
final['baseLocation'] = '/%s' % separator.join(parts[:2])
|
|
565
|
+
parts = parts[2:]
|
|
566
|
+
elif len(parts) == 9:
|
|
567
|
+
final['baseLocation'] = '/%s' % separator.join(parts[:3])
|
|
568
|
+
parts = parts[3:]
|
|
569
|
+
else:
|
|
570
|
+
# How did we end up here?
|
|
571
|
+
# Something just went wrong
|
|
572
|
+
msg = """CRITICAL! This machine has experienced a complete logic failure while parsing LFNs.\n
|
|
573
|
+
If you are a developer this indicates that you have changed the Lexicon LFN regexp functions without changing the parsing.\n
|
|
574
|
+
If you are an operator, this indicates that this machine is likely unstable.\n
|
|
575
|
+
All data should be backed up and the machine removed from production for examination.\n"""
|
|
576
|
+
msg += "Candidate: %s" % candidate
|
|
577
|
+
raise WMException(msg)
|
|
578
|
+
|
|
579
|
+
final['acquisitionEra'] = parts[0]
|
|
580
|
+
final['primaryDataset'] = parts[1]
|
|
581
|
+
final['dataTier'] = parts[2]
|
|
582
|
+
final['processingVersion'] = parts[3]
|
|
583
|
+
final['lfnCounter'] = parts[4]
|
|
584
|
+
final['filename'] = parts[5]
|
|
585
|
+
|
|
586
|
+
return final
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
def parseLFNBase(candidate):
|
|
590
|
+
"""
|
|
591
|
+
_parseLFNBase_
|
|
592
|
+
|
|
593
|
+
Return a meaningful dictionary with info from an LFNBase
|
|
594
|
+
"""
|
|
595
|
+
separator = "/"
|
|
596
|
+
|
|
597
|
+
# First, make sure what we've gotten is a real LFNBase
|
|
598
|
+
lfnBase(candidate)
|
|
599
|
+
|
|
600
|
+
parts = candidate.split('/')
|
|
601
|
+
final = {}
|
|
602
|
+
|
|
603
|
+
if parts[0] == '':
|
|
604
|
+
parts.remove('')
|
|
605
|
+
|
|
606
|
+
if 'user' in parts[1:3] or 'group' in parts[1:3]:
|
|
607
|
+
if parts[1] in ['user', 'group']:
|
|
608
|
+
final['baseLocation'] = '/%s' % separator.join(parts[:2])
|
|
609
|
+
parts = parts[2:]
|
|
610
|
+
else:
|
|
611
|
+
final['baseLocation'] = '/%s' % separator.join(parts[:3])
|
|
612
|
+
parts = parts[3:]
|
|
613
|
+
|
|
614
|
+
final['hnName'] = parts[0]
|
|
615
|
+
final['primaryDataset'] = parts[1]
|
|
616
|
+
final['secondaryDataset'] = parts[2]
|
|
617
|
+
final['processingVersion'] = parts[3]
|
|
618
|
+
|
|
619
|
+
return final
|
|
620
|
+
|
|
621
|
+
if len(parts) == 6:
|
|
622
|
+
# Then we have only two locations
|
|
623
|
+
final['baseLocation'] = '/%s' % separator.join(parts[:2])
|
|
624
|
+
parts = parts[2:]
|
|
625
|
+
elif len(parts) == 7:
|
|
626
|
+
final['baseLocation'] = '/%s' % separator.join(parts[:3])
|
|
627
|
+
parts = parts[3:]
|
|
628
|
+
else:
|
|
629
|
+
# How did we end up here?
|
|
630
|
+
# Something just went wrong
|
|
631
|
+
msg = """CRITICAL! This machine has experienced a complete logic failure while parsing LFNs.\n
|
|
632
|
+
If you are a developer this indicates that you have changed the Lexicon LFN regexp functions without changing the parsing.\n
|
|
633
|
+
If you are an operator, this indicates that this machine is likely unstable.\n
|
|
634
|
+
All data should be backed up and the machine removed from production for examination.\n"""
|
|
635
|
+
msg += "Candidate: %s" % candidate
|
|
636
|
+
raise WMException(msg)
|
|
637
|
+
|
|
638
|
+
final['acquisitionEra'] = parts[0]
|
|
639
|
+
final['primaryDataset'] = parts[1]
|
|
640
|
+
final['dataTier'] = parts[2]
|
|
641
|
+
final['processingVersion'] = parts[3]
|
|
642
|
+
|
|
643
|
+
return final
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
def sanitizeURL(url):
|
|
647
|
+
"""Take the url with/without username and password and return sanitized url,
|
|
648
|
+
username and password in dict format
|
|
649
|
+
WANNING: This doesn't check the correctness of url format.
|
|
650
|
+
Don't use ':' in username or password.
|
|
651
|
+
"""
|
|
652
|
+
endpoint_components = urlparse(url)
|
|
653
|
+
# Cleanly pull out the user/password from the url
|
|
654
|
+
if endpoint_components.port:
|
|
655
|
+
netloc = '%s:%s' % (endpoint_components.hostname,
|
|
656
|
+
endpoint_components.port)
|
|
657
|
+
else:
|
|
658
|
+
netloc = endpoint_components.hostname
|
|
659
|
+
|
|
660
|
+
# Build a URL without the username/password information
|
|
661
|
+
url = urlunparse(
|
|
662
|
+
[endpoint_components.scheme,
|
|
663
|
+
netloc,
|
|
664
|
+
endpoint_components.path,
|
|
665
|
+
endpoint_components.params,
|
|
666
|
+
endpoint_components.query,
|
|
667
|
+
endpoint_components.fragment])
|
|
668
|
+
|
|
669
|
+
return {'url': url, 'username': endpoint_components.username,
|
|
670
|
+
'password': endpoint_components.password}
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
def replaceToSantizeURL(url_str):
|
|
674
|
+
"""
|
|
675
|
+
Take arbitrary string and search for urls with user and password and
|
|
676
|
+
replace it with sanitized url.
|
|
677
|
+
"""
|
|
678
|
+
|
|
679
|
+
def _repUrl(matchObj):
|
|
680
|
+
return matchObj.group(1) + matchObj.group(4)
|
|
681
|
+
|
|
682
|
+
# TODO: won't catch every case (But is it good enough (trade off to performance)?)
|
|
683
|
+
urlRegExpr = r'\b(((?i)http|https|ftp|mysql|oracle|sqlite)+://)([^:]+:[^@]+@)(\S+)\b'
|
|
684
|
+
return re.sub(urlRegExpr, _repUrl, url_str)
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
def splitCouchServiceURL(serviceURL):
|
|
688
|
+
"""
|
|
689
|
+
split service URL to couchURL and couchdb name
|
|
690
|
+
serviceURL should be couchURL/dbname format.
|
|
691
|
+
"""
|
|
692
|
+
|
|
693
|
+
splitedURL = serviceURL.rstrip('/').rsplit('/', 1)
|
|
694
|
+
return splitedURL[0], splitedURL[1]
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
def primaryDatasetType(candidate):
|
|
698
|
+
pDatasetTypes = ["mc", "data", "cosmic", "test"]
|
|
699
|
+
if candidate in pDatasetTypes:
|
|
700
|
+
return True
|
|
701
|
+
# to sync with the check() exception when it doesn't match
|
|
702
|
+
raise AssertionError("Invalid primary dataset type : %s should be 'mc' or 'data' or 'test'" % candidate)
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
def subRequestType(candidate):
|
|
706
|
+
subTypes = ["MC", "ReDigi", "Pilot", "RelVal", "HIRelVal", "ReReco", ""]
|
|
707
|
+
if candidate in subTypes:
|
|
708
|
+
return True
|
|
709
|
+
# to sync with the check() exception when it doesn't match
|
|
710
|
+
msg = "Invalid SubRequestType value: '{}'. Allowed values are: {}".format(candidate, subTypes)
|
|
711
|
+
raise AssertionError(msg)
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
def activity(candidate):
|
|
715
|
+
dashboardActivities = ['reprocessing', 'production', 'relval', 'tier0', 't0',
|
|
716
|
+
'harvesting', 'storeresults', 'integration',
|
|
717
|
+
'test', 'analysis']
|
|
718
|
+
if candidate in dashboardActivities:
|
|
719
|
+
return True
|
|
720
|
+
raise AssertionError("Invalid dashboard activity: %s should 'test'" % candidate)
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
def gpuParameters(candidate):
|
|
724
|
+
"""
|
|
725
|
+
Validate the spec "GPUParams" argument, which is a JSON encoded object, thus:
|
|
726
|
+
* an encoded None object (like 'null')
|
|
727
|
+
* an encoded dictionary with the following parameters:
|
|
728
|
+
* mandatory: GPUMemoryMB (int), CUDARuntime (str), CUDACapabilities (list of str)
|
|
729
|
+
* optional: GPUName (str), CUDADriverVersion (str), CUDARuntimeVersion (str)
|
|
730
|
+
:param candidate: a JSON encoded data to be validated
|
|
731
|
+
:return: True if validation succeeded, False or exception otherwise
|
|
732
|
+
"""
|
|
733
|
+
mandatoryArgs = set(["GPUMemoryMB", "CUDARuntime", "CUDACapabilities"])
|
|
734
|
+
optionalArgs = set(["GPUName", "CUDADriverVersion", "CUDARuntimeVersion"])
|
|
735
|
+
try:
|
|
736
|
+
data = json.loads(candidate)
|
|
737
|
+
except Exception:
|
|
738
|
+
raise AssertionError("GPUParams is not a valid JSON object")
|
|
739
|
+
# once python2 code is deprecated, this is the way to raise only the last exception
|
|
740
|
+
# raise AssertionError("GPUParams is not a valid JSON object") from None
|
|
741
|
+
if data is None:
|
|
742
|
+
return True
|
|
743
|
+
if not isinstance(data, dict):
|
|
744
|
+
raise AssertionError("GPUParams is not a dictionary encoded as JSON object")
|
|
745
|
+
|
|
746
|
+
paramSet = set(viewkeys(data))
|
|
747
|
+
# is every mandatory argument also in the provided args?
|
|
748
|
+
if not mandatoryArgs <= paramSet:
|
|
749
|
+
msg = "GPUParams does not contain all the mandatory arguments. "
|
|
750
|
+
msg +="Mandatory args: {}, while args provided are: {}".format(mandatoryArgs, paramSet)
|
|
751
|
+
raise AssertionError(msg)
|
|
752
|
+
# are there unknown arguments in the data provided?
|
|
753
|
+
unknownArgs = paramSet - mandatoryArgs - optionalArgs
|
|
754
|
+
if unknownArgs:
|
|
755
|
+
msg = "GPUParams contains arguments that are not supported. Args provided: {}, ".format(paramSet)
|
|
756
|
+
msg +="while mandatory args are: {} and optional args are: {}".format(mandatoryArgs, optionalArgs)
|
|
757
|
+
raise AssertionError(msg)
|
|
758
|
+
return _gpuInternalParameters(data)
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
CUDA_VERSION_REGEX = {"re": r"^\d+\.\d+(\.\d+)?$", "maxLength": 100}
|
|
762
|
+
def _gpuInternalParameters(candidate):
|
|
763
|
+
"""
|
|
764
|
+
NOTE: this function is supposed to be called only from gpuParameters, which already
|
|
765
|
+
does the high level validation.
|
|
766
|
+
List of **required** parameters is:
|
|
767
|
+
* `GPUMemoryMB`: integer with the amount of memory, in Megabytes (MB). Validate as `> 0`. E.g.: 8000
|
|
768
|
+
* `CUDACapabilities`: a list of short strings (<= 100 chars). Validation should ensure at least one item
|
|
769
|
+
in the list and matching this regex: `r"^\d+.\d$"`. E.g.: ["7.5", "8.0"]
|
|
770
|
+
* `CUDARuntime`: a short string (<=100 chars) with the runtime version.
|
|
771
|
+
Validated against this regex: `r"^\d+.\d+$"`. E.g.: "11.2"
|
|
772
|
+
List of **optional** parameters is:
|
|
773
|
+
* `GPUName`: a string with the GPU name. Validate against `<= 100 chars`. E.g. "Tesla T4", "Quadro RTX 6000";
|
|
774
|
+
* `CUDADriverVersion`: a string with the CUDA driver version.
|
|
775
|
+
Validated against this regex: `r"^\d+.\d+\d+$"`E.g. "460.32.03"
|
|
776
|
+
* `CUDARuntimeVersion`: a string with the CUDA runtime version.
|
|
777
|
+
Validated against this regex: `r"^\d+.\d+\d+$"`E.g. "11.2.152"
|
|
778
|
+
|
|
779
|
+
This function validates all the internal key/value pairs provided for the GPUParams
|
|
780
|
+
argument, mostly against their own regular expressions.
|
|
781
|
+
:param candidate: the JSON object already decoded (thus, str or dict)
|
|
782
|
+
:return: True if validation succeeded, False or exception otherwise
|
|
783
|
+
"""
|
|
784
|
+
# Generic regular expression for CUDA runtime/driver version
|
|
785
|
+
# It matches either something like "11.2", or "11.2.231"
|
|
786
|
+
# GPUMemoryMB validation
|
|
787
|
+
if not isinstance(candidate["GPUMemoryMB"], int) or not candidate["GPUMemoryMB"] > 0:
|
|
788
|
+
raise AssertionError("Mandatory GPUParams.GPUMemoryMB must be an integer and greater than 0")
|
|
789
|
+
# CUDACapabilities validation
|
|
790
|
+
if not isinstance(candidate["CUDACapabilities"], (list, set)) or not candidate["CUDACapabilities"]:
|
|
791
|
+
raise AssertionError("Mandatory GPUParams.CUDACapabilities must be a non-empty list")
|
|
792
|
+
for cudaCapabItem in candidate["CUDACapabilities"]:
|
|
793
|
+
if not isinstance(cudaCapabItem, (str, bytes)):
|
|
794
|
+
raise AssertionError("Mandatory GPUParams.CUDACapabilities must be a list of strings")
|
|
795
|
+
check(CUDA_VERSION_REGEX["re"], cudaCapabItem, CUDA_VERSION_REGEX["maxLength"])
|
|
796
|
+
# CUDARuntime validation
|
|
797
|
+
if not isinstance(candidate["CUDARuntime"], (str, bytes)) or\
|
|
798
|
+
not check(CUDA_VERSION_REGEX["re"], candidate["CUDARuntime"], CUDA_VERSION_REGEX["maxLength"]):
|
|
799
|
+
raise AssertionError("Mandatory GPUParams.CUDARuntime must be a string and shorter than 100 chars")
|
|
800
|
+
|
|
801
|
+
### And now, validate the optional arguments
|
|
802
|
+
# GPUName validation
|
|
803
|
+
if "GPUName" in candidate:
|
|
804
|
+
if not isinstance(candidate["GPUName"], (str, bytes)):
|
|
805
|
+
raise AssertionError("Optional GPUParams.GPUName must be a string")
|
|
806
|
+
check(r".*", candidate["GPUName"], 100)
|
|
807
|
+
# CUDADriverVersion validation
|
|
808
|
+
if "CUDADriverVersion" in candidate:
|
|
809
|
+
if not isinstance(candidate["CUDADriverVersion"], (str, bytes)):
|
|
810
|
+
raise AssertionError("Optional GPUParams.CUDADriverVersion must be a string")
|
|
811
|
+
check(CUDA_VERSION_REGEX["re"], candidate["CUDADriverVersion"], CUDA_VERSION_REGEX["maxLength"])
|
|
812
|
+
# CUDARuntimeVersion validation
|
|
813
|
+
if "CUDARuntimeVersion" in candidate:
|
|
814
|
+
if not isinstance(candidate["CUDARuntimeVersion"], (str, bytes)):
|
|
815
|
+
raise AssertionError("Optional GPUParams.CUDARuntimeVersion must be a string")
|
|
816
|
+
check(CUDA_VERSION_REGEX["re"], candidate["CUDARuntimeVersion"], CUDA_VERSION_REGEX["maxLength"])
|
|
817
|
+
return True
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
def getStringsBetween(start, end, source):
|
|
821
|
+
"""
|
|
822
|
+
get the string between start string and end string for given source string
|
|
823
|
+
source string is one line string (no new line charactor in it)
|
|
824
|
+
"""
|
|
825
|
+
regex = r"\%s(.*?)\%s" % (start, end)
|
|
826
|
+
result = re.match(regex, source)
|
|
827
|
+
if result:
|
|
828
|
+
return result.group(1).strip()
|
|
829
|
+
else:
|
|
830
|
+
return None
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
def getIterMatchObjectOnRegexp(filePath, regexp):
|
|
834
|
+
with io.open(filePath, 'r', encoding='utf8', errors='ignore') as f:
|
|
835
|
+
for m in re.finditer(regexp, f.read()):
|
|
836
|
+
yield m
|