mesh/merge-gate pass: builds build-agent, gitea, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did witho…
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
Every merge to the controller's repository rebuilt the route proxy and the build seat's holder, because their builds read that repository whole. Named, the build seat hands each only its program's build source and the planner moves each only when that changes. A rename was said under its new name alone, so a file moved out of a build source changed nothing the planner could see.
223 lines
6.1 KiB
JSON
223 lines
6.1 KiB
JSON
{
|
|
"module": "route-proxy",
|
|
"version": "1",
|
|
"slug": "rproxy",
|
|
"capabilities": [
|
|
"container-runtime"
|
|
],
|
|
"provides": [
|
|
{
|
|
"name": "route",
|
|
"scope": "mesh",
|
|
"identity": false
|
|
}
|
|
],
|
|
"serves": {
|
|
"route": {}
|
|
},
|
|
"receives": {
|
|
"route": "${dir:routes-dir}/mesh.json"
|
|
},
|
|
"requires": [
|
|
"internal-acme-ca"
|
|
],
|
|
"binds": {
|
|
"internal-acme-ca": "${dir:state}/internal-acme-ca.json"
|
|
},
|
|
"own-secrets": {
|
|
"broker": "${dir:mesh-state}/broker"
|
|
},
|
|
"listens": [
|
|
{
|
|
"name": "http",
|
|
"port": 80,
|
|
"protocol": "tcp",
|
|
"from": "anywhere",
|
|
"why": "public HTTP, and the ACME HTTP-01 challenge answered at the name being certified"
|
|
},
|
|
{
|
|
"name": "https",
|
|
"port": 443,
|
|
"protocol": "tcp",
|
|
"from": "anywhere",
|
|
"why": "public HTTPS for every name the mesh routes here"
|
|
}
|
|
],
|
|
"data": {
|
|
"own": [
|
|
{
|
|
"id": "acme",
|
|
"path": "${dir:acme-cache}",
|
|
"class": "rebuildable",
|
|
"why": "issued certificates, issued again"
|
|
},
|
|
{
|
|
"id": "ca",
|
|
"path": "${dir:ca-dir}",
|
|
"class": "cache",
|
|
"why": "the authority's roots, fetched again at every start"
|
|
}
|
|
]
|
|
},
|
|
"resources": [
|
|
{
|
|
"id": "state",
|
|
"type": "directory",
|
|
"mode": "0700",
|
|
"place": "."
|
|
},
|
|
{
|
|
"id": "mesh-state",
|
|
"type": "directory",
|
|
"mode": "0700",
|
|
"place": "mesh"
|
|
},
|
|
{
|
|
"id": "routes-dir",
|
|
"type": "directory",
|
|
"path": "/var/lib/route-proxy/routes",
|
|
"mode": "0700"
|
|
},
|
|
{
|
|
"id": "acme-cache",
|
|
"type": "directory",
|
|
"path": "/var/lib/route-proxy/acme",
|
|
"mode": "0700"
|
|
},
|
|
{
|
|
"id": "ca-dir",
|
|
"type": "directory",
|
|
"path": "/var/lib/route-proxy/ca",
|
|
"mode": "0755"
|
|
},
|
|
{
|
|
"id": "acme-env",
|
|
"type": "file",
|
|
"path": "${dir:state}/acme.env",
|
|
"mode": "0600",
|
|
"content": "ACME_DIRECTORY=https://acme-v02.api.letsencrypt.org:443/directory\nACME_ROOTS=https://acme-v02.api.letsencrypt.org:443\nACME_ROOTS_PATH=\n"
|
|
},
|
|
{
|
|
"id": "internal-acme-env",
|
|
"type": "file",
|
|
"path": "${dir:state}/internal-acme.env",
|
|
"mode": "0600",
|
|
"content": "INTERNAL_ACME_DIRECTORY=https://${bound:internal-acme-ca:at}:${bound:internal-acme-ca:port}${bound:internal-acme-ca:path}\nINTERNAL_ACME_ROOTS=https://${bound:internal-acme-ca:at}:${bound:internal-acme-ca:port}${bound:internal-acme-ca:roots}\nINTERNAL_ACME_ROOTS_PATH=${bound:internal-acme-ca:roots}\n"
|
|
},
|
|
{
|
|
"id": "trust",
|
|
"type": "container",
|
|
"name": "route-proxy-trust",
|
|
"artifact": "trust",
|
|
"run-once": true,
|
|
"network": "host",
|
|
"env-file": [
|
|
"${dir:state}/acme.env"
|
|
],
|
|
"volumes": [
|
|
"${dir:ca-dir}:/ca"
|
|
],
|
|
"args": [
|
|
"sh",
|
|
"-c",
|
|
"if [ -z \"$ACME_ROOTS_PATH\" ]; then cp /etc/ssl/certs/ca-certificates.crt /ca/root.crt; exit 0; fi; for i in $(seq 1 60); do wget -q -T 10 --no-check-certificate -O /ca/root.crt \"$ACME_ROOTS\" && grep -q 'BEGIN CERTIFICATE' /ca/root.crt && exit 0; sleep 2; done; echo \"the authority at $ACME_ROOTS did not serve its roots within two minutes\" >&2; exit 1"
|
|
],
|
|
"restart-on": [
|
|
"acme-env"
|
|
]
|
|
},
|
|
{
|
|
"id": "internal-trust",
|
|
"type": "container",
|
|
"name": "route-proxy-internal-trust",
|
|
"artifact": "trust",
|
|
"run-once": true,
|
|
"network": "host",
|
|
"env-file": [
|
|
"${dir:state}/internal-acme.env"
|
|
],
|
|
"volumes": [
|
|
"${dir:ca-dir}:/ca"
|
|
],
|
|
"args": [
|
|
"sh",
|
|
"-c",
|
|
"if [ -z \"$INTERNAL_ACME_ROOTS_PATH\" ]; then cp /etc/ssl/certs/ca-certificates.crt /ca/internal-root.crt; exit 0; fi; for i in $(seq 1 60); do wget -q -T 10 --no-check-certificate -O /ca/internal-root.crt \"$INTERNAL_ACME_ROOTS\" && grep -q 'BEGIN CERTIFICATE' /ca/internal-root.crt && exit 0; sleep 2; done; echo \"the authority at $INTERNAL_ACME_ROOTS did not serve its roots within two minutes\" >&2; exit 1"
|
|
],
|
|
"restart-on": [
|
|
"internal-acme-env"
|
|
]
|
|
},
|
|
{
|
|
"id": "server",
|
|
"type": "container",
|
|
"name": "route-proxy",
|
|
"artifact": "server",
|
|
"network": "host",
|
|
"env-file": [
|
|
"${dir:state}/acme.env",
|
|
"${dir:state}/internal-acme.env"
|
|
],
|
|
"volumes": [
|
|
"${dir:routes-dir}:/routes:ro",
|
|
"${dir:acme-cache}:/acme",
|
|
"${dir:ca-dir}:/ca:ro",
|
|
"${dir:mesh-state}/broker:/run/secrets/broker:ro"
|
|
],
|
|
"env": {
|
|
"ROUTES": "/routes/mesh.json",
|
|
"LISTEN": ":80",
|
|
"TLS_LISTEN": ":443",
|
|
"ACME_CACHE": "/acme",
|
|
"ACME_CA_BUNDLE": "/ca/root.crt",
|
|
"INTERNAL_ACME_CA_BUNDLE": "/ca/internal-root.crt",
|
|
"MESH_BROKER_FILE": "/run/secrets/broker"
|
|
},
|
|
"restart-on": [
|
|
"trust",
|
|
"acme-env",
|
|
"internal-trust",
|
|
"internal-acme-env"
|
|
],
|
|
"logging": "journald"
|
|
}
|
|
],
|
|
"build": {
|
|
"artifacts": [
|
|
{
|
|
"name": "server",
|
|
"kind": "image",
|
|
"from": "Dockerfile",
|
|
"compiles": "examples/route-proxy",
|
|
"context": {
|
|
"seat": "git",
|
|
"repository": "novox/mesh-controller",
|
|
"ref": "main"
|
|
}
|
|
},
|
|
{
|
|
"name": "trust",
|
|
"kind": "upstream",
|
|
"from": "alpine@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b"
|
|
}
|
|
],
|
|
"on": [
|
|
{
|
|
"arg": "GO_BASE",
|
|
"image": "golang@sha256:6c2a5538f964f1c82f97ad14988bf05de100d922d159d0e398b54c7b0ca0c6c9"
|
|
},
|
|
{
|
|
"arg": "ALPINE_BASE",
|
|
"image": "alpine@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc"
|
|
}
|
|
]
|
|
},
|
|
"jails": [
|
|
{
|
|
"name": "route-proxy",
|
|
"failregex": "^.*TLS handshake error from <HOST>:\\d+: (?:no public route for|acme/autocert: missing server name)\n ^.*refused: no route for .*, asked from <HOST>:\\d+$",
|
|
"jail": "backend = systemd\njournalmatch = CONTAINER_NAME=route-proxy\nport = http,https\nmaxretry = 10\nfindtime = 1d\nbantime = 1d"
|
|
}
|
|
]
|
|
}
|