wmglobalqueue 2.4.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (347) hide show
  1. Utils/CPMetrics.py +270 -0
  2. Utils/CertTools.py +100 -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/ProcFS.py +112 -0
  13. Utils/ProcessStats.py +194 -0
  14. Utils/PythonVersion.py +17 -0
  15. Utils/Signals.py +36 -0
  16. Utils/TemporaryEnvironment.py +27 -0
  17. Utils/Throttled.py +227 -0
  18. Utils/Timers.py +130 -0
  19. Utils/Timestamps.py +86 -0
  20. Utils/TokenManager.py +143 -0
  21. Utils/Tracing.py +60 -0
  22. Utils/TwPrint.py +98 -0
  23. Utils/Utilities.py +318 -0
  24. Utils/__init__.py +11 -0
  25. Utils/wmcoreDTools.py +707 -0
  26. WMCore/ACDC/Collection.py +57 -0
  27. WMCore/ACDC/CollectionTypes.py +12 -0
  28. WMCore/ACDC/CouchCollection.py +67 -0
  29. WMCore/ACDC/CouchFileset.py +238 -0
  30. WMCore/ACDC/CouchService.py +73 -0
  31. WMCore/ACDC/DataCollectionService.py +485 -0
  32. WMCore/ACDC/Fileset.py +94 -0
  33. WMCore/ACDC/__init__.py +11 -0
  34. WMCore/Algorithms/Alarm.py +39 -0
  35. WMCore/Algorithms/MathAlgos.py +274 -0
  36. WMCore/Algorithms/MiscAlgos.py +67 -0
  37. WMCore/Algorithms/ParseXMLFile.py +115 -0
  38. WMCore/Algorithms/Permissions.py +27 -0
  39. WMCore/Algorithms/Singleton.py +58 -0
  40. WMCore/Algorithms/SubprocessAlgos.py +129 -0
  41. WMCore/Algorithms/__init__.py +7 -0
  42. WMCore/Cache/GenericDataCache.py +98 -0
  43. WMCore/Cache/WMConfigCache.py +572 -0
  44. WMCore/Cache/__init__.py +0 -0
  45. WMCore/Configuration.py +659 -0
  46. WMCore/DAOFactory.py +47 -0
  47. WMCore/DataStructs/File.py +177 -0
  48. WMCore/DataStructs/Fileset.py +140 -0
  49. WMCore/DataStructs/Job.py +182 -0
  50. WMCore/DataStructs/JobGroup.py +142 -0
  51. WMCore/DataStructs/JobPackage.py +49 -0
  52. WMCore/DataStructs/LumiList.py +734 -0
  53. WMCore/DataStructs/Mask.py +219 -0
  54. WMCore/DataStructs/MathStructs/ContinuousSummaryHistogram.py +197 -0
  55. WMCore/DataStructs/MathStructs/DiscreteSummaryHistogram.py +92 -0
  56. WMCore/DataStructs/MathStructs/SummaryHistogram.py +117 -0
  57. WMCore/DataStructs/MathStructs/__init__.py +0 -0
  58. WMCore/DataStructs/Pickleable.py +24 -0
  59. WMCore/DataStructs/Run.py +256 -0
  60. WMCore/DataStructs/Subscription.py +175 -0
  61. WMCore/DataStructs/WMObject.py +47 -0
  62. WMCore/DataStructs/WorkUnit.py +112 -0
  63. WMCore/DataStructs/Workflow.py +60 -0
  64. WMCore/DataStructs/__init__.py +8 -0
  65. WMCore/Database/CMSCouch.py +1430 -0
  66. WMCore/Database/ConfigDBMap.py +29 -0
  67. WMCore/Database/CouchMonitoring.py +450 -0
  68. WMCore/Database/CouchUtils.py +118 -0
  69. WMCore/Database/DBCore.py +198 -0
  70. WMCore/Database/DBCreator.py +113 -0
  71. WMCore/Database/DBExceptionHandler.py +59 -0
  72. WMCore/Database/DBFactory.py +117 -0
  73. WMCore/Database/DBFormatter.py +177 -0
  74. WMCore/Database/Dialects.py +13 -0
  75. WMCore/Database/ExecuteDAO.py +327 -0
  76. WMCore/Database/MongoDB.py +241 -0
  77. WMCore/Database/MySQL/Destroy.py +42 -0
  78. WMCore/Database/MySQL/ListUserContent.py +20 -0
  79. WMCore/Database/MySQL/__init__.py +9 -0
  80. WMCore/Database/MySQLCore.py +132 -0
  81. WMCore/Database/Oracle/Destroy.py +56 -0
  82. WMCore/Database/Oracle/ListUserContent.py +19 -0
  83. WMCore/Database/Oracle/__init__.py +9 -0
  84. WMCore/Database/ResultSet.py +44 -0
  85. WMCore/Database/Transaction.py +91 -0
  86. WMCore/Database/__init__.py +9 -0
  87. WMCore/Database/ipy_profile_couch.py +438 -0
  88. WMCore/GlobalWorkQueue/CherryPyThreads/CleanUpTask.py +29 -0
  89. WMCore/GlobalWorkQueue/CherryPyThreads/HeartbeatMonitor.py +105 -0
  90. WMCore/GlobalWorkQueue/CherryPyThreads/LocationUpdateTask.py +28 -0
  91. WMCore/GlobalWorkQueue/CherryPyThreads/ReqMgrInteractionTask.py +35 -0
  92. WMCore/GlobalWorkQueue/CherryPyThreads/__init__.py +0 -0
  93. WMCore/GlobalWorkQueue/__init__.py +0 -0
  94. WMCore/GroupUser/CouchObject.py +127 -0
  95. WMCore/GroupUser/Decorators.py +51 -0
  96. WMCore/GroupUser/Group.py +33 -0
  97. WMCore/GroupUser/Interface.py +73 -0
  98. WMCore/GroupUser/User.py +96 -0
  99. WMCore/GroupUser/__init__.py +11 -0
  100. WMCore/Lexicon.py +836 -0
  101. WMCore/REST/Auth.py +202 -0
  102. WMCore/REST/CherryPyPeriodicTask.py +166 -0
  103. WMCore/REST/Error.py +333 -0
  104. WMCore/REST/Format.py +642 -0
  105. WMCore/REST/HeartbeatMonitorBase.py +90 -0
  106. WMCore/REST/Main.py +636 -0
  107. WMCore/REST/Server.py +2435 -0
  108. WMCore/REST/Services.py +24 -0
  109. WMCore/REST/Test.py +120 -0
  110. WMCore/REST/Tools.py +38 -0
  111. WMCore/REST/Validation.py +250 -0
  112. WMCore/REST/__init__.py +1 -0
  113. WMCore/ReqMgr/DataStructs/RequestStatus.py +209 -0
  114. WMCore/ReqMgr/DataStructs/RequestType.py +13 -0
  115. WMCore/ReqMgr/DataStructs/__init__.py +0 -0
  116. WMCore/ReqMgr/__init__.py +1 -0
  117. WMCore/Services/AlertManager/AlertManagerAPI.py +111 -0
  118. WMCore/Services/AlertManager/__init__.py +0 -0
  119. WMCore/Services/CRIC/CRIC.py +238 -0
  120. WMCore/Services/CRIC/__init__.py +0 -0
  121. WMCore/Services/DBS/DBS3Reader.py +1044 -0
  122. WMCore/Services/DBS/DBSConcurrency.py +44 -0
  123. WMCore/Services/DBS/DBSErrors.py +112 -0
  124. WMCore/Services/DBS/DBSReader.py +23 -0
  125. WMCore/Services/DBS/DBSUtils.py +166 -0
  126. WMCore/Services/DBS/DBSWriterObjects.py +381 -0
  127. WMCore/Services/DBS/ProdException.py +133 -0
  128. WMCore/Services/DBS/__init__.py +8 -0
  129. WMCore/Services/FWJRDB/FWJRDBAPI.py +118 -0
  130. WMCore/Services/FWJRDB/__init__.py +0 -0
  131. WMCore/Services/HTTPS/HTTPSAuthHandler.py +66 -0
  132. WMCore/Services/HTTPS/__init__.py +0 -0
  133. WMCore/Services/LogDB/LogDB.py +201 -0
  134. WMCore/Services/LogDB/LogDBBackend.py +191 -0
  135. WMCore/Services/LogDB/LogDBExceptions.py +11 -0
  136. WMCore/Services/LogDB/LogDBReport.py +85 -0
  137. WMCore/Services/LogDB/__init__.py +0 -0
  138. WMCore/Services/MSPileup/__init__.py +0 -0
  139. WMCore/Services/MSUtils/MSUtils.py +54 -0
  140. WMCore/Services/MSUtils/__init__.py +0 -0
  141. WMCore/Services/McM/McM.py +173 -0
  142. WMCore/Services/McM/__init__.py +8 -0
  143. WMCore/Services/MonIT/Grafana.py +133 -0
  144. WMCore/Services/MonIT/__init__.py +0 -0
  145. WMCore/Services/PyCondor/PyCondorAPI.py +154 -0
  146. WMCore/Services/PyCondor/__init__.py +0 -0
  147. WMCore/Services/ReqMgr/ReqMgr.py +261 -0
  148. WMCore/Services/ReqMgr/__init__.py +0 -0
  149. WMCore/Services/ReqMgrAux/ReqMgrAux.py +419 -0
  150. WMCore/Services/ReqMgrAux/__init__.py +0 -0
  151. WMCore/Services/RequestDB/RequestDBReader.py +267 -0
  152. WMCore/Services/RequestDB/RequestDBWriter.py +39 -0
  153. WMCore/Services/RequestDB/__init__.py +0 -0
  154. WMCore/Services/Requests.py +624 -0
  155. WMCore/Services/Rucio/Rucio.py +1290 -0
  156. WMCore/Services/Rucio/RucioUtils.py +74 -0
  157. WMCore/Services/Rucio/__init__.py +0 -0
  158. WMCore/Services/RucioConMon/RucioConMon.py +121 -0
  159. WMCore/Services/RucioConMon/__init__.py +0 -0
  160. WMCore/Services/Service.py +400 -0
  161. WMCore/Services/StompAMQ/__init__.py +0 -0
  162. WMCore/Services/TagCollector/TagCollector.py +155 -0
  163. WMCore/Services/TagCollector/XMLUtils.py +98 -0
  164. WMCore/Services/TagCollector/__init__.py +0 -0
  165. WMCore/Services/UUIDLib.py +13 -0
  166. WMCore/Services/UserFileCache/UserFileCache.py +160 -0
  167. WMCore/Services/UserFileCache/__init__.py +8 -0
  168. WMCore/Services/WMAgent/WMAgent.py +63 -0
  169. WMCore/Services/WMAgent/__init__.py +0 -0
  170. WMCore/Services/WMArchive/CMSSWMetrics.py +526 -0
  171. WMCore/Services/WMArchive/DataMap.py +463 -0
  172. WMCore/Services/WMArchive/WMArchive.py +33 -0
  173. WMCore/Services/WMArchive/__init__.py +0 -0
  174. WMCore/Services/WMBS/WMBS.py +97 -0
  175. WMCore/Services/WMBS/__init__.py +0 -0
  176. WMCore/Services/WMStats/DataStruct/RequestInfoCollection.py +300 -0
  177. WMCore/Services/WMStats/DataStruct/__init__.py +0 -0
  178. WMCore/Services/WMStats/WMStatsPycurl.py +145 -0
  179. WMCore/Services/WMStats/WMStatsReader.py +445 -0
  180. WMCore/Services/WMStats/WMStatsWriter.py +273 -0
  181. WMCore/Services/WMStats/__init__.py +0 -0
  182. WMCore/Services/WMStatsServer/WMStatsServer.py +134 -0
  183. WMCore/Services/WMStatsServer/__init__.py +0 -0
  184. WMCore/Services/WorkQueue/WorkQueue.py +492 -0
  185. WMCore/Services/WorkQueue/__init__.py +0 -0
  186. WMCore/Services/__init__.py +8 -0
  187. WMCore/Services/pycurl_manager.py +574 -0
  188. WMCore/WMBase.py +50 -0
  189. WMCore/WMConnectionBase.py +164 -0
  190. WMCore/WMException.py +183 -0
  191. WMCore/WMExceptions.py +269 -0
  192. WMCore/WMFactory.py +76 -0
  193. WMCore/WMInit.py +377 -0
  194. WMCore/WMLogging.py +104 -0
  195. WMCore/WMSpec/ConfigSectionTree.py +442 -0
  196. WMCore/WMSpec/Persistency.py +135 -0
  197. WMCore/WMSpec/Steps/BuildMaster.py +87 -0
  198. WMCore/WMSpec/Steps/BuildTools.py +201 -0
  199. WMCore/WMSpec/Steps/Builder.py +97 -0
  200. WMCore/WMSpec/Steps/Diagnostic.py +89 -0
  201. WMCore/WMSpec/Steps/Emulator.py +62 -0
  202. WMCore/WMSpec/Steps/ExecuteMaster.py +208 -0
  203. WMCore/WMSpec/Steps/Executor.py +210 -0
  204. WMCore/WMSpec/Steps/StepFactory.py +213 -0
  205. WMCore/WMSpec/Steps/TaskEmulator.py +75 -0
  206. WMCore/WMSpec/Steps/Template.py +204 -0
  207. WMCore/WMSpec/Steps/Templates/AlcaHarvest.py +76 -0
  208. WMCore/WMSpec/Steps/Templates/CMSSW.py +613 -0
  209. WMCore/WMSpec/Steps/Templates/DQMUpload.py +59 -0
  210. WMCore/WMSpec/Steps/Templates/DeleteFiles.py +70 -0
  211. WMCore/WMSpec/Steps/Templates/LogArchive.py +84 -0
  212. WMCore/WMSpec/Steps/Templates/LogCollect.py +105 -0
  213. WMCore/WMSpec/Steps/Templates/StageOut.py +105 -0
  214. WMCore/WMSpec/Steps/Templates/__init__.py +10 -0
  215. WMCore/WMSpec/Steps/WMExecutionFailure.py +21 -0
  216. WMCore/WMSpec/Steps/__init__.py +8 -0
  217. WMCore/WMSpec/Utilities.py +63 -0
  218. WMCore/WMSpec/WMSpecErrors.py +12 -0
  219. WMCore/WMSpec/WMStep.py +347 -0
  220. WMCore/WMSpec/WMTask.py +1997 -0
  221. WMCore/WMSpec/WMWorkload.py +2288 -0
  222. WMCore/WMSpec/WMWorkloadTools.py +382 -0
  223. WMCore/WMSpec/__init__.py +9 -0
  224. WMCore/WorkQueue/DataLocationMapper.py +273 -0
  225. WMCore/WorkQueue/DataStructs/ACDCBlock.py +47 -0
  226. WMCore/WorkQueue/DataStructs/Block.py +48 -0
  227. WMCore/WorkQueue/DataStructs/CouchWorkQueueElement.py +148 -0
  228. WMCore/WorkQueue/DataStructs/WorkQueueElement.py +274 -0
  229. WMCore/WorkQueue/DataStructs/WorkQueueElementResult.py +152 -0
  230. WMCore/WorkQueue/DataStructs/WorkQueueElementsSummary.py +185 -0
  231. WMCore/WorkQueue/DataStructs/__init__.py +0 -0
  232. WMCore/WorkQueue/Policy/End/EndPolicyInterface.py +44 -0
  233. WMCore/WorkQueue/Policy/End/SingleShot.py +22 -0
  234. WMCore/WorkQueue/Policy/End/__init__.py +32 -0
  235. WMCore/WorkQueue/Policy/PolicyInterface.py +17 -0
  236. WMCore/WorkQueue/Policy/Start/Block.py +258 -0
  237. WMCore/WorkQueue/Policy/Start/Dataset.py +180 -0
  238. WMCore/WorkQueue/Policy/Start/MonteCarlo.py +131 -0
  239. WMCore/WorkQueue/Policy/Start/ResubmitBlock.py +171 -0
  240. WMCore/WorkQueue/Policy/Start/StartPolicyInterface.py +316 -0
  241. WMCore/WorkQueue/Policy/Start/__init__.py +34 -0
  242. WMCore/WorkQueue/Policy/__init__.py +57 -0
  243. WMCore/WorkQueue/WMBSHelper.py +772 -0
  244. WMCore/WorkQueue/WorkQueue.py +1237 -0
  245. WMCore/WorkQueue/WorkQueueBackend.py +750 -0
  246. WMCore/WorkQueue/WorkQueueBase.py +39 -0
  247. WMCore/WorkQueue/WorkQueueExceptions.py +44 -0
  248. WMCore/WorkQueue/WorkQueueReqMgrInterface.py +278 -0
  249. WMCore/WorkQueue/WorkQueueUtils.py +130 -0
  250. WMCore/WorkQueue/__init__.py +13 -0
  251. WMCore/Wrappers/JsonWrapper/JSONThunker.py +342 -0
  252. WMCore/Wrappers/JsonWrapper/__init__.py +7 -0
  253. WMCore/Wrappers/__init__.py +6 -0
  254. WMCore/__init__.py +10 -0
  255. wmglobalqueue-2.4.5.1.data/data/bin/wmc-dist-patch +15 -0
  256. wmglobalqueue-2.4.5.1.data/data/bin/wmc-dist-unpatch +8 -0
  257. wmglobalqueue-2.4.5.1.data/data/bin/wmc-httpd +3 -0
  258. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/.couchapprc +1 -0
  259. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/README.md +40 -0
  260. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/index.html +264 -0
  261. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/js/ElementInfoByWorkflow.js +96 -0
  262. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/js/StuckElementInfo.js +57 -0
  263. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/js/WorkloadInfoTable.js +80 -0
  264. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/js/dataTable.js +70 -0
  265. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/js/namespace.js +23 -0
  266. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/_attachments/style/main.css +75 -0
  267. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/couchapp.json +4 -0
  268. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/filters/childQueueFilter.js +13 -0
  269. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/filters/filterDeletedDocs.js +3 -0
  270. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/filters/queueFilter.js +11 -0
  271. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/language +1 -0
  272. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lib/mustache.js +333 -0
  273. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lib/validate.js +27 -0
  274. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lib/workqueue_utils.js +61 -0
  275. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lists/elementsDetail.js +28 -0
  276. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lists/filter.js +86 -0
  277. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lists/stuckElements.js +38 -0
  278. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lists/workRestrictions.js +153 -0
  279. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/lists/workflowSummary.js +28 -0
  280. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/rewrites.json +73 -0
  281. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/shows/redirect.js +23 -0
  282. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/shows/status.js +40 -0
  283. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/ElementSummaryByWorkflow.html +27 -0
  284. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/StuckElementSummary.html +26 -0
  285. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/TaskStatus.html +23 -0
  286. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/WorkflowSummary.html +27 -0
  287. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/partials/workqueue-common-lib.html +2 -0
  288. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib-remote.html +16 -0
  289. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/templates/partials/yui-lib.html +18 -0
  290. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/updates/in-place.js +50 -0
  291. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/validate_doc_update.js +8 -0
  292. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.couch.app.js +235 -0
  293. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.pathbinder.js +173 -0
  294. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activeData/map.js +8 -0
  295. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activeData/reduce.js +2 -0
  296. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activeParentData/map.js +8 -0
  297. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activeParentData/reduce.js +2 -0
  298. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activePileupData/map.js +8 -0
  299. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/activePileupData/reduce.js +2 -0
  300. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/analyticsData/map.js +11 -0
  301. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/analyticsData/reduce.js +1 -0
  302. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/availableByPriority/map.js +6 -0
  303. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/conflicts/map.js +5 -0
  304. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elements/map.js +5 -0
  305. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByData/map.js +8 -0
  306. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByParent/map.js +8 -0
  307. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByParentData/map.js +8 -0
  308. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByPileupData/map.js +8 -0
  309. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByStatus/map.js +8 -0
  310. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsBySubscription/map.js +6 -0
  311. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/map.js +8 -0
  312. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsByWorkflow/reduce.js +3 -0
  313. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/elementsDetailByWorkflowAndStatus/map.js +26 -0
  314. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/map.js +10 -0
  315. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/reduce.js +1 -0
  316. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/map.js +6 -0
  317. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobStatusByRequest/reduce.js +1 -0
  318. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/map.js +6 -0
  319. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/reduce.js +1 -0
  320. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/map.js +6 -0
  321. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/reduce.js +1 -0
  322. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByRequest/map.js +6 -0
  323. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByRequest/reduce.js +1 -0
  324. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByStatus/map.js +6 -0
  325. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByStatus/reduce.js +1 -0
  326. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/map.js +6 -0
  327. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/reduce.js +1 -0
  328. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/openRequests/map.js +6 -0
  329. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/recent-items/map.js +5 -0
  330. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/map.js +6 -0
  331. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/reduce.js +1 -0
  332. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/specsByWorkflow/map.js +5 -0
  333. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/stuckElements/map.js +38 -0
  334. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/map.js +12 -0
  335. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/reduce.js +3 -0
  336. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsUrl/map.js +6 -0
  337. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsUrl/reduce.js +2 -0
  338. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/map.js +6 -0
  339. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/reduce.js +2 -0
  340. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/workflowSummary/map.js +9 -0
  341. wmglobalqueue-2.4.5.1.data/data/data/couchapps/WorkQueue/views/workflowSummary/reduce.js +10 -0
  342. wmglobalqueue-2.4.5.1.dist-info/METADATA +26 -0
  343. wmglobalqueue-2.4.5.1.dist-info/RECORD +347 -0
  344. wmglobalqueue-2.4.5.1.dist-info/WHEEL +5 -0
  345. wmglobalqueue-2.4.5.1.dist-info/licenses/LICENSE +202 -0
  346. wmglobalqueue-2.4.5.1.dist-info/licenses/NOTICE +16 -0
  347. wmglobalqueue-2.4.5.1.dist-info/top_level.txt +2 -0
Utils/CPMetrics.py ADDED
@@ -0,0 +1,270 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ File : CPMetrics.py
4
+ Author : Valentin Kuznetsov <vkuznet AT gmail dot com>
5
+ Description: This module provide functions to flatten cherrypy stats
6
+ and provide them in Prometheus format for scraping.
7
+
8
+ Below we present three different outputs:
9
+ - CherryPy stats default output
10
+ - flatten structure of stats
11
+ - prometheus output for stats
12
+
13
+ ### Defautl CherryPy metrics output
14
+
15
+ {
16
+ "Cheroot HTTPServer 4388603856": {
17
+ "Accepts": 0,
18
+ "Accepts/sec": 0.0,
19
+ "Bind Address": "('127.0.0.1', 8080)",
20
+ "Bytes Read": -1,
21
+ "Bytes Written": -1,
22
+ "Enabled": false,
23
+ "Queue": 0,
24
+ "Read Throughput": -1,
25
+ "Requests": -1,
26
+ "Run time": -1,
27
+ "Socket Errors": 0,
28
+ "Threads": 20,
29
+ "Threads Idle": 19,
30
+ "Work Time": -1,
31
+ "Worker Threads": {
32
+ "CP Server Thread-10": {
33
+ "Bytes Read": 0,
34
+ "Bytes Written": 0,
35
+ "Read Throughput": 0.0,
36
+ "Requests": 0,
37
+ "Work Time": 0,
38
+ "Write Throughput": 0.0
39
+ },
40
+ .....
41
+ },
42
+ "Write Throughput": -1
43
+ },
44
+ "CherryPy Applications": {
45
+ "Bytes Read/Request": 0.0,
46
+ "Bytes Read/Second": 0.0,
47
+ "Bytes Written/Request": 0.0,
48
+ "Bytes Written/Second": 0.0,
49
+ "Current Requests": 0,
50
+ "Current Time": 1601039589.916887,
51
+ "Enabled": true,
52
+ "Requests": {},
53
+ "Requests/Second": 0.0,
54
+ "Server Version": "17.4.2",
55
+ "Start Time": 1601039576.541158,
56
+ "Total Bytes Read": 0,
57
+ "Total Bytes Written": 0,
58
+ "Total Requests": 0,
59
+ "Total Time": 0,
60
+ "Uptime": 13.375718116760254
61
+ }
62
+ }
63
+
64
+ ### flatten structure via flattenStats function
65
+ {
66
+ "cherrypy_app_requests_second": 0.0,
67
+ "cherrypy_app_uptime": 1.7454230785369873,
68
+ "cherrypy_app_total_time": 0,
69
+ "cherrypy_app_current_time": 1601040713.369842,
70
+ "cherrypy_app_bytes_read_second": 0.0,
71
+ "cherrypy_app_requests": {},
72
+ "cherrypy_http_server_queue": 0,
73
+ "cherrypy_app_bytes_written_second": 0.0,
74
+ "cherrypy_app_total_requests": 0,
75
+ "cherrypy_http_server_write_throughput": -1,
76
+ "cherrypy_app_enabled": true,
77
+ "cherrypy_app_start_time": 1601040711.624408,
78
+ "cherrypy_http_server_threads": 20,
79
+ "cherrypy_http_server_work_time": -1,
80
+ "cherrypy_app_bytes_read_request": 0.0,
81
+ "cherrypy_http_server_bytes_read": -1,
82
+ "cherrypy_http_server_accepts_sec": 0.0,
83
+ "cherrypy_server_worker_threads": [
84
+ {"thread_name": "cp_server_thread_3", "read_throughput": 0.0,
85
+ "work_time": 0, "write_throughput": 0.0, "bytes_written": 0,
86
+ "bytes_read": 0, "requests": 0}, ....],
87
+ "cherrypy_http_server_run_time": -1,
88
+ "cherrypy_http_server_bind_address": "('127.0.0.1', 8080)",
89
+ "cherrypy_app_server_version": "17.4.2",
90
+ "cherrypy_http_server_enabled": false,
91
+ "cherrypy_http_server_socket_errors": 0,
92
+ "cherrypy_app_bytes_written_request": 0.0,
93
+ "cherrypy_app_current_requests": 0,
94
+ "cherrypy_app_total_bytes_read": 0,
95
+ "cherrypy_http_server_bytes_written": -1,
96
+ "cherrypy_http_server_threads_idle": 19,
97
+ "cherrypy_http_server_requests": -1,
98
+ "cherrypy_app_total_bytes_written": 0,
99
+ "cherrypy_http_server_read_throughput": -1,
100
+ "cherrypy_http_server_accepts": 0}
101
+
102
+ ### prometheus exporter structure provided via promMetrics function
103
+
104
+ # HELP cherrypy_app_requests_second
105
+ # TYPE cherrypy_app_requests_second gauge
106
+ cherrypy_app_requests_second 0.0
107
+ # HELP cherrypy_app_uptime
108
+ # TYPE cherrypy_app_uptime gauge
109
+ cherrypy_app_uptime 2.03766894341
110
+ # HELP cherrypy_app_total_time
111
+ # TYPE cherrypy_app_total_time counter
112
+ cherrypy_app_total_time 0
113
+ # HELP cherrypy_app_current_time
114
+ # TYPE cherrypy_app_current_time gauge
115
+ cherrypy_app_current_time 1601043839.47
116
+ # HELP cherrypy_app_bytes_read_second
117
+ # TYPE cherrypy_app_bytes_read_second gauge
118
+ cherrypy_app_bytes_read_second 0.0
119
+ # HELP cherrypy_http_server_queue
120
+ # TYPE cherrypy_http_server_queue counter
121
+ cherrypy_http_server_queue 0
122
+ # HELP cherrypy_app_bytes_written_second
123
+ # TYPE cherrypy_app_bytes_written_second gauge
124
+ cherrypy_app_bytes_written_second 0.0
125
+ # HELP cherrypy_app_total_requests
126
+ # TYPE cherrypy_app_total_requests counter
127
+ cherrypy_app_total_requests 0
128
+ # HELP cherrypy_http_server_write_throughput
129
+ # TYPE cherrypy_http_server_write_throughput counter
130
+ cherrypy_http_server_write_throughput -1
131
+ # HELP cherrypy_server_worker_threads
132
+ # TYPE cherrypy_server_worker_threads histogram
133
+ cherrypy_server_worker_threads{thread_name="cp_server_thread_3",...} 1
134
+ # HELP cherrypy_app_start_time
135
+ # TYPE cherrypy_app_start_time gauge
136
+ cherrypy_app_start_time 1601043837.44
137
+ # HELP cherrypy_http_server_threads
138
+ # TYPE cherrypy_http_server_threads counter
139
+ cherrypy_http_server_threads 20
140
+ # HELP cherrypy_http_server_work_time
141
+ # TYPE cherrypy_http_server_work_time counter
142
+ cherrypy_http_server_work_time -1
143
+ # HELP cherrypy_app_bytes_read_request
144
+ # TYPE cherrypy_app_bytes_read_request gauge
145
+ cherrypy_app_bytes_read_request 0.0
146
+ # HELP cherrypy_http_server_bytes_read
147
+ # TYPE cherrypy_http_server_bytes_read counter
148
+ cherrypy_http_server_bytes_read -1
149
+ # HELP cherrypy_http_server_accepts_sec
150
+ # TYPE cherrypy_http_server_accepts_sec gauge
151
+ cherrypy_http_server_accepts_sec 0.0
152
+ # HELP cherrypy_http_server_run_time
153
+ # TYPE cherrypy_http_server_run_time counter
154
+ cherrypy_http_server_run_time -1
155
+ # HELP cherrypy_http_server_socket_errors
156
+ # TYPE cherrypy_http_server_socket_errors counter
157
+ cherrypy_http_server_socket_errors 0
158
+ # HELP cherrypy_app_bytes_written_request
159
+ # TYPE cherrypy_app_bytes_written_request gauge
160
+ cherrypy_app_bytes_written_request 0.0
161
+ # HELP cherrypy_app_current_requests
162
+ # TYPE cherrypy_app_current_requests counter
163
+ cherrypy_app_current_requests 0
164
+ # HELP cherrypy_app_total_bytes_read
165
+ # TYPE cherrypy_app_total_bytes_read counter
166
+ cherrypy_app_total_bytes_read 0
167
+ # HELP cherrypy_http_server_bytes_written
168
+ # TYPE cherrypy_http_server_bytes_written counter
169
+ cherrypy_http_server_bytes_written -1
170
+ # HELP cherrypy_http_server_threads_idle
171
+ # TYPE cherrypy_http_server_threads_idle counter
172
+ cherrypy_http_server_threads_idle 19
173
+ # HELP cherrypy_http_server_requests
174
+ # TYPE cherrypy_http_server_requests counter
175
+ cherrypy_http_server_requests -1
176
+ # HELP cherrypy_app_total_bytes_written
177
+ # TYPE cherrypy_app_total_bytes_written counter
178
+ cherrypy_app_total_bytes_written 0
179
+ # HELP cherrypy_http_server_read_throughput
180
+ # TYPE cherrypy_http_server_read_throughput counter
181
+ cherrypy_http_server_read_throughput -1
182
+ # HELP cherrypy_http_server_accepts
183
+ # TYPE cherrypy_http_server_accepts counter
184
+ cherrypy_http_server_accepts 0
185
+ """
186
+
187
+ # system modules
188
+ import json
189
+
190
+ # WMCore dependencies
191
+ from Utils.Utilities import decodeBytesToUnicode
192
+
193
+
194
+ def promMetrics(data, exporter):
195
+ """
196
+ Provide cherrypy stats prometheus metrics for given exporter name.
197
+ """
198
+ # exporter name should not contain dashes, see
199
+ # https://its.cern.ch/jira/browse/CMSMONIT-514
200
+ exporter = exporter.replace("-", "_")
201
+ metrics = flattenStats(data)
202
+ if isinstance(metrics, str):
203
+ metrics = json.loads(metrics)
204
+ # the following keys will be skipped
205
+ skip = [
206
+ 'cherrypy_app_enabled',
207
+ 'cherrypy_http_server_bind_address',
208
+ 'cherrypy_app_requests',
209
+ 'cherrypy_app_server_version',
210
+ 'cherrypy_http_server_enabled']
211
+ # our prometheus data representation
212
+ pdata = ""
213
+ for key, val in list(metrics.items()):
214
+ if key in skip:
215
+ continue
216
+ # add exporter name as a prefix for each key
217
+ key = '{}_{}'.format(exporter, key)
218
+ mhelp = "# HELP {}\n".format(key)
219
+ if isinstance(val, list):
220
+ mtype = "# TYPE {} histogram\n".format(key)
221
+ pdata += mhelp
222
+ pdata += mtype
223
+ for wdict in val:
224
+ entries = []
225
+ for kkk, vvv in list(wdict.items()):
226
+ entries.append('{}="{}"'.format(kkk, vvv))
227
+ entry = "{%s}" % ','.join(entries)
228
+ pdata += "{}{} 1\n".format(key, entry)
229
+ elif isinstance(val, (str, tuple)):
230
+ continue
231
+ else:
232
+ pdata += mhelp
233
+ if isinstance(val, int):
234
+ mtype = "# TYPE {} counter\n".format(key)
235
+ if isinstance(val, float):
236
+ mtype = "# TYPE {} gauge\n".format(key)
237
+ pdata += mtype
238
+ pdata += "{} {}\n".format(key, val)
239
+ return pdata
240
+
241
+
242
+ def flattenStats(cpdata):
243
+ "Flatten cherrypy stats to make them suitable for monitoring"
244
+ if isinstance(cpdata, str) or isinstance(cpdata, bytes):
245
+ cpdata = json.loads(decodeBytesToUnicode(cpdata))
246
+ data = {}
247
+ for cpKey, cpVal in list(cpdata.items()):
248
+ if cpKey.lower().find('cherrypy') != -1:
249
+ for cpnKey, cpnVal in list(cpVal.items()):
250
+ nkey = 'cherrypy_app_%s' % cpnKey
251
+ nkey = nkey.lower().replace(" ", "_").replace("/", "_")
252
+ data[nkey] = cpnVal
253
+ if cpKey.lower().find('cheroot') != -1:
254
+ for cpnKey, cpnVal in list(cpVal.items()):
255
+ if cpnKey == 'Worker Threads':
256
+ wdata = []
257
+ for workerKey, threadValue in list(cpnVal.items()):
258
+ workerKey = workerKey.lower().replace(" ", "_").replace("/", "_").replace("-", "_")
259
+ threadValue['thread_name'] = workerKey
260
+ nval = {}
261
+ for tkey, tval in list(threadValue.items()):
262
+ tkey = tkey.lower().replace(" ", "_").replace("/", "_")
263
+ nval[tkey] = tval
264
+ wdata.append(nval)
265
+ data["cherrypy_server_worker_threads"] = wdata
266
+ else:
267
+ nkey = 'cherrypy_http_server_%s' % cpnKey
268
+ nkey = nkey.lower().replace(" ", "_").replace("/", "_")
269
+ data[nkey] = cpnVal
270
+ return data
Utils/CertTools.py ADDED
@@ -0,0 +1,100 @@
1
+ """
2
+ Module to deal with user certificates and CAs
3
+ """
4
+ from builtins import str
5
+ import os
6
+
7
+
8
+ def ckey():
9
+ "Return user CA key either from proxy or userkey.pem"
10
+ pair = getKeyCertFromEnv()
11
+ return pair[0]
12
+
13
+
14
+ def cert():
15
+ "Return user CA cert either from proxy or usercert.pem"
16
+ pair = getKeyCertFromEnv()
17
+ return pair[1]
18
+
19
+
20
+ def getKeyCertFromEnv():
21
+ """
22
+ gets key and certificate from environment variables
23
+ If no env variable is set return None, None for key, cert tuple
24
+
25
+ First preference to HOST Certificate, This is how it set in Tier0
26
+
27
+ """
28
+ envPairs = [('X509_HOST_KEY', 'X509_HOST_CERT'), # First preference to HOST Certificate,
29
+ ('X509_USER_PROXY', 'X509_USER_PROXY'), # Second preference to User Proxy, very common
30
+ ('X509_USER_KEY', 'X509_USER_CERT')] # Third preference to User Cert/Proxy combinition
31
+
32
+ for keyEnv, certEnv in envPairs:
33
+ localKey = os.environ.get(keyEnv)
34
+ localCert = os.environ.get(certEnv)
35
+ if localKey and localCert and os.path.exists(localKey) and os.path.exists(localCert):
36
+ # if it is found in env return key, cert
37
+ return localKey, localCert
38
+
39
+ # TODO: only in linux, unix case, add other os case
40
+ # look for proxy at default location /tmp/x509up_u$uid
41
+ localKey = localCert = '/tmp/x509up_u' + str(os.getuid())
42
+ if os.path.exists(localKey):
43
+ return localKey, localCert
44
+
45
+ # Finary look for globaus location
46
+ if (os.environ.get('HOME') and
47
+ os.path.exists(os.environ['HOME'] + '/.globus/usercert.pem') and
48
+ os.path.exists(os.environ['HOME'] + '/.globus/userkey.pem')):
49
+
50
+ localKey = os.environ['HOME'] + '/.globus/userkey.pem'
51
+ localCert = os.environ['HOME'] + '/.globus/usercert.pem'
52
+ return localKey, localCert
53
+ # couldn't find the key, cert files
54
+ return None, None
55
+
56
+
57
+ def getCAPathFromEnv():
58
+ """
59
+ _getCAPathFromEnv_
60
+
61
+ Return the path of the CA certificates. The check is loose in the pycurl_manager:
62
+ is capath == None then the server identity is not verified. To enable this check
63
+ you need to set either the X509_CERT_DIR variable or the cacert key of the request.
64
+ """
65
+ return os.environ.get("X509_CERT_DIR")
66
+
67
+
68
+ def caBundle(caPath="/etc/grid-security/certificates"):
69
+ """
70
+ Load all PEM certificates from the given caPath and write them as single CA bundle PEM.
71
+
72
+ :param caPath: Path to directory containing .pem certificate files.
73
+ :return: A single string containing all concatenated PEM pemCertificates which may be
74
+ written to a caBundleFile if necessary (used by requests library)
75
+ """
76
+ if not os.path.isdir(caPath):
77
+ raise ValueError(f"Invalid caPath: {caPath} is not a directory")
78
+
79
+ pemCertificates = []
80
+
81
+ for fileName in sorted(os.listdir(caPath)):
82
+ filePath = os.path.join(caPath, fileName)
83
+
84
+ # Only consider readable files that look like PEM certificates
85
+ if not os.path.isfile(filePath):
86
+ continue
87
+ if not fileName.endswith(".pem"):
88
+ continue
89
+
90
+ try:
91
+ with open(filePath, "r", encoding="utf-8") as istream:
92
+ certData = istream.read()
93
+ if "BEGIN CERTIFICATE" in certData:
94
+ pemCertificates.append(certData)
95
+ except Exception as e:
96
+ print(f"Warning: Could not read {filePath}: {e}")
97
+
98
+ if len(pemCertificates) == 0:
99
+ raise ValueError(f"No PEM files found in {caPath}")
100
+ return "\n".join(pemCertificates)
Utils/EmailAlert.py ADDED
@@ -0,0 +1,50 @@
1
+ """
2
+ EmailAlert - send alerts via email
3
+
4
+ NOTICE:
5
+ This class does not work from kubernetes pods. The AlertManagerAPI class should be used for alerting from k8s.
6
+ More details at: https://github.com/dmwm/WMCore/issues/10234
7
+ """
8
+
9
+
10
+ from builtins import str, object
11
+ import smtplib
12
+ import logging
13
+
14
+
15
+ class EmailAlert(object):
16
+ """
17
+ A simple class to send alerts via email
18
+ """
19
+
20
+ EMAIL_HEADER = "From: %s\r\nSubject: %s\r\nTo: %s\r\n\r\n"
21
+
22
+ def __init__(self, configDict):
23
+ self.serverName = configDict.get("smtpServer", "localhost")
24
+ self.fromAddr = configDict.get("fromAddr", "noreply@cern.ch")
25
+ self.toAddr = configDict.get("toAddr", "cms-service-production-admins@cern.ch")
26
+ if not isinstance(self.toAddr, (list, set)):
27
+ self.toAddr = [self.toAddr]
28
+
29
+ def send(self, subject, message):
30
+ """
31
+ Send an email
32
+ :param subject: Email subject
33
+ :param message: Email body
34
+ """
35
+ msg = self.EMAIL_HEADER % (self.fromAddr, subject, ", ".join(self.toAddr))
36
+ msg += message
37
+
38
+ try:
39
+ smtp = smtplib.SMTP(self.serverName)
40
+ smtp.sendmail(self.fromAddr, self.toAddr, msg)
41
+ except Exception as ex:
42
+ logging.exception("Error sending alert email.\nDetails: %s", str(ex))
43
+
44
+ try:
45
+ # clean up smtp connection
46
+ smtp.quit()
47
+ except UnboundLocalError:
48
+ # it means our client failed connecting to the SMTP server
49
+ pass
50
+
@@ -0,0 +1,62 @@
1
+ #! /usr/bin/env python
2
+ """
3
+ Unit testing base class with our extensions
4
+ """
5
+
6
+ import copy
7
+ import unittest
8
+
9
+
10
+ class ExtendedUnitTestCase(unittest.TestCase):
11
+ """
12
+ Class that can be imported to switch to 'mock'ed versions of
13
+ services.
14
+ """
15
+
16
+ def assertContentsEqual(self, expected_obj, actual_obj, msg=None):
17
+ """
18
+ A nested object comparison without regard for the ordering of contents. It asserts that
19
+ expected_obj and actual_obj contain the same elements and that their sub-elements are the same.
20
+ However, all sequences are allowed to contain the same elements, but in different orders.
21
+ """
22
+
23
+ def traverse_dict(dictionary):
24
+ for key, value in list(dictionary.items()):
25
+ if isinstance(value, dict):
26
+ traverse_dict(value)
27
+ elif isinstance(value, list):
28
+ traverse_list(value)
29
+ return
30
+
31
+ def get_dict_sortkey(x):
32
+ if isinstance(x, dict):
33
+ return list(x.keys())
34
+ else:
35
+ return x
36
+
37
+ def traverse_list(theList):
38
+ for value in theList:
39
+ if isinstance(value, dict):
40
+ traverse_dict(value)
41
+ elif isinstance(value, list):
42
+ traverse_list(value)
43
+ theList.sort(key=get_dict_sortkey)
44
+ return
45
+
46
+ if not isinstance(expected_obj, type(actual_obj)):
47
+ self.fail(msg="The two objects are different type and cannot be compared: %s and %s" % (
48
+ type(expected_obj), type(actual_obj)))
49
+
50
+ expected = copy.deepcopy(expected_obj)
51
+ actual = copy.deepcopy(actual_obj)
52
+
53
+ if isinstance(expected, dict):
54
+ traverse_dict(expected)
55
+ traverse_dict(actual)
56
+ elif isinstance(expected, list):
57
+ traverse_list(expected)
58
+ traverse_list(actual)
59
+ else:
60
+ self.fail(msg="The two objects are different type (%s) and cannot be compared." % type(expected_obj))
61
+
62
+ return self.assertEqual(expected, actual)
Utils/FileTools.py ADDED
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Utilities related to file handling
4
+ """
5
+
6
+
7
+ import io
8
+ import os
9
+ import glob
10
+ import stat
11
+ import subprocess
12
+ import time
13
+ import zlib
14
+ import logging
15
+
16
+ from Utils.Utilities import decodeBytesToUnicode
17
+
18
+
19
+ def findFiles(path, pat):
20
+ """
21
+ Find files within given path and matching given pattern.
22
+ :param path: starting directory path (string)
23
+ :param pat: match pattern (string), e.g. *.py or name of the file
24
+ :return: matched file names
25
+ """
26
+ files = []
27
+ for idir, _, _ in os.walk(path):
28
+ files.extend(glob.glob(os.path.join(idir, pat)))
29
+ return files
30
+
31
+
32
+ def tarMode(tfile, opMode):
33
+ """
34
+ Extract proper mode of operation for given tar file. For instance,
35
+ if op='r' and tfile name is file.tar.gz we should get 'r:gz',
36
+ while if tfile name is file.tar.bz2 we should get 'r':bz2', while
37
+ if tfile name is file.tar we should get 'r', etc.
38
+ :param opMode: mode of operation (string), e.g. 'r', or 'w'
39
+ :param tfile: sandbox tar file name (string)
40
+ :return: mode of operation
41
+ """
42
+ ext = tfile.split(".")[-1]
43
+ if ext == 'tar':
44
+ return opMode
45
+ mode = opMode + ':' + ext
46
+ return mode
47
+
48
+
49
+ def calculateChecksums(filename):
50
+ """
51
+ _calculateChecksums_
52
+
53
+ Get the adler32 and crc32 checksums of a file. Return None on error
54
+
55
+ Process line by line and adjust for known signed vs. unsigned issues
56
+ http://docs.python.org/library/zlib.html
57
+
58
+ The cksum UNIX command line tool implements a CRC32 checksum that is
59
+ different than any of the python algorithms, therefore open cksum
60
+ in a subprocess and feed it the same chunks of data that are used
61
+ to calculate the adler32 checksum.
62
+
63
+ """
64
+ adler32Checksum = 1 # adler32 of an empty string
65
+ cksumProcess = subprocess.Popen("cksum", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
66
+
67
+ # the lambda basically creates an iterator function with zero
68
+ # arguments that steps through the file in 4096 byte chunks
69
+ with open(filename, 'rb') as f:
70
+ for chunk in iter((lambda: f.read(4096)), b''):
71
+ adler32Checksum = zlib.adler32(chunk, adler32Checksum)
72
+ cksumProcess.stdin.write(chunk)
73
+
74
+ cksumProcess.stdin.close()
75
+ cksumProcess.wait()
76
+
77
+ cksumStdout = cksumProcess.stdout.read().split()
78
+ cksumProcess.stdout.close()
79
+
80
+ # consistency check on the cksum output
81
+ filesize = os.stat(filename)[stat.ST_SIZE]
82
+ if len(cksumStdout) != 2 or int(cksumStdout[1]) != filesize:
83
+ raise RuntimeError("Something went wrong with the cksum calculation !")
84
+
85
+ cksumStdout[0] = decodeBytesToUnicode(cksumStdout[0])
86
+ return (format(adler32Checksum & 0xffffffff, '08x'), cksumStdout[0])
87
+
88
+
89
+ def tail(filename, nLines=20):
90
+ """
91
+ _tail_
92
+
93
+ A version of tail
94
+ Adapted from code on http://stackoverflow.com/questions/136168/get-last-n-lines-of-a-file-with-python-similar-to-tail
95
+ """
96
+ assert nLines >= 0
97
+ pos, lines = nLines + 1, []
98
+
99
+ # make sure only valid utf8 encoded chars will be passed along
100
+ with io.open(filename, 'r', encoding='utf8', errors='ignore') as f:
101
+ while len(lines) <= nLines:
102
+ try:
103
+ f.seek(-pos, 2)
104
+ except IOError:
105
+ f.seek(0)
106
+ break
107
+ finally:
108
+ lines = list(f)
109
+ pos *= 2
110
+
111
+ text = "".join(lines[-nLines:])
112
+
113
+ return text
114
+
115
+
116
+ def getFileInfo(filename):
117
+ """
118
+ _getFileInfo_
119
+
120
+ Return file info in a friendly format
121
+ """
122
+
123
+ filestats = os.stat(filename)
124
+
125
+ fileInfo = {'Name': filename,
126
+ 'Size': filestats[stat.ST_SIZE],
127
+ 'LastModification': time.strftime("%m/%d/%Y %I:%M:%S %p", time.localtime(filestats[stat.ST_MTIME])),
128
+ 'LastAccess': time.strftime("%m/%d/%Y %I:%M:%S %p", time.localtime(filestats[stat.ST_ATIME]))}
129
+ return fileInfo
130
+
131
+
132
+ def findMagicStr(filename, matchString):
133
+ """
134
+ _findMagicStr_
135
+
136
+ Parse a log file looking for a pattern string
137
+ """
138
+ with io.open(filename, 'r', encoding='utf8', errors='ignore') as logfile:
139
+ # TODO: can we avoid reading the whole file
140
+ for line in logfile:
141
+ if matchString in line:
142
+ yield line
143
+
144
+
145
+ def getFullPath(name, envPath="PATH"):
146
+ """
147
+ :param name: file name
148
+ :param envPath: any environment variable specified for path (PATH, PYTHONPATH, etc)
149
+ :return: full path if it is under PATH env
150
+ """
151
+ for path in os.getenv(envPath).split(os.path.pathsep):
152
+ fullPath = os.path.join(path, name)
153
+ if os.path.exists(fullPath):
154
+ return fullPath
155
+ return None
156
+
157
+
158
+ def loadEnvFile(wmaEnvFilePath, logger=None):
159
+ """
160
+ _loadEnvFile_
161
+ A simple function to load an additional bash env file into the current script
162
+ runtime environment
163
+ :param wmaEnvFilePath: The path to the environment file to be loaded
164
+ :return: True if the script has loaded successfully, False otherwise.
165
+ """
166
+ if not logger:
167
+ logger = logging.getLogger()
168
+ subProc = subprocess.run(['bash', '-c', f'source {wmaEnvFilePath} && python -c "import os; print(repr(os.environ.copy()))" '],
169
+ capture_output=True, check=False)
170
+ if subProc.returncode == 0:
171
+ newEnv = eval(subProc.stdout)
172
+ os.environ.update(newEnv)
173
+ if subProc.stderr:
174
+ logger.warning("Environment file: %s loaded with errors:", wmaEnvFilePath)
175
+ logger.warning(subProc.stderr.decode())
176
+ else:
177
+ logger.info("Environment file: %s loaded successfully", wmaEnvFilePath)
178
+ return True
179
+ else:
180
+ logger.error("Failed to load environment file: %s", wmaEnvFilePath)
181
+ logger.error(subProc.stderr.decode())
182
+ return False