Compose a node's own modules from their builds and read what providers elsewhere serve, so a self-composing node hands moved modules and settles served settings as the controller does (issue 1126)

frombus composed every module from the indexer's raw manifest: no moved module
was handed, so the node stood in for own secrets the vault leaves to the
provisioner (the seed's refusals on all four nodes), and a provider elsewhere
had no config values, so mailu's served domain refused shanks.

- takein: the controller's take-in of a done key (artifacts, launchers, the
  templates archive's texts, Resolve) as one SDK rule; catalogue.Launchers holds
  the launcher rule buildstep now delegates to.
- frombus: each module placed on the composing node, and each kept at another
  build (Scope.KeptAt, a fingerprint), composes from its built manifest; another
  node's modules give the keys their served values fill (Reader.Served).
- buscompose: Declared.Served and Principal.ServedReads grant every node the read
  of exactly those keys of mesh-config_resolved.
- compose.ArtifactStoreAddress: the store as the node's composition routes to it.
This commit is contained in:
2026-10-27 21:11:20 +01:00
parent 9f92233a28
commit 04de3e5da2
16 changed files with 890 additions and 45 deletions
@@ -0,0 +1,60 @@
{
"module": "mesh-provisioner-client",
"version": "1",
"claims": [
{
"name": "node-provisioner",
"scope": "node"
}
],
"own-secrets": {
"provisioner-broker": "${dir:state}/broker"
},
"secrets-owner": "mesh-provisioner-client",
"resources": [
{
"id": "account",
"type": "user",
"name": "mesh-provisioner-client",
"shell": "/usr/bin/nologin",
"home": "/var/lib/mesh-provisioner-client"
},
{
"id": "state",
"type": "directory",
"mode": "0700",
"owner": "mesh-provisioner-client",
"place": ".",
"unknown": "program"
},
{
"id": "client",
"type": "process",
"name": "mesh-provisioner-client",
"artifact": "client",
"run": [
"./mesh-provisioner-client"
],
"env": {
"MESH_PROVISIONER_CREDENTIAL": "${dir:state}/broker",
"MESH_PROVISIONER_STATE": "${dir:state}"
},
"user": "mesh-provisioner-client",
"health": {
"kind": "unit"
}
}
],
"build": {
"artifacts": [
{
"name": "client",
"kind": "bundle",
"language": "go",
"system": "arch",
"from": "cmd/mesh-provisioner-client",
"binary": "mesh-provisioner-client"
}
]
}
}
@@ -0,0 +1,2 @@
# What the modules on this machine back up, composed by the mesh (novox/hq to-be 43). Do not edit.
${backup:lines}
@@ -0,0 +1,2 @@
# The data the modules on this machine declare, composed by the mesh (novox/hq ADR 0233). Do not edit.
${backup:data}
@@ -0,0 +1,6 @@
# How many restore points the night keeps, written by the mesh from this machine's settings keep-daily,
# keep-weekly, keep-monthly (novox/hq issue 416) and keep-hand-taken-days (novox/hq issue 453). Replaced on every push; change the settings, never this file.
daily=${config:keep-daily}
weekly=${config:keep-weekly}
monthly=${config:keep-monthly}
hand=${config:keep-hand-taken-days}
@@ -0,0 +1,199 @@
{
"module": "restic",
"version": "1",
"moved": true,
"claims": [
{
"name": "node-backup",
"scope": "node",
"serves": [
"backed-up",
"now",
"restore"
]
}
],
"emits": [
"backed-up"
],
"tools": [
"backup_health",
"backup_delete_retired",
"backup_deleted"
],
"own-secrets": {
"repository": "${dir:state}/repository.secret"
},
"data": {
"own": [
{
"id": "repository",
"path": "${dir:repository}",
"class": "rebuildable",
"backup": "none",
"why": "the restore points themselves: a copy of data kept elsewhere on this machine, never the only copy of anything; lost, the history goes and nothing live does"
},
{
"id": "state",
"path": "${dir:state}",
"class": "cache",
"why": "what the last nights and measurements were; the next night writes it again"
}
]
},
"config": {
"keep-daily": {
"type": "number",
"description": "How many nightly restore points are kept, a count from 1 to 9999: two weeks undo a mistake noticed within a fortnight. Read by the night, which thins nothing while it does not read (novox/hq issue 416); lowering it deletes the restore points beyond the new count at the next night, and that cannot be undone.",
"minimum": 1,
"maximum": 9999,
"trusted": true,
"default": 14
},
"keep-weekly": {
"type": "number",
"description": "How many weekly restore points are kept behind the dailies, a count from 1 to 9999, refused by the night like keep-daily; lowering it deletes the restore points beyond the new count at the next night, and that cannot be undone.",
"minimum": 1,
"maximum": 9999,
"trusted": true,
"default": 8
},
"keep-monthly": {
"type": "number",
"description": "How many monthly restore points are kept behind the weeklies, a count from 1 to 9999, refused by the night like keep-daily; lowering it deletes the restore points beyond the new count at the next night, and that cannot be undone.",
"minimum": 1,
"maximum": 9999,
"trusted": true,
"default": 6
},
"keep-hand-taken-days": {
"type": "number",
"description": "How many days a restore point taken by hand (node-backup.now, or the mesh's before a module moves) is kept at least, a count from 1 to 9999; it is kept until a later good night of its module exists, and this many days in any case, so the next thinning never takes the one taken against a risky change (novox/hq issue 453). Lowering it lets go of the older ones taken by hand at the next thinning, and that cannot be undone.",
"minimum": 1,
"maximum": 9999,
"trusted": true,
"default": 7
}
},
"resources": [
{
"id": "state",
"type": "directory",
"mode": "0700",
"place": ".",
"unknown": "program"
},
{
"id": "repository",
"type": "directory",
"mode": "0700",
"unknown": "program"
},
{
"id": "declared",
"type": "file",
"path": "${dir:state}/backups.conf",
"mode": "0600",
"template": "files/backups.conf"
},
{
"id": "data-declared",
"type": "file",
"path": "${dir:state}/data.conf",
"mode": "0600",
"template": "files/data.conf"
},
{
"id": "retention",
"type": "file",
"path": "${dir:state}/retention.conf",
"mode": "0644",
"trusted": true,
"template": "files/retention.conf"
},
{
"id": "tool",
"type": "package",
"package": "restic"
},
{
"id": "sqlite",
"type": "package",
"package": "sqlite"
},
{
"id": "night",
"type": "process",
"name": "restic-night",
"artifact": "tools",
"run": [
"./restic-backups",
"night"
],
"user": "${machine:account}",
"env": {
"MESH_BACKUP_DECLARED": "${dir:state}/backups.conf",
"MESH_BACKUP_REPOSITORY": "${dir:repository}",
"MESH_BACKUP_PASSWORD_FILE": "${dir:state}/repository.secret",
"MESH_BACKUP_STATE": "${dir:state}",
"MESH_BACKUP_DATA": "${dir:state}/data.conf"
},
"health": {
"kind": "tool",
"tool": "backup_health",
"interval": "60s",
"timeout": "20s",
"looks": 2,
"grace": "60s"
}
},
{
"id": "measure",
"type": "process",
"name": "restic-measure",
"artifact": "tools",
"run": [
"./restic-backups",
"measure"
],
"user": "${machine:account}",
"env": {
"MESH_BACKUP_DECLARED": "${dir:state}/backups.conf",
"MESH_BACKUP_REPOSITORY": "${dir:repository}",
"MESH_BACKUP_PASSWORD_FILE": "${dir:state}/repository.secret",
"MESH_BACKUP_STATE": "${dir:state}",
"MESH_BACKUP_DATA": "${dir:state}/data.conf"
},
"health": {
"kind": "unit"
}
}
],
"build": {
"artifacts": [
{
"name": "tools",
"kind": "bundle",
"language": "go",
"system": "arch",
"from": "cmd/restic-backups",
"binary": "restic-backups",
"loads": [
"restic-backups"
],
"env": {
"MESH_BACKUP_DECLARED": "${dir:state}/backups.conf",
"MESH_BACKUP_REPOSITORY": "${dir:repository}",
"MESH_BACKUP_PASSWORD_FILE": "${dir:state}/repository.secret",
"MESH_BACKUP_STATE": "${dir:state}",
"MESH_BACKUP_DATA": "${dir:state}/data.conf"
}
},
{
"name": "files",
"kind": "archive",
"from": "files"
}
]
}
}