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,173 @@
1
+ #! /bin/env python
2
+
3
+ """
4
+ A service class for retrieving data from McM using
5
+ an SSO cookie since it sits behind CERN SSO
6
+ """
7
+
8
+ from builtins import str, object
9
+ import json
10
+ import os
11
+ import pycurl
12
+ import subprocess
13
+ import logging
14
+ from typing import List
15
+ from io import BytesIO
16
+ from WMCore.WMException import WMException
17
+
18
+
19
+ class McMNoDataError(WMException):
20
+ """
21
+ _McMNoDataError_
22
+ McM responded but has no data for the request
23
+ """
24
+
25
+ def __init__(self):
26
+ WMException.__init__(self, 'McM responded correctly but has no data')
27
+
28
+
29
+ class McM(object):
30
+ """
31
+ A service class for retrieving data from McM using
32
+ an SSO cookie since it sits behind CERN SSO
33
+ 'key' must be unencrypted
34
+ """
35
+
36
+ def __init__(self, url='https://cms-pdmv.cern.ch/mcm', tmpDir='/tmp'):
37
+ self.url = url
38
+ self.tmpDir = tmpDir
39
+ self.logger = self._get_logger()
40
+ self.cookieFile = None
41
+
42
+ def __enter__(self):
43
+ self._krb_ticket()
44
+ self._get_cookie()
45
+ return self
46
+
47
+ def __exit__(self, exception_type, exception_value, traceback):
48
+ if self.cookieFile:
49
+ try:
50
+ os.remove(self.cookieFile)
51
+ except OSError:
52
+ return
53
+ return
54
+
55
+ def _get_logger(self) -> logging.Logger:
56
+ """
57
+ Create a logger for McM client
58
+ """
59
+ logger: logging.Logger = logging.getLogger("mcm_client")
60
+ date_format: str = "%Y-%m-%d %H:%M:%S %z"
61
+ format: str = "[%(levelname)s][%(name)s][%(asctime)s]: %(message)s"
62
+ formatter: logging.Formatter = logging.Formatter(fmt=format, datefmt=date_format)
63
+ handler: logging.StreamHandler = logging.StreamHandler()
64
+
65
+ handler.setLevel(logging.INFO)
66
+ handler.setFormatter(formatter)
67
+ logger.addHandler(handler)
68
+ return logger
69
+
70
+ def _krb_ticket(self) -> None:
71
+ """
72
+ Check there is a valid Kerberos ticket for requesting a SSO
73
+ cookie. Raise a RuntimeError if there is not one.
74
+ """
75
+ process = subprocess.Popen(["klist", "-f"],
76
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False)
77
+ stdout: str = process.communicate()[0].decode("utf-8")
78
+ if process.returncode != 0:
79
+ msg: str = ("There is no valid Kerberos ticket for requesting a SSO cookie. "
80
+ "Please make sure to provide one for your runtime environment"
81
+ )
82
+ self.logger.error(msg)
83
+ raise RuntimeError("FATAL -- %s\nError msg: %s" % (msg, stdout))
84
+
85
+ def _get_cookie(self) -> None:
86
+ """
87
+ Request a SSO cookie to authenticate to McM.
88
+ """
89
+ self.cookieFile = os.path.join(self.tmpDir, 'ssoCookie.txt')
90
+ command: List[str] = ["auth-get-sso-cookie", "-u", self.url, "-o", self.cookieFile, "-vv"]
91
+ callback_not_invoked: str = "DEBUG: Not automatically redirected: trying SAML authentication"
92
+ cookie_stored: str = "INFO: Saving cookies"
93
+
94
+ process = subprocess.Popen(command, stdout=subprocess.PIPE,
95
+ stderr=subprocess.STDOUT, shell=False)
96
+ stdout: str = process.communicate()[0].decode("utf-8")
97
+ stdout_list: List[str] = stdout.strip().split("\n")
98
+ if process.returncode != 0:
99
+ raise RuntimeError("FATAL -- Error requesting SSO cookie\nError msg: %s" % (stdout))
100
+
101
+ if callback_not_invoked in stdout:
102
+ callback_idx: int = stdout_list.index(callback_not_invoked)
103
+ stored_after_issue: bool = cookie_stored in stdout_list[callback_idx + 1]
104
+ if stored_after_issue:
105
+ msg: str = ("Callback method was not invoked. "
106
+ "Please make sure the provided Kerberos ticket is not linked to an account with 2FA"
107
+ )
108
+ raise RuntimeError(msg)
109
+
110
+ def _getURL(self, extendURL):
111
+ """
112
+ Fetch an MCM URL with CURL using the SSO cookie.
113
+ Only intended to be used internally
114
+ """
115
+
116
+ try:
117
+ b = BytesIO()
118
+ c = pycurl.Curl()
119
+
120
+ fullUrl = '%s/%s' % (self.url, extendURL)
121
+
122
+ c.setopt(c.URL, fullUrl)
123
+ c.setopt(c.SSL_VERIFYPEER, False)
124
+ c.setopt(c.SSL_VERIFYHOST, False)
125
+ c.setopt(c.FOLLOWLOCATION, True)
126
+ c.setopt(c.COOKIEJAR, self.cookieFile)
127
+ c.setopt(c.COOKIEFILE, self.cookieFile)
128
+ c.setopt(c.WRITEFUNCTION, b.write)
129
+ c.perform()
130
+ if c.getinfo(pycurl.HTTP_CODE) != 200:
131
+ raise IOError
132
+ except:
133
+ c.close()
134
+ raise IOError('Was not able to fetch or decode URL from McM')
135
+
136
+ try:
137
+ body = b.getvalue()
138
+ res = json.loads(body)
139
+ except ValueError:
140
+ c.close()
141
+ raise IOError('Was not able to decode JSON from McM')
142
+
143
+ c.close()
144
+ return res
145
+
146
+ def getHistory(self, prepID):
147
+ """
148
+ Get the history record which has who did what to an McM request
149
+ """
150
+
151
+ try:
152
+ url = 'search?db_name=batches&contains=%s&get_raw' % prepID
153
+ res = self._getURL(url)
154
+ history = res.get("results", [])[0].get("history", [])
155
+ return history
156
+ except IndexError:
157
+ raise McMNoDataError
158
+
159
+ def getRequest(self, prepID):
160
+ """
161
+ Get the request record which has, among other things,
162
+ the number of requested events
163
+ """
164
+
165
+ url = 'public/restapi/requests/get/%s' % prepID
166
+ res = self._getURL(url)
167
+ return res['results']
168
+
169
+
170
+ if __name__ == '__main__':
171
+ with McM() as mcm:
172
+ history = mcm.getHistory(prepID='BTV-Upg2023SHCAL14DR-00002')
173
+ request = mcm.getRequest(prepID='BTV-Upg2023SHCAL14DR-00002')
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ _McM_
4
+
5
+ API for McM
6
+
7
+ """
8
+ __all__ = []
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env python
2
+ # coding=utf-8
3
+ """
4
+ Wrapper class, based on the PyCuRL module, providing an interface
5
+ to CERN MonIT Grafana APIs
6
+ """
7
+ from __future__ import division, print_function, absolute_import
8
+ from builtins import str, object
9
+ from future import standard_library
10
+ standard_library.install_aliases()
11
+
12
+ import logging
13
+ import json
14
+ from copy import copy
15
+ from pprint import pformat
16
+ from urllib.parse import urljoin
17
+
18
+ from WMCore.Services.pycurl_manager import RequestHandler
19
+
20
+ class Grafana(object):
21
+ """
22
+ Service class providing functionality to CERN monitoring Grafana APIs
23
+ """
24
+
25
+ def __init__(self, token, configDict=None):
26
+ """
27
+ Constructs a Grafana object.
28
+ :param token: mandatory string with the key/token string
29
+ :param configDict: dictionary with extra parameters, such as:
30
+ logger: logger object
31
+ endpoint: string with the url/endpoint to be used
32
+ cacheduration: float with the cache duration, in hours
33
+ headers: dictionary with the headers to be used
34
+ """
35
+ self._token = token
36
+ self.configDict = configDict or {}
37
+ self.configDict.setdefault('endpoint', "https://monit-grafana.cern.ch")
38
+ self.configDict.setdefault('cacheduration', 0) # in hours
39
+ if 'headers' not in self.configDict:
40
+ self.configDict.setdefault('headers', {})
41
+ self.configDict['headers'].update({"Accept": "application/json"})
42
+ self.configDict['headers'].update({"Content-Type": "application/json"})
43
+
44
+ self.logger = self.configDict.get("logger", logging.getLogger())
45
+ self.logger.info("MonIT service initialized with parameters: %s", self.configDict)
46
+
47
+ def updateToken(self, token):
48
+ """
49
+ Update token to be used in requests made through this module
50
+ :param token: string with the new token
51
+ """
52
+ self._token = token
53
+
54
+ def _postRequest(self, url, params, verb='POST', verbose=0):
55
+ "Helper function to POST request to given URL"
56
+ mgr = RequestHandler(logger=self.logger)
57
+ headers = copy(self.configDict['headers'])
58
+ headers.update({"Authorization": self._token})
59
+
60
+ try:
61
+ data = mgr.getdata(url, params, headers, verb=verb, verbose=verbose)
62
+ return json.loads(data)
63
+ except Exception as exc:
64
+ self.logger.error("Failed to retrieve data from MonIT. Error: %s", str(exc))
65
+ return None
66
+
67
+ def getAPIData(self, apiName, queryStr=''):
68
+ """
69
+ _getAPIData_
70
+
71
+ Retrieve data from a given Grafana API and index name
72
+ :param apiName: string with the API name/number
73
+ :param queryStr: string with the whole query logic
74
+ :return: data as retrieved from Grafana
75
+ """
76
+ uri = urljoin(self.configDict['endpoint'], "/api/datasources/proxy/%s/_msearch" % apiName)
77
+ return self._postRequest(uri, queryStr)
78
+
79
+ def getSSBData(self, pathName, metricName, indexName="monit_prod_cmssst_*",
80
+ apiName="9475", queryStr=''):
81
+ """
82
+ _getSSBData_
83
+
84
+ Retrieve data from the SSB index in Grafana
85
+ :param pathName: string with the path to the correct metric, mapped from SSB as:
86
+ columnid=237 ProdStatus path="sts15min" data.prod_status
87
+ columnid=160 CPU bound path="scap15min" data.core_cpu_intensive
88
+ columnid=161 I/O bound path="scap15min" data.core_io_intensive
89
+ columnid=159 Prod Cores path="scap15min" data.core_production
90
+ columnid=136 Real Cores path="scap15min" data.core_max_used
91
+ columnid=107 Tape Pledge path="scap15min" data.tape_pledge
92
+ :param indexName: optional string with the grafana index name
93
+ :param apiName: optional string with the Grafana API number
94
+ :param queryStr: optional string with the full query logic
95
+ :return: dictionary with the site names and the metric value
96
+ """
97
+ # TODO: allow flexible time range instead of the hardwired last 24h
98
+ # TODO: allow flexible number of rows, instead of the hardwired 500
99
+ results = {}
100
+ if metricName not in ('prod_status', 'core_cpu_intensive', 'core_io_intensive',
101
+ 'core_production', 'core_max_used', 'tape_pledge'):
102
+ self.logger.error("SSB metric name '%s' is NOT supported.", metricName)
103
+ return results
104
+
105
+ uri = urljoin(self.configDict['endpoint'], "/api/datasources/proxy/%s/_msearch" % apiName)
106
+ if not queryStr:
107
+ ### NOTE: these '\n' new lines are mandatory to get it working...
108
+ queryStr = '{"search_type":"query_then_fetch","ignore_unavailable":true,"index":["%s"]}\n' % indexName
109
+ queryStr += '{"size":500,"query":{"bool":{"filter":[{"range":{"metadata.timestamp":{"gte":"now-1d","lte":"now","format":"epoch_millis"}}},' \
110
+ '{"query_string":{"analyze_wildcard":true,' \
111
+ '"query":"metadata.type: ssbmetric AND metadata.type_prefix:raw AND metadata.monit_hdfs_path: %s"}}]}},' \
112
+ '"sort":{"metadata.timestamp":{"order":"desc","unmapped_type":"boolean"}},' \
113
+ '"script_fields":{},"docvalue_fields":["metadata.timestamp"]}\n' % pathName
114
+ self.logger.info("Calling API: %s with query: %s", uri, pformat(queryStr))
115
+
116
+ data = self._postRequest(uri, queryStr)
117
+ #self.logger.debug("Data retrieved: %s", pformat(data))
118
+ if data:
119
+ # now parse the ugly output
120
+ hits = data['responses'][0]['hits']['hits']
121
+ for item in hits:
122
+ site = item['_source']['data']['name']
123
+ metricValue = item['_source']['data'][metricName]
124
+ tStamp = int(item['sort'][0])
125
+
126
+ results.setdefault(site, {})
127
+ if tStamp > results[site].get("timeStamp", 0):
128
+ results[site][metricName] = metricValue
129
+ results[site]["timeStamp"] = tStamp
130
+
131
+ data = results
132
+
133
+ return data
File without changes
@@ -0,0 +1,154 @@
1
+ """
2
+ _PyCondorAPI_
3
+
4
+ Class used to interact with Condor daemons on the agent
5
+ """
6
+
7
+ from __future__ import print_function, division
8
+
9
+ from builtins import str, object
10
+ from past.builtins import basestring
11
+ import logging
12
+ try:
13
+ # This module has dependency with python binding for condor package (condor)
14
+ import htcondor2 as htcondor
15
+ except ImportError:
16
+ pass
17
+
18
+
19
+ class PyCondorAPI(object):
20
+ """
21
+ Some APIs to interact with HTCondor via the HTCondor python bindings.
22
+ """
23
+ def __init__(self):
24
+ self.schedd = htcondor.Schedd()
25
+ self.coll = htcondor.Collector()
26
+
27
+ def recreateSchedd(self):
28
+ """
29
+ In case our current schedd object is in a "strange" state, we
30
+ better recreate it.
31
+ """
32
+ logging.warning("Recreating Schedd instance due to query error...")
33
+ self.schedd = htcondor.Schedd()
34
+
35
+ def getCondorJobsSummary(self):
36
+ """
37
+ Retrieves a job summary from the HTCondor Schedd object
38
+ :return: a list of classads representing the matching jobs, or None if failed
39
+ """
40
+ jobs = None # return None to signalize the query failed
41
+ queryOpts = htcondor.htcondor.QueryOpts.SummaryOnly
42
+ try:
43
+ return self.schedd.query(opts=queryOpts)
44
+ except Exception:
45
+ self.recreateSchedd()
46
+
47
+ try:
48
+ jobs = self.schedd.query(opts=queryOpts)
49
+ except Exception as ex:
50
+ logging.exception("Failed to fetch summary of jobs from Condor Schedd. Error: %s", str(ex))
51
+ return jobs
52
+
53
+ def getCondorJobs(self, constraint='true', attrList=None, limit=-1, opts="Default"):
54
+ """
55
+ Given a job/schedd constraint, return a list of job classad.
56
+ :param constraint: the query constraint (str or ExprTree). Defaults to 'true'
57
+ :param attrList: a list of attribute strings to be returned in the call.
58
+ It defaults to all attributes.
59
+ :param limit: a limit on the number of matches to return. Defaults to -1 (all)
60
+ :param opts: string with additional flags for the query. Defaults to Default.
61
+ https://htcondor.readthedocs.io/en/v8_9_7/apis/python-bindings/api/htcondor.html#htcondor.QueryOpts
62
+ :return: returns an iterator to the job classads
63
+ """
64
+ attrList = attrList or []
65
+ # if option parameter is invalid, default it to the standard behavior
66
+ opts = getattr(htcondor.htcondor.QueryOpts, opts, "Default")
67
+ msg = "Querying condor schedd with params: constraint=%s, attrList=%s, limit=%s, opts=%s"
68
+ logging.info(msg, constraint, attrList, limit, opts)
69
+ try:
70
+ return self.schedd.query(constraint, attrList, limit, opts=opts)
71
+ except Exception:
72
+ self.recreateSchedd()
73
+
74
+ # if we hit another exception, let it be raised up in the chain
75
+ return self.schedd.query(constraint, attrList, limit, opts=opts)
76
+
77
+ def editCondorJobs(self, job_spec, attr, value):
78
+ """
79
+ _editCondorJobs_
80
+
81
+ Edit a set of condor jobs given an attribute and value
82
+ job_spec can be a list of job IDs or a string specifying a constraint
83
+ """
84
+ success = False
85
+ try:
86
+ self.schedd.edit(job_spec, attr, value)
87
+ success = True
88
+ except Exception as ex:
89
+ # edit doesn't distinguish between an error and not matching any jobs
90
+ # check for this message and assume it just didn't match any jobs
91
+ if isinstance(ex, RuntimeError) and str(ex) == "Unable to edit jobs matching constraint":
92
+ success = True
93
+ msg = "Condor constraint did not match any jobs. "
94
+ msg += "Message from schedd: %s" % str(ex)
95
+ logging.info(msg)
96
+ else:
97
+ msg = "Condor failed to edit the jobs. "
98
+ msg += "Error message: %s" % str(ex)
99
+ logging.exception(msg)
100
+
101
+ return success
102
+
103
+ def isScheddOverloaded(self):
104
+ """
105
+ check whether job limit is reached in local schedd.
106
+ Condition is check by following logic.
107
+ ( ShadowsRunning > 9.700000000000000E-01 * MAX_RUNNING_JOBS) )
108
+ || ( RecentDaemonCoreDutyCycle > 9.800000000000000E-01 )
109
+ """
110
+ try:
111
+ scheddAd = self.coll.locate(htcondor.DaemonTypes.Schedd)
112
+ q = self.coll.query(htcondor.AdTypes.Schedd, 'Name == "%s"' % scheddAd['Name'],
113
+ projection=['CurbMatchmaking'])[0]
114
+ isOverloaded = q['CurbMatchmaking'].eval(q)
115
+ return isOverloaded
116
+ except Exception:
117
+ # if there is an error, try to recreate the collector instance
118
+ logging.info("Recreating Collector instance due to query error...")
119
+ self.coll = htcondor.Collector()
120
+ try:
121
+ scheddAd = self.coll.locate(htcondor.DaemonTypes.Schedd)
122
+ q = self.coll.query(htcondor.AdTypes.Schedd, 'Name == "%s"' % scheddAd['Name'],
123
+ projection=['CurbMatchmaking'])[0]
124
+ isOverloaded = q['CurbMatchmaking'].eval(q)
125
+ except Exception as ex:
126
+ msg = "Condor failed to fetch schedd attributes."
127
+ msg += "Error message: %s" % str(ex)
128
+ logging.exception(msg)
129
+ # since it failed, assume it's overloaded
130
+ isOverloaded = True
131
+
132
+ return isOverloaded
133
+
134
+
135
+ def getScheddParamValue(param):
136
+ """
137
+ _getScheddParamValue_
138
+
139
+ Given a schedd parameter, retrieve it's value with htcondor, e.g.:
140
+ MAX_JOBS_RUNNING, MAX_JOBS_PER_OWNER, etc
141
+ """
142
+ paramResult = None
143
+ if not isinstance(param, basestring):
144
+ logging.error("Parameter %s must be string type", param)
145
+ return paramResult
146
+
147
+ try:
148
+ paramResult = htcondor.param[param]
149
+ except Exception as ex:
150
+ msg = "Condor failed to fetch schedd parameter: %s" % param
151
+ msg += "Error message: %s" % str(ex)
152
+ logging.exception(msg)
153
+
154
+ return paramResult
File without changes