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,259 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import random
|
|
3
|
+
import re
|
|
4
|
+
import traceback
|
|
5
|
+
|
|
6
|
+
from pandaserver.config import panda_config
|
|
7
|
+
from pandaserver.dataservice import DataServiceUtils
|
|
8
|
+
from pandaserver.taskbuffer import JobUtils
|
|
9
|
+
from pandaserver.taskbuffer.JediTaskSpec import JediTaskSpec
|
|
10
|
+
|
|
11
|
+
from .TaskRefinerBase import TaskRefinerBase
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# brokerage for ATLAS analysis
|
|
15
|
+
class AtlasAnalTaskRefiner(TaskRefinerBase):
|
|
16
|
+
# constructor
|
|
17
|
+
def __init__(self, taskBufferIF, ddmIF):
|
|
18
|
+
TaskRefinerBase.__init__(self, taskBufferIF, ddmIF)
|
|
19
|
+
|
|
20
|
+
# extract common parameters
|
|
21
|
+
def extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule):
|
|
22
|
+
processingTypes = taskParamMap["processingType"].split("-")
|
|
23
|
+
# set ddmBackEnd
|
|
24
|
+
if "ddmBackEnd" not in taskParamMap:
|
|
25
|
+
taskParamMap["ddmBackEnd"] = "rucio"
|
|
26
|
+
# set sourceURL
|
|
27
|
+
try:
|
|
28
|
+
if "sourceURL" in taskParamMap:
|
|
29
|
+
for tmpItem in taskParamMap["jobParameters"]:
|
|
30
|
+
if "value" in tmpItem:
|
|
31
|
+
tmpItem["value"] = re.sub("\$\{SURL\}", taskParamMap["sourceURL"], tmpItem["value"])
|
|
32
|
+
except Exception:
|
|
33
|
+
pass
|
|
34
|
+
if hasattr(panda_config, "wn_script_base_url"):
|
|
35
|
+
base_url = panda_config.wn_script_base_url
|
|
36
|
+
else:
|
|
37
|
+
protocol = "https" if panda_config.pserverportcache == 443 else "http"
|
|
38
|
+
base_url = f"{protocol}://{panda_config.pserveralias}:{panda_config.pserverportcache}"
|
|
39
|
+
# set transPath
|
|
40
|
+
if "transPath" not in taskParamMap:
|
|
41
|
+
if "athena" in processingTypes:
|
|
42
|
+
# athena
|
|
43
|
+
taskParamMap["transPath"] = f"{base_url}/trf/user/runAthena-00-00-12"
|
|
44
|
+
elif "cont" in processingTypes:
|
|
45
|
+
# container
|
|
46
|
+
taskParamMap["transPath"] = f"{base_url}/trf/user/runcontainer"
|
|
47
|
+
else:
|
|
48
|
+
# general executable
|
|
49
|
+
taskParamMap["transPath"] = f"{base_url}/trf/user/runGen-00-00-02"
|
|
50
|
+
# shorter base walltime
|
|
51
|
+
if "baseWalltime" not in taskParamMap:
|
|
52
|
+
taskParamMap["baseWalltime"] = 60
|
|
53
|
+
# set transPath for build
|
|
54
|
+
if "buildSpec" in taskParamMap and "transPath" not in taskParamMap["buildSpec"]:
|
|
55
|
+
if "athena" in processingTypes:
|
|
56
|
+
# athena
|
|
57
|
+
taskParamMap["buildSpec"]["transPath"] = f"{base_url}/trf/user/buildJob-00-00-03"
|
|
58
|
+
else:
|
|
59
|
+
# general executable
|
|
60
|
+
taskParamMap["buildSpec"]["transPath"] = f"{base_url}/trf/user/buildGen-00-00-01"
|
|
61
|
+
# set transPath for preprocessing
|
|
62
|
+
if "preproSpec" in taskParamMap and "transPath" not in taskParamMap["preproSpec"]:
|
|
63
|
+
if "evp" in processingTypes:
|
|
64
|
+
# event picking
|
|
65
|
+
taskParamMap["preproSpec"]["transPath"] = f"{base_url}/trf/user/preEvtPick-00-00-01"
|
|
66
|
+
elif "grl" in processingTypes:
|
|
67
|
+
# good run list
|
|
68
|
+
taskParamMap["preproSpec"]["transPath"] = f"{base_url}/trf/user/preGoodRunList-00-00-01"
|
|
69
|
+
# set transPath for merge
|
|
70
|
+
if "mergeSpec" in taskParamMap and "transPath" not in taskParamMap["mergeSpec"]:
|
|
71
|
+
taskParamMap["mergeSpec"]["transPath"] = f"{base_url}/trf/user/runMerge-00-00-02"
|
|
72
|
+
# min ram count
|
|
73
|
+
if "ramCount" not in taskParamMap:
|
|
74
|
+
taskParamMap["ramCount"] = 2000
|
|
75
|
+
taskParamMap["ramUnit"] = "MBPerCore"
|
|
76
|
+
# disk count
|
|
77
|
+
if "outDiskCount" not in taskParamMap:
|
|
78
|
+
out_disk_count_default = self.taskBufferIF.getConfigValue("taskrefiner", "OUTDISKCOUNT_ANALY_KB", "jedi", "atlas")
|
|
79
|
+
if out_disk_count_default is None or out_disk_count_default < 0:
|
|
80
|
+
out_disk_count_default = 500
|
|
81
|
+
taskParamMap["outDiskCount"] = out_disk_count_default
|
|
82
|
+
taskParamMap["outDiskUnit"] = "kB"
|
|
83
|
+
# set cpu time unit to use HS06
|
|
84
|
+
if "cpuTimeUnit" not in taskParamMap:
|
|
85
|
+
taskParamMap["cpuTimeUnit"] = "HS06sPerEvent"
|
|
86
|
+
# use local IO for ancient releases since inputfilepeeker+xrootd is problematic
|
|
87
|
+
if "transUses" in taskParamMap and taskParamMap["transUses"]:
|
|
88
|
+
try:
|
|
89
|
+
ver = taskParamMap["transUses"].split("-")[1]
|
|
90
|
+
m = re.search("^(\d{2})\.(\d{2})\.", ver)
|
|
91
|
+
if m is not None:
|
|
92
|
+
major = int(m.group(1))
|
|
93
|
+
minor = int(m.group(2))
|
|
94
|
+
if major < 20 or (major == 20 and minor <= 20):
|
|
95
|
+
taskParamMap["useLocalIO"] = 1
|
|
96
|
+
except Exception:
|
|
97
|
+
pass
|
|
98
|
+
# scout success rate
|
|
99
|
+
if "scoutSuccessRate" not in taskParamMap:
|
|
100
|
+
taskParamMap["scoutSuccessRate"] = 5
|
|
101
|
+
# directIO
|
|
102
|
+
if "useLocalIO" not in taskParamMap and "allowInputLAN" not in taskParamMap:
|
|
103
|
+
taskParamMap["allowInputLAN"] = "use"
|
|
104
|
+
# current priority
|
|
105
|
+
if "currentPriority" in taskParamMap and (taskParamMap["currentPriority"] < 900 or taskParamMap["currentPriority"] > 1100):
|
|
106
|
+
taskParamMap["currentPriority"] = 1000
|
|
107
|
+
isSU, isSG = self.taskBufferIF.isSuperUser(taskParamMap["userName"])
|
|
108
|
+
if isSU or (isSG and "workingGroup" in taskParamMap):
|
|
109
|
+
# super high priority to jump over others
|
|
110
|
+
if "currentPriority" not in taskParamMap or taskParamMap["currentPriority"] < JobUtils.priorityTasksToJumpOver:
|
|
111
|
+
taskParamMap["currentPriority"] = JobUtils.priorityTasksToJumpOver
|
|
112
|
+
# max attempts
|
|
113
|
+
if "maxAttempt" not in taskParamMap:
|
|
114
|
+
taskParamMap["maxAttempt"] = 10
|
|
115
|
+
if "maxFailure" not in taskParamMap:
|
|
116
|
+
taskParamMap["maxFailure"] = 3
|
|
117
|
+
# target walltime
|
|
118
|
+
if "maxWalltime" not in taskParamMap:
|
|
119
|
+
tgtWalltime = self.taskBufferIF.getConfigValue("taskrefiner", "USER_JOB_TARGET_WALLTIME", "jedi", "atlas")
|
|
120
|
+
if tgtWalltime:
|
|
121
|
+
taskParamMap["maxWalltime"] = tgtWalltime
|
|
122
|
+
# choose N % of tasks to enable input data motion
|
|
123
|
+
fracTaskWithDataMotion = self.taskBufferIF.getConfigValue("taskrefiner", "USER_TASKS_MOVE_INPUT", "jedi", "atlas")
|
|
124
|
+
if fracTaskWithDataMotion is not None and fracTaskWithDataMotion > 0:
|
|
125
|
+
if random.randint(1, 100) <= fracTaskWithDataMotion:
|
|
126
|
+
if "currentPriority" not in taskParamMap:
|
|
127
|
+
taskParamMap["currentPriority"] = taskParamMap["taskPriority"]
|
|
128
|
+
taskParamMap["taskPriority"] = 1001
|
|
129
|
+
# image name
|
|
130
|
+
if "container_name" not in taskParamMap:
|
|
131
|
+
try:
|
|
132
|
+
for tmpItem in taskParamMap["jobParameters"]:
|
|
133
|
+
if "value" in tmpItem:
|
|
134
|
+
tmpM = re.search("--containerImage\s+([^\s]+)", tmpItem["value"])
|
|
135
|
+
if tmpM is not None:
|
|
136
|
+
taskParamMap["container_name"] = tmpM.group(1)
|
|
137
|
+
break
|
|
138
|
+
except Exception:
|
|
139
|
+
pass
|
|
140
|
+
# extract container name from architecture
|
|
141
|
+
if "container_name" not in taskParamMap and "architecture" in taskParamMap and isinstance(taskParamMap["architecture"], str):
|
|
142
|
+
try:
|
|
143
|
+
# json-serialized architecture
|
|
144
|
+
check_str = json.loads(taskParamMap["architecture"]).get("encoded_platform", "")
|
|
145
|
+
except Exception:
|
|
146
|
+
# encoded architecture
|
|
147
|
+
check_str = taskParamMap["architecture"]
|
|
148
|
+
m = re.search(r"\+([^\s+@#&]+)", check_str)
|
|
149
|
+
if m:
|
|
150
|
+
# use the architecture as container name
|
|
151
|
+
tmp_container_name = m.group(1)
|
|
152
|
+
taskParamMap["container_name"] = tmp_container_name
|
|
153
|
+
# remove the container name from architecture
|
|
154
|
+
tmp_architecture = re.sub(rf"\+{tmp_container_name}", "", taskParamMap["architecture"])
|
|
155
|
+
taskParamMap["architecture"] = tmp_architecture
|
|
156
|
+
self.tmpLog.debug(f"tweaked architecture: container_name={tmp_container_name} new_architecture={tmp_architecture}")
|
|
157
|
+
|
|
158
|
+
# message driven, choose N % of tasks to enable
|
|
159
|
+
if "messageDriven" not in taskParamMap:
|
|
160
|
+
analy_md_percent = self.taskBufferIF.getConfigValue("taskrefiner", "USER_TASKS_MESSAGE_DRIVEN_PERCENT", "jedi", "atlas")
|
|
161
|
+
if analy_md_percent and random.uniform(0, 100) <= analy_md_percent:
|
|
162
|
+
taskParamMap["messageDriven"] = True
|
|
163
|
+
# push status changes, choose N % of tasks to enable
|
|
164
|
+
if "pushStatusChanges" not in taskParamMap:
|
|
165
|
+
analy_pc_percent = self.taskBufferIF.getConfigValue("taskrefiner", "USER_TASKS_PUSH_STATUS_CHANGES_PERCENT", "jedi", "atlas")
|
|
166
|
+
if analy_pc_percent and random.uniform(0, 100) <= analy_pc_percent:
|
|
167
|
+
taskParamMap["pushStatusChanges"] = True
|
|
168
|
+
# disable skipScout fot tasks without for group production role
|
|
169
|
+
if "skipScout" in taskParamMap and ("official" not in taskParamMap or not taskParamMap["official"]):
|
|
170
|
+
del taskParamMap["skipScout"]
|
|
171
|
+
# max core count
|
|
172
|
+
if "maxCoreCount" not in taskParamMap:
|
|
173
|
+
max_core_count = self.taskBufferIF.getConfigValue("taskrefiner", "USER_TASKS_MAX_CORE_COUNT", "jedi", "atlas")
|
|
174
|
+
if max_core_count is None:
|
|
175
|
+
max_core_count = 16
|
|
176
|
+
taskParamMap["maxCoreCount"] = max_core_count
|
|
177
|
+
# set forceStaged when input dataset is RAW
|
|
178
|
+
if "forceStaged" not in taskParamMap:
|
|
179
|
+
for item in taskParamMap.get("jobParameters", []):
|
|
180
|
+
if item["type"] == "template" and "dataset" in item and item["param_type"] == "input":
|
|
181
|
+
dataset_name = item["dataset"]
|
|
182
|
+
if DataServiceUtils.getDatasetType(dataset_name) == "RAW":
|
|
183
|
+
taskParamMap["forceStaged"] = True
|
|
184
|
+
break
|
|
185
|
+
# update task parameters
|
|
186
|
+
self.updatedTaskParams = taskParamMap
|
|
187
|
+
# call base method
|
|
188
|
+
TaskRefinerBase.extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule)
|
|
189
|
+
|
|
190
|
+
# main
|
|
191
|
+
def doRefine(self, jediTaskID, taskParamMap):
|
|
192
|
+
# make logger
|
|
193
|
+
tmpLog = self.tmpLog
|
|
194
|
+
tmpLog.debug(f"start taskType={self.taskSpec.taskType}")
|
|
195
|
+
try:
|
|
196
|
+
# preprocessing
|
|
197
|
+
tmpStat, taskParamMap = self.doPreProRefine(taskParamMap)
|
|
198
|
+
if tmpStat is True:
|
|
199
|
+
tmpLog.debug("done for preprocessing")
|
|
200
|
+
return self.SC_SUCCEEDED
|
|
201
|
+
if tmpStat is False:
|
|
202
|
+
# failed
|
|
203
|
+
tmpLog.error("doPreProRefine failed")
|
|
204
|
+
return self.SC_FAILED
|
|
205
|
+
# normal refine
|
|
206
|
+
self.doBasicRefine(taskParamMap)
|
|
207
|
+
# set nosplit+repeat for DBR
|
|
208
|
+
for datasetSpec in self.inSecDatasetSpecList:
|
|
209
|
+
# get the latest version of DBR
|
|
210
|
+
if datasetSpec.datasetName == "DBR_LATEST":
|
|
211
|
+
tmpLog.debug(f"resolving real name for {datasetSpec.datasetName}")
|
|
212
|
+
datasetSpec.datasetName = self.ddmIF.getInterface(self.taskSpec.vo).getLatestDBRelease(useResultCache=3600)
|
|
213
|
+
datasetSpec.containerName = datasetSpec.datasetName
|
|
214
|
+
# set attributes to DBR
|
|
215
|
+
if DataServiceUtils.isDBR(datasetSpec.datasetName):
|
|
216
|
+
datasetSpec.attributes = "repeat,nosplit"
|
|
217
|
+
# check invalid characters
|
|
218
|
+
for datasetSpec in self.outDatasetSpecList:
|
|
219
|
+
if not DataServiceUtils.checkInvalidCharacters(datasetSpec.datasetName):
|
|
220
|
+
errStr = f"invalid characters in {datasetSpec.datasetName}"
|
|
221
|
+
tmpLog.error(errStr)
|
|
222
|
+
self.taskSpec.setErrDiag(errStr, None)
|
|
223
|
+
return self.SC_FATAL
|
|
224
|
+
# destination
|
|
225
|
+
if "destination" in taskParamMap:
|
|
226
|
+
for datasetSpec in self.outDatasetSpecList:
|
|
227
|
+
datasetSpec.destination = taskParamMap["destination"]
|
|
228
|
+
# use build
|
|
229
|
+
if "buildSpec" in taskParamMap:
|
|
230
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["useBuild"])
|
|
231
|
+
# use template dataset
|
|
232
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["instantiateTmpl"])
|
|
233
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["instantiateTmplSite"])
|
|
234
|
+
for datasetSpec in self.outDatasetSpecList:
|
|
235
|
+
datasetSpec.type = f"tmpl_{datasetSpec.type}"
|
|
236
|
+
# get jobsetID
|
|
237
|
+
tmpStat, tmpJobID = self.taskBufferIF.getUserJobsetID_JEDI(self.taskSpec.userName)
|
|
238
|
+
if not tmpStat:
|
|
239
|
+
tmpLog.error("failed to get jobsetID failed")
|
|
240
|
+
return self.SC_FAILED
|
|
241
|
+
self.taskSpec.reqID = tmpJobID
|
|
242
|
+
# site limitation
|
|
243
|
+
if "excludedSite" in taskParamMap and "includedSite" in taskParamMap:
|
|
244
|
+
self.taskSpec.setLimitedSites("incexc")
|
|
245
|
+
elif "excludedSite" in taskParamMap:
|
|
246
|
+
self.taskSpec.setLimitedSites("exc")
|
|
247
|
+
elif "includedSite" in taskParamMap:
|
|
248
|
+
self.taskSpec.setLimitedSites("inc")
|
|
249
|
+
# input prestaging
|
|
250
|
+
if self.taskSpec.inputPreStaging():
|
|
251
|
+
# set first contents feed flag
|
|
252
|
+
self.taskSpec.set_first_contents_feed(True)
|
|
253
|
+
except Exception as e:
|
|
254
|
+
errStr = f"doRefine failed with {str(e)}"
|
|
255
|
+
tmpLog.error(f"{errStr} {traceback.format_exc()}")
|
|
256
|
+
self.taskSpec.setErrDiag(errStr, None)
|
|
257
|
+
raise e
|
|
258
|
+
tmpLog.debug("done")
|
|
259
|
+
return self.SC_SUCCEEDED
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import json
|
|
3
|
+
import random
|
|
4
|
+
import re
|
|
5
|
+
import traceback
|
|
6
|
+
|
|
7
|
+
from pandacommon.pandautils.PandaUtils import naive_utcnow
|
|
8
|
+
|
|
9
|
+
from pandajedi.jedicore import JediException
|
|
10
|
+
from pandaserver.dataservice import DataServiceUtils
|
|
11
|
+
|
|
12
|
+
from .TaskRefinerBase import TaskRefinerBase
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# brokerage for ATLAS production
|
|
16
|
+
class AtlasProdTaskRefiner(TaskRefinerBase):
|
|
17
|
+
# constructor
|
|
18
|
+
def __init__(self, taskBufferIF, ddmIF):
|
|
19
|
+
TaskRefinerBase.__init__(self, taskBufferIF, ddmIF)
|
|
20
|
+
|
|
21
|
+
# extract common parameters
|
|
22
|
+
def extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule):
|
|
23
|
+
tmpLog = self.tmpLog
|
|
24
|
+
# set ddmBackEnd
|
|
25
|
+
if "ddmBackEnd" not in taskParamMap:
|
|
26
|
+
taskParamMap["ddmBackEnd"] = "rucio"
|
|
27
|
+
# get number of unprocessed events for event service
|
|
28
|
+
autoEsConversion = False
|
|
29
|
+
if "esConvertible" in taskParamMap and taskParamMap["esConvertible"] is True:
|
|
30
|
+
maxPrio = self.taskBufferIF.getConfigValue("taskrefiner", "AES_MAXTASKPRIORITY", "jedi", "atlas")
|
|
31
|
+
minPrio = self.taskBufferIF.getConfigValue("taskrefiner", "AES_MINTASKPRIORITY", "jedi", "atlas")
|
|
32
|
+
if maxPrio is not None and maxPrio < taskParamMap["taskPriority"]:
|
|
33
|
+
pass
|
|
34
|
+
elif minPrio is not None and minPrio > taskParamMap["taskPriority"]:
|
|
35
|
+
pass
|
|
36
|
+
else:
|
|
37
|
+
# get threshold
|
|
38
|
+
minNumEvents = self.taskBufferIF.getConfigValue("taskrefiner", "AES_EVENTPOOLSIZE", "jedi", "atlas")
|
|
39
|
+
maxPending = self.taskBufferIF.getConfigValue("taskrefiner", "AES_MAXPENDING", "jedi", "atlas")
|
|
40
|
+
nEvents, lastTaskTime, nPendingTasks = self.taskBufferIF.getNumUnprocessedEvents_JEDI(
|
|
41
|
+
taskParamMap["vo"], taskParamMap["prodSourceLabel"], {"eventService": 1}, {"gshare": "Validation"}
|
|
42
|
+
)
|
|
43
|
+
tmpStr = "check for ES "
|
|
44
|
+
tmpStr += f"tot_num_unprocessed_events_AES={nEvents} target_num_events_AES={minNumEvents} last_AES_task_time={lastTaskTime} "
|
|
45
|
+
tmpStr += f"num_pending_tasks_AES={nPendingTasks} max_pending_tasks_AES={maxPending} "
|
|
46
|
+
tmpLog.info(tmpStr)
|
|
47
|
+
# not chane many tasks at once
|
|
48
|
+
if lastTaskTime is None or (lastTaskTime < naive_utcnow() - datetime.timedelta(minutes=5)):
|
|
49
|
+
if minNumEvents is not None and nEvents < minNumEvents and maxPending is not None and (maxPending is None or maxPending > nPendingTasks):
|
|
50
|
+
autoEsConversion = True
|
|
51
|
+
tmpLog.info("will be converted to AES unless it goes to pending")
|
|
52
|
+
# add ES paramsters
|
|
53
|
+
if ("esFraction" in taskParamMap and taskParamMap["esFraction"] > 0) or ("esConvertible" in taskParamMap and taskParamMap["esConvertible"] is True):
|
|
54
|
+
tmpStr = "<PANDA_ES_ONLY>--eventService=True</PANDA_ES_ONLY>"
|
|
55
|
+
taskParamMap["jobParameters"].append({"type": "constant", "value": tmpStr})
|
|
56
|
+
if ("esFraction" in taskParamMap and taskParamMap["esFraction"] > 0) or autoEsConversion:
|
|
57
|
+
if "nEventsPerWorker" not in taskParamMap and (("esFraction" in taskParamMap and taskParamMap["esFraction"] > random.random()) or autoEsConversion):
|
|
58
|
+
taskParamMap["nEventsPerWorker"] = 1
|
|
59
|
+
taskParamMap["registerEsFiles"] = True
|
|
60
|
+
if "nEsConsumers" not in taskParamMap:
|
|
61
|
+
tmpVal = self.taskBufferIF.getConfigValue("taskrefiner", "AES_NESCONSUMERS", "jedi", "atlas")
|
|
62
|
+
if tmpVal is None:
|
|
63
|
+
tmpVal = 1
|
|
64
|
+
taskParamMap["nEsConsumers"] = tmpVal
|
|
65
|
+
if "nSitesPerJob" not in taskParamMap:
|
|
66
|
+
tmpVal = self.taskBufferIF.getConfigValue("taskrefiner", "AES_NSITESPERJOB", "jedi", "atlas")
|
|
67
|
+
if tmpVal is not None:
|
|
68
|
+
taskParamMap["nSitesPerJob"] = tmpVal
|
|
69
|
+
if "mergeEsOnOS" not in taskParamMap:
|
|
70
|
+
taskParamMap["mergeEsOnOS"] = True
|
|
71
|
+
if "maxAttemptES" not in taskParamMap:
|
|
72
|
+
taskParamMap["maxAttemptES"] = 1
|
|
73
|
+
if "maxAttemptEsJob" not in taskParamMap:
|
|
74
|
+
taskParamMap["maxAttemptEsJob"] = 0
|
|
75
|
+
if "notDiscardEvents" not in taskParamMap:
|
|
76
|
+
taskParamMap["notDiscardEvents"] = True
|
|
77
|
+
if "decAttOnFailedES" not in taskParamMap:
|
|
78
|
+
taskParamMap["decAttOnFailedES"] = True
|
|
79
|
+
taskParamMap["coreCount"] = 0
|
|
80
|
+
taskParamMap["resurrectConsumers"] = True
|
|
81
|
+
# push status changes, choose N % of tasks to enable
|
|
82
|
+
if "pushStatusChanges" not in taskParamMap:
|
|
83
|
+
prod_pc_percent = self.taskBufferIF.getConfigValue("taskrefiner", "PROD_TASKS_PUSH_STATUS_CHANGES_PERCENT", "jedi", "atlas")
|
|
84
|
+
if prod_pc_percent and random.uniform(0, 100) <= prod_pc_percent:
|
|
85
|
+
taskParamMap["pushStatusChanges"] = True
|
|
86
|
+
# serialize architecture
|
|
87
|
+
if "architecture" in taskParamMap and isinstance(taskParamMap["architecture"], dict):
|
|
88
|
+
# convert to string
|
|
89
|
+
taskParamMap["architecture"] = json.dumps(taskParamMap["architecture"])
|
|
90
|
+
# call base method
|
|
91
|
+
TaskRefinerBase.extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule)
|
|
92
|
+
|
|
93
|
+
# main
|
|
94
|
+
def doRefine(self, jediTaskID, taskParamMap):
|
|
95
|
+
# make logger
|
|
96
|
+
tmpLog = self.tmpLog
|
|
97
|
+
tmpLog.debug(f"start taskType={self.taskSpec.taskType}")
|
|
98
|
+
try:
|
|
99
|
+
# basic refine
|
|
100
|
+
self.doBasicRefine(taskParamMap)
|
|
101
|
+
# set nosplit+repeat for DBR
|
|
102
|
+
for datasetSpec in self.inSecDatasetSpecList:
|
|
103
|
+
if DataServiceUtils.isDBR(datasetSpec.datasetName):
|
|
104
|
+
datasetSpec.attributes = "repeat,nosplit"
|
|
105
|
+
# enable consistency check
|
|
106
|
+
if self.taskSpec.parent_tid not in [None, self.taskSpec.jediTaskID]:
|
|
107
|
+
for datasetSpec in self.inMasterDatasetSpec:
|
|
108
|
+
if datasetSpec.isMaster() and datasetSpec.type == "input":
|
|
109
|
+
datasetSpec.enableCheckConsistency()
|
|
110
|
+
# append attempt number
|
|
111
|
+
for tmpKey, tmpOutTemplateMapList in self.outputTemplateMap.items():
|
|
112
|
+
for tmpOutTemplateMap in tmpOutTemplateMapList:
|
|
113
|
+
outFileTemplate = tmpOutTemplateMap["filenameTemplate"]
|
|
114
|
+
if re.search("\.\d+$", outFileTemplate) is None and not outFileTemplate.endswith(".panda.um"):
|
|
115
|
+
tmpOutTemplateMap["filenameTemplate"] = outFileTemplate + ".1"
|
|
116
|
+
# extract input datatype
|
|
117
|
+
datasetTypeListIn = []
|
|
118
|
+
for datasetSpec in self.inMasterDatasetSpec + self.inSecDatasetSpecList:
|
|
119
|
+
datasetType = DataServiceUtils.getDatasetType(datasetSpec.datasetName)
|
|
120
|
+
if datasetType not in ["", None]:
|
|
121
|
+
datasetTypeListIn.append(datasetType)
|
|
122
|
+
# extract datatype and set destination if necessary
|
|
123
|
+
datasetTypeList = []
|
|
124
|
+
for datasetSpec in self.outDatasetSpecList:
|
|
125
|
+
datasetType = DataServiceUtils.getDatasetType(datasetSpec.datasetName)
|
|
126
|
+
if datasetType not in ["", None]:
|
|
127
|
+
datasetTypeList.append(datasetType)
|
|
128
|
+
# set numThrottled to use the task throttling mechanism
|
|
129
|
+
if "noThrottle" not in taskParamMap:
|
|
130
|
+
self.taskSpec.numThrottled = 0
|
|
131
|
+
# set to register datasets
|
|
132
|
+
self.taskSpec.setToRegisterDatasets()
|
|
133
|
+
# set transient to parent datasets
|
|
134
|
+
if self.taskSpec.processingType in ["merge"] and self.taskSpec.parent_tid not in [None, self.taskSpec.jediTaskID]:
|
|
135
|
+
# get parent
|
|
136
|
+
tmpStat, parentTaskSpec = self.taskBufferIF.getTaskDatasetsWithID_JEDI(self.taskSpec.parent_tid, None, False)
|
|
137
|
+
if tmpStat and parentTaskSpec is not None:
|
|
138
|
+
# set transient to parent datasets
|
|
139
|
+
metaData = {"transient": True}
|
|
140
|
+
for datasetSpec in parentTaskSpec.datasetSpecList:
|
|
141
|
+
if datasetSpec.type in ["log", "output"]:
|
|
142
|
+
datasetType = DataServiceUtils.getDatasetType(datasetSpec.datasetName)
|
|
143
|
+
if datasetType not in ["", None] and datasetType in datasetTypeList and datasetType in datasetTypeListIn:
|
|
144
|
+
tmpLog.info(
|
|
145
|
+
"set metadata={0} to parent jediTaskID={1}:datasetID={2}:Name={3}".format(
|
|
146
|
+
str(metaData), self.taskSpec.parent_tid, datasetSpec.datasetID, datasetSpec.datasetName
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
for metadataName, metadaValue in metaData.items():
|
|
150
|
+
self.ddmIF.getInterface(self.taskSpec.vo).setDatasetMetadata(datasetSpec.datasetName, metadataName, metadaValue)
|
|
151
|
+
# input prestaging
|
|
152
|
+
if self.taskSpec.inputPreStaging():
|
|
153
|
+
# set first contents feed flag
|
|
154
|
+
self.taskSpec.set_first_contents_feed(True)
|
|
155
|
+
except JediException.UnknownDatasetError as e:
|
|
156
|
+
tmpLog.debug(f"in doRefine. {str(e)}")
|
|
157
|
+
raise e
|
|
158
|
+
except Exception as e:
|
|
159
|
+
tmpLog.error(f"doRefine failed with {str(e)} {traceback.format_exc()}")
|
|
160
|
+
raise e
|
|
161
|
+
tmpLog.debug("done")
|
|
162
|
+
return self.SC_SUCCEEDED
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from pandaserver.taskbuffer.JediTaskSpec import JediTaskSpec
|
|
4
|
+
|
|
5
|
+
from .TaskRefinerBase import TaskRefinerBase
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# refiner for general purpose
|
|
9
|
+
class GenTaskRefiner(TaskRefinerBase):
|
|
10
|
+
# constructor
|
|
11
|
+
def __init__(self, taskBufferIF, ddmIF):
|
|
12
|
+
TaskRefinerBase.__init__(self, taskBufferIF, ddmIF)
|
|
13
|
+
|
|
14
|
+
# extract common parameters
|
|
15
|
+
def extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule):
|
|
16
|
+
if "cloud" not in taskParamMap and "workingGroup" in taskParamMap:
|
|
17
|
+
taskParamMap["cloud"] = taskParamMap["workingGroup"]
|
|
18
|
+
if "transPath" not in taskParamMap:
|
|
19
|
+
taskParamMap["transPath"] = "https://pandaserver-doma.cern.ch/trf/user/runGen-00-00-02"
|
|
20
|
+
# set sourceURL
|
|
21
|
+
try:
|
|
22
|
+
if "sourceURL" in taskParamMap:
|
|
23
|
+
for tmpItem in taskParamMap["jobParameters"]:
|
|
24
|
+
if "value" in tmpItem:
|
|
25
|
+
tmpItem["value"] = re.sub("\$\{SURL\}", taskParamMap["sourceURL"], tmpItem["value"])
|
|
26
|
+
except Exception:
|
|
27
|
+
pass
|
|
28
|
+
# min ram count
|
|
29
|
+
if "ramCount" not in taskParamMap:
|
|
30
|
+
taskParamMap["ramCount"] = 2000
|
|
31
|
+
taskParamMap["ramUnit"] = "MBPerCore"
|
|
32
|
+
# push status changes
|
|
33
|
+
if "pushStatusChanges" not in taskParamMap:
|
|
34
|
+
taskParamMap["pushStatusChanges"] = True
|
|
35
|
+
# fine-grained
|
|
36
|
+
if "fineGrainedProc" in taskParamMap:
|
|
37
|
+
taskParamMap["notDiscardEvents"] = True
|
|
38
|
+
taskParamMap["maxAttemptEsJob"] = 0
|
|
39
|
+
taskParamMap["maxAttemptES"] = 1
|
|
40
|
+
# message driven
|
|
41
|
+
if "messageDriven" not in taskParamMap:
|
|
42
|
+
taskParamMap["messageDriven"] = True
|
|
43
|
+
# use cloud as VO
|
|
44
|
+
taskParamMap["cloudAsVO"] = True
|
|
45
|
+
# update task parameters
|
|
46
|
+
self.updatedTaskParams = taskParamMap
|
|
47
|
+
# call base method
|
|
48
|
+
TaskRefinerBase.extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule)
|
|
49
|
+
|
|
50
|
+
# main
|
|
51
|
+
def doRefine(self, jediTaskID, taskParamMap):
|
|
52
|
+
# normal refine
|
|
53
|
+
self.doBasicRefine(taskParamMap)
|
|
54
|
+
# get DDM I/F to check
|
|
55
|
+
if self.ddmIF.getInterface(self.taskSpec.vo, self.taskSpec.cloud):
|
|
56
|
+
# use template dataset
|
|
57
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["instantiateTmpl"])
|
|
58
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["instantiateTmplSite"])
|
|
59
|
+
for datasetSpec in self.outDatasetSpecList:
|
|
60
|
+
datasetSpec.type = f"tmpl_{datasetSpec.type}"
|
|
61
|
+
return self.SC_SUCCEEDED
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# convert UTF-8 to ASCII in json dumps
|
|
6
|
+
def unicodeConvert(input):
|
|
7
|
+
if isinstance(input, dict):
|
|
8
|
+
retMap = {}
|
|
9
|
+
for tmpKey, tmpVal in input.items():
|
|
10
|
+
retMap[unicodeConvert(tmpKey)] = unicodeConvert(tmpVal)
|
|
11
|
+
return retMap
|
|
12
|
+
elif isinstance(input, list):
|
|
13
|
+
retList = []
|
|
14
|
+
for tmpItem in input:
|
|
15
|
+
retList.append(unicodeConvert(tmpItem))
|
|
16
|
+
return retList
|
|
17
|
+
|
|
18
|
+
return input
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# decode
|
|
22
|
+
def decodeJSON(inputStr):
|
|
23
|
+
return json.loads(inputStr, object_hook=unicodeConvert)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# encode
|
|
27
|
+
def encodeJSON(inputMap):
|
|
28
|
+
return json.dumps(inputMap)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# extract stream name
|
|
32
|
+
def extractStreamName(valStr):
|
|
33
|
+
tmpMatch = re.search("\$\{([^\}]+)\}", valStr)
|
|
34
|
+
if tmpMatch is None:
|
|
35
|
+
return None
|
|
36
|
+
# remove decorators
|
|
37
|
+
streamName = tmpMatch.group(1)
|
|
38
|
+
streamName = streamName.split("/")[0]
|
|
39
|
+
return streamName
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# extract output filename template and replace the value field
|
|
43
|
+
def extractReplaceOutFileTemplate(valStr, streamName):
|
|
44
|
+
outFileTempl = valStr.split("=")[-1]
|
|
45
|
+
outFileTempl = outFileTempl.replace("'", "")
|
|
46
|
+
valStr = valStr.replace(outFileTempl, f"${{{streamName}}}")
|
|
47
|
+
return outFileTempl, valStr
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# extract file list
|
|
51
|
+
def extractFileList(taskParamMap, datasetName):
|
|
52
|
+
baseDatasetName = datasetName.split(":")[-1]
|
|
53
|
+
if "log" in taskParamMap:
|
|
54
|
+
itemList = taskParamMap["jobParameters"] + [taskParamMap["log"]]
|
|
55
|
+
else:
|
|
56
|
+
itemList = taskParamMap["jobParameters"]
|
|
57
|
+
fileList = []
|
|
58
|
+
includePatt = []
|
|
59
|
+
excludePatt = []
|
|
60
|
+
for tmpItem in itemList:
|
|
61
|
+
if (
|
|
62
|
+
tmpItem["type"] == "template"
|
|
63
|
+
and "dataset" in tmpItem
|
|
64
|
+
and (
|
|
65
|
+
(tmpItem["dataset"] == datasetName or tmpItem["dataset"] == baseDatasetName)
|
|
66
|
+
or ("expandedList" in tmpItem and (datasetName in tmpItem["expandedList"] or baseDatasetName in tmpItem["expandedList"]))
|
|
67
|
+
)
|
|
68
|
+
):
|
|
69
|
+
if "files" in tmpItem:
|
|
70
|
+
fileList = tmpItem["files"]
|
|
71
|
+
if "include" in tmpItem:
|
|
72
|
+
includePatt = tmpItem["include"].split(",")
|
|
73
|
+
if "exclude" in tmpItem:
|
|
74
|
+
excludePatt = tmpItem["exclude"].split(",")
|
|
75
|
+
return fileList, includePatt, excludePatt
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# append dataset
|
|
79
|
+
def appendDataset(taskParamMap, datasetSpec, fileList):
|
|
80
|
+
# make item for dataset
|
|
81
|
+
tmpItem = {}
|
|
82
|
+
tmpItem["type"] = "template"
|
|
83
|
+
tmpItem["value"] = ""
|
|
84
|
+
tmpItem["dataset"] = datasetSpec.datasetName
|
|
85
|
+
tmpItem["param_type"] = datasetSpec.type
|
|
86
|
+
if fileList != []:
|
|
87
|
+
tmpItem["files"] = fileList
|
|
88
|
+
# append
|
|
89
|
+
if "jobParameters" not in taskParamMap:
|
|
90
|
+
taskParamMap["jobParameters"] = []
|
|
91
|
+
taskParamMap["jobParameters"].append(tmpItem)
|
|
92
|
+
return taskParamMap
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# check if use random seed
|
|
96
|
+
def useRandomSeed(taskParamMap):
|
|
97
|
+
for tmpItem in taskParamMap["jobParameters"]:
|
|
98
|
+
if "value" in tmpItem:
|
|
99
|
+
# get offset for random seed
|
|
100
|
+
if tmpItem["type"] == "template" and tmpItem["param_type"] == "number":
|
|
101
|
+
if "${RNDMSEED}" in tmpItem["value"]:
|
|
102
|
+
return True
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# get initial global share
|
|
107
|
+
def get_initial_global_share(task_buffer, task_id, task_spec=None, task_param_map=None):
|
|
108
|
+
"""
|
|
109
|
+
Get the initial global share for a task
|
|
110
|
+
:param task_buffer: task buffer interface
|
|
111
|
+
:param task_id: task ID
|
|
112
|
+
:param task_spec: task specification object. read through task_buffer if None
|
|
113
|
+
:param task_param_map: task parameter map. read through task_buffer if None
|
|
114
|
+
:return:
|
|
115
|
+
"""
|
|
116
|
+
if task_param_map is None:
|
|
117
|
+
# get task parameters from DB
|
|
118
|
+
tmp_str = task_buffer.getTaskParamsWithID_JEDI(task_id)
|
|
119
|
+
task_param_map = decodeJSON(tmp_str)
|
|
120
|
+
if "gshare" in task_param_map and task_buffer.is_valid_share(task_param_map["gshare"]):
|
|
121
|
+
# global share was already specified in ProdSys
|
|
122
|
+
gshare = task_param_map["gshare"]
|
|
123
|
+
else:
|
|
124
|
+
if task_spec is None:
|
|
125
|
+
# get task specification from DB
|
|
126
|
+
_, task_spec = task_buffer.getTaskWithID_JEDI(task_id)
|
|
127
|
+
# get share based on definition
|
|
128
|
+
gshare = task_buffer.get_share_for_task(task_spec)
|
|
129
|
+
if gshare == "Undefined":
|
|
130
|
+
error_message = "task definition does not match any global share"
|
|
131
|
+
raise RuntimeError(error_message)
|
|
132
|
+
return gshare
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# get sandbox name
|
|
136
|
+
def get_sandbox_name(task_param_map: dict) -> str | None:
|
|
137
|
+
"""
|
|
138
|
+
Get the sandbox name from the task parameters
|
|
139
|
+
:param task_param_map: dictionary of task parameters
|
|
140
|
+
:return: sandbox name or None
|
|
141
|
+
"""
|
|
142
|
+
sandbox_name = None
|
|
143
|
+
if "fixedSandbox" in task_param_map:
|
|
144
|
+
sandbox_name = task_param_map["fixedSandbox"]
|
|
145
|
+
elif "buildSpec" in task_param_map:
|
|
146
|
+
sandbox_name = task_param_map["buildSpec"]["archiveName"]
|
|
147
|
+
else:
|
|
148
|
+
for tmpParam in task_param_map["jobParameters"]:
|
|
149
|
+
if tmpParam["type"] == "constant":
|
|
150
|
+
m = re.search("^-a ([^ ]+)$", tmpParam["value"])
|
|
151
|
+
if m is not None:
|
|
152
|
+
sandbox_name = m.group(1)
|
|
153
|
+
break
|
|
154
|
+
return sandbox_name
|