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/daemons/common.py
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
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 datetime
|
|
16
|
+
import functools
|
|
17
|
+
import logging
|
|
18
|
+
import os
|
|
19
|
+
import queue
|
|
20
|
+
import socket
|
|
21
|
+
import threading
|
|
22
|
+
import time
|
|
23
|
+
from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union
|
|
24
|
+
|
|
25
|
+
from rucio.common.logging import formatted_logger
|
|
26
|
+
from rucio.common.utils import PriorityQueue
|
|
27
|
+
from rucio.core import heartbeat as heartbeat_core
|
|
28
|
+
from rucio.core.monitor import MetricManager
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from collections.abc import Callable, Generator, Iterator, Sequence
|
|
32
|
+
|
|
33
|
+
from rucio.common.types import LoggerFunction
|
|
34
|
+
|
|
35
|
+
T = TypeVar('T')
|
|
36
|
+
METRICS = MetricManager(module=__name__)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class HeartbeatHandler:
|
|
40
|
+
"""
|
|
41
|
+
Simple contextmanager which sets a heartbeat and associated logger on entry and cleans up the heartbeat on exit.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, executable: str, renewal_interval: int):
|
|
45
|
+
"""
|
|
46
|
+
:param executable: the executable name which will be set in heartbeats
|
|
47
|
+
:param renewal_interval: the interval at which the heartbeat will be renewed in the database.
|
|
48
|
+
Calls to live() in-between intervals will reuse the locally cached heartbeat.
|
|
49
|
+
"""
|
|
50
|
+
self.executable = executable
|
|
51
|
+
self._hash_executable = None
|
|
52
|
+
self.renewal_interval = renewal_interval
|
|
53
|
+
self.older_than = renewal_interval * 10 if renewal_interval and renewal_interval > 0 else None # 10 was chosen without any particular reason
|
|
54
|
+
|
|
55
|
+
self.hostname = socket.getfqdn()
|
|
56
|
+
self.pid = os.getpid()
|
|
57
|
+
self.hb_thread = threading.current_thread()
|
|
58
|
+
|
|
59
|
+
self.logger = logging.log
|
|
60
|
+
self.last_heart_beat = None
|
|
61
|
+
self.last_time = None
|
|
62
|
+
self.last_payload = None
|
|
63
|
+
|
|
64
|
+
def __enter__(self) -> 'HeartbeatHandler':
|
|
65
|
+
heartbeat_core.sanity_check(executable=self.executable, hostname=self.hostname)
|
|
66
|
+
self.live()
|
|
67
|
+
return self
|
|
68
|
+
|
|
69
|
+
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
|
|
70
|
+
if self.last_heart_beat:
|
|
71
|
+
heartbeat_core.die(self.executable, self.hostname, self.pid, self.hb_thread)
|
|
72
|
+
if self.logger:
|
|
73
|
+
self.logger(logging.INFO, 'Heartbeat cleaned up')
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def hash_executable(self) -> str:
|
|
77
|
+
if not self._hash_executable:
|
|
78
|
+
self._hash_executable = heartbeat_core.calc_hash(self.executable)
|
|
79
|
+
return self._hash_executable
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def short_executable(self) -> str:
|
|
83
|
+
return min(self.executable, self.hash_executable, key=len)
|
|
84
|
+
|
|
85
|
+
def live(
|
|
86
|
+
self,
|
|
87
|
+
force_renew: bool = False,
|
|
88
|
+
payload: Optional[str] = None
|
|
89
|
+
) -> tuple[int, int, 'Callable']:
|
|
90
|
+
"""
|
|
91
|
+
:return: a tuple: <the number of the current worker>, <total number of workers>, <decorated logger>
|
|
92
|
+
"""
|
|
93
|
+
if force_renew \
|
|
94
|
+
or not self.last_time \
|
|
95
|
+
or not self.last_heart_beat \
|
|
96
|
+
or self.last_time < datetime.datetime.now() - datetime.timedelta(seconds=self.renewal_interval) \
|
|
97
|
+
or self.last_payload != payload:
|
|
98
|
+
if self.older_than:
|
|
99
|
+
self.last_heart_beat = heartbeat_core.live(self.executable, self.hostname, self.pid, self.hb_thread, payload=payload, older_than=self.older_than)
|
|
100
|
+
else:
|
|
101
|
+
self.last_heart_beat = heartbeat_core.live(self.executable, self.hostname, self.pid, self.hb_thread, payload=payload)
|
|
102
|
+
|
|
103
|
+
prefix = '[%i/%i]: ' % (self.last_heart_beat['assign_thread'], self.last_heart_beat['nr_threads'])
|
|
104
|
+
self.logger = formatted_logger(logging.log, prefix + '%s')
|
|
105
|
+
|
|
106
|
+
if not self.last_time:
|
|
107
|
+
self.logger(logging.DEBUG, 'First heartbeat set')
|
|
108
|
+
else:
|
|
109
|
+
self.logger(logging.DEBUG, 'Heartbeat renewed')
|
|
110
|
+
self.last_time = datetime.datetime.now()
|
|
111
|
+
self.last_payload = payload
|
|
112
|
+
|
|
113
|
+
return self.last_heart_beat['assign_thread'], self.last_heart_beat['nr_threads'], self.logger
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _activity_looper(
|
|
117
|
+
once: bool,
|
|
118
|
+
sleep_time: int,
|
|
119
|
+
activities: Optional['Sequence[str]'],
|
|
120
|
+
heartbeat_handler: HeartbeatHandler,
|
|
121
|
+
) -> 'Generator[tuple[str, float], tuple[float, bool], None]':
|
|
122
|
+
"""
|
|
123
|
+
Generator which loops (either once, or indefinitely) over all activities while ensuring that `sleep_time`
|
|
124
|
+
passes between handling twice the same activity.
|
|
125
|
+
|
|
126
|
+
Returns an activity and how much time the calling context must sleep before handling that activity
|
|
127
|
+
and expects to get in return the time when the activity started to be executed and whether next
|
|
128
|
+
execution must be immediate.
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
# For each activity, the priority queue will keep the next absolute time when that
|
|
132
|
+
# activity must be handled.
|
|
133
|
+
activity_next_exe_time = PriorityQueue()
|
|
134
|
+
|
|
135
|
+
# On startup, we schedule to immediately handle all activities.
|
|
136
|
+
now = time.time()
|
|
137
|
+
for activity in activities or [None]:
|
|
138
|
+
activity_next_exe_time[activity] = now
|
|
139
|
+
|
|
140
|
+
while activity_next_exe_time:
|
|
141
|
+
activity = activity_next_exe_time.top()
|
|
142
|
+
desired_exe_time = activity_next_exe_time[activity]
|
|
143
|
+
|
|
144
|
+
if once:
|
|
145
|
+
time_to_sleep = 0
|
|
146
|
+
activity_next_exe_time.pop()
|
|
147
|
+
else:
|
|
148
|
+
time_to_sleep = desired_exe_time - time.time()
|
|
149
|
+
|
|
150
|
+
logger = heartbeat_handler.logger
|
|
151
|
+
if time_to_sleep > 0:
|
|
152
|
+
if activity:
|
|
153
|
+
logger(logging.DEBUG, 'Switching to activity %s and sleeping %s seconds', activity, time_to_sleep)
|
|
154
|
+
else:
|
|
155
|
+
logger(logging.DEBUG, 'Sleeping %s seconds', time_to_sleep)
|
|
156
|
+
else:
|
|
157
|
+
if activity:
|
|
158
|
+
logger(logging.DEBUG, 'Switching to activity %s', activity)
|
|
159
|
+
else:
|
|
160
|
+
logger(logging.DEBUG, 'Starting next iteration')
|
|
161
|
+
|
|
162
|
+
# The calling context notifies us when the activity actually got handled. And if sleeping is desired.
|
|
163
|
+
actual_exe_time, must_sleep = yield activity, time_to_sleep
|
|
164
|
+
|
|
165
|
+
if not once:
|
|
166
|
+
if must_sleep:
|
|
167
|
+
time_diff = time.time() - actual_exe_time
|
|
168
|
+
time_to_sleep = max(1.0, sleep_time - time_diff)
|
|
169
|
+
activity_next_exe_time[activity] = time.time() + time_to_sleep
|
|
170
|
+
else:
|
|
171
|
+
activity_next_exe_time[activity] = time.time() + 1
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def db_workqueue(
|
|
175
|
+
once: bool,
|
|
176
|
+
graceful_stop: threading.Event,
|
|
177
|
+
executable: str,
|
|
178
|
+
partition_wait_time: int,
|
|
179
|
+
sleep_time: int,
|
|
180
|
+
activities: Optional['Sequence[str]'] = None,
|
|
181
|
+
) -> 'Callable[[Callable[..., Union[bool, tuple[bool, T], None]]], Callable[[], Iterator[Union[T, None]]]]':
|
|
182
|
+
"""
|
|
183
|
+
Used to wrap a function for interacting with the database as a work queue: i.e. to select
|
|
184
|
+
a set of rows and perform some work on those rows while ensuring that two instances running in parallel don't
|
|
185
|
+
work on the same set of rows. The last condition is ensured by using heartbeats to keep track of currently
|
|
186
|
+
active workers.
|
|
187
|
+
|
|
188
|
+
:param once: Whether to stop after one iteration
|
|
189
|
+
:param graceful_stop: the threading.Event() object used for graceful stop of the daemon
|
|
190
|
+
:param executable: the name of the executable used for heartbeats
|
|
191
|
+
:param partition_wait_time: time to wait for database partition rebalancing before starting the actual daemon loop
|
|
192
|
+
:param sleep_time: time to sleep between the iterations of the daemon
|
|
193
|
+
:param activities: optional list of activities on which to work. The run_once_fnc will be called on activities one by one.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
def _decorate(run_once_fnc: 'Callable[..., Optional[Union[bool, tuple[bool, T]]]]') -> 'Callable[[], Iterator[Optional[T]]]':
|
|
197
|
+
|
|
198
|
+
@functools.wraps(run_once_fnc)
|
|
199
|
+
def _generator() -> 'Iterator[T]':
|
|
200
|
+
|
|
201
|
+
with HeartbeatHandler(executable=executable, renewal_interval=sleep_time - 1) as heartbeat_handler:
|
|
202
|
+
logger = heartbeat_handler.logger
|
|
203
|
+
logger(logging.INFO, 'started')
|
|
204
|
+
|
|
205
|
+
if partition_wait_time:
|
|
206
|
+
graceful_stop.wait(partition_wait_time)
|
|
207
|
+
_, _, logger = heartbeat_handler.live(force_renew=True)
|
|
208
|
+
|
|
209
|
+
activity_loop = _activity_looper(once=once, sleep_time=sleep_time, activities=activities, heartbeat_handler=heartbeat_handler)
|
|
210
|
+
activity, time_to_sleep = next(activity_loop, (None, None))
|
|
211
|
+
while time_to_sleep is not None:
|
|
212
|
+
if graceful_stop.is_set():
|
|
213
|
+
break
|
|
214
|
+
|
|
215
|
+
if time_to_sleep > 0:
|
|
216
|
+
graceful_stop.wait(time_to_sleep)
|
|
217
|
+
|
|
218
|
+
_, _, logger = heartbeat_handler.live()
|
|
219
|
+
|
|
220
|
+
must_sleep = True
|
|
221
|
+
start_time = time.time()
|
|
222
|
+
try:
|
|
223
|
+
result = run_once_fnc(heartbeat_handler=heartbeat_handler, activity=activity)
|
|
224
|
+
|
|
225
|
+
# Handle return values already existing in the code
|
|
226
|
+
# TODO: update all existing daemons to always explicitly return (must_sleep, ret_value)
|
|
227
|
+
if result is None:
|
|
228
|
+
must_sleep = True
|
|
229
|
+
ret_value = None
|
|
230
|
+
elif isinstance(result, bool):
|
|
231
|
+
must_sleep = result
|
|
232
|
+
ret_value = None
|
|
233
|
+
else:
|
|
234
|
+
must_sleep, ret_value = result
|
|
235
|
+
|
|
236
|
+
if ret_value is not None:
|
|
237
|
+
yield ret_value
|
|
238
|
+
except Exception as e:
|
|
239
|
+
METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
|
|
240
|
+
logger(logging.CRITICAL, "Exception", exc_info=True)
|
|
241
|
+
if once:
|
|
242
|
+
raise
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
activity, time_to_sleep = activity_loop.send((start_time, must_sleep))
|
|
246
|
+
except StopIteration:
|
|
247
|
+
break
|
|
248
|
+
|
|
249
|
+
if not once:
|
|
250
|
+
logger(logging.INFO, 'Graceful stop requested')
|
|
251
|
+
|
|
252
|
+
return _generator
|
|
253
|
+
|
|
254
|
+
return _decorate
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def run_daemon(
|
|
258
|
+
once: bool,
|
|
259
|
+
graceful_stop: threading.Event,
|
|
260
|
+
executable: str,
|
|
261
|
+
partition_wait_time: int,
|
|
262
|
+
sleep_time: int,
|
|
263
|
+
run_once_fnc: 'Callable[..., Optional[Union[bool, tuple[bool, Any]]]]',
|
|
264
|
+
activities: Optional[list[str]] = None
|
|
265
|
+
) -> None:
|
|
266
|
+
"""
|
|
267
|
+
Run the daemon loop and call the function run_once_fnc at each iteration
|
|
268
|
+
"""
|
|
269
|
+
|
|
270
|
+
daemon = db_workqueue(
|
|
271
|
+
once=once,
|
|
272
|
+
graceful_stop=graceful_stop,
|
|
273
|
+
executable=executable,
|
|
274
|
+
partition_wait_time=partition_wait_time,
|
|
275
|
+
sleep_time=sleep_time,
|
|
276
|
+
activities=activities,
|
|
277
|
+
)(run_once_fnc)
|
|
278
|
+
|
|
279
|
+
for _ in daemon():
|
|
280
|
+
pass
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class ProducerConsumerDaemon(Generic[T]):
|
|
284
|
+
"""
|
|
285
|
+
Daemon which connects N producers with M consumers via a queue.
|
|
286
|
+
"""
|
|
287
|
+
|
|
288
|
+
def __init__(
|
|
289
|
+
self,
|
|
290
|
+
producers: 'Sequence[Callable[[], Iterator[T]]]',
|
|
291
|
+
consumers: 'Sequence[Callable[..., None]]',
|
|
292
|
+
graceful_stop: threading.Event,
|
|
293
|
+
logger: "LoggerFunction" = logging.log
|
|
294
|
+
):
|
|
295
|
+
self.producers = producers
|
|
296
|
+
self.consumers = consumers
|
|
297
|
+
|
|
298
|
+
self.queue = queue.Queue()
|
|
299
|
+
self.lock = threading.Lock()
|
|
300
|
+
self.graceful_stop = graceful_stop
|
|
301
|
+
self.active_producers = 0
|
|
302
|
+
self.producers_done_event = threading.Event()
|
|
303
|
+
self.logger = logger
|
|
304
|
+
|
|
305
|
+
def _produce(
|
|
306
|
+
self,
|
|
307
|
+
it: 'Callable[[], Iterator[T]]',
|
|
308
|
+
wait_for_consumers: bool = False
|
|
309
|
+
) -> None:
|
|
310
|
+
"""
|
|
311
|
+
Iterate over the generator function and put the extracted elements into the queue.
|
|
312
|
+
|
|
313
|
+
Perform a graceful shutdown when graceful_stop is set.
|
|
314
|
+
"""
|
|
315
|
+
|
|
316
|
+
i = it()
|
|
317
|
+
with self.lock:
|
|
318
|
+
self.active_producers += 1
|
|
319
|
+
try:
|
|
320
|
+
while not self.graceful_stop.is_set():
|
|
321
|
+
if self.queue.qsize() > len(self.consumers):
|
|
322
|
+
self.graceful_stop.wait(1)
|
|
323
|
+
continue
|
|
324
|
+
|
|
325
|
+
try:
|
|
326
|
+
product = next(i)
|
|
327
|
+
self.queue.put(product)
|
|
328
|
+
except StopIteration:
|
|
329
|
+
break
|
|
330
|
+
except Exception as e:
|
|
331
|
+
METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
|
|
332
|
+
self.logger(logging.CRITICAL, "Exception", exc_info=True)
|
|
333
|
+
finally:
|
|
334
|
+
with self.lock:
|
|
335
|
+
self.active_producers -= 1
|
|
336
|
+
if not self.active_producers > 0:
|
|
337
|
+
self.producers_done_event.set()
|
|
338
|
+
|
|
339
|
+
if wait_for_consumers:
|
|
340
|
+
self.queue.join()
|
|
341
|
+
|
|
342
|
+
def _consume(
|
|
343
|
+
self,
|
|
344
|
+
fnc: 'Callable[[T], Any]'
|
|
345
|
+
) -> None:
|
|
346
|
+
"""
|
|
347
|
+
Wait for elements to arrive via the queue and call the given function on each element.
|
|
348
|
+
|
|
349
|
+
If producers_done_event is set, handle all remaining elements from the queue and exit gracefully.
|
|
350
|
+
"""
|
|
351
|
+
while not self.producers_done_event.is_set() or self.queue.unfinished_tasks:
|
|
352
|
+
try:
|
|
353
|
+
product = self.queue.get_nowait()
|
|
354
|
+
except queue.Empty:
|
|
355
|
+
self.producers_done_event.wait(1)
|
|
356
|
+
continue
|
|
357
|
+
|
|
358
|
+
try:
|
|
359
|
+
fnc(product)
|
|
360
|
+
except Exception as e:
|
|
361
|
+
METRICS.counter('exceptions.{exception}').labels(exception=e.__class__.__name__).inc()
|
|
362
|
+
self.logger(logging.CRITICAL, "Exception", exc_info=True)
|
|
363
|
+
finally:
|
|
364
|
+
self.queue.task_done()
|
|
365
|
+
|
|
366
|
+
def run(self) -> None:
|
|
367
|
+
|
|
368
|
+
producer_threads: list[threading.Thread] = []
|
|
369
|
+
for i, producer in enumerate(self.producers):
|
|
370
|
+
thread = threading.Thread(
|
|
371
|
+
target=self._produce,
|
|
372
|
+
name=f'producer-{i}-{producer.__name__}',
|
|
373
|
+
kwargs={
|
|
374
|
+
'it': producer,
|
|
375
|
+
'wait_for_consumers': True
|
|
376
|
+
}
|
|
377
|
+
)
|
|
378
|
+
thread.start()
|
|
379
|
+
producer_threads.append(thread)
|
|
380
|
+
|
|
381
|
+
consumer_threads: list[threading.Thread] = []
|
|
382
|
+
for i, consumer in enumerate(self.consumers):
|
|
383
|
+
thread = threading.Thread(
|
|
384
|
+
target=self._consume,
|
|
385
|
+
name=f'consumer-{i}-{consumer.__name__}',
|
|
386
|
+
kwargs={
|
|
387
|
+
'fnc': consumer,
|
|
388
|
+
}
|
|
389
|
+
)
|
|
390
|
+
thread.start()
|
|
391
|
+
consumer_threads.append(thread)
|
|
392
|
+
|
|
393
|
+
logging.info('waiting for interrupts')
|
|
394
|
+
|
|
395
|
+
while producer_threads:
|
|
396
|
+
for thread in producer_threads:
|
|
397
|
+
thread.join(timeout=3.14)
|
|
398
|
+
producer_threads = [thread for thread in producer_threads if thread.is_alive()]
|
|
399
|
+
|
|
400
|
+
self.producers_done_event.set()
|
|
401
|
+
|
|
402
|
+
while consumer_threads:
|
|
403
|
+
for thread in consumer_threads:
|
|
404
|
+
thread.join(timeout=3.14)
|
|
405
|
+
consumer_threads = [thread for thread in consumer_threads if thread.is_alive()]
|
|
@@ -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.
|