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,240 @@
|
|
|
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 as json_lib
|
|
16
|
+
import operator
|
|
17
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
18
|
+
|
|
19
|
+
from sqlalchemy import and_, select
|
|
20
|
+
from sqlalchemy.exc import DataError, NoResultFound
|
|
21
|
+
|
|
22
|
+
from rucio.common import exception
|
|
23
|
+
from rucio.core.did_meta_plugins.did_meta_plugin_interface import DidMetaPlugin
|
|
24
|
+
from rucio.core.did_meta_plugins.filter_engine import FilterEngine
|
|
25
|
+
from rucio.db.sqla import models
|
|
26
|
+
from rucio.db.sqla.constants import DIDType
|
|
27
|
+
from rucio.db.sqla.session import read_session, stream_session, transactional_session
|
|
28
|
+
from rucio.db.sqla.util import json_implemented
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from sqlalchemy.orm import Session
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class JSONDidMeta(DidMetaPlugin):
|
|
35
|
+
"""
|
|
36
|
+
A plugin to store DID metadata on a table on the relational database, using JSON blobs
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self):
|
|
40
|
+
super(JSONDidMeta, self).__init__()
|
|
41
|
+
self.plugin_name = "JSON"
|
|
42
|
+
|
|
43
|
+
@read_session
|
|
44
|
+
def get_metadata(self, scope, name, *, session: "Session"):
|
|
45
|
+
"""
|
|
46
|
+
Get data identifier metadata (JSON)
|
|
47
|
+
|
|
48
|
+
:param scope: The scope name.
|
|
49
|
+
:param name: The data identifier name.
|
|
50
|
+
:param session: The database session in use.
|
|
51
|
+
"""
|
|
52
|
+
if not json_implemented(session=session):
|
|
53
|
+
raise NotImplementedError
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
stmt = select(
|
|
57
|
+
models.DidMeta
|
|
58
|
+
).where(
|
|
59
|
+
and_(models.DidMeta.scope == scope,
|
|
60
|
+
models.DidMeta.name == name)
|
|
61
|
+
)
|
|
62
|
+
row = session.execute(stmt).scalar_one()
|
|
63
|
+
meta = getattr(row, 'meta')
|
|
64
|
+
return json_lib.loads(meta) if session.bind.dialect.name in ['oracle', 'sqlite'] else meta
|
|
65
|
+
except NoResultFound:
|
|
66
|
+
return {}
|
|
67
|
+
|
|
68
|
+
@transactional_session
|
|
69
|
+
def set_metadata(self, scope, name, key, value, recursive=False, *, session: "Session"):
|
|
70
|
+
self.set_metadata_bulk(scope=scope, name=name, metadata={key: value}, recursive=recursive, session=session)
|
|
71
|
+
|
|
72
|
+
@transactional_session
|
|
73
|
+
def set_metadata_bulk(self, scope, name, metadata, recursive=False, *, session: "Session"):
|
|
74
|
+
if not json_implemented(session=session):
|
|
75
|
+
raise NotImplementedError
|
|
76
|
+
|
|
77
|
+
stmt = select(
|
|
78
|
+
models.DataIdentifier
|
|
79
|
+
).where(
|
|
80
|
+
and_(models.DataIdentifier.scope == scope,
|
|
81
|
+
models.DataIdentifier.name == name)
|
|
82
|
+
)
|
|
83
|
+
if session.execute(stmt).one_or_none() is None:
|
|
84
|
+
raise exception.DataIdentifierNotFound("Data identifier '%s:%s' not found" % (scope, name))
|
|
85
|
+
|
|
86
|
+
stmt = select(
|
|
87
|
+
models.DidMeta
|
|
88
|
+
).where(
|
|
89
|
+
and_(models.DidMeta.scope == scope,
|
|
90
|
+
models.DidMeta.name == name)
|
|
91
|
+
)
|
|
92
|
+
row_did_meta = session.execute(stmt).scalar_one_or_none()
|
|
93
|
+
if row_did_meta is None:
|
|
94
|
+
# Add metadata column to new table (if not already present)
|
|
95
|
+
row_did_meta = models.DidMeta(scope=scope, name=name)
|
|
96
|
+
row_did_meta.save(session=session, flush=False)
|
|
97
|
+
|
|
98
|
+
existing_meta = {}
|
|
99
|
+
if hasattr(row_did_meta, 'meta'):
|
|
100
|
+
if row_did_meta.meta:
|
|
101
|
+
if session.bind.dialect.name in ['oracle', 'sqlite']:
|
|
102
|
+
# Oracle and sqlite returns a string instead of a dict
|
|
103
|
+
existing_meta = json_lib.loads(cast("str", row_did_meta.meta))
|
|
104
|
+
else:
|
|
105
|
+
existing_meta = cast("dict[str, Any]", row_did_meta.meta)
|
|
106
|
+
|
|
107
|
+
for key, value in metadata.items():
|
|
108
|
+
existing_meta[key] = value
|
|
109
|
+
|
|
110
|
+
row_did_meta.meta = None
|
|
111
|
+
session.flush()
|
|
112
|
+
|
|
113
|
+
# Oracle insert takes a string as input
|
|
114
|
+
if session.bind.dialect.name in ['oracle', 'sqlite']:
|
|
115
|
+
existing_meta = json_lib.dumps(existing_meta)
|
|
116
|
+
|
|
117
|
+
row_did_meta.meta = existing_meta
|
|
118
|
+
row_did_meta.save(session=session, flush=True)
|
|
119
|
+
|
|
120
|
+
@transactional_session
|
|
121
|
+
def delete_metadata(self, scope, name, key, *, session: "Session"):
|
|
122
|
+
"""
|
|
123
|
+
Delete a key from the metadata column
|
|
124
|
+
|
|
125
|
+
:param scope: the scope of did
|
|
126
|
+
:param name: the name of the did
|
|
127
|
+
:param key: the key to be deleted
|
|
128
|
+
:param session: The database session in use.
|
|
129
|
+
"""
|
|
130
|
+
if not json_implemented(session=session):
|
|
131
|
+
raise NotImplementedError
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
stmt = select(
|
|
135
|
+
models.DidMeta
|
|
136
|
+
).where(
|
|
137
|
+
and_(models.DidMeta.scope == scope,
|
|
138
|
+
models.DidMeta.name == name)
|
|
139
|
+
)
|
|
140
|
+
row = session.execute(stmt).scalar_one()
|
|
141
|
+
existing_meta = getattr(row, 'meta')
|
|
142
|
+
# Oracle returns a string instead of a dict
|
|
143
|
+
if session.bind.dialect.name in ['oracle', 'sqlite'] and existing_meta is not None:
|
|
144
|
+
existing_meta = json_lib.loads(existing_meta)
|
|
145
|
+
|
|
146
|
+
if key not in existing_meta:
|
|
147
|
+
raise exception.KeyNotFound(key)
|
|
148
|
+
|
|
149
|
+
existing_meta.pop(key, None)
|
|
150
|
+
|
|
151
|
+
row.meta = None
|
|
152
|
+
session.flush()
|
|
153
|
+
|
|
154
|
+
# Oracle insert takes a string as input
|
|
155
|
+
if session.bind.dialect.name in ['oracle', 'sqlite']:
|
|
156
|
+
existing_meta = json_lib.dumps(existing_meta)
|
|
157
|
+
|
|
158
|
+
row.meta = existing_meta
|
|
159
|
+
except NoResultFound:
|
|
160
|
+
raise exception.DataIdentifierNotFound(f"Key not found for data identifier '{scope}:{name}'")
|
|
161
|
+
|
|
162
|
+
@stream_session
|
|
163
|
+
def list_dids(self, scope, filters, did_type='collection', ignore_case=False, limit=None,
|
|
164
|
+
offset=None, long=False, recursive=False, ignore_dids=None, *, session: "Session"):
|
|
165
|
+
if not json_implemented(session=session):
|
|
166
|
+
raise NotImplementedError
|
|
167
|
+
|
|
168
|
+
if not ignore_dids:
|
|
169
|
+
ignore_dids = set()
|
|
170
|
+
|
|
171
|
+
# backwards compatibility for filters as single {}.
|
|
172
|
+
if isinstance(filters, dict):
|
|
173
|
+
filters = [filters]
|
|
174
|
+
|
|
175
|
+
# instantiate fe and create sqla query, note that coercion to a model keyword
|
|
176
|
+
# is not appropriate here as the filter words are stored in a single json column.
|
|
177
|
+
fe = FilterEngine(filters, model_class=models.DidMeta, strict_coerce=False)
|
|
178
|
+
stmt = fe.create_sqla_query(
|
|
179
|
+
additional_model_attributes=[
|
|
180
|
+
models.DidMeta.scope,
|
|
181
|
+
models.DidMeta.name
|
|
182
|
+
], additional_filters=[
|
|
183
|
+
(models.DidMeta.scope, operator.eq, scope)
|
|
184
|
+
],
|
|
185
|
+
json_column=models.DidMeta.meta,
|
|
186
|
+
session=session
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if limit:
|
|
190
|
+
stmt = stmt.limit(
|
|
191
|
+
limit
|
|
192
|
+
)
|
|
193
|
+
if recursive:
|
|
194
|
+
from rucio.core.did import list_content
|
|
195
|
+
|
|
196
|
+
# Get attached DIDs and save in list because query has to be finished before starting a new one in the recursion
|
|
197
|
+
collections_content = []
|
|
198
|
+
for did in session.execute(stmt).yield_per(100):
|
|
199
|
+
if (did.did_type == DIDType.CONTAINER or did.did_type == DIDType.DATASET):
|
|
200
|
+
collections_content += [d for d in list_content(scope=did.scope, name=did.name)]
|
|
201
|
+
|
|
202
|
+
# Replace any name filtering with recursed DID names.
|
|
203
|
+
for did in collections_content:
|
|
204
|
+
for or_group in filters:
|
|
205
|
+
or_group['name'] = did['name']
|
|
206
|
+
for result in self.list_dids(scope=did['scope'], filters=filters, recursive=True, did_type=did_type, limit=limit, offset=offset,
|
|
207
|
+
long=long, ignore_dids=ignore_dids, session=session):
|
|
208
|
+
yield result
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
for did in session.execute(stmt).yield_per(5): # don't unpack this as it makes it dependent on query return order!
|
|
212
|
+
if long:
|
|
213
|
+
did_full = "{}:{}".format(did.scope, did.name)
|
|
214
|
+
if did_full not in ignore_dids: # concatenating results of OR clauses may contain duplicate DIDs if query result sets not mutually exclusive.
|
|
215
|
+
ignore_dids.add(did_full)
|
|
216
|
+
yield {
|
|
217
|
+
'scope': did.scope,
|
|
218
|
+
'name': did.name,
|
|
219
|
+
'did_type': None, # not available with JSON plugin
|
|
220
|
+
'bytes': None, # not available with JSON plugin
|
|
221
|
+
'length': None # not available with JSON plugin
|
|
222
|
+
}
|
|
223
|
+
else:
|
|
224
|
+
did_full = "{}:{}".format(did.scope, did.name)
|
|
225
|
+
if did_full not in ignore_dids: # concatenating results of OR clauses may contain duplicate DIDs if query result sets not mutually exclusive.
|
|
226
|
+
ignore_dids.add(did_full)
|
|
227
|
+
yield did.name
|
|
228
|
+
except DataError as e:
|
|
229
|
+
raise exception.InvalidMetadata("Database query failed: {}. This can be raised when the datatype of a key is inconsistent between dids.".format(e))
|
|
230
|
+
|
|
231
|
+
@read_session
|
|
232
|
+
def manages_key(self, key, *, session: "Session"):
|
|
233
|
+
return json_implemented(session=session)
|
|
234
|
+
|
|
235
|
+
def get_plugin_name(self):
|
|
236
|
+
"""
|
|
237
|
+
Returns a unique identifier for this plugin. This can be later used for filtering down results to this plugin only.
|
|
238
|
+
:returns: The name of the plugin.
|
|
239
|
+
"""
|
|
240
|
+
return self.plugin_name
|
|
@@ -0,0 +1,229 @@
|
|
|
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 operator
|
|
16
|
+
from typing import TYPE_CHECKING
|
|
17
|
+
|
|
18
|
+
import pymongo
|
|
19
|
+
|
|
20
|
+
from rucio.common import config, exception
|
|
21
|
+
from rucio.common.types import InternalScope
|
|
22
|
+
from rucio.core.did_meta_plugins.did_meta_plugin_interface import DidMetaPlugin
|
|
23
|
+
from rucio.core.did_meta_plugins.filter_engine import FilterEngine
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from typing import Optional
|
|
27
|
+
|
|
28
|
+
from sqlalchemy.orm import Session
|
|
29
|
+
|
|
30
|
+
IMMUTABLE_KEYS = [
|
|
31
|
+
'_id', # index key
|
|
32
|
+
'scope', # generated on insert
|
|
33
|
+
'name', # generated on insert
|
|
34
|
+
'vo' # generated on insert
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class MongoDidMeta(DidMetaPlugin):
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
host: "Optional[str]" = None,
|
|
42
|
+
port: "Optional[int]" = None,
|
|
43
|
+
db: "Optional[str]" = None,
|
|
44
|
+
collection: "Optional[str]" = None,
|
|
45
|
+
user: "Optional[str]" = None,
|
|
46
|
+
password: "Optional[str]" = None,
|
|
47
|
+
):
|
|
48
|
+
super(MongoDidMeta, self).__init__()
|
|
49
|
+
|
|
50
|
+
# Validate required parameters.
|
|
51
|
+
con_params = {
|
|
52
|
+
'mongo_service_host': host,
|
|
53
|
+
'mongo_service_port': port,
|
|
54
|
+
'mongo_db': db,
|
|
55
|
+
'mongo_collection': collection,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for param in con_params:
|
|
59
|
+
if con_params[param] is None:
|
|
60
|
+
if config.config_has_option('metadata', param):
|
|
61
|
+
con_params[param] = (
|
|
62
|
+
config.config_get_int('metadata', param)
|
|
63
|
+
if param == 'mongo_service_port'
|
|
64
|
+
else config.config_get('metadata', param)
|
|
65
|
+
)
|
|
66
|
+
else:
|
|
67
|
+
raise exception.ConnectionParameterNotFound(param)
|
|
68
|
+
|
|
69
|
+
if user is None and config.config_has_option('metadata', 'mongo_user'):
|
|
70
|
+
user = config.config_get('metadata', 'mongo_user', default=None)
|
|
71
|
+
|
|
72
|
+
if password is None and config.config_has_option('metadata', 'mongo_password'):
|
|
73
|
+
password = config.config_get('metadata', 'mongo_password')
|
|
74
|
+
|
|
75
|
+
# Set the auth (fallback to an anonymous connection if either user or password is not defined).
|
|
76
|
+
auth = "" if not user or not password else f"{user}:{password}@"
|
|
77
|
+
|
|
78
|
+
self.client = pymongo.MongoClient(
|
|
79
|
+
f"mongodb://{auth}{con_params['mongo_service_host']}:{con_params['mongo_service_port']}/"
|
|
80
|
+
)
|
|
81
|
+
self.db = self.client[con_params['mongo_db']]
|
|
82
|
+
self.col = self.db[con_params['mongo_collection']]
|
|
83
|
+
|
|
84
|
+
self.plugin_name = "MONGO"
|
|
85
|
+
|
|
86
|
+
def drop_database(self):
|
|
87
|
+
self.client.drop_database(self.db.name)
|
|
88
|
+
|
|
89
|
+
def get_metadata(self, scope, name, *, session: "Optional[Session]" = None):
|
|
90
|
+
"""
|
|
91
|
+
Get data identifier metadata.
|
|
92
|
+
|
|
93
|
+
:param scope: The scope name
|
|
94
|
+
:param name: The data identifier name
|
|
95
|
+
:param session: The database session in use
|
|
96
|
+
:returns: The metadata for the did
|
|
97
|
+
"""
|
|
98
|
+
# get first document with this did == _id
|
|
99
|
+
doc = self.col.find_one({
|
|
100
|
+
"_id": "{}:{}".format(scope.internal, name)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
# pop immutable keys
|
|
104
|
+
for key in IMMUTABLE_KEYS:
|
|
105
|
+
if key in doc:
|
|
106
|
+
doc.pop(key)
|
|
107
|
+
|
|
108
|
+
if not doc:
|
|
109
|
+
raise exception.DataIdentifierNotFound(f"No metadata found for did '{scope}:{name}'")
|
|
110
|
+
return doc
|
|
111
|
+
|
|
112
|
+
def set_metadata(self, scope, name, key, value, recursive=False, *, session: "Optional[Session]" = None):
|
|
113
|
+
"""
|
|
114
|
+
Set single metadata key.
|
|
115
|
+
|
|
116
|
+
:param scope: the scope of did
|
|
117
|
+
:param name: the name of the did
|
|
118
|
+
:param key: the key to be added
|
|
119
|
+
:param value: the value of the key to be added
|
|
120
|
+
:param recursive: recurse into DIDs (not supported)
|
|
121
|
+
:param session: The database session in use
|
|
122
|
+
"""
|
|
123
|
+
self.set_metadata_bulk(scope=scope, name=name, metadata={key: value}, recursive=recursive, session=session)
|
|
124
|
+
|
|
125
|
+
def set_metadata_bulk(self, scope, name, metadata, recursive=False, *, session: "Optional[Session]" = None):
|
|
126
|
+
"""
|
|
127
|
+
Bulk set metadata keys.
|
|
128
|
+
|
|
129
|
+
:param scope: the scope of did
|
|
130
|
+
:param name: the name of the did
|
|
131
|
+
:param metadata: dictionary of metadata keypairs to be added
|
|
132
|
+
:param recursive: recurse into DIDs (not supported)
|
|
133
|
+
:param session: The database session in use
|
|
134
|
+
"""
|
|
135
|
+
# pop immutable keys
|
|
136
|
+
for key in IMMUTABLE_KEYS:
|
|
137
|
+
if key in metadata:
|
|
138
|
+
metadata.pop(key)
|
|
139
|
+
|
|
140
|
+
# set first document with did == _id
|
|
141
|
+
self.col.update_one(
|
|
142
|
+
{
|
|
143
|
+
"_id": "{}:{}".format(scope.internal, name)
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
'$set': metadata,
|
|
147
|
+
'$setOnInsert': {
|
|
148
|
+
'scope': "{}".format(scope.external),
|
|
149
|
+
'vo': "{}".format(scope.vo),
|
|
150
|
+
'name': "{}".format(name)
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
upsert=True
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def delete_metadata(self, scope, name, key, *, session: "Optional[Session]" = None):
|
|
157
|
+
"""
|
|
158
|
+
Delete a key from metadata.
|
|
159
|
+
|
|
160
|
+
:param scope: the scope of did
|
|
161
|
+
:param name: the name of the did
|
|
162
|
+
:param key: the key to be deleted
|
|
163
|
+
"""
|
|
164
|
+
meta = {key: ""}
|
|
165
|
+
try:
|
|
166
|
+
self.col.update_one({"_id": "{}:{}".format(scope.internal, name)}, {'$unset': meta})
|
|
167
|
+
except Exception as e:
|
|
168
|
+
raise exception.DataIdentifierNotFound(e)
|
|
169
|
+
|
|
170
|
+
def list_dids(self, scope, filters, did_type='collection', ignore_case=False, limit=None,
|
|
171
|
+
offset=None, long=False, recursive=False, ignore_dids=None, *, session: "Optional[Session]" = None):
|
|
172
|
+
if not ignore_dids:
|
|
173
|
+
ignore_dids = set()
|
|
174
|
+
|
|
175
|
+
# backwards compatibility for filters as single {}.
|
|
176
|
+
if isinstance(filters, dict):
|
|
177
|
+
filters = [filters]
|
|
178
|
+
|
|
179
|
+
# instantiate fe and create mongo query
|
|
180
|
+
fe = FilterEngine(filters, model_class=None, strict_coerce=False)
|
|
181
|
+
mongo_query_str = fe.create_mongo_query(
|
|
182
|
+
additional_filters=[
|
|
183
|
+
('scope', operator.eq, scope.internal),
|
|
184
|
+
('vo', operator.eq, scope.vo)
|
|
185
|
+
]
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
if recursive:
|
|
189
|
+
# TODO: possible, but requires retrieving the results of a concurrent sqla query to call list_content on for datasets and containers
|
|
190
|
+
raise exception.UnsupportedOperation(
|
|
191
|
+
"'{}' metadata module does not currently support recursive searches".format(
|
|
192
|
+
self.plugin_name.lower()
|
|
193
|
+
))
|
|
194
|
+
|
|
195
|
+
if long:
|
|
196
|
+
query_result = self.col.find(mongo_query_str)
|
|
197
|
+
if limit:
|
|
198
|
+
query_result = query_result.limit(limit)
|
|
199
|
+
for did in query_result:
|
|
200
|
+
did_full = "{}:{}".format(did['scope'], did['name'])
|
|
201
|
+
if did_full not in ignore_dids: # aggregating recursive queries may contain duplicate DIDs
|
|
202
|
+
ignore_dids.add(did_full)
|
|
203
|
+
yield {
|
|
204
|
+
'scope': InternalScope(did['scope']),
|
|
205
|
+
'name': did['name'],
|
|
206
|
+
'did_type': "N/A",
|
|
207
|
+
'bytes': "N/A",
|
|
208
|
+
'length': "N/A"
|
|
209
|
+
}
|
|
210
|
+
else:
|
|
211
|
+
query_result = self.col.find(mongo_query_str)
|
|
212
|
+
if limit:
|
|
213
|
+
query_result = query_result.limit(limit)
|
|
214
|
+
for did in query_result:
|
|
215
|
+
did_full = "{}:{}".format(did['scope'], did['name'])
|
|
216
|
+
if did_full not in ignore_dids: # aggregating recursive queries may contain duplicate DIDs
|
|
217
|
+
ignore_dids.add(did_full)
|
|
218
|
+
yield did['name']
|
|
219
|
+
|
|
220
|
+
def manages_key(self, key, *, session: "Optional[Session]" = None):
|
|
221
|
+
return True
|
|
222
|
+
|
|
223
|
+
def get_plugin_name(self):
|
|
224
|
+
"""
|
|
225
|
+
Returns a unique identifier for this plugin. This can be later used for filtering down results to this plugin only.
|
|
226
|
+
|
|
227
|
+
:returns: The name of the plugin
|
|
228
|
+
"""
|
|
229
|
+
return self.plugin_name
|