diff --git a/ansible/roles/caddy/tasks/main.yaml b/ansible/roles/caddy/tasks/main.yaml index e539d3e..b36ee25 100644 --- a/ansible/roles/caddy/tasks/main.yaml +++ b/ansible/roles/caddy/tasks/main.yaml @@ -11,6 +11,17 @@ Caddy container and its config, before this one. when: not menu_caddyfile.stat.exists +# The Site's web address may still be claimed by an older snippet: the retired +# nginx-menu playbook wrote one per hostname. Two blocks for one address make +# Caddy refuse the whole config, and a refused reload leaves the old proxy in +# place, which is a 502 once the old container is gone. +- name: Drop any older snippet claiming this web address + blockinfile: + path: '{{ caddyfile_path }}' + marker: '# {mark} Ansible managed Caddy snippet for {{ host }}' + state: absent + notify: Reload Caddy + # blockinfile replaces whatever sits between its markers, so redeploying updates # the snippet in place rather than appending a second one. - name: Point the Site's web address at the app diff --git a/ansible/roles/menu-app/tasks/main.yaml b/ansible/roles/menu-app/tasks/main.yaml index 039f295..3399fcf 100644 --- a/ansible/roles/menu-app/tasks/main.yaml +++ b/ansible/roles/menu-app/tasks/main.yaml @@ -61,27 +61,32 @@ mode: '0600' when: menu_site_env.stat.exists -- name: Wait for the app to report healthy - # The image's own HEALTHCHECK fetches /healthz inside the container. Polling - # that is deliberate: a container name resolves only on the Docker network, so - # the host cannot fetch http://{{ docker_container }}:3000/healthz. - docker_container_info: - name: '{{ docker_container }}' +# Deliberately not the image's HEALTHCHECK: podman builds an OCI image by +# default and drops the Docker HEALTHCHECK instruction, so State.Health is absent +# and a wait on it fails on a perfectly healthy container — which stops the play +# before Caddy is ever pointed at the app. +- name: Wait for the app to answer inside its own container + ansible.builtin.command: + argv: + - docker + - exec + - '{{ docker_container }}' + - node + - -e + - "fetch('http://127.0.0.1:3000/healthz').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))" register: menu_health changed_when: false retries: 20 - delay: 5 - until: >- - menu_health.container is defined and - menu_health.container.State.Health is defined and - menu_health.container.State.Health.Status == 'healthy' + delay: 3 + until: menu_health.rc == 0 + failed_when: false -- name: Fail when the app never becomes healthy +- name: Fail when the app never answers fail: msg: >- - {{ docker_container }} did not report healthy within 100s. Check - `docker logs {{ docker_container }}`. - when: menu_health.container.State.Health.Status | default('unknown') != 'healthy' + {{ docker_container }} did not answer /healthz within a minute. Its logs + say why: docker logs {{ docker_container }} + when: menu_health.rc != 0 - name: Check the data directory for integrity problems # Reads the same directory the container writes, as the same user, so a diff --git a/scripts/check-site.ts b/scripts/check-site.ts index b0ea6d3..5ee7fe9 100644 --- a/scripts/check-site.ts +++ b/scripts/check-site.ts @@ -55,7 +55,7 @@ await checkPage('/robots.txt', ['Disallow: /admin']); await checkPage('/admin/login', ['type="password"']); await checkPage('/assets/styles.css', ['--copper']); await checkPage('/assets/app.js', ['data-zoom']); -await checkPage('/assets/fonts/archivo-latin.woff2', []); +await checkPage('/assets/fonts/playfair-display-latin.woff2', []); const missingPage = await request('/definitely-not-here'); record('GET /definitely-not-here', missingPage.status === 404, `status ${missingPage.status}`);