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,624 @@
1
+ #!/usr/bin/env python
2
+ # pylint: disable=C0103,R0913,W0102
3
+ """
4
+ _Requests_
5
+
6
+ A set of classes to handle making http and https requests to a remote server and
7
+ deserialising the response.
8
+
9
+ The response from the remote server is cached if expires/etags are set.
10
+ Note that the cache can have two different behaviors:
11
+ 1. when WMCORE_CACHE_DIR is defined: it defines one specific path to be used for the
12
+ cache files. Cache files are never automatically cleaned up and it's up to the user/
13
+ maintainer to do so. Note that cache directories are named after the base class.
14
+ 2. otherwise, the system will use the Operating System temp dir to store the cache files,
15
+ which uses `/tmp` as default for Linux systems. When using these temporary areas, the
16
+ cache files are automatically cleaned up when the object using it is destroyed and
17
+ garbage collected. Cache directories carry a random name.
18
+
19
+ By default, all of the WMCore central services define the CACHE_DIR (to use /data/srv/state).
20
+ """
21
+ from __future__ import division, print_function
22
+
23
+ from future import standard_library
24
+ standard_library.install_aliases()
25
+
26
+ from builtins import str, bytes, object
27
+ from future.utils import viewvalues
28
+
29
+ import base64
30
+ import logging
31
+ import os
32
+ import shutil
33
+ import socket
34
+ import stat
35
+ import tempfile
36
+ import traceback
37
+ import types
38
+
39
+ from urllib.parse import urlparse, urlencode
40
+ from io import BytesIO
41
+ from http.client import HTTPException
42
+ from json import JSONEncoder, JSONDecoder
43
+
44
+ from Utils.CertTools import getKeyCertFromEnv, getCAPathFromEnv
45
+ from Utils.Utilities import encodeUnicodeToBytes, decodeBytesToUnicode
46
+ from Utils.PythonVersion import PY3
47
+ from WMCore.Algorithms import Permissions
48
+ from WMCore.Lexicon import sanitizeURL
49
+ from WMCore.WMException import WMException
50
+ from WMCore.Wrappers.JsonWrapper.JSONThunker import JSONThunker
51
+ from Utils.PortForward import portForward
52
+
53
+ try:
54
+ from WMCore.Services.pycurl_manager import RequestHandler, ResponseHeader
55
+ except ImportError:
56
+ pass
57
+
58
+ try:
59
+ from httplib2 import ServerNotFoundError
60
+ except ImportError:
61
+ # Mock ServerNotFoundError since we don't want that WMCore depend on httplib2 using pycurl
62
+ class ServerNotFoundError(Exception):
63
+ pass
64
+
65
+
66
+ def check_server_url(srvurl):
67
+ """Check given url for correctness"""
68
+ good_name = srvurl.startswith('http://') or srvurl.startswith('https://')
69
+ if not good_name:
70
+ msg = "You must include "
71
+ msg += "http(s):// in your server's address, %s doesn't" % srvurl
72
+ raise ValueError(msg)
73
+
74
+
75
+ class Requests(dict):
76
+ """
77
+ Generic class for sending different types of HTTP Request to a given URL
78
+ """
79
+
80
+ @portForward(8443)
81
+ def __init__(self, url='http://localhost', idict=None):
82
+ """
83
+ url should really be host - TODO fix that when have sufficient code
84
+ coverage and change _getURLOpener if needed
85
+ """
86
+ if not idict:
87
+ idict = {}
88
+ dict.__init__(self, idict)
89
+ self.pycurl = idict.get('pycurl', True)
90
+ self.capath = idict.get('capath', None)
91
+ if self.pycurl:
92
+ self.reqmgr = RequestHandler()
93
+
94
+ # set up defaults
95
+ self.setdefault("accept_type", 'text/html')
96
+ self.setdefault("content_type", 'application/x-www-form-urlencoded')
97
+ self.additionalHeaders = {}
98
+
99
+ # check for basic auth early, as if found this changes the url
100
+ urlComponent = sanitizeURL(url)
101
+ if urlComponent['username'] is not None:
102
+ self.addBasicAuth(urlComponent['username'], urlComponent['password'])
103
+ # CouchDB 3.x requires user/passwd in the source/target of replication docs
104
+ # More info in: https://github.com/dmwm/WMCore/pull/11001
105
+ url = urlComponent['url'] # remove user, password from url
106
+
107
+ self.setdefault("host", url)
108
+
109
+ # then update with the incoming dict
110
+ self.update(idict)
111
+
112
+ self['endpoint_components'] = urlparse(self['host'])
113
+
114
+ # If cachepath = None disable caching
115
+ if 'cachepath' in idict and idict['cachepath'] is None:
116
+ self["req_cache_path"] = None
117
+ else:
118
+ cache_dir = (self.cachePath(idict.get('cachepath'), idict.get('service_name')))
119
+ self["cachepath"] = cache_dir
120
+ self["req_cache_path"] = os.path.join(cache_dir, '.cache')
121
+
122
+ # Try to resolve the key/cert pair path in the constructor:
123
+ # NOTE: Calling self.getKeyCert() assures that if the pair is already provided by
124
+ # the caller (e.g. the higher level Service class) through the `idict' argument
125
+ # during construction time, no additional os.environ calls would be made.
126
+ # If the pair is not provided anywhere: not by the higher level class
127
+ # nor from the environment, Exception will be raised early during construction
128
+ # time rather than later during an internel method call.
129
+ self.setdefault("cert", None)
130
+ self.setdefault("key", None)
131
+ self['key'], self['cert'] = self.getKeyCert()
132
+
133
+ self.setdefault('capath', None)
134
+ self['capath'] = self.getCAPath()
135
+
136
+ self.setdefault("timeout", 300)
137
+ self.setdefault("logger", logging)
138
+
139
+ check_server_url(self['host'])
140
+
141
+ def get(self, uri=None, data={}, incoming_headers={},
142
+ encode=True, decode=True, contentType=None):
143
+ """
144
+ GET some data
145
+ """
146
+ return self.makeRequest(uri, data, 'GET', incoming_headers,
147
+ encode, decode, contentType)
148
+
149
+ def post(self, uri=None, data={}, incoming_headers={},
150
+ encode=True, decode=True, contentType=None):
151
+ """
152
+ POST some data
153
+ """
154
+ return self.makeRequest(uri, data, 'POST', incoming_headers,
155
+ encode, decode, contentType)
156
+
157
+ def put(self, uri=None, data={}, incoming_headers={},
158
+ encode=True, decode=True, contentType=None):
159
+ """
160
+ PUT some data
161
+ """
162
+ return self.makeRequest(uri, data, 'PUT', incoming_headers,
163
+ encode, decode, contentType)
164
+
165
+ def delete(self, uri=None, data={}, incoming_headers={},
166
+ encode=True, decode=True, contentType=None):
167
+ """
168
+ DELETE some data
169
+ """
170
+ return self.makeRequest(uri, data, 'DELETE', incoming_headers,
171
+ encode, decode, contentType)
172
+
173
+ def makeRequest(self, uri=None, data=None, verb='GET', incoming_headers=None,
174
+ encoder=True, decoder=True, contentType=None):
175
+ """
176
+ Wrapper around request helper functions.
177
+ """
178
+ data = data or {}
179
+ incoming_headers = incoming_headers or {}
180
+ data, headers = self.encodeParams(data, verb, incoming_headers, encoder, contentType)
181
+
182
+ # both httpib2/pycurl require absolute url
183
+ uri = self['host'] + uri
184
+ if self.pycurl:
185
+ result, response = self.makeRequest_pycurl(uri, data, verb, headers)
186
+ else:
187
+ result, response = self.makeRequest_httplib(uri, data, verb, headers)
188
+
189
+ result = self.decodeResult(result, decoder)
190
+ return result, response.status, response.reason, response.fromcache
191
+
192
+ def makeRequest_pycurl(self, uri, data, verb, headers):
193
+ """
194
+ Make HTTP(s) request via pycurl library. Stay complaint with
195
+ makeRequest_httplib method.
196
+ """
197
+ ckey, cert = self.getKeyCert()
198
+ capath = self.getCAPath()
199
+
200
+ headers["Accept-Encoding"] = "gzip,deflate,identity"
201
+
202
+ response, result = self.reqmgr.request(uri, data, headers, verb=verb,
203
+ ckey=ckey, cert=cert, capath=capath)
204
+ return result, response
205
+
206
+ def makeRequest_httplib(self, uri, data, verb, headers):
207
+ """
208
+ Make a request to the remote database. for a give URI. The type of
209
+ request will determine the action take by the server (be careful with
210
+ DELETE!). Data should be a dictionary of {dataname: datavalue}.
211
+
212
+ Returns a tuple of the data from the server, decoded using the
213
+ appropriate method the response status and the response reason, to be
214
+ used in error handling.
215
+
216
+ You can override the method to encode/decode your data by passing in an
217
+ encoding/decoding function to this method. Your encoded data must end up
218
+ as a string.
219
+
220
+ """
221
+ if verb == 'GET' and data:
222
+ uri = "%s?%s" % (uri, data)
223
+
224
+ assert isinstance(data, (str, bytes)), \
225
+ "Data in makeRequest is %s and not encoded to a string" % type(data)
226
+
227
+ # And now overwrite any headers that have been passed into the call:
228
+ # WARNING: doesn't work with deplate so only accept gzip
229
+ headers["Accept-Encoding"] = "gzip,identity"
230
+
231
+ # httplib2 will allow sockets to close on remote end without retrying
232
+ # try to send request - if this fails try again - should then succeed
233
+ try:
234
+ conn = self._getURLOpener()
235
+ response, result = conn.request(uri, method=verb, body=data, headers=headers)
236
+ if response.status == 408: # timeout can indicate a socket error
237
+ raise socket.error
238
+ except ServerNotFoundError as ex:
239
+ # DNS cannot resolve this domain name, let's call it 'Service Unavailable'
240
+ e = HTTPException()
241
+ setattr(e, 'url', uri)
242
+ setattr(e, 'status', 503)
243
+ setattr(e, 'reason', 'Service Unavailable')
244
+ setattr(e, 'result', str(ex))
245
+ raise e from None
246
+ except (socket.error, AttributeError):
247
+ self['logger'].warning("Http request failed, retrying once again..")
248
+ # AttributeError implies initial connection error - need to close
249
+ # & retry. httplib2 doesn't clear httplib state before next request
250
+ # if this is threaded this may spoil things
251
+ # only have one endpoint so don't need to determine which to shut
252
+ for con in viewvalues(conn.connections):
253
+ con.close()
254
+ conn = self._getURLOpener()
255
+ # ... try again... if this fails propagate error to client
256
+ try:
257
+ response, result = conn.request(uri, method=verb, body=data, headers=headers)
258
+ except AttributeError:
259
+ msg = 'Error contacting: {}: {}'.format(self.getDomainName(), traceback.format_exc())
260
+ # socket/httplib really screwed up - nuclear option
261
+ conn.connections = {}
262
+ raise socket.error(msg) from None
263
+ if response.status >= 400:
264
+ e = HTTPException()
265
+ setattr(e, 'req_data', data)
266
+ setattr(e, 'req_headers', headers)
267
+ setattr(e, 'url', uri)
268
+ setattr(e, 'result', result)
269
+ setattr(e, 'status', response.status)
270
+ setattr(e, 'reason', response.reason)
271
+ setattr(e, 'headers', response)
272
+ raise e
273
+
274
+ return result, response
275
+
276
+ def encodeParams(self, data, verb, incomingHeaders, encoder, contentType):
277
+ """
278
+ Encode request parameters for usage with the 4 verbs.
279
+ Assume params is already encoded if it is a string and
280
+ uses a different encoding depending on the HTTP verb
281
+ (either json.dumps or urllib.urlencode)
282
+ """
283
+ # TODO: User agent should be:
284
+ # $client/$client_version (CMS)
285
+ # $http_lib/$http_lib_version $os/$os_version ($arch)
286
+ headers = {"Content-type": contentType if contentType else self['content_type'],
287
+ "User-Agent": "WMCore.Services.Requests/v002",
288
+ "Accept": self['accept_type']}
289
+
290
+ for key in self.additionalHeaders:
291
+ headers[key] = self.additionalHeaders[key]
292
+ # And now overwrite any headers that have been passed into the call:
293
+ # WARNING: doesn't work with deplate so only accept gzip
294
+ incomingHeaders["Accept-Encoding"] = "gzip,identity"
295
+ headers.update(incomingHeaders)
296
+
297
+ # If you're posting an attachment, the data might not be a dict
298
+ # please test against ConfigCache_t if you're unsure.
299
+ # assert type(data) == type({}), \
300
+ # "makeRequest input data must be a dict (key/value pairs)"
301
+ encoded_data = ''
302
+ if verb != 'GET' and data:
303
+ if isinstance(encoder, (types.MethodType, types.FunctionType)):
304
+ encoded_data = encoder(data)
305
+ elif encoder is False:
306
+ # Don't encode the data more than we have to
307
+ # we don't want to URL encode the data blindly,
308
+ # that breaks POSTing attachments... ConfigCache_t
309
+ # encoded_data = urllib.urlencode(data)
310
+ # -- Andrew Melo 25/7/09
311
+ encoded_data = data
312
+ else:
313
+ # Either the encoder is set to True or it's junk, so use
314
+ # self.encode
315
+ encoded_data = self.encode(data)
316
+ headers["Content-Length"] = len(encoded_data)
317
+ elif verb != 'GET':
318
+ # delete requests might not have any body
319
+ headers["Content-Length"] = 0
320
+ elif verb == 'GET' and data:
321
+ # encode the data as a get string
322
+ encoded_data = urlencode(data, doseq=True)
323
+
324
+ return encoded_data, headers
325
+
326
+ def decodeResult(self, result, decoder):
327
+ """
328
+ Decode the http/pycurl request result
329
+ NOTE: if decoder is provided with a False value, then it means no
330
+ decoding is applied on the results at all
331
+ """
332
+ if isinstance(decoder, (types.MethodType, types.FunctionType)):
333
+ result = decoder(result)
334
+ elif decoder is not False:
335
+ result = self.decode(result)
336
+ return result
337
+
338
+ def encode(self, data):
339
+ """
340
+ encode data into some appropriate format, for now make it a string...
341
+ """
342
+ return urlencode(data, doseq=True)
343
+
344
+ def decode(self, data):
345
+ """
346
+ decode data to some appropriate format, for now make it a string...
347
+ """
348
+ if PY3:
349
+ return decodeBytesToUnicode(data)
350
+ return data.__str__()
351
+
352
+ def cachePath(self, given_path, service_name):
353
+ """Return cache location"""
354
+ if not service_name:
355
+ service_name = 'REQUESTS'
356
+ top = self.cacheTopPath(given_path, service_name)
357
+
358
+ # deal with multiple Services that have the same service running and
359
+ # with multiple users for a given Service
360
+ if self.getUserName() is None:
361
+ cachepath = os.path.join(top, self['endpoint_components'].netloc)
362
+ else:
363
+ cachepath = os.path.join(top, '%s-%s' % (self.getUserName(), self.getDomainName()))
364
+
365
+ try:
366
+ # only we should be able to write to this dir
367
+ os.makedirs(cachepath, stat.S_IRWXU)
368
+ except OSError:
369
+ if not os.path.isdir(cachepath):
370
+ raise
371
+ Permissions.owner_readwriteexec(cachepath)
372
+
373
+ return cachepath
374
+
375
+ def cacheTopPath(self, given_path, service_name):
376
+ """Where to cache results?
377
+
378
+ Logic:
379
+ o If passed in take that
380
+ o Is the environment variable "SERVICE_NAME"_CACHE_DIR defined?
381
+ o Is WMCORE_CACHE_DIR set
382
+ o Generate a temporary directory
383
+ """
384
+ if given_path:
385
+ return given_path
386
+ user = str(os.getuid())
387
+ # append user id so users don't clobber each other
388
+ lastbit = os.path.join('.wmcore_cache_%s' % user, service_name.lower())
389
+ for var in ('%s_CACHE_DIR' % service_name.upper(),
390
+ 'WMCORE_CACHE_DIR'):
391
+ if os.environ.get(var):
392
+ firstbit = os.environ[var]
393
+ break
394
+ else:
395
+ idir = tempfile.mkdtemp(prefix='.wmcore_cache_')
396
+ # Alan Malta in 29 Mar 2022: this seems to prematurely remove the cache
397
+ # directory. For details, see: https://github.com/dmwm/WMCore/pull/10915
398
+ self['deleteCacheOnExit'] = TempDirectory(idir)
399
+ return idir
400
+
401
+ return os.path.join(firstbit, lastbit)
402
+
403
+ def getDomainName(self):
404
+ """Parse netloc info to get hostname"""
405
+ return self['endpoint_components'].hostname
406
+
407
+ def getUserName(self):
408
+ """Parse netloc to get user"""
409
+ return self['endpoint_components'].username
410
+
411
+ def _getURLOpener(self):
412
+ """
413
+ method getting a secure (HTTPS) connection
414
+ """
415
+ import httplib2
416
+ key, cert = None, None
417
+ if self['endpoint_components'].scheme == 'https':
418
+ # only add certs to https requests
419
+ # if we have a key/cert add to request,
420
+ # if not proceed as not all https connections require them
421
+ try:
422
+ key, cert = self.getKeyCert()
423
+ except Exception as ex:
424
+ msg = 'No certificate or key found, authentication may fail'
425
+ self['logger'].info(msg)
426
+ self['logger'].debug(str(ex))
427
+
428
+ try:
429
+ # disable validation as we don't have a single PEM with all ca's
430
+ http = httplib2.Http(self['req_cache_path'], self['timeout'],
431
+ disable_ssl_certificate_validation=True)
432
+ except TypeError:
433
+ # old httplib2 versions disable validation by default
434
+ http = httplib2.Http(self['req_cache_path'], self['timeout'])
435
+
436
+ # Domain must be just a hostname and port. self[host] is a URL currently
437
+ if key or cert:
438
+ http.add_certificate(key=key, cert=cert, domain='')
439
+ return http
440
+
441
+ def addBasicAuth(self, username, password):
442
+ """Add basic auth headers to request"""
443
+ username = encodeUnicodeToBytes(username)
444
+ password = encodeUnicodeToBytes(password)
445
+ encodedauth = base64.encodebytes(b'%s:%s' % (username, password)).strip()
446
+ if PY3:
447
+ encodedauth = decodeBytesToUnicode(encodedauth)
448
+ auth_string = "Basic %s" % encodedauth
449
+ self.additionalHeaders["Authorization"] = auth_string
450
+
451
+ def getKeyCert(self):
452
+ """
453
+ _getKeyCert_
454
+
455
+ Get the user credentials if they exist, otherwise throw an exception.
456
+ This code was modified from DBSAPI/dbsHttpService.py
457
+ """
458
+
459
+ # Zeroth case is if the class has over ridden the key/cert and has it
460
+ # stored in self
461
+ if self['cert'] and self['key']:
462
+ key = self['key']
463
+ cert = self['cert']
464
+ else:
465
+ key, cert = getKeyCertFromEnv()
466
+
467
+ # Set but not found
468
+ if key is None or cert is None:
469
+ raise WMException('Request requires a host certificate and key',
470
+ "WMCORE-11")
471
+
472
+ # All looks OK, still doesn't guarantee proxy's validity etc.
473
+ return key, cert
474
+
475
+ def getCAPath(self):
476
+ """
477
+ _getCAPath_
478
+
479
+ Return the path of the CA certificates. The check is loose in the pycurl_manager:
480
+ is capath == None then the server identity is not verified. To enable this check
481
+ you need to set either the X509_CERT_DIR variable or the cacert key of the request.
482
+ """
483
+ capath = self['capath']
484
+ if not capath:
485
+ capath = getCAPathFromEnv()
486
+ return capath
487
+
488
+ def uploadFile(self, fileName, url, fieldName='file1', params=[], verb='POST'):
489
+ """
490
+ Upload a file with curl streaming it directly from disk
491
+
492
+ :rtype: bytes (both py2 and py3)
493
+ """
494
+ ckey, cert = self.getKeyCert()
495
+ capath = self.getCAPath()
496
+ import pycurl
497
+ c = pycurl.Curl()
498
+ if verb == 'POST':
499
+ c.setopt(c.POST, 1)
500
+ elif verb == 'PUT':
501
+ c.setopt(pycurl.CUSTOMREQUEST, 'PUT')
502
+ else:
503
+ raise HTTPException("Verb %s not supported for upload." % verb)
504
+ c.setopt(c.URL, url)
505
+ fullParams = [(fieldName, (c.FORM_FILE, fileName))]
506
+ fullParams.extend(params)
507
+ c.setopt(c.HTTPPOST, fullParams)
508
+ bbuf = BytesIO()
509
+ hbuf = BytesIO()
510
+ c.setopt(pycurl.WRITEFUNCTION, bbuf.write)
511
+ c.setopt(pycurl.HEADERFUNCTION, hbuf.write)
512
+ if capath:
513
+ c.setopt(pycurl.CAPATH, capath)
514
+ c.setopt(pycurl.SSL_VERIFYPEER, True)
515
+ else:
516
+ c.setopt(pycurl.SSL_VERIFYPEER, False)
517
+ if ckey:
518
+ c.setopt(pycurl.SSLKEY, ckey)
519
+ if cert:
520
+ c.setopt(pycurl.SSLCERT, cert)
521
+ c.perform()
522
+ hres = hbuf.getvalue()
523
+ bres = bbuf.getvalue()
524
+ rh = ResponseHeader(hres)
525
+ c.close()
526
+ if rh.status < 200 or rh.status >= 300:
527
+ exc = HTTPException(bres)
528
+ setattr(exc, 'req_data', fullParams)
529
+ setattr(exc, 'url', url)
530
+ setattr(exc, 'result', bres)
531
+ setattr(exc, 'status', rh.status)
532
+ setattr(exc, 'reason', rh.reason)
533
+ setattr(exc, 'headers', rh.header)
534
+ raise exc
535
+
536
+ return bres
537
+
538
+ def downloadFile(self, fileName, url):
539
+ """
540
+ Download a file with curl streaming it directly to disk
541
+ """
542
+ ckey, cert = self.getKeyCert()
543
+ capath = self.getCAPath()
544
+ import pycurl
545
+
546
+ hbuf = BytesIO()
547
+
548
+ with open(fileName, "wb") as fp:
549
+ curl = pycurl.Curl()
550
+ curl.setopt(pycurl.URL, url)
551
+ curl.setopt(pycurl.WRITEDATA, fp)
552
+ curl.setopt(pycurl.HEADERFUNCTION, hbuf.write)
553
+ if capath:
554
+ curl.setopt(pycurl.CAPATH, capath)
555
+ curl.setopt(pycurl.SSL_VERIFYPEER, True)
556
+ else:
557
+ curl.setopt(pycurl.SSL_VERIFYPEER, False)
558
+ if ckey:
559
+ curl.setopt(pycurl.SSLKEY, ckey)
560
+ if cert:
561
+ curl.setopt(pycurl.SSLCERT, cert)
562
+ curl.setopt(pycurl.FOLLOWLOCATION, 1)
563
+ curl.perform()
564
+ curl.close()
565
+
566
+ header = ResponseHeader(hbuf.getvalue())
567
+ if header.status < 200 or header.status >= 300:
568
+ raise RuntimeError('Reading %s failed with code %s' % (url, header.status))
569
+ return fileName, header
570
+
571
+
572
+ class JSONRequests(Requests):
573
+ """
574
+ Example implementation of Requests that encodes data to/from JSON.
575
+ """
576
+
577
+ def __init__(self, url='http://localhost:8080', idict={}):
578
+ Requests.__init__(self, url, idict)
579
+ self['accept_type'] = "application/json"
580
+ self['content_type'] = "application/json"
581
+
582
+ def encode(self, data):
583
+ """
584
+ encode data as json
585
+ """
586
+ encoder = JSONEncoder()
587
+ thunker = JSONThunker()
588
+ thunked = thunker.thunk(data)
589
+ return encoder.encode(thunked)
590
+
591
+ def decode(self, data):
592
+ """
593
+ decode the data to python from json
594
+ """
595
+ if data:
596
+ decoder = JSONDecoder()
597
+ thunker = JSONThunker()
598
+ if PY3:
599
+ data = decodeBytesToUnicode(data)
600
+ data = decoder.decode(data)
601
+ unthunked = thunker.unthunk(data)
602
+ return unthunked
603
+ return {}
604
+
605
+
606
+ class TempDirectory(object):
607
+ """
608
+ Directory that cleans up after itself
609
+
610
+ Except this doesn't work, python __del__ is NOT a destructor
611
+
612
+ Leaving it anyways, since it might work sometimes
613
+
614
+ """
615
+
616
+ def __init__(self, idir):
617
+ self.dir = idir
618
+
619
+ def __del__(self):
620
+ try:
621
+ # it'll likely fail, but give it a try
622
+ shutil.rmtree(self.dir, ignore_errors=True)
623
+ except Exception:
624
+ pass