Skip to content

Asynchronous client configuration

The controller first calls oduflow.ping(minion_id). Once the exact accepted client is reachable and its full pillar is ready, it generates a canonical request UUID and calls oduflow.apply_start(minion_id, request_id). Both identifiers are required on every subsequent oduflow.apply_status call.

The only published command is state.apply roles.client_stack, targeting one canonical client-UUID with Salt's list matcher. No state name, function, arguments, pillar override, or cache path comes from the API caller.

Production uses separate oduflow.production_start(minion_id, request_id) and oduflow.production_status(minion_id, request_id) endpoints with the same response contract. Their only role is roles.client_production. New claims record both a profile (configure or production) and its fixed role before starting the worker. A request UUID already bound to one profile cannot be reused or read through the other profile's endpoint. Legacy receipts without profile fields remain configuration jobs exclusively. The worker validates this persisted pair against its internal whitelist; its command line still accepts identities only.

control_master installs /usr/local/libexec/oduflow-apply-worker and creates /var/cache/salt/oduflow-apply, owned by the Salt service account with mode 0700. The worker runs as that account. Its arguments contain only the two identities. The runner durably writes a mode 0600 claim before launching the worker; the worker records dispatch before publishing. Repeated start calls never publish again. The master retains job_cache: false, pillar_cache: false and no external job cache. Only the sanitized receipt is persisted, not raw Salt returns or pillar.

The response fields are minion_id, request_id, jid, status, passed, total. jid is a preassigned Salt job identifier, or null for not_started. States:

  • not_started: no master claim exists.
  • running: a claim is launching or its worker holds the execution lease.
  • succeeded: a nonempty Salt state return has every result exactly true.
  • failed: a nonempty state return contains at least one result that is not true.
  • unknown: launch/transport failed, no trustworthy result returned, or the worker disappeared. Do not create a new request automatically.

Worker execution waits up to 7200 seconds, with a process alarm at 7250 seconds. Status detects an abandoned lease after a 30-second launch grace period; after 7260 seconds it reports unknown even if the process still holds a lease. A late trustworthy return can replace unknown with its final summary. A service/master restart can kill the detached process while the minion continues applying; this intentionally leaves an unknown receipt requiring explicit reconciliation. A per-client worker lock prevents concurrent publication by different requests.

Apply the updated control_master state before deploying controller code that calls the new endpoints. The eauth allowlist explicitly includes only these fixed runners. Configuration does not create production or publish its HTTP ports. The separate production role owns guarded creation, hardening and publication; both profiles retain the same at-most-once dispatch behavior.