homelab/build/config/ansible/roles/compose_stack/tasks/main.yml
Russell Seymour 1250c9cef6
Some checks are pending
deploy / deploy (push) Waiting to run
Initial checkin of code for managing homelab
2026-08-24 20:52:36 +01:00

75 lines
3.4 KiB
YAML

---
# Converges one stack (one loop iteration of `stack` from playbooks/unraid.yml)
# to the state its host_vars entry asks for.
#
# `state: present` (the default) deploys; `state: absent` tears down. Removal
# has to be asked for explicitly because Ansible keeps no record of what it
# deployed last run — deleting a stack from a host's `stacks:` list only stops
# the loop visiting it, leaving the containers running and unmanaged on the
# host forever. So the entry stays put as a tombstone, with `state: absent`,
# until the teardown has actually been applied.
#
# Unraid-only by design. Proxmox guests install apps natively rather than as
# Compose stacks — see the `lxc_app` role.
- name: Set stack facts
ansible.builtin.set_fact:
stack_local_dir: "{{ repo_root }}/src/{{ stack.src }}"
stack_remote_dir: "{{ compose_projects_root }}/{{ stack.name }}"
stack_state: "{{ stack.state | default('present') }}"
- name: Validate requested stack state
ansible.builtin.assert:
that: stack_state in ['present', 'absent']
fail_msg: >-
Stack '{{ stack.name }}' has state '{{ stack_state }}'; expected
'present' or 'absent'.
quiet: true
# Which icons this stack ships, worked out from the repo checkout on the
# controller rather than from anything on the host — `is exists` and the
# `fileglob` lookup both evaluate locally. Computed here rather than in
# deploy.yml because both branches need it: deploy copies these files out,
# remove deletes them again.
#
# Two naming conventions, because Unraid has two icon consumers (see
# deploy.yml for the full explanation):
#
# icon.png the stack — Compose Manager's project row, plus the
# `net.unraid.docker.icon` label of whichever service
# interpolates ${STACK_ICON}.
# icon-<service>.png one container — becomes ${STACK_ICON_<SERVICE>}, so a
# multi-container stack can label each of its services
# with its own image instead of sharing the stack's.
#
# `<service>` is the compose service name; the variable is it uppercased with
# `-` folded to `_` (icon-shelfarr-libation.png → STACK_ICON_SHELFARR_LIBATION).
- name: Set stack icon facts
ansible.builtin.set_fact:
# Empty when the stack ships no icon.png — an empty label is what the
# webgui already assumes, so it falls back to the placeholder as before.
stack_icon_dest: >-
{{ ((stack_local_dir ~ '/ansible/unraid/icon.png') is exists)
| ternary(unraid_icons_root ~ '/' ~ stack.name ~ '.png', '') }}
stack_service_icon_names: "{{ _service_icon_names }}"
stack_service_icons: >-
{{ dict(_service_icon_names
| map('upper') | map('replace', '-', '_')
| map('regex_replace', '^(.+)$', 'STACK_ICON_\1')
| zip(_service_icon_names
| map('regex_replace', '^(.+)$',
unraid_icons_root ~ '/' ~ stack.name ~ '-\1.png'))) }}
vars:
_service_icon_names: >-
{{ query('fileglob', stack_local_dir ~ '/ansible/unraid/icon-*.png')
| map('basename')
| map('regex_replace', '^icon-(.+)\.png$', '\1')
| map('lower') | list }}
- name: Deploy stack
ansible.builtin.include_tasks: deploy.yml
when: stack_state == 'present'
- name: Remove stack
ansible.builtin.include_tasks: remove.yml
when: stack_state == 'absent'