diff --git a/modules/minio/Dockerfile b/modules/minio/Dockerfile index e5588e6..fc0e121 100644 --- a/modules/minio/Dockerfile +++ b/modules/minio/Dockerfile @@ -9,6 +9,11 @@ # image it RUNS in — the second must not carry a compiler. Declared in module.json's `build.on`. ARG BUILD_BASE ARG RUNTIME_BASE +ARG MC_CLI + +# Named so the final stage's COPY --from can reference a stage, not an ARG — the legacy builder +# this host still runs doesn't expand ARGs inside COPY --from, only inside FROM. +FROM ${MC_CLI} AS mccli FROM ${BUILD_BASE} AS build # Compiled under /app/modules so `@novox/mesh-sdk` resolves upward into the base's own @@ -22,6 +27,13 @@ RUN node /app/node_modules/typescript/bin/tsc client.ts tools/index.ts provision FROM ${RUNTIME_BASE} COPY --from=build /app/modules/minio/dist /app/modules/minio/dist +# The provisioner shells out to mc to actually create buckets and service accounts on the running +# minio server — mc itself was never in this runtime image, only in minio's own. Silently retried +# "spawn mc ENOENT" forever: a requirement was granted at the control-plane level without ever +# materializing the credential on minio. /usr/bin/mc there is a symlink to the real binary, mcli — +# both copied so the symlink resolves. +COPY --from=mccli /usr/bin/mcli /usr/bin/mcli +COPY --from=mccli /usr/bin/mc /usr/bin/mc # Every serve-time entrypoint, loaded by the runtime in serve mode: tools and events serve, and a # provider's provisioner runs its reconcile loop in the same process, with the broker connected — # the convention novox/hq issues 060/061 settled. diff --git a/modules/minio/module.json b/modules/minio/module.json index bbca5d2..8b1a05a 100644 --- a/modules/minio/module.json +++ b/modules/minio/module.json @@ -25,7 +25,7 @@ "serves": { "s3-bucket": { "scheme": "http", - "region": "us-east-1", + "region": "eu-west", "port": 9000 } }, @@ -99,7 +99,8 @@ "/var/lib/minio/root.secret:/run/secrets/root:ro" ], "env": { - "MINIO_ROOT_PASSWORD_FILE": "/run/secrets/root" + "MINIO_ROOT_PASSWORD_FILE": "/run/secrets/root", + "MINIO_REGION": "eu-west" } }, { @@ -116,6 +117,7 @@ "MESH_MINIO_ENDPOINT": "http://minio:9000", "MESH_MINIO_ROOT_USER": "meshroot", "MESH_MINIO_ROOT_PASSWORD_FILE": "/run/secrets/root", + "MESH_MINIO_REGION": "eu-west", "MESH_BROKER_FILE": "/run/secrets/broker", "MESH_RECEIVES": "/var/lib/minio/grants/mesh.json" }, @@ -133,6 +135,10 @@ "arg": "RUNTIME_BASE", "module": "mesh-tools", "artifact": "runtime" + }, + { + "arg": "MC_CLI", + "image": "docker.io/pgsty/minio@sha256:b6bfe7239bfc83fb90d31612d9704d86039dd714f7904b3f1ad68f211e602372" } ], "artifacts": [ diff --git a/modules/nextcloud/Dockerfile b/modules/nextcloud/Dockerfile index 5a6e5a8..d8a00e9 100644 --- a/modules/nextcloud/Dockerfile +++ b/modules/nextcloud/Dockerfile @@ -9,6 +9,11 @@ # image it RUNS in — the second must not carry a compiler. Declared in module.json's `build.on`. ARG BUILD_BASE ARG RUNTIME_BASE +ARG DOCKER_CLI + +# Named so the final stage's COPY --from can reference a stage, not an ARG — the legacy builder +# this host still runs doesn't expand ARGs inside COPY --from, only inside FROM. +FROM ${DOCKER_CLI} AS dockercli FROM ${BUILD_BASE} AS build # Compiled under /app/modules so `@novox/mesh-sdk` resolves upward into the base's own @@ -22,6 +27,11 @@ RUN node /app/node_modules/typescript/bin/tsc client.ts index.ts tools/index.ts FROM ${RUNTIME_BASE} COPY --from=build /app/modules/nextcloud/dist /app/modules/nextcloud/dist +# occ runs inside nextcloud's own container, reached over the mounted docker socket — which needs +# the docker CLI itself present here, not only the socket. Copied from Docker's own official client +# image rather than apt-installed, so this stays the one binary and nothing else (no daemon, no +# systemd unit, no package manager tree pulled in for it). +COPY --from=dockercli /usr/local/bin/docker /usr/local/bin/docker # Every serve-time entrypoint, loaded by the runtime in serve mode: tools and events serve, and a # provider's provisioner runs its reconcile loop in the same process, with the broker connected — # the convention novox/hq issues 060/061 settled. A container that instead ran only its diff --git a/modules/nextcloud/client.ts b/modules/nextcloud/client.ts index 3ee0ce4..e93d9c7 100644 --- a/modules/nextcloud/client.ts +++ b/modules/nextcloud/client.ts @@ -52,8 +52,13 @@ export class NextcloudClient { const container = cfg.container ?? env.MESH_NEXTCLOUD_CONTAINER ?? "nextcloud"; const ocsUrl = cfg.url ?? env.MESH_NEXTCLOUD_URL ?? `http://127.0.0.1:${env.NEXTCLOUD_PORT ?? "80"}`; const adminUser = cfg.user ?? env.MESH_NEXTCLOUD_ADMIN_USER ?? "admin"; - const adminPassword = cfg.password ?? env.MESH_NEXTCLOUD_ADMIN_PASSWORD; - if (!adminPassword) throw new Error("no Nextcloud admin password — set MESH_NEXTCLOUD_ADMIN_PASSWORD"); + const passwordFile = env.MESH_NEXTCLOUD_ADMIN_PASSWORD_FILE; + const adminPassword = cfg.password ?? env.MESH_NEXTCLOUD_ADMIN_PASSWORD + ?? (passwordFile ? readFileSync(passwordFile, "utf8").trim() : undefined); + if (!adminPassword) { + throw new Error("no Nextcloud admin password — set MESH_NEXTCLOUD_ADMIN_PASSWORD_FILE " + + "(or MESH_NEXTCLOUD_ADMIN_PASSWORD)"); + } return new NextcloudClient(container, ocsUrl.replace(/\/$/, ""), adminUser, adminPassword); } diff --git a/modules/nextcloud/module.json b/modules/nextcloud/module.json index 05a982b..621edeb 100644 --- a/modules/nextcloud/module.json +++ b/modules/nextcloud/module.json @@ -65,7 +65,7 @@ "type": "file", "path": "/var/lib/nextcloud-module/server.env", "mode": "0600", - "content": "POSTGRES_HOST=${bound:postgres-database:at}:${bound:postgres-database:port}\nPOSTGRES_DB=${bound:postgres-database:as}\nPOSTGRES_USER=${bound:postgres-database:as}\nPOSTGRES_PASSWORD=${secret:postgres-database}\nNEXTCLOUD_ADMIN_USER=admin\nNEXTCLOUD_ADMIN_PASSWORD=${secret:admin}\nOBJECTSTORE_S3_HOST=${bound:s3-bucket:at}\nOBJECTSTORE_S3_PORT=${bound:s3-bucket:port}\nOBJECTSTORE_S3_BUCKET=nextcloud\nOBJECTSTORE_S3_KEY=${bound:s3-bucket:as}\nOBJECTSTORE_S3_SECRET=${secret:s3-bucket}\nOBJECTSTORE_S3_SSL=false\nOBJECTSTORE_S3_USEPATH_STYLE=true\n" + "content": "POSTGRES_HOST=${bound:postgres-database:at}:${bound:postgres-database:port}\nPOSTGRES_DB=${bound:postgres-database:as}\nPOSTGRES_USER=${bound:postgres-database:as}\nPOSTGRES_PASSWORD=${secret:postgres-database}\nNEXTCLOUD_ADMIN_USER=mesh-admin\nNEXTCLOUD_ADMIN_PASSWORD=${secret:admin}\nOBJECTSTORE_S3_HOST=${bound:s3-bucket:at}\nOBJECTSTORE_S3_PORT=${bound:s3-bucket:port}\nOBJECTSTORE_S3_BUCKET=nextcloud\nOBJECTSTORE_S3_KEY=${bound:s3-bucket:as}\nOBJECTSTORE_S3_SECRET=${secret:s3-bucket}\nOBJECTSTORE_S3_SSL=false\nOBJECTSTORE_S3_USEPATH_STYLE=true\nOBJECTSTORE_S3_REGION=${bound:s3-bucket:region}\n" }, { "id": "html", @@ -78,7 +78,7 @@ "id": "server", "type": "container", "name": "nextcloud", - "image": "nextcloud@sha256:0b8261f6335af6b95264ce893b4d645857638e0fa151b5ba620f25f377318ae1", + "image": "nextcloud@sha256:fb966733647ea03f0446b0c22eac9733c8eb616d37b960caca9d4c3010e14a08", "env-file": [ "/var/lib/nextcloud-module/server.env" ], @@ -106,12 +106,15 @@ "volumes": [ "/var/lib/mesh/nextcloud/broker:/run/secrets/broker:ro", "/var/lib/mesh/nextcloud/config.json:/run/config/config.json:ro", + "/var/lib/nextcloud-module/admin.secret:/run/secrets/admin:ro", "/var/run/docker.sock:/var/run/docker.sock" ], "env": { "MESH_BROKER_FILE": "/run/secrets/broker", - "MESH_NEXTCLOUD_URL": "http://127.0.0.1:80", - "MESH_NEXTCLOUD_CONFIG_FILE": "/run/config/config.json" + "MESH_NEXTCLOUD_URL": "http://127.0.0.1:${port:80}", + "MESH_NEXTCLOUD_CONFIG_FILE": "/run/config/config.json", + "MESH_NEXTCLOUD_ADMIN_USER": "mesh-admin", + "MESH_NEXTCLOUD_ADMIN_PASSWORD_FILE": "/run/secrets/admin" }, "restart-on": [ "runtime-config" @@ -130,6 +133,10 @@ "arg": "RUNTIME_BASE", "module": "mesh-tools", "artifact": "runtime" + }, + { + "arg": "DOCKER_CLI", + "image": "docker@sha256:018edbc908e08fcc9dbf029c812c34251e9b4719e6f71ca0e5eae2a987d014ca" } ], "artifacts": [