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,772 @@
1
+ import datetime
2
+
3
+ from pandacommon.pandalogger.LogWrapper import LogWrapper
4
+ from pandacommon.pandautils.PandaUtils import get_sql_IN_bind_variables, naive_utcnow
5
+
6
+ from pandaserver.config import panda_config
7
+ from pandaserver.taskbuffer.DataCarousel import (
8
+ DataCarouselRequestSpec,
9
+ DataCarouselRequestStatus,
10
+ get_resubmit_request_spec,
11
+ )
12
+ from pandaserver.taskbuffer.db_proxy_mods.base_module import BaseModule, varNUMBER
13
+ from pandaserver.taskbuffer.JediTaskSpec import JediTaskSpec
14
+
15
+
16
+ # Module class to define Data Carousel related methods
17
+ class DataCarouselModule(BaseModule):
18
+ # constructor
19
+ def __init__(self, log_stream: LogWrapper):
20
+ super().__init__(log_stream)
21
+
22
+ # query data carousel request ID by dataset
23
+ def get_data_carousel_request_id_by_dataset_JEDI(self, dataset):
24
+ comment = " /* JediDBProxy.get_data_carousel_request_id_by_dataset_JEDI */"
25
+ tmp_log = self.create_tagged_logger(comment, f"dataset={dataset}")
26
+ tmp_log.debug("start")
27
+ try:
28
+ # sql to query request of the dataset
29
+ status_var_names_str, status_var_map = get_sql_IN_bind_variables(DataCarouselRequestStatus.reusable_statuses, prefix=":status_")
30
+ sql_query = (
31
+ f"SELECT request_id "
32
+ f"FROM {panda_config.schemaJEDI}.data_carousel_requests "
33
+ f"WHERE dataset=:dataset "
34
+ f"AND status IN ({status_var_names_str}) "
35
+ )
36
+ var_map = {":dataset": dataset}
37
+ var_map.update(status_var_map)
38
+ self.cur.execute(sql_query + comment, var_map)
39
+ res = self.cur.fetchone()
40
+ if res is None:
41
+ tmp_log.debug("no such request")
42
+ self._commit()
43
+ return None
44
+ request_id = res[0]
45
+ tmp_log.debug(f"found request_id={request_id}")
46
+ self._commit()
47
+ return request_id
48
+ except Exception:
49
+ # roll back
50
+ self._rollback()
51
+ # error
52
+ self.dump_error_message(tmp_log)
53
+ return None
54
+
55
+ # insert data carousel requests
56
+ def insert_data_carousel_requests_JEDI(self, task_id, dc_req_specs):
57
+ comment = " /* JediDBProxy.insert_data_carousel_requests_JEDI */"
58
+ tmp_log = self.create_tagged_logger(comment, f"jediTaskID={task_id}")
59
+ tmp_log.debug("start")
60
+ try:
61
+ # start transaction
62
+ self.conn.begin()
63
+ # insert requests
64
+ n_req_inserted = 0
65
+ n_rel_inserted = 0
66
+ n_req_reused = 0
67
+ n_rel_reused = 0
68
+ for dc_req_spec in dc_req_specs:
69
+ # sql to query request of the dataset
70
+ status_var_names_str, status_var_map = get_sql_IN_bind_variables(DataCarouselRequestStatus.reusable_statuses, prefix=":status")
71
+ sql_query = (
72
+ f"SELECT request_id "
73
+ f"FROM {panda_config.schemaJEDI}.data_carousel_requests "
74
+ f"WHERE dataset=:dataset "
75
+ f"AND status IN ({status_var_names_str}) "
76
+ )
77
+ var_map = {":dataset": dc_req_spec.dataset}
78
+ var_map.update(status_var_map)
79
+ self.cur.execute(sql_query + comment, var_map)
80
+ res = self.cur.fetchall()
81
+ # check if already existing request for the dataset
82
+ the_request_id = None
83
+ if res:
84
+ # have existing request; reuse it
85
+ for (request_id,) in res:
86
+ the_request_id = request_id
87
+ n_req_reused += 1
88
+ break
89
+ else:
90
+ # no existing request; insert new one
91
+ # sql to insert request
92
+ sql_insert_request = (
93
+ f"INSERT INTO {panda_config.schemaJEDI}.data_carousel_requests ({dc_req_spec.columnNames()}) "
94
+ f"{dc_req_spec.bindValuesExpression()} "
95
+ f"RETURNING request_id INTO :new_request_id "
96
+ )
97
+ var_map = dc_req_spec.valuesMap(useSeq=True)
98
+ var_map[":new_request_id"] = self.cur.var(varNUMBER)
99
+ self.cur.execute(sql_insert_request + comment, var_map)
100
+ the_request_id = int(self.getvalue_corrector(self.cur.getvalue(var_map[":new_request_id"])))
101
+ n_req_inserted += 1
102
+ if the_request_id is None:
103
+ raise RuntimeError("the_request_id is None")
104
+ # sql to query relation
105
+ sql_rel_query = (
106
+ f"SELECT request_id, task_id "
107
+ f"FROM {panda_config.schemaJEDI}.data_carousel_relations "
108
+ f"WHERE request_id=:request_id AND task_id=:task_id "
109
+ )
110
+ var_map = {":request_id": the_request_id, ":task_id": task_id}
111
+ self.cur.execute(sql_rel_query + comment, var_map)
112
+ res = self.cur.fetchall()
113
+ if res:
114
+ # have existing relation; skipped
115
+ n_rel_reused += 1
116
+ else:
117
+ # sql to insert relation
118
+ sql_insert_relation = (
119
+ f"INSERT INTO {panda_config.schemaJEDI}.data_carousel_relations (request_id, task_id) " f"VALUES(:request_id, :task_id) "
120
+ )
121
+ self.cur.execute(sql_insert_relation + comment, var_map)
122
+ n_rel_inserted += 1
123
+ # commit
124
+ if not self._commit():
125
+ raise RuntimeError("Commit error")
126
+ # return
127
+ tmp_log.debug(
128
+ f"inserted {n_req_inserted}/{len(dc_req_specs)} requests and {n_rel_inserted} relations ; reused {n_req_reused} requests and {n_rel_reused} relations"
129
+ )
130
+ return n_req_inserted
131
+ except Exception:
132
+ # roll back
133
+ self._rollback()
134
+ # error
135
+ self.dump_error_message(tmp_log)
136
+ return None
137
+
138
+ # update a data carousel request
139
+ def update_data_carousel_request_JEDI(self, dc_req_spec):
140
+ comment = " /* JediDBProxy.update_data_carousel_request_JEDI */"
141
+ tmp_log = self.create_tagged_logger(comment, f"request_id={dc_req_spec.request_id}")
142
+ tmp_log.debug("start")
143
+ try:
144
+ # start transaction
145
+ self.conn.begin()
146
+ # sql to update request
147
+ dc_req_spec.modification_time = naive_utcnow()
148
+ sql_update = (
149
+ f"UPDATE {panda_config.schemaJEDI}.data_carousel_requests " f"SET {dc_req_spec.bindUpdateChangesExpression()} " "WHERE request_id=:request_id "
150
+ )
151
+ var_map = dc_req_spec.valuesMap(useSeq=False, onlyChanged=True)
152
+ var_map[":request_id"] = dc_req_spec.request_id
153
+ self.cur.execute(sql_update + comment, var_map)
154
+ # commit
155
+ if not self._commit():
156
+ raise RuntimeError("Commit error")
157
+ # return
158
+ tmp_log.debug(f"updated {dc_req_spec.bindUpdateChangesExpression()}")
159
+ return dc_req_spec
160
+ except Exception:
161
+ # roll back
162
+ self._rollback()
163
+ # error
164
+ self.dump_error_message(tmp_log)
165
+ return None
166
+
167
+ # insert data carousel relations
168
+ def insert_data_carousel_relations_JEDI(self, task_id, request_ids):
169
+ comment = " /* JediDBProxy.insert_data_carousel_relations_JEDI */"
170
+ tmp_log = self.create_tagged_logger(comment, f"jediTaskID={task_id}")
171
+ tmp_log.debug("start")
172
+ try:
173
+ # start transaction
174
+ self.conn.begin()
175
+ # insert relations
176
+ n_rel_inserted = 0
177
+ n_rel_reused = 0
178
+ for request_id in request_ids:
179
+ # sql to query relation
180
+ sql_rel_query = (
181
+ f"SELECT request_id, task_id "
182
+ f"FROM {panda_config.schemaJEDI}.data_carousel_relations "
183
+ f"WHERE request_id=:request_id AND task_id=:task_id "
184
+ )
185
+ var_map = {":request_id": request_id, ":task_id": task_id}
186
+ self.cur.execute(sql_rel_query + comment, var_map)
187
+ res = self.cur.fetchall()
188
+ if res:
189
+ # have existing relation; skipped
190
+ n_rel_reused += 1
191
+ else:
192
+ # sql to insert relation
193
+ sql_insert_relation = (
194
+ f"INSERT INTO {panda_config.schemaJEDI}.data_carousel_relations (request_id, task_id) " f"VALUES(:request_id, :task_id) "
195
+ )
196
+ self.cur.execute(sql_insert_relation + comment, var_map)
197
+ n_rel_inserted += 1
198
+ # commit
199
+ if not self._commit():
200
+ raise RuntimeError("Commit error")
201
+ # return
202
+ tmp_log.debug(f"inserted {n_rel_inserted} relations ; reused {n_rel_reused} relations")
203
+ return n_rel_inserted
204
+ except Exception:
205
+ # roll back
206
+ self._rollback()
207
+ # error
208
+ self.dump_error_message(tmp_log)
209
+ return None
210
+
211
+ # get data carousel queued requests and info of their related tasks
212
+ def get_data_carousel_queued_requests_JEDI(self):
213
+ comment = " /* JediDBProxy.get_data_carousel_queued_requests_JEDI */"
214
+ tmp_log = self.create_tagged_logger(comment)
215
+ tmp_log.debug("start")
216
+ try:
217
+ # initialize
218
+ ret_list = []
219
+ # start transaction
220
+ self.conn.begin()
221
+ # sql to query queued requests with gshare and priority info from related tasks
222
+ sql_query_req = (
223
+ f"SELECT {DataCarouselRequestSpec.columnNames()} " f"FROM {panda_config.schemaJEDI}.data_carousel_requests " f"WHERE status=:status "
224
+ )
225
+ var_map = {":status": DataCarouselRequestStatus.queued}
226
+ self.cur.execute(sql_query_req + comment, var_map)
227
+ res_list = self.cur.fetchall()
228
+ if res_list:
229
+ for res in res_list:
230
+ # make request spec
231
+ dc_req_spec = DataCarouselRequestSpec()
232
+ dc_req_spec.pack(res)
233
+ # query info of related tasks
234
+ sql_query_tasks = (
235
+ f"SELECT t.jediTaskID, t.gshare, COALESCE(t.currentPriority, t.taskPriority), t.taskType, t.userName, t.workingGroup "
236
+ f"FROM {panda_config.schemaJEDI}.data_carousel_relations rel, {panda_config.schemaJEDI}.JEDI_Tasks t "
237
+ f"WHERE rel.request_id=:request_id AND rel.task_id=t.jediTaskID "
238
+ )
239
+ var_map = {":request_id": dc_req_spec.request_id}
240
+ self.cur.execute(sql_query_tasks + comment, var_map)
241
+ res_tasks = self.cur.fetchall()
242
+ task_specs = []
243
+ for task_id, gshare, priority, task_type, user_name, working_group in res_tasks:
244
+ task_spec = JediTaskSpec()
245
+ task_spec.jediTaskID = task_id
246
+ task_spec.gshare = gshare
247
+ task_spec.currentPriority = priority
248
+ task_spec.taskType = task_type
249
+ task_spec.userName = user_name
250
+ task_spec.workingGroup = working_group
251
+ task_specs.append(task_spec)
252
+ # add
253
+ ret_list.append((dc_req_spec, task_specs))
254
+ else:
255
+ tmp_log.debug("no queued request")
256
+ # commit
257
+ if not self._commit():
258
+ raise RuntimeError("Commit error")
259
+ # return
260
+ tmp_log.debug(f"got {len(ret_list)} queued requests")
261
+ return ret_list
262
+ except Exception:
263
+ # roll back
264
+ self._rollback()
265
+ # error
266
+ self.dump_error_message(tmp_log)
267
+ return None
268
+
269
+ # get data carousel requests of tasks by task status
270
+ def get_data_carousel_requests_by_task_status_JEDI(self, status_filter_list=None, status_exclusion_list=None):
271
+ comment = " /* JediDBProxy.get_data_carousel_requests_by_task_status_JEDI */"
272
+ tmp_log = self.create_tagged_logger(comment)
273
+ tmp_log.debug("start")
274
+ try:
275
+ # initialize
276
+ ret_requests_map = {}
277
+ ret_relation_map = {}
278
+ # start transaction
279
+ self.conn.begin()
280
+ # sql to query queued requests with gshare and priority info from related tasks
281
+ sql_query_id = (
282
+ f"SELECT rel.request_id, rel.task_id "
283
+ f"FROM {panda_config.schemaJEDI}.data_carousel_relations rel, {panda_config.schemaJEDI}.JEDI_Tasks t "
284
+ f"WHERE rel.task_id=t.jediTaskID "
285
+ )
286
+ var_map = {}
287
+ if status_filter_list:
288
+ status_var_names_str, status_var_map = get_sql_IN_bind_variables(status_filter_list, prefix=":status")
289
+ sql_query_id += f"AND t.status IN ({status_var_names_str}) "
290
+ var_map.update(status_var_map)
291
+ tmp_log.debug(f"status filter: {status_filter_list}")
292
+ if status_exclusion_list:
293
+ antistatus_var_names_str, antistatus_var_map = get_sql_IN_bind_variables(status_exclusion_list, prefix=":antistatus")
294
+ sql_query_id += f"AND t.status NOT IN ({antistatus_var_names_str}) "
295
+ var_map.update(antistatus_var_map)
296
+ tmp_log.debug(f"status exclusion filter: {status_exclusion_list}")
297
+ self.cur.execute(sql_query_id + comment, var_map)
298
+ res_list = self.cur.fetchall()
299
+ if res_list:
300
+ for request_id, task_id in res_list:
301
+ # fill relation map
302
+ ret_relation_map.setdefault(task_id, [])
303
+ ret_relation_map[task_id].append(request_id)
304
+ if request_id in ret_requests_map:
305
+ # already got the request spec; skip
306
+ continue
307
+ else:
308
+ # query info of related tasks
309
+ sql_query_requests = (
310
+ f"SELECT {DataCarouselRequestSpec.columnNames()} "
311
+ f"FROM {panda_config.schemaJEDI}.data_carousel_requests "
312
+ f"WHERE request_id=:request_id "
313
+ )
314
+ var_map = {":request_id": request_id}
315
+ self.cur.execute(sql_query_requests + comment, var_map)
316
+ req_res_list = self.cur.fetchall()
317
+ # make request spec
318
+ dc_req_spec = DataCarouselRequestSpec()
319
+ for req_res in req_res_list:
320
+ dc_req_spec.pack(req_res)
321
+ break
322
+ # fill requests map
323
+ ret_requests_map[request_id] = dc_req_spec
324
+ else:
325
+ tmp_log.debug("no request")
326
+ # commit
327
+ if not self._commit():
328
+ raise RuntimeError("Commit error")
329
+ # return
330
+ tmp_log.debug(f"got {len(ret_requests_map)} requests of {len(ret_relation_map)} active tasks")
331
+ return ret_requests_map, ret_relation_map
332
+ except Exception:
333
+ # roll back
334
+ self._rollback()
335
+ # error
336
+ self.dump_error_message(tmp_log)
337
+ return None
338
+
339
+ # get related tasks and their info of a data carousel request
340
+ def get_related_tasks_of_data_carousel_request_JEDI(self, request_id, status_filter_list=None, status_exclusion_list=None):
341
+ comment = " /* JediDBProxy.get_related_tasks_of_data_carousel_request_JEDI */"
342
+ tmp_log = self.create_tagged_logger(comment, f"request_id={request_id}")
343
+ tmp_log.debug("start")
344
+ try:
345
+ # initialize
346
+ ret_tasks_dict = {}
347
+ # start transaction
348
+ self.conn.begin()
349
+ # sql to query related tasks
350
+ sql_query = (
351
+ f"SELECT rel.task_id, t.status "
352
+ f"FROM {panda_config.schemaJEDI}.data_carousel_relations rel, {panda_config.schemaJEDI}.JEDI_Tasks t "
353
+ f"WHERE rel.task_id=t.jediTaskID "
354
+ f"AND rel.request_id=:request_id "
355
+ )
356
+ var_map = {":request_id": request_id}
357
+ if status_filter_list:
358
+ status_var_names_str, status_var_map = get_sql_IN_bind_variables(status_filter_list, prefix=":status")
359
+ sql_query += f"AND t.status IN ({status_var_names_str}) "
360
+ var_map.update(status_var_map)
361
+ tmp_log.debug(f"status filter: {status_filter_list}")
362
+ if status_exclusion_list:
363
+ antistatus_var_names_str, antistatus_var_map = get_sql_IN_bind_variables(status_exclusion_list, prefix=":antistatus")
364
+ sql_query += f"AND t.status NOT IN ({antistatus_var_names_str}) "
365
+ var_map.update(antistatus_var_map)
366
+ tmp_log.debug(f"status exclusion filter: {status_exclusion_list}")
367
+ self.cur.execute(sql_query + comment, var_map)
368
+ res_list = self.cur.fetchall()
369
+ if res_list:
370
+ for task_id, status in res_list:
371
+ ret_tasks_dict[task_id] = {"task_id": task_id, "status": status}
372
+ else:
373
+ tmp_log.debug("no related task")
374
+ # commit
375
+ if not self._commit():
376
+ raise RuntimeError("Commit error")
377
+ # return
378
+ tmp_log.debug(f"got {len(ret_tasks_dict)} related tasks")
379
+ return ret_tasks_dict
380
+ except Exception:
381
+ # roll back
382
+ self._rollback()
383
+ # error
384
+ self.dump_error_message(tmp_log)
385
+ return None
386
+
387
+ # get data carousel staging requests
388
+ def get_data_carousel_staging_requests_JEDI(self, time_limit_minutes=5):
389
+ comment = " /* JediDBProxy.get_data_carousel_staging_requests_JEDI */"
390
+ tmp_log = self.create_tagged_logger(comment)
391
+ tmp_log.debug("start")
392
+ try:
393
+ # initialize
394
+ ret_list = []
395
+ # start transaction
396
+ self.conn.begin()
397
+ # sql to query staging requests
398
+ sql_query_req = (
399
+ f"SELECT {DataCarouselRequestSpec.columnNames()} "
400
+ f"FROM {panda_config.schemaJEDI}.data_carousel_requests "
401
+ f"WHERE status=:status "
402
+ f"AND ( check_time IS NULL OR check_time<=:check_time_max ) "
403
+ )
404
+ now_time = naive_utcnow()
405
+ var_map = {":status": DataCarouselRequestStatus.staging, ":check_time_max": now_time - datetime.timedelta(minutes=time_limit_minutes)}
406
+ self.cur.execute(sql_query_req + comment, var_map)
407
+ res_list = self.cur.fetchall()
408
+ if res_list:
409
+ now_time = naive_utcnow()
410
+ sql_update = f"UPDATE {panda_config.schemaJEDI}.data_carousel_requests " f"SET check_time=:check_time " f"WHERE request_id=:request_id "
411
+ for res in res_list:
412
+ # make request spec
413
+ dc_req_spec = DataCarouselRequestSpec()
414
+ dc_req_spec.pack(res)
415
+ # update check time
416
+ var_map = {":request_id": dc_req_spec.request_id, ":check_time": now_time}
417
+ self.cur.execute(sql_update + comment, var_map)
418
+ # add
419
+ ret_list.append(dc_req_spec)
420
+ else:
421
+ tmp_log.debug("no staging request")
422
+ # commit
423
+ if not self._commit():
424
+ raise RuntimeError("Commit error")
425
+ # return
426
+ tmp_log.debug(f"got {len(ret_list)} staging requests")
427
+ return ret_list
428
+ except Exception:
429
+ # roll back
430
+ self._rollback()
431
+ # error
432
+ self.dump_error_message(tmp_log)
433
+ return None
434
+
435
+ # delete data carousel requests
436
+ def delete_data_carousel_requests_JEDI(self, request_id_list):
437
+ comment = " /* JediDBProxy.delete_data_carousel_requests_JEDI */"
438
+ tmp_log = self.create_tagged_logger(comment)
439
+ tmp_log.debug("start")
440
+ try:
441
+ # start transaction
442
+ self.conn.begin()
443
+ # sql to delete terminated requests
444
+ status_var_names_str, status_var_map = get_sql_IN_bind_variables(DataCarouselRequestStatus.final_statuses, prefix=":status")
445
+ sql_delete_req = (
446
+ f"DELETE FROM {panda_config.schemaJEDI}.data_carousel_requests " f"WHERE request_id=:request_id " f"AND status IN ({status_var_names_str}) "
447
+ )
448
+ var_map_base = {}
449
+ var_map_base.update(status_var_map)
450
+ var_map_list = []
451
+ for request_id in request_id_list:
452
+ var_map = var_map_base.copy()
453
+ var_map[":request_id"] = request_id
454
+ var_map_list.append(var_map)
455
+ self.cur.executemany(sql_delete_req + comment, var_map_list)
456
+ ret_req = self.cur.rowcount
457
+ # sql to delete relations
458
+ sql_delete_rel = (
459
+ f"DELETE FROM {panda_config.schemaJEDI}.data_carousel_relations rel "
460
+ f"WHERE rel.request_id NOT IN "
461
+ f"(SELECT req.request_id FROM {panda_config.schemaJEDI}.data_carousel_requests req) "
462
+ )
463
+ self.cur.execute(sql_delete_rel + comment, {})
464
+ ret_rel = self.cur.rowcount
465
+ # commit
466
+ if not self._commit():
467
+ raise RuntimeError("Commit error")
468
+ # return
469
+ tmp_log.debug(f"cleaned up {ret_req}/{len(request_id_list)} requests and {ret_rel} relations")
470
+ return ret_req
471
+ except Exception:
472
+ # roll back
473
+ self._rollback()
474
+ # error
475
+ self.dump_error_message(tmp_log)
476
+ return None
477
+
478
+ # clean up data carousel requests
479
+ def clean_up_data_carousel_requests_JEDI(self, time_limit_days=30):
480
+ comment = " /* JediDBProxy.clean_up_data_carousel_requests_JEDI */"
481
+ tmp_log = self.create_tagged_logger(comment)
482
+ tmp_log.debug("start")
483
+ try:
484
+ # start transaction
485
+ self.conn.begin()
486
+ # sql to delete terminated requests
487
+ now_time = naive_utcnow()
488
+ status_var_names_str, status_var_map = get_sql_IN_bind_variables(DataCarouselRequestStatus.final_statuses, prefix=":status")
489
+ sql_delete_req = (
490
+ f"DELETE FROM {panda_config.schemaJEDI}.data_carousel_requests " f"WHERE status IN ({status_var_names_str}) " f"AND end_time<=:end_time_max "
491
+ )
492
+ var_map = {":end_time_max": now_time - datetime.timedelta(days=time_limit_days)}
493
+ var_map.update(status_var_map)
494
+ self.cur.execute(sql_delete_req + comment, var_map)
495
+ ret_req = self.cur.rowcount
496
+ # sql to delete relations
497
+ sql_delete_rel = (
498
+ f"DELETE FROM {panda_config.schemaJEDI}.data_carousel_relations rel "
499
+ f"WHERE rel.request_id NOT IN "
500
+ f"(SELECT req.request_id FROM {panda_config.schemaJEDI}.data_carousel_requests req) "
501
+ )
502
+ self.cur.execute(sql_delete_rel + comment, {})
503
+ ret_rel = self.cur.rowcount
504
+ # commit
505
+ if not self._commit():
506
+ raise RuntimeError("Commit error")
507
+ # return
508
+ tmp_log.debug(f"cleaned up {ret_req} requests and {ret_rel} relations older than {time_limit_days} days")
509
+ return ret_req
510
+ except Exception:
511
+ # roll back
512
+ self._rollback()
513
+ # error
514
+ self.dump_error_message(tmp_log)
515
+ return None
516
+
517
+ # cancel a data carousel request
518
+ def cancel_data_carousel_request_JEDI(self, request_id):
519
+ comment = " /* JediDBProxy.cancel_data_carousel_request_JEDI */"
520
+ tmp_log = self.create_tagged_logger(comment, f"request_id={request_id}")
521
+ tmp_log.debug("start")
522
+ try:
523
+ # start transaction
524
+ self.conn.begin()
525
+ # sql to update request status to cancelled
526
+ now_time = naive_utcnow()
527
+ status_var_names_str, status_var_map = get_sql_IN_bind_variables(DataCarouselRequestStatus.active_statuses, prefix=":old_status")
528
+ sql_update = (
529
+ f"UPDATE {panda_config.schemaJEDI}.data_carousel_requests "
530
+ f"SET status=:new_status, end_time=:now_time, modification_time=:now_time "
531
+ f"WHERE request_id=:request_id "
532
+ f"AND status IN ({status_var_names_str}) "
533
+ )
534
+ var_map = {
535
+ ":request_id": request_id,
536
+ ":new_status": DataCarouselRequestStatus.cancelled,
537
+ ":now_time": now_time,
538
+ }
539
+ var_map.update(status_var_map)
540
+ self.cur.execute(sql_update + comment, var_map)
541
+ ret_req = self.cur.rowcount
542
+ if not ret_req:
543
+ tmp_log.warning(f"already terminated; cannot be cancelled ; skipped")
544
+ else:
545
+ tmp_log.debug(f"cancelled request")
546
+ # commit
547
+ if not self._commit():
548
+ raise RuntimeError("Commit error")
549
+ # return
550
+ return ret_req
551
+ except Exception:
552
+ # roll back
553
+ self._rollback()
554
+ # error
555
+ self.dump_error_message(tmp_log)
556
+ return None
557
+
558
+ # retire a data carousel request
559
+ def retire_data_carousel_request_JEDI(self, request_id):
560
+ comment = " /* JediDBProxy.retire_data_carousel_request_JEDI */"
561
+ tmp_log = self.create_tagged_logger(comment, f"request_id={request_id}")
562
+ tmp_log.debug("start")
563
+ try:
564
+ # start transaction
565
+ self.conn.begin()
566
+ # sql to update request status to retired
567
+ now_time = naive_utcnow()
568
+ sql_update = (
569
+ f"UPDATE {panda_config.schemaJEDI}.data_carousel_requests "
570
+ f"SET status=:new_status, modification_time=:now_time "
571
+ f"WHERE request_id=:request_id "
572
+ f"AND status=:old_status "
573
+ )
574
+ var_map = {
575
+ ":request_id": request_id,
576
+ ":old_status": DataCarouselRequestStatus.done,
577
+ ":new_status": DataCarouselRequestStatus.retired,
578
+ ":now_time": now_time,
579
+ }
580
+ self.cur.execute(sql_update + comment, var_map)
581
+ ret_req = self.cur.rowcount
582
+ if not ret_req:
583
+ tmp_log.warning(f"not done; cannot be retired ; skipped")
584
+ else:
585
+ tmp_log.debug(f"retired request")
586
+ # commit
587
+ if not self._commit():
588
+ raise RuntimeError("Commit error")
589
+ # return
590
+ return ret_req
591
+ except Exception:
592
+ # roll back
593
+ self._rollback()
594
+ # error
595
+ self.dump_error_message(tmp_log)
596
+ return None
597
+
598
+ # resubmit a data carousel request
599
+ def resubmit_data_carousel_request_JEDI(self, request_id, exclude_prev_dst=False):
600
+ comment = " /* JediDBProxy.resubmit_data_carousel_request_JEDI */"
601
+ tmp_log = self.create_tagged_logger(comment, f"request_id={request_id} exclude_prev_dst={exclude_prev_dst}")
602
+ tmp_log.debug("start")
603
+ try:
604
+ # start transaction
605
+ self.conn.begin()
606
+ # get request spec
607
+ dc_req_spec = None
608
+ status_var_names_str, status_var_map = get_sql_IN_bind_variables(DataCarouselRequestStatus.resubmittable_statuses, prefix=":status")
609
+ sql_query_req = (
610
+ f"SELECT {DataCarouselRequestSpec.columnNames()} "
611
+ f"FROM {panda_config.schemaJEDI}.data_carousel_requests "
612
+ f"WHERE request_id=:request_id "
613
+ f"AND status IN ({status_var_names_str}) "
614
+ )
615
+ var_map = {":request_id": request_id}
616
+ var_map.update(status_var_map)
617
+ self.cur.execute(sql_query_req + comment, var_map)
618
+ res_list = self.cur.fetchall()
619
+ for res in res_list:
620
+ # make request spec
621
+ dc_req_spec = DataCarouselRequestSpec()
622
+ dc_req_spec.pack(res)
623
+ break
624
+ # prepare new request spec to resubmit
625
+ if dc_req_spec:
626
+ dc_req_spec_to_resubmit = get_resubmit_request_spec(dc_req_spec, exclude_prev_dst)
627
+ else:
628
+ # roll back
629
+ self._rollback()
630
+ return False
631
+ # sql to update old request status (staging to cancelled, done to retired, others intact)
632
+ now_time = naive_utcnow()
633
+ if dc_req_spec.status == DataCarouselRequestStatus.staging:
634
+ new_status = DataCarouselRequestStatus.cancelled
635
+ sql_update = (
636
+ f"UPDATE {panda_config.schemaJEDI}.data_carousel_requests "
637
+ f"SET status=:new_status, end_time=:now_time, modification_time=:now_time "
638
+ f"WHERE request_id=:request_id "
639
+ )
640
+ var_map = {
641
+ ":request_id": request_id,
642
+ ":new_status": new_status,
643
+ ":now_time": now_time,
644
+ }
645
+ self.cur.execute(sql_update + comment, var_map)
646
+ ret_req = self.cur.rowcount
647
+ if not ret_req:
648
+ tmp_log.warning(f"cannot be cancelled ; skipped")
649
+ # roll back
650
+ self._rollback()
651
+ return False
652
+ else:
653
+ tmp_log.debug(f"cancelled request")
654
+ elif dc_req_spec.status == DataCarouselRequestStatus.done:
655
+ new_status = DataCarouselRequestStatus.retired
656
+ sql_update = (
657
+ f"UPDATE {panda_config.schemaJEDI}.data_carousel_requests "
658
+ f"SET status=:new_status, modification_time=:now_time "
659
+ f"WHERE request_id=:request_id "
660
+ )
661
+ var_map = {
662
+ ":request_id": request_id,
663
+ ":new_status": new_status,
664
+ ":now_time": now_time,
665
+ }
666
+ self.cur.execute(sql_update + comment, var_map)
667
+ ret_req = self.cur.rowcount
668
+ if not ret_req:
669
+ tmp_log.warning(f"cannot be retired ; skipped")
670
+ # roll back
671
+ self._rollback()
672
+ return False
673
+ else:
674
+ tmp_log.debug(f"retired request")
675
+ else:
676
+ tmp_log.debug(f"already {dc_req_spec.status} ; skipped")
677
+ # resubmit new request
678
+ # sql to insert request
679
+ sql_insert_request = (
680
+ f"INSERT INTO {panda_config.schemaJEDI}.data_carousel_requests ({dc_req_spec_to_resubmit.columnNames()}) "
681
+ f"{dc_req_spec_to_resubmit.bindValuesExpression()} "
682
+ f"RETURNING request_id INTO :new_request_id "
683
+ )
684
+ var_map = dc_req_spec_to_resubmit.valuesMap(useSeq=True)
685
+ var_map[":new_request_id"] = self.cur.var(varNUMBER)
686
+ self.cur.execute(sql_insert_request + comment, var_map)
687
+ new_request_id = int(self.getvalue_corrector(self.cur.getvalue(var_map[":new_request_id"])))
688
+ if new_request_id is None:
689
+ raise RuntimeError("new_request_id is None")
690
+ tmp_log.debug(f"resubmitted request with new_request_id={new_request_id}")
691
+ # sql to update relations according to the relations of the old request
692
+ sql_update_relations = (
693
+ f"UPDATE {panda_config.schemaJEDI}.data_carousel_relations " f"SET request_id=:new_request_id " f"WHERE request_id=:old_request_id "
694
+ )
695
+ var_map = {":new_request_id": new_request_id, ":old_request_id": request_id}
696
+ self.cur.execute(sql_update_relations + comment, var_map)
697
+ ret_rel = self.cur.rowcount
698
+ tmp_log.debug(f"updated {ret_rel} relations about new_request_id={new_request_id}")
699
+ # fill new request_id
700
+ dc_req_spec_resubmitted = dc_req_spec_to_resubmit
701
+ dc_req_spec_resubmitted.request_id = new_request_id
702
+ # commit
703
+ if not self._commit():
704
+ raise RuntimeError("Commit error")
705
+ # return
706
+ return dc_req_spec_resubmitted
707
+ except Exception:
708
+ # roll back
709
+ self._rollback()
710
+ # error
711
+ self.dump_error_message(tmp_log)
712
+ return None
713
+
714
+ # get pending data carousel tasks and their input datasets
715
+ def get_pending_dc_tasks_JEDI(self, task_type="prod", time_limit_minutes=60):
716
+ comment = " /* JediDBProxy.get_pending_dc_tasks_JEDI */"
717
+ tmp_log = self.create_tagged_logger(comment)
718
+ tmp_log.debug("start")
719
+ try:
720
+ # sql to get pending tasks
721
+ sql_tasks = (
722
+ "SELECT tabT.jediTaskID, tabT.splitRule "
723
+ "FROM {0}.JEDI_Tasks tabT, {0}.JEDI_AUX_Status_MinTaskID tabA "
724
+ "WHERE tabT.status=:status AND tabA.status=tabT.status "
725
+ "AND tabT.taskType=:taskType AND tabT.modificationTime<:timeLimit".format(panda_config.schemaJEDI)
726
+ )
727
+ # sql to get input dataset
728
+ sql_ds = (
729
+ "SELECT tabD.datasetID, tabD.datasetName "
730
+ "FROM {0}.JEDI_Datasets tabD "
731
+ "WHERE tabD.jediTaskID=:jediTaskID AND tabD.type IN (:type1, :type2) ".format(panda_config.schemaJEDI)
732
+ )
733
+ # initialize
734
+ ret_tasks_dict = {}
735
+ # start transaction
736
+ self.conn.begin()
737
+ # get pending tasks
738
+ var_map = {":status": "pending", ":taskType": task_type}
739
+ var_map[":timeLimit"] = naive_utcnow() - datetime.timedelta(minutes=time_limit_minutes)
740
+ self.cur.execute(sql_tasks + comment, var_map)
741
+ res = self.cur.fetchall()
742
+ if res:
743
+ for task_id, split_rule in res:
744
+ tmp_taskspec = JediTaskSpec()
745
+ tmp_taskspec.splitRule = split_rule
746
+ if tmp_taskspec.inputPreStaging():
747
+ # is data carousel task
748
+ var_map = {
749
+ ":jediTaskID": task_id,
750
+ ":type1": "input",
751
+ ":type2": "pseudo_input",
752
+ }
753
+ self.cur.execute(sql_ds + comment, var_map)
754
+ ds_res = self.cur.fetchall()
755
+ if ds_res:
756
+ ret_tasks_dict[task_id] = []
757
+ for ds_id, ds_name in ds_res:
758
+ ret_tasks_dict[task_id].append(ds_name)
759
+ else:
760
+ tmp_log.debug("no pending task")
761
+ # commit
762
+ if not self._commit():
763
+ raise RuntimeError("Commit error")
764
+ # return
765
+ tmp_log.debug(f"found pending dc tasks: {ret_tasks_dict}")
766
+ return ret_tasks_dict
767
+ except Exception:
768
+ # roll back
769
+ self._rollback()
770
+ # error
771
+ self.dump_error_message(tmp_log)
772
+ return None