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,362 @@
|
|
|
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 random
|
|
16
|
+
import shutil
|
|
17
|
+
import socket
|
|
18
|
+
import tarfile
|
|
19
|
+
from collections import OrderedDict
|
|
20
|
+
from datetime import datetime, timedelta
|
|
21
|
+
from math import asin, cos, radians, sin, sqrt
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from tempfile import TemporaryDirectory, TemporaryFile
|
|
24
|
+
from typing import IO, TYPE_CHECKING, Any, Optional, Union
|
|
25
|
+
from urllib.parse import urlparse
|
|
26
|
+
|
|
27
|
+
import geoip2.database
|
|
28
|
+
import requests
|
|
29
|
+
from dogpile.cache.api import NO_VALUE
|
|
30
|
+
|
|
31
|
+
from rucio.common import utils
|
|
32
|
+
from rucio.common.cache import MemcacheRegion
|
|
33
|
+
from rucio.common.config import config_get, config_get_bool, config_get_int
|
|
34
|
+
from rucio.common.constants import SORTING_ALGORITHMS
|
|
35
|
+
from rucio.common.exception import InvalidRSEExpression, SortingAlgorithmNotSupported
|
|
36
|
+
from rucio.core.rse_expression_parser import parse_expression
|
|
37
|
+
|
|
38
|
+
if TYPE_CHECKING:
|
|
39
|
+
from _typeshed import StrPath
|
|
40
|
+
|
|
41
|
+
from rucio.common.types import IPDict, ReplicaDict
|
|
42
|
+
|
|
43
|
+
REGION = MemcacheRegion(expiration_time=900, function_key_generator=utils.my_key_generator)
|
|
44
|
+
|
|
45
|
+
# This product uses GeoLite data created by MaxMind,
|
|
46
|
+
# available from <a href="http://www.maxmind.com">http://www.maxmind.com</a>
|
|
47
|
+
GEOIP_DB_EDITION = 'GeoLite2-City'
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def extract_file_from_tar_gz(
|
|
51
|
+
archive_file_obj: IO,
|
|
52
|
+
file_name: str,
|
|
53
|
+
destination: 'StrPath'
|
|
54
|
+
) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Extract one file from the archive and put it at the destination
|
|
57
|
+
|
|
58
|
+
archive_fileobj is supposed to be at position 0
|
|
59
|
+
"""
|
|
60
|
+
with TemporaryDirectory(prefix=file_name) as tmp_dir:
|
|
61
|
+
tmp_dir = Path(tmp_dir)
|
|
62
|
+
with tarfile.open(fileobj=archive_file_obj, mode='r:gz') as tfile:
|
|
63
|
+
tfile.extractall(path=tmp_dir) # noqa: S202
|
|
64
|
+
for entry in tfile:
|
|
65
|
+
if entry.name.find(file_name) > -1:
|
|
66
|
+
print('Will move %s to %s' % (tmp_dir / entry.name, destination))
|
|
67
|
+
shutil.move(tmp_dir / entry.name, destination)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def __download_geoip_db(destination: 'StrPath') -> None:
|
|
71
|
+
edition_id = GEOIP_DB_EDITION
|
|
72
|
+
download_url = config_get('core', 'geoip_download_url', raise_exception=False, default=None)
|
|
73
|
+
verify_tls = config_get_bool('core', 'geoip_download_verify_tls', raise_exception=False, default=True)
|
|
74
|
+
if not download_url:
|
|
75
|
+
licence_key = config_get('core', 'geoip_licence_key', raise_exception=False, default=None)
|
|
76
|
+
if not licence_key:
|
|
77
|
+
raise Exception('Cannot download GeoIP database: licence key not provided')
|
|
78
|
+
download_url = 'https://download.maxmind.com/app/geoip_download?edition_id=%s&license_key=%s&suffix=tar.gz' % (edition_id, licence_key)
|
|
79
|
+
|
|
80
|
+
result = requests.get(download_url, stream=True, verify=verify_tls)
|
|
81
|
+
if result and result.status_code in [200, ]:
|
|
82
|
+
with TemporaryFile() as file_obj:
|
|
83
|
+
for chunk in result.iter_content(8192):
|
|
84
|
+
file_obj.write(chunk)
|
|
85
|
+
file_obj.seek(0)
|
|
86
|
+
|
|
87
|
+
extract_file_from_tar_gz(archive_file_obj=file_obj, file_name=f'{edition_id}.mmdb', destination=destination)
|
|
88
|
+
else:
|
|
89
|
+
raise Exception('Cannot download GeoIP database: %s, Code: %s, Error: %s' % (edition_id,
|
|
90
|
+
result.status_code,
|
|
91
|
+
result.text))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def __geoip_db() -> geoip2.database.Reader:
|
|
95
|
+
db_path = Path(f'/tmp/{GEOIP_DB_EDITION}.mmdb')
|
|
96
|
+
db_expire_delay = timedelta(days=config_get_int('core', 'geoip_expire_delay', raise_exception=False, default=30))
|
|
97
|
+
|
|
98
|
+
must_download = False
|
|
99
|
+
if not db_path.is_file():
|
|
100
|
+
print('%s does not exist. Downloading it.' % db_path)
|
|
101
|
+
must_download = True
|
|
102
|
+
elif db_expire_delay and datetime.fromtimestamp(db_path.stat().st_mtime) < datetime.now() - db_expire_delay:
|
|
103
|
+
print('%s is too old. Re-downloading it.' % db_path)
|
|
104
|
+
must_download = True
|
|
105
|
+
|
|
106
|
+
if must_download:
|
|
107
|
+
__download_geoip_db(destination=db_path)
|
|
108
|
+
|
|
109
|
+
return geoip2.database.Reader(str(db_path))
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def __get_lat_long(
|
|
113
|
+
se: str,
|
|
114
|
+
gi: geoip2.database.Reader
|
|
115
|
+
) -> tuple[Optional[float], Optional[float]]:
|
|
116
|
+
"""
|
|
117
|
+
Get the latitude and longitude on one host using the GeoLite DB
|
|
118
|
+
:param se : A hostname or IP.
|
|
119
|
+
:param gi : A Reader object (geoip2 API).
|
|
120
|
+
"""
|
|
121
|
+
try:
|
|
122
|
+
ip = socket.getaddrinfo(se, None)[0][4][0]
|
|
123
|
+
response = gi.city(ip)
|
|
124
|
+
return response.location.latitude, response.location.longitude
|
|
125
|
+
except socket.gaierror as error:
|
|
126
|
+
# Host definitively unknown
|
|
127
|
+
print(error)
|
|
128
|
+
return None, None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def __get_distance(
|
|
132
|
+
se1: str,
|
|
133
|
+
client_location: 'IPDict',
|
|
134
|
+
ignore_error: bool
|
|
135
|
+
) -> float:
|
|
136
|
+
"""
|
|
137
|
+
Get the distance between 2 host using the GeoLite DB
|
|
138
|
+
:param se1 : A first hostname or IP.
|
|
139
|
+
:param client_location : contains {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
|
|
140
|
+
:ignore_error: Ignore exception when the GeoLite DB cannot be retrieved
|
|
141
|
+
"""
|
|
142
|
+
# does not cache ignore_error, str.lower on hostnames/ips is fine
|
|
143
|
+
canonical_parties = list(map(lambda x: str(x).lower(), [se1, client_location['ip'], client_location.get('latitude', ''), client_location.get('longitude', '')]))
|
|
144
|
+
canonical_parties.sort()
|
|
145
|
+
cache_key = f'replica_sorter:__get_distance|site_distance|{"".join(canonical_parties)}'.replace(' ', '.')
|
|
146
|
+
cache_val = REGION.get(cache_key)
|
|
147
|
+
if cache_val is NO_VALUE:
|
|
148
|
+
try:
|
|
149
|
+
gi = __geoip_db()
|
|
150
|
+
|
|
151
|
+
lat1, long1 = __get_lat_long(se1, gi)
|
|
152
|
+
|
|
153
|
+
lat2 = client_location.get('latitude')
|
|
154
|
+
long2 = client_location.get('longitude')
|
|
155
|
+
|
|
156
|
+
if not (lat2 and long2) and client_location['ip'] is not None:
|
|
157
|
+
lat2, long2 = __get_lat_long(client_location['ip'], gi)
|
|
158
|
+
|
|
159
|
+
if lat1 and lat2:
|
|
160
|
+
long1, lat1, long2, lat2 = map(radians, [long1, lat1, long2, lat2]) # type: ignore (lat2 and long2 might be None)
|
|
161
|
+
dlon = long2 - long1
|
|
162
|
+
dlat = lat2 - lat1
|
|
163
|
+
cache_val = 6378 * 2 * asin(sqrt(sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2))
|
|
164
|
+
REGION.set(cache_key, cache_val)
|
|
165
|
+
return cache_val
|
|
166
|
+
except Exception as error:
|
|
167
|
+
if not ignore_error:
|
|
168
|
+
raise error
|
|
169
|
+
# One host is on the Moon
|
|
170
|
+
cache_val = 360000
|
|
171
|
+
REGION.set(cache_key, cache_val)
|
|
172
|
+
return cache_val # type: ignore (cache_val should not be None)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def __download_custom_distance_table() -> None:
|
|
176
|
+
"""
|
|
177
|
+
Downloads and parses the custom distance table specified by custom_distance_download_url
|
|
178
|
+
in the config file. Each line of this CSV file should contain a site name, a RSE name,
|
|
179
|
+
and a numerical distance value. Any additional fields are silently ignored.
|
|
180
|
+
"""
|
|
181
|
+
db_path = Path('/tmp/rucio_custom_distance_table.csv')
|
|
182
|
+
db_expire_delay = timedelta(days=config_get_int('core', 'custom_distance_expire_delay', raise_exception=False, default=30))
|
|
183
|
+
|
|
184
|
+
# check if need to download the file
|
|
185
|
+
must_download = False
|
|
186
|
+
if not db_path.is_file():
|
|
187
|
+
print('%s does not exist. Downloading it.' % db_path)
|
|
188
|
+
must_download = True
|
|
189
|
+
elif db_expire_delay and datetime.fromtimestamp(db_path.stat().st_mtime) < datetime.now() - db_expire_delay:
|
|
190
|
+
print('%s is too old. Re-downloading it.' % db_path)
|
|
191
|
+
must_download = True
|
|
192
|
+
|
|
193
|
+
if must_download:
|
|
194
|
+
download_url = config_get('core', 'custom_distance_download_url', raise_exception=False, default=None)
|
|
195
|
+
if download_url is None:
|
|
196
|
+
raise Exception('Cannot download custom distance table: no URL provided')
|
|
197
|
+
result = requests.get(download_url, stream=True, verify=False)
|
|
198
|
+
if result and result.status_code in [200, ]:
|
|
199
|
+
with open(db_path, mode='w') as file_obj:
|
|
200
|
+
file_obj.write(result.text)
|
|
201
|
+
else:
|
|
202
|
+
raise Exception('Cannot download custom distance table: %s, Code: %s, Error: %s' % (download_url,
|
|
203
|
+
result.status_code,
|
|
204
|
+
result.text))
|
|
205
|
+
|
|
206
|
+
# parse the local file and add its contents to REGION
|
|
207
|
+
with open(db_path, mode='r') as f:
|
|
208
|
+
lines = f.readlines()
|
|
209
|
+
for line in lines:
|
|
210
|
+
if line.strip() == "":
|
|
211
|
+
# ignore blank lines
|
|
212
|
+
continue
|
|
213
|
+
bits = line.split(",")
|
|
214
|
+
if len(bits) < 3:
|
|
215
|
+
raise Exception('Custom distance table must have at least 3 values per line')
|
|
216
|
+
# ignore additional fields after first 3 (DUNE has some)
|
|
217
|
+
site = bits[0].strip()
|
|
218
|
+
rse = bits[1].strip()
|
|
219
|
+
distance = float(bits[2].strip())
|
|
220
|
+
if distance < 0.0 or distance > 1.0:
|
|
221
|
+
raise Exception('Distances in custom distance table must be in range 0-1')
|
|
222
|
+
cache_key = f'replica_sorter:__get_distance_custom|site_distance|{rse}|{site}'
|
|
223
|
+
REGION.set(cache_key, distance)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def __get_distance_custom(rse: Union[tuple, str], client_location: 'IPDict') -> float:
|
|
227
|
+
"""
|
|
228
|
+
Return the distance from a client to a RSE by looking up in custom distance table
|
|
229
|
+
:param rse: RSE name, or tuple containing replica information with RSE name third
|
|
230
|
+
:param client_location: location dictionary containing {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
|
|
231
|
+
:returns: numerical distance value
|
|
232
|
+
"""
|
|
233
|
+
# get RSE name out of tuple if necessary
|
|
234
|
+
if isinstance(rse, tuple) and len(rse) == 4:
|
|
235
|
+
rse = rse[2]
|
|
236
|
+
cache_key = f'replica_sorter:__get_distance_custom|site_distance|{rse}|{client_location["site"]}'
|
|
237
|
+
cache_val = REGION.get(cache_key)
|
|
238
|
+
if not isinstance(cache_val, float):
|
|
239
|
+
# download the table and add all its values to the cache
|
|
240
|
+
__download_custom_distance_table()
|
|
241
|
+
cache_val = REGION.get(cache_key)
|
|
242
|
+
if not isinstance(cache_val, float):
|
|
243
|
+
# assume maximum distance if not specified in table
|
|
244
|
+
cache_val = 1.0
|
|
245
|
+
return cache_val
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def site_selector(
|
|
249
|
+
replicas: dict[str, 'ReplicaDict'],
|
|
250
|
+
site: str,
|
|
251
|
+
vo: str
|
|
252
|
+
) -> list[str]:
|
|
253
|
+
"""
|
|
254
|
+
Return a list of replicas located on one site.
|
|
255
|
+
:param replicas : A dict with RSEs as values and replicas as keys (URIs).
|
|
256
|
+
:param site : The name of the site
|
|
257
|
+
:param vo : The vo within which to search for RSEs
|
|
258
|
+
"""
|
|
259
|
+
result = []
|
|
260
|
+
try:
|
|
261
|
+
rses = parse_expression("site=%s" % site, filter_={'vo': vo})
|
|
262
|
+
except InvalidRSEExpression:
|
|
263
|
+
return result
|
|
264
|
+
except Exception:
|
|
265
|
+
return result
|
|
266
|
+
rses = [i['rse'] for i in rses]
|
|
267
|
+
for replica in replicas:
|
|
268
|
+
if replicas[replica] in rses:
|
|
269
|
+
result.append(replica)
|
|
270
|
+
return result
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def sort_replicas(
|
|
274
|
+
dictreplica: dict[str, Any],
|
|
275
|
+
client_location: 'IPDict',
|
|
276
|
+
selection: Optional[str] = None
|
|
277
|
+
) -> list[str]:
|
|
278
|
+
"""
|
|
279
|
+
General sorting method for a dictionary of replicas. Returns the List of replicas.
|
|
280
|
+
|
|
281
|
+
:param dictreplica: A dict with replicas as keys (URIs).
|
|
282
|
+
:param client_location: Location dictionary containing {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
|
|
283
|
+
:param selection: the selected sorting algorithm.
|
|
284
|
+
:param default: the default sorting algorithm (random, if not defined).
|
|
285
|
+
:returns: the keys of dictreplica in a sorted list.
|
|
286
|
+
"""
|
|
287
|
+
if len(dictreplica) == 0:
|
|
288
|
+
return []
|
|
289
|
+
|
|
290
|
+
if not selection:
|
|
291
|
+
selection = 'geoip'
|
|
292
|
+
elif selection not in SORTING_ALGORITHMS:
|
|
293
|
+
raise SortingAlgorithmNotSupported('Sorting algorithm: %s is not supported. Supported protocols: %s' % (selection, SORTING_ALGORITHMS))
|
|
294
|
+
|
|
295
|
+
items = [(key, value) for key, value in dictreplica.items()]
|
|
296
|
+
# safety check, TODO: remove if all dictreplica values are 4-tuple with priority as second item
|
|
297
|
+
if isinstance(items[0][1], tuple) and len(items[0][1]) == 4:
|
|
298
|
+
# sort by value[1], which is the priority
|
|
299
|
+
items.sort(key=lambda item: item[1][1])
|
|
300
|
+
dictreplica = OrderedDict(items)
|
|
301
|
+
|
|
302
|
+
# all sorts must be stable to preserve the priority (the Python standard sorting functions always are stable)
|
|
303
|
+
if selection == 'geoip':
|
|
304
|
+
replicas = sort_geoip(dictreplica, client_location, ignore_error=config_get_bool('core', 'geoip_ignore_error', raise_exception=False, default=True))
|
|
305
|
+
elif selection == 'custom_table':
|
|
306
|
+
replicas = sort_custom(dictreplica, client_location)
|
|
307
|
+
elif selection == 'random':
|
|
308
|
+
replicas = sort_random(dictreplica)
|
|
309
|
+
|
|
310
|
+
return replicas
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def sort_random(dictreplica: dict[str, Any]) -> list[str]:
|
|
314
|
+
"""
|
|
315
|
+
Return a list of replicas sorted randomly.
|
|
316
|
+
:param dictreplica: A dict with replicas as keys (URIs).
|
|
317
|
+
"""
|
|
318
|
+
|
|
319
|
+
list_replicas = list(dictreplica.keys())
|
|
320
|
+
random.shuffle(list_replicas)
|
|
321
|
+
return list_replicas
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def sort_geoip(
|
|
325
|
+
dictreplica: dict[str, Any],
|
|
326
|
+
client_location: 'IPDict',
|
|
327
|
+
ignore_error: bool = False
|
|
328
|
+
) -> list[str]:
|
|
329
|
+
"""
|
|
330
|
+
Return a list of replicas sorted by geographical distance to the client IP.
|
|
331
|
+
:param dictreplica: A dict with replicas as keys (URIs).
|
|
332
|
+
:param client_location: Location dictionary containing {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
|
|
333
|
+
:param ignore_error: Ignore exception when the GeoLite DB cannot be retrieved
|
|
334
|
+
"""
|
|
335
|
+
|
|
336
|
+
def distance(pfn: str) -> float:
|
|
337
|
+
url = urlparse(pfn)
|
|
338
|
+
if url.scheme == 'root':
|
|
339
|
+
# handle root proxy urls: root://10.0.0.1//root://192.168.1.1:1094//dpm/....
|
|
340
|
+
sub_url = urlparse(url.path.lstrip('/'))
|
|
341
|
+
if sub_url.scheme and sub_url.hostname:
|
|
342
|
+
url = sub_url
|
|
343
|
+
return __get_distance(url.hostname, client_location, ignore_error) # type: ignore (hostname might be None)
|
|
344
|
+
|
|
345
|
+
return list(sorted(dictreplica, key=distance))
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def sort_custom(
|
|
349
|
+
dictreplica: dict[str, Any],
|
|
350
|
+
client_location: 'IPDict'
|
|
351
|
+
) -> list[str]:
|
|
352
|
+
"""
|
|
353
|
+
Return a list of replicas sorted according to the custom distance table.
|
|
354
|
+
:param dictreplica: A dict with replicas as keys (URIs).
|
|
355
|
+
:param client_location: Location dictionary containing {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
|
|
356
|
+
:param ignore_error: Ignore exception when the GeoLite DB cannot be retrieved
|
|
357
|
+
"""
|
|
358
|
+
|
|
359
|
+
def distance(pfn: str) -> float:
|
|
360
|
+
return __get_distance_custom(dictreplica[pfn], client_location)
|
|
361
|
+
|
|
362
|
+
return list(sorted(dictreplica, key=distance))
|