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,562 @@
|
|
|
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
|
+
"""
|
|
16
|
+
Methods common to different conveyor submitter daemons.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import datetime
|
|
20
|
+
import functools
|
|
21
|
+
import itertools
|
|
22
|
+
import logging
|
|
23
|
+
import re
|
|
24
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
25
|
+
|
|
26
|
+
from rucio.common.config import config_get_bool
|
|
27
|
+
from rucio.common.constants import RseAttr
|
|
28
|
+
from rucio.common.exception import DatabaseException, DuplicateFileTransferSubmission, InvalidRSEExpression, RequestNotFound, TransferToolTimeout, TransferToolWrongAnswer, VONotFound
|
|
29
|
+
from rucio.common.stopwatch import Stopwatch
|
|
30
|
+
from rucio.core import request as request_core
|
|
31
|
+
from rucio.core import transfer as transfer_core
|
|
32
|
+
from rucio.core.monitor import MetricManager
|
|
33
|
+
from rucio.core.replica import add_replicas, tombstone_from_delay, update_replica_state
|
|
34
|
+
from rucio.core.request import queue_requests, transition_request_state
|
|
35
|
+
from rucio.core.rse import list_rses
|
|
36
|
+
from rucio.core.rse_expression_parser import parse_expression
|
|
37
|
+
from rucio.core.transfer import build_transfer_paths
|
|
38
|
+
from rucio.core.vo import list_vos
|
|
39
|
+
from rucio.db.sqla import models
|
|
40
|
+
from rucio.db.sqla.constants import ReplicaState, RequestState
|
|
41
|
+
from rucio.db.sqla.session import transactional_session
|
|
42
|
+
from rucio.rse import rsemanager as rsemgr
|
|
43
|
+
|
|
44
|
+
if TYPE_CHECKING:
|
|
45
|
+
from collections.abc import Iterable, Mapping, Sequence
|
|
46
|
+
|
|
47
|
+
from sqlalchemy.orm import Session
|
|
48
|
+
|
|
49
|
+
from rucio.common.types import InternalAccount, LoggerFunction, RSESettingsDict
|
|
50
|
+
from rucio.core.request import DirectTransfer, RequestWithSources
|
|
51
|
+
from rucio.core.topology import Topology
|
|
52
|
+
from rucio.core.transfer import ProtocolFactory
|
|
53
|
+
from rucio.transfertool.transfertool import Transfertool, TransferToolBuilder
|
|
54
|
+
|
|
55
|
+
METRICS = MetricManager(module=__name__)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def pick_and_prepare_submission_path(
|
|
59
|
+
requests_with_sources: "Mapping[str, RequestWithSources]",
|
|
60
|
+
topology: "Topology",
|
|
61
|
+
protocol_factory: "ProtocolFactory",
|
|
62
|
+
default_tombstone_delay: int = transfer_core.DEFAULT_MULTIHOP_TOMBSTONE_DELAY,
|
|
63
|
+
admin_accounts: Optional[set["InternalAccount"]] = None,
|
|
64
|
+
schemes: Optional["Sequence[str]"] = None,
|
|
65
|
+
failover_schemes: Optional["Sequence[str]"] = None,
|
|
66
|
+
max_sources: int = 4,
|
|
67
|
+
transfertools: Optional["Sequence[str]"] = None,
|
|
68
|
+
logger: "LoggerFunction" = logging.log
|
|
69
|
+
) -> dict["TransferToolBuilder", list[list["DirectTransfer"]]]:
|
|
70
|
+
"""
|
|
71
|
+
For each transfer, pick a (sub)path; and a transfertool to be used to submit that (sub)path
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
# for each source, compute the (possibly multihop) path between it and the transfer destination
|
|
75
|
+
_build_paths_fnc = functools.partial(
|
|
76
|
+
build_transfer_paths,
|
|
77
|
+
topology=topology,
|
|
78
|
+
protocol_factory=protocol_factory,
|
|
79
|
+
schemes=schemes,
|
|
80
|
+
failover_schemes=failover_schemes,
|
|
81
|
+
max_sources=max_sources,
|
|
82
|
+
admin_accounts=admin_accounts,
|
|
83
|
+
transfertools=transfertools,
|
|
84
|
+
logger=logger,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Assign paths to be executed by transfertools
|
|
88
|
+
# if the chosen best path is a multihop, create intermediate replicas and the intermediate transfer requests
|
|
89
|
+
_assign_path_fnc = functools.partial(
|
|
90
|
+
assign_paths_to_transfertool_and_create_hops,
|
|
91
|
+
default_tombstone_delay=default_tombstone_delay,
|
|
92
|
+
transfertools=transfertools,
|
|
93
|
+
logger=logger,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# For requests which had source_rse_id set in the database, start by verifying that it's possible to
|
|
97
|
+
# use this source to submit it. If it's possible, use it, otherwise, fallback to searching all
|
|
98
|
+
# possible sources for the request
|
|
99
|
+
requests_to_load_partially = {}
|
|
100
|
+
requests_to_load_fully = {}
|
|
101
|
+
for request_id, rws in requests_with_sources.items():
|
|
102
|
+
if rws.requested_source and datetime.datetime.utcnow() - datetime.timedelta(hours=6) < rws.requested_at:
|
|
103
|
+
requests_to_load_partially[request_id] = rws
|
|
104
|
+
else:
|
|
105
|
+
requests_to_load_fully[request_id] = rws
|
|
106
|
+
|
|
107
|
+
paths_by_transfertool_builder_partial = {}
|
|
108
|
+
if requests_to_load_partially:
|
|
109
|
+
candidate_paths, reqs_no_source, reqs_scheme_mismatch, reqs_only_tape_source, reqs_unsupported_transfertool = _build_paths_fnc(
|
|
110
|
+
requests_with_sources=list(requests_to_load_partially.values()),
|
|
111
|
+
requested_source_only=True,
|
|
112
|
+
)
|
|
113
|
+
paths_by_transfertool_builder_partial, reqs_no_host = _assign_path_fnc(
|
|
114
|
+
candidate_paths_by_request_id=candidate_paths,
|
|
115
|
+
)
|
|
116
|
+
for request_id in itertools.chain(reqs_no_host, reqs_no_source, reqs_scheme_mismatch, reqs_only_tape_source, reqs_unsupported_transfertool):
|
|
117
|
+
rws = requests_to_load_partially[request_id]
|
|
118
|
+
logger(logging.INFO, "%s: source_rse_id was set to %s, but cannot be used. Fall-back to full source scan.", request_id, str(rws.requested_source))
|
|
119
|
+
requests_to_load_fully[request_id] = rws
|
|
120
|
+
|
|
121
|
+
candidate_paths, reqs_no_source, reqs_scheme_mismatch, reqs_only_tape_source, reqs_unsupported_transfertool = _build_paths_fnc(
|
|
122
|
+
requests_with_sources=list(requests_to_load_fully.values())
|
|
123
|
+
)
|
|
124
|
+
paths_by_transfertool_builder, reqs_no_host = _assign_path_fnc(
|
|
125
|
+
candidate_paths_by_request_id=candidate_paths
|
|
126
|
+
)
|
|
127
|
+
# Merge the two dicts with submission work into one
|
|
128
|
+
for tt_builder, paths in paths_by_transfertool_builder_partial.items():
|
|
129
|
+
paths_by_transfertool_builder.setdefault(tt_builder, []).extend(paths)
|
|
130
|
+
|
|
131
|
+
if reqs_unsupported_transfertool:
|
|
132
|
+
logger(logging.INFO, "Ignoring request because of unsupported transfertool: %s", reqs_unsupported_transfertool)
|
|
133
|
+
reqs_no_source.update(reqs_no_host)
|
|
134
|
+
if reqs_no_source:
|
|
135
|
+
logger(logging.INFO, "Marking requests as no-sources: %s", reqs_no_source)
|
|
136
|
+
request_core.transition_requests_state_if_possible(reqs_no_source, RequestState.NO_SOURCES, logger=logger)
|
|
137
|
+
if reqs_only_tape_source:
|
|
138
|
+
logger(logging.INFO, "Marking requests as only-tape-sources: %s", reqs_only_tape_source)
|
|
139
|
+
request_core.transition_requests_state_if_possible(reqs_only_tape_source, RequestState.ONLY_TAPE_SOURCES, logger=logger)
|
|
140
|
+
if reqs_scheme_mismatch:
|
|
141
|
+
logger(logging.INFO, "Marking requests as scheme-mismatch: %s", reqs_scheme_mismatch)
|
|
142
|
+
request_core.transition_requests_state_if_possible(reqs_scheme_mismatch, RequestState.MISMATCH_SCHEME, logger=logger)
|
|
143
|
+
|
|
144
|
+
return paths_by_transfertool_builder
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def __assign_to_transfertool(
|
|
148
|
+
transfer_path: list["DirectTransfer"],
|
|
149
|
+
transfertools: Optional["Iterable[str]"],
|
|
150
|
+
logger: "LoggerFunction",
|
|
151
|
+
) -> list[tuple[list["DirectTransfer"], Optional["TransferToolBuilder"]]]:
|
|
152
|
+
"""
|
|
153
|
+
Iterate over a multihop path and assign sub-paths to transfertools in chucks from left to right.
|
|
154
|
+
|
|
155
|
+
Assignment is done in a greedy way. At each step, the first transfertool which can submit any non-empty prefix
|
|
156
|
+
is selected. No backtracking is done to find better alternatives.
|
|
157
|
+
|
|
158
|
+
For example, for a path A->B->C->D->E, A->B->C may be assigned to transfertool1; while C->D->E to transfertool2.
|
|
159
|
+
This even if transfertool2 could submit the full path in one step without splitting it.
|
|
160
|
+
"""
|
|
161
|
+
if transfertools is None:
|
|
162
|
+
return [(transfer_path, None)]
|
|
163
|
+
|
|
164
|
+
remaining_hops = transfer_path
|
|
165
|
+
tt_builder_for_hops = []
|
|
166
|
+
while remaining_hops:
|
|
167
|
+
tt_builder = None
|
|
168
|
+
assigned_hops = []
|
|
169
|
+
for tt_name in transfertools:
|
|
170
|
+
transfertool_cls = transfer_core.TRANSFERTOOL_CLASSES_BY_NAME.get(tt_name)
|
|
171
|
+
if not transfertool_cls:
|
|
172
|
+
continue
|
|
173
|
+
assigned_hops, tt_builder = transfertool_cls.submission_builder_for_path(remaining_hops, logger=logger)
|
|
174
|
+
if assigned_hops:
|
|
175
|
+
break
|
|
176
|
+
|
|
177
|
+
if not assigned_hops:
|
|
178
|
+
break
|
|
179
|
+
|
|
180
|
+
remaining_hops = remaining_hops[len(assigned_hops):]
|
|
181
|
+
tt_builder_for_hops.append((assigned_hops, tt_builder))
|
|
182
|
+
|
|
183
|
+
if remaining_hops:
|
|
184
|
+
# We cannot submit the whole path
|
|
185
|
+
return []
|
|
186
|
+
|
|
187
|
+
return tt_builder_for_hops
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def assign_paths_to_transfertool_and_create_hops(
|
|
191
|
+
candidate_paths_by_request_id: "Mapping[str, Sequence[DirectTransfer]]",
|
|
192
|
+
default_tombstone_delay: int,
|
|
193
|
+
transfertools: Optional["Sequence[str]"] = None,
|
|
194
|
+
logger: "LoggerFunction" = logging.log,
|
|
195
|
+
) -> "tuple[dict[TransferToolBuilder, list[list[DirectTransfer]]], set[str]]":
|
|
196
|
+
"""
|
|
197
|
+
for each request, pick the first path which can be submitted by one of the transfertools.
|
|
198
|
+
If the chosen path is multihop, create all missing intermediate requests and replicas.
|
|
199
|
+
"""
|
|
200
|
+
reqs_no_host = set()
|
|
201
|
+
paths_by_transfertool_builder = {}
|
|
202
|
+
for request_id, candidate_paths in candidate_paths_by_request_id.items():
|
|
203
|
+
try:
|
|
204
|
+
hops_to_submit, builder_to_use = __assign_paths_to_transfertool_and_create_hops(
|
|
205
|
+
request_id,
|
|
206
|
+
candidate_paths,
|
|
207
|
+
default_tombstone_delay=default_tombstone_delay,
|
|
208
|
+
transfertools=transfertools,
|
|
209
|
+
logger=logger,
|
|
210
|
+
)
|
|
211
|
+
except DatabaseException as e:
|
|
212
|
+
if re.match('.*SOURCES_(REQ_ID|REPLICA|RSES|DEST_RSES)_FK.*', str(e.args[0])):
|
|
213
|
+
logger(logging.WARNING, '%s: Cannot sync DB sources. Skip the transfer for now.', request_id)
|
|
214
|
+
continue
|
|
215
|
+
raise
|
|
216
|
+
|
|
217
|
+
if hops_to_submit is None:
|
|
218
|
+
reqs_no_host.add(request_id)
|
|
219
|
+
continue
|
|
220
|
+
|
|
221
|
+
if not hops_to_submit:
|
|
222
|
+
continue
|
|
223
|
+
|
|
224
|
+
paths_by_transfertool_builder.setdefault(builder_to_use, []).append(hops_to_submit)
|
|
225
|
+
return paths_by_transfertool_builder, reqs_no_host
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@transactional_session
|
|
229
|
+
def __assign_paths_to_transfertool_and_create_hops(
|
|
230
|
+
request_id: str,
|
|
231
|
+
candidate_paths: "Sequence[list[DirectTransfer]]",
|
|
232
|
+
default_tombstone_delay: int,
|
|
233
|
+
transfertools: "Optional[Sequence[str]]" = None,
|
|
234
|
+
*,
|
|
235
|
+
logger: "LoggerFunction" = logging.log,
|
|
236
|
+
session: "Session",
|
|
237
|
+
) -> "tuple[Optional[list[DirectTransfer]], Optional[TransferToolBuilder]]":
|
|
238
|
+
"""
|
|
239
|
+
Out of a sequence of candidate paths for the given request, pick the first path which can
|
|
240
|
+
be submitted by one of the transfertools.
|
|
241
|
+
If the chosen path is multihop, create all missing intermediate requests and replicas.
|
|
242
|
+
"""
|
|
243
|
+
# Get the rws object from any candidate path. It is the same for all candidate paths. For multihop, the initial request is the last hop
|
|
244
|
+
rws = candidate_paths[0][-1].rws
|
|
245
|
+
|
|
246
|
+
# Selects the first path which can be submitted using a chain of supported transfertools
|
|
247
|
+
# and for which the creation of intermediate hops (if it is a multihop) works correctly
|
|
248
|
+
best_path = []
|
|
249
|
+
builder_to_use = None
|
|
250
|
+
hops_to_submit = []
|
|
251
|
+
must_skip_submission = False
|
|
252
|
+
|
|
253
|
+
tt_assignments = [(transfer_path, __assign_to_transfertool(transfer_path, transfertools, logger=logger))
|
|
254
|
+
for transfer_path in candidate_paths]
|
|
255
|
+
# Prioritize the paths which need less transfertool transitions.
|
|
256
|
+
# Ideally, the entire path should be submitted to a single transfertool
|
|
257
|
+
for transfer_path, tt_assignment in sorted(tt_assignments, key=lambda t: len(t[1])):
|
|
258
|
+
if not tt_assignment:
|
|
259
|
+
logger(logging.INFO, '%s: None of the transfertools can submit the request: %s', request_id, transfertools)
|
|
260
|
+
continue
|
|
261
|
+
|
|
262
|
+
# Set the 'transfertool' field on the intermediate hops which should be created in the database
|
|
263
|
+
for sub_path, tt_builder in tt_assignment:
|
|
264
|
+
if tt_builder:
|
|
265
|
+
for hop in sub_path:
|
|
266
|
+
if hop is not transfer_path[-1]:
|
|
267
|
+
hop.rws.transfertool = tt_builder.transfertool_class.external_name
|
|
268
|
+
created, must_skip_submission = __create_missing_replicas_and_requests(
|
|
269
|
+
transfer_path, default_tombstone_delay, logger=logger, session=session
|
|
270
|
+
)
|
|
271
|
+
if created:
|
|
272
|
+
best_path = transfer_path
|
|
273
|
+
# Only the first sub-path will be submitted to the corresponding transfertool,
|
|
274
|
+
# the rest of the hops will wait for first hops to be transferred
|
|
275
|
+
hops_to_submit, builder_to_use = tt_assignment[0]
|
|
276
|
+
if created or must_skip_submission:
|
|
277
|
+
break
|
|
278
|
+
|
|
279
|
+
if builder_to_use is None and hops_to_submit is None:
|
|
280
|
+
logger(logging.INFO, '%s: Cannot pick transfertool, or create intermediate requests' % request_id)
|
|
281
|
+
return hops_to_submit, builder_to_use
|
|
282
|
+
|
|
283
|
+
transfer_core.ensure_db_sources(best_path, logger=logger, session=session)
|
|
284
|
+
|
|
285
|
+
if len(best_path) > 1:
|
|
286
|
+
logger(logging.INFO, '%s: Best path is multihop: %s' % (rws.request_id, transfer_core.transfer_path_str(best_path)))
|
|
287
|
+
elif best_path is not candidate_paths[0] or len(best_path[0].sources) > 1:
|
|
288
|
+
# Only print singlehop if it brings additional information:
|
|
289
|
+
# - either it's not the first candidate path
|
|
290
|
+
# - or it's a multi-source
|
|
291
|
+
# in other cases, it doesn't bring any additional information to what is known from previous logs
|
|
292
|
+
logger(logging.INFO, '%s: Best path is direct: %s' % (rws.request_id, transfer_core.transfer_path_str(best_path)))
|
|
293
|
+
|
|
294
|
+
if must_skip_submission:
|
|
295
|
+
logger(logging.INFO, '%s: Part of the transfer is already being handled. Skip for now.' % request_id)
|
|
296
|
+
hops_to_submit = []
|
|
297
|
+
return hops_to_submit, builder_to_use
|
|
298
|
+
|
|
299
|
+
if len(hops_to_submit) < len(best_path):
|
|
300
|
+
logger(logging.INFO, '%s: Only first %d hops will be submitted by %s', request_id, len(hops_to_submit), builder_to_use)
|
|
301
|
+
|
|
302
|
+
return hops_to_submit, builder_to_use
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@transactional_session
|
|
306
|
+
def __create_missing_replicas_and_requests(
|
|
307
|
+
transfer_path: "list[DirectTransfer]",
|
|
308
|
+
default_tombstone_delay: int,
|
|
309
|
+
*,
|
|
310
|
+
logger: "LoggerFunction",
|
|
311
|
+
session: "Session"
|
|
312
|
+
) -> tuple[bool, bool]:
|
|
313
|
+
"""
|
|
314
|
+
Create replicas and requests in the database for the intermediate hops
|
|
315
|
+
"""
|
|
316
|
+
initial_request_id = transfer_path[-1].rws.request_id
|
|
317
|
+
creation_successful = True
|
|
318
|
+
must_skip_submission = False
|
|
319
|
+
# Iterate the path in reverse order. The last hop is the initial request, so
|
|
320
|
+
# next_hop.rws.request_id will always be initialized when handling the current hop.
|
|
321
|
+
for i in reversed(range(len(transfer_path))):
|
|
322
|
+
hop = transfer_path[i]
|
|
323
|
+
rws = hop.rws
|
|
324
|
+
if rws.request_id:
|
|
325
|
+
continue
|
|
326
|
+
|
|
327
|
+
tombstone_delay = rws.dest_rse.attributes.get(RseAttr.MULTIHOP_TOMBSTONE_DELAY, default_tombstone_delay)
|
|
328
|
+
try:
|
|
329
|
+
tombstone = tombstone_from_delay(tombstone_delay)
|
|
330
|
+
except ValueError:
|
|
331
|
+
logger(logging.ERROR, "%s: Cannot parse multihop tombstone delay %s", initial_request_id, tombstone_delay)
|
|
332
|
+
creation_successful = False
|
|
333
|
+
break
|
|
334
|
+
|
|
335
|
+
files = [{'scope': rws.scope,
|
|
336
|
+
'name': rws.name,
|
|
337
|
+
'bytes': rws.byte_count,
|
|
338
|
+
'adler32': rws.adler32,
|
|
339
|
+
'md5': rws.md5,
|
|
340
|
+
'tombstone': tombstone,
|
|
341
|
+
'state': 'C'}]
|
|
342
|
+
try:
|
|
343
|
+
add_replicas(rse_id=rws.dest_rse.id,
|
|
344
|
+
files=files,
|
|
345
|
+
account=rws.account,
|
|
346
|
+
ignore_availability=False,
|
|
347
|
+
dataset_meta=None,
|
|
348
|
+
session=session)
|
|
349
|
+
# Set replica state to Copying in case replica already existed in another state.
|
|
350
|
+
# Can happen when a multihop transfer failed previously, and we are re-scheduling it now.
|
|
351
|
+
update_replica_state(rse_id=rws.dest_rse.id, scope=rws.scope, name=rws.name, state=ReplicaState.COPYING, session=session)
|
|
352
|
+
except Exception as error:
|
|
353
|
+
logger(logging.ERROR, '%s: Problem adding replicas on %s : %s', initial_request_id, rws.dest_rse, str(error))
|
|
354
|
+
|
|
355
|
+
rws.attributes['is_intermediate_hop'] = True
|
|
356
|
+
rws.attributes['source_replica_expression'] = hop.src.rse.name
|
|
357
|
+
req_to_queue = {'dest_rse_id': rws.dest_rse.id,
|
|
358
|
+
'source_rse_id': hop.src.rse.id,
|
|
359
|
+
'state': RequestState.QUEUED,
|
|
360
|
+
'scope': rws.scope,
|
|
361
|
+
'name': rws.name,
|
|
362
|
+
'rule_id': '00000000000000000000000000000000', # Dummy Rule ID used for multihop. TODO: Replace with actual rule_id once we can flag intermediate requests
|
|
363
|
+
'attributes': rws.attributes,
|
|
364
|
+
'request_type': rws.request_type,
|
|
365
|
+
'retry_count': rws.retry_count,
|
|
366
|
+
'account': rws.account,
|
|
367
|
+
'requested_at': datetime.datetime.utcnow()}
|
|
368
|
+
if rws.transfertool:
|
|
369
|
+
req_to_queue['transfertool'] = rws.transfertool
|
|
370
|
+
new_req = queue_requests(requests=[req_to_queue], session=session)
|
|
371
|
+
# If a request already exists, new_req will be an empty list.
|
|
372
|
+
if new_req:
|
|
373
|
+
db_req = new_req[0]
|
|
374
|
+
logger(logging.DEBUG, '%s: New request created for the transfer between %s and %s : %s', initial_request_id, transfer_path[0].src, transfer_path[-1].dst, db_req['id'])
|
|
375
|
+
else:
|
|
376
|
+
db_req = request_core.get_request_by_did(rws.scope, rws.name, rws.dest_rse.id, session=session)
|
|
377
|
+
# A transfer already exists for part of the path. Just construct the remaining
|
|
378
|
+
# path, but don't submit the transfer. We must wait for the existing transfer to be
|
|
379
|
+
# completed before continuing.
|
|
380
|
+
must_skip_submission = True
|
|
381
|
+
logger(logging.DEBUG, '%s: Reusing intermediate hop between %s and %s : %s', initial_request_id, transfer_path[0].src, transfer_path[-1].dst, db_req['id'])
|
|
382
|
+
|
|
383
|
+
models.TransferHop(request_id=db_req['id'],
|
|
384
|
+
next_hop_request_id=transfer_path[i + 1].rws.request_id,
|
|
385
|
+
initial_request_id=initial_request_id,
|
|
386
|
+
).save(session=session, flush=False)
|
|
387
|
+
rws.request_id = db_req['id']
|
|
388
|
+
rws.requested_at = db_req['requested_at']
|
|
389
|
+
|
|
390
|
+
return creation_successful, must_skip_submission
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def submit_transfer(
|
|
394
|
+
transfertool_obj: "Transfertool",
|
|
395
|
+
transfers: "Sequence[DirectTransfer]",
|
|
396
|
+
job_params: dict[str, str],
|
|
397
|
+
timeout: Optional[int] = None,
|
|
398
|
+
logger: "LoggerFunction" = logging.log
|
|
399
|
+
) -> None:
|
|
400
|
+
"""
|
|
401
|
+
Submit a transfer or staging request
|
|
402
|
+
|
|
403
|
+
:param transfertool_obj: The transfertool object to be used for submission
|
|
404
|
+
:param transfers: Transfer objects to be submitted
|
|
405
|
+
:param job_params: Parameters to be used for all transfers in the given job.
|
|
406
|
+
:param submitter: Name of the submitting entity.
|
|
407
|
+
:param timeout: Timeout
|
|
408
|
+
:param logger: Optional decorated logger that can be passed from the calling daemons or servers.
|
|
409
|
+
"""
|
|
410
|
+
|
|
411
|
+
for transfer in transfers:
|
|
412
|
+
try:
|
|
413
|
+
transfer_core.mark_submitting(transfer, external_host=transfertool_obj.external_host, logger=logger)
|
|
414
|
+
except RequestNotFound as error:
|
|
415
|
+
logger(logging.ERROR, str(error))
|
|
416
|
+
return
|
|
417
|
+
except Exception:
|
|
418
|
+
logger(logging.ERROR, 'Failed to prepare requests %s state to SUBMITTING. Mark it SUBMISSION_FAILED and abort submission.' % [str(t.rws) for t in transfers], exc_info=True)
|
|
419
|
+
transition_request_state(request_id=transfer.rws.request_id, state=RequestState.SUBMISSION_FAILED)
|
|
420
|
+
return
|
|
421
|
+
|
|
422
|
+
try:
|
|
423
|
+
_submit_transfers(transfertool_obj, transfers, job_params, timeout, logger)
|
|
424
|
+
except DuplicateFileTransferSubmission as error:
|
|
425
|
+
logger(logging.WARNING, 'Failed to bulk submit a job because of duplicate file : %s', str(error))
|
|
426
|
+
logger(logging.INFO, 'Submitting files one by one')
|
|
427
|
+
for transfer in transfers:
|
|
428
|
+
_submit_transfers(transfertool_obj, [transfer], job_params, timeout, logger)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def _submit_transfers(
|
|
432
|
+
transfertool_obj: "Transfertool",
|
|
433
|
+
transfers: "Sequence[DirectTransfer]",
|
|
434
|
+
job_params: dict[str, str],
|
|
435
|
+
timeout: Optional[int] = None,
|
|
436
|
+
logger: "LoggerFunction" = logging.log
|
|
437
|
+
) -> None:
|
|
438
|
+
"""
|
|
439
|
+
helper function for submit_transfers. Performs the actual submission of one or more transfers.
|
|
440
|
+
|
|
441
|
+
If the bulk submission of multiple transfers fails due to duplicate submissions, the exception
|
|
442
|
+
is propagated to the caller context, which is then responsible for calling this function again for each
|
|
443
|
+
of the transfers separately.
|
|
444
|
+
"""
|
|
445
|
+
logger(logging.DEBUG, 'About to submit job to %s with timeout %s' % (transfertool_obj, timeout))
|
|
446
|
+
# A eid is returned if the job is properly submitted otherwise an exception is raised
|
|
447
|
+
is_bulk = len(transfers) > 1
|
|
448
|
+
eid = None
|
|
449
|
+
stopwatch = Stopwatch()
|
|
450
|
+
state_to_set = RequestState.SUBMISSION_FAILED
|
|
451
|
+
try:
|
|
452
|
+
METRICS.counter('submit_transfer').inc()
|
|
453
|
+
eid = transfertool_obj.submit(transfers, job_params, timeout)
|
|
454
|
+
state_to_set = RequestState.SUBMITTED
|
|
455
|
+
except DuplicateFileTransferSubmission:
|
|
456
|
+
if is_bulk:
|
|
457
|
+
raise
|
|
458
|
+
except (TransferToolTimeout, TransferToolWrongAnswer) as error:
|
|
459
|
+
logger(logging.ERROR, 'Failed to submit a job with error %s', str(error), exc_info=True)
|
|
460
|
+
except Exception as error:
|
|
461
|
+
logger(logging.ERROR, 'Failed to submit a job with error %s', str(error), exc_info=True)
|
|
462
|
+
# Keep the behavior from before the refactoring: in case of unexpected exception, only
|
|
463
|
+
# update request state on individual transfers, and do nothing for bulks.
|
|
464
|
+
# Don't know why it's like that.
|
|
465
|
+
#
|
|
466
|
+
# FIXME: shouldn't we always set the state to SUBMISSION_FAILED?
|
|
467
|
+
if is_bulk:
|
|
468
|
+
state_to_set = None
|
|
469
|
+
|
|
470
|
+
if eid is not None:
|
|
471
|
+
stopwatch.stop()
|
|
472
|
+
logger(logging.DEBUG, 'Submit job %s to %s in %s seconds' % (eid, transfertool_obj, stopwatch.elapsed))
|
|
473
|
+
METRICS.timer('submit_bulk_transfer_per_file').observe(stopwatch.elapsed / (len(transfers) or 1))
|
|
474
|
+
METRICS.counter('submit_bulk_transfer').inc(len(transfers))
|
|
475
|
+
|
|
476
|
+
if state_to_set:
|
|
477
|
+
try:
|
|
478
|
+
transfer_core.set_transfers_state(
|
|
479
|
+
transfers,
|
|
480
|
+
state=state_to_set,
|
|
481
|
+
external_host=transfertool_obj.external_host,
|
|
482
|
+
external_id=eid,
|
|
483
|
+
submitted_at=datetime.datetime.utcnow(),
|
|
484
|
+
transfertool=transfertool_obj.external_name,
|
|
485
|
+
logger=logger
|
|
486
|
+
)
|
|
487
|
+
except Exception:
|
|
488
|
+
logger(logging.ERROR, 'Failed to register transfer state with error', exc_info=True)
|
|
489
|
+
if eid is not None:
|
|
490
|
+
# The job is still submitted in the file transfer service but the request is not updated.
|
|
491
|
+
# Possibility to have a double submission during the next cycle. Try to cancel the external request.
|
|
492
|
+
try:
|
|
493
|
+
logger(logging.INFO, 'Cancel transfer %s on %s', eid, transfertool_obj)
|
|
494
|
+
transfer_core.cancel_transfer(transfertool_obj, eid)
|
|
495
|
+
except Exception:
|
|
496
|
+
logger(logging.ERROR, 'Failed to cancel transfers %s on %s with error' % (eid, transfertool_obj), exc_info=True)
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def get_conveyor_rses(
|
|
500
|
+
rses: Optional["Sequence[Mapping[str, Any]]"] = None,
|
|
501
|
+
include_rses: Optional[str] = None,
|
|
502
|
+
exclude_rses: Optional[str] = None,
|
|
503
|
+
vos: Optional["Sequence[str]"] = None,
|
|
504
|
+
logger: "LoggerFunction" = logging.log
|
|
505
|
+
) -> list["RSESettingsDict"]:
|
|
506
|
+
"""
|
|
507
|
+
Get a list of rses for conveyor
|
|
508
|
+
|
|
509
|
+
:param rses: List of rses (Single-VO only)
|
|
510
|
+
:param include_rses: RSEs to include
|
|
511
|
+
:param exclude_rses: RSEs to exclude
|
|
512
|
+
:param vos: VOs on which to look for RSEs. Only used in multi-VO mode.
|
|
513
|
+
If None, we either use all VOs if run from "def", or the current VO otherwise.
|
|
514
|
+
:param logger: Optional decorated logger that can be passed from the calling daemons or servers.
|
|
515
|
+
:return: List of working rses
|
|
516
|
+
"""
|
|
517
|
+
multi_vo = config_get_bool('common', 'multi_vo', raise_exception=False, default=False)
|
|
518
|
+
if not multi_vo:
|
|
519
|
+
if vos:
|
|
520
|
+
logger(logging.WARNING, 'Ignoring argument vos, this is only applicable in a multi-VO setup.')
|
|
521
|
+
vos = ['def']
|
|
522
|
+
else:
|
|
523
|
+
if vos:
|
|
524
|
+
invalid = set(vos) - set([v['vo'] for v in list_vos()])
|
|
525
|
+
if invalid:
|
|
526
|
+
msg = 'VO{} {} cannot be found'.format('s' if len(invalid) > 1 else '', ', '.join([repr(v) for v in invalid]))
|
|
527
|
+
raise VONotFound(msg)
|
|
528
|
+
else:
|
|
529
|
+
vos = [v['vo'] for v in list_vos()]
|
|
530
|
+
logger(logging.INFO, 'This instance will work on VO%s: %s' % ('s' if len(vos) > 1 else '', ', '.join([v for v in vos])))
|
|
531
|
+
|
|
532
|
+
working_rses = []
|
|
533
|
+
rses_list = []
|
|
534
|
+
for vo in vos:
|
|
535
|
+
rses_list.extend(list_rses(filters={'vo': vo}))
|
|
536
|
+
if rses:
|
|
537
|
+
working_rses = [rse for rse in rses_list if rse['rse'] in rses]
|
|
538
|
+
|
|
539
|
+
if include_rses:
|
|
540
|
+
for vo in vos:
|
|
541
|
+
try:
|
|
542
|
+
parsed_rses = parse_expression(include_rses, filter_={'vo': vo}, session=None)
|
|
543
|
+
except InvalidRSEExpression:
|
|
544
|
+
logger(logging.ERROR, "Invalid RSE exception %s to include RSEs", include_rses)
|
|
545
|
+
else:
|
|
546
|
+
for rse in parsed_rses:
|
|
547
|
+
if rse not in working_rses:
|
|
548
|
+
working_rses.append(rse)
|
|
549
|
+
|
|
550
|
+
if not (rses or include_rses):
|
|
551
|
+
working_rses = rses_list
|
|
552
|
+
|
|
553
|
+
if exclude_rses:
|
|
554
|
+
try:
|
|
555
|
+
parsed_rses = parse_expression(exclude_rses, session=None)
|
|
556
|
+
except InvalidRSEExpression as error:
|
|
557
|
+
logger(logging.ERROR, "Invalid RSE exception %s to exclude RSEs: %s", exclude_rses, error)
|
|
558
|
+
else:
|
|
559
|
+
working_rses = [rse for rse in working_rses if rse not in parsed_rses]
|
|
560
|
+
|
|
561
|
+
working_rses = [rsemgr.get_rse_info(rse_id=rse['id']) for rse in working_rses]
|
|
562
|
+
return working_rses
|