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,259 @@
1
+ import json
2
+ import random
3
+ import re
4
+ import traceback
5
+
6
+ from pandaserver.config import panda_config
7
+ from pandaserver.dataservice import DataServiceUtils
8
+ from pandaserver.taskbuffer import JobUtils
9
+ from pandaserver.taskbuffer.JediTaskSpec import JediTaskSpec
10
+
11
+ from .TaskRefinerBase import TaskRefinerBase
12
+
13
+
14
+ # brokerage for ATLAS analysis
15
+ class AtlasAnalTaskRefiner(TaskRefinerBase):
16
+ # constructor
17
+ def __init__(self, taskBufferIF, ddmIF):
18
+ TaskRefinerBase.__init__(self, taskBufferIF, ddmIF)
19
+
20
+ # extract common parameters
21
+ def extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule):
22
+ processingTypes = taskParamMap["processingType"].split("-")
23
+ # set ddmBackEnd
24
+ if "ddmBackEnd" not in taskParamMap:
25
+ taskParamMap["ddmBackEnd"] = "rucio"
26
+ # set sourceURL
27
+ try:
28
+ if "sourceURL" in taskParamMap:
29
+ for tmpItem in taskParamMap["jobParameters"]:
30
+ if "value" in tmpItem:
31
+ tmpItem["value"] = re.sub("\$\{SURL\}", taskParamMap["sourceURL"], tmpItem["value"])
32
+ except Exception:
33
+ pass
34
+ if hasattr(panda_config, "wn_script_base_url"):
35
+ base_url = panda_config.wn_script_base_url
36
+ else:
37
+ protocol = "https" if panda_config.pserverportcache == 443 else "http"
38
+ base_url = f"{protocol}://{panda_config.pserveralias}:{panda_config.pserverportcache}"
39
+ # set transPath
40
+ if "transPath" not in taskParamMap:
41
+ if "athena" in processingTypes:
42
+ # athena
43
+ taskParamMap["transPath"] = f"{base_url}/trf/user/runAthena-00-00-12"
44
+ elif "cont" in processingTypes:
45
+ # container
46
+ taskParamMap["transPath"] = f"{base_url}/trf/user/runcontainer"
47
+ else:
48
+ # general executable
49
+ taskParamMap["transPath"] = f"{base_url}/trf/user/runGen-00-00-02"
50
+ # shorter base walltime
51
+ if "baseWalltime" not in taskParamMap:
52
+ taskParamMap["baseWalltime"] = 60
53
+ # set transPath for build
54
+ if "buildSpec" in taskParamMap and "transPath" not in taskParamMap["buildSpec"]:
55
+ if "athena" in processingTypes:
56
+ # athena
57
+ taskParamMap["buildSpec"]["transPath"] = f"{base_url}/trf/user/buildJob-00-00-03"
58
+ else:
59
+ # general executable
60
+ taskParamMap["buildSpec"]["transPath"] = f"{base_url}/trf/user/buildGen-00-00-01"
61
+ # set transPath for preprocessing
62
+ if "preproSpec" in taskParamMap and "transPath" not in taskParamMap["preproSpec"]:
63
+ if "evp" in processingTypes:
64
+ # event picking
65
+ taskParamMap["preproSpec"]["transPath"] = f"{base_url}/trf/user/preEvtPick-00-00-01"
66
+ elif "grl" in processingTypes:
67
+ # good run list
68
+ taskParamMap["preproSpec"]["transPath"] = f"{base_url}/trf/user/preGoodRunList-00-00-01"
69
+ # set transPath for merge
70
+ if "mergeSpec" in taskParamMap and "transPath" not in taskParamMap["mergeSpec"]:
71
+ taskParamMap["mergeSpec"]["transPath"] = f"{base_url}/trf/user/runMerge-00-00-02"
72
+ # min ram count
73
+ if "ramCount" not in taskParamMap:
74
+ taskParamMap["ramCount"] = 2000
75
+ taskParamMap["ramUnit"] = "MBPerCore"
76
+ # disk count
77
+ if "outDiskCount" not in taskParamMap:
78
+ out_disk_count_default = self.taskBufferIF.getConfigValue("taskrefiner", "OUTDISKCOUNT_ANALY_KB", "jedi", "atlas")
79
+ if out_disk_count_default is None or out_disk_count_default < 0:
80
+ out_disk_count_default = 500
81
+ taskParamMap["outDiskCount"] = out_disk_count_default
82
+ taskParamMap["outDiskUnit"] = "kB"
83
+ # set cpu time unit to use HS06
84
+ if "cpuTimeUnit" not in taskParamMap:
85
+ taskParamMap["cpuTimeUnit"] = "HS06sPerEvent"
86
+ # use local IO for ancient releases since inputfilepeeker+xrootd is problematic
87
+ if "transUses" in taskParamMap and taskParamMap["transUses"]:
88
+ try:
89
+ ver = taskParamMap["transUses"].split("-")[1]
90
+ m = re.search("^(\d{2})\.(\d{2})\.", ver)
91
+ if m is not None:
92
+ major = int(m.group(1))
93
+ minor = int(m.group(2))
94
+ if major < 20 or (major == 20 and minor <= 20):
95
+ taskParamMap["useLocalIO"] = 1
96
+ except Exception:
97
+ pass
98
+ # scout success rate
99
+ if "scoutSuccessRate" not in taskParamMap:
100
+ taskParamMap["scoutSuccessRate"] = 5
101
+ # directIO
102
+ if "useLocalIO" not in taskParamMap and "allowInputLAN" not in taskParamMap:
103
+ taskParamMap["allowInputLAN"] = "use"
104
+ # current priority
105
+ if "currentPriority" in taskParamMap and (taskParamMap["currentPriority"] < 900 or taskParamMap["currentPriority"] > 1100):
106
+ taskParamMap["currentPriority"] = 1000
107
+ isSU, isSG = self.taskBufferIF.isSuperUser(taskParamMap["userName"])
108
+ if isSU or (isSG and "workingGroup" in taskParamMap):
109
+ # super high priority to jump over others
110
+ if "currentPriority" not in taskParamMap or taskParamMap["currentPriority"] < JobUtils.priorityTasksToJumpOver:
111
+ taskParamMap["currentPriority"] = JobUtils.priorityTasksToJumpOver
112
+ # max attempts
113
+ if "maxAttempt" not in taskParamMap:
114
+ taskParamMap["maxAttempt"] = 10
115
+ if "maxFailure" not in taskParamMap:
116
+ taskParamMap["maxFailure"] = 3
117
+ # target walltime
118
+ if "maxWalltime" not in taskParamMap:
119
+ tgtWalltime = self.taskBufferIF.getConfigValue("taskrefiner", "USER_JOB_TARGET_WALLTIME", "jedi", "atlas")
120
+ if tgtWalltime:
121
+ taskParamMap["maxWalltime"] = tgtWalltime
122
+ # choose N % of tasks to enable input data motion
123
+ fracTaskWithDataMotion = self.taskBufferIF.getConfigValue("taskrefiner", "USER_TASKS_MOVE_INPUT", "jedi", "atlas")
124
+ if fracTaskWithDataMotion is not None and fracTaskWithDataMotion > 0:
125
+ if random.randint(1, 100) <= fracTaskWithDataMotion:
126
+ if "currentPriority" not in taskParamMap:
127
+ taskParamMap["currentPriority"] = taskParamMap["taskPriority"]
128
+ taskParamMap["taskPriority"] = 1001
129
+ # image name
130
+ if "container_name" not in taskParamMap:
131
+ try:
132
+ for tmpItem in taskParamMap["jobParameters"]:
133
+ if "value" in tmpItem:
134
+ tmpM = re.search("--containerImage\s+([^\s]+)", tmpItem["value"])
135
+ if tmpM is not None:
136
+ taskParamMap["container_name"] = tmpM.group(1)
137
+ break
138
+ except Exception:
139
+ pass
140
+ # extract container name from architecture
141
+ if "container_name" not in taskParamMap and "architecture" in taskParamMap and isinstance(taskParamMap["architecture"], str):
142
+ try:
143
+ # json-serialized architecture
144
+ check_str = json.loads(taskParamMap["architecture"]).get("encoded_platform", "")
145
+ except Exception:
146
+ # encoded architecture
147
+ check_str = taskParamMap["architecture"]
148
+ m = re.search(r"\+([^\s+@#&]+)", check_str)
149
+ if m:
150
+ # use the architecture as container name
151
+ tmp_container_name = m.group(1)
152
+ taskParamMap["container_name"] = tmp_container_name
153
+ # remove the container name from architecture
154
+ tmp_architecture = re.sub(rf"\+{tmp_container_name}", "", taskParamMap["architecture"])
155
+ taskParamMap["architecture"] = tmp_architecture
156
+ self.tmpLog.debug(f"tweaked architecture: container_name={tmp_container_name} new_architecture={tmp_architecture}")
157
+
158
+ # message driven, choose N % of tasks to enable
159
+ if "messageDriven" not in taskParamMap:
160
+ analy_md_percent = self.taskBufferIF.getConfigValue("taskrefiner", "USER_TASKS_MESSAGE_DRIVEN_PERCENT", "jedi", "atlas")
161
+ if analy_md_percent and random.uniform(0, 100) <= analy_md_percent:
162
+ taskParamMap["messageDriven"] = True
163
+ # push status changes, choose N % of tasks to enable
164
+ if "pushStatusChanges" not in taskParamMap:
165
+ analy_pc_percent = self.taskBufferIF.getConfigValue("taskrefiner", "USER_TASKS_PUSH_STATUS_CHANGES_PERCENT", "jedi", "atlas")
166
+ if analy_pc_percent and random.uniform(0, 100) <= analy_pc_percent:
167
+ taskParamMap["pushStatusChanges"] = True
168
+ # disable skipScout fot tasks without for group production role
169
+ if "skipScout" in taskParamMap and ("official" not in taskParamMap or not taskParamMap["official"]):
170
+ del taskParamMap["skipScout"]
171
+ # max core count
172
+ if "maxCoreCount" not in taskParamMap:
173
+ max_core_count = self.taskBufferIF.getConfigValue("taskrefiner", "USER_TASKS_MAX_CORE_COUNT", "jedi", "atlas")
174
+ if max_core_count is None:
175
+ max_core_count = 16
176
+ taskParamMap["maxCoreCount"] = max_core_count
177
+ # set forceStaged when input dataset is RAW
178
+ if "forceStaged" not in taskParamMap:
179
+ for item in taskParamMap.get("jobParameters", []):
180
+ if item["type"] == "template" and "dataset" in item and item["param_type"] == "input":
181
+ dataset_name = item["dataset"]
182
+ if DataServiceUtils.getDatasetType(dataset_name) == "RAW":
183
+ taskParamMap["forceStaged"] = True
184
+ break
185
+ # update task parameters
186
+ self.updatedTaskParams = taskParamMap
187
+ # call base method
188
+ TaskRefinerBase.extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule)
189
+
190
+ # main
191
+ def doRefine(self, jediTaskID, taskParamMap):
192
+ # make logger
193
+ tmpLog = self.tmpLog
194
+ tmpLog.debug(f"start taskType={self.taskSpec.taskType}")
195
+ try:
196
+ # preprocessing
197
+ tmpStat, taskParamMap = self.doPreProRefine(taskParamMap)
198
+ if tmpStat is True:
199
+ tmpLog.debug("done for preprocessing")
200
+ return self.SC_SUCCEEDED
201
+ if tmpStat is False:
202
+ # failed
203
+ tmpLog.error("doPreProRefine failed")
204
+ return self.SC_FAILED
205
+ # normal refine
206
+ self.doBasicRefine(taskParamMap)
207
+ # set nosplit+repeat for DBR
208
+ for datasetSpec in self.inSecDatasetSpecList:
209
+ # get the latest version of DBR
210
+ if datasetSpec.datasetName == "DBR_LATEST":
211
+ tmpLog.debug(f"resolving real name for {datasetSpec.datasetName}")
212
+ datasetSpec.datasetName = self.ddmIF.getInterface(self.taskSpec.vo).getLatestDBRelease(useResultCache=3600)
213
+ datasetSpec.containerName = datasetSpec.datasetName
214
+ # set attributes to DBR
215
+ if DataServiceUtils.isDBR(datasetSpec.datasetName):
216
+ datasetSpec.attributes = "repeat,nosplit"
217
+ # check invalid characters
218
+ for datasetSpec in self.outDatasetSpecList:
219
+ if not DataServiceUtils.checkInvalidCharacters(datasetSpec.datasetName):
220
+ errStr = f"invalid characters in {datasetSpec.datasetName}"
221
+ tmpLog.error(errStr)
222
+ self.taskSpec.setErrDiag(errStr, None)
223
+ return self.SC_FATAL
224
+ # destination
225
+ if "destination" in taskParamMap:
226
+ for datasetSpec in self.outDatasetSpecList:
227
+ datasetSpec.destination = taskParamMap["destination"]
228
+ # use build
229
+ if "buildSpec" in taskParamMap:
230
+ self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["useBuild"])
231
+ # use template dataset
232
+ self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["instantiateTmpl"])
233
+ self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["instantiateTmplSite"])
234
+ for datasetSpec in self.outDatasetSpecList:
235
+ datasetSpec.type = f"tmpl_{datasetSpec.type}"
236
+ # get jobsetID
237
+ tmpStat, tmpJobID = self.taskBufferIF.getUserJobsetID_JEDI(self.taskSpec.userName)
238
+ if not tmpStat:
239
+ tmpLog.error("failed to get jobsetID failed")
240
+ return self.SC_FAILED
241
+ self.taskSpec.reqID = tmpJobID
242
+ # site limitation
243
+ if "excludedSite" in taskParamMap and "includedSite" in taskParamMap:
244
+ self.taskSpec.setLimitedSites("incexc")
245
+ elif "excludedSite" in taskParamMap:
246
+ self.taskSpec.setLimitedSites("exc")
247
+ elif "includedSite" in taskParamMap:
248
+ self.taskSpec.setLimitedSites("inc")
249
+ # input prestaging
250
+ if self.taskSpec.inputPreStaging():
251
+ # set first contents feed flag
252
+ self.taskSpec.set_first_contents_feed(True)
253
+ except Exception as e:
254
+ errStr = f"doRefine failed with {str(e)}"
255
+ tmpLog.error(f"{errStr} {traceback.format_exc()}")
256
+ self.taskSpec.setErrDiag(errStr, None)
257
+ raise e
258
+ tmpLog.debug("done")
259
+ return self.SC_SUCCEEDED
@@ -0,0 +1,162 @@
1
+ import datetime
2
+ import json
3
+ import random
4
+ import re
5
+ import traceback
6
+
7
+ from pandacommon.pandautils.PandaUtils import naive_utcnow
8
+
9
+ from pandajedi.jedicore import JediException
10
+ from pandaserver.dataservice import DataServiceUtils
11
+
12
+ from .TaskRefinerBase import TaskRefinerBase
13
+
14
+
15
+ # brokerage for ATLAS production
16
+ class AtlasProdTaskRefiner(TaskRefinerBase):
17
+ # constructor
18
+ def __init__(self, taskBufferIF, ddmIF):
19
+ TaskRefinerBase.__init__(self, taskBufferIF, ddmIF)
20
+
21
+ # extract common parameters
22
+ def extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule):
23
+ tmpLog = self.tmpLog
24
+ # set ddmBackEnd
25
+ if "ddmBackEnd" not in taskParamMap:
26
+ taskParamMap["ddmBackEnd"] = "rucio"
27
+ # get number of unprocessed events for event service
28
+ autoEsConversion = False
29
+ if "esConvertible" in taskParamMap and taskParamMap["esConvertible"] is True:
30
+ maxPrio = self.taskBufferIF.getConfigValue("taskrefiner", "AES_MAXTASKPRIORITY", "jedi", "atlas")
31
+ minPrio = self.taskBufferIF.getConfigValue("taskrefiner", "AES_MINTASKPRIORITY", "jedi", "atlas")
32
+ if maxPrio is not None and maxPrio < taskParamMap["taskPriority"]:
33
+ pass
34
+ elif minPrio is not None and minPrio > taskParamMap["taskPriority"]:
35
+ pass
36
+ else:
37
+ # get threshold
38
+ minNumEvents = self.taskBufferIF.getConfigValue("taskrefiner", "AES_EVENTPOOLSIZE", "jedi", "atlas")
39
+ maxPending = self.taskBufferIF.getConfigValue("taskrefiner", "AES_MAXPENDING", "jedi", "atlas")
40
+ nEvents, lastTaskTime, nPendingTasks = self.taskBufferIF.getNumUnprocessedEvents_JEDI(
41
+ taskParamMap["vo"], taskParamMap["prodSourceLabel"], {"eventService": 1}, {"gshare": "Validation"}
42
+ )
43
+ tmpStr = "check for ES "
44
+ tmpStr += f"tot_num_unprocessed_events_AES={nEvents} target_num_events_AES={minNumEvents} last_AES_task_time={lastTaskTime} "
45
+ tmpStr += f"num_pending_tasks_AES={nPendingTasks} max_pending_tasks_AES={maxPending} "
46
+ tmpLog.info(tmpStr)
47
+ # not chane many tasks at once
48
+ if lastTaskTime is None or (lastTaskTime < naive_utcnow() - datetime.timedelta(minutes=5)):
49
+ if minNumEvents is not None and nEvents < minNumEvents and maxPending is not None and (maxPending is None or maxPending > nPendingTasks):
50
+ autoEsConversion = True
51
+ tmpLog.info("will be converted to AES unless it goes to pending")
52
+ # add ES paramsters
53
+ if ("esFraction" in taskParamMap and taskParamMap["esFraction"] > 0) or ("esConvertible" in taskParamMap and taskParamMap["esConvertible"] is True):
54
+ tmpStr = "<PANDA_ES_ONLY>--eventService=True</PANDA_ES_ONLY>"
55
+ taskParamMap["jobParameters"].append({"type": "constant", "value": tmpStr})
56
+ if ("esFraction" in taskParamMap and taskParamMap["esFraction"] > 0) or autoEsConversion:
57
+ if "nEventsPerWorker" not in taskParamMap and (("esFraction" in taskParamMap and taskParamMap["esFraction"] > random.random()) or autoEsConversion):
58
+ taskParamMap["nEventsPerWorker"] = 1
59
+ taskParamMap["registerEsFiles"] = True
60
+ if "nEsConsumers" not in taskParamMap:
61
+ tmpVal = self.taskBufferIF.getConfigValue("taskrefiner", "AES_NESCONSUMERS", "jedi", "atlas")
62
+ if tmpVal is None:
63
+ tmpVal = 1
64
+ taskParamMap["nEsConsumers"] = tmpVal
65
+ if "nSitesPerJob" not in taskParamMap:
66
+ tmpVal = self.taskBufferIF.getConfigValue("taskrefiner", "AES_NSITESPERJOB", "jedi", "atlas")
67
+ if tmpVal is not None:
68
+ taskParamMap["nSitesPerJob"] = tmpVal
69
+ if "mergeEsOnOS" not in taskParamMap:
70
+ taskParamMap["mergeEsOnOS"] = True
71
+ if "maxAttemptES" not in taskParamMap:
72
+ taskParamMap["maxAttemptES"] = 1
73
+ if "maxAttemptEsJob" not in taskParamMap:
74
+ taskParamMap["maxAttemptEsJob"] = 0
75
+ if "notDiscardEvents" not in taskParamMap:
76
+ taskParamMap["notDiscardEvents"] = True
77
+ if "decAttOnFailedES" not in taskParamMap:
78
+ taskParamMap["decAttOnFailedES"] = True
79
+ taskParamMap["coreCount"] = 0
80
+ taskParamMap["resurrectConsumers"] = True
81
+ # push status changes, choose N % of tasks to enable
82
+ if "pushStatusChanges" not in taskParamMap:
83
+ prod_pc_percent = self.taskBufferIF.getConfigValue("taskrefiner", "PROD_TASKS_PUSH_STATUS_CHANGES_PERCENT", "jedi", "atlas")
84
+ if prod_pc_percent and random.uniform(0, 100) <= prod_pc_percent:
85
+ taskParamMap["pushStatusChanges"] = True
86
+ # serialize architecture
87
+ if "architecture" in taskParamMap and isinstance(taskParamMap["architecture"], dict):
88
+ # convert to string
89
+ taskParamMap["architecture"] = json.dumps(taskParamMap["architecture"])
90
+ # call base method
91
+ TaskRefinerBase.extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule)
92
+
93
+ # main
94
+ def doRefine(self, jediTaskID, taskParamMap):
95
+ # make logger
96
+ tmpLog = self.tmpLog
97
+ tmpLog.debug(f"start taskType={self.taskSpec.taskType}")
98
+ try:
99
+ # basic refine
100
+ self.doBasicRefine(taskParamMap)
101
+ # set nosplit+repeat for DBR
102
+ for datasetSpec in self.inSecDatasetSpecList:
103
+ if DataServiceUtils.isDBR(datasetSpec.datasetName):
104
+ datasetSpec.attributes = "repeat,nosplit"
105
+ # enable consistency check
106
+ if self.taskSpec.parent_tid not in [None, self.taskSpec.jediTaskID]:
107
+ for datasetSpec in self.inMasterDatasetSpec:
108
+ if datasetSpec.isMaster() and datasetSpec.type == "input":
109
+ datasetSpec.enableCheckConsistency()
110
+ # append attempt number
111
+ for tmpKey, tmpOutTemplateMapList in self.outputTemplateMap.items():
112
+ for tmpOutTemplateMap in tmpOutTemplateMapList:
113
+ outFileTemplate = tmpOutTemplateMap["filenameTemplate"]
114
+ if re.search("\.\d+$", outFileTemplate) is None and not outFileTemplate.endswith(".panda.um"):
115
+ tmpOutTemplateMap["filenameTemplate"] = outFileTemplate + ".1"
116
+ # extract input datatype
117
+ datasetTypeListIn = []
118
+ for datasetSpec in self.inMasterDatasetSpec + self.inSecDatasetSpecList:
119
+ datasetType = DataServiceUtils.getDatasetType(datasetSpec.datasetName)
120
+ if datasetType not in ["", None]:
121
+ datasetTypeListIn.append(datasetType)
122
+ # extract datatype and set destination if necessary
123
+ datasetTypeList = []
124
+ for datasetSpec in self.outDatasetSpecList:
125
+ datasetType = DataServiceUtils.getDatasetType(datasetSpec.datasetName)
126
+ if datasetType not in ["", None]:
127
+ datasetTypeList.append(datasetType)
128
+ # set numThrottled to use the task throttling mechanism
129
+ if "noThrottle" not in taskParamMap:
130
+ self.taskSpec.numThrottled = 0
131
+ # set to register datasets
132
+ self.taskSpec.setToRegisterDatasets()
133
+ # set transient to parent datasets
134
+ if self.taskSpec.processingType in ["merge"] and self.taskSpec.parent_tid not in [None, self.taskSpec.jediTaskID]:
135
+ # get parent
136
+ tmpStat, parentTaskSpec = self.taskBufferIF.getTaskDatasetsWithID_JEDI(self.taskSpec.parent_tid, None, False)
137
+ if tmpStat and parentTaskSpec is not None:
138
+ # set transient to parent datasets
139
+ metaData = {"transient": True}
140
+ for datasetSpec in parentTaskSpec.datasetSpecList:
141
+ if datasetSpec.type in ["log", "output"]:
142
+ datasetType = DataServiceUtils.getDatasetType(datasetSpec.datasetName)
143
+ if datasetType not in ["", None] and datasetType in datasetTypeList and datasetType in datasetTypeListIn:
144
+ tmpLog.info(
145
+ "set metadata={0} to parent jediTaskID={1}:datasetID={2}:Name={3}".format(
146
+ str(metaData), self.taskSpec.parent_tid, datasetSpec.datasetID, datasetSpec.datasetName
147
+ )
148
+ )
149
+ for metadataName, metadaValue in metaData.items():
150
+ self.ddmIF.getInterface(self.taskSpec.vo).setDatasetMetadata(datasetSpec.datasetName, metadataName, metadaValue)
151
+ # input prestaging
152
+ if self.taskSpec.inputPreStaging():
153
+ # set first contents feed flag
154
+ self.taskSpec.set_first_contents_feed(True)
155
+ except JediException.UnknownDatasetError as e:
156
+ tmpLog.debug(f"in doRefine. {str(e)}")
157
+ raise e
158
+ except Exception as e:
159
+ tmpLog.error(f"doRefine failed with {str(e)} {traceback.format_exc()}")
160
+ raise e
161
+ tmpLog.debug("done")
162
+ return self.SC_SUCCEEDED
@@ -0,0 +1,61 @@
1
+ import re
2
+
3
+ from pandaserver.taskbuffer.JediTaskSpec import JediTaskSpec
4
+
5
+ from .TaskRefinerBase import TaskRefinerBase
6
+
7
+
8
+ # refiner for general purpose
9
+ class GenTaskRefiner(TaskRefinerBase):
10
+ # constructor
11
+ def __init__(self, taskBufferIF, ddmIF):
12
+ TaskRefinerBase.__init__(self, taskBufferIF, ddmIF)
13
+
14
+ # extract common parameters
15
+ def extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule):
16
+ if "cloud" not in taskParamMap and "workingGroup" in taskParamMap:
17
+ taskParamMap["cloud"] = taskParamMap["workingGroup"]
18
+ if "transPath" not in taskParamMap:
19
+ taskParamMap["transPath"] = "https://pandaserver-doma.cern.ch/trf/user/runGen-00-00-02"
20
+ # set sourceURL
21
+ try:
22
+ if "sourceURL" in taskParamMap:
23
+ for tmpItem in taskParamMap["jobParameters"]:
24
+ if "value" in tmpItem:
25
+ tmpItem["value"] = re.sub("\$\{SURL\}", taskParamMap["sourceURL"], tmpItem["value"])
26
+ except Exception:
27
+ pass
28
+ # min ram count
29
+ if "ramCount" not in taskParamMap:
30
+ taskParamMap["ramCount"] = 2000
31
+ taskParamMap["ramUnit"] = "MBPerCore"
32
+ # push status changes
33
+ if "pushStatusChanges" not in taskParamMap:
34
+ taskParamMap["pushStatusChanges"] = True
35
+ # fine-grained
36
+ if "fineGrainedProc" in taskParamMap:
37
+ taskParamMap["notDiscardEvents"] = True
38
+ taskParamMap["maxAttemptEsJob"] = 0
39
+ taskParamMap["maxAttemptES"] = 1
40
+ # message driven
41
+ if "messageDriven" not in taskParamMap:
42
+ taskParamMap["messageDriven"] = True
43
+ # use cloud as VO
44
+ taskParamMap["cloudAsVO"] = True
45
+ # update task parameters
46
+ self.updatedTaskParams = taskParamMap
47
+ # call base method
48
+ TaskRefinerBase.extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule)
49
+
50
+ # main
51
+ def doRefine(self, jediTaskID, taskParamMap):
52
+ # normal refine
53
+ self.doBasicRefine(taskParamMap)
54
+ # get DDM I/F to check
55
+ if self.ddmIF.getInterface(self.taskSpec.vo, self.taskSpec.cloud):
56
+ # use template dataset
57
+ self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["instantiateTmpl"])
58
+ self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["instantiateTmplSite"])
59
+ for datasetSpec in self.outDatasetSpecList:
60
+ datasetSpec.type = f"tmpl_{datasetSpec.type}"
61
+ return self.SC_SUCCEEDED
@@ -0,0 +1,154 @@
1
+ import json
2
+ import re
3
+
4
+
5
+ # convert UTF-8 to ASCII in json dumps
6
+ def unicodeConvert(input):
7
+ if isinstance(input, dict):
8
+ retMap = {}
9
+ for tmpKey, tmpVal in input.items():
10
+ retMap[unicodeConvert(tmpKey)] = unicodeConvert(tmpVal)
11
+ return retMap
12
+ elif isinstance(input, list):
13
+ retList = []
14
+ for tmpItem in input:
15
+ retList.append(unicodeConvert(tmpItem))
16
+ return retList
17
+
18
+ return input
19
+
20
+
21
+ # decode
22
+ def decodeJSON(inputStr):
23
+ return json.loads(inputStr, object_hook=unicodeConvert)
24
+
25
+
26
+ # encode
27
+ def encodeJSON(inputMap):
28
+ return json.dumps(inputMap)
29
+
30
+
31
+ # extract stream name
32
+ def extractStreamName(valStr):
33
+ tmpMatch = re.search("\$\{([^\}]+)\}", valStr)
34
+ if tmpMatch is None:
35
+ return None
36
+ # remove decorators
37
+ streamName = tmpMatch.group(1)
38
+ streamName = streamName.split("/")[0]
39
+ return streamName
40
+
41
+
42
+ # extract output filename template and replace the value field
43
+ def extractReplaceOutFileTemplate(valStr, streamName):
44
+ outFileTempl = valStr.split("=")[-1]
45
+ outFileTempl = outFileTempl.replace("'", "")
46
+ valStr = valStr.replace(outFileTempl, f"${{{streamName}}}")
47
+ return outFileTempl, valStr
48
+
49
+
50
+ # extract file list
51
+ def extractFileList(taskParamMap, datasetName):
52
+ baseDatasetName = datasetName.split(":")[-1]
53
+ if "log" in taskParamMap:
54
+ itemList = taskParamMap["jobParameters"] + [taskParamMap["log"]]
55
+ else:
56
+ itemList = taskParamMap["jobParameters"]
57
+ fileList = []
58
+ includePatt = []
59
+ excludePatt = []
60
+ for tmpItem in itemList:
61
+ if (
62
+ tmpItem["type"] == "template"
63
+ and "dataset" in tmpItem
64
+ and (
65
+ (tmpItem["dataset"] == datasetName or tmpItem["dataset"] == baseDatasetName)
66
+ or ("expandedList" in tmpItem and (datasetName in tmpItem["expandedList"] or baseDatasetName in tmpItem["expandedList"]))
67
+ )
68
+ ):
69
+ if "files" in tmpItem:
70
+ fileList = tmpItem["files"]
71
+ if "include" in tmpItem:
72
+ includePatt = tmpItem["include"].split(",")
73
+ if "exclude" in tmpItem:
74
+ excludePatt = tmpItem["exclude"].split(",")
75
+ return fileList, includePatt, excludePatt
76
+
77
+
78
+ # append dataset
79
+ def appendDataset(taskParamMap, datasetSpec, fileList):
80
+ # make item for dataset
81
+ tmpItem = {}
82
+ tmpItem["type"] = "template"
83
+ tmpItem["value"] = ""
84
+ tmpItem["dataset"] = datasetSpec.datasetName
85
+ tmpItem["param_type"] = datasetSpec.type
86
+ if fileList != []:
87
+ tmpItem["files"] = fileList
88
+ # append
89
+ if "jobParameters" not in taskParamMap:
90
+ taskParamMap["jobParameters"] = []
91
+ taskParamMap["jobParameters"].append(tmpItem)
92
+ return taskParamMap
93
+
94
+
95
+ # check if use random seed
96
+ def useRandomSeed(taskParamMap):
97
+ for tmpItem in taskParamMap["jobParameters"]:
98
+ if "value" in tmpItem:
99
+ # get offset for random seed
100
+ if tmpItem["type"] == "template" and tmpItem["param_type"] == "number":
101
+ if "${RNDMSEED}" in tmpItem["value"]:
102
+ return True
103
+ return False
104
+
105
+
106
+ # get initial global share
107
+ def get_initial_global_share(task_buffer, task_id, task_spec=None, task_param_map=None):
108
+ """
109
+ Get the initial global share for a task
110
+ :param task_buffer: task buffer interface
111
+ :param task_id: task ID
112
+ :param task_spec: task specification object. read through task_buffer if None
113
+ :param task_param_map: task parameter map. read through task_buffer if None
114
+ :return:
115
+ """
116
+ if task_param_map is None:
117
+ # get task parameters from DB
118
+ tmp_str = task_buffer.getTaskParamsWithID_JEDI(task_id)
119
+ task_param_map = decodeJSON(tmp_str)
120
+ if "gshare" in task_param_map and task_buffer.is_valid_share(task_param_map["gshare"]):
121
+ # global share was already specified in ProdSys
122
+ gshare = task_param_map["gshare"]
123
+ else:
124
+ if task_spec is None:
125
+ # get task specification from DB
126
+ _, task_spec = task_buffer.getTaskWithID_JEDI(task_id)
127
+ # get share based on definition
128
+ gshare = task_buffer.get_share_for_task(task_spec)
129
+ if gshare == "Undefined":
130
+ error_message = "task definition does not match any global share"
131
+ raise RuntimeError(error_message)
132
+ return gshare
133
+
134
+
135
+ # get sandbox name
136
+ def get_sandbox_name(task_param_map: dict) -> str | None:
137
+ """
138
+ Get the sandbox name from the task parameters
139
+ :param task_param_map: dictionary of task parameters
140
+ :return: sandbox name or None
141
+ """
142
+ sandbox_name = None
143
+ if "fixedSandbox" in task_param_map:
144
+ sandbox_name = task_param_map["fixedSandbox"]
145
+ elif "buildSpec" in task_param_map:
146
+ sandbox_name = task_param_map["buildSpec"]["archiveName"]
147
+ else:
148
+ for tmpParam in task_param_map["jobParameters"]:
149
+ if tmpParam["type"] == "constant":
150
+ m = re.search("^-a ([^ ]+)$", tmpParam["value"])
151
+ if m is not None:
152
+ sandbox_name = m.group(1)
153
+ break
154
+ return sandbox_name