00_core.ymlΒΆ

---
- include_tasks: utils/once/flag.yml

- name: "πŸ“‚ Include dependency 'user-administrator' for the mesh transport"
  include_role:
    name: user-administrator
  when:
    - "'svc-swarm-node' in group_names"
    - run_once_user_administrator is not defined

- name: "πŸ›‘ Fail when the inventory carries no mesh for this host"
  ansible.builtin.fail:
    msg: >-
      {{ inventory_hostname }} is to carry WireGuard but its inventory declares
      no WireGuard mesh. Run cli.administration.inventory.mesh over every
      inventory of this deploy before the play; the mesh is written by that one
      cross-host pass, never by this role.
  when: WIREGUARD_MESH_NAMES | length == 0

- name: "πŸ“¦ Install the WireGuard tooling"
  package_install: # nocheck: package-install the mesh bootstrap runs before the update role and the batch run
    id:
      - wireguard
      - iproute
      - iputils-ping

- name: "πŸ“¦ Install automtu via pip (system-wide)"
  include_role:
    name: sys-pip-install
  vars:
    package_name: "automtu==1.1.1"
    global_install: true

- name: "πŸ” Resolve every endpoint this host dials to its IPv4 address"
  ansible.builtin.command:
    argv:
      - getent
      - ahostsv4
      - "{{ endpoint }}"
  loop: "{{ WIREGUARD_DIALLED_ENDPOINTS }}"
  loop_control:
    loop_var: endpoint
  register: wireguard_underlay_lookup
  changed_when: false
  failed_when: wireguard_underlay_lookup.rc not in [0, 2]

- name: "πŸ”§ Pin every dialled endpoint to the IPv4 address it resolved to"
  ansible.builtin.set_fact:
    wireguard_underlay: "{{ wireguard_underlay_lookup.results | mesh_underlay }}"
  changed_when: false

- name: "πŸ›‘ Fail when a dialled endpoint has no IPv4 address on this host"
  ansible.builtin.fail:
    msg: >-
      {{ unresolved | join(', ') }} resolved to no IPv4 address on
      {{ inventory_hostname }}. The mesh underlay is IPv4: give the name an A
      record this host's resolver answers, give the host an IPv4 address, or
      pass the peer's IPv4 address as --endpoint to
      cli.administration.inventory.mesh.
  vars:
    unresolved: "{{ WIREGUARD_DIALLED_ENDPOINTS | reject('in', wireguard_underlay) | list }}"
  when: unresolved | length > 0

- name: "πŸ” Detect the path MTU the tunnel has to fit inside"
  ansible.builtin.command:
    argv:
      - "{{ ansible_python_interpreter }}"
      - -m
      - automtu
      - --pmtu-target
      - "{{ WIREGUARD_PMTU_TARGETS | join(',') }}"
      - --pmtu-policy
      - min
      - --print-mtu
      - effective
  register: wireguard_pmtu
  changed_when: false

- name: "βœ… Assert automtu returned an integer MTU"
  ansible.builtin.assert:
    that:
      - wireguard_pmtu.stdout is match('^[0-9]+$')
      - (wireguard_pmtu.stdout | int) >= 576
      - (wireguard_pmtu.stdout | int) <= 9000
    fail_msg: "automtu returned unexpected MTU output: '{{ wireguard_pmtu.stdout | default('') }}'"

- name: "πŸ”§ Derive the tunnel and overlay MTUs from the measured path"
  ansible.builtin.set_fact:
    wireguard_mtu: "{{ wireguard_pmtu.stdout | int - WIREGUARD_HEADER_BYTES | int }}"
    wireguard_overlay_mtu: >-
      {{ wireguard_pmtu.stdout | int
         - WIREGUARD_HEADER_BYTES | int
         - WIREGUARD_VXLAN_HEADER_BYTES | int }}
  changed_when: false

- name: "πŸ“ Create {{ WIREGUARD_CONFIG_DIR }}"
  ansible.builtin.file:
    path: "{{ WIREGUARD_CONFIG_DIR }}"
    state: directory
    owner: root
    group: root
    mode: "0700"

- name: "πŸ“„ Render the interface of every mesh this host belongs to"
  ansible.builtin.template: # nocheck: stack-host-template (per-host /etc/wireguard)
    src: wg.conf.j2
    dest: "{{ [WIREGUARD_CONFIG_DIR, mesh_name ~ '.conf'] | path_join }}"
    owner: root
    group: root
    mode: "0600"
  loop: "{{ WIREGUARD_MESH_NAMES }}"
  loop_control:
    loop_var: mesh_name
  vars:
    mesh: "{{ WIREGUARD_ACTIVE_MESHES[mesh_name] }}"
  no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
  register: wireguard_rendered

- name: "πŸ”€ Enable forwarding on the hub"
  ansible.posix.sysctl:
    name: net.ipv4.ip_forward
    value: "1"
    sysctl_set: true
    state: present
    reload: true
  when: WIREGUARD_IS_HUB | bool

- name: "🚿 Bring every rendered interface up"
  ansible.builtin.include_tasks: utils/interface_up.yml
  loop: "{{ WIREGUARD_MESH_NAMES }}"
  loop_control:
    loop_var: mesh_name

- name: "βœ… Gate: prove the layer works before anything depends on it"
  ansible.builtin.include_tasks: 01_gate.yml