rucio 37.0.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rucio might be problematic. Click here for more details.
- rucio/__init__.py +17 -0
- rucio/alembicrevision.py +15 -0
- rucio/cli/__init__.py +14 -0
- rucio/cli/account.py +216 -0
- rucio/cli/bin_legacy/__init__.py +13 -0
- rucio/cli/bin_legacy/rucio.py +2825 -0
- rucio/cli/bin_legacy/rucio_admin.py +2500 -0
- rucio/cli/command.py +272 -0
- rucio/cli/config.py +72 -0
- rucio/cli/did.py +191 -0
- rucio/cli/download.py +128 -0
- rucio/cli/lifetime_exception.py +33 -0
- rucio/cli/replica.py +162 -0
- rucio/cli/rse.py +293 -0
- rucio/cli/rule.py +158 -0
- rucio/cli/scope.py +40 -0
- rucio/cli/subscription.py +73 -0
- rucio/cli/upload.py +60 -0
- rucio/cli/utils.py +226 -0
- rucio/client/__init__.py +15 -0
- rucio/client/accountclient.py +432 -0
- rucio/client/accountlimitclient.py +183 -0
- rucio/client/baseclient.py +983 -0
- rucio/client/client.py +120 -0
- rucio/client/configclient.py +126 -0
- rucio/client/credentialclient.py +59 -0
- rucio/client/didclient.py +868 -0
- rucio/client/diracclient.py +56 -0
- rucio/client/downloadclient.py +1783 -0
- rucio/client/exportclient.py +44 -0
- rucio/client/fileclient.py +50 -0
- rucio/client/importclient.py +42 -0
- rucio/client/lifetimeclient.py +90 -0
- rucio/client/lockclient.py +109 -0
- rucio/client/metaconventionsclient.py +140 -0
- rucio/client/pingclient.py +44 -0
- rucio/client/replicaclient.py +452 -0
- rucio/client/requestclient.py +125 -0
- rucio/client/richclient.py +317 -0
- rucio/client/rseclient.py +746 -0
- rucio/client/ruleclient.py +294 -0
- rucio/client/scopeclient.py +90 -0
- rucio/client/subscriptionclient.py +173 -0
- rucio/client/touchclient.py +82 -0
- rucio/client/uploadclient.py +969 -0
- rucio/common/__init__.py +13 -0
- rucio/common/bittorrent.py +234 -0
- rucio/common/cache.py +111 -0
- rucio/common/checksum.py +168 -0
- rucio/common/client.py +122 -0
- rucio/common/config.py +788 -0
- rucio/common/constants.py +217 -0
- rucio/common/constraints.py +17 -0
- rucio/common/didtype.py +237 -0
- rucio/common/dumper/__init__.py +342 -0
- rucio/common/dumper/consistency.py +497 -0
- rucio/common/dumper/data_models.py +362 -0
- rucio/common/dumper/path_parsing.py +75 -0
- rucio/common/exception.py +1208 -0
- rucio/common/extra.py +31 -0
- rucio/common/logging.py +420 -0
- rucio/common/pcache.py +1409 -0
- rucio/common/plugins.py +185 -0
- rucio/common/policy.py +93 -0
- rucio/common/schema/__init__.py +200 -0
- rucio/common/schema/generic.py +416 -0
- rucio/common/schema/generic_multi_vo.py +395 -0
- rucio/common/stomp_utils.py +423 -0
- rucio/common/stopwatch.py +55 -0
- rucio/common/test_rucio_server.py +154 -0
- rucio/common/types.py +483 -0
- rucio/common/utils.py +1688 -0
- rucio/core/__init__.py +13 -0
- rucio/core/account.py +496 -0
- rucio/core/account_counter.py +236 -0
- rucio/core/account_limit.py +425 -0
- rucio/core/authentication.py +620 -0
- rucio/core/config.py +437 -0
- rucio/core/credential.py +224 -0
- rucio/core/did.py +3004 -0
- rucio/core/did_meta_plugins/__init__.py +252 -0
- rucio/core/did_meta_plugins/did_column_meta.py +331 -0
- rucio/core/did_meta_plugins/did_meta_plugin_interface.py +165 -0
- rucio/core/did_meta_plugins/elasticsearch_meta.py +407 -0
- rucio/core/did_meta_plugins/filter_engine.py +672 -0
- rucio/core/did_meta_plugins/json_meta.py +240 -0
- rucio/core/did_meta_plugins/mongo_meta.py +229 -0
- rucio/core/did_meta_plugins/postgres_meta.py +352 -0
- rucio/core/dirac.py +237 -0
- rucio/core/distance.py +187 -0
- rucio/core/exporter.py +59 -0
- rucio/core/heartbeat.py +363 -0
- rucio/core/identity.py +301 -0
- rucio/core/importer.py +260 -0
- rucio/core/lifetime_exception.py +377 -0
- rucio/core/lock.py +577 -0
- rucio/core/message.py +288 -0
- rucio/core/meta_conventions.py +203 -0
- rucio/core/monitor.py +448 -0
- rucio/core/naming_convention.py +195 -0
- rucio/core/nongrid_trace.py +136 -0
- rucio/core/oidc.py +1463 -0
- rucio/core/permission/__init__.py +161 -0
- rucio/core/permission/generic.py +1124 -0
- rucio/core/permission/generic_multi_vo.py +1144 -0
- rucio/core/quarantined_replica.py +224 -0
- rucio/core/replica.py +4483 -0
- rucio/core/replica_sorter.py +362 -0
- rucio/core/request.py +3091 -0
- rucio/core/rse.py +2079 -0
- rucio/core/rse_counter.py +185 -0
- rucio/core/rse_expression_parser.py +459 -0
- rucio/core/rse_selector.py +304 -0
- rucio/core/rule.py +4484 -0
- rucio/core/rule_grouping.py +1620 -0
- rucio/core/scope.py +181 -0
- rucio/core/subscription.py +362 -0
- rucio/core/topology.py +490 -0
- rucio/core/trace.py +375 -0
- rucio/core/transfer.py +1531 -0
- rucio/core/vo.py +169 -0
- rucio/core/volatile_replica.py +151 -0
- rucio/daemons/__init__.py +13 -0
- rucio/daemons/abacus/__init__.py +13 -0
- rucio/daemons/abacus/account.py +116 -0
- rucio/daemons/abacus/collection_replica.py +124 -0
- rucio/daemons/abacus/rse.py +117 -0
- rucio/daemons/atropos/__init__.py +13 -0
- rucio/daemons/atropos/atropos.py +242 -0
- rucio/daemons/auditor/__init__.py +289 -0
- rucio/daemons/auditor/hdfs.py +97 -0
- rucio/daemons/auditor/srmdumps.py +355 -0
- rucio/daemons/automatix/__init__.py +13 -0
- rucio/daemons/automatix/automatix.py +304 -0
- rucio/daemons/badreplicas/__init__.py +13 -0
- rucio/daemons/badreplicas/minos.py +322 -0
- rucio/daemons/badreplicas/minos_temporary_expiration.py +171 -0
- rucio/daemons/badreplicas/necromancer.py +196 -0
- rucio/daemons/bb8/__init__.py +13 -0
- rucio/daemons/bb8/bb8.py +353 -0
- rucio/daemons/bb8/common.py +759 -0
- rucio/daemons/bb8/nuclei_background_rebalance.py +153 -0
- rucio/daemons/bb8/t2_background_rebalance.py +153 -0
- rucio/daemons/cache/__init__.py +13 -0
- rucio/daemons/cache/consumer.py +133 -0
- rucio/daemons/common.py +405 -0
- rucio/daemons/conveyor/__init__.py +13 -0
- rucio/daemons/conveyor/common.py +562 -0
- rucio/daemons/conveyor/finisher.py +529 -0
- rucio/daemons/conveyor/poller.py +394 -0
- rucio/daemons/conveyor/preparer.py +205 -0
- rucio/daemons/conveyor/receiver.py +179 -0
- rucio/daemons/conveyor/stager.py +133 -0
- rucio/daemons/conveyor/submitter.py +403 -0
- rucio/daemons/conveyor/throttler.py +532 -0
- rucio/daemons/follower/__init__.py +13 -0
- rucio/daemons/follower/follower.py +101 -0
- rucio/daemons/hermes/__init__.py +13 -0
- rucio/daemons/hermes/hermes.py +534 -0
- rucio/daemons/judge/__init__.py +13 -0
- rucio/daemons/judge/cleaner.py +159 -0
- rucio/daemons/judge/evaluator.py +185 -0
- rucio/daemons/judge/injector.py +162 -0
- rucio/daemons/judge/repairer.py +154 -0
- rucio/daemons/oauthmanager/__init__.py +13 -0
- rucio/daemons/oauthmanager/oauthmanager.py +198 -0
- rucio/daemons/reaper/__init__.py +13 -0
- rucio/daemons/reaper/dark_reaper.py +282 -0
- rucio/daemons/reaper/reaper.py +739 -0
- rucio/daemons/replicarecoverer/__init__.py +13 -0
- rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +626 -0
- rucio/daemons/rsedecommissioner/__init__.py +13 -0
- rucio/daemons/rsedecommissioner/config.py +81 -0
- rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
- rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
- rucio/daemons/rsedecommissioner/profiles/generic.py +452 -0
- rucio/daemons/rsedecommissioner/profiles/types.py +93 -0
- rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
- rucio/daemons/storage/__init__.py +13 -0
- rucio/daemons/storage/consistency/__init__.py +13 -0
- rucio/daemons/storage/consistency/actions.py +848 -0
- rucio/daemons/tracer/__init__.py +13 -0
- rucio/daemons/tracer/kronos.py +511 -0
- rucio/daemons/transmogrifier/__init__.py +13 -0
- rucio/daemons/transmogrifier/transmogrifier.py +762 -0
- rucio/daemons/undertaker/__init__.py +13 -0
- rucio/daemons/undertaker/undertaker.py +137 -0
- rucio/db/__init__.py +13 -0
- rucio/db/sqla/__init__.py +52 -0
- rucio/db/sqla/constants.py +206 -0
- rucio/db/sqla/migrate_repo/__init__.py +13 -0
- rucio/db/sqla/migrate_repo/env.py +110 -0
- rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +70 -0
- rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +43 -0
- rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +91 -0
- rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +76 -0
- rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +43 -0
- rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +50 -0
- rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +68 -0
- rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +40 -0
- rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +45 -0
- rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +60 -0
- rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +40 -0
- rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +140 -0
- rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +73 -0
- rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +74 -0
- rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +43 -0
- rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +50 -0
- rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +134 -0
- rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +64 -0
- rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +39 -0
- rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +64 -0
- rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +51 -0
- rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +41 -0
- rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +43 -0
- rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +44 -0
- rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +53 -0
- rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +38 -0
- rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +47 -0
- rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +57 -0
- rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +69 -0
- rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +42 -0
- rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +47 -0
- rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +46 -0
- rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +40 -0
- rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +67 -0
- rucio/db/sqla/migrate_repo/versions/30d5206e9cad_increase_oauthrequest_redirect_msg_.py +37 -0
- rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +44 -0
- rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +77 -0
- rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +60 -0
- rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +72 -0
- rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +42 -0
- rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +65 -0
- rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +133 -0
- rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +76 -0
- rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +60 -0
- rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +44 -0
- rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +64 -0
- rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +40 -0
- rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +43 -0
- rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +44 -0
- rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +78 -0
- rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +41 -0
- rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +44 -0
- rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +49 -0
- rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +40 -0
- rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +63 -0
- rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
- rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +45 -0
- rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +43 -0
- rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +45 -0
- rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +47 -0
- rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +58 -0
- rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +45 -0
- rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +106 -0
- rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +55 -0
- rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +50 -0
- rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +43 -0
- rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +41 -0
- rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +91 -0
- rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +72 -0
- rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +49 -0
- rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +43 -0
- rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +53 -0
- rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +45 -0
- rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +68 -0
- rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +45 -0
- rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +94 -0
- rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +54 -0
- rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +72 -0
- rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +76 -0
- rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +47 -0
- rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +121 -0
- rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +59 -0
- rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +52 -0
- rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +54 -0
- rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +64 -0
- rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +49 -0
- rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
- rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +43 -0
- rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
- rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +91 -0
- rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +40 -0
- rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +143 -0
- rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +76 -0
- rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +50 -0
- rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +72 -0
- rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +43 -0
- rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +65 -0
- rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +47 -0
- rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +146 -0
- rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +104 -0
- rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +44 -0
- rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +43 -0
- rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +103 -0
- rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +49 -0
- rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +104 -0
- rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +29 -0
- rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +74 -0
- rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +47 -0
- rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +43 -0
- rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +37 -0
- rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +43 -0
- rucio/db/sqla/models.py +1743 -0
- rucio/db/sqla/sautils.py +55 -0
- rucio/db/sqla/session.py +529 -0
- rucio/db/sqla/types.py +206 -0
- rucio/db/sqla/util.py +543 -0
- rucio/gateway/__init__.py +13 -0
- rucio/gateway/account.py +345 -0
- rucio/gateway/account_limit.py +363 -0
- rucio/gateway/authentication.py +381 -0
- rucio/gateway/config.py +227 -0
- rucio/gateway/credential.py +70 -0
- rucio/gateway/did.py +987 -0
- rucio/gateway/dirac.py +83 -0
- rucio/gateway/exporter.py +60 -0
- rucio/gateway/heartbeat.py +76 -0
- rucio/gateway/identity.py +189 -0
- rucio/gateway/importer.py +46 -0
- rucio/gateway/lifetime_exception.py +121 -0
- rucio/gateway/lock.py +153 -0
- rucio/gateway/meta_conventions.py +98 -0
- rucio/gateway/permission.py +74 -0
- rucio/gateway/quarantined_replica.py +79 -0
- rucio/gateway/replica.py +538 -0
- rucio/gateway/request.py +330 -0
- rucio/gateway/rse.py +632 -0
- rucio/gateway/rule.py +437 -0
- rucio/gateway/scope.py +100 -0
- rucio/gateway/subscription.py +280 -0
- rucio/gateway/vo.py +126 -0
- rucio/rse/__init__.py +96 -0
- rucio/rse/protocols/__init__.py +13 -0
- rucio/rse/protocols/bittorrent.py +194 -0
- rucio/rse/protocols/cache.py +111 -0
- rucio/rse/protocols/dummy.py +100 -0
- rucio/rse/protocols/gfal.py +708 -0
- rucio/rse/protocols/globus.py +243 -0
- rucio/rse/protocols/http_cache.py +82 -0
- rucio/rse/protocols/mock.py +123 -0
- rucio/rse/protocols/ngarc.py +209 -0
- rucio/rse/protocols/posix.py +250 -0
- rucio/rse/protocols/protocol.py +361 -0
- rucio/rse/protocols/rclone.py +365 -0
- rucio/rse/protocols/rfio.py +145 -0
- rucio/rse/protocols/srm.py +338 -0
- rucio/rse/protocols/ssh.py +414 -0
- rucio/rse/protocols/storm.py +195 -0
- rucio/rse/protocols/webdav.py +594 -0
- rucio/rse/protocols/xrootd.py +302 -0
- rucio/rse/rsemanager.py +881 -0
- rucio/rse/translation.py +260 -0
- rucio/tests/__init__.py +13 -0
- rucio/tests/common.py +280 -0
- rucio/tests/common_server.py +149 -0
- rucio/transfertool/__init__.py +13 -0
- rucio/transfertool/bittorrent.py +200 -0
- rucio/transfertool/bittorrent_driver.py +50 -0
- rucio/transfertool/bittorrent_driver_qbittorrent.py +134 -0
- rucio/transfertool/fts3.py +1600 -0
- rucio/transfertool/fts3_plugins.py +152 -0
- rucio/transfertool/globus.py +201 -0
- rucio/transfertool/globus_library.py +181 -0
- rucio/transfertool/mock.py +89 -0
- rucio/transfertool/transfertool.py +221 -0
- rucio/vcsversion.py +11 -0
- rucio/version.py +45 -0
- rucio/web/__init__.py +13 -0
- rucio/web/rest/__init__.py +13 -0
- rucio/web/rest/flaskapi/__init__.py +13 -0
- rucio/web/rest/flaskapi/authenticated_bp.py +27 -0
- rucio/web/rest/flaskapi/v1/__init__.py +13 -0
- rucio/web/rest/flaskapi/v1/accountlimits.py +236 -0
- rucio/web/rest/flaskapi/v1/accounts.py +1103 -0
- rucio/web/rest/flaskapi/v1/archives.py +102 -0
- rucio/web/rest/flaskapi/v1/auth.py +1644 -0
- rucio/web/rest/flaskapi/v1/common.py +426 -0
- rucio/web/rest/flaskapi/v1/config.py +304 -0
- rucio/web/rest/flaskapi/v1/credentials.py +213 -0
- rucio/web/rest/flaskapi/v1/dids.py +2340 -0
- rucio/web/rest/flaskapi/v1/dirac.py +116 -0
- rucio/web/rest/flaskapi/v1/export.py +75 -0
- rucio/web/rest/flaskapi/v1/heartbeats.py +127 -0
- rucio/web/rest/flaskapi/v1/identities.py +285 -0
- rucio/web/rest/flaskapi/v1/import.py +132 -0
- rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +312 -0
- rucio/web/rest/flaskapi/v1/locks.py +358 -0
- rucio/web/rest/flaskapi/v1/main.py +91 -0
- rucio/web/rest/flaskapi/v1/meta_conventions.py +241 -0
- rucio/web/rest/flaskapi/v1/metrics.py +36 -0
- rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
- rucio/web/rest/flaskapi/v1/ping.py +88 -0
- rucio/web/rest/flaskapi/v1/redirect.py +366 -0
- rucio/web/rest/flaskapi/v1/replicas.py +1894 -0
- rucio/web/rest/flaskapi/v1/requests.py +998 -0
- rucio/web/rest/flaskapi/v1/rses.py +2250 -0
- rucio/web/rest/flaskapi/v1/rules.py +854 -0
- rucio/web/rest/flaskapi/v1/scopes.py +159 -0
- rucio/web/rest/flaskapi/v1/subscriptions.py +650 -0
- rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
- rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
- rucio/web/rest/flaskapi/v1/traces.py +137 -0
- rucio/web/rest/flaskapi/v1/types.py +20 -0
- rucio/web/rest/flaskapi/v1/vos.py +278 -0
- rucio/web/rest/main.py +18 -0
- rucio/web/rest/metrics.py +27 -0
- rucio/web/rest/ping.py +27 -0
- rucio-37.0.0rc1.data/data/rucio/etc/alembic.ini.template +71 -0
- rucio-37.0.0rc1.data/data/rucio/etc/alembic_offline.ini.template +74 -0
- rucio-37.0.0rc1.data/data/rucio/etc/globus-config.yml.template +5 -0
- rucio-37.0.0rc1.data/data/rucio/etc/ldap.cfg.template +30 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.atlas.client.template +43 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.template +241 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio_multi_vo.cfg.template +217 -0
- rucio-37.0.0rc1.data/data/rucio/requirements.server.txt +297 -0
- rucio-37.0.0rc1.data/data/rucio/tools/bootstrap.py +34 -0
- rucio-37.0.0rc1.data/data/rucio/tools/merge_rucio_configs.py +144 -0
- rucio-37.0.0rc1.data/data/rucio/tools/reset_database.py +40 -0
- rucio-37.0.0rc1.data/scripts/rucio +133 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-account +74 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-collection-replica +46 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-rse +78 -0
- rucio-37.0.0rc1.data/scripts/rucio-admin +97 -0
- rucio-37.0.0rc1.data/scripts/rucio-atropos +60 -0
- rucio-37.0.0rc1.data/scripts/rucio-auditor +206 -0
- rucio-37.0.0rc1.data/scripts/rucio-automatix +50 -0
- rucio-37.0.0rc1.data/scripts/rucio-bb8 +57 -0
- rucio-37.0.0rc1.data/scripts/rucio-cache-client +141 -0
- rucio-37.0.0rc1.data/scripts/rucio-cache-consumer +42 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-finisher +58 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-poller +66 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-preparer +37 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-receiver +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-stager +76 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-submitter +139 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-throttler +104 -0
- rucio-37.0.0rc1.data/scripts/rucio-dark-reaper +53 -0
- rucio-37.0.0rc1.data/scripts/rucio-dumper +160 -0
- rucio-37.0.0rc1.data/scripts/rucio-follower +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-hermes +54 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-cleaner +89 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-evaluator +137 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-injector +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-repairer +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-kronos +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-minos +53 -0
- rucio-37.0.0rc1.data/scripts/rucio-minos-temporary-expiration +50 -0
- rucio-37.0.0rc1.data/scripts/rucio-necromancer +120 -0
- rucio-37.0.0rc1.data/scripts/rucio-oauth-manager +63 -0
- rucio-37.0.0rc1.data/scripts/rucio-reaper +83 -0
- rucio-37.0.0rc1.data/scripts/rucio-replica-recoverer +248 -0
- rucio-37.0.0rc1.data/scripts/rucio-rse-decommissioner +66 -0
- rucio-37.0.0rc1.data/scripts/rucio-storage-consistency-actions +74 -0
- rucio-37.0.0rc1.data/scripts/rucio-transmogrifier +77 -0
- rucio-37.0.0rc1.data/scripts/rucio-undertaker +76 -0
- rucio-37.0.0rc1.dist-info/METADATA +92 -0
- rucio-37.0.0rc1.dist-info/RECORD +487 -0
- rucio-37.0.0rc1.dist-info/WHEEL +5 -0
- rucio-37.0.0rc1.dist-info/licenses/AUTHORS.rst +100 -0
- rucio-37.0.0rc1.dist-info/licenses/LICENSE +201 -0
- rucio-37.0.0rc1.dist-info/top_level.txt +1 -0
rucio/core/message.py
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
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
|
+
from typing import TYPE_CHECKING
|
|
17
|
+
|
|
18
|
+
from sqlalchemy import delete, insert, or_, select, update
|
|
19
|
+
from sqlalchemy.exc import IntegrityError
|
|
20
|
+
|
|
21
|
+
from rucio.common.config import config_get_list
|
|
22
|
+
from rucio.common.constants import MAX_MESSAGE_LENGTH, HermesService
|
|
23
|
+
from rucio.common.exception import InvalidObject, RucioException
|
|
24
|
+
from rucio.common.utils import APIEncoder, chunks
|
|
25
|
+
from rucio.db.sqla import filter_thread_work
|
|
26
|
+
from rucio.db.sqla.models import Message, MessageHistory
|
|
27
|
+
from rucio.db.sqla.session import transactional_session
|
|
28
|
+
|
|
29
|
+
if TYPE_CHECKING:
|
|
30
|
+
from typing import Any, Optional
|
|
31
|
+
|
|
32
|
+
from sqlalchemy.orm import Session
|
|
33
|
+
|
|
34
|
+
MessageType = dict[str, Any]
|
|
35
|
+
MessagesListType = list[MessageType]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@transactional_session
|
|
39
|
+
def add_messages(messages: "MessagesListType", *, session: "Session") -> None:
|
|
40
|
+
"""
|
|
41
|
+
Add a list of messages to be submitted asynchronously to a message broker.
|
|
42
|
+
|
|
43
|
+
For messages with payload bigger than MAX_MESSAGE_LENGTH, payload_nolimit is used instead of payload.
|
|
44
|
+
In the case of nolimit, a placeholder string is written to the NOT NULL payload column.
|
|
45
|
+
|
|
46
|
+
:param messages: A list of dictionaries {'event_type': str, 'payload': dict}
|
|
47
|
+
:param session: The database session to use.
|
|
48
|
+
"""
|
|
49
|
+
services = []
|
|
50
|
+
for service in config_get_list('hermes', 'services_list', raise_exception=False, default='activemq,email', session=session):
|
|
51
|
+
try:
|
|
52
|
+
HermesService(service.upper())
|
|
53
|
+
except ValueError as err:
|
|
54
|
+
raise RucioException(str(err))
|
|
55
|
+
services.append(service)
|
|
56
|
+
|
|
57
|
+
msgs = []
|
|
58
|
+
for message in messages:
|
|
59
|
+
event_type = message['event_type']
|
|
60
|
+
payload = message['payload']
|
|
61
|
+
for service in services:
|
|
62
|
+
msg = {'services': service, 'event_type': event_type}
|
|
63
|
+
try:
|
|
64
|
+
if event_type == 'email' and service != 'email':
|
|
65
|
+
continue
|
|
66
|
+
if service == 'email' and event_type != 'email':
|
|
67
|
+
continue
|
|
68
|
+
msg_payload = json.dumps(payload, cls=APIEncoder)
|
|
69
|
+
msg['payload'] = msg_payload
|
|
70
|
+
if len(msg_payload) > MAX_MESSAGE_LENGTH:
|
|
71
|
+
msg['payload_nolimit'] = msg_payload
|
|
72
|
+
msg['payload'] = 'nolimit'
|
|
73
|
+
msgs.append(msg)
|
|
74
|
+
except TypeError as err: # noqa: F841
|
|
75
|
+
raise InvalidObject(f'Invalid JSON for payload: {err}')
|
|
76
|
+
for messages_chunk in chunks(msgs, 1000):
|
|
77
|
+
stmt = insert(
|
|
78
|
+
Message
|
|
79
|
+
)
|
|
80
|
+
session.execute(stmt, messages_chunk)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@transactional_session
|
|
84
|
+
def add_message(event_type: str, payload: dict, *, session: "Session") -> None:
|
|
85
|
+
"""
|
|
86
|
+
Add a message to be submitted asynchronously to a message broker.
|
|
87
|
+
|
|
88
|
+
In the case of nolimit, a placeholder string is written to the NOT NULL payload column.
|
|
89
|
+
|
|
90
|
+
:param event_type: The type of the event as a string, e.g., NEW_DID.
|
|
91
|
+
:param payload: The message payload. Will be persisted as JSON.
|
|
92
|
+
:param session: The database session to use.
|
|
93
|
+
"""
|
|
94
|
+
add_messages([{'event_type': event_type, 'payload': payload}], session=session)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@transactional_session
|
|
98
|
+
def retrieve_messages(bulk: int = 1000,
|
|
99
|
+
thread: "Optional[int]" = None,
|
|
100
|
+
total_threads: "Optional[int]" = None,
|
|
101
|
+
event_type: "Optional[str]" = None,
|
|
102
|
+
lock: bool = False,
|
|
103
|
+
old_mode: bool = True,
|
|
104
|
+
service_filter: "Optional[str]" = None,
|
|
105
|
+
*, session: "Session") -> "MessagesListType":
|
|
106
|
+
"""
|
|
107
|
+
Retrieve up to $bulk messages.
|
|
108
|
+
|
|
109
|
+
:param bulk: Number of messages as an integer.
|
|
110
|
+
:param thread: Identifier of the caller thread as an integer.
|
|
111
|
+
:param total_threads: Maximum number of threads as an integer.
|
|
112
|
+
:param event_type: Return only specified event_type. If None, returns everything.
|
|
113
|
+
:param lock: Select exclusively some rows.
|
|
114
|
+
:param old_mode: If True, doesn't return email if event_type is None.
|
|
115
|
+
:param session: The database session to use.
|
|
116
|
+
:param service_filter: When a service is supplied this queries the database for messages for that service.
|
|
117
|
+
|
|
118
|
+
:returns messages: List of dictionaries {id, created_at, event_type, payload, services}
|
|
119
|
+
"""
|
|
120
|
+
messages = []
|
|
121
|
+
try:
|
|
122
|
+
stmt_subquery = select(
|
|
123
|
+
Message.id
|
|
124
|
+
).order_by(
|
|
125
|
+
Message.created_at
|
|
126
|
+
)
|
|
127
|
+
stmt_subquery = filter_thread_work(session=session, query=stmt_subquery, total_threads=total_threads, thread_id=thread)
|
|
128
|
+
if service_filter:
|
|
129
|
+
stmt_subquery = stmt_subquery.where(
|
|
130
|
+
Message.services == service_filter
|
|
131
|
+
)
|
|
132
|
+
if event_type:
|
|
133
|
+
stmt_subquery = stmt_subquery.where(
|
|
134
|
+
Message.event_type == event_type
|
|
135
|
+
)
|
|
136
|
+
elif old_mode:
|
|
137
|
+
stmt_subquery = stmt_subquery.where(
|
|
138
|
+
Message.event_type != 'email'
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Step 1:
|
|
142
|
+
# MySQL does not support limits in nested queries, limit on the outer query instead.
|
|
143
|
+
# This is not as performant, but the best we can get from MySQL.
|
|
144
|
+
# FIXME: SQLAlchemy generates wrong nowait MySQL8 statement for MySQL5
|
|
145
|
+
# Remove once this is resolved in SQLAlchemy
|
|
146
|
+
stmt = select(
|
|
147
|
+
Message.id,
|
|
148
|
+
Message.created_at,
|
|
149
|
+
Message.event_type,
|
|
150
|
+
Message.payload,
|
|
151
|
+
Message.services
|
|
152
|
+
)
|
|
153
|
+
if session.bind.dialect.name == 'mysql':
|
|
154
|
+
stmt = stmt.where(
|
|
155
|
+
Message.id.in_(stmt_subquery)
|
|
156
|
+
)
|
|
157
|
+
else:
|
|
158
|
+
stmt_subquery = stmt_subquery.limit(
|
|
159
|
+
bulk
|
|
160
|
+
)
|
|
161
|
+
stmt = stmt.where(
|
|
162
|
+
Message.id.in_(stmt_subquery)
|
|
163
|
+
).with_for_update(
|
|
164
|
+
nowait=True
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Step 2:
|
|
168
|
+
# MySQL does not support limits in nested queries, limit on the outer query instead.
|
|
169
|
+
# This is not as performant, but the best we can get from MySQL.
|
|
170
|
+
if session.bind.dialect.name == 'mysql':
|
|
171
|
+
stmt = stmt.limit(
|
|
172
|
+
bulk
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Step 3:
|
|
176
|
+
# Assemble message object
|
|
177
|
+
for id_, created_at, event_type, payload, services in session.execute(stmt).all():
|
|
178
|
+
message = {'id': id_,
|
|
179
|
+
'created_at': created_at,
|
|
180
|
+
'event_type': event_type,
|
|
181
|
+
'services': services}
|
|
182
|
+
|
|
183
|
+
# Only switch SQL context when necessary
|
|
184
|
+
if payload == 'nolimit':
|
|
185
|
+
nolimit_stmt = select(
|
|
186
|
+
Message.payload_nolimit
|
|
187
|
+
).where(
|
|
188
|
+
Message.id == id_
|
|
189
|
+
)
|
|
190
|
+
message['payload'] = json.loads(str(session.execute(nolimit_stmt).scalar_one()))
|
|
191
|
+
else:
|
|
192
|
+
message['payload'] = json.loads(str(payload))
|
|
193
|
+
|
|
194
|
+
messages.append(message)
|
|
195
|
+
|
|
196
|
+
return messages
|
|
197
|
+
|
|
198
|
+
except IntegrityError as e:
|
|
199
|
+
raise RucioException(e.args)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@transactional_session
|
|
203
|
+
def delete_messages(messages: "MessagesListType", *, session: "Session") -> None:
|
|
204
|
+
"""
|
|
205
|
+
Delete all messages with the given IDs, and archive them to the history.
|
|
206
|
+
|
|
207
|
+
:param messages: The messages to delete as a list of dictionaries.
|
|
208
|
+
"""
|
|
209
|
+
message_condition = []
|
|
210
|
+
for message in messages:
|
|
211
|
+
message_condition.append(Message.id == message['id'])
|
|
212
|
+
if len(message['payload']) > MAX_MESSAGE_LENGTH:
|
|
213
|
+
message['payload_nolimit'] = message.pop('payload')
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
if message_condition:
|
|
217
|
+
stmt = delete(
|
|
218
|
+
Message
|
|
219
|
+
).prefix_with(
|
|
220
|
+
'/*+ INDEX(messages MESSAGES_ID_PK) */',
|
|
221
|
+
dialect='oracle'
|
|
222
|
+
).where(
|
|
223
|
+
or_(*message_condition)
|
|
224
|
+
).execution_options(
|
|
225
|
+
synchronize_session=False
|
|
226
|
+
)
|
|
227
|
+
session.execute(stmt)
|
|
228
|
+
|
|
229
|
+
stmt = insert(
|
|
230
|
+
MessageHistory
|
|
231
|
+
)
|
|
232
|
+
session.execute(stmt, messages)
|
|
233
|
+
except IntegrityError as e:
|
|
234
|
+
raise RucioException(e.args)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
@transactional_session
|
|
238
|
+
def truncate_messages(*, session: "Session") -> None:
|
|
239
|
+
"""
|
|
240
|
+
Delete all stored messages. This is for internal purposes only.
|
|
241
|
+
|
|
242
|
+
:param session: The database session to use.
|
|
243
|
+
"""
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
stmt = delete(
|
|
247
|
+
Message
|
|
248
|
+
).execution_options(
|
|
249
|
+
synchronize_session=False
|
|
250
|
+
)
|
|
251
|
+
session.execute(stmt)
|
|
252
|
+
except IntegrityError as e:
|
|
253
|
+
raise RucioException(e.args)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
@transactional_session
|
|
257
|
+
def update_messages_services(messages: "MessagesListType", services: str, *, session: "Session") -> None:
|
|
258
|
+
"""
|
|
259
|
+
Update the services for all messages with the given IDs.
|
|
260
|
+
|
|
261
|
+
:param messages: The messages to delete as a list of dictionaries.
|
|
262
|
+
:param services: A coma separated string containing the list of services to report to.
|
|
263
|
+
:param session: The database session to use.
|
|
264
|
+
"""
|
|
265
|
+
message_condition = []
|
|
266
|
+
for message in messages:
|
|
267
|
+
message_condition.append(Message.id == message['id'])
|
|
268
|
+
if len(message['payload']) > MAX_MESSAGE_LENGTH:
|
|
269
|
+
message['payload_nolimit'] = message.pop('payload')
|
|
270
|
+
|
|
271
|
+
try:
|
|
272
|
+
if message_condition:
|
|
273
|
+
stmt = update(
|
|
274
|
+
Message
|
|
275
|
+
).prefix_with(
|
|
276
|
+
'/*+ INDEX(messages MESSAGES_ID_PK) */',
|
|
277
|
+
dialect='oracle'
|
|
278
|
+
).where(
|
|
279
|
+
or_(*message_condition)
|
|
280
|
+
).execution_options(
|
|
281
|
+
synchronize_session=False
|
|
282
|
+
).values({
|
|
283
|
+
Message.services: services
|
|
284
|
+
})
|
|
285
|
+
session.execute(stmt)
|
|
286
|
+
|
|
287
|
+
except IntegrityError as err:
|
|
288
|
+
raise RucioException(err.args)
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from re import match
|
|
16
|
+
from typing import TYPE_CHECKING, Optional, Union
|
|
17
|
+
|
|
18
|
+
from sqlalchemy import and_, delete, select
|
|
19
|
+
from sqlalchemy.exc import IntegrityError, NoResultFound
|
|
20
|
+
|
|
21
|
+
from rucio.common.constraints import AUTHORIZED_VALUE_TYPES
|
|
22
|
+
from rucio.common.exception import Duplicate, InvalidObject, InvalidValueForKey, KeyNotFound, RucioException, UnsupportedKeyType, UnsupportedValueType
|
|
23
|
+
from rucio.db.sqla import models
|
|
24
|
+
from rucio.db.sqla.constants import DIDType, KeyType
|
|
25
|
+
from rucio.db.sqla.session import read_session, transactional_session
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from sqlalchemy.orm import Session
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@transactional_session
|
|
32
|
+
def add_key(key: str, key_type: Union[KeyType, str], value_type: Optional[str] = None, value_regexp: Optional[str] = None, *, session: "Session") -> None:
|
|
33
|
+
"""
|
|
34
|
+
Add an allowed key for DID metadata (update the DID Metadata Conventions table with a new key).
|
|
35
|
+
|
|
36
|
+
:param key: the name for the new key.
|
|
37
|
+
:param key_type: the type of the key: all(container, dataset, file), collection(dataset or container), file, derived(compute from file for collection).
|
|
38
|
+
:param value_type: the type of the value, if defined.
|
|
39
|
+
:param value_regexp: the regular expression that values should match, if defined.
|
|
40
|
+
:param session: The database session in use.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
# Check if value_type is supported
|
|
44
|
+
if value_type and value_type not in [str(t) for t in AUTHORIZED_VALUE_TYPES]:
|
|
45
|
+
raise UnsupportedValueType(f"The type '{value_type}' is not supported for values!")
|
|
46
|
+
|
|
47
|
+
# Convert key_type
|
|
48
|
+
if isinstance(key_type, str):
|
|
49
|
+
key_type = str(key_type)
|
|
50
|
+
else:
|
|
51
|
+
key_type = str(key_type.value)
|
|
52
|
+
|
|
53
|
+
if key_type == 'F':
|
|
54
|
+
key_type = 'FILE'
|
|
55
|
+
elif key_type == 'D':
|
|
56
|
+
key_type = 'DATASET'
|
|
57
|
+
elif key_type == 'C':
|
|
58
|
+
key_type = 'CONTAINER'
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
key_type = KeyType(key_type)
|
|
62
|
+
except ValueError:
|
|
63
|
+
raise UnsupportedKeyType('The type \'%s\' is not supported for keys!' % str(key_type))
|
|
64
|
+
|
|
65
|
+
new_key = models.DIDMetaConventionsKey(key=key, value_type=value_type and str(value_type), value_regexp=value_regexp, key_type=key_type)
|
|
66
|
+
try:
|
|
67
|
+
new_key.save(session=session)
|
|
68
|
+
except IntegrityError as error:
|
|
69
|
+
if ('UNIQUE constraint failed' in error.args[0]) \
|
|
70
|
+
or ('conflicts with persistent instance' in error.args[0]) \
|
|
71
|
+
or match('.*IntegrityError.*ORA-00001: unique constraint.*DID_KEYS_PK.*violated.*', error.args[0]) \
|
|
72
|
+
or match('.*IntegrityError.*1062.*Duplicate entry.*for key.*', error.args[0]) \
|
|
73
|
+
or match('.*IntegrityError.*duplicate key value violates unique constraint.*', error.args[0]) \
|
|
74
|
+
or match('.*UniqueViolation.*duplicate key value violates unique constraint.*', error.args[0]) \
|
|
75
|
+
or match('.*IntegrityError.*columns? key.*not unique.*', error.args[0]):
|
|
76
|
+
raise Duplicate(f"key '{key}' already exists!")
|
|
77
|
+
raise RucioException(error.args)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@transactional_session
|
|
81
|
+
def del_key(key: str, *, session: "Session") -> None:
|
|
82
|
+
"""
|
|
83
|
+
Delete a key in the DID Metadata Conventions table.
|
|
84
|
+
|
|
85
|
+
:param key: the name for the key.
|
|
86
|
+
:param session: The database session in use.
|
|
87
|
+
"""
|
|
88
|
+
stmt = delete(
|
|
89
|
+
models.DIDMetaConventionsKey
|
|
90
|
+
).where(
|
|
91
|
+
models.DIDMetaConventionsKey.key == key
|
|
92
|
+
)
|
|
93
|
+
session.execute(stmt)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@read_session
|
|
97
|
+
def list_keys(*, session: "Session") -> list[str]:
|
|
98
|
+
"""
|
|
99
|
+
Lists all keys for DID Metadata Conventions.
|
|
100
|
+
|
|
101
|
+
:param session: The database session in use.
|
|
102
|
+
|
|
103
|
+
:returns: A list containing all keys.
|
|
104
|
+
"""
|
|
105
|
+
stmt = select(
|
|
106
|
+
models.DIDMetaConventionsKey.key
|
|
107
|
+
)
|
|
108
|
+
return list(session.execute(stmt).scalars().all())
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@transactional_session
|
|
112
|
+
def add_value(key: str, value: str, *, session: "Session") -> None:
|
|
113
|
+
"""
|
|
114
|
+
Adds a new value for a key in DID Metadata Convention.
|
|
115
|
+
|
|
116
|
+
:param key: the name for the key.
|
|
117
|
+
:param value: the value.
|
|
118
|
+
:param session: The database session in use.
|
|
119
|
+
|
|
120
|
+
:raises Duplicate: Key-Value pair exists
|
|
121
|
+
:raises KeyNotFound: Key not in metadata conventions table
|
|
122
|
+
:raises InvalidValueForKey: Value conflicts with rse expression for key values or does not have the correct type
|
|
123
|
+
"""
|
|
124
|
+
new_value = models.DIDMetaConventionsConstraint(key=key, value=value)
|
|
125
|
+
try:
|
|
126
|
+
new_value.save(session=session)
|
|
127
|
+
except IntegrityError as error:
|
|
128
|
+
if ('UNIQUE constraint failed' in error.args[0]) \
|
|
129
|
+
or ('conflicts with persistent instance' in error.args[0]) \
|
|
130
|
+
or match('.*IntegrityError.*ORA-00001: unique constraint.*DID_KEYS_PK.*violated.*', error.args[0]) \
|
|
131
|
+
or match('.*IntegrityError.*1062.*Duplicate entry.*for key.*', error.args[0]) \
|
|
132
|
+
or match('.*IntegrityError.*duplicate key value violates unique constraint.*', error.args[0]) \
|
|
133
|
+
or match('.*UniqueViolation.*duplicate key value violates unique constraint.*', error.args[0]) \
|
|
134
|
+
or match('.*IntegrityError.*columns? key.*value.*not unique.*', error.args[0]):
|
|
135
|
+
raise Duplicate(f"key-value '{key}-{value}' already exists!")
|
|
136
|
+
if match('.*IntegrityError.*foreign key constraints? failed.*', error.args[0]):
|
|
137
|
+
raise KeyNotFound(f"key '{key}' does not exist!")
|
|
138
|
+
if match('.*IntegrityError.*ORA-02291: integrity constraint.*DID_MAP_KEYS_FK.*violated.*', error.args[0]):
|
|
139
|
+
raise KeyNotFound(f"key '{key}' does not exist!")
|
|
140
|
+
if error.args[0] == "(IntegrityError) (1452, 'Cannot add or update a child row: a foreign key constraint fails (`rucio`.`did_key_map`, CONSTRAINT `DID_MAP_KEYS_FK` FOREIGN KEY (`key`) REFERENCES `did_keys` (`key`))')":
|
|
141
|
+
raise KeyNotFound(f"key '{key}' does not exist!")
|
|
142
|
+
|
|
143
|
+
raise RucioException(error.args)
|
|
144
|
+
|
|
145
|
+
statement = select(
|
|
146
|
+
models.DIDMetaConventionsKey,
|
|
147
|
+
).where(
|
|
148
|
+
models.DIDMetaConventionsKey.key == key
|
|
149
|
+
)
|
|
150
|
+
query = session.execute(statement).scalar_one()
|
|
151
|
+
|
|
152
|
+
# Check value against regexp, if defined
|
|
153
|
+
if query.value_regexp and not match(query.value_regexp, value):
|
|
154
|
+
raise InvalidValueForKey(f"The value {value} for the key {key} does not match the regular expression {query.value_regexp}")
|
|
155
|
+
|
|
156
|
+
# Check value type, if defined
|
|
157
|
+
type_map = dict([(str(t), t) for t in AUTHORIZED_VALUE_TYPES])
|
|
158
|
+
if query.value_type and not isinstance(value, type_map.get(query.value_type)): # type: ignore ; Typing error caused by 'isinstaince' not thinking types count as classes
|
|
159
|
+
raise InvalidValueForKey(f"The value {value} for the key {key} does not match the required type {query.value_type}")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@read_session
|
|
163
|
+
def list_values(key: str, *, session: "Session") -> list[str]:
|
|
164
|
+
"""
|
|
165
|
+
Lists all allowed values for a DID key (all values for a key in DID Metadata Conventions).
|
|
166
|
+
|
|
167
|
+
:param key: the name for the key.
|
|
168
|
+
:param session: The database session in use.
|
|
169
|
+
|
|
170
|
+
:returns: A list containing all values.
|
|
171
|
+
"""
|
|
172
|
+
statement = select(
|
|
173
|
+
models.DIDMetaConventionsConstraint.value
|
|
174
|
+
).where(
|
|
175
|
+
models.DIDMetaConventionsConstraint.key == key
|
|
176
|
+
)
|
|
177
|
+
return list(session.execute(statement).scalars().all())
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@read_session
|
|
181
|
+
def validate_meta(meta: dict, did_type: DIDType, *, session: "Session") -> None:
|
|
182
|
+
"""
|
|
183
|
+
Validates metadata for a did.
|
|
184
|
+
|
|
185
|
+
:param meta: the dictionary of metadata.
|
|
186
|
+
:param meta: the type of the did, e.g, DATASET, CONTAINER, FILE.
|
|
187
|
+
:param session: The database session in use.
|
|
188
|
+
|
|
189
|
+
:raises InvalidObject:
|
|
190
|
+
"""
|
|
191
|
+
# For now only validate the datatype for datasets
|
|
192
|
+
key = 'datatype'
|
|
193
|
+
if did_type == DIDType.DATASET and key in meta:
|
|
194
|
+
try:
|
|
195
|
+
statement = select(
|
|
196
|
+
models.DIDMetaConventionsConstraint.value
|
|
197
|
+
).where(
|
|
198
|
+
and_(models.DIDMetaConventionsConstraint.value == meta[key],
|
|
199
|
+
models.DIDMetaConventionsConstraint.key == key)
|
|
200
|
+
)
|
|
201
|
+
session.execute(statement).one()
|
|
202
|
+
except NoResultFound:
|
|
203
|
+
raise InvalidObject(f"The value {meta[key]}' for the key {key} is not valid")
|