rucio 37.0.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rucio might be problematic. Click here for more details.
- rucio/__init__.py +17 -0
- rucio/alembicrevision.py +15 -0
- rucio/cli/__init__.py +14 -0
- rucio/cli/account.py +216 -0
- rucio/cli/bin_legacy/__init__.py +13 -0
- rucio/cli/bin_legacy/rucio.py +2825 -0
- rucio/cli/bin_legacy/rucio_admin.py +2500 -0
- rucio/cli/command.py +272 -0
- rucio/cli/config.py +72 -0
- rucio/cli/did.py +191 -0
- rucio/cli/download.py +128 -0
- rucio/cli/lifetime_exception.py +33 -0
- rucio/cli/replica.py +162 -0
- rucio/cli/rse.py +293 -0
- rucio/cli/rule.py +158 -0
- rucio/cli/scope.py +40 -0
- rucio/cli/subscription.py +73 -0
- rucio/cli/upload.py +60 -0
- rucio/cli/utils.py +226 -0
- rucio/client/__init__.py +15 -0
- rucio/client/accountclient.py +432 -0
- rucio/client/accountlimitclient.py +183 -0
- rucio/client/baseclient.py +983 -0
- rucio/client/client.py +120 -0
- rucio/client/configclient.py +126 -0
- rucio/client/credentialclient.py +59 -0
- rucio/client/didclient.py +868 -0
- rucio/client/diracclient.py +56 -0
- rucio/client/downloadclient.py +1783 -0
- rucio/client/exportclient.py +44 -0
- rucio/client/fileclient.py +50 -0
- rucio/client/importclient.py +42 -0
- rucio/client/lifetimeclient.py +90 -0
- rucio/client/lockclient.py +109 -0
- rucio/client/metaconventionsclient.py +140 -0
- rucio/client/pingclient.py +44 -0
- rucio/client/replicaclient.py +452 -0
- rucio/client/requestclient.py +125 -0
- rucio/client/richclient.py +317 -0
- rucio/client/rseclient.py +746 -0
- rucio/client/ruleclient.py +294 -0
- rucio/client/scopeclient.py +90 -0
- rucio/client/subscriptionclient.py +173 -0
- rucio/client/touchclient.py +82 -0
- rucio/client/uploadclient.py +969 -0
- rucio/common/__init__.py +13 -0
- rucio/common/bittorrent.py +234 -0
- rucio/common/cache.py +111 -0
- rucio/common/checksum.py +168 -0
- rucio/common/client.py +122 -0
- rucio/common/config.py +788 -0
- rucio/common/constants.py +217 -0
- rucio/common/constraints.py +17 -0
- rucio/common/didtype.py +237 -0
- rucio/common/dumper/__init__.py +342 -0
- rucio/common/dumper/consistency.py +497 -0
- rucio/common/dumper/data_models.py +362 -0
- rucio/common/dumper/path_parsing.py +75 -0
- rucio/common/exception.py +1208 -0
- rucio/common/extra.py +31 -0
- rucio/common/logging.py +420 -0
- rucio/common/pcache.py +1409 -0
- rucio/common/plugins.py +185 -0
- rucio/common/policy.py +93 -0
- rucio/common/schema/__init__.py +200 -0
- rucio/common/schema/generic.py +416 -0
- rucio/common/schema/generic_multi_vo.py +395 -0
- rucio/common/stomp_utils.py +423 -0
- rucio/common/stopwatch.py +55 -0
- rucio/common/test_rucio_server.py +154 -0
- rucio/common/types.py +483 -0
- rucio/common/utils.py +1688 -0
- rucio/core/__init__.py +13 -0
- rucio/core/account.py +496 -0
- rucio/core/account_counter.py +236 -0
- rucio/core/account_limit.py +425 -0
- rucio/core/authentication.py +620 -0
- rucio/core/config.py +437 -0
- rucio/core/credential.py +224 -0
- rucio/core/did.py +3004 -0
- rucio/core/did_meta_plugins/__init__.py +252 -0
- rucio/core/did_meta_plugins/did_column_meta.py +331 -0
- rucio/core/did_meta_plugins/did_meta_plugin_interface.py +165 -0
- rucio/core/did_meta_plugins/elasticsearch_meta.py +407 -0
- rucio/core/did_meta_plugins/filter_engine.py +672 -0
- rucio/core/did_meta_plugins/json_meta.py +240 -0
- rucio/core/did_meta_plugins/mongo_meta.py +229 -0
- rucio/core/did_meta_plugins/postgres_meta.py +352 -0
- rucio/core/dirac.py +237 -0
- rucio/core/distance.py +187 -0
- rucio/core/exporter.py +59 -0
- rucio/core/heartbeat.py +363 -0
- rucio/core/identity.py +301 -0
- rucio/core/importer.py +260 -0
- rucio/core/lifetime_exception.py +377 -0
- rucio/core/lock.py +577 -0
- rucio/core/message.py +288 -0
- rucio/core/meta_conventions.py +203 -0
- rucio/core/monitor.py +448 -0
- rucio/core/naming_convention.py +195 -0
- rucio/core/nongrid_trace.py +136 -0
- rucio/core/oidc.py +1463 -0
- rucio/core/permission/__init__.py +161 -0
- rucio/core/permission/generic.py +1124 -0
- rucio/core/permission/generic_multi_vo.py +1144 -0
- rucio/core/quarantined_replica.py +224 -0
- rucio/core/replica.py +4483 -0
- rucio/core/replica_sorter.py +362 -0
- rucio/core/request.py +3091 -0
- rucio/core/rse.py +2079 -0
- rucio/core/rse_counter.py +185 -0
- rucio/core/rse_expression_parser.py +459 -0
- rucio/core/rse_selector.py +304 -0
- rucio/core/rule.py +4484 -0
- rucio/core/rule_grouping.py +1620 -0
- rucio/core/scope.py +181 -0
- rucio/core/subscription.py +362 -0
- rucio/core/topology.py +490 -0
- rucio/core/trace.py +375 -0
- rucio/core/transfer.py +1531 -0
- rucio/core/vo.py +169 -0
- rucio/core/volatile_replica.py +151 -0
- rucio/daemons/__init__.py +13 -0
- rucio/daemons/abacus/__init__.py +13 -0
- rucio/daemons/abacus/account.py +116 -0
- rucio/daemons/abacus/collection_replica.py +124 -0
- rucio/daemons/abacus/rse.py +117 -0
- rucio/daemons/atropos/__init__.py +13 -0
- rucio/daemons/atropos/atropos.py +242 -0
- rucio/daemons/auditor/__init__.py +289 -0
- rucio/daemons/auditor/hdfs.py +97 -0
- rucio/daemons/auditor/srmdumps.py +355 -0
- rucio/daemons/automatix/__init__.py +13 -0
- rucio/daemons/automatix/automatix.py +304 -0
- rucio/daemons/badreplicas/__init__.py +13 -0
- rucio/daemons/badreplicas/minos.py +322 -0
- rucio/daemons/badreplicas/minos_temporary_expiration.py +171 -0
- rucio/daemons/badreplicas/necromancer.py +196 -0
- rucio/daemons/bb8/__init__.py +13 -0
- rucio/daemons/bb8/bb8.py +353 -0
- rucio/daemons/bb8/common.py +759 -0
- rucio/daemons/bb8/nuclei_background_rebalance.py +153 -0
- rucio/daemons/bb8/t2_background_rebalance.py +153 -0
- rucio/daemons/cache/__init__.py +13 -0
- rucio/daemons/cache/consumer.py +133 -0
- rucio/daemons/common.py +405 -0
- rucio/daemons/conveyor/__init__.py +13 -0
- rucio/daemons/conveyor/common.py +562 -0
- rucio/daemons/conveyor/finisher.py +529 -0
- rucio/daemons/conveyor/poller.py +394 -0
- rucio/daemons/conveyor/preparer.py +205 -0
- rucio/daemons/conveyor/receiver.py +179 -0
- rucio/daemons/conveyor/stager.py +133 -0
- rucio/daemons/conveyor/submitter.py +403 -0
- rucio/daemons/conveyor/throttler.py +532 -0
- rucio/daemons/follower/__init__.py +13 -0
- rucio/daemons/follower/follower.py +101 -0
- rucio/daemons/hermes/__init__.py +13 -0
- rucio/daemons/hermes/hermes.py +534 -0
- rucio/daemons/judge/__init__.py +13 -0
- rucio/daemons/judge/cleaner.py +159 -0
- rucio/daemons/judge/evaluator.py +185 -0
- rucio/daemons/judge/injector.py +162 -0
- rucio/daemons/judge/repairer.py +154 -0
- rucio/daemons/oauthmanager/__init__.py +13 -0
- rucio/daemons/oauthmanager/oauthmanager.py +198 -0
- rucio/daemons/reaper/__init__.py +13 -0
- rucio/daemons/reaper/dark_reaper.py +282 -0
- rucio/daemons/reaper/reaper.py +739 -0
- rucio/daemons/replicarecoverer/__init__.py +13 -0
- rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +626 -0
- rucio/daemons/rsedecommissioner/__init__.py +13 -0
- rucio/daemons/rsedecommissioner/config.py +81 -0
- rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
- rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
- rucio/daemons/rsedecommissioner/profiles/generic.py +452 -0
- rucio/daemons/rsedecommissioner/profiles/types.py +93 -0
- rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
- rucio/daemons/storage/__init__.py +13 -0
- rucio/daemons/storage/consistency/__init__.py +13 -0
- rucio/daemons/storage/consistency/actions.py +848 -0
- rucio/daemons/tracer/__init__.py +13 -0
- rucio/daemons/tracer/kronos.py +511 -0
- rucio/daemons/transmogrifier/__init__.py +13 -0
- rucio/daemons/transmogrifier/transmogrifier.py +762 -0
- rucio/daemons/undertaker/__init__.py +13 -0
- rucio/daemons/undertaker/undertaker.py +137 -0
- rucio/db/__init__.py +13 -0
- rucio/db/sqla/__init__.py +52 -0
- rucio/db/sqla/constants.py +206 -0
- rucio/db/sqla/migrate_repo/__init__.py +13 -0
- rucio/db/sqla/migrate_repo/env.py +110 -0
- rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +70 -0
- rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +43 -0
- rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +91 -0
- rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +76 -0
- rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +43 -0
- rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +50 -0
- rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +68 -0
- rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +40 -0
- rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +45 -0
- rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +60 -0
- rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +40 -0
- rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +140 -0
- rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +73 -0
- rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +74 -0
- rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +43 -0
- rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +50 -0
- rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +134 -0
- rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +64 -0
- rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +39 -0
- rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +64 -0
- rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +51 -0
- rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +41 -0
- rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +43 -0
- rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +44 -0
- rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +53 -0
- rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +38 -0
- rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +47 -0
- rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +57 -0
- rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +69 -0
- rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +42 -0
- rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +47 -0
- rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +46 -0
- rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +40 -0
- rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +67 -0
- rucio/db/sqla/migrate_repo/versions/30d5206e9cad_increase_oauthrequest_redirect_msg_.py +37 -0
- rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +44 -0
- rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +77 -0
- rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +60 -0
- rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +72 -0
- rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +42 -0
- rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +65 -0
- rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +133 -0
- rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +76 -0
- rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +60 -0
- rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +44 -0
- rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +64 -0
- rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +40 -0
- rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +43 -0
- rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +44 -0
- rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +78 -0
- rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +41 -0
- rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +44 -0
- rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +49 -0
- rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +40 -0
- rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +63 -0
- rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
- rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +45 -0
- rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +43 -0
- rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +45 -0
- rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +47 -0
- rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +58 -0
- rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +45 -0
- rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +106 -0
- rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +55 -0
- rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +50 -0
- rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +43 -0
- rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +41 -0
- rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +91 -0
- rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +72 -0
- rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +49 -0
- rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +43 -0
- rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +53 -0
- rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +45 -0
- rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +68 -0
- rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +45 -0
- rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +94 -0
- rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +54 -0
- rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +72 -0
- rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +76 -0
- rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +47 -0
- rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +121 -0
- rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +59 -0
- rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +52 -0
- rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +54 -0
- rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +64 -0
- rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +49 -0
- rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
- rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +43 -0
- rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
- rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +91 -0
- rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +40 -0
- rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +143 -0
- rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +76 -0
- rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +50 -0
- rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +72 -0
- rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +43 -0
- rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +65 -0
- rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +47 -0
- rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +146 -0
- rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +104 -0
- rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +44 -0
- rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +43 -0
- rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +103 -0
- rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +49 -0
- rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +104 -0
- rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +29 -0
- rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +74 -0
- rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +47 -0
- rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +43 -0
- rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +37 -0
- rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +43 -0
- rucio/db/sqla/models.py +1743 -0
- rucio/db/sqla/sautils.py +55 -0
- rucio/db/sqla/session.py +529 -0
- rucio/db/sqla/types.py +206 -0
- rucio/db/sqla/util.py +543 -0
- rucio/gateway/__init__.py +13 -0
- rucio/gateway/account.py +345 -0
- rucio/gateway/account_limit.py +363 -0
- rucio/gateway/authentication.py +381 -0
- rucio/gateway/config.py +227 -0
- rucio/gateway/credential.py +70 -0
- rucio/gateway/did.py +987 -0
- rucio/gateway/dirac.py +83 -0
- rucio/gateway/exporter.py +60 -0
- rucio/gateway/heartbeat.py +76 -0
- rucio/gateway/identity.py +189 -0
- rucio/gateway/importer.py +46 -0
- rucio/gateway/lifetime_exception.py +121 -0
- rucio/gateway/lock.py +153 -0
- rucio/gateway/meta_conventions.py +98 -0
- rucio/gateway/permission.py +74 -0
- rucio/gateway/quarantined_replica.py +79 -0
- rucio/gateway/replica.py +538 -0
- rucio/gateway/request.py +330 -0
- rucio/gateway/rse.py +632 -0
- rucio/gateway/rule.py +437 -0
- rucio/gateway/scope.py +100 -0
- rucio/gateway/subscription.py +280 -0
- rucio/gateway/vo.py +126 -0
- rucio/rse/__init__.py +96 -0
- rucio/rse/protocols/__init__.py +13 -0
- rucio/rse/protocols/bittorrent.py +194 -0
- rucio/rse/protocols/cache.py +111 -0
- rucio/rse/protocols/dummy.py +100 -0
- rucio/rse/protocols/gfal.py +708 -0
- rucio/rse/protocols/globus.py +243 -0
- rucio/rse/protocols/http_cache.py +82 -0
- rucio/rse/protocols/mock.py +123 -0
- rucio/rse/protocols/ngarc.py +209 -0
- rucio/rse/protocols/posix.py +250 -0
- rucio/rse/protocols/protocol.py +361 -0
- rucio/rse/protocols/rclone.py +365 -0
- rucio/rse/protocols/rfio.py +145 -0
- rucio/rse/protocols/srm.py +338 -0
- rucio/rse/protocols/ssh.py +414 -0
- rucio/rse/protocols/storm.py +195 -0
- rucio/rse/protocols/webdav.py +594 -0
- rucio/rse/protocols/xrootd.py +302 -0
- rucio/rse/rsemanager.py +881 -0
- rucio/rse/translation.py +260 -0
- rucio/tests/__init__.py +13 -0
- rucio/tests/common.py +280 -0
- rucio/tests/common_server.py +149 -0
- rucio/transfertool/__init__.py +13 -0
- rucio/transfertool/bittorrent.py +200 -0
- rucio/transfertool/bittorrent_driver.py +50 -0
- rucio/transfertool/bittorrent_driver_qbittorrent.py +134 -0
- rucio/transfertool/fts3.py +1600 -0
- rucio/transfertool/fts3_plugins.py +152 -0
- rucio/transfertool/globus.py +201 -0
- rucio/transfertool/globus_library.py +181 -0
- rucio/transfertool/mock.py +89 -0
- rucio/transfertool/transfertool.py +221 -0
- rucio/vcsversion.py +11 -0
- rucio/version.py +45 -0
- rucio/web/__init__.py +13 -0
- rucio/web/rest/__init__.py +13 -0
- rucio/web/rest/flaskapi/__init__.py +13 -0
- rucio/web/rest/flaskapi/authenticated_bp.py +27 -0
- rucio/web/rest/flaskapi/v1/__init__.py +13 -0
- rucio/web/rest/flaskapi/v1/accountlimits.py +236 -0
- rucio/web/rest/flaskapi/v1/accounts.py +1103 -0
- rucio/web/rest/flaskapi/v1/archives.py +102 -0
- rucio/web/rest/flaskapi/v1/auth.py +1644 -0
- rucio/web/rest/flaskapi/v1/common.py +426 -0
- rucio/web/rest/flaskapi/v1/config.py +304 -0
- rucio/web/rest/flaskapi/v1/credentials.py +213 -0
- rucio/web/rest/flaskapi/v1/dids.py +2340 -0
- rucio/web/rest/flaskapi/v1/dirac.py +116 -0
- rucio/web/rest/flaskapi/v1/export.py +75 -0
- rucio/web/rest/flaskapi/v1/heartbeats.py +127 -0
- rucio/web/rest/flaskapi/v1/identities.py +285 -0
- rucio/web/rest/flaskapi/v1/import.py +132 -0
- rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +312 -0
- rucio/web/rest/flaskapi/v1/locks.py +358 -0
- rucio/web/rest/flaskapi/v1/main.py +91 -0
- rucio/web/rest/flaskapi/v1/meta_conventions.py +241 -0
- rucio/web/rest/flaskapi/v1/metrics.py +36 -0
- rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
- rucio/web/rest/flaskapi/v1/ping.py +88 -0
- rucio/web/rest/flaskapi/v1/redirect.py +366 -0
- rucio/web/rest/flaskapi/v1/replicas.py +1894 -0
- rucio/web/rest/flaskapi/v1/requests.py +998 -0
- rucio/web/rest/flaskapi/v1/rses.py +2250 -0
- rucio/web/rest/flaskapi/v1/rules.py +854 -0
- rucio/web/rest/flaskapi/v1/scopes.py +159 -0
- rucio/web/rest/flaskapi/v1/subscriptions.py +650 -0
- rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
- rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
- rucio/web/rest/flaskapi/v1/traces.py +137 -0
- rucio/web/rest/flaskapi/v1/types.py +20 -0
- rucio/web/rest/flaskapi/v1/vos.py +278 -0
- rucio/web/rest/main.py +18 -0
- rucio/web/rest/metrics.py +27 -0
- rucio/web/rest/ping.py +27 -0
- rucio-37.0.0rc1.data/data/rucio/etc/alembic.ini.template +71 -0
- rucio-37.0.0rc1.data/data/rucio/etc/alembic_offline.ini.template +74 -0
- rucio-37.0.0rc1.data/data/rucio/etc/globus-config.yml.template +5 -0
- rucio-37.0.0rc1.data/data/rucio/etc/ldap.cfg.template +30 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.atlas.client.template +43 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.template +241 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio_multi_vo.cfg.template +217 -0
- rucio-37.0.0rc1.data/data/rucio/requirements.server.txt +297 -0
- rucio-37.0.0rc1.data/data/rucio/tools/bootstrap.py +34 -0
- rucio-37.0.0rc1.data/data/rucio/tools/merge_rucio_configs.py +144 -0
- rucio-37.0.0rc1.data/data/rucio/tools/reset_database.py +40 -0
- rucio-37.0.0rc1.data/scripts/rucio +133 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-account +74 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-collection-replica +46 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-rse +78 -0
- rucio-37.0.0rc1.data/scripts/rucio-admin +97 -0
- rucio-37.0.0rc1.data/scripts/rucio-atropos +60 -0
- rucio-37.0.0rc1.data/scripts/rucio-auditor +206 -0
- rucio-37.0.0rc1.data/scripts/rucio-automatix +50 -0
- rucio-37.0.0rc1.data/scripts/rucio-bb8 +57 -0
- rucio-37.0.0rc1.data/scripts/rucio-cache-client +141 -0
- rucio-37.0.0rc1.data/scripts/rucio-cache-consumer +42 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-finisher +58 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-poller +66 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-preparer +37 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-receiver +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-stager +76 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-submitter +139 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-throttler +104 -0
- rucio-37.0.0rc1.data/scripts/rucio-dark-reaper +53 -0
- rucio-37.0.0rc1.data/scripts/rucio-dumper +160 -0
- rucio-37.0.0rc1.data/scripts/rucio-follower +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-hermes +54 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-cleaner +89 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-evaluator +137 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-injector +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-repairer +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-kronos +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-minos +53 -0
- rucio-37.0.0rc1.data/scripts/rucio-minos-temporary-expiration +50 -0
- rucio-37.0.0rc1.data/scripts/rucio-necromancer +120 -0
- rucio-37.0.0rc1.data/scripts/rucio-oauth-manager +63 -0
- rucio-37.0.0rc1.data/scripts/rucio-reaper +83 -0
- rucio-37.0.0rc1.data/scripts/rucio-replica-recoverer +248 -0
- rucio-37.0.0rc1.data/scripts/rucio-rse-decommissioner +66 -0
- rucio-37.0.0rc1.data/scripts/rucio-storage-consistency-actions +74 -0
- rucio-37.0.0rc1.data/scripts/rucio-transmogrifier +77 -0
- rucio-37.0.0rc1.data/scripts/rucio-undertaker +76 -0
- rucio-37.0.0rc1.dist-info/METADATA +92 -0
- rucio-37.0.0rc1.dist-info/RECORD +487 -0
- rucio-37.0.0rc1.dist-info/WHEEL +5 -0
- rucio-37.0.0rc1.dist-info/licenses/AUTHORS.rst +100 -0
- rucio-37.0.0rc1.dist-info/licenses/LICENSE +201 -0
- rucio-37.0.0rc1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,352 @@
|
|
|
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 json
|
|
16
|
+
import operator
|
|
17
|
+
from typing import TYPE_CHECKING
|
|
18
|
+
|
|
19
|
+
import psycopg
|
|
20
|
+
from psycopg import sql
|
|
21
|
+
from psycopg.rows import dict_row
|
|
22
|
+
|
|
23
|
+
from rucio.common import config, exception
|
|
24
|
+
from rucio.common.types import InternalScope
|
|
25
|
+
from rucio.core.did_meta_plugins.did_meta_plugin_interface import DidMetaPlugin
|
|
26
|
+
from rucio.core.did_meta_plugins.filter_engine import FilterEngine
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from typing import Optional
|
|
30
|
+
|
|
31
|
+
from sqlalchemy.orm import Session
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ExternalPostgresDidMeta(DidMetaPlugin):
|
|
35
|
+
# TODO: column-based plugin? mixed-mode (json & columns)?
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ExternalPostgresJSONDidMeta(DidMetaPlugin):
|
|
40
|
+
def __init__(self, host=None, port=None, db=None, user=None, password=None, db_schema=None, table=None,
|
|
41
|
+
table_is_managed=None, table_column_vo=None, table_column_scope=None, table_column_name=None,
|
|
42
|
+
table_column_data=None):
|
|
43
|
+
super(ExternalPostgresJSONDidMeta, self).__init__()
|
|
44
|
+
if host is None:
|
|
45
|
+
host = config.config_get('metadata', 'postgres_service_host')
|
|
46
|
+
if port is None:
|
|
47
|
+
port = config.config_get_int('metadata', 'postgres_service_port')
|
|
48
|
+
if db is None:
|
|
49
|
+
db = config.config_get('metadata', 'postgres_db')
|
|
50
|
+
if user is None:
|
|
51
|
+
user = config.config_get('metadata', 'postgres_user')
|
|
52
|
+
if password is None:
|
|
53
|
+
password = config.config_get('metadata', 'postgres_password')
|
|
54
|
+
if db_schema is None:
|
|
55
|
+
db_schema = config.config_get('metadata', 'postgres_db_schema', default='public')
|
|
56
|
+
if table is None:
|
|
57
|
+
table = config.config_get('metadata', 'postgres_table', default='dids')
|
|
58
|
+
if table_is_managed is None:
|
|
59
|
+
table_is_managed = config.config_get_bool('metadata', 'postgres_table_is_managed', default=False)
|
|
60
|
+
if table_column_vo is None:
|
|
61
|
+
table_column_vo = config.config_get('metadata', 'postgres_table_column_vo', default='vo')
|
|
62
|
+
if table_column_scope is None:
|
|
63
|
+
table_column_scope = config.config_get('metadata', 'postgres_table_column_scope', default='scope')
|
|
64
|
+
if table_column_name is None:
|
|
65
|
+
table_column_name = config.config_get('metadata', 'postgres_table_column_name', default='name')
|
|
66
|
+
if table_column_data is None:
|
|
67
|
+
table_column_data = config.config_get('metadata', 'postgres_table_column_data', default='data')
|
|
68
|
+
|
|
69
|
+
self.fixed_table_columns = {
|
|
70
|
+
'vo': table_column_vo,
|
|
71
|
+
'scope': table_column_scope,
|
|
72
|
+
'name': table_column_name
|
|
73
|
+
}
|
|
74
|
+
self.jsonb_column = table_column_data
|
|
75
|
+
|
|
76
|
+
self.table = table
|
|
77
|
+
self.client = psycopg.connect(
|
|
78
|
+
host=host,
|
|
79
|
+
port=port,
|
|
80
|
+
dbname=db,
|
|
81
|
+
user=user,
|
|
82
|
+
password=password)
|
|
83
|
+
|
|
84
|
+
# set search_path to include database schema by default
|
|
85
|
+
cur = self.client.cursor()
|
|
86
|
+
cur.execute(
|
|
87
|
+
sql.SQL("SET search_path TO {}").format(
|
|
88
|
+
sql.Identifier(db_schema)
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
cur.close()
|
|
92
|
+
|
|
93
|
+
if not table_is_managed: # not managed by Rucio, so just verify table schema
|
|
94
|
+
self._verify_table_schema(table_column_vo, table_column_scope, table_column_name, table_column_data)
|
|
95
|
+
else: # managed by Rucio, create a metadata table if it doesn't exist
|
|
96
|
+
self._try_create_metadata_table()
|
|
97
|
+
|
|
98
|
+
self.plugin_name = "POSTGRES_JSON"
|
|
99
|
+
|
|
100
|
+
def _try_create_metadata_table(self):
|
|
101
|
+
"""
|
|
102
|
+
Try to create a metadata table.
|
|
103
|
+
"""
|
|
104
|
+
table_clauses = [
|
|
105
|
+
sql.SQL("id bigint NOT NULL GENERATED ALWAYS AS IDENTITY"),
|
|
106
|
+
sql.SQL("vo varchar NOT NULL"),
|
|
107
|
+
sql.SQL("scope varchar NOT NULL"),
|
|
108
|
+
sql.SQL("name varchar NOT NULL"),
|
|
109
|
+
sql.SQL("data jsonb DEFAULT '{}'::jsonb"),
|
|
110
|
+
sql.SQL("UNIQUE (scope, name)") # unique scope+name table constraint, required for ON CONFLICT
|
|
111
|
+
]
|
|
112
|
+
statement = sql.SQL("CREATE TABLE IF NOT EXISTS {} ({})").format(
|
|
113
|
+
sql.Identifier(self.table),
|
|
114
|
+
sql.SQL(', ').join(table_clauses)
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
cur = self.client.cursor()
|
|
118
|
+
cur.execute(statement)
|
|
119
|
+
cur.close()
|
|
120
|
+
self.client.commit()
|
|
121
|
+
|
|
122
|
+
def _verify_table_schema(self, table_column_vo, table_column_scope, table_column_name, table_column_data):
|
|
123
|
+
"""
|
|
124
|
+
Rudimentary verification that the metadata table schema meets the requirements for the plugin.
|
|
125
|
+
|
|
126
|
+
Should be called when using externally managed database tables as a sanity check.
|
|
127
|
+
|
|
128
|
+
:param table_column_vo: The table column used for the vo
|
|
129
|
+
:param table_column_scope: The table column used for the scope
|
|
130
|
+
:param table_column_name: The table column used for the name
|
|
131
|
+
:param table_column_data: The table column used for the data
|
|
132
|
+
:raises: MetadataSchemaMismatchError
|
|
133
|
+
"""
|
|
134
|
+
# Check mandatory columns are of right data type and have the right nullable qualifier.
|
|
135
|
+
statement = sql.SQL(
|
|
136
|
+
"SELECT column_name, data_type, is_nullable FROM INFORMATION_SCHEMA.COLUMNS where table_name = {}").format(
|
|
137
|
+
sql.Literal(self.table)
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
cur = self.client.cursor()
|
|
141
|
+
cur.execute(statement)
|
|
142
|
+
existing_table_columns = cur.fetchall()
|
|
143
|
+
cur.close()
|
|
144
|
+
|
|
145
|
+
mandatory_column_specifications = [
|
|
146
|
+
(table_column_vo, "character varying", "NO"),
|
|
147
|
+
(table_column_scope, "character varying", "NO"),
|
|
148
|
+
(table_column_name, "character varying", "NO"),
|
|
149
|
+
(table_column_data, "jsonb", "YES")
|
|
150
|
+
]
|
|
151
|
+
for specification in mandatory_column_specifications:
|
|
152
|
+
if specification not in existing_table_columns:
|
|
153
|
+
raise exception.MetadataSchemaMismatchError(
|
|
154
|
+
"mandatory table column {} does not match that defined in the required table schema {}".format(
|
|
155
|
+
specification, existing_table_columns))
|
|
156
|
+
|
|
157
|
+
# Check required table constraints exist.
|
|
158
|
+
statement = sql.SQL(
|
|
159
|
+
"SELECT con.contype AS constraint_type, " # type: ignore
|
|
160
|
+
"(SELECT array_agg(att.attname) FROM pg_attribute att "
|
|
161
|
+
" INNER JOIN unnest(con.conkey) unnest(conkey) ON unnest.conkey = att.attnum "
|
|
162
|
+
" WHERE att.attrelid = con.conrelid) AS columns "
|
|
163
|
+
"FROM pg_constraint con "
|
|
164
|
+
"INNER JOIN pg_class rel ON rel.oid = con.conrelid "
|
|
165
|
+
"INNER JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace "
|
|
166
|
+
"WHERE rel.relname = {}"
|
|
167
|
+
).format(
|
|
168
|
+
sql.Literal(self.table)
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
cur = self.client.cursor()
|
|
172
|
+
cur.execute(statement)
|
|
173
|
+
existing_table_constraints = cur.fetchall() # list of (constraint_type, [columns])
|
|
174
|
+
cur.close()
|
|
175
|
+
|
|
176
|
+
mandatory_table_constraints = [
|
|
177
|
+
("u", [table_column_scope, table_column_name]), # unique scope+name table constraint
|
|
178
|
+
]
|
|
179
|
+
for constraint in mandatory_table_constraints:
|
|
180
|
+
if constraint not in existing_table_constraints:
|
|
181
|
+
raise exception.MetadataSchemaMismatchError(
|
|
182
|
+
"mandatory table constraint {} does not match that defined in the required table schema {}".format(
|
|
183
|
+
constraint, len(existing_table_constraints)))
|
|
184
|
+
|
|
185
|
+
def _drop_metadata_table(self):
|
|
186
|
+
cur = self.client.cursor()
|
|
187
|
+
cur.execute(
|
|
188
|
+
sql.SQL("DROP TABLE IF EXISTS {}").format(
|
|
189
|
+
sql.Identifier(self.table)
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
cur.close()
|
|
193
|
+
self.client.commit()
|
|
194
|
+
|
|
195
|
+
def get_metadata(self, scope, name, *, session: "Optional[Session]" = None):
|
|
196
|
+
"""
|
|
197
|
+
Get data identifier metadata.
|
|
198
|
+
|
|
199
|
+
:param scope: The scope name
|
|
200
|
+
:param name: The data identifier name
|
|
201
|
+
:param session: The database session in use
|
|
202
|
+
:returns: the metadata for the did
|
|
203
|
+
"""
|
|
204
|
+
statement = sql.SQL("SELECT data from {} WHERE scope = {} AND name = {}").format(
|
|
205
|
+
sql.Identifier(self.table),
|
|
206
|
+
sql.Literal(scope.internal),
|
|
207
|
+
sql.Literal(name)
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
cur = self.client.cursor()
|
|
211
|
+
cur.execute(statement)
|
|
212
|
+
metadata = cur.fetchone()
|
|
213
|
+
cur.close()
|
|
214
|
+
|
|
215
|
+
if not metadata:
|
|
216
|
+
raise exception.DataIdentifierNotFound("No metadata found for did '{}:{}".format(scope, name))
|
|
217
|
+
|
|
218
|
+
return metadata[0]
|
|
219
|
+
|
|
220
|
+
def set_metadata(self, scope, name, key, value, recursive=False, *, session: "Optional[Session]" = None):
|
|
221
|
+
"""
|
|
222
|
+
Set single metadata key.
|
|
223
|
+
|
|
224
|
+
:param scope: the scope of did
|
|
225
|
+
:param name: the name of the did
|
|
226
|
+
:param key: the key to be added
|
|
227
|
+
:param value: the value of the key to be added
|
|
228
|
+
:param recursive: recurse into DIDs (not supported)
|
|
229
|
+
:param session: The database session in use
|
|
230
|
+
"""
|
|
231
|
+
self.set_metadata_bulk(scope=scope, name=name, metadata={key: value}, recursive=recursive, session=session)
|
|
232
|
+
|
|
233
|
+
def set_metadata_bulk(self, scope, name, metadata, recursive=False, *, session: "Optional[Session]" = None):
|
|
234
|
+
"""
|
|
235
|
+
Bulk set metadata keys.
|
|
236
|
+
|
|
237
|
+
:param scope: the scope of did
|
|
238
|
+
:param name: the name of the did
|
|
239
|
+
:param metadata: dictionary of metadata keypairs to be added
|
|
240
|
+
:param recursive: recurse into DIDs (not supported)
|
|
241
|
+
:param session: The database session in use
|
|
242
|
+
"""
|
|
243
|
+
# upsert metadata
|
|
244
|
+
statement = sql.SQL(
|
|
245
|
+
"INSERT INTO {} (scope, name, vo, data) VALUES ({}, {}, {}, {}) " # type: ignore
|
|
246
|
+
"ON CONFLICT (scope, name) DO UPDATE set data = {}.data || EXCLUDED.data"
|
|
247
|
+
).format(
|
|
248
|
+
sql.Identifier(self.table),
|
|
249
|
+
sql.Literal(scope.external),
|
|
250
|
+
sql.Literal(name),
|
|
251
|
+
sql.Literal(scope.vo),
|
|
252
|
+
sql.Literal(json.dumps(metadata)),
|
|
253
|
+
sql.Identifier(self.table)
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
cur = self.client.cursor()
|
|
257
|
+
cur.execute(statement)
|
|
258
|
+
cur.close()
|
|
259
|
+
self.client.commit()
|
|
260
|
+
|
|
261
|
+
def delete_metadata(self, scope, name, key, *, session: "Optional[Session]" = None):
|
|
262
|
+
"""
|
|
263
|
+
Delete a key from metadata.
|
|
264
|
+
|
|
265
|
+
:param scope: the scope of did
|
|
266
|
+
:param name: the name of the did
|
|
267
|
+
:param key: the key to be deleted
|
|
268
|
+
:param session: the database session in use
|
|
269
|
+
"""
|
|
270
|
+
statement = sql.SQL("UPDATE {} SET data = {}.data - {}").format(
|
|
271
|
+
sql.Identifier(self.table),
|
|
272
|
+
sql.Identifier(self.table),
|
|
273
|
+
sql.Literal(key)
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
cur = self.client.cursor()
|
|
277
|
+
cur.execute(statement)
|
|
278
|
+
cur.close()
|
|
279
|
+
self.client.commit()
|
|
280
|
+
|
|
281
|
+
def list_dids(self, scope, filters, did_type='collection', ignore_case=False, limit=None,
|
|
282
|
+
offset=None, long=False, recursive=False, ignore_dids=None, *, session: "Optional[Session]" = None):
|
|
283
|
+
|
|
284
|
+
if not ignore_dids:
|
|
285
|
+
ignore_dids = set()
|
|
286
|
+
|
|
287
|
+
# backwards compatibility for filters as single {}.
|
|
288
|
+
if isinstance(filters, dict):
|
|
289
|
+
filters = [filters]
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
# instantiate fe and create postgres query
|
|
293
|
+
fe = FilterEngine(filters, model_class=None, strict_coerce=False)
|
|
294
|
+
postgres_query_str = fe.create_postgres_query(
|
|
295
|
+
additional_filters=[
|
|
296
|
+
('scope', operator.eq, scope.internal),
|
|
297
|
+
('vo', operator.eq, scope.vo)
|
|
298
|
+
],
|
|
299
|
+
fixed_table_columns=self.fixed_table_columns,
|
|
300
|
+
jsonb_column=self.jsonb_column
|
|
301
|
+
)
|
|
302
|
+
except Exception as e:
|
|
303
|
+
raise exception.DataIdentifierNotFound(e)
|
|
304
|
+
|
|
305
|
+
if recursive:
|
|
306
|
+
# TODO: possible, but requires retrieving the results of a concurrent sqla query to call list_content
|
|
307
|
+
# on for datasets and containers
|
|
308
|
+
raise exception.UnsupportedOperation(
|
|
309
|
+
"'{}' metadata module does not currently support recursive searches".format(self.plugin_name.lower())
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
statement = sql.SQL("SELECT * FROM {} WHERE {} {}").format(
|
|
313
|
+
sql.Identifier(self.table),
|
|
314
|
+
sql.SQL(postgres_query_str), # type: ignore
|
|
315
|
+
sql.SQL("LIMIT {}").format(sql.Literal(limit)) if limit else sql.SQL("")
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
cur = self.client.cursor(row_factory=dict_row)
|
|
319
|
+
cur.execute(statement)
|
|
320
|
+
query_result = cur.fetchall()
|
|
321
|
+
cur.close()
|
|
322
|
+
|
|
323
|
+
if long:
|
|
324
|
+
for row in query_result:
|
|
325
|
+
did = "{}:{}".format(row['scope'], row['name'])
|
|
326
|
+
if did not in ignore_dids: # aggregating recursive queries may contain duplicate DIDs
|
|
327
|
+
ignore_dids.add(did)
|
|
328
|
+
yield {
|
|
329
|
+
'scope': InternalScope(row['scope']),
|
|
330
|
+
'name': row['name'],
|
|
331
|
+
'did_type': "N/A",
|
|
332
|
+
'bytes': "N/A",
|
|
333
|
+
'length': "N/A"
|
|
334
|
+
}
|
|
335
|
+
else:
|
|
336
|
+
for row in query_result:
|
|
337
|
+
did = "{}:{}".format(row['scope'], row['name'])
|
|
338
|
+
if did not in ignore_dids: # aggregating recursive queries may contain duplicate DIDs
|
|
339
|
+
ignore_dids.add(did)
|
|
340
|
+
yield row['name']
|
|
341
|
+
|
|
342
|
+
def manages_key(self, key, *, session: "Optional[Session]" = None):
|
|
343
|
+
return True
|
|
344
|
+
|
|
345
|
+
def get_plugin_name(self):
|
|
346
|
+
"""
|
|
347
|
+
Returns a unique identifier for this plugin. This can be later used for filtering down results to this
|
|
348
|
+
plugin only.
|
|
349
|
+
|
|
350
|
+
:returns: The name of the plugin
|
|
351
|
+
"""
|
|
352
|
+
return self.plugin_name
|
rucio/core/dirac.py
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
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 re
|
|
16
|
+
from json import loads
|
|
17
|
+
from json.decoder import JSONDecodeError
|
|
18
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
19
|
+
|
|
20
|
+
from sqlalchemy import and_, select
|
|
21
|
+
from sqlalchemy.exc import NoResultFound
|
|
22
|
+
|
|
23
|
+
from rucio.common.config import config_get
|
|
24
|
+
from rucio.common.exception import ConfigNotFound, InvalidType, RucioException, UnsupportedOperation
|
|
25
|
+
from rucio.common.types import InternalAccount, InternalScope
|
|
26
|
+
from rucio.common.utils import extract_scope
|
|
27
|
+
from rucio.core.did import add_did, attach_dids_to_dids
|
|
28
|
+
from rucio.core.replica import add_replicas
|
|
29
|
+
from rucio.core.rule import add_rule, list_rules, update_rule
|
|
30
|
+
from rucio.core.scope import list_scopes
|
|
31
|
+
from rucio.db.sqla import models
|
|
32
|
+
from rucio.db.sqla.constants import DIDType
|
|
33
|
+
from rucio.db.sqla.session import read_session, transactional_session
|
|
34
|
+
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
from collections.abc import Iterable
|
|
37
|
+
|
|
38
|
+
from sqlalchemy.orm import Session
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@read_session
|
|
42
|
+
def _exists(
|
|
43
|
+
scope: str,
|
|
44
|
+
name: str,
|
|
45
|
+
*,
|
|
46
|
+
session: "Session"
|
|
47
|
+
) -> tuple[bool, Optional[DIDType]]:
|
|
48
|
+
"""
|
|
49
|
+
Check if the did exists
|
|
50
|
+
|
|
51
|
+
:scope: The scope
|
|
52
|
+
:name: The name
|
|
53
|
+
:session: The session used
|
|
54
|
+
"""
|
|
55
|
+
try:
|
|
56
|
+
stmt = select(
|
|
57
|
+
models.DataIdentifier.did_type
|
|
58
|
+
).with_hint(
|
|
59
|
+
models.DataIdentifier,
|
|
60
|
+
"INDEX(DIDS DIDS_PK)",
|
|
61
|
+
'oracle'
|
|
62
|
+
).where(
|
|
63
|
+
and_(models.DataIdentifier.scope == scope,
|
|
64
|
+
models.DataIdentifier.name == name)
|
|
65
|
+
)
|
|
66
|
+
return True, session.execute(stmt).scalar_one()
|
|
67
|
+
except NoResultFound:
|
|
68
|
+
return False, None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@transactional_session
|
|
72
|
+
def add_files(
|
|
73
|
+
lfns: "Iterable[dict[str, Any]]",
|
|
74
|
+
account: str,
|
|
75
|
+
ignore_availability: bool,
|
|
76
|
+
parents_metadata: Optional[dict[str, Any]] = None,
|
|
77
|
+
vo: str = 'def',
|
|
78
|
+
*,
|
|
79
|
+
session: "Session"
|
|
80
|
+
) -> None:
|
|
81
|
+
"""
|
|
82
|
+
Bulk add files :
|
|
83
|
+
- Create the file and replica.
|
|
84
|
+
- If doesn't exist create the dataset containing the file as well as a rule on the dataset on ANY sites.
|
|
85
|
+
- Create all the ascendants of the dataset if they do not exist
|
|
86
|
+
|
|
87
|
+
:param lfns: List of lfn (dictionary {'lfn': <lfn>, 'rse': <rse>, 'bytes': <bytes>, 'adler32': <adler32>, 'guid': <guid>, 'pfn': <pfn>}
|
|
88
|
+
:param issuer: The issuer account.
|
|
89
|
+
:param ignore_availability: A boolean to ignore blocklisted sites.
|
|
90
|
+
:param parents_metadata: Metadata for selected hierarchy DIDs. (dictionary {'lpn': {key : value}})
|
|
91
|
+
:param vo: The VO to act on
|
|
92
|
+
:param session: The session used
|
|
93
|
+
"""
|
|
94
|
+
rule_extension_list = []
|
|
95
|
+
attachments = []
|
|
96
|
+
if not parents_metadata:
|
|
97
|
+
parents_metadata = {}
|
|
98
|
+
# The list of scopes is necessary for the extract_scope
|
|
99
|
+
filter_ = {'scope': InternalScope(scope='*', vo=vo)}
|
|
100
|
+
scopes = list_scopes(filter_=filter_, session=session)
|
|
101
|
+
scopes = [scope.external for scope in scopes]
|
|
102
|
+
exist_lfn = []
|
|
103
|
+
try:
|
|
104
|
+
config_lifetime: str = config_get(section='dirac', option='lifetime', default='{}', session=session)
|
|
105
|
+
lifetime_dict: dict = loads(config_lifetime)
|
|
106
|
+
except ConfigNotFound:
|
|
107
|
+
lifetime_dict = {}
|
|
108
|
+
except JSONDecodeError as err:
|
|
109
|
+
raise InvalidType('Problem parsing lifetime option in dirac section : %s' % str(err))
|
|
110
|
+
except Exception as err:
|
|
111
|
+
raise RucioException(str(err))
|
|
112
|
+
|
|
113
|
+
for lfn in lfns:
|
|
114
|
+
# First check if the file exists
|
|
115
|
+
filename = lfn['lfn']
|
|
116
|
+
lfn_scope, _ = extract_scope(filename, scopes)
|
|
117
|
+
lfn_scope = InternalScope(lfn_scope, vo=vo)
|
|
118
|
+
|
|
119
|
+
exists, did_type = _exists(lfn_scope, filename)
|
|
120
|
+
if exists:
|
|
121
|
+
continue
|
|
122
|
+
|
|
123
|
+
# Get all the ascendants of the file
|
|
124
|
+
lfn_split = filename.split('/')
|
|
125
|
+
lpns = ["/".join(lfn_split[:idx]) for idx in range(2, len(lfn_split))]
|
|
126
|
+
lpns.reverse()
|
|
127
|
+
print(lpns)
|
|
128
|
+
|
|
129
|
+
# The parent must be a dataset. Register it as well as the rule
|
|
130
|
+
dsn_name = lpns[0]
|
|
131
|
+
dsn_scope, _ = extract_scope(dsn_name, scopes)
|
|
132
|
+
dsn_scope = InternalScope(dsn_scope, vo=vo)
|
|
133
|
+
dsn_meta = parents_metadata.get(dsn_name, {})
|
|
134
|
+
|
|
135
|
+
# Compute lifetime
|
|
136
|
+
lifetime = None
|
|
137
|
+
if dsn_scope in lifetime_dict:
|
|
138
|
+
lifetime = lifetime_dict[dsn_scope.external]
|
|
139
|
+
else:
|
|
140
|
+
for pattern in lifetime_dict:
|
|
141
|
+
if dsn_scope.external and re.match(pattern, str(dsn_scope.external)):
|
|
142
|
+
lifetime = lifetime_dict[pattern]
|
|
143
|
+
break
|
|
144
|
+
|
|
145
|
+
exists, did_type = _exists(dsn_scope, dsn_name)
|
|
146
|
+
if exists and did_type == DIDType.CONTAINER:
|
|
147
|
+
raise UnsupportedOperation('Cannot create %s as dataset' % dsn_name)
|
|
148
|
+
if (dsn_name not in exist_lfn) and not exists:
|
|
149
|
+
print('Will create %s' % dsn_name)
|
|
150
|
+
# to maintain a compatibility between master and LTS-1.26 branches remove keywords for first 3 arguments
|
|
151
|
+
add_did(dsn_scope,
|
|
152
|
+
dsn_name,
|
|
153
|
+
DIDType.DATASET,
|
|
154
|
+
account=InternalAccount(account, vo=vo),
|
|
155
|
+
statuses=None,
|
|
156
|
+
meta=dsn_meta,
|
|
157
|
+
rules=[{'copies': 1, 'rse_expression': 'ANY=true', 'weight': None, 'account': InternalAccount(account, vo=vo), 'lifetime': lifetime, 'grouping': 'NONE'}],
|
|
158
|
+
lifetime=None,
|
|
159
|
+
dids=None,
|
|
160
|
+
rse_id=None,
|
|
161
|
+
session=session)
|
|
162
|
+
exist_lfn.append(dsn_name)
|
|
163
|
+
parent_name = lpns[1]
|
|
164
|
+
parent_scope, _ = extract_scope(parent_name, scopes)
|
|
165
|
+
parent_scope = InternalScope(parent_scope, vo=vo)
|
|
166
|
+
attachments.append({'scope': parent_scope, 'name': parent_name, 'dids': [{'scope': dsn_scope, 'name': dsn_name}]})
|
|
167
|
+
rule_extension_list.append((dsn_scope, dsn_name))
|
|
168
|
+
if lifetime and (dsn_scope, dsn_name) not in rule_extension_list:
|
|
169
|
+
# Reset the lifetime of the rule to the configured value
|
|
170
|
+
rule = [rul for rul in list_rules({'scope': dsn_scope, 'name': dsn_name, 'account': InternalAccount(account, vo=vo)}, session=session) if rul['rse_expression'] == 'ANY=true']
|
|
171
|
+
if rule:
|
|
172
|
+
update_rule(rule[0]['id'], options={'lifetime': lifetime}, session=session)
|
|
173
|
+
rule_extension_list.append((dsn_scope, dsn_name))
|
|
174
|
+
|
|
175
|
+
# Register the file
|
|
176
|
+
rse_id = lfn.get('rse_id', None)
|
|
177
|
+
if not rse_id:
|
|
178
|
+
raise InvalidType('Missing rse_id')
|
|
179
|
+
bytes_ = lfn.get('bytes', None)
|
|
180
|
+
guid = lfn.get('guid', None)
|
|
181
|
+
adler32 = lfn.get('adler32', None)
|
|
182
|
+
pfn = lfn.get('pfn', None)
|
|
183
|
+
meta = lfn.get('meta', {})
|
|
184
|
+
files = {'scope': lfn_scope, 'name': filename, 'bytes': bytes_, 'adler32': adler32, 'meta': meta}
|
|
185
|
+
if pfn:
|
|
186
|
+
files['pfn'] = str(pfn)
|
|
187
|
+
if guid:
|
|
188
|
+
files['meta']['guid'] = guid
|
|
189
|
+
add_replicas(rse_id=rse_id,
|
|
190
|
+
files=[files],
|
|
191
|
+
dataset_meta=None,
|
|
192
|
+
account=InternalAccount(account, vo=vo),
|
|
193
|
+
ignore_availability=ignore_availability,
|
|
194
|
+
session=session)
|
|
195
|
+
add_rule(dids=[{'scope': lfn_scope, 'name': filename}],
|
|
196
|
+
account=InternalAccount(account, vo=vo),
|
|
197
|
+
copies=1,
|
|
198
|
+
rse_expression=lfn['rse'],
|
|
199
|
+
grouping=None,
|
|
200
|
+
weight=None,
|
|
201
|
+
lifetime=86400,
|
|
202
|
+
locked=None,
|
|
203
|
+
subscription_id=None,
|
|
204
|
+
session=session)
|
|
205
|
+
attachments.append({'scope': dsn_scope, 'name': dsn_name, 'dids': [{'scope': lfn_scope, 'name': filename}]})
|
|
206
|
+
|
|
207
|
+
# Now loop over the ascendants of the dataset and created them
|
|
208
|
+
for lpn in lpns[1:]:
|
|
209
|
+
child_scope, _ = extract_scope(lpn, scopes)
|
|
210
|
+
child_scope = InternalScope(child_scope, vo=vo)
|
|
211
|
+
exists, did_type = _exists(child_scope, lpn)
|
|
212
|
+
child_meta = parents_metadata.get(lpn, {})
|
|
213
|
+
if exists and did_type == DIDType.DATASET:
|
|
214
|
+
raise UnsupportedOperation('Cannot create %s as container' % lpn)
|
|
215
|
+
if (lpn not in exist_lfn) and not exists:
|
|
216
|
+
print('Will create %s' % lpn)
|
|
217
|
+
add_did(child_scope,
|
|
218
|
+
lpn,
|
|
219
|
+
DIDType.CONTAINER,
|
|
220
|
+
account=InternalAccount(account, vo=vo),
|
|
221
|
+
statuses=None,
|
|
222
|
+
meta=child_meta,
|
|
223
|
+
rules=None,
|
|
224
|
+
lifetime=None,
|
|
225
|
+
dids=None,
|
|
226
|
+
rse_id=None,
|
|
227
|
+
session=session)
|
|
228
|
+
exist_lfn.append(lpn)
|
|
229
|
+
parent_name = lpns[lpns.index(lpn) + 1]
|
|
230
|
+
parent_scope, _ = extract_scope(parent_name, scopes)
|
|
231
|
+
parent_scope = InternalScope(parent_scope, vo=vo)
|
|
232
|
+
attachments.append({'scope': parent_scope, 'name': parent_name, 'dids': [{'scope': child_scope, 'name': lpn}]})
|
|
233
|
+
# Finally attach everything
|
|
234
|
+
attach_dids_to_dids(attachments,
|
|
235
|
+
account=InternalAccount(account, vo=vo),
|
|
236
|
+
ignore_duplicate=True,
|
|
237
|
+
session=session)
|