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,529 @@
|
|
|
1
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
Conveyor finisher is a daemon to update replicas and rules based on requests.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import datetime
|
|
20
|
+
import functools
|
|
21
|
+
import logging
|
|
22
|
+
import os
|
|
23
|
+
import re
|
|
24
|
+
import threading
|
|
25
|
+
from typing import TYPE_CHECKING, Any, Literal, Optional
|
|
26
|
+
from urllib.parse import urlparse
|
|
27
|
+
|
|
28
|
+
from dogpile.cache.api import NoValue
|
|
29
|
+
from sqlalchemy.exc import DatabaseError
|
|
30
|
+
|
|
31
|
+
import rucio.db.sqla.util
|
|
32
|
+
from rucio.common.cache import MemcacheRegion
|
|
33
|
+
from rucio.common.config import config_get_bool, config_get_list
|
|
34
|
+
from rucio.common.exception import DatabaseException, ReplicaNotFound, RequestNotFound, RSEProtocolNotSupported, UnsupportedOperation
|
|
35
|
+
from rucio.common.logging import setup_logging
|
|
36
|
+
from rucio.common.stopwatch import Stopwatch
|
|
37
|
+
from rucio.common.types import InternalAccount, LoggerFunction, RequestDict
|
|
38
|
+
from rucio.common.utils import chunks
|
|
39
|
+
from rucio.core import replica as replica_core
|
|
40
|
+
from rucio.core import request as request_core
|
|
41
|
+
from rucio.core.monitor import MetricManager
|
|
42
|
+
from rucio.core.rse import list_rses
|
|
43
|
+
from rucio.core.topology import ExpiringObjectCache, Topology
|
|
44
|
+
from rucio.core.transfer import ProtocolFactory
|
|
45
|
+
from rucio.daemons.common import ProducerConsumerDaemon, db_workqueue
|
|
46
|
+
from rucio.db.sqla.constants import MYSQL_LOCK_WAIT_TIMEOUT_EXCEEDED, ORACLE_DEADLOCK_DETECTED_REGEX, ORACLE_RESOURCE_BUSY_REGEX, BadFilesStatus, ReplicaState, RequestState, RequestType
|
|
47
|
+
from rucio.db.sqla.session import transactional_session
|
|
48
|
+
|
|
49
|
+
if TYPE_CHECKING:
|
|
50
|
+
from types import FrameType
|
|
51
|
+
|
|
52
|
+
from sqlalchemy.orm import Session
|
|
53
|
+
|
|
54
|
+
from rucio.daemons.common import HeartbeatHandler
|
|
55
|
+
|
|
56
|
+
GRACEFUL_STOP = threading.Event()
|
|
57
|
+
|
|
58
|
+
REGION = MemcacheRegion(expiration_time=900)
|
|
59
|
+
METRICS = MetricManager(module=__name__)
|
|
60
|
+
DAEMON_NAME = 'conveyor-finisher'
|
|
61
|
+
FAILED_DURING_SUBMISSION_DELAY = datetime.timedelta(minutes=120)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _fetch_requests(
|
|
65
|
+
db_bulk: int,
|
|
66
|
+
set_last_processed_by: bool,
|
|
67
|
+
cached_topology: Optional[ExpiringObjectCache],
|
|
68
|
+
heartbeat_handler: "HeartbeatHandler",
|
|
69
|
+
activity: str,
|
|
70
|
+
) -> tuple[bool, tuple[list[dict[str, Any]], Topology]]:
|
|
71
|
+
worker_number, total_workers, logger = heartbeat_handler.live()
|
|
72
|
+
|
|
73
|
+
logger(logging.DEBUG, 'Working on activity %s', activity)
|
|
74
|
+
|
|
75
|
+
topology = cached_topology.get() if cached_topology else Topology()
|
|
76
|
+
|
|
77
|
+
get_requests_fnc = functools.partial(
|
|
78
|
+
request_core.get_and_mark_next,
|
|
79
|
+
rse_collection=topology,
|
|
80
|
+
request_type=[RequestType.TRANSFER, RequestType.STAGEIN, RequestType.STAGEOUT],
|
|
81
|
+
processed_by=heartbeat_handler.short_executable if set_last_processed_by else None,
|
|
82
|
+
limit=db_bulk,
|
|
83
|
+
total_workers=total_workers,
|
|
84
|
+
worker_number=worker_number,
|
|
85
|
+
mode_all=True,
|
|
86
|
+
include_dependent=False,
|
|
87
|
+
hash_variable='rule_id',
|
|
88
|
+
)
|
|
89
|
+
reqs = get_requests_fnc(
|
|
90
|
+
state=[
|
|
91
|
+
RequestState.DONE,
|
|
92
|
+
RequestState.FAILED,
|
|
93
|
+
RequestState.LOST,
|
|
94
|
+
RequestState.SUBMISSION_FAILED,
|
|
95
|
+
RequestState.NO_SOURCES,
|
|
96
|
+
RequestState.ONLY_TAPE_SOURCES,
|
|
97
|
+
RequestState.MISMATCH_SCHEME
|
|
98
|
+
],
|
|
99
|
+
)
|
|
100
|
+
reqs.extend(
|
|
101
|
+
get_requests_fnc(
|
|
102
|
+
state=[RequestState.SUBMITTING],
|
|
103
|
+
older_than=datetime.datetime.utcnow() - FAILED_DURING_SUBMISSION_DELAY
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
must_sleep = False
|
|
108
|
+
if len(reqs) < db_bulk / 2:
|
|
109
|
+
logger(logging.INFO, "Only %s transfers, which is less than half of the bulk %s", len(reqs), db_bulk)
|
|
110
|
+
must_sleep = True
|
|
111
|
+
return must_sleep, (reqs, topology)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _handle_requests(
|
|
115
|
+
batch: tuple[list[RequestDict], Topology],
|
|
116
|
+
bulk: int,
|
|
117
|
+
suspicious_patterns: list[re.Pattern],
|
|
118
|
+
retry_protocol_mismatches: bool,
|
|
119
|
+
*,
|
|
120
|
+
logger: LoggerFunction = logging.log,
|
|
121
|
+
) -> None:
|
|
122
|
+
reqs, topology = batch
|
|
123
|
+
if not reqs:
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
logger(logging.DEBUG, 'Updating %i requests', len(reqs))
|
|
128
|
+
|
|
129
|
+
total_stopwatch = Stopwatch()
|
|
130
|
+
|
|
131
|
+
for chunk in chunks(reqs, bulk):
|
|
132
|
+
try:
|
|
133
|
+
stopwatch = Stopwatch()
|
|
134
|
+
_finish_requests(topology, chunk, suspicious_patterns, retry_protocol_mismatches, logger=logger)
|
|
135
|
+
METRICS.timer('handle_requests_time').observe(stopwatch.elapsed / (len(chunk) or 1))
|
|
136
|
+
METRICS.counter('handle_requests').inc(len(chunk))
|
|
137
|
+
except Exception as error:
|
|
138
|
+
logger(logging.WARNING, '%s', str(error))
|
|
139
|
+
|
|
140
|
+
logger(logging.DEBUG, 'Finish to update %s finished requests in %s seconds', len(reqs), total_stopwatch.elapsed)
|
|
141
|
+
|
|
142
|
+
except (DatabaseException, DatabaseError) as error:
|
|
143
|
+
if re.match(ORACLE_RESOURCE_BUSY_REGEX, error.args[0]) or re.match(ORACLE_DEADLOCK_DETECTED_REGEX, error.args[0]) or MYSQL_LOCK_WAIT_TIMEOUT_EXCEEDED in error.args[0]:
|
|
144
|
+
logger(logging.WARNING, 'Lock detected when handling request - skipping: %s', str(error))
|
|
145
|
+
else:
|
|
146
|
+
raise
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def finisher(
|
|
150
|
+
once: bool = False,
|
|
151
|
+
sleep_time: int = 60,
|
|
152
|
+
activities: Optional[list[str]] = None,
|
|
153
|
+
bulk: int = 100,
|
|
154
|
+
db_bulk: int = 1000,
|
|
155
|
+
partition_wait_time: int = 10,
|
|
156
|
+
cached_topology: Optional[ExpiringObjectCache] = None,
|
|
157
|
+
total_threads: int = 1,
|
|
158
|
+
) -> None:
|
|
159
|
+
"""
|
|
160
|
+
Main loop to update the replicas and rules based on finished requests.
|
|
161
|
+
"""
|
|
162
|
+
# Get suspicious patterns
|
|
163
|
+
suspicious_patterns = config_get_list('conveyor', 'suspicious_pattern', default=[])
|
|
164
|
+
suspicious_patterns = [re.compile(pat.strip()) for pat in suspicious_patterns]
|
|
165
|
+
logging.log(logging.DEBUG, "Suspicious patterns: %s" % [pat.pattern for pat in suspicious_patterns])
|
|
166
|
+
|
|
167
|
+
retry_protocol_mismatches = config_get_bool('conveyor', 'retry_protocol_mismatches', default=False)
|
|
168
|
+
|
|
169
|
+
executable = DAEMON_NAME
|
|
170
|
+
if activities:
|
|
171
|
+
activities.sort()
|
|
172
|
+
executable += '--activities ' + str(activities)
|
|
173
|
+
|
|
174
|
+
@db_workqueue(
|
|
175
|
+
once=once,
|
|
176
|
+
graceful_stop=GRACEFUL_STOP,
|
|
177
|
+
executable=executable,
|
|
178
|
+
partition_wait_time=partition_wait_time,
|
|
179
|
+
sleep_time=sleep_time,
|
|
180
|
+
activities=activities,
|
|
181
|
+
)
|
|
182
|
+
def _db_producer(
|
|
183
|
+
*,
|
|
184
|
+
activity: str,
|
|
185
|
+
heartbeat_handler: "HeartbeatHandler"
|
|
186
|
+
) -> tuple[bool, tuple[list[dict[str, Any]], Topology]]:
|
|
187
|
+
return _fetch_requests(
|
|
188
|
+
db_bulk=db_bulk,
|
|
189
|
+
cached_topology=cached_topology,
|
|
190
|
+
activity=activity,
|
|
191
|
+
set_last_processed_by=not once,
|
|
192
|
+
heartbeat_handler=heartbeat_handler,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
def _consumer(batch: tuple[list[RequestDict], Topology]) -> None:
|
|
196
|
+
return _handle_requests(
|
|
197
|
+
batch=batch,
|
|
198
|
+
bulk=bulk,
|
|
199
|
+
suspicious_patterns=suspicious_patterns,
|
|
200
|
+
retry_protocol_mismatches=retry_protocol_mismatches,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
ProducerConsumerDaemon(
|
|
204
|
+
producers=[_db_producer],
|
|
205
|
+
consumers=[_consumer for _ in range(total_threads)],
|
|
206
|
+
graceful_stop=GRACEFUL_STOP,
|
|
207
|
+
).run()
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
|
|
211
|
+
"""
|
|
212
|
+
Graceful exit.
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
GRACEFUL_STOP.set()
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def run(
|
|
219
|
+
once: bool = False,
|
|
220
|
+
total_threads: int = 1,
|
|
221
|
+
sleep_time: int = 60,
|
|
222
|
+
activities: Optional[list[str]] = None,
|
|
223
|
+
bulk: int = 100,
|
|
224
|
+
db_bulk: int = 1000
|
|
225
|
+
) -> None:
|
|
226
|
+
"""
|
|
227
|
+
Starts up the conveyor threads.
|
|
228
|
+
"""
|
|
229
|
+
setup_logging(process_name=DAEMON_NAME)
|
|
230
|
+
|
|
231
|
+
if rucio.db.sqla.util.is_old_db():
|
|
232
|
+
raise DatabaseException('Database was not updated, daemon won\'t start')
|
|
233
|
+
|
|
234
|
+
cached_topology = ExpiringObjectCache(ttl=300, new_obj_fnc=lambda: Topology())
|
|
235
|
+
finisher(
|
|
236
|
+
once=once,
|
|
237
|
+
activities=activities,
|
|
238
|
+
bulk=bulk,
|
|
239
|
+
db_bulk=db_bulk,
|
|
240
|
+
sleep_time=sleep_time,
|
|
241
|
+
cached_topology=cached_topology,
|
|
242
|
+
total_threads=total_threads
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _finish_requests(
|
|
247
|
+
topology: Topology,
|
|
248
|
+
reqs: list[RequestDict],
|
|
249
|
+
suspicious_patterns: list[re.Pattern],
|
|
250
|
+
retry_protocol_mismatches: bool,
|
|
251
|
+
logger: LoggerFunction = logging.log
|
|
252
|
+
) -> None:
|
|
253
|
+
"""
|
|
254
|
+
Used by finisher to handle terminated requests,
|
|
255
|
+
|
|
256
|
+
:param reqs: List of requests.
|
|
257
|
+
:param suspicious_patterns: List of suspicious patterns.
|
|
258
|
+
:param retry_protocol_mismatches: Boolean to retry the transfer in case of protocol mismatch.
|
|
259
|
+
"""
|
|
260
|
+
|
|
261
|
+
failed_during_submission = [RequestState.SUBMITTING, RequestState.SUBMISSION_FAILED, RequestState.LOST]
|
|
262
|
+
failed_no_submission_attempts = [RequestState.NO_SOURCES, RequestState.ONLY_TAPE_SOURCES, RequestState.MISMATCH_SCHEME]
|
|
263
|
+
undeterministic_rses = __get_undeterministic_rses(logger=logger)
|
|
264
|
+
protocol_factory = ProtocolFactory()
|
|
265
|
+
replicas = {}
|
|
266
|
+
for req in reqs:
|
|
267
|
+
try:
|
|
268
|
+
replica = {'scope': req['scope'], 'name': req['name'], 'rse_id': req['dest_rse_id'], 'bytes': req['bytes'], 'adler32': req['adler32'], 'request_id': req['request_id']}
|
|
269
|
+
|
|
270
|
+
replica['pfn'] = req['dest_url']
|
|
271
|
+
replica['request_type'] = req['request_type']
|
|
272
|
+
replica['error_message'] = None
|
|
273
|
+
|
|
274
|
+
if req['request_type'] not in replicas:
|
|
275
|
+
replicas[req['request_type']] = {}
|
|
276
|
+
if req['rule_id'] not in replicas[req['request_type']]:
|
|
277
|
+
replicas[req['request_type']][req['rule_id']] = []
|
|
278
|
+
|
|
279
|
+
if req['state'] == RequestState.DONE:
|
|
280
|
+
replica['state'] = ReplicaState.AVAILABLE
|
|
281
|
+
replica['archived'] = False
|
|
282
|
+
|
|
283
|
+
# for TAPE, replica path is needed
|
|
284
|
+
if req['request_type'] in (RequestType.TRANSFER, RequestType.STAGEIN) and req['dest_rse_id'] in undeterministic_rses:
|
|
285
|
+
dst_rse = topology[req['dest_rse_id']].ensure_loaded(load_info=True)
|
|
286
|
+
pfn = req['dest_url']
|
|
287
|
+
scheme = urlparse(pfn).scheme
|
|
288
|
+
protocol = protocol_factory.protocol(dst_rse, scheme, 'write')
|
|
289
|
+
path = protocol.parse_pfns([pfn])[pfn]['path']
|
|
290
|
+
replica['path'] = os.path.join(path, os.path.basename(pfn))
|
|
291
|
+
|
|
292
|
+
# replica should not be added to replicas until all info are filled
|
|
293
|
+
replicas[req['request_type']][req['rule_id']].append(replica)
|
|
294
|
+
|
|
295
|
+
# Standard failure from the transfer tool
|
|
296
|
+
elif req['state'] == RequestState.FAILED:
|
|
297
|
+
__check_suspicious_files(req, suspicious_patterns, logger=logger)
|
|
298
|
+
try:
|
|
299
|
+
if request_core.should_retry_request(req, retry_protocol_mismatches):
|
|
300
|
+
new_req = request_core.requeue_and_archive(req, source_ranking_update=True, retry_protocol_mismatches=retry_protocol_mismatches, logger=logger)
|
|
301
|
+
# should_retry_request and requeue_and_archive are not in one session,
|
|
302
|
+
# another process can requeue_and_archive and this one will return None.
|
|
303
|
+
logger(logging.WARNING, 'REQUEUED DID %s:%s REQUEST %s AS %s TRY %s' % (req['scope'],
|
|
304
|
+
req['name'],
|
|
305
|
+
req['request_id'],
|
|
306
|
+
new_req['request_id'],
|
|
307
|
+
new_req['retry_count']))
|
|
308
|
+
else:
|
|
309
|
+
# No new_req is return if should_retry_request returns False
|
|
310
|
+
logger(logging.WARNING, 'EXCEEDED SUBMITTING DID %s:%s REQUEST %s in state %s', req['scope'], req['name'], req['request_id'], req['state'])
|
|
311
|
+
replica['state'] = ReplicaState.UNAVAILABLE
|
|
312
|
+
replica['archived'] = False
|
|
313
|
+
replica['error_message'] = req['err_msg'] if req['err_msg'] else request_core.get_transfer_error(req['state'])
|
|
314
|
+
replicas[req['request_type']][req['rule_id']].append(replica)
|
|
315
|
+
except RequestNotFound:
|
|
316
|
+
logger(logging.WARNING, 'Cannot find request %s anymore', req['request_id'])
|
|
317
|
+
|
|
318
|
+
# All other failures
|
|
319
|
+
elif req['state'] in failed_during_submission or req['state'] in failed_no_submission_attempts:
|
|
320
|
+
try:
|
|
321
|
+
if request_core.should_retry_request(req, retry_protocol_mismatches):
|
|
322
|
+
new_req = request_core.requeue_and_archive(req, source_ranking_update=False, retry_protocol_mismatches=retry_protocol_mismatches, logger=logger)
|
|
323
|
+
logger(logging.WARNING, 'REQUEUED SUBMITTING DID %s:%s REQUEST %s AS %s TRY %s' % (req['scope'],
|
|
324
|
+
req['name'],
|
|
325
|
+
req['request_id'],
|
|
326
|
+
new_req['request_id'],
|
|
327
|
+
new_req['retry_count']))
|
|
328
|
+
else:
|
|
329
|
+
# No new_req is return if should_retry_request returns False
|
|
330
|
+
logger(logging.WARNING, 'EXCEEDED SUBMITTING DID %s:%s REQUEST %s in state %s', req['scope'], req['name'], req['request_id'], req['state'])
|
|
331
|
+
replica['state'] = ReplicaState.UNAVAILABLE
|
|
332
|
+
replica['archived'] = False
|
|
333
|
+
replica['error_message'] = req['err_msg'] if req['err_msg'] else request_core.get_transfer_error(req['state'])
|
|
334
|
+
replicas[req['request_type']][req['rule_id']].append(replica)
|
|
335
|
+
except RequestNotFound:
|
|
336
|
+
logger(logging.WARNING, 'Cannot find request %s anymore', req['request_id'])
|
|
337
|
+
|
|
338
|
+
except Exception as error:
|
|
339
|
+
logger(logging.ERROR, "Something unexpected happened when handling request %s(%s:%s) at %s: %s" % (req['request_id'],
|
|
340
|
+
req['scope'],
|
|
341
|
+
req['name'],
|
|
342
|
+
req['dest_rse_id'],
|
|
343
|
+
str(error)))
|
|
344
|
+
|
|
345
|
+
__handle_terminated_replicas(replicas, logger=logger)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def __get_undeterministic_rses(logger: LoggerFunction = logging.log) -> list[str]:
|
|
349
|
+
"""
|
|
350
|
+
Get the undeterministic rses from the database
|
|
351
|
+
|
|
352
|
+
:returns: List of undeterministic rses
|
|
353
|
+
"""
|
|
354
|
+
key = 'undeterministic_rses'
|
|
355
|
+
result = REGION.get(key)
|
|
356
|
+
if isinstance(result, NoValue):
|
|
357
|
+
rses_list = list_rses(filters={'deterministic': False})
|
|
358
|
+
result = [rse['id'] for rse in rses_list]
|
|
359
|
+
try:
|
|
360
|
+
REGION.set(key, result)
|
|
361
|
+
except Exception as error:
|
|
362
|
+
logger(logging.WARNING, "Failed to set dogpile cache, error: %s", str(error))
|
|
363
|
+
return result
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def __check_suspicious_files(
|
|
367
|
+
req: RequestDict,
|
|
368
|
+
suspicious_patterns: list[re.Pattern],
|
|
369
|
+
logger: LoggerFunction = logging.log
|
|
370
|
+
) -> bool:
|
|
371
|
+
"""
|
|
372
|
+
Check suspicious files when a transfer failed.
|
|
373
|
+
|
|
374
|
+
:param req: Request object.
|
|
375
|
+
:param suspicious_patterns: A list of regexp pattern object.
|
|
376
|
+
"""
|
|
377
|
+
is_suspicious = False
|
|
378
|
+
if not suspicious_patterns:
|
|
379
|
+
return is_suspicious
|
|
380
|
+
|
|
381
|
+
try:
|
|
382
|
+
logger(logging.DEBUG, "Checking suspicious file for request: %s, transfer error: %s", req['request_id'], req['err_msg'])
|
|
383
|
+
for pattern in suspicious_patterns:
|
|
384
|
+
if pattern.match(req['err_msg']):
|
|
385
|
+
is_suspicious = True
|
|
386
|
+
break
|
|
387
|
+
|
|
388
|
+
if is_suspicious:
|
|
389
|
+
reason = req['err_msg'][:255]
|
|
390
|
+
urls = request_core.get_sources(req['request_id'], rse_id=req['source_rse_id'])
|
|
391
|
+
if urls:
|
|
392
|
+
pfns = []
|
|
393
|
+
for url in urls:
|
|
394
|
+
pfns.append(url['url'])
|
|
395
|
+
if pfns:
|
|
396
|
+
logger(logging.DEBUG, "Found suspicious urls: %s", str(pfns))
|
|
397
|
+
replica_core.declare_bad_file_replicas(pfns, reason=reason, issuer=InternalAccount('root', vo=req['scope'].vo), status=BadFilesStatus.SUSPICIOUS)
|
|
398
|
+
except Exception as error:
|
|
399
|
+
logger(logging.WARNING, "Failed to check suspicious file with request: %s - %s", req['request_id'], str(error))
|
|
400
|
+
return is_suspicious
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def __handle_terminated_replicas(
|
|
404
|
+
replicas: dict[str, dict[str, list[dict[str, Any]]]],
|
|
405
|
+
logger: LoggerFunction = logging.log
|
|
406
|
+
) -> None:
|
|
407
|
+
"""
|
|
408
|
+
Used by finisher to handle available and unavailable replicas.
|
|
409
|
+
|
|
410
|
+
:param replicas: List of replicas.
|
|
411
|
+
"""
|
|
412
|
+
|
|
413
|
+
for req_type in replicas:
|
|
414
|
+
for rule_id in replicas[req_type]:
|
|
415
|
+
try:
|
|
416
|
+
__update_bulk_replicas(replicas[req_type][rule_id], logger=logger)
|
|
417
|
+
except (UnsupportedOperation, ReplicaNotFound):
|
|
418
|
+
# one replica in the bulk cannot be found. register it one by one
|
|
419
|
+
logger(logging.WARNING, 'Problem to bulk update the replicas states. Will try one by one')
|
|
420
|
+
for replica in replicas[req_type][rule_id]:
|
|
421
|
+
try:
|
|
422
|
+
__update_replica(replica, logger=logger)
|
|
423
|
+
except (DatabaseException, DatabaseError) as error:
|
|
424
|
+
if re.match(ORACLE_RESOURCE_BUSY_REGEX, error.args[0]) or re.match(ORACLE_DEADLOCK_DETECTED_REGEX, error.args[0]) or MYSQL_LOCK_WAIT_TIMEOUT_EXCEEDED in error.args[0]:
|
|
425
|
+
logger(logging.WARNING, "Locks detected when handling replica %s:%s at RSE %s", replica['scope'], replica['name'], replica['rse_id'])
|
|
426
|
+
else:
|
|
427
|
+
logger(logging.ERROR, "Could not finish handling replicas %s:%s at RSE %s", replica['scope'], replica['name'], replica['rse_id'], exc_info=True)
|
|
428
|
+
except Exception as error:
|
|
429
|
+
logger(logging.ERROR, "Something unexpected happened when updating replica state for transfer %s:%s at %s (%s)", replica['scope'], replica['name'], replica['rse_id'], str(error))
|
|
430
|
+
except (DatabaseException, DatabaseError) as error:
|
|
431
|
+
if re.match(ORACLE_RESOURCE_BUSY_REGEX, error.args[0]) or re.match(ORACLE_DEADLOCK_DETECTED_REGEX, error.args[0]) or MYSQL_LOCK_WAIT_TIMEOUT_EXCEEDED in error.args[0]:
|
|
432
|
+
logger(logging.WARNING, "Locks detected when handling replicas on %s rule %s, update updated time.", req_type, rule_id)
|
|
433
|
+
try:
|
|
434
|
+
request_core.touch_requests_by_rule(rule_id)
|
|
435
|
+
except (DatabaseException, DatabaseError):
|
|
436
|
+
logger(logging.ERROR, "Failed to touch requests by rule(%s)", rule_id, exc_info=True)
|
|
437
|
+
else:
|
|
438
|
+
logger(logging.ERROR, "Could not finish handling replicas on %s rule %s", req_type, rule_id, exc_info=True)
|
|
439
|
+
except Exception:
|
|
440
|
+
logger(logging.ERROR, "Something unexpected happened when handling replicas on %s rule %s", req_type, rule_id, exc_info=True)
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
@transactional_session
|
|
444
|
+
def __update_bulk_replicas(
|
|
445
|
+
replicas: list[dict[str, Any]],
|
|
446
|
+
*,
|
|
447
|
+
session: "Session",
|
|
448
|
+
logger: LoggerFunction = logging.log
|
|
449
|
+
) -> Literal[True]:
|
|
450
|
+
"""
|
|
451
|
+
Used by finisher to handle available and unavailable replicas belongs to same rule in bulk way.
|
|
452
|
+
|
|
453
|
+
:param replicas: List of replicas.
|
|
454
|
+
:param session: The database session to use.
|
|
455
|
+
:returns commit_or_rollback: Boolean.
|
|
456
|
+
"""
|
|
457
|
+
try:
|
|
458
|
+
replica_core.update_replicas_states(replicas, nowait=True, session=session)
|
|
459
|
+
except ReplicaNotFound as error:
|
|
460
|
+
logger(logging.WARNING, 'Failed to bulk update replicas, will do it one by one: %s', str(error))
|
|
461
|
+
raise ReplicaNotFound(error)
|
|
462
|
+
|
|
463
|
+
for replica in replicas:
|
|
464
|
+
if not replica['archived']:
|
|
465
|
+
request_core.archive_request(replica['request_id'], session=session)
|
|
466
|
+
logger(logging.INFO, "HANDLED REQUEST %s DID %s:%s AT RSE %s STATE %s", replica['request_id'], replica['scope'], replica['name'], replica['rse_id'], str(replica['state']))
|
|
467
|
+
return True
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
@transactional_session
|
|
471
|
+
def __update_replica(
|
|
472
|
+
replica: dict[str, Any],
|
|
473
|
+
*,
|
|
474
|
+
session: "Session",
|
|
475
|
+
logger: LoggerFunction = logging.log
|
|
476
|
+
) -> None:
|
|
477
|
+
"""
|
|
478
|
+
Used by finisher to update a replica to a finished state.
|
|
479
|
+
|
|
480
|
+
:param replica: Replica as a dictionary.
|
|
481
|
+
:param rule_id: RULE id.
|
|
482
|
+
:param session: The database session to use.
|
|
483
|
+
:returns commit_or_rollback: Boolean.
|
|
484
|
+
"""
|
|
485
|
+
try:
|
|
486
|
+
replica_found = True
|
|
487
|
+
try:
|
|
488
|
+
replica_core.update_replicas_states([replica], nowait=True, session=session)
|
|
489
|
+
except ReplicaNotFound:
|
|
490
|
+
replica_found = False
|
|
491
|
+
|
|
492
|
+
if not replica_found and replica['state'] == ReplicaState.AVAILABLE and replica['request_type'] != RequestType.STAGEIN:
|
|
493
|
+
# FTS tells us that the Replica was successfully transferred, but there is no such replica in Rucio,
|
|
494
|
+
# this can happen if the replica was deleted from rucio in the meantime. As fts tells us that the
|
|
495
|
+
# replica is available, there is a high probability that we just generated dark data.
|
|
496
|
+
# This opportunistic workflow tries to cleanup this dark data by adding a replica with an expired
|
|
497
|
+
# tombstone and letting reaper take care of its deletion.
|
|
498
|
+
logger(logging.INFO, "Replica cannot be found. Adding a replica %s:%s AT RSE %s with tombstone=utcnow", replica['scope'], replica['name'], replica['rse_id'])
|
|
499
|
+
add_replica_kwargs = {
|
|
500
|
+
'rse_id': replica['rse_id'],
|
|
501
|
+
'scope': replica['scope'],
|
|
502
|
+
'name': replica['name'],
|
|
503
|
+
'bytes_': replica['bytes'],
|
|
504
|
+
'account': InternalAccount('root', vo=replica['scope'].vo), # it will deleted immediately, do we need to get the accurate account from rule?
|
|
505
|
+
'adler32': replica['adler32'],
|
|
506
|
+
'tombstone': datetime.datetime.utcnow(),
|
|
507
|
+
}
|
|
508
|
+
try:
|
|
509
|
+
try:
|
|
510
|
+
replica_core.add_replica(**add_replica_kwargs, pfn=replica['pfn'] if 'pfn' in replica else None, session=session)
|
|
511
|
+
except RSEProtocolNotSupported as error:
|
|
512
|
+
# The pfn cannot be matched to any of the protocols configured on the RSE.
|
|
513
|
+
# Most probably the RSE protocol configuration changed since the submission.
|
|
514
|
+
# Try again without explicit pfn. On non-deterministic RSEs it will fail
|
|
515
|
+
# with UnsupportedOperation exception
|
|
516
|
+
logger(logging.ERROR, 'Protocol not supported for DID %s:%s at RSE %s - potential dark data - %s', replica['scope'], replica['name'], replica['rse_id'], str(error))
|
|
517
|
+
replica_core.add_replica(**add_replica_kwargs, pfn=None, session=session)
|
|
518
|
+
except Exception as error:
|
|
519
|
+
logger(logging.ERROR, 'Cannot register replica for DID %s:%s at RSE %s - potential dark data - %s', replica['scope'], replica['name'], replica['rse_id'], str(error))
|
|
520
|
+
raise
|
|
521
|
+
|
|
522
|
+
if not replica['archived']:
|
|
523
|
+
request_core.archive_request(replica['request_id'], session=session)
|
|
524
|
+
|
|
525
|
+
except Exception as error:
|
|
526
|
+
logger(logging.WARNING, "ERROR WHEN HANDLING REQUEST %s DID %s:%s AT RSE %s STATE %s: %s", replica['request_id'], replica['scope'], replica['name'], replica['rse_id'], str(replica['state']), str(error))
|
|
527
|
+
raise
|
|
528
|
+
|
|
529
|
+
logger(logging.INFO, "HANDLED REQUEST %s DID %s:%s AT RSE %s STATE %s", replica['request_id'], replica['scope'], replica['name'], replica['rse_id'], str(replica['state']))
|