mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
Three notifiers pointed at one handler, and that handler always ran ./launcher rebuild. A rotated database password therefore cost a full image build with bundle install and asset precompile: 961.82s in pass 1 and 13m16s in pass 2 of job 103878400427, on a run that then missed its wall-clock budget by 201s. The launcher draws the line itself. set_template_info reads app.yml on every call and turns env: into -e flags that run_start hands to docker run, while templates:, params: and hooks: are consumed during bootstrap only. An env: change needs a new container, not a new image. run_start takes the docker run branch only when no container exists, which is why the start path still stops and removes it first. The digest task is the discriminator: it records a sha256 over every top-level key except env:, so a credential-only change leaves it untouched and the bootstrap handler is never notified. A hash rather than the content because that section carries the OIDC client secret and the administrator password. The guard against running both paths lives in a fact cleared per role run. A register from inside the included file would have outlived the play and, in a later one, silently skipped the recreate while the config change never reached the container. from_yaml adds no failure mode: the launcher parses the same file with YAML.load, so anything it rejects was already a broken deployment. start without an image is structurally impossible, since a running container implies its image and a missing one notifies the bootstrap. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
54 lines
2.2 KiB
YAML
54 lines
2.2 KiB
YAML
---
|
|
- name: "🛑 stop discourse container gracefully if it exist"
|
|
ansible.builtin.command: "container stop {{ DISCOURSE_CONTAINER }}"
|
|
register: container_stop
|
|
changed_when: container_stop.rc == 0
|
|
failed_when: >
|
|
container_stop.rc != 0 and
|
|
'No such container' not in (container_stop.stderr | default(''))
|
|
|
|
- name: "🗑️ remove discourse container if it exist"
|
|
ansible.builtin.command: "container rm {{ DISCOURSE_CONTAINER }}"
|
|
register: container_action
|
|
changed_when: container_action.rc == 0
|
|
failed_when: >
|
|
container_action.rc != 0 and
|
|
'No such container' not in (container_action.stderr | default(''))
|
|
|
|
- name: "🔗 add central database temporary to discourse network"
|
|
command: "container network connect {{ DISCOURSE_NETWORK }} {{ DISCOURSE_DATABASE_CONTAINER }}"
|
|
failed_when: >
|
|
result.rc != 0 and
|
|
not (result.stderr | default('') | docker_network_noop('connect'))
|
|
register: result
|
|
when:
|
|
- DISCOURSE_DATABASE_IS_SHARED | bool
|
|
- DEPLOYMENT_MODE == 'compose'
|
|
|
|
- name: "🔨 {{ DISCOURSE_LAUNCHER_ACTION }} discourse"
|
|
shell: >
|
|
./launcher {{ DISCOURSE_LAUNCHER_ACTION }} {{ DISCOURSE_CONTAINER }}
|
|
{% if DOCKER_IN_CONTAINER | bool %}--skip-prereqs{% endif %}
|
|
args:
|
|
executable: /bin/bash
|
|
chdir: "{{ DISCOURSE_REPOSITORY_DIR }}"
|
|
register: discourse_rebuild
|
|
retries: 3
|
|
delay: 60
|
|
until: discourse_rebuild.rc == 0
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
|
|
- name: "🔗 Connect '{{ DISCOURSE_CONTAINER }}' to its shared swarm overlays"
|
|
command: "container network connect {{ discourse_overlay }} {{ DISCOURSE_CONTAINER }}"
|
|
loop: "{{ ([DISCOURSE_WEB_NETWORK] + ([DISCOURSE_PG_NETWORK] if (DISCOURSE_DATABASE_IS_SHARED | bool) else []) + ([DISCOURSE_REDIS_NETWORK] if (DISCOURSE_REDIS_SHARED
|
|
| bool) else []) + ([DISCOURSE_LITELLM_NETWORK] if (DISCOURSE_LITELLM_ENABLED | bool) else [])) }}"
|
|
loop_control:
|
|
loop_var: discourse_overlay
|
|
label: "{{ discourse_overlay }}"
|
|
register: discourse_overlay_connect
|
|
changed_when: discourse_overlay_connect.rc == 0
|
|
failed_when: >
|
|
discourse_overlay_connect.rc != 0 and
|
|
not (discourse_overlay_connect.stderr | default('') | docker_network_noop('connect'))
|
|
when: SWARM_CLUSTER_AVAILABLE | bool
|