Wzorzec mechaniczny: sekcje deploy/verify/install/testy wycinane do kb/runbooks/<serwis>-*.md, reszta zostaje dokumentem type: service. Wzajemne `links` w obie strony. Tresc sekcji nietknieta — przenoszone doslownie, dodany wylacznie naglowek H1 nowego runbooka. kb-query, paperless-worker, planner-agent, ha-diag-agent, ollama-piha, narty27, home-assistant, ha-mcp, job-gmail-header-backfill, job-mail-body-ingest. Weryfikacja: dla kazdego pliku multizbior niepustych linii (main + runbook) == oryginal z HEAD. Zero zgubionych, zero dodanych. Recon szacowal 13 splitow service+runbook; faktycznie 2-typowych jest 10, pozostale 5 (paperless, nextcloud, gokapi, fleet-prometheus, deploy-runner) sa 3-typowe i ida osobno jako splity wielotypowe. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5.3 KiB
| okf | type | visibility | status | updated | links | |
|---|---|---|---|---|---|---|
| 0.1 | runbook | private | active | 2026-07-22 |
|
home-assistant — import, deploy, testy
Import
scripts/ha/import.sh ken
scripts/ha/import.sh ken-legacy
Read-only, and idempotent for both adapters — re-running against an unchanged instance produces no diff.
docker-exec adapter (ken-legacy): pulls the whole /config tree
over ssh ... docker exec ... tar, filters it through .gitignore,
normalizes and splits it into config/<instance>/, exports curated
.storage/* into storage-export/<instance>/.
api adapter (ken, chelsty-ha): for instances with no
filesystem/SSH access (HAOS has none). Pulls automations/scripts/scenes via
one REST GET per object (/api/config/<domain>/config/<id>) and
dashboards/area+entity registries/input_* helpers via the WebSocket API
(/api/websocket) — read-only commands only, nothing that mutates the live
instance. Full /config import is out of scope for this adapter; see
DESIGN.md, "Deploy path: adapter per instance".
Both adapters also write a dated /api/states fixture snapshot to
fixtures/ if a deploy token exists at
~/.config/ha-deploy/<instance>.token. For the api adapter, that token is
not optional — see "Tokens" below.
Tokens
The api adapter has no filesystem fallback, so a missing or empty token
at token_path (see instances.yaml) is a hard error, not a soft-skip —
import.sh aborts immediately with a clear message rather than silently
producing an empty import. See DESIGN.md, "Tokens", for how the
deploy_agent account and its long-lived access token are provisioned.
The token itself never touches a subprocess argv or a log line: REST calls
go through scripts/ha/lib/ha_api.py, which reads the token file itself and
sets the Authorization header in-process via requests (never curl -H,
which would put the token in that process's argv, visible to any local user
via ps). requests (python3-requests) is a very common preinstalled/
transitive package on Debian-based nodes; if it's ever missing, import.sh
fails with Python's own ModuleNotFoundError — install it the same way as
python3-websocket below (sudo apt install python3-requests or pip install --user requests).
WebSocket dependency
The dashboard/registry/helper export (scripts/ha/lib/ha_ws.py) depends on
the websocket-client PyPI package (import name websocket) — not in the
stdlib, not installed by default. Install one of:
sudo apt install python3-websocket # Debian/Ubuntu package name
# or
pip install --user websocket-client
If it's missing, import.sh ken still imports automations/scripts/scenes
(REST-only, no extra dependency needed) and then reports the
dashboards/registries/helpers step as skipped with an actionable message
naming the package to install — it does not crash with a raw traceback, and
it does not silently produce an incomplete storage-export/ without saying
so.
Deploy
scripts/ha/deploy.sh ken --dry-run # plan only, read-only
scripts/ha/deploy.sh ken --dry-run automations/111.yaml # plan for one object
scripts/ha/deploy.sh ken # deploy everything in scope
scripts/ha/deploy.sh ken scripts/notify_email_ntfy.yaml # deploy one object
Repo -> instance, api adapter only, automations/scripts/scenes only
(dashboards/helpers are WebSocket-only — ha_ws.py has no mutating
command, deliberately, and that write path doesn't exist yet). Refuses any
instance with status != active (see instances.yaml) or an adapter other
than api — no override flag.
Hard sequence, per DESIGN.md's "Sync model" and "Validation gate", any
failure aborts before the next step:
- drift-check — re-imports the instance's current state and diffs it
against the last commit (
HEAD) for every object not being deployed this run. Any difference aborts with a diff printed; drift is never silently overwritten. - validate — local sanity (YAML parses, required keys present per
domain) plus a live
check_configgate on the instance. - write — one
POST /api/config/<domain>/config/<id>per object. - verify — GETs the same object back and compares it to what was written. A mismatch is reported (which object, what differs); there is no auto-rollback.
--dry-run runs steps 1-2 (both read-only in effect) and stops before any
write, printing the same plan a live run would act on.
Tests
scripts/ha/tests/test_split_normalize.sh
scripts/ha/tests/test_normalize_tags.sh
scripts/ha/tests/test_import_api_offline.sh
scripts/ha/tests/test_deploy_api_offline.sh
All offline — no network, no HA instance required. test_import_api_offline.sh
covers the api adapter: normalization of real-shaped API responses (saved
as fixtures under tests/fixtures/), idempotency, stale-file cleanup, and
the missing-websocket-client error path (via sys.modules injection, not
an actual network call). test_deploy_api_offline.sh covers the deploy
write path: a clean deploy, drift-abort, local validation rejecting broken/
unparseable YAML, and verify detecting a post-write mismatch — using a real
temporary git repo for the HEAD comparison and a fake in-memory client for
get/post_config/check_config (no network).