rucio 37.0.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rucio might be problematic. Click here for more details.
- rucio/__init__.py +17 -0
- rucio/alembicrevision.py +15 -0
- rucio/cli/__init__.py +14 -0
- rucio/cli/account.py +216 -0
- rucio/cli/bin_legacy/__init__.py +13 -0
- rucio/cli/bin_legacy/rucio.py +2825 -0
- rucio/cli/bin_legacy/rucio_admin.py +2500 -0
- rucio/cli/command.py +272 -0
- rucio/cli/config.py +72 -0
- rucio/cli/did.py +191 -0
- rucio/cli/download.py +128 -0
- rucio/cli/lifetime_exception.py +33 -0
- rucio/cli/replica.py +162 -0
- rucio/cli/rse.py +293 -0
- rucio/cli/rule.py +158 -0
- rucio/cli/scope.py +40 -0
- rucio/cli/subscription.py +73 -0
- rucio/cli/upload.py +60 -0
- rucio/cli/utils.py +226 -0
- rucio/client/__init__.py +15 -0
- rucio/client/accountclient.py +432 -0
- rucio/client/accountlimitclient.py +183 -0
- rucio/client/baseclient.py +983 -0
- rucio/client/client.py +120 -0
- rucio/client/configclient.py +126 -0
- rucio/client/credentialclient.py +59 -0
- rucio/client/didclient.py +868 -0
- rucio/client/diracclient.py +56 -0
- rucio/client/downloadclient.py +1783 -0
- rucio/client/exportclient.py +44 -0
- rucio/client/fileclient.py +50 -0
- rucio/client/importclient.py +42 -0
- rucio/client/lifetimeclient.py +90 -0
- rucio/client/lockclient.py +109 -0
- rucio/client/metaconventionsclient.py +140 -0
- rucio/client/pingclient.py +44 -0
- rucio/client/replicaclient.py +452 -0
- rucio/client/requestclient.py +125 -0
- rucio/client/richclient.py +317 -0
- rucio/client/rseclient.py +746 -0
- rucio/client/ruleclient.py +294 -0
- rucio/client/scopeclient.py +90 -0
- rucio/client/subscriptionclient.py +173 -0
- rucio/client/touchclient.py +82 -0
- rucio/client/uploadclient.py +969 -0
- rucio/common/__init__.py +13 -0
- rucio/common/bittorrent.py +234 -0
- rucio/common/cache.py +111 -0
- rucio/common/checksum.py +168 -0
- rucio/common/client.py +122 -0
- rucio/common/config.py +788 -0
- rucio/common/constants.py +217 -0
- rucio/common/constraints.py +17 -0
- rucio/common/didtype.py +237 -0
- rucio/common/dumper/__init__.py +342 -0
- rucio/common/dumper/consistency.py +497 -0
- rucio/common/dumper/data_models.py +362 -0
- rucio/common/dumper/path_parsing.py +75 -0
- rucio/common/exception.py +1208 -0
- rucio/common/extra.py +31 -0
- rucio/common/logging.py +420 -0
- rucio/common/pcache.py +1409 -0
- rucio/common/plugins.py +185 -0
- rucio/common/policy.py +93 -0
- rucio/common/schema/__init__.py +200 -0
- rucio/common/schema/generic.py +416 -0
- rucio/common/schema/generic_multi_vo.py +395 -0
- rucio/common/stomp_utils.py +423 -0
- rucio/common/stopwatch.py +55 -0
- rucio/common/test_rucio_server.py +154 -0
- rucio/common/types.py +483 -0
- rucio/common/utils.py +1688 -0
- rucio/core/__init__.py +13 -0
- rucio/core/account.py +496 -0
- rucio/core/account_counter.py +236 -0
- rucio/core/account_limit.py +425 -0
- rucio/core/authentication.py +620 -0
- rucio/core/config.py +437 -0
- rucio/core/credential.py +224 -0
- rucio/core/did.py +3004 -0
- rucio/core/did_meta_plugins/__init__.py +252 -0
- rucio/core/did_meta_plugins/did_column_meta.py +331 -0
- rucio/core/did_meta_plugins/did_meta_plugin_interface.py +165 -0
- rucio/core/did_meta_plugins/elasticsearch_meta.py +407 -0
- rucio/core/did_meta_plugins/filter_engine.py +672 -0
- rucio/core/did_meta_plugins/json_meta.py +240 -0
- rucio/core/did_meta_plugins/mongo_meta.py +229 -0
- rucio/core/did_meta_plugins/postgres_meta.py +352 -0
- rucio/core/dirac.py +237 -0
- rucio/core/distance.py +187 -0
- rucio/core/exporter.py +59 -0
- rucio/core/heartbeat.py +363 -0
- rucio/core/identity.py +301 -0
- rucio/core/importer.py +260 -0
- rucio/core/lifetime_exception.py +377 -0
- rucio/core/lock.py +577 -0
- rucio/core/message.py +288 -0
- rucio/core/meta_conventions.py +203 -0
- rucio/core/monitor.py +448 -0
- rucio/core/naming_convention.py +195 -0
- rucio/core/nongrid_trace.py +136 -0
- rucio/core/oidc.py +1463 -0
- rucio/core/permission/__init__.py +161 -0
- rucio/core/permission/generic.py +1124 -0
- rucio/core/permission/generic_multi_vo.py +1144 -0
- rucio/core/quarantined_replica.py +224 -0
- rucio/core/replica.py +4483 -0
- rucio/core/replica_sorter.py +362 -0
- rucio/core/request.py +3091 -0
- rucio/core/rse.py +2079 -0
- rucio/core/rse_counter.py +185 -0
- rucio/core/rse_expression_parser.py +459 -0
- rucio/core/rse_selector.py +304 -0
- rucio/core/rule.py +4484 -0
- rucio/core/rule_grouping.py +1620 -0
- rucio/core/scope.py +181 -0
- rucio/core/subscription.py +362 -0
- rucio/core/topology.py +490 -0
- rucio/core/trace.py +375 -0
- rucio/core/transfer.py +1531 -0
- rucio/core/vo.py +169 -0
- rucio/core/volatile_replica.py +151 -0
- rucio/daemons/__init__.py +13 -0
- rucio/daemons/abacus/__init__.py +13 -0
- rucio/daemons/abacus/account.py +116 -0
- rucio/daemons/abacus/collection_replica.py +124 -0
- rucio/daemons/abacus/rse.py +117 -0
- rucio/daemons/atropos/__init__.py +13 -0
- rucio/daemons/atropos/atropos.py +242 -0
- rucio/daemons/auditor/__init__.py +289 -0
- rucio/daemons/auditor/hdfs.py +97 -0
- rucio/daemons/auditor/srmdumps.py +355 -0
- rucio/daemons/automatix/__init__.py +13 -0
- rucio/daemons/automatix/automatix.py +304 -0
- rucio/daemons/badreplicas/__init__.py +13 -0
- rucio/daemons/badreplicas/minos.py +322 -0
- rucio/daemons/badreplicas/minos_temporary_expiration.py +171 -0
- rucio/daemons/badreplicas/necromancer.py +196 -0
- rucio/daemons/bb8/__init__.py +13 -0
- rucio/daemons/bb8/bb8.py +353 -0
- rucio/daemons/bb8/common.py +759 -0
- rucio/daemons/bb8/nuclei_background_rebalance.py +153 -0
- rucio/daemons/bb8/t2_background_rebalance.py +153 -0
- rucio/daemons/cache/__init__.py +13 -0
- rucio/daemons/cache/consumer.py +133 -0
- rucio/daemons/common.py +405 -0
- rucio/daemons/conveyor/__init__.py +13 -0
- rucio/daemons/conveyor/common.py +562 -0
- rucio/daemons/conveyor/finisher.py +529 -0
- rucio/daemons/conveyor/poller.py +394 -0
- rucio/daemons/conveyor/preparer.py +205 -0
- rucio/daemons/conveyor/receiver.py +179 -0
- rucio/daemons/conveyor/stager.py +133 -0
- rucio/daemons/conveyor/submitter.py +403 -0
- rucio/daemons/conveyor/throttler.py +532 -0
- rucio/daemons/follower/__init__.py +13 -0
- rucio/daemons/follower/follower.py +101 -0
- rucio/daemons/hermes/__init__.py +13 -0
- rucio/daemons/hermes/hermes.py +534 -0
- rucio/daemons/judge/__init__.py +13 -0
- rucio/daemons/judge/cleaner.py +159 -0
- rucio/daemons/judge/evaluator.py +185 -0
- rucio/daemons/judge/injector.py +162 -0
- rucio/daemons/judge/repairer.py +154 -0
- rucio/daemons/oauthmanager/__init__.py +13 -0
- rucio/daemons/oauthmanager/oauthmanager.py +198 -0
- rucio/daemons/reaper/__init__.py +13 -0
- rucio/daemons/reaper/dark_reaper.py +282 -0
- rucio/daemons/reaper/reaper.py +739 -0
- rucio/daemons/replicarecoverer/__init__.py +13 -0
- rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +626 -0
- rucio/daemons/rsedecommissioner/__init__.py +13 -0
- rucio/daemons/rsedecommissioner/config.py +81 -0
- rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
- rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
- rucio/daemons/rsedecommissioner/profiles/generic.py +452 -0
- rucio/daemons/rsedecommissioner/profiles/types.py +93 -0
- rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
- rucio/daemons/storage/__init__.py +13 -0
- rucio/daemons/storage/consistency/__init__.py +13 -0
- rucio/daemons/storage/consistency/actions.py +848 -0
- rucio/daemons/tracer/__init__.py +13 -0
- rucio/daemons/tracer/kronos.py +511 -0
- rucio/daemons/transmogrifier/__init__.py +13 -0
- rucio/daemons/transmogrifier/transmogrifier.py +762 -0
- rucio/daemons/undertaker/__init__.py +13 -0
- rucio/daemons/undertaker/undertaker.py +137 -0
- rucio/db/__init__.py +13 -0
- rucio/db/sqla/__init__.py +52 -0
- rucio/db/sqla/constants.py +206 -0
- rucio/db/sqla/migrate_repo/__init__.py +13 -0
- rucio/db/sqla/migrate_repo/env.py +110 -0
- rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +70 -0
- rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +43 -0
- rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +91 -0
- rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +76 -0
- rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +43 -0
- rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +50 -0
- rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +68 -0
- rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +40 -0
- rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +45 -0
- rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +60 -0
- rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +40 -0
- rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +140 -0
- rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +73 -0
- rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +74 -0
- rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +43 -0
- rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +50 -0
- rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +134 -0
- rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +64 -0
- rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +39 -0
- rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +64 -0
- rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +51 -0
- rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +41 -0
- rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +43 -0
- rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +44 -0
- rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +53 -0
- rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +38 -0
- rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +47 -0
- rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +57 -0
- rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +69 -0
- rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +42 -0
- rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +47 -0
- rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +46 -0
- rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +40 -0
- rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +67 -0
- rucio/db/sqla/migrate_repo/versions/30d5206e9cad_increase_oauthrequest_redirect_msg_.py +37 -0
- rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +44 -0
- rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +77 -0
- rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +60 -0
- rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +72 -0
- rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +42 -0
- rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +65 -0
- rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +133 -0
- rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +76 -0
- rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +60 -0
- rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +44 -0
- rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +64 -0
- rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +40 -0
- rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +43 -0
- rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +44 -0
- rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +78 -0
- rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +41 -0
- rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +44 -0
- rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +49 -0
- rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +40 -0
- rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +63 -0
- rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
- rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +45 -0
- rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +43 -0
- rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +45 -0
- rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +47 -0
- rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +58 -0
- rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +45 -0
- rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +106 -0
- rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +55 -0
- rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +50 -0
- rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +43 -0
- rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +41 -0
- rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +91 -0
- rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +72 -0
- rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +49 -0
- rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +43 -0
- rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +53 -0
- rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +45 -0
- rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +68 -0
- rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +45 -0
- rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +94 -0
- rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +54 -0
- rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +72 -0
- rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +76 -0
- rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +47 -0
- rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +121 -0
- rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +59 -0
- rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +52 -0
- rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +54 -0
- rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +64 -0
- rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +49 -0
- rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
- rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +43 -0
- rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
- rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +91 -0
- rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +40 -0
- rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +143 -0
- rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +76 -0
- rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +50 -0
- rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +72 -0
- rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +43 -0
- rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +65 -0
- rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +47 -0
- rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +146 -0
- rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +104 -0
- rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +44 -0
- rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +43 -0
- rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +103 -0
- rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +49 -0
- rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +104 -0
- rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +29 -0
- rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +74 -0
- rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +47 -0
- rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +43 -0
- rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +37 -0
- rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +43 -0
- rucio/db/sqla/models.py +1743 -0
- rucio/db/sqla/sautils.py +55 -0
- rucio/db/sqla/session.py +529 -0
- rucio/db/sqla/types.py +206 -0
- rucio/db/sqla/util.py +543 -0
- rucio/gateway/__init__.py +13 -0
- rucio/gateway/account.py +345 -0
- rucio/gateway/account_limit.py +363 -0
- rucio/gateway/authentication.py +381 -0
- rucio/gateway/config.py +227 -0
- rucio/gateway/credential.py +70 -0
- rucio/gateway/did.py +987 -0
- rucio/gateway/dirac.py +83 -0
- rucio/gateway/exporter.py +60 -0
- rucio/gateway/heartbeat.py +76 -0
- rucio/gateway/identity.py +189 -0
- rucio/gateway/importer.py +46 -0
- rucio/gateway/lifetime_exception.py +121 -0
- rucio/gateway/lock.py +153 -0
- rucio/gateway/meta_conventions.py +98 -0
- rucio/gateway/permission.py +74 -0
- rucio/gateway/quarantined_replica.py +79 -0
- rucio/gateway/replica.py +538 -0
- rucio/gateway/request.py +330 -0
- rucio/gateway/rse.py +632 -0
- rucio/gateway/rule.py +437 -0
- rucio/gateway/scope.py +100 -0
- rucio/gateway/subscription.py +280 -0
- rucio/gateway/vo.py +126 -0
- rucio/rse/__init__.py +96 -0
- rucio/rse/protocols/__init__.py +13 -0
- rucio/rse/protocols/bittorrent.py +194 -0
- rucio/rse/protocols/cache.py +111 -0
- rucio/rse/protocols/dummy.py +100 -0
- rucio/rse/protocols/gfal.py +708 -0
- rucio/rse/protocols/globus.py +243 -0
- rucio/rse/protocols/http_cache.py +82 -0
- rucio/rse/protocols/mock.py +123 -0
- rucio/rse/protocols/ngarc.py +209 -0
- rucio/rse/protocols/posix.py +250 -0
- rucio/rse/protocols/protocol.py +361 -0
- rucio/rse/protocols/rclone.py +365 -0
- rucio/rse/protocols/rfio.py +145 -0
- rucio/rse/protocols/srm.py +338 -0
- rucio/rse/protocols/ssh.py +414 -0
- rucio/rse/protocols/storm.py +195 -0
- rucio/rse/protocols/webdav.py +594 -0
- rucio/rse/protocols/xrootd.py +302 -0
- rucio/rse/rsemanager.py +881 -0
- rucio/rse/translation.py +260 -0
- rucio/tests/__init__.py +13 -0
- rucio/tests/common.py +280 -0
- rucio/tests/common_server.py +149 -0
- rucio/transfertool/__init__.py +13 -0
- rucio/transfertool/bittorrent.py +200 -0
- rucio/transfertool/bittorrent_driver.py +50 -0
- rucio/transfertool/bittorrent_driver_qbittorrent.py +134 -0
- rucio/transfertool/fts3.py +1600 -0
- rucio/transfertool/fts3_plugins.py +152 -0
- rucio/transfertool/globus.py +201 -0
- rucio/transfertool/globus_library.py +181 -0
- rucio/transfertool/mock.py +89 -0
- rucio/transfertool/transfertool.py +221 -0
- rucio/vcsversion.py +11 -0
- rucio/version.py +45 -0
- rucio/web/__init__.py +13 -0
- rucio/web/rest/__init__.py +13 -0
- rucio/web/rest/flaskapi/__init__.py +13 -0
- rucio/web/rest/flaskapi/authenticated_bp.py +27 -0
- rucio/web/rest/flaskapi/v1/__init__.py +13 -0
- rucio/web/rest/flaskapi/v1/accountlimits.py +236 -0
- rucio/web/rest/flaskapi/v1/accounts.py +1103 -0
- rucio/web/rest/flaskapi/v1/archives.py +102 -0
- rucio/web/rest/flaskapi/v1/auth.py +1644 -0
- rucio/web/rest/flaskapi/v1/common.py +426 -0
- rucio/web/rest/flaskapi/v1/config.py +304 -0
- rucio/web/rest/flaskapi/v1/credentials.py +213 -0
- rucio/web/rest/flaskapi/v1/dids.py +2340 -0
- rucio/web/rest/flaskapi/v1/dirac.py +116 -0
- rucio/web/rest/flaskapi/v1/export.py +75 -0
- rucio/web/rest/flaskapi/v1/heartbeats.py +127 -0
- rucio/web/rest/flaskapi/v1/identities.py +285 -0
- rucio/web/rest/flaskapi/v1/import.py +132 -0
- rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +312 -0
- rucio/web/rest/flaskapi/v1/locks.py +358 -0
- rucio/web/rest/flaskapi/v1/main.py +91 -0
- rucio/web/rest/flaskapi/v1/meta_conventions.py +241 -0
- rucio/web/rest/flaskapi/v1/metrics.py +36 -0
- rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
- rucio/web/rest/flaskapi/v1/ping.py +88 -0
- rucio/web/rest/flaskapi/v1/redirect.py +366 -0
- rucio/web/rest/flaskapi/v1/replicas.py +1894 -0
- rucio/web/rest/flaskapi/v1/requests.py +998 -0
- rucio/web/rest/flaskapi/v1/rses.py +2250 -0
- rucio/web/rest/flaskapi/v1/rules.py +854 -0
- rucio/web/rest/flaskapi/v1/scopes.py +159 -0
- rucio/web/rest/flaskapi/v1/subscriptions.py +650 -0
- rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
- rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
- rucio/web/rest/flaskapi/v1/traces.py +137 -0
- rucio/web/rest/flaskapi/v1/types.py +20 -0
- rucio/web/rest/flaskapi/v1/vos.py +278 -0
- rucio/web/rest/main.py +18 -0
- rucio/web/rest/metrics.py +27 -0
- rucio/web/rest/ping.py +27 -0
- rucio-37.0.0rc1.data/data/rucio/etc/alembic.ini.template +71 -0
- rucio-37.0.0rc1.data/data/rucio/etc/alembic_offline.ini.template +74 -0
- rucio-37.0.0rc1.data/data/rucio/etc/globus-config.yml.template +5 -0
- rucio-37.0.0rc1.data/data/rucio/etc/ldap.cfg.template +30 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.atlas.client.template +43 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.template +241 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio_multi_vo.cfg.template +217 -0
- rucio-37.0.0rc1.data/data/rucio/requirements.server.txt +297 -0
- rucio-37.0.0rc1.data/data/rucio/tools/bootstrap.py +34 -0
- rucio-37.0.0rc1.data/data/rucio/tools/merge_rucio_configs.py +144 -0
- rucio-37.0.0rc1.data/data/rucio/tools/reset_database.py +40 -0
- rucio-37.0.0rc1.data/scripts/rucio +133 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-account +74 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-collection-replica +46 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-rse +78 -0
- rucio-37.0.0rc1.data/scripts/rucio-admin +97 -0
- rucio-37.0.0rc1.data/scripts/rucio-atropos +60 -0
- rucio-37.0.0rc1.data/scripts/rucio-auditor +206 -0
- rucio-37.0.0rc1.data/scripts/rucio-automatix +50 -0
- rucio-37.0.0rc1.data/scripts/rucio-bb8 +57 -0
- rucio-37.0.0rc1.data/scripts/rucio-cache-client +141 -0
- rucio-37.0.0rc1.data/scripts/rucio-cache-consumer +42 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-finisher +58 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-poller +66 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-preparer +37 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-receiver +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-stager +76 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-submitter +139 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-throttler +104 -0
- rucio-37.0.0rc1.data/scripts/rucio-dark-reaper +53 -0
- rucio-37.0.0rc1.data/scripts/rucio-dumper +160 -0
- rucio-37.0.0rc1.data/scripts/rucio-follower +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-hermes +54 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-cleaner +89 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-evaluator +137 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-injector +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-repairer +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-kronos +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-minos +53 -0
- rucio-37.0.0rc1.data/scripts/rucio-minos-temporary-expiration +50 -0
- rucio-37.0.0rc1.data/scripts/rucio-necromancer +120 -0
- rucio-37.0.0rc1.data/scripts/rucio-oauth-manager +63 -0
- rucio-37.0.0rc1.data/scripts/rucio-reaper +83 -0
- rucio-37.0.0rc1.data/scripts/rucio-replica-recoverer +248 -0
- rucio-37.0.0rc1.data/scripts/rucio-rse-decommissioner +66 -0
- rucio-37.0.0rc1.data/scripts/rucio-storage-consistency-actions +74 -0
- rucio-37.0.0rc1.data/scripts/rucio-transmogrifier +77 -0
- rucio-37.0.0rc1.data/scripts/rucio-undertaker +76 -0
- rucio-37.0.0rc1.dist-info/METADATA +92 -0
- rucio-37.0.0rc1.dist-info/RECORD +487 -0
- rucio-37.0.0rc1.dist-info/WHEEL +5 -0
- rucio-37.0.0rc1.dist-info/licenses/AUTHORS.rst +100 -0
- rucio-37.0.0rc1.dist-info/licenses/LICENSE +201 -0
- rucio-37.0.0rc1.dist-info/top_level.txt +1 -0
rucio/core/config.py
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from typing import TYPE_CHECKING, Any, Optional, TypeVar
|
|
16
|
+
|
|
17
|
+
from dogpile.cache.api import NoValue
|
|
18
|
+
from sqlalchemy import and_, delete, func, select, update
|
|
19
|
+
|
|
20
|
+
from rucio.common.cache import CacheKey, MemcacheRegion
|
|
21
|
+
from rucio.common.exception import ConfigNotFound
|
|
22
|
+
from rucio.db.sqla import models
|
|
23
|
+
from rucio.db.sqla.session import read_session, transactional_session
|
|
24
|
+
|
|
25
|
+
T = TypeVar('T')
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from collections.abc import Callable
|
|
29
|
+
|
|
30
|
+
from sqlalchemy.orm import Session
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
REGION = MemcacheRegion(expiration_time=900)
|
|
34
|
+
|
|
35
|
+
SECTIONS_CACHE_KEY = 'sections'
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@read_session
|
|
39
|
+
def sections(
|
|
40
|
+
*,
|
|
41
|
+
use_cache: bool = True,
|
|
42
|
+
expiration_time: int = 900,
|
|
43
|
+
session: "Session"
|
|
44
|
+
) -> list[str]:
|
|
45
|
+
"""
|
|
46
|
+
Return a list of the sections available.
|
|
47
|
+
|
|
48
|
+
:param use_cache: Boolean if the cache should be used.
|
|
49
|
+
:param expiration_time: Time after that the cached value gets ignored.
|
|
50
|
+
:param session: The database session in use.
|
|
51
|
+
:returns: ['section_name', ...]
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
all_sections = NoValue()
|
|
55
|
+
if use_cache:
|
|
56
|
+
all_sections = read_from_cache(SECTIONS_CACHE_KEY, expiration_time)
|
|
57
|
+
if isinstance(all_sections, NoValue):
|
|
58
|
+
stmt = select(
|
|
59
|
+
models.Config.section
|
|
60
|
+
).distinct(
|
|
61
|
+
)
|
|
62
|
+
all_sections = list(session.execute(stmt).scalars().all())
|
|
63
|
+
write_to_cache(SECTIONS_CACHE_KEY, all_sections)
|
|
64
|
+
|
|
65
|
+
return all_sections
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@transactional_session
|
|
69
|
+
def add_section(section: str, *, session: "Session") -> None:
|
|
70
|
+
"""
|
|
71
|
+
Add a section to the configuration.
|
|
72
|
+
:param session: The database session in use.
|
|
73
|
+
:param section: The name of the section.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
raise NotImplementedError('Irrelevant - sections cannot exist without options')
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@read_session
|
|
80
|
+
def has_section(
|
|
81
|
+
section: str,
|
|
82
|
+
*,
|
|
83
|
+
use_cache: bool = True,
|
|
84
|
+
expiration_time: int = 900,
|
|
85
|
+
session: "Session"
|
|
86
|
+
) -> bool:
|
|
87
|
+
"""
|
|
88
|
+
Indicates whether the named section is present in the configuration.
|
|
89
|
+
|
|
90
|
+
:param section: The name of the section.
|
|
91
|
+
:param use_cache: Boolean if the cache should be used.
|
|
92
|
+
:param expiration_time: Time after that the cached value gets ignored.
|
|
93
|
+
:param session: The database session in use.
|
|
94
|
+
:returns: True/False
|
|
95
|
+
"""
|
|
96
|
+
has_section_key = 'has_section_%s' % section
|
|
97
|
+
has_section = NoValue()
|
|
98
|
+
if use_cache:
|
|
99
|
+
has_section = read_from_cache(has_section_key, expiration_time)
|
|
100
|
+
if isinstance(has_section, NoValue):
|
|
101
|
+
stmt = select(
|
|
102
|
+
models.Config
|
|
103
|
+
).where(
|
|
104
|
+
models.Config.section == section
|
|
105
|
+
)
|
|
106
|
+
has_section = session.execute(stmt).first() is not None
|
|
107
|
+
write_to_cache(has_section_key, has_section)
|
|
108
|
+
return has_section
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@read_session
|
|
112
|
+
def options(
|
|
113
|
+
section: str,
|
|
114
|
+
*,
|
|
115
|
+
use_cache: bool = True,
|
|
116
|
+
expiration_time: int = 900,
|
|
117
|
+
session: "Session"
|
|
118
|
+
) -> list[str]:
|
|
119
|
+
"""
|
|
120
|
+
Returns a list of options available in the specified section.
|
|
121
|
+
|
|
122
|
+
:param section: The name of the section.
|
|
123
|
+
:param use_cache: Boolean if the cache should be used.
|
|
124
|
+
:param expiration_time: Time after that the cached value gets ignored.
|
|
125
|
+
:param session: The database session in use.
|
|
126
|
+
:returns: ['option', ...]
|
|
127
|
+
"""
|
|
128
|
+
options_key = CacheKey.options(section)
|
|
129
|
+
options = NoValue()
|
|
130
|
+
if use_cache:
|
|
131
|
+
options = read_from_cache(options_key, expiration_time)
|
|
132
|
+
if isinstance(options, NoValue):
|
|
133
|
+
stmt = select(
|
|
134
|
+
models.Config.opt
|
|
135
|
+
).where(
|
|
136
|
+
models.Config.section == section
|
|
137
|
+
).distinct()
|
|
138
|
+
options = list(session.execute(stmt).scalars().all())
|
|
139
|
+
write_to_cache(options_key, options)
|
|
140
|
+
return options
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@read_session
|
|
144
|
+
def has_option(
|
|
145
|
+
section: str,
|
|
146
|
+
option: str,
|
|
147
|
+
*,
|
|
148
|
+
use_cache: bool = True,
|
|
149
|
+
expiration_time: int = 900,
|
|
150
|
+
session: "Session"
|
|
151
|
+
) -> bool:
|
|
152
|
+
"""
|
|
153
|
+
Check if the given section exists and contains the given option.
|
|
154
|
+
|
|
155
|
+
:param section: The name of the section.
|
|
156
|
+
:param option: The name of the option.
|
|
157
|
+
:param use_cache: Boolean if the cache should be used.
|
|
158
|
+
:param expiration_time: Time after that the cached value gets ignored.
|
|
159
|
+
:param session: The database session in use.
|
|
160
|
+
:returns: True/False
|
|
161
|
+
"""
|
|
162
|
+
has_option_key = CacheKey.has_option(section, option)
|
|
163
|
+
has_option = NoValue()
|
|
164
|
+
if use_cache:
|
|
165
|
+
has_option = read_from_cache(has_option_key, expiration_time)
|
|
166
|
+
if isinstance(has_option, NoValue):
|
|
167
|
+
stmt = select(
|
|
168
|
+
models.Config
|
|
169
|
+
).where(
|
|
170
|
+
and_(models.Config.section == section,
|
|
171
|
+
models.Config.opt == option)
|
|
172
|
+
)
|
|
173
|
+
has_option = session.execute(stmt).first() is not None
|
|
174
|
+
write_to_cache(has_option_key, has_option)
|
|
175
|
+
return has_option
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@read_session
|
|
179
|
+
def get(
|
|
180
|
+
section: str,
|
|
181
|
+
option: str,
|
|
182
|
+
*,
|
|
183
|
+
default: Optional[T] = None,
|
|
184
|
+
use_cache: bool = True,
|
|
185
|
+
expiration_time: int = 900,
|
|
186
|
+
convert_type_fnc: 'Callable[[str], T]',
|
|
187
|
+
session: "Session"
|
|
188
|
+
) -> T:
|
|
189
|
+
"""
|
|
190
|
+
Get an option value for the named section. Value can be auto-coerced to string, int, float, bool, None.
|
|
191
|
+
|
|
192
|
+
Caveat emptor: Strings, regardless the case, matching 'on'/off', 'true'/'false', 'yes'/'no' are converted to bool.
|
|
193
|
+
0/1 are converted to int, and not to bool.
|
|
194
|
+
|
|
195
|
+
:param section: The name of the section.
|
|
196
|
+
:param option: The name of the option.
|
|
197
|
+
:param default: The default value if no value is found.
|
|
198
|
+
:param use_cache: Boolean if the cache should be used.
|
|
199
|
+
:param expiration_time: Time after that the cached value gets ignored.
|
|
200
|
+
:param convert_type_fnc: A function used to parse the string config value into the desired destination type
|
|
201
|
+
:param session: The database session in use.
|
|
202
|
+
:returns: The auto-coerced value.
|
|
203
|
+
"""
|
|
204
|
+
value_key = CacheKey.value(section, option)
|
|
205
|
+
value = NoValue()
|
|
206
|
+
if use_cache:
|
|
207
|
+
value = read_from_cache(value_key, expiration_time)
|
|
208
|
+
if isinstance(value, NoValue):
|
|
209
|
+
stmt = select(
|
|
210
|
+
models.Config.value
|
|
211
|
+
).where(
|
|
212
|
+
and_(models.Config.section == section,
|
|
213
|
+
models.Config.opt == option)
|
|
214
|
+
)
|
|
215
|
+
tmp = session.execute(stmt).first()
|
|
216
|
+
if tmp is not None:
|
|
217
|
+
value = convert_type_fnc(tmp[0])
|
|
218
|
+
write_to_cache(value_key, tmp[0])
|
|
219
|
+
elif default is None:
|
|
220
|
+
raise ConfigNotFound
|
|
221
|
+
else:
|
|
222
|
+
value = default
|
|
223
|
+
write_to_cache(value_key, value) # Also write default to cache
|
|
224
|
+
else:
|
|
225
|
+
value = convert_type_fnc(value)
|
|
226
|
+
return value
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@read_session
|
|
230
|
+
def items(
|
|
231
|
+
section: str,
|
|
232
|
+
use_cache: bool = True,
|
|
233
|
+
expiration_time: int = 900,
|
|
234
|
+
*,
|
|
235
|
+
convert_type_fnc: 'Callable[[str], T]',
|
|
236
|
+
session: "Session"
|
|
237
|
+
) -> list[tuple[str, T]]:
|
|
238
|
+
"""
|
|
239
|
+
Return a list of (option, value) pairs for each option in the given section. Values are auto-coerced as in get().
|
|
240
|
+
|
|
241
|
+
:param section: The name of the section.
|
|
242
|
+
:param use_cache: Boolean if the cache should be used.
|
|
243
|
+
:param expiration_time: Time after that the cached value gets ignored.
|
|
244
|
+
:param convert_type_fnc: A function used to parse the string config value into the desired destination type
|
|
245
|
+
:param session: The database session in use.
|
|
246
|
+
:returns: [('option', auto-coerced value), ...]
|
|
247
|
+
"""
|
|
248
|
+
items_key = CacheKey.items(section)
|
|
249
|
+
items = NoValue()
|
|
250
|
+
if use_cache:
|
|
251
|
+
items = read_from_cache(items_key, expiration_time)
|
|
252
|
+
if isinstance(items, NoValue):
|
|
253
|
+
stmt = select(
|
|
254
|
+
models.Config.opt,
|
|
255
|
+
models.Config.value
|
|
256
|
+
).where(
|
|
257
|
+
models.Config.section == section
|
|
258
|
+
)
|
|
259
|
+
items = session.execute(stmt).all()
|
|
260
|
+
write_to_cache(items_key, items)
|
|
261
|
+
return [(opt, convert_type_fnc(val)) for opt, val in items]
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@transactional_session
|
|
265
|
+
def set(
|
|
266
|
+
section: str,
|
|
267
|
+
option: str,
|
|
268
|
+
value: Any,
|
|
269
|
+
*,
|
|
270
|
+
session: "Session"
|
|
271
|
+
) -> None:
|
|
272
|
+
"""
|
|
273
|
+
Set the given option to the specified value. If the option doesn't exist, it is created.
|
|
274
|
+
|
|
275
|
+
:param section: The name of the section.
|
|
276
|
+
:param option: The name of the option.
|
|
277
|
+
:param value: The content of the value.
|
|
278
|
+
:param session: The database session in use.
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
if not has_option(section=section, option=option, use_cache=False, session=session):
|
|
282
|
+
section_existed = has_section(section=section)
|
|
283
|
+
|
|
284
|
+
new_option = models.Config(section=section, opt=option, value=value)
|
|
285
|
+
new_option.save(session=session)
|
|
286
|
+
|
|
287
|
+
delete_from_cache(key=CacheKey.value(section, option))
|
|
288
|
+
delete_from_cache(key=CacheKey.has_option(section, option))
|
|
289
|
+
delete_from_cache(key=CacheKey.items(section))
|
|
290
|
+
if not section_existed:
|
|
291
|
+
delete_from_cache(key=SECTIONS_CACHE_KEY)
|
|
292
|
+
delete_from_cache(key=CacheKey.has_section(section))
|
|
293
|
+
else:
|
|
294
|
+
stmt = select(
|
|
295
|
+
models.Config.value
|
|
296
|
+
).where(
|
|
297
|
+
and_(models.Config.section == section,
|
|
298
|
+
models.Config.opt == option)
|
|
299
|
+
)
|
|
300
|
+
old_value = session.execute(stmt).scalar_one_or_none()
|
|
301
|
+
if old_value != str(value):
|
|
302
|
+
old_option = models.ConfigHistory(section=section,
|
|
303
|
+
opt=option,
|
|
304
|
+
value=old_value)
|
|
305
|
+
old_option.save(session=session)
|
|
306
|
+
stmt = update(
|
|
307
|
+
models.Config
|
|
308
|
+
).where(
|
|
309
|
+
and_(models.Config.section == section,
|
|
310
|
+
models.Config.opt == option)
|
|
311
|
+
).values({
|
|
312
|
+
models.Config.value: str(value)
|
|
313
|
+
})
|
|
314
|
+
session.execute(stmt)
|
|
315
|
+
delete_from_cache(key=CacheKey.value(section, option))
|
|
316
|
+
delete_from_cache(key=CacheKey.items(section))
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
@transactional_session
|
|
320
|
+
def remove_section(section: str, *, session: "Session") -> bool:
|
|
321
|
+
"""
|
|
322
|
+
Remove the specified section from the specified section.
|
|
323
|
+
|
|
324
|
+
:param section: The name of the section.
|
|
325
|
+
:param session: The database session in use.
|
|
326
|
+
:returns: True/False.
|
|
327
|
+
"""
|
|
328
|
+
|
|
329
|
+
if not has_section(section=section, session=session):
|
|
330
|
+
return False
|
|
331
|
+
else:
|
|
332
|
+
stmt = select(
|
|
333
|
+
models.Config.value
|
|
334
|
+
).where(
|
|
335
|
+
models.Config.section == section
|
|
336
|
+
)
|
|
337
|
+
for old in session.execute(stmt).all():
|
|
338
|
+
old_option = models.ConfigHistory(section=old[0],
|
|
339
|
+
opt=old[1],
|
|
340
|
+
value=old[2])
|
|
341
|
+
old_option.save(session=session)
|
|
342
|
+
delete_from_cache(key=CacheKey.has_option(old[0], old[1]))
|
|
343
|
+
delete_from_cache(key=CacheKey.value(old[0], old[1]))
|
|
344
|
+
|
|
345
|
+
stmt = delete(
|
|
346
|
+
models.Config
|
|
347
|
+
).where(
|
|
348
|
+
models.Config.section == section
|
|
349
|
+
)
|
|
350
|
+
session.execute(stmt)
|
|
351
|
+
delete_from_cache(key=SECTIONS_CACHE_KEY)
|
|
352
|
+
delete_from_cache(key=CacheKey.items(section))
|
|
353
|
+
return True
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
@transactional_session
|
|
357
|
+
def remove_option(section: str, option: str, *, session: "Session") -> bool:
|
|
358
|
+
"""
|
|
359
|
+
Remove the specified option from the configuration.
|
|
360
|
+
|
|
361
|
+
:param section: The name of the section.
|
|
362
|
+
:param option: The name of the option.
|
|
363
|
+
:param session: The database session in use.
|
|
364
|
+
:returns: True/False
|
|
365
|
+
"""
|
|
366
|
+
|
|
367
|
+
if not has_option(section=section, option=option, session=session, use_cache=False):
|
|
368
|
+
return False
|
|
369
|
+
else:
|
|
370
|
+
stmt = select(
|
|
371
|
+
models.Config.value
|
|
372
|
+
).where(
|
|
373
|
+
and_(models.Config.section == section,
|
|
374
|
+
models.Config.opt == option)
|
|
375
|
+
)
|
|
376
|
+
result = session.execute(stmt).scalar_one_or_none()
|
|
377
|
+
old_option = models.ConfigHistory(section=section,
|
|
378
|
+
opt=option,
|
|
379
|
+
value=result)
|
|
380
|
+
old_option.save(session=session)
|
|
381
|
+
|
|
382
|
+
stmt = delete(
|
|
383
|
+
models.Config
|
|
384
|
+
).where(
|
|
385
|
+
and_(models.Config.section == section,
|
|
386
|
+
models.Config.opt == option)
|
|
387
|
+
)
|
|
388
|
+
session.execute(stmt)
|
|
389
|
+
|
|
390
|
+
stmt = select(
|
|
391
|
+
func.count()
|
|
392
|
+
).select_from(
|
|
393
|
+
models.Config
|
|
394
|
+
).where(
|
|
395
|
+
models.Config.section == section
|
|
396
|
+
)
|
|
397
|
+
if not session.execute(stmt).scalar_one_or_none():
|
|
398
|
+
# we deleted the last config entry in the section. Invalidate the section cache
|
|
399
|
+
delete_from_cache(key=SECTIONS_CACHE_KEY)
|
|
400
|
+
delete_from_cache(key=CacheKey.has_section(section))
|
|
401
|
+
delete_from_cache(key=CacheKey.items(section))
|
|
402
|
+
delete_from_cache(key=CacheKey.has_option(section, option))
|
|
403
|
+
delete_from_cache(key=CacheKey.value(section, option))
|
|
404
|
+
return True
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def read_from_cache(key: str, expiration_time: int = 900) -> Any:
|
|
408
|
+
"""
|
|
409
|
+
Try to read a value from a cache.
|
|
410
|
+
|
|
411
|
+
:param key: Key that stores the value.
|
|
412
|
+
:param expiration_time: Time in seconds that a value should not be older than.
|
|
413
|
+
"""
|
|
414
|
+
key = key.replace(' ', '')
|
|
415
|
+
value = REGION.get(key, expiration_time=expiration_time)
|
|
416
|
+
return value
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def write_to_cache(key: str, value: Any) -> None:
|
|
420
|
+
"""
|
|
421
|
+
Set a value on a key in a cache.
|
|
422
|
+
|
|
423
|
+
:param key: Key that stores the value.
|
|
424
|
+
:param value: Value to be stored.
|
|
425
|
+
"""
|
|
426
|
+
key = key.replace(' ', '')
|
|
427
|
+
REGION.set(key, value)
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def delete_from_cache(key: str) -> None:
|
|
431
|
+
"""
|
|
432
|
+
Delete from cache any data stored for the given key
|
|
433
|
+
|
|
434
|
+
:param key: Key that stores the value.
|
|
435
|
+
"""
|
|
436
|
+
key = key.replace(' ', '')
|
|
437
|
+
REGION.delete(key)
|
rucio/core/credential.py
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import base64
|
|
16
|
+
import datetime
|
|
17
|
+
import hmac
|
|
18
|
+
import time
|
|
19
|
+
from hashlib import sha1
|
|
20
|
+
from typing import Optional
|
|
21
|
+
from urllib.parse import urlencode, urlparse
|
|
22
|
+
|
|
23
|
+
import boto3
|
|
24
|
+
from botocore.client import Config
|
|
25
|
+
from dogpile.cache.api import NO_VALUE
|
|
26
|
+
from google.oauth2.service_account import Credentials
|
|
27
|
+
|
|
28
|
+
from rucio.common.cache import MemcacheRegion
|
|
29
|
+
from rucio.common.config import config_get, get_rse_credentials
|
|
30
|
+
from rucio.common.constants import RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS, RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL, SUPPORTED_SIGN_URL_SERVICES, SUPPORTED_SIGN_URL_SERVICES_LITERAL, RseAttr
|
|
31
|
+
from rucio.common.exception import UnsupportedOperation
|
|
32
|
+
from rucio.core.monitor import MetricManager
|
|
33
|
+
from rucio.core.rse import get_rse_attribute
|
|
34
|
+
|
|
35
|
+
CREDS_GCS = None
|
|
36
|
+
|
|
37
|
+
REGION = MemcacheRegion(expiration_time=900)
|
|
38
|
+
METRICS = MetricManager(module=__name__)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_signed_url(
|
|
42
|
+
rse_id: str,
|
|
43
|
+
service: SUPPORTED_SIGN_URL_SERVICES_LITERAL,
|
|
44
|
+
operation: RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL,
|
|
45
|
+
url: str,
|
|
46
|
+
lifetime: Optional[int] = 600
|
|
47
|
+
) -> str:
|
|
48
|
+
"""
|
|
49
|
+
Get a signed URL for a particular service and operation.
|
|
50
|
+
|
|
51
|
+
The signed URL will be valid for 1 hour but can be overridden.
|
|
52
|
+
|
|
53
|
+
:param rse_id: The ID of the RSE that the URL points to.
|
|
54
|
+
:param service: The service to authorise, either 'gcs', 's3' or 'swift'.
|
|
55
|
+
:param operation: The operation to sign, either 'read', 'write', or 'delete'.
|
|
56
|
+
:param url: The URL to sign.
|
|
57
|
+
:param lifetime: Lifetime of the signed URL in seconds.
|
|
58
|
+
:returns: Signed URL as a variable-length string.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
global CREDS_GCS
|
|
62
|
+
|
|
63
|
+
if service not in SUPPORTED_SIGN_URL_SERVICES:
|
|
64
|
+
raise UnsupportedOperation('Service must be "gcs", "s3" or "swift"')
|
|
65
|
+
|
|
66
|
+
if operation not in RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS:
|
|
67
|
+
raise UnsupportedOperation('Operation must be "read", "write", or "delete"')
|
|
68
|
+
|
|
69
|
+
if url is None or url == '':
|
|
70
|
+
raise UnsupportedOperation('URL must not be empty')
|
|
71
|
+
|
|
72
|
+
if lifetime:
|
|
73
|
+
if not isinstance(lifetime, int):
|
|
74
|
+
try:
|
|
75
|
+
lifetime = int(lifetime)
|
|
76
|
+
except:
|
|
77
|
+
raise UnsupportedOperation('Lifetime must be convertible to numeric.')
|
|
78
|
+
|
|
79
|
+
if service == 'gcs':
|
|
80
|
+
if not CREDS_GCS:
|
|
81
|
+
CREDS_GCS = Credentials.from_service_account_file(config_get('credentials', 'gcs',
|
|
82
|
+
raise_exception=False,
|
|
83
|
+
default='/opt/rucio/etc/google-cloud-storage-test.json'))
|
|
84
|
+
components = urlparse(url)
|
|
85
|
+
host = components.netloc
|
|
86
|
+
|
|
87
|
+
# special case to test signature, force epoch time
|
|
88
|
+
if lifetime is None:
|
|
89
|
+
lifetime = 0
|
|
90
|
+
else:
|
|
91
|
+
# GCS is timezone-sensitive, don't use UTC
|
|
92
|
+
# has to be converted to Unixtime
|
|
93
|
+
lifetime_datetime = datetime.datetime.now() + datetime.timedelta(seconds=lifetime)
|
|
94
|
+
lifetime = int(time.mktime(lifetime_datetime.timetuple()))
|
|
95
|
+
|
|
96
|
+
# sign the path only
|
|
97
|
+
path = components.path
|
|
98
|
+
|
|
99
|
+
# Map operations
|
|
100
|
+
operations = {'read': 'GET', 'write': 'PUT', 'delete': 'DELETE'}
|
|
101
|
+
|
|
102
|
+
# assemble message to sign
|
|
103
|
+
to_sign = "%s\n\n\n%s\n%s" % (operations[operation], lifetime, path)
|
|
104
|
+
|
|
105
|
+
# create URL-capable signature
|
|
106
|
+
# first character is always a '=', remove it
|
|
107
|
+
signature = urlencode({'': base64.b64encode(CREDS_GCS.sign_bytes(to_sign))})[1:]
|
|
108
|
+
|
|
109
|
+
# assemble final signed URL
|
|
110
|
+
signed_url = (
|
|
111
|
+
f'https://{host}{path}'
|
|
112
|
+
f'?GoogleAccessId={CREDS_GCS.service_account_email}'
|
|
113
|
+
f'&Expires={lifetime}&Signature={signature}'
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
elif service == 's3':
|
|
117
|
+
|
|
118
|
+
# get RSE S3 URL style (path or host)
|
|
119
|
+
# path-style: https://s3.region-code.amazonaws.com/bucket-name/key-name
|
|
120
|
+
# host-style: https://bucket-name.s3.region-code.amazonaws.com/key-name
|
|
121
|
+
s3_url_style = get_rse_attribute(rse_id, RseAttr.S3_URL_STYLE)
|
|
122
|
+
|
|
123
|
+
# no S3 URL style specified, assume path-style
|
|
124
|
+
if s3_url_style is None:
|
|
125
|
+
s3_url_style = "path"
|
|
126
|
+
|
|
127
|
+
# split URL to get hostname, bucket and key
|
|
128
|
+
components = urlparse(url)
|
|
129
|
+
host = components.netloc
|
|
130
|
+
pathcomponents = components.path.split('/')
|
|
131
|
+
if s3_url_style == "path":
|
|
132
|
+
if len(pathcomponents) < 3:
|
|
133
|
+
raise UnsupportedOperation('Not a valid Path-Style S3 URL')
|
|
134
|
+
bucket = pathcomponents[1]
|
|
135
|
+
key = '/'.join(pathcomponents[2:])
|
|
136
|
+
elif s3_url_style == "host":
|
|
137
|
+
hostcomponents = host.split('.')
|
|
138
|
+
bucket = hostcomponents[0]
|
|
139
|
+
if len(pathcomponents) < 2:
|
|
140
|
+
raise UnsupportedOperation('Not a valid Host-Style S3 URL')
|
|
141
|
+
key = '/'.join(pathcomponents[1:])
|
|
142
|
+
else:
|
|
143
|
+
raise UnsupportedOperation('Not a valid RSE S3 URL style (allowed values: path|host)')
|
|
144
|
+
|
|
145
|
+
# remove port number from host if present
|
|
146
|
+
colon = host.find(':')
|
|
147
|
+
port = '443'
|
|
148
|
+
if colon >= 0:
|
|
149
|
+
port = host[colon + 1:]
|
|
150
|
+
host = host[:colon]
|
|
151
|
+
|
|
152
|
+
# look up in RSE account configuration by RSE ID
|
|
153
|
+
cred_name = rse_id
|
|
154
|
+
cred = REGION.get('s3-%s' % cred_name)
|
|
155
|
+
if cred is NO_VALUE:
|
|
156
|
+
rse_cred = get_rse_credentials()
|
|
157
|
+
cred = rse_cred.get(cred_name)
|
|
158
|
+
REGION.set('s3-%s' % cred_name, cred)
|
|
159
|
+
access_key = cred['access_key']
|
|
160
|
+
secret_key = cred['secret_key']
|
|
161
|
+
signature_version = cred['signature_version']
|
|
162
|
+
region_name = cred['region']
|
|
163
|
+
|
|
164
|
+
if operation == 'read':
|
|
165
|
+
s3op = 'get_object'
|
|
166
|
+
elif operation == 'write':
|
|
167
|
+
s3op = 'put_object'
|
|
168
|
+
else:
|
|
169
|
+
s3op = 'delete_object'
|
|
170
|
+
|
|
171
|
+
with METRICS.timer('signs3'):
|
|
172
|
+
|
|
173
|
+
if s3_url_style == "host":
|
|
174
|
+
s3_url_style = "virtual"
|
|
175
|
+
|
|
176
|
+
s3 = boto3.client(service_name='s3',
|
|
177
|
+
endpoint_url=f'https://{host}:{port}',
|
|
178
|
+
aws_access_key_id=access_key,
|
|
179
|
+
aws_secret_access_key=secret_key,
|
|
180
|
+
config=Config(signature_version=signature_version,
|
|
181
|
+
region_name=region_name,
|
|
182
|
+
s3={"addressing_style": s3_url_style}))
|
|
183
|
+
|
|
184
|
+
signed_url: str = s3.generate_presigned_url(
|
|
185
|
+
s3op, Params={'Bucket': bucket, 'Key': key}, ExpiresIn=lifetime)
|
|
186
|
+
|
|
187
|
+
else: # service == 'swift'
|
|
188
|
+
# split URL to get hostname and path
|
|
189
|
+
components = urlparse(url)
|
|
190
|
+
host = components.netloc
|
|
191
|
+
|
|
192
|
+
# remove port number from host if present
|
|
193
|
+
colon = host.find(':')
|
|
194
|
+
if colon >= 0:
|
|
195
|
+
host = host[:colon]
|
|
196
|
+
|
|
197
|
+
# use RSE ID to look up key
|
|
198
|
+
cred_name = rse_id
|
|
199
|
+
|
|
200
|
+
# look up tempurl signing key
|
|
201
|
+
cred = REGION.get('swift-%s' % cred_name)
|
|
202
|
+
if cred is NO_VALUE:
|
|
203
|
+
rse_cred = get_rse_credentials()
|
|
204
|
+
cred = rse_cred.get(cred_name)
|
|
205
|
+
REGION.set('swift-%s' % cred_name, cred)
|
|
206
|
+
tempurl_key = cred['tempurl_key']
|
|
207
|
+
|
|
208
|
+
if operation == 'read':
|
|
209
|
+
swiftop = 'GET'
|
|
210
|
+
elif operation == 'write':
|
|
211
|
+
swiftop = 'PUT'
|
|
212
|
+
else:
|
|
213
|
+
swiftop = 'DELETE'
|
|
214
|
+
|
|
215
|
+
expires = int(time.time() + lifetime) # type: ignore (lifetime could be None)
|
|
216
|
+
|
|
217
|
+
# create signed URL
|
|
218
|
+
with METRICS.timer('signswift'):
|
|
219
|
+
hmac_body = '%s\n%s\n%s' % (swiftop, expires, components.path)
|
|
220
|
+
# Python 3 hmac only accepts bytes or bytearray
|
|
221
|
+
sig = hmac.new(bytearray(tempurl_key, 'utf-8'), bytearray(hmac_body, 'utf-8'), sha1).hexdigest()
|
|
222
|
+
signed_url = f'https://{host}{components.path}?temp_url_sig={sig}&temp_url_expires={expires}'
|
|
223
|
+
|
|
224
|
+
return signed_url
|