167 lines
5.1 KiB
Python
167 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Regression test for the kube-vip deploy conditions.
|
|
|
|
The control-plane VIP (roles/k3s_server/tasks/vip.yml) and the kube-vip
|
|
service load balancer (roles/k3s_server/tasks/kube-vip.yml) are both included
|
|
from roles/k3s_server/tasks/main.yml. Before this switch existed the VIP
|
|
include had no gate and always ran, so a user who wanted no kube-vip (single
|
|
node or external LB) could not opt out.
|
|
|
|
This test loads the real `when` expressions from the k3s_server task file and
|
|
evaluates them against representative variable sets, asserting that:
|
|
|
|
- the control-plane VIP is deployed only when kube_vip_enabled is true;
|
|
- the service load balancer is deployed only when kube_vip_enabled is true
|
|
AND kube_vip_lb_ip_range is defined.
|
|
"""
|
|
|
|
from __future__ import print_function
|
|
|
|
import os
|
|
import re
|
|
import subprocess
|
|
|
|
import yaml
|
|
from jinja2 import Environment
|
|
|
|
VIP_WHEN = "kube_vip_enabled"
|
|
KUBE_VIP_WHEN = "kube_vip_enabled and kube_vip_lb_ip_range is defined"
|
|
|
|
|
|
def repo_root():
|
|
return subprocess.check_output(
|
|
["git", "rev-parse", "--show-toplevel"], text=True
|
|
).strip()
|
|
|
|
|
|
def fail(message):
|
|
raise SystemExit("kube-vip deploy condition test failed: " + message)
|
|
|
|
|
|
def extract_when(path, task_name):
|
|
"""Return the `when:` expression string for the named task."""
|
|
with open(path, encoding="utf-8") as handle:
|
|
doc = yaml.safe_load(handle)
|
|
for task in doc:
|
|
if task.get("name") == task_name:
|
|
when = task.get("when")
|
|
return (when or "").strip()
|
|
return None
|
|
|
|
|
|
def evaluate(when, variables):
|
|
"""Evaluate a `when` expression against variables using Jinja2."""
|
|
env = Environment()
|
|
|
|
def fake_bool(value):
|
|
# Minimal stand-in for Ansible's truthiness filter used by `| bool`.
|
|
if isinstance(value, bool):
|
|
return value
|
|
if value is None:
|
|
return False
|
|
return str(value).lower() in ("1", "true", "yes", "on")
|
|
|
|
env.filters["bool"] = fake_bool
|
|
template = env.from_string("{{ " + when + " }}")
|
|
rendered = template.render(**variables)
|
|
# The expression renders to the literal strings "True"/"False".
|
|
if rendered == "True":
|
|
return True
|
|
if rendered == "False":
|
|
return False
|
|
fail("condition did not render to a boolean: {0!r}".format(rendered))
|
|
|
|
|
|
def assert_deployment(when, variables, expected, label):
|
|
result = evaluate(when, variables)
|
|
verdict = "deploy" if result else "skip"
|
|
expected_verdict = "deploy" if expected else "skip"
|
|
if result != expected:
|
|
fail(
|
|
"{0}: expected to {1} but the condition chose to {2} "
|
|
"(vars: {3})".format(label, expected_verdict, verdict, variables)
|
|
)
|
|
|
|
|
|
def scenarios():
|
|
"""Yield (variables, expected_vip, expected_service_lb, label) pairs."""
|
|
yield (
|
|
# Default inventory: kube-vip enabled, no service LB range.
|
|
{
|
|
"kube_vip_enabled": True,
|
|
},
|
|
True,
|
|
False,
|
|
"default: kube-vip VIP only",
|
|
)
|
|
yield (
|
|
# kube-vip owns the service LB range too.
|
|
{
|
|
"kube_vip_enabled": True,
|
|
"kube_vip_lb_ip_range": "192.168.30.80-192.168.30.90",
|
|
},
|
|
True,
|
|
True,
|
|
"kube-vip VIP and service LB",
|
|
)
|
|
yield (
|
|
# Explicitly disabled, no LB range.
|
|
{
|
|
"kube_vip_enabled": False,
|
|
},
|
|
False,
|
|
False,
|
|
"kube_vip_enabled: false",
|
|
)
|
|
yield (
|
|
# Explicitly disabled even when the LB range is present.
|
|
{
|
|
"kube_vip_enabled": False,
|
|
"kube_vip_lb_ip_range": "192.168.30.80-192.168.30.90",
|
|
},
|
|
False,
|
|
False,
|
|
"kube_vip_enabled: false despite LB range",
|
|
)
|
|
|
|
|
|
def main():
|
|
root = repo_root()
|
|
server_tasks = os.path.join(root, "roles", "k3s_server", "tasks", "main.yml")
|
|
|
|
vip_when = extract_when(server_tasks, "Deploy vip manifest")
|
|
kube_vip_when = extract_when(server_tasks, "Deploy kube-vip manifest")
|
|
|
|
if vip_when is None:
|
|
fail("could not find 'Deploy vip manifest' when condition")
|
|
if kube_vip_when is None:
|
|
fail("could not find 'Deploy kube-vip manifest' when condition")
|
|
|
|
if vip_when != VIP_WHEN:
|
|
fail(
|
|
"k3s_server/tasks/main.yml 'Deploy vip manifest' when condition "
|
|
"changed unexpectedly:\n"
|
|
" expected: {0}\n got: {1}".format(VIP_WHEN, vip_when)
|
|
)
|
|
if kube_vip_when != KUBE_VIP_WHEN:
|
|
fail(
|
|
"k3s_server/tasks/main.yml 'Deploy kube-vip manifest' when "
|
|
"condition changed unexpectedly:\n"
|
|
" expected: {0}\n got: {1}".format(KUBE_VIP_WHEN, kube_vip_when)
|
|
)
|
|
|
|
for variables, expected_vip, expected_service_lb, label in scenarios():
|
|
assert_deployment(vip_when, variables, expected_vip, "vip " + label)
|
|
assert_deployment(
|
|
kube_vip_when,
|
|
variables,
|
|
expected_service_lb,
|
|
"service_lb " + label,
|
|
)
|
|
|
|
print("kube-vip deploy condition regression test passed for all scenarios")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|