digitalboard.core/roles/garage/tasks/bootstrap.yml
Simon Bärlocher 1157448d59
fix(garage): make bootstrap & provision idempotent across reruns
* bootstrap: `garage layout show` truncates node IDs to 16 chars, but
  the membership check compared against the full hex. After the first
  successful join, subsequent runs no longer found the short ID in
  `layout show` and re-issued `layout assign`, marking the task
  changed every time. Compare against both the truncated and the full
  form so a configured node stays detected. Also tag the read-only
  `garage node id` / `layout show` probes with `changed_when: false`.

* provision keys: the old parser sliced `stdout_lines[1:]` to drop the
  header but missed that INFO log lines and ANSI escapes can interleave
  with table rows. Replace with an explicit `^GK[0-9a-fA-F]+` filter
  after stripping ANSI, so probe-output noise no longer corrupts the
  existing-keys set and triggers spurious `key new` calls.

* provision buckets: same class of fix — match `^[0-9a-f]{16}\s` data
  rows instead of slicing `[2:]`, which broke when the table header
  wasn't exactly two lines.

* provision permissions: pre-read `bucket info` for each (key, bucket)
  pair and only run `bucket allow` when the current `RWO` flag set for
  that key ID doesn't already match the desired permissions. Previously
  `bucket allow` ran unconditionally and reported changed every play.

* `changed_when: false` on all read-only probes (`key list`, `key info`,
  `bucket list`).
2026-05-26 14:03:58 +02:00

57 lines
No EOL
2 KiB
YAML

#SPDX-License-Identifier: MIT-0
---
# Provisioning tasks for garage (cluster bootstrap, S3 keys, and buckets)
# Cluster bootstrap tasks
- name: Get garage node ID
community.docker.docker_container_exec:
container: "{{ garage_service_name }}"
command: /garage node id -q
register: _garage_node_id
changed_when: false
- name: Extract short node ID
ansible.builtin.set_fact:
_garage_node_id_short: "{{ _garage_node_id.stdout.split('@')[0] }}"
- name: Extract truncated node ID (first 16 chars, matches `garage layout show` output)
ansible.builtin.set_fact:
_garage_node_id_truncated: "{{ _garage_node_id_short[:16] }}"
- name: Check if node layout is configured
community.docker.docker_container_exec:
container: "{{ garage_service_name }}"
command: /garage layout show
register: _garage_layout_show
failed_when: false
changed_when: false
- name: Check if node is in layout
ansible.builtin.set_fact:
_node_in_layout: "{{ (_garage_node_id_truncated in _garage_layout_show.stdout) or (_garage_node_id_short in _garage_layout_show.stdout) }}"
- name: Configure garage node layout
community.docker.docker_container_exec:
container: "{{ garage_service_name }}"
command: /garage layout assign -z {{ garage_bootstrap_zone }} -c {{ garage_bootstrap_capacity }} {{ _garage_node_id_short }}
register: _layout_assign_result
when:
- not _node_in_layout
- name: Extract current layout version
ansible.builtin.set_fact:
_current_layout_version: "{{ _garage_layout_show.stdout | regex_search('Current cluster layout version: (\\d+)', '\\1') | first | default('0') }}"
when:
- _layout_assign_result is changed
- name: Calculate next layout version
ansible.builtin.set_fact:
_next_layout_version: "{{ (_current_layout_version | int) + 1 }}"
when:
- _layout_assign_result is changed
- name: Apply garage layout
community.docker.docker_container_exec:
container: "{{ garage_service_name }}"
command: /garage layout apply --version {{ _next_layout_version }}
when:
- _layout_assign_result is changed