OpenKeel: the sovereign French Cloud solution of the inherent group, with a European reach Discover inherent

Reverse-spec · Services

barbican — Async processing

Processing outside the API — barbican — branch stable/2026.2

Branch stable/2026.2 @ de32745a7a4f — repository https://opendev.org/openstack/barbican — analysed on 2026-10-29

ProcessTriggerTypePurposeReadsWrites / emitsDefined at
barbican-workerprocess_type_orderRPC cast (topic barbican.workers)generate the key(s) of an orderorders, projects, kek_datasecrets, encrypted_data, secret_store_metadata, containers, container_secret, orders statusbarbican/queue/server.py:205
barbican-retry_check_retry_taskstimer (dynamic, [retry_scheduler] periodic_interval_max_seconds = 10 s ± 20 %, first after initial_delay_seconds = 10 s)re-enqueue scheduled order tasksorder_retry_tasks where retry_at <= nowRPC cast, delete the retry rowbarbican/queue/retry_scheduler.py:80
barbican-keystone-listeneridentity.project.deletednotification (exchange keystone, topic notifications)remove a deleted project's dataprojectssoft delete of the project's rowsbarbican/queue/keystone_listener.py:52
barbican-apistart-uponce per processsync [secretstore:*] to secret_stores (multiple back ends)secret_stores, project_secret_storesecret_storesbarbican/api/app.py:85, barbican/plugin/util/multiple_backends.py:106
barbican-apiorder created and [queue] enable = Falsesynchronous callsame as the worker, inside the requestas workeras workerbarbican/queue/client.py:63
barbican-manageoperatorCLIdatabase clean-up, store sync, KEK managementsee § 4see § 4barbican/cmd/barbican_manage.py:50

1. Order processing (barbican-worker)

Trigger: RPC cast process_type_order(order_id, project_id, request_id) from POST /v1/orders (barbican/api/controllers/orders.py:199) or from the retry scheduler. Server: oslo.service Service running an oslo.messaging RPC server, [queue] asynchronous_workers processes (default 1, barbican/cmd/worker.py:52).

Functional purpose: turn a PENDING order into a generated secret (type key) or key pair and container (type asymmetric).

Flow (barbican/queue/server.py:202 decorators monitored → transactional → retryable_order):

  1. BeginTypeOrder.process_and_suppress_exceptions(order_id, project_id) (barbican/tasks/resources.py:45).
  2. Load the order by id and Keystone project id; a missing order is logged (Could not retrieve information needed to process task) and the exception is suppressed (barbican/tasks/resources.py:87).
  3. Copy the order's creator_id into the meta (barbican/tasks/resources.py:265), then plugin.generate_secret or plugin.generate_asymmetric_secret (barbican/plugin/resources.py:163, barbican/plugin/resources.py:191), which choose a store with generate_supports, generate through it and save the rows.
  4. Success: order ACTIVE, secret_id or container_id set (barbican/tasks/resources.py:197). Failure: order ERROR, error_status_code, error_reason (barbican/tasks/resources.py:189).
  5. retryable_order looks at the returned FollowOnProcessingStatusDTO; key and asymmetric orders always return NO_ACTION_REQUIRED, so no retry is ever scheduled on this branch (barbican/tasks/resources.py:260, barbican/queue/server.py:156).
  6. transactional commits, or rolls back on an unexpected exception (barbican/queue/server.py:86).

Concurrency and idempotency: no lock. A redelivered cast would generate a second secret and overwrite order.secret_id [inferred: no status check before generation, barbican/tasks/resources.py:245]. RPC casts are not redelivered by oslo.messaging after acknowledgement, so this only happens with manual replays.

Errors: see 02 § 4. Cost: a handful of queries per order plus the crypto work (RSA 4096 generation can take seconds).

2. Retry scheduler (barbican-retry)

Trigger: self.tg.add_dynamic_timer(self._check_retry_tasks, initial_delay=…, periodic_interval_max=…) (barbican/queue/retry_scheduler.py:65); the callback returns the next delay, random in [0.8, 1.2] × periodic_interval_max_seconds (barbican/queue/retry_scheduler.py:35).

Data read: SELECT * FROM order_retry_tasks WHERE retry_at <= :now AND deleted = 0 ORDER BY created_at (all rows, paging defaults apply) (barbican/queue/retry_scheduler.py:116, barbican/model/repositories.py:1228).

Flow: for each task, call TaskClient.<retry_task>(*retry_args, **retry_kwargs) (an RPC cast), then delete the row and commit; on error roll back and leave the row (barbican/queue/retry_scheduler.py:128).

Concurrency: none — several barbican-retry processes would enqueue the same task twice. Upstream deploys one. Effective use on this branch: none (see § 1 step 5); the process can be omitted unless a third-party plugin returns retries.

3. Keystone listener (barbican-keystone-listener)

Trigger: oslo.messaging notification listener on Target(exchange='keystone', topic='notifications', fanout=True) (barbican/queue/__init__.py:88), pool [keystone_notifications] pool_name, thread_pool_size threads (default 10). Starts only if [keystone_notifications] enable = True (barbican/cmd/keystone_listener.py:52).

Emitter: Keystone with [oslo_messaging_notifications] driver = messagingv2 and its notification_format = basic (the payload must carry resource_info) [inferred from barbican/queue/keystone_listener.py:129].

Flow (barbican/queue/keystone_listener.py:52):

  1. Parse event_type (identity.project.deleted → resource project, operation deleted, barbican/queue/keystone_listener.py:106) and payload['resource_info'].
  2. Other events → return None (acknowledged).
  3. KeystoneEventConsumer.process in its own transaction: find the Barbican project; if absent, log and return (barbican/tasks/keystone_consumer.py:115); else delete_all_project_resources(project.id): soft-delete containers, secrets (with their children), KEKs, then the project row (barbican/model/repositories.py:274).
  4. Return HANDLED; on failure REQUEUE (if allow_requeue) or HANDLED.

Idempotency: a redelivered event finds the project already soft-deleted and does nothing. Gaps: external-store objects (Vault, KMIP, HSM) are left behind; consumers, orders, ACLs and quotas rows are not deleted [inferred from the four repositories called in barbican/model/repositories.py:283]; the error log path is broken (02 § 4).

4. Maintenance commands (barbican-manage)

CommandEffectDefined at
db upgrade [-v head], db revision, db history, db currentAlembicbarbican/cmd/barbican_manage.py:99–barbican/cmd/barbican_manage.py:141
db clean [-m min_days] [-p] [-e] [-V] [-L log]hard-delete soft-deleted rows older than min_days (children first, batched), -p remove projects without secrets/containers/orders/KEKs, -e soft-delete expired secrets firstbarbican/cmd/barbican_manage.py:74, barbican/model/clean.py:458
db sync_secret_storeswrite [secretstore:*] to secret_stores (also done by the API at start)barbican/cmd/barbican_manage.py:157, barbican/model/sync.py:26
hsm gen_mkek, check_mkek, gen_hmac, check_hmaccreate / verify the HSM master keysbarbican/cmd/barbican_manage.py:191–barbican/cmd/barbican_manage.py:287
hsm rewrap_pkek [--dry-run]re-wrap every project KEK with the current MKEK/HMAC keybarbican/cmd/barbican_manage.py:314
simple_crypto rewrap_pkek [--dry-run]re-encrypt every kek_data.plugin_meta with the first master KEK (MultiFernet.rotate)barbican/cmd/barbican_manage.py:361, barbican/cmd/simple_crypto.py:90
simple_crypto new_pkek --projectdeactivate the project's KEK and create a new unbound onebarbican/cmd/simple_crypto.py:40
simple_crypto rewrap_secrets --projectre-encrypt all the project's non-deleted secrets with its active KEKbarbican/cmd/simple_crypto.py:51
barbican-status upgrade checkoslo.upgradecheck (policy file checks)barbican/cmd/status.py:22

clean is the only path that removes ciphertexts of deleted secrets; until it runs they remain decryptable with the master key (07 § 3.6).

Source: reverse-spec-barbican/05-async-processing_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.