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,53 @@
1
+ __author__ = "retmas"
2
+
3
+ import logging
4
+ import logging.config
5
+ import logging.handlers
6
+
7
+
8
+ class Singleton(type):
9
+ def __init__(cls, *args, **kwargs):
10
+ super(Singleton, cls).__init__(*args, **kwargs)
11
+ cls._instance = None
12
+
13
+ def __call__(cls, *args, **kwargs):
14
+ if cls._instance is None:
15
+ cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
16
+ return cls._instance
17
+
18
+
19
+ class Logger(object, metaclass=Singleton):
20
+ _config = {
21
+ "version": 1,
22
+ "disable_existing_loggers": False,
23
+ "formatters": {"default": {"format": "[%(asctime)s] [%(process)d] [%(levelname)s] [%(module)s] [%(funcName)s:%(lineno)d] - %(message)s"}},
24
+ "handlers": {
25
+ "console": {
26
+ "level": "DEBUG",
27
+ "class": "logging.StreamHandler",
28
+ "formatter": "default",
29
+ }
30
+ },
31
+ "loggers": {"snakeparser.log": {"handlers": ["console"], "level": "INFO"}},
32
+ }
33
+
34
+ def __init__(self):
35
+ logging.config.dictConfig(self._config)
36
+
37
+ @staticmethod
38
+ def set_level(level):
39
+ Logger.get().setLevel(level)
40
+
41
+ @staticmethod
42
+ def set_log_file(filename, max_bytes=0, backup_count=0, remove_console=False):
43
+ logger = Logger().get()
44
+ handler = logging.handlers.RotatingFileHandler(filename, maxBytes=max_bytes, backupCount=backup_count, encoding="utf-8")
45
+ handler.formatter = logger.handlers[0].formatter
46
+ handler.level = logging.DEBUG
47
+ logger.addHandler(handler)
48
+ if remove_console:
49
+ logger.removeHandler(logger.handlers[0])
50
+
51
+ @staticmethod
52
+ def get() -> logging.Logger:
53
+ return logging.getLogger(__name__)
@@ -0,0 +1,3 @@
1
+ __author__ = "retmas"
2
+
3
+ WORKFLOW_NAMES = ["prun", "phpo", "junction", "reana"]
@@ -0,0 +1,332 @@
1
+ __author__ = "retmas"
2
+
3
+ import logging
4
+ import os
5
+ import os.path
6
+ import pathlib
7
+ import re
8
+ from itertools import chain
9
+ from pathlib import Path
10
+ from types import SimpleNamespace
11
+
12
+ from snakemake.api import (
13
+ OutputSettings,
14
+ ResourceSettings,
15
+ SnakemakeApi,
16
+ StorageSettings,
17
+ )
18
+
19
+ from pandaserver.workflow.snakeparser.utils import ParamRule, param_of
20
+ from pandaserver.workflow.workflow_utils import ConditionItem, Node
21
+
22
+ from .extensions import inject
23
+ from .log import Logger
24
+ from .names import WORKFLOW_NAMES
25
+
26
+
27
+ class ParamNotFoundException(Exception):
28
+ def __init__(self, param_name, rule_name):
29
+ super().__init__(f"Parameter {param_name} is not found in {rule_name} rule")
30
+
31
+
32
+ class UnknownWorkflowTypeException(Exception):
33
+ def __init__(self, rule_name):
34
+ super().__init__(f"Unknown workflow type for rule {rule_name}")
35
+
36
+
37
+ class UnknownRuleShellException(Exception):
38
+ def __init__(self, rule_name):
39
+ super().__init__(f"Unknown shellcmd for rule {rule_name}")
40
+
41
+
42
+ class NoRuleShellException(Exception):
43
+ def __init__(self, rule_name):
44
+ super().__init__(f"No shellcmd for rule {rule_name}")
45
+
46
+
47
+ class UnknownConditionTokenException(Exception):
48
+ def __init__(self, token):
49
+ super().__init__(f"Unknown token {token}")
50
+
51
+
52
+ # noinspection DuplicatedCode
53
+ class Parser(object):
54
+ def __init__(self, workflow_file, level=None, logger=None):
55
+ self._workflow = None
56
+ self._dag = None
57
+ if logger:
58
+ self._logger = logger
59
+ else:
60
+ self._logger = Logger().get()
61
+ if level:
62
+ self._logger.setLevel(level)
63
+ snakefile = os.path.abspath(workflow_file)
64
+ workdir = os.path.dirname(snakefile)
65
+ self._logger.debug("create workflow")
66
+ # create workflow through API
67
+ with SnakemakeApi(
68
+ OutputSettings(
69
+ verbose=False,
70
+ show_failed_logs=True,
71
+ ),
72
+ ) as snakemake_api:
73
+ workflow_api = snakemake_api.workflow(
74
+ storage_settings=StorageSettings(),
75
+ resource_settings=ResourceSettings(),
76
+ snakefile=Path(snakefile),
77
+ )
78
+ dag_api = workflow_api.dag()
79
+ self._workflow = workflow_api._workflow
80
+ self._workflow.default_target = "all"
81
+ self._workflow.overwrite_workdir = None
82
+ current_workdir = os.getcwd()
83
+ try:
84
+ inject()
85
+ self._workflow.workdir(workdir)
86
+ finally:
87
+ if current_workdir:
88
+ os.chdir(current_workdir)
89
+ # build DAG
90
+ dag_api.unlock()
91
+ self._dag = self._workflow.dag
92
+
93
+ @property
94
+ def jobs(self):
95
+ if self._dag is None:
96
+ return list()
97
+ return self._dag.jobs
98
+
99
+ def parse_nodes(self, in_loop=False):
100
+ try:
101
+ return self._parse_nodes(in_loop)
102
+ except NoRuleShellException as ex:
103
+ self._logger.error(str(ex))
104
+ raise ex
105
+ except UnknownRuleShellException as ex:
106
+ self._logger.error(str(ex))
107
+ raise ex
108
+ except UnknownWorkflowTypeException as ex:
109
+ self._logger.error(str(ex))
110
+ raise ex
111
+ except ParamNotFoundException as ex:
112
+ self._logger.error(str(ex))
113
+ raise ex
114
+
115
+ def _parse_nodes(self, in_loop):
116
+ root_job = next(filter(lambda o: o.rule.name == self._workflow.default_target, self.jobs))
117
+ root_inputs = {Parser._extract_job_id(self._define_id(name)): value for name, value in root_job.params.items()}
118
+ root_outputs = set(
119
+ [
120
+ Parser._extract_job_id(s.id.split("#")[0] + "#" + re.sub(s.id + "/", "", s.outputSource))
121
+ for s in list(
122
+ chain(
123
+ *[
124
+ map(
125
+ lambda output: Parser._define_object(
126
+ {
127
+ "id": self._define_id(output),
128
+ "outputSource": self._define_id(f"{dep.name}/{output}"),
129
+ }
130
+ ),
131
+ dep.output,
132
+ )
133
+ for dep in self._dag.dependencies[root_job]
134
+ ]
135
+ )
136
+ )
137
+ ]
138
+ )
139
+ node_list = []
140
+ output_map = {}
141
+ serial_id = 0
142
+ for job in filter(lambda o: o.name != self._workflow.default_target, self.jobs):
143
+ if job.is_shell:
144
+ if job.shellcmd is None:
145
+ raise NoRuleShellException(job.rule.name)
146
+ else:
147
+ raise UnknownRuleShellException(job.rule.name)
148
+ workflow_name = os.path.basename(job.shellcmd)
149
+ serial_id += 1
150
+ if workflow_name in WORKFLOW_NAMES:
151
+ node = Node(serial_id, workflow_name, None, True, job.name)
152
+ elif workflow_name.lower() == "Snakefile".lower():
153
+ node = Node(serial_id, "workflow", None, False, job.name)
154
+ else:
155
+ raise UnknownWorkflowTypeException(job.rule.name)
156
+ for name, value in job.params.items():
157
+ if isinstance(value, ParamRule):
158
+ if value.rule is None:
159
+ param_job = job
160
+ else:
161
+ param_job = next(filter(lambda o: o.rule.name == value.rule.name, self.jobs))
162
+ if value.name not in param_job.rule.params.keys():
163
+ raise ParamNotFoundException(value.name, param_job.rule.name)
164
+ source = Parser._extract_job_id(self._define_id(f"{param_job.name}/{value.name}"))
165
+ if param_job.name == self._workflow.default_target:
166
+ source = source.replace(f"{param_job.name}/", "")
167
+ node.inputs.update({Parser._extract_job_id(self._define_id(f"{job.name}/{name}")): {"default": None, "source": source}})
168
+ continue
169
+ if node.inputs is None:
170
+ node.inputs = dict()
171
+ default_value = value
172
+ source = None
173
+ if job.dependencies:
174
+ if isinstance(value, list):
175
+ for item in list(value):
176
+ if item in job.dependencies.keys():
177
+ if source is None:
178
+ source = list()
179
+ source.append(Parser._extract_job_id(self._define_id(f"{job.dependencies[item].name}/{item}")))
180
+ if source is not None:
181
+ default_value = None
182
+ else:
183
+ if default_value in job.dependencies.keys():
184
+ source = Parser._extract_job_id(self._define_id(f"{job.dependencies[default_value].name}/{default_value}"))
185
+ default_value = None
186
+ node.inputs.update(
187
+ {
188
+ Parser._extract_job_id(self._define_id(f"{job.name}/{name}")): {
189
+ "default": default_value,
190
+ "source": source,
191
+ }
192
+ }
193
+ )
194
+ node.outputs = {Parser._extract_job_id(self._define_id(f"{job.name}/{output}")): {} for output in job.output}
195
+ if not node.outputs:
196
+ node.outputs = {Parser._extract_job_id(self._define_id(f"{job.name}/outDS")): {}}
197
+ output_map.update({name: serial_id for name in node.outputs})
198
+ scatter = getattr(job.rule, "scatter", None)
199
+ if scatter:
200
+ node.scatter = [
201
+ Parser._extract_job_id(self._define_id(f"{next(filter(lambda o: o.rule.name == v.rule.name, self.jobs)).name}/{v.name}"))
202
+ for v in [ParamRule(v.name, job.rule if v.rule is None else v.rule) for v in job.rule.scatter]
203
+ ]
204
+ else:
205
+ node.scatter = None
206
+ condition = getattr(job.rule, "condition", None)
207
+ if condition:
208
+ pattern = f'{param_of("")}(\w+)'
209
+ for param_name in re.findall(pattern, condition):
210
+ if param_name not in job.rule.params.keys():
211
+ raise ParamNotFoundException(param_name, job.rule.name)
212
+ condition = re.sub(r" *! *", r"!", condition)
213
+ condition = re.sub(r"\|\|", r" || ", condition)
214
+ condition = re.sub(r"&&", r" && ", condition)
215
+ tokens = condition.split()
216
+ param_left = None
217
+ param_operator = None
218
+ for token in tokens:
219
+ token = token.strip()
220
+ if token == "||":
221
+ param_operator = "or"
222
+ continue
223
+ elif token == "&&":
224
+ param_operator = "and"
225
+ continue
226
+ elif token.startswith(str(param_of(""))):
227
+ param_right = ConditionItem(str(re.findall(pattern, token)[0]))
228
+ if not param_left:
229
+ param_left = param_right
230
+ continue
231
+ elif token.startswith(f'!{param_of("")}'):
232
+ param_right = ConditionItem(str(re.findall(pattern, token)[0]), operator="not")
233
+ if not param_left:
234
+ param_left = param_right
235
+ continue
236
+ else:
237
+ raise UnknownConditionTokenException(token)
238
+ param_left = ConditionItem(param_left, param_right, param_operator)
239
+ node.condition = param_left
240
+ self._suppress_inputs(node.condition, node.inputs)
241
+ node.loop = bool(getattr(job.rule, "loop", False))
242
+ if node.loop or in_loop:
243
+ node.in_loop = True
244
+ if not node.is_leaf:
245
+ subworkflow_file = os.path.join(self._workflow.basedir, job.shellcmd)
246
+ subworkflow_parser = Parser(subworkflow_file, level=logging.DEBUG)
247
+ node.sub_nodes, node.root_inputs = subworkflow_parser.parse_nodes()
248
+ if root_outputs & set(node.outputs):
249
+ node.is_tail = True
250
+ node_list.append(node)
251
+ for node in node_list:
252
+ for name, data in node.inputs.items():
253
+ if not data["source"]:
254
+ continue
255
+ if isinstance(data["source"], list):
256
+ sources = data["source"]
257
+ is_str = False
258
+ else:
259
+ sources = [data["source"]]
260
+ is_str = True
261
+ parent_id_list = list()
262
+ for source in sources:
263
+ if source in output_map:
264
+ parent_id = output_map[source]
265
+ node.add_parent(parent_id)
266
+ parent_id_list.append(parent_id)
267
+ if parent_id_list:
268
+ if is_str:
269
+ parent_id_list = parent_id_list[0]
270
+ data["parent_id"] = parent_id_list
271
+ node_list = self._sort_node_list(node_list, set())
272
+ return node_list, root_inputs
273
+
274
+ def verify_workflow(self):
275
+ if self._workflow is None:
276
+ return False
277
+ self._workflow.check()
278
+ return True
279
+
280
+ def get_dot_data(self):
281
+ return str(self._dag)
282
+
283
+ @staticmethod
284
+ def _extract_job_id(job_id):
285
+ if not job_id:
286
+ return job_id
287
+ if not isinstance(job_id, list):
288
+ job_id = [job_id]
289
+ not_list = True
290
+ else:
291
+ not_list = False
292
+ items = [re.search(r"[^/]+#.+$", s).group(0) for s in job_id]
293
+ if not_list:
294
+ return items[0]
295
+ return items
296
+
297
+ @staticmethod
298
+ def _sort_node_list(node_list, visited):
299
+ if not node_list:
300
+ return []
301
+ new_list = []
302
+ new_visited = []
303
+ for node in node_list:
304
+ is_ok = True
305
+ for p in node.parents:
306
+ if p not in visited:
307
+ is_ok = False
308
+ break
309
+ if is_ok:
310
+ new_visited.append(node)
311
+ visited.add(node.id)
312
+ else:
313
+ new_list.append(node)
314
+ return new_visited + Parser._sort_node_list(new_list, visited)
315
+
316
+ def _define_id(self, name):
317
+ return f"{pathlib.Path(os.path.abspath(self._workflow.main_snakefile)).as_uri()}#{name}"
318
+
319
+ @staticmethod
320
+ def _define_object(dict_):
321
+ return SimpleNamespace(**dict_)
322
+
323
+ def _suppress_inputs(self, condition: ConditionItem, inputs):
324
+ if condition.right is None and condition.operator == "not" and isinstance(condition.left, str):
325
+ for name, data in inputs.items():
326
+ if condition.left == name.split("/")[-1]:
327
+ data["suppressed"] = True
328
+ else:
329
+ for item in ["left", "right"]:
330
+ condition_item = getattr(condition, item)
331
+ if isinstance(condition_item, ConditionItem):
332
+ self._suppress_inputs(condition_item, inputs)
@@ -0,0 +1,29 @@
1
+ __author__ = "retmas"
2
+
3
+ from snakemake.workflow import Rule, RuleProxy
4
+
5
+
6
+ class ParamRule(object):
7
+ def __init__(self, name: str, source_rule: Rule = None):
8
+ self._name = name
9
+ self._source_rule = source_rule
10
+
11
+ def __repr__(self):
12
+ return f"param.{self.name}"
13
+
14
+ @property
15
+ def name(self) -> str:
16
+ return self._name
17
+
18
+ @property
19
+ def rule(self) -> Rule:
20
+ return self._source_rule
21
+
22
+
23
+ def param_of(name, source: RuleProxy = None) -> ParamRule:
24
+ rule = source.rule if source is not None else None
25
+ return ParamRule(name, rule)
26
+
27
+
28
+ def param_exp(template):
29
+ return lambda wildcards: template
@@ -0,0 +1,85 @@
1
+ from pandaserver.workflow.workflow_base import (
2
+ WFDataSpec,
3
+ WFDataStatus,
4
+ WFDataType,
5
+ WFStepSpec,
6
+ WFStepStatus,
7
+ WFStepTargetCancelResult,
8
+ WFStepTargetCheckResult,
9
+ WFStepTargetSubmitResult,
10
+ WFStepType,
11
+ WorkflowSpec,
12
+ WorkflowStatus,
13
+ )
14
+
15
+
16
+ class BaseStepHandler:
17
+ """
18
+ Base class for step handlers in the workflow.
19
+ This class provides a common interface and some utility methods for step handlers.
20
+ """
21
+
22
+ def __init__(self, task_buffer, *args, **kwargs):
23
+ """
24
+ Initialize the step handler with necessary parameters.
25
+
26
+ Args:
27
+ task_buffer: The task buffer interface to interact with the task database.
28
+ *args: Additional positional arguments.
29
+ **kwargs: Additional keyword arguments.
30
+ """
31
+ self.tbif = task_buffer
32
+
33
+ def submit_target(self, step_spec: WFStepSpec, **kwargs) -> WFStepTargetSubmitResult:
34
+ """
35
+ Submit a target for processing the step.
36
+ This method should be implemented by subclasses to handle the specifics of target submission.
37
+ This method should NOT modify step_spec. Any update information should be stored in the WFStepTargetSubmitResult returned instead.
38
+
39
+ Args:
40
+ step_spec (WFStepSpec): Specifications of the workflow step whose target is to be submitted.
41
+
42
+ Returns:
43
+ WFStepTargetSubmitResult: An object containing the result of the submission, including success status, target ID, and message.
44
+
45
+ """
46
+ raise NotImplementedError("Subclasses must implement this method.")
47
+
48
+ def check_target(self, step_spec: WFStepSpec, **kwargs) -> WFStepTargetCheckResult:
49
+ """
50
+ Check the status of the submitted target.
51
+ This method should be implemented by subclasses to handle the specifics of target status checking.
52
+ This method should NOT modify step_spec. Any update information should be stored in the WFStepTargetCheckResult returned instead.
53
+
54
+ Args:
55
+ step_spec (WFStepSpec): Specifications of the workflow step to be checked.
56
+
57
+ Returns:
58
+ WFStepTargetCheckResult: An object containing the result of the check, including success status, current step status, and message.
59
+ """
60
+ raise NotImplementedError("Subclasses must implement this method.")
61
+
62
+ def on_all_inputs_done(self, step_spec: WFStepSpec, **kwargs) -> None:
63
+ """
64
+ Hook method called when all inputs for the step are done.
65
+ This method can be overridden by subclasses to perform actions when all inputs are ready.
66
+
67
+ Args:
68
+ step_spec (WFStepSpec): Specifications of the workflow step whose inputs are done.
69
+ **kwargs: Additional keyword arguments.
70
+ """
71
+ raise NotImplementedError("Subclasses must implement this method.")
72
+
73
+ def cancel_target(self, step_spec: WFStepSpec, **kwargs) -> WFStepTargetCancelResult:
74
+ """
75
+ Cancel the submitted target.
76
+ This method can be overridden by subclasses to handle target cancellation.
77
+
78
+ Args:
79
+ step_spec (WFStepSpec): Specifications of the workflow step whose target is to be cancelled.
80
+ **kwargs: Additional keyword arguments.
81
+
82
+ Returns:
83
+ WFStepTargetCancelResult: An object containing the result of the cancellation, including success status and message.
84
+ """
85
+ raise NotImplementedError("Subclasses must implement this method.")