mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 19:01:54 +00:00
The guarantees were asserted against the declared swarm and data pair, so they proved two meshes work rather than that the planner works. A deployment declares its own, and the review asks for any number of them with the nodes arranged however the client wants. The same invariants now run over generated topologies: one to eight meshes, three arrangements each, hosts dealt out so some belong to several meshes and some to none. 2247 subtests, four seconds, and the planner needed no change to pass them.
74 lines
2.6 KiB
YAML
74 lines
2.6 KiB
YAML
---
|
|
- name: "✅ Ensure export base directory exists"
|
|
ansible.builtin.file:
|
|
path: "{{ lookup('nfs_export_base') }}"
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "0755"
|
|
|
|
- name: "📂 Include CI/dev overlay backing for the export base"
|
|
ansible.builtin.include_tasks: 02_overlay_backing.yml
|
|
|
|
- name: "📁 Pre-create cluster-shared state subdir under export base"
|
|
ansible.builtin.file:
|
|
path: "{{ STORAGE_NFS_STATE_PATH }}"
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "0755"
|
|
|
|
- name: "✅ Assert the state subdir is strictly nested under the export base"
|
|
ansible.builtin.assert:
|
|
that:
|
|
- STORAGE_NFS_STATE_PATH != lookup('nfs_export_base')
|
|
fail_msg: >-
|
|
STORAGE_NFS_STATE_PATH must be a strict subdir of the nfs export base;
|
|
equal paths collide on the two distinct exports (root_squash vs no_root_squash).
|
|
|
|
- name: "🔧 Bind-mount state subdir onto itself for stable fsid=0 export root boundary"
|
|
ansible.posix.mount:
|
|
path: "{{ STORAGE_NFS_STATE_PATH }}"
|
|
src: "{{ STORAGE_NFS_STATE_PATH }}"
|
|
fstype: none
|
|
opts: bind
|
|
state: mounted
|
|
when: SVC_STORAGE_NFS_SERVER_FLAVOR == 'kernel'
|
|
|
|
- name: "📊 Gather facts on swarm members so their IPs become available"
|
|
ansible.builtin.setup:
|
|
gather_subset: network
|
|
delegate_to: "{{ item }}"
|
|
delegate_facts: true
|
|
loop: "{{ groups['svc-swarm-node'] | default([]) }}"
|
|
when: hostvars[item].ansible_facts.default_ipv4 is not defined
|
|
|
|
- name: "🧮 Compute swarm-member IPs allowed to mount"
|
|
ansible.builtin.set_fact:
|
|
svc_storage_nfs_server_allowed_ips: >-
|
|
{{
|
|
((groups['svc-swarm-node']
|
|
| default([])
|
|
| map('extract', hostvars, ['ansible_facts', 'default_ipv4', 'address'])
|
|
| select('defined')
|
|
| list)
|
|
or [ansible_facts.default_ipv4.address | default('127.0.0.1')])
|
|
+ (lookup('mesh_ranges')
|
|
if ('svc-net-wireguard' in group_names) else [])
|
|
}}
|
|
|
|
- name: "✅ Assert at least one allowed IP was resolved"
|
|
ansible.builtin.assert:
|
|
that:
|
|
- svc_storage_nfs_server_allowed_ips | length > 0
|
|
fail_msg: |
|
|
Could not resolve any allowed mount IP. In swarm mode this means no
|
|
`svc-swarm-node` member facts were gathered; in single-node/host mode
|
|
the local host's own IP fallback should have applied.
|
|
|
|
- name: "🧮 Default the NFS mount server to this host when unset"
|
|
ansible.builtin.set_fact:
|
|
storage: >-
|
|
{{ storage | combine({'nfs': {'server': ansible_facts.default_ipv4.address | default('127.0.0.1')}}, recursive=True) }}
|
|
when: (storage.nfs.server | trim | length) == 0
|