forked from tim/k3s-ansible
feat(metallb): add option to limit MetalLB layer2 announcements to specific interfaces (#696)
- roles/k3s_server_post/templates/metallb.crs.j2: render spec.interfaces in the L2Advertisement when metal_lb_interfaces is a non-empty list, so MetalLB only announces on the configured interfaces. Empty list (default) keeps announcing on all interfaces, preserving existing behavior. - roles/k3s_server_post/defaults/main.yml: add metal_lb_interfaces: [] default - roles/k3s_server_post/meta/main.yml: add metal_lb_interfaces argument_spec - inventory/sample/group_vars/all.yml: document the new sample variable - .github/scripts/test-metallb-interfaces.py: regression test rendering the template for empty/single/multiple interfaces and confirming the BGP path is unaffected - .pre-commit-config.yaml: wire the new test into pre-commit Co-authored-by: Leo <leo@kuboschek.me>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Regression test for the MetalLB L2Advertisement interfaces.
|
||||
|
||||
`metal_lb_interfaces` restricts which network interfaces MetalLB announces
|
||||
load balancer IPs on in layer2 mode. When the list is non-empty, the
|
||||
L2Advertisement in roles/k3s_server_post/templates/metallb.crs.j2 must render
|
||||
a `spec.interfaces` block; when it is empty (the default), no spec is rendered
|
||||
so MetalLB announces on all interfaces.
|
||||
|
||||
This renders the template and asserts both cases plus the BGP path (which must
|
||||
not be affected by the L2 interfaces variable).
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader, StrictUndefined
|
||||
|
||||
|
||||
def repo_root():
|
||||
return subprocess.check_output(
|
||||
["git", "rev-parse", "--show-toplevel"], text=True
|
||||
).strip()
|
||||
|
||||
|
||||
def fail(message):
|
||||
raise SystemExit("MetalLB interfaces test failed: " + message)
|
||||
|
||||
|
||||
def render(env, extra_vars):
|
||||
base_vars = {
|
||||
"metal_lb_mode": "layer2",
|
||||
"metal_lb_ip_range": "192.168.30.80-192.168.30.90",
|
||||
}
|
||||
base_vars.update(extra_vars)
|
||||
template = env.get_template("metallb.crs.j2")
|
||||
return template.render(**base_vars)
|
||||
|
||||
|
||||
def main():
|
||||
root = repo_root()
|
||||
template_dir = os.path.join(
|
||||
root, "roles", "k3s_server_post", "templates"
|
||||
)
|
||||
env = Environment(
|
||||
loader=FileSystemLoader(template_dir), undefined=StrictUndefined
|
||||
)
|
||||
|
||||
# Empty list (default): no spec.interfaces in the L2Advertisement.
|
||||
output = render(env, {"metal_lb_interfaces": []})
|
||||
if "spec:\n interfaces:" in output:
|
||||
fail("spec.interfaces rendered with an empty metal_lb_interfaces")
|
||||
if "kind: L2Advertisement" not in output:
|
||||
fail("L2Advertisement missing in layer2 mode")
|
||||
|
||||
# Single interface.
|
||||
output = render(env, {"metal_lb_interfaces": ["eth1"]})
|
||||
if "spec:\n interfaces:\n - eth1" not in output:
|
||||
fail("single interface was not rendered in spec.interfaces")
|
||||
|
||||
# Multiple interfaces.
|
||||
output = render(env, {"metal_lb_interfaces": ["eth1", "eth2"]})
|
||||
if "spec:\n interfaces:\n - eth1\n - eth2" not in output:
|
||||
fail("multiple interfaces were not rendered in spec.interfaces")
|
||||
|
||||
# BGP mode must not emit an L2Advertisement spec at all.
|
||||
output = render(
|
||||
env,
|
||||
{
|
||||
"metal_lb_mode": "bgp",
|
||||
"metal_lb_interfaces": ["eth1"],
|
||||
"metal_lb_bgp_my_asn": "64513",
|
||||
"metal_lb_bgp_peer_asn": "64512",
|
||||
"metal_lb_bgp_peer_address": "192.168.30.1",
|
||||
},
|
||||
)
|
||||
if "kind: L2Advertisement" in output:
|
||||
fail("L2Advertisement rendered in bgp mode")
|
||||
if "interfaces:" in output:
|
||||
fail("interfaces rendered in bgp mode")
|
||||
|
||||
print("MetalLB interfaces regression test passed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -93,6 +93,14 @@ repos:
|
||||
language: system
|
||||
pass_filenames: false
|
||||
files: ^roles/k3s_server/tasks/metallb\.yml$|^\.github/scripts/test-metallb-remote-read\.sh$
|
||||
- id: metallb-interfaces-test
|
||||
name: MetalLB interfaces test
|
||||
entry: python3 .github/scripts/test-metallb-interfaces.py
|
||||
language: python
|
||||
additional_dependencies:
|
||||
- Jinja2>=3.1
|
||||
pass_filenames: false
|
||||
files: ^roles/k3s_server_post/templates/metallb\.crs\.j2$|^\.github/scripts/test-metallb-interfaces\.py$
|
||||
- id: metallb-deploy-condition-test
|
||||
name: MetalLB deploy condition test
|
||||
entry: python3 .github/scripts/test-metallb-deploy-condition.py
|
||||
|
||||
@@ -120,6 +120,12 @@ metal_lb_controller_tag_version: v0.16.0
|
||||
# metallb ip range for load balancer
|
||||
metal_lb_ip_range: 192.168.30.80-192.168.30.90
|
||||
|
||||
# (optional) limit MetalLB layer2 announcements to specific network interfaces.
|
||||
# Leave empty (default) to announce on all interfaces.
|
||||
# metal_lb_interfaces:
|
||||
# - eth1
|
||||
# - eth2
|
||||
|
||||
# Only enable if your nodes are proxmox LXC nodes, make sure to configure your proxmox nodes
|
||||
# in your hosts.ini file.
|
||||
# Please read https://gist.github.com/triangletodd/02f595cd4c0dc9aac5f7763ca2264185 before using this.
|
||||
|
||||
@@ -39,4 +39,5 @@ group_name_master: master
|
||||
metal_lb_mode: layer2
|
||||
metal_lb_available_timeout: 240s
|
||||
metal_lb_controller_tag_version: v0.16.0
|
||||
metal_lb_interfaces: []
|
||||
metal_lb_ip_range: 192.168.30.80-192.168.30.90
|
||||
|
||||
@@ -141,6 +141,14 @@ argument_specs:
|
||||
description: MetalLB ip range for load balancer
|
||||
default: 192.168.30.80-192.168.30.90
|
||||
|
||||
metal_lb_interfaces:
|
||||
description: >-
|
||||
List of network interfaces on which MetalLB should announce the
|
||||
load balancer IPs in layer2 mode. When empty (default), MetalLB
|
||||
announces on all interfaces.
|
||||
type: list
|
||||
default: []
|
||||
|
||||
metal_lb_controller_tag_version:
|
||||
description: Image tag for MetalLB
|
||||
default: v0.16.0
|
||||
|
||||
@@ -21,6 +21,11 @@ kind: L2Advertisement
|
||||
metadata:
|
||||
name: default
|
||||
namespace: metallb-system
|
||||
{% if metal_lb_interfaces | default([]) | length > 0 %}
|
||||
spec:
|
||||
interfaces:{% for iface in metal_lb_interfaces %}
|
||||
- {{ iface }}{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if metal_lb_mode == "bgp" %}
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user