--- # Deploy the repo-owned, sanitized Compose declaration to the host. # # Safety model: # - Only hosts with an inventory `compose_repo_project` (allowlisted) are valid. # - The repo file is staged to `.dsh-new` and validated with # `docker compose config --quiet` against the server-local .env BEFORE it # replaces anything. A failed validation never touches the live file. # - The current file is kept as `*.bak-` before promotion. # - Apply mode requires `compose_deploy_confirm=true`; `--check` gives a # read-only diff + validation without writes. # - The playbook never writes, reads, or transfers the server .env. - name: Require an allowlisted repo compose project for this host ansible.builtin.assert: that: - compose_repo_project is defined - compose_repo_project in compose_repo_projects fail_msg: >- No allowlisted compose_repo_project for {{ inventory_hostname }}. Supported: {{ compose_repo_projects | join(', ') }}. - name: Require explicit confirmation for apply mode ansible.builtin.assert: that: - ansible_check_mode or (compose_deploy_confirm | bool) fail_msg: >- This playbook replaces the server compose file and may recreate containers. Run with --check for a read-only diff, or supply compose_deploy_confirm=true to apply. - name: Stage the repo compose file next to the live one ansible.builtin.copy: src: "{{ playbook_dir }}/../../compose/{{ compose_repo_project }}/compose.yml" dest: "{{ compose_project_dir }}/{{ compose_remote_file | default('compose.yml') }}.dsh-new" mode: "0644" diff: true register: compose_stage - name: Validate staged compose against the server .env (read-only) ansible.builtin.command: argv: - docker - compose - -f - "{{ compose_project_dir }}/{{ compose_remote_file | default('compose.yml') }}.dsh-new" - --project-directory - "{{ compose_project_dir }}" - config - --quiet register: compose_validate changed_when: false failed_when: compose_validate.rc != 0 - name: Show staged-vs-live difference ansible.builtin.debug: msg: "{{ compose_stage.diff | default('(no change)') }}" when: ansible_check_mode - name: Back up the current compose file (apply mode) ansible.builtin.shell: cmd: >- cp -a '{{ compose_project_dir }}/{{ compose_remote_file | default('compose.yml') }}' '{{ compose_project_dir }}/{{ compose_remote_file | default('compose.yml') }}.bak-$(date +%Y%m%d-%H%M%S)' when: not ansible_check_mode - name: Promote the validated compose file (apply mode) ansible.builtin.command: argv: - mv - "{{ compose_project_dir }}/{{ compose_remote_file | default('compose.yml') }}.dsh-new" - "{{ compose_project_dir }}/{{ compose_remote_file | default('compose.yml') }}" when: not ansible_check_mode - name: Apply the compose declaration (apply mode) ansible.builtin.command: argv: - docker - compose - --project-directory - "{{ compose_project_dir }}" - up - -d when: not ansible_check_mode