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,185 @@
1
+ import gc
2
+ import json
3
+ import time
4
+
5
+ from pandacommon.pandalogger import logger_utils
6
+ from pandacommon.pandautils.PandaUtils import try_malloc_trim
7
+
8
+ from pandajedi.jedicore.ThreadUtils import ListWithLock
9
+ from pandajedi.jediddm.DDMInterface import DDMInterface
10
+ from pandajedi.jedimsgprocessor.base_msg_processor import BaseMsgProcPlugin
11
+ from pandajedi.jediorder.JobGenerator import JobGeneratorThread, get_params_to_get_tasks
12
+ from pandajedi.jediorder.TaskSetupper import TaskSetupper
13
+ from pandaserver.srvcore import CoreUtils
14
+
15
+ base_logger = logger_utils.setup_logger(__name__.split(".")[-1])
16
+
17
+
18
+ # Jedi Job Generator message processor plugin
19
+ class JediJobGeneratorMsgProcPlugin(BaseMsgProcPlugin):
20
+ """
21
+ Message-driven Job Generator
22
+ """
23
+
24
+ def initialize(self):
25
+ BaseMsgProcPlugin.initialize(self)
26
+ # DDM interface
27
+ self.ddmIF = DDMInterface()
28
+ self.ddmIF.setupInterface()
29
+ self.task_setupper_map = {}
30
+ # cache heavy metadata objects with short TTL to reduce allocation churn
31
+ self._cache_ttl_sec = 300
32
+ self._site_mapper = None
33
+ self._site_mapper_ts = 0
34
+ self._work_queue_mapper = None
35
+ self._work_queue_mapper_ts = 0
36
+ self._resource_types = None
37
+ self._resource_types_ts = 0
38
+ self._params_to_get_tasks = {}
39
+ # memory limit to trigger early cleanup to avoid OOM killer. This is not a hard limit, just a threshold to trigger early cleanup.
40
+ self._mem_usage_threshold_mb = 1500
41
+ # get SiteMapper
42
+ # siteMapper = self.tbIF.get_site_mapper()
43
+ # get work queue mapper
44
+ # workQueueMapper = self.tbIF.getWorkQueueMap()
45
+ # get TaskSetupper
46
+ # taskSetupper = TaskSetupper(self.vos, self.prodSourceLabels)
47
+ # taskSetupper.initializeMods(self.tbIF, self.ddmIF)
48
+ self.pid = self.get_pid()
49
+
50
+ def _is_cache_valid(self, ts):
51
+ return (time.time() - ts) < self._cache_ttl_sec
52
+
53
+ def _get_site_mapper(self):
54
+ if self._site_mapper is None or not self._is_cache_valid(self._site_mapper_ts):
55
+ self._site_mapper = self.tbIF.get_site_mapper()
56
+ self._site_mapper_ts = time.time()
57
+ return self._site_mapper
58
+
59
+ def _get_work_queue_mapper(self):
60
+ if self._work_queue_mapper is None or not self._is_cache_valid(self._work_queue_mapper_ts):
61
+ self._work_queue_mapper = self.tbIF.getWorkQueueMap()
62
+ self._work_queue_mapper_ts = time.time()
63
+ return self._work_queue_mapper
64
+
65
+ def _get_resource_types(self):
66
+ if self._resource_types is None or not self._is_cache_valid(self._resource_types_ts):
67
+ self._resource_types = self.tbIF.load_resource_types()
68
+ self._resource_types_ts = time.time()
69
+ return self._resource_types
70
+
71
+ def process(self, msg_obj):
72
+ tmp_log = logger_utils.make_logger(base_logger, token=self.get_pid(), method_name="process")
73
+ input_list = None
74
+ gen_thr = None
75
+ tmp_list = None
76
+ taskSpec = None
77
+ taskSetupper = None
78
+ # start
79
+ tmp_log.info("start")
80
+ tmp_log.debug(f"sub_id={msg_obj.sub_id} ; msg_id={msg_obj.msg_id}")
81
+ # parse json
82
+ try:
83
+ msg_dict = json.loads(msg_obj.data)
84
+ except Exception as e:
85
+ err_str = f"failed to parse message json {msg_obj.data} , skipped. {e.__class__.__name__} : {e}"
86
+ tmp_log.error(err_str)
87
+ raise
88
+ # sanity check
89
+ try:
90
+ msg_type = msg_dict["msg_type"]
91
+ except Exception as e:
92
+ err_str = f"failed to parse message object dict {msg_dict} , skipped. {e.__class__.__name__} : {e}"
93
+ tmp_log.error(err_str)
94
+ raise
95
+ if msg_type != "jedi_job_generator":
96
+ # FIXME
97
+ err_str = f"got unknown msg_type {msg_type} , skipped"
98
+ tmp_log.error(err_str)
99
+ raise
100
+ # run
101
+ try:
102
+ # get task to generate jobs
103
+ task_id = int(msg_dict["taskid"])
104
+ _, taskSpec = self.tbIF.getTaskWithID_JEDI(task_id)
105
+ if not taskSpec:
106
+ tmp_log.debug(f"unknown task_id={task_id}, skipped")
107
+ else:
108
+ tmp_log.debug(f"processing task_id={task_id} workqueue_id={taskSpec.workQueue_ID} status={taskSpec.status}")
109
+ # get WQ
110
+ vo = taskSpec.vo
111
+ prodSourceLabel = taskSpec.prodSourceLabel
112
+ workQueue = self._get_work_queue_mapper().getQueueWithIDGshare(taskSpec.workQueue_ID, taskSpec.gshare)
113
+ # get resource types
114
+ resource_types = self._get_resource_types()
115
+ if not resource_types:
116
+ raise RuntimeError("failed to get resource types")
117
+ # nFiles from shared JobGenerator config resolver
118
+ tmp_params = get_params_to_get_tasks(
119
+ self.tbIF, self._params_to_get_tasks, vo, prodSourceLabel, workQueue.queue_name if workQueue else "", taskSpec.cloud
120
+ )
121
+ nFiles = tmp_params["nFiles"]
122
+ # get inputs
123
+ tmp_list = self.tbIF.getTasksToBeProcessed_JEDI(self.pid, None, workQueue, None, None, nFiles=nFiles, target_tasks=[task_id])
124
+ if tmp_list:
125
+ input_list = ListWithLock(tmp_list)
126
+ # run generator inline to avoid creating an extra worker thread.
127
+ siteMapper = self._get_site_mapper()
128
+ setupper_key = (vo, prodSourceLabel)
129
+ taskSetupper = self.task_setupper_map.get(setupper_key)
130
+ if taskSetupper is None:
131
+ taskSetupper = TaskSetupper(vo, prodSourceLabel)
132
+ taskSetupper.initializeMods(self.tbIF, self.ddmIF)
133
+ self.task_setupper_map[setupper_key] = taskSetupper
134
+ # log memory usage before running job generator to help identify if this is a source of memory bloat.
135
+ gen_thr = JobGeneratorThread(
136
+ input_list,
137
+ None,
138
+ self.tbIF,
139
+ self.ddmIF,
140
+ siteMapper,
141
+ True,
142
+ taskSetupper,
143
+ self.pid,
144
+ workQueue,
145
+ "pjmsg",
146
+ None,
147
+ None,
148
+ None,
149
+ False,
150
+ resource_types,
151
+ )
152
+ gen_thr.run()
153
+ tmp_log.info(f"task_id={task_id} generated jobs")
154
+ else:
155
+ tmp_log.debug(f"task_id={task_id} is not considered to be processed, skipped")
156
+ except Exception as e:
157
+ err_str = f"failed to run, skipped. {e.__class__.__name__} : {e}"
158
+ tmp_log.error(err_str)
159
+ raise
160
+ finally:
161
+ # Explicitly clear large per-run maps to release references as early as possible.
162
+ if gen_thr is not None:
163
+ try:
164
+ gen_thr.buildSpecMap.clear()
165
+ gen_thr.finished_lib_specs_map.clear()
166
+ gen_thr.active_lib_specs_map.clear()
167
+ gen_thr.inputList = None
168
+ except Exception:
169
+ pass
170
+ gen_thr = None
171
+ input_list = None
172
+ tmp_list = None
173
+ taskSpec = None
174
+ taskSetupper = None
175
+ # If memory usage is above the threshold, trigger early cleanup to avoid OOM killer.
176
+ mem_usage = CoreUtils.getMemoryUsage()
177
+ if mem_usage is None:
178
+ tmp_log.warning("failed to get memory usage, skipped memory cleanup")
179
+ elif mem_usage > self._mem_usage_threshold_mb:
180
+ gc.collect()
181
+ try_malloc_trim(tmp_log)
182
+ new_mem_usage = CoreUtils.getMemoryUsage()
183
+ tmp_log.debug(f"trimmed memory usage from {mem_usage} MB to {new_mem_usage} MB")
184
+ # done
185
+ tmp_log.info("done")
@@ -0,0 +1,82 @@
1
+ import json
2
+
3
+ from pandacommon.pandalogger import logger_utils
4
+
5
+ from pandajedi.jediconfig import jedi_config
6
+ from pandajedi.jedicore.FactoryBase import FactoryBase
7
+ from pandajedi.jediddm.DDMInterface import DDMInterface
8
+ from pandajedi.jedimsgprocessor.base_msg_processor import BaseMsgProcPlugin
9
+ from pandajedi.jediorder.PostProcessor import PostProcessorThread
10
+ from pandaserver.srvcore.CoreUtils import convert_config_params, parse_init_params
11
+
12
+ base_logger = logger_utils.setup_logger(__name__.split(".")[-1])
13
+
14
+
15
+ # Jedi Post-Processor message processor plugin
16
+ class JediPostProcessorMsgProcPlugin(BaseMsgProcPlugin):
17
+ """
18
+ Message-driven Post-Processor
19
+ """
20
+
21
+ def initialize(self):
22
+ BaseMsgProcPlugin.initialize(self)
23
+ # DDM interface
24
+ ddmIF = DDMInterface()
25
+ ddmIF.setupInterface()
26
+ # factory bases and post processor thread object for all vos and prodsourcelabels
27
+ self.post_processor_thread_dict = dict()
28
+ for itemStr in jedi_config.postprocessor.procConfig.split(";"):
29
+ items = convert_config_params(itemStr)
30
+ vos = parse_init_params(items[0])
31
+ prodsourcelabels = parse_init_params(items[1])
32
+ tmp_factory_base_obj = FactoryBase(vos=vos, sourceLabels=prodsourcelabels, logger=base_logger, modConfig=jedi_config.postprocessor.modConfig)
33
+ tmp_post_processor_thread_obj = PostProcessorThread(
34
+ taskList=None, threadPool=None, taskbufferIF=self.tbIF, ddmIF=ddmIF, implFactory=tmp_factory_base_obj
35
+ )
36
+ for vo in vos:
37
+ for prodsourcelabel in prodsourcelabels:
38
+ self.post_processor_thread_dict[(vo, prodsourcelabel)] = tmp_post_processor_thread_obj
39
+
40
+ def process(self, msg_obj):
41
+ tmp_log = logger_utils.make_logger(base_logger, token=self.get_pid(), method_name="process")
42
+ # start
43
+ tmp_log.info("start")
44
+ tmp_log.debug(f"sub_id={msg_obj.sub_id} ; msg_id={msg_obj.msg_id}")
45
+ # parse json
46
+ try:
47
+ msg_dict = json.loads(msg_obj.data)
48
+ except Exception as e:
49
+ err_str = f"failed to parse message json {msg_obj.data} , skipped. {e.__class__.__name__} : {e}"
50
+ tmp_log.error(err_str)
51
+ raise
52
+ # sanity check
53
+ try:
54
+ msg_type = msg_dict["msg_type"]
55
+ except Exception as e:
56
+ err_str = f"failed to parse message object dict {msg_dict} , skipped. {e.__class__.__name__} : {e}"
57
+ tmp_log.error(err_str)
58
+ raise
59
+ if msg_type != "jedi_post_processor":
60
+ # FIXME
61
+ err_str = f"got unknown msg_type {msg_type} , skipped "
62
+ tmp_log.error(err_str)
63
+ raise
64
+ # run
65
+ try:
66
+ task_id = msg_dict["taskid"]
67
+ vo = msg_dict["task_vo"]
68
+ prodsourcelabel = msg_dict["task_prodsourcelabel"]
69
+ ret_list = self.tbIF.prepareTasksToBeFinished_JEDI(vo, prodSourceLabel, jedi_config.postprocessor.nTasks, self.get_pid())
70
+ task_list = self.tbIF.getTasksToBeFinished_JEDI(vo, prodSourceLabel, self.get_pid(), jedi_config.postprocessor.nTasks, target_tasks=ret_list)
71
+ if task_list and task_id in [task_spec.jediTaskID for task_spec in task_list]:
72
+ tmp_post_processor_thread_obj = self.post_processor_thread_dict[(vo, prodsourcelabel)]
73
+ tmp_post_processor_thread_obj.post_process_tasks(task_list)
74
+ tmp_log.info(f"post processed tasks {task_list} including {task_id}")
75
+ else:
76
+ tmp_log.debug(f"did not get task {task_id}; skip ")
77
+ except Exception as e:
78
+ err_str = f"failed to run, skipped. {e.__class__.__name__} : {e}"
79
+ tmp_log.error(err_str)
80
+ raise
81
+ # done
82
+ tmp_log.info("done")
@@ -0,0 +1,44 @@
1
+ import json
2
+
3
+ from pandacommon.kafkapublisher.KafkaPublisher import KafkaPublisher
4
+ from pandacommon.pandalogger import logger_utils
5
+
6
+ from pandajedi.jedimsgprocessor.base_msg_processor import BaseMsgProcPlugin
7
+
8
+ base_logger = logger_utils.setup_logger(__name__.split(".")[-1])
9
+
10
+
11
+ # Kafka message processing plugin
12
+ class KafkaMsgProcPlugin(BaseMsgProcPlugin):
13
+ def initialize(self):
14
+ """
15
+ initialize plugin instance, run once before loop in thread
16
+ """
17
+ self.publisher = KafkaPublisher()
18
+
19
+ def process(self, msg_obj, decoded_data=None):
20
+ tmp_log = logger_utils.make_logger(base_logger, token=self.get_pid(), method_name="process")
21
+
22
+ # start
23
+ tmp_log.info("start")
24
+ tmp_log.debug(f"sub_id={msg_obj.sub_id} ; msg_id={msg_obj.msg_id}")
25
+
26
+ # Parse and access the message content from msg_obj.data
27
+ if decoded_data is None:
28
+ # json decode
29
+ try:
30
+ message_content = json.loads(msg_obj.data)
31
+ except Exception as e:
32
+ err_str = f"failed to parse message json {msg_obj.data} , skipped. {e.__class__.__name__} : {e}"
33
+ tmp_log.error(err_str)
34
+ raise
35
+ else:
36
+ message_content = decoded_data
37
+
38
+ # Publish the message to Kafka
39
+ self.publisher.publish_message(message_content)
40
+ tmp_log.debug(f"sent {message_content}")
41
+ tmp_log.info("done")
42
+
43
+ def terminate(self):
44
+ self.publisher.close()
@@ -0,0 +1,182 @@
1
+ import re
2
+ import traceback
3
+
4
+ import yaml
5
+ from pandacommon.pandalogger import LogWrapper, logger_utils
6
+
7
+ from pandajedi.jedimsgprocessor.base_msg_processor import BaseMsgProcPlugin
8
+ from pandaserver.dataservice.ddm_handler import DDMHandler
9
+
10
+ base_logger = logger_utils.setup_logger(__name__.split(".")[-1])
11
+
12
+
13
+ # panda dataset callback message processing plugin
14
+ class PandaCallbackMsgProcPlugin(BaseMsgProcPlugin):
15
+
16
+ def __init__(self, **params):
17
+ super().__init__(**params)
18
+ self.activities_with_file_callback = []
19
+ self.component_action_map = []
20
+ self.site_mapper = None
21
+ self.verbose = False
22
+
23
+ def initialize(self, **params):
24
+ BaseMsgProcPlugin.initialize(self, **params)
25
+ # activity list to use file callback
26
+ self.activities_with_file_callback = self.params.get("activities_with_file_callback", [])
27
+ # component action map
28
+ # [{"event_type": "<event_type>", "component": "<component_name>", "criteria": {"key": <value>,}, "to_id": "<how_to_get_task_id>}, ...]
29
+ self.component_action_map = self.params.get("component_action_map", [])
30
+ # site mapper
31
+ self.site_mapper = self.tbIF.get_site_mapper()
32
+ # verbose logging
33
+ self.verbose = self.params.get("verbose", False)
34
+
35
+ def process(self, msg_obj):
36
+ tmp_log = logger_utils.make_logger(base_logger, token=self.get_pid(), method_name="process")
37
+ # start
38
+ # tmp_log.info('start')
39
+ # tmp_log.debug('sub_id={0} ; msg_id={1}'.format(msg_obj.sub_id, msg_obj.msg_id))
40
+ # parse yaml
41
+ try:
42
+ message_dict = yaml.safe_load(msg_obj.data)
43
+ except Exception as e:
44
+ err_str = f"failed to parse message yaml {msg_obj.data} , skipped. {e.__class__.__name__} : {e}"
45
+ tmp_log.error(err_str)
46
+ raise
47
+ # run
48
+ try:
49
+ to_continue = True
50
+ dsn = "UNKNOWN"
51
+ # check event type
52
+ if not isinstance(message_dict, dict):
53
+ err_str = f"skip due to invalid message format:{type(message_dict).__name__}. msg:{str(message_dict)}"
54
+ tmp_log.warning(err_str)
55
+ return
56
+ event_type = message_dict["event_type"]
57
+ message_ids = f"sub_id={msg_obj.sub_id} ; msg_id={msg_obj.msg_id}"
58
+ if event_type in ["datasetlock_ok"]:
59
+ self.process_dataset_callback(event_type, message_ids, message_dict, tmp_log)
60
+ elif self.activities_with_file_callback and event_type in ["transfer-done"]:
61
+ self.process_file_callback(event_type, message_ids, message_dict, tmp_log)
62
+ else:
63
+ if self.verbose:
64
+ tmp_log.debug(f"skip event_type={event_type}")
65
+ # trigger component actions
66
+ if self.component_action_map:
67
+ self.trigger_component_action(event_type, message_ids, message_dict, tmp_log)
68
+ # end
69
+ except Exception as e:
70
+ err_str = f"failed to run, skipped. {e.__class__.__name__} : {e}\n{traceback.format_exc()}"
71
+ tmp_log.error(err_str)
72
+ raise
73
+
74
+ def process_dataset_callback(self, event_type: str, message_ids: str, message_dict: dict, tmp_log: LogWrapper.LogWrapper) -> None:
75
+ """
76
+ Process a dataset callback
77
+
78
+ Args:
79
+ event_type: message event type
80
+ message_ids: subscription and message IDs
81
+ message_dict: message dictionary
82
+ tmp_log: logger instance
83
+ """
84
+ message_payload = message_dict["payload"]
85
+ # only for _dis or _sub
86
+ dsn = message_payload["name"]
87
+ if (re.search(r"_dis\d+$", dsn) is None) and (re.search(r"_sub\d+$", dsn) is None):
88
+ return
89
+ tmp_log.debug(message_ids)
90
+ tmp_log.debug(f"{event_type} start")
91
+ # take action
92
+ scope = message_payload["scope"]
93
+ site = message_payload["rse"]
94
+ tmp_log.debug(f"{dsn} site={site} type={event_type}")
95
+ thr = DDMHandler(task_buffer=self.tbIF, vuid=None, site=site, dataset=dsn, scope=scope)
96
+ # just call run rather than start+join, to run it in main thread instead of spawning new thread
97
+ thr.run()
98
+ del thr
99
+ tmp_log.debug(f"done {dsn}")
100
+ return
101
+
102
+ def process_file_callback(self, event_type: str, message_ids: str, message_dict: dict, tmp_log: LogWrapper.LogWrapper) -> None:
103
+ """
104
+ Process a file callback
105
+
106
+ Args:
107
+ event_type: message event type
108
+ message_ids: subscription and message IDs
109
+ message_dict: message dictionary
110
+ tmp_log: logger instance
111
+ """
112
+ message_payload = message_dict["payload"]
113
+ # only for activities with file callback
114
+ activity = message_payload["activity"]
115
+ if activity not in self.activities_with_file_callback:
116
+ return
117
+ # update file status and get corresponding PandaIDs
118
+ filename = message_payload["name"]
119
+ endpoint = message_payload["dst-rse"]
120
+ tmp_log.debug(message_ids)
121
+ tmp_log.debug(f"{event_type} start for lfn={filename} activity={activity}")
122
+ sites = self.site_mapper.get_sites_for_endpoint(endpoint, "input")
123
+ panda_ids = self.tbIF.update_input_files_at_sites_and_get_panda_ids(filename, sites)
124
+ jobs = self.tbIF.peekJobs(panda_ids, fromActive=False, fromArchived=False, fromWaiting=False)
125
+ # activate jobs
126
+ self.tbIF.activateJobs(jobs)
127
+ tmp_log.debug(f"done")
128
+ return
129
+
130
+ def trigger_component_action(self, event_type: str, message_ids: str, message_dict: dict, tmp_log: LogWrapper.LogWrapper) -> None:
131
+ """
132
+ Trigger component action based on the event type
133
+ Args:
134
+ event_type: message event type
135
+ message_ids: subscription and message IDs
136
+ message_dict: message dictionary
137
+ tmp_log: logger instance
138
+ """
139
+ message_payload = message_dict["payload"]
140
+ for action_item in self.component_action_map:
141
+ # check event type
142
+ if action_item["event_type"] != event_type:
143
+ continue
144
+ # check criteria
145
+ criteria_matched = True
146
+ for key, value in action_item.get("criteria", {}).items():
147
+ dict_value = message_payload.get(key)
148
+ if dict_value is None:
149
+ criteria_matched = False
150
+ break
151
+ if dict_value != value and not re.match(value, str(dict_value)):
152
+ criteria_matched = False
153
+ break
154
+ if not criteria_matched:
155
+ continue
156
+ component_name = action_item["component"]
157
+ to_id = action_item["to_id"]
158
+ # extract task ID based on to_id
159
+ jedi_task_ids = None
160
+ if to_id == "from_input_dataset":
161
+ dataset_name = message_payload["name"].split(":")[-1]
162
+ jedi_task_ids = self.tbIF.get_task_ids_with_dataset_attributes({"datasetName": dataset_name, "type": "input"})
163
+ else:
164
+ tmp_log.warning(f"unknown to_id={to_id} for action_item={action_item} ; skipped")
165
+ continue
166
+ if jedi_task_ids is None:
167
+ tmp_log.warning(f"failed to extract jediTaskID for action_item={action_item} ; skipped")
168
+ continue
169
+ if not jedi_task_ids:
170
+ tmp_log.debug(f"no jediTaskID found for action_item={action_item} ; skipped")
171
+ continue
172
+ # loop over task IDs
173
+ for jedi_task_id in jedi_task_ids:
174
+ # release task just in case
175
+ self.tbIF.release_task_on_hold(jedi_task_id)
176
+ # push trigger message
177
+ push_ret = self.tbIF.push_task_trigger_message(component_name, jedi_task_ids)
178
+ if push_ret:
179
+ tmp_log.debug(f"pushed trigger message to {component_name} for jediTaskID={jedi_task_ids}")
180
+ else:
181
+ tmp_log.warning(f"failed to push trigger to {component_name} for jediTaskID={jedi_task_ids}")
182
+ return
@@ -0,0 +1,74 @@
1
+ import json
2
+ import os
3
+ import socket
4
+
5
+ from pandacommon.pandalogger import logger_utils
6
+
7
+ from pandajedi.jedicore.ThreadUtils import ListWithLock, ThreadPool
8
+ from pandajedi.jediddm.DDMInterface import DDMInterface
9
+ from pandajedi.jedimsgprocessor.base_msg_processor import BaseMsgProcPlugin
10
+ from pandajedi.jediorder.JobGenerator import JobGeneratorThread
11
+ from pandajedi.jediorder.TaskSetupper import TaskSetupper
12
+
13
+ base_logger = logger_utils.setup_logger(__name__.split(".")[-1])
14
+
15
+
16
+ # plugin to process messages from Panda to JEDI
17
+ class PandaToJediMsgProcPlugin(BaseMsgProcPlugin):
18
+ def initialize(self):
19
+ BaseMsgProcPlugin.initialize(self)
20
+ self.ddmIF = DDMInterface()
21
+ self.ddmIF.setupInterface()
22
+ self.pid = f"{socket.getfqdn().split('.')[0]}-{os.getpid()}_{os.getpgrp()}-pjmsg"
23
+
24
+ def process(self, msg_obj, decoded_data=None):
25
+ tmp_log = logger_utils.make_logger(base_logger, token=self.get_pid(), method_name="process")
26
+ # start
27
+ tmp_log.info("start")
28
+ # parse
29
+ if decoded_data is None:
30
+ # json decode
31
+ try:
32
+ msg_dict = json.loads(msg_obj.data)
33
+ except Exception as e:
34
+ err_str = f"failed to parse message json {msg_obj.data} , skipped. {e.__class__.__name__} : {e}"
35
+ tmp_log.error(err_str)
36
+ raise
37
+ else:
38
+ msg_dict = decoded_data
39
+ # run
40
+ try:
41
+ tmp_log.debug(f"got message {msg_dict}")
42
+ if msg_dict["msg_type"] == "generate_job":
43
+ # get task to generate jobs
44
+ jediTaskID = int(msg_dict["taskid"])
45
+ s, taskSpec = self.tbIF.getTaskWithID_JEDI(jediTaskID)
46
+ if not taskSpec:
47
+ tmp_log.debug(f"unknown task {jediTaskID}")
48
+ else:
49
+ # get WQ
50
+ vo = taskSpec.vo
51
+ prodSourceLabel = taskSpec.prodSourceLabel
52
+ workQueue = self.tbIF.getWorkQueueMap().getQueueWithIDGshare(taskSpec.workQueue_ID, taskSpec.gshare)
53
+ # get inputs
54
+ tmpList = self.tbIF.getTasksToBeProcessed_JEDI(self.pid, None, workQueue, None, None, nFiles=1000, target_tasks=[jediTaskID])
55
+ if tmpList:
56
+ inputList = ListWithLock(tmpList)
57
+ # create thread
58
+ threadPool = ThreadPool()
59
+ siteMapper = self.tbIF.get_site_mapper()
60
+ taskSetupper = TaskSetupper(vo, prodSourceLabel)
61
+ taskSetupper.initializeMods(self.tbIF, self.ddmIF)
62
+ gen = JobGeneratorThread(
63
+ inputList, threadPool, self.tbIF, self.ddmIF, siteMapper, True, taskSetupper, self.pid, workQueue, "pjmsg", None, None, None, False
64
+ )
65
+ gen.start()
66
+ gen.join()
67
+ else:
68
+ tmp_log.debug(f"unknown message type : {msg_dict['msg_type']}")
69
+ except Exception as e:
70
+ err_str = f"failed to run, skipped. {e.__class__.__name__} : {e}"
71
+ tmp_log.error(err_str)
72
+ raise
73
+ # done
74
+ tmp_log.info("done")