rucio 37.0.0rc1__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.
Potentially problematic release.
This version of rucio might be problematic. Click here for more details.
- rucio/__init__.py +17 -0
- rucio/alembicrevision.py +15 -0
- rucio/cli/__init__.py +14 -0
- rucio/cli/account.py +216 -0
- rucio/cli/bin_legacy/__init__.py +13 -0
- rucio/cli/bin_legacy/rucio.py +2825 -0
- rucio/cli/bin_legacy/rucio_admin.py +2500 -0
- rucio/cli/command.py +272 -0
- rucio/cli/config.py +72 -0
- rucio/cli/did.py +191 -0
- rucio/cli/download.py +128 -0
- rucio/cli/lifetime_exception.py +33 -0
- rucio/cli/replica.py +162 -0
- rucio/cli/rse.py +293 -0
- rucio/cli/rule.py +158 -0
- rucio/cli/scope.py +40 -0
- rucio/cli/subscription.py +73 -0
- rucio/cli/upload.py +60 -0
- rucio/cli/utils.py +226 -0
- rucio/client/__init__.py +15 -0
- rucio/client/accountclient.py +432 -0
- rucio/client/accountlimitclient.py +183 -0
- rucio/client/baseclient.py +983 -0
- rucio/client/client.py +120 -0
- rucio/client/configclient.py +126 -0
- rucio/client/credentialclient.py +59 -0
- rucio/client/didclient.py +868 -0
- rucio/client/diracclient.py +56 -0
- rucio/client/downloadclient.py +1783 -0
- rucio/client/exportclient.py +44 -0
- rucio/client/fileclient.py +50 -0
- rucio/client/importclient.py +42 -0
- rucio/client/lifetimeclient.py +90 -0
- rucio/client/lockclient.py +109 -0
- rucio/client/metaconventionsclient.py +140 -0
- rucio/client/pingclient.py +44 -0
- rucio/client/replicaclient.py +452 -0
- rucio/client/requestclient.py +125 -0
- rucio/client/richclient.py +317 -0
- rucio/client/rseclient.py +746 -0
- rucio/client/ruleclient.py +294 -0
- rucio/client/scopeclient.py +90 -0
- rucio/client/subscriptionclient.py +173 -0
- rucio/client/touchclient.py +82 -0
- rucio/client/uploadclient.py +969 -0
- rucio/common/__init__.py +13 -0
- rucio/common/bittorrent.py +234 -0
- rucio/common/cache.py +111 -0
- rucio/common/checksum.py +168 -0
- rucio/common/client.py +122 -0
- rucio/common/config.py +788 -0
- rucio/common/constants.py +217 -0
- rucio/common/constraints.py +17 -0
- rucio/common/didtype.py +237 -0
- rucio/common/dumper/__init__.py +342 -0
- rucio/common/dumper/consistency.py +497 -0
- rucio/common/dumper/data_models.py +362 -0
- rucio/common/dumper/path_parsing.py +75 -0
- rucio/common/exception.py +1208 -0
- rucio/common/extra.py +31 -0
- rucio/common/logging.py +420 -0
- rucio/common/pcache.py +1409 -0
- rucio/common/plugins.py +185 -0
- rucio/common/policy.py +93 -0
- rucio/common/schema/__init__.py +200 -0
- rucio/common/schema/generic.py +416 -0
- rucio/common/schema/generic_multi_vo.py +395 -0
- rucio/common/stomp_utils.py +423 -0
- rucio/common/stopwatch.py +55 -0
- rucio/common/test_rucio_server.py +154 -0
- rucio/common/types.py +483 -0
- rucio/common/utils.py +1688 -0
- rucio/core/__init__.py +13 -0
- rucio/core/account.py +496 -0
- rucio/core/account_counter.py +236 -0
- rucio/core/account_limit.py +425 -0
- rucio/core/authentication.py +620 -0
- rucio/core/config.py +437 -0
- rucio/core/credential.py +224 -0
- rucio/core/did.py +3004 -0
- rucio/core/did_meta_plugins/__init__.py +252 -0
- rucio/core/did_meta_plugins/did_column_meta.py +331 -0
- rucio/core/did_meta_plugins/did_meta_plugin_interface.py +165 -0
- rucio/core/did_meta_plugins/elasticsearch_meta.py +407 -0
- rucio/core/did_meta_plugins/filter_engine.py +672 -0
- rucio/core/did_meta_plugins/json_meta.py +240 -0
- rucio/core/did_meta_plugins/mongo_meta.py +229 -0
- rucio/core/did_meta_plugins/postgres_meta.py +352 -0
- rucio/core/dirac.py +237 -0
- rucio/core/distance.py +187 -0
- rucio/core/exporter.py +59 -0
- rucio/core/heartbeat.py +363 -0
- rucio/core/identity.py +301 -0
- rucio/core/importer.py +260 -0
- rucio/core/lifetime_exception.py +377 -0
- rucio/core/lock.py +577 -0
- rucio/core/message.py +288 -0
- rucio/core/meta_conventions.py +203 -0
- rucio/core/monitor.py +448 -0
- rucio/core/naming_convention.py +195 -0
- rucio/core/nongrid_trace.py +136 -0
- rucio/core/oidc.py +1463 -0
- rucio/core/permission/__init__.py +161 -0
- rucio/core/permission/generic.py +1124 -0
- rucio/core/permission/generic_multi_vo.py +1144 -0
- rucio/core/quarantined_replica.py +224 -0
- rucio/core/replica.py +4483 -0
- rucio/core/replica_sorter.py +362 -0
- rucio/core/request.py +3091 -0
- rucio/core/rse.py +2079 -0
- rucio/core/rse_counter.py +185 -0
- rucio/core/rse_expression_parser.py +459 -0
- rucio/core/rse_selector.py +304 -0
- rucio/core/rule.py +4484 -0
- rucio/core/rule_grouping.py +1620 -0
- rucio/core/scope.py +181 -0
- rucio/core/subscription.py +362 -0
- rucio/core/topology.py +490 -0
- rucio/core/trace.py +375 -0
- rucio/core/transfer.py +1531 -0
- rucio/core/vo.py +169 -0
- rucio/core/volatile_replica.py +151 -0
- rucio/daemons/__init__.py +13 -0
- rucio/daemons/abacus/__init__.py +13 -0
- rucio/daemons/abacus/account.py +116 -0
- rucio/daemons/abacus/collection_replica.py +124 -0
- rucio/daemons/abacus/rse.py +117 -0
- rucio/daemons/atropos/__init__.py +13 -0
- rucio/daemons/atropos/atropos.py +242 -0
- rucio/daemons/auditor/__init__.py +289 -0
- rucio/daemons/auditor/hdfs.py +97 -0
- rucio/daemons/auditor/srmdumps.py +355 -0
- rucio/daemons/automatix/__init__.py +13 -0
- rucio/daemons/automatix/automatix.py +304 -0
- rucio/daemons/badreplicas/__init__.py +13 -0
- rucio/daemons/badreplicas/minos.py +322 -0
- rucio/daemons/badreplicas/minos_temporary_expiration.py +171 -0
- rucio/daemons/badreplicas/necromancer.py +196 -0
- rucio/daemons/bb8/__init__.py +13 -0
- rucio/daemons/bb8/bb8.py +353 -0
- rucio/daemons/bb8/common.py +759 -0
- rucio/daemons/bb8/nuclei_background_rebalance.py +153 -0
- rucio/daemons/bb8/t2_background_rebalance.py +153 -0
- rucio/daemons/cache/__init__.py +13 -0
- rucio/daemons/cache/consumer.py +133 -0
- rucio/daemons/common.py +405 -0
- rucio/daemons/conveyor/__init__.py +13 -0
- rucio/daemons/conveyor/common.py +562 -0
- rucio/daemons/conveyor/finisher.py +529 -0
- rucio/daemons/conveyor/poller.py +394 -0
- rucio/daemons/conveyor/preparer.py +205 -0
- rucio/daemons/conveyor/receiver.py +179 -0
- rucio/daemons/conveyor/stager.py +133 -0
- rucio/daemons/conveyor/submitter.py +403 -0
- rucio/daemons/conveyor/throttler.py +532 -0
- rucio/daemons/follower/__init__.py +13 -0
- rucio/daemons/follower/follower.py +101 -0
- rucio/daemons/hermes/__init__.py +13 -0
- rucio/daemons/hermes/hermes.py +534 -0
- rucio/daemons/judge/__init__.py +13 -0
- rucio/daemons/judge/cleaner.py +159 -0
- rucio/daemons/judge/evaluator.py +185 -0
- rucio/daemons/judge/injector.py +162 -0
- rucio/daemons/judge/repairer.py +154 -0
- rucio/daemons/oauthmanager/__init__.py +13 -0
- rucio/daemons/oauthmanager/oauthmanager.py +198 -0
- rucio/daemons/reaper/__init__.py +13 -0
- rucio/daemons/reaper/dark_reaper.py +282 -0
- rucio/daemons/reaper/reaper.py +739 -0
- rucio/daemons/replicarecoverer/__init__.py +13 -0
- rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +626 -0
- rucio/daemons/rsedecommissioner/__init__.py +13 -0
- rucio/daemons/rsedecommissioner/config.py +81 -0
- rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
- rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
- rucio/daemons/rsedecommissioner/profiles/generic.py +452 -0
- rucio/daemons/rsedecommissioner/profiles/types.py +93 -0
- rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
- rucio/daemons/storage/__init__.py +13 -0
- rucio/daemons/storage/consistency/__init__.py +13 -0
- rucio/daemons/storage/consistency/actions.py +848 -0
- rucio/daemons/tracer/__init__.py +13 -0
- rucio/daemons/tracer/kronos.py +511 -0
- rucio/daemons/transmogrifier/__init__.py +13 -0
- rucio/daemons/transmogrifier/transmogrifier.py +762 -0
- rucio/daemons/undertaker/__init__.py +13 -0
- rucio/daemons/undertaker/undertaker.py +137 -0
- rucio/db/__init__.py +13 -0
- rucio/db/sqla/__init__.py +52 -0
- rucio/db/sqla/constants.py +206 -0
- rucio/db/sqla/migrate_repo/__init__.py +13 -0
- rucio/db/sqla/migrate_repo/env.py +110 -0
- rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +70 -0
- rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +43 -0
- rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +91 -0
- rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +76 -0
- rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +43 -0
- rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +50 -0
- rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +68 -0
- rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +40 -0
- rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +45 -0
- rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +60 -0
- rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +40 -0
- rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +140 -0
- rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +73 -0
- rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +74 -0
- rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +43 -0
- rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +50 -0
- rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +134 -0
- rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +64 -0
- rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +39 -0
- rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +64 -0
- rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +51 -0
- rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +41 -0
- rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +43 -0
- rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +44 -0
- rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +53 -0
- rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +38 -0
- rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +47 -0
- rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +57 -0
- rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +69 -0
- rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +42 -0
- rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +47 -0
- rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +46 -0
- rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +40 -0
- rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +67 -0
- rucio/db/sqla/migrate_repo/versions/30d5206e9cad_increase_oauthrequest_redirect_msg_.py +37 -0
- rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +44 -0
- rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +77 -0
- rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +60 -0
- rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +72 -0
- rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +42 -0
- rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +65 -0
- rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +133 -0
- rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +76 -0
- rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +60 -0
- rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +44 -0
- rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +64 -0
- rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +40 -0
- rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +43 -0
- rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +44 -0
- rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +78 -0
- rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +41 -0
- rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +44 -0
- rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +49 -0
- rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +40 -0
- rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +63 -0
- rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
- rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +45 -0
- rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +43 -0
- rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +45 -0
- rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +47 -0
- rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +58 -0
- rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +45 -0
- rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +106 -0
- rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +55 -0
- rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +50 -0
- rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +43 -0
- rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +41 -0
- rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +91 -0
- rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +72 -0
- rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +49 -0
- rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +43 -0
- rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +53 -0
- rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +45 -0
- rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +68 -0
- rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +45 -0
- rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +94 -0
- rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +54 -0
- rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +72 -0
- rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +76 -0
- rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +47 -0
- rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +121 -0
- rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +59 -0
- rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +52 -0
- rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +54 -0
- rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +64 -0
- rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +49 -0
- rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
- rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +43 -0
- rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
- rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +91 -0
- rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +40 -0
- rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +143 -0
- rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +76 -0
- rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +50 -0
- rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +72 -0
- rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +43 -0
- rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +65 -0
- rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +47 -0
- rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +146 -0
- rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +104 -0
- rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +44 -0
- rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +43 -0
- rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +103 -0
- rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +49 -0
- rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +104 -0
- rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +29 -0
- rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +74 -0
- rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +47 -0
- rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +43 -0
- rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +37 -0
- rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +43 -0
- rucio/db/sqla/models.py +1743 -0
- rucio/db/sqla/sautils.py +55 -0
- rucio/db/sqla/session.py +529 -0
- rucio/db/sqla/types.py +206 -0
- rucio/db/sqla/util.py +543 -0
- rucio/gateway/__init__.py +13 -0
- rucio/gateway/account.py +345 -0
- rucio/gateway/account_limit.py +363 -0
- rucio/gateway/authentication.py +381 -0
- rucio/gateway/config.py +227 -0
- rucio/gateway/credential.py +70 -0
- rucio/gateway/did.py +987 -0
- rucio/gateway/dirac.py +83 -0
- rucio/gateway/exporter.py +60 -0
- rucio/gateway/heartbeat.py +76 -0
- rucio/gateway/identity.py +189 -0
- rucio/gateway/importer.py +46 -0
- rucio/gateway/lifetime_exception.py +121 -0
- rucio/gateway/lock.py +153 -0
- rucio/gateway/meta_conventions.py +98 -0
- rucio/gateway/permission.py +74 -0
- rucio/gateway/quarantined_replica.py +79 -0
- rucio/gateway/replica.py +538 -0
- rucio/gateway/request.py +330 -0
- rucio/gateway/rse.py +632 -0
- rucio/gateway/rule.py +437 -0
- rucio/gateway/scope.py +100 -0
- rucio/gateway/subscription.py +280 -0
- rucio/gateway/vo.py +126 -0
- rucio/rse/__init__.py +96 -0
- rucio/rse/protocols/__init__.py +13 -0
- rucio/rse/protocols/bittorrent.py +194 -0
- rucio/rse/protocols/cache.py +111 -0
- rucio/rse/protocols/dummy.py +100 -0
- rucio/rse/protocols/gfal.py +708 -0
- rucio/rse/protocols/globus.py +243 -0
- rucio/rse/protocols/http_cache.py +82 -0
- rucio/rse/protocols/mock.py +123 -0
- rucio/rse/protocols/ngarc.py +209 -0
- rucio/rse/protocols/posix.py +250 -0
- rucio/rse/protocols/protocol.py +361 -0
- rucio/rse/protocols/rclone.py +365 -0
- rucio/rse/protocols/rfio.py +145 -0
- rucio/rse/protocols/srm.py +338 -0
- rucio/rse/protocols/ssh.py +414 -0
- rucio/rse/protocols/storm.py +195 -0
- rucio/rse/protocols/webdav.py +594 -0
- rucio/rse/protocols/xrootd.py +302 -0
- rucio/rse/rsemanager.py +881 -0
- rucio/rse/translation.py +260 -0
- rucio/tests/__init__.py +13 -0
- rucio/tests/common.py +280 -0
- rucio/tests/common_server.py +149 -0
- rucio/transfertool/__init__.py +13 -0
- rucio/transfertool/bittorrent.py +200 -0
- rucio/transfertool/bittorrent_driver.py +50 -0
- rucio/transfertool/bittorrent_driver_qbittorrent.py +134 -0
- rucio/transfertool/fts3.py +1600 -0
- rucio/transfertool/fts3_plugins.py +152 -0
- rucio/transfertool/globus.py +201 -0
- rucio/transfertool/globus_library.py +181 -0
- rucio/transfertool/mock.py +89 -0
- rucio/transfertool/transfertool.py +221 -0
- rucio/vcsversion.py +11 -0
- rucio/version.py +45 -0
- rucio/web/__init__.py +13 -0
- rucio/web/rest/__init__.py +13 -0
- rucio/web/rest/flaskapi/__init__.py +13 -0
- rucio/web/rest/flaskapi/authenticated_bp.py +27 -0
- rucio/web/rest/flaskapi/v1/__init__.py +13 -0
- rucio/web/rest/flaskapi/v1/accountlimits.py +236 -0
- rucio/web/rest/flaskapi/v1/accounts.py +1103 -0
- rucio/web/rest/flaskapi/v1/archives.py +102 -0
- rucio/web/rest/flaskapi/v1/auth.py +1644 -0
- rucio/web/rest/flaskapi/v1/common.py +426 -0
- rucio/web/rest/flaskapi/v1/config.py +304 -0
- rucio/web/rest/flaskapi/v1/credentials.py +213 -0
- rucio/web/rest/flaskapi/v1/dids.py +2340 -0
- rucio/web/rest/flaskapi/v1/dirac.py +116 -0
- rucio/web/rest/flaskapi/v1/export.py +75 -0
- rucio/web/rest/flaskapi/v1/heartbeats.py +127 -0
- rucio/web/rest/flaskapi/v1/identities.py +285 -0
- rucio/web/rest/flaskapi/v1/import.py +132 -0
- rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +312 -0
- rucio/web/rest/flaskapi/v1/locks.py +358 -0
- rucio/web/rest/flaskapi/v1/main.py +91 -0
- rucio/web/rest/flaskapi/v1/meta_conventions.py +241 -0
- rucio/web/rest/flaskapi/v1/metrics.py +36 -0
- rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
- rucio/web/rest/flaskapi/v1/ping.py +88 -0
- rucio/web/rest/flaskapi/v1/redirect.py +366 -0
- rucio/web/rest/flaskapi/v1/replicas.py +1894 -0
- rucio/web/rest/flaskapi/v1/requests.py +998 -0
- rucio/web/rest/flaskapi/v1/rses.py +2250 -0
- rucio/web/rest/flaskapi/v1/rules.py +854 -0
- rucio/web/rest/flaskapi/v1/scopes.py +159 -0
- rucio/web/rest/flaskapi/v1/subscriptions.py +650 -0
- rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
- rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
- rucio/web/rest/flaskapi/v1/traces.py +137 -0
- rucio/web/rest/flaskapi/v1/types.py +20 -0
- rucio/web/rest/flaskapi/v1/vos.py +278 -0
- rucio/web/rest/main.py +18 -0
- rucio/web/rest/metrics.py +27 -0
- rucio/web/rest/ping.py +27 -0
- rucio-37.0.0rc1.data/data/rucio/etc/alembic.ini.template +71 -0
- rucio-37.0.0rc1.data/data/rucio/etc/alembic_offline.ini.template +74 -0
- rucio-37.0.0rc1.data/data/rucio/etc/globus-config.yml.template +5 -0
- rucio-37.0.0rc1.data/data/rucio/etc/ldap.cfg.template +30 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.atlas.client.template +43 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.template +241 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio_multi_vo.cfg.template +217 -0
- rucio-37.0.0rc1.data/data/rucio/requirements.server.txt +297 -0
- rucio-37.0.0rc1.data/data/rucio/tools/bootstrap.py +34 -0
- rucio-37.0.0rc1.data/data/rucio/tools/merge_rucio_configs.py +144 -0
- rucio-37.0.0rc1.data/data/rucio/tools/reset_database.py +40 -0
- rucio-37.0.0rc1.data/scripts/rucio +133 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-account +74 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-collection-replica +46 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-rse +78 -0
- rucio-37.0.0rc1.data/scripts/rucio-admin +97 -0
- rucio-37.0.0rc1.data/scripts/rucio-atropos +60 -0
- rucio-37.0.0rc1.data/scripts/rucio-auditor +206 -0
- rucio-37.0.0rc1.data/scripts/rucio-automatix +50 -0
- rucio-37.0.0rc1.data/scripts/rucio-bb8 +57 -0
- rucio-37.0.0rc1.data/scripts/rucio-cache-client +141 -0
- rucio-37.0.0rc1.data/scripts/rucio-cache-consumer +42 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-finisher +58 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-poller +66 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-preparer +37 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-receiver +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-stager +76 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-submitter +139 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-throttler +104 -0
- rucio-37.0.0rc1.data/scripts/rucio-dark-reaper +53 -0
- rucio-37.0.0rc1.data/scripts/rucio-dumper +160 -0
- rucio-37.0.0rc1.data/scripts/rucio-follower +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-hermes +54 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-cleaner +89 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-evaluator +137 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-injector +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-repairer +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-kronos +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-minos +53 -0
- rucio-37.0.0rc1.data/scripts/rucio-minos-temporary-expiration +50 -0
- rucio-37.0.0rc1.data/scripts/rucio-necromancer +120 -0
- rucio-37.0.0rc1.data/scripts/rucio-oauth-manager +63 -0
- rucio-37.0.0rc1.data/scripts/rucio-reaper +83 -0
- rucio-37.0.0rc1.data/scripts/rucio-replica-recoverer +248 -0
- rucio-37.0.0rc1.data/scripts/rucio-rse-decommissioner +66 -0
- rucio-37.0.0rc1.data/scripts/rucio-storage-consistency-actions +74 -0
- rucio-37.0.0rc1.data/scripts/rucio-transmogrifier +77 -0
- rucio-37.0.0rc1.data/scripts/rucio-undertaker +76 -0
- rucio-37.0.0rc1.dist-info/METADATA +92 -0
- rucio-37.0.0rc1.dist-info/RECORD +487 -0
- rucio-37.0.0rc1.dist-info/WHEEL +5 -0
- rucio-37.0.0rc1.dist-info/licenses/AUTHORS.rst +100 -0
- rucio-37.0.0rc1.dist-info/licenses/LICENSE +201 -0
- rucio-37.0.0rc1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
import sys
|
|
17
|
+
from typing import TYPE_CHECKING, Any, Optional, TypeVar
|
|
18
|
+
|
|
19
|
+
from rucio.common.config import config_get_int
|
|
20
|
+
from rucio.common.exception import InvalidRequest
|
|
21
|
+
from rucio.common.plugins import PolicyPackageAlgorithms
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from collections.abc import Callable
|
|
25
|
+
|
|
26
|
+
FTS3TapeMetadataPluginType = TypeVar('FTS3TapeMetadataPluginType', bound='FTS3TapeMetadataPlugin')
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class FTS3TapeMetadataPlugin(PolicyPackageAlgorithms):
|
|
30
|
+
"""
|
|
31
|
+
Add a "archive_metadata" field to a file's transfer parameters.
|
|
32
|
+
Plugins are registered during initialization and called during a transfer with FTS3
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
ALGORITHM_NAME = "fts3_tape_metadata_plugins"
|
|
36
|
+
_INIT_FUNC_NAME = "fts3_plugins_init"
|
|
37
|
+
DEFAULT = "def"
|
|
38
|
+
|
|
39
|
+
def __init__(self, policy_algorithm: str) -> None:
|
|
40
|
+
"""
|
|
41
|
+
:param policy_algorithm: policy algorithm identifier - choose from any of the policy package algorithms registered under the `fts3_tape_metadata_plugins` group.
|
|
42
|
+
"""
|
|
43
|
+
super().__init__()
|
|
44
|
+
self.transfer_limit = config_get_int(
|
|
45
|
+
"transfers",
|
|
46
|
+
option="metadata_byte_limit",
|
|
47
|
+
raise_exception=False,
|
|
48
|
+
default=4096,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if not self._supports(self.ALGORITHM_NAME, policy_algorithm):
|
|
52
|
+
raise ValueError(f'Policy Algorithm {policy_algorithm} not found')
|
|
53
|
+
|
|
54
|
+
if self._supports(self._INIT_FUNC_NAME, policy_algorithm):
|
|
55
|
+
init_func = self._get_one_algorithm(self._INIT_FUNC_NAME, name=policy_algorithm)
|
|
56
|
+
init_func()
|
|
57
|
+
|
|
58
|
+
self.set_in_hints = self._get_one_algorithm(self.ALGORITHM_NAME, name=policy_algorithm)
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def _module_init(cls: type[FTS3TapeMetadataPluginType]) -> None:
|
|
62
|
+
cls.register(cls.DEFAULT, func=lambda x: cls._default(cls, x)) # type: ignore
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def register(cls: type[FTS3TapeMetadataPluginType], name: str, func: 'Callable', init_func: Optional['Callable'] = None) -> None:
|
|
66
|
+
"""
|
|
67
|
+
Register a fts3 transfer plugin
|
|
68
|
+
|
|
69
|
+
:param name: name to register under
|
|
70
|
+
:param func: function called by the plugin
|
|
71
|
+
:param init_func: Initialization requirements for the plugin, defaults to None
|
|
72
|
+
"""
|
|
73
|
+
super()._register(cls.ALGORITHM_NAME, algorithm_dict={name: func})
|
|
74
|
+
if init_func is not None:
|
|
75
|
+
super()._register(cls._INIT_FUNC_NAME, algorithm_dict={name: init_func})
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def _collocation(collocation_func: 'Callable', hints: dict[str, Any]) -> dict[str, dict]:
|
|
79
|
+
"""
|
|
80
|
+
Wraps a 'collocation' style plugin for formatting
|
|
81
|
+
|
|
82
|
+
:param collocation_func: Function that defines the collocation rules
|
|
83
|
+
:param hints: kwargs utilized by the collocation rules
|
|
84
|
+
:return: Collocation hints produced by the collocation_func, wrapped
|
|
85
|
+
"""
|
|
86
|
+
return {"collocation_hints": collocation_func(**hints)}
|
|
87
|
+
|
|
88
|
+
def _default(self, *hints: dict) -> dict:
|
|
89
|
+
return {}
|
|
90
|
+
|
|
91
|
+
def _verify_in_format(self, hint_dict: dict[str, Any]) -> None:
|
|
92
|
+
"""Check the to-be-submitted file transfer params are both json encodable and under the size limit for transfer"""
|
|
93
|
+
try:
|
|
94
|
+
hints_json = json.dumps(hint_dict)
|
|
95
|
+
in_tranfer_limit = sys.getsizeof(hints_json) < self.transfer_limit
|
|
96
|
+
|
|
97
|
+
except TypeError as e:
|
|
98
|
+
raise InvalidRequest("Request malformed, cannot encode to JSON", e)
|
|
99
|
+
|
|
100
|
+
if not in_tranfer_limit:
|
|
101
|
+
raise InvalidRequest(
|
|
102
|
+
f"Request too large, decrease to less than {self.transfer_limit}"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def hints(self, hint_kwargs: dict) -> dict[str, Any]:
|
|
106
|
+
"""
|
|
107
|
+
Produce "archive_metadata" hints for how a transfer should be executed by fts3.
|
|
108
|
+
|
|
109
|
+
:param hint_kwargs: Args passed forward to the plugin algorithm
|
|
110
|
+
:return: Archiving metadata in the format {archive_metadata: {<plugin produced hints>}}
|
|
111
|
+
"""
|
|
112
|
+
hints = self.set_in_hints(hint_kwargs)
|
|
113
|
+
self._verify_in_format(hints)
|
|
114
|
+
return {"archive_metadata": hints}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class ActivityBasedTransferPriorityPlugin(FTS3TapeMetadataPlugin):
|
|
118
|
+
def __init__(self, policy_algorithm: str = 'activity') -> None:
|
|
119
|
+
self.register(
|
|
120
|
+
policy_algorithm,
|
|
121
|
+
func=lambda x: self._get_activity_priority(x),
|
|
122
|
+
init_func=self._init_default_priority)
|
|
123
|
+
super().__init__(policy_algorithm)
|
|
124
|
+
|
|
125
|
+
def _init_default_priority(self) -> None:
|
|
126
|
+
self.default_priority = config_get_int(
|
|
127
|
+
"tape_priority",
|
|
128
|
+
option="default",
|
|
129
|
+
raise_exception=False,
|
|
130
|
+
default=20,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def _get_activity_priority(self, activity_kwargs: dict[str, str]) -> dict[str, dict]:
|
|
134
|
+
""" Activity Hints - assign a priority based on activity"""
|
|
135
|
+
if "activity" in activity_kwargs:
|
|
136
|
+
activity = activity_kwargs["activity"]
|
|
137
|
+
else:
|
|
138
|
+
raise InvalidRequest("`activity` field not found in passed metadata")
|
|
139
|
+
|
|
140
|
+
priority = config_get_int(
|
|
141
|
+
"tape_priority",
|
|
142
|
+
option=activity,
|
|
143
|
+
raise_exception=False,
|
|
144
|
+
default=self.default_priority,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return {"scheduling_hints": {"priority": priority}}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# Register the policies
|
|
151
|
+
FTS3TapeMetadataPlugin._module_init()
|
|
152
|
+
ActivityBasedTransferPriorityPlugin()
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
|
|
17
|
+
from rucio.common.constants import RseAttr
|
|
18
|
+
from rucio.common.utils import chunks
|
|
19
|
+
from rucio.db.sqla.constants import RequestState
|
|
20
|
+
from rucio.transfertool.transfertool import TransferStatusReport, Transfertool, TransferToolBuilder
|
|
21
|
+
|
|
22
|
+
from .globus_library import bulk_check_xfers, bulk_submit_xfer, submit_xfer
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def bulk_group_transfers(transfer_paths, policy='single', group_bulk=200):
|
|
26
|
+
"""
|
|
27
|
+
Group transfers in bulk based on certain criteria
|
|
28
|
+
|
|
29
|
+
:param transfer_paths: List of (potentially multihop) transfer paths to group. Each path is a list of single-hop transfers.
|
|
30
|
+
:param policy: Policy to use to group.
|
|
31
|
+
:param group_bulk: Bulk sizes.
|
|
32
|
+
:return: List of transfer groups
|
|
33
|
+
"""
|
|
34
|
+
if policy == 'single':
|
|
35
|
+
group_bulk = 1
|
|
36
|
+
|
|
37
|
+
grouped_jobs = []
|
|
38
|
+
for chunk in chunks(transfer_paths, group_bulk):
|
|
39
|
+
# Globus doesn't support multihop. Get the first hop only.
|
|
40
|
+
transfers = [transfer_path[0] for transfer_path in chunk]
|
|
41
|
+
|
|
42
|
+
grouped_jobs.append({
|
|
43
|
+
'transfers': transfers,
|
|
44
|
+
# Job params are not used by globus transfertool, but are needed for further common fts/globus code
|
|
45
|
+
'job_params': {}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
return grouped_jobs
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class GlobusTransferStatusReport(TransferStatusReport):
|
|
52
|
+
|
|
53
|
+
supported_db_fields = [
|
|
54
|
+
'state',
|
|
55
|
+
'external_id',
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
def __init__(self, request_id, external_id, globus_response):
|
|
59
|
+
super().__init__(request_id)
|
|
60
|
+
|
|
61
|
+
if globus_response == 'FAILED':
|
|
62
|
+
new_state = RequestState.FAILED
|
|
63
|
+
elif globus_response == 'SUCCEEDED':
|
|
64
|
+
new_state = RequestState.DONE
|
|
65
|
+
else:
|
|
66
|
+
new_state = RequestState.SUBMITTED
|
|
67
|
+
|
|
68
|
+
self.state = new_state
|
|
69
|
+
self.external_id = None
|
|
70
|
+
if new_state in [RequestState.FAILED, RequestState.DONE]:
|
|
71
|
+
self.external_id = external_id
|
|
72
|
+
|
|
73
|
+
def initialize(self, session, logger=logging.log):
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
def get_monitor_msg_fields(self, session, logger=logging.log):
|
|
77
|
+
return {'protocol': 'globus'}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class GlobusTransferTool(Transfertool):
|
|
81
|
+
"""
|
|
82
|
+
Globus implementation of Transfertool abstract base class
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
external_name = 'globus'
|
|
86
|
+
required_rse_attrs = (RseAttr.GLOBUS_ENDPOINT_ID, )
|
|
87
|
+
|
|
88
|
+
def __init__(self, external_host, logger=logging.log, group_bulk=200, group_policy='single'):
|
|
89
|
+
"""
|
|
90
|
+
Initializes the transfertool
|
|
91
|
+
|
|
92
|
+
:param external_host: The external host where the transfertool API is running
|
|
93
|
+
"""
|
|
94
|
+
if not external_host:
|
|
95
|
+
external_host = 'Globus Online Transfertool'
|
|
96
|
+
super().__init__(external_host, logger)
|
|
97
|
+
self.group_bulk = group_bulk
|
|
98
|
+
self.group_policy = group_policy
|
|
99
|
+
# TODO: initialize vars from config file here
|
|
100
|
+
|
|
101
|
+
@classmethod
|
|
102
|
+
def submission_builder_for_path(cls, transfer_path, logger=logging.log):
|
|
103
|
+
hop = transfer_path[0]
|
|
104
|
+
if not cls.can_perform_transfer(hop.src.rse, hop.dst.rse):
|
|
105
|
+
logger(logging.WARNING, "Source or destination globus_endpoint_id not set. Skipping {}".format(hop))
|
|
106
|
+
return [], None
|
|
107
|
+
|
|
108
|
+
return [hop], TransferToolBuilder(cls, external_host='Globus Online Transfertool')
|
|
109
|
+
|
|
110
|
+
def group_into_submit_jobs(self, transfer_paths):
|
|
111
|
+
jobs = bulk_group_transfers(transfer_paths, policy=self.group_policy, group_bulk=self.group_bulk)
|
|
112
|
+
return jobs
|
|
113
|
+
|
|
114
|
+
def submit_one(self, files, timeout=None):
|
|
115
|
+
"""
|
|
116
|
+
Submit transfers to globus API
|
|
117
|
+
|
|
118
|
+
:param files: List of dictionaries describing the file transfers.
|
|
119
|
+
:param job_params: Dictionary containing key/value pairs, for all transfers.
|
|
120
|
+
:param timeout: Timeout in seconds.
|
|
121
|
+
:returns: Globus transfer identifier.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
source_path = files[0]['sources'][0]
|
|
125
|
+
self.logger(logging.INFO, 'source_path: %s' % source_path)
|
|
126
|
+
|
|
127
|
+
source_endpoint_id = files[0]['metadata']['source_globus_endpoint_id']
|
|
128
|
+
|
|
129
|
+
# TODO: use prefix from rse_protocol to properly construct destination url
|
|
130
|
+
# parse and assemble dest_path for Globus endpoint
|
|
131
|
+
dest_path = files[0]['destinations'][0]
|
|
132
|
+
self.logger(logging.INFO, 'dest_path: %s' % dest_path)
|
|
133
|
+
|
|
134
|
+
# TODO: rucio.common.utils.construct_url logic adds unnecessary '/other' into file path
|
|
135
|
+
# s = dest_path.split('/') # s.remove('other') # dest_path = '/'.join(s)
|
|
136
|
+
|
|
137
|
+
destination_endpoint_id = files[0]['metadata']['dest_globus_endpoint_id']
|
|
138
|
+
job_label = files[0]['metadata']['request_id']
|
|
139
|
+
|
|
140
|
+
task_id = submit_xfer(source_endpoint_id, destination_endpoint_id, source_path, dest_path, job_label, recursive=False, logger=self.logger)
|
|
141
|
+
|
|
142
|
+
return task_id
|
|
143
|
+
|
|
144
|
+
def submit(self, transfers, job_params, timeout=None):
|
|
145
|
+
"""
|
|
146
|
+
Submit a bulk transfer to globus API
|
|
147
|
+
|
|
148
|
+
:param transfers: List of dictionaries describing the file transfers.
|
|
149
|
+
:param job_params: Not used by Globus Transfsertool
|
|
150
|
+
:param timeout: Timeout in seconds.
|
|
151
|
+
:returns: Globus transfer identifier.
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
# TODO: support passing a recursive parameter to Globus
|
|
155
|
+
submitjob = [
|
|
156
|
+
{
|
|
157
|
+
# Some dict elements are not needed by globus transfertool, but are accessed by further common fts/globus code
|
|
158
|
+
'sources': [transfer.source_url(s) for s in transfer.sources],
|
|
159
|
+
'destinations': [transfer.dest_url],
|
|
160
|
+
'metadata': {
|
|
161
|
+
'src_rse': transfer.src.rse.name,
|
|
162
|
+
'dst_rse': transfer.dst.rse.name,
|
|
163
|
+
'scope': str(transfer.rws.scope),
|
|
164
|
+
'name': transfer.rws.name,
|
|
165
|
+
'source_globus_endpoint_id': transfer.src.rse.attributes[RseAttr.GLOBUS_ENDPOINT_ID],
|
|
166
|
+
'dest_globus_endpoint_id': transfer.dst.rse.attributes[RseAttr.GLOBUS_ENDPOINT_ID],
|
|
167
|
+
'filesize': transfer.rws.byte_count,
|
|
168
|
+
},
|
|
169
|
+
}
|
|
170
|
+
for transfer in transfers
|
|
171
|
+
]
|
|
172
|
+
self.logger(logging.DEBUG, '... Starting globus xfer ...')
|
|
173
|
+
self.logger(logging.DEBUG, 'job_files: %s' % submitjob)
|
|
174
|
+
task_id = bulk_submit_xfer(submitjob, recursive=False, logger=self.logger)
|
|
175
|
+
|
|
176
|
+
return task_id
|
|
177
|
+
|
|
178
|
+
def bulk_query(self, requests_by_eid, timeout=None):
|
|
179
|
+
"""
|
|
180
|
+
Query the status of a bulk of transfers in globus API
|
|
181
|
+
|
|
182
|
+
:param requests_by_eid: dictionary {external_id1: {request_id1: request1, ...}, ...}
|
|
183
|
+
:returns: Transfer status information as a dictionary.
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
job_responses = bulk_check_xfers(requests_by_eid, logger=self.logger)
|
|
187
|
+
|
|
188
|
+
response = {}
|
|
189
|
+
for transfer_id, requests in requests_by_eid.items():
|
|
190
|
+
for request_id in requests:
|
|
191
|
+
response.setdefault(transfer_id, {})[request_id] = GlobusTransferStatusReport(request_id, transfer_id, job_responses[transfer_id])
|
|
192
|
+
return response
|
|
193
|
+
|
|
194
|
+
def bulk_update(self, resps, request_ids):
|
|
195
|
+
pass
|
|
196
|
+
|
|
197
|
+
def cancel(self):
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
def update_priority(self):
|
|
201
|
+
pass
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import datetime
|
|
16
|
+
import logging
|
|
17
|
+
import os
|
|
18
|
+
|
|
19
|
+
from rucio.common.config import config_get, config_get_int, get_config_dirs
|
|
20
|
+
from rucio.common.extra import import_extras
|
|
21
|
+
from rucio.core.monitor import MetricManager
|
|
22
|
+
|
|
23
|
+
EXTRA_MODULES = import_extras(['globus_sdk'])
|
|
24
|
+
|
|
25
|
+
if EXTRA_MODULES['globus_sdk']:
|
|
26
|
+
import yaml # pylint: disable=import-error
|
|
27
|
+
from globus_sdk import DeleteData, NativeAppAuthClient, RefreshTokenAuthorizer, TransferClient, TransferData # pylint: disable=import-error
|
|
28
|
+
|
|
29
|
+
METRICS = MetricManager(module=__name__)
|
|
30
|
+
|
|
31
|
+
GLOBUS_AUTH_APP = config_get('conveyor', 'globus_auth_app', False, None)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def load_config(cfg_file='globus-config.yml', logger=logging.log):
|
|
35
|
+
config = None
|
|
36
|
+
config_dir = get_config_dirs()[0]
|
|
37
|
+
if os.path.isfile(os.path.join(config_dir, cfg_file)):
|
|
38
|
+
config = os.path.join(config_dir, cfg_file)
|
|
39
|
+
else:
|
|
40
|
+
logger(logging.ERROR, 'Could not find globus config file')
|
|
41
|
+
raise Exception
|
|
42
|
+
return yaml.safe_load(open(config).read())
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_transfer_client(logger=logging.log):
|
|
46
|
+
cfg = load_config(logger=logger)
|
|
47
|
+
# cfg = yaml.safe_load(open("/opt/rucio/lib/rucio/transfertool/config.yml"))
|
|
48
|
+
client_id = cfg['globus']['apps'][GLOBUS_AUTH_APP]['client_id']
|
|
49
|
+
auth_client = NativeAppAuthClient(client_id)
|
|
50
|
+
refresh_token = cfg['globus']['apps'][GLOBUS_AUTH_APP]['refresh_token']
|
|
51
|
+
logger(logging.INFO, 'authorizing token...')
|
|
52
|
+
authorizer = RefreshTokenAuthorizer(refresh_token=refresh_token, auth_client=auth_client)
|
|
53
|
+
logger(logging.INFO, 'initializing TransferClient...')
|
|
54
|
+
tc = TransferClient(authorizer=authorizer)
|
|
55
|
+
return tc
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def auto_activate_endpoint(tc, ep_id, logger=logging.log):
|
|
59
|
+
r = tc.endpoint_autoactivate(ep_id, if_expires_in=3600)
|
|
60
|
+
if r['code'] == 'AutoActivationFailed':
|
|
61
|
+
logger(logging.CRITICAL, 'Endpoint({}) Not Active! Error! Source message: {}'.format(ep_id, r['message']))
|
|
62
|
+
# sys.exit(1) # TODO: don't want to exit; hook into graceful exit
|
|
63
|
+
elif r['code'] == 'AutoActivated.CachedCredential':
|
|
64
|
+
logger(logging.INFO, 'Endpoint({}) autoactivated using a cached credential.'.format(ep_id))
|
|
65
|
+
elif r['code'] == 'AutoActivated.GlobusOnlineCredential':
|
|
66
|
+
logger(logging.INFO, ('Endpoint({}) autoactivated using a built-in Globus credential.').format(ep_id))
|
|
67
|
+
elif r['code'] == 'AlreadyActivated':
|
|
68
|
+
logger(logging.INFO, 'Endpoint({}) already active until at least {}'.format(ep_id, 3600))
|
|
69
|
+
return r['code']
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def submit_xfer(source_endpoint_id, destination_endpoint_id, source_path, dest_path, job_label, recursive=False, logger=logging.log):
|
|
73
|
+
tc = get_transfer_client(logger=logger)
|
|
74
|
+
# as both endpoints are expected to be Globus Server endpoints, send auto-activate commands for both globus endpoints
|
|
75
|
+
auto_activate_endpoint(tc, source_endpoint_id, logger=logger)
|
|
76
|
+
auto_activate_endpoint(tc, destination_endpoint_id, logger=logger)
|
|
77
|
+
|
|
78
|
+
# from Globus... sync_level=checksum means that before files are transferred, Globus will compute checksums on the source and
|
|
79
|
+
# destination files, and only transfer files that have different checksums are transferred. verify_checksum=True means that after
|
|
80
|
+
# a file is transferred, Globus will compute checksums on the source and destination files to verify that the file was transferred
|
|
81
|
+
# correctly. If the checksums do not match, it will redo the transfer of that file.
|
|
82
|
+
# tdata = TransferData(tc, source_endpoint_id, destination_endpoint_id, label=job_label, sync_level="checksum", verify_checksum=True)
|
|
83
|
+
tdata = TransferData(tc, source_endpoint_id, destination_endpoint_id, label=job_label,
|
|
84
|
+
sync_level="checksum", notify_on_succeeded=False, notify_on_failed=False)
|
|
85
|
+
tdata.add_item(source_path, dest_path, recursive=recursive)
|
|
86
|
+
|
|
87
|
+
# logging.info('submitting transfer...')
|
|
88
|
+
transfer_result = tc.submit_transfer(tdata)
|
|
89
|
+
# logging.info("task_id =", transfer_result["task_id"])
|
|
90
|
+
|
|
91
|
+
return transfer_result["task_id"]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def bulk_submit_xfer(submitjob, recursive=False, logger=logging.log):
|
|
95
|
+
cfg = load_config(logger=logger)
|
|
96
|
+
client_id = cfg['globus']['apps'][GLOBUS_AUTH_APP]['client_id']
|
|
97
|
+
auth_client = NativeAppAuthClient(client_id)
|
|
98
|
+
refresh_token = cfg['globus']['apps'][GLOBUS_AUTH_APP]['refresh_token']
|
|
99
|
+
source_endpoint_id = submitjob[0].get('metadata').get('source_globus_endpoint_id')
|
|
100
|
+
destination_endpoint_id = submitjob[0].get('metadata').get('dest_globus_endpoint_id')
|
|
101
|
+
authorizer = RefreshTokenAuthorizer(refresh_token=refresh_token, auth_client=auth_client)
|
|
102
|
+
tc = TransferClient(authorizer=authorizer)
|
|
103
|
+
|
|
104
|
+
# make job_label for task a timestamp
|
|
105
|
+
now = datetime.datetime.utcnow()
|
|
106
|
+
job_label = now.strftime('%Y%m%d%H%M%s')
|
|
107
|
+
|
|
108
|
+
# retrieve globus_task_deadline value to enforce time window to complete transfers
|
|
109
|
+
# default is 2880 minutes or 48 hours
|
|
110
|
+
globus_task_deadline = config_get_int('conveyor', 'globus_task_deadline', False, 2880)
|
|
111
|
+
deadline = now + datetime.timedelta(minutes=globus_task_deadline)
|
|
112
|
+
|
|
113
|
+
# from Globus... sync_level=checksum means that before files are transferred, Globus will compute checksums on the source
|
|
114
|
+
# and destination files, and only transfer files that have different checksums are transferred. verify_checksum=True means
|
|
115
|
+
# that after a file is transferred, Globus will compute checksums on the source and destination files to verify that the
|
|
116
|
+
# file was transferred correctly. If the checksums do not match, it will redo the transfer of that file.
|
|
117
|
+
tdata = TransferData(tc, source_endpoint_id, destination_endpoint_id, label=job_label, sync_level="checksum", deadline=str(deadline))
|
|
118
|
+
|
|
119
|
+
for file in submitjob:
|
|
120
|
+
source_path = file.get('sources')[0]
|
|
121
|
+
dest_path = file.get('destinations')[0]
|
|
122
|
+
filesize = file['metadata']['filesize']
|
|
123
|
+
# TODO: support passing a recursive parameter to Globus
|
|
124
|
+
# md5 = file['metadata']['md5']
|
|
125
|
+
# tdata.add_item(source_path, dest_path, recursive=False, external_checksum=md5)
|
|
126
|
+
tdata.add_item(source_path, dest_path, recursive=False)
|
|
127
|
+
METRICS.counter('submit.filesize').inc(filesize)
|
|
128
|
+
|
|
129
|
+
# logging.info('submitting transfer...')
|
|
130
|
+
transfer_result = tc.submit_transfer(tdata)
|
|
131
|
+
logger(logging.INFO, "transfer_result: %s" % transfer_result)
|
|
132
|
+
|
|
133
|
+
return transfer_result["task_id"]
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def check_xfer(task_id, logger=logging.log):
|
|
137
|
+
tc = get_transfer_client(logger=logger)
|
|
138
|
+
transfer = tc.get_task(task_id)
|
|
139
|
+
status = str(transfer["status"])
|
|
140
|
+
return status
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def bulk_check_xfers(task_ids, logger=logging.log):
|
|
144
|
+
tc = get_transfer_client(logger=logger)
|
|
145
|
+
|
|
146
|
+
logger(logging.DEBUG, 'task_ids: %s' % task_ids)
|
|
147
|
+
|
|
148
|
+
responses = {}
|
|
149
|
+
|
|
150
|
+
for task_id in task_ids:
|
|
151
|
+
transfer = tc.get_task(str(task_id))
|
|
152
|
+
logger(logging.DEBUG, 'transfer: %s' % transfer)
|
|
153
|
+
status = str(transfer["status"])
|
|
154
|
+
if status == 'SUCCEEDED':
|
|
155
|
+
METRICS.counter('bytes_transferred').inc(transfer['bytes_transferred'])
|
|
156
|
+
METRICS.counter('effective_bytes_per_second').inc(transfer['effective_bytes_per_second'])
|
|
157
|
+
responses[str(task_id)] = status
|
|
158
|
+
|
|
159
|
+
logger(logging.DEBUG, 'responses: %s' % responses)
|
|
160
|
+
|
|
161
|
+
return responses
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def send_delete_task(endpoint_id=None, path=None, logger=logging.log):
|
|
165
|
+
tc = get_transfer_client(logger=logger)
|
|
166
|
+
ddata = DeleteData(tc, endpoint_id, recursive=True)
|
|
167
|
+
ddata.add_item(path)
|
|
168
|
+
delete_result = tc.submit_delete(ddata)
|
|
169
|
+
|
|
170
|
+
return delete_result
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def send_bulk_delete_task(endpoint_id=None, pfns=None, logger=logging.log):
|
|
174
|
+
tc = get_transfer_client(logger=logger)
|
|
175
|
+
ddata = DeleteData(tc, endpoint_id, recursive=True)
|
|
176
|
+
for pfn in pfns:
|
|
177
|
+
logger(logging.DEBUG, 'pfn: %s' % pfn)
|
|
178
|
+
ddata.add_item(pfn)
|
|
179
|
+
bulk_delete_result = tc.submit_delete(ddata)
|
|
180
|
+
|
|
181
|
+
return bulk_delete_result
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import itertools
|
|
16
|
+
import logging
|
|
17
|
+
import uuid
|
|
18
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
19
|
+
|
|
20
|
+
from rucio.db.sqla.constants import RequestState
|
|
21
|
+
from rucio.transfertool.transfertool import TransferStatusReport, Transfertool, TransferToolBuilder
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from collections.abc import Iterable, Mapping, Sequence
|
|
25
|
+
|
|
26
|
+
from rucio.common.types import LoggerFunction
|
|
27
|
+
from rucio.core.request import DirectTransfer
|
|
28
|
+
from rucio.db.sqla.session import Session
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class MockTransferStatusReport(TransferStatusReport):
|
|
32
|
+
|
|
33
|
+
supported_db_fields = [
|
|
34
|
+
'state',
|
|
35
|
+
'external_id'
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
def __init__(self, request_id: str, external_id: str):
|
|
39
|
+
super().__init__(request_id)
|
|
40
|
+
self.state = RequestState.DONE
|
|
41
|
+
self.external_id = external_id
|
|
42
|
+
|
|
43
|
+
def initialize(self, session: "Session", logger: "LoggerFunction" = logging.log) -> None:
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
def get_monitor_msg_fields(self, session: "Session", logger: "LoggerFunction" = logging.log) -> dict[str, Any]:
|
|
47
|
+
return {}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class MockTransfertool(Transfertool):
|
|
51
|
+
"""
|
|
52
|
+
Mock implementation of a Rucio transfertool
|
|
53
|
+
|
|
54
|
+
This is not actually used anywhere at the moment
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
external_name = 'mock'
|
|
58
|
+
required_rse_attrs = ()
|
|
59
|
+
supported_schemes = {'mock', 'file'}
|
|
60
|
+
|
|
61
|
+
def __init__(self, external_host: str, logger: "LoggerFunction" = logging.log):
|
|
62
|
+
super(MockTransfertool, self).__init__(external_host, logger)
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def submission_builder_for_path(
|
|
66
|
+
cls,
|
|
67
|
+
transfer_path: list["DirectTransfer"],
|
|
68
|
+
logger: "LoggerFunction" = logging.log
|
|
69
|
+
) -> tuple[list["DirectTransfer"], "TransferToolBuilder"]:
|
|
70
|
+
return transfer_path, TransferToolBuilder(cls, external_host='Mock Transfertool')
|
|
71
|
+
|
|
72
|
+
def group_into_submit_jobs(self, transfers: "Iterable[list[DirectTransfer]]") -> list[dict[str, Any]]:
|
|
73
|
+
return [{'transfers': list(itertools.chain.from_iterable(transfers)), 'job_params': {}}]
|
|
74
|
+
|
|
75
|
+
def submit(self, transfers: "Iterable[DirectTransfer]", job_params: dict[str, str], timeout: Optional[int] = None) -> str:
|
|
76
|
+
return str(uuid.uuid1())
|
|
77
|
+
|
|
78
|
+
def bulk_query(self, requests_by_eid: "Mapping[str, Mapping[str, Any]]", timeout: Optional[int] = None) -> dict[str, dict[str, MockTransferStatusReport]]:
|
|
79
|
+
response = {}
|
|
80
|
+
for transfer_id, requests in requests_by_eid.items():
|
|
81
|
+
for request_id in requests:
|
|
82
|
+
response.setdefault(transfer_id, {})[request_id] = MockTransferStatusReport(request_id, transfer_id)
|
|
83
|
+
return response
|
|
84
|
+
|
|
85
|
+
def cancel(self, transfer_ids: 'Sequence[str]', timeout: Optional[int] = None) -> bool:
|
|
86
|
+
return True
|
|
87
|
+
|
|
88
|
+
def update_priority(self, transfer_id: str, priority: int, timeout: Optional[int] = None) -> bool:
|
|
89
|
+
return True
|