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,245 @@
1
+ import os
2
+ import socket
3
+ import sys
4
+ import traceback
5
+
6
+ from pandacommon.pandalogger.PandaLogger import PandaLogger
7
+
8
+ from pandajedi.jedibrokerage import AtlasBrokerUtils
9
+ from pandajedi.jediconfig import jedi_config
10
+ from pandajedi.jedicore.MsgWrapper import MsgWrapper
11
+ from pandaserver.dataservice import DataServiceUtils
12
+
13
+ from .WatchDogBase import WatchDogBase
14
+
15
+ logger = PandaLogger().getLogger(__name__.split(".")[-1])
16
+
17
+
18
+ # task withholder watchdog for ATLAS
19
+ class AtlasTaskWithholderWatchDog(WatchDogBase):
20
+ # constructor
21
+ def __init__(self, taskBufferIF, ddmIF):
22
+ WatchDogBase.__init__(self, taskBufferIF, ddmIF)
23
+ self.pid = f"{socket.getfqdn().split('.')[0]}-{os.getpid()}-dog"
24
+ # self.cronActions = {'forPrestage': 'atlas_prs'}
25
+ self.vo = "atlas"
26
+ self.prodSourceLabelList = ["managed"]
27
+ # call refresh
28
+ self.refresh()
29
+
30
+ # get process lock
31
+ def _get_lock(self):
32
+ return self.taskBufferIF.lockProcess_JEDI(
33
+ vo=self.vo,
34
+ prodSourceLabel="managed",
35
+ cloud=None,
36
+ workqueue_id=None,
37
+ resource_name=None,
38
+ component="AtlasTaskWithholderWatchDog",
39
+ pid=self.pid,
40
+ timeLimit=5,
41
+ )
42
+
43
+ # refresh information stored in the instance
44
+ def refresh(self):
45
+ # work queue mapper
46
+ self.workQueueMapper = self.taskBufferIF.getWorkQueueMap()
47
+ # site mapper
48
+ self.siteMapper = self.taskBufferIF.get_site_mapper()
49
+ # all sites
50
+ allSiteList = []
51
+ for siteName, tmpSiteSpec in self.siteMapper.siteSpecList.items():
52
+ # if tmpSiteSpec.type == 'analysis' or tmpSiteSpec.is_grandly_unified():
53
+ allSiteList.append(siteName)
54
+ self.allSiteList = allSiteList
55
+
56
+ # get map of site to list of RSEs and blacklisted RSEs
57
+ def get_site_rse_map_and_blacklisted_rse_set(self, prod_source_label):
58
+ site_rse_map = {}
59
+ blacklisted_rse_set = set()
60
+ for tmpPseudoSiteName in self.allSiteList:
61
+ tmpSiteSpec = self.siteMapper.getSite(tmpPseudoSiteName)
62
+ tmpSiteName = tmpSiteSpec.get_unified_name()
63
+ scope_input, scope_output = DataServiceUtils.select_scope(tmpSiteSpec, prod_source_label, prod_source_label)
64
+ try:
65
+ tmp_ddm_spec = tmpSiteSpec.ddm_endpoints_input[scope_input]
66
+ endpoint_name = tmpSiteSpec.ddm_input[scope_input]
67
+ endpoint_token_map = tmp_ddm_spec.getTokenMap("input")
68
+ tmp_endpoint = tmp_ddm_spec.getEndPoint(endpoint_name)
69
+ except KeyError:
70
+ continue
71
+ else:
72
+ # fill site rse map
73
+ site_rse_map[tmpSiteName] = list(endpoint_token_map.values())
74
+ # blacklisted rse
75
+ if tmp_endpoint is not None and tmp_endpoint["blacklisted"] == "Y":
76
+ blacklisted_rse_set.add(endpoint_name)
77
+ # return
78
+ return site_rse_map, blacklisted_rse_set
79
+
80
+ # get busy sites
81
+ def get_busy_sites(self, gshare, cutoff):
82
+ busy_sites_list = []
83
+ # get global share
84
+ tmpSt, jobStatPrioMap = self.taskBufferIF.getJobStatisticsByGlobalShare(self.vo)
85
+ if not tmpSt:
86
+ # got nothing...
87
+ return busy_sites_list
88
+ for tmpPseudoSiteName in self.allSiteList:
89
+ tmpSiteSpec = self.siteMapper.getSite(tmpPseudoSiteName)
90
+ tmpSiteName = tmpSiteSpec.get_unified_name()
91
+ # get nQueue and nRunning
92
+ nRunning = AtlasBrokerUtils.getNumJobs(jobStatPrioMap, tmpSiteName, "running", workQueue_tag=gshare)
93
+ nQueue = 0
94
+ for jobStatus in ["defined", "assigned", "activated", "starting"]:
95
+ nQueue += AtlasBrokerUtils.getNumJobs(jobStatPrioMap, tmpSiteName, jobStatus, workQueue_tag=gshare)
96
+ # busy sites
97
+ if nQueue > max(cutoff, nRunning * 2):
98
+ busy_sites_list.append(tmpSiteName)
99
+ # return
100
+ return busy_sites_list
101
+
102
+ # # handle waiting jobs
103
+ # def do_make_tasks_pending(self, task_list):
104
+ # tmpLog = MsgWrapper(logger, 'do_make_tasks_pending')
105
+ # tmpLog.debug('start')
106
+ # # check every x min
107
+ # checkInterval = 20
108
+ # # make task pending
109
+ # for taskID, pending_reason in task_list:
110
+ # tmpLog = MsgWrapper(logger, '< #ATM #KV do_make_tasks_pending jediTaskID={0}>'.format(taskID))
111
+ # retVal = self.taskBufferIF.makeTaskPending_JEDI(taskID, reason=pending_reason)
112
+ # tmpLog.debug('done with {0}'.format(retVal))
113
+
114
+ # set tasks to be pending due to condition of data locality
115
+ def do_for_data_locality(self):
116
+ tmp_log = MsgWrapper(logger)
117
+ # refresh
118
+ self.refresh()
119
+ # list of resource type
120
+ # resource_type_list = [ rt.resource_name for rt in self.taskBufferIF.load_resource_types() ]
121
+ # loop
122
+ for prod_source_label in self.prodSourceLabelList:
123
+ # site-rse map and blacklisted rses
124
+ site_rse_map, blacklisted_rse_set = self.get_site_rse_map_and_blacklisted_rse_set(prod_source_label)
125
+ tmp_log.debug(f"Found {len(blacklisted_rse_set)} blacklisted RSEs : {','.join(list(blacklisted_rse_set))}")
126
+ # parameter from GDP config
127
+ upplimit_ioIntensity = self.taskBufferIF.getConfigValue("task_withholder", f"LIMIT_IOINTENSITY_{prod_source_label}", "jedi", self.vo)
128
+ lowlimit_currentPriority = self.taskBufferIF.getConfigValue("task_withholder", f"LIMIT_PRIORITY_{prod_source_label}", "jedi", self.vo)
129
+ if upplimit_ioIntensity is None:
130
+ upplimit_ioIntensity = 999999
131
+ if lowlimit_currentPriority is None:
132
+ lowlimit_currentPriority = -999999
133
+ upplimit_ioIntensity = max(upplimit_ioIntensity, 100)
134
+ # get work queue for gshare
135
+ work_queue_list = self.workQueueMapper.getAlignedQueueList(self.vo, prod_source_label)
136
+ # loop over work queue
137
+ for work_queue in work_queue_list:
138
+ gshare = work_queue.queue_name
139
+ # get cutoff
140
+ cutoff = self.taskBufferIF.getConfigValue("jobbroker", f"NQUEUELIMITSITE_{gshare}", "jedi", self.vo)
141
+ if not cutoff:
142
+ cutoff = 20
143
+ # busy sites
144
+ busy_sites_list = self.get_busy_sites(gshare, cutoff)
145
+ # rses of busy sites
146
+ busy_rses = set()
147
+ for site in busy_sites_list:
148
+ try:
149
+ busy_rses.update(set(site_rse_map[site]))
150
+ except KeyError:
151
+ continue
152
+ # make sql parameters of rses
153
+ to_exclude_rses = list(busy_rses | blacklisted_rse_set)
154
+ if not to_exclude_rses:
155
+ continue
156
+ rse_params_list = []
157
+ rse_params_map = {}
158
+ for j, rse in enumerate(to_exclude_rses):
159
+ rse_param = f":rse_{j + 1}"
160
+ rse_params_list.append(rse_param)
161
+ rse_params_map[rse_param] = rse
162
+ rse_params_str = ",".join(rse_params_list)
163
+ # sql
164
+ sql_query = (
165
+ "SELECT t.jediTaskID "
166
+ "FROM {jedi_schema}.JEDI_Tasks t "
167
+ "WHERE t.status IN ('ready','running','scouting') AND t.lockedBy IS NULL "
168
+ "AND t.gshare=:gshare "
169
+ "AND t.ioIntensity>=:ioIntensity AND t.currentPriority<:currentPriority "
170
+ "AND EXISTS ( "
171
+ "SELECT * FROM {jedi_schema}.JEDI_Datasets d "
172
+ "WHERE d.jediTaskID=t.jediTaskID "
173
+ "AND d.type='input' "
174
+ ") "
175
+ "AND NOT EXISTS ( "
176
+ "SELECT * FROM {jedi_schema}.JEDI_Dataset_Locality dl "
177
+ "WHERE dl.jediTaskID=t.jediTaskID "
178
+ "AND dl.rse NOT IN ({rse_params_str}) "
179
+ ") "
180
+ ).format(jedi_schema=jedi_config.db.schemaJEDI, rse_params_str=rse_params_str)
181
+ # params map
182
+ params_map = {
183
+ ":gshare": gshare,
184
+ ":ioIntensity": upplimit_ioIntensity,
185
+ ":currentPriority": lowlimit_currentPriority,
186
+ }
187
+ params_map.update(rse_params_map)
188
+ # pending reason
189
+ reason = (
190
+ "no local input data, ioIntensity>={ioIntensity}, currentPriority<{currentPriority},"
191
+ "nQueue>max({cutOff},nRunning*2) at all sites where the task can run".format(
192
+ ioIntensity=upplimit_ioIntensity, currentPriority=lowlimit_currentPriority, cutOff=cutoff
193
+ )
194
+ )
195
+ # set pending
196
+ dry_run = False
197
+ if dry_run:
198
+ dry_sql_query = (
199
+ "SELECT t.jediTaskID "
200
+ "FROM {jedi_schema}.JEDI_Tasks t "
201
+ "WHERE t.status IN ('ready','running','scouting') AND t.lockedBy IS NULL "
202
+ "AND t.gshare=:gshare "
203
+ "AND t.ioIntensity>=:ioIntensity AND t.currentPriority<:currentPriority "
204
+ "AND EXISTS ( "
205
+ "SELECT * FROM {jedi_schema}.JEDI_Datasets d "
206
+ "WHERE d.jediTaskID=t.jediTaskID "
207
+ "AND d.type='input' "
208
+ ") "
209
+ "AND NOT EXISTS ( "
210
+ "SELECT * FROM {jedi_schema}.JEDI_Dataset_Locality dl "
211
+ "WHERE dl.jediTaskID=t.jediTaskID "
212
+ "AND dl.rse NOT IN ({rse_params_str}) "
213
+ ") "
214
+ ).format(jedi_schema=jedi_config.db.schemaJEDI, rse_params_str=rse_params_str)
215
+ res = self.taskBufferIF.querySQL(dry_sql_query, params_map)
216
+ n_tasks = 0 if res is None else len(res)
217
+ if n_tasks > 0:
218
+ result = [x[0] for x in res]
219
+ tmp_log.debug(f'[dry run] gshare: {gshare:<16} {n_tasks:>5} tasks would be pending : {result} ; reason="{reason}" ')
220
+ else:
221
+ n_tasks = self.taskBufferIF.queryTasksToBePending_JEDI(sql_query, params_map, reason)
222
+ if n_tasks is not None and n_tasks > 0:
223
+ tmp_log.info(f'gshare: {gshare:<16} {str(n_tasks):>5} tasks got pending ; reason="{reason}" ')
224
+
225
+ # main
226
+ def doAction(self):
227
+ try:
228
+ # get logger
229
+ origTmpLog = MsgWrapper(logger)
230
+ origTmpLog.debug("start")
231
+ # lock
232
+ got_lock = self._get_lock()
233
+ if not got_lock:
234
+ origTmpLog.debug("locked by another process. Skipped")
235
+ return self.SC_SUCCEEDED
236
+ origTmpLog.debug("got lock")
237
+ # make tasks pending under certain conditions
238
+ self.do_for_data_locality()
239
+ except Exception:
240
+ errtype, errvalue = sys.exc_info()[:2]
241
+ err_str = traceback.format_exc()
242
+ origTmpLog.error(f"failed with {errtype} {errvalue} ; {err_str}")
243
+ # return
244
+ origTmpLog.debug("done")
245
+ return self.SC_SUCCEEDED
@@ -0,0 +1,63 @@
1
+ import sys
2
+ import traceback
3
+
4
+ # logger
5
+ from pandacommon.pandalogger.PandaLogger import PandaLogger
6
+
7
+ from pandajedi.jedicore.MsgWrapper import MsgWrapper
8
+ from pandaserver.workflow.workflow_core import WorkflowInterface
9
+
10
+ from .WatchDogBase import WatchDogBase
11
+
12
+ logger = PandaLogger().getLogger(__name__.split(".")[-1])
13
+
14
+
15
+ class AtlasWorkflowManagerWatchDog(WatchDogBase):
16
+ """
17
+ Workflow manager watchdog for ATLAS
18
+ """
19
+
20
+ # constructor
21
+ def __init__(self, taskBufferIF, ddmIF):
22
+ WatchDogBase.__init__(self, taskBufferIF, ddmIF)
23
+ self.vo = "atlas"
24
+ self.workflow_interface = WorkflowInterface(taskBufferIF)
25
+
26
+ def doProcessWorkflows(self):
27
+ """
28
+ Action to process active workflows
29
+ """
30
+ tmpLog = MsgWrapper(logger, " #ATM #KV doProcessWorkflows")
31
+ tmpLog.debug("start")
32
+ try:
33
+ # watchdog lock
34
+ got_lock = self.get_process_lock("AtlasWFManagerDog.doProcessWorkflows", timeLimit=5)
35
+ if not got_lock:
36
+ tmpLog.debug("locked by another watchdog process. Skipped")
37
+ return
38
+ tmpLog.debug("got watchdog lock")
39
+ # process active workflows
40
+ stats = self.workflow_interface.process_active_workflows()
41
+ tmpLog.info(f"processed workflows: {stats}")
42
+ # done
43
+ tmpLog.debug("done")
44
+ except Exception:
45
+ errtype, errvalue = sys.exc_info()[:2]
46
+ tmpLog.error(f"failed with {errtype} {errvalue} {traceback.format_exc()}")
47
+
48
+ # main
49
+ def doAction(self):
50
+ try:
51
+ # get logger
52
+ origTmpLog = MsgWrapper(logger)
53
+ origTmpLog.debug("start")
54
+ # clean up
55
+ # check
56
+ # process workflows
57
+ self.doProcessWorkflows()
58
+ except Exception:
59
+ errtype, errvalue = sys.exc_info()[:2]
60
+ origTmpLog.error(f"failed with {errtype} {errvalue}")
61
+ # return
62
+ origTmpLog.debug("done")
63
+ return self.SC_SUCCEEDED
@@ -0,0 +1,21 @@
1
+ from pandacommon.pandalogger.PandaLogger import PandaLogger
2
+
3
+ from pandajedi.jedicore.MsgWrapper import MsgWrapper
4
+
5
+ from .TypicalWatchDogBase import TypicalWatchDogBase
6
+
7
+ logger = PandaLogger().getLogger(__name__.split(".")[-1])
8
+
9
+
10
+ # watchdog for general purpose
11
+ class GenWatchDog(TypicalWatchDogBase):
12
+ # constructor
13
+ def __init__(self, taskBufferIF, ddmIF):
14
+ TypicalWatchDogBase.__init__(self, taskBufferIF, ddmIF)
15
+
16
+ # main
17
+ def doAction(self):
18
+ tmpLog = MsgWrapper(logger)
19
+ tmpLog.debug("start")
20
+ tmpLog.debug("done")
21
+ return self.SC_SUCCEEDED
@@ -0,0 +1,147 @@
1
+ import os
2
+ import socket
3
+ import sys
4
+ import traceback
5
+
6
+ from pandaserver.taskbuffer.JediTaskSpec import JediTaskSpec
7
+
8
+
9
+ # watchdog to take actions for jumbo jobs
10
+ class JumboWatchDog:
11
+ # constructor
12
+ def __init__(self, taskBufferIF, ddmIF, log, vo, prodSourceLabel):
13
+ self.taskBufferIF = taskBufferIF
14
+ self.ddmIF = ddmIF
15
+ self.pid = f"{socket.getfqdn().split('.')[0]}-{os.getpid()}_{os.getpgrp()}-jumbo"
16
+ self.log = log
17
+ self.vo = vo
18
+ self.prodSourceLabel = prodSourceLabel
19
+ self.component = "JumboWatchDog"
20
+ self.dryRun = True
21
+
22
+ # main
23
+ def run(self):
24
+ try:
25
+ # get process lock
26
+ locked = self.taskBufferIF.lockProcess_JEDI(
27
+ vo=self.vo,
28
+ prodSourceLabel=self.prodSourceLabel,
29
+ cloud=None,
30
+ workqueue_id=None,
31
+ resource_name=None,
32
+ component=self.component,
33
+ pid=self.pid,
34
+ timeLimit=10,
35
+ )
36
+ if not locked:
37
+ self.log.debug(f"component={self.component} skipped since locked by another")
38
+ return
39
+ # get parameters for conversion
40
+ self.log.debug(f"component={self.component} start")
41
+ maxTasks = self.taskBufferIF.getConfigValue(self.component, "JUMBO_MAX_TASKS", "jedi", self.vo)
42
+ if maxTasks is None:
43
+ maxTasks = 1
44
+ nEventsToDisable = self.taskBufferIF.getConfigValue(self.component, "JUMBO_MIN_EVENTS_DISABLE", "jedi", self.vo)
45
+ if nEventsToDisable is None:
46
+ nEventsToDisable = 100000
47
+ nEventsToEnable = self.taskBufferIF.getConfigValue(self.component, "JUMBO_MIN_EVENTS_ENABLE", "jedi", self.vo)
48
+ if nEventsToEnable is None:
49
+ nEventsToEnable = nEventsToDisable * 10
50
+ maxEvents = self.taskBufferIF.getConfigValue(self.component, "JUMBO_MAX_EVENTS", "jedi", self.vo)
51
+ if maxEvents is None:
52
+ maxEvents = maxTasks * nEventsToEnable // 2
53
+ nJumboPerTask = self.taskBufferIF.getConfigValue(self.component, "JUMBO_PER_TASK", "jedi", self.vo)
54
+ if nJumboPerTask is None:
55
+ nJumboPerTask = 1
56
+ nJumboPerSite = self.taskBufferIF.getConfigValue(self.component, "JUMBO_PER_SITE", "jedi", self.vo)
57
+ if nJumboPerSite is None:
58
+ nJumboPerSite = 1
59
+ maxPrio = self.taskBufferIF.getConfigValue(self.component, "JUMBO_MAX_CURR_PRIO", "jedi", self.vo)
60
+ if maxPrio is None:
61
+ maxPrio = 500
62
+ progressToBoost = self.taskBufferIF.getConfigValue(self.component, "JUMBO_PROG_TO_BOOST", "jedi", self.vo)
63
+ if progressToBoost is None:
64
+ progressToBoost = 95
65
+ maxFilesToBoost = self.taskBufferIF.getConfigValue(self.component, "JUMBO_MAX_FILES_TO_BOOST", "jedi", self.vo)
66
+ if maxFilesToBoost is None:
67
+ maxFilesToBoost = 500
68
+ prioToBoost = 900
69
+ prioWhenDisabled = self.taskBufferIF.getConfigValue(self.component, "JUMBO_PRIO_DISABLED", "jedi", self.vo)
70
+ if prioWhenDisabled is None:
71
+ prioWhenDisabled = 500
72
+ # get current info
73
+ tasksWithJumbo = self.taskBufferIF.getTaskWithJumbo_JEDI(self.vo, self.prodSourceLabel)
74
+ totEvents = 0
75
+ doneEvents = 0
76
+ nTasks = 0
77
+ for jediTaskID, taskData in tasksWithJumbo.items():
78
+ # disable jumbo
79
+ if taskData["useJumbo"] != JediTaskSpec.enum_useJumbo["disabled"] and taskData["site"] is None:
80
+ if taskData["nEvents"] - taskData["nEventsDone"] < nEventsToDisable:
81
+ # disable
82
+ self.log.info(
83
+ "component={0} disable jumbo in jediTaskID={1} due to n_events_to_process={2} < {3}".format(
84
+ self.component, jediTaskID, taskData["nEvents"] - taskData["nEventsDone"], nEventsToDisable
85
+ )
86
+ )
87
+ self.taskBufferIF.enableJumboJobs(jediTaskID, 0, 0)
88
+ else:
89
+ # wait
90
+ nTasks += 1
91
+ totEvents += taskData["nEvents"]
92
+ doneEvents += taskData["nEventsDone"]
93
+ self.log.info(
94
+ "component={0} keep jumbo in jediTaskID={1} due to n_events_to_process={2} > {3}".format(
95
+ self.component, jediTaskID, taskData["nEvents"] - taskData["nEventsDone"], nEventsToDisable
96
+ )
97
+ )
98
+ # increase priority for jumbo disabled
99
+ if taskData["useJumbo"] == JediTaskSpec.enum_useJumbo["disabled"] and taskData["currentPriority"] < prioWhenDisabled:
100
+ self.taskBufferIF.changeTaskPriorityPanda(jediTaskID, prioWhenDisabled)
101
+ self.log.info(f"component={self.component} priority boost to {prioWhenDisabled} after disabing jumbo in in jediTaskID={jediTaskID}")
102
+ # increase priority when close to completion
103
+ if (
104
+ taskData["nEvents"] > 0
105
+ and (taskData["nEvents"] - taskData["nEventsDone"]) * 100 // taskData["nEvents"] < progressToBoost
106
+ and taskData["currentPriority"] < prioToBoost
107
+ and (taskData["nFiles"] - taskData["nFilesDone"]) < maxFilesToBoost
108
+ ):
109
+ # boost
110
+ tmpStr = "component={0} priority boost to {5} for jediTaskID={1} due to n_events_done={2} > {3}*{4}% ".format(
111
+ self.component, jediTaskID, taskData["nEventsDone"], taskData["nEvents"], progressToBoost, prioToBoost
112
+ )
113
+ tmpStr += f"n_files_remaining={taskData['nFiles'] - taskData['nFilesDone']} < {maxFilesToBoost}"
114
+ self.log.info(tmpStr)
115
+ self.taskBufferIF.changeTaskPriorityPanda(jediTaskID, prioToBoost)
116
+ # kick pending
117
+ if taskData["taskStatus"] in ["pending", "running"] and taskData["useJumbo"] in [
118
+ JediTaskSpec.enum_useJumbo["pending"],
119
+ JediTaskSpec.enum_useJumbo["running"],
120
+ ]:
121
+ nActiveJumbo = 0
122
+ for computingSite, jobStatusMap in taskData["jumboJobs"].items():
123
+ for jobStatus, nJobs in jobStatusMap.items():
124
+ if jobStatus in ["defined", "assigned", "activated", "sent", "starting", "running", "transferring", "holding"]:
125
+ nActiveJumbo += nJobs
126
+ if nActiveJumbo == 0:
127
+ self.log.info(f"component={self.component} kick jumbo in {taskData['taskStatus']} jediTaskID={jediTaskID}")
128
+ self.taskBufferIF.kickPendingTasksWithJumbo_JEDI(jediTaskID)
129
+ # reset input to re-generate co-jumbo
130
+ if taskData["currentPriority"] >= prioToBoost:
131
+ nReset = self.taskBufferIF.resetInputToReGenCoJumbo_JEDI(jediTaskID)
132
+ if nReset is not None and nReset > 0:
133
+ self.log.info(f"component={self.component} reset {nReset} inputs to regenerate co-jumbo for jediTaskID={jediTaskID}")
134
+ else:
135
+ self.log.debug(f"component={self.component} tried to reset inputs to regenerate co-jumbo with {nReset} for jediTaskID={jediTaskID}")
136
+ self.log.info(
137
+ f"component={self.component} total_events={totEvents} n_events_to_process={totEvents - doneEvents} n_tasks={nTasks} available for jumbo"
138
+ )
139
+
140
+ self.log.debug(f"component={self.component} done")
141
+ except Exception:
142
+ # error
143
+ errtype, errvalue = sys.exc_info()[:2]
144
+ errStr = f": {errtype.__name__} {errvalue}"
145
+ errStr.strip()
146
+ errStr += traceback.format_exc()
147
+ self.log.error(errStr)
@@ -0,0 +1,122 @@
1
+ import os
2
+ import socket
3
+
4
+ from pandajedi.jediconfig import jedi_config
5
+ from pandajedi.jedicore import Interaction
6
+ from pandaserver.proxycache.token_cache import TokenCache
7
+ from pandaserver.srvcore import CoreUtils
8
+
9
+ from .WatchDogBase import WatchDogBase
10
+
11
+
12
+ # base class for typical watchdog (for production and analysis, etc.)
13
+ class TypicalWatchDogBase(WatchDogBase):
14
+ # pre-action
15
+ def pre_action(self, tmpLog, vo, prodSourceLabel, pid, *args, **kwargs):
16
+ # rescue picked files
17
+ tmpLog.info(f"rescue tasks with picked files for vo={vo} label={prodSourceLabel}")
18
+ tmpRet = self.taskBufferIF.rescuePickedFiles_JEDI(vo, prodSourceLabel, jedi_config.watchdog.waitForPicked)
19
+ if tmpRet is None:
20
+ # failed
21
+ tmpLog.error("failed to rescue")
22
+ else:
23
+ tmpLog.info(f"rescued {tmpRet} tasks")
24
+ # reactivate pending tasks
25
+ tmpLog.info(f"reactivate pending tasks for vo={vo} label={prodSourceLabel}")
26
+ timeoutForPending = self.taskBufferIF.getConfigValue("watchdog", f"PENDING_TIMEOUT_{prodSourceLabel}", "jedi", vo)
27
+ if timeoutForPending is None:
28
+ if hasattr(jedi_config.watchdog, "timeoutForPendingVoLabel"):
29
+ timeoutForPending = CoreUtils.getConfigParam(jedi_config.watchdog.timeoutForPendingVoLabel, vo, prodSourceLabel)
30
+ if timeoutForPending is None:
31
+ timeoutForPending = jedi_config.watchdog.timeoutForPending
32
+ timeoutForPending = int(timeoutForPending) * 24
33
+ tmpRet, msg_driven_taskid_set = self.taskBufferIF.reactivatePendingTasks_JEDI(
34
+ vo, prodSourceLabel, jedi_config.watchdog.waitForPending, timeoutForPending
35
+ )
36
+ if tmpRet is None:
37
+ # failed
38
+ tmpLog.error("failed to reactivate")
39
+ else:
40
+ tmpLog.info(f"reactivated {tmpRet} tasks")
41
+ for jeditaskid in msg_driven_taskid_set:
42
+ push_ret = self.taskBufferIF.push_task_trigger_message("jedi_job_generator", jeditaskid)
43
+ if push_ret:
44
+ tmpLog.debug(f"pushed trigger message to jedi_job_generator for jeditaskid={jeditaskid}")
45
+ else:
46
+ tmpLog.warning(f"failed to push trigger message to jedi_job_generator for jeditaskid={jeditaskid}")
47
+ # unlock tasks
48
+ tmpLog.info(f"unlock tasks for vo={vo} label={prodSourceLabel} host={socket.getfqdn().split('.')[0]} pgid={os.getpgrp()}")
49
+ tmpRet = self.taskBufferIF.unlockTasks_JEDI(vo, prodSourceLabel, 10, socket.getfqdn().split(".")[0], os.getpgrp())
50
+ if tmpRet is None:
51
+ # failed
52
+ tmpLog.error("failed to unlock")
53
+ else:
54
+ tmpLog.info(f"unlock {tmpRet} tasks")
55
+ # unlock tasks
56
+ tmpLog.info(f"unlock tasks for vo={vo} label={prodSourceLabel}")
57
+ tmpRet = self.taskBufferIF.unlockTasks_JEDI(vo, prodSourceLabel, jedi_config.watchdog.waitForLocked)
58
+ if tmpRet is None:
59
+ # failed
60
+ tmpLog.error("failed to unlock")
61
+ else:
62
+ tmpLog.info(f"unlock {tmpRet} tasks")
63
+ # restart contents update
64
+ tmpLog.info(f"restart contents update for vo={vo} label={prodSourceLabel}")
65
+ tmpRet, msg_driven_taskid_set = self.taskBufferIF.restartTasksForContentsUpdate_JEDI(vo, prodSourceLabel)
66
+ if tmpRet is None:
67
+ # failed
68
+ tmpLog.error("failed to restart")
69
+ else:
70
+ tmpLog.info(f"restarted {tmpRet} tasks")
71
+ for jeditaskid in msg_driven_taskid_set:
72
+ push_ret = self.taskBufferIF.push_task_trigger_message("jedi_contents_feeder", jeditaskid)
73
+ if push_ret:
74
+ tmpLog.debug(f"pushed trigger message to jedi_contents_feeder for jeditaskid={jeditaskid}")
75
+ else:
76
+ tmpLog.warning(f"failed to push trigger message to jedi_contents_feeder for jeditaskid={jeditaskid}")
77
+ # kick exhausted tasks
78
+ tmpLog.info(f"kick exhausted tasks for vo={vo} label={prodSourceLabel}")
79
+ tmpRet = self.taskBufferIF.kickExhaustedTasks_JEDI(vo, prodSourceLabel, jedi_config.watchdog.waitForExhausted)
80
+ if tmpRet is None:
81
+ # failed
82
+ tmpLog.error("failed to kick")
83
+ else:
84
+ tmpLog.info(f"kicked {tmpRet} tasks")
85
+ # finish tasks when goal is reached
86
+ tmpLog.info(f"finish achieved tasks for vo={vo} label={prodSourceLabel}")
87
+ tmpRet = self.taskBufferIF.getAchievedTasks_JEDI(vo, prodSourceLabel, jedi_config.watchdog.waitForAchieved)
88
+ if tmpRet is None:
89
+ # failed
90
+ tmpLog.error("failed to finish")
91
+ else:
92
+ for jediTaskID in tmpRet:
93
+ self.taskBufferIF.sendCommandTaskPanda(jediTaskID, "JEDI. Goal reached", True, "finish", comQualifier="soft")
94
+ tmpLog.info(f"finished {tmpRet} tasks")
95
+ # rescue unlocked tasks with picked files
96
+ tmpLog.info(f"rescue unlocked tasks with picked files for vo={vo} label={prodSourceLabel}")
97
+ tmpRet = self.taskBufferIF.rescueUnLockedTasksWithPicked_JEDI(vo, prodSourceLabel, 60, pid)
98
+ if tmpRet is None:
99
+ # failed
100
+ tmpLog.error("failed to rescue unlocked tasks")
101
+ else:
102
+ tmpLog.info(f"rescue unlocked {tmpRet} tasks")
103
+ # cache tokens
104
+ got_lock = self.get_process_lock("TypicalWatchDogBase.cache_tokens", timeLimit=5)
105
+ if not got_lock:
106
+ tmpLog.debug("locked by another watchdog process. Skipped to cache tokens")
107
+ else:
108
+ tmpLog.info(f"cache tokens")
109
+ cacher = TokenCache()
110
+ cacher.run()
111
+
112
+ # action to set scout job data w/o scouts
113
+ def doActionToSetScoutJobData(self, gTmpLog):
114
+ tmpRet = self.taskBufferIF.setScoutJobDataToTasks_JEDI(self.vo, self.prodSourceLabel)
115
+ if tmpRet is None:
116
+ # failed
117
+ gTmpLog.error("failed to set scout job data")
118
+ else:
119
+ gTmpLog.info("set scout job data successfully")
120
+
121
+
122
+ Interaction.installSC(TypicalWatchDogBase)
@@ -0,0 +1,53 @@
1
+ import os
2
+ import socket
3
+
4
+ from pandajedi.jedicore import Interaction
5
+
6
+
7
+ # base class for watchdog
8
+ class WatchDogBase(object):
9
+ """
10
+ Base class for watchdog
11
+ """
12
+
13
+ # constructor
14
+ def __init__(self, taskBufferIF, ddmIF):
15
+ self.taskBufferIF = taskBufferIF
16
+ self.ddmIF = ddmIF
17
+ self.pid = f"{socket.getfqdn().split('.')[0]}-{os.getpid()}-dog"
18
+ self.vo = None
19
+ self.refresh()
20
+
21
+ def get_process_lock(self, component, timeLimit=5, **kwargs):
22
+ """
23
+ Shortcut of get process lock for watchdog action methods
24
+
25
+ Args:
26
+ component (str): spec of the request
27
+ timeLimit (int): lifetime of the lock in minutes
28
+ **kwargs: other arguments for taskBufferIF.lockProcess_JEDI
29
+
30
+ Returns:
31
+ bool : True if got lock, False otherwise
32
+ """
33
+ return self.taskBufferIF.lockProcess_JEDI(
34
+ vo=self.vo,
35
+ prodSourceLabel=kwargs.get("prodSourceLabel", "default"),
36
+ cloud=kwargs.get("cloud", None),
37
+ workqueue_id=kwargs.get("workqueue_id", None),
38
+ resource_name=kwargs.get("resource_name", None),
39
+ component=component,
40
+ pid=self.pid,
41
+ timeLimit=timeLimit,
42
+ )
43
+
44
+ # refresh
45
+ def refresh(self):
46
+ self.siteMapper = self.taskBufferIF.get_site_mapper()
47
+
48
+ # pre-action
49
+ def pre_action(self, tmpLog, vo, prodSourceLabel, pid, *args, **kwargs):
50
+ pass
51
+
52
+
53
+ Interaction.installSC(WatchDogBase)
File without changes