panda-server-source 0.8.0__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 (375) hide show
  1. panda_server_source-0.8.0.dist-info/METADATA +55 -0
  2. panda_server_source-0.8.0.dist-info/RECORD +375 -0
  3. panda_server_source-0.8.0.dist-info/WHEEL +4 -0
  4. panda_server_source-0.8.0.dist-info/licenses/LICENSE.txt +202 -0
  5. pandajedi/__init__.py +0 -0
  6. pandajedi/jedibrokerage/AtlasAnalJobBroker.py +2343 -0
  7. pandajedi/jedibrokerage/AtlasBrokerUtils.py +1292 -0
  8. pandajedi/jedibrokerage/AtlasProdJobBroker.py +2064 -0
  9. pandajedi/jedibrokerage/AtlasProdTaskBroker.py +629 -0
  10. pandajedi/jedibrokerage/GenJobBroker.py +381 -0
  11. pandajedi/jedibrokerage/JobBrokerBase.py +133 -0
  12. pandajedi/jedibrokerage/TaskBrokerBase.py +15 -0
  13. pandajedi/jedibrokerage/__init__.py +0 -0
  14. pandajedi/jediconfig/__init__.py +0 -0
  15. pandajedi/jediconfig/jedi_config.py +40 -0
  16. pandajedi/jedicore/FactoryBase.py +182 -0
  17. pandajedi/jedicore/Interaction.py +433 -0
  18. pandajedi/jedicore/JediDBProxy.py +56 -0
  19. pandajedi/jedicore/JediDBProxyPool.py +37 -0
  20. pandajedi/jedicore/JediDBSchemaInfo.py +17 -0
  21. pandajedi/jedicore/JediException.py +13 -0
  22. pandajedi/jedicore/JediTaskBuffer.py +984 -0
  23. pandajedi/jedicore/JediTaskBufferInterface.py +50 -0
  24. pandajedi/jedicore/MsgWrapper.py +124 -0
  25. pandajedi/jedicore/ProcessUtils.py +34 -0
  26. pandajedi/jedicore/SiteCandidate.py +90 -0
  27. pandajedi/jedicore/ThreadUtils.py +205 -0
  28. pandajedi/jedicore/__init__.py +0 -0
  29. pandajedi/jediddm/AtlasDDMClient.py +1708 -0
  30. pandajedi/jediddm/DDMClientBase.py +16 -0
  31. pandajedi/jediddm/DDMInterface.py +83 -0
  32. pandajedi/jediddm/GenDDMClient.py +17 -0
  33. pandajedi/jediddm/__init__.py +0 -0
  34. pandajedi/jedidog/AtlasAnalWatchDog.py +648 -0
  35. pandajedi/jedidog/AtlasDataCarouselWatchDog.py +189 -0
  36. pandajedi/jedidog/AtlasDataLocalityUpdaterWatchDog.py +215 -0
  37. pandajedi/jedidog/AtlasProdWatchDog.py +443 -0
  38. pandajedi/jedidog/AtlasQueueFillerWatchDog.py +800 -0
  39. pandajedi/jedidog/AtlasTaskWithholderWatchDog.py +245 -0
  40. pandajedi/jedidog/AtlasWorkflowManagerWatchDog.py +63 -0
  41. pandajedi/jedidog/GenWatchDog.py +21 -0
  42. pandajedi/jedidog/JumboWatchDog.py +147 -0
  43. pandajedi/jedidog/TypicalWatchDogBase.py +122 -0
  44. pandajedi/jedidog/WatchDogBase.py +53 -0
  45. pandajedi/jedidog/__init__.py +0 -0
  46. pandajedi/jediexec/reniceJEDI.py +25 -0
  47. pandajedi/jedigen/AtlasTaskGenerator.py +110 -0
  48. pandajedi/jedigen/TaskGeneratorBase.py +15 -0
  49. pandajedi/jedigen/__init__.py +0 -0
  50. pandajedi/jedimsgprocessor/__init__.py +0 -0
  51. pandajedi/jedimsgprocessor/ai_parameter_adjuster_msg_processor +71 -0
  52. pandajedi/jedimsgprocessor/atlas_idds_msg_processor.py +66 -0
  53. pandajedi/jedimsgprocessor/base_msg_processor.py +33 -0
  54. pandajedi/jedimsgprocessor/forwarding_msg_processor.py +29 -0
  55. pandajedi/jedimsgprocessor/hpo_msg_processor.py +93 -0
  56. pandajedi/jedimsgprocessor/jedi_contents_feeder_msg_processor.py +63 -0
  57. pandajedi/jedimsgprocessor/jedi_job_generator_msg_processor.py +185 -0
  58. pandajedi/jedimsgprocessor/jedi_post_processor_msg_processor.py +82 -0
  59. pandajedi/jedimsgprocessor/kafka_msg_processor.py +44 -0
  60. pandajedi/jedimsgprocessor/panda_callback_msg_processor.py +182 -0
  61. pandajedi/jedimsgprocessor/panda_to_jedi_msg_processor.py +74 -0
  62. pandajedi/jedimsgprocessor/processing_msg_processor.py +134 -0
  63. pandajedi/jedimsgprocessor/status_report_msg_processor.py +129 -0
  64. pandajedi/jedimsgprocessor/tape_carousel_msg_processor.py +118 -0
  65. pandajedi/jedimsgprocessor/workflow_manager_msg_processor.py +89 -0
  66. pandajedi/jediorder/ContentsFeeder.py +785 -0
  67. pandajedi/jediorder/JediDaemon.py +27 -0
  68. pandajedi/jediorder/JediKnight.py +55 -0
  69. pandajedi/jediorder/JediMaster.py +238 -0
  70. pandajedi/jediorder/JediMsgProcessor.py +32 -0
  71. pandajedi/jediorder/JobBroker.py +33 -0
  72. pandajedi/jediorder/JobGenerator.py +2763 -0
  73. pandajedi/jediorder/JobSplitter.py +308 -0
  74. pandajedi/jediorder/JobThrottler.py +28 -0
  75. pandajedi/jediorder/PostProcessor.py +166 -0
  76. pandajedi/jediorder/TaskBroker.py +268 -0
  77. pandajedi/jediorder/TaskCommando.py +334 -0
  78. pandajedi/jediorder/TaskGenerator.py +17 -0
  79. pandajedi/jediorder/TaskRefiner.py +611 -0
  80. pandajedi/jediorder/TaskSetupper.py +17 -0
  81. pandajedi/jediorder/WatchDog.py +79 -0
  82. pandajedi/jediorder/__init__.py +0 -0
  83. pandajedi/jedipprocess/AtlasAnalPostProcessor.py +404 -0
  84. pandajedi/jedipprocess/AtlasPostProcessorUtils.py +50 -0
  85. pandajedi/jedipprocess/AtlasProdPostProcessor.py +178 -0
  86. pandajedi/jedipprocess/GenPostProcessor.py +35 -0
  87. pandajedi/jedipprocess/MailTemplates.py +185 -0
  88. pandajedi/jedipprocess/PostProcessorBase.py +269 -0
  89. pandajedi/jedipprocess/__init__.py +0 -0
  90. pandajedi/jedirefine/AtlasAnalTaskRefiner.py +259 -0
  91. pandajedi/jedirefine/AtlasProdTaskRefiner.py +162 -0
  92. pandajedi/jedirefine/GenTaskRefiner.py +61 -0
  93. pandajedi/jedirefine/RefinerUtils.py +154 -0
  94. pandajedi/jedirefine/TaskRefinerBase.py +996 -0
  95. pandajedi/jedirefine/__init__.py +0 -0
  96. pandajedi/jedisetup/AtlasTaskSetupper.py +309 -0
  97. pandajedi/jedisetup/GenTaskSetupper.py +16 -0
  98. pandajedi/jedisetup/SimpleTaskSetupper.py +152 -0
  99. pandajedi/jedisetup/TaskSetupperBase.py +15 -0
  100. pandajedi/jedisetup/__init__.py +0 -0
  101. pandajedi/jeditest/SchemaChecker.py +41 -0
  102. pandajedi/jeditest/addContWoSoTask.py +54 -0
  103. pandajedi/jeditest/addDataCarouselRequest.py +47 -0
  104. pandajedi/jeditest/addEventServiceTask.py +101 -0
  105. pandajedi/jeditest/addHpoTask.py +81 -0
  106. pandajedi/jeditest/addIDDSStageInRequest.py +56 -0
  107. pandajedi/jeditest/addNonAtlasTask.py +71 -0
  108. pandajedi/jeditest/addNonAtlasTaskEnc.py +64 -0
  109. pandajedi/jeditest/addTestTask.py +124 -0
  110. pandajedi/jeditest/addTestTaskParamToDEFT.py +70 -0
  111. pandajedi/jeditest/addTestTaskWithMerger.py +97 -0
  112. pandajedi/jeditest/brokerTest.py +78 -0
  113. pandajedi/jeditest/cancelDataCarouselRequest.py +35 -0
  114. pandajedi/jeditest/contentsFeederTest.py +28 -0
  115. pandajedi/jeditest/contentsFeederTestWithTask.py +18 -0
  116. pandajedi/jeditest/ddmTest.py +4 -0
  117. pandajedi/jeditest/jobGenForOneTask.py +38 -0
  118. pandajedi/jeditest/jobGeneratorTest.py +43 -0
  119. pandajedi/jeditest/jobSplitterTest.py +104 -0
  120. pandajedi/jeditest/jobThrottlerTest.py +22 -0
  121. pandajedi/jeditest/msgProcessorTest.py +9 -0
  122. pandajedi/jeditest/postProcessorTest.py +18 -0
  123. pandajedi/jeditest/resubmitDataCarouselRequest.py +35 -0
  124. pandajedi/jeditest/resubmitTaskParam.py +20 -0
  125. pandajedi/jeditest/taskBrokerTest.py +22 -0
  126. pandajedi/jeditest/taskBrokerTestWithTask.py +38 -0
  127. pandajedi/jeditest/taskBufferTest.py +5 -0
  128. pandajedi/jeditest/taskCommandoTest.py +28 -0
  129. pandajedi/jeditest/taskRefinerTest.py +30 -0
  130. pandajedi/jeditest/testOneTaskToRefine.py +49 -0
  131. pandajedi/jeditest/testOneTaskToTaskBroker.py +42 -0
  132. pandajedi/jeditest/testPandaDDMMap.py +62 -0
  133. pandajedi/jeditest/updateDataCarouselRequestParams.py +50 -0
  134. pandajedi/jeditest/watchDogTest.py +25 -0
  135. pandajedi/jeditest/workQueueTest.py +22 -0
  136. pandajedi/jedithrottle/AtlasAnalJobThrottler.py +19 -0
  137. pandajedi/jedithrottle/AtlasProdJobThrottler.py +18 -0
  138. pandajedi/jedithrottle/GenJobThrottler.py +26 -0
  139. pandajedi/jedithrottle/JobThrottlerBase.py +496 -0
  140. pandajedi/jedithrottle/__init__.py +0 -0
  141. pandaserver/__init__.py +0 -0
  142. pandaserver/api/__init__.py +0 -0
  143. pandaserver/api/v1/__init__.py +0 -0
  144. pandaserver/api/v1/common.py +339 -0
  145. pandaserver/api/v1/credential_management_api.py +372 -0
  146. pandaserver/api/v1/data_carousel_api.py +264 -0
  147. pandaserver/api/v1/event_api.py +269 -0
  148. pandaserver/api/v1/file_server_api.py +942 -0
  149. pandaserver/api/v1/harvester_api.py +445 -0
  150. pandaserver/api/v1/http_client.py +166 -0
  151. pandaserver/api/v1/idds_api.py +180 -0
  152. pandaserver/api/v1/job_api.py +463 -0
  153. pandaserver/api/v1/metaconfig_api.py +122 -0
  154. pandaserver/api/v1/pilot_api.py +895 -0
  155. pandaserver/api/v1/statistics_api.py +207 -0
  156. pandaserver/api/v1/system_api.py +186 -0
  157. pandaserver/api/v1/task_api.py +1520 -0
  158. pandaserver/api/v1/tests/__init__.py +0 -0
  159. pandaserver/api/v1/tests/credential_management_api_tests.py +116 -0
  160. pandaserver/api/v1/tests/data_carousel_api_tests.py +82 -0
  161. pandaserver/api/v1/tests/harvester_api_tests.py +188 -0
  162. pandaserver/api/v1/tests/idds_api_tests.py +45 -0
  163. pandaserver/api/v1/tests/job_api_tests.py +112 -0
  164. pandaserver/api/v1/tests/pilot_api_tests.py +154 -0
  165. pandaserver/api/v1/tests/statistics_api_tests.py +104 -0
  166. pandaserver/api/v1/tests/system_api_tests.py +58 -0
  167. pandaserver/api/v1/tests/task_api_tests.py +590 -0
  168. pandaserver/api/v1/version.py +2 -0
  169. pandaserver/api/v1/workflow_api.py +136 -0
  170. pandaserver/brokerage/SiteMapper.py +406 -0
  171. pandaserver/brokerage/__init__.py +0 -0
  172. pandaserver/brokerage/broker.py +272 -0
  173. pandaserver/config/__init__.py +0 -0
  174. pandaserver/config/config_utils.py +15 -0
  175. pandaserver/config/daemon_config.py +29 -0
  176. pandaserver/config/mcp_config.py +38 -0
  177. pandaserver/config/panda_config.py +233 -0
  178. pandaserver/configurator/Carbon.py +65 -0
  179. pandaserver/configurator/Configurator.py +908 -0
  180. pandaserver/configurator/__init__.py +0 -0
  181. pandaserver/configurator/aux.py +73 -0
  182. pandaserver/daemons/__init__.py +0 -0
  183. pandaserver/daemons/master.py +110 -0
  184. pandaserver/daemons/master_systemd.py +79 -0
  185. pandaserver/daemons/scripts/__init__.py +0 -0
  186. pandaserver/daemons/scripts/add_main.py +264 -0
  187. pandaserver/daemons/scripts/add_sub.py +221 -0
  188. pandaserver/daemons/scripts/cache_pilots.py +47 -0
  189. pandaserver/daemons/scripts/cache_schedconfig.py +286 -0
  190. pandaserver/daemons/scripts/carbon.py +50 -0
  191. pandaserver/daemons/scripts/configurator.py +94 -0
  192. pandaserver/daemons/scripts/copyArchive.py +1387 -0
  193. pandaserver/daemons/scripts/datasetManager.py +1154 -0
  194. pandaserver/daemons/scripts/dummy_test.py +25 -0
  195. pandaserver/daemons/scripts/evpPD2P.py +144 -0
  196. pandaserver/daemons/scripts/hs_scrapers.py +264 -0
  197. pandaserver/daemons/scripts/metric_collector.py +927 -0
  198. pandaserver/daemons/scripts/panda_activeusers_query.py +80 -0
  199. pandaserver/daemons/scripts/pilotStreaming.py +109 -0
  200. pandaserver/daemons/scripts/process_workflow_files_daemon.py +166 -0
  201. pandaserver/daemons/scripts/recover_lost_files_daemon.py +177 -0
  202. pandaserver/daemons/scripts/task_evaluator.py +405 -0
  203. pandaserver/daemons/scripts/tmpwatch.py +70 -0
  204. pandaserver/daemons/scripts/worker_synchronization.py +97 -0
  205. pandaserver/daemons/utils.py +753 -0
  206. pandaserver/dataservice/DataServiceUtils.py +323 -0
  207. pandaserver/dataservice/ErrorCode.py +25 -0
  208. pandaserver/dataservice/RecoverLostFilesCore.py +322 -0
  209. pandaserver/dataservice/__init__.py +0 -0
  210. pandaserver/dataservice/activator.py +79 -0
  211. pandaserver/dataservice/adder_atlas_plugin.py +1106 -0
  212. pandaserver/dataservice/adder_dummy_plugin.py +31 -0
  213. pandaserver/dataservice/adder_gen.py +954 -0
  214. pandaserver/dataservice/adder_plugin_base.py +27 -0
  215. pandaserver/dataservice/adder_result.py +75 -0
  216. pandaserver/dataservice/adder_simple_plugin.py +160 -0
  217. pandaserver/dataservice/closer.py +247 -0
  218. pandaserver/dataservice/closer_atlas_plugin.py +90 -0
  219. pandaserver/dataservice/ddm.py +1381 -0
  220. pandaserver/dataservice/ddm_handler.py +95 -0
  221. pandaserver/dataservice/dyn_data_distributer.py +824 -0
  222. pandaserver/dataservice/event_lookup_client_ei.py +77 -0
  223. pandaserver/dataservice/event_picker.py +268 -0
  224. pandaserver/dataservice/finisher.py +194 -0
  225. pandaserver/dataservice/setupper.py +225 -0
  226. pandaserver/dataservice/setupper_atlas_plugin.py +1851 -0
  227. pandaserver/dataservice/setupper_dummy_plugin.py +47 -0
  228. pandaserver/dataservice/setupper_plugin_base.py +67 -0
  229. pandaserver/jobdispatcher/DispatcherUtils.py +35 -0
  230. pandaserver/jobdispatcher/ErrorCode.py +19 -0
  231. pandaserver/jobdispatcher/JobDispatcher.py +1625 -0
  232. pandaserver/jobdispatcher/Protocol.py +443 -0
  233. pandaserver/jobdispatcher/Watcher.py +186 -0
  234. pandaserver/jobdispatcher/__init__.py +0 -0
  235. pandaserver/pandamcp/__init__.py +0 -0
  236. pandaserver/pandamcp/mcp_main.py +56 -0
  237. pandaserver/pandamcp/mcp_test_client.py +95 -0
  238. pandaserver/pandamcp/mcp_utils.py +74 -0
  239. pandaserver/proxycache/__init__.py +0 -0
  240. pandaserver/proxycache/panda_proxy_cache.py +240 -0
  241. pandaserver/proxycache/token_cache.py +141 -0
  242. pandaserver/server/.gacl +6 -0
  243. pandaserver/server/panda.py +539 -0
  244. pandaserver/srvcore/CoreUtils.py +572 -0
  245. pandaserver/srvcore/MailUtils.py +106 -0
  246. pandaserver/srvcore/__init__.py +0 -0
  247. pandaserver/srvcore/allowed_methods.py +100 -0
  248. pandaserver/srvcore/oidc_utils.py +152 -0
  249. pandaserver/srvcore/panda_request.py +196 -0
  250. pandaserver/srvcore/srv_msg_utils.py +42 -0
  251. pandaserver/taskbuffer/ConBridge.py +513 -0
  252. pandaserver/taskbuffer/DBProxyPool.py +95 -0
  253. pandaserver/taskbuffer/DataCarousel.py +3053 -0
  254. pandaserver/taskbuffer/DatasetSpec.py +137 -0
  255. pandaserver/taskbuffer/DdmSpec.py +201 -0
  256. pandaserver/taskbuffer/ErrorCode.py +87 -0
  257. pandaserver/taskbuffer/EventServiceUtils.py +396 -0
  258. pandaserver/taskbuffer/FileSpec.py +290 -0
  259. pandaserver/taskbuffer/GlobalShares.py +244 -0
  260. pandaserver/taskbuffer/HarvesterMetricsSpec.py +92 -0
  261. pandaserver/taskbuffer/Initializer.py +82 -0
  262. pandaserver/taskbuffer/InputChunk.py +1080 -0
  263. pandaserver/taskbuffer/JediCacheSpec.py +57 -0
  264. pandaserver/taskbuffer/JediDatasetSpec.py +588 -0
  265. pandaserver/taskbuffer/JediFileSpec.py +242 -0
  266. pandaserver/taskbuffer/JediTaskSpec.py +1687 -0
  267. pandaserver/taskbuffer/JobSpec.py +1006 -0
  268. pandaserver/taskbuffer/JobUtils.py +232 -0
  269. pandaserver/taskbuffer/NucleusSpec.py +116 -0
  270. pandaserver/taskbuffer/OraDBProxy.py +174 -0
  271. pandaserver/taskbuffer/PanDAMsgProcessor.py +8 -0
  272. pandaserver/taskbuffer/PandaDBSchemaInfo.py +18 -0
  273. pandaserver/taskbuffer/ParseJobXML.py +350 -0
  274. pandaserver/taskbuffer/PickleFileSpec.py +18 -0
  275. pandaserver/taskbuffer/PickleJobSpec.py +25 -0
  276. pandaserver/taskbuffer/PrioUtil.py +40 -0
  277. pandaserver/taskbuffer/ProcessGroups.py +111 -0
  278. pandaserver/taskbuffer/ResourceSpec.py +175 -0
  279. pandaserver/taskbuffer/SQLDumper.py +37 -0
  280. pandaserver/taskbuffer/SQLManager.py +60 -0
  281. pandaserver/taskbuffer/SiteSpec.py +304 -0
  282. pandaserver/taskbuffer/SupErrors.py +10 -0
  283. pandaserver/taskbuffer/TaskBuffer.py +2882 -0
  284. pandaserver/taskbuffer/TaskBufferInterface.py +163 -0
  285. pandaserver/taskbuffer/Utils.py +848 -0
  286. pandaserver/taskbuffer/WorkQueue.py +227 -0
  287. pandaserver/taskbuffer/WorkQueueMapper.py +203 -0
  288. pandaserver/taskbuffer/WorkerSpec.py +143 -0
  289. pandaserver/taskbuffer/WrappedCursor.py +487 -0
  290. pandaserver/taskbuffer/WrappedPickle.py +88 -0
  291. pandaserver/taskbuffer/WrappedPostgresConn.py +24 -0
  292. pandaserver/taskbuffer/__init__.py +0 -0
  293. pandaserver/taskbuffer/db_proxy_mods/OraDBProxy_structure.png +0 -0
  294. pandaserver/taskbuffer/db_proxy_mods/__init__.py +7 -0
  295. pandaserver/taskbuffer/db_proxy_mods/base_module.py +841 -0
  296. pandaserver/taskbuffer/db_proxy_mods/data_carousel_module.py +772 -0
  297. pandaserver/taskbuffer/db_proxy_mods/entity_module.py +3804 -0
  298. pandaserver/taskbuffer/db_proxy_mods/job_complex_module.py +5661 -0
  299. pandaserver/taskbuffer/db_proxy_mods/job_standalone_module.py +2640 -0
  300. pandaserver/taskbuffer/db_proxy_mods/metrics_module.py +874 -0
  301. pandaserver/taskbuffer/db_proxy_mods/misc_standalone_module.py +4272 -0
  302. pandaserver/taskbuffer/db_proxy_mods/task_complex_module.py +6172 -0
  303. pandaserver/taskbuffer/db_proxy_mods/task_event_module.py +4953 -0
  304. pandaserver/taskbuffer/db_proxy_mods/task_standalone_module.py +4999 -0
  305. pandaserver/taskbuffer/db_proxy_mods/task_utils_module.py +2063 -0
  306. pandaserver/taskbuffer/db_proxy_mods/worker_module.py +1944 -0
  307. pandaserver/taskbuffer/db_proxy_mods/workflow_module.py +832 -0
  308. pandaserver/taskbuffer/retryModule.py +552 -0
  309. pandaserver/taskbuffer/task_split_rules.py +308 -0
  310. pandaserver/taskbuffer/workflow_processor.py +249 -0
  311. pandaserver/taskbuffer/wrapped_oracle_conn.py +18 -0
  312. pandaserver/test/SchemaChecker.py +40 -0
  313. pandaserver/test/__init__.py +0 -0
  314. pandaserver/test/banUser.py +43 -0
  315. pandaserver/test/boostPrio.py +19 -0
  316. pandaserver/test/boostUser.py +35 -0
  317. pandaserver/test/callbackDDM.py +11 -0
  318. pandaserver/test/daod_on_demand.py +95 -0
  319. pandaserver/test/finishJob.py +184 -0
  320. pandaserver/test/finishTaskJEDI.py +11 -0
  321. pandaserver/test/getJobs.py +53 -0
  322. pandaserver/test/killJob.py +79 -0
  323. pandaserver/test/killJobLowPrio.py +99 -0
  324. pandaserver/test/killJobsInTask.py +56 -0
  325. pandaserver/test/killTask.py +80 -0
  326. pandaserver/test/killTaskJEDI.py +11 -0
  327. pandaserver/test/killUser.py +83 -0
  328. pandaserver/test/lsst/README.txt +7 -0
  329. pandaserver/test/lsst/lsstSubmit.py +139 -0
  330. pandaserver/test/lsst/lsstSubmitMERGEtest.py +141 -0
  331. pandaserver/test/lsst/lsstSubmitPhosim332.py +53 -0
  332. pandaserver/test/lsst/prepare-client-tarball-from-bigpanda-server.sh +41 -0
  333. pandaserver/test/reassignJobs.py +17 -0
  334. pandaserver/test/reassignSite.py +82 -0
  335. pandaserver/test/reassignTask.py +117 -0
  336. pandaserver/test/reassignWaiting.py +39 -0
  337. pandaserver/test/recoverLostFiles.py +7 -0
  338. pandaserver/test/reloadInputDS.py +51 -0
  339. pandaserver/test/sendCommandToJob.py +26 -0
  340. pandaserver/test/setDebugMode.py +38 -0
  341. pandaserver/test/setPriority.py +28 -0
  342. pandaserver/test/testEvgen.py +60 -0
  343. pandaserver/test/testEvgen17.py +58 -0
  344. pandaserver/test/testG4sim.py +81 -0
  345. pandaserver/test/testG4sim17.py +90 -0
  346. pandaserver/test/testGlobalShares.py +131 -0
  347. pandaserver/test/testReco.py +103 -0
  348. pandaserver/test/testSimulReco14.py +98 -0
  349. pandaserver/test/testSiteMap.py +26 -0
  350. pandaserver/test/testUpdateWorkerPilotStatus.py +9 -0
  351. pandaserver/userinterface/Client.py +1686 -0
  352. pandaserver/userinterface/UserIF.py +1799 -0
  353. pandaserver/userinterface/__init__.py +0 -0
  354. pandaserver/workflow/__init__.py +0 -0
  355. pandaserver/workflow/data_handler_plugins/base_data_handler.py +48 -0
  356. pandaserver/workflow/data_handler_plugins/ddm_collection_data_handler.py +100 -0
  357. pandaserver/workflow/data_handler_plugins/panda_task_data_handler.py +140 -0
  358. pandaserver/workflow/pcwl_test.py +122 -0
  359. pandaserver/workflow/pcwl_utils.py +384 -0
  360. pandaserver/workflow/psnakemake_container.json +68 -0
  361. pandaserver/workflow/psnakemake_task.json +62 -0
  362. pandaserver/workflow/psnakemake_test.py +60 -0
  363. pandaserver/workflow/snakeparser/__init__.py +3 -0
  364. pandaserver/workflow/snakeparser/extensions.py +74 -0
  365. pandaserver/workflow/snakeparser/log.py +53 -0
  366. pandaserver/workflow/snakeparser/names.py +3 -0
  367. pandaserver/workflow/snakeparser/parser.py +332 -0
  368. pandaserver/workflow/snakeparser/utils.py +29 -0
  369. pandaserver/workflow/step_handler_plugins/base_step_handler.py +85 -0
  370. pandaserver/workflow/step_handler_plugins/panda_task_step_handler.py +280 -0
  371. pandaserver/workflow/workflow_base.py +531 -0
  372. pandaserver/workflow/workflow_core.py +1974 -0
  373. pandaserver/workflow/workflow_core_smoketest.py +388 -0
  374. pandaserver/workflow/workflow_parser.py +222 -0
  375. pandaserver/workflow/workflow_utils.py +1047 -0
@@ -0,0 +1,381 @@
1
+ import random
2
+ import re
3
+
4
+ from pandacommon.pandalogger.PandaLogger import PandaLogger
5
+
6
+ from pandajedi.jedicore import Interaction
7
+ from pandajedi.jedicore.MsgWrapper import MsgWrapper
8
+ from pandajedi.jedicore.SiteCandidate import SiteCandidate
9
+ from pandajedi.jedirefine import RefinerUtils
10
+ from pandaserver.srvcore import CoreUtils
11
+
12
+ from . import AtlasBrokerUtils
13
+ from .JobBrokerBase import JobBrokerBase
14
+
15
+ logger = PandaLogger().getLogger(__name__.split(".")[-1])
16
+
17
+
18
+ # brokerage for general purpose
19
+ class GenJobBroker(JobBrokerBase):
20
+ # constructor
21
+ def __init__(self, ddmIF, taskBufferIF):
22
+ JobBrokerBase.__init__(self, ddmIF, taskBufferIF)
23
+
24
+ # main
25
+ def doBrokerage(self, taskSpec, cloudName, inputChunk, taskParamMap):
26
+ # make logger
27
+ tmpLog = MsgWrapper(logger, f"<jediTaskID={taskSpec.jediTaskID}>")
28
+ tmpLog.debug("start")
29
+ # return for failure
30
+ retFatal = self.SC_FATAL, inputChunk
31
+ retTmpError = self.SC_FAILED, inputChunk
32
+ # set cloud
33
+ try:
34
+ if not taskParamMap:
35
+ taskParam = self.taskBufferIF.getTaskParamsWithID_JEDI(taskSpec.jediTaskID)
36
+ taskParamMap = RefinerUtils.decodeJSON(taskParam)
37
+ if not taskSpec.cloud and "cloud" in taskParamMap:
38
+ taskSpec.cloud = taskParamMap["cloud"]
39
+ except Exception:
40
+ pass
41
+ # get sites in the cloud
42
+ site_preassigned = True
43
+ if taskSpec.site not in ["", None]:
44
+ tmpLog.debug(f"site={taskSpec.site} is pre-assigned")
45
+ if self.siteMapper.checkSite(taskSpec.site):
46
+ scanSiteList = [taskSpec.site]
47
+ else:
48
+ scanSiteList = []
49
+ for tmpSite in self.siteMapper.getCloud(taskSpec.cloud)["sites"]:
50
+ if re.search(taskSpec.site, tmpSite):
51
+ scanSiteList.append(tmpSite)
52
+ if not scanSiteList:
53
+ tmpLog.error(f"unknown site={taskSpec.site}")
54
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
55
+ return retTmpError
56
+ elif inputChunk.getPreassignedSite() is not None:
57
+ scanSiteList = [inputChunk.getPreassignedSite()]
58
+ tmpLog.debug(f"site={inputChunk.getPreassignedSite()} is pre-assigned in masterDS")
59
+ else:
60
+ site_preassigned = False
61
+ scanSiteList = self.siteMapper.getCloud(taskSpec.cloud)["sites"]
62
+ # remove NA
63
+ if "NA" in scanSiteList:
64
+ scanSiteList.remove("NA")
65
+ tmpLog.debug(f"cloud={taskSpec.cloud} has {len(scanSiteList)} candidates")
66
+ tmpLog.debug(f"initial {len(scanSiteList)} candidates")
67
+ ######################################
68
+ # selection for status and PandaSite
69
+ newScanSiteList = []
70
+ for tmpSiteName in scanSiteList:
71
+ tmpSiteSpec = self.siteMapper.getSite(tmpSiteName)
72
+ # check site status
73
+ if tmpSiteSpec.status != "online" and not site_preassigned:
74
+ tmpLog.debug(f" skip {tmpSiteName} due to status={tmpSiteSpec.status}")
75
+ continue
76
+ # check PandaSite
77
+ if "PandaSite" in taskParamMap and taskParamMap["PandaSite"]:
78
+ if tmpSiteSpec.pandasite != taskParamMap["PandaSite"]:
79
+ tmpLog.debug(f" skip {tmpSiteName} due to wrong PandaSite={tmpSiteSpec.pandasite} <> {taskParamMap['PandaSite']}")
80
+ continue
81
+ newScanSiteList.append(tmpSiteName)
82
+ scanSiteList = newScanSiteList
83
+ tmpLog.debug(f"{len(scanSiteList)} candidates passed site status check")
84
+ if scanSiteList == []:
85
+ tmpLog.error("no candidates")
86
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
87
+ return retTmpError
88
+ ######################################
89
+ # selection for scratch disk
90
+ minDiskCountS = taskSpec.getOutDiskSize() + taskSpec.getWorkDiskSize() + inputChunk.getMaxAtomSize()
91
+ minDiskCountS = minDiskCountS // 1024 // 1024
92
+ # size for direct IO sites
93
+ if taskSpec.useLocalIO():
94
+ minDiskCountR = minDiskCountS
95
+ else:
96
+ minDiskCountR = taskSpec.getOutDiskSize() + taskSpec.getWorkDiskSize()
97
+ minDiskCountR = minDiskCountR // 1024 // 1024
98
+ newScanSiteList = []
99
+ for tmpSiteName in scanSiteList:
100
+ tmpSiteSpec = self.siteMapper.getSite(tmpSiteName)
101
+ # check at the site
102
+ if tmpSiteSpec.maxwdir:
103
+ if CoreUtils.use_direct_io_for_job(taskSpec, tmpSiteSpec, inputChunk):
104
+ minDiskCount = minDiskCountR
105
+ else:
106
+ minDiskCount = minDiskCountS
107
+ if minDiskCount > tmpSiteSpec.maxwdir:
108
+ tmpLog.debug(f" skip {tmpSiteName} due to small scratch disk={tmpSiteSpec.maxwdir} < {minDiskCount}")
109
+ continue
110
+ newScanSiteList.append(tmpSiteName)
111
+ scanSiteList = newScanSiteList
112
+ tmpLog.debug(f"{len(scanSiteList)} candidates passed scratch disk check")
113
+ if scanSiteList == []:
114
+ tmpLog.error("no candidates")
115
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
116
+ return retTmpError
117
+ ######################################
118
+ # selection for available space in SE
119
+ newScanSiteList = []
120
+ for tmpSiteName in scanSiteList:
121
+ # check at the site
122
+ tmpSiteSpec = self.siteMapper.getSite(tmpSiteName)
123
+ # free space must be >= 200GB
124
+ diskThreshold = 200
125
+ tmpSpaceSize = tmpSiteSpec.space
126
+ if tmpSiteSpec.space and tmpSpaceSize < diskThreshold:
127
+ tmpLog.debug(f" skip {tmpSiteName} due to disk shortage in SE = {tmpSiteSpec.space} < {diskThreshold}GB")
128
+ continue
129
+ newScanSiteList.append(tmpSiteName)
130
+ scanSiteList = newScanSiteList
131
+ tmpLog.debug(f"{len(scanSiteList)} candidates passed SE space check")
132
+ if not scanSiteList:
133
+ tmpLog.error("no candidates")
134
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
135
+ return retTmpError
136
+ ######################################
137
+ # selection for walltime
138
+ minWalltime = taskSpec.walltime
139
+ if minWalltime not in [0, None]:
140
+ newScanSiteList = []
141
+ for tmpSiteName in scanSiteList:
142
+ tmpSiteSpec = self.siteMapper.getSite(tmpSiteName)
143
+ # check at the site
144
+ if tmpSiteSpec.maxtime != 0 and minWalltime > tmpSiteSpec.maxtime:
145
+ tmpLog.debug(f" skip {tmpSiteName} due to short site walltime={tmpSiteSpec.maxtime}(site upper limit) < {minWalltime}")
146
+ continue
147
+ if tmpSiteSpec.mintime != 0 and minWalltime < tmpSiteSpec.mintime:
148
+ tmpLog.debug(f" skip {tmpSiteName} due to short job walltime={tmpSiteSpec.mintime}(site lower limit) > {minWalltime}")
149
+ continue
150
+ newScanSiteList.append(tmpSiteName)
151
+ scanSiteList = newScanSiteList
152
+ tmpLog.debug(f"{len(scanSiteList)} candidates passed walltime check ={minWalltime}{taskSpec.walltimeUnit}")
153
+ if not scanSiteList:
154
+ tmpLog.error("no candidates")
155
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
156
+ return retTmpError
157
+ ######################################
158
+ # selection for MP
159
+ if taskSpec.coreCount is not None and taskSpec.coreCount >= 0:
160
+ if not site_preassigned:
161
+ newScanSiteList = []
162
+ for tmpSiteName in scanSiteList:
163
+ tmpSiteSpec = self.siteMapper.getSite(tmpSiteName)
164
+ # check at the site
165
+ is_ok = False
166
+ if taskSpec.coreCount == 0:
167
+ # any
168
+ is_ok = True
169
+ elif taskSpec.coreCount == 1:
170
+ # score
171
+ if tmpSiteSpec.coreCount in [0, 1, -1, None]:
172
+ is_ok = True
173
+ else:
174
+ # mcore
175
+ if tmpSiteSpec.coreCount in [0, -1]:
176
+ is_ok = True
177
+ elif tmpSiteSpec.coreCount and tmpSiteSpec.coreCount >= taskSpec.coreCount:
178
+ is_ok = True
179
+ if is_ok:
180
+ newScanSiteList.append(tmpSiteName)
181
+ else:
182
+ tmpLog.info(
183
+ f" skip site={tmpSiteName} due to core mismatch site:{tmpSiteSpec.coreCount} <> task:{taskSpec.coreCount} criteria=-cpucore"
184
+ )
185
+ scanSiteList = newScanSiteList
186
+ tmpLog.info(f"{len(scanSiteList)} candidates passed for core count check")
187
+ if not scanSiteList:
188
+ self.dump_summary(tmpLog)
189
+ tmpLog.error("no candidates")
190
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
191
+ return retTmpError
192
+ ######################################
193
+ # selection for memory
194
+ origMinRamCount = inputChunk.getMaxRamCount()
195
+ if not site_preassigned and origMinRamCount:
196
+ newScanSiteList = []
197
+ for tmpSiteName in scanSiteList:
198
+ tmpSiteSpec = self.siteMapper.getSite(tmpSiteName)
199
+ # job memory requirement
200
+ if taskSpec.ramPerCore():
201
+ if tmpSiteSpec.coreCount and tmpSiteSpec.coreCount > 0:
202
+ minRamCount = origMinRamCount * tmpSiteSpec.coreCount
203
+ else:
204
+ minRamCount = origMinRamCount * (taskSpec.coreCount if taskSpec.coreCount else 1)
205
+ minRamCount += taskSpec.baseRamCount if taskSpec.baseRamCount else 0
206
+ else:
207
+ minRamCount = origMinRamCount
208
+ # site max memory requirement
209
+ site_maxmemory = tmpSiteSpec.maxrss if tmpSiteSpec.maxrss else 0
210
+ # check at the site
211
+ if site_maxmemory and minRamCount and minRamCount > site_maxmemory:
212
+ tmpMsg = f" skip site={tmpSiteName} due to site RAM shortage. {site_maxmemory} (site upper limit) less than {minRamCount} "
213
+ tmpLog.debug(tmpMsg)
214
+ continue
215
+ # site min memory requirement
216
+ site_minmemory = tmpSiteSpec.minrss if tmpSiteSpec.minrss else 0
217
+ if site_minmemory and minRamCount and minRamCount < site_minmemory:
218
+ tmpMsg = f" skip site={tmpSiteName} due to job RAM shortage. {site_minmemory} (site lower limit) greater than {minRamCount} "
219
+ tmpLog.info(tmpMsg)
220
+ continue
221
+ newScanSiteList.append(tmpSiteName)
222
+ scanSiteList = newScanSiteList
223
+ tmpLog.debug(f"{len(scanSiteList)} candidates passed memory check")
224
+ if not scanSiteList:
225
+ tmpLog.error("no candidates")
226
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
227
+ return retTmpError
228
+ ######################################
229
+ # selection with processing types
230
+ newScanSiteList = []
231
+ for tmpSiteName in scanSiteList:
232
+ tmpSiteSpec = self.siteMapper.getSite(tmpSiteName)
233
+ allowed_list = tmpSiteSpec.get_allowed_processing_types()
234
+ exclude_list = tmpSiteSpec.get_excluded_processing_types()
235
+ if allowed_list is not None:
236
+ if taskSpec.processingType not in allowed_list:
237
+ tmpLog.debug(f" skip {tmpSiteName} due to processing type not in allowed list")
238
+ continue
239
+ if exclude_list is not None:
240
+ if taskSpec.processingType in exclude_list:
241
+ tmpLog.debug(f" skip {tmpSiteName} due to processing type in excluded list")
242
+ continue
243
+ newScanSiteList.append(tmpSiteName)
244
+ scanSiteList = newScanSiteList
245
+ tmpLog.debug(f"{len(scanSiteList)} candidates passed allowed/excluded processing type check")
246
+ if not scanSiteList:
247
+ tmpLog.error("no candidates")
248
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
249
+ return retTmpError
250
+ ######################################
251
+ # selection for nPilot
252
+ nWNmap = self.taskBufferIF.getCurrentSiteData()
253
+ newScanSiteList = []
254
+ for tmpSiteName in scanSiteList:
255
+ tmp_site_spec = self.siteMapper.getSite(tmpSiteName)
256
+ # check at the site
257
+ nPilot = 0
258
+ if tmpSiteName in nWNmap:
259
+ nPilot = nWNmap[tmpSiteName]["getJob"] + nWNmap[tmpSiteName]["updateJob"]
260
+ if nPilot == 0 and taskSpec.prodSourceLabel not in ["test"] and not tmp_site_spec.hasValueInCatchall("allow_no_pilot"):
261
+ tmpLog.debug(f" skip {tmpSiteName} due to no pilot")
262
+ continue
263
+ newScanSiteList.append(tmpSiteName)
264
+ scanSiteList = newScanSiteList
265
+ tmpLog.debug(f"{len(scanSiteList)} candidates passed pilot activity check")
266
+ if scanSiteList == []:
267
+ tmpLog.error("no candidates")
268
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
269
+ return retTmpError
270
+ ######################################
271
+ # sites already used by task
272
+ tmpSt, sitesUsedByTask = self.taskBufferIF.getSitesUsedByTask_JEDI(taskSpec.jediTaskID)
273
+ if not tmpSt:
274
+ tmpLog.error("failed to get sites which already used by task")
275
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
276
+ return retTmpError
277
+ ######################################
278
+ # get list of available files
279
+ availableFileMap = {}
280
+ for datasetSpec in inputChunk.getDatasets():
281
+ try:
282
+ # get list of site to be scanned
283
+ tmpLog.debug(f"getting the list of available files for {datasetSpec.datasetName}")
284
+ fileScanSiteList = []
285
+ for tmpPseudoSiteName in scanSiteList:
286
+ tmpSiteSpec = self.siteMapper.getSite(tmpPseudoSiteName)
287
+ tmpSiteName = tmpSiteSpec.get_unified_name()
288
+ if tmpSiteName in fileScanSiteList:
289
+ continue
290
+ fileScanSiteList.append(tmpSiteName)
291
+ # mapping between sites and input storage endpoints
292
+ siteStorageEP = AtlasBrokerUtils.getSiteInputStorageEndpointMap(fileScanSiteList, self.siteMapper, taskSpec.prodSourceLabel, None)
293
+ # disable file lookup for merge jobs
294
+ if inputChunk.isMerging:
295
+ checkCompleteness = False
296
+ else:
297
+ checkCompleteness = True
298
+ if not datasetSpec.isMaster():
299
+ useCompleteOnly = True
300
+ else:
301
+ useCompleteOnly = False
302
+ # get available files per site/endpoint
303
+ tmpAvFileMap = self.ddmIF.getAvailableFiles(
304
+ datasetSpec,
305
+ siteStorageEP,
306
+ self.siteMapper,
307
+ check_completeness=checkCompleteness,
308
+ file_scan_in_container=False,
309
+ complete_only=useCompleteOnly,
310
+ use_deep=True,
311
+ )
312
+ if tmpAvFileMap is None:
313
+ raise Interaction.JEDITemporaryError("ddmIF.getAvailableFiles failed")
314
+ availableFileMap[datasetSpec.datasetName] = tmpAvFileMap
315
+ except Exception as e:
316
+ tmpLog.error(f"failed to get available files with {e}")
317
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
318
+ return retTmpError
319
+ ######################################
320
+ # calculate weight
321
+ tmpSt, jobStatPrioMap = self.taskBufferIF.getJobStatisticsByGlobalShare(taskSpec.vo)
322
+ if not tmpSt:
323
+ tmpLog.error("failed to get job statistics with priority")
324
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
325
+ return retTmpError
326
+ ######################################
327
+ # final procedure
328
+ tmpLog.debug(f"final {len(scanSiteList)} candidates")
329
+ weightMap = {}
330
+ candidateSpecList = []
331
+ preSiteCandidateSpec = None
332
+ for tmpSiteName in scanSiteList:
333
+ # get number of jobs in each job status. Using workQueueID=None to include non-JEDI jobs
334
+ nRunning = AtlasBrokerUtils.getNumJobs(jobStatPrioMap, tmpSiteName, "running", None, None)
335
+ nAssigned = AtlasBrokerUtils.getNumJobs(jobStatPrioMap, tmpSiteName, "defined", None, None)
336
+ nActivated = AtlasBrokerUtils.getNumJobs(jobStatPrioMap, tmpSiteName, "activated", None, None)
337
+ weight = float(nRunning + 1) / float(nActivated + nAssigned + 1) / float(nAssigned + 1)
338
+ # make candidate
339
+ siteCandidateSpec = SiteCandidate(tmpSiteName)
340
+ # set weight
341
+ siteCandidateSpec.weight = weight
342
+ # files
343
+ for tmpDatasetName, availableFiles in availableFileMap.items():
344
+ if tmpSiteName in availableFiles:
345
+ siteCandidateSpec.add_local_disk_files(availableFiles[tmpSiteName]["localdisk"])
346
+ # append
347
+ if tmpSiteName in sitesUsedByTask:
348
+ candidateSpecList.append(siteCandidateSpec)
349
+ else:
350
+ if weight not in weightMap:
351
+ weightMap[weight] = []
352
+ weightMap[weight].append(siteCandidateSpec)
353
+ # limit the number of sites
354
+ maxNumSites = 5
355
+ weightList = sorted(weightMap.keys())
356
+ weightList.reverse()
357
+ for weightVal in weightList:
358
+ if len(candidateSpecList) >= maxNumSites:
359
+ break
360
+ sitesWithWeight = weightMap[weightVal]
361
+ random.shuffle(sitesWithWeight)
362
+ candidateSpecList += sitesWithWeight[: (maxNumSites - len(candidateSpecList))]
363
+ # collect site names
364
+ scanSiteList = []
365
+ for siteCandidateSpec in candidateSpecList:
366
+ scanSiteList.append(siteCandidateSpec.siteName)
367
+ # append candidates
368
+ newScanSiteList = []
369
+ for siteCandidateSpec in candidateSpecList:
370
+ # append
371
+ inputChunk.addSiteCandidate(siteCandidateSpec)
372
+ newScanSiteList.append(siteCandidateSpec.siteName)
373
+ tmpLog.debug(f" use {siteCandidateSpec.siteName} with weight={siteCandidateSpec.weight} nFiles={len(siteCandidateSpec.localDiskFiles)}")
374
+ scanSiteList = newScanSiteList
375
+ if scanSiteList == []:
376
+ tmpLog.error("no candidates")
377
+ taskSpec.setErrDiag(tmpLog.uploadLog(taskSpec.jediTaskID))
378
+ return retTmpError
379
+ # return
380
+ tmpLog.debug("done")
381
+ return self.SC_SUCCEEDED, inputChunk
@@ -0,0 +1,133 @@
1
+ import math
2
+ from typing import Any
3
+
4
+ from pandajedi.jedicore import Interaction
5
+
6
+
7
+ # base class for job brokerage
8
+ class JobBrokerBase(object):
9
+ def __init__(self, ddmIF, taskBufferIF):
10
+ self.ddmIF = ddmIF
11
+ self.taskBufferIF = taskBufferIF
12
+ self.liveCounter = None
13
+ self.lockID = None
14
+ self.baseLockID = None
15
+ self.useLock = False
16
+ self.testMode = False
17
+ self.refresh()
18
+ self.task_common = None
19
+ self.summaryList = None
20
+
21
+ # set task common dictionary
22
+ def set_task_common_dict(self, task_common):
23
+ self.task_common = task_common
24
+
25
+ # get task common attribute
26
+ def get_task_common(self, attr_name):
27
+ if self.task_common:
28
+ return self.task_common.get(attr_name)
29
+
30
+ # set task common attribute
31
+ def set_task_common(self, attr_name, attr_value):
32
+ self.task_common[attr_name] = attr_value
33
+
34
+ def refresh(self):
35
+ self.siteMapper = self.taskBufferIF.get_site_mapper()
36
+
37
+ def setLiveCounter(self, liveCounter):
38
+ self.liveCounter = liveCounter
39
+
40
+ def getLiveCount(self, siteName):
41
+ if self.liveCounter is None:
42
+ return 0
43
+ return self.liveCounter.get(siteName)
44
+
45
+ def setLockID(self, pid, tid):
46
+ self.baseLockID = f"{pid}-jbr"
47
+ self.lockID = f"{self.baseLockID}-{tid}"
48
+
49
+ def getBaseLockID(self):
50
+ if self.useLock:
51
+ return self.baseLockID
52
+ return None
53
+
54
+ def checkSiteLock(self, vo, prodSourceLabel, siteName, queue_id, resource_name):
55
+ return self.taskBufferIF.checkProcessLock_JEDI(
56
+ vo=vo,
57
+ prodSourceLabel=prodSourceLabel,
58
+ cloud=siteName,
59
+ workqueue_id=queue_id,
60
+ resource_name=resource_name,
61
+ component=None,
62
+ pid=self.baseLockID,
63
+ checkBase=True,
64
+ )
65
+
66
+ def setTestMode(self):
67
+ self.testMode = True
68
+
69
+ # get list of unified sites
70
+ def get_unified_sites(self, scan_site_list):
71
+ unified_list = set()
72
+ for tmpSiteName in scan_site_list:
73
+ tmpSiteSpec = self.siteMapper.getSite(tmpSiteName)
74
+ unifiedName = tmpSiteSpec.get_unified_name()
75
+ unified_list.add(unifiedName)
76
+ return tuple(unified_list)
77
+
78
+ # get list of pseudo sites
79
+ def get_pseudo_sites(self, unified_list, scan_site_list):
80
+ unified_list = set(unified_list)
81
+ pseudo_list = set()
82
+ for tmpSiteName in scan_site_list:
83
+ tmpSiteSpec = self.siteMapper.getSite(tmpSiteName)
84
+ if tmpSiteSpec.get_unified_name() in unified_list:
85
+ pseudo_list.add(tmpSiteName)
86
+ return tuple(pseudo_list)
87
+
88
+ # add pseudo sites to skip
89
+ def add_pseudo_sites_to_skip(self, unified_dict, scan_site_list, skipped_dict):
90
+ for tmpSiteName in scan_site_list:
91
+ tmpSiteSpec = self.siteMapper.getSite(tmpSiteName)
92
+ if tmpSiteSpec.get_unified_name() in unified_dict:
93
+ skipped_dict[tmpSiteName] = unified_dict[tmpSiteSpec.get_unified_name()]
94
+ return skipped_dict
95
+
96
+ # init summary list
97
+ def init_summary_list(self, header, comment, initial_list):
98
+ self.summaryList = []
99
+ self.summaryList.append(f"===== {header} =====")
100
+ if comment:
101
+ self.summaryList.append(comment)
102
+ self.summaryList.append(f"the number of initial candidates: {len(initial_list)}")
103
+
104
+ # dump summary
105
+ def dump_summary(self, tmp_log, final_candidates=None):
106
+ if not self.summaryList:
107
+ return
108
+ tmp_log.info("")
109
+ for m in self.summaryList:
110
+ tmp_log.info(m)
111
+ if not final_candidates:
112
+ final_candidates = []
113
+ tmp_log.info(f"the number of final candidates: {len(final_candidates)}")
114
+ tmp_log.info("")
115
+
116
+ # add summary entry and show intermediate message
117
+ def add_summary_message(self, old_list: list, new_list: list, message: str, tmp_log: Any, msg_map: dict):
118
+ # consolidate lists to emit messages only for unified sites
119
+ old_list = self.get_unified_sites(old_list)
120
+ new_list = self.get_unified_sites(new_list)
121
+ # get skipped sites
122
+ skipped = [i for i in old_list if i not in new_list]
123
+ for skipped_site in skipped:
124
+ if skipped_site in msg_map:
125
+ tmp_log.info(msg_map[skipped_site])
126
+ tmp_log.info(f"{len(new_list)} candidates passed {message}")
127
+ # add a summary entry
128
+ if old_list and len(old_list) != len(new_list):
129
+ red = int(math.ceil(((len(old_list) - len(new_list)) * 100) / len(old_list)))
130
+ self.summaryList.append(f"{len(old_list):>5} -> {len(new_list):>3} candidates, {red:>3}% cut : {message}")
131
+
132
+
133
+ Interaction.installSC(JobBrokerBase)
@@ -0,0 +1,15 @@
1
+ from pandajedi.jedicore import Interaction
2
+
3
+
4
+ # base class for task brokerge
5
+ class TaskBrokerBase(object):
6
+ def __init__(self, taskBufferIF, ddmIF):
7
+ self.ddmIF = ddmIF
8
+ self.taskBufferIF = taskBufferIF
9
+ self.refresh()
10
+
11
+ def refresh(self):
12
+ self.siteMapper = self.taskBufferIF.get_site_mapper()
13
+
14
+
15
+ Interaction.installSC(TaskBrokerBase)
File without changes
File without changes
@@ -0,0 +1,40 @@
1
+ import json
2
+ import os
3
+ import sys
4
+
5
+ from liveconfigparser.LiveConfigParser import LiveConfigParser, expand_values
6
+
7
+ # get ConfigParser
8
+ tmp_conf = LiveConfigParser()
9
+
10
+ # read
11
+ tmp_conf.read("panda_jedi.cfg")
12
+
13
+
14
+ # dummy section class
15
+ class _SectionClass:
16
+ pass
17
+
18
+
19
+ # load configmap
20
+ config_map_data = {}
21
+ if "PANDA_HOME" in os.environ:
22
+ config_map_name = "panda_jedi_config.json"
23
+ config_map_path = os.path.join(os.environ["PANDA_HOME"], "etc/config_json", config_map_name)
24
+ if os.path.exists(config_map_path):
25
+ with open(config_map_path) as f:
26
+ config_map_data = json.load(f)
27
+
28
+ # loop over all sections
29
+ for tmp_section in tmp_conf.sections():
30
+ # read section
31
+ tmp_dict = getattr(tmp_conf, tmp_section)
32
+ # load configmap
33
+ if tmp_section in config_map_data:
34
+ tmp_dict.update(config_map_data[tmp_section])
35
+ # make section class
36
+ tmp_self = _SectionClass()
37
+ # update module dict
38
+ sys.modules[__name__].__dict__[tmp_section] = tmp_self
39
+ # expand all values
40
+ expand_values(tmp_self, tmp_dict)