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.
- panda_server_source-0.8.0.dist-info/METADATA +55 -0
- panda_server_source-0.8.0.dist-info/RECORD +375 -0
- panda_server_source-0.8.0.dist-info/WHEEL +4 -0
- panda_server_source-0.8.0.dist-info/licenses/LICENSE.txt +202 -0
- pandajedi/__init__.py +0 -0
- pandajedi/jedibrokerage/AtlasAnalJobBroker.py +2343 -0
- pandajedi/jedibrokerage/AtlasBrokerUtils.py +1292 -0
- pandajedi/jedibrokerage/AtlasProdJobBroker.py +2064 -0
- pandajedi/jedibrokerage/AtlasProdTaskBroker.py +629 -0
- pandajedi/jedibrokerage/GenJobBroker.py +381 -0
- pandajedi/jedibrokerage/JobBrokerBase.py +133 -0
- pandajedi/jedibrokerage/TaskBrokerBase.py +15 -0
- pandajedi/jedibrokerage/__init__.py +0 -0
- pandajedi/jediconfig/__init__.py +0 -0
- pandajedi/jediconfig/jedi_config.py +40 -0
- pandajedi/jedicore/FactoryBase.py +182 -0
- pandajedi/jedicore/Interaction.py +433 -0
- pandajedi/jedicore/JediDBProxy.py +56 -0
- pandajedi/jedicore/JediDBProxyPool.py +37 -0
- pandajedi/jedicore/JediDBSchemaInfo.py +17 -0
- pandajedi/jedicore/JediException.py +13 -0
- pandajedi/jedicore/JediTaskBuffer.py +984 -0
- pandajedi/jedicore/JediTaskBufferInterface.py +50 -0
- pandajedi/jedicore/MsgWrapper.py +124 -0
- pandajedi/jedicore/ProcessUtils.py +34 -0
- pandajedi/jedicore/SiteCandidate.py +90 -0
- pandajedi/jedicore/ThreadUtils.py +205 -0
- pandajedi/jedicore/__init__.py +0 -0
- pandajedi/jediddm/AtlasDDMClient.py +1708 -0
- pandajedi/jediddm/DDMClientBase.py +16 -0
- pandajedi/jediddm/DDMInterface.py +83 -0
- pandajedi/jediddm/GenDDMClient.py +17 -0
- pandajedi/jediddm/__init__.py +0 -0
- pandajedi/jedidog/AtlasAnalWatchDog.py +648 -0
- pandajedi/jedidog/AtlasDataCarouselWatchDog.py +189 -0
- pandajedi/jedidog/AtlasDataLocalityUpdaterWatchDog.py +215 -0
- pandajedi/jedidog/AtlasProdWatchDog.py +443 -0
- pandajedi/jedidog/AtlasQueueFillerWatchDog.py +800 -0
- pandajedi/jedidog/AtlasTaskWithholderWatchDog.py +245 -0
- pandajedi/jedidog/AtlasWorkflowManagerWatchDog.py +63 -0
- pandajedi/jedidog/GenWatchDog.py +21 -0
- pandajedi/jedidog/JumboWatchDog.py +147 -0
- pandajedi/jedidog/TypicalWatchDogBase.py +122 -0
- pandajedi/jedidog/WatchDogBase.py +53 -0
- pandajedi/jedidog/__init__.py +0 -0
- pandajedi/jediexec/reniceJEDI.py +25 -0
- pandajedi/jedigen/AtlasTaskGenerator.py +110 -0
- pandajedi/jedigen/TaskGeneratorBase.py +15 -0
- pandajedi/jedigen/__init__.py +0 -0
- pandajedi/jedimsgprocessor/__init__.py +0 -0
- pandajedi/jedimsgprocessor/ai_parameter_adjuster_msg_processor +71 -0
- pandajedi/jedimsgprocessor/atlas_idds_msg_processor.py +66 -0
- pandajedi/jedimsgprocessor/base_msg_processor.py +33 -0
- pandajedi/jedimsgprocessor/forwarding_msg_processor.py +29 -0
- pandajedi/jedimsgprocessor/hpo_msg_processor.py +93 -0
- pandajedi/jedimsgprocessor/jedi_contents_feeder_msg_processor.py +63 -0
- pandajedi/jedimsgprocessor/jedi_job_generator_msg_processor.py +185 -0
- pandajedi/jedimsgprocessor/jedi_post_processor_msg_processor.py +82 -0
- pandajedi/jedimsgprocessor/kafka_msg_processor.py +44 -0
- pandajedi/jedimsgprocessor/panda_callback_msg_processor.py +182 -0
- pandajedi/jedimsgprocessor/panda_to_jedi_msg_processor.py +74 -0
- pandajedi/jedimsgprocessor/processing_msg_processor.py +134 -0
- pandajedi/jedimsgprocessor/status_report_msg_processor.py +129 -0
- pandajedi/jedimsgprocessor/tape_carousel_msg_processor.py +118 -0
- pandajedi/jedimsgprocessor/workflow_manager_msg_processor.py +89 -0
- pandajedi/jediorder/ContentsFeeder.py +785 -0
- pandajedi/jediorder/JediDaemon.py +27 -0
- pandajedi/jediorder/JediKnight.py +55 -0
- pandajedi/jediorder/JediMaster.py +238 -0
- pandajedi/jediorder/JediMsgProcessor.py +32 -0
- pandajedi/jediorder/JobBroker.py +33 -0
- pandajedi/jediorder/JobGenerator.py +2763 -0
- pandajedi/jediorder/JobSplitter.py +308 -0
- pandajedi/jediorder/JobThrottler.py +28 -0
- pandajedi/jediorder/PostProcessor.py +166 -0
- pandajedi/jediorder/TaskBroker.py +268 -0
- pandajedi/jediorder/TaskCommando.py +334 -0
- pandajedi/jediorder/TaskGenerator.py +17 -0
- pandajedi/jediorder/TaskRefiner.py +611 -0
- pandajedi/jediorder/TaskSetupper.py +17 -0
- pandajedi/jediorder/WatchDog.py +79 -0
- pandajedi/jediorder/__init__.py +0 -0
- pandajedi/jedipprocess/AtlasAnalPostProcessor.py +404 -0
- pandajedi/jedipprocess/AtlasPostProcessorUtils.py +50 -0
- pandajedi/jedipprocess/AtlasProdPostProcessor.py +178 -0
- pandajedi/jedipprocess/GenPostProcessor.py +35 -0
- pandajedi/jedipprocess/MailTemplates.py +185 -0
- pandajedi/jedipprocess/PostProcessorBase.py +269 -0
- pandajedi/jedipprocess/__init__.py +0 -0
- pandajedi/jedirefine/AtlasAnalTaskRefiner.py +259 -0
- pandajedi/jedirefine/AtlasProdTaskRefiner.py +162 -0
- pandajedi/jedirefine/GenTaskRefiner.py +61 -0
- pandajedi/jedirefine/RefinerUtils.py +154 -0
- pandajedi/jedirefine/TaskRefinerBase.py +996 -0
- pandajedi/jedirefine/__init__.py +0 -0
- pandajedi/jedisetup/AtlasTaskSetupper.py +309 -0
- pandajedi/jedisetup/GenTaskSetupper.py +16 -0
- pandajedi/jedisetup/SimpleTaskSetupper.py +152 -0
- pandajedi/jedisetup/TaskSetupperBase.py +15 -0
- pandajedi/jedisetup/__init__.py +0 -0
- pandajedi/jeditest/SchemaChecker.py +41 -0
- pandajedi/jeditest/addContWoSoTask.py +54 -0
- pandajedi/jeditest/addDataCarouselRequest.py +47 -0
- pandajedi/jeditest/addEventServiceTask.py +101 -0
- pandajedi/jeditest/addHpoTask.py +81 -0
- pandajedi/jeditest/addIDDSStageInRequest.py +56 -0
- pandajedi/jeditest/addNonAtlasTask.py +71 -0
- pandajedi/jeditest/addNonAtlasTaskEnc.py +64 -0
- pandajedi/jeditest/addTestTask.py +124 -0
- pandajedi/jeditest/addTestTaskParamToDEFT.py +70 -0
- pandajedi/jeditest/addTestTaskWithMerger.py +97 -0
- pandajedi/jeditest/brokerTest.py +78 -0
- pandajedi/jeditest/cancelDataCarouselRequest.py +35 -0
- pandajedi/jeditest/contentsFeederTest.py +28 -0
- pandajedi/jeditest/contentsFeederTestWithTask.py +18 -0
- pandajedi/jeditest/ddmTest.py +4 -0
- pandajedi/jeditest/jobGenForOneTask.py +38 -0
- pandajedi/jeditest/jobGeneratorTest.py +43 -0
- pandajedi/jeditest/jobSplitterTest.py +104 -0
- pandajedi/jeditest/jobThrottlerTest.py +22 -0
- pandajedi/jeditest/msgProcessorTest.py +9 -0
- pandajedi/jeditest/postProcessorTest.py +18 -0
- pandajedi/jeditest/resubmitDataCarouselRequest.py +35 -0
- pandajedi/jeditest/resubmitTaskParam.py +20 -0
- pandajedi/jeditest/taskBrokerTest.py +22 -0
- pandajedi/jeditest/taskBrokerTestWithTask.py +38 -0
- pandajedi/jeditest/taskBufferTest.py +5 -0
- pandajedi/jeditest/taskCommandoTest.py +28 -0
- pandajedi/jeditest/taskRefinerTest.py +30 -0
- pandajedi/jeditest/testOneTaskToRefine.py +49 -0
- pandajedi/jeditest/testOneTaskToTaskBroker.py +42 -0
- pandajedi/jeditest/testPandaDDMMap.py +62 -0
- pandajedi/jeditest/updateDataCarouselRequestParams.py +50 -0
- pandajedi/jeditest/watchDogTest.py +25 -0
- pandajedi/jeditest/workQueueTest.py +22 -0
- pandajedi/jedithrottle/AtlasAnalJobThrottler.py +19 -0
- pandajedi/jedithrottle/AtlasProdJobThrottler.py +18 -0
- pandajedi/jedithrottle/GenJobThrottler.py +26 -0
- pandajedi/jedithrottle/JobThrottlerBase.py +496 -0
- pandajedi/jedithrottle/__init__.py +0 -0
- pandaserver/__init__.py +0 -0
- pandaserver/api/__init__.py +0 -0
- pandaserver/api/v1/__init__.py +0 -0
- pandaserver/api/v1/common.py +339 -0
- pandaserver/api/v1/credential_management_api.py +372 -0
- pandaserver/api/v1/data_carousel_api.py +264 -0
- pandaserver/api/v1/event_api.py +269 -0
- pandaserver/api/v1/file_server_api.py +942 -0
- pandaserver/api/v1/harvester_api.py +445 -0
- pandaserver/api/v1/http_client.py +166 -0
- pandaserver/api/v1/idds_api.py +180 -0
- pandaserver/api/v1/job_api.py +463 -0
- pandaserver/api/v1/metaconfig_api.py +122 -0
- pandaserver/api/v1/pilot_api.py +895 -0
- pandaserver/api/v1/statistics_api.py +207 -0
- pandaserver/api/v1/system_api.py +186 -0
- pandaserver/api/v1/task_api.py +1520 -0
- pandaserver/api/v1/tests/__init__.py +0 -0
- pandaserver/api/v1/tests/credential_management_api_tests.py +116 -0
- pandaserver/api/v1/tests/data_carousel_api_tests.py +82 -0
- pandaserver/api/v1/tests/harvester_api_tests.py +188 -0
- pandaserver/api/v1/tests/idds_api_tests.py +45 -0
- pandaserver/api/v1/tests/job_api_tests.py +112 -0
- pandaserver/api/v1/tests/pilot_api_tests.py +154 -0
- pandaserver/api/v1/tests/statistics_api_tests.py +104 -0
- pandaserver/api/v1/tests/system_api_tests.py +58 -0
- pandaserver/api/v1/tests/task_api_tests.py +590 -0
- pandaserver/api/v1/version.py +2 -0
- pandaserver/api/v1/workflow_api.py +136 -0
- pandaserver/brokerage/SiteMapper.py +406 -0
- pandaserver/brokerage/__init__.py +0 -0
- pandaserver/brokerage/broker.py +272 -0
- pandaserver/config/__init__.py +0 -0
- pandaserver/config/config_utils.py +15 -0
- pandaserver/config/daemon_config.py +29 -0
- pandaserver/config/mcp_config.py +38 -0
- pandaserver/config/panda_config.py +233 -0
- pandaserver/configurator/Carbon.py +65 -0
- pandaserver/configurator/Configurator.py +908 -0
- pandaserver/configurator/__init__.py +0 -0
- pandaserver/configurator/aux.py +73 -0
- pandaserver/daemons/__init__.py +0 -0
- pandaserver/daemons/master.py +110 -0
- pandaserver/daemons/master_systemd.py +79 -0
- pandaserver/daemons/scripts/__init__.py +0 -0
- pandaserver/daemons/scripts/add_main.py +264 -0
- pandaserver/daemons/scripts/add_sub.py +221 -0
- pandaserver/daemons/scripts/cache_pilots.py +47 -0
- pandaserver/daemons/scripts/cache_schedconfig.py +286 -0
- pandaserver/daemons/scripts/carbon.py +50 -0
- pandaserver/daemons/scripts/configurator.py +94 -0
- pandaserver/daemons/scripts/copyArchive.py +1387 -0
- pandaserver/daemons/scripts/datasetManager.py +1154 -0
- pandaserver/daemons/scripts/dummy_test.py +25 -0
- pandaserver/daemons/scripts/evpPD2P.py +144 -0
- pandaserver/daemons/scripts/hs_scrapers.py +264 -0
- pandaserver/daemons/scripts/metric_collector.py +927 -0
- pandaserver/daemons/scripts/panda_activeusers_query.py +80 -0
- pandaserver/daemons/scripts/pilotStreaming.py +109 -0
- pandaserver/daemons/scripts/process_workflow_files_daemon.py +166 -0
- pandaserver/daemons/scripts/recover_lost_files_daemon.py +177 -0
- pandaserver/daemons/scripts/task_evaluator.py +405 -0
- pandaserver/daemons/scripts/tmpwatch.py +70 -0
- pandaserver/daemons/scripts/worker_synchronization.py +97 -0
- pandaserver/daemons/utils.py +753 -0
- pandaserver/dataservice/DataServiceUtils.py +323 -0
- pandaserver/dataservice/ErrorCode.py +25 -0
- pandaserver/dataservice/RecoverLostFilesCore.py +322 -0
- pandaserver/dataservice/__init__.py +0 -0
- pandaserver/dataservice/activator.py +79 -0
- pandaserver/dataservice/adder_atlas_plugin.py +1106 -0
- pandaserver/dataservice/adder_dummy_plugin.py +31 -0
- pandaserver/dataservice/adder_gen.py +954 -0
- pandaserver/dataservice/adder_plugin_base.py +27 -0
- pandaserver/dataservice/adder_result.py +75 -0
- pandaserver/dataservice/adder_simple_plugin.py +160 -0
- pandaserver/dataservice/closer.py +247 -0
- pandaserver/dataservice/closer_atlas_plugin.py +90 -0
- pandaserver/dataservice/ddm.py +1381 -0
- pandaserver/dataservice/ddm_handler.py +95 -0
- pandaserver/dataservice/dyn_data_distributer.py +824 -0
- pandaserver/dataservice/event_lookup_client_ei.py +77 -0
- pandaserver/dataservice/event_picker.py +268 -0
- pandaserver/dataservice/finisher.py +194 -0
- pandaserver/dataservice/setupper.py +225 -0
- pandaserver/dataservice/setupper_atlas_plugin.py +1851 -0
- pandaserver/dataservice/setupper_dummy_plugin.py +47 -0
- pandaserver/dataservice/setupper_plugin_base.py +67 -0
- pandaserver/jobdispatcher/DispatcherUtils.py +35 -0
- pandaserver/jobdispatcher/ErrorCode.py +19 -0
- pandaserver/jobdispatcher/JobDispatcher.py +1625 -0
- pandaserver/jobdispatcher/Protocol.py +443 -0
- pandaserver/jobdispatcher/Watcher.py +186 -0
- pandaserver/jobdispatcher/__init__.py +0 -0
- pandaserver/pandamcp/__init__.py +0 -0
- pandaserver/pandamcp/mcp_main.py +56 -0
- pandaserver/pandamcp/mcp_test_client.py +95 -0
- pandaserver/pandamcp/mcp_utils.py +74 -0
- pandaserver/proxycache/__init__.py +0 -0
- pandaserver/proxycache/panda_proxy_cache.py +240 -0
- pandaserver/proxycache/token_cache.py +141 -0
- pandaserver/server/.gacl +6 -0
- pandaserver/server/panda.py +539 -0
- pandaserver/srvcore/CoreUtils.py +572 -0
- pandaserver/srvcore/MailUtils.py +106 -0
- pandaserver/srvcore/__init__.py +0 -0
- pandaserver/srvcore/allowed_methods.py +100 -0
- pandaserver/srvcore/oidc_utils.py +152 -0
- pandaserver/srvcore/panda_request.py +196 -0
- pandaserver/srvcore/srv_msg_utils.py +42 -0
- pandaserver/taskbuffer/ConBridge.py +513 -0
- pandaserver/taskbuffer/DBProxyPool.py +95 -0
- pandaserver/taskbuffer/DataCarousel.py +3053 -0
- pandaserver/taskbuffer/DatasetSpec.py +137 -0
- pandaserver/taskbuffer/DdmSpec.py +201 -0
- pandaserver/taskbuffer/ErrorCode.py +87 -0
- pandaserver/taskbuffer/EventServiceUtils.py +396 -0
- pandaserver/taskbuffer/FileSpec.py +290 -0
- pandaserver/taskbuffer/GlobalShares.py +244 -0
- pandaserver/taskbuffer/HarvesterMetricsSpec.py +92 -0
- pandaserver/taskbuffer/Initializer.py +82 -0
- pandaserver/taskbuffer/InputChunk.py +1080 -0
- pandaserver/taskbuffer/JediCacheSpec.py +57 -0
- pandaserver/taskbuffer/JediDatasetSpec.py +588 -0
- pandaserver/taskbuffer/JediFileSpec.py +242 -0
- pandaserver/taskbuffer/JediTaskSpec.py +1687 -0
- pandaserver/taskbuffer/JobSpec.py +1006 -0
- pandaserver/taskbuffer/JobUtils.py +232 -0
- pandaserver/taskbuffer/NucleusSpec.py +116 -0
- pandaserver/taskbuffer/OraDBProxy.py +174 -0
- pandaserver/taskbuffer/PanDAMsgProcessor.py +8 -0
- pandaserver/taskbuffer/PandaDBSchemaInfo.py +18 -0
- pandaserver/taskbuffer/ParseJobXML.py +350 -0
- pandaserver/taskbuffer/PickleFileSpec.py +18 -0
- pandaserver/taskbuffer/PickleJobSpec.py +25 -0
- pandaserver/taskbuffer/PrioUtil.py +40 -0
- pandaserver/taskbuffer/ProcessGroups.py +111 -0
- pandaserver/taskbuffer/ResourceSpec.py +175 -0
- pandaserver/taskbuffer/SQLDumper.py +37 -0
- pandaserver/taskbuffer/SQLManager.py +60 -0
- pandaserver/taskbuffer/SiteSpec.py +304 -0
- pandaserver/taskbuffer/SupErrors.py +10 -0
- pandaserver/taskbuffer/TaskBuffer.py +2882 -0
- pandaserver/taskbuffer/TaskBufferInterface.py +163 -0
- pandaserver/taskbuffer/Utils.py +848 -0
- pandaserver/taskbuffer/WorkQueue.py +227 -0
- pandaserver/taskbuffer/WorkQueueMapper.py +203 -0
- pandaserver/taskbuffer/WorkerSpec.py +143 -0
- pandaserver/taskbuffer/WrappedCursor.py +487 -0
- pandaserver/taskbuffer/WrappedPickle.py +88 -0
- pandaserver/taskbuffer/WrappedPostgresConn.py +24 -0
- pandaserver/taskbuffer/__init__.py +0 -0
- pandaserver/taskbuffer/db_proxy_mods/OraDBProxy_structure.png +0 -0
- pandaserver/taskbuffer/db_proxy_mods/__init__.py +7 -0
- pandaserver/taskbuffer/db_proxy_mods/base_module.py +841 -0
- pandaserver/taskbuffer/db_proxy_mods/data_carousel_module.py +772 -0
- pandaserver/taskbuffer/db_proxy_mods/entity_module.py +3804 -0
- pandaserver/taskbuffer/db_proxy_mods/job_complex_module.py +5661 -0
- pandaserver/taskbuffer/db_proxy_mods/job_standalone_module.py +2640 -0
- pandaserver/taskbuffer/db_proxy_mods/metrics_module.py +874 -0
- pandaserver/taskbuffer/db_proxy_mods/misc_standalone_module.py +4272 -0
- pandaserver/taskbuffer/db_proxy_mods/task_complex_module.py +6172 -0
- pandaserver/taskbuffer/db_proxy_mods/task_event_module.py +4953 -0
- pandaserver/taskbuffer/db_proxy_mods/task_standalone_module.py +4999 -0
- pandaserver/taskbuffer/db_proxy_mods/task_utils_module.py +2063 -0
- pandaserver/taskbuffer/db_proxy_mods/worker_module.py +1944 -0
- pandaserver/taskbuffer/db_proxy_mods/workflow_module.py +832 -0
- pandaserver/taskbuffer/retryModule.py +552 -0
- pandaserver/taskbuffer/task_split_rules.py +308 -0
- pandaserver/taskbuffer/workflow_processor.py +249 -0
- pandaserver/taskbuffer/wrapped_oracle_conn.py +18 -0
- pandaserver/test/SchemaChecker.py +40 -0
- pandaserver/test/__init__.py +0 -0
- pandaserver/test/banUser.py +43 -0
- pandaserver/test/boostPrio.py +19 -0
- pandaserver/test/boostUser.py +35 -0
- pandaserver/test/callbackDDM.py +11 -0
- pandaserver/test/daod_on_demand.py +95 -0
- pandaserver/test/finishJob.py +184 -0
- pandaserver/test/finishTaskJEDI.py +11 -0
- pandaserver/test/getJobs.py +53 -0
- pandaserver/test/killJob.py +79 -0
- pandaserver/test/killJobLowPrio.py +99 -0
- pandaserver/test/killJobsInTask.py +56 -0
- pandaserver/test/killTask.py +80 -0
- pandaserver/test/killTaskJEDI.py +11 -0
- pandaserver/test/killUser.py +83 -0
- pandaserver/test/lsst/README.txt +7 -0
- pandaserver/test/lsst/lsstSubmit.py +139 -0
- pandaserver/test/lsst/lsstSubmitMERGEtest.py +141 -0
- pandaserver/test/lsst/lsstSubmitPhosim332.py +53 -0
- pandaserver/test/lsst/prepare-client-tarball-from-bigpanda-server.sh +41 -0
- pandaserver/test/reassignJobs.py +17 -0
- pandaserver/test/reassignSite.py +82 -0
- pandaserver/test/reassignTask.py +117 -0
- pandaserver/test/reassignWaiting.py +39 -0
- pandaserver/test/recoverLostFiles.py +7 -0
- pandaserver/test/reloadInputDS.py +51 -0
- pandaserver/test/sendCommandToJob.py +26 -0
- pandaserver/test/setDebugMode.py +38 -0
- pandaserver/test/setPriority.py +28 -0
- pandaserver/test/testEvgen.py +60 -0
- pandaserver/test/testEvgen17.py +58 -0
- pandaserver/test/testG4sim.py +81 -0
- pandaserver/test/testG4sim17.py +90 -0
- pandaserver/test/testGlobalShares.py +131 -0
- pandaserver/test/testReco.py +103 -0
- pandaserver/test/testSimulReco14.py +98 -0
- pandaserver/test/testSiteMap.py +26 -0
- pandaserver/test/testUpdateWorkerPilotStatus.py +9 -0
- pandaserver/userinterface/Client.py +1686 -0
- pandaserver/userinterface/UserIF.py +1799 -0
- pandaserver/userinterface/__init__.py +0 -0
- pandaserver/workflow/__init__.py +0 -0
- pandaserver/workflow/data_handler_plugins/base_data_handler.py +48 -0
- pandaserver/workflow/data_handler_plugins/ddm_collection_data_handler.py +100 -0
- pandaserver/workflow/data_handler_plugins/panda_task_data_handler.py +140 -0
- pandaserver/workflow/pcwl_test.py +122 -0
- pandaserver/workflow/pcwl_utils.py +384 -0
- pandaserver/workflow/psnakemake_container.json +68 -0
- pandaserver/workflow/psnakemake_task.json +62 -0
- pandaserver/workflow/psnakemake_test.py +60 -0
- pandaserver/workflow/snakeparser/__init__.py +3 -0
- pandaserver/workflow/snakeparser/extensions.py +74 -0
- pandaserver/workflow/snakeparser/log.py +53 -0
- pandaserver/workflow/snakeparser/names.py +3 -0
- pandaserver/workflow/snakeparser/parser.py +332 -0
- pandaserver/workflow/snakeparser/utils.py +29 -0
- pandaserver/workflow/step_handler_plugins/base_step_handler.py +85 -0
- pandaserver/workflow/step_handler_plugins/panda_task_step_handler.py +280 -0
- pandaserver/workflow/workflow_base.py +531 -0
- pandaserver/workflow/workflow_core.py +1974 -0
- pandaserver/workflow/workflow_core_smoketest.py +388 -0
- pandaserver/workflow/workflow_parser.py +222 -0
- 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
|
|
Binary file
|