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/db/sqla/util.py
ADDED
|
@@ -0,0 +1,543 @@
|
|
|
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 logging
|
|
16
|
+
from datetime import datetime
|
|
17
|
+
from hashlib import sha256
|
|
18
|
+
from os import urandom
|
|
19
|
+
from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union
|
|
20
|
+
|
|
21
|
+
import sqlalchemy
|
|
22
|
+
from alembic import command, op
|
|
23
|
+
from alembic.config import Config
|
|
24
|
+
from dogpile.cache.api import NoValue
|
|
25
|
+
from sqlalchemy import Column, PrimaryKeyConstraint, func, inspect
|
|
26
|
+
from sqlalchemy.dialects.postgresql.base import PGInspector
|
|
27
|
+
from sqlalchemy.exc import DatabaseError, IntegrityError
|
|
28
|
+
from sqlalchemy.orm import declarative_base
|
|
29
|
+
from sqlalchemy.schema import CreateSchema, CreateTable, DropConstraint, DropTable, ForeignKeyConstraint, MetaData, Table
|
|
30
|
+
from sqlalchemy.sql.ddl import DropSchema
|
|
31
|
+
from sqlalchemy.sql.expression import select, text
|
|
32
|
+
|
|
33
|
+
from rucio import alembicrevision
|
|
34
|
+
from rucio.common.cache import MemcacheRegion
|
|
35
|
+
from rucio.common.config import config_get, config_get_list
|
|
36
|
+
from rucio.common.schema import get_schema_value
|
|
37
|
+
from rucio.common.types import InternalAccount, LoggerFunction
|
|
38
|
+
from rucio.common.utils import generate_uuid
|
|
39
|
+
from rucio.db.sqla import models
|
|
40
|
+
from rucio.db.sqla.constants import AccountStatus, AccountType, IdentityType
|
|
41
|
+
from rucio.db.sqla.session import get_dump_engine, get_engine, get_session
|
|
42
|
+
from rucio.db.sqla.types import InternalScopeString, String
|
|
43
|
+
|
|
44
|
+
if TYPE_CHECKING:
|
|
45
|
+
from collections.abc import Sequence
|
|
46
|
+
|
|
47
|
+
from sqlalchemy.engine import Inspector
|
|
48
|
+
from sqlalchemy.orm import Query, Session
|
|
49
|
+
|
|
50
|
+
# TypeVar representing the DeclarativeObj class defined inside _create_temp_table
|
|
51
|
+
DeclarativeObj = TypeVar('DeclarativeObj')
|
|
52
|
+
|
|
53
|
+
REGION = MemcacheRegion(expiration_time=600, memcached_expire_time=3660)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def build_database() -> None:
|
|
57
|
+
""" Applies the schema to the database. Run this command once to build the database. """
|
|
58
|
+
engine = get_engine()
|
|
59
|
+
|
|
60
|
+
schema = config_get('database', 'schema', raise_exception=False, check_config_table=False)
|
|
61
|
+
if schema:
|
|
62
|
+
print('Schema set in config, trying to create schema:', schema)
|
|
63
|
+
try:
|
|
64
|
+
with engine.connect() as conn:
|
|
65
|
+
with conn.begin():
|
|
66
|
+
conn.execute(CreateSchema(schema))
|
|
67
|
+
except Exception as e:
|
|
68
|
+
print('Cannot create schema, please validate manually if schema creation is needed, continuing:', e)
|
|
69
|
+
|
|
70
|
+
models.register_models(engine)
|
|
71
|
+
|
|
72
|
+
# Put the database under version control
|
|
73
|
+
alembic_cfg = Config(config_get('alembic', 'cfg'))
|
|
74
|
+
command.stamp(alembic_cfg, "head")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def dump_schema() -> None:
|
|
78
|
+
""" Creates a schema dump to a specific database. """
|
|
79
|
+
engine = get_dump_engine()
|
|
80
|
+
models.register_models(engine)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def destroy_database() -> None:
|
|
84
|
+
""" Removes the schema from the database. Only useful for test cases or malicious intents. """
|
|
85
|
+
engine = get_engine()
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
models.unregister_models(engine)
|
|
89
|
+
except Exception as e:
|
|
90
|
+
print('Cannot destroy schema -- assuming already gone, continuing:', e)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def drop_everything() -> None:
|
|
94
|
+
"""
|
|
95
|
+
Pre-gather all named constraints and table names, and drop everything.
|
|
96
|
+
This is better than using metadata.reflect(); metadata.drop_all()
|
|
97
|
+
as it handles cyclical constraints between tables.
|
|
98
|
+
Ref. https://github.com/sqlalchemy/sqlalchemy/wiki/DropEverything
|
|
99
|
+
"""
|
|
100
|
+
engine = get_engine()
|
|
101
|
+
|
|
102
|
+
# the transaction only applies if the DB supports
|
|
103
|
+
# transactional DDL, i.e. Postgresql, MS SQL Server
|
|
104
|
+
|
|
105
|
+
with engine.connect() as conn:
|
|
106
|
+
|
|
107
|
+
inspector: Union["Inspector", PGInspector] = inspect(conn)
|
|
108
|
+
|
|
109
|
+
for tname, fkcs in reversed(
|
|
110
|
+
inspector.get_sorted_table_and_fkc_names(schema='*')):
|
|
111
|
+
if tname:
|
|
112
|
+
drop_table_stmt = DropTable(Table(tname, MetaData(), schema='*'))
|
|
113
|
+
conn.execute(drop_table_stmt)
|
|
114
|
+
elif fkcs:
|
|
115
|
+
if not engine.dialect.supports_alter:
|
|
116
|
+
continue
|
|
117
|
+
for tname, fkc in fkcs:
|
|
118
|
+
fk_constraint = ForeignKeyConstraint((), (), name=fkc)
|
|
119
|
+
Table(tname, MetaData(), fk_constraint)
|
|
120
|
+
drop_constraint_stmt = DropConstraint(fk_constraint)
|
|
121
|
+
conn.execute(drop_constraint_stmt)
|
|
122
|
+
|
|
123
|
+
schema = config_get('database', 'schema', raise_exception=False)
|
|
124
|
+
if schema:
|
|
125
|
+
conn.execute(DropSchema(schema, cascade=True))
|
|
126
|
+
|
|
127
|
+
if engine.dialect.name == 'postgresql':
|
|
128
|
+
if not isinstance(inspector, PGInspector):
|
|
129
|
+
raise ValueError('expected a PGInspector')
|
|
130
|
+
for enum in inspector.get_enums(schema='*'):
|
|
131
|
+
sqlalchemy.Enum(**enum).drop(bind=conn)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def create_base_vo() -> None:
|
|
135
|
+
""" Creates the base VO """
|
|
136
|
+
|
|
137
|
+
session_scoped = get_session()
|
|
138
|
+
|
|
139
|
+
vo = models.VO(vo='def', description='Default base VO', email='N/A')
|
|
140
|
+
with session_scoped() as s:
|
|
141
|
+
with s.begin():
|
|
142
|
+
s.add_all([vo])
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def create_root_account() -> None:
|
|
146
|
+
"""
|
|
147
|
+
Inserts the default root account to an existing database. Make sure to change the default password later.
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
multi_vo = bool(config_get('common', 'multi_vo', False, False))
|
|
151
|
+
|
|
152
|
+
up_id = config_get('bootstrap', 'userpass_identity', default='ddmlab')
|
|
153
|
+
up_pwd = config_get('bootstrap', 'userpass_pwd', default='secret')
|
|
154
|
+
up_email = config_get('bootstrap', 'userpass_email', default='ph-adp-ddm-lab@cern.ch')
|
|
155
|
+
x509_id = config_get('bootstrap', 'x509_identity', default='emailAddress=ph-adp-ddm-lab@cern.ch,CN=DDMLAB Client Certificate,OU=PH-ADP-CO,O=CERN,ST=Geneva,C=CH')
|
|
156
|
+
x509_email = config_get('bootstrap', 'x509_email', default='ph-adp-ddm-lab@cern.ch')
|
|
157
|
+
gss_id = config_get('bootstrap', 'gss_identity', default='ddmlab@CERN.CH')
|
|
158
|
+
gss_email = config_get('bootstrap', 'gss_email', default='ph-adp-ddm-lab@cern.ch')
|
|
159
|
+
ssh_id = config_get('bootstrap', 'ssh_identity',
|
|
160
|
+
default='ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq5LySllrQFpPL614sulXQ7wnIr1aGhGtl8b+HCB/'
|
|
161
|
+
'0FhMSMTHwSjX78UbfqEorZV16rXrWPgUpvcbp2hqctw6eCbxwqcgu3uGWaeS5A0iWRw7oXUh6ydn'
|
|
162
|
+
'Vy89zGzX1FJFFDZ+AgiZ3ytp55tg1bjqqhK1OSC0pJxdNe878TRVVo5MLI0S/rZY2UovCSGFaQG2'
|
|
163
|
+
'iLj14wz/YqI7NFMUuJFR4e6xmNsOP7fCZ4bGMsmnhR0GmY0dWYTupNiP5WdYXAfKExlnvFLTlDI5'
|
|
164
|
+
'Mgh4Z11NraQ8pv4YE1woolYpqOc/IMMBBXFniTT4tC7cgikxWb9ZmFe+r4t6yCDpX4IL8L5GOQ== ddmlab'
|
|
165
|
+
)
|
|
166
|
+
ssh_email = config_get('bootstrap', 'ssh_email', default='ph-adp-ddm-lab@cern.ch')
|
|
167
|
+
|
|
168
|
+
session_scoped = get_session()
|
|
169
|
+
|
|
170
|
+
if multi_vo:
|
|
171
|
+
access = 'super_root'
|
|
172
|
+
else:
|
|
173
|
+
access = 'root'
|
|
174
|
+
|
|
175
|
+
account = models.Account(account=InternalAccount(access, 'def'), account_type=AccountType.SERVICE, status=AccountStatus.ACTIVE)
|
|
176
|
+
|
|
177
|
+
salt = urandom(255)
|
|
178
|
+
salted_password = salt + up_pwd.encode()
|
|
179
|
+
hashed_password = sha256(salted_password).hexdigest()
|
|
180
|
+
|
|
181
|
+
identities = []
|
|
182
|
+
associations = []
|
|
183
|
+
|
|
184
|
+
if up_id and up_pwd:
|
|
185
|
+
identity1 = models.Identity(identity=up_id, identity_type=IdentityType.USERPASS, password=hashed_password, salt=salt, email=up_email)
|
|
186
|
+
iaa1 = models.IdentityAccountAssociation(identity=identity1.identity, identity_type=identity1.identity_type, account=account.account, is_default=True)
|
|
187
|
+
identities.append(identity1)
|
|
188
|
+
associations.append(iaa1)
|
|
189
|
+
|
|
190
|
+
# X509 authentication
|
|
191
|
+
if x509_id and x509_email:
|
|
192
|
+
identity2 = models.Identity(identity=x509_id, identity_type=IdentityType.X509, email=x509_email)
|
|
193
|
+
iaa2 = models.IdentityAccountAssociation(identity=identity2.identity, identity_type=identity2.identity_type, account=account.account, is_default=True)
|
|
194
|
+
identities.append(identity2)
|
|
195
|
+
associations.append(iaa2)
|
|
196
|
+
|
|
197
|
+
# GSS authentication
|
|
198
|
+
if gss_id and gss_email:
|
|
199
|
+
identity3 = models.Identity(identity=gss_id, identity_type=IdentityType.GSS, email=gss_email)
|
|
200
|
+
iaa3 = models.IdentityAccountAssociation(identity=identity3.identity, identity_type=identity3.identity_type, account=account.account, is_default=True)
|
|
201
|
+
identities.append(identity3)
|
|
202
|
+
associations.append(iaa3)
|
|
203
|
+
|
|
204
|
+
# SSH authentication
|
|
205
|
+
if ssh_id and ssh_email:
|
|
206
|
+
identity4 = models.Identity(identity=ssh_id, identity_type=IdentityType.SSH, email=ssh_email)
|
|
207
|
+
iaa4 = models.IdentityAccountAssociation(identity=identity4.identity, identity_type=identity4.identity_type, account=account.account, is_default=True)
|
|
208
|
+
identities.append(identity4)
|
|
209
|
+
associations.append(iaa4)
|
|
210
|
+
|
|
211
|
+
with session_scoped() as s:
|
|
212
|
+
s.begin()
|
|
213
|
+
# Apply
|
|
214
|
+
for identity in identities:
|
|
215
|
+
try:
|
|
216
|
+
s.add(identity)
|
|
217
|
+
s.commit()
|
|
218
|
+
except IntegrityError:
|
|
219
|
+
# Identities may already be in the DB when running multi-VO conversion
|
|
220
|
+
s.rollback()
|
|
221
|
+
s.add(account)
|
|
222
|
+
s.flush()
|
|
223
|
+
s.add_all(associations)
|
|
224
|
+
s.commit()
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def get_db_time() -> Optional[datetime]:
|
|
228
|
+
""" Gives the utc time on the db. """
|
|
229
|
+
session_scoped = get_session()
|
|
230
|
+
try:
|
|
231
|
+
storage_date_format = None
|
|
232
|
+
if session_scoped.bind.dialect.name == 'oracle':
|
|
233
|
+
query = select(text("sys_extract_utc(systimestamp)"))
|
|
234
|
+
elif session_scoped.bind.dialect.name == 'mysql':
|
|
235
|
+
query = select(text("utc_timestamp()"))
|
|
236
|
+
elif session_scoped.bind.dialect.name == 'sqlite':
|
|
237
|
+
query = select(text("datetime('now', 'utc')"))
|
|
238
|
+
storage_date_format = '%Y-%m-%d %H:%M:%S'
|
|
239
|
+
else:
|
|
240
|
+
query = select(func.current_date())
|
|
241
|
+
|
|
242
|
+
session = session_scoped()
|
|
243
|
+
session.begin()
|
|
244
|
+
for now, in session.execute(query):
|
|
245
|
+
if storage_date_format:
|
|
246
|
+
return datetime.strptime(now, storage_date_format)
|
|
247
|
+
return now
|
|
248
|
+
finally:
|
|
249
|
+
session_scoped.remove()
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def get_count(q: "Query") -> int:
|
|
253
|
+
"""
|
|
254
|
+
Fast way to get count in SQLAlchemy
|
|
255
|
+
Source: https://gist.github.com/hest/8798884
|
|
256
|
+
Some limits, see a more thorough version above
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
count_q = q.statement.with_only_columns([func.count()]).order_by(None)
|
|
260
|
+
count = q.session.execute(count_q).scalar()
|
|
261
|
+
return count
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def is_old_db() -> bool:
|
|
265
|
+
"""
|
|
266
|
+
Returns true, if alembic is used and the database is not on the
|
|
267
|
+
same revision as the code base.
|
|
268
|
+
"""
|
|
269
|
+
schema = config_get('database', 'schema', raise_exception=False)
|
|
270
|
+
|
|
271
|
+
# checks if alembic is being used by looking up the AlembicVersion table
|
|
272
|
+
inspector = inspect(get_engine())
|
|
273
|
+
if not inspector.has_table(models.AlembicVersion.__tablename__, schema):
|
|
274
|
+
return False
|
|
275
|
+
|
|
276
|
+
session_scoped = get_session()
|
|
277
|
+
with session_scoped() as s:
|
|
278
|
+
with s.begin():
|
|
279
|
+
# query = s.query(models.AlembicVersion.version_num)
|
|
280
|
+
query = s.execute(select(models.AlembicVersion)).scalars().all()
|
|
281
|
+
# return query.count() != 0 and str(query.first()[0]) != alembicrevision.ALEMBIC_REVISION
|
|
282
|
+
return (len(query) != 0 and str(query[0].version_num) != alembicrevision.ALEMBIC_REVISION)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def json_implemented(*, session: Optional["Session"] = None) -> bool:
|
|
286
|
+
"""
|
|
287
|
+
Checks if the database on the current server installation can support json fields.
|
|
288
|
+
|
|
289
|
+
:param session: The active session of the database.
|
|
290
|
+
:type session: Optional[Session]
|
|
291
|
+
:returns: True, if json is supported, False otherwise.
|
|
292
|
+
"""
|
|
293
|
+
if session is None:
|
|
294
|
+
session = get_session()
|
|
295
|
+
|
|
296
|
+
if session.bind.dialect.name == 'oracle':
|
|
297
|
+
oracle_version = int(session.connection().connection.version.split('.')[0])
|
|
298
|
+
if oracle_version < 12:
|
|
299
|
+
return False
|
|
300
|
+
elif session.bind.dialect.name == 'sqlite':
|
|
301
|
+
return False
|
|
302
|
+
|
|
303
|
+
return True
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def try_drop_constraint(constraint_name: str, table_name: str) -> None:
|
|
307
|
+
"""
|
|
308
|
+
Tries to drop the given constrained and returns successfully if the
|
|
309
|
+
constraint already existed on Oracle databases.
|
|
310
|
+
|
|
311
|
+
:param constraint_name: the constraint's name
|
|
312
|
+
:param table_name: the table name where the constraint resides
|
|
313
|
+
"""
|
|
314
|
+
try:
|
|
315
|
+
op.drop_constraint(constraint_name, table_name)
|
|
316
|
+
except DatabaseError as e:
|
|
317
|
+
if 'nonexistent constraint' not in str(e):
|
|
318
|
+
raise RuntimeError(e)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def list_oracle_global_temp_tables(session: "Session") -> list[str]:
|
|
322
|
+
"""
|
|
323
|
+
Retrieve the list of global temporary tables in oracle
|
|
324
|
+
"""
|
|
325
|
+
global_temp_tables = config_get_list('core', 'oracle_global_temp_tables', raise_exception=False, check_config_table=False, default='')
|
|
326
|
+
if global_temp_tables:
|
|
327
|
+
return [t.upper() for t in global_temp_tables]
|
|
328
|
+
|
|
329
|
+
cache_key = 'oracle_global_temp_tables'
|
|
330
|
+
# Set long expiration time to avoid hammering the database with this costly query
|
|
331
|
+
global_temp_tables = REGION.get(cache_key, expiration_time=3600)
|
|
332
|
+
if isinstance(global_temp_tables, NoValue):
|
|
333
|
+
# As of time of writing, get_temp_table_names doesn't allow setting the correct schema when called
|
|
334
|
+
# (like get_table_names allows). This may be fixed in a later version of sqlalchemy:
|
|
335
|
+
# FIXME: substitute with something like this:
|
|
336
|
+
# global_temp_tables = [t.upper() for t in inspect(session.bind).get_temp_table_names()]
|
|
337
|
+
global_temp_tables = [
|
|
338
|
+
str(t[0]).upper()
|
|
339
|
+
for t in session.execute(
|
|
340
|
+
text('SELECT UPPER(table_name) '
|
|
341
|
+
'FROM all_tables '
|
|
342
|
+
'WHERE OWNER = :owner AND IOT_NAME IS NULL AND DURATION IS NOT NULL'),
|
|
343
|
+
dict(owner=models.BASE.metadata.schema.upper())
|
|
344
|
+
)
|
|
345
|
+
]
|
|
346
|
+
REGION.set(cache_key, global_temp_tables)
|
|
347
|
+
return global_temp_tables
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _create_temp_table(
|
|
351
|
+
name: str,
|
|
352
|
+
*columns: "Sequence[Column]",
|
|
353
|
+
primary_key: Optional["Sequence[Any]"] = None,
|
|
354
|
+
oracle_global_name: Optional[str] = None,
|
|
355
|
+
session: Optional["Session"] = None,
|
|
356
|
+
logger: LoggerFunction = logging.log
|
|
357
|
+
) -> type["DeclarativeObj"]:
|
|
358
|
+
"""
|
|
359
|
+
Create a temporary table with the given columns, register it into a declarative base, and return it.
|
|
360
|
+
|
|
361
|
+
Attention! calling this function while a table with the same `name` is being used will lead to
|
|
362
|
+
bad consequences. Don't use it in recursive calls without taking special care.
|
|
363
|
+
|
|
364
|
+
Declarative definition _requires_ a primary key. It should be a subset of '*columns' argument
|
|
365
|
+
(either a single column, or a list). If not explicitly give, will use the first column as primary key.
|
|
366
|
+
|
|
367
|
+
On oracle, there are 2 possible types of temporary tables: global/private.
|
|
368
|
+
In the global case, tables are created once and then can be used by any session (with private data).
|
|
369
|
+
Private tables are created on-the fly, but have many limitations. For example: no indexes allowed.
|
|
370
|
+
This primary key is "fake" in this case, because it only exists in sqlalchemy and not in the database.
|
|
371
|
+
|
|
372
|
+
Mysql and sqlite don't support automatic cleanup of temporary tables on commit. This means that a
|
|
373
|
+
temporary table definition is preserved for the lifetime of a session. A session is regularly
|
|
374
|
+
re-used by sqlalchemy, that's why we have to assume the required temporary table already exist and
|
|
375
|
+
could contain data from a previous transaction. Drop all data from that table.
|
|
376
|
+
"""
|
|
377
|
+
if not primary_key:
|
|
378
|
+
primary_key = columns[0]
|
|
379
|
+
if not hasattr(primary_key, '__iter__'):
|
|
380
|
+
primary_key = (primary_key, )
|
|
381
|
+
|
|
382
|
+
oracle_table_is_global = False
|
|
383
|
+
if session.bind.dialect.name == 'oracle':
|
|
384
|
+
# Retrieve the list of global temporary tables on oracle.
|
|
385
|
+
# If the requested table is found to be global, reuse it,
|
|
386
|
+
# otherwise create a private temporary table with random name
|
|
387
|
+
global_temp_tables = list_oracle_global_temp_tables(session=session)
|
|
388
|
+
if oracle_global_name is None:
|
|
389
|
+
oracle_global_name = name
|
|
390
|
+
if oracle_global_name.upper() in global_temp_tables:
|
|
391
|
+
oracle_table_is_global = True
|
|
392
|
+
additional_kwargs = {
|
|
393
|
+
'oracle_on_commit': 'DELETE ROWS',
|
|
394
|
+
'prefixes': ['GLOBAL TEMPORARY'],
|
|
395
|
+
}
|
|
396
|
+
else:
|
|
397
|
+
logger(logging.WARNING, f"Global temporary table {name} doesn't exist. Using private temporary table.")
|
|
398
|
+
additional_kwargs = {
|
|
399
|
+
'oracle_on_commit': 'DROP DEFINITION',
|
|
400
|
+
'prefixes': ['PRIVATE TEMPORARY'],
|
|
401
|
+
}
|
|
402
|
+
# PRIVATE_TEMP_TABLE_PREFIX, which defaults to "ORA$PTT_", _must_ prefix the name
|
|
403
|
+
name = f"ORA$PTT_{name}"
|
|
404
|
+
# Oracle doesn't support the if_not_exists construct, so add a random suffix to the
|
|
405
|
+
# name to allow multiple calls to the same function within the same session.
|
|
406
|
+
# For example: multiple attach_dids_to_dids(..., session=session)
|
|
407
|
+
name = f'{name}_{generate_uuid()}'
|
|
408
|
+
elif session.bind.dialect.name == 'postgresql':
|
|
409
|
+
additional_kwargs = {
|
|
410
|
+
'postgresql_on_commit': 'DROP',
|
|
411
|
+
'prefixes': ['TEMPORARY'],
|
|
412
|
+
}
|
|
413
|
+
else:
|
|
414
|
+
additional_kwargs = {
|
|
415
|
+
'prefixes': ['TEMPORARY'],
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
base = declarative_base()
|
|
419
|
+
table = Table(
|
|
420
|
+
oracle_global_name if oracle_table_is_global else name,
|
|
421
|
+
base.metadata,
|
|
422
|
+
*columns,
|
|
423
|
+
schema=models.BASE.metadata.schema if oracle_table_is_global else None, # Temporary tables exist in a special schema, so a schema name cannot be given when creating a temporary table
|
|
424
|
+
**additional_kwargs,
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
# Oracle private temporary tables don't support indexes.
|
|
428
|
+
# So skip adding the constraints to the table in that case.
|
|
429
|
+
if not session.bind.dialect.name == 'oracle' or oracle_table_is_global:
|
|
430
|
+
table.append_constraint(PrimaryKeyConstraint(*primary_key))
|
|
431
|
+
|
|
432
|
+
class DeclarativeObj(base):
|
|
433
|
+
__table__ = table
|
|
434
|
+
# The declarative base requires a primary key, even if it doesn't exist in the database.
|
|
435
|
+
__mapper_args__ = {
|
|
436
|
+
"primary_key": primary_key,
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
# Ensure the table exists and is empty.
|
|
440
|
+
if session.bind.dialect.name == 'oracle':
|
|
441
|
+
# Oracle doesn't support if_not_exists.
|
|
442
|
+
# We ensured the unicity by appending a random string to the table name.
|
|
443
|
+
if not oracle_table_is_global:
|
|
444
|
+
session.execute(CreateTable(table))
|
|
445
|
+
elif session.bind.dialect.name == 'postgresql':
|
|
446
|
+
session.execute(CreateTable(table))
|
|
447
|
+
else:
|
|
448
|
+
# If it already exists, it can contain leftover data from a previous transaction
|
|
449
|
+
# executed by sqlalchemy within the same session (which is being re-used now)
|
|
450
|
+
# This is not the case for oracle and postgresql thanks to their "on_commit" support.
|
|
451
|
+
session.execute(CreateTable(table, if_not_exists=True))
|
|
452
|
+
session.query(DeclarativeObj).delete()
|
|
453
|
+
return DeclarativeObj
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
class TempTableManager:
|
|
457
|
+
"""
|
|
458
|
+
A class which manages temporary tables created during a session.
|
|
459
|
+
|
|
460
|
+
Attempts to create multiple temporary tables with the same name during a session will
|
|
461
|
+
result in creation of unique tables with an integer "index" suffix added to their name.
|
|
462
|
+
Without this, there would be a risk that a temporary table containing needed data are
|
|
463
|
+
cleaned up during a recursive function call, resulting in unexpected behavior.
|
|
464
|
+
The recursive call may be indirect and hard to catch. For example:
|
|
465
|
+
functionA -> functionB -> functionC -> functionA
|
|
466
|
+
|
|
467
|
+
The lifecycle of this object is bound to a particular session. In rucio, we naver use
|
|
468
|
+
sessions in multiple threads at a time, so no need to protect indexes with a mutex.
|
|
469
|
+
"""
|
|
470
|
+
|
|
471
|
+
def __init__(self, session: "Session"):
|
|
472
|
+
self.session = session
|
|
473
|
+
|
|
474
|
+
self.next_idx_to_use = {}
|
|
475
|
+
|
|
476
|
+
def create_temp_table(
|
|
477
|
+
self,
|
|
478
|
+
name: str,
|
|
479
|
+
*columns: "Sequence[Column]",
|
|
480
|
+
primary_key: Optional["Sequence[Any]"] = None,
|
|
481
|
+
logger: LoggerFunction = logging.log
|
|
482
|
+
) -> type["DeclarativeObj"]:
|
|
483
|
+
idx = self.next_idx_to_use.setdefault(name, 0)
|
|
484
|
+
table = _create_temp_table(f'{name}_{idx}', *columns, primary_key=primary_key, session=self.session, logger=logger)
|
|
485
|
+
self.next_idx_to_use[name] = idx + 1
|
|
486
|
+
return table
|
|
487
|
+
|
|
488
|
+
def create_scope_name_table(self, logger: LoggerFunction = logging.log) -> type["DeclarativeObj"]:
|
|
489
|
+
"""
|
|
490
|
+
Create a temporary table with columns 'scope' and 'name'
|
|
491
|
+
"""
|
|
492
|
+
|
|
493
|
+
columns = [
|
|
494
|
+
Column("scope", InternalScopeString(get_schema_value('SCOPE_LENGTH'))),
|
|
495
|
+
Column("name", String(get_schema_value('NAME_LENGTH'))),
|
|
496
|
+
]
|
|
497
|
+
return self.create_temp_table(
|
|
498
|
+
'TEMPORARY_SCOPE_NAME',
|
|
499
|
+
*columns,
|
|
500
|
+
primary_key=columns,
|
|
501
|
+
logger=logger,
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
def create_association_table(self, logger: LoggerFunction = logging.log) -> type["DeclarativeObj"]:
|
|
505
|
+
"""
|
|
506
|
+
Create a temporary table with columns 'scope', 'name', 'child_scope'and 'child_name'
|
|
507
|
+
"""
|
|
508
|
+
|
|
509
|
+
columns = [
|
|
510
|
+
Column("scope", InternalScopeString(get_schema_value('SCOPE_LENGTH'))),
|
|
511
|
+
Column("name", String(get_schema_value('NAME_LENGTH'))),
|
|
512
|
+
Column("child_scope", InternalScopeString(get_schema_value('SCOPE_LENGTH'))),
|
|
513
|
+
Column("child_name", String(get_schema_value('NAME_LENGTH'))),
|
|
514
|
+
]
|
|
515
|
+
return self.create_temp_table(
|
|
516
|
+
'TEMPORARY_ASSOCIATION',
|
|
517
|
+
*columns,
|
|
518
|
+
primary_key=columns,
|
|
519
|
+
logger=logger,
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
def create_id_table(self, logger: LoggerFunction = logging.log) -> type["DeclarativeObj"]:
|
|
523
|
+
"""
|
|
524
|
+
Create a temp table with a single id column of uuid type
|
|
525
|
+
"""
|
|
526
|
+
|
|
527
|
+
return self.create_temp_table(
|
|
528
|
+
'TEMPORARY_ID',
|
|
529
|
+
Column("id", models.GUID()),
|
|
530
|
+
logger=logger,
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
def temp_table_mngr(session: "Session") -> TempTableManager:
|
|
535
|
+
"""
|
|
536
|
+
Creates (if doesn't yet exist) and returns a TempTableManager instance associated to the session
|
|
537
|
+
"""
|
|
538
|
+
key = 'temp_table_mngr'
|
|
539
|
+
mngr = session.info.get(key)
|
|
540
|
+
if not mngr:
|
|
541
|
+
mngr = TempTableManager(session)
|
|
542
|
+
session.info[key] = mngr
|
|
543
|
+
return mngr
|
|
@@ -0,0 +1,13 @@
|
|
|
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.
|