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,487 @@
1
+ """
2
+ WrappedCursor for a generic database connection proxy
3
+
4
+ """
5
+
6
+ import os
7
+ import re
8
+ import warnings
9
+
10
+ from pandacommon.pandalogger.PandaLogger import PandaLogger
11
+
12
+ from pandaserver.config import panda_config
13
+
14
+ warnings.filterwarnings("ignore")
15
+
16
+ _logger = PandaLogger().getLogger("WrappedCursor")
17
+
18
+
19
+ # extract table names from sql query
20
+ def extract_table_names(sql):
21
+ table_names = []
22
+ for item in re.findall(r" FROM (.+?)(WHERE|$)", sql, flags=re.IGNORECASE):
23
+ if "FROM" in item[0]:
24
+ table_names += extract_table_names(item[0])
25
+ else:
26
+ table_strs = item[0].split(",")
27
+ table_names += [re.sub(r"\(|\)", "", t.strip().lower()) for table_str in table_strs for t in table_str.split() if t.strip()]
28
+ return table_names
29
+
30
+
31
+ # convert SQL and parameters in_printf format
32
+ def convert_query_in_printf_format(sql, var_dict_list, sql_conv_map):
33
+ if sql in sql_conv_map:
34
+ sql = sql_conv_map[sql]
35
+ else:
36
+ old_sql = sql
37
+ if var_dict_list:
38
+ var_dict = var_dict_list[0]
39
+ else:
40
+ var_dict = {}
41
+ # %
42
+ sql = re.sub(r"%", r"%%", sql)
43
+ # current date except for being used for interval
44
+ if re.search(r"CURRENT_DATE\s*[\+-]", sql, flags=re.IGNORECASE) is None:
45
+ sql = re.sub(r"CURRENT_DATE", r"CURRENT_TIMESTAMP", sql, flags=re.IGNORECASE)
46
+ # sequence
47
+ sql = re.sub(r"""([^ $,()]+).currval""", r"currval('\1')", sql, flags=re.IGNORECASE)
48
+ sql = re.sub(r"""([^ $,()]+).nextval""", r"nextval('\1')", sql, flags=re.IGNORECASE)
49
+ # returning
50
+ sql = re.sub(r"(RETURNING\s+\S+\s+)INTO\s+\S+", r"\1", sql, flags=re.IGNORECASE)
51
+ # sub query + rownum
52
+ sql = re.sub(r"\)\s+WHERE\s+rownum", r") tmp_sub WHERE rownum", sql, flags=re.IGNORECASE)
53
+ # sub query + GROUP BY
54
+ if re.search(r"FROM\s+\(\s*SELECT", sql, flags=re.IGNORECASE):
55
+ sql = re.sub(r"\)\s+GROUP\s+BY", r") tmp_sub GROUP BY", sql, flags=re.IGNORECASE)
56
+ # rownum
57
+ sql = re.sub(
58
+ r"(WHERE|AND)\s+rownum[^\d:]+(\d+|:[^ \)]+)",
59
+ r" LIMIT \2",
60
+ sql,
61
+ flags=re.IGNORECASE,
62
+ )
63
+ # NVL
64
+ sql = re.sub(r"NVL\(", r"COALESCE(", sql, flags=re.IGNORECASE)
65
+ # INSTR
66
+ sql = re.sub(r"INSTR\(", r"STRPOS(", sql, flags=re.IGNORECASE)
67
+ # random
68
+ sql = re.sub(r"DBMS_RANDOM.value", r"RANDOM()", sql, flags=re.IGNORECASE)
69
+ # MINUS
70
+ sql = re.sub(r" MINUS ", r" EXCEPT ", sql, flags=re.IGNORECASE)
71
+ # GENERATE_SERIES
72
+ sql = re.sub(
73
+ r"\(SELECT\s+level\s+FROM\s+dual\s+CONNECT\s+BY\s+level\s*<=\s*(:[^ \)]+)\)*",
74
+ r"GENERATE_SERIES(1,\1)",
75
+ sql,
76
+ flags=re.IGNORECASE,
77
+ )
78
+ # dual
79
+ sql = re.sub(r"FROM dual", "", sql, flags=re.IGNORECASE)
80
+ # NOWAIT
81
+ sql = re.sub(r"FOR UPDATE NOWAIT", "FOR UPDATE SKIP LOCKED", sql, flags=re.IGNORECASE)
82
+ # json
83
+ if "/* use_json_type */" in sql:
84
+ # remove \n to make regexp easier
85
+ sql = re.sub(r"\n", r" ", sql)
86
+ # collect table names
87
+ table_names = set(extract_table_names(sql))
88
+ checked_items = set()
89
+ # look for a.b(.c)*
90
+ for item in re.findall(r"(\w+\.\w+\.*\w*)", sql):
91
+ # skip if already checked
92
+ if item in checked_items:
93
+ continue
94
+ checked_items.add(item)
95
+ item_l = item.lower()
96
+ # ignore tables
97
+ if item_l in table_names:
98
+ continue
99
+ # ignore float
100
+ if item.replace(".", "", 1).isdigit():
101
+ continue
102
+ to_skip = False
103
+ new_pat = None
104
+ # check if table.column.field
105
+ for table_name in table_names:
106
+ if item_l.startswith(f"{table_name}."):
107
+ item_body = re.sub(f"^{table_name}" + r"\.", "", item, flags=re.IGNORECASE)
108
+ # no json field
109
+ if item_body.count(".") == 0:
110
+ to_skip = True
111
+ break
112
+ # convert . to ->>''
113
+ new_body = re.sub(r"\.(?P<pat>\w+)", r"->>'\1'", item_body)
114
+ # prepend the table name
115
+ new_pat = ".".join(item.split(".")[: -(1 + item_body.count("."))]) + "." + new_body
116
+ break
117
+ # ignore table.column
118
+ if to_skip:
119
+ continue
120
+ old_pat = item
121
+ # colum.field
122
+ if not new_pat:
123
+ new_pat = re.sub(r"\.(?P<pat>\w+)", r"->>'\1'", item)
124
+ # guess type
125
+ right_vals = re.findall(old_pat + r"\s*[=<>!*]+\s*([\w:\']+)", sql)
126
+ for right_val in right_vals:
127
+ # string
128
+ if "'" in right_val:
129
+ break
130
+ # integer
131
+ if right_val.isdigit():
132
+ new_pat = f"CAST({new_pat} AS integer)"
133
+ break
134
+ # float
135
+ if right_val.replace(".", "", 1).isdigit():
136
+ new_pat = f"CAST({new_pat} AS float)"
137
+ break
138
+ # bind variable
139
+ if right_val.startswith(":"):
140
+ if right_val not in var_dict:
141
+ raise KeyError(f"{right_val} is missing to guess data type")
142
+ if isinstance(var_dict[right_val], int):
143
+ new_pat = f"CAST({new_pat} AS integer)"
144
+ break
145
+ if isinstance(var_dict[right_val], float):
146
+ new_pat = f"CAST({new_pat} AS float)"
147
+ break
148
+ # replace
149
+ print(old_pat, new_pat)
150
+ sql = sql.replace(old_pat, new_pat)
151
+ # cache
152
+ sql_conv_map[old_sql] = sql
153
+ # extract placeholders
154
+ params_list = []
155
+ items = re.findall(r":[^ $,)\+\-\n]+", sql)
156
+ for var_dict in var_dict_list:
157
+ params = []
158
+ for item in items:
159
+ if item not in var_dict:
160
+ raise KeyError(f"{item} is missing in SQL parameters")
161
+ params.append(var_dict[item])
162
+ params_list.append(params)
163
+ # using the printf style syntax
164
+ sql = re.sub(":[^ $,)\+\-]+", "%s", sql)
165
+ return sql, params_list
166
+
167
+
168
+ # proxy
169
+ class WrappedCursor(object):
170
+ # constructor
171
+ def __init__(self, connection):
172
+ # connection object
173
+ self.conn = connection
174
+ # cursor object
175
+ self.cur = self.conn.cursor()
176
+ # backend
177
+ self.backend = panda_config.backend
178
+ # statement
179
+ self.statement = None
180
+ # dump
181
+ if hasattr(panda_config, "cursor_dump") and panda_config.cursor_dump:
182
+ self.dump = True
183
+ else:
184
+ self.dump = False
185
+ # SQL conversion map
186
+ self.sql_conv_map = {}
187
+ # executemany
188
+ if self.backend == "postgres":
189
+ from psycopg2.extras import execute_batch
190
+
191
+ self.alt_executemany = execute_batch
192
+ else:
193
+ self.alt_executemany = None
194
+
195
+ # __iter__
196
+ def __iter__(self):
197
+ return iter(self.cur)
198
+
199
+ # serialize
200
+ def __str__(self):
201
+ return f"WrappedCursor[{self.conn}]"
202
+
203
+ # initialize
204
+ def initialize(self):
205
+ hostname = None
206
+ if self.backend == "oracle":
207
+ # get hostname
208
+ self.execute("SELECT SYS_CONTEXT('USERENV','HOST') FROM dual")
209
+ res = self.fetchone()
210
+ if res is not None:
211
+ hostname = res[0]
212
+ # set TZ
213
+ self.execute("ALTER SESSION SET TIME_ZONE='UTC'")
214
+ # set DATE format
215
+ self.execute("ALTER SESSION SET NLS_DATE_FORMAT='YYYY/MM/DD HH24:MI:SS'")
216
+ # set Oracle optimizer version. This is done only temporarily for controlled migration to 19c
217
+ self.execute("ALTER SESSION SET optimizer_features_enable='19.1.0'")
218
+
219
+ elif self.backend == "postgres":
220
+ # disable autocommit
221
+ # make sure that always have commit() since any query execution, including SELECT will start a transaction
222
+ self.conn.set_session(autocommit=False)
223
+ # encoding
224
+ self.conn.set_client_encoding("UTF-8")
225
+ # TZ
226
+ self.execute("SET timezone=0")
227
+ # commit to set session params permanently
228
+ self.conn.commit()
229
+ else:
230
+ # get hostname
231
+ self.execute("SELECT SUBSTRING_INDEX(USER(),'@',-1)")
232
+ res = self.fetchone()
233
+ if res is not None:
234
+ hostname = res[0]
235
+ # set TZ
236
+ self.execute("SET @@SESSION.TIME_ZONE = '+00:00'")
237
+ # set DATE format
238
+ # self.execute("SET @@SESSION.DATETIME_FORMAT='%%Y/%%m/%%d %%H:%%i:%%s'")
239
+ # disable autocommit
240
+ self.execute("SET autocommit=0")
241
+ return hostname
242
+
243
+ # execute query on cursor
244
+ def execute(self, sql, varDict=None, cur=None): # , returningInto=None
245
+ if varDict is None:
246
+ varDict = {}
247
+ if cur is None:
248
+ cur = self.cur
249
+ ret = None
250
+ # schema names
251
+ sql = self.change_schema(sql)
252
+ # remove `
253
+ sql = re.sub("`", "", sql)
254
+ if self.backend == "oracle":
255
+ ret = cur.execute(sql, varDict)
256
+ elif self.backend == "postgres":
257
+ if self.dump:
258
+ _logger.debug(f"OLD: {sql} {str(varDict)}")
259
+ sql, vars_list = convert_query_in_printf_format(sql, [varDict], self.sql_conv_map)
260
+ varList = vars_list[0]
261
+ if self.dump:
262
+ _logger.debug(f"NEW: {sql} {str(varList)}")
263
+ # counting the number of unlocked rows and raise when nothing available, to mimic NOWAIT behavior in Oracle
264
+ if "FOR UPDATE SKIP LOCKED" in sql:
265
+ cur.execute(f"SELECT COUNT(*) FROM ({sql}) t", varList)
266
+ if cur.fetchone()[0] == 0:
267
+ from psycopg2.errors import LockNotAvailable
268
+
269
+ raise LockNotAvailable("could not obtain lock on row")
270
+ ret = cur.execute(sql, varList)
271
+ elif self.backend == "mysql":
272
+ print(f"DEBUG execute : original SQL {sql} ")
273
+ print(f"DEBUG execute : original varDict {varDict} ")
274
+ # CURRENT_DATE interval
275
+ sql = re.sub(
276
+ "CURRENT_DATE\s*-\s*(\d+|:[^\s\)]+)",
277
+ "DATE_SUB(CURRENT_TIMESTAMP,INTERVAL \g<1> DAY)",
278
+ sql,
279
+ )
280
+ # CURRENT_DATE
281
+ sql = re.sub("CURRENT_DATE", "CURRENT_TIMESTAMP", sql)
282
+ # SYSDATE interval
283
+ sql = re.sub(
284
+ "SYSDATE\s*-\s*(\d+|:[^\s\)]+)",
285
+ "DATE_SUB(SYSDATE,INTERVAL \g<1> DAY)",
286
+ sql,
287
+ )
288
+ # SYSDATE
289
+ sql = re.sub("SYSDATE", "SYSDATE()", sql)
290
+ # EMPTY_CLOB()
291
+ sql = re.sub("EMPTY_CLOB\(\)", "''", sql)
292
+ # ROWNUM
293
+ sql = re.sub("(?i)(AND)*\s*ROWNUM.*(\d+)", " LIMIT \g<2>", sql)
294
+ sql = re.sub("(?i)(WHERE)\s*LIMIT\s*(\d+)", " LIMIT \g<2>", sql)
295
+ # NOWAIT
296
+ sql = re.sub("NOWAIT", "", sql)
297
+ # RETURNING INTO
298
+ returningInto = None
299
+ m = re.search("RETURNING ([^\s]+) INTO ([^\s]+)", sql, re.I)
300
+ if m is not None:
301
+ returningInto = [{"returning": m.group(1), "into": m.group(2)}]
302
+ self._returningIntoMySQLpre(returningInto, varDict, cur)
303
+ sql = re.sub(m.group(0), "", sql)
304
+ # Addressing sequence
305
+ if "INSERT" in sql:
306
+ sql = re.sub("[a-zA-Z\._]+\.nextval", "NULL", sql)
307
+ # schema names
308
+ sql = re.sub("ATLAS_PANDA\.", panda_config.schemaPANDA + ".", sql)
309
+ sql = re.sub("ATLAS_PANDAMETA\.", panda_config.schemaMETA + ".", sql)
310
+ sql = re.sub("ATLAS_GRISLI\.", panda_config.schemaGRISLI + ".", sql)
311
+ sql = re.sub("ATLAS_PANDAARCH\.", panda_config.schemaPANDAARCH + ".", sql)
312
+ # bind variables
313
+ newVarDict = {}
314
+ # make sure that :prodDBlockToken will not be replaced by %(prodDBlock)sToken
315
+ keys = sorted(list(varDict), key=lambda s: -len(str(s)))
316
+ for key in keys:
317
+ val = varDict[key]
318
+ if key[0] == ":":
319
+ newKey = key[1:]
320
+ sql = sql.replace(key, "%(" + newKey + ")s")
321
+ else:
322
+ newKey = key
323
+ sql = sql.replace(":" + key, "%(" + newKey + ")s")
324
+ newVarDict[newKey] = val
325
+ try:
326
+ # from PanDA monitor it is hard to log queries sometimes, so let's debug with hardcoded query dumps
327
+ import time
328
+
329
+ if os.path.exists("/data/atlpan/oracle/panda/monitor/logs/write_queries.txt"):
330
+ f = open(
331
+ "/data/atlpan/oracle/panda/monitor/logs/mysql_queries_WrappedCursor.txt",
332
+ "a",
333
+ )
334
+ f.write(f"mysql|{str(time.time())}|{str(sql)}|{str(newVarDict)}\n")
335
+ f.close()
336
+ except Exception:
337
+ pass
338
+ _logger.debug(f"execute : SQL {sql} ")
339
+ _logger.debug(f"execute : varDict {newVarDict} ")
340
+ print(f"DEBUG execute : SQL {sql} ")
341
+ print(f"DEBUG execute : varDict {newVarDict} ")
342
+ ret = cur.execute(sql, newVarDict)
343
+ if returningInto is not None:
344
+ ret = self._returningIntoMySQLpost(returningInto, varDict, cur)
345
+ return ret
346
+
347
+ def _returningIntoOracle(self, returningInputData, varDict, cur, dryRun=False):
348
+ # returningInputData=[{'returning': 'PandaID', 'into': ':newPandaID'}, {'returning': 'row_ID', 'into': ':newRowID'}]
349
+ result = ""
350
+ if returningInputData is not None:
351
+ try:
352
+ valReturning = str(",").join([x["returning"] for x in returningInputData])
353
+ listInto = [x["into"] for x in returningInputData]
354
+ valInto = str(",").join(listInto)
355
+ # assuming that we use RETURNING INTO only for PandaID or row_ID columns
356
+ if not dryRun:
357
+ for x in listInto:
358
+ varDict[x] = cur.var(oracledb.NUMBER)
359
+ result = f" RETURNING {valReturning} INTO {valInto} "
360
+ except Exception:
361
+ pass
362
+ return result
363
+
364
+ def _returningIntoMySQLpre(self, returningInputData, varDict, cur):
365
+ # returningInputData=[{'returning': 'PandaID', 'into': ':newPandaID'}, {'returning': 'row_ID', 'into': ':newRowID'}]
366
+ if returningInputData is not None:
367
+ try:
368
+ # get rid of "returning into" items in varDict
369
+ listInto = [x["into"] for x in returningInputData]
370
+ for x in listInto:
371
+ try:
372
+ del varDict[x]
373
+ except KeyError:
374
+ pass
375
+ if len(returningInputData) == 1:
376
+ # and set original value in varDict to null, let auto_increment do the work
377
+ listReturning = [x["returning"] for x in returningInputData]
378
+ for x in listReturning:
379
+ varDict[":" + x] = None
380
+ except Exception:
381
+ pass
382
+
383
+ def _returningIntoMySQLpost(self, returningInputData, varDict, cur):
384
+ # returningInputData=[{'returning': 'PandaID', 'into': ':newPandaID'}, {'returning': 'row_ID', 'into': ':newRowID'}]
385
+ result = int(0)
386
+ if len(returningInputData) == 1:
387
+ ret = self.cur.execute(""" SELECT LAST_INSERT_ID() """)
388
+ (result,) = self.cur.fetchone()
389
+ if returningInputData is not None:
390
+ try:
391
+ # update of "returning into" items in varDict
392
+ listInto = [x["into"] for x in returningInputData]
393
+ for x in listInto:
394
+ try:
395
+ varDict[x] = int(result)
396
+ except KeyError:
397
+ pass
398
+ except Exception:
399
+ pass
400
+ return result
401
+
402
+ # fetchall
403
+ def fetchall(self):
404
+ return self.cur.fetchall()
405
+
406
+ # fetchmany
407
+ def fetchmany(self, arraysize=1000):
408
+ self.cur.arraysize = arraysize
409
+ return self.cur.fetchmany()
410
+
411
+ # fetchall
412
+ def fetchone(self):
413
+ return self.cur.fetchone()
414
+
415
+ # var
416
+ def var(self, dataType, *args, **kwargs):
417
+ if self.backend == "mysql":
418
+ return apply(dataType, [0])
419
+ elif self.backend == "postgres":
420
+ return None
421
+ else:
422
+ return self.cur.var(dataType, *args, **kwargs)
423
+
424
+ # get value
425
+ def getvalue(self, dataItem):
426
+ if self.backend == "mysql":
427
+ return dataItem
428
+ elif self.backend == "postgres":
429
+ return self.cur.fetchone()[0]
430
+ else:
431
+ return dataItem.getvalue()
432
+
433
+ # next
434
+ def next(self):
435
+ if self.backend == "mysql":
436
+ return self.cur.fetchone()
437
+ return self.cur.next()
438
+
439
+ # close
440
+ def close(self):
441
+ return self.cur.close()
442
+
443
+ # prepare
444
+ def prepare(self, statement):
445
+ self.statement = statement
446
+
447
+ # executemany
448
+ def executemany(self, sql, params):
449
+ if sql is None:
450
+ sql = self.statement
451
+ sql = self.change_schema(sql)
452
+ if self.backend == "postgres":
453
+ sql, vars_list = convert_query_in_printf_format(sql, params, self.sql_conv_map)
454
+ self.alt_executemany(self.cur, sql, vars_list)
455
+ else:
456
+ self.cur.executemany(sql, params)
457
+
458
+ # get_description
459
+ @property
460
+ def description(self):
461
+ return self.cur.description
462
+
463
+ # rowcount
464
+ @property
465
+ def rowcount(self):
466
+ return self.cur.rowcount
467
+
468
+ # arraysize
469
+ @property
470
+ def arraysize(self):
471
+ return self.cur.arraysize
472
+
473
+ @arraysize.setter
474
+ def arraysize(self, val):
475
+ self.cur.arraysize = val
476
+
477
+ # change schema
478
+ def change_schema(self, sql):
479
+ if panda_config.schemaPANDA != "ATLAS_PANDA":
480
+ sql = re.sub("ATLAS_PANDA\.", panda_config.schemaPANDA + ".", sql)
481
+ if panda_config.schemaMETA != "ATLAS_PANDAMETA":
482
+ sql = re.sub("ATLAS_PANDAMETA\.", panda_config.schemaMETA + ".", sql)
483
+ if panda_config.schemaGRISLI != "ATLAS_GRISLI":
484
+ sql = re.sub("ATLAS_GRISLI\.", panda_config.schemaGRISLI + ".", sql)
485
+ if panda_config.schemaPANDAARCH != "ATLAS_PANDAARCH":
486
+ sql = re.sub("ATLAS_PANDAARCH\.", panda_config.schemaPANDAARCH + ".", sql)
487
+ return sql
@@ -0,0 +1,88 @@
1
+ import decimal
2
+ import pickle
3
+ import sys
4
+ from copyreg import _reconstructor as map__reconstructor
5
+ from io import BytesIO
6
+
7
+
8
+ class Common_Unpickler(pickle.Unpickler):
9
+ def __setattr__(self, key, value):
10
+ if key == "find_global":
11
+ pickle.Unpickler.__setattr__(self, "find_class", value)
12
+ else:
13
+ pickle.Unpickler.__setattr__(self, key, value)
14
+
15
+
16
+ # conversion for unserializable values
17
+ def conversion_func(item):
18
+ if isinstance(item, list):
19
+ return [conversion_func(i) for i in item]
20
+ if isinstance(item, dict):
21
+ return {k: conversion_func(item[k]) for k in item}
22
+ if isinstance(item, decimal.Decimal):
23
+ if item == item.to_integral_value():
24
+ item = int(item)
25
+ else:
26
+ item = float(item)
27
+ return item
28
+
29
+
30
+ # wrapper to avoid de-serializing unsafe objects
31
+ class WrappedPickle(object):
32
+ # allowed modules and classes
33
+ allowedModClass = {
34
+ "copy_reg": ["_reconstructor"],
35
+ "__builtin__": ["object"],
36
+ "datetime": ["datetime"],
37
+ "taskbuffer.JobSpec": ["JobSpec"],
38
+ "taskbuffer.FileSpec": ["FileSpec"],
39
+ "pandaserver.taskbuffer.JobSpec": ["JobSpec"],
40
+ "pandaserver.taskbuffer.FileSpec": ["FileSpec"],
41
+ }
42
+ # bare modules
43
+ bareMods = {"taskbuffer.": "pandaserver."}
44
+ # predefined class map
45
+ predefined_class = {
46
+ ("copy_reg", "_reconstructor"): map__reconstructor,
47
+ ("__builtin__", "object"): object,
48
+ }
49
+
50
+ # check module and class
51
+ @classmethod
52
+ def find_class(cls, module, name):
53
+ # append prefix to bare modules
54
+ for bareMod in cls.bareMods:
55
+ if module.startswith(bareMod):
56
+ module = cls.bareMods[bareMod] + module
57
+ break
58
+ # check module
59
+ if module not in cls.allowedModClass:
60
+ raise pickle.UnpicklingError(f"Attempting to import disallowed module {module}")
61
+ # return predefined class
62
+ key = (module, name)
63
+ if key in cls.predefined_class:
64
+ return cls.predefined_class[key]
65
+ # import module
66
+ __import__(module)
67
+ mod = sys.modules[module]
68
+ # check class
69
+ if name not in cls.allowedModClass[module]:
70
+ raise pickle.UnpicklingError(f"Attempting to get disallowed class {name} in {module}")
71
+ klass = getattr(mod, name)
72
+ return klass
73
+
74
+ # loads
75
+ @classmethod
76
+ def loads(cls, pickle_string):
77
+ if isinstance(pickle_string, str):
78
+ pickle_string = pickle_string.encode()
79
+ pickle_obj = Common_Unpickler(BytesIO(pickle_string))
80
+ pickle_obj.find_global = cls.find_class
81
+ return pickle_obj.load()
82
+
83
+ # dumps
84
+ @classmethod
85
+ def dumps(cls, obj, convert_to_safe=False):
86
+ if convert_to_safe:
87
+ obj = conversion_func(obj)
88
+ return pickle.dumps(obj, protocol=0)
@@ -0,0 +1,24 @@
1
+ # wrapper for Postgres Connection
2
+ class WrappedPostgresConn(object):
3
+ def __init__(self, conn):
4
+ self.orig_conn = conn
5
+
6
+ def __getattribute__(self, item):
7
+ try:
8
+ return object.__getattribute__(self.orig_conn, item)
9
+ except Exception:
10
+ pass
11
+ return object.__getattribute__(self, item)
12
+
13
+ def begin(self):
14
+ pass
15
+
16
+ def ping(self):
17
+ if self.orig_conn.closed:
18
+ raise RuntimeError("connection closed")
19
+
20
+ def __enter__(self):
21
+ return self.orig_conn.__enter__()
22
+
23
+ def __exit__(self, exc_type, exc_val, exc_tb):
24
+ self.orig_conn.__exit__(exc_type, exc_val, exc_tb)
File without changes
@@ -0,0 +1,7 @@
1
+ """
2
+ Inheritance structure:
3
+
4
+ Base -> Entity, Metrics -> TaskEvent -> JobComplex -> DBProxy
5
+ Base -> Entity -> Worker -> JobComplex -> DBProxy
6
+ Base -> JobStandalone, MiscStandalone -> DBProxy
7
+ """