rucio 32.8.6__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 +18 -0
- rucio/alembicrevision.py +16 -0
- rucio/api/__init__.py +14 -0
- rucio/api/account.py +266 -0
- rucio/api/account_limit.py +287 -0
- rucio/api/authentication.py +302 -0
- rucio/api/config.py +218 -0
- rucio/api/credential.py +60 -0
- rucio/api/did.py +726 -0
- rucio/api/dirac.py +71 -0
- rucio/api/exporter.py +60 -0
- rucio/api/heartbeat.py +62 -0
- rucio/api/identity.py +160 -0
- rucio/api/importer.py +46 -0
- rucio/api/lifetime_exception.py +95 -0
- rucio/api/lock.py +131 -0
- rucio/api/meta.py +85 -0
- rucio/api/permission.py +72 -0
- rucio/api/quarantined_replica.py +69 -0
- rucio/api/replica.py +528 -0
- rucio/api/request.py +220 -0
- rucio/api/rse.py +601 -0
- rucio/api/rule.py +335 -0
- rucio/api/scope.py +89 -0
- rucio/api/subscription.py +255 -0
- rucio/api/temporary_did.py +49 -0
- rucio/api/vo.py +112 -0
- rucio/client/__init__.py +16 -0
- rucio/client/accountclient.py +413 -0
- rucio/client/accountlimitclient.py +155 -0
- rucio/client/baseclient.py +929 -0
- rucio/client/client.py +77 -0
- rucio/client/configclient.py +113 -0
- rucio/client/credentialclient.py +54 -0
- rucio/client/didclient.py +691 -0
- rucio/client/diracclient.py +48 -0
- rucio/client/downloadclient.py +1674 -0
- rucio/client/exportclient.py +44 -0
- rucio/client/fileclient.py +51 -0
- rucio/client/importclient.py +42 -0
- rucio/client/lifetimeclient.py +74 -0
- rucio/client/lockclient.py +99 -0
- rucio/client/metaclient.py +137 -0
- rucio/client/pingclient.py +45 -0
- rucio/client/replicaclient.py +444 -0
- rucio/client/requestclient.py +109 -0
- rucio/client/rseclient.py +664 -0
- rucio/client/ruleclient.py +287 -0
- rucio/client/scopeclient.py +88 -0
- rucio/client/subscriptionclient.py +161 -0
- rucio/client/touchclient.py +78 -0
- rucio/client/uploadclient.py +871 -0
- rucio/common/__init__.py +14 -0
- rucio/common/cache.py +74 -0
- rucio/common/config.py +796 -0
- rucio/common/constants.py +92 -0
- rucio/common/constraints.py +18 -0
- rucio/common/didtype.py +187 -0
- rucio/common/dumper/__init__.py +306 -0
- rucio/common/dumper/consistency.py +449 -0
- rucio/common/dumper/data_models.py +325 -0
- rucio/common/dumper/path_parsing.py +65 -0
- rucio/common/exception.py +1092 -0
- rucio/common/extra.py +37 -0
- rucio/common/logging.py +404 -0
- rucio/common/pcache.py +1387 -0
- rucio/common/policy.py +84 -0
- rucio/common/schema/__init__.py +143 -0
- rucio/common/schema/atlas.py +411 -0
- rucio/common/schema/belleii.py +406 -0
- rucio/common/schema/cms.py +478 -0
- rucio/common/schema/domatpc.py +399 -0
- rucio/common/schema/escape.py +424 -0
- rucio/common/schema/generic.py +431 -0
- rucio/common/schema/generic_multi_vo.py +410 -0
- rucio/common/schema/icecube.py +404 -0
- rucio/common/schema/lsst.py +423 -0
- rucio/common/stomp_utils.py +160 -0
- rucio/common/stopwatch.py +56 -0
- rucio/common/test_rucio_server.py +148 -0
- rucio/common/types.py +158 -0
- rucio/common/utils.py +1946 -0
- rucio/core/__init__.py +14 -0
- rucio/core/account.py +426 -0
- rucio/core/account_counter.py +171 -0
- rucio/core/account_limit.py +357 -0
- rucio/core/authentication.py +563 -0
- rucio/core/config.py +386 -0
- rucio/core/credential.py +218 -0
- rucio/core/did.py +3102 -0
- rucio/core/did_meta_plugins/__init__.py +250 -0
- rucio/core/did_meta_plugins/did_column_meta.py +326 -0
- rucio/core/did_meta_plugins/did_meta_plugin_interface.py +116 -0
- rucio/core/did_meta_plugins/filter_engine.py +573 -0
- rucio/core/did_meta_plugins/json_meta.py +215 -0
- rucio/core/did_meta_plugins/mongo_meta.py +199 -0
- rucio/core/did_meta_plugins/postgres_meta.py +317 -0
- rucio/core/dirac.py +208 -0
- rucio/core/distance.py +164 -0
- rucio/core/exporter.py +59 -0
- rucio/core/heartbeat.py +263 -0
- rucio/core/identity.py +290 -0
- rucio/core/importer.py +248 -0
- rucio/core/lifetime_exception.py +377 -0
- rucio/core/lock.py +474 -0
- rucio/core/message.py +241 -0
- rucio/core/meta.py +190 -0
- rucio/core/monitor.py +441 -0
- rucio/core/naming_convention.py +154 -0
- rucio/core/nongrid_trace.py +124 -0
- rucio/core/oidc.py +1339 -0
- rucio/core/permission/__init__.py +107 -0
- rucio/core/permission/atlas.py +1333 -0
- rucio/core/permission/belleii.py +1076 -0
- rucio/core/permission/cms.py +1166 -0
- rucio/core/permission/escape.py +1076 -0
- rucio/core/permission/generic.py +1128 -0
- rucio/core/permission/generic_multi_vo.py +1148 -0
- rucio/core/quarantined_replica.py +190 -0
- rucio/core/replica.py +3627 -0
- rucio/core/replica_sorter.py +368 -0
- rucio/core/request.py +2241 -0
- rucio/core/rse.py +1835 -0
- rucio/core/rse_counter.py +155 -0
- rucio/core/rse_expression_parser.py +460 -0
- rucio/core/rse_selector.py +277 -0
- rucio/core/rule.py +3419 -0
- rucio/core/rule_grouping.py +1473 -0
- rucio/core/scope.py +152 -0
- rucio/core/subscription.py +316 -0
- rucio/core/temporary_did.py +188 -0
- rucio/core/topology.py +448 -0
- rucio/core/trace.py +361 -0
- rucio/core/transfer.py +1233 -0
- rucio/core/vo.py +151 -0
- rucio/core/volatile_replica.py +123 -0
- rucio/daemons/__init__.py +14 -0
- rucio/daemons/abacus/__init__.py +14 -0
- rucio/daemons/abacus/account.py +106 -0
- rucio/daemons/abacus/collection_replica.py +113 -0
- rucio/daemons/abacus/rse.py +107 -0
- rucio/daemons/atropos/__init__.py +14 -0
- rucio/daemons/atropos/atropos.py +243 -0
- rucio/daemons/auditor/__init__.py +261 -0
- rucio/daemons/auditor/hdfs.py +86 -0
- rucio/daemons/auditor/srmdumps.py +284 -0
- rucio/daemons/automatix/__init__.py +14 -0
- rucio/daemons/automatix/automatix.py +281 -0
- rucio/daemons/badreplicas/__init__.py +14 -0
- rucio/daemons/badreplicas/minos.py +311 -0
- rucio/daemons/badreplicas/minos_temporary_expiration.py +173 -0
- rucio/daemons/badreplicas/necromancer.py +200 -0
- rucio/daemons/bb8/__init__.py +14 -0
- rucio/daemons/bb8/bb8.py +356 -0
- rucio/daemons/bb8/common.py +762 -0
- rucio/daemons/bb8/nuclei_background_rebalance.py +147 -0
- rucio/daemons/bb8/t2_background_rebalance.py +146 -0
- rucio/daemons/c3po/__init__.py +14 -0
- rucio/daemons/c3po/algorithms/__init__.py +14 -0
- rucio/daemons/c3po/algorithms/simple.py +131 -0
- rucio/daemons/c3po/algorithms/t2_free_space.py +125 -0
- rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +127 -0
- rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +279 -0
- rucio/daemons/c3po/c3po.py +342 -0
- rucio/daemons/c3po/collectors/__init__.py +14 -0
- rucio/daemons/c3po/collectors/agis.py +108 -0
- rucio/daemons/c3po/collectors/free_space.py +62 -0
- rucio/daemons/c3po/collectors/jedi_did.py +48 -0
- rucio/daemons/c3po/collectors/mock_did.py +46 -0
- rucio/daemons/c3po/collectors/network_metrics.py +63 -0
- rucio/daemons/c3po/collectors/workload.py +110 -0
- rucio/daemons/c3po/utils/__init__.py +14 -0
- rucio/daemons/c3po/utils/dataset_cache.py +40 -0
- rucio/daemons/c3po/utils/expiring_dataset_cache.py +45 -0
- rucio/daemons/c3po/utils/expiring_list.py +63 -0
- rucio/daemons/c3po/utils/popularity.py +82 -0
- rucio/daemons/c3po/utils/timeseries.py +76 -0
- rucio/daemons/cache/__init__.py +14 -0
- rucio/daemons/cache/consumer.py +191 -0
- rucio/daemons/common.py +391 -0
- rucio/daemons/conveyor/__init__.py +14 -0
- rucio/daemons/conveyor/common.py +530 -0
- rucio/daemons/conveyor/finisher.py +492 -0
- rucio/daemons/conveyor/poller.py +372 -0
- rucio/daemons/conveyor/preparer.py +198 -0
- rucio/daemons/conveyor/receiver.py +206 -0
- rucio/daemons/conveyor/stager.py +127 -0
- rucio/daemons/conveyor/submitter.py +379 -0
- rucio/daemons/conveyor/throttler.py +468 -0
- rucio/daemons/follower/__init__.py +14 -0
- rucio/daemons/follower/follower.py +97 -0
- rucio/daemons/hermes/__init__.py +14 -0
- rucio/daemons/hermes/hermes.py +738 -0
- rucio/daemons/judge/__init__.py +14 -0
- rucio/daemons/judge/cleaner.py +149 -0
- rucio/daemons/judge/evaluator.py +172 -0
- rucio/daemons/judge/injector.py +154 -0
- rucio/daemons/judge/repairer.py +144 -0
- rucio/daemons/oauthmanager/__init__.py +14 -0
- rucio/daemons/oauthmanager/oauthmanager.py +199 -0
- rucio/daemons/reaper/__init__.py +14 -0
- rucio/daemons/reaper/dark_reaper.py +272 -0
- rucio/daemons/reaper/light_reaper.py +255 -0
- rucio/daemons/reaper/reaper.py +701 -0
- rucio/daemons/replicarecoverer/__init__.py +14 -0
- rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +487 -0
- rucio/daemons/storage/__init__.py +14 -0
- rucio/daemons/storage/consistency/__init__.py +14 -0
- rucio/daemons/storage/consistency/actions.py +753 -0
- rucio/daemons/tracer/__init__.py +14 -0
- rucio/daemons/tracer/kronos.py +513 -0
- rucio/daemons/transmogrifier/__init__.py +14 -0
- rucio/daemons/transmogrifier/transmogrifier.py +753 -0
- rucio/daemons/undertaker/__init__.py +14 -0
- rucio/daemons/undertaker/undertaker.py +137 -0
- rucio/db/__init__.py +14 -0
- rucio/db/sqla/__init__.py +38 -0
- rucio/db/sqla/constants.py +192 -0
- rucio/db/sqla/migrate_repo/__init__.py +14 -0
- rucio/db/sqla/migrate_repo/env.py +111 -0
- rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +71 -0
- rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +50 -0
- rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +61 -0
- rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +46 -0
- rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +93 -0
- rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +78 -0
- rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +46 -0
- rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +53 -0
- rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +69 -0
- rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +42 -0
- rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +46 -0
- rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +61 -0
- rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +42 -0
- rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +141 -0
- rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +75 -0
- rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +75 -0
- rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +46 -0
- rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +51 -0
- rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +135 -0
- rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +65 -0
- rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +42 -0
- rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +66 -0
- rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +54 -0
- rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +43 -0
- rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +46 -0
- rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +54 -0
- rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +39 -0
- rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +48 -0
- rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +47 -0
- rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +48 -0
- rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +47 -0
- rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +72 -0
- rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +46 -0
- rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +48 -0
- rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +48 -0
- rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +42 -0
- rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +69 -0
- rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +46 -0
- rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +78 -0
- rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +62 -0
- rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +74 -0
- rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +44 -0
- rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +67 -0
- rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +134 -0
- rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +58 -0
- rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +79 -0
- rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +61 -0
- rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +45 -0
- rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +46 -0
- rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +65 -0
- rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +42 -0
- rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +46 -0
- rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +46 -0
- rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +80 -0
- rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +61 -0
- rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +47 -0
- rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +46 -0
- rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +52 -0
- rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +42 -0
- rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +65 -0
- rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +46 -0
- rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +47 -0
- rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +45 -0
- rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +46 -0
- rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +48 -0
- rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +50 -0
- rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +48 -0
- rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +108 -0
- rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +57 -0
- rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +51 -0
- rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +50 -0
- rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +46 -0
- rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +42 -0
- rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +93 -0
- rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +73 -0
- rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +52 -0
- rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +45 -0
- rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +46 -0
- rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +54 -0
- rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +48 -0
- rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +70 -0
- rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +48 -0
- rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +95 -0
- rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +74 -0
- rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +78 -0
- rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +49 -0
- rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +124 -0
- rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +60 -0
- rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +53 -0
- rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +56 -0
- rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +67 -0
- rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +50 -0
- rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +46 -0
- rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +92 -0
- rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +42 -0
- rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +46 -0
- rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +147 -0
- rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +78 -0
- rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +53 -0
- rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +74 -0
- rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +56 -0
- rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +46 -0
- rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +68 -0
- rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +48 -0
- rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +149 -0
- rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +106 -0
- rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +45 -0
- rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +105 -0
- rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +52 -0
- rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +106 -0
- rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +30 -0
- rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +75 -0
- rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +49 -0
- rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +45 -0
- rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +38 -0
- rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +44 -0
- rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +46 -0
- rucio/db/sqla/models.py +1834 -0
- rucio/db/sqla/sautils.py +48 -0
- rucio/db/sqla/session.py +470 -0
- rucio/db/sqla/types.py +207 -0
- rucio/db/sqla/util.py +521 -0
- rucio/rse/__init__.py +97 -0
- rucio/rse/protocols/__init__.py +14 -0
- rucio/rse/protocols/cache.py +123 -0
- rucio/rse/protocols/dummy.py +112 -0
- rucio/rse/protocols/gfal.py +701 -0
- rucio/rse/protocols/globus.py +243 -0
- rucio/rse/protocols/gsiftp.py +93 -0
- rucio/rse/protocols/http_cache.py +83 -0
- rucio/rse/protocols/mock.py +124 -0
- rucio/rse/protocols/ngarc.py +210 -0
- rucio/rse/protocols/posix.py +251 -0
- rucio/rse/protocols/protocol.py +530 -0
- rucio/rse/protocols/rclone.py +365 -0
- rucio/rse/protocols/rfio.py +137 -0
- rucio/rse/protocols/srm.py +339 -0
- rucio/rse/protocols/ssh.py +414 -0
- rucio/rse/protocols/storm.py +207 -0
- rucio/rse/protocols/webdav.py +547 -0
- rucio/rse/protocols/xrootd.py +295 -0
- rucio/rse/rsemanager.py +752 -0
- rucio/tests/__init__.py +14 -0
- rucio/tests/common.py +244 -0
- rucio/tests/common_server.py +132 -0
- rucio/transfertool/__init__.py +14 -0
- rucio/transfertool/fts3.py +1484 -0
- rucio/transfertool/globus.py +200 -0
- rucio/transfertool/globus_library.py +182 -0
- rucio/transfertool/mock.py +81 -0
- rucio/transfertool/transfertool.py +212 -0
- rucio/vcsversion.py +11 -0
- rucio/version.py +46 -0
- rucio/web/__init__.py +14 -0
- rucio/web/rest/__init__.py +14 -0
- rucio/web/rest/flaskapi/__init__.py +14 -0
- rucio/web/rest/flaskapi/authenticated_bp.py +28 -0
- rucio/web/rest/flaskapi/v1/__init__.py +14 -0
- rucio/web/rest/flaskapi/v1/accountlimits.py +234 -0
- rucio/web/rest/flaskapi/v1/accounts.py +1088 -0
- rucio/web/rest/flaskapi/v1/archives.py +100 -0
- rucio/web/rest/flaskapi/v1/auth.py +1642 -0
- rucio/web/rest/flaskapi/v1/common.py +385 -0
- rucio/web/rest/flaskapi/v1/config.py +305 -0
- rucio/web/rest/flaskapi/v1/credentials.py +213 -0
- rucio/web/rest/flaskapi/v1/dids.py +2204 -0
- rucio/web/rest/flaskapi/v1/dirac.py +116 -0
- rucio/web/rest/flaskapi/v1/export.py +77 -0
- rucio/web/rest/flaskapi/v1/heartbeats.py +129 -0
- rucio/web/rest/flaskapi/v1/identities.py +263 -0
- rucio/web/rest/flaskapi/v1/import.py +133 -0
- rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +315 -0
- rucio/web/rest/flaskapi/v1/locks.py +360 -0
- rucio/web/rest/flaskapi/v1/main.py +83 -0
- rucio/web/rest/flaskapi/v1/meta.py +226 -0
- rucio/web/rest/flaskapi/v1/metrics.py +37 -0
- rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
- rucio/web/rest/flaskapi/v1/ping.py +89 -0
- rucio/web/rest/flaskapi/v1/redirect.py +366 -0
- rucio/web/rest/flaskapi/v1/replicas.py +1866 -0
- rucio/web/rest/flaskapi/v1/requests.py +841 -0
- rucio/web/rest/flaskapi/v1/rses.py +2204 -0
- rucio/web/rest/flaskapi/v1/rules.py +824 -0
- rucio/web/rest/flaskapi/v1/scopes.py +161 -0
- rucio/web/rest/flaskapi/v1/subscriptions.py +646 -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/tmp_dids.py +115 -0
- rucio/web/rest/flaskapi/v1/traces.py +100 -0
- rucio/web/rest/flaskapi/v1/vos.py +280 -0
- rucio/web/rest/main.py +19 -0
- rucio/web/rest/metrics.py +28 -0
- rucio-32.8.6.data/data/rucio/etc/alembic.ini.template +71 -0
- rucio-32.8.6.data/data/rucio/etc/alembic_offline.ini.template +74 -0
- rucio-32.8.6.data/data/rucio/etc/globus-config.yml.template +5 -0
- rucio-32.8.6.data/data/rucio/etc/ldap.cfg.template +30 -0
- rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
- rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
- rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
- rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
- rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
- rucio-32.8.6.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
- rucio-32.8.6.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
- rucio-32.8.6.data/data/rucio/etc/rucio.cfg.atlas.client.template +42 -0
- rucio-32.8.6.data/data/rucio/etc/rucio.cfg.template +257 -0
- rucio-32.8.6.data/data/rucio/etc/rucio_multi_vo.cfg.template +234 -0
- rucio-32.8.6.data/data/rucio/requirements.txt +55 -0
- rucio-32.8.6.data/data/rucio/tools/bootstrap.py +34 -0
- rucio-32.8.6.data/data/rucio/tools/merge_rucio_configs.py +147 -0
- rucio-32.8.6.data/data/rucio/tools/reset_database.py +40 -0
- rucio-32.8.6.data/scripts/rucio +2540 -0
- rucio-32.8.6.data/scripts/rucio-abacus-account +75 -0
- rucio-32.8.6.data/scripts/rucio-abacus-collection-replica +47 -0
- rucio-32.8.6.data/scripts/rucio-abacus-rse +79 -0
- rucio-32.8.6.data/scripts/rucio-admin +2434 -0
- rucio-32.8.6.data/scripts/rucio-atropos +61 -0
- rucio-32.8.6.data/scripts/rucio-auditor +199 -0
- rucio-32.8.6.data/scripts/rucio-automatix +51 -0
- rucio-32.8.6.data/scripts/rucio-bb8 +58 -0
- rucio-32.8.6.data/scripts/rucio-c3po +86 -0
- rucio-32.8.6.data/scripts/rucio-cache-client +135 -0
- rucio-32.8.6.data/scripts/rucio-cache-consumer +43 -0
- rucio-32.8.6.data/scripts/rucio-conveyor-finisher +59 -0
- rucio-32.8.6.data/scripts/rucio-conveyor-poller +67 -0
- rucio-32.8.6.data/scripts/rucio-conveyor-preparer +38 -0
- rucio-32.8.6.data/scripts/rucio-conveyor-receiver +44 -0
- rucio-32.8.6.data/scripts/rucio-conveyor-stager +77 -0
- rucio-32.8.6.data/scripts/rucio-conveyor-submitter +140 -0
- rucio-32.8.6.data/scripts/rucio-conveyor-throttler +105 -0
- rucio-32.8.6.data/scripts/rucio-dark-reaper +54 -0
- rucio-32.8.6.data/scripts/rucio-dumper +159 -0
- rucio-32.8.6.data/scripts/rucio-follower +45 -0
- rucio-32.8.6.data/scripts/rucio-hermes +55 -0
- rucio-32.8.6.data/scripts/rucio-judge-cleaner +90 -0
- rucio-32.8.6.data/scripts/rucio-judge-evaluator +138 -0
- rucio-32.8.6.data/scripts/rucio-judge-injector +45 -0
- rucio-32.8.6.data/scripts/rucio-judge-repairer +45 -0
- rucio-32.8.6.data/scripts/rucio-kronos +45 -0
- rucio-32.8.6.data/scripts/rucio-light-reaper +53 -0
- rucio-32.8.6.data/scripts/rucio-minos +54 -0
- rucio-32.8.6.data/scripts/rucio-minos-temporary-expiration +51 -0
- rucio-32.8.6.data/scripts/rucio-necromancer +121 -0
- rucio-32.8.6.data/scripts/rucio-oauth-manager +64 -0
- rucio-32.8.6.data/scripts/rucio-reaper +84 -0
- rucio-32.8.6.data/scripts/rucio-replica-recoverer +249 -0
- rucio-32.8.6.data/scripts/rucio-storage-consistency-actions +75 -0
- rucio-32.8.6.data/scripts/rucio-transmogrifier +78 -0
- rucio-32.8.6.data/scripts/rucio-undertaker +77 -0
- rucio-32.8.6.dist-info/METADATA +83 -0
- rucio-32.8.6.dist-info/RECORD +481 -0
- rucio-32.8.6.dist-info/WHEEL +5 -0
- rucio-32.8.6.dist-info/licenses/AUTHORS.rst +94 -0
- rucio-32.8.6.dist-info/licenses/LICENSE +201 -0
- rucio-32.8.6.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
import importlib
|
|
17
|
+
from configparser import NoOptionError, NoSectionError
|
|
18
|
+
from typing import TYPE_CHECKING
|
|
19
|
+
|
|
20
|
+
from rucio.common import config, exception
|
|
21
|
+
from rucio.db.sqla.session import read_session, transactional_session
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from sqlalchemy.orm import Session
|
|
25
|
+
|
|
26
|
+
# Set default modules.
|
|
27
|
+
#
|
|
28
|
+
# - "base" metadata is tied to column fields in the "dids" table. As such, types are restricted to column types and
|
|
29
|
+
# additional fields cannot be created.
|
|
30
|
+
# - "custom" metadata refers to any plugin that has been written to interface with Rucio's metadata plugin system.
|
|
31
|
+
#
|
|
32
|
+
# By default, the default custom metadata plugin is set to the prepackaged json module. This utilises a separate table,
|
|
33
|
+
# "did_meta", allowing users to add custom metadata key/value pairs of any type.
|
|
34
|
+
#
|
|
35
|
+
DEFAULT_BASE_METADATA_PLUGIN_MODULE_PATH = "rucio.core.did_meta_plugins.did_column_meta.DidColumnMeta"
|
|
36
|
+
DEFAULT_CUSTOM_METADATA_PLUGIN_MODULE_PATH = "rucio.core.did_meta_plugins.json_meta.JSONDidMeta"
|
|
37
|
+
|
|
38
|
+
# Overwrite these defaults if plugins are set in the configuration file.
|
|
39
|
+
#
|
|
40
|
+
if config.config_has_section('metadata'):
|
|
41
|
+
try:
|
|
42
|
+
CUSTOM_METADATA_PLUGIN_MODULE_PATHS = config.config_get('metadata', 'plugins')
|
|
43
|
+
except (NoOptionError, NoSectionError):
|
|
44
|
+
CUSTOM_METADATA_PLUGIN_MODULE_PATHS = DEFAULT_CUSTOM_METADATA_PLUGIN_MODULE_PATH
|
|
45
|
+
else:
|
|
46
|
+
CUSTOM_METADATA_PLUGIN_MODULE_PATHS = DEFAULT_CUSTOM_METADATA_PLUGIN_MODULE_PATH
|
|
47
|
+
METADATA_PLUGIN_MODULE_PATHS = [DEFAULT_BASE_METADATA_PLUGIN_MODULE_PATH] + CUSTOM_METADATA_PLUGIN_MODULE_PATHS.split(",")
|
|
48
|
+
|
|
49
|
+
# Import plugin modules.
|
|
50
|
+
#
|
|
51
|
+
# Note that the order of this list is important. As the base metadata plugin module is always first, base key
|
|
52
|
+
# retrieval and setting will always take precedence over custom plugins, i.e. it is not possible to set a custom key with
|
|
53
|
+
# the same name as those in the base list.
|
|
54
|
+
#
|
|
55
|
+
# Another consequence of this is that if set_metadata() is called with multiple plugins specified, the first to return
|
|
56
|
+
# True to manages_key() will be used.
|
|
57
|
+
#
|
|
58
|
+
METADATA_PLUGIN_MODULES = []
|
|
59
|
+
for meta_module_path in METADATA_PLUGIN_MODULE_PATHS:
|
|
60
|
+
try:
|
|
61
|
+
base_module = ".".join(meta_module_path.split(".")[:-1])
|
|
62
|
+
base_class = meta_module_path.split(".")[-1]
|
|
63
|
+
metadata_plugin_module = getattr(importlib.import_module(base_module), base_class)()
|
|
64
|
+
METADATA_PLUGIN_MODULES.append(metadata_plugin_module)
|
|
65
|
+
except ImportError:
|
|
66
|
+
raise exception.PolicyPackageNotFound('Module ' + meta_module_path + ' not found')
|
|
67
|
+
|
|
68
|
+
# Set restricted character set for metadata in form character: reason
|
|
69
|
+
#
|
|
70
|
+
RESTRICTED_CHARACTERS = {
|
|
71
|
+
'.': "Used as a delimiter for key and operator (<key>.<operator>) in filtering engine."
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@read_session
|
|
76
|
+
def get_metadata(scope, name, plugin="DID_COLUMN", *, session: "Session"):
|
|
77
|
+
"""
|
|
78
|
+
Gets the metadata for a given did from a specified plugin.
|
|
79
|
+
|
|
80
|
+
If [plugin] is set to "all", metadata from all available metadata plugins will be returned,
|
|
81
|
+
else [plugin] can be used to only return the metadata using a specific plugin.
|
|
82
|
+
|
|
83
|
+
:param scope: The scope of the did.
|
|
84
|
+
:param name: The data identifier name.
|
|
85
|
+
:param plugin: (optional) Filter specific metadata plugins.
|
|
86
|
+
:returns: List of metadata for did.
|
|
87
|
+
:raises: NotImplementedError
|
|
88
|
+
"""
|
|
89
|
+
if plugin.lower() == "all":
|
|
90
|
+
all_metadata = {}
|
|
91
|
+
for metadata_plugin in METADATA_PLUGIN_MODULES:
|
|
92
|
+
metadata = metadata_plugin.get_metadata(scope, name, session=session)
|
|
93
|
+
all_metadata.update(metadata)
|
|
94
|
+
return all_metadata
|
|
95
|
+
else:
|
|
96
|
+
for metadata_plugin in METADATA_PLUGIN_MODULES:
|
|
97
|
+
if metadata_plugin.get_plugin_name().lower() == plugin.lower():
|
|
98
|
+
return metadata_plugin.get_metadata(scope, name, session=session)
|
|
99
|
+
raise NotImplementedError('Metadata plugin "%s" is not enabled on the server.' % plugin)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@transactional_session
|
|
103
|
+
def set_metadata(scope, name, key, value, recursive=False, *, session: "Session"):
|
|
104
|
+
"""
|
|
105
|
+
Sets metadata for a given did.
|
|
106
|
+
|
|
107
|
+
:param scope: The scope of the did.
|
|
108
|
+
:param name: The data identifier name.
|
|
109
|
+
:param key: Metadata key.
|
|
110
|
+
:param value: Metadata value.
|
|
111
|
+
:param recursive: (optional) Propagate the metadata change recursively to content.
|
|
112
|
+
:param session: (optional) The database session in use.
|
|
113
|
+
:raises: InvalidMetadata
|
|
114
|
+
"""
|
|
115
|
+
# Check for forbidden characters in key.
|
|
116
|
+
for char in RESTRICTED_CHARACTERS:
|
|
117
|
+
if char in key:
|
|
118
|
+
raise exception.InvalidMetadata('Restricted character "{}" found in metadata key. Reason: {}'.format(
|
|
119
|
+
char,
|
|
120
|
+
RESTRICTED_CHARACTERS[char]
|
|
121
|
+
))
|
|
122
|
+
|
|
123
|
+
# Sequentially check if each metadata plugin manages this key. Note that the order of [METADATA_PLUGIN_MODULES]
|
|
124
|
+
# means that the key is always checked for existence in the base list first.
|
|
125
|
+
metadata_was_set = False
|
|
126
|
+
for metadata_plugin in METADATA_PLUGIN_MODULES:
|
|
127
|
+
if metadata_plugin.manages_key(key, session=session):
|
|
128
|
+
metadata_plugin.set_metadata(scope, name, key, value, recursive, session=session)
|
|
129
|
+
metadata_was_set = True
|
|
130
|
+
break
|
|
131
|
+
|
|
132
|
+
if not metadata_was_set:
|
|
133
|
+
raise exception.InvalidMetadata('No plugin manages metadata key %s for DID %s:%s' % (key, scope, name))
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@transactional_session
|
|
137
|
+
def set_metadata_bulk(scope, name, meta, recursive=False, *, session: "Session"):
|
|
138
|
+
"""
|
|
139
|
+
Bulk sets metadata for a given did.
|
|
140
|
+
|
|
141
|
+
:param scope: The scope name.
|
|
142
|
+
:param name: The data identifier name.
|
|
143
|
+
:param meta: The key-value mapping of metadata to set.
|
|
144
|
+
:param recursive: (optional) Propagate the metadata change recursively to content.
|
|
145
|
+
:param session: (optional) The database session in use.
|
|
146
|
+
:raises: InvalidMetadata
|
|
147
|
+
"""
|
|
148
|
+
metadata = meta
|
|
149
|
+
|
|
150
|
+
unmanaged_keys = list()
|
|
151
|
+
if not isinstance(metadata, dict):
|
|
152
|
+
metadata = dict(metadata)
|
|
153
|
+
metadata_plugin_keys = {metadata_plugin: [] for metadata_plugin in METADATA_PLUGIN_MODULES}
|
|
154
|
+
|
|
155
|
+
# Iterate through all keys, sequentially checking if each metadata plugin manages the considered key. If it
|
|
156
|
+
# does, add it to the list in the plugin's entry in {metadata_plugin_keys}. Note that the order of
|
|
157
|
+
# [METADATA_PLUGIN_MODULES] means that the key is always checked for existence in the base list first.
|
|
158
|
+
for key in metadata.keys():
|
|
159
|
+
# Check for forbidden characters in key.
|
|
160
|
+
for char in RESTRICTED_CHARACTERS:
|
|
161
|
+
if char in key:
|
|
162
|
+
raise exception.InvalidMetadata('Restricted character "{}" found in metadata key. Reason: {}'.format(
|
|
163
|
+
char,
|
|
164
|
+
RESTRICTED_CHARACTERS[char]
|
|
165
|
+
))
|
|
166
|
+
metadata_is_included = False
|
|
167
|
+
for metadata_plugin in METADATA_PLUGIN_MODULES:
|
|
168
|
+
if metadata_plugin.manages_key(key, session=session):
|
|
169
|
+
metadata_plugin_keys[metadata_plugin].append(key)
|
|
170
|
+
metadata_is_included = True
|
|
171
|
+
break
|
|
172
|
+
if not metadata_is_included:
|
|
173
|
+
unmanaged_keys.append(key)
|
|
174
|
+
if unmanaged_keys:
|
|
175
|
+
raise exception.InvalidMetadata('No plugin manages metadata keys %s on DID %s:%s' % (unmanaged_keys, scope, name))
|
|
176
|
+
|
|
177
|
+
# For each plugin, set the metadata.
|
|
178
|
+
for metadata_plugin, keys_managed_by_this_plugin in metadata_plugin_keys.items():
|
|
179
|
+
if keys_managed_by_this_plugin:
|
|
180
|
+
this_plugin_metadata = {key: metadata[key] for key in keys_managed_by_this_plugin}
|
|
181
|
+
metadata_plugin.set_metadata_bulk(scope, name, metadata=this_plugin_metadata, recursive=recursive, session=session)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@transactional_session
|
|
185
|
+
def delete_metadata(scope, name, key, *, session: "Session"):
|
|
186
|
+
"""
|
|
187
|
+
Deletes metadata stored for a given key.
|
|
188
|
+
|
|
189
|
+
:param scope: The scope of the did.
|
|
190
|
+
:param name: The name of the did.
|
|
191
|
+
:param key: Key of the metadata.
|
|
192
|
+
"""
|
|
193
|
+
for metadata_plugin in METADATA_PLUGIN_MODULES:
|
|
194
|
+
if metadata_plugin.manages_key(key, session=session):
|
|
195
|
+
metadata_plugin.delete_metadata(scope, name, key, session=session)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@read_session
|
|
199
|
+
def list_dids(scope=None, filters=None, did_type='collection', ignore_case=False, limit=None,
|
|
200
|
+
offset=None, long=False, recursive=False, ignore_dids=None, *, session: "Session"):
|
|
201
|
+
"""
|
|
202
|
+
Search data identifiers.
|
|
203
|
+
|
|
204
|
+
All filter keys should belong to a single plugin. Queries across plugins are not currently supported.
|
|
205
|
+
|
|
206
|
+
:param scope: the scope name.
|
|
207
|
+
:param filters: dictionary of attributes by which the results should be filtered.
|
|
208
|
+
:param did_type: the type of the did: all(container, dataset, file), collection(dataset or container), dataset, container, file.
|
|
209
|
+
:param ignore_case: ignore case distinctions.
|
|
210
|
+
:param limit: limit number.
|
|
211
|
+
:param offset: offset number.
|
|
212
|
+
:param long: Long format option to display more information for each DID.
|
|
213
|
+
:param recursive: Recursively list DIDs content.
|
|
214
|
+
:param ignore_dids: List of DIDs to refrain from yielding.
|
|
215
|
+
:param session: The database session in use.
|
|
216
|
+
:returns: List of dids satisfying metadata criteria.
|
|
217
|
+
:raises: InvalidMetadata
|
|
218
|
+
"""
|
|
219
|
+
# backwards compatability for filters as single {}.
|
|
220
|
+
if isinstance(filters, dict):
|
|
221
|
+
filters = [filters]
|
|
222
|
+
|
|
223
|
+
required_unique_plugins = set() # keep track of which plugins are required
|
|
224
|
+
for or_group in filters:
|
|
225
|
+
for key in or_group.keys():
|
|
226
|
+
if key == 'name': # [name] is always passed through, and needs to be in schema of all plugins
|
|
227
|
+
continue
|
|
228
|
+
key_nooperator = key.split('.')[0] # remove operator attribute from key if suffixed
|
|
229
|
+
|
|
230
|
+
# Iterate through the list of metadata plugins, checking which (if any) manages this particular key
|
|
231
|
+
# and appending the corresponding plugin to the set, required_unique_plugins.
|
|
232
|
+
is_this_key_managed = False
|
|
233
|
+
for metadata_plugin in METADATA_PLUGIN_MODULES:
|
|
234
|
+
if metadata_plugin.manages_key(key_nooperator, session=session):
|
|
235
|
+
required_unique_plugins.add(metadata_plugin)
|
|
236
|
+
is_this_key_managed = True
|
|
237
|
+
break
|
|
238
|
+
if not is_this_key_managed:
|
|
239
|
+
raise exception.InvalidMetadata('There is no metadata plugin that manages the filter key(s) you requested.')
|
|
240
|
+
|
|
241
|
+
if not required_unique_plugins: # if no metadata keys were specified, fall back to using the base plugin
|
|
242
|
+
required_unique_plugins = [METADATA_PLUGIN_MODULES[0]]
|
|
243
|
+
elif len(required_unique_plugins) > 1: # check that only a single plugin is required for the query, otherwise not supported
|
|
244
|
+
raise exception.InvalidMetadata('Filter keys used do not all belong to the same metadata plugin.')
|
|
245
|
+
selected_plugin_to_use = list(required_unique_plugins)[0]
|
|
246
|
+
|
|
247
|
+
return selected_plugin_to_use.list_dids(scope=scope, filters=filters, did_type=did_type,
|
|
248
|
+
ignore_case=ignore_case, limit=limit,
|
|
249
|
+
offset=offset, long=long, recursive=recursive,
|
|
250
|
+
ignore_dids=ignore_dids, session=session)
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
import operator
|
|
17
|
+
from datetime import datetime, timedelta
|
|
18
|
+
from typing import TYPE_CHECKING
|
|
19
|
+
|
|
20
|
+
from sqlalchemy import update, inspect
|
|
21
|
+
from sqlalchemy.exc import CompileError, InvalidRequestError
|
|
22
|
+
from sqlalchemy.orm.exc import NoResultFound
|
|
23
|
+
from sqlalchemy.sql import func
|
|
24
|
+
from sqlalchemy.sql.expression import true
|
|
25
|
+
|
|
26
|
+
from rucio.common import exception
|
|
27
|
+
from rucio.core import account_counter, rse_counter
|
|
28
|
+
from rucio.core.did_meta_plugins.did_meta_plugin_interface import DidMetaPlugin
|
|
29
|
+
from rucio.core.did_meta_plugins.filter_engine import FilterEngine
|
|
30
|
+
from rucio.db.sqla import models
|
|
31
|
+
from rucio.db.sqla.constants import DIDType
|
|
32
|
+
from rucio.db.sqla.session import stream_session, read_session, transactional_session
|
|
33
|
+
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
from typing import Optional
|
|
36
|
+
from sqlalchemy.orm import Session
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class DidColumnMeta(DidMetaPlugin):
|
|
40
|
+
"""
|
|
41
|
+
A metadata plugin to interact with the base did table metadata.
|
|
42
|
+
"""
|
|
43
|
+
def __init__(self):
|
|
44
|
+
super(DidColumnMeta, self).__init__()
|
|
45
|
+
self.plugin_name = "DID_COLUMN"
|
|
46
|
+
|
|
47
|
+
@read_session
|
|
48
|
+
def get_metadata(self, scope, name, *, session: "Session"):
|
|
49
|
+
"""
|
|
50
|
+
Get data identifier metadata.
|
|
51
|
+
|
|
52
|
+
:param scope: The scope name.
|
|
53
|
+
:param name: The data identifier name.
|
|
54
|
+
:param session: The database session in use.
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
row = session.query(models.DataIdentifier).filter_by(scope=scope, name=name).\
|
|
58
|
+
with_hint(models.DataIdentifier, "INDEX(DIDS DIDS_PK)", 'oracle').one()
|
|
59
|
+
return row.to_dict()
|
|
60
|
+
except NoResultFound:
|
|
61
|
+
raise exception.DataIdentifierNotFound(f"Data identifier '{scope}:{name}' not found")
|
|
62
|
+
|
|
63
|
+
@transactional_session
|
|
64
|
+
def set_metadata(self, scope, name, key, value, recursive=False, *, session: "Session"):
|
|
65
|
+
self.set_metadata_bulk(scope=scope, name=name, metadata={key: value}, recursive=recursive, session=session)
|
|
66
|
+
|
|
67
|
+
@transactional_session
|
|
68
|
+
def set_metadata_bulk(self, scope, name, metadata, recursive=False, *, session: "Session"):
|
|
69
|
+
did_query = session.query(models.DataIdentifier).with_hint(models.DataIdentifier, "INDEX(DIDS DIDS_PK)", 'oracle').filter_by(scope=scope, name=name)
|
|
70
|
+
if did_query.one_or_none() is None:
|
|
71
|
+
raise exception.DataIdentifierNotFound("Data identifier '%s:%s' not found" % (scope, name))
|
|
72
|
+
|
|
73
|
+
remainder = {}
|
|
74
|
+
for key, value in metadata.items():
|
|
75
|
+
if key == 'eol_at' and isinstance(value, str):
|
|
76
|
+
try:
|
|
77
|
+
eol_at = datetime.strptime(value, '%Y-%M-%d')
|
|
78
|
+
rowcount = did_query.update({'eol_at': eol_at}, synchronize_session='fetch')
|
|
79
|
+
except TypeError as error:
|
|
80
|
+
raise exception.InvalidValueForKey(error)
|
|
81
|
+
if not rowcount:
|
|
82
|
+
# check for did presence
|
|
83
|
+
raise exception.UnsupportedOperation('%s for %s:%s cannot be updated' % (key, scope, name))
|
|
84
|
+
elif key == 'lifetime':
|
|
85
|
+
try:
|
|
86
|
+
expired_at = None
|
|
87
|
+
if value is not None:
|
|
88
|
+
expired_at = datetime.utcnow() + timedelta(seconds=float(value))
|
|
89
|
+
rowcount = did_query.update({'expired_at': expired_at}, synchronize_session='fetch')
|
|
90
|
+
except TypeError as error:
|
|
91
|
+
raise exception.InvalidValueForKey(error)
|
|
92
|
+
if not rowcount:
|
|
93
|
+
# check for did presence
|
|
94
|
+
raise exception.UnsupportedOperation('%s for %s:%s cannot be updated' % (key, scope, name))
|
|
95
|
+
elif key in ['guid', 'events']:
|
|
96
|
+
rowcount = did_query.filter_by(did_type=DIDType.FILE).update({key: value}, synchronize_session=False)
|
|
97
|
+
if not rowcount:
|
|
98
|
+
# check for did presence
|
|
99
|
+
raise exception.UnsupportedOperation('%s for %s:%s cannot be updated' % (key, scope, name))
|
|
100
|
+
|
|
101
|
+
session.query(models.DataIdentifierAssociation).filter_by(child_scope=scope, child_name=name, child_type=DIDType.FILE).update({key: value}, synchronize_session=False)
|
|
102
|
+
if key == 'events':
|
|
103
|
+
for parent_scope, parent_name in session.query(models.DataIdentifierAssociation.scope, models.DataIdentifierAssociation.name).filter_by(child_scope=scope, child_name=name):
|
|
104
|
+
events = session.query(func.sum(models.DataIdentifierAssociation.events)).filter_by(scope=parent_scope, name=parent_name).one()[0]
|
|
105
|
+
session.query(models.DataIdentifier).filter_by(scope=parent_scope, name=parent_name).update({'events': events}, synchronize_session=False)
|
|
106
|
+
elif key == 'adler32':
|
|
107
|
+
rowcount = did_query.filter_by(did_type=DIDType.FILE).update({key: value}, synchronize_session=False)
|
|
108
|
+
if not rowcount:
|
|
109
|
+
# check for did presence
|
|
110
|
+
raise exception.UnsupportedOperation('%s for %s:%s cannot be updated' % (key, scope, name))
|
|
111
|
+
|
|
112
|
+
session.query(models.DataIdentifierAssociation).filter_by(child_scope=scope, child_name=name, child_type=DIDType.FILE).update({key: value}, synchronize_session=False)
|
|
113
|
+
session.query(models.Request).filter_by(scope=scope, name=name).update({key: value}, synchronize_session=False)
|
|
114
|
+
session.query(models.RSEFileAssociation).filter_by(scope=scope, name=name).update({key: value}, synchronize_session=False)
|
|
115
|
+
elif key == 'bytes':
|
|
116
|
+
rowcount = did_query.filter_by(did_type=DIDType.FILE).update({key: value}, synchronize_session=False)
|
|
117
|
+
if not rowcount:
|
|
118
|
+
# check for did presence
|
|
119
|
+
raise exception.UnsupportedOperation('%s for %s:%s cannot be updated' % (key, scope, name))
|
|
120
|
+
|
|
121
|
+
session.query(models.DataIdentifierAssociation).filter_by(child_scope=scope, child_name=name, child_type=DIDType.FILE).update({key: value}, synchronize_session=False)
|
|
122
|
+
session.query(models.Request).filter_by(scope=scope, name=name).update({key: value}, synchronize_session=False)
|
|
123
|
+
|
|
124
|
+
for account, bytes_, rse_id, rule_id in session.query(models.ReplicaLock.account, models.ReplicaLock.bytes, models.ReplicaLock.rse_id, models.ReplicaLock.rule_id).filter_by(scope=scope, name=name):
|
|
125
|
+
session.query(models.ReplicaLock).filter_by(scope=scope, name=name, rule_id=rule_id, rse_id=rse_id).update({key: value}, synchronize_session=False)
|
|
126
|
+
account_counter.decrease(rse_id=rse_id, account=account, files=1, bytes_=bytes_, session=session)
|
|
127
|
+
account_counter.increase(rse_id=rse_id, account=account, files=1, bytes_=value, session=session)
|
|
128
|
+
|
|
129
|
+
for bytes_, rse_id in session.query(models.RSEFileAssociation.bytes, models.RSEFileAssociation.rse_id).filter_by(scope=scope, name=name):
|
|
130
|
+
session.query(models.RSEFileAssociation).filter_by(scope=scope, name=name, rse_id=rse_id).update({key: value}, synchronize_session=False)
|
|
131
|
+
rse_counter.decrease(rse_id=rse_id, files=1, bytes_=bytes_, session=session)
|
|
132
|
+
rse_counter.increase(rse_id=rse_id, files=1, bytes_=value, session=session)
|
|
133
|
+
|
|
134
|
+
for parent_scope, parent_name in session.query(models.DataIdentifierAssociation.scope, models.DataIdentifierAssociation.name).filter_by(child_scope=scope, child_name=name):
|
|
135
|
+
values = {}
|
|
136
|
+
values['length'], values['bytes'], values['events'] = session.query(func.count(models.DataIdentifierAssociation.scope),
|
|
137
|
+
func.sum(models.DataIdentifierAssociation.bytes),
|
|
138
|
+
func.sum(models.DataIdentifierAssociation.events)).filter_by(scope=parent_scope, name=parent_name).one()
|
|
139
|
+
session.query(models.DataIdentifier).filter_by(scope=parent_scope, name=parent_name).update(values, synchronize_session=False)
|
|
140
|
+
session.query(models.DatasetLock).filter_by(scope=parent_scope, name=parent_name).update({'length': values['length'], 'bytes': values['bytes']}, synchronize_session=False)
|
|
141
|
+
else:
|
|
142
|
+
remainder[key] = value
|
|
143
|
+
|
|
144
|
+
if remainder:
|
|
145
|
+
try:
|
|
146
|
+
rowcount = did_query.update(remainder, synchronize_session='fetch')
|
|
147
|
+
except CompileError as error:
|
|
148
|
+
raise exception.InvalidMetadata(error)
|
|
149
|
+
except InvalidRequestError:
|
|
150
|
+
raise exception.InvalidMetadata("Some of the keys are not accepted: " + str(list(remainder.keys())))
|
|
151
|
+
if not rowcount:
|
|
152
|
+
raise exception.UnsupportedOperation('Some of the keys for %s:%s cannot be updated: %s' % (scope, name, str(list(remainder.keys()))))
|
|
153
|
+
|
|
154
|
+
# propagate metadata updates to child content
|
|
155
|
+
if recursive:
|
|
156
|
+
content_query = session.query(models.DataIdentifierAssociation.child_scope, models.DataIdentifierAssociation.child_name)
|
|
157
|
+
content_query = content_query.with_hint(models.DataIdentifierAssociation, "INDEX(CONTENTS CONTENTS_PK)", 'oracle').filter_by(scope=scope, name=name)
|
|
158
|
+
|
|
159
|
+
for child_scope, child_name in content_query:
|
|
160
|
+
try:
|
|
161
|
+
stmt = update(models.DataIdentifier)\
|
|
162
|
+
.prefix_with("/*+ INDEX(DIDS DIDS_PK) */", dialect='oracle')\
|
|
163
|
+
.filter_by(scope=child_scope, name=child_name)\
|
|
164
|
+
.execution_options(synchronize_session='fetch')\
|
|
165
|
+
.values(remainder)
|
|
166
|
+
session.execute(stmt)
|
|
167
|
+
except CompileError as error:
|
|
168
|
+
raise exception.InvalidMetadata(error)
|
|
169
|
+
except InvalidRequestError:
|
|
170
|
+
raise exception.InvalidMetadata("Some of the keys are not accepted recursively: " + str(list(remainder.keys())))
|
|
171
|
+
|
|
172
|
+
@stream_session
|
|
173
|
+
def list_dids(self, scope, filters, did_type='collection', ignore_case=False, limit=None,
|
|
174
|
+
offset=None, long=False, recursive=False, ignore_dids=None, *, session: "Session"):
|
|
175
|
+
"""
|
|
176
|
+
Search data identifiers.
|
|
177
|
+
|
|
178
|
+
:param scope: the scope name.
|
|
179
|
+
:param filters: dictionary of attributes by which the results should be filtered.
|
|
180
|
+
:param did_type: the type of the did: all(container, dataset, file), collection(dataset or container), dataset, container, file.
|
|
181
|
+
:param ignore_case: ignore case distinctions.
|
|
182
|
+
:param limit: limit number.
|
|
183
|
+
:param offset: offset number.
|
|
184
|
+
:param long: Long format option to display more information for each DID.
|
|
185
|
+
:param session: The database session in use.
|
|
186
|
+
:param recursive: Recursively list DIDs content.
|
|
187
|
+
:param ignore_dids: List of DIDs to refrain from yielding.
|
|
188
|
+
"""
|
|
189
|
+
if not ignore_dids:
|
|
190
|
+
ignore_dids = set()
|
|
191
|
+
|
|
192
|
+
# mapping for semantic <type> to a (set of) recognised DIDType(s).
|
|
193
|
+
type_to_did_type_mapping = {
|
|
194
|
+
'all': [DIDType.CONTAINER, DIDType.DATASET, DIDType.FILE],
|
|
195
|
+
'collection': [DIDType.CONTAINER, DIDType.DATASET],
|
|
196
|
+
'container': [DIDType.CONTAINER],
|
|
197
|
+
'dataset': [DIDType.DATASET],
|
|
198
|
+
'file': [DIDType.FILE]
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
# backwards compatability for filters as single {}.
|
|
202
|
+
if isinstance(filters, dict):
|
|
203
|
+
filters = [filters]
|
|
204
|
+
|
|
205
|
+
# for each or_group, make sure there is a mapped "did_type" filter.
|
|
206
|
+
# if type maps to many DIDTypes, the corresponding or_group will be copied the required number of times to satisfy all the logical possibilities.
|
|
207
|
+
filters_tmp = []
|
|
208
|
+
for or_group in filters:
|
|
209
|
+
if 'type' not in or_group:
|
|
210
|
+
or_group_type = did_type.lower()
|
|
211
|
+
else:
|
|
212
|
+
or_group_type = or_group.pop('type').lower()
|
|
213
|
+
if or_group_type not in type_to_did_type_mapping.keys():
|
|
214
|
+
raise exception.UnsupportedOperation('{} is not a valid type. Valid types are {}'.format(or_group_type, type_to_did_type_mapping.keys()))
|
|
215
|
+
|
|
216
|
+
for mapped_did_type in type_to_did_type_mapping[or_group_type]:
|
|
217
|
+
or_group['did_type'] = mapped_did_type
|
|
218
|
+
filters_tmp.append(or_group.copy())
|
|
219
|
+
filters = filters_tmp
|
|
220
|
+
|
|
221
|
+
# instantiate fe and create sqla query
|
|
222
|
+
fe = FilterEngine(filters, model_class=models.DataIdentifier)
|
|
223
|
+
query = fe.create_sqla_query(
|
|
224
|
+
additional_model_attributes=[
|
|
225
|
+
models.DataIdentifier.scope,
|
|
226
|
+
models.DataIdentifier.name,
|
|
227
|
+
models.DataIdentifier.did_type,
|
|
228
|
+
models.DataIdentifier.bytes,
|
|
229
|
+
models.DataIdentifier.length
|
|
230
|
+
], additional_filters=[
|
|
231
|
+
(models.DataIdentifier.scope, operator.eq, scope),
|
|
232
|
+
(models.DataIdentifier.suppressed, operator.ne, true())
|
|
233
|
+
],
|
|
234
|
+
session=session
|
|
235
|
+
)
|
|
236
|
+
query.with_hint(models.DataIdentifier, 'NO_EXPAND', 'oracle')
|
|
237
|
+
|
|
238
|
+
if limit:
|
|
239
|
+
query = query.limit(limit)
|
|
240
|
+
if recursive:
|
|
241
|
+
from rucio.core.did import list_content
|
|
242
|
+
|
|
243
|
+
# Get attached DIDs and save in list because query has to be finished before starting a new one in the recursion
|
|
244
|
+
collections_content = []
|
|
245
|
+
for did in query.yield_per(100):
|
|
246
|
+
if (did.did_type == DIDType.CONTAINER or did.did_type == DIDType.DATASET):
|
|
247
|
+
collections_content += [d for d in list_content(scope=did.scope, name=did.name)]
|
|
248
|
+
|
|
249
|
+
# Replace any name filtering with recursed DID names.
|
|
250
|
+
for did in collections_content:
|
|
251
|
+
for or_group in filters:
|
|
252
|
+
or_group['name'] = did['name']
|
|
253
|
+
for result in self.list_dids(scope=did['scope'], filters=filters, recursive=True, did_type=did_type, limit=limit, offset=offset,
|
|
254
|
+
long=long, ignore_dids=ignore_dids, session=session):
|
|
255
|
+
yield result
|
|
256
|
+
|
|
257
|
+
for did in query.yield_per(5): # don't unpack this as it makes it dependent on query return order!
|
|
258
|
+
if long:
|
|
259
|
+
did_full = "{}:{}".format(did.scope, did.name)
|
|
260
|
+
if did_full not in ignore_dids: # concatenating results of OR clauses may contain duplicate DIDs if query result sets not mutually exclusive.
|
|
261
|
+
ignore_dids.add(did_full)
|
|
262
|
+
yield {
|
|
263
|
+
'scope': did.scope,
|
|
264
|
+
'name': did.name,
|
|
265
|
+
'did_type': str(did.did_type),
|
|
266
|
+
'bytes': did.bytes,
|
|
267
|
+
'length': did.length
|
|
268
|
+
}
|
|
269
|
+
else:
|
|
270
|
+
did_full = "{}:{}".format(did.scope, did.name)
|
|
271
|
+
if did_full not in ignore_dids: # concatenating results of OR clauses may contain duplicate DIDs if query result sets not mutually exclusive.
|
|
272
|
+
ignore_dids.add(did_full)
|
|
273
|
+
yield did.name
|
|
274
|
+
|
|
275
|
+
def delete_metadata(self, scope, name, key, *, session: "Optional[Session]" = None):
|
|
276
|
+
"""
|
|
277
|
+
Deletes the metadata stored for the given key.
|
|
278
|
+
|
|
279
|
+
:param scope: The scope of the did.
|
|
280
|
+
:param name: The name of the did.
|
|
281
|
+
:param key: Key of the metadata.
|
|
282
|
+
"""
|
|
283
|
+
raise NotImplementedError('The DidColumnMeta plugin does not currently support deleting metadata.')
|
|
284
|
+
|
|
285
|
+
def manages_key(self, key, *, session: "Optional[Session]" = None):
|
|
286
|
+
# Build list of which keys are managed by this plugin.
|
|
287
|
+
#
|
|
288
|
+
all_did_table_columns = []
|
|
289
|
+
for column in inspect(models.DataIdentifier).attrs:
|
|
290
|
+
all_did_table_columns.append(column.key)
|
|
291
|
+
|
|
292
|
+
exclude_did_table_columns = [
|
|
293
|
+
'account',
|
|
294
|
+
'availability',
|
|
295
|
+
'complete',
|
|
296
|
+
'created_at',
|
|
297
|
+
'did_type',
|
|
298
|
+
'is_open',
|
|
299
|
+
'monotonic',
|
|
300
|
+
'obsolete',
|
|
301
|
+
'scope',
|
|
302
|
+
'suppressed',
|
|
303
|
+
'updated_at'
|
|
304
|
+
]
|
|
305
|
+
|
|
306
|
+
additional_keys = [
|
|
307
|
+
'lifetime',
|
|
308
|
+
'created_before',
|
|
309
|
+
'created_after',
|
|
310
|
+
'length.gt',
|
|
311
|
+
'length.lt',
|
|
312
|
+
'length.gte',
|
|
313
|
+
'length.lte',
|
|
314
|
+
'type'
|
|
315
|
+
]
|
|
316
|
+
|
|
317
|
+
hardcoded_keys = list(set(all_did_table_columns) - set(exclude_did_table_columns)) + additional_keys
|
|
318
|
+
|
|
319
|
+
return key in hardcoded_keys
|
|
320
|
+
|
|
321
|
+
def get_plugin_name(self):
|
|
322
|
+
"""
|
|
323
|
+
Returns a unique identifier for this plugin. This can be later used for filtering down results to this plugin only.
|
|
324
|
+
:returns: The name of the plugin.
|
|
325
|
+
"""
|
|
326
|
+
return self.plugin_name
|