Placement profiles

Placement profiles

stado placement profile reads and writes the placement profiles themselves. list [--json] prints each profile's name, services and hosts; show NAME prints one exactly as the registry holds it. declare --file PATH|- [--json] adds a profile, or replaces the one of the same name, from its JSON (name, services, start_order, stop_order, state, hosts with each host's units and probes, and optionally routing and allow_unhealthy_source), and in the same registry commit links each listed service's directory route to it: the route names the profile and drops managed_service, which a placement-backed route derives from the profile. The directory generation advances once. A profile may name only the host it is placed on, for standby to add destinations to, and may declare no state when its services keep nothing durable. Refusals, each before anything is written: a profile that does not parse as the registry reads one; a service another profile holds (service <s> already moves with placement profile <p>; …); a service the directory does not declare (service <s> is not in the service directory; declare it with stado service declare before placing it in a profile); a redeclaration that drops a service the profile holds; and a profile a placement transaction holds. The registry's own validation then judges the whole document, as every push does. remove NAME [--json] takes the profile out and turns each of its services back into a fixed route naming the unit the profile declares on the route's active host, dropping its standby addresses; it is refused for an unknown profile and while a move holds it.

sync NAME [--json] adds to the profile, in one registry commit, every store the catalog declares for its products (service.state, the product found by the service's name, else its unit) that the profile does not carry, each with the catalog's tree and required. It prints `placement profile

now carries (), … (registry generation )` (`{"profile", "state": "synced", "added": […], "registry_generation"}` with `--json`), or that it already carries every one (`"state": "unchanged"`), and is refused for an unknown profile and while a move holds it. A move refuses a profile missing such a store and names this command; Stado Desktop runs it. `sync --all [--json]` does the same for every profile the registry declares, one commit each, printing one line per profile (`{"profiles": [{"profile", "state": "synced"|"unchanged"|"refused", "added", "registry_generation"|"refused"}]}` with `--json`); a profile that cannot be synced is named with its cause while the others still sync, and the command then refuses naming them. It closes every `profile-lacks-catalog-stores` finding `stado registry doctor` reports, and Stado Desktop runs it as "Add to every placement profile the stores the catalog declares".

draft NAME --service S [--service S …] [--probe S=URL …] [--state PATH …] [--tree-state PATH …] is its inverse for services declared as fixed routes: it prints, and writes nothing, the profile that would move them, with each unit's kind, file and launchd label or systemd name read from the services the route's active host declares under its managed_service. The services start in the order given and stop in the reverse; each --state is a required file and each --tree-state a required directory under the host's home (edit the printed JSON for a work-root store), and the stores the catalog declares for the products the units run (a product's service.state: paths under the home, each a file or a tree, required or not — Weles keeps .weles/keeper and .stado/weles-detached-runs) are added after them, a path named on the command line keeping its own entry. The catalog refuses a state path that is absolute, starts with $, or holds an empty or .. part. Nothing the registry or the catalog does not hold is guessed: a service's probe is its --probe, else the catalog's answering request for the product its unit runs, when that is a GET with no body, asked at the address the directory names for the service on its active host (Weles' GET /healthz, for instance); a service neither gives a probe is refused (a placement profile probes every service on its host, and neither a --probe SERVICE=URL nor a GET answering request the catalog declares for its product names <s>). Refused: a service the directory does not declare, one another profile already moves (`directory service already moves with placement profile

`), a route with no `active_host` or `managed_service`, a route served by the host Stado process (`com.wisent.stado`, which runs on every host, so a move would find it running on the destination and fence the whole process on the source: `… cannot move a role of that process`), a unit its host does not declare, a unit whose record names no file (`registry target declares managed service with no unit file path, which a placement profile must name; …`: the file is under that host's home, which is not guessed), and services active on different hosts (`one placement profile moves from one host`). The printed profile is parsed as `declare` parses it, so `stado placement profile draft … | stado placement profile declare --file -` gives the services the profile in one registry commit. Stado Desktop runs the five verbs under **Hosts → Routes → Available operations…**.

Source: this website