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,759 @@
|
|
|
1
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
from datetime import date, datetime, timedelta
|
|
17
|
+
from string import Template
|
|
18
|
+
from typing import TYPE_CHECKING, Any, Literal, Optional, Union
|
|
19
|
+
|
|
20
|
+
from requests import get
|
|
21
|
+
from sqlalchemy import BigInteger, and_, case, cast, false, func, or_, select
|
|
22
|
+
from sqlalchemy.orm import Session, aliased
|
|
23
|
+
|
|
24
|
+
from rucio.common.config import config_get, config_get_bool, config_get_int
|
|
25
|
+
from rucio.common.exception import (
|
|
26
|
+
DuplicateRule,
|
|
27
|
+
InsufficientAccountLimit,
|
|
28
|
+
InsufficientTargetRSEs,
|
|
29
|
+
RuleNotFound,
|
|
30
|
+
)
|
|
31
|
+
from rucio.common.types import InternalAccount, InternalScope
|
|
32
|
+
from rucio.core.lock import get_dataset_locks
|
|
33
|
+
from rucio.core.rse import get_rse_name, get_rse_vo, list_rse_attributes
|
|
34
|
+
from rucio.core.rse_expression_parser import parse_expression
|
|
35
|
+
from rucio.core.rse_selector import RSESelector
|
|
36
|
+
from rucio.core.rule import add_rule, get_rule, update_rule
|
|
37
|
+
from rucio.db.sqla import models
|
|
38
|
+
from rucio.db.sqla.constants import DIDType, LockState, RuleGrouping, RuleState
|
|
39
|
+
from rucio.db.sqla.session import read_session, transactional_session
|
|
40
|
+
|
|
41
|
+
if TYPE_CHECKING:
|
|
42
|
+
from collections.abc import Mapping, Sequence
|
|
43
|
+
|
|
44
|
+
from sqlalchemy.engine import Row
|
|
45
|
+
|
|
46
|
+
from rucio.common.types import LoggerFunction
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@transactional_session
|
|
50
|
+
def rebalance_rule(
|
|
51
|
+
parent_rule: "Mapping[str, Any]",
|
|
52
|
+
activity: str,
|
|
53
|
+
rse_expression: str,
|
|
54
|
+
priority: int,
|
|
55
|
+
source_replica_expression: str = "*\\bb8-enabled=false",
|
|
56
|
+
comment: Optional[str] = None,
|
|
57
|
+
*,
|
|
58
|
+
session: Session,
|
|
59
|
+
) -> Optional[list[str]]:
|
|
60
|
+
"""
|
|
61
|
+
Rebalance a replication rule to a new RSE
|
|
62
|
+
:param parent_rule: Replication rule to be rebalanced.
|
|
63
|
+
:param activity: Activity to be used for the rebalancing.
|
|
64
|
+
:param rse_expression: RSE expression of the new rule.
|
|
65
|
+
:param priority: Priority of the newly created rule.
|
|
66
|
+
:param source_replica_expression: Source replica expression of the new rule.
|
|
67
|
+
:param comment: Comment to set on the new rules.
|
|
68
|
+
:returns: The new child rule id.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
if parent_rule["expires_at"] is None:
|
|
72
|
+
lifetime = None
|
|
73
|
+
else:
|
|
74
|
+
lifetime = (parent_rule["expires_at"] - datetime.utcnow()).days * 24 * 3600 + (
|
|
75
|
+
parent_rule["expires_at"] - datetime.utcnow()
|
|
76
|
+
).seconds
|
|
77
|
+
|
|
78
|
+
if parent_rule["grouping"] == RuleGrouping.ALL:
|
|
79
|
+
grouping = "ALL"
|
|
80
|
+
elif parent_rule["grouping"] == RuleGrouping.NONE:
|
|
81
|
+
grouping = "NONE"
|
|
82
|
+
else:
|
|
83
|
+
grouping = "DATASET"
|
|
84
|
+
|
|
85
|
+
# check if concurrent replica at target rse does not exist
|
|
86
|
+
concurrent_replica = False
|
|
87
|
+
for lock in get_dataset_locks(parent_rule["scope"], parent_rule["name"]):
|
|
88
|
+
lock_rse_expr = lock["rse"]
|
|
89
|
+
if lock_rse_expr == rse_expression:
|
|
90
|
+
concurrent_replica = True
|
|
91
|
+
|
|
92
|
+
if concurrent_replica:
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
child_rule = add_rule(
|
|
96
|
+
dids=[{"scope": parent_rule["scope"], "name": parent_rule["name"]}],
|
|
97
|
+
account=parent_rule["account"],
|
|
98
|
+
copies=parent_rule["copies"],
|
|
99
|
+
rse_expression=rse_expression,
|
|
100
|
+
grouping=grouping,
|
|
101
|
+
weight=parent_rule["weight"],
|
|
102
|
+
lifetime=lifetime,
|
|
103
|
+
locked=parent_rule["locked"],
|
|
104
|
+
subscription_id=parent_rule["subscription_id"],
|
|
105
|
+
source_replica_expression=source_replica_expression,
|
|
106
|
+
activity=activity,
|
|
107
|
+
notify=parent_rule["notification"],
|
|
108
|
+
purge_replicas=parent_rule["purge_replicas"],
|
|
109
|
+
ignore_availability=False,
|
|
110
|
+
comment=parent_rule["comments"] if not comment else comment,
|
|
111
|
+
ask_approval=False,
|
|
112
|
+
asynchronous=False,
|
|
113
|
+
ignore_account_limit=True,
|
|
114
|
+
priority=priority,
|
|
115
|
+
session=session,
|
|
116
|
+
)[0]
|
|
117
|
+
|
|
118
|
+
update_rule(
|
|
119
|
+
rule_id=parent_rule["id"],
|
|
120
|
+
options={"child_rule_id": child_rule, "lifetime": 0},
|
|
121
|
+
session=session,
|
|
122
|
+
)
|
|
123
|
+
return child_rule
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def __dump_url(
|
|
127
|
+
rse_id: str,
|
|
128
|
+
logger: "LoggerFunction" = logging.log
|
|
129
|
+
) -> Union[list[str], Literal[False]]:
|
|
130
|
+
"""
|
|
131
|
+
getting potential urls of the dump over last week
|
|
132
|
+
:param rse_id: RSE where the dump is released.
|
|
133
|
+
:param logger: Logger.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
rse = get_rse_name(rse_id=rse_id)
|
|
137
|
+
vo = get_rse_vo(rse_id=rse_id)
|
|
138
|
+
|
|
139
|
+
# get the date of the most recent dump
|
|
140
|
+
today = date.today()
|
|
141
|
+
dump_dates = []
|
|
142
|
+
dump_production_day = config_get(
|
|
143
|
+
"bb8", "dump_production_day", raise_exception=False, default=None
|
|
144
|
+
)
|
|
145
|
+
if dump_production_day is None:
|
|
146
|
+
for idx in range(0, 7):
|
|
147
|
+
dump_date = today - timedelta(idx)
|
|
148
|
+
dump_dates.append(dump_date.strftime("%d-%m-%Y"))
|
|
149
|
+
else:
|
|
150
|
+
weekdays = {
|
|
151
|
+
"Sunday": 6,
|
|
152
|
+
"Monday": 0,
|
|
153
|
+
"Tuesday": 1,
|
|
154
|
+
"Wednesday": 2,
|
|
155
|
+
"Thursday": 3,
|
|
156
|
+
"Friday": 4,
|
|
157
|
+
"Saturday": 5,
|
|
158
|
+
}
|
|
159
|
+
if dump_production_day not in weekdays:
|
|
160
|
+
logger(
|
|
161
|
+
logging.WARNING,
|
|
162
|
+
"ERROR: please set the day of a dump creation in bb8 config correctly, e.g. Monday",
|
|
163
|
+
)
|
|
164
|
+
return False
|
|
165
|
+
today_idx = (today.weekday() - weekdays[dump_production_day]) % 7
|
|
166
|
+
dump_date = today - timedelta(today_idx)
|
|
167
|
+
dump_dates = [dump_date.strftime("%d-%m-%Y")]
|
|
168
|
+
|
|
169
|
+
# getting structure (template) of url location of a dump
|
|
170
|
+
url_template_str = config_get(
|
|
171
|
+
"bb8",
|
|
172
|
+
"dump_url_template",
|
|
173
|
+
raise_exception=False,
|
|
174
|
+
)
|
|
175
|
+
url_template = Template(url_template_str)
|
|
176
|
+
|
|
177
|
+
# populating url template
|
|
178
|
+
urls = []
|
|
179
|
+
for d in dump_dates:
|
|
180
|
+
url = url_template.substitute({"date": d, "rse": rse, "vo": vo})
|
|
181
|
+
urls.append(url)
|
|
182
|
+
return urls
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _list_rebalance_rule_candidates_dump(
|
|
186
|
+
rse_id: str,
|
|
187
|
+
mode: Optional[str] = None,
|
|
188
|
+
logger: "LoggerFunction" = logging.log
|
|
189
|
+
) -> list[tuple]:
|
|
190
|
+
"""
|
|
191
|
+
Download dump to temporary directory
|
|
192
|
+
:param rse_id: RSE of the source.
|
|
193
|
+
:param mode: Rebalancing mode.
|
|
194
|
+
:param logger: Logger.
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
# fetching the dump
|
|
198
|
+
candidates = []
|
|
199
|
+
rules = {}
|
|
200
|
+
rse_dump_urls = __dump_url(rse_id=rse_id)
|
|
201
|
+
resp = None
|
|
202
|
+
if not rse_dump_urls:
|
|
203
|
+
logger(logging.DEBUG, "URL of the dump was not built from template.")
|
|
204
|
+
return candidates
|
|
205
|
+
rse_dump_urls.reverse()
|
|
206
|
+
success = False
|
|
207
|
+
while not success and len(rse_dump_urls):
|
|
208
|
+
url = rse_dump_urls.pop()
|
|
209
|
+
resp = get(url, stream=True)
|
|
210
|
+
if resp:
|
|
211
|
+
success = True
|
|
212
|
+
if not resp or resp is None:
|
|
213
|
+
logger(logging.WARNING, "RSE dump not available")
|
|
214
|
+
return candidates
|
|
215
|
+
|
|
216
|
+
# looping over the dump and selecting the rules
|
|
217
|
+
for line in resp.iter_lines():
|
|
218
|
+
if line:
|
|
219
|
+
_, _, rule_id, rse_expression, account, file_size, state = line.split("\t")
|
|
220
|
+
if rule_id not in rules:
|
|
221
|
+
rule_info = {}
|
|
222
|
+
try:
|
|
223
|
+
rule_info = get_rule(rule_id=rule_id)
|
|
224
|
+
except Exception as err:
|
|
225
|
+
rules[rule_id] = {"state": "DELETED"}
|
|
226
|
+
logger(logging.ERROR, str(err))
|
|
227
|
+
continue
|
|
228
|
+
if rule_info["child_rule_id"]:
|
|
229
|
+
rules[rule_id] = {"state": "DELETED"}
|
|
230
|
+
continue
|
|
231
|
+
rules[rule_id] = {
|
|
232
|
+
"scope": rule_info["scope"],
|
|
233
|
+
"name": rule_info["name"],
|
|
234
|
+
"rse_expression": rse_expression,
|
|
235
|
+
"subscription_id": rule_info["subscription_id"],
|
|
236
|
+
"length": 1,
|
|
237
|
+
"state": "ACTIVE",
|
|
238
|
+
"bytes": int(file_size),
|
|
239
|
+
}
|
|
240
|
+
elif rules[rule_id]["state"] == "ACTIVE":
|
|
241
|
+
rules[rule_id]["length"] += 1
|
|
242
|
+
rules[rule_id]["bytes"] += int(file_size)
|
|
243
|
+
|
|
244
|
+
# looping over agragated rules collected from dump
|
|
245
|
+
for r_id in rules:
|
|
246
|
+
if mode == "decommission": # other modes can be added later
|
|
247
|
+
if rules[r_id]["state"] == "DELETED":
|
|
248
|
+
continue
|
|
249
|
+
if int(rules[r_id]["length"]) == 0:
|
|
250
|
+
continue
|
|
251
|
+
candidates.append(
|
|
252
|
+
(
|
|
253
|
+
rules[r_id]["scope"],
|
|
254
|
+
rules[r_id]["name"],
|
|
255
|
+
r_id,
|
|
256
|
+
rules[r_id]["rse_expression"],
|
|
257
|
+
rules[r_id]["subscription_id"],
|
|
258
|
+
rules[r_id]["bytes"],
|
|
259
|
+
rules[r_id]["length"],
|
|
260
|
+
int(rules[r_id]["bytes"] / rules[r_id]["length"]),
|
|
261
|
+
)
|
|
262
|
+
)
|
|
263
|
+
return candidates
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@transactional_session
|
|
267
|
+
def list_rebalance_rule_candidates(
|
|
268
|
+
rse_id: str,
|
|
269
|
+
mode: Optional[str] = None,
|
|
270
|
+
*,
|
|
271
|
+
session: Optional[Session] = None
|
|
272
|
+
) -> Union[list[tuple], list["Row[tuple]"]]:
|
|
273
|
+
"""
|
|
274
|
+
List the rebalance rule candidates based on the agreed on specification
|
|
275
|
+
:param rse_id: RSE of the source.
|
|
276
|
+
:param mode: Rebalancing mode.
|
|
277
|
+
:param session: DB Session.
|
|
278
|
+
"""
|
|
279
|
+
|
|
280
|
+
vo = get_rse_vo(rse_id=rse_id)
|
|
281
|
+
|
|
282
|
+
# dumps can be applied only for decommission since the dumps doesn't contain info from dids
|
|
283
|
+
if mode == "decommission":
|
|
284
|
+
return _list_rebalance_rule_candidates_dump(rse_id, mode)
|
|
285
|
+
|
|
286
|
+
# If no decommissioning use SQLAlchemy
|
|
287
|
+
|
|
288
|
+
# Rules constraints. By default only moves rules in state OK that have no children and have only one copy
|
|
289
|
+
# Additional constraints can be imposed by setting specific configuration
|
|
290
|
+
rule_clause = [
|
|
291
|
+
models.ReplicationRule.state == RuleState.OK,
|
|
292
|
+
models.ReplicationRule.child_rule_id.is_(None),
|
|
293
|
+
models.ReplicationRule.copies == 1,
|
|
294
|
+
]
|
|
295
|
+
|
|
296
|
+
# Only move rules w/o expiration date, or rules with expiration_date > >min_expires_date_in_days> days
|
|
297
|
+
expiration_clause = models.ReplicationRule.expires_at.is_(None)
|
|
298
|
+
min_expires_date_in_days = config_get_int(
|
|
299
|
+
section="bb8",
|
|
300
|
+
option="min_expires_date_in_days",
|
|
301
|
+
raise_exception=False,
|
|
302
|
+
default=-1,
|
|
303
|
+
expiration_time=3600,
|
|
304
|
+
)
|
|
305
|
+
if min_expires_date_in_days > 0:
|
|
306
|
+
min_expires_date_in_days = datetime.utcnow() + timedelta(
|
|
307
|
+
days=min_expires_date_in_days
|
|
308
|
+
)
|
|
309
|
+
expiration_clause = or_(models.ReplicationRule.expires_at > min_expires_date_in_days,
|
|
310
|
+
models.ReplicationRule.expires_at.is_(None))
|
|
311
|
+
rule_clause.append(expiration_clause)
|
|
312
|
+
|
|
313
|
+
# Only move rules which were created more than <min_created_days> days ago
|
|
314
|
+
min_created_days = config_get_int(
|
|
315
|
+
section="bb8",
|
|
316
|
+
option="min_created_days",
|
|
317
|
+
raise_exception=False,
|
|
318
|
+
default=-1,
|
|
319
|
+
expiration_time=3600,
|
|
320
|
+
)
|
|
321
|
+
if min_created_days > 0:
|
|
322
|
+
min_created_days = datetime.utcnow() - timedelta(days=min_created_days)
|
|
323
|
+
rule_clause.append(models.ReplicationRule.created_at < min_created_days)
|
|
324
|
+
|
|
325
|
+
# Only move rules which are owned by <allowed_accounts> (coma separated accounts, e.g. panda,root,ddmadmin,jdoe)
|
|
326
|
+
allowed_accounts = config_get(
|
|
327
|
+
section="bb8",
|
|
328
|
+
option="allowed_accounts",
|
|
329
|
+
raise_exception=False,
|
|
330
|
+
default=None,
|
|
331
|
+
expiration_time=3600,
|
|
332
|
+
)
|
|
333
|
+
if allowed_accounts:
|
|
334
|
+
allowed_accounts = [
|
|
335
|
+
InternalAccount(acc.strip(" "), vo=vo)
|
|
336
|
+
for acc in allowed_accounts.split(",")
|
|
337
|
+
]
|
|
338
|
+
rule_clause.append(models.ReplicationRule.account.in_(allowed_accounts))
|
|
339
|
+
|
|
340
|
+
# Only move rules which with scope <allowed_scopes> (coma separated scopes, e.g. mc16_13TeV,data18_13TeV)
|
|
341
|
+
allowed_scopes = config_get(
|
|
342
|
+
section="bb8",
|
|
343
|
+
option="allowed_scopes",
|
|
344
|
+
raise_exception=False,
|
|
345
|
+
default=None,
|
|
346
|
+
expiration_time=3600,
|
|
347
|
+
)
|
|
348
|
+
if allowed_scopes:
|
|
349
|
+
allowed_scopes = [
|
|
350
|
+
InternalScope(scope.strip(" "), vo=vo)
|
|
351
|
+
for scope in allowed_scopes.split(",")
|
|
352
|
+
]
|
|
353
|
+
rule_clause.append(models.ReplicationRule.scope.in_(allowed_scopes))
|
|
354
|
+
|
|
355
|
+
# Only move rules that have a certain grouping <allowed_grouping> (accepted values : all, dataset, none)
|
|
356
|
+
rule_grouping_mapping = {
|
|
357
|
+
"all": RuleGrouping.ALL,
|
|
358
|
+
"dataset": RuleGrouping.DATASET,
|
|
359
|
+
"none": RuleGrouping.NONE,
|
|
360
|
+
}
|
|
361
|
+
allowed_grouping = config_get(
|
|
362
|
+
section="bb8",
|
|
363
|
+
option="allowed_grouping",
|
|
364
|
+
raise_exception=False,
|
|
365
|
+
default=None,
|
|
366
|
+
expiration_time=3600,
|
|
367
|
+
)
|
|
368
|
+
if allowed_grouping:
|
|
369
|
+
rule_clause.append(
|
|
370
|
+
models.ReplicationRule.grouping
|
|
371
|
+
== rule_grouping_mapping.get(allowed_grouping)
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
# DIDs constraints. By default only moves rules of DID where we can compute the size
|
|
375
|
+
# Additional constraints can be imposed by setting specific configuration
|
|
376
|
+
did_clause = [models.DataIdentifier.bytes.isnot(None)]
|
|
377
|
+
|
|
378
|
+
type_to_did_type_mapping = {
|
|
379
|
+
"all": [DIDType.CONTAINER, DIDType.DATASET, DIDType.FILE],
|
|
380
|
+
"collection": [DIDType.CONTAINER, DIDType.DATASET],
|
|
381
|
+
"container": [DIDType.CONTAINER],
|
|
382
|
+
"dataset": [DIDType.DATASET],
|
|
383
|
+
"file": [DIDType.FILE],
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
# Only allows to migrate rules of a certain did_type <allowed_did_type> (accepted values : all, collection, container, dataset, file)
|
|
387
|
+
allowed_did_type = config_get(
|
|
388
|
+
section="bb8",
|
|
389
|
+
option="allowed_did_type",
|
|
390
|
+
raise_exception=False,
|
|
391
|
+
default=None,
|
|
392
|
+
expiration_time=3600,
|
|
393
|
+
)
|
|
394
|
+
if allowed_did_type:
|
|
395
|
+
allowed_did_type = [
|
|
396
|
+
models.DataIdentifier.did_type == did_type
|
|
397
|
+
for did_type in type_to_did_type_mapping.get(allowed_did_type)
|
|
398
|
+
]
|
|
399
|
+
did_clause.append(or_(*allowed_did_type))
|
|
400
|
+
|
|
401
|
+
# Only allows to migrate rules of closed DID is <only_move_closed_did> is set
|
|
402
|
+
only_move_closed_did = config_get_bool(
|
|
403
|
+
section="bb8",
|
|
404
|
+
option="only_move_closed_did",
|
|
405
|
+
raise_exception=False,
|
|
406
|
+
default=None,
|
|
407
|
+
expiration_time=3600,
|
|
408
|
+
)
|
|
409
|
+
if only_move_closed_did:
|
|
410
|
+
did_clause.append(models.DataIdentifier.is_open == false())
|
|
411
|
+
|
|
412
|
+
# Now build the query
|
|
413
|
+
external_dsl = aliased(models.DatasetLock)
|
|
414
|
+
count_locks = select(
|
|
415
|
+
func.count()
|
|
416
|
+
).select_from(
|
|
417
|
+
models.DatasetLock
|
|
418
|
+
).where(
|
|
419
|
+
and_(external_dsl.scope == models.DatasetLock.scope,
|
|
420
|
+
external_dsl.name == models.DatasetLock.name,
|
|
421
|
+
external_dsl.rse_id == models.DatasetLock.rse_id)
|
|
422
|
+
).scalar_subquery()
|
|
423
|
+
|
|
424
|
+
stmt = select(
|
|
425
|
+
models.DatasetLock.scope,
|
|
426
|
+
models.DatasetLock.name,
|
|
427
|
+
models.ReplicationRule.id,
|
|
428
|
+
models.ReplicationRule.rse_expression,
|
|
429
|
+
models.ReplicationRule.subscription_id,
|
|
430
|
+
models.DataIdentifier.bytes,
|
|
431
|
+
models.DataIdentifier.length,
|
|
432
|
+
case(
|
|
433
|
+
(
|
|
434
|
+
or_(models.DatasetLock.length < 1,
|
|
435
|
+
models.DatasetLock.length.is_(None)),
|
|
436
|
+
0
|
|
437
|
+
),
|
|
438
|
+
else_=cast(
|
|
439
|
+
models.DatasetLock.bytes / models.DatasetLock.length, BigInteger
|
|
440
|
+
)
|
|
441
|
+
)
|
|
442
|
+
).join(
|
|
443
|
+
models.ReplicationRule,
|
|
444
|
+
models.ReplicationRule.id == models.DatasetLock.rule_id
|
|
445
|
+
).join(
|
|
446
|
+
models.DataIdentifier,
|
|
447
|
+
and_(models.DatasetLock.scope == models.DataIdentifier.scope,
|
|
448
|
+
models.DatasetLock.name == models.DataIdentifier.name)
|
|
449
|
+
).where(
|
|
450
|
+
and_(models.DatasetLock.rse_id == rse_id,
|
|
451
|
+
*rule_clause,
|
|
452
|
+
*did_clause,
|
|
453
|
+
case(
|
|
454
|
+
(
|
|
455
|
+
or_(models.DatasetLock.length < 1,
|
|
456
|
+
models.DatasetLock.length.is_(None)),
|
|
457
|
+
0
|
|
458
|
+
),
|
|
459
|
+
else_=cast(
|
|
460
|
+
models.DatasetLock.bytes / models.DatasetLock.length, BigInteger
|
|
461
|
+
)
|
|
462
|
+
) > 1000000000,
|
|
463
|
+
count_locks == 1)
|
|
464
|
+
).order_by(
|
|
465
|
+
case(
|
|
466
|
+
(
|
|
467
|
+
or_(models.DatasetLock.length < 1,
|
|
468
|
+
models.DatasetLock.length.is_(None)),
|
|
469
|
+
0
|
|
470
|
+
),
|
|
471
|
+
else_=cast(
|
|
472
|
+
models.DatasetLock.bytes / models.DatasetLock.length, BigInteger
|
|
473
|
+
)
|
|
474
|
+
),
|
|
475
|
+
models.DatasetLock.accessed_at
|
|
476
|
+
)
|
|
477
|
+
return list(session.execute(stmt).all()) # type: ignore (session could be None)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
@read_session
|
|
481
|
+
def select_target_rse(
|
|
482
|
+
parent_rule: "Mapping[str, Any]",
|
|
483
|
+
current_rse_id: str,
|
|
484
|
+
rse_expression: str,
|
|
485
|
+
subscription_id: str,
|
|
486
|
+
rse_attributes: "Mapping[str, Any]",
|
|
487
|
+
other_rses: Optional["Sequence[str]"] = None,
|
|
488
|
+
exclude_expression: Optional[str] = None,
|
|
489
|
+
force_expression: Optional[str] = None,
|
|
490
|
+
*,
|
|
491
|
+
session: Optional[Session] = None,
|
|
492
|
+
) -> str:
|
|
493
|
+
"""
|
|
494
|
+
Select a new target RSE for a rebalanced rule.
|
|
495
|
+
:param parent_rule rule that is rebalanced.
|
|
496
|
+
:param current_rse_id: RSE of the source.
|
|
497
|
+
:param rse_expression: RSE Expression of the source rule.
|
|
498
|
+
:param subscription_id: Subscription ID of the source rule.
|
|
499
|
+
:param rse_attributes: The attributes of the source rse.
|
|
500
|
+
:param other_rses: Other RSEs with existing dataset replicas.
|
|
501
|
+
:param exclude_expression: Exclude this rse_expression from being target_rses.
|
|
502
|
+
:param force_expression: Force a specific rse_expression as target.
|
|
503
|
+
:param session: The DB Session.
|
|
504
|
+
:returns: New RSE expression.
|
|
505
|
+
"""
|
|
506
|
+
|
|
507
|
+
other_rses = other_rses or []
|
|
508
|
+
current_rse = get_rse_name(rse_id=current_rse_id)
|
|
509
|
+
current_rse_expr = current_rse
|
|
510
|
+
# if parent rule has a vo, enforce it
|
|
511
|
+
vo = parent_rule["scope"].vo
|
|
512
|
+
if exclude_expression:
|
|
513
|
+
target_rse = "((%s)|(%s))" % (exclude_expression, current_rse_expr)
|
|
514
|
+
else:
|
|
515
|
+
target_rse = current_rse_expr
|
|
516
|
+
list_target_rses = [
|
|
517
|
+
rse["rse"]
|
|
518
|
+
for rse in parse_expression(
|
|
519
|
+
expression=target_rse, filter_={"vo": vo}, session=session
|
|
520
|
+
)
|
|
521
|
+
]
|
|
522
|
+
list_target_rses.sort()
|
|
523
|
+
|
|
524
|
+
rses = parse_expression(
|
|
525
|
+
expression=rse_expression, filter_={"vo": vo}, session=session
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
# TODO: Implement subscription rebalancing
|
|
529
|
+
|
|
530
|
+
if force_expression is not None:
|
|
531
|
+
if parent_rule["grouping"] != RuleGrouping.NONE:
|
|
532
|
+
rses = parse_expression(
|
|
533
|
+
expression="(%s)\\%s" % (force_expression, target_rse),
|
|
534
|
+
filter_={"vo": vo, "availability_write": True},
|
|
535
|
+
session=session,
|
|
536
|
+
)
|
|
537
|
+
else:
|
|
538
|
+
# in order to avoid replication of the part of distributed dataset not present at rebalanced rse -> rses in force_expression
|
|
539
|
+
# this will be extended with development of delayed rule
|
|
540
|
+
rses = parse_expression(
|
|
541
|
+
expression="((%s)|(%s))\\%s"
|
|
542
|
+
% (force_expression, rse_expression, target_rse),
|
|
543
|
+
filter_={"vo": vo, "availability_write": True},
|
|
544
|
+
session=session,
|
|
545
|
+
)
|
|
546
|
+
else:
|
|
547
|
+
# force_expression is not set, RSEs will be selected as rse_expression\rse
|
|
548
|
+
list_rses = [rse["rse"] for rse in rses]
|
|
549
|
+
list_rses.sort()
|
|
550
|
+
if list_rses == list_target_rses:
|
|
551
|
+
raise InsufficientTargetRSEs(
|
|
552
|
+
"Not enough RSEs to rebalance rule %s" % parent_rule["id"]
|
|
553
|
+
)
|
|
554
|
+
else:
|
|
555
|
+
rses = parse_expression(
|
|
556
|
+
expression="(%s)\\%s" % (rse_expression, target_rse),
|
|
557
|
+
filter_={"vo": vo, "availability_write": True},
|
|
558
|
+
session=session,
|
|
559
|
+
)
|
|
560
|
+
rseselector = RSESelector(
|
|
561
|
+
account=InternalAccount("root", vo=vo),
|
|
562
|
+
rses=rses,
|
|
563
|
+
weight="freespace",
|
|
564
|
+
copies=1,
|
|
565
|
+
ignore_account_limit=True,
|
|
566
|
+
session=session,
|
|
567
|
+
)
|
|
568
|
+
return get_rse_name(
|
|
569
|
+
[
|
|
570
|
+
rse_id
|
|
571
|
+
for rse_id, _, _ in rseselector.select_rse(
|
|
572
|
+
size=0, preferred_rse_ids=[], blocklist=other_rses
|
|
573
|
+
)
|
|
574
|
+
][0],
|
|
575
|
+
session=session,
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
@transactional_session
|
|
580
|
+
def rebalance_rse(
|
|
581
|
+
rse_id: str,
|
|
582
|
+
max_bytes: float = 1e9,
|
|
583
|
+
max_files: Optional[int] = None,
|
|
584
|
+
dry_run: bool = False,
|
|
585
|
+
exclude_expression: Optional[str] = None,
|
|
586
|
+
comment: Optional[str] = None,
|
|
587
|
+
force_expression: Optional[str] = None,
|
|
588
|
+
mode: Optional[str] = None,
|
|
589
|
+
priority: int = 3,
|
|
590
|
+
source_replica_expression: str = "*\\bb8-enabled=false",
|
|
591
|
+
*,
|
|
592
|
+
session: Optional[Session] = None,
|
|
593
|
+
logger: "LoggerFunction" = logging.log,
|
|
594
|
+
) -> list[tuple]:
|
|
595
|
+
"""
|
|
596
|
+
Rebalance data from an RSE
|
|
597
|
+
:param rse_id: RSE to rebalance data from.
|
|
598
|
+
:param max_bytes: Maximum amount of bytes to rebalance.
|
|
599
|
+
:param max_files: Maximum amount of files to rebalance.
|
|
600
|
+
:param dry_run: Only run in dry-run mode.
|
|
601
|
+
:param exclude_expression: Exclude this rse_expression from being target_rses.
|
|
602
|
+
:param comment: Comment to set on the new rules.
|
|
603
|
+
:param force_expression: Force a specific rse_expression as target.
|
|
604
|
+
:param mode: BB8 mode to execute (None=normal, 'decomission'=Decomission mode)
|
|
605
|
+
:param priority: Priority of the new created rules.
|
|
606
|
+
:param source_replica_expression: Source replica expression of the new created rules.
|
|
607
|
+
:param session: The database session.
|
|
608
|
+
:param logger: Logger.
|
|
609
|
+
:returns: List of rebalanced datasets.
|
|
610
|
+
"""
|
|
611
|
+
rebalanced_bytes = 0
|
|
612
|
+
rebalanced_files = 0
|
|
613
|
+
rebalanced_datasets = []
|
|
614
|
+
|
|
615
|
+
rse_attributes = list_rse_attributes(rse_id=rse_id, session=session)
|
|
616
|
+
src_rse = get_rse_name(rse_id=rse_id)
|
|
617
|
+
|
|
618
|
+
logger(logging.INFO, "***************************")
|
|
619
|
+
logger(logging.INFO, "BB8 - Execution Summary")
|
|
620
|
+
logger(logging.INFO, "Mode: %s" % ("STANDARD" if mode is None else mode.upper()))
|
|
621
|
+
logger(logging.INFO, "Dry Run: %s" % (dry_run))
|
|
622
|
+
logger(logging.INFO, "***************************")
|
|
623
|
+
|
|
624
|
+
for (
|
|
625
|
+
scope,
|
|
626
|
+
name,
|
|
627
|
+
rule_id,
|
|
628
|
+
rse_expression,
|
|
629
|
+
subscription_id,
|
|
630
|
+
bytes_,
|
|
631
|
+
length,
|
|
632
|
+
fsize,
|
|
633
|
+
) in list_rebalance_rule_candidates(rse_id=rse_id, mode=mode):
|
|
634
|
+
if force_expression is not None and subscription_id is not None:
|
|
635
|
+
continue
|
|
636
|
+
|
|
637
|
+
if rebalanced_bytes + bytes_ > max_bytes:
|
|
638
|
+
continue
|
|
639
|
+
if max_files:
|
|
640
|
+
if rebalanced_files + length > max_files:
|
|
641
|
+
continue
|
|
642
|
+
|
|
643
|
+
try:
|
|
644
|
+
rule = get_rule(rule_id=rule_id)
|
|
645
|
+
other_rses = [
|
|
646
|
+
r["rse_id"] for r in get_dataset_locks(scope, name, session=session)
|
|
647
|
+
]
|
|
648
|
+
# Select the target RSE for this rule
|
|
649
|
+
try:
|
|
650
|
+
target_rse_exp = select_target_rse(
|
|
651
|
+
parent_rule=rule,
|
|
652
|
+
current_rse_id=rse_id,
|
|
653
|
+
rse_expression=rse_expression,
|
|
654
|
+
subscription_id=subscription_id,
|
|
655
|
+
rse_attributes=rse_attributes,
|
|
656
|
+
other_rses=other_rses,
|
|
657
|
+
exclude_expression=exclude_expression,
|
|
658
|
+
force_expression=force_expression,
|
|
659
|
+
session=session,
|
|
660
|
+
)
|
|
661
|
+
# Rebalance this rule
|
|
662
|
+
if not dry_run:
|
|
663
|
+
child_rule_id = rebalance_rule(
|
|
664
|
+
parent_rule=rule,
|
|
665
|
+
activity="Data Rebalancing",
|
|
666
|
+
rse_expression=target_rse_exp,
|
|
667
|
+
priority=priority,
|
|
668
|
+
source_replica_expression=source_replica_expression,
|
|
669
|
+
comment=comment,
|
|
670
|
+
)
|
|
671
|
+
else:
|
|
672
|
+
child_rule_id = ""
|
|
673
|
+
except (
|
|
674
|
+
InsufficientTargetRSEs,
|
|
675
|
+
DuplicateRule,
|
|
676
|
+
RuleNotFound,
|
|
677
|
+
InsufficientAccountLimit,
|
|
678
|
+
) as err:
|
|
679
|
+
logger(logging.ERROR, str(err))
|
|
680
|
+
continue
|
|
681
|
+
if child_rule_id is None:
|
|
682
|
+
logger(
|
|
683
|
+
logging.WARNING,
|
|
684
|
+
"A rule for %s:%s already exists on %s. It cannot be rebalanced",
|
|
685
|
+
scope,
|
|
686
|
+
name,
|
|
687
|
+
target_rse_exp,
|
|
688
|
+
)
|
|
689
|
+
continue
|
|
690
|
+
logger(
|
|
691
|
+
logging.INFO,
|
|
692
|
+
"Rebalancing %s:%s rule %s (%f GB) from %s to %s. New rule %s",
|
|
693
|
+
scope,
|
|
694
|
+
name,
|
|
695
|
+
str(rule_id),
|
|
696
|
+
bytes_ / 1e9,
|
|
697
|
+
rule["rse_expression"],
|
|
698
|
+
target_rse_exp,
|
|
699
|
+
child_rule_id,
|
|
700
|
+
)
|
|
701
|
+
rebalanced_bytes += bytes_
|
|
702
|
+
rebalanced_files += length
|
|
703
|
+
rebalanced_datasets.append(
|
|
704
|
+
(scope, name, bytes_, length, target_rse_exp, rule_id, child_rule_id)
|
|
705
|
+
)
|
|
706
|
+
except Exception as error:
|
|
707
|
+
logger(
|
|
708
|
+
logging.ERROR,
|
|
709
|
+
"Exception %s occurred while rebalancing %s:%s, rule_id: %s!",
|
|
710
|
+
str(error),
|
|
711
|
+
scope,
|
|
712
|
+
name,
|
|
713
|
+
str(rule_id),
|
|
714
|
+
)
|
|
715
|
+
|
|
716
|
+
logger(
|
|
717
|
+
logging.INFO,
|
|
718
|
+
"BB8 is rebalancing %d GB of data (%d rules) from %s",
|
|
719
|
+
rebalanced_bytes / 1e9,
|
|
720
|
+
len(rebalanced_datasets),
|
|
721
|
+
src_rse,
|
|
722
|
+
)
|
|
723
|
+
return rebalanced_datasets
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
@read_session
|
|
727
|
+
def get_active_locks(
|
|
728
|
+
*,
|
|
729
|
+
session: Optional[Session] = None
|
|
730
|
+
) -> dict[str, dict[str, int]]:
|
|
731
|
+
locks_dict: dict[str, dict[str, int]] = {}
|
|
732
|
+
stmt = select(
|
|
733
|
+
models.ReplicationRule.id
|
|
734
|
+
).where(
|
|
735
|
+
and_(or_(models.ReplicationRule.state == RuleState.REPLICATING,
|
|
736
|
+
models.ReplicationRule.state == RuleState.STUCK),
|
|
737
|
+
models.ReplicationRule.comments == "Background rebalancing")
|
|
738
|
+
)
|
|
739
|
+
for rule_id in session.execute(stmt).scalars().all(): # type: ignore (session could be None)
|
|
740
|
+
stmt = select(
|
|
741
|
+
func.count(),
|
|
742
|
+
func.sum(models.ReplicaLock.bytes),
|
|
743
|
+
models.ReplicaLock.state,
|
|
744
|
+
models.ReplicaLock.rse_id
|
|
745
|
+
).select_from(
|
|
746
|
+
models.ReplicaLock
|
|
747
|
+
).where(
|
|
748
|
+
and_(models.ReplicaLock.rule_id == rule_id,
|
|
749
|
+
models.ReplicaLock.state != LockState.OK)
|
|
750
|
+
).group_by(
|
|
751
|
+
models.ReplicaLock.state,
|
|
752
|
+
models.ReplicaLock.rse_id
|
|
753
|
+
)
|
|
754
|
+
for cnt, size, _, rse_id in session.execute(stmt).all(): # type: ignore (session could be None)
|
|
755
|
+
if rse_id not in locks_dict:
|
|
756
|
+
locks_dict[rse_id] = {"bytes": 0, "locks": 0}
|
|
757
|
+
locks_dict[rse_id]["locks"] += cnt
|
|
758
|
+
locks_dict[rse_id]["bytes"] += size
|
|
759
|
+
return locks_dict
|