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,272 @@
1
+ import datetime
2
+ import functools
3
+ import time
4
+ import traceback
5
+ import uuid
6
+
7
+ from pandacommon.pandalogger.LogWrapper import LogWrapper
8
+ from pandacommon.pandalogger.PandaLogger import PandaLogger
9
+ from pandacommon.pandautils.PandaUtils import naive_utcnow
10
+
11
+ from pandaserver.config import panda_config
12
+ from pandaserver.dataservice import DataServiceUtils
13
+
14
+ _log = PandaLogger().getLogger("broker")
15
+
16
+ # all known sites
17
+ _allSites = []
18
+
19
+ # processingType to skip brokerage
20
+ skipBrokerageProTypes = ["prod_test"]
21
+
22
+
23
+ # comparison function for sort
24
+ def _compFunc(job_a, job_b):
25
+ # This comparison helps in sorting the jobs based on the order of their computing sites in the _allSites list.
26
+ # append site if not in list
27
+ if job_a.computingSite not in _allSites:
28
+ _allSites.append(job_a.computingSite)
29
+ if job_b.computingSite not in _allSites:
30
+ _allSites.append(job_b.computingSite)
31
+
32
+ # compare site indices
33
+ index_a = _allSites.index(job_a.computingSite)
34
+ index_b = _allSites.index(job_b.computingSite)
35
+
36
+ if index_a > index_b:
37
+ return 1
38
+ elif index_a < index_b:
39
+ return -1
40
+ else:
41
+ return 0
42
+
43
+
44
+ def schedule(jobs, siteMapper):
45
+ timestamp = naive_utcnow().isoformat("/")
46
+ tmp_log = LogWrapper(_log, f"start_ts={timestamp}")
47
+
48
+ try:
49
+ # no jobs
50
+ if len(jobs) == 0:
51
+ tmp_log.debug("finished : no jobs")
52
+ return
53
+
54
+ max_jobs = 20
55
+ max_files = 20
56
+
57
+ iJob = 0
58
+ fileList = []
59
+ chosen_panda_queue = None
60
+ prodDBlock = None
61
+ computingSite = None
62
+ dispatchDBlock = None
63
+ previousCloud = None
64
+ prevProType = None
65
+ prevSourceLabel = None
66
+ prevDirectAcc = None
67
+ prevIsJEDI = None
68
+ prevBrokerageSiteList = None
69
+
70
+ indexJob = 0
71
+
72
+ # sort jobs by siteID. Some jobs may already define computingSite
73
+ jobs = sorted(jobs, key=functools.cmp_to_key(_compFunc))
74
+
75
+ # loop over all jobs + terminator(None)
76
+ for job in jobs + [None]:
77
+ indexJob += 1
78
+
79
+ # ignore failed jobs
80
+ if job and job.jobStatus == "failed":
81
+ continue
82
+
83
+ # list of sites for special brokerage
84
+ specialBrokerageSiteList = []
85
+
86
+ # manually set site
87
+ if job and job.computingSite != "NULL" and job.prodSourceLabel in ("test", "managed") and specialBrokerageSiteList == []:
88
+ specialBrokerageSiteList = [job.computingSite]
89
+
90
+ overwriteSite = False
91
+
92
+ # check JEDI
93
+ isJEDI = False
94
+ if job and job.lockedby == "jedi":
95
+ isJEDI = True
96
+
97
+ # new bunch or terminator
98
+ if (
99
+ job is None
100
+ or len(fileList) >= max_files
101
+ or (dispatchDBlock is None and job.homepackage.startswith("AnalysisTransforms"))
102
+ or prodDBlock != job.prodDBlock
103
+ or job.computingSite != computingSite
104
+ or iJob > max_jobs
105
+ or previousCloud != job.getCloud()
106
+ or (prevProType in skipBrokerageProTypes and iJob > 0)
107
+ or prevDirectAcc != job.transferType
108
+ or prevProType != job.processingType
109
+ or prevBrokerageSiteList != specialBrokerageSiteList
110
+ or prevIsJEDI != isJEDI
111
+ ):
112
+ if indexJob > 1:
113
+ tmp_log.debug("new bunch")
114
+ tmp_log.debug(f" iJob {iJob}")
115
+ tmp_log.debug(f" cloud {previousCloud}")
116
+ tmp_log.debug(f" sourceLabel {prevSourceLabel}")
117
+ tmp_log.debug(f" prodDBlock {prodDBlock}")
118
+ tmp_log.debug(f" computingSite {computingSite}")
119
+ tmp_log.debug(f" processingType {prevProType}")
120
+ tmp_log.debug(f" transferType {prevDirectAcc}")
121
+
122
+ if (iJob != 0 and chosen_panda_queue == "TOBEDONE") or prevBrokerageSiteList not in [None, []]:
123
+ # load balancing
124
+ minSites = {}
125
+ if prevBrokerageSiteList:
126
+ # special brokerage
127
+ scanSiteList = prevBrokerageSiteList
128
+ else:
129
+ if siteMapper.checkCloud(previousCloud):
130
+ # use cloud sites
131
+ scanSiteList = siteMapper.getCloud(previousCloud)["sites"]
132
+
133
+ # loop over all sites
134
+ for site in scanSiteList:
135
+ tmp_log.debug(f"calculate weight for site:{site}")
136
+ # _allSites may contain NULL after sort()
137
+ if site == "NULL":
138
+ tmp_log.debug("site is NULL")
139
+ continue
140
+
141
+ winv = 1
142
+
143
+ tmp_log.debug(f"Site:{site} 1/Weight:{winv}")
144
+
145
+ # choose largest nMinSites weights
146
+ minSites[site] = winv
147
+
148
+ # choose site
149
+ tmp_log.debug(f"Min Sites:{minSites}")
150
+ if len(fileList) == 0 or prevIsJEDI is True:
151
+ # choose min 1/weight
152
+ minSite = list(minSites)[0]
153
+ chosen_panda_queue = siteMapper.getSite(minSite)
154
+
155
+ # set job spec
156
+ tmp_log.debug(f"indexJob : {indexJob}")
157
+
158
+ for tmpJob in jobs[indexJob - iJob - 1 : indexJob - 1]:
159
+ # set computingSite
160
+ tmpJob.computingSite = chosen_panda_queue.sitename
161
+ tmp_log.debug(f"PandaID:{tmpJob.PandaID} -> site:{tmpJob.computingSite}")
162
+
163
+ # terminate
164
+ if job is None:
165
+ break
166
+ # reset iJob
167
+ iJob = 0
168
+ # reset file list
169
+ fileList = []
170
+ # create new dispDBlock
171
+ if job.prodDBlock != "NULL":
172
+ # get datatype
173
+ try:
174
+ tmpDataType = job.prodDBlock.split(":")[-1].split(".")[-2]
175
+ except Exception:
176
+ # default
177
+ tmpDataType = "GEN"
178
+ if len(tmpDataType) > 20:
179
+ # avoid too long name
180
+ tmpDataType = "GEN"
181
+ transferType = "transfer"
182
+ if job.useInputPrestaging():
183
+ transferType = "prestaging"
184
+ dispatchDBlock = f"panda.{job.taskID}.{time.strftime('%m.%d')}.{tmpDataType}.{transferType}.{str(uuid.uuid4())}_dis{job.PandaID}"
185
+ tmp_log.debug(f"New dispatchDBlock: {dispatchDBlock}")
186
+ prodDBlock = job.prodDBlock
187
+ # already define computingSite
188
+ if job.computingSite != "NULL":
189
+ # instantiate KnownSite
190
+ chosen_panda_queue = siteMapper.getSite(job.computingSite)
191
+
192
+ # if site doesn't exist, use the default site
193
+ if job.homepackage.startswith("AnalysisTransforms"):
194
+ if chosen_panda_queue.sitename == panda_config.def_sitename:
195
+ chosen_panda_queue = siteMapper.getSite(panda_config.def_queue)
196
+ overwriteSite = True
197
+ else:
198
+ # default for Analysis jobs
199
+ if job.homepackage.startswith("AnalysisTransforms"):
200
+ chosen_panda_queue = siteMapper.getSite(panda_config.def_queue)
201
+ overwriteSite = True
202
+ else:
203
+ # set chosen_panda_queue
204
+ chosen_panda_queue = "TOBEDONE"
205
+ # increment iJob
206
+ iJob += 1
207
+ # reserve computingSite and cloud
208
+ computingSite = job.computingSite
209
+ previousCloud = job.getCloud()
210
+ prevProType = job.processingType
211
+ prevSourceLabel = job.prodSourceLabel
212
+ prevDirectAcc = job.transferType
213
+ prevBrokerageSiteList = specialBrokerageSiteList
214
+ prevIsJEDI = isJEDI
215
+
216
+ # assign site
217
+ if chosen_panda_queue != "TOBEDONE":
218
+ job.computingSite = chosen_panda_queue.sitename
219
+ tmp_log.debug(f"PandaID:{job.PandaID} -> preset site:{chosen_panda_queue.sitename}")
220
+ # set cloud
221
+ if job.cloud in ["NULL", None, ""]:
222
+ job.cloud = chosen_panda_queue.cloud
223
+
224
+ # set destinationSE
225
+ destSE = job.destinationSE
226
+ if siteMapper.checkCloud(job.getCloud()):
227
+ # use cloud dest for non-existing sites
228
+ if job.prodSourceLabel != "user" and job.destinationSE not in siteMapper.siteSpecList and job.destinationSE != "local":
229
+ if DataServiceUtils.checkJobDestinationSE(job):
230
+ destSE = DataServiceUtils.checkJobDestinationSE(job)
231
+ job.destinationSE = destSE
232
+
233
+ if overwriteSite:
234
+ # overwrite SE for analysis jobs which set non-existing sites
235
+ destSE = job.computingSite
236
+ job.destinationSE = destSE
237
+
238
+ # set dispatchDBlock and destinationSE
239
+ first = True
240
+ for file in job.Files:
241
+ # Set dispatch data block for pre-stating jobs too
242
+ if file.type == "input" and file.dispatchDBlock == "NULL" and file.status not in ["ready", "missing", "cached"]:
243
+ if first:
244
+ first = False
245
+ job.dispatchDBlock = dispatchDBlock
246
+ file.dispatchDBlock = dispatchDBlock
247
+ file.status = "pending"
248
+ if file.lfn not in fileList:
249
+ fileList.append(file.lfn)
250
+
251
+ # destinationSE
252
+ if file.type in ["output", "log"] and destSE != "":
253
+ if job.prodSourceLabel == "user" and job.computingSite == file.destinationSE:
254
+ pass
255
+ elif job.prodSourceLabel == "user" and prevIsJEDI is True and file.destinationSE not in ["", "NULL"]:
256
+ pass
257
+ elif destSE == "local":
258
+ pass
259
+ elif DataServiceUtils.getDistributedDestination(file.destinationDBlockToken):
260
+ pass
261
+ else:
262
+ file.destinationSE = destSE
263
+
264
+ # pre-assign GUID to log
265
+ if file.type == "log":
266
+ # generate GUID
267
+ file.GUID = str(uuid.uuid4())
268
+
269
+ tmp_log.debug("finished")
270
+
271
+ except Exception as e:
272
+ tmp_log.error(f"schedule : {str(e)} {traceback.format_exc()}")
File without changes
@@ -0,0 +1,15 @@
1
+ import json
2
+ import os
3
+
4
+
5
+ # load configmap
6
+ def load_config_map(section, target_dict):
7
+ if "PANDA_HOME" not in os.environ:
8
+ return
9
+ config_map_name = "panda_server_config.json"
10
+ config_map_path = os.path.join(os.environ["PANDA_HOME"], "etc/config_json", config_map_name)
11
+ if os.path.exists(config_map_path):
12
+ with open(config_map_path) as f:
13
+ tmp_data = json.load(f)
14
+ if section in tmp_data:
15
+ target_dict.update(tmp_data[section])
@@ -0,0 +1,29 @@
1
+ import re
2
+ import sys
3
+
4
+ from pandacommon.liveconfigparser.LiveConfigParser import (
5
+ LiveConfigParser,
6
+ expand_values,
7
+ )
8
+
9
+ from . import config_utils
10
+
11
+ # get ConfigParser
12
+ tmpConf = LiveConfigParser()
13
+
14
+ # read
15
+ tmpConf.read("panda_server.cfg")
16
+
17
+ # get daemon section
18
+ tmpDict = getattr(tmpConf, "daemon", {})
19
+
20
+ # read configmap
21
+ config_utils.load_config_map("daemon", tmpDict)
22
+
23
+ # expand all values
24
+ tmpSelf = sys.modules[__name__]
25
+ expand_values(tmpSelf, tmpDict)
26
+
27
+ # default values
28
+ if "enable" not in tmpSelf.__dict__:
29
+ tmpSelf.__dict__["enable"] = False
@@ -0,0 +1,38 @@
1
+ import re
2
+ import sys
3
+
4
+ from pandacommon.liveconfigparser.LiveConfigParser import (
5
+ LiveConfigParser,
6
+ expand_values,
7
+ )
8
+
9
+ from . import config_utils
10
+
11
+ # get ConfigParser
12
+ tmp_conf = LiveConfigParser()
13
+
14
+ # read
15
+ tmp_conf.read("panda_server.cfg")
16
+
17
+ # get daemon section
18
+ tmp_dict = getattr(tmp_conf, "mcp", {})
19
+
20
+ # read configmap
21
+ config_utils.load_config_map("mcp", tmp_dict)
22
+
23
+ # expand all values
24
+ tmp_self = sys.modules[__name__]
25
+ expand_values(tmp_self, tmp_dict)
26
+
27
+ # default values
28
+ if "transport" not in tmp_self.__dict__:
29
+ tmp_self.__dict__["transport"] = "streamable-http"
30
+
31
+ if "endpoint_list_file" not in tmp_self.__dict__:
32
+ tmp_self.__dict__["endpoint_list_file"] = "/opt/panda/etc/panda/panda_mcp_endpoints.json"
33
+
34
+ if "ssl_keyfile" not in tmp_self.__dict__:
35
+ tmp_self.__dict__["ssl_keyfile"] = None
36
+
37
+ if "ssl_certfile" not in tmp_self.__dict__:
38
+ tmp_self.__dict__["ssl_certfile"] = None
@@ -0,0 +1,233 @@
1
+ import glob
2
+ import json
3
+ import os
4
+ import re
5
+ import socket
6
+ import sys
7
+
8
+ from pandacommon.liveconfigparser.LiveConfigParser import (
9
+ LiveConfigParser,
10
+ expand_values,
11
+ )
12
+
13
+ from . import config_utils
14
+
15
+ # get ConfigParser
16
+ tmpConf = LiveConfigParser()
17
+
18
+ # read
19
+ tmpConf.read("panda_server.cfg")
20
+
21
+ # get server section
22
+ tmpDict = tmpConf.server
23
+
24
+ # read configmap
25
+ config_utils.load_config_map("server", tmpDict)
26
+
27
+ # expand all values
28
+ tmpSelf = sys.modules[__name__]
29
+ expand_values(tmpSelf, tmpDict)
30
+
31
+ # set hostname
32
+ if "pserverhost" not in tmpSelf.__dict__:
33
+ tmpSelf.__dict__["pserverhost"] = socket.getfqdn()
34
+
35
+ # set port for http
36
+ if "pserverporthttp" not in tmpSelf.__dict__:
37
+ tmpSelf.__dict__["pserverporthttp"] = 25080
38
+
39
+ # set host for http
40
+ if "pserverhosthttp" not in tmpSelf.__dict__:
41
+ tmpSelf.__dict__["pserverhosthttp"] = tmpSelf.__dict__["pserverhost"]
42
+
43
+ # disable http
44
+ if "disableHTTP" not in tmpSelf.__dict__:
45
+ tmpSelf.__dict__["disableHTTP"] = False
46
+
47
+ # DB backend
48
+ if "backend" not in tmpSelf.__dict__:
49
+ tmpSelf.__dict__["backend"] = "oracle"
50
+ if "dbport" not in tmpSelf.__dict__:
51
+ tmpSelf.__dict__["dbport"] = 0
52
+ if "dbtimeout" not in tmpSelf.__dict__:
53
+ tmpSelf.__dict__["dbtimeout"] = 60
54
+
55
+ # Directory for certs
56
+ if "certdir" not in tmpSelf.__dict__:
57
+ tmpSelf.__dict__["certdir"] = "/data/atlpan"
58
+
59
+ # endpoint map file
60
+ if "endpoint_mapfile" not in tmpSelf.__dict__:
61
+ tmpSelf.__dict__["endpoint_mapfile"] = (
62
+ "/cvmfs/atlas.cern.ch/repo/sw/local/etc/cric_ddmendpoints.json" ",/cvmfs/atlas.cern.ch/repo/sw/local/etc/agis_ddmendpoints.json"
63
+ )
64
+
65
+ # sandbox info
66
+ if "record_sandbox_info" not in tmpSelf.__dict__:
67
+ tmpSelf.__dict__["record_sandbox_info"] = True
68
+
69
+ # secrets
70
+ if "pilot_secrets" not in tmpSelf.__dict__:
71
+ tmpSelf.__dict__["pilot_secrets"] = "pilot secrets"
72
+
73
+ # schemas
74
+ if "schemaPANDA" not in tmpSelf.__dict__:
75
+ tmpSelf.__dict__["schemaPANDA"] = "ATLAS_PANDA"
76
+ if "schemaPANDAARCH" not in tmpSelf.__dict__:
77
+ tmpSelf.__dict__["schemaPANDAARCH"] = "ATLAS_PANDAARCH"
78
+ if "schemaMETA" not in tmpSelf.__dict__:
79
+ tmpSelf.__dict__["schemaMETA"] = "ATLAS_PANDAMETA"
80
+ if "schemaJEDI" not in tmpSelf.__dict__:
81
+ tmpSelf.__dict__["schemaJEDI"] = "ATLAS_PANDA"
82
+ if "schemaDEFT" not in tmpSelf.__dict__:
83
+ tmpSelf.__dict__["schemaDEFT"] = "ATLAS_DEFT"
84
+ if "schemaGRISLI" not in tmpSelf.__dict__:
85
+ tmpSelf.__dict__["schemaGRISLI"] = "ATLAS_GRISLI"
86
+ if "schemaEI" not in tmpSelf.__dict__:
87
+ tmpSelf.__dict__["schemaEI"] = "ATLAS_EVENTINDEX"
88
+
89
+ # default site
90
+ if "def_sitename" not in tmpSelf.__dict__:
91
+ tmpSelf.__dict__["def_sitename"] = "BNL_ATLAS_1"
92
+ if "def_queue" not in tmpSelf.__dict__:
93
+ tmpSelf.__dict__["def_queue"] = "ANALY_BNL_ATLAS_1"
94
+ if "def_nickname" not in tmpSelf.__dict__:
95
+ tmpSelf.__dict__["def_nickname"] = "BNL_ATLAS_1-condor"
96
+ if "def_ddm" not in tmpSelf.__dict__:
97
+ tmpSelf.__dict__["def_ddm"] = "PANDA_UNDEFINED2"
98
+ if "def_type" not in tmpSelf.__dict__:
99
+ tmpSelf.__dict__["def_type"] = "production"
100
+ if "def_status" not in tmpSelf.__dict__:
101
+ tmpSelf.__dict__["def_status"] = "online"
102
+ if "token_authType" not in tmpSelf.__dict__:
103
+ tmpSelf.__dict__["token_authType"] = "oidc"
104
+ if "auth_config" not in tmpSelf.__dict__:
105
+ tmpSelf.__dict__["auth_config"] = "/opt/panda/etc/panda/auth/"
106
+ if "token_audience" not in tmpSelf.__dict__:
107
+ tmpSelf.__dict__["token_audience"] = "https://pandaserver.cern.ch"
108
+ if "token_issuers" not in tmpSelf.__dict__:
109
+ tmpSelf.__dict__["token_issuers"] = ""
110
+ if "legacy_token_issuers" not in tmpSelf.__dict__:
111
+ tmpSelf.__dict__["legacy_token_issuers"] = "https://atlas-auth.cern.ch/,https://atlas-auth.web.cern.ch/"
112
+ if tmpSelf.__dict__["legacy_token_issuers"]:
113
+ tmpSelf.__dict__["legacy_token_issuers"] = tmpSelf.__dict__["legacy_token_issuers"].split(",")
114
+ else:
115
+ tmpSelf.__dict__["legacy_token_issuers"] = None
116
+ tmpSelf.__dict__["production_dns"] = [x for x in tmpSelf.__dict__.get("production_dns", "").split(",") if x]
117
+ tmpSelf.__dict__["pilot_owners"] = [x for x in tmpSelf.__dict__.get("pilot_owners", "").split(",") if x]
118
+ tmpSelf.__dict__["auth_policies"] = {}
119
+ tmpSelf.__dict__["auth_vo_dict"] = {}
120
+ try:
121
+ data_dict = {}
122
+ vo_data_dict = {}
123
+ policy_dict = {}
124
+ for name in glob.glob(os.path.join(tmpSelf.__dict__["auth_config"], "*_auth_config.json")):
125
+ with open(name) as f:
126
+ data = json.load(f)
127
+ data_dict[data["client_id"]] = data
128
+ if "secondary_ids" in data:
129
+ for tmp_id in data["secondary_ids"]:
130
+ data_dict[tmp_id] = data
131
+ m = re.search("^(.+)_auth_config.json", os.path.basename(name))
132
+ if m:
133
+ # Extract the VO group from the filename
134
+ tmp_vo_group = m.group(1)
135
+
136
+ # Determine tmp_vo and tmp_group based on delimiters
137
+ if tmp_vo_group.startswith("vo.") and ":" in tmp_vo_group:
138
+ tmp_vo, tmp_group = tmp_vo_group.split(":", 1)
139
+ elif ":" in tmp_vo_group:
140
+ tmp_vo, tmp_group = tmp_vo_group.split(":", 1)
141
+ elif tmp_vo_group.startswith("vo."):
142
+ # If it starts with "vo." but has no ":", treat it as a single VO with "user" as the group
143
+ tmp_vo = tmp_vo_group
144
+ tmp_group = "user"
145
+ elif "." in tmp_vo_group:
146
+ tmp_vo, tmp_group = tmp_vo_group.split(".", 1)
147
+ else:
148
+ tmp_vo, tmp_group = tmp_vo_group, "user"
149
+
150
+ policy_dict.setdefault(tmp_vo, [])
151
+ policy_dict[tmp_vo].append([tmp_vo, {"group": tmp_group, "role": tmp_group}])
152
+ vo_data_dict[tmp_vo_group.replace(":", ".")] = data
153
+ tmpSelf.__dict__["auth_config"] = data_dict
154
+ tmpSelf.__dict__["auth_policies"] = policy_dict
155
+ tmpSelf.__dict__["auth_vo_dict"] = vo_data_dict
156
+ except Exception:
157
+ tmpSelf.__dict__["auth_config"] = {}
158
+
159
+ if "token_cache_config" not in tmpSelf.__dict__:
160
+ tmpSelf.__dict__["token_cache_config"] = "/opt/panda/etc/panda/token_cache_config.json"
161
+
162
+ # use cert in configurator
163
+ if "configurator_use_cert" not in tmpSelf.__dict__:
164
+ tmpSelf.__dict__["configurator_use_cert"] = True
165
+
166
+ # adder serialization
167
+ if "add_serialized" not in tmpSelf.__dict__:
168
+ tmpSelf.__dict__["add_serialized"] = False
169
+
170
+ # disable file aggregation
171
+ if "disable_file_aggregation" not in tmpSelf.__dict__:
172
+ tmpSelf.__dict__["disable_file_aggregation"] = False
173
+
174
+ # dict for plugins
175
+ g_pluginMap = {}
176
+
177
+
178
+ # parser for plugin setup
179
+ def parsePluginConf(modConfigName):
180
+ global tmpSelf
181
+ global g_pluginMap
182
+ g_pluginMap.setdefault(modConfigName, {})
183
+ # parse plugin setup
184
+ try:
185
+ for configStr in getattr(tmpSelf, modConfigName).split(","):
186
+ configStr = configStr.strip()
187
+ items = configStr.split(":")
188
+ vos = items[0].split("|")
189
+ moduleName = items[1]
190
+ className = items[2]
191
+ if len(items) > 3:
192
+ group = items[3]
193
+ else:
194
+ group = None
195
+ for vo in vos:
196
+ # import
197
+ mod = __import__(moduleName)
198
+ for subModuleName in moduleName.split(".")[1:]:
199
+ mod = getattr(mod, subModuleName)
200
+ # get class
201
+ cls = getattr(mod, className)
202
+ if group:
203
+ vo_key = f"{vo}_{group}"
204
+ else:
205
+ vo_key = vo
206
+ g_pluginMap[modConfigName][vo_key] = cls
207
+ except Exception:
208
+ pass
209
+
210
+
211
+ # accessor for plugin
212
+ def getPlugin(modConfigName, vo, group=None):
213
+ if modConfigName not in g_pluginMap:
214
+ return None
215
+ if group:
216
+ vo_group = f"{vo}_{group}"
217
+ if vo_group in g_pluginMap[modConfigName]:
218
+ # VO+group specified
219
+ return g_pluginMap[modConfigName][vo_group]
220
+ if vo in g_pluginMap[modConfigName]:
221
+ # VO specified
222
+ return g_pluginMap[modConfigName][vo]
223
+ if "any" in g_pluginMap[modConfigName]:
224
+ # catch all
225
+ return g_pluginMap[modConfigName]["any"]
226
+ # undefined
227
+ return None
228
+
229
+
230
+ # plug-ins
231
+ def setupPlugin():
232
+ parsePluginConf("adder_plugins")
233
+ parsePluginConf("setupper_plugins")
@@ -0,0 +1,65 @@
1
+ import datetime
2
+ import threading
3
+ import traceback
4
+
5
+ from pandacommon.pandalogger.PandaLogger import PandaLogger
6
+ from pandaserver.config import panda_config
7
+ from pandaserver.configurator import aux
8
+
9
+ _logger = PandaLogger().getLogger("carbon")
10
+
11
+
12
+ class CarbonEmissions(threading.Thread):
13
+ """
14
+ Downloads the carbon information from the relevant sources
15
+ """
16
+
17
+ def __init__(self, taskBuffer):
18
+ threading.Thread.__init__(self)
19
+
20
+ self.bearer_token = None
21
+ if hasattr(panda_config, "CO2_BEARER_TOKEN"):
22
+ self.bearer_token = panda_config.CO2_BEARER_TOKEN
23
+
24
+ self.taskBuffer = taskBuffer
25
+
26
+ def download_region_emissions(self):
27
+ # Don't indent the query
28
+ query = """
29
+ {"search_type": "query_then_fetch","ignore_unavailable": true,"index": ["monit_prod_green-it_raw_regionmetric*"]}
30
+ {"query": {"range": {"metadata.timestamp": {"gte": "now-2h","lt": "now"}}}, "size": 100}}
31
+ """
32
+ try:
33
+ results = aux.query_grafana_proxy(query, self.bearer_token)
34
+ if not results:
35
+ _logger.error("download_region_emissions was not able to download data")
36
+ return None
37
+
38
+ status = results["responses"][0]["status"]
39
+ if status != 200:
40
+ _logger.error(f"download_region_emissions was not able to download data with status {status}")
41
+ return None
42
+
43
+ hits = results["responses"][0]["hits"]["hits"] # That's how the json is structured...
44
+ results = []
45
+ for entry in hits:
46
+ simplified_entry = {
47
+ "region": entry["_source"]["data"]["region"],
48
+ # timestamps come in ms
49
+ "timestamp": datetime.datetime.fromtimestamp(entry["_source"]["metadata"]["timestamp"] / 1000),
50
+ "value": entry["_source"]["data"]["gCO2_perkWh"],
51
+ }
52
+ results.append(simplified_entry)
53
+ return results
54
+ except Exception:
55
+ _logger.error(f"download_region_emissions excepted with {traceback.format_exc()}")
56
+ return None
57
+
58
+ def run(self):
59
+ # download emissions and store them in the DB
60
+ results = self.download_region_emissions()
61
+ if results:
62
+ self.taskBuffer.carbon_write_region_emissions(results)
63
+
64
+ # aggregate the emissions for the grid
65
+ self.taskBuffer.carbon_aggregate_emissions()