rucio 32.8.6__py3-none-any.whl → 35.8.0__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 +0 -1
- rucio/alembicrevision.py +1 -2
- rucio/client/__init__.py +0 -1
- rucio/client/accountclient.py +45 -25
- rucio/client/accountlimitclient.py +37 -9
- rucio/client/baseclient.py +199 -154
- rucio/client/client.py +2 -3
- rucio/client/configclient.py +19 -6
- rucio/client/credentialclient.py +9 -4
- rucio/client/didclient.py +238 -63
- rucio/client/diracclient.py +13 -5
- rucio/client/downloadclient.py +162 -51
- rucio/client/exportclient.py +4 -4
- rucio/client/fileclient.py +3 -4
- rucio/client/importclient.py +4 -4
- rucio/client/lifetimeclient.py +21 -5
- rucio/client/lockclient.py +18 -8
- rucio/client/{metaclient.py → metaconventionsclient.py} +18 -15
- rucio/client/pingclient.py +0 -1
- rucio/client/replicaclient.py +15 -5
- rucio/client/requestclient.py +35 -19
- rucio/client/rseclient.py +133 -51
- rucio/client/ruleclient.py +29 -22
- rucio/client/scopeclient.py +8 -6
- rucio/client/subscriptionclient.py +47 -35
- rucio/client/touchclient.py +8 -4
- rucio/client/uploadclient.py +166 -82
- rucio/common/__init__.py +0 -1
- rucio/common/cache.py +4 -4
- rucio/common/config.py +52 -47
- rucio/common/constants.py +69 -2
- rucio/common/constraints.py +0 -1
- rucio/common/didtype.py +24 -22
- rucio/common/dumper/__init__.py +70 -41
- rucio/common/dumper/consistency.py +26 -22
- rucio/common/dumper/data_models.py +16 -23
- rucio/common/dumper/path_parsing.py +0 -1
- rucio/common/exception.py +281 -222
- rucio/common/extra.py +0 -1
- rucio/common/logging.py +54 -38
- rucio/common/pcache.py +122 -101
- rucio/common/plugins.py +153 -0
- rucio/common/policy.py +4 -4
- rucio/common/schema/__init__.py +17 -10
- rucio/common/schema/atlas.py +7 -5
- rucio/common/schema/belleii.py +7 -5
- rucio/common/schema/domatpc.py +7 -5
- rucio/common/schema/escape.py +7 -5
- rucio/common/schema/generic.py +8 -6
- rucio/common/schema/generic_multi_vo.py +7 -5
- rucio/common/schema/icecube.py +7 -5
- rucio/common/stomp_utils.py +0 -1
- rucio/common/stopwatch.py +0 -1
- rucio/common/test_rucio_server.py +2 -2
- rucio/common/types.py +262 -17
- rucio/common/utils.py +743 -451
- rucio/core/__init__.py +0 -1
- rucio/core/account.py +99 -29
- rucio/core/account_counter.py +89 -24
- rucio/core/account_limit.py +90 -24
- rucio/core/authentication.py +86 -29
- rucio/core/config.py +108 -38
- rucio/core/credential.py +14 -7
- rucio/core/did.py +680 -782
- rucio/core/did_meta_plugins/__init__.py +8 -6
- rucio/core/did_meta_plugins/did_column_meta.py +17 -12
- rucio/core/did_meta_plugins/did_meta_plugin_interface.py +60 -11
- rucio/core/did_meta_plugins/filter_engine.py +90 -50
- rucio/core/did_meta_plugins/json_meta.py +41 -16
- rucio/core/did_meta_plugins/mongo_meta.py +25 -8
- rucio/core/did_meta_plugins/postgres_meta.py +3 -4
- rucio/core/dirac.py +46 -17
- rucio/core/distance.py +66 -43
- rucio/core/exporter.py +5 -5
- rucio/core/heartbeat.py +181 -81
- rucio/core/identity.py +22 -12
- rucio/core/importer.py +23 -12
- rucio/core/lifetime_exception.py +32 -32
- rucio/core/lock.py +244 -142
- rucio/core/message.py +79 -38
- rucio/core/{meta.py → meta_conventions.py} +57 -44
- rucio/core/monitor.py +19 -13
- rucio/core/naming_convention.py +68 -27
- rucio/core/nongrid_trace.py +17 -5
- rucio/core/oidc.py +151 -29
- rucio/core/permission/__init__.py +18 -6
- rucio/core/permission/atlas.py +50 -35
- rucio/core/permission/belleii.py +6 -5
- rucio/core/permission/escape.py +8 -6
- rucio/core/permission/generic.py +82 -80
- rucio/core/permission/generic_multi_vo.py +9 -7
- rucio/core/quarantined_replica.py +91 -58
- rucio/core/replica.py +1303 -772
- rucio/core/replica_sorter.py +10 -12
- rucio/core/request.py +1133 -285
- rucio/core/rse.py +142 -102
- rucio/core/rse_counter.py +49 -18
- rucio/core/rse_expression_parser.py +6 -7
- rucio/core/rse_selector.py +41 -16
- rucio/core/rule.py +1538 -474
- rucio/core/rule_grouping.py +213 -68
- rucio/core/scope.py +50 -22
- rucio/core/subscription.py +92 -44
- rucio/core/topology.py +66 -24
- rucio/core/trace.py +42 -28
- rucio/core/transfer.py +543 -259
- rucio/core/vo.py +36 -18
- rucio/core/volatile_replica.py +59 -32
- rucio/daemons/__init__.py +0 -1
- rucio/daemons/abacus/__init__.py +0 -1
- rucio/daemons/abacus/account.py +29 -19
- rucio/daemons/abacus/collection_replica.py +21 -10
- rucio/daemons/abacus/rse.py +22 -12
- rucio/daemons/atropos/__init__.py +0 -1
- rucio/daemons/atropos/atropos.py +1 -2
- rucio/daemons/auditor/__init__.py +56 -28
- rucio/daemons/auditor/hdfs.py +17 -6
- rucio/daemons/auditor/srmdumps.py +116 -45
- rucio/daemons/automatix/__init__.py +0 -1
- rucio/daemons/automatix/automatix.py +30 -18
- rucio/daemons/badreplicas/__init__.py +0 -1
- rucio/daemons/badreplicas/minos.py +29 -18
- rucio/daemons/badreplicas/minos_temporary_expiration.py +5 -7
- rucio/daemons/badreplicas/necromancer.py +9 -13
- rucio/daemons/bb8/__init__.py +0 -1
- rucio/daemons/bb8/bb8.py +10 -13
- rucio/daemons/bb8/common.py +151 -154
- rucio/daemons/bb8/nuclei_background_rebalance.py +15 -9
- rucio/daemons/bb8/t2_background_rebalance.py +15 -8
- rucio/daemons/c3po/__init__.py +0 -1
- rucio/daemons/c3po/algorithms/__init__.py +0 -1
- rucio/daemons/c3po/algorithms/simple.py +8 -5
- rucio/daemons/c3po/algorithms/t2_free_space.py +10 -7
- rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +10 -7
- rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +30 -15
- rucio/daemons/c3po/c3po.py +81 -52
- rucio/daemons/c3po/collectors/__init__.py +0 -1
- rucio/daemons/c3po/collectors/agis.py +17 -17
- rucio/daemons/c3po/collectors/free_space.py +32 -13
- rucio/daemons/c3po/collectors/jedi_did.py +14 -5
- rucio/daemons/c3po/collectors/mock_did.py +11 -6
- rucio/daemons/c3po/collectors/network_metrics.py +12 -4
- rucio/daemons/c3po/collectors/workload.py +21 -19
- rucio/daemons/c3po/utils/__init__.py +0 -1
- rucio/daemons/c3po/utils/dataset_cache.py +15 -5
- rucio/daemons/c3po/utils/expiring_dataset_cache.py +16 -5
- rucio/daemons/c3po/utils/expiring_list.py +6 -7
- rucio/daemons/c3po/utils/popularity.py +5 -2
- rucio/daemons/c3po/utils/timeseries.py +25 -12
- rucio/daemons/cache/__init__.py +0 -1
- rucio/daemons/cache/consumer.py +21 -15
- rucio/daemons/common.py +42 -18
- rucio/daemons/conveyor/__init__.py +0 -1
- rucio/daemons/conveyor/common.py +69 -37
- rucio/daemons/conveyor/finisher.py +83 -46
- rucio/daemons/conveyor/poller.py +101 -69
- rucio/daemons/conveyor/preparer.py +35 -28
- rucio/daemons/conveyor/receiver.py +64 -21
- rucio/daemons/conveyor/stager.py +33 -28
- rucio/daemons/conveyor/submitter.py +71 -47
- rucio/daemons/conveyor/throttler.py +99 -35
- rucio/daemons/follower/__init__.py +0 -1
- rucio/daemons/follower/follower.py +12 -8
- rucio/daemons/hermes/__init__.py +0 -1
- rucio/daemons/hermes/hermes.py +57 -21
- rucio/daemons/judge/__init__.py +0 -1
- rucio/daemons/judge/cleaner.py +27 -17
- rucio/daemons/judge/evaluator.py +31 -18
- rucio/daemons/judge/injector.py +31 -23
- rucio/daemons/judge/repairer.py +28 -18
- rucio/daemons/oauthmanager/__init__.py +0 -1
- rucio/daemons/oauthmanager/oauthmanager.py +7 -8
- rucio/daemons/reaper/__init__.py +0 -1
- rucio/daemons/reaper/dark_reaper.py +15 -9
- rucio/daemons/reaper/reaper.py +109 -67
- rucio/daemons/replicarecoverer/__init__.py +0 -1
- rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +255 -116
- rucio/{api → daemons/rsedecommissioner}/__init__.py +0 -1
- 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 +451 -0
- rucio/daemons/rsedecommissioner/profiles/types.py +92 -0
- rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
- rucio/daemons/storage/__init__.py +0 -1
- rucio/daemons/storage/consistency/__init__.py +0 -1
- rucio/daemons/storage/consistency/actions.py +152 -59
- rucio/daemons/tracer/__init__.py +0 -1
- rucio/daemons/tracer/kronos.py +47 -24
- rucio/daemons/transmogrifier/__init__.py +0 -1
- rucio/daemons/transmogrifier/transmogrifier.py +35 -26
- rucio/daemons/undertaker/__init__.py +0 -1
- rucio/daemons/undertaker/undertaker.py +10 -10
- rucio/db/__init__.py +0 -1
- rucio/db/sqla/__init__.py +16 -2
- rucio/db/sqla/constants.py +10 -1
- rucio/db/sqla/migrate_repo/__init__.py +0 -1
- rucio/db/sqla/migrate_repo/env.py +0 -1
- rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +0 -1
- rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +0 -3
- rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +0 -3
- rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +1 -3
- rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +0 -3
- rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +1 -4
- rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +0 -1
- rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +0 -2
- rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +0 -1
- rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +0 -1
- rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +0 -2
- rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +0 -1
- rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +0 -1
- rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +0 -3
- rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +0 -1
- rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +1 -2
- rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +0 -1
- rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +0 -3
- rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +1 -4
- rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +0 -2
- rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +0 -3
- rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +0 -3
- rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +1 -2
- rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +0 -1
- rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +0 -1
- rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +0 -2
- rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +0 -3
- rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +0 -2
- rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +1 -4
- rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +0 -3
- rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +1 -4
- rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +0 -1
- rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +1 -3
- rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +0 -2
- rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +1 -3
- rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +1 -2
- rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +1 -3
- rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +0 -2
- rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +2 -3
- rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +0 -3
- rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +1 -4
- rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +0 -1
- rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +0 -1
- rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +0 -3
- rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +0 -1
- rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +0 -2
- rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +0 -3
- rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +0 -2
- rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +2 -4
- rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +0 -2
- rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +1 -4
- rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +0 -3
- rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +0 -3
- rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +0 -2
- rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +0 -3
- 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 +0 -2
- rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +0 -2
- rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +0 -3
- rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +0 -3
- rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +0 -3
- rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +1 -2
- rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +0 -3
- rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +1 -3
- rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +1 -3
- rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +1 -2
- rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +0 -3
- rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +0 -3
- rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +1 -2
- rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +2 -4
- rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +0 -1
- rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +1 -4
- rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +0 -2
- rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +0 -3
- rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +1 -2
- rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +0 -3
- rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +1 -3
- rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +0 -3
- rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +0 -1
- rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +1 -2
- rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +0 -2
- 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 +1 -3
- rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +0 -2
- rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +1 -4
- rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +0 -1
- rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +0 -1
- rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +1 -4
- rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +0 -1
- 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 +0 -3
- 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 +1 -2
- rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +1 -3
- rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +0 -3
- rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +1 -5
- rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +1 -3
- rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +0 -3
- rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +1 -3
- rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +1 -2
- rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +0 -3
- rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +1 -4
- rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +1 -2
- rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +1 -4
- rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +1 -3
- rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +1 -4
- rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +0 -2
- rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +0 -3
- rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +1 -3
- rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +0 -1
- rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +1 -2
- rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +1 -3
- rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +0 -2
- rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +0 -1
- rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +1 -2
- rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +0 -3
- rucio/db/sqla/models.py +122 -216
- rucio/db/sqla/sautils.py +12 -5
- rucio/db/sqla/session.py +71 -43
- rucio/db/sqla/types.py +3 -4
- rucio/db/sqla/util.py +91 -69
- rucio/gateway/__init__.py +13 -0
- rucio/{api → gateway}/account.py +119 -46
- rucio/{api → gateway}/account_limit.py +12 -13
- rucio/{api → gateway}/authentication.py +106 -33
- rucio/{api → gateway}/config.py +12 -13
- rucio/{api → gateway}/credential.py +15 -4
- rucio/{api → gateway}/did.py +384 -140
- rucio/{api → gateway}/dirac.py +16 -6
- rucio/{api → gateway}/exporter.py +3 -4
- rucio/{api → gateway}/heartbeat.py +17 -5
- rucio/{api → gateway}/identity.py +63 -19
- rucio/{api → gateway}/importer.py +3 -4
- rucio/{api → gateway}/lifetime_exception.py +35 -10
- rucio/{api → gateway}/lock.py +34 -12
- rucio/{api/meta.py → gateway/meta_conventions.py} +18 -16
- rucio/{api → gateway}/permission.py +4 -5
- rucio/{api → gateway}/quarantined_replica.py +13 -4
- rucio/{api → gateway}/replica.py +12 -11
- rucio/{api → gateway}/request.py +129 -28
- rucio/{api → gateway}/rse.py +11 -12
- rucio/{api → gateway}/rule.py +117 -35
- rucio/{api → gateway}/scope.py +24 -14
- rucio/{api → gateway}/subscription.py +65 -43
- rucio/{api → gateway}/vo.py +17 -7
- rucio/rse/__init__.py +3 -4
- rucio/rse/protocols/__init__.py +0 -1
- rucio/rse/protocols/bittorrent.py +184 -0
- rucio/rse/protocols/cache.py +1 -2
- rucio/rse/protocols/dummy.py +1 -2
- rucio/rse/protocols/gfal.py +12 -10
- rucio/rse/protocols/globus.py +7 -7
- rucio/rse/protocols/gsiftp.py +2 -3
- rucio/rse/protocols/http_cache.py +1 -2
- rucio/rse/protocols/mock.py +1 -2
- rucio/rse/protocols/ngarc.py +1 -2
- rucio/rse/protocols/posix.py +12 -13
- rucio/rse/protocols/protocol.py +116 -52
- rucio/rse/protocols/rclone.py +6 -7
- rucio/rse/protocols/rfio.py +4 -5
- rucio/rse/protocols/srm.py +9 -10
- rucio/rse/protocols/ssh.py +8 -9
- rucio/rse/protocols/storm.py +2 -3
- rucio/rse/protocols/webdav.py +17 -14
- rucio/rse/protocols/xrootd.py +23 -17
- rucio/rse/rsemanager.py +19 -7
- rucio/tests/__init__.py +0 -1
- rucio/tests/common.py +43 -17
- rucio/tests/common_server.py +3 -3
- rucio/transfertool/__init__.py +0 -1
- rucio/transfertool/bittorrent.py +199 -0
- rucio/transfertool/bittorrent_driver.py +52 -0
- rucio/transfertool/bittorrent_driver_qbittorrent.py +133 -0
- rucio/transfertool/fts3.py +250 -138
- rucio/transfertool/fts3_plugins.py +152 -0
- rucio/transfertool/globus.py +9 -8
- rucio/transfertool/globus_library.py +1 -2
- rucio/transfertool/mock.py +21 -12
- rucio/transfertool/transfertool.py +33 -24
- rucio/vcsversion.py +4 -4
- rucio/version.py +5 -13
- rucio/web/__init__.py +0 -1
- rucio/web/rest/__init__.py +0 -1
- rucio/web/rest/flaskapi/__init__.py +0 -1
- rucio/web/rest/flaskapi/authenticated_bp.py +0 -1
- rucio/web/rest/flaskapi/v1/__init__.py +0 -1
- rucio/web/rest/flaskapi/v1/accountlimits.py +15 -13
- rucio/web/rest/flaskapi/v1/accounts.py +49 -48
- rucio/web/rest/flaskapi/v1/archives.py +12 -10
- rucio/web/rest/flaskapi/v1/auth.py +146 -144
- rucio/web/rest/flaskapi/v1/common.py +82 -41
- rucio/web/rest/flaskapi/v1/config.py +5 -6
- rucio/web/rest/flaskapi/v1/credentials.py +7 -8
- rucio/web/rest/flaskapi/v1/dids.py +158 -28
- rucio/web/rest/flaskapi/v1/dirac.py +8 -8
- rucio/web/rest/flaskapi/v1/export.py +3 -5
- rucio/web/rest/flaskapi/v1/heartbeats.py +3 -5
- rucio/web/rest/flaskapi/v1/identities.py +3 -5
- rucio/web/rest/flaskapi/v1/import.py +3 -4
- rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +6 -9
- rucio/web/rest/flaskapi/v1/locks.py +2 -4
- rucio/web/rest/flaskapi/v1/main.py +10 -2
- rucio/web/rest/flaskapi/v1/{meta.py → meta_conventions.py} +26 -11
- rucio/web/rest/flaskapi/v1/metrics.py +1 -2
- rucio/web/rest/flaskapi/v1/nongrid_traces.py +4 -4
- rucio/web/rest/flaskapi/v1/ping.py +6 -7
- rucio/web/rest/flaskapi/v1/redirect.py +8 -9
- rucio/web/rest/flaskapi/v1/replicas.py +43 -19
- rucio/web/rest/flaskapi/v1/requests.py +178 -21
- rucio/web/rest/flaskapi/v1/rses.py +61 -26
- rucio/web/rest/flaskapi/v1/rules.py +48 -18
- rucio/web/rest/flaskapi/v1/scopes.py +3 -5
- rucio/web/rest/flaskapi/v1/subscriptions.py +22 -18
- rucio/web/rest/flaskapi/v1/traces.py +4 -4
- rucio/web/rest/flaskapi/v1/types.py +20 -0
- rucio/web/rest/flaskapi/v1/vos.py +3 -5
- rucio/web/rest/main.py +0 -1
- rucio/web/rest/metrics.py +0 -1
- rucio/web/rest/ping.py +27 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/ldap.cfg.template +1 -1
- rucio-35.8.0.data/data/rucio/requirements.server.txt +268 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/bootstrap.py +3 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/merge_rucio_configs.py +2 -5
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/reset_database.py +3 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio +87 -85
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-account +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-collection-replica +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-rse +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-admin +45 -32
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-atropos +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-auditor +13 -7
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-automatix +1 -2
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-bb8 +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-c3po +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-cache-client +2 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-cache-consumer +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-finisher +1 -2
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-poller +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-preparer +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-receiver +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-stager +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-submitter +2 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-throttler +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-dark-reaper +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-dumper +11 -10
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-follower +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-hermes +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-cleaner +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-evaluator +2 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-injector +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-repairer +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-kronos +1 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-minos +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-minos-temporary-expiration +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-necromancer +1 -2
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-oauth-manager +2 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-reaper +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-replica-recoverer +6 -7
- rucio-35.8.0.data/scripts/rucio-rse-decommissioner +66 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-storage-consistency-actions +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-transmogrifier +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-undertaker +1 -2
- rucio-35.8.0.dist-info/METADATA +72 -0
- rucio-35.8.0.dist-info/RECORD +493 -0
- {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/WHEEL +1 -1
- {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/licenses/AUTHORS.rst +3 -0
- rucio/api/temporary_did.py +0 -49
- rucio/common/schema/cms.py +0 -478
- rucio/common/schema/lsst.py +0 -423
- rucio/core/permission/cms.py +0 -1166
- rucio/core/temporary_did.py +0 -188
- rucio/daemons/reaper/light_reaper.py +0 -255
- rucio/web/rest/flaskapi/v1/tmp_dids.py +0 -115
- rucio-32.8.6.data/data/rucio/requirements.txt +0 -55
- rucio-32.8.6.data/scripts/rucio-light-reaper +0 -53
- rucio-32.8.6.dist-info/METADATA +0 -83
- rucio-32.8.6.dist-info/RECORD +0 -481
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/alembic.ini.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio.cfg.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -0
- {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/licenses/LICENSE +0 -0
- {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -28,8 +27,9 @@ import threading
|
|
|
28
27
|
import time
|
|
29
28
|
import traceback
|
|
30
29
|
from datetime import datetime
|
|
31
|
-
from typing import TYPE_CHECKING
|
|
30
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
32
31
|
|
|
32
|
+
from sqlalchemy import and_, delete
|
|
33
33
|
from sqlalchemy.exc import DatabaseError, IntegrityError
|
|
34
34
|
from sqlalchemy.orm.exc import FlushError
|
|
35
35
|
|
|
@@ -37,21 +37,25 @@ from rucio.common import exception
|
|
|
37
37
|
from rucio.common.logging import formatted_logger, setup_logging
|
|
38
38
|
from rucio.common.types import InternalAccount, InternalScope
|
|
39
39
|
from rucio.common.utils import daemon_sleep
|
|
40
|
-
from rucio.core.heartbeat import
|
|
40
|
+
from rucio.core.heartbeat import die, live, sanity_check
|
|
41
41
|
from rucio.core.monitor import MetricManager
|
|
42
42
|
from rucio.core.quarantined_replica import add_quarantined_replicas
|
|
43
43
|
from rucio.core.replica import __exist_replicas, update_replicas_states
|
|
44
|
-
from rucio.core.rse import
|
|
44
|
+
from rucio.core.rse import get_rse_id, list_rses
|
|
45
|
+
|
|
45
46
|
# FIXME: these are needed by local version of declare_bad_file_replicas()
|
|
46
47
|
# TODO: remove after move of this code to core/replica.py - see https://github.com/rucio/rucio/pull/5068
|
|
47
48
|
from rucio.db.sqla import models
|
|
48
|
-
from rucio.db.sqla.constants import
|
|
49
|
+
from rucio.db.sqla.constants import BadFilesStatus, ReplicaState
|
|
49
50
|
from rucio.db.sqla.session import transactional_session
|
|
50
|
-
from rucio.rse.rsemanager import
|
|
51
|
+
from rucio.rse.rsemanager import get_rse_info, lfns2pfns, parse_pfns
|
|
51
52
|
|
|
52
53
|
if TYPE_CHECKING:
|
|
54
|
+
from collections.abc import Iterable, Sequence
|
|
53
55
|
from types import FrameType
|
|
54
|
-
|
|
56
|
+
|
|
57
|
+
from _typeshed import FileDescriptorOrPath, SupportsKeysAndGetItem
|
|
58
|
+
from sqlalchemy.orm import Session
|
|
55
59
|
|
|
56
60
|
METRICS = MetricManager(module=__name__)
|
|
57
61
|
graceful_stop = threading.Event()
|
|
@@ -62,8 +66,16 @@ DAEMON_NAME = 'storage-consistency-actions'
|
|
|
62
66
|
|
|
63
67
|
|
|
64
68
|
@transactional_session
|
|
65
|
-
def declare_bad_file_replicas(
|
|
66
|
-
|
|
69
|
+
def declare_bad_file_replicas(
|
|
70
|
+
dids: "Iterable[dict[str, str]]",
|
|
71
|
+
rse_id: str,
|
|
72
|
+
reason: str,
|
|
73
|
+
issuer: InternalAccount,
|
|
74
|
+
status=BadFilesStatus.BAD,
|
|
75
|
+
scheme: Optional[str] = None,
|
|
76
|
+
*,
|
|
77
|
+
session: Optional["Session"] = None
|
|
78
|
+
):
|
|
67
79
|
"""
|
|
68
80
|
Declare a list of bad replicas.
|
|
69
81
|
|
|
@@ -87,12 +99,20 @@ def declare_bad_file_replicas(dids, rse_id, reason, issuer,
|
|
|
87
99
|
already_declared) or str(status) == str(BadFilesStatus.SUSPICIOUS)):
|
|
88
100
|
replicas.append({'scope': scope, 'name': name, 'rse_id': rse_id,
|
|
89
101
|
'state': ReplicaState.BAD})
|
|
90
|
-
new_bad_replica = models.
|
|
91
|
-
|
|
92
|
-
|
|
102
|
+
new_bad_replica = models.BadReplica(scope=scope, name=name, rse_id=rse_id,
|
|
103
|
+
reason=reason, state=status, account=issuer,
|
|
104
|
+
bytes=size)
|
|
93
105
|
new_bad_replica.save(session=session, flush=False)
|
|
94
|
-
|
|
95
|
-
|
|
106
|
+
stmt = delete(
|
|
107
|
+
models.Source
|
|
108
|
+
).where(
|
|
109
|
+
and_(models.Source.scope == scope,
|
|
110
|
+
models.Source.name == name,
|
|
111
|
+
models.Source.rse_id == rse_id)
|
|
112
|
+
).execution_options(
|
|
113
|
+
synchronize_session=False
|
|
114
|
+
)
|
|
115
|
+
session.execute(stmt) # type: ignore (session could be None)
|
|
96
116
|
else:
|
|
97
117
|
if already_declared:
|
|
98
118
|
unknown_replicas.append('%s:%s %s' % (did['scope'], did['name'],
|
|
@@ -108,7 +128,7 @@ def declare_bad_file_replicas(dids, rse_id, reason, issuer,
|
|
|
108
128
|
except exception.UnsupportedOperation:
|
|
109
129
|
raise exception.ReplicaNotFound("One or several replicas don't exist.")
|
|
110
130
|
try:
|
|
111
|
-
session.flush()
|
|
131
|
+
session.flush() # type: ignore (session could be None)
|
|
112
132
|
except IntegrityError as error:
|
|
113
133
|
raise exception.RucioException(error.args)
|
|
114
134
|
except DatabaseError as error:
|
|
@@ -122,27 +142,27 @@ def declare_bad_file_replicas(dids, rse_id, reason, issuer,
|
|
|
122
142
|
# TODO: This is Igor's Stats class.It will be factored out as a separate class in a future version of the code.
|
|
123
143
|
# - Igor Mandrichenko <ivm@fnal.gov>, 2018
|
|
124
144
|
|
|
125
|
-
class Stats
|
|
145
|
+
class Stats:
|
|
126
146
|
|
|
127
|
-
def __init__(self, path):
|
|
147
|
+
def __init__(self, path: "FileDescriptorOrPath"):
|
|
128
148
|
self.path = path
|
|
129
149
|
self.Data = {}
|
|
130
150
|
|
|
131
|
-
def __getitem__(self, name):
|
|
151
|
+
def __getitem__(self, name: str) -> Any:
|
|
132
152
|
return self.Data[name]
|
|
133
153
|
|
|
134
|
-
def __setitem__(self, name, value):
|
|
154
|
+
def __setitem__(self, name: str, value: Any) -> None:
|
|
135
155
|
self.Data[name] = value
|
|
136
156
|
self.save()
|
|
137
157
|
|
|
138
|
-
def get(self, name, default=None):
|
|
158
|
+
def get(self, name, default: Any = None) -> Any:
|
|
139
159
|
return self.Data.get(name, default)
|
|
140
160
|
|
|
141
|
-
def update(self, data):
|
|
161
|
+
def update(self, data: "SupportsKeysAndGetItem") -> None:
|
|
142
162
|
self.Data.update(data)
|
|
143
163
|
self.save()
|
|
144
164
|
|
|
145
|
-
def save(self):
|
|
165
|
+
def save(self) -> None:
|
|
146
166
|
try:
|
|
147
167
|
with open(self.path, "r") as f:
|
|
148
168
|
data = f.read()
|
|
@@ -153,7 +173,11 @@ class Stats(object):
|
|
|
153
173
|
open(self.path, "w").write(json.dumps(data, indent=4))
|
|
154
174
|
|
|
155
175
|
|
|
156
|
-
def write_stats(
|
|
176
|
+
def write_stats(
|
|
177
|
+
my_stats: Any,
|
|
178
|
+
stats_file: "FileDescriptorOrPath",
|
|
179
|
+
stats_key: Optional[str] = None
|
|
180
|
+
):
|
|
157
181
|
if stats_file:
|
|
158
182
|
stats = {}
|
|
159
183
|
if os.path.isfile(stats_file):
|
|
@@ -168,13 +192,18 @@ def write_stats(my_stats, stats_file, stats_key=None):
|
|
|
168
192
|
# TODO: Consider breaking the logic into two functions, following discussion in https://github.com/rucio/rucio/pull/5120#discussion_r792673599
|
|
169
193
|
|
|
170
194
|
|
|
171
|
-
def cmp2dark(
|
|
195
|
+
def cmp2dark(
|
|
196
|
+
new_list: "FileDescriptorOrPath",
|
|
197
|
+
old_list: "FileDescriptorOrPath",
|
|
198
|
+
comm_list: "FileDescriptorOrPath",
|
|
199
|
+
stats_file: "FileDescriptorOrPath"
|
|
200
|
+
) -> None:
|
|
172
201
|
|
|
173
202
|
t0 = time.time()
|
|
174
203
|
stats_key = "cmp2dark"
|
|
175
204
|
my_stats = stats = None
|
|
176
205
|
|
|
177
|
-
with open(new_list, "r") as a_list, open(old_list, "r") as b_list
|
|
206
|
+
with open(new_list, "r") as a_list, open(old_list, "r") as b_list, \
|
|
178
207
|
open(comm_list, "w") as out_list:
|
|
179
208
|
|
|
180
209
|
if stats_file is not None:
|
|
@@ -210,7 +239,7 @@ def cmp2dark(new_list, old_list, comm_list, stats_file):
|
|
|
210
239
|
|
|
211
240
|
|
|
212
241
|
# TODO: Changes suggested in https://github.com/rucio/rucio/pull/5120#discussion_r792681245
|
|
213
|
-
def parse_filename(fn):
|
|
242
|
+
def parse_filename(fn: str) -> tuple[str, str, str, str]:
|
|
214
243
|
# filename looks like this:
|
|
215
244
|
#
|
|
216
245
|
# <rse>_%Y_%m_%d_%H_%M_<type>.<extension>
|
|
@@ -224,7 +253,7 @@ def parse_filename(fn):
|
|
|
224
253
|
return rse, timestamp, typ, ext
|
|
225
254
|
|
|
226
255
|
|
|
227
|
-
def list_cc_scanned_rses(path):
|
|
256
|
+
def list_cc_scanned_rses(path: "FileDescriptorOrPath") -> list[str]:
|
|
228
257
|
files = glob.glob(f"{path}/*_stats.json")
|
|
229
258
|
rses = set()
|
|
230
259
|
for path in files:
|
|
@@ -234,7 +263,11 @@ def list_cc_scanned_rses(path):
|
|
|
234
263
|
return sorted(list(rses))
|
|
235
264
|
|
|
236
265
|
|
|
237
|
-
def list_runs_by_age(
|
|
266
|
+
def list_runs_by_age(
|
|
267
|
+
path: "FileDescriptorOrPath",
|
|
268
|
+
rse: str,
|
|
269
|
+
reffile: str
|
|
270
|
+
) -> dict[str, int]:
|
|
238
271
|
files = glob.glob(f"{path}/{rse}_*_stats.json")
|
|
239
272
|
r, reftimestamp, typ, ext = parse_filename(reffile)
|
|
240
273
|
reftime = datetime.strptime(reftimestamp, '%Y_%m_%d_%H_%M')
|
|
@@ -253,7 +286,11 @@ def list_runs_by_age(path, rse, reffile):
|
|
|
253
286
|
return {k: v for k, v in sorted(runs.items(), reverse=True)}
|
|
254
287
|
|
|
255
288
|
|
|
256
|
-
def list_runs(
|
|
289
|
+
def list_runs(
|
|
290
|
+
path: "FileDescriptorOrPath",
|
|
291
|
+
rse: str,
|
|
292
|
+
nlast: int = 0
|
|
293
|
+
) -> list[str]:
|
|
257
294
|
files = glob.glob(f"{path}/{rse}_*_stats.json")
|
|
258
295
|
runs = []
|
|
259
296
|
for path in files:
|
|
@@ -269,7 +306,11 @@ def list_runs(path, rse, nlast=0):
|
|
|
269
306
|
return sorted(runs, reverse=False)[-nlast:]
|
|
270
307
|
|
|
271
308
|
|
|
272
|
-
def list_unprocessed_runs(
|
|
309
|
+
def list_unprocessed_runs(
|
|
310
|
+
path: "FileDescriptorOrPath",
|
|
311
|
+
rse: str,
|
|
312
|
+
nlast: int = 0
|
|
313
|
+
) -> list[str]:
|
|
273
314
|
files = glob.glob(f"{path}/{rse}_*_stats.json")
|
|
274
315
|
unproc_runs = []
|
|
275
316
|
for path in files:
|
|
@@ -286,7 +327,9 @@ def list_unprocessed_runs(path, rse, nlast=0):
|
|
|
286
327
|
return sorted(unproc_runs, reverse=True)[-nlast:]
|
|
287
328
|
|
|
288
329
|
|
|
289
|
-
def was_cc_attempted(
|
|
330
|
+
def was_cc_attempted(
|
|
331
|
+
stats_file: "FileDescriptorOrPath"
|
|
332
|
+
) -> Optional[bool]:
|
|
290
333
|
try:
|
|
291
334
|
f = open(stats_file, "r")
|
|
292
335
|
except:
|
|
@@ -299,7 +342,9 @@ def was_cc_attempted(stats_file):
|
|
|
299
342
|
return False
|
|
300
343
|
|
|
301
344
|
|
|
302
|
-
def was_cc_processed(
|
|
345
|
+
def was_cc_processed(
|
|
346
|
+
stats_file: "FileDescriptorOrPath"
|
|
347
|
+
) -> Optional[bool]:
|
|
303
348
|
try:
|
|
304
349
|
f = open(stats_file, "r")
|
|
305
350
|
except:
|
|
@@ -320,8 +365,16 @@ def was_cc_processed(stats_file):
|
|
|
320
365
|
return False
|
|
321
366
|
|
|
322
367
|
|
|
323
|
-
def process_dark_files(
|
|
324
|
-
|
|
368
|
+
def process_dark_files(
|
|
369
|
+
path: "FileDescriptorOrPath",
|
|
370
|
+
scope: str,
|
|
371
|
+
rse: str,
|
|
372
|
+
latest_run: str,
|
|
373
|
+
max_dark_fraction: float,
|
|
374
|
+
max_files_at_site: int,
|
|
375
|
+
old_enough_run: str,
|
|
376
|
+
force_proceed: bool
|
|
377
|
+
) -> None:
|
|
325
378
|
|
|
326
379
|
"""
|
|
327
380
|
Process the Dark Files.
|
|
@@ -434,8 +487,16 @@ def process_dark_files(path, scope, rse, latest_run, max_dark_fraction,
|
|
|
434
487
|
METRICS.gauge('actions_dark_files_deleted.{rse}').labels(**labels).set(deleted_files)
|
|
435
488
|
|
|
436
489
|
|
|
437
|
-
def process_miss_files(
|
|
438
|
-
|
|
490
|
+
def process_miss_files(
|
|
491
|
+
path: "FileDescriptorOrPath",
|
|
492
|
+
scope: str,
|
|
493
|
+
rse: str,
|
|
494
|
+
latest_run: str,
|
|
495
|
+
max_miss_fraction: float,
|
|
496
|
+
max_files_at_site: int,
|
|
497
|
+
old_enough_run: Optional[str],
|
|
498
|
+
force_proceed: bool
|
|
499
|
+
) -> None:
|
|
439
500
|
|
|
440
501
|
"""
|
|
441
502
|
Process the Missing Replicas.
|
|
@@ -529,8 +590,15 @@ def process_miss_files(path, scope, rse, latest_run, max_miss_fraction,
|
|
|
529
590
|
METRICS.gauge('actions_miss_files_to_retransfer.{rse}').labels(**labels).set(invalidated_files)
|
|
530
591
|
|
|
531
592
|
|
|
532
|
-
def deckard(
|
|
533
|
-
|
|
593
|
+
def deckard(
|
|
594
|
+
scope: str,
|
|
595
|
+
rse: str,
|
|
596
|
+
dark_min_age: int,
|
|
597
|
+
dark_threshold_percent: float,
|
|
598
|
+
miss_threshold_percent: float,
|
|
599
|
+
force_proceed: bool,
|
|
600
|
+
scanner_files_path: "FileDescriptorOrPath"
|
|
601
|
+
) -> None:
|
|
534
602
|
|
|
535
603
|
"""
|
|
536
604
|
The core of CC actions.
|
|
@@ -611,7 +679,7 @@ def deckard(scope, rse, dark_min_age, dark_threshold_percent, miss_threshold_per
|
|
|
611
679
|
max_files_at_site, old_enough_run, force_proceed)
|
|
612
680
|
else:
|
|
613
681
|
logger(logging.INFO, 'There is no other run for this RSE at least %d days older,\
|
|
614
|
-
so cannot safely proceed with dark files
|
|
682
|
+
so cannot safely proceed with dark files deletion.' % minagedark)
|
|
615
683
|
|
|
616
684
|
process_miss_files(path, scope, rse, latest_run, max_miss_fraction,
|
|
617
685
|
max_files_at_site, old_enough_run, force_proceed)
|
|
@@ -625,8 +693,15 @@ def deckard(scope, rse, dark_min_age, dark_threshold_percent, miss_threshold_per
|
|
|
625
693
|
logger(logging.INFO, 'No scans available for this RSE')
|
|
626
694
|
|
|
627
695
|
|
|
628
|
-
def deckard_loop(
|
|
629
|
-
|
|
696
|
+
def deckard_loop(
|
|
697
|
+
scope: str,
|
|
698
|
+
rses: "Iterable[str]",
|
|
699
|
+
dark_min_age: int,
|
|
700
|
+
dark_threshold_percent: float,
|
|
701
|
+
miss_threshold_percent: float,
|
|
702
|
+
force_proceed: bool,
|
|
703
|
+
scanner_files_path: "FileDescriptorOrPath"
|
|
704
|
+
) -> None:
|
|
630
705
|
|
|
631
706
|
prefix = 'storage-consistency-actions (deckard_loop())'
|
|
632
707
|
logger = formatted_logger(logging.log, prefix + '%s')
|
|
@@ -637,8 +712,17 @@ def deckard_loop(scope, rses, dark_min_age, dark_threshold_percent, miss_thresho
|
|
|
637
712
|
force_proceed, scanner_files_path)
|
|
638
713
|
|
|
639
714
|
|
|
640
|
-
def actions_loop(
|
|
641
|
-
|
|
715
|
+
def actions_loop(
|
|
716
|
+
once: bool,
|
|
717
|
+
scope: str,
|
|
718
|
+
rses: "Sequence[str]",
|
|
719
|
+
sleep_time: int,
|
|
720
|
+
dark_min_age: int,
|
|
721
|
+
dark_threshold_percent: float,
|
|
722
|
+
miss_threshold_percent: float,
|
|
723
|
+
force_proceed: bool,
|
|
724
|
+
scanner_files_path: "FileDescriptorOrPath"
|
|
725
|
+
) -> None:
|
|
642
726
|
|
|
643
727
|
"""
|
|
644
728
|
Main loop to apply the CC actions
|
|
@@ -687,16 +771,25 @@ def actions_loop(once, scope, rses, sleep_time, dark_min_age, dark_threshold_per
|
|
|
687
771
|
die(executable=DAEMON_NAME, hostname=hostname, pid=pid, thread=current_thread)
|
|
688
772
|
|
|
689
773
|
|
|
690
|
-
def stop(signum:
|
|
774
|
+
def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
|
|
691
775
|
"""
|
|
692
776
|
Graceful exit.
|
|
693
777
|
"""
|
|
694
778
|
graceful_stop.set()
|
|
695
779
|
|
|
696
780
|
|
|
697
|
-
def run(
|
|
698
|
-
|
|
699
|
-
|
|
781
|
+
def run(
|
|
782
|
+
once: bool = False,
|
|
783
|
+
scope: Optional[str] = None,
|
|
784
|
+
rses: Optional["Sequence[str]"] = None,
|
|
785
|
+
sleep_time: int = 60,
|
|
786
|
+
default_dark_min_age: int = 28,
|
|
787
|
+
default_dark_threshold_percent: float = 1.0,
|
|
788
|
+
default_miss_threshold_percent: float = 1.0,
|
|
789
|
+
force_proceed: bool = False,
|
|
790
|
+
default_scanner_files_path: "FileDescriptorOrPath" = "/var/cache/consistency-dump",
|
|
791
|
+
threads: int = 1
|
|
792
|
+
) -> None:
|
|
700
793
|
"""
|
|
701
794
|
Starts up the Consistency-Actions.
|
|
702
795
|
"""
|
|
@@ -735,19 +828,19 @@ def run(once=False, scope=None, rses=None, sleep_time=60, default_dark_min_age=2
|
|
|
735
828
|
threads = 1
|
|
736
829
|
|
|
737
830
|
if once:
|
|
738
|
-
actions_loop(once, scope, rses, sleep_time, dark_min_age, dark_threshold_percent,
|
|
831
|
+
actions_loop(once, scope, rses, sleep_time, dark_min_age, dark_threshold_percent, # type: ignore (scope and rses might be None)
|
|
739
832
|
miss_threshold_percent, force_proceed, scanner_files_path)
|
|
740
833
|
else:
|
|
741
834
|
logging.info('Consistency Actions starting %s threads' % str(threads))
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
logger(logging.INFO, 'Threads: %d' % len(
|
|
750
|
-
[t.start() for t in
|
|
835
|
+
thread_list = [threading.Thread(target=actions_loop,
|
|
836
|
+
kwargs={'once': once, 'scope': scope, 'rses': rses, 'sleep_time': sleep_time,
|
|
837
|
+
'dark_min_age': dark_min_age,
|
|
838
|
+
'dark_threshold_percent': dark_threshold_percent,
|
|
839
|
+
'miss_threshold_percent': miss_threshold_percent,
|
|
840
|
+
'force_proceed': force_proceed,
|
|
841
|
+
'scanner_files_path': scanner_files_path}) for i in range(0, threads)]
|
|
842
|
+
logger(logging.INFO, 'Threads: %d' % len(thread_list))
|
|
843
|
+
[t.start() for t in thread_list]
|
|
751
844
|
# Interruptible joins require a timeout.
|
|
752
|
-
while
|
|
753
|
-
[t.join(timeout=3.14) for t in
|
|
845
|
+
while thread_list[0].is_alive():
|
|
846
|
+
[t.join(timeout=3.14) for t in thread_list]
|
rucio/daemons/tracer/__init__.py
CHANGED
rucio/daemons/tracer/kronos.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -22,30 +21,34 @@ import logging
|
|
|
22
21
|
import re
|
|
23
22
|
from configparser import NoOptionError, NoSectionError
|
|
24
23
|
from datetime import datetime
|
|
25
|
-
from json import
|
|
24
|
+
from json import dumps as jdumps
|
|
25
|
+
from json import loads as jloads
|
|
26
26
|
from queue import Queue
|
|
27
27
|
from threading import Event, Thread
|
|
28
28
|
from time import time
|
|
29
|
-
from typing import TYPE_CHECKING
|
|
29
|
+
from typing import TYPE_CHECKING, Optional
|
|
30
30
|
|
|
31
31
|
import rucio.db.sqla.util
|
|
32
32
|
from rucio.common.config import config_get, config_get_bool, config_get_int, config_get_list
|
|
33
|
-
from rucio.common.exception import
|
|
33
|
+
from rucio.common.exception import DatabaseException, RSENotFound
|
|
34
34
|
from rucio.common.logging import setup_logging
|
|
35
35
|
from rucio.common.stomp_utils import StompConnectionManager
|
|
36
36
|
from rucio.common.stopwatch import Stopwatch
|
|
37
|
-
from rucio.common.types import InternalAccount, InternalScope
|
|
38
|
-
from rucio.core.did import
|
|
37
|
+
from rucio.common.types import InternalAccount, InternalScope, LoggerFunction
|
|
38
|
+
from rucio.core.did import list_parent_dids, touch_dids
|
|
39
39
|
from rucio.core.lock import touch_dataset_locks
|
|
40
40
|
from rucio.core.monitor import MetricManager
|
|
41
|
-
from rucio.core.replica import
|
|
41
|
+
from rucio.core.replica import declare_bad_file_replicas, touch_collection_replicas, touch_replica
|
|
42
42
|
from rucio.core.rse import get_rse_id
|
|
43
43
|
from rucio.daemons.common import HeartbeatHandler, run_daemon
|
|
44
|
-
from rucio.db.sqla.constants import
|
|
44
|
+
from rucio.db.sqla.constants import BadFilesStatus, DIDType
|
|
45
45
|
|
|
46
46
|
if TYPE_CHECKING:
|
|
47
|
+
from collections.abc import Set
|
|
47
48
|
from types import FrameType
|
|
48
|
-
|
|
49
|
+
|
|
50
|
+
from stomp import Connection
|
|
51
|
+
from stomp.utils import Frame
|
|
49
52
|
|
|
50
53
|
|
|
51
54
|
logging.getLogger("stomp").setLevel(logging.CRITICAL)
|
|
@@ -57,7 +60,18 @@ graceful_stop = Event()
|
|
|
57
60
|
class AMQConsumer:
|
|
58
61
|
"""ActiveMQ message consumer"""
|
|
59
62
|
|
|
60
|
-
def __init__(
|
|
63
|
+
def __init__(
|
|
64
|
+
self,
|
|
65
|
+
broker: str,
|
|
66
|
+
conn: "Connection",
|
|
67
|
+
queue: str,
|
|
68
|
+
chunksize: int,
|
|
69
|
+
subscription_id: str,
|
|
70
|
+
excluded_usrdns: "Set[str]",
|
|
71
|
+
dataset_queue: Queue,
|
|
72
|
+
bad_files_patterns: list[re.Pattern],
|
|
73
|
+
logger: LoggerFunction = logging.log
|
|
74
|
+
):
|
|
61
75
|
self.__broker = broker
|
|
62
76
|
self.__conn = conn
|
|
63
77
|
self.__queue = queue
|
|
@@ -74,15 +88,15 @@ class AMQConsumer:
|
|
|
74
88
|
self.__logger = logger
|
|
75
89
|
|
|
76
90
|
@METRICS.count_it
|
|
77
|
-
def on_heartbeat_timeout(self):
|
|
91
|
+
def on_heartbeat_timeout(self) -> None:
|
|
78
92
|
self.__conn.disconnect()
|
|
79
93
|
|
|
80
94
|
@METRICS.count_it
|
|
81
|
-
def on_error(self, frame):
|
|
95
|
+
def on_error(self, frame: "Frame") -> None:
|
|
82
96
|
self.__logger(logging.ERROR, 'Message receive error: [%s] %s' % (self.__broker, frame.body))
|
|
83
97
|
|
|
84
98
|
@METRICS.count_it
|
|
85
|
-
def on_message(self, frame):
|
|
99
|
+
def on_message(self, frame: "Frame") -> None:
|
|
86
100
|
appversion = 'dq2'
|
|
87
101
|
msg_id = frame.headers['message-id']
|
|
88
102
|
if 'appversion' in frame.headers:
|
|
@@ -96,7 +110,7 @@ class AMQConsumer:
|
|
|
96
110
|
self.__conn.ack(msg_id, self.__subscription_id)
|
|
97
111
|
return
|
|
98
112
|
else:
|
|
99
|
-
report = jloads(frame.body)
|
|
113
|
+
report = jloads(frame.body) # type: ignore
|
|
100
114
|
except Exception:
|
|
101
115
|
# message is corrupt, not much to do here
|
|
102
116
|
# send count to graphite, send ack to broker and return
|
|
@@ -121,7 +135,7 @@ class AMQConsumer:
|
|
|
121
135
|
self.__reports = []
|
|
122
136
|
self.__ids = []
|
|
123
137
|
|
|
124
|
-
def __update_atime(self):
|
|
138
|
+
def __update_atime(self) -> None:
|
|
125
139
|
"""
|
|
126
140
|
Bulk update atime.
|
|
127
141
|
"""
|
|
@@ -142,8 +156,8 @@ class AMQConsumer:
|
|
|
142
156
|
self.__logger(logging.ERROR, 'Missing url in the following trace : ' + str(report))
|
|
143
157
|
else:
|
|
144
158
|
try:
|
|
145
|
-
|
|
146
|
-
declare_bad_file_replicas([
|
|
159
|
+
pfn = report['url']
|
|
160
|
+
declare_bad_file_replicas([pfn, ], reason=reason, issuer=InternalAccount('root', vo=report['vo']), status=BadFilesStatus.SUSPICIOUS)
|
|
147
161
|
self.__logger(logging.INFO, 'Declare suspicious file %s with reason %s' % (report['url'], reason))
|
|
148
162
|
except Exception as error:
|
|
149
163
|
self.__logger(logging.ERROR, 'Failed to declare suspicious file' + str(error))
|
|
@@ -297,7 +311,11 @@ class AMQConsumer:
|
|
|
297
311
|
METRICS.counter('updated_replicas').inc()
|
|
298
312
|
|
|
299
313
|
|
|
300
|
-
def kronos_file(
|
|
314
|
+
def kronos_file(
|
|
315
|
+
once: bool = False,
|
|
316
|
+
dataset_queue: Optional[Queue] = None,
|
|
317
|
+
sleep_time: int = 60
|
|
318
|
+
) -> None:
|
|
301
319
|
"""
|
|
302
320
|
Main loop to consume tracer reports.
|
|
303
321
|
"""
|
|
@@ -311,14 +329,14 @@ def kronos_file(once: bool = False, dataset_queue: Queue = None, sleep_time: int
|
|
|
311
329
|
run_once_fnc=functools.partial(
|
|
312
330
|
run_once_kronos_file,
|
|
313
331
|
stomp_conn_mngr=stomp_conn_mngr,
|
|
314
|
-
dataset_queue=dataset_queue,
|
|
332
|
+
dataset_queue=dataset_queue, # type: ignore
|
|
315
333
|
sleep_time=sleep_time,
|
|
316
334
|
)
|
|
317
335
|
)
|
|
318
336
|
stomp_conn_mngr.disconnect()
|
|
319
337
|
|
|
320
338
|
|
|
321
|
-
def run_once_kronos_file(heartbeat_handler: HeartbeatHandler, stomp_conn_mngr: StompConnectionManager, dataset_queue: Queue, sleep_time: int, **kwargs):
|
|
339
|
+
def run_once_kronos_file(heartbeat_handler: HeartbeatHandler, stomp_conn_mngr: StompConnectionManager, dataset_queue: Queue, sleep_time: int, **kwargs) -> None:
|
|
322
340
|
"""
|
|
323
341
|
Run the amq consumer once.
|
|
324
342
|
"""
|
|
@@ -388,7 +406,7 @@ def run_once_kronos_file(heartbeat_handler: HeartbeatHandler, stomp_conn_mngr: S
|
|
|
388
406
|
conn.subscribe(destination=config_get('tracer-kronos', 'queue'), ack='client-individual', id=subscription_id, headers={'activemq.prefetchSize': prefetch_size})
|
|
389
407
|
|
|
390
408
|
|
|
391
|
-
def kronos_dataset(dataset_queue: Queue, once: bool = False, sleep_time: int = 60):
|
|
409
|
+
def kronos_dataset(dataset_queue: Queue, once: bool = False, sleep_time: int = 60) -> None:
|
|
392
410
|
return_values = {'heartbeat_handler': HeartbeatHandler("kronos-dataset", 10)}
|
|
393
411
|
run_daemon(
|
|
394
412
|
once=once,
|
|
@@ -407,7 +425,7 @@ def kronos_dataset(dataset_queue: Queue, once: bool = False, sleep_time: int = 6
|
|
|
407
425
|
run_once_kronos_dataset(dataset_queue=dataset_queue, return_values=return_values, heartbeat_handler=return_values['heartbeat_handler'], sleep_time=sleep_time)
|
|
408
426
|
|
|
409
427
|
|
|
410
|
-
def run_once_kronos_dataset(dataset_queue: Queue, return_values: dict, heartbeat_handler: HeartbeatHandler, **kwargs):
|
|
428
|
+
def run_once_kronos_dataset(dataset_queue: Queue, return_values: dict, heartbeat_handler: HeartbeatHandler, **kwargs) -> None:
|
|
411
429
|
if heartbeat_handler is None:
|
|
412
430
|
if "heartbeat_handler" not in return_values.keys():
|
|
413
431
|
return_values["heartbeat_handler"] = HeartbeatHandler("kronos-dataset", 10)
|
|
@@ -477,14 +495,19 @@ def run_once_kronos_dataset(dataset_queue: Queue, return_values: dict, heartbeat
|
|
|
477
495
|
logger(logging.INFO, 'update done for %d collection replicas, %d failed (%ds)' % (total, failed, time() - start))
|
|
478
496
|
|
|
479
497
|
|
|
480
|
-
def stop(signum:
|
|
498
|
+
def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
|
|
481
499
|
"""
|
|
482
500
|
Graceful exit.
|
|
483
501
|
"""
|
|
484
502
|
graceful_stop.set()
|
|
485
503
|
|
|
486
504
|
|
|
487
|
-
def run(
|
|
505
|
+
def run(
|
|
506
|
+
once: bool = False,
|
|
507
|
+
threads: int = 1,
|
|
508
|
+
sleep_time_datasets: int = 60,
|
|
509
|
+
sleep_time_files: int = 60
|
|
510
|
+
) -> None:
|
|
488
511
|
"""
|
|
489
512
|
Starts up the consumer threads
|
|
490
513
|
"""
|