From 92f1281dac9ebd0446ee8b12df9c590cb6075092 Mon Sep 17 00:00:00 2001 From: Ryan Westfall Date: Wed, 28 Oct 2026 03:51:37 -0500 Subject: [PATCH] Register disney_hotel_service for beta and prod deploy (closes #47). Give the Disney Hotel app stable host ports and a shared-Postgres layout so beta and prod can be deployed without colliding with WordPress. Co-authored-by: Cursor --- IMPLEMENTATION.md | 49 +++++++++++++++++++++++--- docs/WORDPRESS.md | 7 ++-- inventory/group_vars/all.yml | 9 +++++ inventory/host_vars/adama.yml | 3 ++ inventory/host_vars/ai-server-4080.yml | 6 ++-- inventory/host_vars/apollo.yml | 4 ++- inventory/host_vars/roslin.yml | 4 ++- inventory/host_vars/starbuck.yml | 4 ++- roles/app-deploy/tasks/django.yml | 5 +-- scripts/deploy.sh | 2 +- 10 files changed, 77 insertions(+), 16 deletions(-) diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md index 8055a8b..f0a1fd8 100644 --- a/IMPLEMENTATION.md +++ b/IMPLEMENTATION.md @@ -241,6 +241,7 @@ After Docker install, re-SSH so the `docker` group membership takes effect. | `abc_voice` | django-type compose (FastAPI) | all webservers | **beta only** | Same repo as `abc_worker`, compose `docker-compose.voice.yml`, join API on host port 8020. One uvicorn worker. | | `abc_fe` | node-static (Vite) | all webservers | **beta only** | built to `/var/www/.abc.aimloperations/html`; no prod `host_apps` row | | `livekit` | django-type compose (LiveKit SFU) | all webservers | **beta only** | Docker like `abc_worker`. Host network `:7880`. **Do not NPM-balance** until Redis — pick one upstream (adama). Router DNAT UDP 3478 + 50000–60000 and TCP 7881 to that host. Secrets `~/Documents/secrets/livekit/livekit_beta.env` | +| `disney_hotel_service` | django (docker) | all webservers | beta + prod | active/active behind NPM; no bundled Postgres. Alert worker (`db_worker`) **singleton on adama** only (`compose --profile worker`). Repo `DisneyHotel/disney_hotel_service` (local folder `disney_reservation_finder`). Reads `POSTGRES_*`, not `DATABASE_URL`. | Django apps use a **shared external Postgres** (via `DATABASE_URL` in each host's env file) so active/active replicas share one database. Beta and prod never share @@ -251,7 +252,8 @@ a DB. - `app_catalog` (`group_vars/all.yml`) — how each app is built (repo, type, compose file, migrate cmd). - `host_apps` (`host_vars/.yml`) — which app+env+port runs on that host. Optional `compose_profiles: [worker]` activates docker compose profiles on that - host only (used for `monica_site` / `college_craft` / `print_forge` dj-queue singleton on adama). + host only (used for `monica_site` / `college_craft` / `print_forge` dj-queue + and `disney_hotel_service` alert-worker singleton on adama). Optional `enabled: false` skips deploy (CI included) but keeps the row for ports and `stop.sh`. Omit the key (or `true`) to deploy as before. Do not use Jinja `rejectattr('enabled')` — missing key is an error, not "enabled". @@ -282,6 +284,7 @@ future beta replica. | abc_fe (nginx) | **8085** | 8084 (*not deployed*) | all webservers | | dta_blog (nginx) | **8087** | **8086** | all webservers | | livekit | **7880** | — | all webservers (signaling). UDP 3478 + 50000–60000 + TCP 7881 via router DNAT to the NPM upstream host | +| disney_hotel_service | **8024** | **8023** | all webservers. **8021/8022** are WordPress `relawfirm` — do not reuse | | SearxNG (LAN only) | — | **8088** | ai-server-4080 only (`searxng_stack`); not an NPM upstream | Host-local services on ai-server-4080 (not balanced by NPM): @@ -324,9 +327,9 @@ again. `stop.sh` still matches disabled rows. to host `{{ apps_env_dir }}` → git checkout at ref → copy `.env` into checkout → `docker compose build` → `up -d` (with `COMPOSE_PROFILES` from optional `host_apps.compose_profiles`) → migrate (run once, shared DB). - **`monica_site` / `college_craft` / `print_forge` worker:** adama `host_apps` sets - `compose_profiles: [worker]` so deploy starts dj-queue with web. Other hosts - omit profiles (web only). + **`monica_site` / `college_craft` / `print_forge` / `disney_hotel_service` worker:** + adama `host_apps` sets `compose_profiles: [worker]` so deploy starts the worker + with web. Other hosts omit profiles (web only). - **node-static**: git checkout at ref → `npm ci` → `npm run build:` (writes to the app's `webroot_pattern`, e.g. `/var/www/{env}.realpath.app/html`, `/var/www/{env}.blog.realpath.app/html`, or `/var/www/{env}.chat.aimloperations/html`). @@ -366,6 +369,7 @@ point each domain at the backend(s): | abc_worker | `beta.abc.worker.aimloperations.com` (beta only; HTTP + WebSocket upgrade) | `adama:8018` + same on roslin / starbuck / apollo / ai-server-4080 | | abc_voice | `beta.abc.voice.aimloperations.com` (beta only). Balance this host. Do not balance LiveKit. | `adama:8020` + same on roslin / starbuck / apollo / ai-server-4080 | | livekit | `LIVEKIT_DOMAIN` (e.g. `livekit.aimloperations.com`) — NPM Proxy Host, WebSocket, **single upstream** | `adama:7880` (do not balance until Redis) | +| disney_hotel_service | `disneyhotel.app` (+ www); `beta.disneyhotel.app` (beta) | `adama:8023` / `8024` + same on roslin / starbuck / apollo / ai-server-4080 | ### Required changes IN each app repo (owned separately) @@ -412,11 +416,45 @@ do not). | abc_be | beta | `abc_be_beta` | `postgres://westfarn:@10.0.0.230:5432/abc_be_beta` | | abc_worker | beta | *(same `abc_be_beta`)* | worker uses `DB_*` pointing at `abc_be_beta` — do **not** create a second DB | | abc_voice | beta | *(same `abc_be_beta`)* | voice container uses the worker DB settings — do **not** create a second DB | +| disney_hotel_service | prod | `disney_hotel_service` | `postgres://westfarn:@10.0.0.230:5432/disney_hotel_service` | +| disney_hotel_service | beta | `disney_hotel_service_beta` | `postgres://westfarn:@10.0.0.230:5432/disney_hotel_service_beta` | Server prereqs on 10.0.0.230: create each DB + grant `westfarn`; `listen_addresses` covers LAN; `pg_hba.conf` allows `10.0.0.0/24`; firewall opens 5432 to `10.0.0.0/24` only. +`disney_hotel_service` secrets (control node, never git, mode `600`) — [#47](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/47): + +```text +~/Documents/secrets/disney_hotel_service/disney_hotel_service_prod.env +~/Documents/secrets/disney_hotel_service/disney_hotel_service_beta.env +``` + +Ansible copies those to `/opt/apps/env/disney_hotel_service_.env` on each +app host. Create them on the machine that runs `deploy.sh` (ai-server-4080). +Unix dotenv: `KEY=value`, one per line, no `export`. This app reads `POSTGRES_*` +(`config/settings.py` and `scripts/entrypoint.sh`). It ignores `DATABASE_URL`. + +Same keys in both files. These values differ: + +| | prod | beta | +|--|------|------| +| `POSTGRES_DB` | `disney_hotel_service` | `disney_hotel_service_beta` | +| `WEB_PORT` | `8023` | `8024` | +| `DJANGO_ALLOWED_HOSTS` | `disneyhotel.app,www.disneyhotel.app` | `beta.disneyhotel.app` | +| `DJANGO_CSRF_TRUSTED_ORIGINS` | `https://disneyhotel.app,https://www.disneyhotel.app` | `https://beta.disneyhotel.app` | +| `SITE_BASE_URL` | `https://disneyhotel.app` | `https://beta.disneyhotel.app` | + +Shared DB settings: `POSTGRES_USER=westfarn`, `POSTGRES_HOST=10.0.0.230`, +`POSTGRES_PORT=5432`. `DJANGO_DEBUG=0`. Leave `RUN_MIGRATIONS=0` and +`RUN_SEED=0` (deploy runs migrate once; seed parks by hand after the first +deploy). Blank `STRIPE_SECRET_KEY` skips payment enforcement. Blank +`SMTP2GO_API_KEY` logs email to the container console. + +App repo still needs `docker-compose.prod.yml` on `master` (no bundled `db`, +`ports: ["${WEB_PORT}:8000"]`, `worker` under profile `worker`) before the +first deploy succeeds. + `url_shortening_service` extra env (control-node secrets, not in git): `SHORT_PUBLIC_HOSTS` / `SHORT_API_HOSTS` / `SHORT_ADMIN_HOSTS` (admin = `localhost,127.0.0.1` only), `SHORTENER_API_TOKENS` (`monica:`), `SHORT_ALLOWED_HOSTS`, `CLICK_IP_PEPPER` @@ -595,7 +633,8 @@ Store vault password for CI in a file readable only by the Act runner (e.g. `~/. | 10i | Register + deploy ABC beta (`abc_be` 8017, `abc_worker` 8018, `abc_fe` 8085) | Done ([#26](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/26)) | | 10j | Register + deploy `print_forge` (django, ports 8007/8019) | Done ([#27](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/27)) | | 10k | Register + deploy `dta_blog` (node-static, ports 8086/8087) | Done ([#29](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/29)) | -| 10l | Register GIS LiveKit SFU (`abc_worker`-style docker on webservers, port 7880) | This PR | +| 10l | Register GIS LiveKit SFU (`abc_worker`-style docker on webservers, port 7880) | Done | +| 10m | Register + deploy `disney_hotel_service` (django, ports 8023/8024) | This PR ([#47](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/47)) | | 11 | Gitea container registry (optional) | Future | ## Open Decisions diff --git a/docs/WORDPRESS.md b/docs/WORDPRESS.md index e305947..3fe6375 100644 --- a/docs/WORDPRESS.md +++ b/docs/WORDPRESS.md @@ -56,8 +56,9 @@ Same host port on every app server for a given site and env. NPM balances `adama:PORT` + `roslin:PORT` + `starbuck:PORT` + `apollo:PORT` + `ai-server-4080:PORT`. These are not in the Ansible `host_apps` tables. Do not reuse a port from -[IMPLEMENTATION.md](../IMPLEMENTATION.md) (8000–8020 and 8080–8088 are taken; -**8020** is `abc_voice`). +[IMPLEMENTATION.md](../IMPLEMENTATION.md) (8000–8020, **8023–8024**, and 8080–8088 +are taken; **8020** is `abc_voice`, **8023/8024** are `disney_hotel_service`). +Next WordPress site starts at **8025**. | Site | prod port | beta port | prod database | beta database | |------|-----------|-----------|---------------|---------------| @@ -335,7 +336,7 @@ The project name is already in the compose file, so `-p` is optional. The databa Repeat sections 2–8 with the beta column of the table: - database `_beta` -- port **8022** for relawfirm (next free port for the next site) +- port **8022** for relawfirm (next free WordPress port is **8025**; **8023/8024** are `disney_hotel_service`) - its own env file, salts, NFS dataset, compose project, NPM host, and adama cron Do not point beta `WORDPRESS_DB_NAME` at the prod database. diff --git a/inventory/group_vars/all.yml b/inventory/group_vars/all.yml index 3c75add..7bff5f8 100644 --- a/inventory/group_vars/all.yml +++ b/inventory/group_vars/all.yml @@ -221,6 +221,15 @@ app_catalog: web_service: web # SFU — no Django migrations. `true` keeps the django deploy path happy. migrate_cmd: "true" + disney_hotel_service: + type: django + repo: "{{ git_base_url }}/DisneyHotel/disney_hotel_service.git" + default_branch: master + compose_file: docker-compose.prod.yml + web_service: web + migrate_cmd: "uv run python manage.py migrate --noinput" + # Alert worker (db_worker + enqueue_due_alerts) = compose profile `worker` + # (singleton). Deploy starts it via host_apps.compose_profiles on adama only. # Deploy filter vars. CI passes these; manual runs may leave them undefined # to (re)deploy every app listed in the host's host_apps. diff --git a/inventory/host_vars/adama.yml b/inventory/host_vars/adama.yml index 5fe1afe..342b139 100644 --- a/inventory/host_vars/adama.yml +++ b/inventory/host_vars/adama.yml @@ -34,3 +34,6 @@ host_apps: - { name: abc_voice, env: beta, port: 8020 } - { name: abc_fe, env: beta, port: 8085 } - { name: livekit, env: beta, port: 7880 } + # Alert worker singleton (db_worker). Other hosts omit compose_profiles. + - { name: disney_hotel_service, env: prod, port: 8023, compose_profiles: [worker] } + - { name: disney_hotel_service, env: beta, port: 8024, compose_profiles: [worker] } diff --git a/inventory/host_vars/ai-server-4080.yml b/inventory/host_vars/ai-server-4080.yml index 46f9ea7..4ffe4c6 100644 --- a/inventory/host_vars/ai-server-4080.yml +++ b/inventory/host_vars/ai-server-4080.yml @@ -36,7 +36,7 @@ host_apps: - { name: chat_web_app, env: beta, port: 8083 } - { name: chat_backend, env: prod, port: 8003 } - { name: chat_backend, env: beta, port: 8013 } - # monica_site / college_craft / print_forge workers NOT here — adama sets compose_profiles: [worker]. + # monica_site / college_craft / print_forge / disney_hotel_service workers NOT here — adama sets compose_profiles: [worker]. - { name: monica_site, env: prod, port: 8004 } - { name: monica_site, env: beta, port: 8014 } - { name: url_shortening_service, env: prod, port: 8005 } @@ -49,4 +49,6 @@ host_apps: - { name: abc_worker, env: beta, port: 8018 } - { name: abc_voice, env: beta, port: 8020 } - { name: abc_fe, env: beta, port: 8085 } - - { name: livekit, env: beta, port: 7880 } \ No newline at end of file + - { name: livekit, env: beta, port: 7880 } + - { name: disney_hotel_service, env: prod, port: 8023 } + - { name: disney_hotel_service, env: beta, port: 8024 } \ No newline at end of file diff --git a/inventory/host_vars/apollo.yml b/inventory/host_vars/apollo.yml index 02f121a..b4ebb53 100644 --- a/inventory/host_vars/apollo.yml +++ b/inventory/host_vars/apollo.yml @@ -15,7 +15,7 @@ host_apps: - { name: chat_web_app, env: beta, port: 8083 } - { name: chat_backend, env: prod, port: 8003 } - { name: chat_backend, env: beta, port: 8013 } - # monica_site / college_craft / print_forge workers NOT here — adama sets compose_profiles: [worker]. + # monica_site / college_craft / print_forge / disney_hotel_service workers NOT here — adama sets compose_profiles: [worker]. - { name: monica_site, env: prod, port: 8004 } - { name: monica_site, env: beta, port: 8014 } - { name: url_shortening_service, env: prod, port: 8005 } @@ -29,3 +29,5 @@ host_apps: - { name: abc_voice, env: beta, port: 8020 } - { name: abc_fe, env: beta, port: 8085 } - { name: livekit, env: beta, port: 7880 } + - { name: disney_hotel_service, env: prod, port: 8023 } + - { name: disney_hotel_service, env: beta, port: 8024 } diff --git a/inventory/host_vars/roslin.yml b/inventory/host_vars/roslin.yml index 3d74bbe..3852d61 100644 --- a/inventory/host_vars/roslin.yml +++ b/inventory/host_vars/roslin.yml @@ -15,7 +15,7 @@ host_apps: - { name: chat_web_app, env: beta, port: 8083 } - { name: chat_backend, env: prod, port: 8003 } - { name: chat_backend, env: beta, port: 8013 } - # monica_site / college_craft / print_forge workers NOT here — adama sets compose_profiles: [worker]. + # monica_site / college_craft / print_forge / disney_hotel_service workers NOT here — adama sets compose_profiles: [worker]. - { name: monica_site, env: prod, port: 8004 } - { name: monica_site, env: beta, port: 8014 } - { name: url_shortening_service, env: prod, port: 8005 } @@ -29,3 +29,5 @@ host_apps: - { name: abc_voice, env: beta, port: 8020 } - { name: abc_fe, env: beta, port: 8085 } - { name: livekit, env: beta, port: 7880 } + - { name: disney_hotel_service, env: prod, port: 8023 } + - { name: disney_hotel_service, env: beta, port: 8024 } diff --git a/inventory/host_vars/starbuck.yml b/inventory/host_vars/starbuck.yml index c1ae80b..f01323a 100644 --- a/inventory/host_vars/starbuck.yml +++ b/inventory/host_vars/starbuck.yml @@ -15,7 +15,7 @@ host_apps: - { name: chat_web_app, env: beta, port: 8083 } - { name: chat_backend, env: prod, port: 8003 } - { name: chat_backend, env: beta, port: 8013 } - # monica_site / college_craft / print_forge workers NOT here — adama sets compose_profiles: [worker]. + # monica_site / college_craft / print_forge / disney_hotel_service workers NOT here — adama sets compose_profiles: [worker]. - { name: monica_site, env: prod, port: 8004 } - { name: monica_site, env: beta, port: 8014 } - { name: url_shortening_service, env: prod, port: 8005 } @@ -29,3 +29,5 @@ host_apps: - { name: abc_voice, env: beta, port: 8020 } - { name: abc_fe, env: beta, port: 8085 } - { name: livekit, env: beta, port: 7880 } + - { name: disney_hotel_service, env: prod, port: 8023 } + - { name: disney_hotel_service, env: beta, port: 8024 } diff --git a/roles/app-deploy/tasks/django.yml b/roles/app-deploy/tasks/django.yml index 0879bc7..667a510 100644 --- a/roles/app-deploy/tasks/django.yml +++ b/roles/app-deploy/tasks/django.yml @@ -104,8 +104,9 @@ - _legacy_systemd_probe.stdout | default('') | length > 0 # Optional host_apps.compose_profiles (e.g. [worker]) activates compose profiles -# on this host only. Used for monica_site / college_craft / print_forge dj-queue singleton on -# adama — without it, plain up --remove-orphans can drop a manually started worker. +# on this host only. Used for monica_site / college_craft / print_forge / +# disney_hotel_service worker singleton on adama — without it, plain up +# --remove-orphans can drop a manually started worker. - name: "django[{{ _project }}] start containers" ansible.builtin.command: cmd: "docker compose -f {{ _spec.compose_file }} --env-file .env up -d --remove-orphans" diff --git a/scripts/deploy.sh b/scripts/deploy.sh index ff53447..1481fb9 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -17,7 +17,7 @@ Deploy applications with deploy-apps.yml. HOST Optional. Limit to one host: adama, roslin, starbuck, apollo, or ai-server-4080. Options: - --app NAME App to deploy (company_site, dta_service, dta_webapp, dta_blog, scha, chat_web_app, chat_backend, monica_site, url_shortening_service, college_craft, print_forge, abc_be, abc_worker, abc_fe, livekit) + --app NAME App to deploy (company_site, dta_service, dta_webapp, dta_blog, scha, chat_web_app, chat_backend, monica_site, url_shortening_service, college_craft, print_forge, abc_be, abc_worker, abc_fe, livekit, disney_hotel_service) --env ENV Environment: beta or prod --ref REF Git ref/sha to deploy (default: master) --check Dry run -- 2.54.0