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,2882 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
import shlex
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
import traceback
|
|
8
|
+
from contextlib import contextmanager
|
|
9
|
+
from threading import Lock
|
|
10
|
+
|
|
11
|
+
from pandacommon.pandalogger.LogWrapper import LogWrapper
|
|
12
|
+
from pandacommon.pandalogger.PandaLogger import PandaLogger
|
|
13
|
+
from pandacommon.pandautils.PandaUtils import naive_utcnow
|
|
14
|
+
|
|
15
|
+
from pandaserver.brokerage.SiteMapper import SiteMapper
|
|
16
|
+
from pandaserver.config import panda_config
|
|
17
|
+
from pandaserver.dataservice.closer import Closer
|
|
18
|
+
from pandaserver.dataservice.setupper import Setupper
|
|
19
|
+
from pandaserver.srvcore import CoreUtils
|
|
20
|
+
from pandaserver.taskbuffer import ErrorCode, EventServiceUtils, JobUtils, ProcessGroups
|
|
21
|
+
from pandaserver.taskbuffer.DBProxyPool import DBProxyPool
|
|
22
|
+
|
|
23
|
+
_logger = PandaLogger().getLogger("TaskBuffer")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TaskBuffer:
|
|
27
|
+
"""
|
|
28
|
+
task queue
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
# constructor
|
|
33
|
+
def __init__(self):
|
|
34
|
+
self.proxyPool = None
|
|
35
|
+
self.lock = Lock()
|
|
36
|
+
self.nDBConnection = None
|
|
37
|
+
|
|
38
|
+
# save the requester for monitoring/logging purposes
|
|
39
|
+
self.start_time = time.time()
|
|
40
|
+
|
|
41
|
+
# site mapper
|
|
42
|
+
self.site_mapper = None
|
|
43
|
+
# update time for site mapper
|
|
44
|
+
self.last_update_site_mapper = None
|
|
45
|
+
|
|
46
|
+
def __repr__(self):
|
|
47
|
+
return "TaskBuffer"
|
|
48
|
+
|
|
49
|
+
# initialize
|
|
50
|
+
def init(self, dbname, dbpass, nDBConnection=10, useTimeout=False, requester=None):
|
|
51
|
+
# acquire lock
|
|
52
|
+
self.lock.acquire()
|
|
53
|
+
self.nDBConnection = nDBConnection
|
|
54
|
+
|
|
55
|
+
# create Proxy Pool
|
|
56
|
+
if self.proxyPool is None:
|
|
57
|
+
_logger.info(f"creating DBProxyPool with n_connections={nDBConnection} on behalf of {requester}")
|
|
58
|
+
self.start_time = time.time()
|
|
59
|
+
self.proxyPool = DBProxyPool(dbname, dbpass, nDBConnection, useTimeout)
|
|
60
|
+
|
|
61
|
+
# release lock
|
|
62
|
+
self.lock.release()
|
|
63
|
+
|
|
64
|
+
# cleanup
|
|
65
|
+
def cleanup(self, requester=None):
|
|
66
|
+
if self.proxyPool:
|
|
67
|
+
try:
|
|
68
|
+
pool_duration = time.time() - self.start_time
|
|
69
|
+
except TypeError:
|
|
70
|
+
pool_duration = -1 # duration unknown
|
|
71
|
+
|
|
72
|
+
_logger.info(f"destroying DBProxyPool after n_seconds={pool_duration} on behalf of {requester}")
|
|
73
|
+
self.proxyPool.cleanup()
|
|
74
|
+
|
|
75
|
+
# transaction as a context manager
|
|
76
|
+
# CANNOT be used with ConBridge or TaskBufferInterface which uses multiprocess.pipe
|
|
77
|
+
@contextmanager
|
|
78
|
+
def transaction(self, name=None, tmp_log=None):
|
|
79
|
+
with self.proxyPool.get() as proxy:
|
|
80
|
+
with proxy.transaction(name, tmp_log) as txn:
|
|
81
|
+
if txn is None:
|
|
82
|
+
raise RuntimeError(f"Failed to start transaction {name}")
|
|
83
|
+
# yield the transaction
|
|
84
|
+
yield txn
|
|
85
|
+
|
|
86
|
+
# get number of database connections
|
|
87
|
+
def get_num_connections(self):
|
|
88
|
+
return self.nDBConnection
|
|
89
|
+
|
|
90
|
+
# get SiteMapper
|
|
91
|
+
def get_site_mapper(self):
|
|
92
|
+
time_now = naive_utcnow()
|
|
93
|
+
if self.last_update_site_mapper is None or datetime.datetime.now(datetime.timezone.utc).replace(
|
|
94
|
+
tzinfo=None
|
|
95
|
+
) - self.last_update_site_mapper > datetime.timedelta(minutes=10):
|
|
96
|
+
self.site_mapper = SiteMapper(self)
|
|
97
|
+
self.last_update_site_mapper = time_now
|
|
98
|
+
return self.site_mapper
|
|
99
|
+
|
|
100
|
+
# check production role
|
|
101
|
+
def checkProdRole(self, fqans):
|
|
102
|
+
for fqan in fqans:
|
|
103
|
+
# check production role
|
|
104
|
+
match = re.search("/([^/]+)/Role=production", fqan)
|
|
105
|
+
if match is not None:
|
|
106
|
+
return True, match.group(1)
|
|
107
|
+
return False, None
|
|
108
|
+
|
|
109
|
+
# get priority parameters for user
|
|
110
|
+
def getPrioParameters(self, jobs, user, fqans, userDefinedWG, validWorkingGroup):
|
|
111
|
+
priorityOffset = 0
|
|
112
|
+
serNum = 0
|
|
113
|
+
weight = None
|
|
114
|
+
prio_reduction = True
|
|
115
|
+
# get boosted users and groups
|
|
116
|
+
boost_dict = {}
|
|
117
|
+
# get DB proxy
|
|
118
|
+
with self.proxyPool.get() as proxy:
|
|
119
|
+
# check production role
|
|
120
|
+
withProdRole, workingGroup = self.checkProdRole(fqans)
|
|
121
|
+
if withProdRole and jobs != []:
|
|
122
|
+
# check dataset name
|
|
123
|
+
for tmpFile in jobs[-1].Files:
|
|
124
|
+
if tmpFile.type in ["output", "log"] and not (tmpFile.lfn.startswith("group") or tmpFile.lfn.startswith("panda.um.group")):
|
|
125
|
+
# reset
|
|
126
|
+
withProdRole, workingGroup = False, None
|
|
127
|
+
break
|
|
128
|
+
# reset nJob/weight for HC
|
|
129
|
+
if jobs != []:
|
|
130
|
+
if jobs[0].processingType in [
|
|
131
|
+
"hammercloud",
|
|
132
|
+
"gangarobot",
|
|
133
|
+
"hammercloud-fax",
|
|
134
|
+
] or jobs[
|
|
135
|
+
0
|
|
136
|
+
].processingType.startswith("gangarobot-"):
|
|
137
|
+
serNum = 0
|
|
138
|
+
weight = 0.0
|
|
139
|
+
elif jobs[0].processingType in ["gangarobot", "gangarobot-pft"]:
|
|
140
|
+
priorityOffset = 3000
|
|
141
|
+
elif jobs[0].processingType in ["hammercloud-fax"]:
|
|
142
|
+
priorityOffset = 1001
|
|
143
|
+
else:
|
|
144
|
+
# get users and groups to boost job priorities
|
|
145
|
+
boost_dict = proxy.get_dict_to_boost_job_prio(jobs[-1].VO)
|
|
146
|
+
if boost_dict:
|
|
147
|
+
prodUserName = CoreUtils.clean_user_id(user)
|
|
148
|
+
# check boost list
|
|
149
|
+
if userDefinedWG and validWorkingGroup:
|
|
150
|
+
if "group" in boost_dict and jobs[-1].workingGroup in boost_dict["group"]:
|
|
151
|
+
priorityOffset = boost_dict["group"][jobs[-1].workingGroup]
|
|
152
|
+
weight = 0.0
|
|
153
|
+
prio_reduction = False
|
|
154
|
+
else:
|
|
155
|
+
if "user" in boost_dict and prodUserName in boost_dict["user"]:
|
|
156
|
+
priorityOffset = boost_dict["user"][prodUserName]
|
|
157
|
+
weight = 0.0
|
|
158
|
+
prio_reduction = False
|
|
159
|
+
# check quota
|
|
160
|
+
if weight is None:
|
|
161
|
+
weight = proxy.checkQuota(user)
|
|
162
|
+
# get nJob
|
|
163
|
+
if jobs == []:
|
|
164
|
+
serNum = proxy.getNumberJobsUser(user, workingGroup=userDefinedWG)
|
|
165
|
+
elif userDefinedWG and validWorkingGroup:
|
|
166
|
+
# check if group privileged
|
|
167
|
+
isSU, isGU = proxy.isSuperUser(jobs[0].workingGroup)
|
|
168
|
+
if not isSU:
|
|
169
|
+
serNum = proxy.getNumberJobsUser(user, workingGroup=jobs[0].workingGroup)
|
|
170
|
+
else:
|
|
171
|
+
# set high priority for production role
|
|
172
|
+
serNum = 0
|
|
173
|
+
weight = 0.0
|
|
174
|
+
priorityOffset = 2000
|
|
175
|
+
else:
|
|
176
|
+
serNum = proxy.getNumberJobsUser(user, workingGroup=None)
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
withProdRole,
|
|
180
|
+
workingGroup,
|
|
181
|
+
priorityOffset,
|
|
182
|
+
serNum,
|
|
183
|
+
weight,
|
|
184
|
+
prio_reduction,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# store Jobs into DB
|
|
188
|
+
def storeJobs(
|
|
189
|
+
self,
|
|
190
|
+
jobs,
|
|
191
|
+
user,
|
|
192
|
+
joinThr=False,
|
|
193
|
+
fqans=[],
|
|
194
|
+
hostname="",
|
|
195
|
+
checkSpecialHandling=True,
|
|
196
|
+
toPending=False,
|
|
197
|
+
oldPandaIDs=None,
|
|
198
|
+
relationType=None,
|
|
199
|
+
userVO="atlas",
|
|
200
|
+
esJobsetMap=None,
|
|
201
|
+
getEsJobsetMap=False,
|
|
202
|
+
unprocessedMap=None,
|
|
203
|
+
bulk_job_insert=False,
|
|
204
|
+
trust_user=False,
|
|
205
|
+
):
|
|
206
|
+
try:
|
|
207
|
+
tmpLog = LogWrapper(_logger, f"storeJobs <{CoreUtils.clean_user_id(user)} nJobs={len(jobs)}>")
|
|
208
|
+
tmpLog.debug(f"start toPending={toPending}")
|
|
209
|
+
# check quota for priority calculation
|
|
210
|
+
weight = 0.0
|
|
211
|
+
userJobID = -1
|
|
212
|
+
userJobsetID = -1
|
|
213
|
+
userStatus = True
|
|
214
|
+
priorityOffset = 0
|
|
215
|
+
userCountry = None
|
|
216
|
+
useExpress = False
|
|
217
|
+
nExpressJobs = 0
|
|
218
|
+
useDebugMode = False
|
|
219
|
+
siteMapper = self.get_site_mapper()
|
|
220
|
+
|
|
221
|
+
# check ban user
|
|
222
|
+
if not trust_user and len(jobs) > 0:
|
|
223
|
+
# get DB proxy
|
|
224
|
+
with self.proxyPool.get() as proxy:
|
|
225
|
+
# check user status
|
|
226
|
+
tmpStatus = proxy.checkBanUser(user, jobs[0].prodSourceLabel)
|
|
227
|
+
# return if DN is blocked
|
|
228
|
+
if not tmpStatus:
|
|
229
|
+
tmpLog.debug(f"end 1 since DN {user} is blocked")
|
|
230
|
+
if getEsJobsetMap:
|
|
231
|
+
return [], None, unprocessedMap
|
|
232
|
+
return []
|
|
233
|
+
|
|
234
|
+
tmpLog.debug(f"checked ban user")
|
|
235
|
+
# set parameters for user jobs
|
|
236
|
+
if (
|
|
237
|
+
len(jobs) > 0
|
|
238
|
+
and (jobs[0].prodSourceLabel in JobUtils.analy_sources + JobUtils.list_ptest_prod_sources)
|
|
239
|
+
and (not jobs[0].processingType in ["merge", "unmerge"])
|
|
240
|
+
):
|
|
241
|
+
# get DB proxy
|
|
242
|
+
with self.proxyPool.get() as proxy:
|
|
243
|
+
# get JobID and status
|
|
244
|
+
userJobID, userJobsetID, userStatus = proxy.getUserParameter(user, jobs[0].jobDefinitionID, jobs[0].jobsetID)
|
|
245
|
+
|
|
246
|
+
# check quota for express jobs
|
|
247
|
+
if "express" in jobs[0].specialHandling:
|
|
248
|
+
expressQuota = proxy.getExpressJobs(user)
|
|
249
|
+
if expressQuota is not None and expressQuota["status"] and expressQuota["quota"] > 0:
|
|
250
|
+
nExpressJobs = expressQuota["quota"]
|
|
251
|
+
if nExpressJobs > 0:
|
|
252
|
+
useExpress = True
|
|
253
|
+
# debug mode
|
|
254
|
+
if jobs[0].is_debug_mode() or jobs[-1].is_debug_mode():
|
|
255
|
+
useDebugMode = True
|
|
256
|
+
|
|
257
|
+
# extract country group
|
|
258
|
+
for tmpFQAN in fqans:
|
|
259
|
+
match = re.search("^/atlas/([^/]+)/", tmpFQAN)
|
|
260
|
+
if match is not None:
|
|
261
|
+
tmpCountry = match.group(1)
|
|
262
|
+
# use country code or usatlas
|
|
263
|
+
if len(tmpCountry) == 2:
|
|
264
|
+
userCountry = tmpCountry
|
|
265
|
+
break
|
|
266
|
+
# usatlas
|
|
267
|
+
if tmpCountry in ["usatlas"]:
|
|
268
|
+
userCountry = "us"
|
|
269
|
+
break
|
|
270
|
+
tmpLog.debug(f"set user job parameters")
|
|
271
|
+
|
|
272
|
+
# return if DN is blocked
|
|
273
|
+
if not userStatus:
|
|
274
|
+
tmpLog.debug(f"end 2 since {user} DN is blocked")
|
|
275
|
+
if getEsJobsetMap:
|
|
276
|
+
return ([], None, unprocessedMap)
|
|
277
|
+
return []
|
|
278
|
+
# extract VO
|
|
279
|
+
for tmpFQAN in fqans:
|
|
280
|
+
match = re.search("^/([^/]+)/", tmpFQAN)
|
|
281
|
+
if match is not None:
|
|
282
|
+
userVO = match.group(1)
|
|
283
|
+
break
|
|
284
|
+
|
|
285
|
+
# get number of jobs currently in PandaDB
|
|
286
|
+
serNum = 0
|
|
287
|
+
userDefinedWG = False
|
|
288
|
+
validWorkingGroup = False
|
|
289
|
+
usingBuild = False
|
|
290
|
+
withProdRole = False
|
|
291
|
+
workingGroup = None
|
|
292
|
+
prio_reduction = True
|
|
293
|
+
if len(jobs) > 0 and (jobs[0].prodSourceLabel in JobUtils.analy_sources) and (not jobs[0].processingType in ["merge", "unmerge"]):
|
|
294
|
+
# extract user's working group from FQANs
|
|
295
|
+
userWorkingGroupList = []
|
|
296
|
+
for tmpFQAN in fqans:
|
|
297
|
+
match = re.search("/([^/]+)/Role=production", tmpFQAN)
|
|
298
|
+
if match is not None:
|
|
299
|
+
userWorkingGroupList.append(match.group(1))
|
|
300
|
+
# check workingGroup
|
|
301
|
+
if jobs[0].workingGroup not in ["", None, "NULL"]:
|
|
302
|
+
userDefinedWG = True
|
|
303
|
+
# check with FQANs
|
|
304
|
+
if jobs[0].workingGroup in userWorkingGroupList:
|
|
305
|
+
validWorkingGroup = True
|
|
306
|
+
# using build for analysis
|
|
307
|
+
if jobs[0].prodSourceLabel == "panda":
|
|
308
|
+
usingBuild = True
|
|
309
|
+
# get priority parameters for user
|
|
310
|
+
(
|
|
311
|
+
withProdRole,
|
|
312
|
+
workingGroup,
|
|
313
|
+
priorityOffset,
|
|
314
|
+
serNum,
|
|
315
|
+
weight,
|
|
316
|
+
prio_reduction,
|
|
317
|
+
) = self.getPrioParameters(jobs, user, fqans, userDefinedWG, validWorkingGroup)
|
|
318
|
+
tmpLog.debug(f"workingGroup={jobs[0].workingGroup} serNum={serNum} weight={weight} pOffset={priorityOffset} reduction={prio_reduction}")
|
|
319
|
+
tmpLog.debug(f"got prio parameters")
|
|
320
|
+
# get DB proxy
|
|
321
|
+
with self.proxyPool.get() as proxy:
|
|
322
|
+
tmpLog.debug(f"got proxy")
|
|
323
|
+
# get total number of files
|
|
324
|
+
totalNumFiles = 0
|
|
325
|
+
for job in jobs:
|
|
326
|
+
totalNumFiles += len(job.Files)
|
|
327
|
+
# bulk fetch PandaIDs
|
|
328
|
+
new_panda_ids = proxy.bulk_fetch_panda_ids(len(jobs))
|
|
329
|
+
tmpLog.debug(f"got PandaIDs")
|
|
330
|
+
# bulk fetch fileIDs
|
|
331
|
+
fileIDPool = []
|
|
332
|
+
if totalNumFiles > 0:
|
|
333
|
+
fileIDPool = sorted(proxy.bulkFetchFileIDsPanda(totalNumFiles))
|
|
334
|
+
# loop over all jobs
|
|
335
|
+
ret = []
|
|
336
|
+
newJobs = []
|
|
337
|
+
if esJobsetMap is None:
|
|
338
|
+
esJobsetMap = {}
|
|
339
|
+
try:
|
|
340
|
+
tmpLog.debug(f"jediTaskID={jobs[0].jediTaskID} len(esJobsetMap)={len(esJobsetMap)} nJobs={len(jobs)}")
|
|
341
|
+
except Exception:
|
|
342
|
+
pass
|
|
343
|
+
job_ret_list = []
|
|
344
|
+
params_for_bulk_insert = []
|
|
345
|
+
special_handling_list = []
|
|
346
|
+
num_original_event_service_jobs = 0
|
|
347
|
+
for idxJob, job in enumerate(jobs):
|
|
348
|
+
# set PandaID
|
|
349
|
+
job.PandaID = new_panda_ids[idxJob]
|
|
350
|
+
# set JobID. keep original JobID when retry
|
|
351
|
+
if (
|
|
352
|
+
userJobID != -1
|
|
353
|
+
and job.prodSourceLabel in JobUtils.analy_sources
|
|
354
|
+
and (job.attemptNr in [0, "0", "NULL"] or (job.jobExecutionID not in [0, "0", "NULL"]) or job.lockedby == "jedi")
|
|
355
|
+
and (not jobs[0].processingType in ["merge", "unmerge"])
|
|
356
|
+
):
|
|
357
|
+
job.jobDefinitionID = userJobID
|
|
358
|
+
# set jobsetID
|
|
359
|
+
if job.prodSourceLabel in JobUtils.analy_sources + JobUtils.list_ptest_prod_sources:
|
|
360
|
+
job.jobsetID = userJobsetID
|
|
361
|
+
# set relocation flag
|
|
362
|
+
if job.computingSite != "NULL" and job.relocationFlag != 2:
|
|
363
|
+
job.relocationFlag = 1
|
|
364
|
+
# protection agains empty jobParameters
|
|
365
|
+
if job.jobParameters in ["", None, "NULL"]:
|
|
366
|
+
job.jobParameters = " "
|
|
367
|
+
# set country group and nJobs (=taskID)
|
|
368
|
+
if job.prodSourceLabel in JobUtils.analy_sources:
|
|
369
|
+
if job.lockedby != "jedi":
|
|
370
|
+
job.countryGroup = userCountry
|
|
371
|
+
# set workingGroup
|
|
372
|
+
if not validWorkingGroup:
|
|
373
|
+
if withProdRole:
|
|
374
|
+
# set country group if submitted with production role
|
|
375
|
+
job.workingGroup = workingGroup
|
|
376
|
+
else:
|
|
377
|
+
if userDefinedWG:
|
|
378
|
+
# reset invalid working group
|
|
379
|
+
job.workingGroup = None
|
|
380
|
+
# set nJobs (=taskID)
|
|
381
|
+
if usingBuild:
|
|
382
|
+
tmpNumBuild = 1
|
|
383
|
+
tmpNunRun = len(jobs) - 1
|
|
384
|
+
else:
|
|
385
|
+
tmpNumBuild = 0
|
|
386
|
+
tmpNunRun = len(jobs)
|
|
387
|
+
# encode
|
|
388
|
+
job.taskID = tmpNumBuild + (tmpNunRun << 1)
|
|
389
|
+
# set hostname
|
|
390
|
+
if hostname != "":
|
|
391
|
+
job.creationHost = hostname
|
|
392
|
+
|
|
393
|
+
# process and set the job_label
|
|
394
|
+
if not job.job_label or job.job_label not in (
|
|
395
|
+
JobUtils.PROD_PS,
|
|
396
|
+
JobUtils.ANALY_PS,
|
|
397
|
+
):
|
|
398
|
+
tmpSiteSpec = siteMapper.getSite(job.computingSite)
|
|
399
|
+
queue_type = tmpSiteSpec.type
|
|
400
|
+
if queue_type == "analysis":
|
|
401
|
+
job.job_label = JobUtils.ANALY_PS
|
|
402
|
+
elif queue_type == "production":
|
|
403
|
+
job.job_label = JobUtils.PROD_PS
|
|
404
|
+
elif queue_type == "unified":
|
|
405
|
+
if job.prodSourceLabel in JobUtils.analy_sources:
|
|
406
|
+
job.job_label = JobUtils.ANALY_PS
|
|
407
|
+
else:
|
|
408
|
+
# set production as default if not specified and neutral prodsourcelabel
|
|
409
|
+
job.job_label = JobUtils.PROD_PS
|
|
410
|
+
else: # e.g. type = special
|
|
411
|
+
job.job_label = JobUtils.PROD_PS
|
|
412
|
+
|
|
413
|
+
# extract file info, change specialHandling for event service
|
|
414
|
+
origSH = job.specialHandling
|
|
415
|
+
(
|
|
416
|
+
eventServiceInfo,
|
|
417
|
+
job.specialHandling,
|
|
418
|
+
esIndex,
|
|
419
|
+
) = EventServiceUtils.decodeFileInfo(job.specialHandling)
|
|
420
|
+
origEsJob = False
|
|
421
|
+
if eventServiceInfo != {}:
|
|
422
|
+
# set jobsetID
|
|
423
|
+
if esIndex in esJobsetMap:
|
|
424
|
+
job.jobsetID = esJobsetMap[esIndex]
|
|
425
|
+
else:
|
|
426
|
+
origEsJob = True
|
|
427
|
+
num_original_event_service_jobs += 1
|
|
428
|
+
esJobsetMap[esIndex] = None
|
|
429
|
+
# sort files since file order is important for positional event number
|
|
430
|
+
job.sortFiles()
|
|
431
|
+
if oldPandaIDs is not None and len(oldPandaIDs) > idxJob:
|
|
432
|
+
jobOldPandaIDs = oldPandaIDs[idxJob]
|
|
433
|
+
else:
|
|
434
|
+
jobOldPandaIDs = None
|
|
435
|
+
# check events for jumbo jobs
|
|
436
|
+
isOK = True
|
|
437
|
+
if EventServiceUtils.isJumboJob(job):
|
|
438
|
+
hasReadyEvents = proxy.hasReadyEvents(job.jediTaskID)
|
|
439
|
+
if hasReadyEvents is False:
|
|
440
|
+
isOK = False
|
|
441
|
+
# insert job to DB
|
|
442
|
+
if not isOK:
|
|
443
|
+
# skip since there is no ready event
|
|
444
|
+
job.PandaID = None
|
|
445
|
+
if not bulk_job_insert:
|
|
446
|
+
tmp_ret_i = proxy.insertNewJob(
|
|
447
|
+
job,
|
|
448
|
+
user,
|
|
449
|
+
serNum,
|
|
450
|
+
weight,
|
|
451
|
+
priorityOffset,
|
|
452
|
+
userVO,
|
|
453
|
+
toPending,
|
|
454
|
+
origEsJob,
|
|
455
|
+
eventServiceInfo,
|
|
456
|
+
oldPandaIDs=jobOldPandaIDs,
|
|
457
|
+
relationType=relationType,
|
|
458
|
+
fileIDPool=fileIDPool,
|
|
459
|
+
origSpecialHandling=origSH,
|
|
460
|
+
unprocessedMap=unprocessedMap,
|
|
461
|
+
prio_reduction=prio_reduction,
|
|
462
|
+
)
|
|
463
|
+
if unprocessedMap is not None:
|
|
464
|
+
tmp_ret_i, unprocessedMap = tmp_ret_i
|
|
465
|
+
else:
|
|
466
|
+
# keep parameters for late bulk execution
|
|
467
|
+
params_for_bulk_insert.append(
|
|
468
|
+
[
|
|
469
|
+
[job, user, serNum, weight, priorityOffset, userVO, toPending],
|
|
470
|
+
{
|
|
471
|
+
"origEsJob": origEsJob,
|
|
472
|
+
"eventServiceInfo": eventServiceInfo,
|
|
473
|
+
"oldPandaIDs": jobOldPandaIDs,
|
|
474
|
+
"relationType": relationType,
|
|
475
|
+
"fileIDPool": fileIDPool,
|
|
476
|
+
"origSpecialHandling": origSH,
|
|
477
|
+
"unprocessedMap": unprocessedMap,
|
|
478
|
+
"prio_reduction": prio_reduction,
|
|
479
|
+
},
|
|
480
|
+
{"esIndex": esIndex},
|
|
481
|
+
]
|
|
482
|
+
)
|
|
483
|
+
special_handling_list.append(origSH)
|
|
484
|
+
tmp_ret_i = True
|
|
485
|
+
if tmp_ret_i and origEsJob and not bulk_job_insert:
|
|
486
|
+
# mapping of jobsetID for event service
|
|
487
|
+
esJobsetMap[esIndex] = job.jobsetID
|
|
488
|
+
job_ret_list.append([job, tmp_ret_i])
|
|
489
|
+
serNum += 1
|
|
490
|
+
try:
|
|
491
|
+
fileIDPool = fileIDPool[len(job.Files) :]
|
|
492
|
+
except Exception:
|
|
493
|
+
fileIDPool = []
|
|
494
|
+
# bulk insert
|
|
495
|
+
if bulk_job_insert:
|
|
496
|
+
# get jobset IDs for event service jobs
|
|
497
|
+
if num_original_event_service_jobs > 0:
|
|
498
|
+
new_jobset_ids = proxy.bulk_fetch_panda_ids(num_original_event_service_jobs)
|
|
499
|
+
else:
|
|
500
|
+
new_jobset_ids = []
|
|
501
|
+
tmp_ret, job_ret_list, es_jobset_map = proxy.bulk_insert_new_jobs(
|
|
502
|
+
jobs[0].jediTaskID, params_for_bulk_insert, new_jobset_ids, special_handling_list
|
|
503
|
+
)
|
|
504
|
+
if not tmp_ret:
|
|
505
|
+
raise RuntimeError("bulk job insert failed")
|
|
506
|
+
# update esJobsetMap
|
|
507
|
+
esJobsetMap.update(es_jobset_map)
|
|
508
|
+
|
|
509
|
+
# check returns
|
|
510
|
+
for job, tmp_ret_i in job_ret_list:
|
|
511
|
+
if not tmp_ret_i:
|
|
512
|
+
# reset if failed
|
|
513
|
+
job.PandaID = None
|
|
514
|
+
else:
|
|
515
|
+
# append
|
|
516
|
+
newJobs.append(job)
|
|
517
|
+
if job.prodSourceLabel in JobUtils.analy_sources + JobUtils.list_ptest_prod_sources:
|
|
518
|
+
ret.append((job.PandaID, job.jobDefinitionID, {"jobsetID": job.jobsetID}))
|
|
519
|
+
else:
|
|
520
|
+
ret.append((job.PandaID, job.jobDefinitionID, job.jobName))
|
|
521
|
+
# set up dataset
|
|
522
|
+
if not toPending:
|
|
523
|
+
if joinThr:
|
|
524
|
+
thr = Setupper(
|
|
525
|
+
self,
|
|
526
|
+
newJobs,
|
|
527
|
+
)
|
|
528
|
+
thr.start()
|
|
529
|
+
thr.join()
|
|
530
|
+
else:
|
|
531
|
+
# cannot use 'thr =' because it may trigger garbage collector
|
|
532
|
+
Setupper(
|
|
533
|
+
self,
|
|
534
|
+
newJobs,
|
|
535
|
+
).start()
|
|
536
|
+
# return jobIDs
|
|
537
|
+
tmpLog.debug("end successfully")
|
|
538
|
+
if getEsJobsetMap:
|
|
539
|
+
return (ret, esJobsetMap, unprocessedMap)
|
|
540
|
+
return ret
|
|
541
|
+
except Exception as e:
|
|
542
|
+
tmpLog.error(f"{str(e)} {traceback.format_exc()}")
|
|
543
|
+
errStr = "ERROR: ServerError with storeJobs"
|
|
544
|
+
if getEsJobsetMap:
|
|
545
|
+
return (errStr, None, unprocessedMap)
|
|
546
|
+
return errStr
|
|
547
|
+
|
|
548
|
+
# lock jobs for reassign
|
|
549
|
+
def lockJobsForReassign(
|
|
550
|
+
self,
|
|
551
|
+
tableName,
|
|
552
|
+
timeLimit,
|
|
553
|
+
statList,
|
|
554
|
+
labels,
|
|
555
|
+
processTypes,
|
|
556
|
+
sites,
|
|
557
|
+
clouds,
|
|
558
|
+
useJEDI=False,
|
|
559
|
+
onlyReassignable=False,
|
|
560
|
+
useStateChangeTime=False,
|
|
561
|
+
getEventService=False,
|
|
562
|
+
):
|
|
563
|
+
# get DB proxy
|
|
564
|
+
with self.proxyPool.get() as proxy:
|
|
565
|
+
# exec
|
|
566
|
+
res = proxy.lockJobsForReassign(
|
|
567
|
+
tableName,
|
|
568
|
+
timeLimit,
|
|
569
|
+
statList,
|
|
570
|
+
labels,
|
|
571
|
+
processTypes,
|
|
572
|
+
sites,
|
|
573
|
+
clouds,
|
|
574
|
+
useJEDI,
|
|
575
|
+
onlyReassignable,
|
|
576
|
+
useStateChangeTime,
|
|
577
|
+
getEventService,
|
|
578
|
+
)
|
|
579
|
+
return res
|
|
580
|
+
|
|
581
|
+
# get a DB configuration value
|
|
582
|
+
def getConfigValue(self, component, key, app="pandaserver", vo=None, default=None):
|
|
583
|
+
# get DB proxy
|
|
584
|
+
with self.proxyPool.get() as proxy:
|
|
585
|
+
# exec
|
|
586
|
+
res = proxy.getConfigValue(component, key, app, vo)
|
|
587
|
+
if res is None and default is not None:
|
|
588
|
+
res = default
|
|
589
|
+
return res
|
|
590
|
+
|
|
591
|
+
# lock jobs for finisher
|
|
592
|
+
def lockJobsForFinisher(self, timeNow, rownum, highPrio):
|
|
593
|
+
# get DB proxy
|
|
594
|
+
with self.proxyPool.get() as proxy:
|
|
595
|
+
# exec
|
|
596
|
+
res = proxy.lockJobsForFinisher(timeNow, rownum, highPrio)
|
|
597
|
+
return res
|
|
598
|
+
|
|
599
|
+
# lock jobs for activator
|
|
600
|
+
def lockJobsForActivator(self, timeLimit, rownum, prio):
|
|
601
|
+
# get DB proxy
|
|
602
|
+
with self.proxyPool.get() as proxy:
|
|
603
|
+
# exec
|
|
604
|
+
res = proxy.lockJobsForActivator(timeLimit, rownum, prio)
|
|
605
|
+
return res
|
|
606
|
+
|
|
607
|
+
# update overall job information
|
|
608
|
+
def updateJobs(
|
|
609
|
+
self,
|
|
610
|
+
jobs,
|
|
611
|
+
inJobsDefined,
|
|
612
|
+
oldJobStatusList=None,
|
|
613
|
+
extraInfo=None,
|
|
614
|
+
async_dataset_update=False,
|
|
615
|
+
):
|
|
616
|
+
# get DB proxy
|
|
617
|
+
with self.proxyPool.get() as proxy:
|
|
618
|
+
# loop over all jobs
|
|
619
|
+
returns = []
|
|
620
|
+
ddmIDs = []
|
|
621
|
+
ddmAttempt = 0
|
|
622
|
+
newMover = None
|
|
623
|
+
for idxJob, job in enumerate(jobs):
|
|
624
|
+
# update DB
|
|
625
|
+
tmpddmIDs = []
|
|
626
|
+
if oldJobStatusList is not None and idxJob < len(oldJobStatusList):
|
|
627
|
+
oldJobStatus = oldJobStatusList[idxJob]
|
|
628
|
+
else:
|
|
629
|
+
oldJobStatus = None
|
|
630
|
+
# check for jumbo jobs
|
|
631
|
+
if EventServiceUtils.isJumboJob(job):
|
|
632
|
+
if job.jobStatus in ["defined", "assigned", "activated"]:
|
|
633
|
+
pass
|
|
634
|
+
else:
|
|
635
|
+
# check if there are done events
|
|
636
|
+
hasDone = proxy.hasDoneEvents(job.jediTaskID, job.PandaID, job)
|
|
637
|
+
if hasDone:
|
|
638
|
+
job.jobStatus = "finished"
|
|
639
|
+
else:
|
|
640
|
+
if job.pilotErrorCode in [1144, "1144"]:
|
|
641
|
+
job.jobStatus = "cancelled"
|
|
642
|
+
else:
|
|
643
|
+
job.jobStatus = "failed"
|
|
644
|
+
if job.taskBufferErrorDiag in ["", "NULL", None]:
|
|
645
|
+
job.taskBufferErrorDiag = f"set {job.jobStatus} since no successful events"
|
|
646
|
+
job.taskBufferErrorCode = ErrorCode.EC_EventServiceNoEvent
|
|
647
|
+
if job.jobStatus in ["finished", "failed", "cancelled"]:
|
|
648
|
+
if async_dataset_update and job.jediTaskID not in [None, "NULL"]:
|
|
649
|
+
async_params = {
|
|
650
|
+
"exec_order": 0,
|
|
651
|
+
"PandaID": job.PandaID,
|
|
652
|
+
"jediTaskID": job.jediTaskID,
|
|
653
|
+
}
|
|
654
|
+
else:
|
|
655
|
+
async_params = None
|
|
656
|
+
ret, tmpddmIDs, ddmAttempt, newMover = proxy.archiveJob(job, inJobsDefined, extraInfo=extraInfo, async_params=async_params)
|
|
657
|
+
if async_params is not None and ret:
|
|
658
|
+
proxy.async_update_datasets(job.PandaID)
|
|
659
|
+
else:
|
|
660
|
+
ret = proxy.updateJob(job, inJobsDefined, oldJobStatus=oldJobStatus, extraInfo=extraInfo)
|
|
661
|
+
returns.append(ret)
|
|
662
|
+
# collect IDs for reassign
|
|
663
|
+
if ret:
|
|
664
|
+
ddmIDs += tmpddmIDs
|
|
665
|
+
# retry mover
|
|
666
|
+
if newMover is not None:
|
|
667
|
+
self.storeJobs([newMover], None, joinThr=True)
|
|
668
|
+
# reassign jobs when ddm failed
|
|
669
|
+
if ddmIDs != []:
|
|
670
|
+
self.reassignJobs(ddmIDs, ddmAttempt, joinThr=True)
|
|
671
|
+
|
|
672
|
+
return returns
|
|
673
|
+
|
|
674
|
+
# update job jobStatus only
|
|
675
|
+
def updateJobStatus(self, jobID, jobStatus, param, updateStateChange=False, attemptNr=None):
|
|
676
|
+
# get DB proxy
|
|
677
|
+
with self.proxyPool.get() as proxy:
|
|
678
|
+
# update DB and buffer
|
|
679
|
+
ret, post_action = proxy.updateJobStatus(jobID, jobStatus, param, updateStateChange, attemptNr)
|
|
680
|
+
# take post-action
|
|
681
|
+
if post_action:
|
|
682
|
+
# get semaphore for job cloning with runonce
|
|
683
|
+
if post_action["action"] == "get_event":
|
|
684
|
+
event_ret = proxy.getEventRanges(post_action["pandaID"], post_action["jobsetID"], post_action["jediTaskID"], 1, True, False, None)
|
|
685
|
+
if not event_ret:
|
|
686
|
+
proxy.killJob(post_action["pandaID"], "job cloning", "", True)
|
|
687
|
+
ret = "tobekilled"
|
|
688
|
+
# get secrets for debug mode
|
|
689
|
+
if isinstance(ret, str) and "debug" in ret:
|
|
690
|
+
tmpS, secrets = proxy.get_user_secrets(panda_config.pilot_secrets)
|
|
691
|
+
if tmpS and secrets:
|
|
692
|
+
ret = {"command": ret, "secrets": secrets}
|
|
693
|
+
return ret
|
|
694
|
+
|
|
695
|
+
# update worker status by the pilot
|
|
696
|
+
def updateWorkerPilotStatus(self, workerID, harvesterID, status, node_id):
|
|
697
|
+
# get DB proxy
|
|
698
|
+
with self.proxyPool.get() as proxy:
|
|
699
|
+
# update DB and buffer
|
|
700
|
+
ret = proxy.updateWorkerPilotStatus(workerID, harvesterID, status, node_id)
|
|
701
|
+
return ret
|
|
702
|
+
|
|
703
|
+
def update_worker_node(
|
|
704
|
+
self,
|
|
705
|
+
site,
|
|
706
|
+
panda_queue,
|
|
707
|
+
host_name,
|
|
708
|
+
cpu_model,
|
|
709
|
+
cpu_model_normalized,
|
|
710
|
+
n_logical_cpus,
|
|
711
|
+
n_sockets,
|
|
712
|
+
cores_per_socket,
|
|
713
|
+
threads_per_core,
|
|
714
|
+
cpu_architecture,
|
|
715
|
+
cpu_architecture_level,
|
|
716
|
+
clock_speed,
|
|
717
|
+
total_memory,
|
|
718
|
+
total_local_disk,
|
|
719
|
+
):
|
|
720
|
+
# get DB proxy
|
|
721
|
+
with self.proxyPool.get() as proxy:
|
|
722
|
+
# update DB and buffer
|
|
723
|
+
ret = proxy.update_worker_node(
|
|
724
|
+
site,
|
|
725
|
+
panda_queue,
|
|
726
|
+
host_name,
|
|
727
|
+
cpu_model,
|
|
728
|
+
cpu_model_normalized,
|
|
729
|
+
n_logical_cpus,
|
|
730
|
+
n_sockets,
|
|
731
|
+
cores_per_socket,
|
|
732
|
+
threads_per_core,
|
|
733
|
+
cpu_architecture,
|
|
734
|
+
cpu_architecture_level,
|
|
735
|
+
clock_speed,
|
|
736
|
+
total_memory,
|
|
737
|
+
total_local_disk,
|
|
738
|
+
)
|
|
739
|
+
return ret
|
|
740
|
+
|
|
741
|
+
def update_worker_node_gpu(
|
|
742
|
+
self,
|
|
743
|
+
site: str,
|
|
744
|
+
host_name: str,
|
|
745
|
+
vendor: str,
|
|
746
|
+
model: str,
|
|
747
|
+
count: int,
|
|
748
|
+
vram: int,
|
|
749
|
+
architecture: str,
|
|
750
|
+
framework: str,
|
|
751
|
+
framework_version: str,
|
|
752
|
+
driver_version: str,
|
|
753
|
+
):
|
|
754
|
+
# get DB proxy
|
|
755
|
+
with self.proxyPool.get() as proxy:
|
|
756
|
+
# update DB and buffer
|
|
757
|
+
ret = proxy.update_worker_node_gpu(
|
|
758
|
+
site,
|
|
759
|
+
host_name,
|
|
760
|
+
vendor,
|
|
761
|
+
model,
|
|
762
|
+
count,
|
|
763
|
+
vram,
|
|
764
|
+
architecture,
|
|
765
|
+
framework,
|
|
766
|
+
framework_version,
|
|
767
|
+
driver_version,
|
|
768
|
+
)
|
|
769
|
+
return ret
|
|
770
|
+
|
|
771
|
+
def get_architecture_level_map(self):
|
|
772
|
+
# get DB proxy
|
|
773
|
+
with self.proxyPool.get() as proxy:
|
|
774
|
+
ret = proxy.get_architecture_level_map()
|
|
775
|
+
return ret
|
|
776
|
+
|
|
777
|
+
# finalize pending analysis jobs
|
|
778
|
+
def finalizePendingJobs(self, prodUserName, jobDefinitionID, waitLock=False):
|
|
779
|
+
# get DB proxy
|
|
780
|
+
with self.proxyPool.get() as proxy:
|
|
781
|
+
# update DB
|
|
782
|
+
ret = proxy.finalizePendingJobs(prodUserName, jobDefinitionID, waitLock)
|
|
783
|
+
return ret
|
|
784
|
+
|
|
785
|
+
# retry job
|
|
786
|
+
def retryJob(
|
|
787
|
+
self,
|
|
788
|
+
jobID,
|
|
789
|
+
param,
|
|
790
|
+
failedInActive=False,
|
|
791
|
+
changeJobInMem=False,
|
|
792
|
+
inMemJob=None,
|
|
793
|
+
getNewPandaID=False,
|
|
794
|
+
attemptNr=None,
|
|
795
|
+
recoverableEsMerge=False,
|
|
796
|
+
):
|
|
797
|
+
# get DB proxy
|
|
798
|
+
with self.proxyPool.get() as proxy:
|
|
799
|
+
# update DB
|
|
800
|
+
ret = proxy.retryJob(
|
|
801
|
+
jobID,
|
|
802
|
+
param,
|
|
803
|
+
failedInActive,
|
|
804
|
+
changeJobInMem,
|
|
805
|
+
inMemJob,
|
|
806
|
+
getNewPandaID,
|
|
807
|
+
attemptNr,
|
|
808
|
+
recoverableEsMerge,
|
|
809
|
+
)
|
|
810
|
+
return ret
|
|
811
|
+
|
|
812
|
+
# activate jobs
|
|
813
|
+
def activateJobs(self, jobs):
|
|
814
|
+
# get DB proxy
|
|
815
|
+
with self.proxyPool.get() as proxy:
|
|
816
|
+
# loop over all jobs
|
|
817
|
+
returns = []
|
|
818
|
+
for job in jobs:
|
|
819
|
+
# update DB
|
|
820
|
+
ret = proxy.activateJob(job)
|
|
821
|
+
returns.append(ret)
|
|
822
|
+
return returns
|
|
823
|
+
|
|
824
|
+
# send jobs to jobsWaiting
|
|
825
|
+
def keepJobs(self, jobs):
|
|
826
|
+
# get DB proxy
|
|
827
|
+
with self.proxyPool.get() as proxy:
|
|
828
|
+
# loop over all jobs
|
|
829
|
+
returns = []
|
|
830
|
+
for job in jobs:
|
|
831
|
+
# update DB
|
|
832
|
+
ret = proxy.keepJob(job)
|
|
833
|
+
returns.append(ret)
|
|
834
|
+
return returns
|
|
835
|
+
|
|
836
|
+
# archive jobs
|
|
837
|
+
def archiveJobs(self, jobs, inJobsDefined, fromJobsWaiting=False):
|
|
838
|
+
# get DB proxy
|
|
839
|
+
with self.proxyPool.get() as proxy:
|
|
840
|
+
# loop over all jobs
|
|
841
|
+
returns = []
|
|
842
|
+
for job in jobs:
|
|
843
|
+
# update DB
|
|
844
|
+
ret = proxy.archiveJob(job, inJobsDefined, fromJobsWaiting=fromJobsWaiting)
|
|
845
|
+
returns.append(ret[0])
|
|
846
|
+
return returns
|
|
847
|
+
|
|
848
|
+
# set debug mode
|
|
849
|
+
def setDebugMode(self, dn, pandaID, prodManager, modeOn, workingGroup):
|
|
850
|
+
# get DB proxy
|
|
851
|
+
with self.proxyPool.get() as proxy:
|
|
852
|
+
# check the number of debug jobs
|
|
853
|
+
hitLimit = False
|
|
854
|
+
if modeOn is True:
|
|
855
|
+
if prodManager:
|
|
856
|
+
limitNum = None
|
|
857
|
+
elif workingGroup is not None:
|
|
858
|
+
jobList = proxy.getActiveDebugJobs(workingGroup=workingGroup)
|
|
859
|
+
limitNum = ProcessGroups.maxDebugWgJobs
|
|
860
|
+
else:
|
|
861
|
+
jobList = proxy.getActiveDebugJobs(dn=dn)
|
|
862
|
+
limitNum = ProcessGroups.maxDebugJobs
|
|
863
|
+
if limitNum and len(jobList) >= limitNum:
|
|
864
|
+
# exceeded
|
|
865
|
+
retStr = "You already hit the limit on the maximum number of debug subjobs "
|
|
866
|
+
retStr += f"({limitNum} jobs). "
|
|
867
|
+
retStr += "Please set the debug mode off for one of the following PandaIDs : "
|
|
868
|
+
for tmpID in jobList:
|
|
869
|
+
retStr += f"{tmpID},"
|
|
870
|
+
retStr = retStr[:-1]
|
|
871
|
+
hitLimit = True
|
|
872
|
+
if not hitLimit:
|
|
873
|
+
# execute
|
|
874
|
+
retStr = proxy.setDebugMode(dn, pandaID, prodManager, modeOn, workingGroup)
|
|
875
|
+
return retStr
|
|
876
|
+
|
|
877
|
+
# get jobs
|
|
878
|
+
def getJobs(
|
|
879
|
+
self,
|
|
880
|
+
nJobs,
|
|
881
|
+
siteName,
|
|
882
|
+
prodSourceLabel,
|
|
883
|
+
mem,
|
|
884
|
+
diskSpace,
|
|
885
|
+
node,
|
|
886
|
+
timeout,
|
|
887
|
+
computingElement,
|
|
888
|
+
prodUserID,
|
|
889
|
+
taskID,
|
|
890
|
+
background,
|
|
891
|
+
resourceType,
|
|
892
|
+
harvester_id,
|
|
893
|
+
worker_id,
|
|
894
|
+
schedulerID,
|
|
895
|
+
jobType,
|
|
896
|
+
is_gu,
|
|
897
|
+
via_topic,
|
|
898
|
+
remaining_time,
|
|
899
|
+
):
|
|
900
|
+
# get DBproxy
|
|
901
|
+
with self.proxyPool.get() as proxy:
|
|
902
|
+
# get waiting jobs
|
|
903
|
+
t_before = time.time()
|
|
904
|
+
jobs, nSent = proxy.getJobs(
|
|
905
|
+
nJobs,
|
|
906
|
+
siteName,
|
|
907
|
+
prodSourceLabel,
|
|
908
|
+
mem,
|
|
909
|
+
diskSpace,
|
|
910
|
+
node,
|
|
911
|
+
timeout,
|
|
912
|
+
computingElement,
|
|
913
|
+
prodUserID,
|
|
914
|
+
taskID,
|
|
915
|
+
background,
|
|
916
|
+
resourceType,
|
|
917
|
+
harvester_id,
|
|
918
|
+
worker_id,
|
|
919
|
+
schedulerID,
|
|
920
|
+
jobType,
|
|
921
|
+
is_gu,
|
|
922
|
+
via_topic,
|
|
923
|
+
remaining_time,
|
|
924
|
+
)
|
|
925
|
+
t_after = time.time()
|
|
926
|
+
t_total = t_after - t_before
|
|
927
|
+
_logger.debug(f"getJobs : took {t_total}s for {siteName} nJobs={nJobs} prodSourceLabel={prodSourceLabel}")
|
|
928
|
+
|
|
929
|
+
# get secret
|
|
930
|
+
secrets_map = {}
|
|
931
|
+
for job in jobs:
|
|
932
|
+
if job.use_secrets() and job.prodUserName not in secrets_map:
|
|
933
|
+
# get secret
|
|
934
|
+
with self.proxyPool.get() as proxy:
|
|
935
|
+
tmp_status, secret = proxy.get_user_secrets(job.prodUserName)
|
|
936
|
+
if not tmp_status:
|
|
937
|
+
secret = None
|
|
938
|
+
secrets_map[job.prodUserName] = secret
|
|
939
|
+
if job.is_debug_mode():
|
|
940
|
+
if panda_config.pilot_secrets not in secrets_map:
|
|
941
|
+
# get secret
|
|
942
|
+
with self.proxyPool.get() as proxy:
|
|
943
|
+
tmp_status, secret = proxy.get_user_secrets(panda_config.pilot_secrets)
|
|
944
|
+
if not tmp_status:
|
|
945
|
+
secret = None
|
|
946
|
+
secrets_map[panda_config.pilot_secrets] = secret
|
|
947
|
+
|
|
948
|
+
return jobs + [nSent, {}, secrets_map]
|
|
949
|
+
|
|
950
|
+
# get job status
|
|
951
|
+
def getJobStatus(
|
|
952
|
+
self,
|
|
953
|
+
jobIDs,
|
|
954
|
+
fromDefined=True,
|
|
955
|
+
fromActive=True,
|
|
956
|
+
fromArchived=True,
|
|
957
|
+
fromWaiting=True,
|
|
958
|
+
):
|
|
959
|
+
# get DBproxy
|
|
960
|
+
with self.proxyPool.get() as proxy:
|
|
961
|
+
retStatus = []
|
|
962
|
+
# peek at job
|
|
963
|
+
for jobID in jobIDs:
|
|
964
|
+
res = proxy.peekJob(jobID, fromDefined, fromActive, fromArchived, fromWaiting)
|
|
965
|
+
if res:
|
|
966
|
+
retStatus.append(res.jobStatus)
|
|
967
|
+
else:
|
|
968
|
+
retStatus.append(None)
|
|
969
|
+
return retStatus
|
|
970
|
+
|
|
971
|
+
# peek at jobs
|
|
972
|
+
def peekJobs(
|
|
973
|
+
self,
|
|
974
|
+
jobIDs,
|
|
975
|
+
fromDefined=True,
|
|
976
|
+
fromActive=True,
|
|
977
|
+
fromArchived=True,
|
|
978
|
+
fromWaiting=True,
|
|
979
|
+
forAnal=False,
|
|
980
|
+
use_json=False,
|
|
981
|
+
):
|
|
982
|
+
# get proxy
|
|
983
|
+
with self.proxyPool.get() as proxy:
|
|
984
|
+
retJobs = []
|
|
985
|
+
# peek at job
|
|
986
|
+
for jobID in jobIDs:
|
|
987
|
+
res = proxy.peekJob(jobID, fromDefined, fromActive, fromArchived, fromWaiting, forAnal)
|
|
988
|
+
if res:
|
|
989
|
+
if use_json:
|
|
990
|
+
retJobs.append(res.to_dict())
|
|
991
|
+
else:
|
|
992
|
+
retJobs.append(res)
|
|
993
|
+
else:
|
|
994
|
+
retJobs.append(None)
|
|
995
|
+
return retJobs
|
|
996
|
+
|
|
997
|
+
# get PandaIDs with TaskID
|
|
998
|
+
def getPandaIDsWithTaskID(self, jediTaskID: int, scout_only: bool = False, unsuccessful_only: bool = False) -> list[int]:
|
|
999
|
+
"""Get PanDA job IDs associated with a JEDI task.
|
|
1000
|
+
|
|
1001
|
+
Args:
|
|
1002
|
+
jediTaskID: JEDI task ID.
|
|
1003
|
+
scout_only: When True, return only scout job IDs.
|
|
1004
|
+
unsuccessful_only: When True, return only job IDs with status failed, cancelled, or closed.
|
|
1005
|
+
|
|
1006
|
+
Returns:
|
|
1007
|
+
list[int]: PanDA job IDs for the task.
|
|
1008
|
+
"""
|
|
1009
|
+
# get DBproxy
|
|
1010
|
+
with self.proxyPool.get() as proxy:
|
|
1011
|
+
# exec
|
|
1012
|
+
retJobs = proxy.getPandaIDsWithTaskID(jediTaskID, scout_only=scout_only, unsuccessful_only=unsuccessful_only)
|
|
1013
|
+
return retJobs
|
|
1014
|
+
|
|
1015
|
+
# get full job status
|
|
1016
|
+
def getFullJobStatus(self, jobIDs, fromDefined=True, fromActive=True, fromArchived=True, fromWaiting=True, forAnal=True, days=30, use_json=False):
|
|
1017
|
+
retJobMap = {}
|
|
1018
|
+
|
|
1019
|
+
# peek at job
|
|
1020
|
+
for jobID in jobIDs:
|
|
1021
|
+
# get DBproxy for each job to avoid occupying connection for long time
|
|
1022
|
+
with self.proxyPool.get() as proxy:
|
|
1023
|
+
# peek job
|
|
1024
|
+
res = proxy.peekJob(jobID, fromDefined, fromActive, fromArchived, fromWaiting, forAnal)
|
|
1025
|
+
retJobMap[jobID] = res
|
|
1026
|
+
|
|
1027
|
+
# get IDs
|
|
1028
|
+
for jobID in jobIDs:
|
|
1029
|
+
if retJobMap[jobID] is None:
|
|
1030
|
+
# get ArchiveDBproxy
|
|
1031
|
+
with self.proxyPool.get() as proxy:
|
|
1032
|
+
# peek job
|
|
1033
|
+
res = proxy.peekJobLog(jobID, days)
|
|
1034
|
+
retJobMap[jobID] = res
|
|
1035
|
+
|
|
1036
|
+
# sort
|
|
1037
|
+
retJobs = []
|
|
1038
|
+
for jobID in jobIDs:
|
|
1039
|
+
if use_json:
|
|
1040
|
+
if retJobMap[jobID] is None:
|
|
1041
|
+
retJobs.append(None)
|
|
1042
|
+
else:
|
|
1043
|
+
retJobs.append(retJobMap[jobID].to_dict())
|
|
1044
|
+
else:
|
|
1045
|
+
retJobs.append(retJobMap[jobID])
|
|
1046
|
+
|
|
1047
|
+
return retJobs
|
|
1048
|
+
|
|
1049
|
+
# get script for offline running
|
|
1050
|
+
def getScriptOfflineRunning(self, pandaID, days=None):
|
|
1051
|
+
try:
|
|
1052
|
+
# get job
|
|
1053
|
+
tmpJobs = self.getFullJobStatus([pandaID], days=days)
|
|
1054
|
+
if tmpJobs == [] or tmpJobs[0] is None:
|
|
1055
|
+
errStr = f"ERROR: Cannot get PandaID={pandaID} in DB "
|
|
1056
|
+
if days is None:
|
|
1057
|
+
errStr += "for the last 30 days. You may add &days=N to the URL"
|
|
1058
|
+
else:
|
|
1059
|
+
errStr += f"for the last {days} days. You may change &days=N in the URL"
|
|
1060
|
+
return errStr
|
|
1061
|
+
tmpJob = tmpJobs[0]
|
|
1062
|
+
# user job
|
|
1063
|
+
isUser = False
|
|
1064
|
+
for trf in [
|
|
1065
|
+
"runAthena",
|
|
1066
|
+
"runGen",
|
|
1067
|
+
"runcontainer",
|
|
1068
|
+
"runMerge",
|
|
1069
|
+
"buildJob",
|
|
1070
|
+
"buildGen",
|
|
1071
|
+
]:
|
|
1072
|
+
if trf in tmpJob.transformation:
|
|
1073
|
+
isUser = True
|
|
1074
|
+
break
|
|
1075
|
+
# check prodSourceLabel
|
|
1076
|
+
if tmpJob.prodSourceLabel == "user":
|
|
1077
|
+
isUser = True
|
|
1078
|
+
if isUser:
|
|
1079
|
+
tmpAtls = [tmpJob.AtlasRelease]
|
|
1080
|
+
tmpRels = [re.sub("^AnalysisTransforms-*", "", tmpJob.homepackage)]
|
|
1081
|
+
tmpPars = [tmpJob.jobParameters]
|
|
1082
|
+
tmpTrfs = [tmpJob.transformation]
|
|
1083
|
+
else:
|
|
1084
|
+
# release and trf
|
|
1085
|
+
tmpAtls = tmpJob.AtlasRelease.split("\n")
|
|
1086
|
+
tmpRels = tmpJob.homepackage.split("\n")
|
|
1087
|
+
tmpPars = tmpJob.jobParameters.split("\n")
|
|
1088
|
+
tmpTrfs = tmpJob.transformation.split("\n")
|
|
1089
|
+
if not (len(tmpRels) == len(tmpPars) == len(tmpTrfs)):
|
|
1090
|
+
return "ERROR: The number of releases or parameters or trfs is inconsistent with others"
|
|
1091
|
+
# construct script
|
|
1092
|
+
scrStr = (
|
|
1093
|
+
"#!/bin/bash\n\n"
|
|
1094
|
+
"# To rerun the job interactively :\n"
|
|
1095
|
+
"# 1) download this script\n"
|
|
1096
|
+
"# 2) chmod +x ./<this script>\n"
|
|
1097
|
+
"# 3) setupATLAS\n"
|
|
1098
|
+
"# 4) ./<this script>\n\n"
|
|
1099
|
+
"temp_file=$(mktemp)\n"
|
|
1100
|
+
'cat << EOF > "$temp_file"\n\n'
|
|
1101
|
+
"source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh\n"
|
|
1102
|
+
"lsetup rucio\n\n"
|
|
1103
|
+
"#retrieve inputs\n\n"
|
|
1104
|
+
)
|
|
1105
|
+
# collect inputs
|
|
1106
|
+
dsFileMap = {}
|
|
1107
|
+
for tmpFile in tmpJob.Files:
|
|
1108
|
+
if tmpFile.type == "input":
|
|
1109
|
+
if tmpFile.dataset not in dsFileMap:
|
|
1110
|
+
dsFileMap[tmpFile.dataset] = []
|
|
1111
|
+
if tmpFile.lfn not in dsFileMap[tmpFile.dataset]:
|
|
1112
|
+
dsFileMap[tmpFile.dataset].append(tmpFile.scope + ":" + tmpFile.lfn)
|
|
1113
|
+
# get
|
|
1114
|
+
for tmpDS in dsFileMap:
|
|
1115
|
+
tmpFileList = dsFileMap[tmpDS]
|
|
1116
|
+
for tmpLFN in tmpFileList:
|
|
1117
|
+
scrStr += f"rucio download {tmpLFN} --no-subdir\n"
|
|
1118
|
+
if isUser:
|
|
1119
|
+
scrStr += "\n#get trf\n"
|
|
1120
|
+
scrStr += f"wget {tmpTrfs[0]}\n"
|
|
1121
|
+
scrStr += f"chmod +x {tmpTrfs[0].split('/')[-1]}\n"
|
|
1122
|
+
scrStr += "\n#transform commands\n\n"
|
|
1123
|
+
for tmpIdx, tmpRel in enumerate(tmpRels):
|
|
1124
|
+
# asetup
|
|
1125
|
+
atlRel = re.sub("Atlas-", "", tmpAtls[tmpIdx])
|
|
1126
|
+
atlTags = re.split("[/_]", tmpRel)
|
|
1127
|
+
if "" in atlTags:
|
|
1128
|
+
atlTags.remove("")
|
|
1129
|
+
if atlRel != "" and atlRel not in atlTags and (re.search("^\d+\.\d+\.\d+$", atlRel) is None or isUser):
|
|
1130
|
+
atlTags.append(atlRel)
|
|
1131
|
+
try:
|
|
1132
|
+
cmtConfig = [s for s in tmpJob.cmtConfig.split("@") if s][-1]
|
|
1133
|
+
except Exception:
|
|
1134
|
+
cmtConfig = ""
|
|
1135
|
+
scrStr += f"asetup --platform={tmpJob.cmtConfig.split('@')[0]} {','.join(atlTags)}\n"
|
|
1136
|
+
# athenaMP
|
|
1137
|
+
if tmpJob.coreCount not in ["NULL", None] and tmpJob.coreCount > 1:
|
|
1138
|
+
scrStr += f"export ATHENA_PROC_NUMBER={tmpJob.coreCount}\n"
|
|
1139
|
+
scrStr += f"export ATHENA_CORE_NUMBER={tmpJob.coreCount}\n"
|
|
1140
|
+
# add double quotes for zsh
|
|
1141
|
+
tmpParamStr = tmpPars[tmpIdx]
|
|
1142
|
+
tmpSplitter = shlex.shlex(tmpParamStr, posix=True)
|
|
1143
|
+
tmpSplitter.whitespace = " "
|
|
1144
|
+
tmpSplitter.whitespace_split = True
|
|
1145
|
+
# loop for params
|
|
1146
|
+
for tmpItem in tmpSplitter:
|
|
1147
|
+
tmpMatch = re.search("^(-[^=]+=)(.+)$", tmpItem)
|
|
1148
|
+
if tmpMatch is not None:
|
|
1149
|
+
tmpArgName = tmpMatch.group(1)
|
|
1150
|
+
tmpArgVal = tmpMatch.group(2)
|
|
1151
|
+
tmpArgIdx = tmpParamStr.find(tmpArgName) + len(tmpArgName)
|
|
1152
|
+
# add "
|
|
1153
|
+
if tmpParamStr[tmpArgIdx] != '"':
|
|
1154
|
+
tmpParamStr = tmpParamStr.replace(tmpMatch.group(0), tmpArgName + '"' + tmpArgVal + '"')
|
|
1155
|
+
# run trf
|
|
1156
|
+
if isUser:
|
|
1157
|
+
scrStr += "./"
|
|
1158
|
+
tmpParamStr += " --debug"
|
|
1159
|
+
scrStr += f"{tmpTrfs[tmpIdx].split('/')[-1]} {tmpParamStr}\n\n"
|
|
1160
|
+
scrStr += "EOF\n\n" 'chmod +x "$temp_file"\n'
|
|
1161
|
+
scrStr += 'source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh -c %s -r "$temp_file"\n' % cmtConfig
|
|
1162
|
+
scrStr += 'rm "$temp_file"\n'
|
|
1163
|
+
return scrStr
|
|
1164
|
+
except Exception as e:
|
|
1165
|
+
_logger.error(f"getScriptOfflineRunning : {str(e)} {traceback.format_exc()}")
|
|
1166
|
+
return f"ERROR: ServerError in getScriptOfflineRunning with {str(e)}"
|
|
1167
|
+
|
|
1168
|
+
# kill jobs
|
|
1169
|
+
def killJobs(self, ids, user, code, prodManager, wgProdRole=[], killOptions=[]):
|
|
1170
|
+
tmp_log = LogWrapper(_logger, "killJobs")
|
|
1171
|
+
tmp_log.debug(f"start for {len(ids)} IDs")
|
|
1172
|
+
# get DBproxy
|
|
1173
|
+
with self.proxyPool.get() as proxy:
|
|
1174
|
+
rets = []
|
|
1175
|
+
# kill jobs
|
|
1176
|
+
pandaIDforCloserMap = {}
|
|
1177
|
+
for id in ids:
|
|
1178
|
+
# retry event service merge
|
|
1179
|
+
toKill = True
|
|
1180
|
+
if "keepUnmerged" in killOptions:
|
|
1181
|
+
tmpJobSpec = proxy.peekJob(id, True, True, False, False, False)
|
|
1182
|
+
if tmpJobSpec is not None:
|
|
1183
|
+
if EventServiceUtils.isEventServiceMerge(tmpJobSpec):
|
|
1184
|
+
# retry ES merge jobs not to discard events
|
|
1185
|
+
proxy.retryJob(
|
|
1186
|
+
id,
|
|
1187
|
+
{},
|
|
1188
|
+
getNewPandaID=True,
|
|
1189
|
+
attemptNr=tmpJobSpec.attemptNr,
|
|
1190
|
+
recoverableEsMerge=True,
|
|
1191
|
+
)
|
|
1192
|
+
elif EventServiceUtils.isEventServiceJob(tmpJobSpec) and not EventServiceUtils.isJobCloningJob(tmpJobSpec):
|
|
1193
|
+
# get number of started events
|
|
1194
|
+
nEvt = proxy.getNumStartedEvents(tmpJobSpec)
|
|
1195
|
+
# not to kill jobset if there are started events
|
|
1196
|
+
if nEvt is not None and nEvt > 0:
|
|
1197
|
+
# set sub status if any
|
|
1198
|
+
for killOpt in killOptions:
|
|
1199
|
+
if killOpt.startswith("jobSubStatus"):
|
|
1200
|
+
tmpJobSpec.jobSubStatus = killOpt.split("=")[-1]
|
|
1201
|
+
break
|
|
1202
|
+
# trigger ppE for ES jobs to properly trigger subsequent procedures
|
|
1203
|
+
ret = proxy.archiveJob(
|
|
1204
|
+
tmpJobSpec,
|
|
1205
|
+
tmpJobSpec.jobStatus in ["defined", "assigned"],
|
|
1206
|
+
)
|
|
1207
|
+
toKill = False
|
|
1208
|
+
userInfo = {"prodSourceLabel": None}
|
|
1209
|
+
if toKill:
|
|
1210
|
+
ret, userInfo = proxy.killJob(id, user, code, prodManager, True, wgProdRole, killOptions)
|
|
1211
|
+
rets.append(ret)
|
|
1212
|
+
if ret and userInfo["prodSourceLabel"] in ["user", "managed", "test"]:
|
|
1213
|
+
jobIDKey = (
|
|
1214
|
+
userInfo["prodUserID"],
|
|
1215
|
+
userInfo["jobDefinitionID"],
|
|
1216
|
+
userInfo["jobsetID"],
|
|
1217
|
+
)
|
|
1218
|
+
if jobIDKey not in pandaIDforCloserMap:
|
|
1219
|
+
pandaIDforCloserMap[jobIDKey] = id
|
|
1220
|
+
# run Closer
|
|
1221
|
+
try:
|
|
1222
|
+
if pandaIDforCloserMap != {}:
|
|
1223
|
+
for pandaIDforCloser in pandaIDforCloserMap.values():
|
|
1224
|
+
tmpJobs = self.peekJobs([pandaIDforCloser])
|
|
1225
|
+
tmpJob = tmpJobs[0]
|
|
1226
|
+
if tmpJob is not None:
|
|
1227
|
+
tmpDestDBlocks = []
|
|
1228
|
+
# get destDBlock
|
|
1229
|
+
for tmpFile in tmpJob.Files:
|
|
1230
|
+
if tmpFile.type in ["output", "log"]:
|
|
1231
|
+
if tmpFile.destinationDBlock not in tmpDestDBlocks:
|
|
1232
|
+
tmpDestDBlocks.append(tmpFile.destinationDBlock)
|
|
1233
|
+
# run
|
|
1234
|
+
closer_process = Closer(self, tmpDestDBlocks, tmpJob)
|
|
1235
|
+
closer_process.run()
|
|
1236
|
+
except Exception as e:
|
|
1237
|
+
tmp_log.error(f"failed with {str(e)} {traceback.format_exc()}")
|
|
1238
|
+
tmp_log.debug("done")
|
|
1239
|
+
return rets
|
|
1240
|
+
|
|
1241
|
+
# reassign jobs
|
|
1242
|
+
def reassignJobs(
|
|
1243
|
+
self,
|
|
1244
|
+
ids,
|
|
1245
|
+
attempt=0,
|
|
1246
|
+
joinThr=False,
|
|
1247
|
+
forPending=False,
|
|
1248
|
+
firstSubmission=True,
|
|
1249
|
+
):
|
|
1250
|
+
tmp_log = LogWrapper(_logger, "reassignJobs")
|
|
1251
|
+
tmp_log.debug(f"start for {len(ids)} IDs")
|
|
1252
|
+
# get DB proxy
|
|
1253
|
+
with self.proxyPool.get() as proxy:
|
|
1254
|
+
jobs = []
|
|
1255
|
+
# reset jobs
|
|
1256
|
+
n_reset_waiting = 0
|
|
1257
|
+
n_reset_defined = 0
|
|
1258
|
+
for tmp_id in ids:
|
|
1259
|
+
try:
|
|
1260
|
+
# try to reset a job in waiting table
|
|
1261
|
+
ret = proxy.resetJob(
|
|
1262
|
+
tmp_id,
|
|
1263
|
+
activeTable=False,
|
|
1264
|
+
forPending=True,
|
|
1265
|
+
)
|
|
1266
|
+
if ret is not None:
|
|
1267
|
+
jobs.append(ret)
|
|
1268
|
+
n_reset_waiting += 1
|
|
1269
|
+
# waiting jobs don't create sub or dis
|
|
1270
|
+
continue
|
|
1271
|
+
# try to reset a job in defined table
|
|
1272
|
+
ret = proxy.resetDefinedJob(tmp_id)
|
|
1273
|
+
if ret is not None:
|
|
1274
|
+
jobs.append(ret)
|
|
1275
|
+
n_reset_defined += 1
|
|
1276
|
+
continue
|
|
1277
|
+
except Exception as e:
|
|
1278
|
+
tmp_log.error(f"failed with {str(e)} {traceback.format_exc()}")
|
|
1279
|
+
tmp_log.debug(f"got {len(jobs)} IDs in total: {n_reset_waiting} from Waiting, {n_reset_defined} from Defined")
|
|
1280
|
+
# trigger subsequent agent
|
|
1281
|
+
if jobs:
|
|
1282
|
+
if joinThr:
|
|
1283
|
+
thr = Setupper(
|
|
1284
|
+
self,
|
|
1285
|
+
jobs,
|
|
1286
|
+
resubmit=True,
|
|
1287
|
+
first_submission=firstSubmission,
|
|
1288
|
+
)
|
|
1289
|
+
thr.start()
|
|
1290
|
+
thr.join()
|
|
1291
|
+
else:
|
|
1292
|
+
# cannot use 'thr =' because it may trigger a garbage collector
|
|
1293
|
+
Setupper(
|
|
1294
|
+
self,
|
|
1295
|
+
jobs,
|
|
1296
|
+
resubmit=True,
|
|
1297
|
+
first_submission=firstSubmission,
|
|
1298
|
+
).start()
|
|
1299
|
+
tmp_log.debug("done")
|
|
1300
|
+
|
|
1301
|
+
return True
|
|
1302
|
+
|
|
1303
|
+
# update input files and return corresponding PandaIDs
|
|
1304
|
+
def updateInFilesReturnPandaIDs(self, dataset, status, fileLFN=""):
|
|
1305
|
+
# get DBproxy
|
|
1306
|
+
with self.proxyPool.get() as proxy:
|
|
1307
|
+
retList = []
|
|
1308
|
+
# query PandaID
|
|
1309
|
+
retList = proxy.updateInFilesReturnPandaIDs(dataset, status, fileLFN)
|
|
1310
|
+
return retList
|
|
1311
|
+
|
|
1312
|
+
# update input files for jobs at certain sites and return corresponding PandaIDs
|
|
1313
|
+
def update_input_files_at_sites_and_get_panda_ids(self, filename: str, sites: list) -> list:
|
|
1314
|
+
with self.proxyPool.get() as proxy:
|
|
1315
|
+
ret = proxy.update_input_files_at_sites_and_get_panda_ids(filename, sites)
|
|
1316
|
+
return ret
|
|
1317
|
+
|
|
1318
|
+
# update output files and return corresponding PandaIDs
|
|
1319
|
+
def updateOutFilesReturnPandaIDs(self, dataset, fileLFN=""):
|
|
1320
|
+
# get DBproxy
|
|
1321
|
+
with self.proxyPool.get() as proxy:
|
|
1322
|
+
retList = []
|
|
1323
|
+
# query PandaID
|
|
1324
|
+
retList = proxy.updateOutFilesReturnPandaIDs(dataset, fileLFN)
|
|
1325
|
+
return retList
|
|
1326
|
+
|
|
1327
|
+
# get _dis datasets associated to _sub
|
|
1328
|
+
def getAssociatedDisDatasets(self, subDsName):
|
|
1329
|
+
# get DBproxy
|
|
1330
|
+
with self.proxyPool.get() as proxy:
|
|
1331
|
+
retList = []
|
|
1332
|
+
# query
|
|
1333
|
+
retList = proxy.getAssociatedDisDatasets(subDsName)
|
|
1334
|
+
return retList
|
|
1335
|
+
|
|
1336
|
+
# insert sandbox file info
|
|
1337
|
+
def insertSandboxFileInfo(self, userName, hostName, fileName, fileSize, checkSum):
|
|
1338
|
+
# get DBproxy
|
|
1339
|
+
with self.proxyPool.get() as proxy:
|
|
1340
|
+
# exec
|
|
1341
|
+
ret = proxy.insertSandboxFileInfo(userName, hostName, fileName, fileSize, checkSum)
|
|
1342
|
+
return ret
|
|
1343
|
+
|
|
1344
|
+
# get and lock sandbox files
|
|
1345
|
+
def getLockSandboxFiles(self, time_limit, n_files):
|
|
1346
|
+
# get DBproxy
|
|
1347
|
+
with self.proxyPool.get() as proxy:
|
|
1348
|
+
# exec
|
|
1349
|
+
ret = proxy.getLockSandboxFiles(time_limit, n_files)
|
|
1350
|
+
return ret
|
|
1351
|
+
|
|
1352
|
+
# check duplicated sandbox file
|
|
1353
|
+
def checkSandboxFile(self, userName, fileSize, checkSum):
|
|
1354
|
+
# get DBproxy
|
|
1355
|
+
with self.proxyPool.get() as proxy:
|
|
1356
|
+
# exec
|
|
1357
|
+
ret = proxy.checkSandboxFile(userName, fileSize, checkSum)
|
|
1358
|
+
return ret
|
|
1359
|
+
|
|
1360
|
+
# insert datasets
|
|
1361
|
+
def insertDatasets(self, datasets):
|
|
1362
|
+
# get DBproxy
|
|
1363
|
+
with self.proxyPool.get() as proxy:
|
|
1364
|
+
retList = []
|
|
1365
|
+
# insert
|
|
1366
|
+
for dataset in datasets:
|
|
1367
|
+
ret = proxy.insertDataset(dataset)
|
|
1368
|
+
retList.append(ret)
|
|
1369
|
+
return retList
|
|
1370
|
+
|
|
1371
|
+
# get and lock dataset with a query
|
|
1372
|
+
def getLockDatasets(self, sqlQuery, varMapGet, modTimeOffset="", getVersion=False):
|
|
1373
|
+
# get DBproxy
|
|
1374
|
+
with self.proxyPool.get() as proxy:
|
|
1375
|
+
# query Dataset
|
|
1376
|
+
ret = proxy.getLockDatasets(sqlQuery, varMapGet, modTimeOffset, getVersion)
|
|
1377
|
+
return ret
|
|
1378
|
+
|
|
1379
|
+
# query Dataset
|
|
1380
|
+
def queryDatasetWithMap(self, map):
|
|
1381
|
+
# get DBproxy
|
|
1382
|
+
with self.proxyPool.get() as proxy:
|
|
1383
|
+
# query Dataset
|
|
1384
|
+
ret = proxy.queryDatasetWithMap(map)
|
|
1385
|
+
return ret
|
|
1386
|
+
|
|
1387
|
+
# set GUIDs
|
|
1388
|
+
def setGUIDs(self, files):
|
|
1389
|
+
# get DBproxy
|
|
1390
|
+
with self.proxyPool.get() as proxy:
|
|
1391
|
+
# set GUIDs
|
|
1392
|
+
ret = proxy.setGUIDs(files)
|
|
1393
|
+
return ret
|
|
1394
|
+
|
|
1395
|
+
# update dataset
|
|
1396
|
+
def updateDatasets(self, datasets, withLock=False, withCriteria="", criteriaMap={}):
|
|
1397
|
+
# get DBproxy
|
|
1398
|
+
with self.proxyPool.get() as proxy:
|
|
1399
|
+
# update Dataset
|
|
1400
|
+
retList = proxy.updateDataset(datasets, withLock, withCriteria, criteriaMap)
|
|
1401
|
+
return retList
|
|
1402
|
+
|
|
1403
|
+
# trigger cleanup of internal datasets used by a task
|
|
1404
|
+
def trigger_cleanup_internal_datasets(self, task_id: int) -> bool:
|
|
1405
|
+
with self.proxyPool.get() as proxy:
|
|
1406
|
+
ret = proxy.trigger_cleanup_internal_datasets(task_id)
|
|
1407
|
+
return ret
|
|
1408
|
+
|
|
1409
|
+
# count the number of files with map
|
|
1410
|
+
def countFilesWithMap(self, map):
|
|
1411
|
+
# get DBproxy
|
|
1412
|
+
with self.proxyPool.get() as proxy:
|
|
1413
|
+
# query files
|
|
1414
|
+
ret = proxy.countFilesWithMap(map)
|
|
1415
|
+
return ret
|
|
1416
|
+
|
|
1417
|
+
# get serial number for dataset
|
|
1418
|
+
def getSerialNumber(self, datasetname, definedFreshFlag=None):
|
|
1419
|
+
# get DBproxy
|
|
1420
|
+
with self.proxyPool.get() as proxy:
|
|
1421
|
+
# get serial number
|
|
1422
|
+
ret = proxy.getSerialNumber(datasetname, definedFreshFlag)
|
|
1423
|
+
return ret
|
|
1424
|
+
|
|
1425
|
+
# add metadata
|
|
1426
|
+
def addMetadata(self, ids, metadataList, newStatusList):
|
|
1427
|
+
# get DBproxy
|
|
1428
|
+
with self.proxyPool.get() as proxy:
|
|
1429
|
+
# add metadata
|
|
1430
|
+
index = 0
|
|
1431
|
+
retList = []
|
|
1432
|
+
for id in ids:
|
|
1433
|
+
ret = proxy.addMetadata(id, metadataList[index], newStatusList[index])
|
|
1434
|
+
retList.append(ret)
|
|
1435
|
+
index += 1
|
|
1436
|
+
return retList
|
|
1437
|
+
|
|
1438
|
+
# add stdout
|
|
1439
|
+
def addStdOut(self, id, stdout):
|
|
1440
|
+
# get DBproxy
|
|
1441
|
+
with self.proxyPool.get() as proxy:
|
|
1442
|
+
# add
|
|
1443
|
+
ret = proxy.addStdOut(id, stdout)
|
|
1444
|
+
return ret
|
|
1445
|
+
|
|
1446
|
+
# extract scope from dataset name
|
|
1447
|
+
def extractScope(self, name):
|
|
1448
|
+
# get DBproxy
|
|
1449
|
+
with self.proxyPool.get() as proxy:
|
|
1450
|
+
# get
|
|
1451
|
+
ret = proxy.extractScope(name)
|
|
1452
|
+
return ret
|
|
1453
|
+
|
|
1454
|
+
# get job statistics
|
|
1455
|
+
def getJobStatistics(self):
|
|
1456
|
+
# get DBproxy
|
|
1457
|
+
with self.proxyPool.get() as proxy:
|
|
1458
|
+
# get serial number
|
|
1459
|
+
ret = proxy.getJobStatistics()
|
|
1460
|
+
return ret
|
|
1461
|
+
|
|
1462
|
+
# get detailed job statistics with resource_type and prodsourcelabel
|
|
1463
|
+
def getDetailedJobStatistics(self):
|
|
1464
|
+
with self.proxyPool.get() as proxy:
|
|
1465
|
+
ret = proxy.getDetailedJobStatistics()
|
|
1466
|
+
return ret
|
|
1467
|
+
|
|
1468
|
+
# get job statistics for ExtIF. Source type is analysis or production
|
|
1469
|
+
def getJobStatisticsForExtIF(self, sourcetype=None):
|
|
1470
|
+
# get DBproxy
|
|
1471
|
+
with self.proxyPool.get() as proxy:
|
|
1472
|
+
# get serial number
|
|
1473
|
+
ret = proxy.getJobStatisticsForExtIF(sourcetype)
|
|
1474
|
+
return ret
|
|
1475
|
+
|
|
1476
|
+
# get job statistics for Bamboo
|
|
1477
|
+
def getJobStatisticsForBamboo(self):
|
|
1478
|
+
# get DBproxy
|
|
1479
|
+
with self.proxyPool.get() as proxy:
|
|
1480
|
+
# get serial number
|
|
1481
|
+
ret = proxy.getJobStatisticsPerProcessingType()
|
|
1482
|
+
return ret
|
|
1483
|
+
|
|
1484
|
+
# update site data
|
|
1485
|
+
def updateSiteData(self, hostID, pilotRequests, interval=3):
|
|
1486
|
+
# get DBproxy
|
|
1487
|
+
with self.proxyPool.get() as proxy:
|
|
1488
|
+
# get serial number
|
|
1489
|
+
ret = proxy.updateSiteData(hostID, pilotRequests, interval)
|
|
1490
|
+
return ret
|
|
1491
|
+
|
|
1492
|
+
# get current site data
|
|
1493
|
+
def getCurrentSiteData(self):
|
|
1494
|
+
# get DBproxy
|
|
1495
|
+
with self.proxyPool.get() as proxy:
|
|
1496
|
+
# get serial number
|
|
1497
|
+
ret = proxy.getCurrentSiteData()
|
|
1498
|
+
return ret
|
|
1499
|
+
|
|
1500
|
+
# insert nRunning in site data
|
|
1501
|
+
def insertnRunningInSiteData(self):
|
|
1502
|
+
# get DBproxy
|
|
1503
|
+
with self.proxyPool.get() as proxy:
|
|
1504
|
+
# get serial number
|
|
1505
|
+
ret = proxy.insertnRunningInSiteData()
|
|
1506
|
+
return ret
|
|
1507
|
+
|
|
1508
|
+
# get site info
|
|
1509
|
+
def getSiteInfo(self):
|
|
1510
|
+
# get DBproxy
|
|
1511
|
+
with self.proxyPool.get() as proxy:
|
|
1512
|
+
# get site info
|
|
1513
|
+
ret = proxy.getSiteInfo()
|
|
1514
|
+
return ret
|
|
1515
|
+
|
|
1516
|
+
# get cloud list
|
|
1517
|
+
def get_cloud_list(self):
|
|
1518
|
+
# get DBproxy
|
|
1519
|
+
with self.proxyPool.get() as proxy:
|
|
1520
|
+
# get cloud list
|
|
1521
|
+
ret = proxy.get_cloud_list()
|
|
1522
|
+
return ret
|
|
1523
|
+
|
|
1524
|
+
# get special dispatcher parameters
|
|
1525
|
+
def get_special_dispatch_params(self):
|
|
1526
|
+
# get DBproxy
|
|
1527
|
+
with self.proxyPool.get() as proxy:
|
|
1528
|
+
# exec
|
|
1529
|
+
ret = proxy.get_special_dispatch_params()
|
|
1530
|
+
return ret
|
|
1531
|
+
|
|
1532
|
+
# get email address
|
|
1533
|
+
def getEmailAddr(self, name, withDN=False, withUpTime=False):
|
|
1534
|
+
# get DBproxy
|
|
1535
|
+
with self.proxyPool.get() as proxy:
|
|
1536
|
+
# get
|
|
1537
|
+
ret = proxy.getEmailAddr(name, withDN, withUpTime)
|
|
1538
|
+
return ret
|
|
1539
|
+
|
|
1540
|
+
# set email address for a user
|
|
1541
|
+
def setEmailAddr(self, userName, emailAddr):
|
|
1542
|
+
# get DBproxy
|
|
1543
|
+
with self.proxyPool.get() as proxy:
|
|
1544
|
+
# set
|
|
1545
|
+
ret = proxy.setEmailAddr(userName, emailAddr)
|
|
1546
|
+
return ret
|
|
1547
|
+
|
|
1548
|
+
# get banned users
|
|
1549
|
+
def get_ban_users(self):
|
|
1550
|
+
# get DBproxy
|
|
1551
|
+
with self.proxyPool.get() as proxy:
|
|
1552
|
+
# get
|
|
1553
|
+
ret = proxy.get_ban_users()
|
|
1554
|
+
return ret
|
|
1555
|
+
|
|
1556
|
+
# register a token key
|
|
1557
|
+
def register_token_key(self, client_name, lifetime):
|
|
1558
|
+
# get DBproxy
|
|
1559
|
+
with self.proxyPool.get() as proxy:
|
|
1560
|
+
# register proxy key
|
|
1561
|
+
ret = proxy.register_token_key(client_name, lifetime)
|
|
1562
|
+
return ret
|
|
1563
|
+
|
|
1564
|
+
# query an SQL return Status
|
|
1565
|
+
def querySQLS(self, sql, varMap, arraySize=1000):
|
|
1566
|
+
# get DBproxy
|
|
1567
|
+
with self.proxyPool.get() as proxy:
|
|
1568
|
+
# get
|
|
1569
|
+
ret = proxy.querySQLS(sql, varMap, arraySize)
|
|
1570
|
+
return ret
|
|
1571
|
+
|
|
1572
|
+
# query an SQL
|
|
1573
|
+
def querySQL(self, sql, varMap, arraySize=1000):
|
|
1574
|
+
# get DBproxy
|
|
1575
|
+
with self.proxyPool.get() as proxy:
|
|
1576
|
+
# get
|
|
1577
|
+
ret = proxy.querySQLS(sql, varMap, arraySize)[1]
|
|
1578
|
+
return ret
|
|
1579
|
+
|
|
1580
|
+
# execute an SQL return with executemany
|
|
1581
|
+
def executemanySQL(self, sql, varMaps, arraySize=1000):
|
|
1582
|
+
# get DBproxy
|
|
1583
|
+
with self.proxyPool.get() as proxy:
|
|
1584
|
+
# get
|
|
1585
|
+
ret = proxy.executemanySQL(sql, varMaps, arraySize)
|
|
1586
|
+
return ret
|
|
1587
|
+
|
|
1588
|
+
# check quota
|
|
1589
|
+
def checkQuota(self, dn):
|
|
1590
|
+
# query an SQL return Status
|
|
1591
|
+
with self.proxyPool.get() as proxy:
|
|
1592
|
+
# get
|
|
1593
|
+
ret = proxy.checkQuota(dn)
|
|
1594
|
+
return ret
|
|
1595
|
+
|
|
1596
|
+
# insert TaskParams
|
|
1597
|
+
def insertTaskParamsPanda(self, taskParams, user, prodRole, fqans=[], parent_tid=None, properErrorCode=False, allowActiveTask=False, decode=True):
|
|
1598
|
+
# query an SQL return Status
|
|
1599
|
+
with self.proxyPool.get() as proxy:
|
|
1600
|
+
# check user status
|
|
1601
|
+
tmpStatus = proxy.checkBanUser(user, None, True)
|
|
1602
|
+
if tmpStatus is True:
|
|
1603
|
+
# exec
|
|
1604
|
+
ret = proxy.insertTaskParamsPanda(taskParams, user, prodRole, fqans, parent_tid, properErrorCode, allowActiveTask, decode)
|
|
1605
|
+
elif tmpStatus == 1:
|
|
1606
|
+
ret = False, "Failed to update DN in PandaDB"
|
|
1607
|
+
elif tmpStatus == 2:
|
|
1608
|
+
ret = False, "Failed to insert user info to PandaDB"
|
|
1609
|
+
else:
|
|
1610
|
+
ret = False, f"The following DN is banned: DN={user}"
|
|
1611
|
+
return ret
|
|
1612
|
+
|
|
1613
|
+
# send command to task
|
|
1614
|
+
def sendCommandTaskPanda(
|
|
1615
|
+
self,
|
|
1616
|
+
jediTaskID,
|
|
1617
|
+
dn,
|
|
1618
|
+
prodRole,
|
|
1619
|
+
comStr,
|
|
1620
|
+
comComment=None,
|
|
1621
|
+
useCommit=True,
|
|
1622
|
+
properErrorCode=False,
|
|
1623
|
+
comQualifier=None,
|
|
1624
|
+
broadcast=False,
|
|
1625
|
+
):
|
|
1626
|
+
# query an SQL return Status
|
|
1627
|
+
with self.proxyPool.get() as proxy:
|
|
1628
|
+
# exec
|
|
1629
|
+
ret = proxy.sendCommandTaskPanda(
|
|
1630
|
+
jediTaskID,
|
|
1631
|
+
dn,
|
|
1632
|
+
prodRole,
|
|
1633
|
+
comStr,
|
|
1634
|
+
comComment,
|
|
1635
|
+
useCommit,
|
|
1636
|
+
properErrorCode,
|
|
1637
|
+
comQualifier,
|
|
1638
|
+
broadcast,
|
|
1639
|
+
)
|
|
1640
|
+
return ret
|
|
1641
|
+
|
|
1642
|
+
# update unmerged datasets to trigger merging
|
|
1643
|
+
def updateUnmergedDatasets(self, job, finalStatusDS, updateCompleted=False):
|
|
1644
|
+
# get proxy
|
|
1645
|
+
with self.proxyPool.get() as proxy:
|
|
1646
|
+
# exec
|
|
1647
|
+
ret = proxy.updateUnmergedDatasets(job, finalStatusDS, updateCompleted)
|
|
1648
|
+
return ret
|
|
1649
|
+
|
|
1650
|
+
# get active JediTasks in a time range
|
|
1651
|
+
def getJediTasksInTimeRange(self, dn, timeRangeStr, fullFlag=False, minTaskID=None, task_type="user"):
|
|
1652
|
+
# check DN
|
|
1653
|
+
if dn in ["NULL", "", "None", None]:
|
|
1654
|
+
return {}
|
|
1655
|
+
# check timeRange
|
|
1656
|
+
match = re.match("^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$", timeRangeStr)
|
|
1657
|
+
if match is None:
|
|
1658
|
+
return {}
|
|
1659
|
+
timeRange = datetime.datetime(
|
|
1660
|
+
year=int(match.group(1)),
|
|
1661
|
+
month=int(match.group(2)),
|
|
1662
|
+
day=int(match.group(3)),
|
|
1663
|
+
hour=int(match.group(4)),
|
|
1664
|
+
minute=int(match.group(5)),
|
|
1665
|
+
second=int(match.group(6)),
|
|
1666
|
+
)
|
|
1667
|
+
# max range is 3 months
|
|
1668
|
+
maxRange = naive_utcnow() - datetime.timedelta(days=30)
|
|
1669
|
+
if timeRange < maxRange:
|
|
1670
|
+
timeRange = maxRange
|
|
1671
|
+
# get proxy
|
|
1672
|
+
with self.proxyPool.get() as proxy:
|
|
1673
|
+
# exec
|
|
1674
|
+
ret = proxy.getJediTasksInTimeRange(dn, timeRange, fullFlag, minTaskID, task_type)
|
|
1675
|
+
return ret
|
|
1676
|
+
|
|
1677
|
+
# get details of JediTask
|
|
1678
|
+
def getJediTaskDetails(self, jediTaskID, fullFlag, withTaskInfo):
|
|
1679
|
+
# get proxy
|
|
1680
|
+
with self.proxyPool.get() as proxy:
|
|
1681
|
+
# exec
|
|
1682
|
+
ret = proxy.getJediTaskDetails(jediTaskID, fullFlag, withTaskInfo)
|
|
1683
|
+
return ret
|
|
1684
|
+
|
|
1685
|
+
# get task details as a plain dict (read-only, no lock)
|
|
1686
|
+
def get_task_details_json(self, jedi_task_id, resolve_parent=False, include_resolve_status=False):
|
|
1687
|
+
with self.proxyPool.get() as proxy:
|
|
1688
|
+
return proxy.get_task_details_json(
|
|
1689
|
+
jedi_task_id,
|
|
1690
|
+
resolve_parent=resolve_parent,
|
|
1691
|
+
include_resolve_status=include_resolve_status,
|
|
1692
|
+
)
|
|
1693
|
+
|
|
1694
|
+
# get a list of even ranges for a PandaID
|
|
1695
|
+
def getEventRanges(self, pandaID, jobsetID, jediTaskID, nRanges, acceptJson, scattered, segment_id):
|
|
1696
|
+
# get proxy
|
|
1697
|
+
with self.proxyPool.get() as proxy:
|
|
1698
|
+
# exec
|
|
1699
|
+
ret = proxy.getEventRanges(pandaID, jobsetID, jediTaskID, nRanges, acceptJson, scattered, segment_id)
|
|
1700
|
+
return ret
|
|
1701
|
+
|
|
1702
|
+
# update an even range
|
|
1703
|
+
def updateEventRange(self, eventRangeID, eventStatus, cpuCore, cpuConsumptionTime, objstoreID=None):
|
|
1704
|
+
eventDict = {}
|
|
1705
|
+
eventDict["eventRangeID"] = eventRangeID
|
|
1706
|
+
eventDict["eventStatus"] = eventStatus
|
|
1707
|
+
eventDict["cpuCore"] = cpuCore
|
|
1708
|
+
eventDict["cpuConsumptionTime"] = cpuConsumptionTime
|
|
1709
|
+
eventDict["objstoreID"] = objstoreID
|
|
1710
|
+
# get proxy
|
|
1711
|
+
with self.proxyPool.get() as proxy:
|
|
1712
|
+
# exec
|
|
1713
|
+
ret = proxy.updateEventRanges([eventDict])
|
|
1714
|
+
# extract return
|
|
1715
|
+
try:
|
|
1716
|
+
retVal = ret[0][0]
|
|
1717
|
+
except Exception:
|
|
1718
|
+
retVal = False
|
|
1719
|
+
|
|
1720
|
+
return retVal, json.dumps(ret[1])
|
|
1721
|
+
|
|
1722
|
+
# update even ranges
|
|
1723
|
+
def updateEventRanges(self, eventRanges, version=0):
|
|
1724
|
+
# decode json
|
|
1725
|
+
try:
|
|
1726
|
+
eventRanges = json.loads(eventRanges)
|
|
1727
|
+
except Exception:
|
|
1728
|
+
return json.dumps("ERROR : failed to convert eventRanges with json")
|
|
1729
|
+
# get proxy
|
|
1730
|
+
with self.proxyPool.get() as proxy:
|
|
1731
|
+
# exec
|
|
1732
|
+
ret = proxy.updateEventRanges(eventRanges, version)
|
|
1733
|
+
if version != 0:
|
|
1734
|
+
return ret
|
|
1735
|
+
return json.dumps(ret[0]), json.dumps(ret[1])
|
|
1736
|
+
|
|
1737
|
+
# change task priority
|
|
1738
|
+
def changeTaskPriorityPanda(self, jediTaskID, newPriority):
|
|
1739
|
+
# get proxy
|
|
1740
|
+
with self.proxyPool.get() as proxy:
|
|
1741
|
+
# exec
|
|
1742
|
+
ret = proxy.changeTaskPriorityPanda(jediTaskID, newPriority)
|
|
1743
|
+
return ret
|
|
1744
|
+
|
|
1745
|
+
# throttle user jobs
|
|
1746
|
+
def throttleUserJobs(self, prodUserName, workingGroup, get_dict=False):
|
|
1747
|
+
# get proxy
|
|
1748
|
+
with self.proxyPool.get() as proxy:
|
|
1749
|
+
# exec
|
|
1750
|
+
ret = proxy.throttleUserJobs(prodUserName, workingGroup, get_dict)
|
|
1751
|
+
return ret
|
|
1752
|
+
|
|
1753
|
+
# unthrottle user jobs
|
|
1754
|
+
def unThrottleUserJobs(self, prodUserName, workingGroup, get_dict=False):
|
|
1755
|
+
# get proxy
|
|
1756
|
+
with self.proxyPool.get() as proxy:
|
|
1757
|
+
# exec
|
|
1758
|
+
ret = proxy.unThrottleUserJobs(prodUserName, workingGroup, get_dict)
|
|
1759
|
+
return ret
|
|
1760
|
+
|
|
1761
|
+
# get throttled users
|
|
1762
|
+
def getThrottledUsers(self):
|
|
1763
|
+
# get proxy
|
|
1764
|
+
with self.proxyPool.get() as proxy:
|
|
1765
|
+
# exec
|
|
1766
|
+
ret = proxy.getThrottledUsers()
|
|
1767
|
+
return ret
|
|
1768
|
+
|
|
1769
|
+
# get the list of jobdefIDs for failed jobs in a task
|
|
1770
|
+
def getJobdefIDsForFailedJob(self, jediTaskID):
|
|
1771
|
+
# get proxy
|
|
1772
|
+
with self.proxyPool.get() as proxy:
|
|
1773
|
+
# exec
|
|
1774
|
+
ret = proxy.getJobdefIDsForFailedJob(jediTaskID)
|
|
1775
|
+
return ret
|
|
1776
|
+
|
|
1777
|
+
# change task attribute
|
|
1778
|
+
def changeTaskAttributePanda(self, jediTaskID, attrName, attrValue):
|
|
1779
|
+
# get proxy
|
|
1780
|
+
with self.proxyPool.get() as proxy:
|
|
1781
|
+
# exec
|
|
1782
|
+
ret = proxy.changeTaskAttributePanda(jediTaskID, attrName, attrValue)
|
|
1783
|
+
return ret
|
|
1784
|
+
|
|
1785
|
+
# change split rule for task
|
|
1786
|
+
def changeTaskSplitRulePanda(self, jediTaskID, attrName, attrValue):
|
|
1787
|
+
# get proxy
|
|
1788
|
+
with self.proxyPool.get() as proxy:
|
|
1789
|
+
# exec
|
|
1790
|
+
ret = proxy.changeTaskSplitRulePanda(jediTaskID, attrName, attrValue)
|
|
1791
|
+
return ret
|
|
1792
|
+
|
|
1793
|
+
# increase attempt number for unprocessed files
|
|
1794
|
+
def increaseAttemptNrPanda(self, jediTaskID, increasedNr):
|
|
1795
|
+
# get proxy
|
|
1796
|
+
with self.proxyPool.get() as proxy:
|
|
1797
|
+
# exec
|
|
1798
|
+
ret = proxy.increaseAttemptNrPanda(jediTaskID, increasedNr)
|
|
1799
|
+
return ret
|
|
1800
|
+
|
|
1801
|
+
# get jediTaskID from taskName
|
|
1802
|
+
def getTaskIDwithTaskNameJEDI(self, userName, taskName):
|
|
1803
|
+
# get proxy
|
|
1804
|
+
with self.proxyPool.get() as proxy:
|
|
1805
|
+
# exec
|
|
1806
|
+
ret = proxy.getTaskIDwithTaskNameJEDI(userName, taskName)
|
|
1807
|
+
return ret
|
|
1808
|
+
|
|
1809
|
+
# update error dialog for a jediTaskID
|
|
1810
|
+
def updateTaskErrorDialogJEDI(self, jediTaskID, msg):
|
|
1811
|
+
# get proxy
|
|
1812
|
+
with self.proxyPool.get() as proxy:
|
|
1813
|
+
# exec
|
|
1814
|
+
ret = proxy.updateTaskErrorDialogJEDI(jediTaskID, msg)
|
|
1815
|
+
return ret
|
|
1816
|
+
|
|
1817
|
+
# update modificationtime for a jediTaskID to trigger subsequent process
|
|
1818
|
+
def updateTaskModTimeJEDI(self, jediTaskID, newStatus=None):
|
|
1819
|
+
# get proxy
|
|
1820
|
+
with self.proxyPool.get() as proxy:
|
|
1821
|
+
# exec
|
|
1822
|
+
ret = proxy.updateTaskModTimeJEDI(jediTaskID, newStatus)
|
|
1823
|
+
return ret
|
|
1824
|
+
|
|
1825
|
+
# check input file status
|
|
1826
|
+
def checkInputFileStatusInJEDI(self, jobSpec):
|
|
1827
|
+
# get proxy
|
|
1828
|
+
with self.proxyPool.get() as proxy:
|
|
1829
|
+
# exec
|
|
1830
|
+
ret = proxy.checkInputFileStatusInJEDI(jobSpec)
|
|
1831
|
+
return ret
|
|
1832
|
+
|
|
1833
|
+
# increase memory limit
|
|
1834
|
+
def increaseRamLimitJEDI(self, jediTaskID, jobRamCount):
|
|
1835
|
+
# get proxy
|
|
1836
|
+
with self.proxyPool.get() as proxy:
|
|
1837
|
+
# exec
|
|
1838
|
+
ret = proxy.increaseRamLimitJEDI(jediTaskID, jobRamCount)
|
|
1839
|
+
return ret
|
|
1840
|
+
|
|
1841
|
+
# increase memory limit
|
|
1842
|
+
def increaseRamLimitJobJEDI(self, job, jobRamCount, jediTaskID):
|
|
1843
|
+
# get proxy
|
|
1844
|
+
with self.proxyPool.get() as proxy:
|
|
1845
|
+
# exec
|
|
1846
|
+
ret = proxy.increaseRamLimitJobJEDI(job, jobRamCount, jediTaskID)
|
|
1847
|
+
return ret
|
|
1848
|
+
|
|
1849
|
+
# increase memory limit xtimes
|
|
1850
|
+
def increaseRamLimitJobJEDI_xtimes(self, job, jobRamCount, jediTaskID, attemptNr):
|
|
1851
|
+
# get proxy
|
|
1852
|
+
with self.proxyPool.get() as proxy:
|
|
1853
|
+
# exec
|
|
1854
|
+
ret = proxy.increaseRamLimitJobJEDI_xtimes(job, jobRamCount, jediTaskID, attemptNr)
|
|
1855
|
+
return ret
|
|
1856
|
+
|
|
1857
|
+
# reduce input per job
|
|
1858
|
+
def reduce_input_per_job(self, panda_id, jedi_task_id, attempt_nr, excluded_rules, steps, dry_mode=False):
|
|
1859
|
+
# get proxy
|
|
1860
|
+
with self.proxyPool.get() as proxy:
|
|
1861
|
+
# exec
|
|
1862
|
+
ret = proxy.reduce_input_per_job(panda_id, jedi_task_id, attempt_nr, excluded_rules, steps, dry_mode)
|
|
1863
|
+
return ret
|
|
1864
|
+
|
|
1865
|
+
# reset files in JEDI
|
|
1866
|
+
def resetFileStatusInJEDI(self, dn, prodManager, datasetName, lostFiles, recoverParent, simul=False):
|
|
1867
|
+
# get proxy
|
|
1868
|
+
with self.proxyPool.get() as proxy:
|
|
1869
|
+
# exec
|
|
1870
|
+
ret = proxy.resetFileStatusInJEDI(dn, prodManager, datasetName, lostFiles, recoverParent, simul)
|
|
1871
|
+
return ret
|
|
1872
|
+
|
|
1873
|
+
# copy file records
|
|
1874
|
+
def copy_file_records(self, new_lfns, file_spec):
|
|
1875
|
+
# get proxy
|
|
1876
|
+
with self.proxyPool.get() as proxy:
|
|
1877
|
+
# exec
|
|
1878
|
+
ret = proxy.copy_file_records(new_lfns, file_spec)
|
|
1879
|
+
return ret
|
|
1880
|
+
|
|
1881
|
+
# retry module: get the defined rules
|
|
1882
|
+
def getRetrialRules(self):
|
|
1883
|
+
# get proxy
|
|
1884
|
+
with self.proxyPool.get() as proxy:
|
|
1885
|
+
# exec
|
|
1886
|
+
ret = proxy.getRetrialRules()
|
|
1887
|
+
return ret
|
|
1888
|
+
|
|
1889
|
+
# retry module action: set max number of retries
|
|
1890
|
+
def setMaxAttempt(self, jobID, jediTaskID, files, attemptNr):
|
|
1891
|
+
# get proxy
|
|
1892
|
+
with self.proxyPool.get() as proxy:
|
|
1893
|
+
# exec
|
|
1894
|
+
ret = proxy.setMaxAttempt(jobID, jediTaskID, files, attemptNr)
|
|
1895
|
+
return ret
|
|
1896
|
+
|
|
1897
|
+
# error classification action: increase by one the max number of retries
|
|
1898
|
+
def increase_max_failure(self, job_id, task_id, files):
|
|
1899
|
+
# get proxy
|
|
1900
|
+
with self.proxyPool.get() as proxy:
|
|
1901
|
+
# exec
|
|
1902
|
+
ret = proxy.increase_max_failure(job_id, task_id, files)
|
|
1903
|
+
return ret
|
|
1904
|
+
|
|
1905
|
+
# retry module action: set maxAttempt to the current attemptNr to avoid further retries
|
|
1906
|
+
def setNoRetry(self, jobID, jediTaskID, files):
|
|
1907
|
+
# get proxy
|
|
1908
|
+
with self.proxyPool.get() as proxy:
|
|
1909
|
+
# exec
|
|
1910
|
+
ret = proxy.setNoRetry(jobID, jediTaskID, files)
|
|
1911
|
+
return ret
|
|
1912
|
+
|
|
1913
|
+
# retry module action: increase CPU Time
|
|
1914
|
+
def initialize_cpu_time_task(self, jobID, taskID, siteid, files, active):
|
|
1915
|
+
# get proxy
|
|
1916
|
+
with self.proxyPool.get() as proxy:
|
|
1917
|
+
# exec
|
|
1918
|
+
ret = proxy.initialize_cpu_time_task(jobID, taskID, siteid, files, active)
|
|
1919
|
+
return ret
|
|
1920
|
+
|
|
1921
|
+
# retry module action: recalculate the Task Parameters
|
|
1922
|
+
def requestTaskParameterRecalculation(self, taskID):
|
|
1923
|
+
# get proxy
|
|
1924
|
+
with self.proxyPool.get() as proxy:
|
|
1925
|
+
# exec
|
|
1926
|
+
ret = proxy.requestTaskParameterRecalculation(taskID)
|
|
1927
|
+
return ret
|
|
1928
|
+
|
|
1929
|
+
# add associate sub datasets for single consumer job
|
|
1930
|
+
def getDestDBlocksWithSingleConsumer(self, jediTaskID, PandaID, ngDatasets):
|
|
1931
|
+
# get proxy
|
|
1932
|
+
with self.proxyPool.get() as proxy:
|
|
1933
|
+
# exec
|
|
1934
|
+
ret = proxy.getDestDBlocksWithSingleConsumer(jediTaskID, PandaID, ngDatasets)
|
|
1935
|
+
return ret
|
|
1936
|
+
|
|
1937
|
+
# check validity of merge job
|
|
1938
|
+
def isValidMergeJob(self, pandaID, jediTaskID):
|
|
1939
|
+
# get proxy
|
|
1940
|
+
with self.proxyPool.get() as proxy:
|
|
1941
|
+
# exec
|
|
1942
|
+
ret = proxy.isValidMergeJob(pandaID, jediTaskID)
|
|
1943
|
+
return ret
|
|
1944
|
+
|
|
1945
|
+
# Configurator: insert network matrix data
|
|
1946
|
+
def insertNetworkMatrixData(self, data):
|
|
1947
|
+
# get proxy
|
|
1948
|
+
with self.proxyPool.get() as proxy:
|
|
1949
|
+
# exec
|
|
1950
|
+
ret = proxy.insertNetworkMatrixData(data)
|
|
1951
|
+
return ret
|
|
1952
|
+
|
|
1953
|
+
# Configurator: delete old network matrix data
|
|
1954
|
+
def deleteOldNetworkData(self):
|
|
1955
|
+
# get proxy
|
|
1956
|
+
with self.proxyPool.get() as proxy:
|
|
1957
|
+
# exec
|
|
1958
|
+
ret = proxy.deleteOldNetworkData()
|
|
1959
|
+
return ret
|
|
1960
|
+
|
|
1961
|
+
# get dispatch datasets per user
|
|
1962
|
+
def getDispatchDatasetsPerUser(self, vo, prodSourceLabel, onlyActive, withSize):
|
|
1963
|
+
# get proxy
|
|
1964
|
+
with self.proxyPool.get() as proxy:
|
|
1965
|
+
# exec
|
|
1966
|
+
ret = proxy.getDispatchDatasetsPerUser(vo, prodSourceLabel, onlyActive, withSize)
|
|
1967
|
+
return ret
|
|
1968
|
+
|
|
1969
|
+
# get task parameters
|
|
1970
|
+
def getTaskParamsPanda(self, jediTaskID):
|
|
1971
|
+
# get proxy
|
|
1972
|
+
with self.proxyPool.get() as proxy:
|
|
1973
|
+
# exec
|
|
1974
|
+
ret = proxy.getTaskParamsPanda(jediTaskID)
|
|
1975
|
+
return ret
|
|
1976
|
+
|
|
1977
|
+
# get task attributes
|
|
1978
|
+
def getTaskAttributesPanda(self, jediTaskID, attrs):
|
|
1979
|
+
# get proxy
|
|
1980
|
+
with self.proxyPool.get() as proxy:
|
|
1981
|
+
# exec
|
|
1982
|
+
ret = proxy.getTaskAttributesPanda(jediTaskID, attrs)
|
|
1983
|
+
return ret
|
|
1984
|
+
|
|
1985
|
+
# check for cloned jobs
|
|
1986
|
+
def checkClonedJob(self, jobSpec):
|
|
1987
|
+
# get proxy
|
|
1988
|
+
with self.proxyPool.get() as proxy:
|
|
1989
|
+
# exec
|
|
1990
|
+
ret = proxy.checkClonedJob(jobSpec)
|
|
1991
|
+
return ret
|
|
1992
|
+
|
|
1993
|
+
# get co-jumbo jobs to be finished
|
|
1994
|
+
def getCoJumboJobsToBeFinished(self, timeLimit, minPriority, maxJobs):
|
|
1995
|
+
# get proxy
|
|
1996
|
+
with self.proxyPool.get() as proxy:
|
|
1997
|
+
# exec
|
|
1998
|
+
ret = proxy.getCoJumboJobsToBeFinished(timeLimit, minPriority, maxJobs)
|
|
1999
|
+
return ret
|
|
2000
|
+
|
|
2001
|
+
# get number of events to be processed
|
|
2002
|
+
def getNumReadyEvents(self, jediTaskID):
|
|
2003
|
+
# get proxy
|
|
2004
|
+
with self.proxyPool.get() as proxy:
|
|
2005
|
+
# exec
|
|
2006
|
+
ret = proxy.getNumReadyEvents(jediTaskID)
|
|
2007
|
+
return ret
|
|
2008
|
+
|
|
2009
|
+
# check if task is applicable for jumbo jobs
|
|
2010
|
+
def isApplicableTaskForJumbo(self, jediTaskID):
|
|
2011
|
+
# get proxy
|
|
2012
|
+
with self.proxyPool.get() as proxy:
|
|
2013
|
+
# exec
|
|
2014
|
+
ret = proxy.isApplicableTaskForJumbo(jediTaskID)
|
|
2015
|
+
return ret
|
|
2016
|
+
|
|
2017
|
+
# cleanup jumbo jobs
|
|
2018
|
+
def cleanupJumboJobs(self, jediTaskID=None):
|
|
2019
|
+
# get proxy
|
|
2020
|
+
with self.proxyPool.get() as proxy:
|
|
2021
|
+
# exec
|
|
2022
|
+
ret = proxy.cleanupJumboJobs(jediTaskID)
|
|
2023
|
+
return ret
|
|
2024
|
+
|
|
2025
|
+
# convert ObjID to endpoint
|
|
2026
|
+
def convertObjIDtoEndPoint(self, srcFileName, ObjID):
|
|
2027
|
+
# get DB proxy
|
|
2028
|
+
with self.proxyPool.get() as proxy:
|
|
2029
|
+
# exec
|
|
2030
|
+
res = proxy.convertObjIDtoEndPoint(srcFileName, ObjID)
|
|
2031
|
+
return res
|
|
2032
|
+
|
|
2033
|
+
# get task status
|
|
2034
|
+
def getTaskStatus(self, jediTaskID):
|
|
2035
|
+
# get DB proxy
|
|
2036
|
+
with self.proxyPool.get() as proxy:
|
|
2037
|
+
# exec
|
|
2038
|
+
res = proxy.getTaskStatus(jediTaskID)
|
|
2039
|
+
return res
|
|
2040
|
+
|
|
2041
|
+
# get task status and superstatus
|
|
2042
|
+
def getTaskStatusSuperstatus(self, jediTaskID):
|
|
2043
|
+
# get DB proxy
|
|
2044
|
+
with self.proxyPool.get() as proxy:
|
|
2045
|
+
# exec
|
|
2046
|
+
res = proxy.getTaskStatusSuperstatus(jediTaskID)
|
|
2047
|
+
return res
|
|
2048
|
+
|
|
2049
|
+
# reactivate task
|
|
2050
|
+
def reactivateTask(self, jediTaskID, keep_attempt_nr=False, trigger_job_generation=False):
|
|
2051
|
+
# get DB proxy
|
|
2052
|
+
with self.proxyPool.get() as proxy:
|
|
2053
|
+
# exec
|
|
2054
|
+
res = proxy.reactivateTask(jediTaskID, keep_attempt_nr, trigger_job_generation)
|
|
2055
|
+
return res
|
|
2056
|
+
|
|
2057
|
+
# get event statistics
|
|
2058
|
+
def getEventStat(self, jediTaskID, PandaID):
|
|
2059
|
+
# get DB proxy
|
|
2060
|
+
with self.proxyPool.get() as proxy:
|
|
2061
|
+
# exec
|
|
2062
|
+
res = proxy.getEventStat(jediTaskID, PandaID)
|
|
2063
|
+
return res
|
|
2064
|
+
|
|
2065
|
+
# get nested dict of gshare names implying the tree structure
|
|
2066
|
+
def get_tree_of_gshare_names(self):
|
|
2067
|
+
# get DB proxy
|
|
2068
|
+
with self.proxyPool.get() as proxy:
|
|
2069
|
+
# exec
|
|
2070
|
+
res = proxy.get_tree_of_gshare_names()
|
|
2071
|
+
return res
|
|
2072
|
+
|
|
2073
|
+
# get the HS06 distribution for global shares
|
|
2074
|
+
def get_hs_distribution(self):
|
|
2075
|
+
# get DB proxy
|
|
2076
|
+
with self.proxyPool.get() as proxy:
|
|
2077
|
+
# exec
|
|
2078
|
+
res = proxy.get_hs_distribution()
|
|
2079
|
+
return res
|
|
2080
|
+
|
|
2081
|
+
# reassign share
|
|
2082
|
+
def reassignShare(self, jedi_task_ids, share_dest, reassign_running):
|
|
2083
|
+
# get DB proxy
|
|
2084
|
+
with self.proxyPool.get() as proxy:
|
|
2085
|
+
# exec
|
|
2086
|
+
res = proxy.reassignShare(jedi_task_ids, share_dest, reassign_running)
|
|
2087
|
+
return res
|
|
2088
|
+
|
|
2089
|
+
def is_valid_share(self, share_name):
|
|
2090
|
+
"""
|
|
2091
|
+
Checks whether the share is a valid leave share
|
|
2092
|
+
"""
|
|
2093
|
+
# get DB proxy
|
|
2094
|
+
with self.proxyPool.get() as proxy:
|
|
2095
|
+
# exec
|
|
2096
|
+
res = proxy.is_valid_share(share_name)
|
|
2097
|
+
return res
|
|
2098
|
+
|
|
2099
|
+
def get_share_for_task(self, task):
|
|
2100
|
+
"""
|
|
2101
|
+
Return the share based on a task specification
|
|
2102
|
+
"""
|
|
2103
|
+
# get DB proxy
|
|
2104
|
+
with self.proxyPool.get() as proxy:
|
|
2105
|
+
# exec
|
|
2106
|
+
res = proxy.get_share_for_task(task)
|
|
2107
|
+
return res
|
|
2108
|
+
|
|
2109
|
+
def get_share_for_job(self, job):
|
|
2110
|
+
"""
|
|
2111
|
+
Return the share based on a task specification
|
|
2112
|
+
"""
|
|
2113
|
+
# get DB proxy
|
|
2114
|
+
with self.proxyPool.get() as proxy:
|
|
2115
|
+
# exec
|
|
2116
|
+
res = proxy.get_share_for_job(job)
|
|
2117
|
+
return res
|
|
2118
|
+
|
|
2119
|
+
def getTaskParamsMap(self, jediTaskID):
|
|
2120
|
+
"""
|
|
2121
|
+
Return the taskParamsMap
|
|
2122
|
+
"""
|
|
2123
|
+
# get DB proxy
|
|
2124
|
+
with self.proxyPool.get() as proxy:
|
|
2125
|
+
# exec
|
|
2126
|
+
res = proxy.getTaskParamsPanda(jediTaskID)
|
|
2127
|
+
return res
|
|
2128
|
+
|
|
2129
|
+
def getCommands(self, harvester_id, n_commands):
|
|
2130
|
+
"""
|
|
2131
|
+
Get n commands for a particular harvester instance
|
|
2132
|
+
"""
|
|
2133
|
+
# get DB proxy
|
|
2134
|
+
with self.proxyPool.get() as proxy:
|
|
2135
|
+
# exec
|
|
2136
|
+
res = proxy.getCommands(harvester_id, n_commands)
|
|
2137
|
+
return res
|
|
2138
|
+
|
|
2139
|
+
def ackCommands(self, command_ids):
|
|
2140
|
+
"""
|
|
2141
|
+
Acknowledge a list of command IDs
|
|
2142
|
+
"""
|
|
2143
|
+
# get DB proxy
|
|
2144
|
+
with self.proxyPool.get() as proxy:
|
|
2145
|
+
# exec
|
|
2146
|
+
res = proxy.ackCommands(command_ids)
|
|
2147
|
+
return res
|
|
2148
|
+
|
|
2149
|
+
# send command to harvester or lock command
|
|
2150
|
+
def commandToHarvester(
|
|
2151
|
+
self,
|
|
2152
|
+
harvester_ID,
|
|
2153
|
+
command,
|
|
2154
|
+
ack_requested,
|
|
2155
|
+
status,
|
|
2156
|
+
lockInterval=None,
|
|
2157
|
+
comInterval=None,
|
|
2158
|
+
params=None,
|
|
2159
|
+
):
|
|
2160
|
+
# get DB proxy
|
|
2161
|
+
with self.proxyPool.get() as proxy:
|
|
2162
|
+
# exec
|
|
2163
|
+
res = proxy.commandToHarvester(
|
|
2164
|
+
harvester_ID,
|
|
2165
|
+
command,
|
|
2166
|
+
ack_requested,
|
|
2167
|
+
status,
|
|
2168
|
+
lockInterval,
|
|
2169
|
+
comInterval,
|
|
2170
|
+
params,
|
|
2171
|
+
)
|
|
2172
|
+
return res
|
|
2173
|
+
|
|
2174
|
+
def getResourceTypes(self):
|
|
2175
|
+
"""
|
|
2176
|
+
Get resource types (SCORE, MCORE, ...) and their definitions
|
|
2177
|
+
"""
|
|
2178
|
+
# get DB proxy
|
|
2179
|
+
with self.proxyPool.get() as proxy:
|
|
2180
|
+
# exec
|
|
2181
|
+
res = proxy.load_resource_types(formatting="dict")
|
|
2182
|
+
return res
|
|
2183
|
+
|
|
2184
|
+
# report stat of workers
|
|
2185
|
+
def reportWorkerStats_jobtype(self, harvesterID, siteName, paramsList):
|
|
2186
|
+
# get DB proxy
|
|
2187
|
+
with self.proxyPool.get() as proxy:
|
|
2188
|
+
# exec
|
|
2189
|
+
res = proxy.reportWorkerStats_jobtype(harvesterID, siteName, paramsList)
|
|
2190
|
+
return res
|
|
2191
|
+
|
|
2192
|
+
# get command locks
|
|
2193
|
+
def getCommandLocksHarvester(self, harvester_ID, command, lockedBy, lockInterval, commandInterval):
|
|
2194
|
+
# get DB proxy
|
|
2195
|
+
with self.proxyPool.get() as proxy:
|
|
2196
|
+
# exec
|
|
2197
|
+
res = proxy.getCommandLocksHarvester(harvester_ID, command, lockedBy, lockInterval, commandInterval)
|
|
2198
|
+
return res
|
|
2199
|
+
|
|
2200
|
+
# release command lock
|
|
2201
|
+
def releaseCommandLockHarvester(self, harvester_ID, command, computingSite, resourceType, lockedBy):
|
|
2202
|
+
# get DB proxy
|
|
2203
|
+
with self.proxyPool.get() as proxy:
|
|
2204
|
+
# exec
|
|
2205
|
+
res = proxy.releaseCommandLockHarvester(harvester_ID, command, computingSite, resourceType, lockedBy)
|
|
2206
|
+
return res
|
|
2207
|
+
|
|
2208
|
+
# update workers
|
|
2209
|
+
def updateWorkers(self, harvesterID, data):
|
|
2210
|
+
"""
|
|
2211
|
+
Update workers
|
|
2212
|
+
"""
|
|
2213
|
+
# get DB proxy
|
|
2214
|
+
with self.proxyPool.get() as proxy:
|
|
2215
|
+
# exec
|
|
2216
|
+
res = proxy.updateWorkers(harvesterID, data)
|
|
2217
|
+
return res
|
|
2218
|
+
|
|
2219
|
+
# update workers
|
|
2220
|
+
def updateServiceMetrics(self, harvesterID, data):
|
|
2221
|
+
"""
|
|
2222
|
+
Update workers
|
|
2223
|
+
"""
|
|
2224
|
+
# get DB proxy
|
|
2225
|
+
with self.proxyPool.get() as proxy:
|
|
2226
|
+
# exec
|
|
2227
|
+
res = proxy.updateServiceMetrics(harvesterID, data)
|
|
2228
|
+
return res
|
|
2229
|
+
|
|
2230
|
+
# heartbeat for harvester
|
|
2231
|
+
def harvesterIsAlive(self, user, host, harvesterID, data):
|
|
2232
|
+
"""
|
|
2233
|
+
update harvester instance information
|
|
2234
|
+
"""
|
|
2235
|
+
# get DB proxy
|
|
2236
|
+
with self.proxyPool.get() as proxy:
|
|
2237
|
+
# exec
|
|
2238
|
+
res = proxy.harvesterIsAlive(user, host, harvesterID, data)
|
|
2239
|
+
return res
|
|
2240
|
+
|
|
2241
|
+
def storePilotLog(self, panda_id, pilot_log):
|
|
2242
|
+
"""
|
|
2243
|
+
Store the pilot log in the pandalog table
|
|
2244
|
+
"""
|
|
2245
|
+
# get DB proxy
|
|
2246
|
+
with self.proxyPool.get() as proxy:
|
|
2247
|
+
# exec
|
|
2248
|
+
res = proxy.storePilotLog(panda_id, pilot_log)
|
|
2249
|
+
return res
|
|
2250
|
+
|
|
2251
|
+
# read the resource types from the DB
|
|
2252
|
+
def load_resource_types(self):
|
|
2253
|
+
# get DBproxy
|
|
2254
|
+
with self.proxyPool.get() as proxy:
|
|
2255
|
+
# exec
|
|
2256
|
+
ret_val = proxy.load_resource_types()
|
|
2257
|
+
return ret_val
|
|
2258
|
+
|
|
2259
|
+
# get the resource of a task
|
|
2260
|
+
def get_resource_type_task(self, task_spec):
|
|
2261
|
+
# get DBproxy
|
|
2262
|
+
with self.proxyPool.get() as proxy:
|
|
2263
|
+
# exec
|
|
2264
|
+
ret_val = proxy.get_resource_type_task(task_spec)
|
|
2265
|
+
return ret_val
|
|
2266
|
+
|
|
2267
|
+
def reset_resource_type_task(self, jedi_task_id, use_commit=True):
|
|
2268
|
+
# get DBproxy
|
|
2269
|
+
with self.proxyPool.get() as proxy:
|
|
2270
|
+
# exec
|
|
2271
|
+
ret_val = proxy.reset_resource_type_task(jedi_task_id, use_commit)
|
|
2272
|
+
return ret_val
|
|
2273
|
+
|
|
2274
|
+
# get the resource of a task
|
|
2275
|
+
def get_resource_type_job(self, job_spec):
|
|
2276
|
+
# get DBproxy
|
|
2277
|
+
with self.proxyPool.get() as proxy:
|
|
2278
|
+
# exec
|
|
2279
|
+
ret_val = proxy.get_resource_type_job(job_spec)
|
|
2280
|
+
return ret_val
|
|
2281
|
+
|
|
2282
|
+
# check Job status
|
|
2283
|
+
def checkJobStatus(self, pandaIDs):
|
|
2284
|
+
try:
|
|
2285
|
+
pandaIDs = pandaIDs.split(",")
|
|
2286
|
+
except Exception:
|
|
2287
|
+
pandaIDs = []
|
|
2288
|
+
# get DBproxy
|
|
2289
|
+
with self.proxyPool.get() as proxy:
|
|
2290
|
+
# exec
|
|
2291
|
+
retList = []
|
|
2292
|
+
for pandaID in pandaIDs:
|
|
2293
|
+
ret = proxy.checkJobStatus(pandaID)
|
|
2294
|
+
retList.append(ret)
|
|
2295
|
+
return retList
|
|
2296
|
+
|
|
2297
|
+
# get stat of workers
|
|
2298
|
+
def getWorkerStats(self):
|
|
2299
|
+
# get DBproxy
|
|
2300
|
+
with self.proxyPool.get() as proxy:
|
|
2301
|
+
# exec
|
|
2302
|
+
ret = proxy.getWorkerStats()
|
|
2303
|
+
return ret
|
|
2304
|
+
|
|
2305
|
+
# get unified pilot streaming queues
|
|
2306
|
+
def ups_get_queues(self):
|
|
2307
|
+
# get DBproxy
|
|
2308
|
+
with self.proxyPool.get() as proxy:
|
|
2309
|
+
# exec
|
|
2310
|
+
ret = proxy.ups_get_queues()
|
|
2311
|
+
return ret
|
|
2312
|
+
|
|
2313
|
+
# load harvester worker stats
|
|
2314
|
+
def ups_load_worker_stats(self):
|
|
2315
|
+
# get DBproxy
|
|
2316
|
+
with self.proxyPool.get() as proxy:
|
|
2317
|
+
# exec
|
|
2318
|
+
ret = proxy.ups_load_worker_stats()
|
|
2319
|
+
return ret
|
|
2320
|
+
|
|
2321
|
+
# get the distribution of new workers to submit
|
|
2322
|
+
def get_average_memory_workers(self, queue, harvester_id, target):
|
|
2323
|
+
# get DBproxy
|
|
2324
|
+
with self.proxyPool.get() as proxy:
|
|
2325
|
+
# exec
|
|
2326
|
+
ret = proxy.get_average_memory_workers(queue, harvester_id, target)
|
|
2327
|
+
return ret
|
|
2328
|
+
|
|
2329
|
+
# get the distribution of new workers to submit
|
|
2330
|
+
def ups_new_worker_distribution(self, queue, worker_stats):
|
|
2331
|
+
# get DBproxy
|
|
2332
|
+
with self.proxyPool.get() as proxy:
|
|
2333
|
+
# exec
|
|
2334
|
+
ret = proxy.ups_new_worker_distribution(queue, worker_stats)
|
|
2335
|
+
return ret
|
|
2336
|
+
|
|
2337
|
+
# check event availability
|
|
2338
|
+
def checkEventsAvailability(self, pandaID, jobsetID, jediTaskID):
|
|
2339
|
+
# get DBproxy
|
|
2340
|
+
with self.proxyPool.get() as proxy:
|
|
2341
|
+
# exec
|
|
2342
|
+
ret = proxy.checkEventsAvailability(pandaID, jobsetID, jediTaskID)
|
|
2343
|
+
return ret
|
|
2344
|
+
|
|
2345
|
+
# get LNFs for jumbo job
|
|
2346
|
+
def getLFNsForJumbo(self, jediTaskID):
|
|
2347
|
+
# get DBproxy
|
|
2348
|
+
with self.proxyPool.get() as proxy:
|
|
2349
|
+
# exec
|
|
2350
|
+
ret = proxy.getLFNsForJumbo(jediTaskID)
|
|
2351
|
+
return ret
|
|
2352
|
+
|
|
2353
|
+
# get active job attribute
|
|
2354
|
+
def getActiveJobAttributes(self, pandaID, attrs):
|
|
2355
|
+
# get DBproxy
|
|
2356
|
+
with self.proxyPool.get() as proxy:
|
|
2357
|
+
# exec
|
|
2358
|
+
ret = proxy.getActiveJobAttributes(pandaID, attrs)
|
|
2359
|
+
return ret
|
|
2360
|
+
|
|
2361
|
+
# get original consumers
|
|
2362
|
+
def getOriginalConsumers(self, jediTaskID, jobsetID, pandaID):
|
|
2363
|
+
# get DBproxy
|
|
2364
|
+
with self.proxyPool.get() as proxy:
|
|
2365
|
+
# exec
|
|
2366
|
+
ret = proxy.getOriginalConsumers(jediTaskID, jobsetID, pandaID)
|
|
2367
|
+
return ret
|
|
2368
|
+
|
|
2369
|
+
# add harvester dialog messages
|
|
2370
|
+
def addHarvesterDialogs(self, harvesterID, dialogs):
|
|
2371
|
+
# get DBproxy
|
|
2372
|
+
with self.proxyPool.get() as proxy:
|
|
2373
|
+
# exec
|
|
2374
|
+
ret = proxy.addHarvesterDialogs(harvesterID, dialogs)
|
|
2375
|
+
return ret
|
|
2376
|
+
|
|
2377
|
+
# get job statistics per site and resource
|
|
2378
|
+
def getJobStatisticsPerSiteResource(self, timeWindow=None):
|
|
2379
|
+
# get DBproxy
|
|
2380
|
+
with self.proxyPool.get() as proxy:
|
|
2381
|
+
# exec
|
|
2382
|
+
ret = proxy.getJobStatisticsPerSiteResource(timeWindow)
|
|
2383
|
+
return ret
|
|
2384
|
+
|
|
2385
|
+
# get job statistics per site, source label, and resource type
|
|
2386
|
+
def get_job_statistics_per_site_label_resource(self, time_window=None):
|
|
2387
|
+
# get DBproxy
|
|
2388
|
+
with self.proxyPool.get() as proxy:
|
|
2389
|
+
# exec
|
|
2390
|
+
ret = proxy.get_job_statistics_per_site_label_resource(time_window)
|
|
2391
|
+
return ret
|
|
2392
|
+
|
|
2393
|
+
# set num slots for workload provisioning
|
|
2394
|
+
def setNumSlotsForWP(self, pandaQueueName, numSlots, gshare, resourceType, validPeriod):
|
|
2395
|
+
# get DBproxy
|
|
2396
|
+
with self.proxyPool.get() as proxy:
|
|
2397
|
+
# exec
|
|
2398
|
+
ret = proxy.setNumSlotsForWP(pandaQueueName, numSlots, gshare, resourceType, validPeriod)
|
|
2399
|
+
return ret
|
|
2400
|
+
|
|
2401
|
+
# enable jumbo jobs
|
|
2402
|
+
def enableJumboJobs(self, jediTaskID, totalJumboJobs, nJumboPerSite):
|
|
2403
|
+
# get DBproxy
|
|
2404
|
+
with self.proxyPool.get() as proxy:
|
|
2405
|
+
# exec
|
|
2406
|
+
ret = proxy.enableJumboJobs(jediTaskID, totalJumboJobs, nJumboPerSite)
|
|
2407
|
+
return ret
|
|
2408
|
+
|
|
2409
|
+
# enable event service
|
|
2410
|
+
def enableEventService(self, jediTaskID):
|
|
2411
|
+
# get DBproxy
|
|
2412
|
+
with self.proxyPool.get() as proxy:
|
|
2413
|
+
# exec
|
|
2414
|
+
ret = proxy.enableEventService(jediTaskID)
|
|
2415
|
+
return ret
|
|
2416
|
+
|
|
2417
|
+
# get JEDI file attributes
|
|
2418
|
+
def getJediFileAttributes(self, PandaID, jediTaskID, datasetID, fileID, attrs):
|
|
2419
|
+
# get DBproxy
|
|
2420
|
+
with self.proxyPool.get() as proxy:
|
|
2421
|
+
# exec
|
|
2422
|
+
ret = proxy.getJediFileAttributes(PandaID, jediTaskID, datasetID, fileID, attrs)
|
|
2423
|
+
return ret
|
|
2424
|
+
|
|
2425
|
+
# check if super user
|
|
2426
|
+
def isSuperUser(self, userName):
|
|
2427
|
+
# get DBproxy
|
|
2428
|
+
with self.proxyPool.get() as proxy:
|
|
2429
|
+
# exec
|
|
2430
|
+
ret = proxy.isSuperUser(userName)
|
|
2431
|
+
return ret
|
|
2432
|
+
|
|
2433
|
+
# get workers for a job
|
|
2434
|
+
def getWorkersForJob(self, PandaID):
|
|
2435
|
+
# get DBproxy
|
|
2436
|
+
with self.proxyPool.get() as proxy:
|
|
2437
|
+
# exec
|
|
2438
|
+
ret = proxy.getWorkersForJob(PandaID)
|
|
2439
|
+
return ret
|
|
2440
|
+
|
|
2441
|
+
# get user job metadata
|
|
2442
|
+
def getUserJobMetadata(self, jediTaskID):
|
|
2443
|
+
# get DBproxy
|
|
2444
|
+
with self.proxyPool.get() as proxy:
|
|
2445
|
+
# exec
|
|
2446
|
+
ret = proxy.getUserJobMetadata(jediTaskID)
|
|
2447
|
+
return ret
|
|
2448
|
+
|
|
2449
|
+
# get jumbo job datasets
|
|
2450
|
+
def getJumboJobDatasets(self, n_days, grace_period):
|
|
2451
|
+
# get DBproxy
|
|
2452
|
+
with self.proxyPool.get() as proxy:
|
|
2453
|
+
# exec
|
|
2454
|
+
ret = proxy.getJumboJobDatasets(n_days, grace_period)
|
|
2455
|
+
return ret
|
|
2456
|
+
|
|
2457
|
+
# get global shares status
|
|
2458
|
+
def getGShareStatus(self):
|
|
2459
|
+
# get DBproxy
|
|
2460
|
+
with self.proxyPool.get() as proxy:
|
|
2461
|
+
# exec
|
|
2462
|
+
ret = proxy.getGShareStatus()
|
|
2463
|
+
return ret
|
|
2464
|
+
|
|
2465
|
+
# get output datasets
|
|
2466
|
+
def getOutputDatasetsJEDI(self, panda_id):
|
|
2467
|
+
# get DBproxy
|
|
2468
|
+
with self.proxyPool.get() as proxy:
|
|
2469
|
+
# exec
|
|
2470
|
+
ret = proxy.getOutputDatasetsJEDI(panda_id)
|
|
2471
|
+
return ret
|
|
2472
|
+
|
|
2473
|
+
# update/insert JSON queue information into the scheconfig replica
|
|
2474
|
+
def upsertQueuesInJSONSchedconfig(self, schedconfig_dump):
|
|
2475
|
+
# get DBproxy
|
|
2476
|
+
with self.proxyPool.get() as proxy:
|
|
2477
|
+
# exec
|
|
2478
|
+
ret = proxy.upsertQueuesInJSONSchedconfig(schedconfig_dump)
|
|
2479
|
+
return ret
|
|
2480
|
+
|
|
2481
|
+
# update/insert SW tag information
|
|
2482
|
+
def loadSWTags(self, sw_tags):
|
|
2483
|
+
# get DBproxy
|
|
2484
|
+
with self.proxyPool.get() as proxy:
|
|
2485
|
+
# exec
|
|
2486
|
+
ret = proxy.loadSWTags(sw_tags)
|
|
2487
|
+
return ret
|
|
2488
|
+
|
|
2489
|
+
# generate a harvester command to clean up the workers of a site
|
|
2490
|
+
def sweepPQ(self, panda_queue_des, status_list_des, ce_list_des, submission_host_list_des):
|
|
2491
|
+
# get DBproxy
|
|
2492
|
+
with self.proxyPool.get() as proxy:
|
|
2493
|
+
# exec
|
|
2494
|
+
ret = proxy.sweepPQ(panda_queue_des, status_list_des, ce_list_des, submission_host_list_des)
|
|
2495
|
+
return ret
|
|
2496
|
+
|
|
2497
|
+
# lock process
|
|
2498
|
+
def lockProcess_PANDA(self, component, pid, time_limit=5, force=False):
|
|
2499
|
+
with self.proxyPool.get() as proxy:
|
|
2500
|
+
ret = proxy.lockProcess_PANDA(component, pid, time_limit, force)
|
|
2501
|
+
return ret
|
|
2502
|
+
|
|
2503
|
+
# unlock process
|
|
2504
|
+
def unlockProcess_PANDA(self, component, pid):
|
|
2505
|
+
with self.proxyPool.get() as proxy:
|
|
2506
|
+
ret = proxy.unlockProcess_PANDA(component, pid)
|
|
2507
|
+
return ret
|
|
2508
|
+
|
|
2509
|
+
# check process lock
|
|
2510
|
+
def checkProcessLock_PANDA(self, component, pid, time_limit, check_base=False):
|
|
2511
|
+
with self.proxyPool.get() as proxy:
|
|
2512
|
+
ret = proxy.checkProcessLock_PANDA(component, pid, time_limit, check_base)
|
|
2513
|
+
return ret
|
|
2514
|
+
|
|
2515
|
+
# insert job output report
|
|
2516
|
+
def insertJobOutputReport(self, panda_id, prod_source_label, job_status, attempt_nr, data):
|
|
2517
|
+
with self.proxyPool.get() as proxy:
|
|
2518
|
+
ret = proxy.insertJobOutputReport(panda_id, prod_source_label, job_status, attempt_nr, data)
|
|
2519
|
+
return ret
|
|
2520
|
+
|
|
2521
|
+
# deleted job output report
|
|
2522
|
+
def deleteJobOutputReport(self, panda_id, attempt_nr):
|
|
2523
|
+
with self.proxyPool.get() as proxy:
|
|
2524
|
+
ret = proxy.deleteJobOutputReport(panda_id, attempt_nr)
|
|
2525
|
+
return ret
|
|
2526
|
+
|
|
2527
|
+
# update data of job output report
|
|
2528
|
+
def updateJobOutputReport(self, panda_id, attempt_nr, data):
|
|
2529
|
+
with self.proxyPool.get() as proxy:
|
|
2530
|
+
ret = proxy.updateJobOutputReport(panda_id, attempt_nr, data)
|
|
2531
|
+
return ret
|
|
2532
|
+
|
|
2533
|
+
# get job output report
|
|
2534
|
+
def getJobOutputReport(self, panda_id, attempt_nr):
|
|
2535
|
+
with self.proxyPool.get() as proxy:
|
|
2536
|
+
ret = proxy.getJobOutputReport(panda_id, attempt_nr)
|
|
2537
|
+
return ret
|
|
2538
|
+
|
|
2539
|
+
# lock job output report
|
|
2540
|
+
def lockJobOutputReport(self, panda_id, attempt_nr, pid, time_limit, take_over_from=None):
|
|
2541
|
+
with self.proxyPool.get() as proxy:
|
|
2542
|
+
ret = proxy.lockJobOutputReport(panda_id, attempt_nr, pid, time_limit, take_over_from)
|
|
2543
|
+
return ret
|
|
2544
|
+
|
|
2545
|
+
# unlock job output report
|
|
2546
|
+
def unlockJobOutputReport(self, panda_id, attempt_nr, pid, lock_offset):
|
|
2547
|
+
with self.proxyPool.get() as proxy:
|
|
2548
|
+
ret = proxy.unlockJobOutputReport(panda_id, attempt_nr, pid, lock_offset)
|
|
2549
|
+
return ret
|
|
2550
|
+
|
|
2551
|
+
# list pandaID and attemptNr of job output report
|
|
2552
|
+
def listJobOutputReport(
|
|
2553
|
+
self,
|
|
2554
|
+
only_unlocked=False,
|
|
2555
|
+
time_limit=5,
|
|
2556
|
+
limit=999999,
|
|
2557
|
+
grace_period=3,
|
|
2558
|
+
labels=None,
|
|
2559
|
+
anti_labels=None,
|
|
2560
|
+
):
|
|
2561
|
+
with self.proxyPool.get() as proxy:
|
|
2562
|
+
ret = proxy.listJobOutputReport(only_unlocked, time_limit, limit, grace_period, labels, anti_labels)
|
|
2563
|
+
return ret
|
|
2564
|
+
|
|
2565
|
+
# update problematic resource info for user
|
|
2566
|
+
def update_problematic_resource_info(self, user_name, jedi_task_id, resource, problem_type):
|
|
2567
|
+
with self.proxyPool.get() as proxy:
|
|
2568
|
+
ret = proxy.update_problematic_resource_info(user_name, jedi_task_id, resource, problem_type)
|
|
2569
|
+
return ret
|
|
2570
|
+
|
|
2571
|
+
# send command to a job
|
|
2572
|
+
def send_command_to_job(self, panda_id, com):
|
|
2573
|
+
with self.proxyPool.get() as proxy:
|
|
2574
|
+
ret = proxy.send_command_to_job(panda_id, com)
|
|
2575
|
+
return ret
|
|
2576
|
+
|
|
2577
|
+
# get workers with stale states and update them with pilot information
|
|
2578
|
+
def get_workers_to_synchronize(self):
|
|
2579
|
+
with self.proxyPool.get() as proxy:
|
|
2580
|
+
ret = proxy.get_workers_to_synchronize()
|
|
2581
|
+
return ret
|
|
2582
|
+
|
|
2583
|
+
# set user secret
|
|
2584
|
+
def set_user_secret(self, owner, key, value):
|
|
2585
|
+
with self.proxyPool.get() as proxy:
|
|
2586
|
+
ret = proxy.set_user_secret(owner, key, value)
|
|
2587
|
+
return ret
|
|
2588
|
+
|
|
2589
|
+
# get user secrets
|
|
2590
|
+
def get_user_secrets(self, owner, keys=None, get_json=False):
|
|
2591
|
+
with self.proxyPool.get() as proxy:
|
|
2592
|
+
ret = proxy.get_user_secrets(owner, keys, get_json)
|
|
2593
|
+
return ret
|
|
2594
|
+
|
|
2595
|
+
def configurator_write_sites(self, sites_list):
|
|
2596
|
+
with self.proxyPool.get() as proxy:
|
|
2597
|
+
ret = proxy.configurator_write_sites(sites_list)
|
|
2598
|
+
return ret
|
|
2599
|
+
|
|
2600
|
+
def configurator_write_panda_sites(self, panda_site_list):
|
|
2601
|
+
with self.proxyPool.get() as proxy:
|
|
2602
|
+
ret = proxy.configurator_write_panda_sites(panda_site_list)
|
|
2603
|
+
return ret
|
|
2604
|
+
|
|
2605
|
+
def configurator_write_ddm_endpoints(self, ddm_endpoint_list):
|
|
2606
|
+
with self.proxyPool.get() as proxy:
|
|
2607
|
+
ret = proxy.configurator_write_ddm_endpoints(ddm_endpoint_list)
|
|
2608
|
+
return ret
|
|
2609
|
+
|
|
2610
|
+
def configurator_write_panda_ddm_relations(self, relation_list):
|
|
2611
|
+
with self.proxyPool.get() as proxy:
|
|
2612
|
+
ret = proxy.configurator_write_panda_ddm_relations(relation_list)
|
|
2613
|
+
return ret
|
|
2614
|
+
|
|
2615
|
+
def configurator_read_sites(self):
|
|
2616
|
+
with self.proxyPool.get() as proxy:
|
|
2617
|
+
ret = proxy.configurator_read_sites()
|
|
2618
|
+
return ret
|
|
2619
|
+
|
|
2620
|
+
def configurator_read_panda_sites(self):
|
|
2621
|
+
with self.proxyPool.get() as proxy:
|
|
2622
|
+
ret = proxy.configurator_read_panda_sites()
|
|
2623
|
+
return ret
|
|
2624
|
+
|
|
2625
|
+
def configurator_read_ddm_endpoints(self):
|
|
2626
|
+
with self.proxyPool.get() as proxy:
|
|
2627
|
+
ret = proxy.configurator_read_ddm_endpoints()
|
|
2628
|
+
return ret
|
|
2629
|
+
|
|
2630
|
+
def configurator_read_cric_sites(self):
|
|
2631
|
+
with self.proxyPool.get() as proxy:
|
|
2632
|
+
ret = proxy.configurator_read_cric_sites()
|
|
2633
|
+
return ret
|
|
2634
|
+
|
|
2635
|
+
def configurator_read_cric_panda_sites(self):
|
|
2636
|
+
with self.proxyPool.get() as proxy:
|
|
2637
|
+
ret = proxy.configurator_read_cric_panda_sites()
|
|
2638
|
+
return ret
|
|
2639
|
+
|
|
2640
|
+
def configurator_delete_sites(self, sites_to_delete):
|
|
2641
|
+
with self.proxyPool.get() as proxy:
|
|
2642
|
+
ret = proxy.configurator_delete_sites(sites_to_delete)
|
|
2643
|
+
return ret
|
|
2644
|
+
|
|
2645
|
+
def configurator_delete_panda_sites(self, panda_sites_to_delete):
|
|
2646
|
+
with self.proxyPool.get() as proxy:
|
|
2647
|
+
ret = proxy.configurator_delete_panda_sites(panda_sites_to_delete)
|
|
2648
|
+
return ret
|
|
2649
|
+
|
|
2650
|
+
def configurator_delete_ddm_endpoints(self, ddm_endpoints_to_delete):
|
|
2651
|
+
with self.proxyPool.get() as proxy:
|
|
2652
|
+
ret = proxy.configurator_delete_ddm_endpoints(ddm_endpoints_to_delete)
|
|
2653
|
+
return ret
|
|
2654
|
+
|
|
2655
|
+
def carbon_write_region_emissions(self, emissions):
|
|
2656
|
+
with self.proxyPool.get() as proxy:
|
|
2657
|
+
ret = proxy.carbon_write_region_emissions(emissions)
|
|
2658
|
+
return ret
|
|
2659
|
+
|
|
2660
|
+
def carbon_aggregate_emissions(self):
|
|
2661
|
+
with self.proxyPool.get() as proxy:
|
|
2662
|
+
ret = proxy.carbon_aggregate_emissions()
|
|
2663
|
+
return ret
|
|
2664
|
+
|
|
2665
|
+
def get_files_in_datasets(self, task_id, dataset_types):
|
|
2666
|
+
with self.proxyPool.get() as proxy:
|
|
2667
|
+
ret = proxy.get_files_in_datasets(task_id, dataset_types)
|
|
2668
|
+
return ret
|
|
2669
|
+
|
|
2670
|
+
def get_max_worker_id(self, harvester_id):
|
|
2671
|
+
with self.proxyPool.get() as proxy:
|
|
2672
|
+
ret = proxy.get_max_worker_id(harvester_id)
|
|
2673
|
+
return ret
|
|
2674
|
+
|
|
2675
|
+
def get_events_status(self, ids):
|
|
2676
|
+
with self.proxyPool.get() as proxy:
|
|
2677
|
+
ret = proxy.get_events_status(ids)
|
|
2678
|
+
return ret
|
|
2679
|
+
|
|
2680
|
+
def async_update_datasets(self, panda_id):
|
|
2681
|
+
with self.proxyPool.get() as proxy:
|
|
2682
|
+
ret = proxy.async_update_datasets(panda_id)
|
|
2683
|
+
return ret
|
|
2684
|
+
|
|
2685
|
+
def set_workload_metrics(self, jedi_task_id, panda_id, metrics):
|
|
2686
|
+
with self.proxyPool.get() as proxy:
|
|
2687
|
+
ret = proxy.set_workload_metrics(jedi_task_id, panda_id, metrics, True)
|
|
2688
|
+
return ret
|
|
2689
|
+
|
|
2690
|
+
def get_workload_metrics(self, jedi_task_id, panda_id):
|
|
2691
|
+
with self.proxyPool.get() as proxy:
|
|
2692
|
+
ret = proxy.get_workload_metrics(jedi_task_id, panda_id)
|
|
2693
|
+
return ret
|
|
2694
|
+
|
|
2695
|
+
def get_jobs_metrics_in_task(self, jedi_task_id: int):
|
|
2696
|
+
with self.proxyPool.get() as proxy:
|
|
2697
|
+
ret = proxy.get_jobs_metrics_in_task(jedi_task_id)
|
|
2698
|
+
return ret
|
|
2699
|
+
|
|
2700
|
+
def enable_job_cloning(self, jedi_task_id, mode, multiplicity, num_sites):
|
|
2701
|
+
with self.proxyPool.get() as proxy:
|
|
2702
|
+
ret = proxy.enable_job_cloning(jedi_task_id, mode, multiplicity, num_sites)
|
|
2703
|
+
return ret
|
|
2704
|
+
|
|
2705
|
+
def disable_job_cloning(self, jedi_task_id):
|
|
2706
|
+
with self.proxyPool.get() as proxy:
|
|
2707
|
+
ret = proxy.disable_job_cloning(jedi_task_id)
|
|
2708
|
+
return ret
|
|
2709
|
+
|
|
2710
|
+
# gets statistics on the number of jobs with a specific status for each nucleus at each site
|
|
2711
|
+
def get_num_jobs_with_status_by_nucleus(self, vo, job_status):
|
|
2712
|
+
with self.proxyPool.get() as proxy:
|
|
2713
|
+
return proxy.get_num_jobs_with_status_by_nucleus(vo, job_status)
|
|
2714
|
+
|
|
2715
|
+
# ==== JEDI taskbuffer functions ===========================
|
|
2716
|
+
|
|
2717
|
+
# get JEDI task with jediTaskID
|
|
2718
|
+
def getTaskWithID_JEDI(self, jediTaskID, fullFlag=False, lockTask=False, pid=None, lockInterval=None, clearError=False):
|
|
2719
|
+
with self.proxyPool.get() as proxy:
|
|
2720
|
+
return proxy.getTaskWithID_JEDI(jediTaskID, fullFlag, lockTask, pid, lockInterval, clearError)
|
|
2721
|
+
|
|
2722
|
+
# update input files stage-in done (according to message from iDDS, called by other methods, etc.)
|
|
2723
|
+
def updateInputFilesStaged_JEDI(self, jeditaskid, scope, filenames_dict, chunk_size=500, by=None, check_scope=True):
|
|
2724
|
+
with self.proxyPool.get() as proxy:
|
|
2725
|
+
return proxy.updateInputFilesStaged_JEDI(jeditaskid, scope, filenames_dict, chunk_size, by, check_scope)
|
|
2726
|
+
|
|
2727
|
+
# ==== Data Carousel functions =============================
|
|
2728
|
+
|
|
2729
|
+
# query data carousel request ID by dataset
|
|
2730
|
+
def get_data_carousel_request_id_by_dataset_JEDI(self, dataset):
|
|
2731
|
+
with self.proxyPool.get() as proxy:
|
|
2732
|
+
return proxy.get_data_carousel_request_id_by_dataset_JEDI(dataset)
|
|
2733
|
+
|
|
2734
|
+
# insert data carousel requests
|
|
2735
|
+
def insert_data_carousel_requests_JEDI(self, task_id, dc_req_specs):
|
|
2736
|
+
with self.proxyPool.get() as proxy:
|
|
2737
|
+
return proxy.insert_data_carousel_requests_JEDI(task_id, dc_req_specs)
|
|
2738
|
+
|
|
2739
|
+
# update a data carousel request
|
|
2740
|
+
def update_data_carousel_request_JEDI(self, dc_req_spec):
|
|
2741
|
+
with self.proxyPool.get() as proxy:
|
|
2742
|
+
return proxy.update_data_carousel_request_JEDI(dc_req_spec)
|
|
2743
|
+
|
|
2744
|
+
# insert data carousel relations
|
|
2745
|
+
def insert_data_carousel_relations_JEDI(self, task_id, request_ids):
|
|
2746
|
+
with self.proxyPool.get() as proxy:
|
|
2747
|
+
return proxy.insert_data_carousel_relations_JEDI(task_id, request_ids)
|
|
2748
|
+
|
|
2749
|
+
# get data carousel queued requests and info of their related tasks
|
|
2750
|
+
def get_data_carousel_queued_requests_JEDI(self):
|
|
2751
|
+
with self.proxyPool.get() as proxy:
|
|
2752
|
+
return proxy.get_data_carousel_queued_requests_JEDI()
|
|
2753
|
+
|
|
2754
|
+
# get data carousel requests of tasks by task status
|
|
2755
|
+
def get_data_carousel_requests_by_task_status_JEDI(self, status_filter_list=None, status_exclusion_list=None):
|
|
2756
|
+
with self.proxyPool.get() as proxy:
|
|
2757
|
+
return proxy.get_data_carousel_requests_by_task_status_JEDI(status_filter_list=status_filter_list, status_exclusion_list=status_exclusion_list)
|
|
2758
|
+
|
|
2759
|
+
# get related tasks and their info of a data carousel request
|
|
2760
|
+
def get_related_tasks_of_data_carousel_request_JEDI(self, request_id, status_filter_list=None, status_exclusion_list=None):
|
|
2761
|
+
with self.proxyPool.get() as proxy:
|
|
2762
|
+
return proxy.get_related_tasks_of_data_carousel_request_JEDI(
|
|
2763
|
+
request_id, status_filter_list=status_filter_list, status_exclusion_list=status_exclusion_list
|
|
2764
|
+
)
|
|
2765
|
+
|
|
2766
|
+
# get data carousel staging requests
|
|
2767
|
+
def get_data_carousel_staging_requests_JEDI(self):
|
|
2768
|
+
with self.proxyPool.get() as proxy:
|
|
2769
|
+
return proxy.get_data_carousel_staging_requests_JEDI()
|
|
2770
|
+
|
|
2771
|
+
# delete data carousel requests
|
|
2772
|
+
def delete_data_carousel_requests_JEDI(self, request_id_list):
|
|
2773
|
+
with self.proxyPool.get() as proxy:
|
|
2774
|
+
return proxy.delete_data_carousel_requests_JEDI(request_id_list)
|
|
2775
|
+
|
|
2776
|
+
# clean up data carousel requests
|
|
2777
|
+
def clean_up_data_carousel_requests_JEDI(self, time_limit_days=30):
|
|
2778
|
+
with self.proxyPool.get() as proxy:
|
|
2779
|
+
return proxy.clean_up_data_carousel_requests_JEDI(time_limit_days)
|
|
2780
|
+
|
|
2781
|
+
# cancel a data carousel request
|
|
2782
|
+
def cancel_data_carousel_request_JEDI(self, request_id):
|
|
2783
|
+
with self.proxyPool.get() as proxy:
|
|
2784
|
+
return proxy.cancel_data_carousel_request_JEDI(request_id)
|
|
2785
|
+
|
|
2786
|
+
# retire a data carousel request
|
|
2787
|
+
def retire_data_carousel_request_JEDI(self, request_id):
|
|
2788
|
+
with self.proxyPool.get() as proxy:
|
|
2789
|
+
return proxy.retire_data_carousel_request_JEDI(request_id)
|
|
2790
|
+
|
|
2791
|
+
# resubmit a data carousel request
|
|
2792
|
+
def resubmit_data_carousel_request_JEDI(self, request_id, exclude_prev_dst=False):
|
|
2793
|
+
with self.proxyPool.get() as proxy:
|
|
2794
|
+
return proxy.resubmit_data_carousel_request_JEDI(request_id, exclude_prev_dst)
|
|
2795
|
+
|
|
2796
|
+
# ==== Workflow fucntions ==================================
|
|
2797
|
+
|
|
2798
|
+
def get_workflow(self, workflow_id):
|
|
2799
|
+
with self.proxyPool.get() as proxy:
|
|
2800
|
+
return proxy.get_workflow(workflow_id)
|
|
2801
|
+
|
|
2802
|
+
def get_workflow_step(self, step_id):
|
|
2803
|
+
with self.proxyPool.get() as proxy:
|
|
2804
|
+
return proxy.get_workflow_step(step_id)
|
|
2805
|
+
|
|
2806
|
+
def get_workflow_data(self, data_id):
|
|
2807
|
+
with self.proxyPool.get() as proxy:
|
|
2808
|
+
return proxy.get_workflow_data(data_id)
|
|
2809
|
+
|
|
2810
|
+
def get_workflow_data_by_name(self, name, workflow_id=None):
|
|
2811
|
+
with self.proxyPool.get() as proxy:
|
|
2812
|
+
return proxy.get_workflow_data_by_name(name, workflow_id)
|
|
2813
|
+
|
|
2814
|
+
def get_steps_of_workflow(self, workflow_id, status_filter_list=None, status_exclusion_list=None):
|
|
2815
|
+
with self.proxyPool.get() as proxy:
|
|
2816
|
+
return proxy.get_steps_of_workflow(workflow_id, status_filter_list, status_exclusion_list)
|
|
2817
|
+
|
|
2818
|
+
def get_data_of_workflow(self, workflow_id, status_filter_list=None, status_exclusion_list=None, type_filter_list=None):
|
|
2819
|
+
with self.proxyPool.get() as proxy:
|
|
2820
|
+
return proxy.get_data_of_workflow(workflow_id, status_filter_list, status_exclusion_list, type_filter_list)
|
|
2821
|
+
|
|
2822
|
+
def query_workflows(self, status_filter_list=None, status_exclusion_list=None, check_interval_sec=300):
|
|
2823
|
+
with self.proxyPool.get() as proxy:
|
|
2824
|
+
return proxy.query_workflows(status_filter_list, status_exclusion_list, check_interval_sec)
|
|
2825
|
+
|
|
2826
|
+
def lock_workflow(self, workflow_id, locked_by, lock_expiration_sec=120):
|
|
2827
|
+
with self.proxyPool.get() as proxy:
|
|
2828
|
+
return proxy.lock_workflow(workflow_id, locked_by, lock_expiration_sec)
|
|
2829
|
+
|
|
2830
|
+
def unlock_workflow(self, workflow_id, locked_by):
|
|
2831
|
+
with self.proxyPool.get() as proxy:
|
|
2832
|
+
return proxy.unlock_workflow(workflow_id, locked_by)
|
|
2833
|
+
|
|
2834
|
+
def lock_workflow_step(self, step_id, locked_by, lock_expiration_sec=120):
|
|
2835
|
+
with self.proxyPool.get() as proxy:
|
|
2836
|
+
return proxy.lock_workflow_step(step_id, locked_by, lock_expiration_sec)
|
|
2837
|
+
|
|
2838
|
+
def unlock_workflow_step(self, step_id, locked_by):
|
|
2839
|
+
with self.proxyPool.get() as proxy:
|
|
2840
|
+
return proxy.unlock_workflow_step(step_id, locked_by)
|
|
2841
|
+
|
|
2842
|
+
def lock_workflow_data(self, data_id, locked_by, lock_expiration_sec=120):
|
|
2843
|
+
with self.proxyPool.get() as proxy:
|
|
2844
|
+
return proxy.lock_workflow_data(data_id, locked_by, lock_expiration_sec)
|
|
2845
|
+
|
|
2846
|
+
def unlock_workflow_data(self, data_id, locked_by):
|
|
2847
|
+
with self.proxyPool.get() as proxy:
|
|
2848
|
+
return proxy.unlock_workflow_data(data_id, locked_by)
|
|
2849
|
+
|
|
2850
|
+
def insert_workflow(self, workflow_spec):
|
|
2851
|
+
with self.proxyPool.get() as proxy:
|
|
2852
|
+
return proxy.insert_workflow(workflow_spec)
|
|
2853
|
+
|
|
2854
|
+
def insert_workflow_step(self, wf_step_spec):
|
|
2855
|
+
with self.proxyPool.get() as proxy:
|
|
2856
|
+
return proxy.insert_workflow_step(wf_step_spec)
|
|
2857
|
+
|
|
2858
|
+
def insert_workflow_data(self, wf_data_spec):
|
|
2859
|
+
with self.proxyPool.get() as proxy:
|
|
2860
|
+
return proxy.insert_workflow_data(wf_data_spec)
|
|
2861
|
+
|
|
2862
|
+
def update_workflow(self, workflow_spec):
|
|
2863
|
+
with self.proxyPool.get() as proxy:
|
|
2864
|
+
return proxy.update_workflow(workflow_spec)
|
|
2865
|
+
|
|
2866
|
+
def update_workflow_step(self, wf_step_spec):
|
|
2867
|
+
with self.proxyPool.get() as proxy:
|
|
2868
|
+
return proxy.update_workflow_step(wf_step_spec)
|
|
2869
|
+
|
|
2870
|
+
def update_workflow_data(self, wf_data_spec):
|
|
2871
|
+
with self.proxyPool.get() as proxy:
|
|
2872
|
+
return proxy.update_workflow_data(wf_data_spec)
|
|
2873
|
+
|
|
2874
|
+
def upsert_workflow_entities(self, workflow_id, actions_dict=None, workflow_spec=None, step_specs=None, data_specs=None):
|
|
2875
|
+
with self.proxyPool.get() as proxy:
|
|
2876
|
+
return proxy.upsert_workflow_entities(workflow_id, actions_dict, workflow_spec, step_specs, data_specs)
|
|
2877
|
+
|
|
2878
|
+
# ==========================================================
|
|
2879
|
+
|
|
2880
|
+
|
|
2881
|
+
# Singleton
|
|
2882
|
+
taskBuffer = TaskBuffer()
|