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,996 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import datetime
|
|
3
|
+
import re
|
|
4
|
+
import sys
|
|
5
|
+
import uuid
|
|
6
|
+
|
|
7
|
+
from pandacommon.pandautils.PandaUtils import naive_utcnow
|
|
8
|
+
|
|
9
|
+
from pandajedi.jedicore import Interaction, JediException
|
|
10
|
+
from pandaserver.taskbuffer import EventServiceUtils, task_split_rules
|
|
11
|
+
from pandaserver.taskbuffer.JediDatasetSpec import JediDatasetSpec
|
|
12
|
+
from pandaserver.taskbuffer.JediFileSpec import JediFileSpec
|
|
13
|
+
from pandaserver.taskbuffer.JediTaskSpec import JediTaskSpec
|
|
14
|
+
|
|
15
|
+
from . import RefinerUtils
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
import idds.common.constants
|
|
19
|
+
import idds.common.utils
|
|
20
|
+
from idds.client.client import Client as iDDS_Client
|
|
21
|
+
except ImportError:
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# base class for task refine
|
|
26
|
+
class TaskRefinerBase(object):
|
|
27
|
+
# constructor
|
|
28
|
+
def __init__(self, taskBufferIF, ddmIF):
|
|
29
|
+
self.ddmIF = ddmIF
|
|
30
|
+
self.taskBufferIF = taskBufferIF
|
|
31
|
+
self.initializeRefiner(None)
|
|
32
|
+
self.refresh()
|
|
33
|
+
|
|
34
|
+
# refresh
|
|
35
|
+
def refresh(self):
|
|
36
|
+
self.siteMapper = self.taskBufferIF.get_site_mapper()
|
|
37
|
+
|
|
38
|
+
# initialize
|
|
39
|
+
def initializeRefiner(self, tmpLog):
|
|
40
|
+
self.taskSpec = None
|
|
41
|
+
self.inMasterDatasetSpec = []
|
|
42
|
+
self.inSecDatasetSpecList = []
|
|
43
|
+
self.outDatasetSpecList = []
|
|
44
|
+
self.outputTemplateMap = {}
|
|
45
|
+
self.jobParamsTemplate = None
|
|
46
|
+
self.cloudName = None
|
|
47
|
+
self.siteName = None
|
|
48
|
+
self.tmpLog = tmpLog
|
|
49
|
+
self.updatedTaskParams = None
|
|
50
|
+
self.unmergeMasterDatasetSpec = {}
|
|
51
|
+
self.unmergeDatasetSpecMap = {}
|
|
52
|
+
self.oldTaskStatus = None
|
|
53
|
+
self.unknownDatasetList = []
|
|
54
|
+
|
|
55
|
+
# set jobParamsTemplate
|
|
56
|
+
def setJobParamsTemplate(self, jobParamsTemplate):
|
|
57
|
+
self.jobParamsTemplate = jobParamsTemplate
|
|
58
|
+
|
|
59
|
+
# create a unique identifier of the payload based on the task parameters
|
|
60
|
+
def create_payload_identifier(self, task_param_map: dict) -> str:
|
|
61
|
+
"""
|
|
62
|
+
Create a unique identifier of the payload based on the task parameters
|
|
63
|
+
:param task_param_map: dictionary of task parameters
|
|
64
|
+
:return: identifier string
|
|
65
|
+
"""
|
|
66
|
+
# remove placeholders from job parameter template
|
|
67
|
+
if self.jobParamsTemplate:
|
|
68
|
+
job_params = re.sub(r"\$\{.*?\}", "", self.jobParamsTemplate)
|
|
69
|
+
else:
|
|
70
|
+
job_params = ""
|
|
71
|
+
# create a base string for the payload identifier
|
|
72
|
+
base_str = "+".join(
|
|
73
|
+
[
|
|
74
|
+
str(self.taskSpec.transUses),
|
|
75
|
+
str(self.taskSpec.transHome),
|
|
76
|
+
str(self.taskSpec.transPath),
|
|
77
|
+
job_params,
|
|
78
|
+
str(RefinerUtils.get_sandbox_name(task_param_map)),
|
|
79
|
+
]
|
|
80
|
+
)
|
|
81
|
+
# create a unique identifier of the payload based on the task parameters
|
|
82
|
+
return uuid.uuid5(uuid.NAMESPACE_DNS, base_str).hex
|
|
83
|
+
|
|
84
|
+
# extract common parameters
|
|
85
|
+
def extractCommon(self, jediTaskID, taskParamMap, workQueueMapper, splitRule):
|
|
86
|
+
# remove irrelevant
|
|
87
|
+
if "maxAttempt" in taskParamMap and not taskParamMap["maxAttempt"]:
|
|
88
|
+
del taskParamMap["maxAttempt"]
|
|
89
|
+
# make task spec
|
|
90
|
+
taskSpec = JediTaskSpec()
|
|
91
|
+
taskSpec.jediTaskID = jediTaskID
|
|
92
|
+
taskSpec.attemptNr = 0
|
|
93
|
+
taskSpec.taskName = taskParamMap["taskName"]
|
|
94
|
+
taskSpec.userName = taskParamMap["userName"]
|
|
95
|
+
taskSpec.vo = taskParamMap["vo"]
|
|
96
|
+
taskSpec.framework = taskParamMap.get("framework", None)
|
|
97
|
+
taskSpec.prodSourceLabel = taskParamMap["prodSourceLabel"]
|
|
98
|
+
taskSpec.taskPriority = taskParamMap["taskPriority"]
|
|
99
|
+
if taskSpec.taskPriority is None:
|
|
100
|
+
taskSpec.taskPriority = 0
|
|
101
|
+
if "currentPriority" in taskParamMap:
|
|
102
|
+
taskSpec.currentPriority = taskParamMap["currentPriority"]
|
|
103
|
+
else:
|
|
104
|
+
taskSpec.currentPriority = taskSpec.taskPriority
|
|
105
|
+
taskSpec.architecture = taskParamMap["architecture"]
|
|
106
|
+
taskSpec.reformat_architecture()
|
|
107
|
+
taskSpec.transUses = taskParamMap["transUses"]
|
|
108
|
+
taskSpec.transHome = taskParamMap["transHome"]
|
|
109
|
+
if "transPath" in taskParamMap:
|
|
110
|
+
taskSpec.transPath = taskParamMap["transPath"]
|
|
111
|
+
taskSpec.processingType = taskParamMap["processingType"]
|
|
112
|
+
taskSpec.taskType = taskParamMap["taskType"]
|
|
113
|
+
taskSpec.splitRule = splitRule
|
|
114
|
+
taskSpec.startTime = naive_utcnow()
|
|
115
|
+
if "workingGroup" in taskParamMap:
|
|
116
|
+
taskSpec.workingGroup = taskParamMap["workingGroup"]
|
|
117
|
+
if "countryGroup" in taskParamMap:
|
|
118
|
+
taskSpec.countryGroup = taskParamMap["countryGroup"]
|
|
119
|
+
if "ticketID" in taskParamMap:
|
|
120
|
+
taskSpec.ticketID = taskParamMap["ticketID"]
|
|
121
|
+
if "ticketSystemType" in taskParamMap:
|
|
122
|
+
taskSpec.ticketSystemType = taskParamMap["ticketSystemType"]
|
|
123
|
+
if "reqID" in taskParamMap:
|
|
124
|
+
taskSpec.reqID = taskParamMap["reqID"]
|
|
125
|
+
else:
|
|
126
|
+
taskSpec.reqID = jediTaskID
|
|
127
|
+
if "coreCount" in taskParamMap:
|
|
128
|
+
taskSpec.coreCount = taskParamMap["coreCount"]
|
|
129
|
+
else:
|
|
130
|
+
taskSpec.coreCount = 1
|
|
131
|
+
if "walltime" in taskParamMap:
|
|
132
|
+
taskSpec.walltime = taskParamMap["walltime"]
|
|
133
|
+
else:
|
|
134
|
+
taskSpec.walltime = 0
|
|
135
|
+
if "walltimeUnit" not in taskParamMap:
|
|
136
|
+
# force to set NULL so that retried tasks get data from scouts again
|
|
137
|
+
taskSpec.forceUpdate("walltimeUnit")
|
|
138
|
+
if "outDiskCount" in taskParamMap:
|
|
139
|
+
taskSpec.outDiskCount = taskParamMap["outDiskCount"]
|
|
140
|
+
else:
|
|
141
|
+
taskSpec.outDiskCount = 0
|
|
142
|
+
if "outDiskUnit" in taskParamMap:
|
|
143
|
+
taskSpec.outDiskUnit = taskParamMap["outDiskUnit"]
|
|
144
|
+
if "workDiskCount" in taskParamMap:
|
|
145
|
+
taskSpec.workDiskCount = taskParamMap["workDiskCount"]
|
|
146
|
+
else:
|
|
147
|
+
taskSpec.workDiskCount = 0
|
|
148
|
+
if "workDiskUnit" in taskParamMap:
|
|
149
|
+
taskSpec.workDiskUnit = taskParamMap["workDiskUnit"]
|
|
150
|
+
if "ramCount" in taskParamMap:
|
|
151
|
+
taskSpec.ramCount = taskParamMap["ramCount"]
|
|
152
|
+
else:
|
|
153
|
+
taskSpec.ramCount = 0
|
|
154
|
+
if "ramUnit" in taskParamMap:
|
|
155
|
+
taskSpec.ramUnit = taskParamMap["ramUnit"]
|
|
156
|
+
elif "ramCountUnit" in taskParamMap:
|
|
157
|
+
taskSpec.ramUnit = taskParamMap["ramCountUnit"]
|
|
158
|
+
if "baseRamCount" in taskParamMap:
|
|
159
|
+
taskSpec.baseRamCount = taskParamMap["baseRamCount"]
|
|
160
|
+
else:
|
|
161
|
+
taskSpec.baseRamCount = 0
|
|
162
|
+
# IO
|
|
163
|
+
if "ioIntensity" in taskParamMap:
|
|
164
|
+
taskSpec.ioIntensity = taskParamMap["ioIntensity"]
|
|
165
|
+
if "ioIntensityUnit" in taskParamMap:
|
|
166
|
+
taskSpec.ioIntensityUnit = taskParamMap["ioIntensityUnit"]
|
|
167
|
+
# HS06 stuff
|
|
168
|
+
if "cpuTimeUnit" in taskParamMap:
|
|
169
|
+
taskSpec.cpuTimeUnit = taskParamMap["cpuTimeUnit"]
|
|
170
|
+
if "cpuTime" in taskParamMap:
|
|
171
|
+
taskSpec.cpuTime = taskParamMap["cpuTime"]
|
|
172
|
+
if "cpuEfficiency" in taskParamMap:
|
|
173
|
+
taskSpec.cpuEfficiency = taskParamMap["cpuEfficiency"]
|
|
174
|
+
else:
|
|
175
|
+
# 90% of cpu efficiency by default
|
|
176
|
+
taskSpec.cpuEfficiency = 90
|
|
177
|
+
if "baseWalltime" in taskParamMap:
|
|
178
|
+
taskSpec.baseWalltime = taskParamMap["baseWalltime"]
|
|
179
|
+
else:
|
|
180
|
+
# 10min of offset by default
|
|
181
|
+
taskSpec.baseWalltime = 10 * 60
|
|
182
|
+
# for merge
|
|
183
|
+
if "mergeRamCount" in taskParamMap:
|
|
184
|
+
taskSpec.mergeRamCount = taskParamMap["mergeRamCount"]
|
|
185
|
+
if "mergeCoreCount" in taskParamMap:
|
|
186
|
+
taskSpec.mergeCoreCount = taskParamMap["mergeCoreCount"]
|
|
187
|
+
# scout
|
|
188
|
+
if "skipScout" not in taskParamMap and not taskSpec.isPostScout():
|
|
189
|
+
taskSpec.setUseScout(True)
|
|
190
|
+
# cloud
|
|
191
|
+
if "cloud" in taskParamMap:
|
|
192
|
+
self.cloudName = taskParamMap["cloud"]
|
|
193
|
+
taskSpec.cloud = self.cloudName
|
|
194
|
+
else:
|
|
195
|
+
# set dummy to force update
|
|
196
|
+
taskSpec.cloud = "dummy"
|
|
197
|
+
taskSpec.cloud = None
|
|
198
|
+
# site
|
|
199
|
+
if "site" in taskParamMap:
|
|
200
|
+
self.siteName = taskParamMap["site"]
|
|
201
|
+
taskSpec.site = self.siteName
|
|
202
|
+
else:
|
|
203
|
+
# set dummy to force update
|
|
204
|
+
taskSpec.site = "dummy"
|
|
205
|
+
taskSpec.site = None
|
|
206
|
+
# nucleus
|
|
207
|
+
if "nucleus" in taskParamMap:
|
|
208
|
+
taskSpec.nucleus = taskParamMap["nucleus"]
|
|
209
|
+
# preset some parameters for job cloning
|
|
210
|
+
if "useJobCloning" in taskParamMap:
|
|
211
|
+
# set implicit parameters
|
|
212
|
+
if "nEventsPerWorker" not in taskParamMap:
|
|
213
|
+
taskParamMap["nEventsPerWorker"] = 1
|
|
214
|
+
if "nSitesPerJob" not in taskParamMap:
|
|
215
|
+
taskParamMap["nSitesPerJob"] = 2
|
|
216
|
+
if "nEsConsumers" not in taskParamMap:
|
|
217
|
+
taskParamMap["nEsConsumers"] = taskParamMap["nSitesPerJob"]
|
|
218
|
+
# minimum granularity
|
|
219
|
+
if "minGranularity" in taskParamMap:
|
|
220
|
+
taskParamMap["nEventsPerRange"] = taskParamMap["minGranularity"]
|
|
221
|
+
# event service flag
|
|
222
|
+
if "useJobCloning" in taskParamMap:
|
|
223
|
+
taskSpec.eventService = EventServiceUtils.TASK_JOB_CLONING
|
|
224
|
+
elif "nEventsPerWorker" in taskParamMap:
|
|
225
|
+
taskSpec.eventService = EventServiceUtils.TASK_EVENT_SERVICE
|
|
226
|
+
elif "fineGrainedProc" in taskParamMap:
|
|
227
|
+
taskSpec.eventService = EventServiceUtils.TASK_FINE_GRAINED
|
|
228
|
+
else:
|
|
229
|
+
taskSpec.eventService = EventServiceUtils.TASK_NORMAL
|
|
230
|
+
# OS
|
|
231
|
+
if "osInfo" in taskParamMap:
|
|
232
|
+
taskSpec.termCondition = taskParamMap["osInfo"]
|
|
233
|
+
# ttcr: requested time to completion
|
|
234
|
+
if "ttcrTimestamp" in taskParamMap:
|
|
235
|
+
try:
|
|
236
|
+
# get rid of the +00:00 timezone string and parse the timestamp
|
|
237
|
+
taskSpec.ttcRequested = datetime.datetime.strptime(taskParamMap["ttcrTimestamp"].split("+")[0], "%Y-%m-%d %H:%M:%S.%f")
|
|
238
|
+
except (IndexError, ValueError):
|
|
239
|
+
pass
|
|
240
|
+
# goal
|
|
241
|
+
if "goal" in taskParamMap:
|
|
242
|
+
try:
|
|
243
|
+
taskSpec.goal = int(float(taskParamMap["goal"]) * 10)
|
|
244
|
+
if taskSpec.goal > 1000:
|
|
245
|
+
taskSpec.goal = None
|
|
246
|
+
except Exception:
|
|
247
|
+
pass
|
|
248
|
+
# campaign
|
|
249
|
+
if "campaign" in taskParamMap:
|
|
250
|
+
taskSpec.campaign = taskParamMap["campaign"]
|
|
251
|
+
# image name
|
|
252
|
+
if "container_name" in taskParamMap:
|
|
253
|
+
taskSpec.container_name = taskParamMap["container_name"]
|
|
254
|
+
self.taskSpec = taskSpec
|
|
255
|
+
# set split rule
|
|
256
|
+
if "nFilesPerJob" not in taskParamMap:
|
|
257
|
+
if "tgtNumEventsPerJob" in taskParamMap:
|
|
258
|
+
# set nEventsPerJob not to respect file boundaries when nFilesPerJob is not used
|
|
259
|
+
self.setSplitRule(None, taskParamMap["tgtNumEventsPerJob"], JediTaskSpec.splitRuleToken["nEventsPerJob"])
|
|
260
|
+
elif (
|
|
261
|
+
"nEventsPerInputFile" in taskParamMap
|
|
262
|
+
and "nEventsPerJob" in taskParamMap
|
|
263
|
+
and taskParamMap["nEventsPerJob"] >= taskParamMap["nEventsPerInputFile"]
|
|
264
|
+
):
|
|
265
|
+
# set nFilesPerJob if nEventsPerJob and nEventsPerInputFile are set
|
|
266
|
+
nFilesPerJob = taskParamMap["nEventsPerJob"] // taskParamMap["nEventsPerInputFile"]
|
|
267
|
+
self.setSplitRule(None, nFilesPerJob, JediTaskSpec.splitRuleToken["nFilesPerJob"])
|
|
268
|
+
else:
|
|
269
|
+
self.setSplitRule(taskParamMap, "nFilesPerJob", JediTaskSpec.splitRuleToken["nFilesPerJob"])
|
|
270
|
+
self.setSplitRule(taskParamMap, "nEventsPerJob", JediTaskSpec.splitRuleToken["nEventsPerJob"])
|
|
271
|
+
self.setSplitRule(taskParamMap, "nGBPerJob", JediTaskSpec.splitRuleToken["nGBPerJob"])
|
|
272
|
+
self.setSplitRule(taskParamMap, "nMaxFilesPerJob", JediTaskSpec.splitRuleToken["nMaxFilesPerJob"])
|
|
273
|
+
self.setSplitRule(taskParamMap, "maxEventsPerJob", JediTaskSpec.splitRuleToken["maxEventsPerJob"])
|
|
274
|
+
self.setSplitRule(taskParamMap, "nEventsPerWorker", JediTaskSpec.splitRuleToken["nEventsPerWorker"])
|
|
275
|
+
self.setSplitRule(taskParamMap, "nEventsPerInputFile", JediTaskSpec.splitRuleToken["nEventsPerInput"])
|
|
276
|
+
self.setSplitRule(taskParamMap, "disableAutoRetry", JediTaskSpec.splitRuleToken["disableAutoRetry"])
|
|
277
|
+
self.setSplitRule(taskParamMap, "nEsConsumers", JediTaskSpec.splitRuleToken["nEsConsumers"])
|
|
278
|
+
self.setSplitRule(taskParamMap, "waitInput", JediTaskSpec.splitRuleToken["waitInput"])
|
|
279
|
+
self.setSplitRule(taskParamMap, "addNthFieldToLFN", JediTaskSpec.splitRuleToken["addNthFieldToLFN"])
|
|
280
|
+
self.setSplitRule(taskParamMap, "scoutSuccessRate", JediTaskSpec.splitRuleToken["scoutSuccessRate"])
|
|
281
|
+
self.setSplitRule(taskParamMap, "t1Weight", JediTaskSpec.splitRuleToken["t1Weight"])
|
|
282
|
+
self.setSplitRule(taskParamMap, "maxAttemptES", JediTaskSpec.splitRuleToken["maxAttemptES"])
|
|
283
|
+
self.setSplitRule(taskParamMap, "maxAttemptEsJob", JediTaskSpec.splitRuleToken["maxAttemptEsJob"])
|
|
284
|
+
self.setSplitRule(taskParamMap, "nSitesPerJob", JediTaskSpec.splitRuleToken["nSitesPerJob"])
|
|
285
|
+
self.setSplitRule(taskParamMap, "nEventsPerMergeJob", JediTaskSpec.splitRuleToken["nEventsPerMergeJob"])
|
|
286
|
+
self.setSplitRule(taskParamMap, "nFilesPerMergeJob", JediTaskSpec.splitRuleToken["nFilesPerMergeJob"])
|
|
287
|
+
self.setSplitRule(taskParamMap, "nGBPerMergeJob", JediTaskSpec.splitRuleToken["nGBPerMergeJob"])
|
|
288
|
+
self.setSplitRule(taskParamMap, "nMaxFilesPerMergeJob", JediTaskSpec.splitRuleToken["nMaxFilesPerMergeJob"])
|
|
289
|
+
self.setSplitRule(taskParamMap, "maxWalltime", JediTaskSpec.splitRuleToken["maxWalltime"])
|
|
290
|
+
self.setSplitRule(taskParamMap, "tgtMaxOutputForNG", JediTaskSpec.splitRuleToken["tgtMaxOutputForNG"])
|
|
291
|
+
self.setSplitRule(taskParamMap, "maxNumJobs", JediTaskSpec.splitRuleToken["maxNumJobs"])
|
|
292
|
+
self.setSplitRule(taskParamMap, "totNumJobs", JediTaskSpec.splitRuleToken["totNumJobs"])
|
|
293
|
+
self.setSplitRule(taskParamMap, "nChunksToWait", JediTaskSpec.splitRuleToken["nChunksToWait"])
|
|
294
|
+
self.setSplitRule(taskParamMap, "retryRamOffset", JediTaskSpec.splitRuleToken["retryRamOffset"])
|
|
295
|
+
self.setSplitRule(taskParamMap, "retryRamStep", JediTaskSpec.splitRuleToken["retryRamStep"])
|
|
296
|
+
self.setSplitRule(taskParamMap, "retryRamMax", JediTaskSpec.splitRuleToken["retryRamMax"])
|
|
297
|
+
if "forceStaged" in taskParamMap:
|
|
298
|
+
taskParamMap["useLocalIO"] = taskParamMap["forceStaged"]
|
|
299
|
+
if "useLocalIO" in taskParamMap:
|
|
300
|
+
if taskParamMap["useLocalIO"]:
|
|
301
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["useLocalIO"])
|
|
302
|
+
else:
|
|
303
|
+
self.setSplitRule(None, 0, JediTaskSpec.splitRuleToken["useLocalIO"])
|
|
304
|
+
if "nJumboJobs" in taskParamMap:
|
|
305
|
+
self.setSplitRule(taskParamMap, "nJumboJobs", JediTaskSpec.splitRuleToken["nJumboJobs"])
|
|
306
|
+
taskSpec.useJumbo = JediTaskSpec.enum_useJumbo["waiting"]
|
|
307
|
+
if "maxJumboPerSite" in taskParamMap:
|
|
308
|
+
self.setSplitRule(taskParamMap, "maxJumboPerSite", JediTaskSpec.splitRuleToken["maxJumboPerSite"])
|
|
309
|
+
if "minCpuEfficiency" in taskParamMap:
|
|
310
|
+
self.setSplitRule(taskParamMap, "minCpuEfficiency", JediTaskSpec.splitRuleToken["minCpuEfficiency"])
|
|
311
|
+
if "loadXML" in taskParamMap:
|
|
312
|
+
self.setSplitRule(None, 3, JediTaskSpec.splitRuleToken["loadXML"])
|
|
313
|
+
self.setSplitRule(None, 4, JediTaskSpec.splitRuleToken["groupBoundaryID"])
|
|
314
|
+
if "pfnList" in taskParamMap:
|
|
315
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["pfnList"])
|
|
316
|
+
if "noWaitParent" in taskParamMap and taskParamMap["noWaitParent"] is True:
|
|
317
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["noWaitParent"])
|
|
318
|
+
if "respectLB" in taskParamMap:
|
|
319
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["respectLB"])
|
|
320
|
+
if "releasePerLB" in taskParamMap:
|
|
321
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["releasePerLB"])
|
|
322
|
+
if "orderByLB" in taskParamMap:
|
|
323
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["orderByLB"])
|
|
324
|
+
if "respectSplitRule" in taskParamMap:
|
|
325
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["respectSplitRule"])
|
|
326
|
+
if "reuseSecOnDemand" in taskParamMap:
|
|
327
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["reuseSecOnDemand"])
|
|
328
|
+
if "ddmBackEnd" in taskParamMap:
|
|
329
|
+
self.taskSpec.setDdmBackEnd(taskParamMap["ddmBackEnd"])
|
|
330
|
+
if "disableReassign" in taskParamMap:
|
|
331
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["disableReassign"])
|
|
332
|
+
if "allowPartialFinish" in taskParamMap:
|
|
333
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["allowPartialFinish"])
|
|
334
|
+
if "useExhausted" in taskParamMap:
|
|
335
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["useExhausted"])
|
|
336
|
+
if "useRealNumEvents" in taskParamMap:
|
|
337
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["useRealNumEvents"])
|
|
338
|
+
if "ipConnectivity" in taskParamMap:
|
|
339
|
+
self.taskSpec.setIpConnectivity(taskParamMap["ipConnectivity"])
|
|
340
|
+
if "altStageOut" in taskParamMap:
|
|
341
|
+
self.taskSpec.setAltStageOut(taskParamMap["altStageOut"])
|
|
342
|
+
if "allowInputLAN" in taskParamMap:
|
|
343
|
+
self.taskSpec.setAllowInputLAN(taskParamMap["allowInputLAN"])
|
|
344
|
+
if "runUntilClosed" in taskParamMap:
|
|
345
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["runUntilClosed"])
|
|
346
|
+
if "stayOutputOnSite" in taskParamMap:
|
|
347
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["stayOutputOnSite"])
|
|
348
|
+
if "useJobCloning" in taskParamMap:
|
|
349
|
+
scValue = EventServiceUtils.getJobCloningValue(taskParamMap["useJobCloning"])
|
|
350
|
+
self.setSplitRule(None, scValue, JediTaskSpec.splitRuleToken["useJobCloning"])
|
|
351
|
+
if "failWhenGoalUnreached" in taskParamMap and taskParamMap["failWhenGoalUnreached"] is True:
|
|
352
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["failGoalUnreached"])
|
|
353
|
+
if "switchEStoNormal" in taskParamMap:
|
|
354
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["switchEStoNormal"])
|
|
355
|
+
if "nEventsPerRange" in taskParamMap:
|
|
356
|
+
self.setSplitRule(taskParamMap, "nEventsPerRange", JediTaskSpec.splitRuleToken["dynamicNumEvents"])
|
|
357
|
+
if "allowInputWAN" in taskParamMap and taskParamMap["allowInputWAN"] is True:
|
|
358
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["allowInputWAN"])
|
|
359
|
+
if "putLogToOS" in taskParamMap and taskParamMap["putLogToOS"] is True:
|
|
360
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["putLogToOS"])
|
|
361
|
+
if "mergeEsOnOS" in taskParamMap and taskParamMap["mergeEsOnOS"] is True:
|
|
362
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["mergeEsOnOS"])
|
|
363
|
+
if "writeInputToFile" in taskParamMap and taskParamMap["writeInputToFile"] is True:
|
|
364
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["writeInputToFile"])
|
|
365
|
+
if "useFileAsSourceLFN" in taskParamMap and taskParamMap["useFileAsSourceLFN"] is True:
|
|
366
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["useFileAsSourceLFN"])
|
|
367
|
+
if "ignoreMissingInDS" in taskParamMap and taskParamMap["ignoreMissingInDS"] is True:
|
|
368
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["ignoreMissingInDS"])
|
|
369
|
+
if "noExecStrCnv" in taskParamMap and taskParamMap["noExecStrCnv"] is True:
|
|
370
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["noExecStrCnv"])
|
|
371
|
+
if "inFilePosEvtNum" in taskParamMap and taskParamMap["inFilePosEvtNum"] is True:
|
|
372
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["inFilePosEvtNum"])
|
|
373
|
+
if self.taskSpec.useEventService() and not taskSpec.useJobCloning():
|
|
374
|
+
if "registerEsFiles" in taskParamMap and taskParamMap["registerEsFiles"] is True:
|
|
375
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["registerEsFiles"])
|
|
376
|
+
if "disableAutoFinish" in taskParamMap and taskParamMap["disableAutoFinish"] is True:
|
|
377
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["disableAutoFinish"])
|
|
378
|
+
if "resurrectConsumers" in taskParamMap and taskParamMap["resurrectConsumers"] is True:
|
|
379
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["resurrectConsumers"])
|
|
380
|
+
if "usePrefetcher" in taskParamMap and taskParamMap["usePrefetcher"] is True:
|
|
381
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["usePrefetcher"])
|
|
382
|
+
if "notDiscardEvents" in taskParamMap and taskParamMap["notDiscardEvents"] is True:
|
|
383
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["notDiscardEvents"])
|
|
384
|
+
if "decAttOnFailedES" in taskParamMap and taskParamMap["decAttOnFailedES"] is True:
|
|
385
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["decAttOnFailedES"])
|
|
386
|
+
if "useZipToPin" in taskParamMap and taskParamMap["useZipToPin"] is True:
|
|
387
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["useZipToPin"])
|
|
388
|
+
if "osMatching" in taskParamMap and taskParamMap["osMatching"] is True:
|
|
389
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["osMatching"])
|
|
390
|
+
if "multiStepExec" in taskParamMap:
|
|
391
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["multiStepExec"])
|
|
392
|
+
if "onlyTagsForFC" in taskParamMap:
|
|
393
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["onlyTagsForFC"])
|
|
394
|
+
if "segmentedWork" in taskParamMap and "segmentSpecs" in taskParamMap:
|
|
395
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["segmentedWork"])
|
|
396
|
+
if "avoidVP" in taskParamMap:
|
|
397
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["avoidVP"])
|
|
398
|
+
if "inputPreStaging" in taskParamMap and taskParamMap["inputPreStaging"] is True:
|
|
399
|
+
self.setSplitRule(None, JediTaskSpec.enum_inputPreStaging["use"], JediTaskSpec.splitRuleToken["inputPreStaging"])
|
|
400
|
+
if "hpoWorkflow" in taskParamMap and taskParamMap["hpoWorkflow"] is True and "hpoRequestData" in taskParamMap:
|
|
401
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["hpoWorkflow"])
|
|
402
|
+
if "noLoopingCheck" in taskParamMap and taskParamMap["noLoopingCheck"]:
|
|
403
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["noLoopingCheck"])
|
|
404
|
+
if "encJobParams" in taskParamMap and taskParamMap["encJobParams"]:
|
|
405
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["encJobParams"])
|
|
406
|
+
if "useSecrets" in taskParamMap and taskParamMap["useSecrets"]:
|
|
407
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["useSecrets"])
|
|
408
|
+
if "debugMode" in taskParamMap and taskParamMap["debugMode"]:
|
|
409
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["debugMode"])
|
|
410
|
+
if "pushStatusChanges" in taskParamMap and taskParamMap["pushStatusChanges"]:
|
|
411
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["pushStatusChanges"])
|
|
412
|
+
if "maxCoreCount" in taskParamMap:
|
|
413
|
+
self.setSplitRule(taskParamMap, "maxCoreCount", JediTaskSpec.splitRuleToken["maxCoreCount"])
|
|
414
|
+
if "cloudAsVO" in taskParamMap:
|
|
415
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["cloudAsVO"])
|
|
416
|
+
if "pushJob" in taskParamMap and taskParamMap["pushJob"]:
|
|
417
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["pushJob"])
|
|
418
|
+
if "fineGrainedProc" in taskParamMap and taskParamMap["fineGrainedProc"]:
|
|
419
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["fineGrainedProc"])
|
|
420
|
+
if "onSiteMerging" in taskParamMap and taskParamMap["onSiteMerging"]:
|
|
421
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["onSiteMerging"])
|
|
422
|
+
if "fullChain" in taskParamMap:
|
|
423
|
+
self.taskSpec.set_full_chain(taskParamMap["fullChain"])
|
|
424
|
+
if "orderInputBy" in taskParamMap:
|
|
425
|
+
self.taskSpec.set_order_input_by(taskParamMap["orderInputBy"])
|
|
426
|
+
if "intermediateTask" in taskParamMap:
|
|
427
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["intermediateTask"])
|
|
428
|
+
if "allowEmptyInput" in taskParamMap:
|
|
429
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["allowEmptyInput"])
|
|
430
|
+
if "messageDriven" in taskParamMap and taskParamMap["messageDriven"]:
|
|
431
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["messageDriven"])
|
|
432
|
+
if "allowIncompleteInDS" in taskParamMap and taskParamMap["allowIncompleteInDS"]:
|
|
433
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["allowIncompleteInDS"])
|
|
434
|
+
if "noAutoPause" in taskParamMap and taskParamMap["noAutoPause"]:
|
|
435
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["noAutoPause"])
|
|
436
|
+
if "workflowHoldup" in taskParamMap and taskParamMap["workflowHoldup"]:
|
|
437
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["workflowHoldup"])
|
|
438
|
+
# work queue
|
|
439
|
+
workQueue = None
|
|
440
|
+
if "workQueueName" in taskParamMap:
|
|
441
|
+
# work queue is specified
|
|
442
|
+
workQueue = workQueueMapper.getQueueByName(taskSpec.vo, taskSpec.prodSourceLabel, taskParamMap["workQueueName"])
|
|
443
|
+
if workQueue is None:
|
|
444
|
+
# get work queue based on task attributes
|
|
445
|
+
workQueue, tmpStr = workQueueMapper.getQueueWithSelParams(
|
|
446
|
+
taskSpec.vo,
|
|
447
|
+
taskSpec.prodSourceLabel,
|
|
448
|
+
prodSourceLabel=taskSpec.prodSourceLabel,
|
|
449
|
+
processingType=taskSpec.processingType,
|
|
450
|
+
workingGroup=taskSpec.workingGroup,
|
|
451
|
+
coreCount=taskSpec.coreCount,
|
|
452
|
+
site=taskSpec.site,
|
|
453
|
+
eventService=taskSpec.eventService,
|
|
454
|
+
splitRule=taskSpec.splitRule,
|
|
455
|
+
campaign=taskSpec.campaign,
|
|
456
|
+
)
|
|
457
|
+
if workQueue is None:
|
|
458
|
+
errStr = f"workqueue is undefined for vo={taskSpec.vo} label={taskSpec.prodSourceLabel} "
|
|
459
|
+
errStr += "processingType={0} workingGroup={1} coreCount={2} eventService={3} ".format(
|
|
460
|
+
taskSpec.processingType, taskSpec.workingGroup, taskSpec.coreCount, taskSpec.eventService
|
|
461
|
+
)
|
|
462
|
+
errStr += f"splitRule={taskSpec.splitRule} campaign={taskSpec.campaign}"
|
|
463
|
+
raise RuntimeError(errStr)
|
|
464
|
+
self.taskSpec.workQueue_ID = workQueue.queue_id
|
|
465
|
+
|
|
466
|
+
# Initialize the global share
|
|
467
|
+
self.taskSpec.gshare = RefinerUtils.get_initial_global_share(self.taskBufferIF, self.taskSpec.jediTaskID, taskSpec, taskParamMap)
|
|
468
|
+
|
|
469
|
+
# Initialize the resource type
|
|
470
|
+
try:
|
|
471
|
+
self.taskSpec.resource_type = self.taskBufferIF.get_resource_type_task(self.taskSpec)
|
|
472
|
+
except Exception:
|
|
473
|
+
self.taskSpec.resource_type = "Undefined"
|
|
474
|
+
|
|
475
|
+
# return
|
|
476
|
+
return
|
|
477
|
+
|
|
478
|
+
# basic refinement procedure
|
|
479
|
+
def doBasicRefine(self, taskParamMap):
|
|
480
|
+
# get input/output/log dataset specs
|
|
481
|
+
nIn = 0
|
|
482
|
+
nOutMap = {}
|
|
483
|
+
if "log" not in taskParamMap:
|
|
484
|
+
itemList = taskParamMap["jobParameters"]
|
|
485
|
+
elif isinstance(taskParamMap["log"], dict):
|
|
486
|
+
itemList = taskParamMap["jobParameters"] + [taskParamMap["log"]]
|
|
487
|
+
else:
|
|
488
|
+
itemList = taskParamMap["jobParameters"] + taskParamMap["log"]
|
|
489
|
+
if "log_merge" in taskParamMap:
|
|
490
|
+
itemList += [taskParamMap["log_merge"]]
|
|
491
|
+
# pseudo input
|
|
492
|
+
if "noInput" in taskParamMap and taskParamMap["noInput"] is True:
|
|
493
|
+
tmpItem = {}
|
|
494
|
+
tmpItem["type"] = "template"
|
|
495
|
+
tmpItem["value"] = ""
|
|
496
|
+
tmpItem["dataset"] = "pseudo_dataset"
|
|
497
|
+
tmpItem["param_type"] = "pseudo_input"
|
|
498
|
+
itemList = [tmpItem] + itemList
|
|
499
|
+
# random seed
|
|
500
|
+
if RefinerUtils.useRandomSeed(taskParamMap):
|
|
501
|
+
tmpItem = {}
|
|
502
|
+
tmpItem["type"] = "template"
|
|
503
|
+
tmpItem["value"] = ""
|
|
504
|
+
tmpItem["dataset"] = "RNDMSEED"
|
|
505
|
+
tmpItem["param_type"] = "random_seed"
|
|
506
|
+
itemList.append(tmpItem)
|
|
507
|
+
# loop over all items
|
|
508
|
+
allDsList = []
|
|
509
|
+
checked_endpoints = set()
|
|
510
|
+
for tmpItem in itemList:
|
|
511
|
+
# look for datasets
|
|
512
|
+
if tmpItem["type"] == "template" and "dataset" in tmpItem:
|
|
513
|
+
# avoid duplication
|
|
514
|
+
if tmpItem["dataset"] not in allDsList:
|
|
515
|
+
allDsList.append(tmpItem["dataset"])
|
|
516
|
+
else:
|
|
517
|
+
continue
|
|
518
|
+
datasetSpec = JediDatasetSpec()
|
|
519
|
+
datasetSpec.datasetName = tmpItem["dataset"]
|
|
520
|
+
datasetSpec.jediTaskID = self.taskSpec.jediTaskID
|
|
521
|
+
datasetSpec.type = tmpItem["param_type"]
|
|
522
|
+
if "container" in tmpItem:
|
|
523
|
+
datasetSpec.containerName = tmpItem["container"]
|
|
524
|
+
if "token" in tmpItem:
|
|
525
|
+
datasetSpec.storageToken = tmpItem["token"]
|
|
526
|
+
if "destination" in tmpItem:
|
|
527
|
+
datasetSpec.destination = tmpItem["destination"]
|
|
528
|
+
if "attributes" in tmpItem:
|
|
529
|
+
datasetSpec.setDatasetAttribute(tmpItem["attributes"])
|
|
530
|
+
if "ratio" in tmpItem:
|
|
531
|
+
datasetSpec.setDatasetAttribute(f"ratio={tmpItem['ratio']}")
|
|
532
|
+
if "eventRatio" in tmpItem:
|
|
533
|
+
datasetSpec.setEventRatio(tmpItem["eventRatio"])
|
|
534
|
+
if "check" in tmpItem:
|
|
535
|
+
datasetSpec.setDatasetAttribute("cc")
|
|
536
|
+
if "usedup" in tmpItem:
|
|
537
|
+
datasetSpec.setDatasetAttribute("ud")
|
|
538
|
+
if "random" in tmpItem:
|
|
539
|
+
datasetSpec.setDatasetAttribute("rd")
|
|
540
|
+
if "reusable" in tmpItem:
|
|
541
|
+
datasetSpec.setDatasetAttribute("ru")
|
|
542
|
+
if "indexConsistent" in tmpItem:
|
|
543
|
+
datasetSpec.setDatasetAttributeWithLabel("indexConsistent")
|
|
544
|
+
if "mergeOnly" in tmpItem:
|
|
545
|
+
datasetSpec.setDatasetAttributeWithLabel("mergeOnly")
|
|
546
|
+
if "offset" in tmpItem:
|
|
547
|
+
datasetSpec.setOffset(tmpItem["offset"])
|
|
548
|
+
if "allowNoOutput" in tmpItem:
|
|
549
|
+
datasetSpec.allowNoOutput()
|
|
550
|
+
if "nFilesPerJob" in tmpItem:
|
|
551
|
+
datasetSpec.setNumFilesPerJob(tmpItem["nFilesPerJob"])
|
|
552
|
+
if "num_records" in tmpItem:
|
|
553
|
+
datasetSpec.setNumRecords(tmpItem["num_records"])
|
|
554
|
+
if "transient" in tmpItem:
|
|
555
|
+
datasetSpec.setTransient(tmpItem["transient"])
|
|
556
|
+
if "pseudo" in tmpItem:
|
|
557
|
+
datasetSpec.setPseudo()
|
|
558
|
+
datasetSpec.vo = self.taskSpec.vo
|
|
559
|
+
datasetSpec.nFiles = 0
|
|
560
|
+
datasetSpec.nFilesUsed = 0
|
|
561
|
+
datasetSpec.nFilesFinished = 0
|
|
562
|
+
datasetSpec.nFilesFailed = 0
|
|
563
|
+
datasetSpec.nFilesOnHold = 0
|
|
564
|
+
datasetSpec.nFilesWaiting = 0
|
|
565
|
+
datasetSpec.nFilesMissing = 0
|
|
566
|
+
datasetSpec.nEvents = 0
|
|
567
|
+
datasetSpec.nEventsUsed = 0
|
|
568
|
+
datasetSpec.nEventsToBeUsed = 0
|
|
569
|
+
datasetSpec.status = "defined"
|
|
570
|
+
if datasetSpec.type in JediDatasetSpec.getInputTypes() + ["random_seed"]:
|
|
571
|
+
datasetSpec.streamName = RefinerUtils.extractStreamName(tmpItem["value"])
|
|
572
|
+
if "expandedList" not in tmpItem:
|
|
573
|
+
tmpItem["expandedList"] = []
|
|
574
|
+
# dataset names could be comma-concatenated
|
|
575
|
+
datasetNameList = datasetSpec.datasetName.split(",")
|
|
576
|
+
# datasets could be added by incexec
|
|
577
|
+
incexecDS = f"dsFor{datasetSpec.streamName}"
|
|
578
|
+
# remove /XYZ
|
|
579
|
+
incexecDS = incexecDS.split("/")[0]
|
|
580
|
+
if incexecDS in taskParamMap:
|
|
581
|
+
for tmpDatasetName in taskParamMap[incexecDS].split(","):
|
|
582
|
+
if tmpDatasetName not in datasetNameList:
|
|
583
|
+
datasetNameList.append(tmpDatasetName)
|
|
584
|
+
# consolidation
|
|
585
|
+
if len(datasetNameList) > 1 and "consolidate" in tmpItem:
|
|
586
|
+
tmpIF = self.ddmIF.getInterface(self.taskSpec.vo, self.taskSpec.cloud)
|
|
587
|
+
if tmpIF:
|
|
588
|
+
containerName = tmpItem["consolidate"]
|
|
589
|
+
tmpStat = tmpIF.registerNewDataset(containerName)
|
|
590
|
+
if not tmpStat:
|
|
591
|
+
errStr = f"failed to register {containerName}"
|
|
592
|
+
raise JediException.ExternalTempError(errStr)
|
|
593
|
+
tmpDsListInCont = tmpIF.listDatasetsInContainer(containerName)
|
|
594
|
+
for tmpContName in datasetNameList:
|
|
595
|
+
tmpDsNameList = tmpIF.expandContainer(tmpContName)
|
|
596
|
+
for tmpDsName in tmpDsNameList:
|
|
597
|
+
if tmpDsName not in tmpDsListInCont:
|
|
598
|
+
tmpStat = tmpIF.addDatasetsToContainer(containerName, [tmpDsName])
|
|
599
|
+
if not tmpStat:
|
|
600
|
+
errStr = f"failed to add {tmpDsName} to {containerName}"
|
|
601
|
+
raise JediException.ExternalTempError(errStr)
|
|
602
|
+
datasetNameList = [containerName]
|
|
603
|
+
# loop over all dataset names
|
|
604
|
+
inDatasetSpecList = []
|
|
605
|
+
for datasetName in datasetNameList:
|
|
606
|
+
# skip empty
|
|
607
|
+
if datasetName == "":
|
|
608
|
+
continue
|
|
609
|
+
# expand
|
|
610
|
+
if datasetSpec.isPseudo() or datasetSpec.type in ["random_seed"] or datasetName == "DBR_LATEST":
|
|
611
|
+
# pseudo input
|
|
612
|
+
tmpDatasetNameList = [datasetName]
|
|
613
|
+
if self.taskSpec.is_work_segmented():
|
|
614
|
+
tmpDatasetNameList *= len(taskParamMap["segmentSpecs"])
|
|
615
|
+
else:
|
|
616
|
+
tmpIF = self.ddmIF.getInterface(self.taskSpec.vo, self.taskSpec.cloud)
|
|
617
|
+
if not tmpIF:
|
|
618
|
+
tmpDatasetNameList = []
|
|
619
|
+
else:
|
|
620
|
+
if "expand" in tmpItem and tmpItem["expand"] is True:
|
|
621
|
+
# expand dataset container
|
|
622
|
+
tmpDatasetNameList = tmpIF.expandContainer(datasetName)
|
|
623
|
+
# sort datasets to process online complete replicas first
|
|
624
|
+
tmp_ok_list = []
|
|
625
|
+
tmp_ng_list = []
|
|
626
|
+
for tmp_dataset_name in tmpDatasetNameList:
|
|
627
|
+
# skip the check if enough datasets are OK
|
|
628
|
+
if len(tmp_ok_list) > 10:
|
|
629
|
+
is_ok = True
|
|
630
|
+
else:
|
|
631
|
+
# check if complete replica is available at online endpoint
|
|
632
|
+
is_ok = False
|
|
633
|
+
tmp_dict = tmpIF.listDatasetReplicas(tmp_dataset_name)
|
|
634
|
+
for tmp_endpoint, tmp_data_list in tmp_dict.items():
|
|
635
|
+
tmp_data = tmp_data_list[0]
|
|
636
|
+
if (
|
|
637
|
+
tmp_data["total"]
|
|
638
|
+
and tmp_data["total"] == tmp_data["found"]
|
|
639
|
+
and self.siteMapper.is_readable_remotely(tmp_endpoint)
|
|
640
|
+
):
|
|
641
|
+
is_ok = True
|
|
642
|
+
break
|
|
643
|
+
if is_ok:
|
|
644
|
+
tmp_ok_list.append(tmp_dataset_name)
|
|
645
|
+
else:
|
|
646
|
+
tmp_ng_list.append(tmp_dataset_name)
|
|
647
|
+
tmpDatasetNameList = tmp_ok_list + tmp_ng_list
|
|
648
|
+
else:
|
|
649
|
+
# normal dataset name
|
|
650
|
+
tmpDatasetNameList = tmpIF.listDatasets(datasetName)
|
|
651
|
+
i_element = 0
|
|
652
|
+
for elementDatasetName in tmpDatasetNameList:
|
|
653
|
+
if "expandedList" in tmpItem:
|
|
654
|
+
if elementDatasetName not in tmpItem["expandedList"]:
|
|
655
|
+
tmpItem["expandedList"].append(elementDatasetName)
|
|
656
|
+
inDatasetSpec = copy.copy(datasetSpec)
|
|
657
|
+
inDatasetSpec.datasetName = elementDatasetName
|
|
658
|
+
if nIn > 0 or not self.taskSpec.is_hpo_workflow():
|
|
659
|
+
inDatasetSpec.containerName = datasetName
|
|
660
|
+
else:
|
|
661
|
+
if self.taskSpec.is_work_segmented():
|
|
662
|
+
inDatasetSpec.containerName = "{}/{}".format(
|
|
663
|
+
taskParamMap["segmentSpecs"][i_element]["name"], taskParamMap["segmentSpecs"][i_element]["id"]
|
|
664
|
+
)
|
|
665
|
+
else:
|
|
666
|
+
inDatasetSpec.containerName = "None/None"
|
|
667
|
+
inDatasetSpecList.append(inDatasetSpec)
|
|
668
|
+
i_element += 1
|
|
669
|
+
# empty input
|
|
670
|
+
if inDatasetSpecList == [] and self.oldTaskStatus != "rerefine":
|
|
671
|
+
errStr = f'doBasicRefine : unknown input dataset "{datasetSpec.datasetName}"'
|
|
672
|
+
self.taskSpec.setErrDiag(errStr)
|
|
673
|
+
if datasetSpec.datasetName not in self.unknownDatasetList:
|
|
674
|
+
self.unknownDatasetList.append(datasetSpec.datasetName)
|
|
675
|
+
raise JediException.UnknownDatasetError(errStr)
|
|
676
|
+
# set master flag
|
|
677
|
+
for inDatasetSpec in inDatasetSpecList:
|
|
678
|
+
if nIn == 0:
|
|
679
|
+
# master
|
|
680
|
+
self.inMasterDatasetSpec.append(inDatasetSpec)
|
|
681
|
+
else:
|
|
682
|
+
# secondary
|
|
683
|
+
self.inSecDatasetSpecList.append(inDatasetSpec)
|
|
684
|
+
nIn += 1
|
|
685
|
+
continue
|
|
686
|
+
if datasetSpec.type in ["output", "log"]:
|
|
687
|
+
# check endpoint
|
|
688
|
+
if (
|
|
689
|
+
datasetSpec.destination is not None
|
|
690
|
+
and re.search("^[a-zA-Z0-9_-]+$", datasetSpec.destination)
|
|
691
|
+
and datasetSpec.destination not in checked_endpoints
|
|
692
|
+
):
|
|
693
|
+
checked_endpoints.add(datasetSpec.destination)
|
|
694
|
+
tmp_if = self.ddmIF.getInterface(self.taskSpec.vo, self.taskSpec.cloud)
|
|
695
|
+
if tmp_if:
|
|
696
|
+
tmp_status, tmp_output = tmp_if.check_endpoint(datasetSpec.destination)
|
|
697
|
+
if tmp_status is None:
|
|
698
|
+
# unknown error
|
|
699
|
+
raise JediException.ExternalTempError(tmp_output)
|
|
700
|
+
elif tmp_status is False:
|
|
701
|
+
# bad endpoint
|
|
702
|
+
raise JediException.TempBadStorageError(tmp_output)
|
|
703
|
+
# collect output types
|
|
704
|
+
if datasetSpec.type not in nOutMap:
|
|
705
|
+
nOutMap[datasetSpec.type] = 0
|
|
706
|
+
# make stream name
|
|
707
|
+
if not datasetSpec.is_merge_only():
|
|
708
|
+
datasetSpec.streamName = f"{datasetSpec.type.upper()}{nOutMap[datasetSpec.type]}"
|
|
709
|
+
else:
|
|
710
|
+
datasetSpec.streamName = "LOG_MERGE"
|
|
711
|
+
nOutMap[datasetSpec.type] += 1
|
|
712
|
+
# set attribute for event service
|
|
713
|
+
if self.taskSpec.useEventService() and "objectStore" in taskParamMap and datasetSpec.type in ["output"]:
|
|
714
|
+
datasetSpec.setObjectStore(taskParamMap["objectStore"])
|
|
715
|
+
# extract output filename template and change the value field
|
|
716
|
+
outFileTemplate, tmpItem["value"] = RefinerUtils.extractReplaceOutFileTemplate(tmpItem["value"], datasetSpec.streamName)
|
|
717
|
+
# make output template
|
|
718
|
+
if outFileTemplate is not None:
|
|
719
|
+
if "offset" in tmpItem:
|
|
720
|
+
offsetVal = 1 + tmpItem["offset"]
|
|
721
|
+
else:
|
|
722
|
+
offsetVal = 1
|
|
723
|
+
outTemplateMap = {
|
|
724
|
+
"jediTaskID": self.taskSpec.jediTaskID,
|
|
725
|
+
"serialNr": offsetVal,
|
|
726
|
+
"streamName": datasetSpec.streamName,
|
|
727
|
+
"filenameTemplate": outFileTemplate,
|
|
728
|
+
"outtype": datasetSpec.type,
|
|
729
|
+
}
|
|
730
|
+
if datasetSpec.outputMapKey() in self.outputTemplateMap:
|
|
731
|
+
# multiple files are associated to the same output datasets
|
|
732
|
+
self.outputTemplateMap[datasetSpec.outputMapKey()].append(outTemplateMap)
|
|
733
|
+
# don't insert the same output dataset
|
|
734
|
+
continue
|
|
735
|
+
self.outputTemplateMap[datasetSpec.outputMapKey()] = [outTemplateMap]
|
|
736
|
+
# append
|
|
737
|
+
self.outDatasetSpecList.append(datasetSpec)
|
|
738
|
+
# used only in merge
|
|
739
|
+
if datasetSpec.is_merge_only():
|
|
740
|
+
continue
|
|
741
|
+
# make unmerged dataset
|
|
742
|
+
if "mergeOutput" in taskParamMap and taskParamMap["mergeOutput"] is True:
|
|
743
|
+
umDatasetSpec = JediDatasetSpec()
|
|
744
|
+
umDatasetSpec.datasetName = "panda.um." + datasetSpec.datasetName
|
|
745
|
+
umDatasetSpec.jediTaskID = self.taskSpec.jediTaskID
|
|
746
|
+
umDatasetSpec.storageToken = "TOMERGE"
|
|
747
|
+
umDatasetSpec.vo = datasetSpec.vo
|
|
748
|
+
umDatasetSpec.type = "tmpl_trn_" + datasetSpec.type
|
|
749
|
+
umDatasetSpec.nFiles = 0
|
|
750
|
+
umDatasetSpec.nFilesUsed = 0
|
|
751
|
+
umDatasetSpec.nFilesToBeUsed = 0
|
|
752
|
+
umDatasetSpec.nFilesFinished = 0
|
|
753
|
+
umDatasetSpec.nFilesFailed = 0
|
|
754
|
+
umDatasetSpec.nFilesOnHold = 0
|
|
755
|
+
umDatasetSpec.status = "defined"
|
|
756
|
+
umDatasetSpec.streamName = datasetSpec.streamName
|
|
757
|
+
if datasetSpec.isAllowedNoOutput():
|
|
758
|
+
umDatasetSpec.allowNoOutput()
|
|
759
|
+
# ratio
|
|
760
|
+
if datasetSpec.getRatioToMaster() > 1:
|
|
761
|
+
umDatasetSpec.setDatasetAttribute(f"ratio={datasetSpec.getRatioToMaster()}")
|
|
762
|
+
# make unmerged output template
|
|
763
|
+
if outFileTemplate is not None:
|
|
764
|
+
umOutTemplateMap = {
|
|
765
|
+
"jediTaskID": self.taskSpec.jediTaskID,
|
|
766
|
+
"serialNr": 1,
|
|
767
|
+
"streamName": umDatasetSpec.streamName,
|
|
768
|
+
"outtype": datasetSpec.type,
|
|
769
|
+
}
|
|
770
|
+
# append temporary name
|
|
771
|
+
if "umNameAtEnd" in taskParamMap and taskParamMap["umNameAtEnd"] is True:
|
|
772
|
+
# append temporary name at the end
|
|
773
|
+
umOutTemplateMap["filenameTemplate"] = outFileTemplate + ".panda.um"
|
|
774
|
+
else:
|
|
775
|
+
umOutTemplateMap["filenameTemplate"] = "panda.um." + outFileTemplate
|
|
776
|
+
if umDatasetSpec.outputMapKey() in self.outputTemplateMap:
|
|
777
|
+
# multiple files are associated to the same output datasets
|
|
778
|
+
self.outputTemplateMap[umDatasetSpec.outputMapKey()].append(umOutTemplateMap)
|
|
779
|
+
# don't insert the same output dataset
|
|
780
|
+
continue
|
|
781
|
+
self.outputTemplateMap[umDatasetSpec.outputMapKey()] = [umOutTemplateMap]
|
|
782
|
+
# use log as master for merging
|
|
783
|
+
if datasetSpec.type == "log":
|
|
784
|
+
self.unmergeMasterDatasetSpec[datasetSpec.outputMapKey()] = umDatasetSpec
|
|
785
|
+
else:
|
|
786
|
+
# append
|
|
787
|
+
self.unmergeDatasetSpecMap[datasetSpec.outputMapKey()] = umDatasetSpec
|
|
788
|
+
# set attributes for merging
|
|
789
|
+
if "mergeOutput" in taskParamMap and taskParamMap["mergeOutput"] is True:
|
|
790
|
+
self.setSplitRule(None, 1, JediTaskSpec.splitRuleToken["mergeOutput"])
|
|
791
|
+
# make job parameters
|
|
792
|
+
rndmSeedOffset = None
|
|
793
|
+
firstEventOffset = None
|
|
794
|
+
jobParameters = ""
|
|
795
|
+
for tmpItem in taskParamMap["jobParameters"]:
|
|
796
|
+
if "value" in tmpItem:
|
|
797
|
+
# hidden parameter
|
|
798
|
+
if "hidden" in tmpItem and tmpItem["hidden"] is True:
|
|
799
|
+
continue
|
|
800
|
+
# add tags for ES-only parameters
|
|
801
|
+
esOnly = False
|
|
802
|
+
if "es_only" in tmpItem and tmpItem["es_only"] is True:
|
|
803
|
+
esOnly = True
|
|
804
|
+
if esOnly:
|
|
805
|
+
jobParameters += "<PANDA_ES_ONLY>"
|
|
806
|
+
jobParameters += f"{tmpItem['value']}"
|
|
807
|
+
if esOnly:
|
|
808
|
+
jobParameters += "</PANDA_ES_ONLY>"
|
|
809
|
+
# padding
|
|
810
|
+
if "padding" in tmpItem and tmpItem["padding"] is False:
|
|
811
|
+
pass
|
|
812
|
+
else:
|
|
813
|
+
jobParameters += " "
|
|
814
|
+
# get offset for random seed and first event
|
|
815
|
+
if tmpItem["type"] == "template" and tmpItem["param_type"] == "number":
|
|
816
|
+
if "${RNDMSEED}" in tmpItem["value"]:
|
|
817
|
+
if "offset" in tmpItem:
|
|
818
|
+
rndmSeedOffset = tmpItem["offset"]
|
|
819
|
+
else:
|
|
820
|
+
rndmSeedOffset = 0
|
|
821
|
+
elif "${FIRSTEVENT}" in tmpItem["value"]:
|
|
822
|
+
if "offset" in tmpItem:
|
|
823
|
+
firstEventOffset = tmpItem["offset"]
|
|
824
|
+
jobParameters = jobParameters[:-1]
|
|
825
|
+
# append parameters for event service merging if necessary
|
|
826
|
+
esmergeParams = self.getParamsForEventServiceMerging(taskParamMap)
|
|
827
|
+
if esmergeParams is not None:
|
|
828
|
+
jobParameters += esmergeParams
|
|
829
|
+
self.setJobParamsTemplate(jobParameters)
|
|
830
|
+
# set payload identifier
|
|
831
|
+
self.taskSpec.requestType = self.create_payload_identifier(taskParamMap)
|
|
832
|
+
# set random seed offset
|
|
833
|
+
if rndmSeedOffset is not None:
|
|
834
|
+
self.setSplitRule(None, rndmSeedOffset, JediTaskSpec.splitRuleToken["randomSeed"])
|
|
835
|
+
if firstEventOffset is not None:
|
|
836
|
+
self.setSplitRule(None, firstEventOffset, JediTaskSpec.splitRuleToken["firstEvent"])
|
|
837
|
+
# send HPO request
|
|
838
|
+
if self.taskSpec.is_hpo_workflow():
|
|
839
|
+
try:
|
|
840
|
+
data = copy.copy(taskParamMap["hpoRequestData"])
|
|
841
|
+
data["workload_id"] = self.taskSpec.jediTaskID
|
|
842
|
+
data["is_pseudo_input"] = True
|
|
843
|
+
req = {
|
|
844
|
+
"requester": "panda",
|
|
845
|
+
"request_type": idds.common.constants.RequestType.HyperParameterOpt,
|
|
846
|
+
"transform_tag": idds.common.constants.RequestType.HyperParameterOpt.value,
|
|
847
|
+
"status": idds.common.constants.RequestStatus.New,
|
|
848
|
+
"priority": 0,
|
|
849
|
+
"lifetime": 30,
|
|
850
|
+
"request_metadata": data,
|
|
851
|
+
}
|
|
852
|
+
c = iDDS_Client(idds.common.utils.get_rest_host())
|
|
853
|
+
self.tmpLog.debug(f"req {str(req)}")
|
|
854
|
+
ret = c.add_request(**req)
|
|
855
|
+
self.tmpLog.debug(f"got requestID={str(ret)}")
|
|
856
|
+
except Exception as e:
|
|
857
|
+
errStr = f"iDDS failed with {str(e)}"
|
|
858
|
+
raise JediException.ExternalTempError(errStr)
|
|
859
|
+
|
|
860
|
+
return
|
|
861
|
+
|
|
862
|
+
# replace placeholder with dict provided by prepro job
|
|
863
|
+
def replacePlaceHolders(self, paramItem, placeHolderName, newValue):
|
|
864
|
+
if isinstance(paramItem, dict):
|
|
865
|
+
# loop over all dict params
|
|
866
|
+
for tmpParName, tmpParVal in paramItem.items():
|
|
867
|
+
if tmpParVal == placeHolderName:
|
|
868
|
+
# replace placeholder
|
|
869
|
+
paramItem[tmpParName] = newValue
|
|
870
|
+
elif isinstance(tmpParVal, dict) or isinstance(tmpParVal, list):
|
|
871
|
+
# recursive execution
|
|
872
|
+
self.replacePlaceHolders(tmpParVal, placeHolderName, newValue)
|
|
873
|
+
elif isinstance(paramItem, list):
|
|
874
|
+
# loop over all list items
|
|
875
|
+
for tmpItem in paramItem:
|
|
876
|
+
self.replacePlaceHolders(tmpItem, placeHolderName, newValue)
|
|
877
|
+
|
|
878
|
+
# refinement procedure for preprocessing
|
|
879
|
+
def doPreProRefine(self, taskParamMap):
|
|
880
|
+
# no preprocessing
|
|
881
|
+
if "preproSpec" not in taskParamMap:
|
|
882
|
+
return None, taskParamMap
|
|
883
|
+
# already preprocessed
|
|
884
|
+
if self.taskSpec.checkPreProcessed():
|
|
885
|
+
# get replaced task params
|
|
886
|
+
tmpStat, tmpJsonStr = self.taskBufferIF.getPreprocessMetadata_JEDI(self.taskSpec.jediTaskID)
|
|
887
|
+
try:
|
|
888
|
+
# replace placeholders
|
|
889
|
+
replaceParams = RefinerUtils.decodeJSON(tmpJsonStr)
|
|
890
|
+
self.tmpLog.debug("replace placeholders with " + str(replaceParams))
|
|
891
|
+
for tmpKey, tmpVal in replaceParams.items():
|
|
892
|
+
self.replacePlaceHolders(taskParamMap, tmpKey, tmpVal)
|
|
893
|
+
except Exception:
|
|
894
|
+
errtype, errvalue = sys.exc_info()[:2]
|
|
895
|
+
self.tmpLog.error(f"{self.__class__.__name__} failed to get additional task params with {errtype}:{errvalue}")
|
|
896
|
+
return False, taskParamMap
|
|
897
|
+
# succeeded
|
|
898
|
+
self.updatedTaskParams = taskParamMap
|
|
899
|
+
return None, taskParamMap
|
|
900
|
+
# make dummy dataset to keep track of preprocessing
|
|
901
|
+
datasetSpec = JediDatasetSpec()
|
|
902
|
+
datasetSpec.datasetName = f"panda.pp.in.{uuid.uuid4()}.{self.taskSpec.jediTaskID}"
|
|
903
|
+
datasetSpec.jediTaskID = self.taskSpec.jediTaskID
|
|
904
|
+
datasetSpec.type = "pp_input"
|
|
905
|
+
datasetSpec.vo = self.taskSpec.vo
|
|
906
|
+
datasetSpec.nFiles = 1
|
|
907
|
+
datasetSpec.nFilesUsed = 0
|
|
908
|
+
datasetSpec.nFilesToBeUsed = 1
|
|
909
|
+
datasetSpec.nFilesFinished = 0
|
|
910
|
+
datasetSpec.nFilesFailed = 0
|
|
911
|
+
datasetSpec.nFilesOnHold = 0
|
|
912
|
+
datasetSpec.status = "ready"
|
|
913
|
+
self.inMasterDatasetSpec.append(datasetSpec)
|
|
914
|
+
# make file
|
|
915
|
+
fileSpec = JediFileSpec()
|
|
916
|
+
fileSpec.jediTaskID = datasetSpec.jediTaskID
|
|
917
|
+
fileSpec.type = datasetSpec.type
|
|
918
|
+
fileSpec.status = "ready"
|
|
919
|
+
fileSpec.lfn = "pseudo_lfn"
|
|
920
|
+
fileSpec.attemptNr = 0
|
|
921
|
+
fileSpec.maxAttempt = 3
|
|
922
|
+
fileSpec.keepTrack = 1
|
|
923
|
+
datasetSpec.addFile(fileSpec)
|
|
924
|
+
# make log dataset
|
|
925
|
+
logDatasetSpec = JediDatasetSpec()
|
|
926
|
+
logDatasetSpec.datasetName = f"panda.pp.log.{uuid.uuid4()}.{self.taskSpec.jediTaskID}"
|
|
927
|
+
logDatasetSpec.jediTaskID = self.taskSpec.jediTaskID
|
|
928
|
+
logDatasetSpec.type = "tmpl_pp_log"
|
|
929
|
+
logDatasetSpec.streamName = "PP_LOG"
|
|
930
|
+
logDatasetSpec.vo = self.taskSpec.vo
|
|
931
|
+
logDatasetSpec.nFiles = 0
|
|
932
|
+
logDatasetSpec.nFilesUsed = 0
|
|
933
|
+
logDatasetSpec.nFilesToBeUsed = 0
|
|
934
|
+
logDatasetSpec.nFilesFinished = 0
|
|
935
|
+
logDatasetSpec.nFilesFailed = 0
|
|
936
|
+
logDatasetSpec.nFilesOnHold = 0
|
|
937
|
+
logDatasetSpec.status = "defined"
|
|
938
|
+
self.outDatasetSpecList.append(logDatasetSpec)
|
|
939
|
+
# make output template for log
|
|
940
|
+
outTemplateMap = {
|
|
941
|
+
"jediTaskID": self.taskSpec.jediTaskID,
|
|
942
|
+
"serialNr": 1,
|
|
943
|
+
"streamName": logDatasetSpec.streamName,
|
|
944
|
+
"filenameTemplate": f"{logDatasetSpec.datasetName}._${{SN}}.log.tgz",
|
|
945
|
+
"outtype": re.sub("^tmpl_", "", logDatasetSpec.type),
|
|
946
|
+
}
|
|
947
|
+
self.outputTemplateMap[logDatasetSpec.outputMapKey()] = [outTemplateMap]
|
|
948
|
+
# set split rule to use preprocessing
|
|
949
|
+
self.taskSpec.setPrePro()
|
|
950
|
+
# set task status
|
|
951
|
+
self.taskSpec.status = "topreprocess"
|
|
952
|
+
# return
|
|
953
|
+
return True, taskParamMap
|
|
954
|
+
|
|
955
|
+
# set split rule
|
|
956
|
+
def setSplitRule(self, taskParamMap, key_or_value, rule_token):
|
|
957
|
+
if taskParamMap is not None:
|
|
958
|
+
if key_or_value not in taskParamMap:
|
|
959
|
+
self.taskSpec.splitRule = task_split_rules.remove_rule(self.taskSpec.splitRule, rule_token)
|
|
960
|
+
return
|
|
961
|
+
tmpStr = f"{rule_token}={taskParamMap[key_or_value]}"
|
|
962
|
+
else:
|
|
963
|
+
if key_or_value is None:
|
|
964
|
+
self.taskSpec.splitRule = task_split_rules.remove_rule(self.taskSpec.splitRule, rule_token)
|
|
965
|
+
return
|
|
966
|
+
tmpStr = f"{rule_token}={key_or_value}"
|
|
967
|
+
if self.taskSpec.splitRule in [None, ""]:
|
|
968
|
+
self.taskSpec.splitRule = tmpStr
|
|
969
|
+
else:
|
|
970
|
+
tmpMatch = re.search(rule_token + "=(-*\d+)(,-*\d+)*", self.taskSpec.splitRule)
|
|
971
|
+
if tmpMatch is None:
|
|
972
|
+
# append
|
|
973
|
+
self.taskSpec.splitRule += f",{tmpStr}"
|
|
974
|
+
else:
|
|
975
|
+
# replace
|
|
976
|
+
self.taskSpec.splitRule = self.taskSpec.splitRule.replace(tmpMatch.group(0), tmpStr)
|
|
977
|
+
return
|
|
978
|
+
|
|
979
|
+
# get parameters for event service merging
|
|
980
|
+
def getParamsForEventServiceMerging(self, taskParamMap):
|
|
981
|
+
# no event service
|
|
982
|
+
if not self.taskSpec.useEventService() or self.taskSpec.on_site_merging():
|
|
983
|
+
return None
|
|
984
|
+
# extract parameters
|
|
985
|
+
transPath = "UnDefined"
|
|
986
|
+
jobParameters = "UnDefined"
|
|
987
|
+
if "esmergeSpec" in taskParamMap:
|
|
988
|
+
if "transPath" in taskParamMap["esmergeSpec"]:
|
|
989
|
+
transPath = taskParamMap["esmergeSpec"]["transPath"]
|
|
990
|
+
if "jobParameters" in taskParamMap["esmergeSpec"]:
|
|
991
|
+
jobParameters = jobParameters["esmergeSpec"]["jobParameters"]
|
|
992
|
+
# return
|
|
993
|
+
return "<PANDA_ESMERGE_TRF>" + transPath + "</PANDA_ESMERGE_TRF>" + "<PANDA_ESMERGE_JOBP>" + jobParameters + "</PANDA_ESMERGE_JOBP>"
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
Interaction.installSC(TaskRefinerBase)
|