signalk-container 1.8.1 → 1.9.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +5 -0
- package/AGENTS.md +7 -5
- package/README.md +136 -76
- package/dist/containers.d.ts +9 -1
- package/dist/containers.d.ts.map +1 -1
- package/dist/containers.js +49 -2
- package/dist/containers.js.map +1 -1
- package/dist/doctor.d.ts +55 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +554 -2
- package/dist/doctor.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +110 -13
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +125 -0
- package/dist/types.d.ts.map +1 -1
- package/doc/plugin-developer-guide.md +76 -1
- package/package.json +1 -1
- package/public/configpanel-entry.js +3 -2
package/.gitattributes
ADDED
package/AGENTS.md
CHANGED
|
@@ -10,7 +10,7 @@ Key components:
|
|
|
10
10
|
- **`src/resources.ts`** — cgroup-limit flag emission + live-update path via `podman/docker update`. The "Bug D" precedent for diff-on-already-running lives here.
|
|
11
11
|
- **`src/runtime.ts`** — Runtime detection (`podman` vs `docker`), version probing, `execRuntime`/`execRuntimeLong` dispatch, `isContainerized()` self-detection.
|
|
12
12
|
- **`src/updates/`** — Centralized image-update detection (digest drift for floating tags, version comparison for semver). Used by all consumer plugins via `containers.updates.register(...)`.
|
|
13
|
-
- **`
|
|
13
|
+
- **`src/configpanel/`** — React config panel source. Built with Vite + `@module-federation/vite` (see `vite.config.ts`); build artifacts land in `public/`, served via Module Federation into the Signal K Admin UI.
|
|
14
14
|
|
|
15
15
|
## Code Quality Principles
|
|
16
16
|
|
|
@@ -39,7 +39,7 @@ Do not add error handling, fallbacks, or validation for scenarios that cannot ha
|
|
|
39
39
|
- All new code requires tests. Test behavior at the function boundary, not internal control flow.
|
|
40
40
|
- Inject `exec: ExecFn = execRuntime` rather than calling the runtime directly. Tests stub via `fakeExec`. See `src/test/getLiveResources.test.ts` for the canonical pattern: synthetic `{stdout, stderr, exitCode}`, no real podman invocations.
|
|
41
41
|
- Container-integration tests (those that actually pull `alpine:3.19`) gate on `hasContainerRuntime()` which returns `null` on Windows. Do not add new tests that pull real Linux images without the same guard.
|
|
42
|
-
-
|
|
42
|
+
- All tests must pass on every commit. Run `npm test` after `npm run build` (or `npm run build:all` to do both); `node --test` runs the compiled `dist/test/**/*.test.js` glob, so a fresh build is required before testing.
|
|
43
43
|
|
|
44
44
|
## Runtime Invariants
|
|
45
45
|
|
|
@@ -137,11 +137,13 @@ This repo is maintained by Dirk Wahrheit. Workflow is deliberate; AI tools shoul
|
|
|
137
137
|
|
|
138
138
|
Before pushing or opening a PR:
|
|
139
139
|
|
|
140
|
-
1. `npm run format` — prettier write + eslint --fix
|
|
141
|
-
2. `npm run build:all` — `clean && tsc &&
|
|
142
|
-
3. `npm run ci-lint` — `eslint && prettier --check
|
|
140
|
+
1. `npm run format` — `prettier --write .` + `eslint --fix` (writes back fixes)
|
|
141
|
+
2. `npm run build:all` — `build && test`, where `build` = `clean && build:server (tsc) && build:configpanel (vite build)`. All tests must pass.
|
|
142
|
+
3. `npm run ci-lint` — `eslint && prettier --check .` — read-only verification of step 1's output; this is what CI runs and what catches uncommitted format/lint drift.
|
|
143
143
|
4. `cr review --plain | tee /tmp/cr-review-<branch>.txt` — local CodeRabbit pass. `cr` only sees committed changes, so commit first, then review. The CLI is rate-limited (~50min cooldown); pipe to a file so reruns aren't needed.
|
|
144
144
|
|
|
145
|
+
For iterative server-side work, `npm run watch` runs `tsc --watch`. It does **not** rebuild the configpanel and does **not** clean stale `dist/test/` — run a full `npm run build` before invoking `npm test`.
|
|
146
|
+
|
|
145
147
|
Only push after all four pass. **Never push without explicit approval.** `git push` always needs its own permission — commit/test/format/cr approval does not cover push.
|
|
146
148
|
|
|
147
149
|
### Release flow
|
package/README.md
CHANGED
|
@@ -117,60 +117,64 @@ See [doc/plugin-developer-guide.md](doc/plugin-developer-guide.md) for the full
|
|
|
117
117
|
|
|
118
118
|
## API
|
|
119
119
|
|
|
120
|
-
| Method
|
|
121
|
-
|
|
|
122
|
-
| `getRuntime()`
|
|
123
|
-
| `whenReady()`
|
|
124
|
-
| `pullImage(image, onProgress?)`
|
|
125
|
-
| `imageExists(image)`
|
|
126
|
-
| `getImageDigest(imageOrContainer)`
|
|
127
|
-
| `ensureRunning(name, config, options?)`
|
|
128
|
-
| `start(name)`
|
|
129
|
-
| `stop(name)`
|
|
130
|
-
| `remove(name)`
|
|
131
|
-
| `getState(name)`
|
|
132
|
-
| `runJob(config)`
|
|
133
|
-
| `getLogs(name, options?)`
|
|
134
|
-
| `prune()`
|
|
135
|
-
| `listContainers()`
|
|
136
|
-
| `execInContainer(name, command)`
|
|
137
|
-
| `ensureNetwork(name)`
|
|
138
|
-
| `removeNetwork(name)`
|
|
139
|
-
| `connectToNetwork(container, network)`
|
|
140
|
-
| `disconnectFromNetwork(container, net)`
|
|
141
|
-
| `updates.register(reg)`
|
|
142
|
-
| `updates.unregister(pluginId)`
|
|
143
|
-
| `updates.checkOne(pluginId)`
|
|
144
|
-
| `updates.getLastResult(pluginId)`
|
|
145
|
-
| `updateResources(name, limits)`
|
|
146
|
-
| `getResources(name)`
|
|
147
|
-
| `resolveSignalkDataMount()`
|
|
148
|
-
| `resolveHostPath(absPath)`
|
|
149
|
-
| `resolveContainerAddress(name, port)`
|
|
150
|
-
| `doctor.imageRunsAsUser(image, user?)`
|
|
120
|
+
| Method | Description |
|
|
121
|
+
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
122
|
+
| `getRuntime()` | Returns `{ runtime, version, isPodmanDockerShim }` or `null` |
|
|
123
|
+
| `whenReady()` | Resolves once runtime detection settles (success OR failure). Replaces the polling-loop pattern; check `getRuntime()` after the await |
|
|
124
|
+
| `pullImage(image, onProgress?)` | Pull a container image (auto-qualifies for Podman) |
|
|
125
|
+
| `imageExists(image)` | Check if image exists locally |
|
|
126
|
+
| `getImageDigest(imageOrContainer)` | Local image ID (sha256) for an image:tag or container |
|
|
127
|
+
| `ensureRunning(name, config, options?)` | Create and start container if not running; auto-recreates on config drift across `image`, `tag`, `command`, `networkMode`, `env`, `volumes`, `ports` |
|
|
128
|
+
| `start(name)` | Start a stopped container |
|
|
129
|
+
| `stop(name)` | Stop a running container |
|
|
130
|
+
| `remove(name)` | Stop and remove a container |
|
|
131
|
+
| `getState(name)` | Returns `running`, `stopped`, `missing`, or `no-runtime` |
|
|
132
|
+
| `runJob(config)` | Execute a one-shot container job |
|
|
133
|
+
| `getLogs(name, options?)` | One-shot fetch of the last N lines of a container's combined stdout+stderr log. `tail` defaults to 200, max 10000; `since` is unix-epoch seconds |
|
|
134
|
+
| `prune()` | Remove dangling images |
|
|
135
|
+
| `listContainers()` | List all `sk-` prefixed containers |
|
|
136
|
+
| `execInContainer(name, command)` | Run a command inside a running container |
|
|
137
|
+
| `ensureNetwork(name)` | Create a Podman/Docker network if it doesn't exist |
|
|
138
|
+
| `removeNetwork(name)` | Remove a network |
|
|
139
|
+
| `connectToNetwork(container, network)` | Add a container to a network (bridge mode only) |
|
|
140
|
+
| `disconnectFromNetwork(container, net)` | Remove a container from a network |
|
|
141
|
+
| `updates.register(reg)` | Register a container for update detection |
|
|
142
|
+
| `updates.unregister(pluginId)` | Stop tracking updates for a plugin |
|
|
143
|
+
| `updates.checkOne(pluginId)` | Force a fresh update check (or coalesce with in-flight) |
|
|
144
|
+
| `updates.getLastResult(pluginId)` | Cached last result, no network |
|
|
145
|
+
| `updateResources(name, limits)` | Apply new resource limits live, fall back to recreate |
|
|
146
|
+
| `getResources(name)` | Currently effective limits (plugin defaults ⊕ user override) |
|
|
147
|
+
| `resolveSignalkDataMount()` | Resolve the volume name or host path that backs `app.getDataDirPath()` in the current deployment; returns `null` if the runtime is not yet initialised |
|
|
148
|
+
| `resolveHostPath(absPath)` | Translate an arbitrary absolute path into the `{ source, subPath }` pair the runtime needs to mount it; handles bare-metal, bind, and named-volume topologies |
|
|
149
|
+
| `resolveContainerAddress(name, port)` | Return the `host:port` string to reach `port` on a managed container from the SignalK process; call after `ensureRunning()` with `signalkAccessiblePorts` set |
|
|
150
|
+
| `doctor.imageRunsAsUser(image, user?)` | Probe whether `image` runs cleanly under the host-UID mapping signalk-container will emit (1.8.0+). Never throws — returns `{ ok, output, error? }` |
|
|
151
|
+
| `doctor.selfDeployment()` | Diagnose the Signal K deployment itself: binary discovery, daemon reachability, rootless/rootful detection, and (when containerized) self-container ID. Returns `{ status, remediation, ... }` — see `SelfDeploymentResult` in `src/types.ts` |
|
|
152
|
+
| `doctor.generateSetupSnippet(format?, result?)` | Generate a ready-to-paste compose fragment (`format: "compose"`, default) or `podman/docker run` command (`format: "run"`) tailored to the detected runtime. Pure templating over `SelfDeploymentResult`; bundles a minimal Dockerfile sidecar and operator notes. |
|
|
151
153
|
|
|
152
154
|
## REST Endpoints
|
|
153
155
|
|
|
154
156
|
All mounted at `/plugins/signalk-container/api/`:
|
|
155
157
|
|
|
156
|
-
| Method | Path | Description
|
|
157
|
-
| ------ | ---------------------------------------- |
|
|
158
|
-
| GET | `/runtime` | Detected runtime info
|
|
159
|
-
| GET | `/containers` | List managed containers
|
|
160
|
-
| GET | `/containers/:name/state` | Container state
|
|
161
|
-
| POST | `/containers/:name/start` | Start a stopped container
|
|
162
|
-
| POST | `/containers/:name/stop` | Stop a running container
|
|
163
|
-
| POST | `/containers/:name/remove` | Stop and remove a container
|
|
164
|
-
| GET | `/containers/:name/logs?tail=N&since=ts` | Last N lines of the container's combined stdout+stderr log (one-shot). `tail` defaults 200, max 10000
|
|
165
|
-
| GET | `/containers/:name/logs/stream` | Server-Sent Events stream of live log lines. Closes when the container is removed or the client disconnects
|
|
166
|
-
| POST | `/prune` | Prune dangling images
|
|
167
|
-
| GET | `/updates` | List last update-check results
|
|
168
|
-
| GET | `/updates/:pluginId` | Last update-check result for one plugin
|
|
169
|
-
| POST | `/updates/:pluginId/check` | Force a fresh update check (HTTP 200 even when offline)
|
|
170
|
-
| GET | `/containers/:name/resources` | Effective resource limits + user override
|
|
171
|
-
| POST | `/containers/:name/resources` | Apply new resource limits (live or recreate). Body is a `ContainerResourceLimits` diff against the consumer plugin's default.
|
|
172
|
-
| DELETE | `/containers/:name/resources` | Clear any user override and restore the consumer plugin's pristine default limits to the running container.
|
|
173
|
-
| POST | `/doctor/image` | Probe whether an image runs cleanly under the live host-UID mapping. Body: `{ image, tag?, user? }`. Never 5xx for a failed probe — `{ ok: false, error }` is a successful response (1.8.0+).
|
|
158
|
+
| Method | Path | Description |
|
|
159
|
+
| ------ | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
160
|
+
| GET | `/runtime` | Detected runtime info |
|
|
161
|
+
| GET | `/containers` | List managed containers |
|
|
162
|
+
| GET | `/containers/:name/state` | Container state |
|
|
163
|
+
| POST | `/containers/:name/start` | Start a stopped container |
|
|
164
|
+
| POST | `/containers/:name/stop` | Stop a running container |
|
|
165
|
+
| POST | `/containers/:name/remove` | Stop and remove a container |
|
|
166
|
+
| GET | `/containers/:name/logs?tail=N&since=ts` | Last N lines of the container's combined stdout+stderr log (one-shot). `tail` defaults 200, max 10000 |
|
|
167
|
+
| GET | `/containers/:name/logs/stream` | Server-Sent Events stream of live log lines. Closes when the container is removed or the client disconnects |
|
|
168
|
+
| POST | `/prune` | Prune dangling images |
|
|
169
|
+
| GET | `/updates` | List last update-check results |
|
|
170
|
+
| GET | `/updates/:pluginId` | Last update-check result for one plugin |
|
|
171
|
+
| POST | `/updates/:pluginId/check` | Force a fresh update check (HTTP 200 even when offline) |
|
|
172
|
+
| GET | `/containers/:name/resources` | Effective resource limits + user override |
|
|
173
|
+
| POST | `/containers/:name/resources` | Apply new resource limits (live or recreate). Body is a `ContainerResourceLimits` diff against the consumer plugin's default. |
|
|
174
|
+
| DELETE | `/containers/:name/resources` | Clear any user override and restore the consumer plugin's pristine default limits to the running container. |
|
|
175
|
+
| POST | `/doctor/image` | Probe whether an image runs cleanly under the live host-UID mapping. Body: `{ image, tag?, user? }`. Never 5xx for a failed probe — `{ ok: false, error }` is a successful response (1.8.0+). |
|
|
176
|
+
| GET | `/doctor/deployment` | Diagnose this Signal K deployment: binary discovery, daemon reachability, rootless/rootful detection, self-container ID cascade. Returns a `SelfDeploymentResult` with `status` and copy-pasteable `remediation` lines. |
|
|
177
|
+
| GET | `/doctor/snippet?format=compose\|run` | Generate a ready-to-paste compose fragment or shell command for setting up Signal K with this runtime. `text/plain` by default; pass `Accept: application/json` for the structured `SetupSnippetResult`. |
|
|
174
178
|
|
|
175
179
|
## Configuration
|
|
176
180
|
|
|
@@ -448,45 +452,107 @@ this plugin needs access to the host's container runtime to manage other
|
|
|
448
452
|
containers. The plugin auto-detects this scenario via `/.dockerenv` or
|
|
449
453
|
`/run/.containerenv` and prefixes the status with `(in-container)`.
|
|
450
454
|
|
|
451
|
-
For the plugin to work,
|
|
452
|
-
|
|
455
|
+
For the plugin to work, two things must be true inside the Signal K
|
|
456
|
+
container:
|
|
453
457
|
|
|
454
|
-
|
|
458
|
+
1. **The runtime CLI is installed.** Bake `podman` (or `podman-remote`)
|
|
459
|
+
into your Signal K image — this is the recommended path. As a quick
|
|
460
|
+
alternative you can bind-mount the host binary read-only, but that
|
|
461
|
+
couples the container to the host's exact runtime version.
|
|
462
|
+
2. **The runtime socket is bind-mounted** from the host (rootless or
|
|
463
|
+
rootful, podman or docker — see examples below).
|
|
464
|
+
|
|
465
|
+
### Quick check: `/api/doctor/deployment`
|
|
466
|
+
|
|
467
|
+
The plugin ships a self-diagnostic. After starting, hit:
|
|
468
|
+
|
|
469
|
+
```bash
|
|
470
|
+
curl http://<signalk-host>:3000/plugins/signalk-container/api/doctor/deployment
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
The response includes a `status` field (`ok` / `no-runtime` /
|
|
474
|
+
`socket-unreachable` / `permission-denied` / `self-id-unresolved`) and a
|
|
475
|
+
`remediation` array of copy-pasteable lines for whichever failure mode
|
|
476
|
+
applies. When startup detection fails, the same remediation is also
|
|
477
|
+
logged to the Signal K server log.
|
|
478
|
+
|
|
479
|
+
### Generate a starter snippet
|
|
480
|
+
|
|
481
|
+
To bootstrap a new deployment, ask the plugin for a ready-to-paste
|
|
482
|
+
compose fragment or shell command tailored to the detected runtime:
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
curl 'http://<signalk-host>:3000/plugins/signalk-container/api/doctor/snippet?format=compose' > docker-compose.yml
|
|
486
|
+
curl 'http://<signalk-host>:3000/plugins/signalk-container/api/doctor/snippet?format=run' > run-signalk.sh
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
The endpoint returns plain text by default; pass
|
|
490
|
+
`Accept: application/json` to get the structured
|
|
491
|
+
`SetupSnippetResult` (snippet + Dockerfile sidecar + operator notes)
|
|
492
|
+
for programmatic consumers.
|
|
493
|
+
|
|
494
|
+
### Rootless Podman (recommended)
|
|
495
|
+
|
|
496
|
+
The cleanest setup. Runs as your user, not root, so the security
|
|
497
|
+
exposure is limited to your user account rather than the entire host —
|
|
498
|
+
and matches signalk-container's default behaviour.
|
|
499
|
+
|
|
500
|
+
On the host, ensure the user-scoped podman socket is enabled:
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
systemctl --user enable --now podman.socket
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
Then in your compose / `podman run`:
|
|
455
507
|
|
|
456
508
|
```yaml
|
|
457
509
|
services:
|
|
458
510
|
signalk:
|
|
459
|
-
image: signalk
|
|
511
|
+
image: your-signalk-image-with-podman-remote
|
|
512
|
+
user: "${UID}:${GID}" # match the uid that owns the host's podman socket
|
|
460
513
|
volumes:
|
|
461
|
-
- /
|
|
462
|
-
|
|
514
|
+
- /run/user/${UID}/podman/podman.sock:/run/user/${UID}/podman/podman.sock
|
|
515
|
+
environment:
|
|
516
|
+
- CONTAINER_HOST=unix:///run/user/${UID}/podman/podman.sock
|
|
463
517
|
```
|
|
464
518
|
|
|
465
|
-
|
|
466
|
-
it from the host as shown above. Containers managed by the plugin
|
|
467
|
-
become **siblings** of the Signal K container, not nested.
|
|
519
|
+
Your image's Dockerfile should include `podman` or `podman-remote`:
|
|
468
520
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
521
|
+
```dockerfile
|
|
522
|
+
RUN apt-get update && apt-get install -y podman # Debian/Ubuntu
|
|
523
|
+
# or:
|
|
524
|
+
RUN dnf install -y podman-remote # Fedora/RHEL
|
|
525
|
+
```
|
|
474
526
|
|
|
475
|
-
### Podman
|
|
527
|
+
### Rootful Podman
|
|
476
528
|
|
|
477
529
|
```yaml
|
|
478
530
|
services:
|
|
479
531
|
signalk:
|
|
480
|
-
image: signalk
|
|
532
|
+
image: your-signalk-image-with-podman
|
|
481
533
|
volumes:
|
|
482
|
-
-
|
|
483
|
-
- /usr/bin/podman:/usr/bin/podman:ro
|
|
534
|
+
- /run/podman/podman.sock:/run/podman/podman.sock
|
|
484
535
|
environment:
|
|
485
|
-
-
|
|
536
|
+
- CONTAINER_HOST=unix:///run/podman/podman.sock
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### Docker
|
|
540
|
+
|
|
541
|
+
```yaml
|
|
542
|
+
services:
|
|
543
|
+
signalk:
|
|
544
|
+
image: your-signalk-image-with-docker-cli
|
|
545
|
+
volumes:
|
|
546
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
|
547
|
+
group_add:
|
|
548
|
+
- "<docker-gid-from-host>" # `getent group docker | cut -d: -f3`
|
|
486
549
|
```
|
|
487
550
|
|
|
488
|
-
|
|
489
|
-
|
|
551
|
+
> [!warning]
|
|
552
|
+
> Mounting `/var/run/docker.sock` gives the container **root-equivalent
|
|
553
|
+
> access to the host**. Anyone who compromises Signal K (including via
|
|
554
|
+
> a malicious plugin) can take over the entire host. Prefer rootless
|
|
555
|
+
> Podman for production.
|
|
490
556
|
|
|
491
557
|
### Networking caveats
|
|
492
558
|
|
|
@@ -502,12 +568,6 @@ network namespace. This affects:
|
|
|
502
568
|
to Docker containers automatically (Podman already provides it); set
|
|
503
569
|
`ContainerConfig.extraHosts` to override it or to add other hostnames.
|
|
504
570
|
|
|
505
|
-
### Recommended setup
|
|
506
|
-
|
|
507
|
-
For the simplest experience with managed containers, run **Signal K
|
|
508
|
-
natively on the host** rather than in a container. The plugin and its
|
|
509
|
-
ecosystem (signalk-questdb, signalk-grafana) are designed for this case.
|
|
510
|
-
|
|
511
571
|
## License
|
|
512
572
|
|
|
513
573
|
MIT
|
package/dist/containers.d.ts
CHANGED
|
@@ -363,6 +363,13 @@ export declare function getLiveContainerConfig(runtime: ContainerRuntimeInfo, na
|
|
|
363
363
|
export declare function diffContainerConfig(requested: ContainerConfig, live: LiveContainerConfig, runtime: ContainerRuntimeInfo, prior?: ContainerConfig): {
|
|
364
364
|
drifted: string[];
|
|
365
365
|
};
|
|
366
|
+
/**
|
|
367
|
+
* Pull function injected into `ensureRunning` for testability. Production
|
|
368
|
+
* uses the module-level `pullImage` (which shells out via `execRuntimeLong`,
|
|
369
|
+
* not the injectable `ExecFn`). Tests pass a stub to assert call counts
|
|
370
|
+
* and simulate offline failures without touching the network.
|
|
371
|
+
*/
|
|
372
|
+
type PullFn = (runtime: ContainerRuntimeInfo, image: string, onProgress?: (msg: string) => void) => Promise<void>;
|
|
366
373
|
export declare function ensureRunning(runtime: ContainerRuntimeInfo, name: string, config: ContainerConfig, debug: (msg: string) => void, options?: HealthCheckOptions, exec?: ExecFn,
|
|
367
374
|
/**
|
|
368
375
|
* Prior `ContainerConfig` from the previous `ensureRunning` call within
|
|
@@ -372,7 +379,7 @@ export declare function ensureRunning(runtime: ContainerRuntimeInfo, name: strin
|
|
|
372
379
|
* overwriting it; on the first call (or after a Signal K restart) this
|
|
373
380
|
* will be undefined and only positive drift is detected.
|
|
374
381
|
*/
|
|
375
|
-
prior?: ContainerConfig, _postRecreate?: boolean): Promise<void>;
|
|
382
|
+
prior?: ContainerConfig, _postRecreate?: boolean, _pull?: PullFn): Promise<void>;
|
|
376
383
|
export declare function startContainer(runtime: ContainerRuntimeInfo, name: string): Promise<void>;
|
|
377
384
|
export declare function stopContainer(runtime: ContainerRuntimeInfo, name: string): Promise<void>;
|
|
378
385
|
export declare function removeContainer(runtime: ContainerRuntimeInfo, name: string, exec?: ExecFn): Promise<void>;
|
|
@@ -593,4 +600,5 @@ export declare function findAvailablePort(preferred: number): Promise<number>;
|
|
|
593
600
|
*/
|
|
594
601
|
export declare function resolveSignalkNetworks(runtime: ContainerRuntimeInfo, debug?: (msg: string) => void): Promise<string[] | null>;
|
|
595
602
|
export declare function waitForReady(url: string, timeoutMs?: number, intervalMs?: number): Promise<void>;
|
|
603
|
+
export {};
|
|
596
604
|
//# sourceMappingURL=containers.d.ts.map
|
package/dist/containers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containers.d.ts","sourceRoot":"","sources":["../src/containers.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,UAAU,EACX,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,sBAAsB,EAItB,qBAAqB,EAEtB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"containers.d.ts","sourceRoot":"","sources":["../src/containers.ts"],"names":[],"mappings":"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"}
|
package/dist/containers.js
CHANGED
|
@@ -2,6 +2,8 @@ import * as net from "node:net";
|
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { execRuntime, execRuntimeLong, isContainerized, spawnRuntimeStreaming, userMappingFlags, } from "./runtime.js";
|
|
4
4
|
import { resourceFlagsForRun } from "./resources.js";
|
|
5
|
+
import { classifyTag } from "./updates/tagClassifier.js";
|
|
6
|
+
import { isOfflineError } from "./updates/offline.js";
|
|
5
7
|
const CONTAINER_PREFIX = "sk-";
|
|
6
8
|
function prefixedName(name) {
|
|
7
9
|
return name.startsWith(CONTAINER_PREFIX)
|
|
@@ -1147,7 +1149,7 @@ export async function ensureRunning(runtime, name, config, debug, options, exec
|
|
|
1147
1149
|
* overwriting it; on the first call (or after a Signal K restart) this
|
|
1148
1150
|
* will be undefined and only positive drift is detected.
|
|
1149
1151
|
*/
|
|
1150
|
-
prior, _postRecreate = false) {
|
|
1152
|
+
prior, _postRecreate = false, _pull = pullImage) {
|
|
1151
1153
|
const state = await getContainerState(runtime, name, exec);
|
|
1152
1154
|
const fullName = prefixedName(name);
|
|
1153
1155
|
const imageRef = qualifyImage(config.digest
|
|
@@ -1167,7 +1169,48 @@ prior, _postRecreate = false) {
|
|
|
1167
1169
|
return false;
|
|
1168
1170
|
debug(`Container ${fullName} config drift detected (${drifted.join(", ")}); recreating`);
|
|
1169
1171
|
await removeContainer(runtime, name, exec);
|
|
1170
|
-
await ensureRunning(runtime, name, config, debug, options, exec, prior, true);
|
|
1172
|
+
await ensureRunning(runtime, name, config, debug, options, exec, prior, true, _pull);
|
|
1173
|
+
return true;
|
|
1174
|
+
};
|
|
1175
|
+
// Floating-tag digest drift: pull the tag, compare the registry-fresh
|
|
1176
|
+
// image-id to the running container's image-id, treat a mismatch as drift.
|
|
1177
|
+
// Skipped silently on offline or any pull/inspect error — update probing
|
|
1178
|
+
// must never block startup. `config.digest` set means the caller already
|
|
1179
|
+
// pins to a digest; nothing to probe.
|
|
1180
|
+
const checkAndRecreateOnDigestDrift = async () => {
|
|
1181
|
+
if (!config.autoUpdateOnFloatingTag)
|
|
1182
|
+
return false;
|
|
1183
|
+
if (config.digest)
|
|
1184
|
+
return false;
|
|
1185
|
+
if (classifyTag(config.tag) !== "floating")
|
|
1186
|
+
return false;
|
|
1187
|
+
const fullImage = `${config.image}:${config.tag}`;
|
|
1188
|
+
try {
|
|
1189
|
+
await _pull(runtime, qualifyImage(fullImage, runtime), debug);
|
|
1190
|
+
}
|
|
1191
|
+
catch (err) {
|
|
1192
|
+
if (isOfflineError(err)) {
|
|
1193
|
+
debug(`Container ${fullName} floating-tag digest check skipped (offline)`);
|
|
1194
|
+
}
|
|
1195
|
+
else {
|
|
1196
|
+
debug(`Container ${fullName} floating-tag digest check skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
1197
|
+
}
|
|
1198
|
+
return false;
|
|
1199
|
+
}
|
|
1200
|
+
// Compare image-ids (local content-store hash), not manifest digests.
|
|
1201
|
+
// `getImageDigest` returns the local `.Id` for both an `image:tag` ref
|
|
1202
|
+
// and a container name (via `.Image` on the container) — like-for-like.
|
|
1203
|
+
// Mixing in a `RepoDigest`-based identity here would always show drift
|
|
1204
|
+
// because RepoDigest and image-id are different namespaces. The same
|
|
1205
|
+
// image-id-vs-image-id comparison is what updates/service.ts uses.
|
|
1206
|
+
const remoteId = await getImageDigest(runtime, qualifyImage(fullImage, runtime), exec);
|
|
1207
|
+
const liveId = await getImageDigest(runtime, prefixedName(name), exec);
|
|
1208
|
+
if (!remoteId || !liveId || remoteId === liveId) {
|
|
1209
|
+
return false;
|
|
1210
|
+
}
|
|
1211
|
+
debug(`Container ${fullName} floating-tag digest drift detected (${liveId.slice(0, 19)}… → ${remoteId.slice(0, 19)}…); recreating`);
|
|
1212
|
+
await removeContainer(runtime, name, exec);
|
|
1213
|
+
await ensureRunning(runtime, name, config, debug, options, exec, prior, true, _pull);
|
|
1171
1214
|
return true;
|
|
1172
1215
|
};
|
|
1173
1216
|
switch (state) {
|
|
@@ -1180,6 +1223,8 @@ prior, _postRecreate = false) {
|
|
|
1180
1223
|
}
|
|
1181
1224
|
if (await checkAndRecreateOnDrift("already running"))
|
|
1182
1225
|
return;
|
|
1226
|
+
if (await checkAndRecreateOnDigestDrift())
|
|
1227
|
+
return;
|
|
1183
1228
|
debug(`Container ${fullName} already running`);
|
|
1184
1229
|
return;
|
|
1185
1230
|
}
|
|
@@ -1196,6 +1241,8 @@ prior, _postRecreate = false) {
|
|
|
1196
1241
|
}
|
|
1197
1242
|
if (await checkAndRecreateOnDrift("stopped"))
|
|
1198
1243
|
return;
|
|
1244
|
+
if (await checkAndRecreateOnDigestDrift())
|
|
1245
|
+
return;
|
|
1199
1246
|
debug(`Starting stopped container ${fullName}`);
|
|
1200
1247
|
const startResult = await exec(runtime, ["start", fullName]);
|
|
1201
1248
|
if (startResult.exitCode !== 0) {
|