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
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ This module contains a few basic WMCore-related utilitarian
5
+ Rucio data structures and functions
6
+ """
7
+
8
+ import random
9
+
10
+ RUCIO_VALID_PROJECT = ("Production", "RelVal", "Tier0", "Test", "User")
11
+ # grouping values are extracted from:
12
+ # https://github.com/rucio/rucio/blob/master/lib/rucio/common/schema/cms.py#L117
13
+ GROUPING_DSET = "DATASET"
14
+ GROUPING_ALL = "ALL"
15
+ RUCIO_RULES_PRIORITY = {"low": 2, "normal": 3, "high": 4, "reserved": 5}
16
+ # number of copies to be defined when creating replication rules
17
+ NUM_COPIES_DEFAULT = 1
18
+ NUM_COPIES_NANO = 2
19
+
20
+ def validateMetaData(did, metaDict, logger):
21
+ """
22
+ This function can be extended in the future, for now it will only
23
+ validate the DID creation metadata, more specifically only the
24
+ "project" parameter
25
+ :param did: the DID that will be inserted
26
+ :param metaDict: a dictionary with all the DID metadata data to be inserted
27
+ :param logger: a logger object
28
+ :return: False if validation fails, otherwise True
29
+ """
30
+ if metaDict.get("project", "Production") in RUCIO_VALID_PROJECT:
31
+ return True
32
+ msg = f"DID: {did} has an invalid 'project' meta-data value: {metaDict['project']}"
33
+ msg += f"The supported 'project' values are: {str(RUCIO_VALID_PROJECT)}"
34
+ logger.error(msg)
35
+ return False
36
+
37
+
38
+ def weightedChoice(rses, rseWeights):
39
+ """
40
+ Given a list of items and their respective weights (quota in this case),
41
+ perform a weighted selection.
42
+ :param rses: a list of tuples with the RSE name and whether it requires approval
43
+ :param rseWeights: a list with RSE weights (quota)
44
+ :return: a tuple from the choices list
45
+ """
46
+ listChoice = random.choices(population=rses, weights=rseWeights, k=1)
47
+ # return only the tuple, not the list with a tuple item
48
+ return listChoice[0]
49
+
50
+
51
+ def isTapeRSE(rseName):
52
+ """
53
+ Given an RSE name, return True if it's a Tape RSE (rse_type=TAPE), otherwise False
54
+ :param rseName: string with the RSE name
55
+ :return: True or False
56
+ """
57
+ # NOTE: a more reliable - but more expensive - way to know that would be
58
+ # to query `get_rse` and evaluate the rse_type parameter
59
+ return rseName.endswith("_Tape")
60
+
61
+
62
+ def dropTapeRSEs(listRSEs):
63
+ """
64
+ Method to parse a list of RSE names and return only those that
65
+ are not a rse_type=TAPE, so in general only Disk endpoints
66
+ :param listRSEs: list with the RSE names
67
+ :return: a new list with only DISK RSE names
68
+ """
69
+ diskRSEs = []
70
+ for rse in listRSEs:
71
+ if isTapeRSE(rse):
72
+ continue
73
+ diskRSEs.append(rse)
74
+ return diskRSEs
File without changes
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env python
2
+ # coding=utf-8
3
+ """
4
+ Rucio Consistency Monitor Service class developed on top of the native WMCore
5
+ Service APIs providing custom output and handling as necessary for the
6
+ CMS Workload Management system
7
+ """
8
+
9
+ from __future__ import division, print_function, absolute_import
10
+ from future import standard_library
11
+
12
+ from urllib.parse import urlencode
13
+
14
+ import json
15
+ import logging
16
+
17
+ from WMCore.Services.Service import Service
18
+ from Utils.Utilities import decodeBytesToUnicode
19
+
20
+
21
+ standard_library.install_aliases()
22
+
23
+
24
+ class RucioConMon(Service):
25
+ """
26
+ API for dealing with retrieving information from Rucio Consistency Monitor
27
+ """
28
+
29
+ def __init__(self, url, logger=None, configDict=None):
30
+ """
31
+ Init method for the RucioConMon Class
32
+ """
33
+ configDict = configDict or {}
34
+ configDict.setdefault('endpoint', url)
35
+ configDict.setdefault('cacheduration', 1) # in hours
36
+ configDict.setdefault('accept_type', 'application/json')
37
+ configDict.setdefault('content_type', 'application/json')
38
+ configDict['logger'] = logger if logger else logging.getLogger()
39
+ super(RucioConMon, self).__init__(configDict)
40
+ self['logger'].debug("Initializing RucioConMon with url: %s", self['endpoint'])
41
+
42
+ def _getResult(self, uri, callname="", clearCache=False, args=None):
43
+ """
44
+ Either fetch data from the cache file or query the data-service
45
+ :param uri: The endpoint uri
46
+ :param callname: alias for caller function
47
+ :param clearCache: parameter to control the cache behavior
48
+ :param args: additional parameters to HTTP request call
49
+ :return: A dictionary
50
+ """
51
+
52
+ # NOTE: Unlike the common case we are not using the callname for building
53
+ # apiUrl. we are using it only for giving proper name of the cache
54
+ # file.
55
+ # NOTE: The 'callname' should not contain '/', otherwise the cache is
56
+ # tried to be created with a a non existing subdirectory structure
57
+
58
+ cachedApi = "%s.json" % callname
59
+ # apiUrl = '%s?json&preset=%s' % (uri, callname)
60
+ apiUrl = uri
61
+
62
+ self['logger'].debug('Fetching data from %s, with args %s', apiUrl, args)
63
+ if args:
64
+ apiUrl = "%s&%s" % (apiUrl, urlencode(args, doseq=True))
65
+
66
+ if clearCache:
67
+ self.clearCache(cachedApi, args)
68
+ with self.refreshCache(cachedApi, apiUrl, decoder=True, binary=False) as istream:
69
+ return json.load(istream)
70
+
71
+ def _getResultZipped(self, uri, callname="", clearCache=True):
72
+ """
73
+ This method retrieves gzipped content, instead of the standard json format.
74
+ :param uri: The endpoint uri
75
+ :param callname: alias for caller function
76
+ :param clearCache: parameter to control the cache behavior
77
+ :return: yields a single record from the data retrieved
78
+ """
79
+ cachedApi = callname
80
+ if clearCache:
81
+ self.clearCache(cachedApi)
82
+
83
+ with self.refreshCache(cachedApi, uri, decoder=False, binary=True) as istream:
84
+ for line in istream:
85
+ line = decodeBytesToUnicode(line).replace("\n", "")
86
+ yield line
87
+
88
+ def getRSEStats(self):
89
+ """
90
+ Gets the latest statistics from the RucioConMon, together with the last
91
+ update timestamps for all RSEs known to CMS Rucio
92
+ :return: A dictionary
93
+ """
94
+ uri = "stats"
95
+ rseStats = self._getResult(uri, callname='stats')
96
+ return rseStats
97
+
98
+ def getRSEUnmerged(self, rseName, zipped=False):
99
+ """
100
+ Gets the list of all unmerged files in an RSE
101
+ :param rseName: The RSE whose list of unmerged files to be retrieved
102
+ :param zipped: If True the interface providing the zipped lists will be called
103
+ :return: a generator of unmerged files for the RSE in question
104
+ """
105
+ # NOTE: The default API provided by Rucio Consistency Monitor is in a form of a
106
+ # zipped file/stream. Currently we are using the newly provided json API
107
+ # But in in case we figure out the data is too big we may need to
108
+ # implement the method with the zipped API and use disc cache for
109
+ # reading/streaming from file. This will prevent any set arithmetic
110
+ # in the future.
111
+ if zipped:
112
+ uri = "files?rse=%s&format=raw" % rseName
113
+ callname = '{}.zipped'.format(rseName)
114
+ rseUnmerged = self._getResultZipped(uri, callname=callname, clearCache=True)
115
+ else:
116
+ uri = "files?rse=%s&format=json" % rseName
117
+ callname = '{}.json'.format(rseName)
118
+ rseUnmerged = self._getResult(uri, callname=callname)
119
+ # now lazily return items
120
+ for item in rseUnmerged:
121
+ yield item
File without changes
@@ -0,0 +1,400 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ _Service_
4
+
5
+ A Service talks to some http(s) accessible service that provides information and
6
+ caches the result of these queries. The cache will be refreshed if the file is
7
+ older than a timeout set in the instance of Service.
8
+
9
+ It has a cache path, cache duration, an endpoint (the url the
10
+ service exists on) a logger and an accept type (json, xml etc) and method
11
+ (GET/POST).
12
+
13
+ The Service satisfies two caching cases:
14
+
15
+ 1. set a defined query, cache results, poll for new ones
16
+ 2. use a changing query, cache results to a file depending on the query, poll
17
+ for new ones
18
+
19
+ Data maybe passed to the remote service either via adding the query string to
20
+ the URL (for GET's) or by passing a dictionary to either the service constructor
21
+ (case 1.) or by passing the data as a dictionary to the refreshCache,
22
+ forceCache, clearCache calls. By default the cache lasts 30 minutes.
23
+
24
+ Calling refreshCache/forceRefresh will return an open file object, the cache
25
+ file. Once done with it you should close the object.
26
+
27
+ The service has a default timeout to receive a response from the remote service
28
+ of 300 seconds. Over ride this by passing in a timeout via the configuration
29
+ dict, set to None if you want to turn off the timeout.
30
+
31
+ If you just want to retrieve the data without caching use the Requests class
32
+ directly.
33
+
34
+ The Service class provides two layers of caching:
35
+ 1. Caching from httplib2 is provided via Request, this respects etag and
36
+ expires, but the cache will be lost if the service raises an exception or
37
+ similar.
38
+ 2. Internal caching which respects an internal cache duration. If the remote
39
+ service fails to respond the second layer cache will be used until the cache
40
+ dies.
41
+
42
+ In tabular form:
43
+
44
+ httplib2 cache | yes | yes | no | no |
45
+ ----------------+----------+----------+----------+------------+
46
+ service cache | no | yes | yes | no |
47
+ ----------------+----------+----------+----------+------------+
48
+ result | cached | cached | cached | not cached |
49
+ """
50
+
51
+ from builtins import str
52
+ from future import standard_library
53
+ standard_library.install_aliases()
54
+
55
+ import datetime
56
+ import json
57
+ import logging
58
+ import os
59
+ import time
60
+ from io import BytesIO, StringIO
61
+ from http.client import HTTPException
62
+
63
+ from Utils.PythonVersion import PY3
64
+ from WMCore.Services.Requests import Requests, JSONRequests
65
+ from WMCore.WMException import WMException
66
+
67
+ try:
68
+ from httplib2 import HttpLib2Error
69
+ except ImportError:
70
+ # Mock HttpLib2Error since we don't want that WMCore depend on httplib2 using pycurl
71
+ class HttpLib2Error(Exception):
72
+ pass
73
+
74
+
75
+ def isfile(obj):
76
+ """
77
+ Check whether obj is a file-like object (file, StringIO)"
78
+ """
79
+ return hasattr(obj, 'flush')
80
+
81
+
82
+ def cache_expired(cache, delta=0):
83
+ """
84
+ Is the cache expired? At delta hours (default 0) in the future.
85
+ """
86
+ if isfile(cache):
87
+ # already opened file-like object, assume we need to refresh
88
+ return True
89
+ else:
90
+ # then it's a file name
91
+ if not os.path.exists(cache):
92
+ return True
93
+
94
+ delta = datetime.timedelta(hours=delta)
95
+ t = datetime.datetime.now() - delta
96
+ # cache file mtime has been set to cache expiry time
97
+ if os.path.getmtime(cache) < time.mktime(t.timetuple()):
98
+ return True
99
+
100
+ return False
101
+
102
+
103
+ def _makeHash(inputdata):
104
+ """
105
+ Turn the input data into json and hash the string. This is simple and
106
+ means that the input data must be json-serialisable, which is good.
107
+ """
108
+ json_hash = json.dumps(inputdata)
109
+ return json_hash.__hash__()
110
+
111
+
112
+ class Service(dict):
113
+ def __init__(self, cfg_dict=None):
114
+ super(Service, self).__init__()
115
+ cfg_dict = cfg_dict or {}
116
+ # The following should read the configuration class
117
+ for a in ['endpoint']:
118
+ assert a in list(cfg_dict), "Can't have a service without a %s" % a
119
+
120
+ # if end point ends without '/', add that
121
+ if not cfg_dict['endpoint'].endswith('/'):
122
+ cfg_dict['endpoint'] = cfg_dict['endpoint'].strip() + '/'
123
+
124
+ # set up defaults
125
+ self.setdefault("inputdata", {})
126
+ self.setdefault("cacheduration", 0.5)
127
+ self.supportVerbList = ('GET', 'POST', 'PUT', 'DELETE')
128
+ # this value should be only set when whole service class uses
129
+ # the same verb ('GET', 'POST', 'PUT', 'DELETE')
130
+ self.setdefault("method", None)
131
+
132
+ # Set a timeout for the socket
133
+ self.setdefault("timeout", 300)
134
+
135
+ # then update with the incoming dict
136
+ self.update(cfg_dict)
137
+
138
+ self['service_name'] = self.__class__.__name__ # used for cache naming
139
+
140
+ # Get the request class, to instantiate later
141
+ # either passed as param to __init__, determine via scheme or default
142
+ if isinstance(self.get('requests'), type):
143
+ requests = self['requests']
144
+ elif self.get('accept_type') == "application/json" and self.get('content_type') == "application/json":
145
+ requests = JSONRequests
146
+ else:
147
+ requests = Requests
148
+ # Instantiate a Request
149
+ try:
150
+ self["requests"] = requests(cfg_dict['endpoint'], cfg_dict)
151
+ except WMException as ex:
152
+ msg = str(ex)
153
+ self["logger"].exception(msg)
154
+ raise
155
+
156
+ # cachepath will be modified - i.e. hostname added
157
+ self['cachepath'] = self["requests"]["cachepath"]
158
+
159
+ if 'logger' not in self:
160
+ if self['cachepath']:
161
+ logfile = os.path.join(self['cachepath'], '%s.log' % self.__class__.__name__.lower())
162
+ else:
163
+ logfile = None
164
+ logging.basicConfig(level=logging.DEBUG,
165
+ format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
166
+ datefmt='%m-%d %H:%M',
167
+ filename=logfile,
168
+ filemode='w')
169
+ self['logger'] = logging.getLogger(self.__class__.__name__)
170
+ self['requests']['logger'] = self['logger']
171
+
172
+ msg = "Service '%s' initialized with the following settings: %s"
173
+ self['logger'].debug(msg, self.__class__.__name__, self)
174
+
175
+ def cacheFileName(self, cachefile, verb='GET', inputdata=None):
176
+ """
177
+ Calculate the cache filename for a given query.
178
+ """
179
+ # if not caching to disk return StringIO object
180
+ if not self['cachepath'] or not cachefile:
181
+ return StringIO() if PY3 else BytesIO()
182
+
183
+ inputdata = inputdata or {}
184
+ if inputdata:
185
+ hash_ = _makeHash(inputdata)
186
+ else:
187
+ hash_ = _makeHash(self['inputdata'])
188
+ cachefile = "%s/%s_%s_%s" % (self["cachepath"], hash_, verb, cachefile)
189
+
190
+ return cachefile
191
+
192
+ def refreshCache(self, cachefile, url='', inputdata=None, openfile=True,
193
+ encoder=True, decoder=True, verb='GET', contentType=None, incoming_headers=None, binary=False):
194
+ """
195
+ See if the cache has expired. If it has make a new request to the
196
+ service for the input data. Return the cachefile as an open file object.
197
+ If cachefile is None returns StringIO.
198
+
199
+ :param cachefile: cache file name
200
+ :param url: url value
201
+ :param inputdata: HTTP (JSON) payload string
202
+ :param openfile: flag to use open file, boolean
203
+ :param encoder: flag to use encoder, boolean
204
+ :param decoder: flag to use decode, boolean
205
+ :param verb: HTTP method, string
206
+ :param contentType: HTTP content type value, string
207
+ :param incoming_headers: set of HTTP headers, dict
208
+ :param binary: use binary mode to decode HTTP data, boolean
209
+ :return: either file object or StringIO
210
+ """
211
+ inputdata = inputdata or {}
212
+ incoming_headers = incoming_headers or {}
213
+ verb = self._verbCheck(verb)
214
+
215
+ cachefile = self.cacheFileName(cachefile, verb, inputdata)
216
+
217
+ if cache_expired(cachefile, self["cacheduration"]):
218
+ self.getData(cachefile, url, inputdata, incoming_headers, encoder, decoder, verb, contentType, binary=binary)
219
+ else:
220
+ self['logger'].debug('Data is from the Service cache')
221
+
222
+ # cachefile may be filename or file object
223
+ if openfile and not isfile(cachefile):
224
+ if binary:
225
+ return open(cachefile, 'rb')
226
+ return open(cachefile, 'r', encoding='utf-8')
227
+ else:
228
+ return cachefile
229
+
230
+ def forceRefresh(self, cachefile, url='', inputdata=None, openfile=True,
231
+ encoder=True, decoder=True, verb='GET',
232
+ contentType=None, incoming_headers=None, binary=False):
233
+ """
234
+ Make a new request to the service for the input data, regardless of the
235
+ cache state. Return the cachefile as an open file object.
236
+ If cachefile is None returns StringIO.
237
+
238
+ :param cachefile: cache file name
239
+ :param url: url value
240
+ :param inputdata: HTTP (JSON) payload string
241
+ :param openfile: flag to use open file, boolean
242
+ :param encoder: flag to use encoder, boolean
243
+ :param decoder: flag to use decode, boolean
244
+ :param verb: HTTP method, string
245
+ :param contentType: HTTP content type value, string
246
+ :param incoming_headers: set of HTTP headers, dict
247
+ :param binary: use binary mode to decode HTTP data, boolean
248
+ :return: either file object or StringIO
249
+ """
250
+ inputdata = inputdata or {}
251
+ incoming_headers = incoming_headers or {}
252
+ verb = self._verbCheck(verb)
253
+
254
+ cachefile = self.cacheFileName(cachefile, verb, inputdata)
255
+
256
+ self['logger'].debug("Forcing cache refresh of %s" % cachefile)
257
+ incoming_headers.update({'cache-control': 'no-cache'})
258
+ self.getData(cachefile, url, inputdata, incoming_headers,
259
+ encoder, decoder, verb, contentType, force_refresh=True, binary=binary)
260
+ if openfile and not isfile(cachefile):
261
+ if binary:
262
+ return open(cachefile, 'rb')
263
+ return open(cachefile, 'r', encoding='utf-8')
264
+ else:
265
+ return cachefile
266
+
267
+ def clearCache(self, cachefile, inputdata=None, verb='GET'):
268
+ """
269
+ Delete the cache file and the httplib2 cache.
270
+ """
271
+ if not self['cachepath'] or not cachefile:
272
+ # nothing to clear
273
+ return
274
+
275
+ inputdata = inputdata or {}
276
+ verb = self._verbCheck(verb)
277
+ os.system("/bin/rm -f %s/*" % self['requests']['req_cache_path'])
278
+ cachefile = self.cacheFileName(cachefile, verb, inputdata)
279
+ try:
280
+ if not isfile(cachefile):
281
+ os.remove(cachefile)
282
+ except OSError: # File doesn't exist
283
+ return
284
+
285
+ def getData(self, cachefile, url, inputdata=None, incoming_headers=None,
286
+ encoder=True, decoder=True,
287
+ verb='GET', contentType=None, force_refresh=False, binary=False):
288
+ """
289
+ Takes the already generated *full* path to cachefile and the url of the
290
+ resource. Don't need to call self.cacheFileName(cachefile, verb, inputdata)
291
+ here.
292
+
293
+ If cachefile is StringIO append to that
294
+
295
+ :param cachefile: cache file name
296
+ :param url: url value
297
+ :param inputdata: HTTP (JSON) payload string
298
+ :param encoder: flag to use encoder, boolean
299
+ :param decoder: flag to use decode, boolean
300
+ :param verb: HTTP method, string
301
+ :param contentType: HTTP content type value, string
302
+ :param force_refresh: refresh internal cache, boolean
303
+ :param binary: use binary mode to decode HTTP data, boolean
304
+ :return: None
305
+ """
306
+ inputdata = inputdata or {}
307
+ incoming_headers = incoming_headers or {}
308
+ verb = self._verbCheck(verb)
309
+
310
+ try:
311
+ # Get the data
312
+ if not inputdata:
313
+ inputdata = self["inputdata"]
314
+ self['logger'].debug('getData: \n\turl: %s\n\tverb: %s\n\tincoming_headers: %s\n\tdata: %s',
315
+ url, verb, incoming_headers, inputdata)
316
+ # self['logger'].debug('getData: \n\turl: %s\n\tdata: %s' % \
317
+ # (url, inputdata))
318
+ data, dummyStatus, dummyReason, from_cache = self["requests"].makeRequest(uri=url,
319
+ verb=verb,
320
+ data=inputdata,
321
+ incoming_headers=incoming_headers,
322
+ encoder=encoder,
323
+ decoder=decoder,
324
+ contentType=contentType)
325
+ if from_cache:
326
+ # If it's coming from the cache we don't need to write it to the
327
+ # second cache, or do we?
328
+ self['logger'].debug('Data is from the Requests cache')
329
+ else:
330
+ # getData have done that for us
331
+ if isfile(cachefile):
332
+ cachefile.write(data)
333
+ cachefile.seek(0, 0) # return to beginning of file
334
+ elif binary:
335
+ with open(cachefile, 'wb') as f:
336
+ f.write(data)
337
+ elif isinstance(data, (dict, list)):
338
+ with open(cachefile, 'w', encoding='utf-8') as f:
339
+ f.write(json.dumps(data))
340
+ else:
341
+ with open(cachefile, 'w', encoding='utf-8') as f:
342
+ f.write(data)
343
+
344
+
345
+ except (IOError, HttpLib2Error, HTTPException) as he:
346
+ #
347
+ # Overly complicated exception handling. This is due to a request
348
+ # from *Ops that it is very clear that data is is being returned
349
+ # from a cachefile, and that cachefiles can be good/stale/dead.
350
+ #
351
+ if force_refresh or isfile(cachefile) or not os.path.exists(cachefile):
352
+ msg = 'The cachefile %s does not exist and the service at %s'
353
+ msg = msg % (cachefile, self["requests"]['host'] + url)
354
+ if hasattr(he, 'status') and hasattr(he, 'reason'):
355
+ msg += ' is unavailable - it returned %s because %s' % (he.status,
356
+ he.reason)
357
+ if hasattr(he, 'result'):
358
+ msg += ' with result: %s\n' % he.result
359
+ else:
360
+ msg += ' raised a %s when accessed' % he.__repr__()
361
+ self['logger'].warning(msg)
362
+ raise he
363
+ else:
364
+ cache_dead = cache_expired(cachefile, delta=self["cacheduration"])
365
+ if cache_dead:
366
+ msg = 'The cachefile %s is dead (older than %s hours of cache duration), '
367
+ msg += 'and the service at %s '
368
+ msg = msg % (cachefile, self["cacheduration"], url)
369
+ if hasattr(he, 'status') and hasattr(he, 'reason'):
370
+ msg += 'is unavailable - it returned %s because %s' % (he.status, he.reason)
371
+ else:
372
+ msg += 'raised a %s when accessed' % he.__repr__()
373
+ self['logger'].warning(msg)
374
+ raise he
375
+ if self.get('usestalecache', False):
376
+ # then we can return data from the cache file, without raising an exception
377
+ # but with a suitable message in the log
378
+ msg = 'Returning stale cache data from %s, the service at ' % cachefile
379
+ if hasattr(he, 'status') and hasattr(he, 'reason'):
380
+ msg += '%s returned %s because %s' % (he.url, he.status, he.reason)
381
+ else:
382
+ msg += '%s raised a %s when accessed' % (url, he.__repr__())
383
+ self['logger'].warning(msg)
384
+ else:
385
+ # Cache is not dead, but Service is configured to not return stale data.
386
+ msg = 'The cachefile %s is stale and the service at %s ' % (cachefile, url)
387
+ if hasattr(he, 'status') and hasattr(he, 'reason'):
388
+ msg += 'is unavailable - it returned %s because %s' % (he.status, he.reason)
389
+ else:
390
+ msg += 'raised a %s when accessed' % he.__repr__()
391
+ self['logger'].warning(msg)
392
+ raise he
393
+
394
+ def _verbCheck(self, verb='GET'):
395
+ if verb.upper() in self.supportVerbList:
396
+ return verb.upper()
397
+ elif self['method'].upper() in self.supportVerbList:
398
+ return self['method'].upper()
399
+ else:
400
+ raise TypeError('verb parameter needs to be set')
File without changes