Roll out the tool runtime to the remaining tools+events modules (ADR 0052/0051)
Nineteen modules gain a broker-bound runtime container that serves the module's tools under its own scoped account: bazarr, gitea, grafana, home-assistant, icecast, influxdb, jackett, keycloak, mailu, nextcloud, nodered, nzbget, ombi, photos, portainer, qbittorrent, searxng, tautulli, verdaccio. Config is the assignment's, not the manifest's (ADR 0051): each client's fromEnv overlays a settings-merged config file (MESH_<M>_CONFIG_FILE) over its env fallbacks, so URL and credentials come from `settings set`, with the URL defaulting to the server on the node. nextcloud and mailu also mount the docker socket for their exec-based tools. Proven in the mesh-lab: assigned-grafana green — settings deliver the URL and token, the runtime reads the merged config and serves grafana's tools under the scoped account, with nothing in the manifest. Two gaps this surfaced are filed as hq issues 008 (a provider runtime's seal key) and 009 (a settings change does not restart a container runtime). Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
// which the host owns and emits — so this module reads Portainer's own resources (endpoints,
|
||||
// stacks, containers) and exposes them, and stops there.
|
||||
|
||||
import { readFileSync } from "node:fs";
|
||||
|
||||
export interface PortainerEndpoint {
|
||||
id: number;
|
||||
name: string;
|
||||
@@ -27,6 +29,13 @@ export interface PortainerContainer {
|
||||
status: string;
|
||||
}
|
||||
|
||||
/** The settings-merged config the mesh delivers (novox/hq ADR 0051): { url, apiKey, token, password, user, ... }. */
|
||||
function meshConfig(file?: string): Record<string, string> {
|
||||
if (!file) return {};
|
||||
try { return JSON.parse(readFileSync(file, "utf8")) as Record<string, string>; }
|
||||
catch { return {}; }
|
||||
}
|
||||
|
||||
export class PortainerClient {
|
||||
readonly baseUrl: string;
|
||||
|
||||
@@ -44,8 +53,9 @@ export class PortainerClient {
|
||||
* exposes nothing rather than calling Portainer unauthenticated.
|
||||
*/
|
||||
static fromEnv(env: NodeJS.ProcessEnv = process.env): PortainerClient {
|
||||
const url = env.MESH_PORTAINER_URL ?? `https://127.0.0.1:${env.PORTAINER_PORT ?? "9443"}`;
|
||||
const token = env.MESH_PORTAINER_TOKEN;
|
||||
const cfg = meshConfig(env.MESH_PORTAINER_CONFIG_FILE);
|
||||
const url = cfg.url ?? env.MESH_PORTAINER_URL ?? `https://127.0.0.1:${env.PORTAINER_PORT ?? "9443"}`;
|
||||
const token = cfg.token ?? env.MESH_PORTAINER_TOKEN;
|
||||
if (!token) throw new Error("no Portainer token — set MESH_PORTAINER_TOKEN");
|
||||
return new PortainerClient(url, token);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"id": "mesh-state",
|
||||
"type": "directory",
|
||||
"path": "/var/lib/mesh/portainer",
|
||||
"mode": "0700"
|
||||
},
|
||||
{
|
||||
"id": "data",
|
||||
"type": "directory",
|
||||
@@ -31,6 +37,33 @@
|
||||
"/services/portainer/data:/data",
|
||||
"/var/run/docker.sock:/var/run/docker.sock"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "config",
|
||||
"type": "file",
|
||||
"path": "/var/lib/mesh/portainer/config.json",
|
||||
"mode": "0600",
|
||||
"content": "{}\n",
|
||||
"merge": "json"
|
||||
},
|
||||
{
|
||||
"id": "runtime",
|
||||
"type": "container",
|
||||
"name": "mesh-portainer",
|
||||
"image": "mesh-runtime-portainer@sha256:0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"network": "host",
|
||||
"volumes": [
|
||||
"/var/lib/mesh/portainer/broker:/run/secrets/broker:ro",
|
||||
"/var/lib/mesh/portainer/config.json:/run/config/config.json:ro"
|
||||
],
|
||||
"env": {
|
||||
"MESH_BROKER_FILE": "/run/secrets/broker",
|
||||
"MESH_PORTAINER_URL": "https://127.0.0.1:9443",
|
||||
"MESH_PORTAINER_CONFIG_FILE": "/run/config/config.json"
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"own-secrets": {
|
||||
"broker": "/var/lib/mesh/portainer/broker"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user