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,81 @@
|
|
|
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
|
+
"""Functions to manage decommissioning configurations."""
|
|
16
|
+
|
|
17
|
+
from enum import Enum
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from rucio.common.constants import RseAttr
|
|
21
|
+
from rucio.core.rse import add_rse_attribute, get_rse_attribute
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DecommissioningStatus(Enum):
|
|
25
|
+
"""Decommissioning status flags."""
|
|
26
|
+
|
|
27
|
+
PROCESSING = 'processing'
|
|
28
|
+
DONE = 'done'
|
|
29
|
+
SUSPENDED = 'suspended'
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class InvalidStatusName(Exception):
|
|
33
|
+
"""Exception for invalid decommissioning status name set from command line."""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def config_to_attr(config: dict[str, Any]) -> str:
|
|
37
|
+
"""Form the attribute string from a config dictionary.
|
|
38
|
+
|
|
39
|
+
:param config: Decommissioning configuration dictionary.
|
|
40
|
+
:returns: Comma-separated key-value string encoding the configuration.
|
|
41
|
+
"""
|
|
42
|
+
attr = f'profile={config["profile"].value}'
|
|
43
|
+
if config.get('move_dest'):
|
|
44
|
+
attr += f',move_dest={config["move_dest"]}'
|
|
45
|
+
attr += f',status={config["status"].value}'
|
|
46
|
+
|
|
47
|
+
return attr
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def attr_to_config(attr: str) -> dict[str, Any]:
|
|
51
|
+
"""Form the config dictionary from an attribute string.
|
|
52
|
+
|
|
53
|
+
:param attr: Comma-separated key-value string encoding the configuration.
|
|
54
|
+
:returns: Decommissioning configuration dictionary.
|
|
55
|
+
"""
|
|
56
|
+
# The decommission attribute is a comma-separated list of key=value settings
|
|
57
|
+
config: dict[str, Any] = dict(map(lambda s: s.split('='), attr.split(',')))
|
|
58
|
+
if 'status' in config:
|
|
59
|
+
try:
|
|
60
|
+
config['status'] = DecommissioningStatus[config['status'].upper()]
|
|
61
|
+
except KeyError as exc:
|
|
62
|
+
raise InvalidStatusName() from exc
|
|
63
|
+
else:
|
|
64
|
+
config['status'] = DecommissioningStatus.PROCESSING
|
|
65
|
+
|
|
66
|
+
return config
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def set_status(
|
|
70
|
+
rse_id: str,
|
|
71
|
+
status: DecommissioningStatus
|
|
72
|
+
) -> None:
|
|
73
|
+
"""Update the decommission attribute of the RSE.
|
|
74
|
+
|
|
75
|
+
:param rse_id: RSE ID.
|
|
76
|
+
:param status: RSE decommissioning status.
|
|
77
|
+
"""
|
|
78
|
+
config = attr_to_config(get_rse_attribute(rse_id, RseAttr.DECOMMISSION)) # type: ignore (get_rse_attribute could return None)
|
|
79
|
+
config['status'] = status
|
|
80
|
+
# add_rse_attribute can handle updating existing entries too
|
|
81
|
+
add_rse_attribute(rse_id, RseAttr.DECOMMISSION, config_to_attr(config))
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
"""Decommissioning profile definitions."""
|
|
16
|
+
|
|
17
|
+
from .atlas import atlas_move
|
|
18
|
+
from .generic import generic_delete, generic_move
|
|
19
|
+
|
|
20
|
+
PROFILE_MAP = {
|
|
21
|
+
'generic_delete': generic_delete,
|
|
22
|
+
'generic_move': generic_move,
|
|
23
|
+
'atlas_move': atlas_move
|
|
24
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
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
|
+
"""ATLAS-specific decommissioning profiles."""
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
from typing import TYPE_CHECKING, Any
|
|
19
|
+
|
|
20
|
+
from rucio.core.did import get_metadata
|
|
21
|
+
|
|
22
|
+
from .generic import _call_for_attention, generic_move
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from rucio.common.types import LoggerFunction
|
|
26
|
+
|
|
27
|
+
from .types import DecommissioningProfile
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def atlas_move(rse: dict[str, Any], config: dict[str, Any]) -> 'DecommissioningProfile':
|
|
31
|
+
"""Return a profile for moving rules that satisfy conditions to a specific destination.
|
|
32
|
+
|
|
33
|
+
The "ATLAS move" profile lists out all rules that are locking replicas
|
|
34
|
+
at the given RSE, and moves them to the specified destination if either
|
|
35
|
+
one of the following is true:
|
|
36
|
+
|
|
37
|
+
- The RSE expression of the rule is trivial (the RSE name itself).
|
|
38
|
+
- There are no replicas locked by the rule that reside on another RSE.
|
|
39
|
+
- The datatype of the DID is not "log".
|
|
40
|
+
|
|
41
|
+
:param rse: RSE to decommission.
|
|
42
|
+
:param config: Decommissioning configuration dictionary.
|
|
43
|
+
:returns: A decommissioning profile dictionary.
|
|
44
|
+
"""
|
|
45
|
+
profile = generic_move(rse, config)
|
|
46
|
+
# Insert before the trivial RSE expression handler
|
|
47
|
+
idx = next(pos for pos, handler in enumerate(profile.handlers)
|
|
48
|
+
if handler[0].__name__ == '_has_trivial_rse_expression')
|
|
49
|
+
profile.handlers.insert(idx, (_is_log_file, _call_for_attention))
|
|
50
|
+
return profile
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _is_log_file(
|
|
54
|
+
rule: dict[str, Any],
|
|
55
|
+
rse: dict[str, Any],
|
|
56
|
+
*,
|
|
57
|
+
logger: "LoggerFunction" = logging.log
|
|
58
|
+
) -> bool:
|
|
59
|
+
"""Check if the datatype metadata is 'log'."""
|
|
60
|
+
return get_metadata(rule['scope'], rule['name'])['datatype'] == 'log'
|
|
@@ -0,0 +1,452 @@
|
|
|
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
|
+
"""Generic decommissioning profiles."""
|
|
16
|
+
import logging
|
|
17
|
+
from datetime import datetime, timedelta
|
|
18
|
+
from typing import TYPE_CHECKING, Any
|
|
19
|
+
|
|
20
|
+
from sqlalchemy.exc import NoResultFound
|
|
21
|
+
|
|
22
|
+
from rucio.common.constants import RseAttr
|
|
23
|
+
from rucio.common.exception import Duplicate, ReplicaNotFound, RequestNotFound, RucioException, RuleNotFound, RuleReplaceFailed, UnsupportedOperation
|
|
24
|
+
from rucio.core.lock import get_replica_locks, get_replica_locks_for_rule_id
|
|
25
|
+
from rucio.core.replica import list_replicas_per_rse, set_tombstone, update_replica_state
|
|
26
|
+
from rucio.core.request import get_request_by_did
|
|
27
|
+
from rucio.core.rse import add_rse_attribute, update_rse
|
|
28
|
+
from rucio.core.rule import list_rules_for_rse_decommissioning, move_rule, update_rule
|
|
29
|
+
from rucio.db.sqla.constants import ReplicaState
|
|
30
|
+
|
|
31
|
+
from .types import DecommissioningProfile, HandlerOutcome
|
|
32
|
+
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
from collections.abc import Iterable
|
|
35
|
+
|
|
36
|
+
from rucio.common.types import LoggerFunction
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def generic_delete(rse: dict[str, Any], config: dict[str, Any]) -> DecommissioningProfile:
|
|
40
|
+
"""Return a profile for simply deleting rules.
|
|
41
|
+
|
|
42
|
+
The "generic delete" profile lists out all rules that are locking replicas at the given RSE,
|
|
43
|
+
and deletes them if either one of the following is true:
|
|
44
|
+
|
|
45
|
+
- The RSE expression of the rule is trivial (the RSE name itself).
|
|
46
|
+
- There are no replicas locked by the rule that reside on another RSE.
|
|
47
|
+
|
|
48
|
+
:param rse: RSE to decommission.
|
|
49
|
+
:param config: Decommissioning configuration dictionary.
|
|
50
|
+
:returns: A decommissioning profile.
|
|
51
|
+
"""
|
|
52
|
+
return DecommissioningProfile(
|
|
53
|
+
rse=rse,
|
|
54
|
+
initializer=_generic_initialize,
|
|
55
|
+
discoverer=_generic_discover,
|
|
56
|
+
handlers=[
|
|
57
|
+
(_is_locked, _call_for_attention),
|
|
58
|
+
(_is_being_deleted, _count_as_processed),
|
|
59
|
+
(_has_trivial_rse_expression, _delete_rule),
|
|
60
|
+
(_has_all_replicas_on_rse, _delete_rule),
|
|
61
|
+
],
|
|
62
|
+
finalizer=_generic_finalize
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def generic_move(rse: dict[str, Any], config: dict[str, Any]) -> DecommissioningProfile:
|
|
67
|
+
"""Return a profile for moving rules that satisfy conditions to a specific destination.
|
|
68
|
+
|
|
69
|
+
The "generic move" profile lists out all rules that are locking replicas at the given RSE,
|
|
70
|
+
and moves them to the specified destination if either one of the following is true:
|
|
71
|
+
|
|
72
|
+
- The RSE expression of the rule is trivial (the RSE name itself).
|
|
73
|
+
- There are no replicas locked by the rule that reside on another RSE.
|
|
74
|
+
|
|
75
|
+
:param rse: RSE to decommission.
|
|
76
|
+
:param config: Decommissioning configuration dictionary.
|
|
77
|
+
:returns: A decommissioning profile dictionary.
|
|
78
|
+
"""
|
|
79
|
+
try:
|
|
80
|
+
destination = config['destination']
|
|
81
|
+
except KeyError as exc:
|
|
82
|
+
raise RucioException('Configuration parameter "destination" not set') from exc
|
|
83
|
+
|
|
84
|
+
move_to_destination = RuleMover(destination)
|
|
85
|
+
return DecommissioningProfile(
|
|
86
|
+
rse=rse,
|
|
87
|
+
initializer=_generic_initialize,
|
|
88
|
+
discoverer=_generic_discover,
|
|
89
|
+
handlers=[
|
|
90
|
+
(_is_locked, _call_for_attention),
|
|
91
|
+
(_is_being_deleted, _count_as_processed),
|
|
92
|
+
(_has_child_rule_id, _count_as_processed),
|
|
93
|
+
(_has_trivial_rse_expression, move_to_destination),
|
|
94
|
+
(_has_all_replicas_on_rse, move_to_destination),
|
|
95
|
+
],
|
|
96
|
+
finalizer=_generic_finalize
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _generic_initialize(
|
|
101
|
+
rse: dict[str, Any],
|
|
102
|
+
*,
|
|
103
|
+
logger: "LoggerFunction" = logging.log,
|
|
104
|
+
) -> None:
|
|
105
|
+
"""Initializer function that sets the RSE availability flags and the decommissioning status.
|
|
106
|
+
|
|
107
|
+
When an RSE is initialized for decommissioning, the availability flags are set as follows:
|
|
108
|
+
|
|
109
|
+
- `availability_read=True`
|
|
110
|
+
- `availability_write=False`
|
|
111
|
+
- `availability_delete=True`
|
|
112
|
+
|
|
113
|
+
and the following attribute is set:
|
|
114
|
+
|
|
115
|
+
- `greedyDeletion=True`
|
|
116
|
+
|
|
117
|
+
:param rse: RSE table entry as a dictionary.
|
|
118
|
+
:param logger: Logging function.
|
|
119
|
+
"""
|
|
120
|
+
logger(logging.INFO,
|
|
121
|
+
'(%s) Setting RSE availability flags of to read !write delete, greedyDeletion=true.',
|
|
122
|
+
rse['rse'])
|
|
123
|
+
|
|
124
|
+
parameters = {
|
|
125
|
+
'availability_read': True,
|
|
126
|
+
'availability_write': False,
|
|
127
|
+
'availability_delete': True
|
|
128
|
+
}
|
|
129
|
+
update_rse(rse['id'], parameters)
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
add_rse_attribute(rse['id'], RseAttr.GREEDYDELETION, True)
|
|
133
|
+
except Duplicate:
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _generic_discover(
|
|
138
|
+
rse: dict[str, Any],
|
|
139
|
+
*,
|
|
140
|
+
logger: "LoggerFunction" = logging.log
|
|
141
|
+
) -> 'Iterable[dict[str, Any]]':
|
|
142
|
+
"""Discoverer function that calls the listing function from core.rule.
|
|
143
|
+
|
|
144
|
+
:param rse: RSE table entry as a dictionary.
|
|
145
|
+
:param logger: Logging function.
|
|
146
|
+
:returns: An iterable of rule dictionaries.
|
|
147
|
+
"""
|
|
148
|
+
return list_rules_for_rse_decommissioning(rse['id'])
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _generic_finalize(
|
|
152
|
+
rse: dict[str, Any],
|
|
153
|
+
*,
|
|
154
|
+
logger: "LoggerFunction" = logging.log
|
|
155
|
+
) -> bool:
|
|
156
|
+
"""Check for remaining replicas at the RSE and resolve where possible.
|
|
157
|
+
|
|
158
|
+
If for some reason there are still a large number of replicas remaining at the RSE, this
|
|
159
|
+
function cuts off automatic processing attempts at a hard-coded 100.
|
|
160
|
+
|
|
161
|
+
:param rse: RSE table entry as a dictionary.
|
|
162
|
+
:param logger: Logging function.
|
|
163
|
+
:returns: A boolean flag indicating the completion status.
|
|
164
|
+
"""
|
|
165
|
+
num_remaining_replicas = _process_replicas_with_no_locks(rse,
|
|
166
|
+
list_replicas_per_rse(rse['id']),
|
|
167
|
+
limit=100,
|
|
168
|
+
logger=logger)
|
|
169
|
+
|
|
170
|
+
if num_remaining_replicas == 0:
|
|
171
|
+
# The RSE is now really completely cleared.
|
|
172
|
+
logger(logging.INFO,
|
|
173
|
+
'(%s) Completed deleting the RSE contents. Updating the decommissioning status'
|
|
174
|
+
' to "done".',
|
|
175
|
+
rse['rse'])
|
|
176
|
+
return True
|
|
177
|
+
|
|
178
|
+
logger(logging.WARNING,
|
|
179
|
+
'(%s) %d replicas remain on the RSE even though there are no more rules creating'
|
|
180
|
+
' locks on them.',
|
|
181
|
+
rse['rse'], num_remaining_replicas)
|
|
182
|
+
|
|
183
|
+
# We now wait for reaper to pick the updated replicas (if there are any). Hopefully all
|
|
184
|
+
# replicas will be deleted at the next cycle.
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _process_replicas_with_no_locks(
|
|
189
|
+
rse: dict[str, Any],
|
|
190
|
+
replicas: 'Iterable[dict[str, Any]]',
|
|
191
|
+
limit: int = 0,
|
|
192
|
+
*,
|
|
193
|
+
logger: "LoggerFunction" = logging.log,
|
|
194
|
+
) -> int:
|
|
195
|
+
"""Process replicas that remain at the RSE after the decommissioning.
|
|
196
|
+
|
|
197
|
+
Replicas that remain at the RSE at this point should be unlocked. While this is a situation
|
|
198
|
+
that should not happen, it can due to various errors. This function checks each such replica
|
|
199
|
+
and attempt to resolve the invalid state for known cases.
|
|
200
|
+
|
|
201
|
+
:param rse: RSE table entry as a dictionary.
|
|
202
|
+
:param replicas: Sequence or generator of replica objects.
|
|
203
|
+
:param logger: Logging function.
|
|
204
|
+
:returns: Number of processed replicas.
|
|
205
|
+
"""
|
|
206
|
+
num_processed = 0
|
|
207
|
+
num_updated = 0
|
|
208
|
+
num_waiting_reap = 0
|
|
209
|
+
|
|
210
|
+
# Check if each replica satisfies the condition in list_and_mark_unlocked_replicas() (in
|
|
211
|
+
# core.replica).
|
|
212
|
+
# For each of the conditions, in case of failure, handle cases that can be handled.
|
|
213
|
+
for replica in replicas:
|
|
214
|
+
num_processed += 1
|
|
215
|
+
if limit > 0 and num_processed == limit:
|
|
216
|
+
break
|
|
217
|
+
|
|
218
|
+
updated = False
|
|
219
|
+
|
|
220
|
+
# If the replica fails any of the following three conditions, reaper won't pick it up.
|
|
221
|
+
reap_pending = True
|
|
222
|
+
|
|
223
|
+
# 1. Condition on the replica state & update time
|
|
224
|
+
in_stable_state = replica['state'] in [ReplicaState.AVAILABLE,
|
|
225
|
+
ReplicaState.UNAVAILABLE,
|
|
226
|
+
ReplicaState.BAD]
|
|
227
|
+
|
|
228
|
+
ten_minutes_ago = datetime.utcnow() - timedelta(seconds=600)
|
|
229
|
+
deleting_stuck = (replica['state'] == ReplicaState.BEING_DELETED
|
|
230
|
+
and replica['updated_at'] < ten_minutes_ago)
|
|
231
|
+
|
|
232
|
+
if not (in_stable_state or deleting_stuck):
|
|
233
|
+
# 1.1 If COPYING without a valid request
|
|
234
|
+
# -> Update the state to UNAVAILABLE
|
|
235
|
+
if replica['state'] == ReplicaState.COPYING:
|
|
236
|
+
# Should we allow requests in certain states? Depends on the details of the
|
|
237
|
+
# request state machine.
|
|
238
|
+
try:
|
|
239
|
+
get_request_by_did(replica['scope'], replica['name'], rse['id'])
|
|
240
|
+
except RequestNotFound:
|
|
241
|
+
logger(logging.INFO,
|
|
242
|
+
'(%s) Replica %s:%s is in COPYING state without a valid request.'
|
|
243
|
+
' Changing state to UNAVAILABLE.',
|
|
244
|
+
rse['rse'], replica['scope'], replica['name'])
|
|
245
|
+
|
|
246
|
+
try:
|
|
247
|
+
update_replica_state(rse['id'], replica['scope'], replica['name'],
|
|
248
|
+
ReplicaState.UNAVAILABLE)
|
|
249
|
+
except ReplicaNotFound:
|
|
250
|
+
logger(logging.WARNING,
|
|
251
|
+
'(%s) Replica %s:%s disappeared during cleanup',
|
|
252
|
+
rse['rse'], replica['scope'], replica['name'])
|
|
253
|
+
except UnsupportedOperation as error:
|
|
254
|
+
logger(logging.ERROR, '(%s) %s', rse['rse'], str(error))
|
|
255
|
+
else:
|
|
256
|
+
updated = True
|
|
257
|
+
|
|
258
|
+
reap_pending = False
|
|
259
|
+
|
|
260
|
+
# 2. Condition on the lock count
|
|
261
|
+
if replica['lock_cnt'] != 0:
|
|
262
|
+
# 2.1 No actual lock -> Reset the lock count
|
|
263
|
+
try:
|
|
264
|
+
locks = get_replica_locks(replica['scope'], replica['name'],
|
|
265
|
+
restrict_rses=[rse['id']])
|
|
266
|
+
except NoResultFound:
|
|
267
|
+
logger(logging.WARNING,
|
|
268
|
+
'(%s) Replica %s:%s disappeared during cleanup',
|
|
269
|
+
rse['rse'], replica['scope'], replica['name'])
|
|
270
|
+
else:
|
|
271
|
+
if len(locks) == 0:
|
|
272
|
+
logger(logging.WARNING,
|
|
273
|
+
'(%s) Replica %s:%s has lock count %s but zero actual locks. Please'
|
|
274
|
+
' fix the counts.',
|
|
275
|
+
rse['rse'], replica['scope'], replica['name'], replica['lock_cnt'])
|
|
276
|
+
|
|
277
|
+
reap_pending = False
|
|
278
|
+
|
|
279
|
+
# 3. Tombstone missing or in the future -> RIP now
|
|
280
|
+
if replica['tombstone'] is None or replica['tombstone'] >= datetime.utcnow():
|
|
281
|
+
logger(logging.INFO, '(%s) Marking tombstone of replica %s:%s as UTCNOW.',
|
|
282
|
+
rse['rse'], replica['scope'], replica['name'])
|
|
283
|
+
|
|
284
|
+
try:
|
|
285
|
+
set_tombstone(rse['id'], replica['scope'], replica['name'],
|
|
286
|
+
tombstone=datetime.utcnow())
|
|
287
|
+
except ReplicaNotFound as error:
|
|
288
|
+
logger(logging.WARNING, '(%s) %s', rse['rse'], str(error))
|
|
289
|
+
else:
|
|
290
|
+
updated = True
|
|
291
|
+
|
|
292
|
+
reap_pending = False
|
|
293
|
+
|
|
294
|
+
if updated:
|
|
295
|
+
num_updated += 1
|
|
296
|
+
|
|
297
|
+
if reap_pending:
|
|
298
|
+
num_waiting_reap += 1
|
|
299
|
+
|
|
300
|
+
logger(logging.INFO, '(%s) %s replicas have been updated. %s replicas are pending deletion.'
|
|
301
|
+
' >=%s replicas remain unhandled.',
|
|
302
|
+
rse['rse'], num_updated, num_waiting_reap,
|
|
303
|
+
num_processed - num_updated - num_waiting_reap)
|
|
304
|
+
|
|
305
|
+
return num_processed
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
# Condition functions
|
|
309
|
+
|
|
310
|
+
def _is_locked(
|
|
311
|
+
rule: dict[str, Any],
|
|
312
|
+
rse: dict[str, Any],
|
|
313
|
+
*,
|
|
314
|
+
logger: "LoggerFunction" = logging.log
|
|
315
|
+
) -> bool:
|
|
316
|
+
logger(logging.INFO,
|
|
317
|
+
'(%s) Rule %s for %s:%s is locked',
|
|
318
|
+
rse['rse'], rule['id'], rule['scope'], rule['name'])
|
|
319
|
+
return rule['locked']
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def _is_being_deleted(
|
|
323
|
+
rule: dict[str, Any],
|
|
324
|
+
rse: dict[str, Any],
|
|
325
|
+
*,
|
|
326
|
+
logger: "LoggerFunction" = logging.log
|
|
327
|
+
) -> bool:
|
|
328
|
+
"""Check if the rule is already set to be deleted."""
|
|
329
|
+
if rule['expires_at'] is not None and rule['expires_at'] < datetime.utcnow():
|
|
330
|
+
logger(logging.DEBUG,
|
|
331
|
+
'(%s) Rule %s for %s:%s is bound for deletion',
|
|
332
|
+
rse['rse'], rule['id'], rule['scope'], rule['name'])
|
|
333
|
+
return True
|
|
334
|
+
return False
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def _has_trivial_rse_expression(
|
|
338
|
+
rule: dict[str, Any],
|
|
339
|
+
rse: dict[str, Any],
|
|
340
|
+
*,
|
|
341
|
+
logger: "LoggerFunction" = logging.log
|
|
342
|
+
) -> bool:
|
|
343
|
+
"""Check for a trivial rse_expression."""
|
|
344
|
+
return rule['rse_expression'] == rse['rse']
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def _has_all_replicas_on_rse(
|
|
348
|
+
rule: dict[str, Any],
|
|
349
|
+
rse: dict[str, Any],
|
|
350
|
+
*,
|
|
351
|
+
logger: "LoggerFunction" = logging.log
|
|
352
|
+
) -> bool:
|
|
353
|
+
"""Check if the all the replicas are on the RSE."""
|
|
354
|
+
# Check the list of RSEs that the replicas locked by this rule reside on.
|
|
355
|
+
try:
|
|
356
|
+
locks = get_replica_locks_for_rule_id(rule['id'])
|
|
357
|
+
except NoResultFound:
|
|
358
|
+
# No replica is locked to begin with -> treat as having the last replica on this RSE
|
|
359
|
+
return True
|
|
360
|
+
|
|
361
|
+
replica_rse_ids = set(lock['rse_id'] for lock in locks)
|
|
362
|
+
|
|
363
|
+
return len(replica_rse_ids) == 1 and list(replica_rse_ids)[0] == rse['id']
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def _has_child_rule_id(
|
|
367
|
+
rule: dict[str, Any],
|
|
368
|
+
rse: dict[str, Any],
|
|
369
|
+
*,
|
|
370
|
+
logger: "LoggerFunction" = logging.log
|
|
371
|
+
) -> bool:
|
|
372
|
+
"""Check for non-empty child_rule_id."""
|
|
373
|
+
if rule['child_rule_id']:
|
|
374
|
+
logger(logging.DEBUG, '(%s) Rule %s for %s:%s is being moved',
|
|
375
|
+
rse['rse'], rule['id'], rule['scope'], rule['name'])
|
|
376
|
+
return True
|
|
377
|
+
return False
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
# Action functions
|
|
381
|
+
|
|
382
|
+
def _call_for_attention(
|
|
383
|
+
rule: dict[str, Any],
|
|
384
|
+
rse: dict[str, Any],
|
|
385
|
+
*,
|
|
386
|
+
logger: "LoggerFunction" = logging.log
|
|
387
|
+
) -> HandlerOutcome:
|
|
388
|
+
return HandlerOutcome.NEED_ATTENTION
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _count_as_processed(
|
|
392
|
+
rule: dict[str, Any],
|
|
393
|
+
rse: dict[str, Any],
|
|
394
|
+
*,
|
|
395
|
+
logger: "LoggerFunction" = logging.log
|
|
396
|
+
) -> HandlerOutcome:
|
|
397
|
+
"""Do nothing but increment the limit checker."""
|
|
398
|
+
return HandlerOutcome.UNTOUCHED
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def _delete_rule(
|
|
402
|
+
rule: dict[str, Any],
|
|
403
|
+
rse: dict[str, Any],
|
|
404
|
+
*,
|
|
405
|
+
logger: "LoggerFunction" = logging.log
|
|
406
|
+
) -> HandlerOutcome:
|
|
407
|
+
"""Delete the rule."""
|
|
408
|
+
logger(logging.DEBUG, '(%s) Deleting rule %s for %s:%s',
|
|
409
|
+
rse['rse'], rule['id'], rule['scope'], rule['name'])
|
|
410
|
+
|
|
411
|
+
try:
|
|
412
|
+
update_rule(rule['id'], {'lifetime': 0})
|
|
413
|
+
except RuleNotFound:
|
|
414
|
+
logger(logging.WARNING, '(%s) Rule %s for %s:%s disappeared before deleting',
|
|
415
|
+
rse['rse'], rule['id'], rule['scope'], rule['name'])
|
|
416
|
+
return HandlerOutcome.UNTOUCHED
|
|
417
|
+
|
|
418
|
+
return HandlerOutcome.REMOVED
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
class RuleMover:
|
|
422
|
+
"""Callable object with a destination attribute."""
|
|
423
|
+
def __init__(self, destination: str) -> None:
|
|
424
|
+
self.destination = destination
|
|
425
|
+
|
|
426
|
+
def __call__(
|
|
427
|
+
self,
|
|
428
|
+
rule: dict[str, Any],
|
|
429
|
+
rse: dict[str, Any],
|
|
430
|
+
*,
|
|
431
|
+
logger: "LoggerFunction" = logging.log
|
|
432
|
+
) -> HandlerOutcome:
|
|
433
|
+
"""Move the rule."""
|
|
434
|
+
# Move the rule.
|
|
435
|
+
logger(logging.DEBUG, '(%s) Moving rule %s for %s:%s to %s',
|
|
436
|
+
rse['rse'], rule['id'], rule['scope'], rule['name'],
|
|
437
|
+
self.destination)
|
|
438
|
+
|
|
439
|
+
try:
|
|
440
|
+
move_rule(rule['id'], self.destination,
|
|
441
|
+
override={'weight': None, 'source_replica_expression': None})
|
|
442
|
+
except RuleNotFound:
|
|
443
|
+
logger(logging.WARNING, '(%s) Rule %s for %s:%s disappeared before moving',
|
|
444
|
+
rse['rse'], rule['id'], rule['scope'], rule['name'])
|
|
445
|
+
return HandlerOutcome.UNTOUCHED
|
|
446
|
+
except RuleReplaceFailed:
|
|
447
|
+
logger(logging.ERROR,
|
|
448
|
+
'(%s) Failed to move rule %s for %s:%s to %s',
|
|
449
|
+
rse['rse'], rule['id'], rule['scope'], rule['name'],
|
|
450
|
+
self.destination)
|
|
451
|
+
return HandlerOutcome.NEED_ATTENTION
|
|
452
|
+
return HandlerOutcome.REMOVED
|