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/core/naming_convention.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");
|
|
@@ -13,27 +12,42 @@
|
|
|
13
12
|
# See the License for the specific language governing permissions and
|
|
14
13
|
# limitations under the License.
|
|
15
14
|
|
|
16
|
-
from re import
|
|
15
|
+
from re import compile, error, match
|
|
17
16
|
from traceback import format_exc
|
|
18
|
-
from typing import TYPE_CHECKING
|
|
17
|
+
from typing import TYPE_CHECKING, Any, Optional, cast
|
|
19
18
|
|
|
20
19
|
from dogpile.cache.api import NO_VALUE
|
|
20
|
+
from sqlalchemy import and_, delete, select
|
|
21
21
|
from sqlalchemy.exc import IntegrityError
|
|
22
22
|
|
|
23
23
|
from rucio.common.cache import make_region_memcached
|
|
24
|
-
from rucio.common.exception import Duplicate,
|
|
24
|
+
from rucio.common.exception import Duplicate, InvalidObject, RucioException
|
|
25
25
|
from rucio.db.sqla import models
|
|
26
26
|
from rucio.db.sqla.constants import KeyType
|
|
27
27
|
from rucio.db.sqla.session import read_session, transactional_session
|
|
28
28
|
|
|
29
29
|
if TYPE_CHECKING:
|
|
30
|
+
from typing import TypedDict
|
|
31
|
+
|
|
30
32
|
from sqlalchemy.orm import Session
|
|
31
33
|
|
|
34
|
+
from rucio.common.types import InternalScope
|
|
35
|
+
|
|
36
|
+
class NamingConventionDict(TypedDict):
|
|
37
|
+
scope: InternalScope
|
|
38
|
+
regexp: str
|
|
39
|
+
|
|
32
40
|
REGION = make_region_memcached(expiration_time=900)
|
|
33
41
|
|
|
34
42
|
|
|
35
43
|
@transactional_session
|
|
36
|
-
def add_naming_convention(
|
|
44
|
+
def add_naming_convention(
|
|
45
|
+
scope: "InternalScope",
|
|
46
|
+
regexp: str,
|
|
47
|
+
convention_type: KeyType,
|
|
48
|
+
*,
|
|
49
|
+
session: "Session"
|
|
50
|
+
) -> None:
|
|
37
51
|
"""
|
|
38
52
|
add a naming convention for a given scope
|
|
39
53
|
|
|
@@ -60,7 +74,12 @@ def add_naming_convention(scope, regexp, convention_type, *, session: "Session")
|
|
|
60
74
|
|
|
61
75
|
|
|
62
76
|
@read_session
|
|
63
|
-
def get_naming_convention(
|
|
77
|
+
def get_naming_convention(
|
|
78
|
+
scope: "InternalScope",
|
|
79
|
+
convention_type: KeyType,
|
|
80
|
+
*,
|
|
81
|
+
session: "Session"
|
|
82
|
+
) -> Optional[str]:
|
|
64
83
|
"""
|
|
65
84
|
Get the naming convention for a given scope
|
|
66
85
|
|
|
@@ -70,15 +89,22 @@ def get_naming_convention(scope, convention_type, *, session: "Session"):
|
|
|
70
89
|
|
|
71
90
|
:returns: the regular expression.
|
|
72
91
|
"""
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
92
|
+
stmt = select(
|
|
93
|
+
models.NamingConvention.regexp
|
|
94
|
+
).where(
|
|
95
|
+
and_(models.NamingConvention.scope == scope,
|
|
96
|
+
models.NamingConvention.convention_type == convention_type)
|
|
97
|
+
)
|
|
98
|
+
return session.execute(stmt).scalar()
|
|
78
99
|
|
|
79
100
|
|
|
80
101
|
@transactional_session
|
|
81
|
-
def delete_naming_convention(
|
|
102
|
+
def delete_naming_convention(
|
|
103
|
+
scope: "InternalScope",
|
|
104
|
+
convention_type: KeyType,
|
|
105
|
+
*,
|
|
106
|
+
session: "Session"
|
|
107
|
+
) -> int:
|
|
82
108
|
"""
|
|
83
109
|
delete a naming convention for a given scope
|
|
84
110
|
|
|
@@ -87,14 +113,19 @@ def delete_naming_convention(scope, convention_type, *, session: "Session"):
|
|
|
87
113
|
:param convention_type: the did_type on which the regexp should apply.
|
|
88
114
|
:param session: The database session in use.
|
|
89
115
|
"""
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
.
|
|
116
|
+
if scope.internal is not None:
|
|
117
|
+
REGION.delete(scope.internal)
|
|
118
|
+
stmt = delete(
|
|
119
|
+
models.NamingConvention
|
|
120
|
+
).where(
|
|
121
|
+
and_(models.NamingConvention.scope == scope,
|
|
122
|
+
models.NamingConvention.convention_type == convention_type)
|
|
123
|
+
)
|
|
124
|
+
return session.execute(stmt).rowcount
|
|
94
125
|
|
|
95
126
|
|
|
96
127
|
@read_session
|
|
97
|
-
def list_naming_conventions(*, session: "Session"):
|
|
128
|
+
def list_naming_conventions(*, session: "Session") -> list["NamingConventionDict"]:
|
|
98
129
|
"""
|
|
99
130
|
List all naming conventions.
|
|
100
131
|
|
|
@@ -102,13 +133,21 @@ def list_naming_conventions(*, session: "Session"):
|
|
|
102
133
|
|
|
103
134
|
:returns: a list of dictionaries.
|
|
104
135
|
"""
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
136
|
+
stmt = select(
|
|
137
|
+
models.NamingConvention.scope,
|
|
138
|
+
models.NamingConvention.regexp
|
|
139
|
+
)
|
|
140
|
+
return [cast("NamingConventionDict", row._asdict()) for row in session.execute(stmt).all()]
|
|
108
141
|
|
|
109
142
|
|
|
110
143
|
@read_session
|
|
111
|
-
def validate_name(
|
|
144
|
+
def validate_name(
|
|
145
|
+
scope: "InternalScope",
|
|
146
|
+
name: str,
|
|
147
|
+
did_type: str,
|
|
148
|
+
*,
|
|
149
|
+
session: "Session"
|
|
150
|
+
) -> Optional[dict[str, Any]]:
|
|
112
151
|
"""
|
|
113
152
|
Validate a name according to a naming convention.
|
|
114
153
|
|
|
@@ -120,10 +159,11 @@ def validate_name(scope, name, did_type, *, session: "Session"):
|
|
|
120
159
|
|
|
121
160
|
:returns: a dictionary with metadata.
|
|
122
161
|
"""
|
|
123
|
-
if scope.external
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
162
|
+
if scope.external is not None:
|
|
163
|
+
if scope.external.startswith('user'):
|
|
164
|
+
return {'project': 'user'}
|
|
165
|
+
elif scope.external.startswith('group'):
|
|
166
|
+
return {'project': 'group'}
|
|
127
167
|
|
|
128
168
|
# Check if naming convention can be found in cache region
|
|
129
169
|
regexp = REGION.get(scope.internal)
|
|
@@ -131,13 +171,14 @@ def validate_name(scope, name, did_type, *, session: "Session"):
|
|
|
131
171
|
regexp = get_naming_convention(scope=scope,
|
|
132
172
|
convention_type=KeyType.DATASET,
|
|
133
173
|
session=session)
|
|
134
|
-
|
|
174
|
+
if scope.internal is not None:
|
|
175
|
+
regexp and REGION.set(scope.internal, regexp)
|
|
135
176
|
|
|
136
177
|
if not regexp:
|
|
137
178
|
return
|
|
138
179
|
|
|
139
180
|
# Validate with regexp
|
|
140
|
-
groups = match(regexp, str(name))
|
|
181
|
+
groups = match(regexp, str(name)) # type: ignore
|
|
141
182
|
if groups:
|
|
142
183
|
meta = groups.groupdict()
|
|
143
184
|
# Hack to get task_id from version
|
rucio/core/nongrid_trace.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");
|
|
@@ -17,6 +16,7 @@ import json
|
|
|
17
16
|
import logging.handlers
|
|
18
17
|
import random
|
|
19
18
|
import socket
|
|
19
|
+
from typing import TYPE_CHECKING, Any, Union, overload
|
|
20
20
|
|
|
21
21
|
import stomp
|
|
22
22
|
|
|
@@ -24,6 +24,9 @@ from rucio.common.config import config_get, config_get_int
|
|
|
24
24
|
from rucio.common.logging import rucio_log_formatter
|
|
25
25
|
from rucio.core.monitor import MetricManager
|
|
26
26
|
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from datetime import datetime
|
|
29
|
+
|
|
27
30
|
METRICS = MetricManager(module=__name__)
|
|
28
31
|
|
|
29
32
|
CONFIG_COMMON_LOGLEVEL = getattr(logging, config_get('common', 'loglevel', raise_exception=False, default='DEBUG').upper())
|
|
@@ -80,14 +83,23 @@ for broker in BROKERS_RESOLVED:
|
|
|
80
83
|
CONNS.append(stomp.Connection(host_and_ports=[(broker, PORT)], vhost=VHOST, reconnect_attempts_max=3))
|
|
81
84
|
|
|
82
85
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
@overload
|
|
87
|
+
def date_handler(obj: "datetime") -> str:
|
|
88
|
+
...
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@overload
|
|
92
|
+
def date_handler(obj: object) -> object:
|
|
93
|
+
...
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def date_handler(obj: Any) -> Union[str, object]:
|
|
97
|
+
""" Format dates to ISO format. """
|
|
86
98
|
return obj.isoformat() if hasattr(obj, 'isoformat') else obj
|
|
87
99
|
|
|
88
100
|
|
|
89
101
|
@METRICS.count_it
|
|
90
|
-
def trace(payload):
|
|
102
|
+
def trace(payload: dict[str, Any]) -> None:
|
|
91
103
|
"""
|
|
92
104
|
Write a trace to the buffer log file and send it to active mq.
|
|
93
105
|
|
rucio/core/oidc.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");
|
|
@@ -13,46 +12,52 @@
|
|
|
13
12
|
# See the License for the specific language governing permissions and
|
|
14
13
|
# limitations under the License.
|
|
15
14
|
|
|
15
|
+
import hashlib
|
|
16
16
|
import json
|
|
17
17
|
import logging
|
|
18
|
-
import random
|
|
19
18
|
import subprocess
|
|
20
19
|
import traceback
|
|
21
20
|
from datetime import datetime, timedelta
|
|
22
|
-
from
|
|
23
|
-
from
|
|
21
|
+
from math import floor
|
|
22
|
+
from secrets import choice
|
|
23
|
+
from typing import TYPE_CHECKING, Any, Final, Optional, Union
|
|
24
|
+
from urllib.parse import parse_qs, urljoin, urlparse
|
|
24
25
|
|
|
26
|
+
import requests
|
|
27
|
+
from dogpile.cache.api import NoValue
|
|
25
28
|
from jwkest.jws import JWS
|
|
26
29
|
from jwkest.jwt import JWT
|
|
27
|
-
from math import floor
|
|
28
30
|
from oic import rndstr
|
|
29
31
|
from oic.oauth2.message import CCAccessTokenRequest
|
|
30
|
-
from oic.oic import Client, Grant, Token
|
|
31
|
-
from oic.oic.message import
|
|
32
|
-
Message, RegistrationResponse)
|
|
32
|
+
from oic.oic import REQUEST2ENDPOINT, Client, Grant, Token
|
|
33
|
+
from oic.oic.message import AccessTokenResponse, AuthorizationResponse, Message, RegistrationResponse
|
|
33
34
|
from oic.utils import time_util
|
|
34
35
|
from oic.utils.authn.client import CLIENT_AUTHN_METHOD
|
|
35
36
|
from sqlalchemy import delete, select, update
|
|
36
37
|
from sqlalchemy.sql.expression import true
|
|
37
38
|
|
|
38
39
|
from rucio.common import types
|
|
40
|
+
from rucio.common.cache import make_region_memcached
|
|
39
41
|
from rucio.common.config import config_get, config_get_int
|
|
40
|
-
from rucio.common.exception import
|
|
41
|
-
RucioException)
|
|
42
|
+
from rucio.common.exception import CannotAuthenticate, CannotAuthorize, RucioException
|
|
42
43
|
from rucio.common.stopwatch import Stopwatch
|
|
43
44
|
from rucio.common.utils import all_oidc_req_claims_present, build_url, val_to_space_sep_str
|
|
44
45
|
from rucio.core.account import account_exists
|
|
45
46
|
from rucio.core.identity import exist_identity_account, get_default_account
|
|
46
47
|
from rucio.core.monitor import MetricManager
|
|
47
|
-
from rucio.db.sqla import filter_thread_work
|
|
48
|
-
from rucio.db.sqla import models
|
|
48
|
+
from rucio.db.sqla import filter_thread_work, models
|
|
49
49
|
from rucio.db.sqla.constants import IdentityType
|
|
50
50
|
from rucio.db.sqla.session import read_session, transactional_session
|
|
51
51
|
|
|
52
52
|
if TYPE_CHECKING:
|
|
53
53
|
from sqlalchemy.orm import Session
|
|
54
54
|
|
|
55
|
+
# The WLCG Common JWT Profile dictates that the lifetime of access and ID tokens
|
|
56
|
+
# should range from five minutes to six hours.
|
|
57
|
+
TOKEN_MIN_LIFETIME: Final = config_get_int('oidc', 'token_min_lifetime', default=300)
|
|
58
|
+
TOKEN_MAX_LIFETIME: Final = config_get_int('oidc', 'token_max_lifetime', default=21600)
|
|
55
59
|
|
|
60
|
+
REGION: Final = make_region_memcached(expiration_time=TOKEN_MAX_LIFETIME)
|
|
56
61
|
METRICS = MetricManager(module=__name__)
|
|
57
62
|
|
|
58
63
|
# worokaround for a bug in pyoidc (as of Dec 2019)
|
|
@@ -75,6 +80,81 @@ LEEWAY_SECS = 120
|
|
|
75
80
|
# --> check 'profile' info (requested profile scope)
|
|
76
81
|
|
|
77
82
|
|
|
83
|
+
@METRICS.time_it
|
|
84
|
+
def _token_cache_get(
|
|
85
|
+
key: str,
|
|
86
|
+
min_lifetime: int = TOKEN_MIN_LIFETIME,
|
|
87
|
+
) -> Optional[str]:
|
|
88
|
+
"""Retrieve a token from the cache.
|
|
89
|
+
|
|
90
|
+
Return ``None`` if the cache backend did not return a value, the value is
|
|
91
|
+
not a valid JWT, or the token has a remaining lifetime less than
|
|
92
|
+
``min_lifetime`` seconds.
|
|
93
|
+
"""
|
|
94
|
+
value = REGION.get(key)
|
|
95
|
+
if isinstance(value, NoValue):
|
|
96
|
+
METRICS.counter('token_cache.miss').inc()
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
if isinstance(value, str):
|
|
100
|
+
try:
|
|
101
|
+
payload = JWT().unpack(value).payload()
|
|
102
|
+
except Exception:
|
|
103
|
+
METRICS.counter('token_cache.invalid').inc()
|
|
104
|
+
return None
|
|
105
|
+
else:
|
|
106
|
+
METRICS.counter('token_cache.invalid').inc()
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
now = datetime.utcnow().timestamp()
|
|
110
|
+
expiration = payload.get('exp', 0) # type: ignore
|
|
111
|
+
if now + min_lifetime > expiration:
|
|
112
|
+
METRICS.counter('token_cache.expired').inc()
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
METRICS.counter('token_cache.hit').inc()
|
|
116
|
+
return value
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _token_cache_set(key: str, value: str) -> None:
|
|
120
|
+
"""Store a token in the cache."""
|
|
121
|
+
REGION.set(key, value)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def request_token(audience: str, scope: str, use_cache: bool = True) -> Optional[str]:
|
|
125
|
+
"""Request a token from the provider.
|
|
126
|
+
|
|
127
|
+
Return ``None`` if the configuration was not loaded properly or the request
|
|
128
|
+
was unsuccessful.
|
|
129
|
+
"""
|
|
130
|
+
if not all([OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_PROVIDER_ENDPOINT]):
|
|
131
|
+
if OIDC_CONFIGURATION_RUN or not __load_oidc_configuration():
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
key = hashlib.md5(f'audience={audience};scope={scope}'.encode()).hexdigest()
|
|
135
|
+
|
|
136
|
+
if use_cache and (token := _token_cache_get(key)):
|
|
137
|
+
return token
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
response = requests.post(url=OIDC_PROVIDER_ENDPOINT,
|
|
141
|
+
auth=(OIDC_CLIENT_ID, OIDC_CLIENT_SECRET),
|
|
142
|
+
data={'grant_type': 'client_credentials',
|
|
143
|
+
'audience': audience,
|
|
144
|
+
'scope': scope})
|
|
145
|
+
response.raise_for_status()
|
|
146
|
+
payload = response.json()
|
|
147
|
+
token = payload['access_token']
|
|
148
|
+
except Exception:
|
|
149
|
+
logging.debug('Failed to procure a token', exc_info=True)
|
|
150
|
+
return None
|
|
151
|
+
|
|
152
|
+
if use_cache:
|
|
153
|
+
_token_cache_set(key, token)
|
|
154
|
+
|
|
155
|
+
return token
|
|
156
|
+
|
|
157
|
+
|
|
78
158
|
def __get_rucio_oidc_clients(keytimeout: int = 43200) -> tuple[dict, dict]:
|
|
79
159
|
"""
|
|
80
160
|
Creates a Rucio OIDC Client instances per Identity Provider (IdP)
|
|
@@ -125,6 +205,11 @@ def __get_rucio_oidc_clients(keytimeout: int = 43200) -> tuple[dict, dict]:
|
|
|
125
205
|
# global variables to represent the IdP clients
|
|
126
206
|
OIDC_CLIENTS = {}
|
|
127
207
|
OIDC_ADMIN_CLIENTS = {}
|
|
208
|
+
# New-style token support.
|
|
209
|
+
OIDC_CLIENT_ID = ''
|
|
210
|
+
OIDC_CLIENT_SECRET = ''
|
|
211
|
+
OIDC_PROVIDER_ENDPOINT = ''
|
|
212
|
+
OIDC_CONFIGURATION_RUN = False
|
|
128
213
|
|
|
129
214
|
|
|
130
215
|
def __initialize_oidc_clients() -> None:
|
|
@@ -143,8 +228,40 @@ def __initialize_oidc_clients() -> None:
|
|
|
143
228
|
pass
|
|
144
229
|
|
|
145
230
|
|
|
146
|
-
|
|
147
|
-
|
|
231
|
+
def __load_oidc_configuration() -> bool:
|
|
232
|
+
"""Load the configuration for the new-style token support."""
|
|
233
|
+
global OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_PROVIDER_ENDPOINT, OIDC_CONFIGURATION_RUN
|
|
234
|
+
|
|
235
|
+
OIDC_CONFIGURATION_RUN = True
|
|
236
|
+
|
|
237
|
+
if not IDPSECRETS:
|
|
238
|
+
logging.error('Configuration option "idpsecrets" in section "oidc" is not set')
|
|
239
|
+
return False
|
|
240
|
+
if not ADMIN_ISSUER_ID:
|
|
241
|
+
logging.error('Configuration option "admin_issuer" in section "oidc" is not set')
|
|
242
|
+
return False
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
with open(IDPSECRETS) as f:
|
|
246
|
+
data = json.load(f)
|
|
247
|
+
OIDC_CLIENT_ID = data[ADMIN_ISSUER_ID]['client_id']
|
|
248
|
+
OIDC_CLIENT_SECRET = data[ADMIN_ISSUER_ID]['client_secret']
|
|
249
|
+
issuer = data[ADMIN_ISSUER_ID]['issuer']
|
|
250
|
+
except Exception:
|
|
251
|
+
logging.error('Failed to parse configuration file "%s"', IDPSECRETS,
|
|
252
|
+
exc_info=True)
|
|
253
|
+
return False
|
|
254
|
+
try:
|
|
255
|
+
oidc_discover_url = urljoin(issuer, '.well-known/openid-configuration')
|
|
256
|
+
response = requests.get(oidc_discover_url)
|
|
257
|
+
response.raise_for_status()
|
|
258
|
+
payload = response.json()
|
|
259
|
+
OIDC_PROVIDER_ENDPOINT = payload['token_endpoint']
|
|
260
|
+
except (requests.HTTPError, requests.JSONDecodeError, KeyError):
|
|
261
|
+
logging.error('Failed to discover token endpoint', exc_info=True)
|
|
262
|
+
return False
|
|
263
|
+
|
|
264
|
+
return True
|
|
148
265
|
|
|
149
266
|
|
|
150
267
|
def __get_init_oidc_client(token_object: models.Token = None, token_type: str = None, **kwargs) -> dict[Any, Any]:
|
|
@@ -189,11 +306,11 @@ def __get_init_oidc_client(token_object: models.Token = None, token_type: str =
|
|
|
189
306
|
token = ''
|
|
190
307
|
if not token_type:
|
|
191
308
|
token_type = kwargs.get('token_type', None)
|
|
192
|
-
if token_type == 'subject_token':
|
|
309
|
+
if token_type == 'subject_token': # noqa: S105
|
|
193
310
|
token = token_object.token
|
|
194
311
|
# do not remove - even though None, oic expects this key to exist
|
|
195
312
|
auth_args["redirect_uri"] = None
|
|
196
|
-
if token_type == 'refresh_token':
|
|
313
|
+
if token_type == 'refresh_token': # noqa: S105
|
|
197
314
|
token = token_object.refresh_token
|
|
198
315
|
# do not remove - even though None, oic expects this key to exist
|
|
199
316
|
auth_args["redirect_uri"] = None
|
|
@@ -219,7 +336,7 @@ def __get_init_oidc_client(token_object: models.Token = None, token_type: str =
|
|
|
219
336
|
if not redirect_url:
|
|
220
337
|
redirect_to = kwargs.get("redirect_to", "auth/oidc_token")
|
|
221
338
|
redirect_urls = [u for u in client_secret["redirect_uris"] if redirect_to in u]
|
|
222
|
-
redirect_url =
|
|
339
|
+
redirect_url = choice(redirect_urls)
|
|
223
340
|
if not redirect_url:
|
|
224
341
|
raise CannotAuthenticate("Could not pick any redirect URL(s) from the ones defined "
|
|
225
342
|
+ "in Rucio OIDC Client configuration file.") # NOQA: W503
|
|
@@ -275,7 +392,7 @@ def get_auth_oidc(account: str, *, session: "Session", **kwargs) -> str:
|
|
|
275
392
|
OR a redirection url to be used in user's browser for authentication.
|
|
276
393
|
"""
|
|
277
394
|
# TO-DO - implement a check if that account already has a valid
|
|
278
|
-
# token
|
|
395
|
+
# token with the required scope and audience and return such token !
|
|
279
396
|
auth_scope = kwargs.get('auth_scope', EXPECTED_OIDC_SCOPE)
|
|
280
397
|
if not auth_scope:
|
|
281
398
|
auth_scope = EXPECTED_OIDC_SCOPE
|
|
@@ -360,7 +477,12 @@ def get_auth_oidc(account: str, *, session: "Session", **kwargs) -> str:
|
|
|
360
477
|
|
|
361
478
|
|
|
362
479
|
@transactional_session
|
|
363
|
-
def get_token_oidc(
|
|
480
|
+
def get_token_oidc(
|
|
481
|
+
auth_query_string: str,
|
|
482
|
+
ip: Optional[str] = None,
|
|
483
|
+
*,
|
|
484
|
+
session: "Session"
|
|
485
|
+
) -> Optional[dict[str, Optional[Union[str, bool]]]]:
|
|
364
486
|
"""
|
|
365
487
|
After Rucio User got redirected to Rucio /auth/oidc_token (or /auth/oidc_code)
|
|
366
488
|
REST endpoints with authz code and session state encoded within the URL.
|
|
@@ -651,8 +773,8 @@ def get_token_for_account_operation(account: str, req_audience: str = None, req_
|
|
|
651
773
|
# supported by Rucio server (have OIDC admin client registered as well)
|
|
652
774
|
# that is why we take the issuer of the account identity that has an active/valid token
|
|
653
775
|
# and look for admin account identity which has this issuer assigned
|
|
654
|
-
#
|
|
655
|
-
# this is why we first discover if the
|
|
776
|
+
# requester should always have at least one active subject token unless it is root
|
|
777
|
+
# this is why we first discover if the requester is root or not
|
|
656
778
|
get_token_for_adminacc = False
|
|
657
779
|
admin_identity = None
|
|
658
780
|
admin_issuer = None
|
|
@@ -662,10 +784,10 @@ def get_token_for_account_operation(account: str, req_audience: str = None, req_
|
|
|
662
784
|
preferred_issuer = None
|
|
663
785
|
for token in account_tokens:
|
|
664
786
|
preferred_issuer = token.identity.split(", ")[1].split("=")[1]
|
|
665
|
-
# loop through all OIDC identities
|
|
787
|
+
# loop through all OIDC identities registered for the account of the requester
|
|
666
788
|
for identity in identities:
|
|
667
789
|
issuer = identity.split(", ")[1].split("=")[1]
|
|
668
|
-
# compare the account of the
|
|
790
|
+
# compare the account of the requester with the account of the admin
|
|
669
791
|
if account == admin_iss_acc_idt_dict[issuer][0]:
|
|
670
792
|
# take first matching case which means root is requesting OIDC authentication
|
|
671
793
|
admin_identity = admin_iss_acc_idt_dict[issuer][1]
|
|
@@ -765,7 +887,7 @@ def get_token_for_account_operation(account: str, req_audience: str = None, req_
|
|
|
765
887
|
subject_token = token
|
|
766
888
|
# if not proceed with token exchange
|
|
767
889
|
if not subject_token:
|
|
768
|
-
subject_token =
|
|
890
|
+
subject_token = choice(account_tokens)
|
|
769
891
|
exchanged_token = __exchange_token_oidc(subject_token,
|
|
770
892
|
scope=req_scope,
|
|
771
893
|
audience=req_audience,
|
|
@@ -813,7 +935,7 @@ def __exchange_token_oidc(subject_token_object: models.Token, *, session: "Sessi
|
|
|
813
935
|
if not grant_type:
|
|
814
936
|
grant_type = EXCHANGE_GRANT_TYPE
|
|
815
937
|
try:
|
|
816
|
-
oidc_dict = __get_init_oidc_client(token_object=subject_token_object, token_type="subject_token")
|
|
938
|
+
oidc_dict = __get_init_oidc_client(token_object=subject_token_object, token_type="subject_token") # noqa: S106
|
|
817
939
|
oidc_client = oidc_dict['client']
|
|
818
940
|
args = {"subject_token": subject_token_object.token,
|
|
819
941
|
"scope": jwt_row_dict['authz_scope'],
|
|
@@ -891,7 +1013,7 @@ def __change_refresh_state(token: str, refresh: bool = False, *, session: "Sessi
|
|
|
891
1013
|
|
|
892
1014
|
|
|
893
1015
|
@transactional_session
|
|
894
|
-
def refresh_cli_auth_token(token_string: str, account: str, *, session: "Session"):
|
|
1016
|
+
def refresh_cli_auth_token(token_string: str, account: str, *, session: "Session") -> Optional[tuple[str, int]]:
|
|
895
1017
|
"""
|
|
896
1018
|
Checks if there is active refresh token and if so returns
|
|
897
1019
|
either active token with expiration timestamp or requests a new
|
|
@@ -1057,7 +1179,7 @@ def __refresh_token_oidc(token_object: models.Token, *, session: "Session"):
|
|
|
1057
1179
|
if datetime.utcnow() - extra_dict['refresh_start'] > timedelta(hours=extra_dict['refresh_lifetime']):
|
|
1058
1180
|
__change_refresh_state(token_object.token, refresh=False, session=session)
|
|
1059
1181
|
return None
|
|
1060
|
-
oidc_dict = __get_init_oidc_client(token_object=token_object, token_type="refresh_token")
|
|
1182
|
+
oidc_dict = __get_init_oidc_client(token_object=token_object, token_type="refresh_token") # noqa: S106
|
|
1061
1183
|
oidc_client = oidc_dict['client']
|
|
1062
1184
|
# getting a new refreshed set of tokens
|
|
1063
1185
|
state = oidc_dict['state']
|
|
@@ -1169,7 +1291,7 @@ def __get_keyvalues_from_claims(token: str, keys=None):
|
|
|
1169
1291
|
for key in keys:
|
|
1170
1292
|
value = ''
|
|
1171
1293
|
if key in claims:
|
|
1172
|
-
value = val_to_space_sep_str(claims[key])
|
|
1294
|
+
value = val_to_space_sep_str(claims[key]) # type: ignore
|
|
1173
1295
|
resdict[key] = value
|
|
1174
1296
|
return resdict
|
|
1175
1297
|
except Exception as error:
|
|
@@ -1293,7 +1415,7 @@ def validate_jwt(json_web_token: str, *, session: "Session") -> dict[str, Any]:
|
|
|
1293
1415
|
# try to get it from IdP introspection endpoint
|
|
1294
1416
|
# TO-BE-REMOVED - once all IdPs support scope and audience in token claims !!!
|
|
1295
1417
|
if not token_dict['authz_scope'] or not token_dict['audience']:
|
|
1296
|
-
clprocess = subprocess.Popen(['curl', '-s', '-L', '-u', '%s:%s'
|
|
1418
|
+
clprocess = subprocess.Popen(['curl', '-s', '-L', '-u', '%s:%s' # noqa: S607
|
|
1297
1419
|
% (oidc_client.client_id, oidc_client.client_secret),
|
|
1298
1420
|
'-d', 'token=%s' % (json_web_token),
|
|
1299
1421
|
oidc_client.introspection_endpoint],
|
|
@@ -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");
|
|
@@ -16,15 +15,18 @@
|
|
|
16
15
|
import importlib
|
|
17
16
|
from configparser import NoOptionError, NoSectionError
|
|
18
17
|
from os import environ
|
|
19
|
-
from typing import TYPE_CHECKING
|
|
18
|
+
from typing import TYPE_CHECKING, Any
|
|
20
19
|
|
|
21
20
|
from rucio.common import config, exception
|
|
22
21
|
from rucio.common.utils import check_policy_package_version
|
|
23
22
|
|
|
24
23
|
if TYPE_CHECKING:
|
|
25
24
|
from typing import Optional
|
|
25
|
+
|
|
26
26
|
from sqlalchemy.orm import Session
|
|
27
27
|
|
|
28
|
+
from rucio.common.types import InternalAccount
|
|
29
|
+
|
|
28
30
|
# dictionary of permission modules for each VO
|
|
29
31
|
permission_modules = {}
|
|
30
32
|
|
|
@@ -66,13 +68,15 @@ if not multivo:
|
|
|
66
68
|
|
|
67
69
|
try:
|
|
68
70
|
module = importlib.import_module(POLICY)
|
|
71
|
+
except ModuleNotFoundError:
|
|
72
|
+
raise exception.PolicyPackageNotFound(POLICY)
|
|
69
73
|
except ImportError:
|
|
70
|
-
raise exception.
|
|
74
|
+
raise exception.ErrorLoadingPolicyPackage(POLICY)
|
|
71
75
|
|
|
72
76
|
permission_modules["def"] = module
|
|
73
77
|
|
|
74
78
|
|
|
75
|
-
def load_permission_for_vo(vo):
|
|
79
|
+
def load_permission_for_vo(vo: str) -> None:
|
|
76
80
|
GENERIC_FALLBACK = 'generic_multi_vo'
|
|
77
81
|
if config.config_has_section('policy'):
|
|
78
82
|
try:
|
|
@@ -95,13 +99,21 @@ def load_permission_for_vo(vo):
|
|
|
95
99
|
|
|
96
100
|
try:
|
|
97
101
|
module = importlib.import_module(POLICY)
|
|
102
|
+
except ModuleNotFoundError:
|
|
103
|
+
raise exception.PolicyPackageNotFound(POLICY)
|
|
98
104
|
except ImportError:
|
|
99
|
-
raise exception.
|
|
105
|
+
raise exception.ErrorLoadingPolicyPackage(POLICY)
|
|
100
106
|
|
|
101
107
|
permission_modules[vo] = module
|
|
102
108
|
|
|
103
109
|
|
|
104
|
-
def has_permission(
|
|
110
|
+
def has_permission(
|
|
111
|
+
issuer: "InternalAccount",
|
|
112
|
+
action: str,
|
|
113
|
+
kwargs: dict[str, Any],
|
|
114
|
+
*,
|
|
115
|
+
session: "Optional[Session]" = None
|
|
116
|
+
) -> bool:
|
|
105
117
|
if issuer.vo not in permission_modules:
|
|
106
118
|
load_permission_for_vo(issuer.vo)
|
|
107
119
|
return permission_modules[issuer.vo].has_permission(issuer, action, kwargs, session=session)
|