From 0d9c580a0ac0f4439e752dbfa23982c56ba7d50f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Tue, 6 Oct 2026 15:09:32 +0200 Subject: [PATCH] Automate first-run LDAP and database setup The documented flow started web (with Solid Queue in Puma) before the databases existed, and required manually creating the 389ds back-end and seeding the LDAP directory and databases. Automate it: - add an ldap-init one-shot service that creates the 389ds back-end if it does not exist - add a web entrypoint that seeds LDAP and the databases on first start, and runs db:prepare on later boots - update README and AGENTS accordingly, including the reset steps --- AGENTS.md | 9 ++++++--- README.md | 29 +++++++++++++++++------------ docker-compose.yml | 24 +++++++++++++++++++++--- docker/ldap-init.sh | 14 ++++++++++++++ docker/web-entrypoint.sh | 14 ++++++++++++++ 5 files changed, 72 insertions(+), 18 deletions(-) create mode 100644 docker/ldap-init.sh create mode 100644 docker/web-entrypoint.sh diff --git a/AGENTS.md b/AGENTS.md index 13e4939..6fe3e30 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,9 +11,12 @@ Start services: `docker compose up` (web, ldap, redis, minio, liquor-cabinet, st The `web` service runs `bin/dev` (foreman: Puma + Tailwind CSS watcher) and embeds Solid Queue workers (`SOLID_QUEUE_IN_PUMA=true`). -First-time LDAP setup (after creating the 389ds backend once): -`docker compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be_name="dev"` -then `docker compose run web bin/rails ldap:setup`. +First-time LDAP and database setup is automated: the `ldap-init` service +creates the 389ds back-end, then the `web` entrypoint seeds LDAP and the +databases on first start and runs `db:prepare` on every boot. Manual +equivalents: `docker compose exec ldap dsconf localhost backend create +--suffix="dc=kosmos,dc=org" --be-name="dev"` and `docker compose run --rm web +bin/rails ldap:setup`. ## Common commands (prefix with `docker compose exec web`) diff --git a/README.md b/README.md index e20a535..6739b35 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,14 @@ so: 1. Make sure [Docker Compose is installed][1] and Docker is running (included in Docker Desktop) -3. Run `docker compose up --build` and wait until all services have started +2. Run `docker compose up --build` and wait until all services have started (389ds might take an extra minute to be ready). This will take a while when running for the first time, so you might want to do something else in the meantime. -4. `docker-compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be-name="dev"` -5. `docker compose run web rails ldap:setup` -6. `docker compose run web rails db:setup` + +On the first start, the `ldap-init` service creates the 389ds back-end, and the +`web` container then seeds the LDAP directory and the databases automatically. +On every start, `web` also applies any pending database migrations. After these steps, you should have a working Rails app with a handful of test users running on [http://localhost:3000](http://localhost:3000). @@ -71,15 +72,12 @@ containers you want to run to the `up` command, like so: #### LDAP server -After creating the Docker container for the first time (or after deleting it), -you need to run the following command once, in order to create the dirsrv -back-end: +On first start, the `ldap-init` service creates the dirsrv back-end +automatically, and the `web` container then seeds it with development entries. +To do either step manually (for example, after changing the setup), run: - docker-compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be-name="dev" - -Now you can seed the back-end with data using this Rails task: - - bundle exec rails ldap:setup + docker compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be-name="dev" + docker compose run --rm web bin/rails ldap:setup The setup task will first delete any existing entries in the directory tree ("dc=kosmos,dc=org"), and then create our development entries. @@ -88,6 +86,13 @@ Note that all 389ds data is stored in the `389ds-data` volume. So if you want to start over with a fresh installation, delete both that volume as well as the container. +To reset the development environment completely, remove all volumes plus the +generated database files and the first-run marker, then start over: + + docker compose down -v + rm -f db/*.sqlite3 tmp/.setup-complete + docker compose up --build + #### Minio / remoteStorage If you want to run remoteStorage accounts locally, you will have to create the diff --git a/docker-compose.yml b/docker-compose.yml index 61cd458..467cc45 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,20 @@ services: DS_DM_PASSWORD: passthebutter SUFFIX_NAME: "dc=kosmos,dc=org" + ldap-init: + image: 4teamwork/389ds:latest + networks: + - internal_network + volumes: + - ./docker/ldap-init.sh:/ldap-init.sh:ro + environment: + LDAP_ADMIN_PASSWORD: passthebutter + LDAP_SUFFIX: "dc=kosmos,dc=org" + depends_on: + ldap: + condition: service_healthy + command: ["/bin/sh", "/ldap-init.sh"] + redis: restart: always image: redis:7-alpine @@ -26,7 +40,7 @@ services: web: build: . tty: true - command: bash -c "rm -f /akkounts/tmp/pids/server.pid; bin/dev" + command: ["bash", "docker/web-entrypoint.sh"] volumes: - .:/akkounts - /akkounts/node_modules @@ -57,8 +71,12 @@ services: NOSTR_PRIVATE_KEY: 7c3ef7e448505f0615137af38569d01807d3b05b5005d5ecf8aaafcd40323cea NOSTR_RELAY_URL: ws://strfry:7777 depends_on: - - ldap - - redis + ldap: + condition: service_started + ldap-init: + condition: service_completed_successfully + redis: + condition: service_started minio: image: quay.io/minio/minio:latest diff --git a/docker/ldap-init.sh b/docker/ldap-init.sh new file mode 100644 index 0000000..fc4ccc1 --- /dev/null +++ b/docker/ldap-init.sh @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +SUFFIX="${LDAP_SUFFIX:-dc=kosmos,dc=org}" +URI="ldap://ldap:3389" + +if dsconf -D "cn=Directory Manager" -w "$LDAP_ADMIN_PASSWORD" "$URI" \ + backend suffix list --suffix 2>/dev/null | grep -Fqx "$SUFFIX"; then + echo "LDAP backend for $SUFFIX already exists, skipping." +else + echo "Creating LDAP backend for $SUFFIX..." + dsconf -D "cn=Directory Manager" -w "$LDAP_ADMIN_PASSWORD" "$URI" \ + backend create --suffix "$SUFFIX" --be-name dev +fi diff --git a/docker/web-entrypoint.sh b/docker/web-entrypoint.sh new file mode 100644 index 0000000..2001ecb --- /dev/null +++ b/docker/web-entrypoint.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -e + +if [ ! -f tmp/.setup-complete ]; then + echo "First start: setting up LDAP entries and databases..." + bin/rails ldap:setup + bin/rails db:setup + touch tmp/.setup-complete +else + bin/rails db:prepare +fi + +rm -f tmp/pids/server.pid +exec bin/dev