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,100 @@
|
|
|
1
|
+
# List of methods that can be executed by the clients
|
|
2
|
+
|
|
3
|
+
allowed_methods = []
|
|
4
|
+
|
|
5
|
+
# methods from pandaserver.taskbuffer.Utils
|
|
6
|
+
allowed_methods += [
|
|
7
|
+
"isAlive",
|
|
8
|
+
"putFile",
|
|
9
|
+
"deleteFile",
|
|
10
|
+
"getServer",
|
|
11
|
+
"updateLog",
|
|
12
|
+
"fetchLog",
|
|
13
|
+
"touchFile",
|
|
14
|
+
"getVomsAttr",
|
|
15
|
+
"putEventPickingRequest",
|
|
16
|
+
"getAttr",
|
|
17
|
+
"uploadLog",
|
|
18
|
+
"put_checkpoint",
|
|
19
|
+
"delete_checkpoint",
|
|
20
|
+
"put_file_recovery_request",
|
|
21
|
+
"put_workflow_request",
|
|
22
|
+
]
|
|
23
|
+
# methods from pandaserver.jobdispatcher.JobDispatcher
|
|
24
|
+
allowed_methods += [
|
|
25
|
+
"getJob",
|
|
26
|
+
"updateJob",
|
|
27
|
+
"getStatus",
|
|
28
|
+
"getEventRanges",
|
|
29
|
+
"updateEventRange",
|
|
30
|
+
"getKeyPair",
|
|
31
|
+
"updateEventRanges",
|
|
32
|
+
"getProxy",
|
|
33
|
+
"get_access_token",
|
|
34
|
+
"get_token_key",
|
|
35
|
+
"getCommands",
|
|
36
|
+
"ackCommands",
|
|
37
|
+
"checkJobStatus",
|
|
38
|
+
"checkEventsAvailability",
|
|
39
|
+
"updateJobsInBulk",
|
|
40
|
+
"getResourceTypes",
|
|
41
|
+
"updateWorkerPilotStatus",
|
|
42
|
+
"get_max_worker_id",
|
|
43
|
+
"get_events_status",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
# methods from pandaserver.userinterface.UserIF
|
|
47
|
+
allowed_methods += [
|
|
48
|
+
"submitJobs",
|
|
49
|
+
"getJobStatus",
|
|
50
|
+
"killJobs",
|
|
51
|
+
"reassignJobs",
|
|
52
|
+
"getJobStatisticsPerSite",
|
|
53
|
+
"getFullJobStatus",
|
|
54
|
+
"getScriptOfflineRunning",
|
|
55
|
+
"setDebugMode",
|
|
56
|
+
"insertSandboxFileInfo",
|
|
57
|
+
"checkSandboxFile",
|
|
58
|
+
"insertTaskParams",
|
|
59
|
+
"killTask",
|
|
60
|
+
"finishTask",
|
|
61
|
+
"getJediTasksInTimeRange",
|
|
62
|
+
"getJediTaskDetails",
|
|
63
|
+
"retryTask",
|
|
64
|
+
"changeTaskPriority",
|
|
65
|
+
"reassignTask",
|
|
66
|
+
"changeTaskAttributePanda",
|
|
67
|
+
"pauseTask",
|
|
68
|
+
"resumeTask",
|
|
69
|
+
"increaseAttemptNrPanda",
|
|
70
|
+
"killUnfinishedJobs",
|
|
71
|
+
"changeTaskSplitRulePanda",
|
|
72
|
+
"changeTaskModTimePanda",
|
|
73
|
+
"avalancheTask",
|
|
74
|
+
"getPandaIDsWithTaskID",
|
|
75
|
+
"reactivateTask",
|
|
76
|
+
"getTaskStatus",
|
|
77
|
+
"reassignShare",
|
|
78
|
+
"getTaskParamsMap",
|
|
79
|
+
"updateWorkers",
|
|
80
|
+
"harvesterIsAlive",
|
|
81
|
+
"reportWorkerStats_jobtype",
|
|
82
|
+
"getWorkerStats",
|
|
83
|
+
"addHarvesterDialogs",
|
|
84
|
+
"setNumSlotsForWP",
|
|
85
|
+
"reloadInput",
|
|
86
|
+
"enableJumboJobs",
|
|
87
|
+
"updateServiceMetrics",
|
|
88
|
+
"getUserJobMetadata",
|
|
89
|
+
"getJumboJobDatasets",
|
|
90
|
+
"sweepPQ",
|
|
91
|
+
"get_job_statistics_per_site_label_resource",
|
|
92
|
+
"relay_idds_command",
|
|
93
|
+
"send_command_to_job",
|
|
94
|
+
"execute_idds_workflow_command",
|
|
95
|
+
"set_user_secret",
|
|
96
|
+
"get_user_secrets",
|
|
97
|
+
"get_ban_users",
|
|
98
|
+
"get_files_in_datasets",
|
|
99
|
+
"release_task",
|
|
100
|
+
]
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import datetime
|
|
3
|
+
from threading import Lock
|
|
4
|
+
|
|
5
|
+
import jwt
|
|
6
|
+
import requests
|
|
7
|
+
from cryptography.hazmat.backends import default_backend
|
|
8
|
+
from cryptography.hazmat.primitives import serialization
|
|
9
|
+
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
|
|
10
|
+
from jwt.exceptions import InvalidTokenError
|
|
11
|
+
from pandacommon.pandautils.PandaUtils import naive_utcnow
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def decode_value(val):
|
|
15
|
+
if isinstance(val, str):
|
|
16
|
+
val = val.encode()
|
|
17
|
+
decoded = base64.urlsafe_b64decode(val + b"==")
|
|
18
|
+
return int.from_bytes(decoded, "big")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def rsa_pem_from_jwk(jwk):
|
|
22
|
+
public_num = RSAPublicNumbers(n=decode_value(jwk["n"]), e=decode_value(jwk["e"]))
|
|
23
|
+
public_key = public_num.public_key(default_backend())
|
|
24
|
+
pem = public_key.public_bytes(
|
|
25
|
+
encoding=serialization.Encoding.PEM,
|
|
26
|
+
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
|
27
|
+
)
|
|
28
|
+
return pem
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_jwk(kid, jwks):
|
|
32
|
+
for jwk in jwks.get("keys", []):
|
|
33
|
+
if jwk.get("kid") == kid:
|
|
34
|
+
return jwk
|
|
35
|
+
raise InvalidTokenError("JWK not found for kid={0}".format(kid, str(jwks)))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# token decoder
|
|
39
|
+
class TokenDecoder:
|
|
40
|
+
# constructor
|
|
41
|
+
def __init__(self, refresh_interval=10):
|
|
42
|
+
self.lock = Lock()
|
|
43
|
+
self.data = {}
|
|
44
|
+
self.refresh_interval = refresh_interval
|
|
45
|
+
|
|
46
|
+
# get cached data
|
|
47
|
+
def get_data(self, url, log_stream):
|
|
48
|
+
try:
|
|
49
|
+
with self.lock:
|
|
50
|
+
if url not in self.data or naive_utcnow() - self.data[url]["last_update"] > datetime.timedelta(minutes=self.refresh_interval):
|
|
51
|
+
log_stream.debug(f"to refresh {url}")
|
|
52
|
+
tmp_data = requests.get(url).json()
|
|
53
|
+
log_stream.debug("refreshed")
|
|
54
|
+
self.data[url] = {
|
|
55
|
+
"data": tmp_data,
|
|
56
|
+
"last_update": naive_utcnow(),
|
|
57
|
+
}
|
|
58
|
+
return self.data[url]["data"]
|
|
59
|
+
except Exception as e:
|
|
60
|
+
log_stream.error(f"failed to refresh with {str(e)}")
|
|
61
|
+
raise
|
|
62
|
+
|
|
63
|
+
# decode and verify JWT token
|
|
64
|
+
def deserialize_token(self, token, auth_config, vo, log_stream, legacy_token_issuers):
|
|
65
|
+
try:
|
|
66
|
+
# check audience
|
|
67
|
+
unverified = jwt.decode(token, verify=False, options={"verify_signature": False})
|
|
68
|
+
conf_key = None
|
|
69
|
+
audience = None
|
|
70
|
+
if "aud" in unverified:
|
|
71
|
+
audience = unverified["aud"]
|
|
72
|
+
if audience in auth_config:
|
|
73
|
+
conf_key = audience
|
|
74
|
+
if not conf_key:
|
|
75
|
+
# use sub as config key for access token
|
|
76
|
+
conf_key = unverified["sub"]
|
|
77
|
+
discovery_endpoint = auth_config[conf_key]["oidc_config_url"]
|
|
78
|
+
# decode headers
|
|
79
|
+
headers = jwt.get_unverified_header(token)
|
|
80
|
+
# get key id
|
|
81
|
+
if headers is None or "kid" not in headers:
|
|
82
|
+
raise jwt.exceptions.InvalidTokenError("cannot extract kid from headers")
|
|
83
|
+
kid = headers["kid"]
|
|
84
|
+
# retrieve OIDC configuration and JWK set
|
|
85
|
+
oidc_config = self.get_data(discovery_endpoint, log_stream)
|
|
86
|
+
jwks = self.get_data(oidc_config["jwks_uri"], log_stream)
|
|
87
|
+
# get JWK and public key
|
|
88
|
+
jwk = get_jwk(kid, jwks)
|
|
89
|
+
public_key = rsa_pem_from_jwk(jwk)
|
|
90
|
+
# decode token only with RS256
|
|
91
|
+
if unverified["iss"] and unverified["iss"] != oidc_config["issuer"] and oidc_config["issuer"].startswith(unverified["iss"]):
|
|
92
|
+
# iss is missing the last '/' in access tokens
|
|
93
|
+
issuer = unverified["iss"]
|
|
94
|
+
else:
|
|
95
|
+
issuer = oidc_config["issuer"]
|
|
96
|
+
if legacy_token_issuers:
|
|
97
|
+
issuers = list(dict.fromkeys([issuer] + legacy_token_issuers))
|
|
98
|
+
else:
|
|
99
|
+
issuers = [issuer]
|
|
100
|
+
decoded = None
|
|
101
|
+
err_msg = None
|
|
102
|
+
for tmp_issuer in issuers:
|
|
103
|
+
try:
|
|
104
|
+
decoded = jwt.decode(
|
|
105
|
+
token,
|
|
106
|
+
public_key,
|
|
107
|
+
verify=True,
|
|
108
|
+
algorithms="RS256",
|
|
109
|
+
audience=audience,
|
|
110
|
+
issuer=tmp_issuer,
|
|
111
|
+
)
|
|
112
|
+
break
|
|
113
|
+
except jwt.exceptions.InvalidIssuerError as e:
|
|
114
|
+
err_msg = str(e)
|
|
115
|
+
if not decoded:
|
|
116
|
+
raise jwt.exceptions.InvalidTokenError(f"failed to decode: {err_msg}")
|
|
117
|
+
if vo is not None:
|
|
118
|
+
decoded["vo"] = vo
|
|
119
|
+
else:
|
|
120
|
+
decoded["vo"] = auth_config[conf_key]["vo"]
|
|
121
|
+
return decoded
|
|
122
|
+
except Exception:
|
|
123
|
+
raise
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# get an access token with client_credentials flow
|
|
127
|
+
def get_access_token(token_endpoint: str, client_id: str, client_secret: str, scope: str = None, timeout: int = 180) -> tuple[bool, str]:
|
|
128
|
+
"""
|
|
129
|
+
Get an access token with client_credentials flow
|
|
130
|
+
|
|
131
|
+
:param token_endpoint: URL for token request
|
|
132
|
+
:param client_id: client ID
|
|
133
|
+
:param client_secret: client secret
|
|
134
|
+
:param scope: space separated string of scopes
|
|
135
|
+
:param timeout: timeout in seconds
|
|
136
|
+
|
|
137
|
+
:return: (True, access_token) or (False, error_str)
|
|
138
|
+
"""
|
|
139
|
+
try:
|
|
140
|
+
token_request = {
|
|
141
|
+
"grant_type": "client_credentials",
|
|
142
|
+
"client_id": client_id,
|
|
143
|
+
"client_secret": client_secret,
|
|
144
|
+
}
|
|
145
|
+
if scope:
|
|
146
|
+
token_request["scope"] = scope
|
|
147
|
+
token_response = requests.post(token_endpoint, data=token_request, timeout=timeout)
|
|
148
|
+
token_response.raise_for_status()
|
|
149
|
+
return True, token_response.json()["access_token"]
|
|
150
|
+
except Exception as e:
|
|
151
|
+
error_str = f"failed to get access token with {str(e)}"
|
|
152
|
+
return False, error_str
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
from pandaserver.config import panda_config
|
|
2
|
+
from pandaserver.srvcore.CoreUtils import CacheDict
|
|
3
|
+
|
|
4
|
+
if panda_config.token_authType is None:
|
|
5
|
+
pass
|
|
6
|
+
elif panda_config.token_authType == "scitokens":
|
|
7
|
+
import scitokens
|
|
8
|
+
else:
|
|
9
|
+
from pandaserver.srvcore.oidc_utils import TokenDecoder
|
|
10
|
+
|
|
11
|
+
token_decoder = TokenDecoder()
|
|
12
|
+
|
|
13
|
+
import traceback
|
|
14
|
+
|
|
15
|
+
import jwt
|
|
16
|
+
|
|
17
|
+
cache_dict = CacheDict()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# decode token
|
|
21
|
+
def decode_token(serialized_token, env, tmp_log):
|
|
22
|
+
authenticated = False
|
|
23
|
+
message_str = None
|
|
24
|
+
subprocess_env = {}
|
|
25
|
+
try:
|
|
26
|
+
vo = None
|
|
27
|
+
role = None
|
|
28
|
+
if panda_config.token_authType == "oidc":
|
|
29
|
+
if "HTTP_ORIGIN" in env:
|
|
30
|
+
# two formats, vo:role and vo.role
|
|
31
|
+
vo = env["HTTP_ORIGIN"]
|
|
32
|
+
# only vo.role for auth filename which is a key of auth_vo_dict
|
|
33
|
+
else:
|
|
34
|
+
vo = None
|
|
35
|
+
# only vo.role for auth filename which is a key of auth_vo_dict
|
|
36
|
+
vo_role = vo.replace(":", ".")
|
|
37
|
+
token = token_decoder.deserialize_token(serialized_token, panda_config.auth_config, vo, tmp_log, panda_config.legacy_token_issuers)
|
|
38
|
+
# extract role
|
|
39
|
+
if "vo" in token:
|
|
40
|
+
vo_raw = token["vo"] # Original input value of vo
|
|
41
|
+
tmp_log.debug(f"Raw VO from token: {vo_raw}")
|
|
42
|
+
|
|
43
|
+
if vo_raw.startswith("vo."):
|
|
44
|
+
# Handle vo names starting with "vo."
|
|
45
|
+
if ":" in vo_raw:
|
|
46
|
+
vo, role = vo_raw.split(":", 1) # Split by ':' into vo and role
|
|
47
|
+
else:
|
|
48
|
+
vo, role = vo_raw, None # No role present
|
|
49
|
+
else:
|
|
50
|
+
# Handle cases without "vo." prefix
|
|
51
|
+
if ":" in vo_raw:
|
|
52
|
+
vo, role = vo_raw.split(":", 1)
|
|
53
|
+
elif "." in vo_raw:
|
|
54
|
+
parts = vo_raw.rsplit(".", 1) # Split only on the last '.'
|
|
55
|
+
vo, role = parts[0], parts[1]
|
|
56
|
+
else:
|
|
57
|
+
vo, role = vo_raw, None # Single part, no role
|
|
58
|
+
|
|
59
|
+
tmp_log.debug(f"Parsed VO: {vo}, role: {role}")
|
|
60
|
+
|
|
61
|
+
# check vo
|
|
62
|
+
if vo not in panda_config.auth_policies:
|
|
63
|
+
tmp_log.error(f"VO '{vo}' not found in auth_policies: {list(panda_config.auth_policies.keys())}")
|
|
64
|
+
message_str = f"Unknown vo : {vo}"
|
|
65
|
+
else:
|
|
66
|
+
# groups claim name based on JWT profile
|
|
67
|
+
groups_claim_name = "groups"
|
|
68
|
+
if vo_role in panda_config.auth_vo_dict:
|
|
69
|
+
jwt_profile = panda_config.auth_vo_dict[vo_role].get("jwt_profile")
|
|
70
|
+
if jwt_profile == "wlcg":
|
|
71
|
+
groups_claim_name = "wlcg.groups"
|
|
72
|
+
# robot
|
|
73
|
+
if vo_role in panda_config.auth_vo_dict and "robot_ids" in panda_config.auth_vo_dict[vo_role]:
|
|
74
|
+
robot_ids = panda_config.auth_vo_dict[vo_role].get("robot_ids")
|
|
75
|
+
if isinstance(robot_ids, str):
|
|
76
|
+
robot_ids = robot_ids.split(",")
|
|
77
|
+
if not robot_ids:
|
|
78
|
+
robot_ids = []
|
|
79
|
+
robot_ids = [i for i in robot_ids if i]
|
|
80
|
+
if token["sub"] in robot_ids:
|
|
81
|
+
if groups_claim_name not in token:
|
|
82
|
+
if role:
|
|
83
|
+
token[groups_claim_name] = [f"{vo}/{role}"]
|
|
84
|
+
else:
|
|
85
|
+
token[groups_claim_name] = [f"{vo}"]
|
|
86
|
+
if "name" not in token:
|
|
87
|
+
token["name"] = f"robot {role}"
|
|
88
|
+
# check role
|
|
89
|
+
if role:
|
|
90
|
+
if f"{vo}/{role}" not in token[groups_claim_name] and f"/{vo}/{role}" not in token[groups_claim_name]:
|
|
91
|
+
message_str = f"Not a member of the {vo}/{role} group"
|
|
92
|
+
else:
|
|
93
|
+
subprocess_env["PANDA_OIDC_VO"] = vo
|
|
94
|
+
subprocess_env["PANDA_OIDC_GROUP"] = role
|
|
95
|
+
subprocess_env["PANDA_OIDC_ROLE"] = role
|
|
96
|
+
authenticated = True
|
|
97
|
+
else:
|
|
98
|
+
for member_string, member_info in panda_config.auth_policies[vo]:
|
|
99
|
+
if member_string in token[groups_claim_name] or f"/{member_string}" in token[groups_claim_name]:
|
|
100
|
+
subprocess_env["PANDA_OIDC_VO"] = vo
|
|
101
|
+
subprocess_env["PANDA_OIDC_GROUP"] = member_info["group"]
|
|
102
|
+
subprocess_env["PANDA_OIDC_ROLE"] = member_info["role"]
|
|
103
|
+
authenticated = True
|
|
104
|
+
break
|
|
105
|
+
if not authenticated:
|
|
106
|
+
message_str = f"Not a member of the {vo} group"
|
|
107
|
+
else:
|
|
108
|
+
token = scitokens.SciToken.deserialize(serialized_token, audience=panda_config.token_audience)
|
|
109
|
+
|
|
110
|
+
# check issuer
|
|
111
|
+
if "iss" not in token:
|
|
112
|
+
message_str = "Issuer is undefined in the token"
|
|
113
|
+
else:
|
|
114
|
+
if panda_config.token_authType == "scitokens":
|
|
115
|
+
items = token.claims()
|
|
116
|
+
else:
|
|
117
|
+
items = token.items()
|
|
118
|
+
for c, v in items:
|
|
119
|
+
subprocess_env[f"PANDA_OIDC_CLAIM_{str(c)}"] = str(v)
|
|
120
|
+
# use sub and scope as DN and FQAN
|
|
121
|
+
if "SSL_CLIENT_S_DN" not in env:
|
|
122
|
+
if "name" in token:
|
|
123
|
+
subprocess_env["SSL_CLIENT_S_DN"] = " ".join([t[:1].upper() + t[1:].lower() for t in str(token["name"]).split()])
|
|
124
|
+
if "preferred_username" in token:
|
|
125
|
+
subprocess_env["SSL_CLIENT_S_DN"] += f"/CN=nickname:{token['preferred_username']}"
|
|
126
|
+
else:
|
|
127
|
+
subprocess_env["SSL_CLIENT_S_DN"] = str(token["sub"])
|
|
128
|
+
i = 0
|
|
129
|
+
for scope in token.get("scope", "").split():
|
|
130
|
+
if scope.startswith("role:"):
|
|
131
|
+
subprocess_env[f"GRST_CRED_AUTH_TOKEN_{i}"] = "VOMS " + str(scope.split(":")[-1])
|
|
132
|
+
i += 1
|
|
133
|
+
if role:
|
|
134
|
+
subprocess_env[f"GRST_CRED_AUTH_TOKEN_{i}"] = f"VOMS /{vo}/Role={role}"
|
|
135
|
+
i += 1
|
|
136
|
+
else:
|
|
137
|
+
# protection against cached decisions that miss x509-related variables due to token+x509 access
|
|
138
|
+
subprocess_env["SSL_CLIENT_S_DN"] = env["SSL_CLIENT_S_DN"]
|
|
139
|
+
for key in env:
|
|
140
|
+
if key.startswith("GRST_CRED_") or key.startswith("GRST_CONN_"):
|
|
141
|
+
subprocess_env[key] = env[key]
|
|
142
|
+
|
|
143
|
+
except jwt.exceptions.InvalidTokenError as e:
|
|
144
|
+
message_str = f"Invalid token. {str(e)}"
|
|
145
|
+
except Exception as e:
|
|
146
|
+
message_str = f"Token decode failure. {str(e)} {traceback.format_exc()}"
|
|
147
|
+
return {"authenticated": authenticated, "message": message_str, "subprocess_env": subprocess_env}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# PanDA request object
|
|
151
|
+
class PandaRequest:
|
|
152
|
+
def __init__(self, env, tmp_log):
|
|
153
|
+
# environment
|
|
154
|
+
self.subprocess_env = env
|
|
155
|
+
# header
|
|
156
|
+
self.headers_in = {}
|
|
157
|
+
# authentication
|
|
158
|
+
self.authenticated = True
|
|
159
|
+
# message
|
|
160
|
+
self.message = None
|
|
161
|
+
|
|
162
|
+
# content-length
|
|
163
|
+
if "CONTENT_LENGTH" in self.subprocess_env:
|
|
164
|
+
self.headers_in["content-length"] = self.subprocess_env["CONTENT_LENGTH"]
|
|
165
|
+
|
|
166
|
+
# tokens
|
|
167
|
+
try:
|
|
168
|
+
if panda_config.token_authType in ["scitokens", "oidc"] and "HTTP_AUTHORIZATION" in env:
|
|
169
|
+
serialized_token = env["HTTP_AUTHORIZATION"].split()[1]
|
|
170
|
+
decision_key = f"""{serialized_token} : {env.get("HTTP_ORIGIN", None)} : {env.get("SSL_CLIENT_S_DN", None)}"""
|
|
171
|
+
cached_decision = cache_dict.get(decision_key, tmp_log, decode_token, serialized_token, env, tmp_log)
|
|
172
|
+
self.authenticated = cached_decision["authenticated"]
|
|
173
|
+
self.message = cached_decision["message"]
|
|
174
|
+
if self.message:
|
|
175
|
+
tmp_log.error(f"""{self.message} - Origin: {env.get("HTTP_ORIGIN", None)}, Token: {env["HTTP_AUTHORIZATION"]}""")
|
|
176
|
+
self.subprocess_env.update(cached_decision["subprocess_env"])
|
|
177
|
+
except Exception as e:
|
|
178
|
+
self.message = f"Failed to instantiate reqeust object. {str(e)}"
|
|
179
|
+
tmp_log.error(
|
|
180
|
+
f"""{self.message} - Origin: {env.get("HTTP_ORIGIN", None)}, Token: {env.get("HTTP_AUTHORIZATION", None)}\n{traceback.format_exc()}"""
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# get remote host
|
|
184
|
+
def get_remote_host(self):
|
|
185
|
+
if "REMOTE_HOST" in self.subprocess_env:
|
|
186
|
+
return self.subprocess_env["REMOTE_HOST"]
|
|
187
|
+
return ""
|
|
188
|
+
|
|
189
|
+
# accept json
|
|
190
|
+
def acceptJson(self):
|
|
191
|
+
try:
|
|
192
|
+
if "HTTP_ACCEPT" in self.subprocess_env:
|
|
193
|
+
return "application/json" in self.subprocess_env["HTTP_ACCEPT"]
|
|
194
|
+
except Exception:
|
|
195
|
+
pass
|
|
196
|
+
return False
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from pandacommon.pandautils.PandaUtils import naive_utcnow
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# make message
|
|
8
|
+
def make_message(msg_type, **kwargs):
|
|
9
|
+
msg_dict = {"msg_type": msg_type}
|
|
10
|
+
msg_dict.update(kwargs)
|
|
11
|
+
msg_dict["timestamp"] = int(naive_utcnow().timestamp())
|
|
12
|
+
return json.dumps(msg_dict)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# send a job message
|
|
16
|
+
def send_job_message(msg_queue, msg_topic, task_id, job_id):
|
|
17
|
+
# make message
|
|
18
|
+
msg = make_message("get_job", taskid=task_id, jobid=job_id)
|
|
19
|
+
# use job ID for selector
|
|
20
|
+
headers = {"type": job_id}
|
|
21
|
+
# send message to topic first
|
|
22
|
+
msg_topic.send(msg)
|
|
23
|
+
# send the same message to queue
|
|
24
|
+
msg_queue.send(msg, headers=headers)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# delete a job message
|
|
28
|
+
def delete_job_message(msg_queue, job_id, time_out=10):
|
|
29
|
+
# job ID for selector
|
|
30
|
+
headers = {"selector": "type='{0}' OR JMSType='{0}'".format(job_id)}
|
|
31
|
+
# subscribe to remove job messages
|
|
32
|
+
msg_queue.add_remover(headers, time_out)
|
|
33
|
+
# delete old removers
|
|
34
|
+
msg_queue.purge_removers()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# send a task message
|
|
38
|
+
def send_task_message(msg_topic, command_str, task_id):
|
|
39
|
+
# make message
|
|
40
|
+
msg = make_message(f"{command_str}_task", taskid=task_id)
|
|
41
|
+
# send message to topic
|
|
42
|
+
msg_topic.send(msg)
|