mesh/merge-gate head 4193eacec459 merged into trunk 39e7a06e6293 — pass: builds grafana, home-assistant → ace; no bus step; every machine composes with the…
mesh/repo-check head 4193eacec459 merged into trunk 39e7a06e6293 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
grafana runs without influxdb and home-assistant without the Servarr apps or a broker, yet a mesh without them could not assign either. Their requirements are now optional: bound when a provider runs, absent otherwise, with nothing installed for them. grafana's data source and its credential are delivered only while influxdb-api is bound, into directories it mounts, so an absent file never becomes a directory docker made in its place.
40 lines
1.9 KiB
TypeScript
40 lines
1.9 KiB
TypeScript
// grafana runs without a data source, so its influxdb-api is optional (novox/hq ADR 0330, issue 166):
|
|
// a mesh without influxdb can assign grafana, and influxdb is never installed for it. While absent, the
|
|
// data source and its credential are not delivered, and grafana mounts their directories empty.
|
|
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
|
|
type Requirement = string | { name: string; optional?: boolean };
|
|
type Resource = { id: string; type: string; path?: string; content?: string; volumes?: string[]; "only-when-bound"?: string };
|
|
const manifest = JSON.parse(readFileSync(new URL("../module.json", import.meta.url), "utf8")) as {
|
|
requires: Requirement[];
|
|
resources: Resource[];
|
|
};
|
|
|
|
const optional = (name: string) =>
|
|
manifest.requires.some((r) => typeof r !== "string" && r.name === name && r.optional === true);
|
|
|
|
test("influxdb-api is optional, and route and oidc-client stay hard", () => {
|
|
assert.ok(optional("influxdb-api"));
|
|
assert.ok(manifest.requires.includes("route"));
|
|
assert.ok(manifest.requires.includes("oidc-client"));
|
|
});
|
|
|
|
test("every file naming influxdb-api is delivered only while it is bound", () => {
|
|
for (const r of manifest.resources) {
|
|
if (r.type === "file" && /\$\{(bound:influxdb-api:|secret:influxdb-api\})/.test(r.content ?? "")) {
|
|
assert.equal(r["only-when-bound"], "influxdb-api", `${r.id} names influxdb-api and is delivered while it is absent`);
|
|
}
|
|
}
|
|
});
|
|
|
|
test("the container mounts the data source's directories, never a file that may be absent", () => {
|
|
// A bind mount of a missing file makes a directory in its place, which the file could then never be written over.
|
|
const server = manifest.resources.find((r) => r.id === "server");
|
|
for (const v of server?.volumes ?? []) {
|
|
assert.ok(!/influxdb.*\.(yaml|secret)|influxdb-api:/.test(v.split(":")[0]), `${v} mounts an only-when-bound file`);
|
|
}
|
|
});
|