Add the menu-admin playbook

Deploys the menu app for one Site: pulls the tag, creates the data root, runs
the container against a config baked into the image, waits for health, verifies
the data directory, and points Caddy at the app with a marker it can update in
place. The parallel run uses a temporary hostname; cutover sets the retire
flags.
This commit is contained in:
tanshu committed 2026-09-22 21:27:13 +05:30
1 parent e54dd127ed
commit c87cd15c8c
8 files changed
+293

No files matched your search

@@ -0,0 +1,6 @@
---
- name: Reload Caddy
# Caddy validates before it applies, so a mistake here leaves the running
# config untouched and fails the play loudly.
command: "docker exec -w /etc/caddy {{ caddy_container }} caddy reload"
listen: Reload Caddy
+39
View File
@@ -0,0 +1,39 @@
---
- name: Check the Caddyfile exists
stat:
path: "{{ caddyfile_path }}"
register: menu_caddyfile
- name: Fail when Caddy is not where we expect it
fail:
msg: >-
{{ caddyfile_path }} is missing. Deploy the caddy playbook (which owns the
Caddy container and its config) before this one.
when: not menu_caddyfile.stat.exists
# blockinfile replaces whatever sits between its markers, so changing `vhost`
# updates the snippet in place. The sibling nginx-menu role only appended a
# block when its exact text was absent, which cannot change a proxy target.
- name: Point Caddy at the app
blockinfile:
path: "{{ caddyfile_path }}"
marker: "# {mark} ANSIBLE MANAGED: menu app ({{ site }})"
block: "{{ caddy_snippet }}"
create: no
notify: Reload Caddy
- name: Remove the snippet the nginx-menu playbook wrote for this vhost
# A different marker, written by a different role. Leaving it in place would
# leave Caddy with two blocks for the same hostname.
blockinfile:
path: "{{ caddyfile_path }}"
marker: "# {mark} Ansible managed Caddy snippet for {{ host }}"
state: absent
when: retire_nginx_snippet | bool
notify: Reload Caddy
- name: Stop the old nginx container
docker_container:
name: "{{ legacy_container }}"
state: stopped
when: retire_nginx_container | bool
+91
View File
@@ -0,0 +1,91 @@
---
- name: Pull the app image
docker_image:
name: "{{ image_name }}"
tag: "{{ image_tag }}"
source: pull
force_source: yes
- name: Ensure the app root exists
file:
path: "{{ app_root }}"
state: directory
owner: "{{ app_uid }}"
group: "{{ app_gid }}"
mode: "0750"
- name: Ensure the data directory exists
file:
path: "{{ app_root }}/data"
state: directory
owner: "{{ app_uid }}"
group: "{{ app_gid }}"
mode: "0750"
- name: Look for the untracked site.env
stat:
path: "{{ app_root }}/site.env"
register: menu_site_env
- name: Warn when the admin has no password yet
debug:
msg: >-
{{ app_root }}/site.env is missing, so the admin is disabled: the public
menu still serves. Run scripts/provision-site-env.sh {{ app_root }} on
this host, then re-run this playbook.
when: not menu_site_env.stat.exists
- name: Run the menu app
docker_container:
name: "{{ docker_container }}"
image: "{{ image_name }}:{{ image_tag }}"
state: started
restart_policy: unless-stopped
user: "{{ app_uid }}:{{ app_gid }}"
env:
MENU_ROOT: /data
MENU_SITE_CONFIG: "/app/config/{{ site }}.site.json"
SECURE_COOKIES: "true"
LOG_LEVEL: info
PORT: "3000"
volumes:
- "{{ app_root }}:/data"
networks:
- name: "{{ docker_network }}"
- name: Wait for the app to answer
uri:
url: "http://{{ docker_container }}:3000/healthz"
status_code: 200
register: menu_health
retries: 10
delay: 2
until: menu_health.status == 200
changed_when: false
- name: Check the data directory for integrity problems
# Reads the same directory the container writes, as the same user, so a
# permissions mistake shows up here rather than at 8pm service.
command:
argv:
- docker
- run
- --rm
- --user
- "{{ app_uid }}:{{ app_gid }}"
- -e
- MENU_ROOT=/data
- -e
- "MENU_SITE_CONFIG=/app/config/{{ site }}.site.json"
- --entrypoint
- node
- "{{ image_name }}:{{ image_tag }}"
- src/cli/verify.ts
register: menu_verify
changed_when: false
failed_when: false
- name: Report integrity problems
debug:
msg: "{{ menu_verify.stdout_lines | default([]) }}"
when: menu_verify.rc != 0
+8
View File
@@ -0,0 +1,8 @@
---
- name: "Ensure {{ docker_network }} exists and Caddy is on it"
docker_network:
name: "{{ docker_network }}"
state: present
connected:
- "{{ caddy_container }}"
appends: yes