fix(flannel): default the interface to each host's default IPv4 interface (#689)

* fix(flannel): default the interface to each host's default IPv4 interface

- Replace the hardcoded flannel_iface: eth0 with a per-host default derived
  from ansible_facts.default_ipv4.interface
- KVM/cloud hosts that are not named eth0 (e.g. enp1s0, ens3) now resolve the
  interface automatically instead of failing the k3s_node_ip lookup
- Update the commented calico_iface / cilium_iface examples to match
- Co-authored-by: Fritz Dunkel <677609+FinalDoom@users.noreply.github.com>
- Fixes #621

* test(flannel): add regression test for per-host interface default

- Add a focused test that renders the sample inventory's flannel_iface
  expression against fake ansible facts
- Assert a non-eth0 host (enp1s0, ens3) resolves its own interface and that
  the expression defaults from ansible_facts.default_ipv4.interface
- Wire it as a local pre-commit hook (default-interface-test)

* test(molecule): assert nodes register a non-loopback InternalIP

- Add a flannel-scenario verify assertion that every node reports an
  InternalIP derived from its configured flannel_iface
- Guards against k3s binding to 127.0.0.1 instead of the cluster interface
- Complements the pre-commit default-interface test with an end-to-end check
This commit is contained in:
Techno Tim
2026-08-03 12:01:50 -05:00
committed by GitHub
parent 88159b3875
commit f5483cdabe
4 changed files with 127 additions and 3 deletions
@@ -38,6 +38,30 @@
loop_control:
label: "{{ item.metadata.name }} ready"
- name: Assert every node registered a node IP from its interface
# Each k3s node is launched with --node-ip derived from flannel_iface.
# Confirm every node carries a real InternalIP (not a loopback), which
# proves k3s bound to the cluster interface rather than defaulting to 127.0.0.1.
ansible.builtin.assert:
that: >-
(node_internal_ips | length) >= 1 and
(node_internal_ips | reject('eq', '127.0.0.1') | list | length) == node_internal_ips | length
success_msg: "{{ item.metadata.name }} is bound to {{ node_internal_ips | join(', ') }}"
fail_msg: >-
{{ item.metadata.name }} has no non-loopback InternalIP
(got: {{ node_internal_ips | join(', ') }})
vars:
node_internal_ips: >-
{{
(item.status.addresses | default([]))
| selectattr('type', 'equalto', 'InternalIP')
| map(attribute='address')
| list
}}
loop: "{{ verify_nodes.resources }}"
loop_control:
label: "{{ item.metadata.name }} InternalIP"
- name: Get any Calico namespaces with Flannel enabled
kubernetes.core.k8s_info:
kind: Namespace