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,323 @@
1
+ import re
2
+
3
+ from pandaserver.taskbuffer import JobUtils
4
+
5
+
6
+ def isCachedFile(dataset_name, site_spec):
7
+ """
8
+ Check if the file is cached on a site using CVMFS, e.g. for DB releases.
9
+
10
+ Args:
11
+ dataset_name (str): The name of the dataset.
12
+ site_spec (SiteSpec): The site specification object.
13
+ Returns:
14
+ bool: True if the file is cached, False otherwise.
15
+ """
16
+ # Site does not use CVMFS
17
+ if site_spec.iscvmfs is not True:
18
+ return False
19
+ # look for DBR
20
+ if not dataset_name.startswith("ddo"):
21
+ return False
22
+ # look for the letter 'v' followed by 6 digits
23
+ if re.search(r"v\d{6}$", dataset_name) is None:
24
+ return False
25
+ return True
26
+
27
+
28
+ # check invalid characters in dataset name
29
+ def checkInvalidCharacters(dataset_name):
30
+ """
31
+ Checks the validity of a dataset name.
32
+ - The dataset name starts with an alphanumeric character ([A-Za-z0-9]).
33
+ - The rest of the dataset name can contain alphanumeric characters, dots(.), hyphens(-),
34
+ underscores(_), or slashes( /), and its length is between 1 and 255 characters({1, 255}).
35
+
36
+ Args:
37
+ dataset_name: The name of the dataset.
38
+ Returns:
39
+ True if the dataset name is valid, False otherwise.
40
+ """
41
+ if re.match("^[A-Za-z0-9][A-Za-z0-9\.\-\_/]{1,255}$", dataset_name) is not None:
42
+ return True
43
+ return False
44
+
45
+
46
+ # get dataset type
47
+ def getDatasetType(dataset):
48
+ """
49
+ Get the dataset type by extracting the fifth element from the dataset name.
50
+
51
+ The dataset name is expected to be a string with elements separated by dots.
52
+ For example:
53
+ - 'mc23_13p6TeV:mc23_13p6TeV.801169.Py8EG_A14NNPDF23LO_jj_JZ4.merge.EVNT.e8514_e8528_tid38750682_00' would return 'EVNT'.
54
+ - 'mc23_13p6TeV.801169.Py8EG_A14NNPDF23LO_jj_JZ4.simul.HITS.e8514_e8528_a934_tid41381346_00' would return 'HITS'.
55
+
56
+ Args:
57
+ dataset (str): The name of the dataset.
58
+ Returns:
59
+ str: The dataset type if it can be extracted, otherwise None.
60
+ """
61
+ try:
62
+ if dataset.startswith("user") or dataset.startswith("group"):
63
+ return None
64
+ dataset_type = dataset.split(".")[4]
65
+ except Exception:
66
+ dataset_type = None
67
+ return dataset_type
68
+
69
+
70
+ def getSitesShareDDM(site_mapper, site_name, prod_source_label, job_label, output_share=False):
71
+ """
72
+ Get sites which share the DDM endpoint.
73
+
74
+ Args:
75
+ site_mapper (SiteMapper): The site mapper object.
76
+ site_name (str): The name of the site.
77
+ prod_source_label (str): The production source label.
78
+ job_label (str): The job label.
79
+ output_share (bool): False to get sites which use the output RSE as input,
80
+ True to get sites which use the input RSEs as output.
81
+ Returns:
82
+ list: A list of site names that share the DDM endpoint.
83
+ """
84
+ if not site_mapper.checkSite(site_name):
85
+ return []
86
+
87
+ site_spec = site_mapper.getSite(site_name)
88
+ scope_site_input, scope_site_output = select_scope(site_spec, prod_source_label, job_label)
89
+ runs_production = site_spec.runs_production()
90
+ runs_analysis = site_spec.runs_analysis()
91
+
92
+ ret_sites = []
93
+ for tmp_site_name, tmp_site_spec in site_mapper.siteSpecList.items():
94
+ scope_tmp_site_input, scope_tmp_site_output = select_scope(tmp_site_spec, prod_source_label, job_label)
95
+
96
+ if (runs_production and not tmp_site_spec.runs_production()) or (runs_analysis and not tmp_site_spec.runs_analysis()):
97
+ continue
98
+ if tmp_site_spec.status != "online":
99
+ continue
100
+
101
+ try:
102
+ if not output_share and site_spec.ddm_output[scope_site_output] not in tmp_site_spec.ddm_endpoints_input[scope_tmp_site_input].all:
103
+ continue
104
+ if output_share and tmp_site_spec.ddm_output[scope_site_output] not in site_spec.ddm_endpoints_input[scope_tmp_site_input].all:
105
+ continue
106
+ except Exception:
107
+ continue
108
+
109
+ if site_name != tmp_site_spec.sitename and tmp_site_spec.sitename not in ret_sites:
110
+ ret_sites.append(tmp_site_spec.sitename)
111
+
112
+ return ret_sites
113
+
114
+
115
+ def checkJobDestinationSE(tmp_job):
116
+ """
117
+ Check if the job has a destination storage element in a file specification.
118
+
119
+ Args:
120
+ tmp_job (JobSpec): The job object containing file specifications.
121
+ Returns:
122
+ str: The destination SE if specified, otherwise None.
123
+ """
124
+ for tmp_file in tmp_job.Files:
125
+ destination_se = getDestinationSE(tmp_file.destinationDBlockToken)
126
+ if destination_se is not None:
127
+ return tmp_file.destinationSE
128
+ return None
129
+
130
+
131
+ def getDestinationSE(destination_dblock_token):
132
+ """
133
+ Check if the destination is specified (e.g. dst:CERN-PROD_DATADISK) and extract it.
134
+
135
+ Args:
136
+ destination_dblock_token (str): The destination data block token.
137
+ Returns:
138
+ str: The extracted destination if specified, otherwise None.
139
+ """
140
+ if destination_dblock_token is not None:
141
+ for tmp_token in destination_dblock_token.split(","):
142
+ tmp_match = re.search(r"^dst:([^/]*)(/.*)*$", tmp_token)
143
+ if tmp_match is not None:
144
+ return tmp_match.group(1)
145
+ return None
146
+
147
+
148
+ def getDistributedDestination(destination_dblock_token, ignore_empty=True):
149
+ """
150
+ Check if the destination is distributed (e.g. ddd:CERN-PROD_DATADISK) and extract it.
151
+
152
+ Args:
153
+ destination_dblock_token (str): The destination data block token.
154
+ ignore_empty (bool): Flag to ignore empty locations.
155
+
156
+ Returns:
157
+ str: The extracted location if specified, otherwise None.
158
+ """
159
+ if destination_dblock_token is not None:
160
+ for tmp_token in destination_dblock_token.split(","):
161
+ tmp_match = re.search(r"^ddd:([^/]*)(/.*)*$", tmp_token)
162
+ if tmp_match is not None:
163
+ location = tmp_match.group(1)
164
+ if ignore_empty and not location:
165
+ return None
166
+ return location
167
+ return None
168
+
169
+
170
+ def extractImportantError(message):
171
+ """
172
+ Extract important error strings from a message. This function searches for specific substrings within a given message and returns
173
+ a concatenated string of lines containing those substrings.
174
+
175
+ Args:
176
+ message (str): The message string to search within.
177
+ Returns:
178
+ str: A concatenated string of lines containing the specified substrings.
179
+ Returns an empty string if no matches are found or an exception occurs.
180
+ """
181
+ try:
182
+ # list of strings to search for
183
+ str_list = ["InvalidRSEExpression", "Details:"]
184
+ return_string = " ".join(line for line in message.split("\n") if any(tmp_string in line for tmp_string in str_list))
185
+ except Exception:
186
+ return_string = ""
187
+ return return_string
188
+
189
+
190
+ def getActivityForOut(prod_source_label):
191
+ """
192
+ Get the DDM activity type for the job output based on the production source label.
193
+
194
+ Args:
195
+ prod_source_label (str): The production source label.
196
+ Returns:
197
+ str: The activity type for output.
198
+ """
199
+ if prod_source_label in ["managed"]:
200
+ activity = "Production Output"
201
+ elif prod_source_label in ["user", "panda"]:
202
+ activity = "Analysis Output"
203
+ else:
204
+ activity = "Functional Test"
205
+ return activity
206
+
207
+
208
+ def select_scope(site_spec, prod_source_label, job_label):
209
+ """
210
+ Select the scopes of the activity for input and output. The scope was introduced for prod-analy queues where you might want to associate
211
+ different RSEs depending on production or analysis.
212
+
213
+ Args:
214
+ site_spec (SiteSpec): The site specification object.
215
+ prod_source_label (str): The production source label.
216
+ job_label (str): The job label.
217
+ Returns:
218
+ tuple: A tuple containing the input scope and output scope.
219
+ """
220
+ scope_input = "default"
221
+ aux_scopes_input = site_spec.ddm_endpoints_input.keys()
222
+ if (job_label == JobUtils.ANALY_PS or prod_source_label in JobUtils.analy_sources) and "analysis" in aux_scopes_input:
223
+ scope_input = "analysis"
224
+
225
+ scope_output = "default"
226
+ aux_scopes_output = site_spec.ddm_endpoints_output.keys()
227
+ if (job_label == JobUtils.ANALY_PS or prod_source_label in JobUtils.analy_sources) and "analysis" in aux_scopes_output:
228
+ scope_output = "analysis"
229
+
230
+ return scope_input, scope_output
231
+
232
+
233
+ def isDBR(dataset_name):
234
+ """
235
+ Check if the dataset is a DB release. A DB release dataset name starts with 'ddo'.
236
+
237
+ Args:
238
+ dataset_name (str): The name of the dataset.
239
+
240
+ Returns:
241
+ bool: True if the dataset name starts with 'ddo', False otherwise.
242
+ """
243
+ if dataset_name.startswith("ddo"):
244
+ return True
245
+ return False
246
+
247
+
248
+ def is_top_level_dataset(dataset_name: str) -> bool:
249
+ """
250
+ Check if top dataset. Top datasets do not finish with '_sub' followed by one or more digits.
251
+
252
+ Args:
253
+ dataset_name (str): Dataset name.
254
+
255
+ Returns:
256
+ bool: True if top dataset, False otherwise.
257
+ """
258
+ return re.sub("_sub\d+$", "", dataset_name) == dataset_name
259
+
260
+
261
+ def is_sub_dataset(dataset_name: str) -> bool:
262
+ """
263
+ Check if the dataset name ends with '_sub' followed by one or more digits.
264
+
265
+ Args:
266
+ dataset_name (str): The name of the dataset.
267
+
268
+ Returns:
269
+ bool: True if the dataset name ends with '_sub' followed by one or more digits, False otherwise.
270
+ """
271
+ return re.search("_sub\d+$", dataset_name) is not None
272
+
273
+
274
+ def is_tid_dataset(destination_data_block: str) -> bool:
275
+ """
276
+ Check if the destination data block ends with '_tid' followed by one or more digits.
277
+
278
+ Args:
279
+ destination_data_block (str): The destination data block.
280
+
281
+ Returns:
282
+ bool: True if the destination data block ends with '_tid' followed by one or more digits, False otherwise.
283
+ """
284
+ return re.search("_tid[\d_]+$", destination_data_block) is not None
285
+
286
+
287
+ def is_hammercloud_dataset(destination_data_block: str) -> bool:
288
+ """
289
+ Check if the destination data block starts with 'hc_test.'.
290
+
291
+ Args:
292
+ destination_data_block (str): The destination data block.
293
+
294
+ Returns:
295
+ bool: True if the destination data block starts with 'hc_test.', False otherwise.
296
+ """
297
+ return re.search("^hc_test\.", destination_data_block) is not None
298
+
299
+
300
+ def is_user_gangarbt_dataset(destination_data_block: str) -> bool:
301
+ """
302
+ Check if the destination data block starts with 'user.gangarbt.'.
303
+
304
+ Args:
305
+ destination_data_block (str): The destination data block.
306
+
307
+ Returns:
308
+ bool: True if the destination data block starts with 'user.gangarbt.', False otherwise.
309
+ """
310
+ return re.search("^user\.gangarbt\.", destination_data_block) is not None
311
+
312
+
313
+ def is_lib_dataset(destination_data_block: str) -> bool:
314
+ """
315
+ Check if the destination data block ends with '.lib'.
316
+
317
+ Args:
318
+ destination_data_block (str): The destination data block.
319
+
320
+ Returns:
321
+ bool: True if the destination data block ends with '.lib', False otherwise.
322
+ """
323
+ return re.search("\.lib$", destination_data_block) is not None
@@ -0,0 +1,25 @@
1
+ # error code
2
+
3
+ # Setupper
4
+ EC_Setupper = 100
5
+
6
+ # Setupper
7
+ EC_GUID = 101
8
+
9
+ # Adder
10
+ EC_Adder = 200
11
+
12
+ # Subscription failures
13
+ EC_Subscription = 201
14
+
15
+ # location registration failures
16
+ EC_Location = 203
17
+
18
+ # missing nEvents
19
+ EC_MissingNumEvents = 204
20
+
21
+ # inconsistent GUID
22
+ EC_InconsistentGUID = 205
23
+
24
+ # wrong RSE configuration
25
+ EC_RSE = 206
@@ -0,0 +1,322 @@
1
+ import argparse
2
+ import os
3
+ import sys
4
+
5
+ from pandacommon.pandalogger.LogWrapper import LogWrapper
6
+ from pandacommon.pandautils.thread_utils import GenericThread
7
+ from rucio.client import Client as RucioClient
8
+ from rucio.common.exception import DataIdentifierNotFound
9
+
10
+ from pandaserver.config import panda_config
11
+ from pandaserver.dataservice.ddm import rucioAPI
12
+ from pandaserver.userinterface import Client
13
+
14
+
15
+ # get files form rucio
16
+ def get_files_from_rucio(ds_name):
17
+ # get files from rucio
18
+ try:
19
+ rc = RucioClient()
20
+ scope, name = rucioAPI.extract_scope(ds_name)
21
+ if name.endswith("/"):
22
+ name = name[:-1]
23
+ files_rucio = set()
24
+ for i in rc.list_files(scope, name):
25
+ files_rucio.add(i["name"])
26
+ return True, files_rucio
27
+ except DataIdentifierNotFound:
28
+ return False, f"unknown dataset {ds_name}"
29
+ except Exception as e:
30
+ msg_str = f"failed to get files from rucio: {str(e)}"
31
+ return None, msg_str
32
+
33
+
34
+ # print a message
35
+ def print_msg(message: str, log_stream: LogWrapper | None, is_error: bool = False, put_log: str | None = None):
36
+ """
37
+ Print a message to log stream or stdout.
38
+
39
+ :param message: Message string.
40
+ :param log_stream: LogWrapper object or None.
41
+ :param is_error: If True, log as error.
42
+ :param put_log: Log filename to dump log to this file in cache_dir.
43
+ """
44
+ if log_stream:
45
+ if is_error:
46
+ log_stream.error("Error: " + message)
47
+ else:
48
+ log_stream.info(message)
49
+ if put_log:
50
+ with open(os.path.join(panda_config.cache_dir, put_log), "w") as f:
51
+ f.write(log_stream.dumpToString())
52
+ f.write("done\n")
53
+ else:
54
+ if is_error:
55
+ print("ERROR: ", message)
56
+ else:
57
+ print(message)
58
+
59
+
60
+ # main
61
+ def main(taskBuffer=None, exec_options=None, log_stream=None, args_list=None):
62
+ # options
63
+ parser = argparse.ArgumentParser()
64
+ parser.add_argument(
65
+ "--ds",
66
+ action="store",
67
+ dest="ds",
68
+ default=None,
69
+ help="dataset name",
70
+ )
71
+ parser.add_argument(
72
+ "--files",
73
+ action="store",
74
+ dest="files",
75
+ default=None,
76
+ help="comma-separated list of lost file names. The list is deduced if this option is omitted",
77
+ )
78
+ parser.add_argument(
79
+ "--jediTaskID",
80
+ action="store",
81
+ dest="jediTaskID",
82
+ type=int,
83
+ default=None,
84
+ help="JEDI task ID that produced the dataset",
85
+ )
86
+ parser.add_argument(
87
+ "--noChildRetry",
88
+ action="store_const",
89
+ const=True,
90
+ dest="noChildRetry",
91
+ default=False,
92
+ help="not retry child tasks",
93
+ )
94
+ parser.add_argument(
95
+ "--resurrectDS",
96
+ action="store_const",
97
+ const=True,
98
+ dest="resurrectDS",
99
+ default=False,
100
+ help="resurrect output and log datasets if they were already deleted",
101
+ )
102
+ parser.add_argument(
103
+ "--dryRun",
104
+ action="store_const",
105
+ const=True,
106
+ dest="dryRun",
107
+ default=False,
108
+ help="dry run",
109
+ )
110
+ parser.add_argument(
111
+ "--force",
112
+ action="store_const",
113
+ const=True,
114
+ dest="force",
115
+ default=False,
116
+ help="force retry even if no lost files",
117
+ )
118
+ parser.add_argument(
119
+ "--reproduceParent",
120
+ action="store_const",
121
+ const=True,
122
+ dest="reproduceParent",
123
+ default=False,
124
+ help="reproduce the input files from which the lost files were produced. "
125
+ "Typically useful to recover merged files when unmerged files were already deleted",
126
+ )
127
+ parser.add_argument(
128
+ "--reproduceUptoNthGen",
129
+ action="store",
130
+ dest="reproduceUptoNthGen",
131
+ type=int,
132
+ default=0,
133
+ help="reproduce files up to N-th upper generation. --reproduceUptoNthGen=1 corresponds "
134
+ "to --reproduceParent. 0 by default so that any provenance files are not reproduced",
135
+ )
136
+ # parse options
137
+ if taskBuffer:
138
+ if args_list:
139
+ options = parser.parse_args(args_list)
140
+ else:
141
+ options, unknown = parser.parse_known_args()
142
+ else:
143
+ if args_list:
144
+ options = parser.parse_args(args_list)
145
+ else:
146
+ options = parser.parse_args()
147
+
148
+ requester_id = GenericThread().get_full_id(__name__, sys.modules[__name__].__file__)
149
+
150
+ if taskBuffer is None:
151
+ # instantiate TB
152
+ from pandaserver.taskbuffer.TaskBuffer import taskBuffer
153
+
154
+ taskBuffer.init(
155
+ panda_config.dbhost,
156
+ panda_config.dbpasswd,
157
+ nDBConnection=1,
158
+ requester=requester_id,
159
+ )
160
+
161
+ # set options from dict
162
+ if exec_options is None:
163
+ exec_options = {}
164
+ keys = set(vars(options).keys())
165
+ for k in exec_options:
166
+ if k in keys:
167
+ setattr(options, k, exec_options[k])
168
+
169
+ dn = exec_options.get("userName")
170
+ is_production_manager = exec_options.get("isProductionManager", False)
171
+ log_filename = exec_options.get("logFilename")
172
+ print_msg(f"User='{dn}' is_prod={is_production_manager} log_name={log_filename}", log_stream)
173
+
174
+ if options.reproduceUptoNthGen > 0:
175
+ options.reproduceUptoNthGen -= 1
176
+ options.reproduceParent = True
177
+
178
+ # check if dataset name or taskID is given
179
+ if options.jediTaskID is None and options.ds is None:
180
+ msg_str = "Dataset name or jediTaskID is required"
181
+ print_msg(msg_str, log_stream, is_error=True, put_log=log_filename)
182
+ return False, msg_str
183
+
184
+ ds_files = {}
185
+ if options.files is not None:
186
+ files = options.files.split(",")
187
+ ds_files[options.ds] = files
188
+ else:
189
+ # look for lost files
190
+ if not options.jediTaskID:
191
+ # get files from rucio
192
+ st, files_rucio = get_files_from_rucio(options.ds)
193
+ if st is not True:
194
+ print_msg(files_rucio, log_stream, is_error=True, put_log=log_filename)
195
+ return st, files_rucio
196
+ # get files from panda
197
+ dsName = options.ds.split(":")[-1]
198
+ fd, fo = taskBuffer.querySQLS(
199
+ "SELECT c.lfn FROM ATLAS_PANDA.JEDI_Datasets d,ATLAS_PANDA.JEDI_Dataset_Contents c "
200
+ "WHERE c.jediTaskID=d.jediTaskID AND c.datasetID=d.datasetID AND "
201
+ "d.type=:t1 AND c.status=:s AND d.datasetName=:name ",
202
+ {":s": "finished", ":t1": "output", ":name": dsName},
203
+ )
204
+ for (tmpLFN,) in fo:
205
+ if tmpLFN not in files_rucio:
206
+ ds_files.setdefault(options.ds, [])
207
+ ds_files[options.ds].append(tmpLFN)
208
+ # get taskID
209
+ td, to = taskBuffer.querySQLS(
210
+ "SELECT jediTaskID FROM ATLAS_PANDA.JEDI_Datasets " "WHERE datasetName=:datasetName AND type=:t1 ",
211
+ {":t1": "output", ":datasetName": dsName},
212
+ )
213
+ (jediTaskID,) = to[0]
214
+ else:
215
+ # get dataset names
216
+ dd, do = taskBuffer.querySQLS(
217
+ "SELECT datasetName FROM ATLAS_PANDA.JEDI_Datasets " "WHERE jediTaskID=:jediTaskID AND type=:t1 ",
218
+ {":t1": "output", ":jediTaskID": options.jediTaskID},
219
+ )
220
+ # get files from rucio
221
+ files_rucio = set()
222
+ for (tmpDS,) in do:
223
+ st, tmp_files_rucio = get_files_from_rucio(tmpDS)
224
+ if st is None:
225
+ print_msg(tmp_files_rucio, log_stream, is_error=True, put_log=log_filename)
226
+ return st, tmp_files_rucio
227
+ # ignore unknown dataset
228
+ if st:
229
+ files_rucio = files_rucio.union(tmp_files_rucio)
230
+ # get files from PanDA
231
+ fd, fo = taskBuffer.querySQLS(
232
+ "SELECT d.datasetName,c.lfn FROM ATLAS_PANDA.JEDI_Datasets d,ATLAS_PANDA.JEDI_Dataset_Contents c "
233
+ "WHERE d.jediTaskID=:jediTaskID AND c.jediTaskID=d.jediTaskID AND c.datasetID=d.datasetID AND "
234
+ "d.type=:t1 AND c.status=:s ",
235
+ {
236
+ ":s": "finished",
237
+ ":t1": "output",
238
+ ":jediTaskID": options.jediTaskID,
239
+ },
240
+ )
241
+ for tmpDS, tmpLFN in fo:
242
+ if tmpLFN not in files_rucio:
243
+ ds_files.setdefault(tmpDS, [])
244
+ ds_files[tmpDS].append(tmpLFN)
245
+ for tmpDS in ds_files:
246
+ files = ds_files[tmpDS]
247
+ msg_str = f"{tmpDS} has {len(files)} lost files -> {','.join(files)}"
248
+ print_msg(msg_str, log_stream)
249
+
250
+ # no lost files
251
+ if not ds_files and not options.force:
252
+ msg_str = "No lost files. Use --force to ignore this check"
253
+ print_msg(msg_str, log_stream, put_log=log_filename)
254
+ return True, msg_str
255
+
256
+ # reset file status
257
+ s = False
258
+ for tmpDS in ds_files:
259
+ files = ds_files[tmpDS]
260
+ if not is_production_manager:
261
+ ts, jediTaskID, lostInputFiles, error_message = taskBuffer.resetFileStatusInJEDI(dn, False, tmpDS, files, options.reproduceParent, options.dryRun)
262
+ else:
263
+ ts, jediTaskID, lostInputFiles, error_message = taskBuffer.resetFileStatusInJEDI("", True, tmpDS, files, options.reproduceParent, options.dryRun)
264
+ if error_message:
265
+ msg_str = f"Failed to reset file status in the DB since {error_message}"
266
+ print_msg(msg_str, log_stream, is_error=True)
267
+ else:
268
+ msg_str = f"Reset file status for {tmpDS} in the DB: done with {ts} for jediTaskID={jediTaskID}"
269
+ print_msg(msg_str, log_stream)
270
+ s |= ts
271
+ # recover provenance
272
+ if options.reproduceParent:
273
+ # reproduce input
274
+ for lostDS in lostInputFiles:
275
+ com_args = ["--ds", lostDS, "--noChildRetry", "--resurrectDS"]
276
+ if options.reproduceUptoNthGen > 0:
277
+ com_args += [
278
+ "--reproduceUptoNthGen",
279
+ str(options.reproduceUptoNthGen),
280
+ ]
281
+ if options.dryRun:
282
+ com_args.append("--dryRun")
283
+ com_args += ["--files", ",".join(lostInputFiles[lostDS])]
284
+ main(taskBuffer=taskBuffer, log_stream=log_stream, args_list=com_args)
285
+
286
+ # go ahead
287
+ if options.dryRun:
288
+ msg_str = f"Done in the dry-run mode with {s}"
289
+ print_msg(msg_str, log_stream, put_log=log_filename)
290
+ return True, msg_str
291
+ if s or options.force:
292
+ if options.resurrectDS:
293
+ sd, so = taskBuffer.querySQLS(
294
+ "SELECT datasetName FROM ATLAS_PANDA.JEDI_Datasets WHERE jediTaskID=:id AND type IN (:t1,:t2)",
295
+ {":id": jediTaskID, ":t1": "output", ":t2": "log"},
296
+ )
297
+ rc = RucioClient()
298
+ for (datasetName,) in so:
299
+ for i in range(3):
300
+ try:
301
+ scope, name = rucioAPI.extract_scope(datasetName)
302
+ rc.get_did(scope, name)
303
+ break
304
+ except DataIdentifierNotFound:
305
+ msg_str = f"resurrect {datasetName}"
306
+ print_msg(msg_str, log_stream)
307
+ rc.resurrect([{"scope": scope, "name": name}])
308
+ try:
309
+ rc.set_metadata(scope, name, "lifetime", None)
310
+ except Exception:
311
+ pass
312
+ if not options.reproduceParent:
313
+ tmp_ret = Client.retry_task(jediTaskID, no_child_retry=options.noChildRetry)
314
+ else:
315
+ tmp_ret = Client.reload_input(jediTaskID)
316
+ msg_str = f"Retried task {jediTaskID}: done with {tmp_ret}"
317
+ print_msg(msg_str, log_stream, put_log=log_filename)
318
+ return True, msg_str
319
+ else:
320
+ msg_str = "Failed"
321
+ print_msg(msg_str, log_stream, is_error=True, put_log=log_filename)
322
+ return False, msg_str
File without changes