Part of #24.
Unit 3: halos-restore.sh — InfluxDB + Grafana restore (the hard core)
Goal: Within the same restore script, reinstate the historical InfluxDB data via raw swap and re-import Grafana dashboards/datasources, aligned to Halos' marine defaults.
Requirements: R2, R5
Dependencies: Unit 2 (script skeleton, manifest validation).
Files:
- Modify:
docs/migrate/halos-restore.sh
- Test: manual integration verification (smoke queries below).
Approach:
- InfluxDB: install/confirm
marine-influxdb-container; let it initialize once; stop it. Mint an operator token from the boat influxd.bolt via docker run --rm influxdb:2.9.1 influxd recovery auth create-operator. Move Halos …/data/db → db.halos-default; copy the boat influx tree from USB into …/data/db; set ownership/permissions to match the container's expectation (origin run used pi:root, 0700 — confirm against current package). Back up env → env.halos-default; set INFLUXDB_ADMIN_TOKEN to the minted token. Start; verify org/bucket list with the token. Discover orgs/buckets (names arbitrary, boat-specific; there may be more than one bucket); pick the telemetry-bearing one by data presence/size, prompting the user to confirm or choose when ambiguous; rename that org + bucket to marine. Create v1 DBRP marine/autogen (default). Smoke-test a Flux first()/last() query returning real telemetry.
- Grafana: confirm
marine-grafana-container up; reach it at the container's internal IP:3000 with admin:admin (fallback: provision a temp admin if OIDC blocks basic auth). Read the boat grafana.db from USB with python3 stdlib sqlite3: extract datasources and dashboards. Recreate the boat datasource preserving its UID, db skdata-db, token as Authorization: Token … header. Import each dashboard with id cleared and overwrite:true. Verify datasource /health and one InfluxQL query through the proxy.
- Final: combined health check of all three marine services + a printed verification summary (what restored, any warnings, the SK plugin reconciliation note).
Technical design (directional): token mint → db swap → start → org/bucket rename → DBRP → smoke query is a strict ordering; the rename must happen after the service is up with the minted token, and Grafana import must happen after the rename so the default datasource resolves marine.
Patterns to follow: Sequence/values validated in the origin migration; do not fight prestart — inject token before start so prestart leaves it alone.
Test scenarios:
- Happy path: boat influx tree →
influx bucket list shows marine, a Flux query returns the latest real telemetry value; Halos default Grafana datasource /health reports measurements found.
- Happy path: boat dashboards import successfully and render against the boat datasource (preserved UID,
skdata-rp queries resolve via legacy DBRP).
- Edge: arbitrary single org/bucket name → discovered by id and renamed to
marine without any hardcoded name.
- Edge: multiple buckets present → user prompted to choose which to rename to
marine; the rest remain present under original names (carried automatically by the raw swap), queryable via the operator token.
- Error: minted-token influx start fails (version/format) → surface logs,
db.halos-default intact for rollback.
- Error: Grafana basic auth rejected → fall back to temp admin or fail with clear guidance.
- Integration: injected
INFLUXDB_ADMIN_TOKEN survives a service restart (prestart password-sync does not clobber it).
- Integration: renamed
marine bucket is what Halos' provisioned datasource and the SK influx plugin target.
Verification: Historical telemetry is queryable in Halos Grafana through both the provisioned default datasource and the imported boat dashboards.
Part of #24.
Unit 3:
halos-restore.sh— InfluxDB + Grafana restore (the hard core)Goal: Within the same restore script, reinstate the historical InfluxDB data via raw swap and re-import Grafana dashboards/datasources, aligned to Halos'
marinedefaults.Requirements: R2, R5
Dependencies: Unit 2 (script skeleton, manifest validation).
Files:
docs/migrate/halos-restore.shApproach:
marine-influxdb-container; let it initialize once; stop it. Mint an operator token from the boatinfluxd.boltviadocker run --rm influxdb:2.9.1 influxd recovery auth create-operator. Move Halos…/data/db→db.halos-default; copy the boat influx tree from USB into…/data/db; set ownership/permissions to match the container's expectation (origin run usedpi:root,0700— confirm against current package). Back upenv→env.halos-default; setINFLUXDB_ADMIN_TOKENto the minted token. Start; verify org/bucket list with the token. Discover orgs/buckets (names arbitrary, boat-specific; there may be more than one bucket); pick the telemetry-bearing one by data presence/size, prompting the user to confirm or choose when ambiguous; rename that org + bucket tomarine. Create v1 DBRPmarine/autogen(default). Smoke-test a Fluxfirst()/last()query returning real telemetry.marine-grafana-containerup; reach it at the container's internal IP:3000 withadmin:admin(fallback: provision a temp admin if OIDC blocks basic auth). Read the boatgrafana.dbfrom USB withpython3stdlib sqlite3: extract datasources and dashboards. Recreate the boat datasource preserving its UID, dbskdata-db, token asAuthorization: Token …header. Import each dashboard withidcleared andoverwrite:true. Verify datasource/healthand one InfluxQL query through the proxy.Technical design (directional): token mint → db swap → start → org/bucket rename → DBRP → smoke query is a strict ordering; the rename must happen after the service is up with the minted token, and Grafana import must happen after the rename so the default datasource resolves
marine.Patterns to follow: Sequence/values validated in the origin migration; do not fight prestart — inject token before start so prestart leaves it alone.
Test scenarios:
influx bucket listshowsmarine, a Flux query returns the latest real telemetry value; Halos default Grafana datasource/healthreports measurements found.skdata-rpqueries resolve via legacy DBRP).marinewithout any hardcoded name.marine; the rest remain present under original names (carried automatically by the raw swap), queryable via the operator token.db.halos-defaultintact for rollback.INFLUXDB_ADMIN_TOKENsurvives a service restart (prestart password-sync does not clobber it).marinebucket is what Halos' provisioned datasource and the SK influx plugin target.Verification: Historical telemetry is queryable in Halos Grafana through both the provisioned default datasource and the imported boat dashboards.