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
rucio/common/dumper/__init__.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,6 +21,7 @@ import os
|
|
|
22
21
|
import re
|
|
23
22
|
import sys
|
|
24
23
|
import tempfile
|
|
24
|
+
from typing import TYPE_CHECKING, Any, Literal, Optional, Union
|
|
25
25
|
|
|
26
26
|
import gfal2
|
|
27
27
|
import magic
|
|
@@ -30,29 +30,39 @@ import requests
|
|
|
30
30
|
from rucio.common import config
|
|
31
31
|
from rucio.core.rse import get_rse_id, get_rse_protocols
|
|
32
32
|
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
from collections.abc import Iterator
|
|
35
|
+
from multiprocessing.connection import Connection
|
|
36
|
+
from types import ModuleType
|
|
37
|
+
from typing import IO, TextIO
|
|
38
|
+
|
|
39
|
+
from _typeshed import FileDescriptorOrPath, GenericPath, StrOrBytesPath
|
|
40
|
+
|
|
41
|
+
from rucio.common.types import RSEProtocolDict
|
|
42
|
+
|
|
33
43
|
|
|
34
44
|
class HTTPDownloadFailed(Exception):
|
|
35
|
-
def __init__(self, msg='', code=None):
|
|
45
|
+
def __init__(self, msg: str = '', code: Optional[str] = None):
|
|
36
46
|
self.code = code
|
|
37
47
|
if code is not None:
|
|
38
48
|
msg = '{0} (Status {1})'.format(msg, code)
|
|
39
49
|
super(HTTPDownloadFailed, self).__init__(msg)
|
|
40
50
|
|
|
41
51
|
|
|
42
|
-
class LogPipeHandler(logging.Handler
|
|
43
|
-
def __init__(self, pipe):
|
|
52
|
+
class LogPipeHandler(logging.Handler):
|
|
53
|
+
def __init__(self, pipe: "Connection"):
|
|
44
54
|
super(LogPipeHandler, self).__init__()
|
|
45
55
|
self.pipe = pipe
|
|
46
56
|
|
|
47
|
-
def emit(self, record):
|
|
57
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
48
58
|
self.pipe.send(self.format(record))
|
|
49
59
|
|
|
50
|
-
def close(self):
|
|
60
|
+
def close(self) -> None:
|
|
51
61
|
super(LogPipeHandler, self).close()
|
|
52
62
|
self.pipe.close()
|
|
53
63
|
|
|
54
64
|
|
|
55
|
-
def error(text, exit_code=1):
|
|
65
|
+
def error(text: str, exit_code: int = 1) -> None:
|
|
56
66
|
'''
|
|
57
67
|
Log and print `text` error. This function ends the execution of the program with exit code
|
|
58
68
|
`exit_code` (defaults to 1).
|
|
@@ -63,7 +73,7 @@ def error(text, exit_code=1):
|
|
|
63
73
|
exit(1)
|
|
64
74
|
|
|
65
75
|
|
|
66
|
-
def mkdir(dir_):
|
|
76
|
+
def mkdir(dir_: "StrOrBytesPath") -> None:
|
|
67
77
|
'''
|
|
68
78
|
This functions creates the `dir_` directory if it doesn't exist. If `dir_`
|
|
69
79
|
already exists this function does nothing.
|
|
@@ -71,10 +81,11 @@ def mkdir(dir_):
|
|
|
71
81
|
try:
|
|
72
82
|
os.mkdir(dir_)
|
|
73
83
|
except OSError as error:
|
|
74
|
-
|
|
84
|
+
if error.errno != 17:
|
|
85
|
+
raise error
|
|
75
86
|
|
|
76
87
|
|
|
77
|
-
def cacert_config(config, rucio_home):
|
|
88
|
+
def cacert_config(config: "ModuleType", rucio_home: str) -> Optional[Union["FileDescriptorOrPath", Literal[False]]]:
|
|
78
89
|
logger = logging.getLogger('dumper.__init__')
|
|
79
90
|
try:
|
|
80
91
|
cacert = config.config_get('client', 'ca_cert').replace('$RUCIO_HOME', rucio_home)
|
|
@@ -88,13 +99,13 @@ def cacert_config(config, rucio_home):
|
|
|
88
99
|
return cacert
|
|
89
100
|
|
|
90
101
|
|
|
91
|
-
def rucio_home():
|
|
102
|
+
def rucio_home() -> str:
|
|
92
103
|
return os.environ.get('RUCIO_HOME', '/opt/rucio')
|
|
93
104
|
|
|
94
105
|
|
|
95
|
-
def get_requests_session():
|
|
106
|
+
def get_requests_session() -> requests.Session:
|
|
96
107
|
requests_session = requests.Session()
|
|
97
|
-
requests_session.verify = cacert_config(config, rucio_home())
|
|
108
|
+
requests_session.verify = cacert_config(config, rucio_home()) # type: ignore
|
|
98
109
|
requests_session.stream = True
|
|
99
110
|
return requests_session
|
|
100
111
|
|
|
@@ -116,7 +127,7 @@ else:
|
|
|
116
127
|
# pylint: enable=no-member
|
|
117
128
|
|
|
118
129
|
|
|
119
|
-
def isplaintext(filename):
|
|
130
|
+
def isplaintext(filename: "GenericPath") -> bool:
|
|
120
131
|
'''
|
|
121
132
|
Returns True if `filename` has mimetype == 'text/plain'.
|
|
122
133
|
'''
|
|
@@ -125,7 +136,7 @@ def isplaintext(filename):
|
|
|
125
136
|
return mimetype(filename).split(';')[0] == 'text/plain'
|
|
126
137
|
|
|
127
138
|
|
|
128
|
-
def smart_open(filename):
|
|
139
|
+
def smart_open(filename: "GenericPath") -> Optional[Union["TextIO", gzip.GzipFile]]:
|
|
129
140
|
'''
|
|
130
141
|
Returns an open file object if `filename` is plain text, else assumes
|
|
131
142
|
it is a bzip2 compressed file and returns a file-like object to
|
|
@@ -146,14 +157,18 @@ def smart_open(filename):
|
|
|
146
157
|
|
|
147
158
|
|
|
148
159
|
@contextlib.contextmanager
|
|
149
|
-
def temp_file(
|
|
160
|
+
def temp_file(
|
|
161
|
+
directory: str,
|
|
162
|
+
final_name: Optional[str] = None,
|
|
163
|
+
binary: bool = False
|
|
164
|
+
) -> "Iterator[tuple[IO[Any], StrOrBytesPath]]":
|
|
150
165
|
'''
|
|
151
166
|
Allows to create a temporal file to store partial results, when the
|
|
152
167
|
file is complete it is renamed to `final_name`.
|
|
153
168
|
|
|
154
169
|
- `directory`: working path to create the temporal and the final file.
|
|
155
170
|
- `final_name`: Path of the final file, relative to `directory`.
|
|
156
|
-
If the `final_name` is omitted or None the renaming step is
|
|
171
|
+
If the `final_name` is omitted or None the renaming step is omitted,
|
|
157
172
|
leaving the temporal file with the results.
|
|
158
173
|
- `binary`: whether to open the file in binary mode (default: False).
|
|
159
174
|
|
|
@@ -193,7 +208,7 @@ DATETIME_FORMAT_FULL = '%Y-%m-%dT%H:%M:%S'
|
|
|
193
208
|
MILLISECONDS_RE = re.compile(r'\.(\d{3})Z$')
|
|
194
209
|
|
|
195
210
|
|
|
196
|
-
def to_datetime(str_or_datetime):
|
|
211
|
+
def to_datetime(str_or_datetime: Union[datetime.datetime, str]) -> Optional[datetime.datetime]:
|
|
197
212
|
"""
|
|
198
213
|
Convert string to datetime. The format is somewhat flexible.
|
|
199
214
|
Timezone information is ignored.
|
|
@@ -221,51 +236,65 @@ def to_datetime(str_or_datetime):
|
|
|
221
236
|
'Trying to parse "%s" date with resolution of milliseconds',
|
|
222
237
|
str_or_datetime,
|
|
223
238
|
)
|
|
224
|
-
|
|
239
|
+
milliseconds = int(MILLISECONDS_RE.search(str_or_datetime).group(1))
|
|
225
240
|
str_or_datetime = MILLISECONDS_RE.sub('', str_or_datetime)
|
|
226
241
|
date = datetime.datetime.strptime(
|
|
227
242
|
str_or_datetime,
|
|
228
243
|
DATETIME_FORMAT,
|
|
229
244
|
)
|
|
230
|
-
date = date + datetime.timedelta(microseconds=
|
|
245
|
+
date = date + datetime.timedelta(microseconds=milliseconds * 1000)
|
|
231
246
|
return date
|
|
232
247
|
|
|
233
248
|
|
|
234
|
-
def ddmendpoint_preferred_protocol(ddmendpoint):
|
|
249
|
+
def ddmendpoint_preferred_protocol(ddmendpoint: str) -> "RSEProtocolDict":
|
|
235
250
|
return next(p for p in get_rse_protocols(get_rse_id(ddmendpoint))['protocols'] if p['domains']['wan']['read'] == 1)
|
|
236
251
|
|
|
237
252
|
|
|
238
|
-
def ddmendpoint_url(ddmendpoint):
|
|
253
|
+
def ddmendpoint_url(ddmendpoint: str) -> str:
|
|
239
254
|
preferred_protocol = ddmendpoint_preferred_protocol(ddmendpoint)
|
|
240
255
|
prefix = re.sub(r'rucio/$', '', preferred_protocol['prefix'])
|
|
241
256
|
return '{scheme}://{hostname}:{port}'.format(**preferred_protocol) + prefix
|
|
242
257
|
|
|
243
258
|
|
|
244
|
-
def http_download_to_file(url, file_, session=None):
|
|
259
|
+
def http_download_to_file(url: str, file_: "IO", session: Optional[requests.Session] = None) -> None:
|
|
245
260
|
'''
|
|
246
261
|
Download the file in `url` storing it in the `file_` file-like
|
|
247
262
|
object.
|
|
248
263
|
If given `session` must be a requests.Session instance, and will be
|
|
249
264
|
used to download the file, otherwise requests.get() will be used.
|
|
250
265
|
'''
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
266
|
+
def _do_download(url, file_, session, try_decode=False):
|
|
267
|
+
if session is None:
|
|
268
|
+
response = requests.get(url, stream=True)
|
|
269
|
+
else:
|
|
270
|
+
response = session.get(url)
|
|
271
|
+
|
|
272
|
+
if response.status_code != 200:
|
|
273
|
+
logging.error(
|
|
274
|
+
'Retrieving %s returned %d status code',
|
|
275
|
+
url,
|
|
276
|
+
response.status_code,
|
|
277
|
+
)
|
|
278
|
+
raise HTTPDownloadFailed('Error downloading ' + url, str(response.status_code))
|
|
279
|
+
|
|
280
|
+
if try_decode:
|
|
281
|
+
if response.encoding is None:
|
|
282
|
+
response.encoding = 'utf-8'
|
|
283
|
+
for chunk in response.iter_content(CHUNK_SIZE, decode_unicode=True):
|
|
284
|
+
file_.write(chunk)
|
|
285
|
+
else:
|
|
286
|
+
for chunk in response.iter_content(CHUNK_SIZE):
|
|
287
|
+
file_.write(chunk)
|
|
263
288
|
|
|
264
|
-
|
|
265
|
-
|
|
289
|
+
try:
|
|
290
|
+
# try without decoding first
|
|
291
|
+
_do_download(url, file_, session, False)
|
|
292
|
+
except TypeError:
|
|
293
|
+
# if that fails due to writing binary data to text file, try to force decode
|
|
294
|
+
_do_download(url, file_, session, True)
|
|
266
295
|
|
|
267
296
|
|
|
268
|
-
def http_download(url, filename):
|
|
297
|
+
def http_download(url: str, filename: "FileDescriptorOrPath") -> None:
|
|
269
298
|
'''
|
|
270
299
|
Download the file in `url` storing it in the path given by `filename`.
|
|
271
300
|
'''
|
|
@@ -273,7 +302,7 @@ def http_download(url, filename):
|
|
|
273
302
|
http_download_to_file(url, f)
|
|
274
303
|
|
|
275
304
|
|
|
276
|
-
def gfal_download_to_file(url, file_):
|
|
305
|
+
def gfal_download_to_file(url: str, file_: "IO") -> None:
|
|
277
306
|
'''
|
|
278
307
|
Download the file in `url` storing it in the `file_` file-like
|
|
279
308
|
object.
|
|
@@ -286,7 +315,7 @@ def gfal_download_to_file(url, file_):
|
|
|
286
315
|
chunk = infile.read(CHUNK_SIZE)
|
|
287
316
|
except gfal2.GError as e:
|
|
288
317
|
if e.code == 70:
|
|
289
|
-
logger.debug('GError(70) raised, using GRIDFTP PLUGIN:STAT_ON_OPEN=False
|
|
318
|
+
logger.debug('GError(70) raised, using GRIDFTP PLUGIN:STAT_ON_OPEN=False workaround to download %s', url)
|
|
290
319
|
ctx.set_opt_boolean('GRIDFTP PLUGIN', 'STAT_ON_OPEN', False)
|
|
291
320
|
infile = ctx.open(url, 'r')
|
|
292
321
|
chunk = infile.read(CHUNK_SIZE)
|
|
@@ -298,7 +327,7 @@ def gfal_download_to_file(url, file_):
|
|
|
298
327
|
chunk = infile.read(CHUNK_SIZE)
|
|
299
328
|
|
|
300
329
|
|
|
301
|
-
def gfal_download(url, filename):
|
|
330
|
+
def gfal_download(url: str, filename: "FileDescriptorOrPath") -> None:
|
|
302
331
|
'''
|
|
303
332
|
Download the file in `url` storing it in the path given by `filename`.
|
|
304
333
|
'''
|
|
@@ -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");
|
|
@@ -19,9 +18,10 @@ import os
|
|
|
19
18
|
import re
|
|
20
19
|
import subprocess
|
|
21
20
|
import tempfile
|
|
21
|
+
from typing import cast
|
|
22
22
|
|
|
23
23
|
from rucio.common import dumper
|
|
24
|
-
from rucio.common.dumper import
|
|
24
|
+
from rucio.common.dumper import DUMPS_CACHE_DIR, data_models, error, path_parsing
|
|
25
25
|
|
|
26
26
|
subcommands = ['consistency', 'consistency-manual']
|
|
27
27
|
|
|
@@ -42,10 +42,12 @@ class Consistency(data_models.DataModel):
|
|
|
42
42
|
ddm_endpoint, prev_date, cache_dir=cache_dir)
|
|
43
43
|
next_date_fname = data_models.Replica.download(
|
|
44
44
|
ddm_endpoint, next_date, cache_dir=cache_dir)
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
if (prev_date_fname is None) or (next_date_fname is None):
|
|
46
|
+
raise ValueError("Both prev_date_fname and next_date_fname are required for subcommand='consistency'; found prev_data_fname=%s and next_date_fname=%s" % (prev_date_fname, next_date_fname))
|
|
47
|
+
elif subcommand == 'consistency-manual':
|
|
48
|
+
pass
|
|
47
49
|
else:
|
|
48
|
-
|
|
50
|
+
raise ValueError("subcommand %s not accepted, choice from ('consistency','consistency-manual')" % subcommand)
|
|
49
51
|
|
|
50
52
|
prefix_components = path_parsing.components(dumper.ddmendpoint_url(ddm_endpoint))
|
|
51
53
|
|
|
@@ -67,7 +69,7 @@ class Consistency(data_models.DataModel):
|
|
|
67
69
|
Parser to have consistent paths in storage dumps.
|
|
68
70
|
|
|
69
71
|
:param line: String with one line of a dump.
|
|
70
|
-
:returns: Path
|
|
72
|
+
:returns: Path formatted as in the Rucio Replica Dumps.
|
|
71
73
|
'''
|
|
72
74
|
relative = path_parsing.remove_prefix(
|
|
73
75
|
prefix_components,
|
|
@@ -162,13 +164,14 @@ def _try_to_advance(it, default=None):
|
|
|
162
164
|
return el.strip()
|
|
163
165
|
|
|
164
166
|
|
|
165
|
-
def
|
|
167
|
+
def min_value(*values):
|
|
166
168
|
'''
|
|
167
|
-
Minimum between the
|
|
169
|
+
Minimum between the input values, ignoring None
|
|
168
170
|
'''
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
171
|
+
values_without_none = cast('list[str]', [value for value in values if value is not None])
|
|
172
|
+
if len(values_without_none) == 0:
|
|
173
|
+
raise ValueError("Input contains 0 non-null values.")
|
|
174
|
+
return min(values_without_none)
|
|
172
175
|
|
|
173
176
|
|
|
174
177
|
def split_if_not_none(value, sep=',', fields=2):
|
|
@@ -199,7 +202,7 @@ def compare3(it0, it1, it2):
|
|
|
199
202
|
path0, status0 = split_if_not_none(v0)
|
|
200
203
|
path2, status2 = split_if_not_none(v2)
|
|
201
204
|
|
|
202
|
-
vmin =
|
|
205
|
+
vmin = min_value(path0, v1, path2)
|
|
203
206
|
in0 = in1 = in2 = False
|
|
204
207
|
in0_status = in2_status = None
|
|
205
208
|
|
|
@@ -292,7 +295,7 @@ def gnu_sort(file_path, prefix=None, delimiter=None, fieldspec=None, cache_dir=D
|
|
|
292
295
|
|
|
293
296
|
:param prefix: If given the output file will be named <prefix>_sorted.
|
|
294
297
|
Otherwise the prefix is the name of the input file.
|
|
295
|
-
:param delimiter: Delimiter character if the data is
|
|
298
|
+
:param delimiter: Delimiter character if the data is formatted in
|
|
296
299
|
columns (argument of -t in the sort command).
|
|
297
300
|
:param fieldspec: String with the specification of column or columns
|
|
298
301
|
to be used to sort (argument -k in the sort command).
|
|
@@ -302,7 +305,8 @@ def gnu_sort(file_path, prefix=None, delimiter=None, fieldspec=None, cache_dir=D
|
|
|
302
305
|
memory and it is relatively fast if used with the environment variable
|
|
303
306
|
LC_ALL set to C as in this function.
|
|
304
307
|
'''
|
|
305
|
-
|
|
308
|
+
if (delimiter is not None) ^ (fieldspec is not None):
|
|
309
|
+
raise ValueError("Either both delimiter and fieldspec is set, or neither are.")
|
|
306
310
|
if delimiter is None:
|
|
307
311
|
cmd_line = 'LC_ALL=C sort {0} > {1}'
|
|
308
312
|
else:
|
|
@@ -316,23 +320,21 @@ def gnu_sort(file_path, prefix=None, delimiter=None, fieldspec=None, cache_dir=D
|
|
|
316
320
|
if os.path.exists(sorted_path):
|
|
317
321
|
return sorted_path
|
|
318
322
|
|
|
319
|
-
|
|
320
|
-
# threat in some scenarios. Find another way to do it.
|
|
321
|
-
tfile = tempfile.mktemp(dir=cache_dir)
|
|
323
|
+
tfile = tempfile.NamedTemporaryFile(dir=cache_dir, delete=False)
|
|
322
324
|
|
|
323
325
|
subprocess.check_call(
|
|
324
|
-
cmd_line.format(file_path, tfile),
|
|
326
|
+
cmd_line.format(file_path, tfile.name),
|
|
325
327
|
shell=True,
|
|
326
328
|
)
|
|
327
329
|
|
|
328
|
-
os.link(tfile, sorted_path)
|
|
329
|
-
os.unlink(tfile)
|
|
330
|
+
os.link(tfile.name, sorted_path)
|
|
331
|
+
os.unlink(tfile.name)
|
|
330
332
|
|
|
331
333
|
return sorted_path
|
|
332
334
|
|
|
333
335
|
|
|
334
336
|
def populate_args(argparser):
|
|
335
|
-
# Option to download the rucio replica dumps
|
|
337
|
+
# Option to download the rucio replica dumps automatically
|
|
336
338
|
parser = argparser.add_parser(
|
|
337
339
|
'consistency',
|
|
338
340
|
help='Consistency check to verify possible lost files and dark data '
|
|
@@ -391,8 +393,10 @@ def _parse_args_consistency(args):
|
|
|
391
393
|
error('The storage dump filename must be of the form '
|
|
392
394
|
'"dump_YYYYMMDD" where the date correspond to the date '
|
|
393
395
|
'of the newest files included')
|
|
396
|
+
|
|
394
397
|
date_str = date_str.group(1)
|
|
395
|
-
|
|
398
|
+
if date_str is None:
|
|
399
|
+
error('Invalid date {0}'.format(date_str))
|
|
396
400
|
try:
|
|
397
401
|
args_dict['date'] = date = datetime.datetime.strptime(date_str, '%Y%m%d')
|
|
398
402
|
except ValueError:
|
|
@@ -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");
|
|
@@ -27,16 +26,10 @@ import re
|
|
|
27
26
|
|
|
28
27
|
from tabulate import tabulate
|
|
29
28
|
|
|
30
|
-
from rucio.common.dumper import DUMPS_CACHE_DIR
|
|
31
|
-
from rucio.common.dumper import HTTPDownloadFailed
|
|
32
|
-
from rucio.common.dumper import get_requests_session
|
|
33
|
-
from rucio.common.dumper import http_download_to_file
|
|
34
|
-
from rucio.common.dumper import smart_open
|
|
35
|
-
from rucio.common.dumper import temp_file
|
|
36
|
-
from rucio.common.dumper import to_datetime
|
|
29
|
+
from rucio.common.dumper import DUMPS_CACHE_DIR, HTTPDownloadFailed, get_requests_session, http_download_to_file, smart_open, temp_file, to_datetime
|
|
37
30
|
|
|
38
31
|
|
|
39
|
-
class DataModel
|
|
32
|
+
class DataModel:
|
|
40
33
|
"""
|
|
41
34
|
Data model for the dumps
|
|
42
35
|
"""
|
|
@@ -50,7 +43,7 @@ class DataModel(object):
|
|
|
50
43
|
def __init__(self, *args):
|
|
51
44
|
if len(args) != len(self.SCHEMA):
|
|
52
45
|
raise TypeError(
|
|
53
|
-
'Wrong number of parameters (fields) to
|
|
46
|
+
'Wrong number of parameters (fields) to initialize {0} '
|
|
54
47
|
'instance. {1} given, {2} expected:\n{3}'.format(
|
|
55
48
|
type(self).__name__,
|
|
56
49
|
len(args),
|
|
@@ -157,20 +150,17 @@ class DataModel(object):
|
|
|
157
150
|
logger = logging.getLogger('auditor.data_models')
|
|
158
151
|
requests_session = get_requests_session()
|
|
159
152
|
if date == 'latest':
|
|
160
|
-
url = ''.join((cls.BASE_URL, cls.URI, '?rse={0}'.format(rse)))
|
|
153
|
+
url = ''.join((cls.BASE_URL, cls.URI, '?rse={0}'.format(rse))) # type: ignore
|
|
161
154
|
request_headers = requests_session.head(url)
|
|
162
155
|
for field in request_headers.headers['content-disposition'].split(';'):
|
|
163
156
|
if field.startswith('filename='):
|
|
164
157
|
date = field.split('=')[1].split('_')[-1].split('.')[0]
|
|
165
158
|
|
|
159
|
+
elif isinstance(date, datetime.datetime):
|
|
160
|
+
date = date.strftime('%d-%m-%Y')
|
|
161
|
+
url = ''.join((cls.BASE_URL, cls.URI, '?rse={0}&date={1}'.format(rse, date))) # type: ignore
|
|
166
162
|
else:
|
|
167
|
-
|
|
168
|
-
date = date.strftime('%d-%m-%Y') # pylint: disable=no-member
|
|
169
|
-
url = ''.join((
|
|
170
|
-
cls.BASE_URL,
|
|
171
|
-
cls.URI,
|
|
172
|
-
'?rse={0}&date={1}'.format(rse, date),
|
|
173
|
-
))
|
|
163
|
+
raise ValueError("Passed date (%s) must be a datetime object or 'latest'." % date)
|
|
174
164
|
|
|
175
165
|
if not os.path.isdir(cache_dir):
|
|
176
166
|
os.mkdir(cache_dir)
|
|
@@ -193,7 +183,7 @@ class DataModel(object):
|
|
|
193
183
|
url,
|
|
194
184
|
response.status_code,
|
|
195
185
|
)
|
|
196
|
-
raise HTTPDownloadFailed('Downloading {0} dump'.format(cls.__name__), code=response.status_code)
|
|
186
|
+
raise HTTPDownloadFailed('Downloading {0} dump'.format(cls.__name__), code=str(response.status_code))
|
|
197
187
|
|
|
198
188
|
with temp_file(cache_dir, final_name=filename) as (tfile, _):
|
|
199
189
|
http_download_to_file(url, tfile, session=requests_session)
|
|
@@ -244,7 +234,8 @@ class CompleteDataset(DataModel):
|
|
|
244
234
|
self.state = args[7]
|
|
245
235
|
else:
|
|
246
236
|
self.state = None
|
|
247
|
-
|
|
237
|
+
if len(args) > 8:
|
|
238
|
+
raise ValueError("Too many arguments, must be 8 or less. Instead passed %s" % len(args))
|
|
248
239
|
|
|
249
240
|
|
|
250
241
|
class Replica(DataModel):
|
|
@@ -271,10 +262,11 @@ class Replica(DataModel):
|
|
|
271
262
|
|
|
272
263
|
if len(args) == 8:
|
|
273
264
|
logger.warning('Missing parameter\nrse: %s\ndataset: %s\n', self.rse, self.name)
|
|
274
|
-
|
|
265
|
+
elif len(args) > 9:
|
|
266
|
+
raise ValueError("Too many arguments. Must be 9 or less, instead passed %s" % len(args))
|
|
275
267
|
|
|
276
268
|
|
|
277
|
-
class Filter
|
|
269
|
+
class Filter:
|
|
278
270
|
_Condition = collections.namedtuple('_Condition', ('comparator', 'attribute', 'expected'))
|
|
279
271
|
|
|
280
272
|
def __init__(self, filter_str, record_class):
|
|
@@ -299,7 +291,8 @@ class Filter(object):
|
|
|
299
291
|
for expr in filter_str.split(','):
|
|
300
292
|
key, expected = expr.split('=')
|
|
301
293
|
# Better checks required
|
|
302
|
-
|
|
294
|
+
if key not in record_class.get_fieldnames():
|
|
295
|
+
raise ValueError("Key %s not supported." % key)
|
|
303
296
|
parser = list(filter(lambda t: t[0] == key, record_class.SCHEMA))[0][1]
|
|
304
297
|
self.conditions.append(self._Condition(
|
|
305
298
|
comparator=operator.eq,
|