Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4426190b0 | ||
|
|
2154ea8e3c | ||
|
|
812c528479 | ||
|
|
8b32e04e2f | ||
|
|
79f44386d2 | ||
|
|
80df1b6361 | ||
|
|
816cf96459 | ||
|
|
3f05df5d1a |
@@ -56,9 +56,15 @@ func TestModuleCheckJudgesBetweenTheManifestsGiven(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// The real catalogue passes the command, the way it passes the test that used to be the only check.
|
||||
// The real catalogue passes the command, the way it passes the test that used to be the only check: the catalogue this
|
||||
// controller is released with, captured in testdata/beside at the commit CAPTURED names. Not the clone a merge check puts
|
||||
// beside, which is the catalogue's trunk even in a delivery group holding a catalogue pull request (ADR 0484 clause 4):
|
||||
// a controller whose check reads a word that group's catalogue brings would fail on the trunk's catalogue before the
|
||||
// group merges both (issue 774: the release's sdk refuses an offer that states no credential form, and the catalogue's
|
||||
// trunk states none until the release's catalogue merges). Moving CAPTURED to the catalogue a change is released with is
|
||||
// part of that change.
|
||||
func TestModuleCheckPassesTheCatalogue(t *testing.T) {
|
||||
root := beside.Catalogue(t)
|
||||
root := filepath.Join(beside.CapturedDir(t, "mesh-catalog"), "modules")
|
||||
paths, err := manifestsUnder(root)
|
||||
if err != nil || len(paths) == 0 {
|
||||
t.Fatalf("no manifests under %s: %v", root, err)
|
||||
|
||||
@@ -23,10 +23,10 @@ func TestModuleCheckRefusesAnIdentityThatOverflowsWhatItRequires(t *testing.T) {
|
||||
return p
|
||||
}
|
||||
objects := write("objects", `{"module":"objects","version":"1",
|
||||
"provides":[{"name":"s3-bucket","scope":"mesh","identity":{"max":20,"in":"an S3 access key"}}],
|
||||
"provides":[{"name":"s3-bucket","scope":"mesh","identity":{"max":20,"in":"an S3 access key"},"credential":{"form":"pair"}}],
|
||||
"receives":{"s3-bucket":"/var/lib/mesh/objects/mesh.json"}}`)
|
||||
resolver := write("resolver", `{"module":"resolver","version":"1",
|
||||
"provides":[{"name":"wildcard-resolution","scope":"mesh","identity":false}]}`)
|
||||
"provides":[{"name":"wildcard-resolution","scope":"mesh","identity":false,"credential":{"form":"none"}}]}`)
|
||||
album := write("photoalbum", `{"module":"photoalbum","version":"1","requires":["s3-bucket"]}`)
|
||||
nm := write("networkmanager", `{"module":"networkmanager","version":"1","requires":["wildcard-resolution"]}`)
|
||||
|
||||
|
||||
@@ -182,6 +182,9 @@ func TestANeedIsIssuedToItsHolderOnlyWhereTheProviderIsMovedAndItsSoftwareIssues
|
||||
offer := catalogue.Offer{Name: "gitea-read", Scope: catalogue.ScopeMesh}
|
||||
if issued {
|
||||
offer.Credential = &catalogue.OfferCredential{IssuedBy: catalogue.IssuedBySoftware, Tool: "gitea_agent_token"}
|
||||
} else {
|
||||
// A login of each consumer's own, said: an offer naming no form has no credential (mesh-sdk 6b8c694).
|
||||
offer.Credential = &catalogue.OfferCredential{Form: catalogue.CredentialFormPair}
|
||||
}
|
||||
return catalogue.Manifest{Module: "gitea", Version: "1", Moved: moved, Provides: []catalogue.Offer{offer}}
|
||||
}
|
||||
@@ -216,8 +219,10 @@ func TestANeedIsIssuedToItsHolderOnlyWhereTheProviderIsMovedAndItsSoftwareIssues
|
||||
// marked moved; another module is not.
|
||||
func TestTheModuleHoldingTheVaultSeatCountsAsMovedForItsConsumers(t *testing.T) {
|
||||
vault := catalogue.Manifest{Module: "mesh-vault", Version: "1", Claims: []catalogue.Claim{{Name: "mesh-vault", Scope: catalogue.ScopeMesh}},
|
||||
Provides: []catalogue.Offer{{Name: "secret", Scope: catalogue.ScopeMesh}}}
|
||||
other := catalogue.Manifest{Module: "mesh-vault", Version: "1", Provides: []catalogue.Offer{{Name: "secret", Scope: catalogue.ScopeMesh}}}
|
||||
Provides: []catalogue.Offer{{Name: "secret", Scope: catalogue.ScopeMesh,
|
||||
Credential: &catalogue.OfferCredential{Form: catalogue.CredentialFormPair}}}}
|
||||
other := catalogue.Manifest{Module: "mesh-vault", Version: "1", Provides: []catalogue.Offer{{Name: "secret", Scope: catalogue.ScopeMesh,
|
||||
Credential: &catalogue.OfferCredential{Form: catalogue.CredentialFormPair}}}}
|
||||
if got := needOf(t, map[string]catalogue.Manifest{"mesh-vault": vault}, "mesh-vault", "gitea", "secret"); !got.IssuedToHolder || !got.ProviderMoved {
|
||||
t.Errorf("the vault's consumer is not answered by a moved provider: %+v", got)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ module github.com/novox/mesh-controller
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030001116-2da0de75c3f0
|
||||
github.com/jackc/pgx/v5 v5.10.0
|
||||
github.com/nats-io/nats-server/v2 v2.11.17
|
||||
github.com/nats-io/nats.go v1.54.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
git.novox.be/novox/mesh-host v0.0.0-20261018171808-9d9e3a46c4f5 h1:E5stfIeCN6uYgA9TCv+4K8JgaURg3zQppvUgJLaDMP4=
|
||||
git.novox.be/novox/mesh-host v0.0.0-20261018171808-9d9e3a46c4f5/go.mod h1:4wyoCr6IIIIarEUuROThWDj7DAvJvIidqMjWcpSnOwE=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771 h1:Tt16HJk8JZRce1i3JzzDSNdCWOrv7dw8FQ/bckNQ5Ig=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029233535-78c9ec881771/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030001116-2da0de75c3f0 h1:lKU3HjNXGiVbLW2hUgFjU/TMTUYMlNnnmZxG5T7biQA=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030001116-2da0de75c3f0/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
||||
@@ -53,6 +53,16 @@ func Dir(t testing.TB, repository string) string {
|
||||
t.Logf("judged against %s as cloned beside this check", dir)
|
||||
return dir
|
||||
}
|
||||
t.Logf("no %s beside this check: a merge check judges %s against its own clone", Env, repository)
|
||||
return CapturedDir(t, repository)
|
||||
}
|
||||
|
||||
// CapturedDir is the copy of the named repository captured in testdata/beside, laid out as Dir lays it out, whatever
|
||||
// MESH_CHECK_BESIDE says: for a test that judges this repository against the commit it was released with, which a
|
||||
// merge check does not clone (it clones the catalogue at its trunk even in a delivery group holding a catalogue pull
|
||||
// request, ADR 0484 clause 4).
|
||||
func CapturedDir(t testing.TB, repository string) string {
|
||||
t.Helper()
|
||||
from := filepath.Join(Captured(), repository)
|
||||
if _, err := os.Stat(from); err != nil {
|
||||
t.Fatalf("no captured copy of %s at %s: %v", repository, from, err)
|
||||
@@ -81,8 +91,7 @@ func Dir(t testing.TB, repository string) string {
|
||||
if err != nil {
|
||||
t.Fatalf("the captured copy of %s could not be laid out: %v", repository, err)
|
||||
}
|
||||
t.Logf("judged against the copy of %s captured in testdata/beside (see CAPTURED); a merge check "+
|
||||
"judges it against the repository's own clone", repository)
|
||||
t.Logf("judged against the copy of %s captured in testdata/beside (see CAPTURED)", repository)
|
||||
return dir
|
||||
}
|
||||
|
||||
|
||||
@@ -127,9 +127,10 @@ var (
|
||||
// begin.
|
||||
var PlacementKinds = []string{"dir", "access", "port", "seat", "machine", "backup"}
|
||||
|
||||
// credentialForms are the forms a provider's offer may declare for its credential (issue 768).
|
||||
// credentialForms are the forms a provider's offer may declare for its credential (issue 768); "none" is an offer with
|
||||
// no credential, which the release's catalogue states on every such offer (issue 774).
|
||||
var credentialForms = []string{catalogue.CredentialFormShared, catalogue.CredentialFormPair,
|
||||
catalogue.CredentialFormIssued, catalogue.CredentialFormGiven}
|
||||
catalogue.CredentialFormIssued, catalogue.CredentialFormGiven, catalogue.CredentialFormNone}
|
||||
|
||||
var (
|
||||
digestShape = regexp.MustCompile(`^sha256:[0-9a-f]{64}$`)
|
||||
|
||||
@@ -316,14 +316,16 @@ func TestAPlanNamesTheCredentialFormOfEachProvidersOffer(t *testing.T) {
|
||||
p := aPlan()
|
||||
p.Provisions = []ProvisionedCredential{
|
||||
{Provision: "postgres-database", Provider: "novox", ProviderModule: "postgres", CredentialForm: "pair"},
|
||||
{Provision: "sonarr-api", Provider: "ace", ProviderModule: "sonarr", CredentialForm: "shared"}}
|
||||
{Provision: "sonarr-api", Provider: "ace", ProviderModule: "sonarr", CredentialForm: "shared"},
|
||||
{Provision: "artifact-store", Provider: "novox", ProviderModule: "distribution", CredentialForm: "none"}}
|
||||
values, err := AssignmentValues(assigned, map[string]Provisioning{"g14.dunst": p})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want := `{"provision":"postgres-database","provider":"novox","provider-module":"postgres",` +
|
||||
`"credential-form":"pair"},{"provision":"sonarr-api","provider":"ace","provider-module":"sonarr",` +
|
||||
`"credential-form":"shared"}`; !strings.Contains(string(values["g14.dunst"]), want) {
|
||||
`"credential-form":"shared"},{"provision":"artifact-store","provider":"novox","provider-module":"distribution",` +
|
||||
`"credential-form":"none"}`; !strings.Contains(string(values["g14.dunst"]), want) {
|
||||
t.Errorf("the plan's value is %s, want it to carry %s", values["g14.dunst"], want)
|
||||
}
|
||||
bad := aPlan()
|
||||
|
||||
Vendored
+2
-2
@@ -7,9 +7,9 @@ The copy carries the catalogue's private details: domains, first names in module
|
||||
private addresses. That is acceptable while mesh-controller is private; if it ever goes public, this copy is
|
||||
a second place to clean besides the catalogue itself.
|
||||
|
||||
mesh-catalog 3a1017f5594217092a654dd1e2d72226766bc16a modules/*/module.json, modules/*/files, modules/*/templates, predefined.json
|
||||
mesh-catalog f3a57dcc56fb6c198095cafd11d0decff9f720c4 modules/*/module.json, modules/*/files, modules/*/templates, predefined.json
|
||||
mesh-host 9d9e3a46c4f5943cfffb413d962ce48b75e2fd39 examples/foundation-first-node.lock
|
||||
mesh-sdk 78c9ec8817710eae7f1a068aef68924293fdef59 conformance/events/module-event.json
|
||||
mesh-sdk 2da0de75c3f0087cff9c2f5ef789ca6dc3c59045 conformance/events/module-event.json
|
||||
|
||||
To move them, from this repository's root, with the two repositories checked out beside it:
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
${seat:mesh-artifact-store:reach}
|
||||
+46
-11
@@ -1,26 +1,52 @@
|
||||
{
|
||||
"module": "artifact-store-tools",
|
||||
"version": "1",
|
||||
"claims": [
|
||||
{
|
||||
"name": "mesh-artifact-sweep",
|
||||
"scope": "mesh",
|
||||
"serves": [
|
||||
"artifacts",
|
||||
"held",
|
||||
"collect",
|
||||
"mirrors",
|
||||
"images"
|
||||
]
|
||||
}
|
||||
],
|
||||
"requires": [
|
||||
"artifact-store"
|
||||
],
|
||||
"invokes": [
|
||||
"seat:mesh-controller.artifacts",
|
||||
"seat:mesh-controller.collect",
|
||||
"seat:mesh-hand-acts.hand-act",
|
||||
"mesh-catalog.catalog_modules",
|
||||
"mesh-catalog.catalog_module"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-delivery-assigner.wants",
|
||||
"mesh-delivery-builder.builds",
|
||||
"mesh-delivery-builder.build-log",
|
||||
"mesh-delivery-indexer.manifests",
|
||||
"node-engine.have",
|
||||
"mesh-controller.lease"
|
||||
],
|
||||
"state": [
|
||||
"findings"
|
||||
],
|
||||
"tools": [
|
||||
"artifact_store_repositories",
|
||||
"artifact_store_usage",
|
||||
"artifact_store_references",
|
||||
"artifact_store_collect"
|
||||
],
|
||||
"config": {
|
||||
"older-store-names": {
|
||||
"type": "string",
|
||||
"description": "The names the artifact store had before, as host names or host:port separated by spaces, or none when it had no other. artifact_store_references reads every definition under these as well as under the store's current name, so an image a definition pins under one is said to be named by a definition (novox/hq issue 323).",
|
||||
"pattern": "none|[A-Za-z0-9.:-]+( [A-Za-z0-9.:-]+)*",
|
||||
"default": "none"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"older-store-names": {
|
||||
"type": "string",
|
||||
"description": "The names the artifact store had before, as host names or host:port separated by spaces, or none when it had no other. artifact_store_references reads every definition under these as well as under the store's current name, so an image a definition pins under one is said to be named by a definition (novox/hq issue 323).",
|
||||
"pattern": "none|[A-Za-z0-9.:-]+( [A-Za-z0-9.:-]+)*",
|
||||
"default": "none"
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"id": "state",
|
||||
@@ -36,6 +62,14 @@
|
||||
"mode": "0600",
|
||||
"trusted": false,
|
||||
"template": "files/store-names"
|
||||
},
|
||||
{
|
||||
"id": "store-address",
|
||||
"type": "file",
|
||||
"path": "${dir:state}/store-address",
|
||||
"mode": "0600",
|
||||
"trusted": false,
|
||||
"template": "files/store-address"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
@@ -52,7 +86,8 @@
|
||||
],
|
||||
"env": {
|
||||
"MESH_ARTIFACT_STORE_CONTAINER": "mesh-registry",
|
||||
"MESH_ARTIFACT_STORE_NAMES_FILE": "${dir:state}/store-names"
|
||||
"MESH_ARTIFACT_STORE_NAMES_FILE": "${dir:state}/store-names",
|
||||
"MESH_ARTIFACT_STORE_ADDRESS_FILE": "${dir:state}/store-address"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "rootless-image-build",
|
||||
"reach": "machine"
|
||||
"reach": "machine",
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
"disk_filesystems",
|
||||
"disk_folders",
|
||||
"disk_devices",
|
||||
"cpu_top"
|
||||
"cpu_top",
|
||||
"disk_readings",
|
||||
"disk_measure"
|
||||
],
|
||||
"build": {
|
||||
"artifacts": [
|
||||
@@ -23,5 +25,16 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"state": [
|
||||
"readings"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-config.resolved",
|
||||
"mesh-delivery-assigner.placement",
|
||||
"mesh-delivery-builder.builds",
|
||||
"mesh-delivery-indexer.manifests",
|
||||
"mesh-delivery-indexer.modules",
|
||||
"node-engine.have"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "artifact-store",
|
||||
"scope": "mesh"
|
||||
"scope": "mesh",
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"claims": [
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
# Written by the mesh (module dnsmasq, novox/hq issue 348). Replaced on every push.
|
||||
#
|
||||
# The resolver binds its addresses once, at start (bind-interfaces), so it starts only once this
|
||||
# machine's private address is there: it waits up to 80 seconds for it, and a start that found it
|
||||
# missing is tried again every ten seconds rather than left failed.
|
||||
# machine's private address is there: a start that finds it missing fails after at most two seconds and
|
||||
# is tried again every ten seconds (Restart=on-failure, no start limit) until the tunnel has brought it.
|
||||
# It does not order itself After= or Wants= network-online.target, and its wait is short: the packaged
|
||||
# unit is Before= network-online.target and nss-lookup.target, and the tunnel is ordered after them, so
|
||||
# a long wait would hold the tunnel back and a drop-in ordering would be a cycle (issue 1126).
|
||||
[Unit]
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/sh -c 'for i in $(seq 1 80); do ip -4 -o addr show to ${machine:address} | grep -q . && exit 0; sleep 1; done; echo "${machine:address} is not on this machine" >&2; exit 1'
|
||||
ExecStartPre=/usr/bin/sh -c 'for i in $(seq 1 2); do ip -4 -o addr show to ${machine:address} | grep -q . && exit 0; sleep 1; done; echo "${machine:address} is not on this machine" >&2; exit 1'
|
||||
Restart=on-failure
|
||||
RestartSec=10s
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
{
|
||||
"name": "wildcard-resolution",
|
||||
"scope": "mesh",
|
||||
"identity": false
|
||||
"identity": false,
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requires": [
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"privileged"
|
||||
],
|
||||
"invokes": [
|
||||
"seat:mesh-controller.images"
|
||||
"seat:mesh-artifact-sweep.images"
|
||||
],
|
||||
"claims": [
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
],
|
||||
"emits": [
|
||||
"repo.created",
|
||||
"repo.writable",
|
||||
"issue.opened",
|
||||
"pull.merged",
|
||||
"pull.updated",
|
||||
@@ -181,6 +182,12 @@
|
||||
"trusted": true,
|
||||
"default": {}
|
||||
},
|
||||
"check-gates-merge": {
|
||||
"type": "boolean",
|
||||
"description": "Whether gitea_merge_pull_request judges mesh/check before it merges. True (the default): a head merges only on a passing mesh/check judged against the trunk's head (ADR 0447, ADR 0534 §4). False (the operator, 2026-10-25 22:56: \"run the check locally only, but not as a gate, it loses us too much time\"): a head the operator's Approve names in approved_heads merges whatever its mesh/check says (pending, failed, missing or judged on an older trunk); a head that moved, a branch no rule guards and a merge git refuses are still refused. Set together with mesh-delivery-gate's check-gates-merge.",
|
||||
"trusted": true,
|
||||
"default": true
|
||||
},
|
||||
"main-mergers": {
|
||||
"type": "list",
|
||||
"description": "The forge logins that may merge into main beside the tools' account, on every repository of the organisation (ADR 0534 §2): the operator's own, so the operator can always merge by hand at the forge. The tools' account is always on main's merge whitelist; no agent's account belongs here.",
|
||||
@@ -259,7 +266,8 @@
|
||||
"env": {
|
||||
"DB_TYPE": "postgres",
|
||||
"USER_UID": "1000",
|
||||
"USER_GID": "1000"
|
||||
"USER_GID": "1000",
|
||||
"SSH_MAX_STARTUPS": "100:30:200"
|
||||
},
|
||||
"env-file": [
|
||||
"${dir:state}/server.env"
|
||||
@@ -316,7 +324,8 @@
|
||||
"takes-config": [
|
||||
"url",
|
||||
"keep-main-rules",
|
||||
"main-mergers"
|
||||
"main-mergers",
|
||||
"check-gates-merge"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -391,6 +400,7 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "npm-package-registry",
|
||||
"credential": {"form": "pair"},
|
||||
"scope": "mesh",
|
||||
"identity": {
|
||||
"max": 40,
|
||||
@@ -399,6 +409,7 @@
|
||||
},
|
||||
{
|
||||
"name": "git",
|
||||
"credential": {"form": "none"},
|
||||
"scope": "mesh"
|
||||
},
|
||||
{
|
||||
@@ -411,6 +422,7 @@
|
||||
},
|
||||
{
|
||||
"name": "forge-account",
|
||||
"credential": {"form": "none"},
|
||||
"scope": "mesh"
|
||||
}
|
||||
],
|
||||
@@ -537,6 +549,7 @@
|
||||
"MESH_GITEA_ADMIN_PASSWORD_FILE": "${dir:state}/admin.secret",
|
||||
"MESH_GITEA_ORIGINS_FILE": "${dir:mesh-state}/origins",
|
||||
"MESH_GITEA_SSH_PORT": "222",
|
||||
"MESH_GITEA_HOST_KEY_FILE": "${dir:data}/ssh/ssh_host_ed25519_key.pub",
|
||||
"MESH_FORGE_HOST_FILE": "/etc/gitea/forge-host"
|
||||
}
|
||||
}
|
||||
@@ -554,11 +567,14 @@
|
||||
"announced"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-controller.assignments",
|
||||
"mesh-provisioner.plans",
|
||||
"mesh-provisioner.provisions",
|
||||
"ssh-client.keys",
|
||||
"mesh-build-go.keys",
|
||||
"mesh-build-node.keys",
|
||||
"mesh-build-image.keys",
|
||||
"mesh-delivery-checker.owed"
|
||||
"mesh-delivery-checker.owed",
|
||||
"mesh-delivery-indexer.modules",
|
||||
"mesh-delivery-gate.source"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "go-toolchain",
|
||||
"reach": "machine"
|
||||
"reach": "machine",
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
"scope": "mesh",
|
||||
"identity": {
|
||||
"in": "an InfluxDB v1 authorization"
|
||||
},
|
||||
"credential": {
|
||||
"form": "pair"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# Written by the mesh's kernel module (systemd-modules-load reads it at boot).
|
||||
# tun: buildah's network for a RUN line (pasta) and every other user-space tunnel open /dev/net/tun.
|
||||
# Loaded at boot, so an upgrade that removes the running kernel's modules cannot keep it out later.
|
||||
tun
|
||||
@@ -100,6 +100,25 @@
|
||||
"id": "linux-lts-headers",
|
||||
"type": "package",
|
||||
"package": "linux-lts-headers"
|
||||
},
|
||||
{
|
||||
"id": "modules-load",
|
||||
"type": "file",
|
||||
"path": "/etc/modules-load.d/mesh-kernel.conf",
|
||||
"mode": "0644",
|
||||
"template": "files/modules-load.conf"
|
||||
},
|
||||
{
|
||||
"id": "modules-keep",
|
||||
"type": "package",
|
||||
"package": "kernel-modules-hook"
|
||||
},
|
||||
{
|
||||
"id": "modules-cleanup",
|
||||
"type": "service",
|
||||
"unit": "linux-modules-cleanup.service",
|
||||
"state": "stopped",
|
||||
"boot": "enabled"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "oidc-client",
|
||||
"credential": {"form": "pair"},
|
||||
"scope": "mesh",
|
||||
"identity": {
|
||||
"max": 255,
|
||||
@@ -240,6 +241,7 @@
|
||||
"bound"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-controller.assignments"
|
||||
"mesh-provisioner.plans",
|
||||
"mesh-provisioner.provisions"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -665,7 +665,14 @@
|
||||
"path": "${dir:mesh-state}/config.json",
|
||||
"mode": "0600",
|
||||
"template": "files/config.json",
|
||||
"takes-config": ["domain", "proxy-address", "sitename", "website", "url", "container"],
|
||||
"takes-config": [
|
||||
"domain",
|
||||
"proxy-address",
|
||||
"sitename",
|
||||
"website",
|
||||
"url",
|
||||
"container"
|
||||
],
|
||||
"merge": "json"
|
||||
},
|
||||
{
|
||||
@@ -758,6 +765,9 @@
|
||||
"identity": {
|
||||
"max": 64,
|
||||
"in": "a mailbox's local part"
|
||||
},
|
||||
"credential": {
|
||||
"form": "pair"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"capacity": "shanks=3,ace=2,g14=0,novox=0"
|
||||
"capacity": 0,
|
||||
"cores-per-step": 6,
|
||||
"build-hours": ""
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"state": [
|
||||
"toolchains",
|
||||
"keys",
|
||||
"steps"
|
||||
{"name": "steps", "ttl-seconds": 172800}, "pauses"
|
||||
],
|
||||
"claims": [
|
||||
{
|
||||
@@ -20,14 +20,27 @@
|
||||
}
|
||||
],
|
||||
"reads": [
|
||||
"mesh-delivery-checker.kept"
|
||||
"mesh-delivery-checker.kept",
|
||||
"mesh-delivery-indexer.manifests"
|
||||
],
|
||||
"config": {
|
||||
"capacity": {
|
||||
"type": "number",
|
||||
"description": "How many asks of the Go build seat this module runs at once on this node (novox/hq ADR 0525 §5); 0 pulls nothing. It is set per node in the mesh's configuration; a node with no value builds nothing.",
|
||||
"minimum": 0,
|
||||
"default": 0
|
||||
},
|
||||
"build-hours": {
|
||||
"type": "string",
|
||||
"description": "How many asks of the Go build seat this module runs at once on each node, as node=asks pairs separated by commas, such as shanks=3,ace=2 (novox/hq ADR 0525 §5); a node set to 0 pulls nothing, a node not named runs one at a time. The control-node and the laptop build nothing.",
|
||||
"pattern": "|[a-z0-9_-]+=[0-9]+(,[a-z0-9_-]+=[0-9]+)*",
|
||||
"default": "shanks=3,ace=2,g14=0,novox=0"
|
||||
"description": "When this node may take this module's build asks: one window HH:MM-HH:MM in the node's local time (an end before its start crosses midnight, 18:00-06:00). Outside it the node takes no new step and finishes the ones it runs; an empty value builds at any hour. It is set per node in the mesh's configuration.",
|
||||
"pattern": "|([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9]",
|
||||
"default": ""
|
||||
},
|
||||
"cores-per-step": {
|
||||
"type": "number",
|
||||
"description": "How many processors one Go step of this module needs (a full check of a large repository takes what it is given: three at about 4 cores each ran past the 30-minute step bound on 2026-10-26). The capacity above is an upper bound: on each node the module runs at most floor(the cores of its build slice's CPU quota / this) steps at once, the quota read live from its cgroup (issue 1806), so a lowered build CPU share never starves its steps. Above 0.",
|
||||
"minimum": 0.1,
|
||||
"default": 6
|
||||
}
|
||||
},
|
||||
"tools": [
|
||||
@@ -38,6 +51,7 @@
|
||||
"build_go_release",
|
||||
"build_go_step",
|
||||
"build_go_steps",
|
||||
"build_go_step_end",
|
||||
"build_go_toolchains",
|
||||
"build_go_status",
|
||||
"build_go_health"
|
||||
@@ -105,7 +119,7 @@
|
||||
"path": "${dir:state}/settings.json",
|
||||
"mode": "0600",
|
||||
"owner": "mesh-build-go",
|
||||
"takes-config": ["capacity"],
|
||||
"takes-config": ["capacity", "cores-per-step", "build-hours"],
|
||||
"merge": "json",
|
||||
"template": "files/settings.json"
|
||||
},
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"capacity": "shanks=3,ace=2,g14=0,novox=0"
|
||||
"capacity": 0,
|
||||
"cores-per-step": 2,
|
||||
"build-hours": ""
|
||||
}
|
||||
|
||||
+18
-5
@@ -9,7 +9,7 @@
|
||||
],
|
||||
"state": [
|
||||
"keys",
|
||||
"steps"
|
||||
{"name": "steps", "ttl-seconds": 172800}, "pauses"
|
||||
],
|
||||
"claims": [
|
||||
{
|
||||
@@ -20,10 +20,22 @@
|
||||
],
|
||||
"config": {
|
||||
"capacity": {
|
||||
"type": "number",
|
||||
"description": "How many asks of the image build seat this module runs at once on this node (novox/hq ADR 0525 §5); 0 pulls nothing. It is set per node in the mesh's configuration; a node with no value builds nothing.",
|
||||
"minimum": 0,
|
||||
"default": 0
|
||||
},
|
||||
"build-hours": {
|
||||
"type": "string",
|
||||
"description": "How many asks of the image build seat this module runs at once on each node, as node=asks pairs separated by commas, such as shanks=3,ace=2 (novox/hq ADR 0525 §5); a node set to 0 pulls nothing, a node not named runs one at a time. The control-node and the laptop build nothing.",
|
||||
"pattern": "|[a-z0-9_-]+=[0-9]+(,[a-z0-9_-]+=[0-9]+)*",
|
||||
"default": "shanks=3,ace=2,g14=0,novox=0"
|
||||
"description": "When this node may take this module's build asks: one window HH:MM-HH:MM in the node's local time (an end before its start crosses midnight, 18:00-06:00). Outside it the node takes no new step and finishes the ones it runs; an empty value builds at any hour. It is set per node in the mesh's configuration.",
|
||||
"pattern": "|([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9]",
|
||||
"default": ""
|
||||
},
|
||||
"cores-per-step": {
|
||||
"type": "number",
|
||||
"description": "How many processors one image step of this module needs (buildah, whose RUN lines are mostly fetches). The capacity above is an upper bound: on each node the module runs at most floor(the cores of its build slice's CPU quota / this) steps at once, the quota read live from its cgroup (issue 1806), so a lowered build CPU share never starves its steps. Above 0.",
|
||||
"minimum": 0.1,
|
||||
"default": 2
|
||||
}
|
||||
},
|
||||
"tools": [
|
||||
@@ -33,6 +45,7 @@
|
||||
"build_image_release",
|
||||
"build_image_step",
|
||||
"build_image_steps",
|
||||
"build_image_step_end",
|
||||
"build_image_status",
|
||||
"build_image_health"
|
||||
],
|
||||
@@ -77,7 +90,7 @@
|
||||
"path": "${dir:state}/settings.json",
|
||||
"mode": "0600",
|
||||
"owner": "mesh-build-image",
|
||||
"takes-config": ["capacity"],
|
||||
"takes-config": ["capacity", "cores-per-step", "build-hours"],
|
||||
"merge": "json",
|
||||
"template": "files/settings.json"
|
||||
},
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"capacity": "shanks=3,ace=2,g14=0,novox=0"
|
||||
"capacity": 0,
|
||||
"cores-per-step": 2,
|
||||
"build-hours": ""
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"state": [
|
||||
"toolchains",
|
||||
"keys",
|
||||
"steps"
|
||||
{"name": "steps", "ttl-seconds": 172800}, "pauses"
|
||||
],
|
||||
"claims": [
|
||||
{
|
||||
@@ -21,10 +21,22 @@
|
||||
],
|
||||
"config": {
|
||||
"capacity": {
|
||||
"type": "number",
|
||||
"description": "How many asks of the Node build seat this module runs at once on this node (novox/hq ADR 0525 §5); 0 pulls nothing. It is set per node in the mesh's configuration; a node with no value builds nothing.",
|
||||
"minimum": 0,
|
||||
"default": 0
|
||||
},
|
||||
"build-hours": {
|
||||
"type": "string",
|
||||
"description": "How many asks of the Node build seat this module runs at once on each node, as node=asks pairs separated by commas, such as shanks=3,ace=2 (novox/hq ADR 0525 §5); a node set to 0 pulls nothing, a node not named runs one at a time. The control-node and the laptop build nothing.",
|
||||
"pattern": "|[a-z0-9_-]+=[0-9]+(,[a-z0-9_-]+=[0-9]+)*",
|
||||
"default": "shanks=3,ace=2,g14=0,novox=0"
|
||||
"description": "When this node may take this module's build asks: one window HH:MM-HH:MM in the node's local time (an end before its start crosses midnight, 18:00-06:00). Outside it the node takes no new step and finishes the ones it runs; an empty value builds at any hour. It is set per node in the mesh's configuration.",
|
||||
"pattern": "|([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9]",
|
||||
"default": ""
|
||||
},
|
||||
"cores-per-step": {
|
||||
"type": "number",
|
||||
"description": "How many processors one Node step of this module needs (tsc, esbuild and a test runner; a median step takes 15 s). The capacity above is an upper bound: on each node the module runs at most floor(the cores of its build slice's CPU quota / this) steps at once, the quota read live from its cgroup (issue 1806), so a lowered build CPU share never starves its steps. Above 0.",
|
||||
"minimum": 0.1,
|
||||
"default": 2
|
||||
}
|
||||
},
|
||||
"tools": [
|
||||
@@ -34,6 +46,7 @@
|
||||
"build_node_release",
|
||||
"build_node_step",
|
||||
"build_node_steps",
|
||||
"build_node_step_end",
|
||||
"build_node_toolchains",
|
||||
"build_node_status",
|
||||
"build_node_health"
|
||||
@@ -99,7 +112,7 @@
|
||||
"path": "${dir:state}/settings.json",
|
||||
"mode": "0600",
|
||||
"owner": "mesh-build-node",
|
||||
"takes-config": ["capacity"],
|
||||
"takes-config": ["capacity", "cores-per-step", "build-hours"],
|
||||
"merge": "json",
|
||||
"template": "files/settings.json"
|
||||
},
|
||||
|
||||
@@ -25,9 +25,7 @@
|
||||
"secrets": {
|
||||
"postgres-database": "${dir:state}/database.secret"
|
||||
},
|
||||
"consumes": [
|
||||
"mesh-controller.built-before"
|
||||
],
|
||||
"consumes": [],
|
||||
"emits": [
|
||||
"registered",
|
||||
"upgraded",
|
||||
@@ -92,5 +90,12 @@
|
||||
"from": "files"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"invokes": [
|
||||
"mesh-delivery-builder.builder_builds_since"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-delivery-builder.builds",
|
||||
"mesh-delivery-indexer.manifests"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"module": "mesh-conditions",
|
||||
"version": "1",
|
||||
"runs-as": "mesh-conditions",
|
||||
"claims": [
|
||||
{
|
||||
"name": "mesh-conditions",
|
||||
"scope": "mesh",
|
||||
"serves": [
|
||||
"conditions",
|
||||
"silence",
|
||||
"compare",
|
||||
"take-over",
|
||||
"hand-back",
|
||||
"resync"
|
||||
]
|
||||
}
|
||||
],
|
||||
"uses": [
|
||||
"operator-channel"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-delivery-watchman.findings",
|
||||
"mesh-self-check.findings",
|
||||
"mesh-healers.findings",
|
||||
"mesh-delivery-assigner.findings",
|
||||
"messenger.findings",
|
||||
"mesh-provisioner.findings",
|
||||
"artifact-store-tools.findings",
|
||||
"mesh-healers.attempts",
|
||||
"mesh-controller.conditions",
|
||||
"mesh-controller.lease",
|
||||
"mesh-delivery-assigner.wants",
|
||||
"node-engine.have",
|
||||
"mesh-delivery-assigner.placement"
|
||||
],
|
||||
"state": [
|
||||
"conditions",
|
||||
{
|
||||
"name": "history",
|
||||
"ttl-seconds": 7776000
|
||||
},
|
||||
"takeover",
|
||||
"held",
|
||||
{
|
||||
"name": "bounds",
|
||||
"key-ttl": true
|
||||
},
|
||||
"asked"
|
||||
],
|
||||
"own-secrets": {
|
||||
"broker": "${dir:state}/broker"
|
||||
},
|
||||
"secrets-owner": "mesh-conditions",
|
||||
"resources": [
|
||||
{
|
||||
"id": "account",
|
||||
"type": "user",
|
||||
"name": "mesh-conditions",
|
||||
"shell": "/usr/bin/nologin",
|
||||
"home": "/var/lib/mesh-conditions"
|
||||
},
|
||||
{
|
||||
"id": "state",
|
||||
"type": "directory",
|
||||
"mode": "0700",
|
||||
"owner": "mesh-conditions",
|
||||
"place": ".",
|
||||
"unknown": "program"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
"artifacts": [
|
||||
{
|
||||
"name": "tools",
|
||||
"kind": "bundle",
|
||||
"language": "go",
|
||||
"system": "arch",
|
||||
"from": "cmd/mesh-conditions",
|
||||
"binary": "mesh-conditions",
|
||||
"loads": [
|
||||
"mesh-conditions"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,10 @@
|
||||
"name": "mesh-config",
|
||||
"scope": "mesh",
|
||||
"serves": [
|
||||
"config"
|
||||
"config",
|
||||
"compare",
|
||||
"take-over",
|
||||
"hand-back"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -23,14 +26,30 @@
|
||||
"gitea.forge.pull-request.closed"
|
||||
],
|
||||
"invokes": [
|
||||
"seat:mesh-hand-acts.hand-act",
|
||||
"seat:mesh-hand-acts.warranted",
|
||||
"seat:mesh-controller.hand-act",
|
||||
"seat:mesh-controller.warranted",
|
||||
"gitea.gitea_get_pull_request"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-controller.assignments",
|
||||
"mesh-delivery-assigner.placement",
|
||||
"mesh-delivery-assigner.wants",
|
||||
"mesh-delivery-builder.builds",
|
||||
"mesh-delivery-indexer.modules",
|
||||
"mesh-delivery-indexer.manifests",
|
||||
"mesh-controller.predefined",
|
||||
"mesh-controller.declared-config",
|
||||
"mesh-controller.predefined"
|
||||
"mesh-delivery-indexer.predefined",
|
||||
"mesh-delivery-indexer.config-candidates",
|
||||
"mesh-controller.lease"
|
||||
],
|
||||
"tools": [
|
||||
"config_compare",
|
||||
"config_take_over",
|
||||
"config_hand_back",
|
||||
"config_declared",
|
||||
"config_resync"
|
||||
],
|
||||
"state": [
|
||||
"values",
|
||||
@@ -38,7 +57,9 @@
|
||||
"predefined",
|
||||
"proposals",
|
||||
"pulls",
|
||||
"kept"
|
||||
"kept",
|
||||
"declared",
|
||||
"takeover"
|
||||
],
|
||||
"logs": [
|
||||
"history"
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"refusal-stall-floor-minutes": 10,
|
||||
"author-new-head-minutes": 120
|
||||
"author-new-head-minutes": 120,
|
||||
"check-gates-merge": true
|
||||
}
|
||||
|
||||
+26
-5
@@ -14,7 +14,8 @@
|
||||
"table",
|
||||
"stalled",
|
||||
"recheck",
|
||||
"close"
|
||||
"close",
|
||||
"settle"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -26,13 +27,17 @@
|
||||
"gitea.forge.pull-request.edited",
|
||||
"gitea.forge.pull-request.closed",
|
||||
"mesh-delivery-forge-bridge.forge.**",
|
||||
"mesh-config.config-changed"
|
||||
"mesh-config.config-changed",
|
||||
"gitea.repo.writable"
|
||||
],
|
||||
"emits": [
|
||||
"transition",
|
||||
"group",
|
||||
"merged"
|
||||
],
|
||||
"uses": [
|
||||
"operator-channel"
|
||||
],
|
||||
"invokes": [
|
||||
"gitea.gitea_commit_statuses",
|
||||
"gitea.gitea_contains",
|
||||
@@ -57,14 +62,23 @@
|
||||
{
|
||||
"name": "source",
|
||||
"history": 64
|
||||
},
|
||||
"conditions",
|
||||
{
|
||||
"name": "turns",
|
||||
"history": 5
|
||||
}
|
||||
],
|
||||
"reads": [
|
||||
"mesh-delivery-teller.answers",
|
||||
"mesh-delivery-checker.verdicts"
|
||||
"mesh-delivery-checker.verdicts",
|
||||
"mesh-delivery-view.reach"
|
||||
],
|
||||
"tools": [
|
||||
"delivery_status"
|
||||
"delivery_hand_now",
|
||||
"delivery_merge_again",
|
||||
"delivery_status",
|
||||
"delivery_turns"
|
||||
],
|
||||
"config": {
|
||||
"refusal-stall-floor-minutes": {
|
||||
@@ -82,6 +96,12 @@
|
||||
"maximum": 10080,
|
||||
"trusted": false,
|
||||
"default": 120
|
||||
},
|
||||
"check-gates-merge": {
|
||||
"type": "boolean",
|
||||
"description": "Whether mesh/check gates the merge. True (the default): the operator's Approve is asked, and a merge handed, only on a passing verdict judged against the trunk's head, and a trunk's move puts a verdict out of date (ADR 0447, ADR 0505 §4). False (the operator, 2026-10-25 22:56: \"run the check locally only, but not as a gate, it loses us too much time\"; developers run the unit and integration levels locally before a pull request): a pull request reviewed at its head is ready, and its Approve is asked once the check at its heads (a group: of all its heads together) has a verdict, a pass or a failure said in the ask, or after 60 minutes with none, said so (the operator, 2026-10-27 23:54: \"if you don't want me to approve it, don't send the approval request\"); an approved merge waits for no verdict; no merge is refused for a check judged on an older trunk; a later verdict is shown on the pull request and the delivery, and asks a pending Approve again in its words; a group still merges all its members in one pass. Set it false together with the gitea module's check-gates-merge, which lets its merge tool merge an approved head without a passing mesh/check.",
|
||||
"trusted": false,
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
@@ -99,7 +119,8 @@
|
||||
"mode": "0600",
|
||||
"takes-config": [
|
||||
"refusal-stall-floor-minutes",
|
||||
"author-new-head-minutes"
|
||||
"author-new-head-minutes",
|
||||
"check-gates-merge"
|
||||
],
|
||||
"merge": "json",
|
||||
"template": "files/settings.json"
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"module": "mesh-hand-acts",
|
||||
"version": "1",
|
||||
"runs-as": "mesh-hand-acts",
|
||||
"claims": [
|
||||
{
|
||||
"name": "mesh-hand-acts",
|
||||
"scope": "mesh",
|
||||
"serves": [
|
||||
"hand-act",
|
||||
"hand-acts",
|
||||
"warranted"
|
||||
]
|
||||
}
|
||||
],
|
||||
"reads": [
|
||||
"mesh-controller.hand-acts",
|
||||
"messenger.asks"
|
||||
],
|
||||
"logs": [
|
||||
{
|
||||
"name": "acts",
|
||||
"max-age-days": 400
|
||||
}
|
||||
],
|
||||
"state": [
|
||||
"warrants"
|
||||
],
|
||||
"own-secrets": {
|
||||
"broker": "${dir:state}/broker"
|
||||
},
|
||||
"secrets-owner": "mesh-hand-acts",
|
||||
"resources": [
|
||||
{
|
||||
"id": "account",
|
||||
"type": "user",
|
||||
"name": "mesh-hand-acts",
|
||||
"shell": "/usr/bin/nologin",
|
||||
"home": "/var/lib/mesh-hand-acts"
|
||||
},
|
||||
{
|
||||
"id": "state",
|
||||
"type": "directory",
|
||||
"mode": "0700",
|
||||
"owner": "mesh-hand-acts",
|
||||
"place": ".",
|
||||
"unknown": "program"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
"artifacts": [
|
||||
{
|
||||
"name": "tools",
|
||||
"kind": "bundle",
|
||||
"language": "go",
|
||||
"system": "arch",
|
||||
"from": "cmd/mesh-hand-acts",
|
||||
"binary": "mesh-hand-acts",
|
||||
"loads": [
|
||||
"mesh-hand-acts"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"module": "mesh-healers",
|
||||
"version": "1",
|
||||
"runs-as": "mesh-healers",
|
||||
"claims": [
|
||||
{
|
||||
"name": "mesh-healers",
|
||||
"scope": "mesh",
|
||||
"serves": [
|
||||
"healers",
|
||||
"heal",
|
||||
"drill"
|
||||
]
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"mesh-conditions.condition-raised",
|
||||
"mesh-conditions.condition-changed",
|
||||
"mesh-hand-acts.act-recorded"
|
||||
],
|
||||
"invokes": [
|
||||
"mesh-grants.grants_assert",
|
||||
"seat:mesh-hand-acts.hand-act",
|
||||
"seat:mesh-controller.drill"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-controller.lease",
|
||||
"mesh-conditions.conditions",
|
||||
"mesh-controller.hand-acts"
|
||||
],
|
||||
"state": [
|
||||
{
|
||||
"name": "attempts",
|
||||
"key-ttl": true
|
||||
},
|
||||
{
|
||||
"name": "would",
|
||||
"key-ttl": true
|
||||
},
|
||||
"findings",
|
||||
{
|
||||
"name": "wakes",
|
||||
"key-ttl": true
|
||||
}
|
||||
],
|
||||
"own-secrets": {
|
||||
"broker": "${dir:state}/broker"
|
||||
},
|
||||
"secrets-owner": "mesh-healers",
|
||||
"resources": [
|
||||
{
|
||||
"id": "account",
|
||||
"type": "user",
|
||||
"name": "mesh-healers",
|
||||
"shell": "/usr/bin/nologin",
|
||||
"home": "/var/lib/mesh-healers"
|
||||
},
|
||||
{
|
||||
"id": "state",
|
||||
"type": "directory",
|
||||
"mode": "0700",
|
||||
"owner": "mesh-healers",
|
||||
"place": ".",
|
||||
"unknown": "program"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
"artifacts": [
|
||||
{
|
||||
"name": "tools",
|
||||
"kind": "bundle",
|
||||
"language": "go",
|
||||
"system": "arch",
|
||||
"from": "cmd/mesh-healers",
|
||||
"binary": "mesh-healers",
|
||||
"loads": [
|
||||
"mesh-healers"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -62,10 +62,13 @@
|
||||
"mesh-catalog modules/mesh-build-node",
|
||||
"mesh-catalog modules/mesh-catalog",
|
||||
"mesh-catalog modules/mesh-cli",
|
||||
"mesh-catalog modules/mesh-conditions",
|
||||
"mesh-catalog modules/mesh-config",
|
||||
"mesh-catalog modules/mesh-delivery",
|
||||
"mesh-catalog modules/mesh-delivery-gate",
|
||||
"mesh-catalog modules/mesh-files",
|
||||
"mesh-catalog modules/mesh-hand-acts",
|
||||
"mesh-catalog modules/mesh-healers",
|
||||
"mesh-catalog modules/mesh-issues",
|
||||
"mesh-catalog modules/mesh-knowledge",
|
||||
"mesh-catalog modules/mesh-mail",
|
||||
@@ -75,6 +78,7 @@
|
||||
"mesh-catalog modules/mesh-provisioner",
|
||||
"mesh-catalog modules/mesh-provisioner-client",
|
||||
"mesh-catalog modules/mesh-reads",
|
||||
"mesh-catalog modules/mesh-self-check",
|
||||
"mesh-catalog modules/mesh-vault",
|
||||
"mesh-catalog modules/mesh-watcher",
|
||||
"mesh-catalog modules/messenger",
|
||||
|
||||
@@ -13,12 +13,17 @@
|
||||
"move",
|
||||
"note",
|
||||
"link",
|
||||
"milestones",
|
||||
"milestone-set",
|
||||
"milestone-move",
|
||||
"import",
|
||||
"groom",
|
||||
"set",
|
||||
"tracking",
|
||||
"reserve",
|
||||
"fix-times"
|
||||
"fix-times",
|
||||
"learn-fixes",
|
||||
"changes"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -33,12 +38,17 @@
|
||||
"move",
|
||||
"note",
|
||||
"link",
|
||||
"milestones",
|
||||
"milestone-set",
|
||||
"milestone-move",
|
||||
"import",
|
||||
"groom",
|
||||
"set",
|
||||
"tracking",
|
||||
"reserve",
|
||||
"fix-times"
|
||||
"fix-times",
|
||||
"learn-fixes",
|
||||
"changes"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -52,7 +62,9 @@
|
||||
"triaged",
|
||||
"ready",
|
||||
"ready-to-verify",
|
||||
"reserved"
|
||||
"reserved",
|
||||
"milestone-set",
|
||||
"milestone-moved"
|
||||
],
|
||||
"consumes": [
|
||||
"mesh-issues.opened",
|
||||
@@ -66,6 +78,7 @@
|
||||
"seat:operator-channel.notify",
|
||||
"gitea.gitea_pull_reviews",
|
||||
"gitea.gitea_contains",
|
||||
"gitea.gitea_get_pull_request",
|
||||
"records.records_status",
|
||||
"records.records_list",
|
||||
"records.records_read",
|
||||
@@ -81,7 +94,11 @@
|
||||
},
|
||||
"counters",
|
||||
"grooming",
|
||||
"reservations"
|
||||
"reservations",
|
||||
{
|
||||
"name": "milestones",
|
||||
"history": 5
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"first-number": {
|
||||
@@ -157,10 +174,13 @@
|
||||
"mesh-catalog modules/mesh-build-node",
|
||||
"mesh-catalog modules/mesh-catalog",
|
||||
"mesh-catalog modules/mesh-cli",
|
||||
"mesh-catalog modules/mesh-conditions",
|
||||
"mesh-catalog modules/mesh-config",
|
||||
"mesh-catalog modules/mesh-delivery",
|
||||
"mesh-catalog modules/mesh-delivery-gate",
|
||||
"mesh-catalog modules/mesh-files",
|
||||
"mesh-catalog modules/mesh-hand-acts",
|
||||
"mesh-catalog modules/mesh-healers",
|
||||
"mesh-catalog modules/mesh-issues",
|
||||
"mesh-catalog modules/mesh-knowledge",
|
||||
"mesh-catalog modules/mesh-mail",
|
||||
@@ -170,6 +190,7 @@
|
||||
"mesh-catalog modules/mesh-provisioner",
|
||||
"mesh-catalog modules/mesh-provisioner-client",
|
||||
"mesh-catalog modules/mesh-reads",
|
||||
"mesh-catalog modules/mesh-self-check",
|
||||
"mesh-catalog modules/mesh-vault",
|
||||
"mesh-catalog modules/mesh-watcher",
|
||||
"mesh-catalog modules/messenger",
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
"propose",
|
||||
"import",
|
||||
"return",
|
||||
"withdraw"
|
||||
"withdraw",
|
||||
"progress"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -52,13 +53,15 @@
|
||||
"propose",
|
||||
"import",
|
||||
"return",
|
||||
"withdraw"
|
||||
"withdraw",
|
||||
"progress"
|
||||
]
|
||||
}
|
||||
],
|
||||
"tools": [
|
||||
"knowledge_health",
|
||||
"knowledge_highest"
|
||||
"knowledge_highest",
|
||||
"knowledge_marks"
|
||||
],
|
||||
"emits": [
|
||||
"reserved",
|
||||
@@ -81,7 +84,14 @@
|
||||
"records.records_status",
|
||||
"records.records_list",
|
||||
"records.records_read",
|
||||
"seat:operator-channel.notify"
|
||||
"seat:operator-channel.notify",
|
||||
"seat:issue-tracker.list",
|
||||
"seat:issue-tracker.get",
|
||||
"seat:issue-tracker.milestones",
|
||||
"seat:issue-tracker.changes",
|
||||
"seat:mesh-delivery.deliveries",
|
||||
"seat:mesh-delivery.show",
|
||||
"seat:mesh-delivery.groups"
|
||||
],
|
||||
"config": {
|
||||
"judge-model": {
|
||||
|
||||
+26
-1
@@ -11,11 +11,36 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"uses": [
|
||||
"operator-channel"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-delivery-assigner.placement",
|
||||
"mesh-delivery-assigner.wants",
|
||||
"mesh-delivery-indexer.modules",
|
||||
"mesh-delivery-indexer.manifests",
|
||||
"mesh-delivery-builder.builds",
|
||||
"node-engine.have",
|
||||
"mesh-config.resolved",
|
||||
"gitea.bound",
|
||||
"keycloak.bound",
|
||||
"postgres.bound",
|
||||
"route-adapter.bound",
|
||||
"mesh-vault.bound"
|
||||
],
|
||||
"tools": [
|
||||
"provisioner_provisions",
|
||||
"provisioner_plans",
|
||||
"provisioner_compose",
|
||||
"provisioner_decide"
|
||||
],
|
||||
"state": [
|
||||
"registry",
|
||||
"needs",
|
||||
"applied",
|
||||
"collect"
|
||||
"collect",
|
||||
"provisions",
|
||||
"plans"
|
||||
],
|
||||
"own-secrets": {
|
||||
"broker": "${dir:state}/broker"
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"module": "mesh-self-check",
|
||||
"version": "1",
|
||||
"runs-as": "mesh-self-check",
|
||||
"claims": [
|
||||
{
|
||||
"name": "mesh-self-check",
|
||||
"scope": "mesh",
|
||||
"serves": [
|
||||
"doctor",
|
||||
"probes"
|
||||
]
|
||||
}
|
||||
],
|
||||
"invokes": [
|
||||
"nats.nats_streams",
|
||||
"nats.nats_closed_connections",
|
||||
"seat:mesh-watchdogs.signals",
|
||||
"seat:node-intrusion-prevention.banned"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-delivery-assigner.placement",
|
||||
"mesh-delivery-assigner.seat-holders",
|
||||
"mesh-delivery-watchman.presence",
|
||||
"mesh-host.health",
|
||||
"disk-load.readings",
|
||||
"restic.good",
|
||||
"mesh-delivery-indexer.modules",
|
||||
"mesh-delivery-indexer.manifests"
|
||||
],
|
||||
"state": [
|
||||
"findings",
|
||||
"verdict",
|
||||
{
|
||||
"name": "verdicts",
|
||||
"ttl-seconds": 604800
|
||||
}
|
||||
],
|
||||
"own-secrets": {
|
||||
"broker": "${dir:state}/broker"
|
||||
},
|
||||
"secrets-owner": "mesh-self-check",
|
||||
"resources": [
|
||||
{
|
||||
"id": "account",
|
||||
"type": "user",
|
||||
"name": "mesh-self-check",
|
||||
"shell": "/usr/bin/nologin",
|
||||
"home": "/var/lib/mesh-self-check"
|
||||
},
|
||||
{
|
||||
"id": "state",
|
||||
"type": "directory",
|
||||
"mode": "0700",
|
||||
"owner": "mesh-self-check",
|
||||
"place": ".",
|
||||
"unknown": "program"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
"artifacts": [
|
||||
{
|
||||
"name": "tools",
|
||||
"kind": "bundle",
|
||||
"language": "go",
|
||||
"system": "arch",
|
||||
"from": "cmd/mesh-self-check",
|
||||
"binary": "mesh-self-check",
|
||||
"loads": [
|
||||
"mesh-self-check"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"probes": {
|
||||
"type": "list",
|
||||
"description": "The ids of the probes that run, each judging one thing of the mesh (mesh-self-check.probes lists them with what each asserts). A probe not listed runs nothing and raises nothing, and what it raised before is cleared. D8 and DA are in the code and off by default.",
|
||||
"trusted": true,
|
||||
"default": [
|
||||
"D13",
|
||||
"D-fill"
|
||||
],
|
||||
"runtime": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,9 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "secret",
|
||||
"credential": {
|
||||
"form": "pair"
|
||||
},
|
||||
"scope": "mesh",
|
||||
"identity": {
|
||||
"in": "a vault entry"
|
||||
@@ -14,10 +17,27 @@
|
||||
"emits": [
|
||||
"provisioned",
|
||||
"rotated",
|
||||
"secret-changed"
|
||||
"secret-changed",
|
||||
"account-hashed",
|
||||
"own-replaced",
|
||||
"account-issued",
|
||||
"signed"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-controller.assignments"
|
||||
"node-engine.have",
|
||||
"mesh-grants.accounts",
|
||||
"mesh-controller.lease",
|
||||
"mesh-delivery-assigner.placement",
|
||||
"mesh-provisioner.plans",
|
||||
"mesh-provisioner.provisions"
|
||||
],
|
||||
"state": [
|
||||
{
|
||||
"name": "bus-accounts",
|
||||
"history": 2
|
||||
},
|
||||
"signers",
|
||||
"bound"
|
||||
],
|
||||
"receives": {
|
||||
"secret": "${dir:grants}/mesh.json"
|
||||
@@ -135,7 +155,8 @@
|
||||
"MESH_VAULT_LEDGER": "${dir:ledger}",
|
||||
"MESH_VAULT_ROOT": "${dir:root}",
|
||||
"MESH_VAULT_STORE": "${dir:store}",
|
||||
"MESH_VAULT_STATE": "${dir:state}"
|
||||
"MESH_VAULT_STATE": "${dir:state}",
|
||||
"MESH_VAULT_SECRET_ASK_CALLERS": "node-tools"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -145,6 +166,10 @@
|
||||
"secret_holders",
|
||||
"secret_verify",
|
||||
"secret_handed",
|
||||
"secret_own",
|
||||
"account_hash",
|
||||
"account_adopt",
|
||||
"account_retire",
|
||||
"secret_asks",
|
||||
"secret_vault_export",
|
||||
"provisioner_retirement",
|
||||
@@ -152,7 +177,12 @@
|
||||
"provisioner_retire_reject",
|
||||
"provisioner_delete",
|
||||
"vault_status",
|
||||
"vault_health"
|
||||
"vault_health",
|
||||
"own_drift",
|
||||
"own_take_switch",
|
||||
"vault_signers",
|
||||
"vault_signed",
|
||||
"signers_reassert"
|
||||
],
|
||||
"claims": [
|
||||
{
|
||||
@@ -166,7 +196,10 @@
|
||||
"rotate",
|
||||
"move-in",
|
||||
"node-key",
|
||||
"move-asks"
|
||||
"move-asks",
|
||||
"own",
|
||||
"issue-account",
|
||||
"sign"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
"version": "1",
|
||||
"slug": "watch",
|
||||
"consumes": [
|
||||
"mesh-controller.doctor-heartbeat"
|
||||
"mesh-controller.doctor-heartbeat",
|
||||
"mesh-self-check.checked"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-conditions.takeover",
|
||||
"mesh-delivery-assigner.seat-holders"
|
||||
],
|
||||
"invokes": [
|
||||
"mesh-watcher.watcher_ping",
|
||||
"seat:mesh-controller.seats"
|
||||
"mesh-watcher.watcher_ping"
|
||||
],
|
||||
"own-secrets": {
|
||||
"telegram-token": "${dir:state}/telegram-token"
|
||||
@@ -39,7 +43,9 @@
|
||||
"type": "file",
|
||||
"path": "${dir:state}/settings.json",
|
||||
"mode": "0600",
|
||||
"takes-config": ["telegram-chat-id"],
|
||||
"takes-config": [
|
||||
"telegram-chat-id"
|
||||
],
|
||||
"merge": "json",
|
||||
"template": "files/settings.json"
|
||||
}
|
||||
|
||||
@@ -77,6 +77,9 @@
|
||||
"mesh-controller.condition-raised",
|
||||
"mesh-controller.condition-changed",
|
||||
"mesh-controller.condition-cleared",
|
||||
"mesh-conditions.condition-raised",
|
||||
"mesh-conditions.condition-changed",
|
||||
"mesh-conditions.condition-cleared",
|
||||
"mesh-delivery-view.moving",
|
||||
"mesh-delivery-view.settled",
|
||||
"mesh-delivery-view.stuck",
|
||||
@@ -90,9 +93,13 @@
|
||||
],
|
||||
"invokes": [
|
||||
"seat:mesh-controller.conditions",
|
||||
"seat:mesh-controller.root-free",
|
||||
"seat:mesh-conditions.conditions",
|
||||
"seat:node-engine.root-free",
|
||||
"seat:issue-tracker.tracking"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-conditions.takeover"
|
||||
],
|
||||
"state": [
|
||||
"open",
|
||||
"sent",
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
"identity": {
|
||||
"max": 20,
|
||||
"in": "an S3 access key"
|
||||
},
|
||||
"credential": {
|
||||
"form": "pair"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -36,8 +39,8 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"invokes": [
|
||||
"seat:mesh-controller.seats"
|
||||
"reads": [
|
||||
"mesh-delivery-assigner.seat-holders"
|
||||
],
|
||||
"contributes": {
|
||||
"route": {
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
"identity": {
|
||||
"max": 63,
|
||||
"in": "a MongoDB database name"
|
||||
},
|
||||
"credential": {
|
||||
"form": "pair"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
"scope": "mesh",
|
||||
"identity": {
|
||||
"in": "a Mosquitto client and topic prefix"
|
||||
},
|
||||
"credential": {
|
||||
"form": "pair"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
"nfs-share"
|
||||
],
|
||||
"reads": [
|
||||
"disk-load.readings",
|
||||
"nfs-server.exports"
|
||||
],
|
||||
"invokes": [
|
||||
"seat:mesh-controller.data"
|
||||
],
|
||||
"capabilities": [
|
||||
"package-manager",
|
||||
"service-manager"
|
||||
@@ -38,20 +36,20 @@
|
||||
"per-machine": true
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"shares": {
|
||||
"type": "string",
|
||||
"description": "The shares of another machine this machine mounts: space-separated name=mountpoint, each optionally :ro, or none (novox/hq ADR 0263 rule 5).",
|
||||
"trusted": true,
|
||||
"default": "none"
|
||||
},
|
||||
"sources": {
|
||||
"type": "string",
|
||||
"description": "The occasional sources this machine mounts: space-separated name=smb://[<user>@]<host>/<share>@<mountpoint> or name=disk:<uuid>@<mountpoint>, each optionally :ro, or none (novox/hq ADR 0263 rule 6); an SMB source's username is in its entry, its password the secret smb-password-<name> (novox/hq ADR 0283).",
|
||||
"trusted": true,
|
||||
"default": "none"
|
||||
}
|
||||
"config": {
|
||||
"shares": {
|
||||
"type": "string",
|
||||
"description": "The shares of another machine this machine mounts: space-separated name=mountpoint, each optionally :ro, or none (novox/hq ADR 0263 rule 5).",
|
||||
"trusted": true,
|
||||
"default": "none"
|
||||
},
|
||||
"sources": {
|
||||
"type": "string",
|
||||
"description": "The occasional sources this machine mounts: space-separated name=smb://[<user>@]<host>/<share>@<mountpoint> or name=disk:<uuid>@<mountpoint>, each optionally :ro, or none (novox/hq ADR 0263 rule 6); an SMB source's username is in its entry, its password the secret smb-password-<name> (novox/hq ADR 0283).",
|
||||
"trusted": true,
|
||||
"default": "none"
|
||||
}
|
||||
},
|
||||
"own-secrets": {
|
||||
"smb-password-*": {
|
||||
"path": "${dir:state}/smb-password-*.secret",
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
"identity": {
|
||||
"max": 128,
|
||||
"in": "a SQL Server login and database name"
|
||||
},
|
||||
"credential": {
|
||||
"form": "pair"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "mesh-bus",
|
||||
"scope": "mesh"
|
||||
"scope": "mesh",
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"claims": [
|
||||
@@ -19,12 +22,16 @@
|
||||
],
|
||||
"bus-users": "/var/lib/nats-module/conf/accounts.conf",
|
||||
"own-secrets": {
|
||||
"broker": "${dir:mesh-state}/broker"
|
||||
"broker": "${dir:mesh-state}/broker",
|
||||
"broker-nats-tools": "${dir:tools-secret}/broker-nats-tools"
|
||||
},
|
||||
"capabilities": [
|
||||
"container-runtime"
|
||||
],
|
||||
"emits": [],
|
||||
"emits": [
|
||||
"consumer-removed",
|
||||
"bucket-keys-removed"
|
||||
],
|
||||
"consumes": [],
|
||||
"listens": [
|
||||
{
|
||||
@@ -45,7 +52,9 @@
|
||||
"nats_buckets",
|
||||
"nats_users",
|
||||
"nats_user_can",
|
||||
"nats_snapshot_verify"
|
||||
"nats_snapshot_verify",
|
||||
"nats_consumer_remove",
|
||||
"nats_bucket_remove"
|
||||
],
|
||||
"guards": [
|
||||
8222
|
||||
@@ -86,6 +95,13 @@
|
||||
"mode": "0700",
|
||||
"unknown": "program"
|
||||
},
|
||||
{
|
||||
"id": "tools-secret",
|
||||
"type": "directory",
|
||||
"path": "/var/lib/mesh/nats-tools",
|
||||
"mode": "0711",
|
||||
"unknown": "program"
|
||||
},
|
||||
{
|
||||
"id": "snapshots",
|
||||
"type": "directory",
|
||||
@@ -190,11 +206,18 @@
|
||||
"loads": [
|
||||
"nats-tools"
|
||||
],
|
||||
"bus": {
|
||||
"removes": [
|
||||
"DEAD_LETTER_NOTICES.controller",
|
||||
"mesh-host_acts"
|
||||
]
|
||||
},
|
||||
"env": {
|
||||
"MESH_NATS_MONITOR": "http://127.0.0.1:8222",
|
||||
"MESH_NATS_CONTAINER": "mesh-broker-nats",
|
||||
"MESH_NATS_USERS_FILE": "/etc/nats/accounts.conf",
|
||||
"MESH_NATS_SNAPSHOTS_DIR": "${dir:snapshots}"
|
||||
"MESH_NATS_SNAPSHOTS_DIR": "${dir:snapshots}",
|
||||
"NATS_TOOLS_CREDENTIAL": "${dir:tools-secret}/broker-nats-tools"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
},
|
||||
"user": {
|
||||
"type": "string",
|
||||
"description": "The Nextcloud account the module's tools act as; empty is admin.",
|
||||
"description": "The Nextcloud account the module's tools act as; empty is mesh-admin, the account the module makes and keeps for itself. Any other account is used as given and never repaired.",
|
||||
"trusted": true,
|
||||
"default": ""
|
||||
}
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
{
|
||||
"name": "nfs-share",
|
||||
"scope": "mesh",
|
||||
"identity": false
|
||||
"identity": false,
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
@@ -45,26 +48,24 @@
|
||||
}
|
||||
],
|
||||
"reads": [
|
||||
"disk-load.readings",
|
||||
"mesh-delivery-assigner.seat-holders",
|
||||
"mounts.shares"
|
||||
],
|
||||
"invokes": [
|
||||
"seat:mesh-controller.seats",
|
||||
"seat:mesh-controller.data"
|
||||
],
|
||||
"config": {
|
||||
"shares": {
|
||||
"type": "string",
|
||||
"description": "The folders this machine exports, as space-separated name=path; the operator's, with no default (novox/hq ADR 0263).",
|
||||
"trusted": true,
|
||||
"required": true
|
||||
},
|
||||
"grants": {
|
||||
"type": "string",
|
||||
"description": "Which nodes may mount which share, and how: share=node:rw|ro[,node:rw|ro], entries separated by spaces, or none to export to no node whatever a node wants (novox/hq ADR 0263).",
|
||||
"trusted": true,
|
||||
"default": "none"
|
||||
}
|
||||
"config": {
|
||||
"shares": {
|
||||
"type": "string",
|
||||
"description": "The folders this machine exports, as space-separated name=path; the operator's, with no default (novox/hq ADR 0263).",
|
||||
"trusted": true,
|
||||
"required": true
|
||||
},
|
||||
"grants": {
|
||||
"type": "string",
|
||||
"description": "Which nodes may mount which share, and how: share=node:rw|ro[,node:rw|ro], entries separated by spaces, or none to export to no node whatever a node wants (novox/hq ADR 0263).",
|
||||
"trusted": true,
|
||||
"default": "none"
|
||||
}
|
||||
},
|
||||
"facts": {
|
||||
"machines": {
|
||||
"path": "/etc/nfs-server/machines",
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "node-toolchain",
|
||||
"reach": "machine"
|
||||
"reach": "machine",
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "model-access",
|
||||
"scope": "node"
|
||||
"scope": "node",
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"listens": [
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "postgres-database",
|
||||
"credential": {"form": "pair"},
|
||||
"scope": "mesh",
|
||||
"identity": {
|
||||
"max": 63,
|
||||
@@ -195,6 +196,7 @@
|
||||
"bound"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-controller.assignments"
|
||||
"mesh-provisioner.plans",
|
||||
"mesh-provisioner.provisions"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -314,6 +314,48 @@
|
||||
"mode": "0644",
|
||||
"template": "templates/systemd/system/suspend-then-hibernate.target.d/mesh-power.conf"
|
||||
},
|
||||
{
|
||||
"id": "reboot-drop-ins",
|
||||
"type": "directory",
|
||||
"path": "/etc/systemd/system/reboot.target.d",
|
||||
"mode": "0755",
|
||||
"unknown": "program"
|
||||
},
|
||||
{
|
||||
"id": "reboot-bound",
|
||||
"type": "file",
|
||||
"path": "/etc/systemd/system/reboot.target.d/mesh-power.conf",
|
||||
"mode": "0644",
|
||||
"template": "templates/systemd/system/reboot.target.d/mesh-power.conf"
|
||||
},
|
||||
{
|
||||
"id": "poweroff-drop-ins",
|
||||
"type": "directory",
|
||||
"path": "/etc/systemd/system/poweroff.target.d",
|
||||
"mode": "0755",
|
||||
"unknown": "program"
|
||||
},
|
||||
{
|
||||
"id": "poweroff-bound",
|
||||
"type": "file",
|
||||
"path": "/etc/systemd/system/poweroff.target.d/mesh-power.conf",
|
||||
"mode": "0644",
|
||||
"template": "templates/systemd/system/poweroff.target.d/mesh-power.conf"
|
||||
},
|
||||
{
|
||||
"id": "halt-drop-ins",
|
||||
"type": "directory",
|
||||
"path": "/etc/systemd/system/halt.target.d",
|
||||
"mode": "0755",
|
||||
"unknown": "program"
|
||||
},
|
||||
{
|
||||
"id": "halt-bound",
|
||||
"type": "file",
|
||||
"path": "/etc/systemd/system/halt.target.d/mesh-power.conf",
|
||||
"mode": "0644",
|
||||
"template": "templates/systemd/system/halt.target.d/mesh-power.conf"
|
||||
},
|
||||
{
|
||||
"id": "udev-rule",
|
||||
"type": "file",
|
||||
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
# Written by the mesh (module power, novox/hq ADR 0211; issue 1126). Replaced on every push.
|
||||
#
|
||||
# A shutdown is bounded at ten minutes, not systemd's thirty. A unit started again during the shutdown
|
||||
# (on ace, 2026-10-28, the bus and the authorization manager) is never stopped a second time, and the
|
||||
# shutdown then waits on this job's timeout with nothing on the console. The target keeps its own
|
||||
# forcing action: the last phase still ends every process, unmounts and syncs.
|
||||
[Unit]
|
||||
JobTimeoutSec=10min
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
# Written by the mesh (module power, novox/hq ADR 0211; issue 1126). Replaced on every push.
|
||||
#
|
||||
# A shutdown is bounded at ten minutes, not systemd's thirty. A unit started again during the shutdown
|
||||
# (on ace, 2026-10-28, the bus and the authorization manager) is never stopped a second time, and the
|
||||
# shutdown then waits on this job's timeout with nothing on the console. The target keeps its own
|
||||
# forcing action: the last phase still ends every process, unmounts and syncs.
|
||||
[Unit]
|
||||
JobTimeoutSec=10min
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
# Written by the mesh (module power, novox/hq ADR 0211; issue 1126). Replaced on every push.
|
||||
#
|
||||
# A shutdown is bounded at ten minutes, not systemd's thirty. A unit started again during the shutdown
|
||||
# (on ace, 2026-10-28, the bus and the authorization manager) is never stopped a second time, and the
|
||||
# shutdown then waits on this job's timeout with nothing on the console. The target keeps its own
|
||||
# forcing action: the last phase still ends every process, unmounts and syncs.
|
||||
[Unit]
|
||||
JobTimeoutSec=10min
|
||||
@@ -7,6 +7,9 @@
|
||||
"scope": "mesh",
|
||||
"identity": {
|
||||
"in": "a Redis ACL user and key prefix"
|
||||
},
|
||||
"credential": {
|
||||
"form": "pair"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -41,40 +41,40 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"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
|
||||
}
|
||||
"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",
|
||||
@@ -139,22 +139,17 @@
|
||||
"MESH_BACKUP_DATA": "${dir:state}/data.conf"
|
||||
},
|
||||
"health": {
|
||||
"kind": "tool",
|
||||
"tool": "backup_health",
|
||||
"interval": "60s",
|
||||
"timeout": "20s",
|
||||
"looks": 2,
|
||||
"grace": "60s"
|
||||
"kind": "unit"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "measure",
|
||||
"id": "awake",
|
||||
"type": "process",
|
||||
"name": "restic-measure",
|
||||
"name": "restic-awake",
|
||||
"artifact": "tools",
|
||||
"run": [
|
||||
"./restic-backups",
|
||||
"measure"
|
||||
"awake"
|
||||
],
|
||||
"user": "${machine:account}",
|
||||
"env": {
|
||||
@@ -165,7 +160,12 @@
|
||||
"MESH_BACKUP_DATA": "${dir:state}/data.conf"
|
||||
},
|
||||
"health": {
|
||||
"kind": "unit"
|
||||
"kind": "tool",
|
||||
"tool": "backup_health",
|
||||
"interval": "60s",
|
||||
"timeout": "20s",
|
||||
"looks": 2,
|
||||
"grace": "60s"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -195,5 +195,11 @@
|
||||
"from": "files"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"reads": [
|
||||
"disk-load.readings"
|
||||
],
|
||||
"state": [
|
||||
"good"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "route",
|
||||
"credential": {"form": "none"},
|
||||
"scope": "mesh",
|
||||
"identity": false
|
||||
}
|
||||
@@ -129,6 +130,7 @@
|
||||
"bound"
|
||||
],
|
||||
"reads": [
|
||||
"mesh-controller.assignments"
|
||||
"mesh-provisioner.plans",
|
||||
"mesh-provisioner.provisions"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "greeting",
|
||||
"scope": "mesh"
|
||||
"scope": "mesh",
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"serves": {
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "internal-acme-ca",
|
||||
"scope": "mesh"
|
||||
"scope": "mesh",
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"serves": {
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "split-dns",
|
||||
"reach": "machine"
|
||||
"reach": "machine",
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requires": [
|
||||
|
||||
@@ -32,7 +32,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "analytics",
|
||||
"scope": "mesh"
|
||||
"scope": "mesh",
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"serves": {
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
"provides": [
|
||||
{
|
||||
"name": "x11-display",
|
||||
"reach": "machine"
|
||||
"reach": "machine",
|
||||
"credential": {
|
||||
"form": "none"
|
||||
}
|
||||
}
|
||||
],
|
||||
"claims": [
|
||||
|
||||
Reference in New Issue
Block a user