signalk-container 1.17.0 → 1.19.0
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/README.md +87 -1
- package/dist/containers.d.ts +56 -2
- package/dist/containers.d.ts.map +1 -1
- package/dist/containers.js +136 -4
- package/dist/containers.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -11
- package/dist/index.js.map +1 -1
- package/dist/jobs.d.ts.map +1 -1
- package/dist/jobs.js +6 -0
- package/dist/jobs.js.map +1 -1
- package/dist/types.d.ts +95 -0
- package/dist/types.d.ts.map +1 -1
- package/doc/plugin-developer-guide.md +36 -2
- package/package.json +1 -1
- package/public/chunks/_virtual_mf-localSharedImportMap___mfe_internal__signalk_container-B5hUF6Hj.js +1 -0
- package/public/chunks/hostInit-QCfJ3xgy.js +1 -0
- package/public/chunks/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__signalk_container__remoteEntry_js-BxaYmhe5.js +4 -0
- package/public/configpanel-entry.js +1 -1
- package/public/remoteEntry.js +1 -1
- package/public/chunks/_virtual_mf-localSharedImportMap___mfe_internal__signalk_container-BEsDhqjG.js +0 -1
- package/public/chunks/dist-B5XYILWI.js +0 -4
- package/public/chunks/hostInit-B3-ZMCBI.js +0 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Instead of each plugin implementing its own container orchestration, they delega
|
|
|
14
14
|
- **Update detection** -- centralized "is there a newer image?" service for all consumer plugins. Auto-detects semver vs floating tags (`:latest`, `:main`), offline-tolerant with persistent cache, emits Signal K notifications, visible inline in the config panel. See the [developer guide](doc/plugin-developer-guide.md#update-detection).
|
|
15
15
|
- **Resource limits editor** -- interactive UI in the config panel for setting CPU/memory/PID caps per container. Values are applied live via `podman update` when possible (no downtime), falls back to recreate when needed. Stored overrides are minimized against the consumer plugin's defaults so a future default bump flows through automatically. See the [developer guide](doc/plugin-developer-guide.md#resource-limits).
|
|
16
16
|
- **Reset to plugin default** -- one-click restore of a container's original resource limits, clearing any user override.
|
|
17
|
-
- **Per-process ulimits** -- `ContainerConfig.ulimits` pins per-process limits (`nofile`, `nproc`, …) on a container. A containerized process inherits these from the runtime, not the host sysctl, so raising the host `fs.file-max` alone does not lift a database's open-files limit; setting `ulimits` does. See the [developer guide](doc/plugin-developer-guide.md#per-process-ulimits-nofile-).
|
|
17
|
+
- **Per-process ulimits** -- `ContainerConfig.ulimits` pins per-process limits (`nofile`, `nproc`, …) on a container. A containerized process inherits these from the runtime, not the host sysctl, so raising the host `fs.file-max` alone does not lift a database's open-files limit; setting `ulimits` does. A `nofile` request over the host ceiling is clamped (not rejected) so the container still starts. See the [developer guide](doc/plugin-developer-guide.md#per-process-ulimits-nofile-) and, for raising the host limit, [Raising the open-files limit](#raising-the-open-files-limit-nofile).
|
|
18
18
|
- **Image management** -- scheduled pruning of dangling images (weekly/monthly)
|
|
19
19
|
- **Zero-config data dir sharing** -- `signalkDataMount` mounts the SignalK data directory into any managed container automatically, whether Signal K runs bare-metal, in Docker (named volume), or in Podman (named volume or bind mount). No host paths to configure.
|
|
20
20
|
- **Zero-config config root sharing** -- `signalkConfigRootMount` mounts the entire SignalK installation config (`~/.signalk/`) — for backup, audit, or config-sync tools that need the whole tree, not the per-plugin subdirectory.
|
|
@@ -23,6 +23,7 @@ Instead of each plugin implementing its own container orchestration, they delega
|
|
|
23
23
|
- **Per-volume host-source policy** -- volumes accept `{ source, ifMissing: "skip" | "abort" }` for user-managed (USB drives, NFS) or deployment-required (TLS certs) mounts. Plugins subscribe to `onVolumeIssue` events for `'skipped'`, `'aborted'`, and `'recovered'` actions; signalk-container auto-recreates the container when a previously-missing source reappears. See the [developer guide](doc/plugin-developer-guide.md#optional-and-required-volumes).
|
|
24
24
|
- **Container log streaming** -- click **Logs** on any managed-container card to open a live-streaming popup of the container's stdout+stderr (combined, the same shape `podman logs <name>` produces). Plugin authors can also wire `onContainerLog` in `ensureRunning` options to forward the same stream into their plugin's `app.debug` channel — visible in the Signal K server log when debug is enabled. Multiple subscribers share a single underlying log stream. See the [developer guide](doc/plugin-developer-guide.md#streaming-container-logs-into-your-plugins-debug-channel).
|
|
25
25
|
- **Host-UID ownership alignment** -- managed containers run by default under the Signal K host user's UID/GID (via `--user host:host` on Docker/rootful Podman, `--userns=keep-id` on rootless Podman). Files created on bind mounts are owned by the same identity that runs Signal K, with no `chmod` sweeps. Override per container via `ContainerConfig.user` for images with a non-root `USER` directive, or `user: false` to opt out. See the [developer guide](doc/plugin-developer-guide.md#host-uid-ownership).
|
|
26
|
+
- **Data-directory teardown** -- `containers.removeManagedData(name, hostPath)` removes a managed container _and_ deletes its bind-mount data, even on rootless Podman where a container process running as a non-root in-container UID writes files owned by a host **subuid** the Signal K user can't `rm`. The host-side delete is tried first (docker / rootful); on EACCES it falls back to an in-userns wipe using the container's own image (no extra pull). Use it for plugin uninstall cleanup. See the [developer guide](doc/plugin-developer-guide.md#removemanageddataname-hostpath-options-promisevoid).
|
|
26
27
|
- **Image compliance probes** -- `containers.doctor.imageRunsAsUser(image, user?)` runs the image under the live UID mapping and verifies it can write `/tmp` as the host caller. Surfaces UID-compatibility problems _before_ a container wedges in a restart loop. See the [developer guide](doc/plugin-developer-guide.md#containersdoctorimagerunsasuserimage-user-promiseimageproberesult).
|
|
27
28
|
- **Podman image qualification** -- automatically prefixes `docker.io/` for short image names
|
|
28
29
|
- **Docker `host.containers.internal` parity** -- signalk-container adds the `host-gateway` mapping for Docker automatically (Podman has it natively). User-supplied `extraHosts` overrides are respected.
|
|
@@ -272,6 +273,91 @@ The deployment doctor at `/api/doctor/deployment` also detects this
|
|
|
272
273
|
scenario and surfaces the same kernel-cmdline fix in its `remediation`
|
|
273
274
|
array, so you don't have to guess which layer is broken first.
|
|
274
275
|
|
|
276
|
+
### Raising the open-files limit (`nofile`)
|
|
277
|
+
|
|
278
|
+
Some managed containers ask for a high per-process open-files limit
|
|
279
|
+
(`RLIMIT_NOFILE`). QuestDB is the common case — it recommends
|
|
280
|
+
`nofile=1048576` and otherwise logs an open-files warning and risks WAL
|
|
281
|
+
corruption under heavy ingestion.
|
|
282
|
+
|
|
283
|
+
A containerized process inherits `nofile` from the **container runtime**,
|
|
284
|
+
not from the host's `fs.file-max` sysctl — so raising `fs.file-max` does
|
|
285
|
+
**not** help here. And under **rootless Podman** a container can never
|
|
286
|
+
raise its hard limit above the limit of the user that runs the runtime.
|
|
287
|
+
When a plugin requests more than the host allows, signalk-container clamps
|
|
288
|
+
the request to the host ceiling so the container still starts (you'll see
|
|
289
|
+
an advisory in the requesting plugin's config panel, e.g. QuestDB's
|
|
290
|
+
"open-files limit capped by the host"). To grant the full value, raise the
|
|
291
|
+
host limit.
|
|
292
|
+
|
|
293
|
+
**Check the limit the container actually got:**
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
# podman, or `docker exec` on Docker
|
|
297
|
+
podman exec <sk-container> cat /proc/1/limits | grep -i "open files"
|
|
298
|
+
# Max open files 524288 524288 ← the per-process cap in effect
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Rootless Podman** runs under the systemd user session, so the lever is the
|
|
302
|
+
user manager's open-files limit, which a rootless container can never exceed.
|
|
303
|
+
There are two places to set it; on stock Debian / Raspberry Pi OS you usually
|
|
304
|
+
need the **second**. Editing `/etc/security/limits.conf` does **not** help —
|
|
305
|
+
`pam_limits` only touches login shells, not the user manager that parents the
|
|
306
|
+
podman socket. `LimitNOFILE` takes a `soft:hard` form; a single number sets
|
|
307
|
+
soft = hard, and the container's hard ceiling is the user manager's _hard_
|
|
308
|
+
limit.
|
|
309
|
+
|
|
310
|
+
**1. Per-user-manager drop-in.** One-time, requires sudo:
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
sudo mkdir -p /etc/systemd/system/user@.service.d
|
|
314
|
+
sudo tee /etc/systemd/system/user@.service.d/nofile.conf <<'EOF'
|
|
315
|
+
[Service]
|
|
316
|
+
LimitNOFILE=1048576
|
|
317
|
+
EOF
|
|
318
|
+
sudo systemctl daemon-reload
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
The new limit only applies once the **user manager itself restarts** — and
|
|
322
|
+
`daemon-reload` does **not** restart an already-running `user@<uid>.service`.
|
|
323
|
+
On a headless boat the SK user has linger enabled (`loginctl enable-linger`),
|
|
324
|
+
so logging out and back in does not tear it down. Force a fresh user manager,
|
|
325
|
+
then restart the container:
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
sudo systemctl restart user@$(id -u <sk-user>).service # or just reboot
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**2. System-wide default (Raspberry Pi OS / openplotter, and the reliable
|
|
332
|
+
fallback).** Stock Debian / Pi OS ships `/etc/systemd/system.conf` with a
|
|
333
|
+
commented `#DefaultLimitNOFILE=1024:524288` — that 524288 _hard_ default is
|
|
334
|
+
what bounds the per-unit request when step 1 doesn't take. Raise the system
|
|
335
|
+
(PID 1) manager's default directly:
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
sudo sed -i 's/^#\?DefaultLimitNOFILE=.*/DefaultLimitNOFILE=1048576:1048576/' /etc/systemd/system.conf
|
|
339
|
+
sudo systemctl daemon-reexec # NOT daemon-reload — manager-global defaults
|
|
340
|
+
# are only re-read when PID 1 re-executes itself
|
|
341
|
+
sudo reboot # respawns the lingering user@.service + podman
|
|
342
|
+
# under the raised default
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Rootful Podman / Docker** read the limit from the daemon's own service.
|
|
346
|
+
For Docker, set `LimitNOFILE=1048576` in a `docker.service` drop-in
|
|
347
|
+
(`/etc/systemd/system/docker.service.d/nofile.conf`), `daemon-reload`, and
|
|
348
|
+
restart the daemon.
|
|
349
|
+
|
|
350
|
+
The value cannot exceed the kernel's absolute per-process cap, `fs.nr_open`
|
|
351
|
+
(`cat /proc/sys/fs/nr_open` — typically ~1 billion, so not a practical limit).
|
|
352
|
+
Verify (either path):
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
systemctl show user@$(id -u <sk-user>).service -p LimitNOFILE
|
|
356
|
+
# LimitNOFILE=1048576 ← the user manager now allows it
|
|
357
|
+
<runtime> exec <sk-container> cat /proc/1/limits | grep -i "open files"
|
|
358
|
+
# Max open files 1048576 1048576 ← the container actually got it
|
|
359
|
+
```
|
|
360
|
+
|
|
275
361
|
### Watch out for systemd auto-restart (Quadlet / `Restart=always`)
|
|
276
362
|
|
|
277
363
|
If you run Signal K via a podman Quadlet (`*.container` in
|
package/dist/containers.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type Docker from "dockerode";
|
|
2
|
-
import { ContainerConfig, ContainerInfo, ContainerRuntimeInfo, ContainerState,
|
|
2
|
+
import { ContainerConfig, ContainerInfo, ContainerRuntimeInfo, ContainerState, EnsureRunningOptions, UlimitClamp, VolumeIssue, VolumeSpec } from "./types.js";
|
|
3
3
|
import { StreamingProcessHandle } from "./runtime.js";
|
|
4
4
|
import { type ContainerClient } from "./client.js";
|
|
5
5
|
/**
|
|
@@ -126,6 +126,11 @@ export declare function safeInvokeVolumeIssue(handler: ((event: VolumeIssue) =>
|
|
|
126
126
|
* is needed.
|
|
127
127
|
*/
|
|
128
128
|
export declare function safeInvokeContainerLog(handler: ((line: string) => void | Promise<void>) | undefined, line: string, reportError: (err: unknown) => void): void;
|
|
129
|
+
/**
|
|
130
|
+
* Invoke an `onUlimitClamped` callback safely. Same shape and rationale
|
|
131
|
+
* as `safeInvokeVolumeIssue` — see that helper's doc.
|
|
132
|
+
*/
|
|
133
|
+
export declare function safeInvokeUlimitClamped(handler: ((event: UlimitClamp) => void | Promise<void>) | undefined, event: UlimitClamp, reportError: (err: unknown) => void): void;
|
|
129
134
|
/**
|
|
130
135
|
* Spawn `podman logs -f --tail=N sk-<name>` (or `docker logs -f`)
|
|
131
136
|
* and emit each line to `onLine`. Returns a stop-handle; the caller
|
|
@@ -446,7 +451,7 @@ export declare function ulimitsForRun(ulimits: ContainerConfig["ulimits"], nofil
|
|
|
446
451
|
* without touching the network.
|
|
447
452
|
*/
|
|
448
453
|
type PullFn = (runtime: ContainerRuntimeInfo, image: string, onProgress?: (msg: string) => void) => Promise<void>;
|
|
449
|
-
export declare function ensureRunning(runtime: ContainerRuntimeInfo, name: string, config: ContainerConfig, debug: (msg: string) => void, options?:
|
|
454
|
+
export declare function ensureRunning(runtime: ContainerRuntimeInfo, name: string, config: ContainerConfig, debug: (msg: string) => void, options?: EnsureRunningOptions, client?: ContainerClient,
|
|
450
455
|
/**
|
|
451
456
|
* Prior `ContainerConfig` from the previous `ensureRunning` call within
|
|
452
457
|
* this signalk-container lifetime, if any. Used to detect "unset" drift
|
|
@@ -459,6 +464,55 @@ prior?: ContainerConfig, _postRecreate?: boolean, _pull?: PullFn): Promise<void>
|
|
|
459
464
|
export declare function startContainer(runtime: ContainerRuntimeInfo, name: string, client?: ContainerClient): Promise<void>;
|
|
460
465
|
export declare function stopContainer(runtime: ContainerRuntimeInfo, name: string, client?: ContainerClient): Promise<void>;
|
|
461
466
|
export declare function removeContainer(runtime: ContainerRuntimeInfo, name: string, client?: ContainerClient): Promise<void>;
|
|
467
|
+
/**
|
|
468
|
+
* Reject host paths that must never be recursively wiped. The guard is the
|
|
469
|
+
* cheap, always-correct floor (empty / `/` / a non-absolute path); the
|
|
470
|
+
* caller layers any deployment-specific "must be under the Signal K tree"
|
|
471
|
+
* check on top, where it has the data/config roots to compare against.
|
|
472
|
+
*/
|
|
473
|
+
export declare function assertWipablePath(hostPath: string): void;
|
|
474
|
+
/**
|
|
475
|
+
* Result of one wipe-job run, mirroring the bits of `ContainerJobResult`
|
|
476
|
+
* that `removeManagedData` reasons about. Keeps `containers.ts` free of a
|
|
477
|
+
* `jobs.ts` import (jobs.ts already imports from here — the cycle would be
|
|
478
|
+
* real) while staying fully testable via an injected runner.
|
|
479
|
+
*/
|
|
480
|
+
export interface WipeJobOutcome {
|
|
481
|
+
ok: boolean;
|
|
482
|
+
error?: string;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Delete a managed container's bind-mount data, working around the
|
|
486
|
+
* rootless-Podman subuid-ownership trap.
|
|
487
|
+
*
|
|
488
|
+
* Sequence:
|
|
489
|
+
* 1. Remove the container `name` (idempotent — a missing container is fine)
|
|
490
|
+
* so nothing holds the mount.
|
|
491
|
+
* 2. Try a direct host-side `fs.rm(hostPath, {recursive, force})`. On
|
|
492
|
+
* docker / rootful Podman the files are host-owned and this succeeds.
|
|
493
|
+
* 3. On EACCES/EPERM (the rootless-Podman case — files are owned by a
|
|
494
|
+
* subuid the host user can't touch) run `runWipeJob`: a one-shot helper
|
|
495
|
+
* that bind-mounts `hostPath` and `rm -rf`s its CONTENTS from inside the
|
|
496
|
+
* userns as in-container root, then retry the host-side delete to drop
|
|
497
|
+
* the now-empty host-owned parent dir.
|
|
498
|
+
*
|
|
499
|
+
* `runWipeJob(image, hostPath)` is injected so the runtime logic stays out
|
|
500
|
+
* of the `jobs.ts` import cycle and so unit tests can drive every branch
|
|
501
|
+
* without a real runtime. The wrapper in `index.ts` wires it to `runJob`
|
|
502
|
+
* with the container's own (already-present) image.
|
|
503
|
+
*
|
|
504
|
+
* `wipeImage` is the container's own image, captured from `inspect` BEFORE
|
|
505
|
+
* removal so the helper reuses bits already on disk — no registry pull on a
|
|
506
|
+
* possibly-offline boat. `null` when the container was already gone; the
|
|
507
|
+
* fallback then can't run, so a still-undeletable dir surfaces as an error.
|
|
508
|
+
*/
|
|
509
|
+
export declare function removeManagedData(runtime: ContainerRuntimeInfo, name: string, hostPath: string, runWipeJob: (image: string, hostPath: string) => Promise<WipeJobOutcome>, client?: ContainerClient, onRemoved?: () => void): Promise<void>;
|
|
510
|
+
/**
|
|
511
|
+
* Container path the wipe helper mounts the data directory at — re-exported
|
|
512
|
+
* for the wrapper that builds the `runJob` config and for tests asserting the
|
|
513
|
+
* mount/command shape.
|
|
514
|
+
*/
|
|
515
|
+
export declare const WIPE_MOUNT_PATH = "/sk-wipe-target";
|
|
462
516
|
export declare function listContainers(runtime: ContainerRuntimeInfo, client?: ContainerClient): Promise<ContainerInfo[]>;
|
|
463
517
|
export declare function pruneImages(runtime: ContainerRuntimeInfo, client?: ContainerClient): Promise<{
|
|
464
518
|
imagesRemoved: number;
|
package/dist/containers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containers.d.ts","sourceRoot":"","sources":["../src/containers.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"containers.d.ts","sourceRoot":"","sources":["../src/containers.ts"],"names":[],"mappings":"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"}
|
package/dist/containers.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as net from "node:net";
|
|
2
|
+
import * as path from "node:path";
|
|
2
3
|
import { PassThrough } from "node:stream";
|
|
3
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { rm } from "node:fs/promises";
|
|
4
6
|
import { isContainerized, makeLineSplitter, userMappingFlags, } from "./runtime.js";
|
|
5
7
|
import { demuxToText, demuxBufferToText, getClient, safe, safeInspect, } from "./client.js";
|
|
6
8
|
import { resourcePayloadForRun } from "./resources.js";
|
|
@@ -209,6 +211,20 @@ export function safeInvokeContainerLog(handler, line, reportError) {
|
|
|
209
211
|
reportError(err);
|
|
210
212
|
}
|
|
211
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* Invoke an `onUlimitClamped` callback safely. Same shape and rationale
|
|
216
|
+
* as `safeInvokeVolumeIssue` — see that helper's doc.
|
|
217
|
+
*/
|
|
218
|
+
export function safeInvokeUlimitClamped(handler, event, reportError) {
|
|
219
|
+
if (!handler)
|
|
220
|
+
return;
|
|
221
|
+
try {
|
|
222
|
+
void Promise.resolve(handler(event)).catch(reportError);
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
reportError(err);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
212
228
|
/**
|
|
213
229
|
* Spawn `podman logs -f --tail=N sk-<name>` (or `docker logs -f`)
|
|
214
230
|
* and emit each line to `onLine`. Returns a stop-handle; the caller
|
|
@@ -1324,7 +1340,7 @@ export function ulimitsForRun(ulimits, nofileCeiling, onClamp) {
|
|
|
1324
1340
|
* Replaces the former `buildRunArgs` flag-array builder; the same fields
|
|
1325
1341
|
* map onto the structured create payload (top-level vs `HostConfig`).
|
|
1326
1342
|
*/
|
|
1327
|
-
function buildCreateOptions(name, config, runtime, healthcheck, debug = () => { }) {
|
|
1343
|
+
function buildCreateOptions(name, config, runtime, healthcheck, debug = () => { }, onClamp = () => { }) {
|
|
1328
1344
|
const fullName = prefixedName(name);
|
|
1329
1345
|
const imageRef = qualifyImage(config.digest
|
|
1330
1346
|
? `${config.image}@${config.digest}`
|
|
@@ -1413,8 +1429,12 @@ function buildCreateOptions(name, config, runtime, healthcheck, debug = () => {
|
|
|
1413
1429
|
// rootless container asking for more than the calling user's hard limit
|
|
1414
1430
|
// is rejected by crun and never starts, so we lower it (and log) rather
|
|
1415
1431
|
// than let the container fail.
|
|
1416
|
-
const ulimits = ulimitsForRun(config.ulimits, readNofileHardCeiling(runtime), (requested, granted) =>
|
|
1417
|
-
`
|
|
1432
|
+
const ulimits = ulimitsForRun(config.ulimits, readNofileHardCeiling(runtime), (requested, granted) => {
|
|
1433
|
+
const reason = `nofile ulimit ${requested} exceeds this host's hard limit; clamped to ${granted}. ` +
|
|
1434
|
+
`Raise the limit for the user running the container runtime to use a higher value.`;
|
|
1435
|
+
debug(reason);
|
|
1436
|
+
onClamp({ ulimit: "nofile", requested, granted, reason });
|
|
1437
|
+
});
|
|
1418
1438
|
if (ulimits)
|
|
1419
1439
|
hostConfig.Ulimits = ulimits;
|
|
1420
1440
|
const options = {
|
|
@@ -1565,7 +1585,7 @@ prior, _postRecreate = false, _pull = pullImage) {
|
|
|
1565
1585
|
const healthcheck = config.healthcheck !== undefined
|
|
1566
1586
|
? null
|
|
1567
1587
|
: await getImageHealthcheck(runtime, imageRef, client);
|
|
1568
|
-
const createOpts = buildCreateOptions(name, config, runtime, healthcheck, debug);
|
|
1588
|
+
const createOpts = buildCreateOptions(name, config, runtime, healthcheck, debug, (event) => safeInvokeUlimitClamped(options?.onUlimitClamped, event, (err) => debug(`ensureRunning(${name}): onUlimitClamped handler threw: ${err instanceof Error ? err.message : String(err)}`)));
|
|
1569
1589
|
const created = await createAndStart(client, createOpts);
|
|
1570
1590
|
if (!created.ok && created.conflict) {
|
|
1571
1591
|
// getContainerState reported "missing" because `inspect` failed,
|
|
@@ -1685,6 +1705,118 @@ export async function removeContainer(runtime, name, client = getClient()) {
|
|
|
1685
1705
|
throw new Error(`Failed to remove ${fullName}: ${result.error.userMessage}`);
|
|
1686
1706
|
}
|
|
1687
1707
|
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Container path the wipe helper mounts the data directory at. Arbitrary —
|
|
1710
|
+
* the only requirement is that it not collide with image-baked paths the
|
|
1711
|
+
* helper's `rm` might depend on; a dedicated top-level dir avoids that.
|
|
1712
|
+
*/
|
|
1713
|
+
const WIPE_MOUNT = "/sk-wipe-target";
|
|
1714
|
+
/** Posix error codes that signal "the host user can't delete this" and so
|
|
1715
|
+
* warrant the in-userns fallback rather than a hard failure. */
|
|
1716
|
+
const OWNERSHIP_ERROR_CODES = new Set(["EACCES", "EPERM"]);
|
|
1717
|
+
/** True for the EACCES/EPERM ownership errors that the in-userns wipe can fix.
|
|
1718
|
+
* Anything else (ENOENT, ENOTEMPTY from a live mount, …) is not an ownership
|
|
1719
|
+
* problem and should surface unchanged. */
|
|
1720
|
+
function isOwnershipError(err) {
|
|
1721
|
+
const code = err?.code;
|
|
1722
|
+
return code !== undefined && OWNERSHIP_ERROR_CODES.has(code);
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Reject host paths that must never be recursively wiped. The guard is the
|
|
1726
|
+
* cheap, always-correct floor (empty / `/` / a non-absolute path); the
|
|
1727
|
+
* caller layers any deployment-specific "must be under the Signal K tree"
|
|
1728
|
+
* check on top, where it has the data/config roots to compare against.
|
|
1729
|
+
*/
|
|
1730
|
+
export function assertWipablePath(hostPath) {
|
|
1731
|
+
// Require an absolute path: a relative value would `path.resolve` to a
|
|
1732
|
+
// cwd-relative dir and quietly pass the root check, risking an rm -rf of
|
|
1733
|
+
// the wrong tree. The data/config sources signalk-container deals with are
|
|
1734
|
+
// always absolute, so reject anything else outright. Normalize first so a
|
|
1735
|
+
// root-equivalent like `/..` collapses to the root and is rejected too.
|
|
1736
|
+
const normalized = path.normalize(hostPath || "");
|
|
1737
|
+
if (!hostPath ||
|
|
1738
|
+
hostPath.trim() === "" ||
|
|
1739
|
+
!path.isAbsolute(hostPath) ||
|
|
1740
|
+
normalized === path.parse(normalized).root) {
|
|
1741
|
+
throw new Error(`removeManagedData: refusing to delete unsafe path ${JSON.stringify(hostPath)}`);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
/**
|
|
1745
|
+
* Delete a managed container's bind-mount data, working around the
|
|
1746
|
+
* rootless-Podman subuid-ownership trap.
|
|
1747
|
+
*
|
|
1748
|
+
* Sequence:
|
|
1749
|
+
* 1. Remove the container `name` (idempotent — a missing container is fine)
|
|
1750
|
+
* so nothing holds the mount.
|
|
1751
|
+
* 2. Try a direct host-side `fs.rm(hostPath, {recursive, force})`. On
|
|
1752
|
+
* docker / rootful Podman the files are host-owned and this succeeds.
|
|
1753
|
+
* 3. On EACCES/EPERM (the rootless-Podman case — files are owned by a
|
|
1754
|
+
* subuid the host user can't touch) run `runWipeJob`: a one-shot helper
|
|
1755
|
+
* that bind-mounts `hostPath` and `rm -rf`s its CONTENTS from inside the
|
|
1756
|
+
* userns as in-container root, then retry the host-side delete to drop
|
|
1757
|
+
* the now-empty host-owned parent dir.
|
|
1758
|
+
*
|
|
1759
|
+
* `runWipeJob(image, hostPath)` is injected so the runtime logic stays out
|
|
1760
|
+
* of the `jobs.ts` import cycle and so unit tests can drive every branch
|
|
1761
|
+
* without a real runtime. The wrapper in `index.ts` wires it to `runJob`
|
|
1762
|
+
* with the container's own (already-present) image.
|
|
1763
|
+
*
|
|
1764
|
+
* `wipeImage` is the container's own image, captured from `inspect` BEFORE
|
|
1765
|
+
* removal so the helper reuses bits already on disk — no registry pull on a
|
|
1766
|
+
* possibly-offline boat. `null` when the container was already gone; the
|
|
1767
|
+
* fallback then can't run, so a still-undeletable dir surfaces as an error.
|
|
1768
|
+
*/
|
|
1769
|
+
export async function removeManagedData(runtime, name, hostPath, runWipeJob, client = getClient(),
|
|
1770
|
+
// Invoked exactly once, the instant the container is removed (before the data
|
|
1771
|
+
// delete). Lets the caller tear down container-scoped state (ports, log
|
|
1772
|
+
// broker) only when removal actually happened — not on a pre-removal failure
|
|
1773
|
+
// such as a non-404 inspect error, when the container is still running.
|
|
1774
|
+
onRemoved = () => { }) {
|
|
1775
|
+
assertWipablePath(hostPath);
|
|
1776
|
+
// Capture the image before removal so the in-userns fallback can reuse it
|
|
1777
|
+
// (guaranteed present locally — the container was just running it).
|
|
1778
|
+
const fullName = prefixedName(name);
|
|
1779
|
+
const info = await safeInspect(() => client.getContainer(fullName).inspect());
|
|
1780
|
+
const wipeImage = typeof info?.Config?.Image === "string" ? info.Config.Image : null;
|
|
1781
|
+
await removeContainer(runtime, name, client);
|
|
1782
|
+
onRemoved();
|
|
1783
|
+
// Docker / rootful Podman: bind-mount files are host-owned, plain rm works.
|
|
1784
|
+
try {
|
|
1785
|
+
await rm(hostPath, { recursive: true, force: true });
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1788
|
+
catch (err) {
|
|
1789
|
+
if (!isOwnershipError(err))
|
|
1790
|
+
throw err;
|
|
1791
|
+
}
|
|
1792
|
+
// Rootless-Podman subuid case: the host user can't delete subuid-owned
|
|
1793
|
+
// files. Wipe the dir contents from inside the userns (as in-container
|
|
1794
|
+
// root, which owns them) using the container's own image, then retry the
|
|
1795
|
+
// host-side delete to drop the now-empty host-owned parent.
|
|
1796
|
+
if (!wipeImage) {
|
|
1797
|
+
throw new Error(`removeManagedData: ${hostPath} is not deletable by the Signal K user ` +
|
|
1798
|
+
`and the container's image is unknown (it was already removed), so the ` +
|
|
1799
|
+
`in-userns cleanup helper cannot run. Delete ${hostPath} manually.`);
|
|
1800
|
+
}
|
|
1801
|
+
const wipe = await runWipeJob(wipeImage, hostPath);
|
|
1802
|
+
if (!wipe.ok) {
|
|
1803
|
+
throw new Error(`removeManagedData: in-userns wipe of ${hostPath} failed: ${wipe.error ?? "unknown error"}`);
|
|
1804
|
+
}
|
|
1805
|
+
try {
|
|
1806
|
+
await rm(hostPath, { recursive: true, force: true });
|
|
1807
|
+
}
|
|
1808
|
+
catch (err) {
|
|
1809
|
+
const code = err.code ?? "unknown";
|
|
1810
|
+
throw new Error(`removeManagedData: ${hostPath} still not removable after in-userns wipe (${code}). ` +
|
|
1811
|
+
`Delete it manually.`, { cause: err });
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
/**
|
|
1815
|
+
* Container path the wipe helper mounts the data directory at — re-exported
|
|
1816
|
+
* for the wrapper that builds the `runJob` config and for tests asserting the
|
|
1817
|
+
* mount/command shape.
|
|
1818
|
+
*/
|
|
1819
|
+
export const WIPE_MOUNT_PATH = WIPE_MOUNT;
|
|
1688
1820
|
export async function listContainers(runtime, client = getClient()) {
|
|
1689
1821
|
const result = await safe(() => client.listContainers({
|
|
1690
1822
|
all: true,
|