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,272 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import functools
|
|
3
|
+
import time
|
|
4
|
+
import traceback
|
|
5
|
+
import uuid
|
|
6
|
+
|
|
7
|
+
from pandacommon.pandalogger.LogWrapper import LogWrapper
|
|
8
|
+
from pandacommon.pandalogger.PandaLogger import PandaLogger
|
|
9
|
+
from pandacommon.pandautils.PandaUtils import naive_utcnow
|
|
10
|
+
|
|
11
|
+
from pandaserver.config import panda_config
|
|
12
|
+
from pandaserver.dataservice import DataServiceUtils
|
|
13
|
+
|
|
14
|
+
_log = PandaLogger().getLogger("broker")
|
|
15
|
+
|
|
16
|
+
# all known sites
|
|
17
|
+
_allSites = []
|
|
18
|
+
|
|
19
|
+
# processingType to skip brokerage
|
|
20
|
+
skipBrokerageProTypes = ["prod_test"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# comparison function for sort
|
|
24
|
+
def _compFunc(job_a, job_b):
|
|
25
|
+
# This comparison helps in sorting the jobs based on the order of their computing sites in the _allSites list.
|
|
26
|
+
# append site if not in list
|
|
27
|
+
if job_a.computingSite not in _allSites:
|
|
28
|
+
_allSites.append(job_a.computingSite)
|
|
29
|
+
if job_b.computingSite not in _allSites:
|
|
30
|
+
_allSites.append(job_b.computingSite)
|
|
31
|
+
|
|
32
|
+
# compare site indices
|
|
33
|
+
index_a = _allSites.index(job_a.computingSite)
|
|
34
|
+
index_b = _allSites.index(job_b.computingSite)
|
|
35
|
+
|
|
36
|
+
if index_a > index_b:
|
|
37
|
+
return 1
|
|
38
|
+
elif index_a < index_b:
|
|
39
|
+
return -1
|
|
40
|
+
else:
|
|
41
|
+
return 0
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def schedule(jobs, siteMapper):
|
|
45
|
+
timestamp = naive_utcnow().isoformat("/")
|
|
46
|
+
tmp_log = LogWrapper(_log, f"start_ts={timestamp}")
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
# no jobs
|
|
50
|
+
if len(jobs) == 0:
|
|
51
|
+
tmp_log.debug("finished : no jobs")
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
max_jobs = 20
|
|
55
|
+
max_files = 20
|
|
56
|
+
|
|
57
|
+
iJob = 0
|
|
58
|
+
fileList = []
|
|
59
|
+
chosen_panda_queue = None
|
|
60
|
+
prodDBlock = None
|
|
61
|
+
computingSite = None
|
|
62
|
+
dispatchDBlock = None
|
|
63
|
+
previousCloud = None
|
|
64
|
+
prevProType = None
|
|
65
|
+
prevSourceLabel = None
|
|
66
|
+
prevDirectAcc = None
|
|
67
|
+
prevIsJEDI = None
|
|
68
|
+
prevBrokerageSiteList = None
|
|
69
|
+
|
|
70
|
+
indexJob = 0
|
|
71
|
+
|
|
72
|
+
# sort jobs by siteID. Some jobs may already define computingSite
|
|
73
|
+
jobs = sorted(jobs, key=functools.cmp_to_key(_compFunc))
|
|
74
|
+
|
|
75
|
+
# loop over all jobs + terminator(None)
|
|
76
|
+
for job in jobs + [None]:
|
|
77
|
+
indexJob += 1
|
|
78
|
+
|
|
79
|
+
# ignore failed jobs
|
|
80
|
+
if job and job.jobStatus == "failed":
|
|
81
|
+
continue
|
|
82
|
+
|
|
83
|
+
# list of sites for special brokerage
|
|
84
|
+
specialBrokerageSiteList = []
|
|
85
|
+
|
|
86
|
+
# manually set site
|
|
87
|
+
if job and job.computingSite != "NULL" and job.prodSourceLabel in ("test", "managed") and specialBrokerageSiteList == []:
|
|
88
|
+
specialBrokerageSiteList = [job.computingSite]
|
|
89
|
+
|
|
90
|
+
overwriteSite = False
|
|
91
|
+
|
|
92
|
+
# check JEDI
|
|
93
|
+
isJEDI = False
|
|
94
|
+
if job and job.lockedby == "jedi":
|
|
95
|
+
isJEDI = True
|
|
96
|
+
|
|
97
|
+
# new bunch or terminator
|
|
98
|
+
if (
|
|
99
|
+
job is None
|
|
100
|
+
or len(fileList) >= max_files
|
|
101
|
+
or (dispatchDBlock is None and job.homepackage.startswith("AnalysisTransforms"))
|
|
102
|
+
or prodDBlock != job.prodDBlock
|
|
103
|
+
or job.computingSite != computingSite
|
|
104
|
+
or iJob > max_jobs
|
|
105
|
+
or previousCloud != job.getCloud()
|
|
106
|
+
or (prevProType in skipBrokerageProTypes and iJob > 0)
|
|
107
|
+
or prevDirectAcc != job.transferType
|
|
108
|
+
or prevProType != job.processingType
|
|
109
|
+
or prevBrokerageSiteList != specialBrokerageSiteList
|
|
110
|
+
or prevIsJEDI != isJEDI
|
|
111
|
+
):
|
|
112
|
+
if indexJob > 1:
|
|
113
|
+
tmp_log.debug("new bunch")
|
|
114
|
+
tmp_log.debug(f" iJob {iJob}")
|
|
115
|
+
tmp_log.debug(f" cloud {previousCloud}")
|
|
116
|
+
tmp_log.debug(f" sourceLabel {prevSourceLabel}")
|
|
117
|
+
tmp_log.debug(f" prodDBlock {prodDBlock}")
|
|
118
|
+
tmp_log.debug(f" computingSite {computingSite}")
|
|
119
|
+
tmp_log.debug(f" processingType {prevProType}")
|
|
120
|
+
tmp_log.debug(f" transferType {prevDirectAcc}")
|
|
121
|
+
|
|
122
|
+
if (iJob != 0 and chosen_panda_queue == "TOBEDONE") or prevBrokerageSiteList not in [None, []]:
|
|
123
|
+
# load balancing
|
|
124
|
+
minSites = {}
|
|
125
|
+
if prevBrokerageSiteList:
|
|
126
|
+
# special brokerage
|
|
127
|
+
scanSiteList = prevBrokerageSiteList
|
|
128
|
+
else:
|
|
129
|
+
if siteMapper.checkCloud(previousCloud):
|
|
130
|
+
# use cloud sites
|
|
131
|
+
scanSiteList = siteMapper.getCloud(previousCloud)["sites"]
|
|
132
|
+
|
|
133
|
+
# loop over all sites
|
|
134
|
+
for site in scanSiteList:
|
|
135
|
+
tmp_log.debug(f"calculate weight for site:{site}")
|
|
136
|
+
# _allSites may contain NULL after sort()
|
|
137
|
+
if site == "NULL":
|
|
138
|
+
tmp_log.debug("site is NULL")
|
|
139
|
+
continue
|
|
140
|
+
|
|
141
|
+
winv = 1
|
|
142
|
+
|
|
143
|
+
tmp_log.debug(f"Site:{site} 1/Weight:{winv}")
|
|
144
|
+
|
|
145
|
+
# choose largest nMinSites weights
|
|
146
|
+
minSites[site] = winv
|
|
147
|
+
|
|
148
|
+
# choose site
|
|
149
|
+
tmp_log.debug(f"Min Sites:{minSites}")
|
|
150
|
+
if len(fileList) == 0 or prevIsJEDI is True:
|
|
151
|
+
# choose min 1/weight
|
|
152
|
+
minSite = list(minSites)[0]
|
|
153
|
+
chosen_panda_queue = siteMapper.getSite(minSite)
|
|
154
|
+
|
|
155
|
+
# set job spec
|
|
156
|
+
tmp_log.debug(f"indexJob : {indexJob}")
|
|
157
|
+
|
|
158
|
+
for tmpJob in jobs[indexJob - iJob - 1 : indexJob - 1]:
|
|
159
|
+
# set computingSite
|
|
160
|
+
tmpJob.computingSite = chosen_panda_queue.sitename
|
|
161
|
+
tmp_log.debug(f"PandaID:{tmpJob.PandaID} -> site:{tmpJob.computingSite}")
|
|
162
|
+
|
|
163
|
+
# terminate
|
|
164
|
+
if job is None:
|
|
165
|
+
break
|
|
166
|
+
# reset iJob
|
|
167
|
+
iJob = 0
|
|
168
|
+
# reset file list
|
|
169
|
+
fileList = []
|
|
170
|
+
# create new dispDBlock
|
|
171
|
+
if job.prodDBlock != "NULL":
|
|
172
|
+
# get datatype
|
|
173
|
+
try:
|
|
174
|
+
tmpDataType = job.prodDBlock.split(":")[-1].split(".")[-2]
|
|
175
|
+
except Exception:
|
|
176
|
+
# default
|
|
177
|
+
tmpDataType = "GEN"
|
|
178
|
+
if len(tmpDataType) > 20:
|
|
179
|
+
# avoid too long name
|
|
180
|
+
tmpDataType = "GEN"
|
|
181
|
+
transferType = "transfer"
|
|
182
|
+
if job.useInputPrestaging():
|
|
183
|
+
transferType = "prestaging"
|
|
184
|
+
dispatchDBlock = f"panda.{job.taskID}.{time.strftime('%m.%d')}.{tmpDataType}.{transferType}.{str(uuid.uuid4())}_dis{job.PandaID}"
|
|
185
|
+
tmp_log.debug(f"New dispatchDBlock: {dispatchDBlock}")
|
|
186
|
+
prodDBlock = job.prodDBlock
|
|
187
|
+
# already define computingSite
|
|
188
|
+
if job.computingSite != "NULL":
|
|
189
|
+
# instantiate KnownSite
|
|
190
|
+
chosen_panda_queue = siteMapper.getSite(job.computingSite)
|
|
191
|
+
|
|
192
|
+
# if site doesn't exist, use the default site
|
|
193
|
+
if job.homepackage.startswith("AnalysisTransforms"):
|
|
194
|
+
if chosen_panda_queue.sitename == panda_config.def_sitename:
|
|
195
|
+
chosen_panda_queue = siteMapper.getSite(panda_config.def_queue)
|
|
196
|
+
overwriteSite = True
|
|
197
|
+
else:
|
|
198
|
+
# default for Analysis jobs
|
|
199
|
+
if job.homepackage.startswith("AnalysisTransforms"):
|
|
200
|
+
chosen_panda_queue = siteMapper.getSite(panda_config.def_queue)
|
|
201
|
+
overwriteSite = True
|
|
202
|
+
else:
|
|
203
|
+
# set chosen_panda_queue
|
|
204
|
+
chosen_panda_queue = "TOBEDONE"
|
|
205
|
+
# increment iJob
|
|
206
|
+
iJob += 1
|
|
207
|
+
# reserve computingSite and cloud
|
|
208
|
+
computingSite = job.computingSite
|
|
209
|
+
previousCloud = job.getCloud()
|
|
210
|
+
prevProType = job.processingType
|
|
211
|
+
prevSourceLabel = job.prodSourceLabel
|
|
212
|
+
prevDirectAcc = job.transferType
|
|
213
|
+
prevBrokerageSiteList = specialBrokerageSiteList
|
|
214
|
+
prevIsJEDI = isJEDI
|
|
215
|
+
|
|
216
|
+
# assign site
|
|
217
|
+
if chosen_panda_queue != "TOBEDONE":
|
|
218
|
+
job.computingSite = chosen_panda_queue.sitename
|
|
219
|
+
tmp_log.debug(f"PandaID:{job.PandaID} -> preset site:{chosen_panda_queue.sitename}")
|
|
220
|
+
# set cloud
|
|
221
|
+
if job.cloud in ["NULL", None, ""]:
|
|
222
|
+
job.cloud = chosen_panda_queue.cloud
|
|
223
|
+
|
|
224
|
+
# set destinationSE
|
|
225
|
+
destSE = job.destinationSE
|
|
226
|
+
if siteMapper.checkCloud(job.getCloud()):
|
|
227
|
+
# use cloud dest for non-existing sites
|
|
228
|
+
if job.prodSourceLabel != "user" and job.destinationSE not in siteMapper.siteSpecList and job.destinationSE != "local":
|
|
229
|
+
if DataServiceUtils.checkJobDestinationSE(job):
|
|
230
|
+
destSE = DataServiceUtils.checkJobDestinationSE(job)
|
|
231
|
+
job.destinationSE = destSE
|
|
232
|
+
|
|
233
|
+
if overwriteSite:
|
|
234
|
+
# overwrite SE for analysis jobs which set non-existing sites
|
|
235
|
+
destSE = job.computingSite
|
|
236
|
+
job.destinationSE = destSE
|
|
237
|
+
|
|
238
|
+
# set dispatchDBlock and destinationSE
|
|
239
|
+
first = True
|
|
240
|
+
for file in job.Files:
|
|
241
|
+
# Set dispatch data block for pre-stating jobs too
|
|
242
|
+
if file.type == "input" and file.dispatchDBlock == "NULL" and file.status not in ["ready", "missing", "cached"]:
|
|
243
|
+
if first:
|
|
244
|
+
first = False
|
|
245
|
+
job.dispatchDBlock = dispatchDBlock
|
|
246
|
+
file.dispatchDBlock = dispatchDBlock
|
|
247
|
+
file.status = "pending"
|
|
248
|
+
if file.lfn not in fileList:
|
|
249
|
+
fileList.append(file.lfn)
|
|
250
|
+
|
|
251
|
+
# destinationSE
|
|
252
|
+
if file.type in ["output", "log"] and destSE != "":
|
|
253
|
+
if job.prodSourceLabel == "user" and job.computingSite == file.destinationSE:
|
|
254
|
+
pass
|
|
255
|
+
elif job.prodSourceLabel == "user" and prevIsJEDI is True and file.destinationSE not in ["", "NULL"]:
|
|
256
|
+
pass
|
|
257
|
+
elif destSE == "local":
|
|
258
|
+
pass
|
|
259
|
+
elif DataServiceUtils.getDistributedDestination(file.destinationDBlockToken):
|
|
260
|
+
pass
|
|
261
|
+
else:
|
|
262
|
+
file.destinationSE = destSE
|
|
263
|
+
|
|
264
|
+
# pre-assign GUID to log
|
|
265
|
+
if file.type == "log":
|
|
266
|
+
# generate GUID
|
|
267
|
+
file.GUID = str(uuid.uuid4())
|
|
268
|
+
|
|
269
|
+
tmp_log.debug("finished")
|
|
270
|
+
|
|
271
|
+
except Exception as e:
|
|
272
|
+
tmp_log.error(f"schedule : {str(e)} {traceback.format_exc()}")
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# load configmap
|
|
6
|
+
def load_config_map(section, target_dict):
|
|
7
|
+
if "PANDA_HOME" not in os.environ:
|
|
8
|
+
return
|
|
9
|
+
config_map_name = "panda_server_config.json"
|
|
10
|
+
config_map_path = os.path.join(os.environ["PANDA_HOME"], "etc/config_json", config_map_name)
|
|
11
|
+
if os.path.exists(config_map_path):
|
|
12
|
+
with open(config_map_path) as f:
|
|
13
|
+
tmp_data = json.load(f)
|
|
14
|
+
if section in tmp_data:
|
|
15
|
+
target_dict.update(tmp_data[section])
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from pandacommon.liveconfigparser.LiveConfigParser import (
|
|
5
|
+
LiveConfigParser,
|
|
6
|
+
expand_values,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from . import config_utils
|
|
10
|
+
|
|
11
|
+
# get ConfigParser
|
|
12
|
+
tmpConf = LiveConfigParser()
|
|
13
|
+
|
|
14
|
+
# read
|
|
15
|
+
tmpConf.read("panda_server.cfg")
|
|
16
|
+
|
|
17
|
+
# get daemon section
|
|
18
|
+
tmpDict = getattr(tmpConf, "daemon", {})
|
|
19
|
+
|
|
20
|
+
# read configmap
|
|
21
|
+
config_utils.load_config_map("daemon", tmpDict)
|
|
22
|
+
|
|
23
|
+
# expand all values
|
|
24
|
+
tmpSelf = sys.modules[__name__]
|
|
25
|
+
expand_values(tmpSelf, tmpDict)
|
|
26
|
+
|
|
27
|
+
# default values
|
|
28
|
+
if "enable" not in tmpSelf.__dict__:
|
|
29
|
+
tmpSelf.__dict__["enable"] = False
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from pandacommon.liveconfigparser.LiveConfigParser import (
|
|
5
|
+
LiveConfigParser,
|
|
6
|
+
expand_values,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from . import config_utils
|
|
10
|
+
|
|
11
|
+
# get ConfigParser
|
|
12
|
+
tmp_conf = LiveConfigParser()
|
|
13
|
+
|
|
14
|
+
# read
|
|
15
|
+
tmp_conf.read("panda_server.cfg")
|
|
16
|
+
|
|
17
|
+
# get daemon section
|
|
18
|
+
tmp_dict = getattr(tmp_conf, "mcp", {})
|
|
19
|
+
|
|
20
|
+
# read configmap
|
|
21
|
+
config_utils.load_config_map("mcp", tmp_dict)
|
|
22
|
+
|
|
23
|
+
# expand all values
|
|
24
|
+
tmp_self = sys.modules[__name__]
|
|
25
|
+
expand_values(tmp_self, tmp_dict)
|
|
26
|
+
|
|
27
|
+
# default values
|
|
28
|
+
if "transport" not in tmp_self.__dict__:
|
|
29
|
+
tmp_self.__dict__["transport"] = "streamable-http"
|
|
30
|
+
|
|
31
|
+
if "endpoint_list_file" not in tmp_self.__dict__:
|
|
32
|
+
tmp_self.__dict__["endpoint_list_file"] = "/opt/panda/etc/panda/panda_mcp_endpoints.json"
|
|
33
|
+
|
|
34
|
+
if "ssl_keyfile" not in tmp_self.__dict__:
|
|
35
|
+
tmp_self.__dict__["ssl_keyfile"] = None
|
|
36
|
+
|
|
37
|
+
if "ssl_certfile" not in tmp_self.__dict__:
|
|
38
|
+
tmp_self.__dict__["ssl_certfile"] = None
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import glob
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import socket
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from pandacommon.liveconfigparser.LiveConfigParser import (
|
|
9
|
+
LiveConfigParser,
|
|
10
|
+
expand_values,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from . import config_utils
|
|
14
|
+
|
|
15
|
+
# get ConfigParser
|
|
16
|
+
tmpConf = LiveConfigParser()
|
|
17
|
+
|
|
18
|
+
# read
|
|
19
|
+
tmpConf.read("panda_server.cfg")
|
|
20
|
+
|
|
21
|
+
# get server section
|
|
22
|
+
tmpDict = tmpConf.server
|
|
23
|
+
|
|
24
|
+
# read configmap
|
|
25
|
+
config_utils.load_config_map("server", tmpDict)
|
|
26
|
+
|
|
27
|
+
# expand all values
|
|
28
|
+
tmpSelf = sys.modules[__name__]
|
|
29
|
+
expand_values(tmpSelf, tmpDict)
|
|
30
|
+
|
|
31
|
+
# set hostname
|
|
32
|
+
if "pserverhost" not in tmpSelf.__dict__:
|
|
33
|
+
tmpSelf.__dict__["pserverhost"] = socket.getfqdn()
|
|
34
|
+
|
|
35
|
+
# set port for http
|
|
36
|
+
if "pserverporthttp" not in tmpSelf.__dict__:
|
|
37
|
+
tmpSelf.__dict__["pserverporthttp"] = 25080
|
|
38
|
+
|
|
39
|
+
# set host for http
|
|
40
|
+
if "pserverhosthttp" not in tmpSelf.__dict__:
|
|
41
|
+
tmpSelf.__dict__["pserverhosthttp"] = tmpSelf.__dict__["pserverhost"]
|
|
42
|
+
|
|
43
|
+
# disable http
|
|
44
|
+
if "disableHTTP" not in tmpSelf.__dict__:
|
|
45
|
+
tmpSelf.__dict__["disableHTTP"] = False
|
|
46
|
+
|
|
47
|
+
# DB backend
|
|
48
|
+
if "backend" not in tmpSelf.__dict__:
|
|
49
|
+
tmpSelf.__dict__["backend"] = "oracle"
|
|
50
|
+
if "dbport" not in tmpSelf.__dict__:
|
|
51
|
+
tmpSelf.__dict__["dbport"] = 0
|
|
52
|
+
if "dbtimeout" not in tmpSelf.__dict__:
|
|
53
|
+
tmpSelf.__dict__["dbtimeout"] = 60
|
|
54
|
+
|
|
55
|
+
# Directory for certs
|
|
56
|
+
if "certdir" not in tmpSelf.__dict__:
|
|
57
|
+
tmpSelf.__dict__["certdir"] = "/data/atlpan"
|
|
58
|
+
|
|
59
|
+
# endpoint map file
|
|
60
|
+
if "endpoint_mapfile" not in tmpSelf.__dict__:
|
|
61
|
+
tmpSelf.__dict__["endpoint_mapfile"] = (
|
|
62
|
+
"/cvmfs/atlas.cern.ch/repo/sw/local/etc/cric_ddmendpoints.json" ",/cvmfs/atlas.cern.ch/repo/sw/local/etc/agis_ddmendpoints.json"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# sandbox info
|
|
66
|
+
if "record_sandbox_info" not in tmpSelf.__dict__:
|
|
67
|
+
tmpSelf.__dict__["record_sandbox_info"] = True
|
|
68
|
+
|
|
69
|
+
# secrets
|
|
70
|
+
if "pilot_secrets" not in tmpSelf.__dict__:
|
|
71
|
+
tmpSelf.__dict__["pilot_secrets"] = "pilot secrets"
|
|
72
|
+
|
|
73
|
+
# schemas
|
|
74
|
+
if "schemaPANDA" not in tmpSelf.__dict__:
|
|
75
|
+
tmpSelf.__dict__["schemaPANDA"] = "ATLAS_PANDA"
|
|
76
|
+
if "schemaPANDAARCH" not in tmpSelf.__dict__:
|
|
77
|
+
tmpSelf.__dict__["schemaPANDAARCH"] = "ATLAS_PANDAARCH"
|
|
78
|
+
if "schemaMETA" not in tmpSelf.__dict__:
|
|
79
|
+
tmpSelf.__dict__["schemaMETA"] = "ATLAS_PANDAMETA"
|
|
80
|
+
if "schemaJEDI" not in tmpSelf.__dict__:
|
|
81
|
+
tmpSelf.__dict__["schemaJEDI"] = "ATLAS_PANDA"
|
|
82
|
+
if "schemaDEFT" not in tmpSelf.__dict__:
|
|
83
|
+
tmpSelf.__dict__["schemaDEFT"] = "ATLAS_DEFT"
|
|
84
|
+
if "schemaGRISLI" not in tmpSelf.__dict__:
|
|
85
|
+
tmpSelf.__dict__["schemaGRISLI"] = "ATLAS_GRISLI"
|
|
86
|
+
if "schemaEI" not in tmpSelf.__dict__:
|
|
87
|
+
tmpSelf.__dict__["schemaEI"] = "ATLAS_EVENTINDEX"
|
|
88
|
+
|
|
89
|
+
# default site
|
|
90
|
+
if "def_sitename" not in tmpSelf.__dict__:
|
|
91
|
+
tmpSelf.__dict__["def_sitename"] = "BNL_ATLAS_1"
|
|
92
|
+
if "def_queue" not in tmpSelf.__dict__:
|
|
93
|
+
tmpSelf.__dict__["def_queue"] = "ANALY_BNL_ATLAS_1"
|
|
94
|
+
if "def_nickname" not in tmpSelf.__dict__:
|
|
95
|
+
tmpSelf.__dict__["def_nickname"] = "BNL_ATLAS_1-condor"
|
|
96
|
+
if "def_ddm" not in tmpSelf.__dict__:
|
|
97
|
+
tmpSelf.__dict__["def_ddm"] = "PANDA_UNDEFINED2"
|
|
98
|
+
if "def_type" not in tmpSelf.__dict__:
|
|
99
|
+
tmpSelf.__dict__["def_type"] = "production"
|
|
100
|
+
if "def_status" not in tmpSelf.__dict__:
|
|
101
|
+
tmpSelf.__dict__["def_status"] = "online"
|
|
102
|
+
if "token_authType" not in tmpSelf.__dict__:
|
|
103
|
+
tmpSelf.__dict__["token_authType"] = "oidc"
|
|
104
|
+
if "auth_config" not in tmpSelf.__dict__:
|
|
105
|
+
tmpSelf.__dict__["auth_config"] = "/opt/panda/etc/panda/auth/"
|
|
106
|
+
if "token_audience" not in tmpSelf.__dict__:
|
|
107
|
+
tmpSelf.__dict__["token_audience"] = "https://pandaserver.cern.ch"
|
|
108
|
+
if "token_issuers" not in tmpSelf.__dict__:
|
|
109
|
+
tmpSelf.__dict__["token_issuers"] = ""
|
|
110
|
+
if "legacy_token_issuers" not in tmpSelf.__dict__:
|
|
111
|
+
tmpSelf.__dict__["legacy_token_issuers"] = "https://atlas-auth.cern.ch/,https://atlas-auth.web.cern.ch/"
|
|
112
|
+
if tmpSelf.__dict__["legacy_token_issuers"]:
|
|
113
|
+
tmpSelf.__dict__["legacy_token_issuers"] = tmpSelf.__dict__["legacy_token_issuers"].split(",")
|
|
114
|
+
else:
|
|
115
|
+
tmpSelf.__dict__["legacy_token_issuers"] = None
|
|
116
|
+
tmpSelf.__dict__["production_dns"] = [x for x in tmpSelf.__dict__.get("production_dns", "").split(",") if x]
|
|
117
|
+
tmpSelf.__dict__["pilot_owners"] = [x for x in tmpSelf.__dict__.get("pilot_owners", "").split(",") if x]
|
|
118
|
+
tmpSelf.__dict__["auth_policies"] = {}
|
|
119
|
+
tmpSelf.__dict__["auth_vo_dict"] = {}
|
|
120
|
+
try:
|
|
121
|
+
data_dict = {}
|
|
122
|
+
vo_data_dict = {}
|
|
123
|
+
policy_dict = {}
|
|
124
|
+
for name in glob.glob(os.path.join(tmpSelf.__dict__["auth_config"], "*_auth_config.json")):
|
|
125
|
+
with open(name) as f:
|
|
126
|
+
data = json.load(f)
|
|
127
|
+
data_dict[data["client_id"]] = data
|
|
128
|
+
if "secondary_ids" in data:
|
|
129
|
+
for tmp_id in data["secondary_ids"]:
|
|
130
|
+
data_dict[tmp_id] = data
|
|
131
|
+
m = re.search("^(.+)_auth_config.json", os.path.basename(name))
|
|
132
|
+
if m:
|
|
133
|
+
# Extract the VO group from the filename
|
|
134
|
+
tmp_vo_group = m.group(1)
|
|
135
|
+
|
|
136
|
+
# Determine tmp_vo and tmp_group based on delimiters
|
|
137
|
+
if tmp_vo_group.startswith("vo.") and ":" in tmp_vo_group:
|
|
138
|
+
tmp_vo, tmp_group = tmp_vo_group.split(":", 1)
|
|
139
|
+
elif ":" in tmp_vo_group:
|
|
140
|
+
tmp_vo, tmp_group = tmp_vo_group.split(":", 1)
|
|
141
|
+
elif tmp_vo_group.startswith("vo."):
|
|
142
|
+
# If it starts with "vo." but has no ":", treat it as a single VO with "user" as the group
|
|
143
|
+
tmp_vo = tmp_vo_group
|
|
144
|
+
tmp_group = "user"
|
|
145
|
+
elif "." in tmp_vo_group:
|
|
146
|
+
tmp_vo, tmp_group = tmp_vo_group.split(".", 1)
|
|
147
|
+
else:
|
|
148
|
+
tmp_vo, tmp_group = tmp_vo_group, "user"
|
|
149
|
+
|
|
150
|
+
policy_dict.setdefault(tmp_vo, [])
|
|
151
|
+
policy_dict[tmp_vo].append([tmp_vo, {"group": tmp_group, "role": tmp_group}])
|
|
152
|
+
vo_data_dict[tmp_vo_group.replace(":", ".")] = data
|
|
153
|
+
tmpSelf.__dict__["auth_config"] = data_dict
|
|
154
|
+
tmpSelf.__dict__["auth_policies"] = policy_dict
|
|
155
|
+
tmpSelf.__dict__["auth_vo_dict"] = vo_data_dict
|
|
156
|
+
except Exception:
|
|
157
|
+
tmpSelf.__dict__["auth_config"] = {}
|
|
158
|
+
|
|
159
|
+
if "token_cache_config" not in tmpSelf.__dict__:
|
|
160
|
+
tmpSelf.__dict__["token_cache_config"] = "/opt/panda/etc/panda/token_cache_config.json"
|
|
161
|
+
|
|
162
|
+
# use cert in configurator
|
|
163
|
+
if "configurator_use_cert" not in tmpSelf.__dict__:
|
|
164
|
+
tmpSelf.__dict__["configurator_use_cert"] = True
|
|
165
|
+
|
|
166
|
+
# adder serialization
|
|
167
|
+
if "add_serialized" not in tmpSelf.__dict__:
|
|
168
|
+
tmpSelf.__dict__["add_serialized"] = False
|
|
169
|
+
|
|
170
|
+
# disable file aggregation
|
|
171
|
+
if "disable_file_aggregation" not in tmpSelf.__dict__:
|
|
172
|
+
tmpSelf.__dict__["disable_file_aggregation"] = False
|
|
173
|
+
|
|
174
|
+
# dict for plugins
|
|
175
|
+
g_pluginMap = {}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
# parser for plugin setup
|
|
179
|
+
def parsePluginConf(modConfigName):
|
|
180
|
+
global tmpSelf
|
|
181
|
+
global g_pluginMap
|
|
182
|
+
g_pluginMap.setdefault(modConfigName, {})
|
|
183
|
+
# parse plugin setup
|
|
184
|
+
try:
|
|
185
|
+
for configStr in getattr(tmpSelf, modConfigName).split(","):
|
|
186
|
+
configStr = configStr.strip()
|
|
187
|
+
items = configStr.split(":")
|
|
188
|
+
vos = items[0].split("|")
|
|
189
|
+
moduleName = items[1]
|
|
190
|
+
className = items[2]
|
|
191
|
+
if len(items) > 3:
|
|
192
|
+
group = items[3]
|
|
193
|
+
else:
|
|
194
|
+
group = None
|
|
195
|
+
for vo in vos:
|
|
196
|
+
# import
|
|
197
|
+
mod = __import__(moduleName)
|
|
198
|
+
for subModuleName in moduleName.split(".")[1:]:
|
|
199
|
+
mod = getattr(mod, subModuleName)
|
|
200
|
+
# get class
|
|
201
|
+
cls = getattr(mod, className)
|
|
202
|
+
if group:
|
|
203
|
+
vo_key = f"{vo}_{group}"
|
|
204
|
+
else:
|
|
205
|
+
vo_key = vo
|
|
206
|
+
g_pluginMap[modConfigName][vo_key] = cls
|
|
207
|
+
except Exception:
|
|
208
|
+
pass
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# accessor for plugin
|
|
212
|
+
def getPlugin(modConfigName, vo, group=None):
|
|
213
|
+
if modConfigName not in g_pluginMap:
|
|
214
|
+
return None
|
|
215
|
+
if group:
|
|
216
|
+
vo_group = f"{vo}_{group}"
|
|
217
|
+
if vo_group in g_pluginMap[modConfigName]:
|
|
218
|
+
# VO+group specified
|
|
219
|
+
return g_pluginMap[modConfigName][vo_group]
|
|
220
|
+
if vo in g_pluginMap[modConfigName]:
|
|
221
|
+
# VO specified
|
|
222
|
+
return g_pluginMap[modConfigName][vo]
|
|
223
|
+
if "any" in g_pluginMap[modConfigName]:
|
|
224
|
+
# catch all
|
|
225
|
+
return g_pluginMap[modConfigName]["any"]
|
|
226
|
+
# undefined
|
|
227
|
+
return None
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# plug-ins
|
|
231
|
+
def setupPlugin():
|
|
232
|
+
parsePluginConf("adder_plugins")
|
|
233
|
+
parsePluginConf("setupper_plugins")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import threading
|
|
3
|
+
import traceback
|
|
4
|
+
|
|
5
|
+
from pandacommon.pandalogger.PandaLogger import PandaLogger
|
|
6
|
+
from pandaserver.config import panda_config
|
|
7
|
+
from pandaserver.configurator import aux
|
|
8
|
+
|
|
9
|
+
_logger = PandaLogger().getLogger("carbon")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CarbonEmissions(threading.Thread):
|
|
13
|
+
"""
|
|
14
|
+
Downloads the carbon information from the relevant sources
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, taskBuffer):
|
|
18
|
+
threading.Thread.__init__(self)
|
|
19
|
+
|
|
20
|
+
self.bearer_token = None
|
|
21
|
+
if hasattr(panda_config, "CO2_BEARER_TOKEN"):
|
|
22
|
+
self.bearer_token = panda_config.CO2_BEARER_TOKEN
|
|
23
|
+
|
|
24
|
+
self.taskBuffer = taskBuffer
|
|
25
|
+
|
|
26
|
+
def download_region_emissions(self):
|
|
27
|
+
# Don't indent the query
|
|
28
|
+
query = """
|
|
29
|
+
{"search_type": "query_then_fetch","ignore_unavailable": true,"index": ["monit_prod_green-it_raw_regionmetric*"]}
|
|
30
|
+
{"query": {"range": {"metadata.timestamp": {"gte": "now-2h","lt": "now"}}}, "size": 100}}
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
results = aux.query_grafana_proxy(query, self.bearer_token)
|
|
34
|
+
if not results:
|
|
35
|
+
_logger.error("download_region_emissions was not able to download data")
|
|
36
|
+
return None
|
|
37
|
+
|
|
38
|
+
status = results["responses"][0]["status"]
|
|
39
|
+
if status != 200:
|
|
40
|
+
_logger.error(f"download_region_emissions was not able to download data with status {status}")
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
hits = results["responses"][0]["hits"]["hits"] # That's how the json is structured...
|
|
44
|
+
results = []
|
|
45
|
+
for entry in hits:
|
|
46
|
+
simplified_entry = {
|
|
47
|
+
"region": entry["_source"]["data"]["region"],
|
|
48
|
+
# timestamps come in ms
|
|
49
|
+
"timestamp": datetime.datetime.fromtimestamp(entry["_source"]["metadata"]["timestamp"] / 1000),
|
|
50
|
+
"value": entry["_source"]["data"]["gCO2_perkWh"],
|
|
51
|
+
}
|
|
52
|
+
results.append(simplified_entry)
|
|
53
|
+
return results
|
|
54
|
+
except Exception:
|
|
55
|
+
_logger.error(f"download_region_emissions excepted with {traceback.format_exc()}")
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
def run(self):
|
|
59
|
+
# download emissions and store them in the DB
|
|
60
|
+
results = self.download_region_emissions()
|
|
61
|
+
if results:
|
|
62
|
+
self.taskBuffer.carbon_write_region_emissions(results)
|
|
63
|
+
|
|
64
|
+
# aggregate the emissions for the grid
|
|
65
|
+
self.taskBuffer.carbon_aggregate_emissions()
|