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.

Files changed (345) hide show
  1. Utils/CPMetrics.py +270 -0
  2. Utils/CertTools.py +62 -0
  3. Utils/EmailAlert.py +50 -0
  4. Utils/ExtendedUnitTestCase.py +62 -0
  5. Utils/FileTools.py +182 -0
  6. Utils/IteratorTools.py +80 -0
  7. Utils/MathUtils.py +31 -0
  8. Utils/MemoryCache.py +119 -0
  9. Utils/Patterns.py +24 -0
  10. Utils/Pipeline.py +137 -0
  11. Utils/PortForward.py +97 -0
  12. Utils/ProcessStats.py +103 -0
  13. Utils/PythonVersion.py +17 -0
  14. Utils/Signals.py +36 -0
  15. Utils/TemporaryEnvironment.py +27 -0
  16. Utils/Throttled.py +227 -0
  17. Utils/Timers.py +130 -0
  18. Utils/Timestamps.py +86 -0
  19. Utils/TokenManager.py +143 -0
  20. Utils/Tracing.py +60 -0
  21. Utils/TwPrint.py +98 -0
  22. Utils/Utilities.py +308 -0
  23. Utils/__init__.py +11 -0
  24. WMCore/ACDC/Collection.py +57 -0
  25. WMCore/ACDC/CollectionTypes.py +12 -0
  26. WMCore/ACDC/CouchCollection.py +67 -0
  27. WMCore/ACDC/CouchFileset.py +238 -0
  28. WMCore/ACDC/CouchService.py +73 -0
  29. WMCore/ACDC/DataCollectionService.py +485 -0
  30. WMCore/ACDC/Fileset.py +94 -0
  31. WMCore/ACDC/__init__.py +11 -0
  32. WMCore/Algorithms/Alarm.py +39 -0
  33. WMCore/Algorithms/MathAlgos.py +274 -0
  34. WMCore/Algorithms/MiscAlgos.py +67 -0
  35. WMCore/Algorithms/ParseXMLFile.py +115 -0
  36. WMCore/Algorithms/Permissions.py +27 -0
  37. WMCore/Algorithms/Singleton.py +58 -0
  38. WMCore/Algorithms/SubprocessAlgos.py +129 -0
  39. WMCore/Algorithms/__init__.py +7 -0
  40. WMCore/Cache/GenericDataCache.py +98 -0
  41. WMCore/Cache/WMConfigCache.py +572 -0
  42. WMCore/Cache/__init__.py +0 -0
  43. WMCore/Configuration.py +651 -0
  44. WMCore/DAOFactory.py +47 -0
  45. WMCore/DataStructs/File.py +177 -0
  46. WMCore/DataStructs/Fileset.py +140 -0
  47. WMCore/DataStructs/Job.py +182 -0
  48. WMCore/DataStructs/JobGroup.py +142 -0
  49. WMCore/DataStructs/JobPackage.py +49 -0
  50. WMCore/DataStructs/LumiList.py +734 -0
  51. WMCore/DataStructs/Mask.py +219 -0
  52. WMCore/DataStructs/MathStructs/ContinuousSummaryHistogram.py +197 -0
  53. WMCore/DataStructs/MathStructs/DiscreteSummaryHistogram.py +92 -0
  54. WMCore/DataStructs/MathStructs/SummaryHistogram.py +117 -0
  55. WMCore/DataStructs/MathStructs/__init__.py +0 -0
  56. WMCore/DataStructs/Pickleable.py +24 -0
  57. WMCore/DataStructs/Run.py +256 -0
  58. WMCore/DataStructs/Subscription.py +175 -0
  59. WMCore/DataStructs/WMObject.py +47 -0
  60. WMCore/DataStructs/WorkUnit.py +112 -0
  61. WMCore/DataStructs/Workflow.py +60 -0
  62. WMCore/DataStructs/__init__.py +8 -0
  63. WMCore/Database/CMSCouch.py +1349 -0
  64. WMCore/Database/ConfigDBMap.py +29 -0
  65. WMCore/Database/CouchUtils.py +118 -0
  66. WMCore/Database/DBCore.py +198 -0
  67. WMCore/Database/DBCreator.py +113 -0
  68. WMCore/Database/DBExceptionHandler.py +57 -0
  69. WMCore/Database/DBFactory.py +110 -0
  70. WMCore/Database/DBFormatter.py +177 -0
  71. WMCore/Database/Dialects.py +13 -0
  72. WMCore/Database/ExecuteDAO.py +327 -0
  73. WMCore/Database/MongoDB.py +241 -0
  74. WMCore/Database/MySQL/Destroy.py +42 -0
  75. WMCore/Database/MySQL/ListUserContent.py +20 -0
  76. WMCore/Database/MySQL/__init__.py +9 -0
  77. WMCore/Database/MySQLCore.py +132 -0
  78. WMCore/Database/Oracle/Destroy.py +56 -0
  79. WMCore/Database/Oracle/ListUserContent.py +19 -0
  80. WMCore/Database/Oracle/__init__.py +9 -0
  81. WMCore/Database/ResultSet.py +44 -0
  82. WMCore/Database/Transaction.py +91 -0
  83. WMCore/Database/__init__.py +9 -0
  84. WMCore/Database/ipy_profile_couch.py +438 -0
  85. WMCore/GlobalWorkQueue/CherryPyThreads/CleanUpTask.py +29 -0
  86. WMCore/GlobalWorkQueue/CherryPyThreads/HeartbeatMonitor.py +105 -0
  87. WMCore/GlobalWorkQueue/CherryPyThreads/LocationUpdateTask.py +28 -0
  88. WMCore/GlobalWorkQueue/CherryPyThreads/ReqMgrInteractionTask.py +35 -0
  89. WMCore/GlobalWorkQueue/CherryPyThreads/__init__.py +0 -0
  90. WMCore/GlobalWorkQueue/__init__.py +0 -0
  91. WMCore/GroupUser/CouchObject.py +127 -0
  92. WMCore/GroupUser/Decorators.py +51 -0
  93. WMCore/GroupUser/Group.py +33 -0
  94. WMCore/GroupUser/Interface.py +73 -0
  95. WMCore/GroupUser/User.py +96 -0
  96. WMCore/GroupUser/__init__.py +11 -0
  97. WMCore/Lexicon.py +836 -0
  98. WMCore/REST/Auth.py +202 -0
  99. WMCore/REST/CherryPyPeriodicTask.py +166 -0
  100. WMCore/REST/Error.py +333 -0
  101. WMCore/REST/Format.py +642 -0
  102. WMCore/REST/HeartbeatMonitorBase.py +90 -0
  103. WMCore/REST/Main.py +623 -0
  104. WMCore/REST/Server.py +2435 -0
  105. WMCore/REST/Services.py +24 -0
  106. WMCore/REST/Test.py +120 -0
  107. WMCore/REST/Tools.py +38 -0
  108. WMCore/REST/Validation.py +250 -0
  109. WMCore/REST/__init__.py +1 -0
  110. WMCore/ReqMgr/DataStructs/RequestStatus.py +209 -0
  111. WMCore/ReqMgr/DataStructs/RequestType.py +13 -0
  112. WMCore/ReqMgr/DataStructs/__init__.py +0 -0
  113. WMCore/ReqMgr/__init__.py +1 -0
  114. WMCore/Services/AlertManager/AlertManagerAPI.py +111 -0
  115. WMCore/Services/AlertManager/__init__.py +0 -0
  116. WMCore/Services/CRIC/CRIC.py +238 -0
  117. WMCore/Services/CRIC/__init__.py +0 -0
  118. WMCore/Services/DBS/DBS3Reader.py +1044 -0
  119. WMCore/Services/DBS/DBSConcurrency.py +44 -0
  120. WMCore/Services/DBS/DBSErrors.py +113 -0
  121. WMCore/Services/DBS/DBSReader.py +23 -0
  122. WMCore/Services/DBS/DBSUtils.py +139 -0
  123. WMCore/Services/DBS/DBSWriterObjects.py +381 -0
  124. WMCore/Services/DBS/ProdException.py +133 -0
  125. WMCore/Services/DBS/__init__.py +8 -0
  126. WMCore/Services/FWJRDB/FWJRDBAPI.py +118 -0
  127. WMCore/Services/FWJRDB/__init__.py +0 -0
  128. WMCore/Services/HTTPS/HTTPSAuthHandler.py +66 -0
  129. WMCore/Services/HTTPS/__init__.py +0 -0
  130. WMCore/Services/LogDB/LogDB.py +201 -0
  131. WMCore/Services/LogDB/LogDBBackend.py +191 -0
  132. WMCore/Services/LogDB/LogDBExceptions.py +11 -0
  133. WMCore/Services/LogDB/LogDBReport.py +85 -0
  134. WMCore/Services/LogDB/__init__.py +0 -0
  135. WMCore/Services/MSPileup/__init__.py +0 -0
  136. WMCore/Services/MSUtils/MSUtils.py +54 -0
  137. WMCore/Services/MSUtils/__init__.py +0 -0
  138. WMCore/Services/McM/McM.py +173 -0
  139. WMCore/Services/McM/__init__.py +8 -0
  140. WMCore/Services/MonIT/Grafana.py +133 -0
  141. WMCore/Services/MonIT/__init__.py +0 -0
  142. WMCore/Services/PyCondor/PyCondorAPI.py +154 -0
  143. WMCore/Services/PyCondor/PyCondorUtils.py +105 -0
  144. WMCore/Services/PyCondor/__init__.py +0 -0
  145. WMCore/Services/ReqMgr/ReqMgr.py +261 -0
  146. WMCore/Services/ReqMgr/__init__.py +0 -0
  147. WMCore/Services/ReqMgrAux/ReqMgrAux.py +419 -0
  148. WMCore/Services/ReqMgrAux/__init__.py +0 -0
  149. WMCore/Services/RequestDB/RequestDBReader.py +267 -0
  150. WMCore/Services/RequestDB/RequestDBWriter.py +39 -0
  151. WMCore/Services/RequestDB/__init__.py +0 -0
  152. WMCore/Services/Requests.py +624 -0
  153. WMCore/Services/Rucio/Rucio.py +1287 -0
  154. WMCore/Services/Rucio/RucioUtils.py +74 -0
  155. WMCore/Services/Rucio/__init__.py +0 -0
  156. WMCore/Services/RucioConMon/RucioConMon.py +128 -0
  157. WMCore/Services/RucioConMon/__init__.py +0 -0
  158. WMCore/Services/Service.py +400 -0
  159. WMCore/Services/StompAMQ/__init__.py +0 -0
  160. WMCore/Services/TagCollector/TagCollector.py +155 -0
  161. WMCore/Services/TagCollector/XMLUtils.py +98 -0
  162. WMCore/Services/TagCollector/__init__.py +0 -0
  163. WMCore/Services/UUIDLib.py +13 -0
  164. WMCore/Services/UserFileCache/UserFileCache.py +160 -0
  165. WMCore/Services/UserFileCache/__init__.py +8 -0
  166. WMCore/Services/WMAgent/WMAgent.py +63 -0
  167. WMCore/Services/WMAgent/__init__.py +0 -0
  168. WMCore/Services/WMArchive/CMSSWMetrics.py +526 -0
  169. WMCore/Services/WMArchive/DataMap.py +463 -0
  170. WMCore/Services/WMArchive/WMArchive.py +33 -0
  171. WMCore/Services/WMArchive/__init__.py +0 -0
  172. WMCore/Services/WMBS/WMBS.py +97 -0
  173. WMCore/Services/WMBS/__init__.py +0 -0
  174. WMCore/Services/WMStats/DataStruct/RequestInfoCollection.py +300 -0
  175. WMCore/Services/WMStats/DataStruct/__init__.py +0 -0
  176. WMCore/Services/WMStats/WMStatsPycurl.py +145 -0
  177. WMCore/Services/WMStats/WMStatsReader.py +445 -0
  178. WMCore/Services/WMStats/WMStatsWriter.py +273 -0
  179. WMCore/Services/WMStats/__init__.py +0 -0
  180. WMCore/Services/WMStatsServer/WMStatsServer.py +134 -0
  181. WMCore/Services/WMStatsServer/__init__.py +0 -0
  182. WMCore/Services/WorkQueue/WorkQueue.py +492 -0
  183. WMCore/Services/WorkQueue/__init__.py +0 -0
  184. WMCore/Services/__init__.py +8 -0
  185. WMCore/Services/pycurl_manager.py +574 -0
  186. WMCore/WMBase.py +50 -0
  187. WMCore/WMConnectionBase.py +164 -0
  188. WMCore/WMException.py +183 -0
  189. WMCore/WMExceptions.py +269 -0
  190. WMCore/WMFactory.py +76 -0
  191. WMCore/WMInit.py +228 -0
  192. WMCore/WMLogging.py +108 -0
  193. WMCore/WMSpec/ConfigSectionTree.py +442 -0
  194. WMCore/WMSpec/Persistency.py +135 -0
  195. WMCore/WMSpec/Steps/BuildMaster.py +87 -0
  196. WMCore/WMSpec/Steps/BuildTools.py +201 -0
  197. WMCore/WMSpec/Steps/Builder.py +97 -0
  198. WMCore/WMSpec/Steps/Diagnostic.py +89 -0
  199. WMCore/WMSpec/Steps/Emulator.py +62 -0
  200. WMCore/WMSpec/Steps/ExecuteMaster.py +208 -0
  201. WMCore/WMSpec/Steps/Executor.py +210 -0
  202. WMCore/WMSpec/Steps/StepFactory.py +213 -0
  203. WMCore/WMSpec/Steps/TaskEmulator.py +75 -0
  204. WMCore/WMSpec/Steps/Template.py +204 -0
  205. WMCore/WMSpec/Steps/Templates/AlcaHarvest.py +76 -0
  206. WMCore/WMSpec/Steps/Templates/CMSSW.py +613 -0
  207. WMCore/WMSpec/Steps/Templates/DQMUpload.py +59 -0
  208. WMCore/WMSpec/Steps/Templates/DeleteFiles.py +70 -0
  209. WMCore/WMSpec/Steps/Templates/LogArchive.py +84 -0
  210. WMCore/WMSpec/Steps/Templates/LogCollect.py +105 -0
  211. WMCore/WMSpec/Steps/Templates/StageOut.py +105 -0
  212. WMCore/WMSpec/Steps/Templates/__init__.py +10 -0
  213. WMCore/WMSpec/Steps/WMExecutionFailure.py +21 -0
  214. WMCore/WMSpec/Steps/__init__.py +8 -0
  215. WMCore/WMSpec/Utilities.py +63 -0
  216. WMCore/WMSpec/WMSpecErrors.py +12 -0
  217. WMCore/WMSpec/WMStep.py +347 -0
  218. WMCore/WMSpec/WMTask.py +1980 -0
  219. WMCore/WMSpec/WMWorkload.py +2288 -0
  220. WMCore/WMSpec/WMWorkloadTools.py +370 -0
  221. WMCore/WMSpec/__init__.py +9 -0
  222. WMCore/WorkQueue/DataLocationMapper.py +273 -0
  223. WMCore/WorkQueue/DataStructs/ACDCBlock.py +47 -0
  224. WMCore/WorkQueue/DataStructs/Block.py +48 -0
  225. WMCore/WorkQueue/DataStructs/CouchWorkQueueElement.py +148 -0
  226. WMCore/WorkQueue/DataStructs/WorkQueueElement.py +274 -0
  227. WMCore/WorkQueue/DataStructs/WorkQueueElementResult.py +152 -0
  228. WMCore/WorkQueue/DataStructs/WorkQueueElementsSummary.py +185 -0
  229. WMCore/WorkQueue/DataStructs/__init__.py +0 -0
  230. WMCore/WorkQueue/Policy/End/EndPolicyInterface.py +44 -0
  231. WMCore/WorkQueue/Policy/End/SingleShot.py +22 -0
  232. WMCore/WorkQueue/Policy/End/__init__.py +32 -0
  233. WMCore/WorkQueue/Policy/PolicyInterface.py +17 -0
  234. WMCore/WorkQueue/Policy/Start/Block.py +258 -0
  235. WMCore/WorkQueue/Policy/Start/Dataset.py +180 -0
  236. WMCore/WorkQueue/Policy/Start/MonteCarlo.py +131 -0
  237. WMCore/WorkQueue/Policy/Start/ResubmitBlock.py +171 -0
  238. WMCore/WorkQueue/Policy/Start/StartPolicyInterface.py +316 -0
  239. WMCore/WorkQueue/Policy/Start/__init__.py +34 -0
  240. WMCore/WorkQueue/Policy/__init__.py +57 -0
  241. WMCore/WorkQueue/WMBSHelper.py +772 -0
  242. WMCore/WorkQueue/WorkQueue.py +1237 -0
  243. WMCore/WorkQueue/WorkQueueBackend.py +750 -0
  244. WMCore/WorkQueue/WorkQueueBase.py +39 -0
  245. WMCore/WorkQueue/WorkQueueExceptions.py +44 -0
  246. WMCore/WorkQueue/WorkQueueReqMgrInterface.py +278 -0
  247. WMCore/WorkQueue/WorkQueueUtils.py +130 -0
  248. WMCore/WorkQueue/__init__.py +13 -0
  249. WMCore/Wrappers/JsonWrapper/JSONThunker.py +342 -0
  250. WMCore/Wrappers/JsonWrapper/__init__.py +7 -0
  251. WMCore/Wrappers/__init__.py +6 -0
  252. WMCore/__init__.py +10 -0
  253. wmglobalqueue-2.3.10.data/data/bin/wmc-dist-patch +15 -0
  254. wmglobalqueue-2.3.10.data/data/bin/wmc-dist-unpatch +8 -0
  255. wmglobalqueue-2.3.10.data/data/bin/wmc-httpd +3 -0
  256. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/.couchapprc +1 -0
  257. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/README.md +40 -0
  258. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/index.html +264 -0
  259. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/ElementInfoByWorkflow.js +96 -0
  260. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/StuckElementInfo.js +57 -0
  261. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/WorkloadInfoTable.js +80 -0
  262. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/dataTable.js +70 -0
  263. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/js/namespace.js +23 -0
  264. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/_attachments/style/main.css +75 -0
  265. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/couchapp.json +4 -0
  266. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/filters/childQueueFilter.js +13 -0
  267. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/filters/filterDeletedDocs.js +3 -0
  268. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/filters/queueFilter.js +11 -0
  269. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/language +1 -0
  270. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lib/mustache.js +333 -0
  271. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lib/validate.js +27 -0
  272. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lib/workqueue_utils.js +61 -0
  273. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/elementsDetail.js +28 -0
  274. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/filter.js +86 -0
  275. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/stuckElements.js +38 -0
  276. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/workRestrictions.js +153 -0
  277. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/lists/workflowSummary.js +28 -0
  278. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/rewrites.json +73 -0
  279. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/shows/redirect.js +23 -0
  280. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/shows/status.js +40 -0
  281. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/ElementSummaryByWorkflow.html +27 -0
  282. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/StuckElementSummary.html +26 -0
  283. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/TaskStatus.html +23 -0
  284. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/WorkflowSummary.html +27 -0
  285. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/partials/workqueue-common-lib.html +2 -0
  286. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib-remote.html +16 -0
  287. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib.html +18 -0
  288. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/updates/in-place.js +50 -0
  289. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/validate_doc_update.js +8 -0
  290. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.couch.app.js +235 -0
  291. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.pathbinder.js +173 -0
  292. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeData/map.js +8 -0
  293. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeData/reduce.js +2 -0
  294. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeParentData/map.js +8 -0
  295. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activeParentData/reduce.js +2 -0
  296. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activePileupData/map.js +8 -0
  297. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/activePileupData/reduce.js +2 -0
  298. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/analyticsData/map.js +11 -0
  299. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/analyticsData/reduce.js +1 -0
  300. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/availableByPriority/map.js +6 -0
  301. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/conflicts/map.js +5 -0
  302. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elements/map.js +5 -0
  303. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByData/map.js +8 -0
  304. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByParent/map.js +8 -0
  305. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByParentData/map.js +8 -0
  306. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByPileupData/map.js +8 -0
  307. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByStatus/map.js +8 -0
  308. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsBySubscription/map.js +6 -0
  309. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/map.js +8 -0
  310. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/reduce.js +3 -0
  311. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/elementsDetailByWorkflowAndStatus/map.js +26 -0
  312. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/map.js +10 -0
  313. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/reduce.js +1 -0
  314. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/map.js +6 -0
  315. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/reduce.js +1 -0
  316. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/map.js +6 -0
  317. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/reduce.js +1 -0
  318. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/map.js +6 -0
  319. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/reduce.js +1 -0
  320. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByRequest/map.js +6 -0
  321. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByRequest/reduce.js +1 -0
  322. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatus/map.js +6 -0
  323. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatus/reduce.js +1 -0
  324. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/map.js +6 -0
  325. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/reduce.js +1 -0
  326. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/openRequests/map.js +6 -0
  327. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/recent-items/map.js +5 -0
  328. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/map.js +6 -0
  329. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/reduce.js +1 -0
  330. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/specsByWorkflow/map.js +5 -0
  331. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/stuckElements/map.js +38 -0
  332. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/map.js +12 -0
  333. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/reduce.js +3 -0
  334. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrl/map.js +6 -0
  335. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrl/reduce.js +2 -0
  336. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/map.js +6 -0
  337. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/reduce.js +2 -0
  338. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/workflowSummary/map.js +9 -0
  339. wmglobalqueue-2.3.10.data/data/data/couchapps/WorkQueue/views/workflowSummary/reduce.js +10 -0
  340. wmglobalqueue-2.3.10.dist-info/LICENSE +202 -0
  341. wmglobalqueue-2.3.10.dist-info/METADATA +24 -0
  342. wmglobalqueue-2.3.10.dist-info/NOTICE +16 -0
  343. wmglobalqueue-2.3.10.dist-info/RECORD +345 -0
  344. wmglobalqueue-2.3.10.dist-info/WHEEL +5 -0
  345. wmglobalqueue-2.3.10.dist-info/top_level.txt +2 -0
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ LogDBBackend
4
+
5
+ Interface to LogDB persistent storage
6
+ """
7
+
8
+ from builtins import object, bytes
9
+
10
+ from Utils.PythonVersion import PY3
11
+ from Utils.Utilities import encodeUnicodeToBytes, encodeUnicodeToBytesConditional
12
+
13
+ # system modules
14
+ import datetime
15
+ import hashlib
16
+ import time
17
+
18
+ # WMCore modules
19
+ from WMCore.Database.CMSCouch import CouchServer, CouchNotFoundError
20
+ from WMCore.Services.LogDB.LogDBExceptions import LogDBError
21
+
22
+ # define full list of supported LogDB types
23
+ LOGDB_MSG_TYPES = ['info', 'error', 'warning', 'comment']
24
+
25
+ def gen_hash(key):
26
+ "Generate hash for given key"
27
+ key = encodeUnicodeToBytes(key) # if key is not unicode, then it is not changed
28
+ if not isinstance(key, bytes):
29
+ raise NotImplementedError
30
+ keyhash = hashlib.md5()
31
+ keyhash.update(encodeUnicodeToBytesConditional(key, condition=PY3))
32
+ return keyhash.hexdigest()
33
+
34
+ def tstamp():
35
+ "Return timestamp with microseconds"
36
+ now = datetime.datetime.now()
37
+ base = str(time.mktime(now.timetuple())).split('.')[0]
38
+ ctime = '%s.%s' % (base, now.microsecond)
39
+ return float(ctime)
40
+
41
+ def clean_entry(doc):
42
+ """Clean document from CouchDB attributes"""
43
+ for attr in ['_rev', '_id']:
44
+ if attr in doc:
45
+ del doc[attr]
46
+ return doc
47
+
48
+ class LogDBBackend(object):
49
+ """
50
+ Represents persistent storage for LogDB
51
+ """
52
+ def __init__(self, db_url, db_name, identifier, thread_name, **kwds):
53
+ self.db_url = db_url
54
+ self.server = CouchServer(db_url)
55
+ self.db_name = db_name
56
+ self.dbid = identifier
57
+ self.thread_name = thread_name
58
+ self.agent = kwds.get('agent', 0)
59
+ self.db = self.server.connectDatabase(db_name, create=False)
60
+ self.design = 'LogDB' # name of design document
61
+ self.view = 'requests' # name of view to look-up requests
62
+ self.tsview = 'tstamp' # name of tsview to look-up requests
63
+ self.threadview = 'logByRequestAndThread'
64
+ self.requestview = 'logByRequest'
65
+
66
+ def deleteDatabase(self):
67
+ """Delete back-end database"""
68
+ if self.db_name in self.server.listDatabases():
69
+ self.server.deleteDatabase(self.db_name)
70
+
71
+ def check(self, request, mtype=None):
72
+ """Check that given request name is valid"""
73
+ # TODO: we may add some logic to check request name, etc.
74
+ if not request:
75
+ raise LogDBError("Request name is empty")
76
+ if mtype and mtype not in LOGDB_MSG_TYPES:
77
+ raise LogDBError("Unsupported message type: '%s', supported types %s" \
78
+ % (mtype, LOGDB_MSG_TYPES))
79
+
80
+ def docid(self, request, mtype):
81
+ """Generate doc id, we use double dash to avoid dashes from thread names"""
82
+ return gen_hash('--'.join((request, self.dbid, self.thread_name, mtype)))
83
+
84
+ def prefix(self, mtype):
85
+ """Generate agent specific prefix for given message type"""
86
+ if self.agent:
87
+ # we add prefix for agent messages, all others will not have this index
88
+ mtype = 'agent-%s' % mtype
89
+ return mtype
90
+
91
+ def agent_update(self, request, msg='', mtype="info"):
92
+ """Update agent info in LogDB for given request"""
93
+ self.check(request, mtype)
94
+ mtype = self.prefix(mtype)
95
+ rec = {"ts":tstamp(), "msg":msg}
96
+ doc = {"_id": self.docid(request, mtype), "messages": [rec],
97
+ "request":request, "identifier":self.dbid,
98
+ "thr":self.thread_name, "type":mtype}
99
+ try:
100
+ exist_doc = self.db.document(doc["_id"])
101
+ doc["_rev"] = exist_doc["_rev"]
102
+ except CouchNotFoundError:
103
+ # this means document is not exist so we will just insert
104
+ pass
105
+ finally:
106
+ res = self.db.commitOne(doc)
107
+ return res
108
+
109
+ def user_update(self, request, msg, mtype='comment'):
110
+ """Update user info in LogDB for given request"""
111
+ rec = {"ts":tstamp(), "msg":msg}
112
+ doc = {"_id": self.docid(request, mtype), "messages": [rec],
113
+ "request":request, "identifier":self.dbid,
114
+ "thr":self.thread_name, "type":mtype}
115
+ try:
116
+ exist_doc = self.db.document(doc["_id"])
117
+ doc["_rev"] = exist_doc["_rev"]
118
+ doc["messages"] += exist_doc["messages"]
119
+ except CouchNotFoundError:
120
+ # this means document is not exist so we will just insert
121
+ pass
122
+ finally:
123
+ res = self.db.commitOne(doc)
124
+ return res
125
+
126
+ def get(self, request, mtype=None, detail=True, agent=True):
127
+ """Retrieve all entries from LogDB for given request"""
128
+ self.check(request, mtype)
129
+ if agent and mtype:
130
+ mtype = self.prefix(mtype)
131
+ options = {'reduce':False}
132
+ if mtype:
133
+ keys = [[request, mtype]]
134
+ else:
135
+ keys=[]
136
+ options.update({'startkey': [request], 'endkey':[request, {}]})
137
+ if detail:
138
+ options.update({'include_docs': True})
139
+ docs = self.db.loadView(self.design, self.view, options, keys=keys)
140
+ return docs
141
+
142
+ def get_by_thread(self, request, mtype='error', detail=False, agent=True):
143
+ self.check(request, mtype)
144
+ if agent and mtype:
145
+ mtype = self.prefix(mtype)
146
+ keys = [[request, self.dbid, self.thread_name, mtype]]
147
+ options = {'reduce':False}
148
+ if detail:
149
+ options.update({'include_docs': True})
150
+ docs = self.db.loadView(self.design, self.threadview, options, keys)
151
+ return docs
152
+
153
+ def get_by_request(self, request):
154
+ keys = [request]
155
+ options = {'reduce':False}
156
+ docs = self.db.loadView(self.design, self.requestview, options, keys)
157
+ return docs
158
+
159
+ def get_all_requests(self):
160
+ """Retrieve all entries from LogDB"""
161
+ options = {'reduce':True, 'group_level':1}
162
+ docs = self.db.loadView(self.design, self.view, options)
163
+ return docs
164
+
165
+ def delete(self, request, mtype=None, this_thread=False, agent=True):
166
+ """Delete entry in LogDB for given request"""
167
+ if mtype:
168
+ self.check(request, mtype)
169
+ else:
170
+ self.check(request)
171
+ if this_thread:
172
+ docs = self.get_by_thread(request, mtype=mtype, detail=False, agent=agent)
173
+ else:
174
+ docs = self.get(request, mtype=mtype, detail=False, agent=agent)
175
+ ids = [r['id'] for r in docs.get('rows', [])]
176
+ res = self.db.bulkDeleteByIDs(ids)
177
+ return res
178
+
179
+ def cleanup(self, thr):
180
+ """
181
+ Clean-up docs older then given threshold (thr should be specified in seconds).
182
+ This is done via tstamp view end endkey, e.g.
183
+ curl "http://127.0.0.1:5984/logdb/_design/LogDB/_view/tstamp?endkey=1427912282"
184
+ """
185
+ cutoff = int(round(time.time()-thr))
186
+ #docs = self.db.allDocs() # may need another view to look-up old docs
187
+ spec = {'endkey':cutoff, 'reduce':False}
188
+ docs = self.db.loadView(self.design, self.tsview, spec)
189
+ ids = [d['id'] for d in docs.get('rows', [])]
190
+ self.db.bulkDeleteByIDs(ids)
191
+ return ids
@@ -0,0 +1,11 @@
1
+ """LogDB Exceptions"""
2
+
3
+ class LogDBError(Exception):
4
+ """Standard error baseclass"""
5
+ def __init__(self, error):
6
+ Exception.__init__(self, error)
7
+ self.msg = LogDBError.__class__.__name__
8
+ self.error = error
9
+
10
+ def __str__(self):
11
+ return "%s: %s" % (self.msg, self.error)
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env python
2
+ #-*- coding: utf-8 -*-
3
+ #pylint: disable=
4
+ """
5
+ File : LogDBReport.py
6
+ Author : Valentin Kuznetsov <vkuznet AT gmail dot com>
7
+ Description: LogDB report class to represent LogDB messages
8
+ """
9
+ from __future__ import print_function
10
+
11
+ from builtins import range
12
+ from builtins import object
13
+
14
+ class LogDBReport(object):
15
+ """LogDBReport class to represent LogDB messages"""
16
+ def __init__(self, logdb):
17
+ self.logdb = logdb
18
+
19
+ def docs(self, request):
20
+ """Fetch LogDB messages for given request"""
21
+ if request == 'all':
22
+ docs = self.logdb.get_all_requests()
23
+ else:
24
+ docs = self.logdb.get(request)
25
+ return docs
26
+
27
+ def orderby(self, docs, order):
28
+ """Order LogDB messages by given type"""
29
+ odict = {}
30
+ for item in docs:
31
+ odict[item['ts']] = item
32
+ keys = sorted(odict.keys())
33
+ keys.reverse()
34
+ out = []
35
+ for key in keys:
36
+ out.append(odict[key])
37
+ return out
38
+
39
+ def to_json(self, request, order='ts'):
40
+ """Represent given messages in JSON data-format for given set of requests"""
41
+ docs = self.orderby(self.docs(request), order)
42
+ return docs
43
+
44
+ def to_txt(self, request, order='ts', sep=' '):
45
+ """Represent given messages in ASCII text format for given set of requests"""
46
+ docs = self.orderby(self.docs(request), order)
47
+ keys = list(docs[0])
48
+ out = sep.join(keys) + '\n'
49
+ for doc in docs:
50
+ values = []
51
+ for key in keys:
52
+ values.append('%s' % doc[key])
53
+ out += sep.join(values) + '\n'
54
+ return out
55
+
56
+ def to_html(self, request, order='ts'):
57
+ """Represent given messages in ASCII text format for given set of requests"""
58
+ out = '<table id="logdb-report">\n'
59
+ for doc in self.to_txt(request, order, sep='</td><td>').split('\n'):
60
+ if doc:
61
+ out += '<tr><td>'+doc+'</td></tr>\n'
62
+ out += '</table>'
63
+ return out
64
+
65
+ def to_stdout(self, request, order='ts'):
66
+ """Yield to stdout LogDB messages for given request/type"""
67
+ msg = '\nReport for %s' % request
68
+ print(msg, '\n', '-'*len(msg))
69
+ docs = self.orderby(self.docs(request), order)
70
+ times = []
71
+ messages = []
72
+ mtypes = []
73
+ for doc in docs:
74
+ times.append(str(doc['ts']))
75
+ messages.append(doc['msg'])
76
+ mtypes.append(doc['type'])
77
+ tstpad = max([len(t) for t in times])
78
+ msgpad = max([len(m) for m in messages])
79
+ mtppad = max([len(m) for m in mtypes])
80
+ out = []
81
+ for idx in range(len(times)):
82
+ tcol = '%s%s' % (times[idx], ' '*(tstpad-len(times[idx])))
83
+ mcol = '%s%s' % (messages[idx], ' '*(msgpad-len(messages[idx])))
84
+ ecol = '%s%s' % (mtypes[idx], ' '*(mtppad-len(mtypes[idx])))
85
+ print("%s %s %s" % (tcol, mcol, ecol))
File without changes
File without changes
@@ -0,0 +1,54 @@
1
+ """
2
+ This module contains a few basic WMCore-related utilitarian functions
3
+ """
4
+
5
+ from Utils.CertTools import ckey, cert
6
+
7
+ from WMCore.Services.pycurl_manager import RequestHandler
8
+
9
+
10
+ def makeHttpRequest(srvUrl, payload=None, method='GET', headers=None, encode=True, decode=True, payloadSizeToDump=50):
11
+ """
12
+ Perform HTTP call to provided service URL. This can be any of supported methods like
13
+ GET, POST, PUT, DELETE. It will return HTTP response from upstream MicroService
14
+ and parse it accordingly (the WMCore MS service returns results as {'result': {'data':...}}
15
+ HTTP response.
16
+
17
+ :param srvUrl: string with the service url
18
+ :param payload: payload query or document, in case of GET HTTP request it is query dictionary,
19
+ in case of POST/PUT HTTP requests it is JSON payload to the service
20
+ :param method: string, defines which HTTP method to use
21
+ :param headers: HTTP headers (presented as dictionarY)
22
+ :param encode: boolean to reflect if data should be encoded, see pycurl_manager.py
23
+ :param decode: boolean to reflect if data should be decoded, see pycurl_manager.py
24
+ :param payloadSizeToDump: amount of characters to dump in a log from payload (to make log entries readable)
25
+ :return: returns a list with all objects, or raises
26
+ an exception in case of failure
27
+ """
28
+ payload = payload or {}
29
+ mgr = RequestHandler()
30
+ headers = headers or {'Content-Type': 'application/json'}
31
+ data = mgr.getdata(srvUrl, payload, headers, verb=method,
32
+ ckey=ckey(), cert=cert(), encode=encode, decode=decode)
33
+ if data and data.get("result", []):
34
+ if "error" in data["result"][0]:
35
+ # strip off part of payload to make readable log message
36
+ sdata = f"{payload}"
37
+ if len(sdata) > payloadSizeToDump:
38
+ sdata = sdata[:payloadSizeToDump] + "..."
39
+ msg = f"Failed to contact {srvUrl} via {method} request with {sdata}"
40
+ msg += f" and error message: {data}"
41
+ raise RuntimeError(msg)
42
+ return data["result"]
43
+
44
+ def getPileupDocs(mspileupUrl, queryDict=None, method='GET'):
45
+ """
46
+ Fetch documents from MSPileup according to the query passed in using POST.
47
+
48
+ :param mspileupUrl: string with the MSPileup url
49
+ :param queryDict: dictionary with the MongoDB query to run
50
+ :param method: string, defines which HTTP method to use
51
+ :return: returns a list with all the pileup objects, or raises
52
+ an exception in case of failure
53
+ """
54
+ return makeHttpRequest(mspileupUrl, payload=queryDict, method=method)
File without changes
@@ -0,0 +1,173 @@
1
+ #! /bin/env python
2
+
3
+ """
4
+ A service class for retrieving data from McM using
5
+ an SSO cookie since it sits behind CERN SSO
6
+ """
7
+
8
+ from builtins import str, object
9
+ import json
10
+ import os
11
+ import pycurl
12
+ import subprocess
13
+ import logging
14
+ from typing import List
15
+ from io import BytesIO
16
+ from WMCore.WMException import WMException
17
+
18
+
19
+ class McMNoDataError(WMException):
20
+ """
21
+ _McMNoDataError_
22
+ McM responded but has no data for the request
23
+ """
24
+
25
+ def __init__(self):
26
+ WMException.__init__(self, 'McM responded correctly but has no data')
27
+
28
+
29
+ class McM(object):
30
+ """
31
+ A service class for retrieving data from McM using
32
+ an SSO cookie since it sits behind CERN SSO
33
+ 'key' must be unencrypted
34
+ """
35
+
36
+ def __init__(self, url='https://cms-pdmv.cern.ch/mcm', tmpDir='/tmp'):
37
+ self.url = url
38
+ self.tmpDir = tmpDir
39
+ self.logger = self._get_logger()
40
+ self.cookieFile = None
41
+
42
+ def __enter__(self):
43
+ self._krb_ticket()
44
+ self._get_cookie()
45
+ return self
46
+
47
+ def __exit__(self, exception_type, exception_value, traceback):
48
+ if self.cookieFile:
49
+ try:
50
+ os.remove(self.cookieFile)
51
+ except OSError:
52
+ return
53
+ return
54
+
55
+ def _get_logger(self) -> logging.Logger:
56
+ """
57
+ Create a logger for McM client
58
+ """
59
+ logger: logging.Logger = logging.getLogger("mcm_client")
60
+ date_format: str = "%Y-%m-%d %H:%M:%S %z"
61
+ format: str = "[%(levelname)s][%(name)s][%(asctime)s]: %(message)s"
62
+ formatter: logging.Formatter = logging.Formatter(fmt=format, datefmt=date_format)
63
+ handler: logging.StreamHandler = logging.StreamHandler()
64
+
65
+ handler.setLevel(logging.INFO)
66
+ handler.setFormatter(formatter)
67
+ logger.addHandler(handler)
68
+ return logger
69
+
70
+ def _krb_ticket(self) -> None:
71
+ """
72
+ Check there is a valid Kerberos ticket for requesting a SSO
73
+ cookie. Raise a RuntimeError if there is not one.
74
+ """
75
+ process = subprocess.Popen(["klist", "-f"],
76
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False)
77
+ stdout: str = process.communicate()[0].decode("utf-8")
78
+ if process.returncode != 0:
79
+ msg: str = ("There is no valid Kerberos ticket for requesting a SSO cookie. "
80
+ "Please make sure to provide one for your runtime environment"
81
+ )
82
+ self.logger.error(msg)
83
+ raise RuntimeError("FATAL -- %s\nError msg: %s" % (msg, stdout))
84
+
85
+ def _get_cookie(self) -> None:
86
+ """
87
+ Request a SSO cookie to authenticate to McM.
88
+ """
89
+ self.cookieFile = os.path.join(self.tmpDir, 'ssoCookie.txt')
90
+ command: List[str] = ["auth-get-sso-cookie", "-u", self.url, "-o", self.cookieFile, "-vv"]
91
+ callback_not_invoked: str = "DEBUG: Not automatically redirected: trying SAML authentication"
92
+ cookie_stored: str = "INFO: Saving cookies"
93
+
94
+ process = subprocess.Popen(command, stdout=subprocess.PIPE,
95
+ stderr=subprocess.STDOUT, shell=False)
96
+ stdout: str = process.communicate()[0].decode("utf-8")
97
+ stdout_list: List[str] = stdout.strip().split("\n")
98
+ if process.returncode != 0:
99
+ raise RuntimeError("FATAL -- Error requesting SSO cookie\nError msg: %s" % (stdout))
100
+
101
+ if callback_not_invoked in stdout:
102
+ callback_idx: int = stdout_list.index(callback_not_invoked)
103
+ stored_after_issue: bool = cookie_stored in stdout_list[callback_idx + 1]
104
+ if stored_after_issue:
105
+ msg: str = ("Callback method was not invoked. "
106
+ "Please make sure the provided Kerberos ticket is not linked to an account with 2FA"
107
+ )
108
+ raise RuntimeError(msg)
109
+
110
+ def _getURL(self, extendURL):
111
+ """
112
+ Fetch an MCM URL with CURL using the SSO cookie.
113
+ Only intended to be used internally
114
+ """
115
+
116
+ try:
117
+ b = BytesIO()
118
+ c = pycurl.Curl()
119
+
120
+ fullUrl = '%s/%s' % (self.url, extendURL)
121
+
122
+ c.setopt(c.URL, fullUrl)
123
+ c.setopt(c.SSL_VERIFYPEER, False)
124
+ c.setopt(c.SSL_VERIFYHOST, False)
125
+ c.setopt(c.FOLLOWLOCATION, True)
126
+ c.setopt(c.COOKIEJAR, self.cookieFile)
127
+ c.setopt(c.COOKIEFILE, self.cookieFile)
128
+ c.setopt(c.WRITEFUNCTION, b.write)
129
+ c.perform()
130
+ if c.getinfo(pycurl.HTTP_CODE) != 200:
131
+ raise IOError
132
+ except:
133
+ c.close()
134
+ raise IOError('Was not able to fetch or decode URL from McM')
135
+
136
+ try:
137
+ body = b.getvalue()
138
+ res = json.loads(body)
139
+ except ValueError:
140
+ c.close()
141
+ raise IOError('Was not able to decode JSON from McM')
142
+
143
+ c.close()
144
+ return res
145
+
146
+ def getHistory(self, prepID):
147
+ """
148
+ Get the history record which has who did what to an McM request
149
+ """
150
+
151
+ try:
152
+ url = 'search?db_name=batches&contains=%s&get_raw' % prepID
153
+ res = self._getURL(url)
154
+ history = res.get("results", [])[0].get("history", [])
155
+ return history
156
+ except IndexError:
157
+ raise McMNoDataError
158
+
159
+ def getRequest(self, prepID):
160
+ """
161
+ Get the request record which has, among other things,
162
+ the number of requested events
163
+ """
164
+
165
+ url = 'public/restapi/requests/get/%s' % prepID
166
+ res = self._getURL(url)
167
+ return res['results']
168
+
169
+
170
+ if __name__ == '__main__':
171
+ with McM() as mcm:
172
+ history = mcm.getHistory(prepID='BTV-Upg2023SHCAL14DR-00002')
173
+ request = mcm.getRequest(prepID='BTV-Upg2023SHCAL14DR-00002')
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ _McM_
4
+
5
+ API for McM
6
+
7
+ """
8
+ __all__ = []
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env python
2
+ # coding=utf-8
3
+ """
4
+ Wrapper class, based on the PyCuRL module, providing an interface
5
+ to CERN MonIT Grafana APIs
6
+ """
7
+ from __future__ import division, print_function, absolute_import
8
+ from builtins import str, object
9
+ from future import standard_library
10
+ standard_library.install_aliases()
11
+
12
+ import logging
13
+ import json
14
+ from copy import copy
15
+ from pprint import pformat
16
+ from urllib.parse import urljoin
17
+
18
+ from WMCore.Services.pycurl_manager import RequestHandler
19
+
20
+ class Grafana(object):
21
+ """
22
+ Service class providing functionality to CERN monitoring Grafana APIs
23
+ """
24
+
25
+ def __init__(self, token, configDict=None):
26
+ """
27
+ Constructs a Grafana object.
28
+ :param token: mandatory string with the key/token string
29
+ :param configDict: dictionary with extra parameters, such as:
30
+ logger: logger object
31
+ endpoint: string with the url/endpoint to be used
32
+ cacheduration: float with the cache duration, in hours
33
+ headers: dictionary with the headers to be used
34
+ """
35
+ self._token = token
36
+ self.configDict = configDict or {}
37
+ self.configDict.setdefault('endpoint', "https://monit-grafana.cern.ch")
38
+ self.configDict.setdefault('cacheduration', 0) # in hours
39
+ if 'headers' not in self.configDict:
40
+ self.configDict.setdefault('headers', {})
41
+ self.configDict['headers'].update({"Accept": "application/json"})
42
+ self.configDict['headers'].update({"Content-Type": "application/json"})
43
+
44
+ self.logger = self.configDict.get("logger", logging.getLogger())
45
+ self.logger.info("MonIT service initialized with parameters: %s", self.configDict)
46
+
47
+ def updateToken(self, token):
48
+ """
49
+ Update token to be used in requests made through this module
50
+ :param token: string with the new token
51
+ """
52
+ self._token = token
53
+
54
+ def _postRequest(self, url, params, verb='POST', verbose=0):
55
+ "Helper function to POST request to given URL"
56
+ mgr = RequestHandler(logger=self.logger)
57
+ headers = copy(self.configDict['headers'])
58
+ headers.update({"Authorization": self._token})
59
+
60
+ try:
61
+ data = mgr.getdata(url, params, headers, verb=verb, verbose=verbose)
62
+ return json.loads(data)
63
+ except Exception as exc:
64
+ self.logger.error("Failed to retrieve data from MonIT. Error: %s", str(exc))
65
+ return None
66
+
67
+ def getAPIData(self, apiName, queryStr=''):
68
+ """
69
+ _getAPIData_
70
+
71
+ Retrieve data from a given Grafana API and index name
72
+ :param apiName: string with the API name/number
73
+ :param queryStr: string with the whole query logic
74
+ :return: data as retrieved from Grafana
75
+ """
76
+ uri = urljoin(self.configDict['endpoint'], "/api/datasources/proxy/%s/_msearch" % apiName)
77
+ return self._postRequest(uri, queryStr)
78
+
79
+ def getSSBData(self, pathName, metricName, indexName="monit_prod_cmssst_*",
80
+ apiName="9475", queryStr=''):
81
+ """
82
+ _getSSBData_
83
+
84
+ Retrieve data from the SSB index in Grafana
85
+ :param pathName: string with the path to the correct metric, mapped from SSB as:
86
+ columnid=237 ProdStatus path="sts15min" data.prod_status
87
+ columnid=160 CPU bound path="scap15min" data.core_cpu_intensive
88
+ columnid=161 I/O bound path="scap15min" data.core_io_intensive
89
+ columnid=159 Prod Cores path="scap15min" data.core_production
90
+ columnid=136 Real Cores path="scap15min" data.core_max_used
91
+ columnid=107 Tape Pledge path="scap15min" data.tape_pledge
92
+ :param indexName: optional string with the grafana index name
93
+ :param apiName: optional string with the Grafana API number
94
+ :param queryStr: optional string with the full query logic
95
+ :return: dictionary with the site names and the metric value
96
+ """
97
+ # TODO: allow flexible time range instead of the hardwired last 24h
98
+ # TODO: allow flexible number of rows, instead of the hardwired 500
99
+ results = {}
100
+ if metricName not in ('prod_status', 'core_cpu_intensive', 'core_io_intensive',
101
+ 'core_production', 'core_max_used', 'tape_pledge'):
102
+ self.logger.error("SSB metric name '%s' is NOT supported.", metricName)
103
+ return results
104
+
105
+ uri = urljoin(self.configDict['endpoint'], "/api/datasources/proxy/%s/_msearch" % apiName)
106
+ if not queryStr:
107
+ ### NOTE: these '\n' new lines are mandatory to get it working...
108
+ queryStr = '{"search_type":"query_then_fetch","ignore_unavailable":true,"index":["%s"]}\n' % indexName
109
+ queryStr += '{"size":500,"query":{"bool":{"filter":[{"range":{"metadata.timestamp":{"gte":"now-1d","lte":"now","format":"epoch_millis"}}},' \
110
+ '{"query_string":{"analyze_wildcard":true,' \
111
+ '"query":"metadata.type: ssbmetric AND metadata.type_prefix:raw AND metadata.monit_hdfs_path: %s"}}]}},' \
112
+ '"sort":{"metadata.timestamp":{"order":"desc","unmapped_type":"boolean"}},' \
113
+ '"script_fields":{},"docvalue_fields":["metadata.timestamp"]}\n' % pathName
114
+ self.logger.info("Calling API: %s with query: %s", uri, pformat(queryStr))
115
+
116
+ data = self._postRequest(uri, queryStr)
117
+ #self.logger.debug("Data retrieved: %s", pformat(data))
118
+ if data:
119
+ # now parse the ugly output
120
+ hits = data['responses'][0]['hits']['hits']
121
+ for item in hits:
122
+ site = item['_source']['data']['name']
123
+ metricValue = item['_source']['data'][metricName]
124
+ tStamp = int(item['sort'][0])
125
+
126
+ results.setdefault(site, {})
127
+ if tStamp > results[site].get("timeStamp", 0):
128
+ results[site][metricName] = metricValue
129
+ results[site]["timeStamp"] = tStamp
130
+
131
+ data = results
132
+
133
+ return data
File without changes