mirror of
https://github.com/techno-tim/k3s-ansible.git
synced 2026-10-23 12:12:04 +02:00
Compare commits
2
Commits
1b994f7479
...
a976f16b21
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a976f16b21 | ||
|
|
377687cbbe |
No files matched your search
+112
@@ -0,0 +1,112 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Assert the k3s-init log destination guard skips when unset.
|
||||||
|
|
||||||
|
``roles/k3s_server/tasks/main.yml`` fetches k3s-init diagnostics only when
|
||||||
|
``ANSIBLE_K3S_LOG_DIR`` is set. The lookup default must be an empty string:
|
||||||
|
Jinja stringifies the boolean ``False`` to ``'False'``, which is non-empty, so
|
||||||
|
a boolean default makes the guard pass and the role creates a directory
|
||||||
|
literally named ``False`` in the operator's working directory on every run.
|
||||||
|
|
||||||
|
This test extracts the real ``log_destination`` expression from the role and
|
||||||
|
renders it for both the unset and set cases.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
from jinja2 import Environment
|
||||||
|
|
||||||
|
ROLE = os.path.join("roles", "k3s_server", "tasks", "main.yml")
|
||||||
|
|
||||||
|
|
||||||
|
def repo_root():
|
||||||
|
return subprocess.check_output(
|
||||||
|
["git", "rev-parse", "--show-toplevel"], text=True
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def fail(message):
|
||||||
|
raise SystemExit("k3s-init log destination test failed: " + message)
|
||||||
|
|
||||||
|
|
||||||
|
def find_log_task(root):
|
||||||
|
"""Return the 'Save logs of k3s-init.service' task from the role."""
|
||||||
|
with open(os.path.join(root, ROLE), "r") as handle:
|
||||||
|
tasks = yaml.safe_load(handle)
|
||||||
|
|
||||||
|
def walk(entries):
|
||||||
|
for entry in entries or []:
|
||||||
|
if not isinstance(entry, dict):
|
||||||
|
continue
|
||||||
|
if "Save logs of k3s-init.service" in str(entry.get("name", "")):
|
||||||
|
return entry
|
||||||
|
for key in ("block", "always", "rescue"):
|
||||||
|
found = walk(entry.get(key))
|
||||||
|
if found:
|
||||||
|
return found
|
||||||
|
return None
|
||||||
|
|
||||||
|
task = walk(tasks)
|
||||||
|
if task is None:
|
||||||
|
fail("could not find the 'Save logs of k3s-init.service' task in " + ROLE)
|
||||||
|
return task
|
||||||
|
|
||||||
|
|
||||||
|
def env_lookup(name, default=None, **kwargs):
|
||||||
|
"""Stand-in for the env lookup: unset names fall back to the default."""
|
||||||
|
return {"ANSIBLE_K3S_LOG_DIR": None}.get(name, default)
|
||||||
|
|
||||||
|
|
||||||
|
def render(task, env, value):
|
||||||
|
"""Render log_destination the way Ansible folds a '>-' scalar."""
|
||||||
|
expression = str(task["vars"]["log_destination"]).strip()
|
||||||
|
template = env.from_string(expression)
|
||||||
|
|
||||||
|
def lookup(*args, **kwargs):
|
||||||
|
name = args[1] if len(args) > 1 else kwargs.get("name")
|
||||||
|
if name != "ANSIBLE_K3S_LOG_DIR":
|
||||||
|
return kwargs.get("default")
|
||||||
|
return kwargs["default"] if value is None else value
|
||||||
|
|
||||||
|
return template.render(lookup=lookup).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
root = repo_root()
|
||||||
|
task = find_log_task(root)
|
||||||
|
env = Environment()
|
||||||
|
|
||||||
|
unset = render(task, env, None)
|
||||||
|
if unset != "":
|
||||||
|
fail(
|
||||||
|
"log_destination resolved to %r when ANSIBLE_K3S_LOG_DIR is unset; "
|
||||||
|
"it must be an empty string so the guard skips" % unset
|
||||||
|
)
|
||||||
|
if task["when"].strip() == "":
|
||||||
|
fail("the guard on the log task is empty, so it would always run")
|
||||||
|
|
||||||
|
set_path = render(task, env, "/var/log/k3s-init")
|
||||||
|
if set_path != "/var/log/k3s-init":
|
||||||
|
fail(
|
||||||
|
"log_destination resolved to %r when ANSIBLE_K3S_LOG_DIR is set; "
|
||||||
|
"expected the path to be passed through unchanged" % set_path
|
||||||
|
)
|
||||||
|
|
||||||
|
# A stray default= would leave the boolean in place even though the
|
||||||
|
# expression still renders empty, so assert the source no longer carries
|
||||||
|
# it. This is the exact regression that produced the False/ directory.
|
||||||
|
if re.search(r"default\s*=\s*False", yaml.safe_dump(task)):
|
||||||
|
fail(
|
||||||
|
"log_destination still uses a boolean default; Jinja would "
|
||||||
|
"stringify it to 'False' and create a directory named False"
|
||||||
|
)
|
||||||
|
|
||||||
|
print("k3s-init log destination regression test passed")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -68,7 +68,7 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # 7.0.1
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # 7.0.1
|
||||||
- name: Ensure SHA pinned actions
|
- name: Ensure SHA pinned actions
|
||||||
uses: zgosalvez/github-actions-ensure-sha-pinned-actions@60e3a74c7b74a319e8e53e46bc455205f7173e1a # 5.0.8
|
uses: zgosalvez/github-actions-ensure-sha-pinned-actions@62574f011e0d1967d555a862bd28a7abba8684fe # 5.0.9
|
||||||
with:
|
with:
|
||||||
allowlist: |
|
allowlist: |
|
||||||
aws-actions/
|
aws-actions/
|
||||||
|
|||||||
@@ -64,6 +64,12 @@ repos:
|
|||||||
language: system
|
language: system
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
files: ^roles/k3s_server/tasks/(main|join_master)\.yml$|^\.github/scripts/test-k3s-server-bootstrap\.sh$
|
files: ^roles/k3s_server/tasks/(main|join_master)\.yml$|^\.github/scripts/test-k3s-server-bootstrap\.sh$
|
||||||
|
- id: k3s-init-log-destination-test
|
||||||
|
name: K3s init log destination test
|
||||||
|
entry: .github/scripts/test-k3s-init-log-destination.py
|
||||||
|
language: system
|
||||||
|
pass_filenames: false
|
||||||
|
files: ^roles/k3s_server/tasks/main\.yml$|^\.github/scripts/test-k3s-init-log-destination\.py$
|
||||||
- id: unique-hostname-precheck-test
|
- id: unique-hostname-precheck-test
|
||||||
name: Unique hostname precheck test
|
name: Unique hostname precheck test
|
||||||
entry: .github/scripts/test-unique-hostname-precheck.sh
|
entry: .github/scripts/test-unique-hostname-precheck.sh
|
||||||
|
|||||||
@@ -124,13 +124,18 @@
|
|||||||
always:
|
always:
|
||||||
- name: Save logs of k3s-init.service
|
- name: Save logs of k3s-init.service
|
||||||
ansible.builtin.include_tasks: fetch_k3s_init_logs.yml
|
ansible.builtin.include_tasks: fetch_k3s_init_logs.yml
|
||||||
# ANSIBLE_K3S_LOG_DIR is a path string when set; evaluate it as a boolean
|
# The env lookup default must be an empty string, not the boolean
|
||||||
# so the conditional is a real boolean (ansible-core 2.19 rejects string
|
# False. The `!= ''` comparison below always evaluates to a bool, so
|
||||||
# conditionals derived from env vars).
|
# ansible-core 2.19 never sees a non-boolean conditional and no boolean
|
||||||
|
# default is needed. With a boolean default, an unset ANSIBLE_K3S_LOG_DIR
|
||||||
|
# leaves log_destination as the bool False, and `False != ''` is True
|
||||||
|
# because False == 0. The guard would then always pass, running the
|
||||||
|
# diagnostics on every provisioning run and creating a directory
|
||||||
|
# literally named 'False' in the operator's working directory.
|
||||||
when: log_destination | default('') != ''
|
when: log_destination | default('') != ''
|
||||||
vars:
|
vars:
|
||||||
log_destination: >-
|
log_destination: >-
|
||||||
{{ lookup('ansible.builtin.env', 'ANSIBLE_K3S_LOG_DIR', default=False) }}
|
{{ lookup('ansible.builtin.env', 'ANSIBLE_K3S_LOG_DIR', default='') }}
|
||||||
- name: Kill the temporary service used for initialization
|
- name: Kill the temporary service used for initialization
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: k3s-init
|
name: k3s-init
|
||||||
|
|||||||
@@ -85,5 +85,5 @@
|
|||||||
dest: ./kubeconfig
|
dest: ./kubeconfig
|
||||||
flat: true
|
flat: true
|
||||||
when: >-
|
when: >-
|
||||||
ansible_facts.hostname == hostvars[groups[group_name_master | default('master')][0]]
|
ansible_facts.hostname ==
|
||||||
['ansible_facts']['hostname']
|
hostvars[groups[group_name_master | default('master')][0]]['ansible_facts']['hostname']
|
||||||
Reference in new issue
Block a user