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,27 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The Adder module is the core for add_main to post-process jobs’ output data, such as data registration, trigger data aggregation and so on.
|
|
3
|
+
Those post-processing procedures are experiment-dependent so that the Adder also has a plugin structure to load an experiment-specific plugin.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .adder_result import AdderResult
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AdderPluginBase:
|
|
11
|
+
"""
|
|
12
|
+
Base class for Adder plugins.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, job, params):
|
|
16
|
+
"""
|
|
17
|
+
Initialize the AdderPluginBase.
|
|
18
|
+
|
|
19
|
+
:param job: The job object.
|
|
20
|
+
:param params: Additional parameters.
|
|
21
|
+
"""
|
|
22
|
+
self.job = job
|
|
23
|
+
self.logger = None
|
|
24
|
+
self.result = AdderResult()
|
|
25
|
+
self.extra_info = {}
|
|
26
|
+
for key, value in params.items():
|
|
27
|
+
setattr(self, key, value)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Class to represent the result of the Adder operation
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
class AdderResult:
|
|
7
|
+
"""
|
|
8
|
+
Class to represent the result of the Adder operation.
|
|
9
|
+
"""
|
|
10
|
+
# slot
|
|
11
|
+
__slot__ = ("statusCode", "transferringFiles")
|
|
12
|
+
|
|
13
|
+
# return code
|
|
14
|
+
rc_succeeded = 0
|
|
15
|
+
rc_temporary = 1
|
|
16
|
+
rc_fatal = 2
|
|
17
|
+
|
|
18
|
+
# constructor
|
|
19
|
+
def __init__(self) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Initialize the AdderResult with default values.
|
|
22
|
+
"""
|
|
23
|
+
# result of interactions with data management system (DMS)
|
|
24
|
+
self.status_code = None
|
|
25
|
+
|
|
26
|
+
# list of files which are being transferred by DMS
|
|
27
|
+
self.transferring_files = []
|
|
28
|
+
|
|
29
|
+
# list of files which are being merged
|
|
30
|
+
self.merging_files = []
|
|
31
|
+
|
|
32
|
+
# succeeded
|
|
33
|
+
def set_succeeded(self):
|
|
34
|
+
"""
|
|
35
|
+
Set the status to succeeded.
|
|
36
|
+
"""
|
|
37
|
+
self.status_code = self.rc_succeeded
|
|
38
|
+
|
|
39
|
+
# temporary error to retry later
|
|
40
|
+
def set_temporary(self):
|
|
41
|
+
"""
|
|
42
|
+
Set the status to temporary error.
|
|
43
|
+
"""
|
|
44
|
+
self.status_code = self.rc_temporary
|
|
45
|
+
|
|
46
|
+
# fatal error
|
|
47
|
+
def set_fatal(self):
|
|
48
|
+
"""
|
|
49
|
+
Set the status to fatal.
|
|
50
|
+
"""
|
|
51
|
+
self.status_code = self.rc_fatal
|
|
52
|
+
|
|
53
|
+
# check if succeeded
|
|
54
|
+
def is_succeeded(self):
|
|
55
|
+
"""
|
|
56
|
+
Check if the status is 'succeeded'.
|
|
57
|
+
True if status is 'succeeded', False otherwise.
|
|
58
|
+
"""
|
|
59
|
+
return self.status_code == self.rc_succeeded
|
|
60
|
+
|
|
61
|
+
# check if temporary
|
|
62
|
+
def is_temporary(self):
|
|
63
|
+
"""
|
|
64
|
+
Check if the status is 'temporary'.
|
|
65
|
+
True if status is 'temporary', False otherwise.
|
|
66
|
+
"""
|
|
67
|
+
return self.status_code == self.rc_temporary
|
|
68
|
+
|
|
69
|
+
# check if fatal error
|
|
70
|
+
def is_fatal(self):
|
|
71
|
+
"""
|
|
72
|
+
Check if the status is 'fatal'.
|
|
73
|
+
True if status is 'fatal', False otherwise.
|
|
74
|
+
"""
|
|
75
|
+
return self.status_code == self.rc_fatal
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Simple plugin of Adder for VOs with Rucio
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import datetime
|
|
7
|
+
import time
|
|
8
|
+
import traceback
|
|
9
|
+
import uuid
|
|
10
|
+
|
|
11
|
+
from pandacommon.pandautils.PandaUtils import naive_utcnow
|
|
12
|
+
from rucio.common.exception import (
|
|
13
|
+
DataIdentifierNotFound,
|
|
14
|
+
FileConsistencyMismatch,
|
|
15
|
+
InvalidObject,
|
|
16
|
+
InvalidPath,
|
|
17
|
+
InvalidRSEExpression,
|
|
18
|
+
RSEFileNameNotSupported,
|
|
19
|
+
RSENotFound,
|
|
20
|
+
RSEProtocolNotSupported,
|
|
21
|
+
UnsupportedOperation,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
from pandaserver.dataservice import DataServiceUtils, ErrorCode
|
|
25
|
+
from pandaserver.dataservice.ddm import rucioAPI
|
|
26
|
+
|
|
27
|
+
from .adder_plugin_base import AdderPluginBase
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class AdderSimplePlugin(AdderPluginBase):
|
|
31
|
+
"""
|
|
32
|
+
Simple plugin of Adder for VOs with Rucio.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
# constructor
|
|
36
|
+
def __init__(self, job, **params) -> None:
|
|
37
|
+
"""
|
|
38
|
+
Initialize the AdderSimplePlugin.
|
|
39
|
+
|
|
40
|
+
:param job: The job object.
|
|
41
|
+
:param params: Additional parameters.
|
|
42
|
+
"""
|
|
43
|
+
AdderPluginBase.__init__(self, job, params)
|
|
44
|
+
|
|
45
|
+
# main
|
|
46
|
+
def execute(self) -> None:
|
|
47
|
+
"""
|
|
48
|
+
Execute the simple adder plugin.
|
|
49
|
+
|
|
50
|
+
:return: None
|
|
51
|
+
"""
|
|
52
|
+
try:
|
|
53
|
+
# loop over all files
|
|
54
|
+
file_map = {}
|
|
55
|
+
for file_spec in self.job.Files:
|
|
56
|
+
# ignore inputs
|
|
57
|
+
if file_spec.type not in ["output", "log"]:
|
|
58
|
+
continue
|
|
59
|
+
# ignore local
|
|
60
|
+
if file_spec.destinationSE == "local":
|
|
61
|
+
continue
|
|
62
|
+
# collect file attributes
|
|
63
|
+
try:
|
|
64
|
+
file_size = int(file_spec.fsize)
|
|
65
|
+
except Exception:
|
|
66
|
+
file_size = None
|
|
67
|
+
# set GUID if empty
|
|
68
|
+
if not file_spec.GUID:
|
|
69
|
+
file_spec.GUID = str(uuid.uuid4())
|
|
70
|
+
file_attrs = {
|
|
71
|
+
"guid": file_spec.GUID,
|
|
72
|
+
"lfn": file_spec.lfn,
|
|
73
|
+
"size": file_size,
|
|
74
|
+
"checksum": file_spec.checksum,
|
|
75
|
+
"ds": file_spec.destinationDBlock,
|
|
76
|
+
}
|
|
77
|
+
if self.extra_info:
|
|
78
|
+
if "surl" in self.extra_info and file_spec.lfn in self.extra_info["surl"]:
|
|
79
|
+
file_attrs["surl"] = self.extra_info["surl"][file_spec.lfn]
|
|
80
|
+
if "nevents" in self.extra_info and file_spec.lfn in self.extra_info["nevents"]:
|
|
81
|
+
file_attrs["events"] = self.extra_info["nevents"][file_spec.lfn]
|
|
82
|
+
file_map.setdefault(file_spec.destinationDBlock, [])
|
|
83
|
+
file_map[file_spec.destinationDBlock].append(file_attrs)
|
|
84
|
+
# register files
|
|
85
|
+
if file_map:
|
|
86
|
+
destination_rse = self.siteMapper.getSite(self.job.computingSite).ddm_output["default"]
|
|
87
|
+
destination_id_map = {destination_rse: file_map}
|
|
88
|
+
max_attempt = 3
|
|
89
|
+
for attempt_number in range(max_attempt):
|
|
90
|
+
is_fatal = False
|
|
91
|
+
is_failed = False
|
|
92
|
+
registration_start = naive_utcnow()
|
|
93
|
+
try:
|
|
94
|
+
self.logger.debug(f"registerFilesInDatasets {str(destination_id_map)}")
|
|
95
|
+
out = rucioAPI.register_files_in_dataset(destination_id_map, {})
|
|
96
|
+
except (
|
|
97
|
+
DataIdentifierNotFound,
|
|
98
|
+
FileConsistencyMismatch,
|
|
99
|
+
UnsupportedOperation,
|
|
100
|
+
InvalidPath,
|
|
101
|
+
InvalidObject,
|
|
102
|
+
RSENotFound,
|
|
103
|
+
RSEProtocolNotSupported,
|
|
104
|
+
InvalidRSEExpression,
|
|
105
|
+
RSEFileNameNotSupported,
|
|
106
|
+
KeyError,
|
|
107
|
+
) as e:
|
|
108
|
+
# fatal errors
|
|
109
|
+
out = f"failed with {str(e)}\n {traceback.format_exc()}"
|
|
110
|
+
is_fatal = True
|
|
111
|
+
is_failed = True
|
|
112
|
+
except Exception as e:
|
|
113
|
+
# unknown errors
|
|
114
|
+
is_failed = True
|
|
115
|
+
out = f"failed with unknown error: {str(e)}\n {traceback.format_exc()}"
|
|
116
|
+
if (
|
|
117
|
+
"value too large for column" in out
|
|
118
|
+
or "unique constraint (ATLAS_RUCIO.DIDS_GUID_IDX) violate" in out
|
|
119
|
+
or "unique constraint (ATLAS_RUCIO.DIDS_PK) violated" in out
|
|
120
|
+
or "unique constraint (ATLAS_RUCIO.ARCH_CONTENTS_PK) violated" in out
|
|
121
|
+
):
|
|
122
|
+
is_fatal = True
|
|
123
|
+
else:
|
|
124
|
+
is_fatal = False
|
|
125
|
+
registration_time = naive_utcnow() - registration_start
|
|
126
|
+
self.logger.debug("took %s.%03d sec" % (registration_time.seconds, registration_time.microseconds / 1000))
|
|
127
|
+
|
|
128
|
+
# failed
|
|
129
|
+
if is_failed or is_fatal:
|
|
130
|
+
self.logger.error(f"{out}")
|
|
131
|
+
if (attempt_number + 1) == max_attempt or is_fatal:
|
|
132
|
+
self.job.ddmErrorCode = ErrorCode.EC_Adder
|
|
133
|
+
# extract important error string
|
|
134
|
+
extracted_error = DataServiceUtils.extractImportantError(out)
|
|
135
|
+
err_msg = "Could not add files to DDM: "
|
|
136
|
+
if extracted_error == "":
|
|
137
|
+
self.job.ddmErrorDiag = err_msg + out.split("\n")[-1]
|
|
138
|
+
else:
|
|
139
|
+
self.job.ddmErrorDiag = err_msg + extracted_error
|
|
140
|
+
if is_fatal:
|
|
141
|
+
self.result.set_fatal()
|
|
142
|
+
else:
|
|
143
|
+
self.result.set_temporary()
|
|
144
|
+
return
|
|
145
|
+
self.logger.error(f"Try:{attempt_number}")
|
|
146
|
+
# sleep
|
|
147
|
+
time.sleep(10)
|
|
148
|
+
else:
|
|
149
|
+
self.logger.debug(f"{str(out)}")
|
|
150
|
+
break
|
|
151
|
+
# done
|
|
152
|
+
self.result.set_succeeded()
|
|
153
|
+
self.logger.debug("end plugin")
|
|
154
|
+
except Exception as e:
|
|
155
|
+
err_str = f"failed to execute with {str(e)}\n"
|
|
156
|
+
err_str += traceback.format_exc()
|
|
157
|
+
self.logger.error(err_str)
|
|
158
|
+
self.result.set_temporary()
|
|
159
|
+
# return
|
|
160
|
+
return
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""
|
|
2
|
+
update dataset DB, and then close dataset and start Activator if needed
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import datetime
|
|
7
|
+
import sys
|
|
8
|
+
from typing import Dict, List
|
|
9
|
+
|
|
10
|
+
from pandacommon.pandalogger.LogWrapper import LogWrapper
|
|
11
|
+
from pandacommon.pandalogger.PandaLogger import PandaLogger
|
|
12
|
+
from pandacommon.pandautils.PandaUtils import naive_utcnow
|
|
13
|
+
|
|
14
|
+
from pandaserver.config import panda_config
|
|
15
|
+
from pandaserver.dataservice import DataServiceUtils
|
|
16
|
+
from pandaserver.dataservice.activator import Activator
|
|
17
|
+
from pandaserver.taskbuffer import EventServiceUtils
|
|
18
|
+
|
|
19
|
+
# logger
|
|
20
|
+
_logger = PandaLogger().getLogger("closer")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Closer:
|
|
24
|
+
"""
|
|
25
|
+
Update dataset DB, and then close dataset and start Activator if needed.
|
|
26
|
+
The class updates output-related dataset records (_sub, output, and log) in
|
|
27
|
+
the database, closes _sub datasets if necessary, and activates downstream
|
|
28
|
+
runJobs if the output dataset is for buildJob (libDS, library dataset).
|
|
29
|
+
Activator changes job status from defined/assigned to activated.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
# constructor
|
|
33
|
+
def __init__(self, taskBuffer, destination_data_blocks: List[str], job, dataset_map: Dict = None) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Constructor
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
taskBuffer: Task buffer.
|
|
39
|
+
destination_data_blocks (List[str]): Destination Dispatch blocks.
|
|
40
|
+
job: Job.
|
|
41
|
+
dataset_map (Dict, optional): Dataset map. Defaults to {}.
|
|
42
|
+
"""
|
|
43
|
+
self.task_buffer = taskBuffer
|
|
44
|
+
self.destination_data_blocks = destination_data_blocks
|
|
45
|
+
self.job = job
|
|
46
|
+
self.panda_id = job.PandaID
|
|
47
|
+
self.site_mapper = None
|
|
48
|
+
self.dataset_map = dataset_map if dataset_map is not None else {}
|
|
49
|
+
self.all_subscription_finished = None
|
|
50
|
+
|
|
51
|
+
def check_sub_datasets_in_jobset(self) -> bool:
|
|
52
|
+
"""
|
|
53
|
+
Check sub datasets with the same jobset
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
bool: True if all sub datasets are done, False otherwise.
|
|
57
|
+
"""
|
|
58
|
+
tmp_log = LogWrapper(_logger, f"check_sub_datasets_in_jobset-{naive_utcnow().isoformat('/')}")
|
|
59
|
+
# skip already checked
|
|
60
|
+
if self.all_subscription_finished is not None:
|
|
61
|
+
return self.all_subscription_finished
|
|
62
|
+
# get consumers in the jobset
|
|
63
|
+
jobs = self.task_buffer.getOriginalConsumers(self.job.jediTaskID, self.job.jobsetID, self.job.panda_id)
|
|
64
|
+
checked_dataset = set()
|
|
65
|
+
for job_spec in jobs:
|
|
66
|
+
# collect all sub datasets
|
|
67
|
+
sub_datasets = set()
|
|
68
|
+
for file_spec in job_spec.Files:
|
|
69
|
+
if file_spec.type == "output":
|
|
70
|
+
sub_datasets.add(file_spec.destinationDBlock)
|
|
71
|
+
sub_datasets = sorted(sub_datasets)
|
|
72
|
+
if len(sub_datasets) > 0:
|
|
73
|
+
# use the first sub dataset
|
|
74
|
+
sub_dataset = sub_datasets[0]
|
|
75
|
+
# skip if already checked
|
|
76
|
+
if sub_dataset in checked_dataset:
|
|
77
|
+
continue
|
|
78
|
+
checked_dataset.add(sub_dataset)
|
|
79
|
+
# count the number of unfinished
|
|
80
|
+
not_finish = self.task_buffer.countFilesWithMap({"destinationDBlock": sub_dataset, "status": "unknown"})
|
|
81
|
+
if not_finish != 0:
|
|
82
|
+
tmp_log.debug(f"related sub dataset {sub_dataset} from {job_spec.PandaID} has {not_finish} unfinished files")
|
|
83
|
+
self.all_subscription_finished = False
|
|
84
|
+
break
|
|
85
|
+
if self.all_subscription_finished is None:
|
|
86
|
+
tmp_log.debug("all related sub datasets are done")
|
|
87
|
+
self.all_subscription_finished = True
|
|
88
|
+
return self.all_subscription_finished
|
|
89
|
+
|
|
90
|
+
def determine_final_status(self, destination_data_block: str) -> str:
|
|
91
|
+
"""
|
|
92
|
+
Determine the final status of a dispatch block.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
destination_data_block (str): The destination dispatch block.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
str: The final status.
|
|
99
|
+
"""
|
|
100
|
+
# for queues without rucio storage element attached
|
|
101
|
+
if self.job.destinationSE == "local" and self.job.prodSourceLabel in ["user", "panda"]:
|
|
102
|
+
# close non-Rucio destinationDBlock immediately
|
|
103
|
+
return "closed"
|
|
104
|
+
if self.job.lockedby == "jedi" and DataServiceUtils.is_top_level_dataset(destination_data_block):
|
|
105
|
+
# set it closed in order not to trigger DDM cleanup. It will be closed by JEDI
|
|
106
|
+
return "closed"
|
|
107
|
+
if self.job.produceUnMerge():
|
|
108
|
+
return "doing"
|
|
109
|
+
|
|
110
|
+
# set status to 'tobeclosed' to trigger Rucio closing
|
|
111
|
+
return "tobeclosed"
|
|
112
|
+
|
|
113
|
+
def perform_vo_actions(self, final_status_dataset: list) -> None:
|
|
114
|
+
"""
|
|
115
|
+
Perform special actions for vo.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
final_status_dataset (list): The final status dataset.
|
|
119
|
+
"""
|
|
120
|
+
closer_plugin_class = panda_config.getPlugin("closer_plugins", self.job.VO)
|
|
121
|
+
if closer_plugin_class is None and self.job.VO == "atlas":
|
|
122
|
+
# use ATLAS plugin for ATLAS
|
|
123
|
+
from pandaserver.dataservice.closer_atlas_plugin import CloserAtlasPlugin
|
|
124
|
+
|
|
125
|
+
closer_plugin_class = CloserAtlasPlugin
|
|
126
|
+
if closer_plugin_class is not None:
|
|
127
|
+
closer_plugin = closer_plugin_class(self.job, final_status_dataset, _logger)
|
|
128
|
+
closer_plugin.execute()
|
|
129
|
+
|
|
130
|
+
def start_activator(self, dataset):
|
|
131
|
+
"""
|
|
132
|
+
Start the activator
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
dataset: Dataset.
|
|
136
|
+
final_status (str): Final status.
|
|
137
|
+
"""
|
|
138
|
+
# start Activator
|
|
139
|
+
if (
|
|
140
|
+
not DataServiceUtils.is_sub_dataset(dataset.name)
|
|
141
|
+
and self.job.jobStatus == "finished"
|
|
142
|
+
and (self.job.prodSourceLabel != "panda" or self.job.processingType not in ["merge", "unmerge"])
|
|
143
|
+
):
|
|
144
|
+
activator_thread = Activator(self.task_buffer, dataset)
|
|
145
|
+
activator_thread.run()
|
|
146
|
+
|
|
147
|
+
# main
|
|
148
|
+
def run(self):
|
|
149
|
+
"""
|
|
150
|
+
Main method to run the Closer class. It processes each destination dispatch block,
|
|
151
|
+
updates the dataset status and finalizes pending jobs if necessary.
|
|
152
|
+
"""
|
|
153
|
+
try:
|
|
154
|
+
tmp_log = LogWrapper(_logger, f"run-{naive_utcnow().isoformat('/')}-{self.panda_id}")
|
|
155
|
+
tmp_log.debug(f"Start with job status: {self.job.jobStatus}")
|
|
156
|
+
flag_complete = True
|
|
157
|
+
final_status_dataset = []
|
|
158
|
+
|
|
159
|
+
for destination_data_block in self.destination_data_blocks:
|
|
160
|
+
dataset_list = []
|
|
161
|
+
tmp_log.debug(f"start with destination dispatch block: {destination_data_block}")
|
|
162
|
+
|
|
163
|
+
# ignore task output datasets (tid) datasets
|
|
164
|
+
if DataServiceUtils.is_tid_dataset(destination_data_block):
|
|
165
|
+
tmp_log.debug(f"skip {destination_data_block}")
|
|
166
|
+
continue
|
|
167
|
+
|
|
168
|
+
# ignore HC datasets
|
|
169
|
+
if DataServiceUtils.is_hammercloud_dataset(destination_data_block) or DataServiceUtils.is_user_gangarbt_dataset(destination_data_block):
|
|
170
|
+
if not DataServiceUtils.is_sub_dataset(destination_data_block) and not DataServiceUtils.is_lib_dataset(destination_data_block):
|
|
171
|
+
tmp_log.debug(f"skip HC {destination_data_block}")
|
|
172
|
+
continue
|
|
173
|
+
|
|
174
|
+
# query dataset
|
|
175
|
+
if destination_data_block in self.dataset_map:
|
|
176
|
+
dataset = self.dataset_map[destination_data_block]
|
|
177
|
+
else:
|
|
178
|
+
dataset = self.task_buffer.queryDatasetWithMap({"name": destination_data_block})
|
|
179
|
+
|
|
180
|
+
if dataset is None:
|
|
181
|
+
tmp_log.error(f"Not found : {destination_data_block}")
|
|
182
|
+
flag_complete = False
|
|
183
|
+
continue
|
|
184
|
+
|
|
185
|
+
# skip tobedeleted/tobeclosed
|
|
186
|
+
if dataset.status in ["cleanup", "tobeclosed", "completed", "deleted"]:
|
|
187
|
+
tmp_log.debug(f"skip {destination_data_block} due to dataset status: {dataset.status}")
|
|
188
|
+
continue
|
|
189
|
+
|
|
190
|
+
dataset_list.append(dataset)
|
|
191
|
+
dataset_list.sort()
|
|
192
|
+
|
|
193
|
+
# count number of completed files
|
|
194
|
+
not_finish = self.task_buffer.countFilesWithMap({"destinationDBlock": destination_data_block, "status": "unknown"})
|
|
195
|
+
if not_finish < 0:
|
|
196
|
+
tmp_log.error(f"Invalid dispatch block file count: {not_finish}")
|
|
197
|
+
flag_complete = False
|
|
198
|
+
continue
|
|
199
|
+
|
|
200
|
+
# check if completed
|
|
201
|
+
tmp_log.debug(f"Pending file count: {not_finish}")
|
|
202
|
+
final_status = self.determine_final_status(destination_data_block)
|
|
203
|
+
|
|
204
|
+
if not_finish == 0 and EventServiceUtils.isEventServiceMerge(self.job):
|
|
205
|
+
all_in_jobset_finished = self.check_sub_datasets_in_jobset()
|
|
206
|
+
else:
|
|
207
|
+
all_in_jobset_finished = True
|
|
208
|
+
|
|
209
|
+
if not_finish == 0 and all_in_jobset_finished:
|
|
210
|
+
tmp_log.debug(f"Set final status: {final_status} to dataset: {destination_data_block}")
|
|
211
|
+
# set status
|
|
212
|
+
dataset.status = final_status
|
|
213
|
+
# update dataset in DB
|
|
214
|
+
ret_t = self.task_buffer.updateDatasets(
|
|
215
|
+
dataset_list,
|
|
216
|
+
withLock=True,
|
|
217
|
+
withCriteria="status<>:crStatus AND status<>:lockStatus ",
|
|
218
|
+
criteriaMap={":crStatus": final_status, ":lockStatus": "locked"},
|
|
219
|
+
)
|
|
220
|
+
if len(ret_t) > 0 and ret_t[0] == 1:
|
|
221
|
+
final_status_dataset += dataset_list
|
|
222
|
+
self.start_activator(dataset)
|
|
223
|
+
else:
|
|
224
|
+
# update dataset in DB
|
|
225
|
+
self.task_buffer.updateDatasets(
|
|
226
|
+
dataset_list,
|
|
227
|
+
withLock=True,
|
|
228
|
+
withCriteria="status<>:crStatus AND status<>:lockStatus ",
|
|
229
|
+
criteriaMap={":crStatus": final_status, ":lockStatus": "locked"},
|
|
230
|
+
)
|
|
231
|
+
# unset flag
|
|
232
|
+
flag_complete = False
|
|
233
|
+
# end
|
|
234
|
+
tmp_log.debug(f"end {destination_data_block}")
|
|
235
|
+
# special actions for vo
|
|
236
|
+
if flag_complete:
|
|
237
|
+
self.perform_vo_actions(final_status_dataset)
|
|
238
|
+
|
|
239
|
+
# update unmerged datasets in JEDI to trigger merging
|
|
240
|
+
if flag_complete and self.job.produceUnMerge() and final_status_dataset:
|
|
241
|
+
tmp_stat = self.task_buffer.updateUnmergedDatasets(self.job, final_status_dataset)
|
|
242
|
+
tmp_log.debug(f"updated unmerged datasets with {tmp_stat}")
|
|
243
|
+
|
|
244
|
+
tmp_log.debug("End")
|
|
245
|
+
except Exception:
|
|
246
|
+
err_type, err_value = sys.exc_info()[:2]
|
|
247
|
+
tmp_log.error(f"{err_type} {err_value}")
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ATLAS plugin for closer
|
|
3
|
+
"""
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from pandacommon.pandalogger.LogWrapper import LogWrapper
|
|
7
|
+
from pandaserver.dataservice.ddm import rucioAPI
|
|
8
|
+
from pandaserver.dataservice import DataServiceUtils
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# plugin for ATLAS closer
|
|
12
|
+
class CloserAtlasPlugin:
|
|
13
|
+
"""
|
|
14
|
+
A class used to represent the ATLAS closer plugin.
|
|
15
|
+
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
Attributes
|
|
19
|
+
----------
|
|
20
|
+
jobSpec : object
|
|
21
|
+
an object representing the job specification
|
|
22
|
+
datasets : list
|
|
23
|
+
a list of datasets to be processed
|
|
24
|
+
tmp_log : LogWrapper
|
|
25
|
+
a LogWrapper object for logging
|
|
26
|
+
|
|
27
|
+
Methods
|
|
28
|
+
-------
|
|
29
|
+
__init__(self, job, datasets, log)
|
|
30
|
+
Constructs all the necessary attributes for the CloserAtlasPlugin object.
|
|
31
|
+
execute(self)
|
|
32
|
+
Executes the plugin's main functionality.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
# constructor
|
|
36
|
+
def __init__(self, job, datasets, log):
|
|
37
|
+
"""
|
|
38
|
+
Constructs all the necessary attributes for the CloserAtlasPlugin object.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
job : object
|
|
43
|
+
an object representing the job specification
|
|
44
|
+
datasets : list
|
|
45
|
+
a list of datasets to be processed
|
|
46
|
+
log : LogWrapper
|
|
47
|
+
a LogWrapper object for logging
|
|
48
|
+
"""
|
|
49
|
+
self.jobSpec = job
|
|
50
|
+
self.datasets = datasets
|
|
51
|
+
self.tmp_log = LogWrapper(log, f"{self.jobSpec.PandaID} CloserAtlasPlugin")
|
|
52
|
+
|
|
53
|
+
# execute
|
|
54
|
+
def execute(self):
|
|
55
|
+
"""
|
|
56
|
+
Executes the main functionality of the CloserAtlasPlugin.
|
|
57
|
+
|
|
58
|
+
This method is responsible for closing datasets that meet certain criteria.
|
|
59
|
+
It only operates on production jobs that are either 'urgent' or have a high priority.
|
|
60
|
+
For each dataset in the job, if the dataset's name ends with '_sub' followed by a number and its status is 'tobeclosed',
|
|
61
|
+
it attempts to close the dataset using the rucioAPI. If an error occurs during this process, it logs a warning message.
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
bool
|
|
66
|
+
Always returns True regardless of whether the datasets were successfully closed or not.
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
# only for production
|
|
70
|
+
if self.jobSpec.prodSourceLabel not in ["managed", "test"]:
|
|
71
|
+
return True
|
|
72
|
+
# only for urgent or high prio
|
|
73
|
+
if self.jobSpec.processingType not in ["urgent"] and self.jobSpec.currentPriority <= 1000:
|
|
74
|
+
return True
|
|
75
|
+
# close datasets
|
|
76
|
+
for datasetSpec in self.datasets:
|
|
77
|
+
if not DataServiceUtils.is_sub_dataset(datasetSpec.name):
|
|
78
|
+
continue
|
|
79
|
+
if datasetSpec.status != "tobeclosed":
|
|
80
|
+
continue
|
|
81
|
+
try:
|
|
82
|
+
self.tmp_log.debug(f"immediate close {datasetSpec.name}")
|
|
83
|
+
rucioAPI.close_dataset(datasetSpec.name)
|
|
84
|
+
except Exception:
|
|
85
|
+
errtype, errvalue = sys.exc_info()[:2]
|
|
86
|
+
self.tmp_log.warning(f"failed to close : {errtype} {errvalue}")
|
|
87
|
+
except Exception:
|
|
88
|
+
errtype, errvalue = sys.exc_info()[:2]
|
|
89
|
+
self.tmp_log.warning(f"failed to execute : {errtype} {errvalue}")
|
|
90
|
+
return True
|