Turn talos patches into templates and resolve them

This commit is contained in:
2025-11-08 05:47:24 +01:00
parent 0642fde397
commit 3290a76193
11 changed files with 64 additions and 15 deletions

3
.prettierrc Normal file
View File

@@ -0,0 +1,3 @@
{
"bracketSpacing": false
}

View File

@@ -18,6 +18,12 @@ dns:
- 1.1.1.1
- 8.8.8.8
ntp: nl.pool.ntp.org
installDisk: /dev/sda
install: false
patch: !patch
- hostname
patches:
- !patch hostname
- !patch install-disk
- !patch network
- !patch vip
patchesControlplane:
- !patch allow-controlplane-workloads

View File

@@ -1,3 +1,4 @@
netmask: 255.255.252.0
gateway: 10.0.0.1
install: true
controlplaneIp: 10.0.2.1

View File

@@ -1,2 +1,5 @@
netmask: 255.255.255.0
gateway: 192.168.1.1
clusterName: testing
controlplaneIp: 192.168.1.100
instalDisk: /dev/vda

View File

@@ -1,4 +1,4 @@
serial: talos-vm
interface: enp1s0
interface: eth0
ip: 192.168.1.2
install: true

View File

@@ -1,4 +1,4 @@
---
machine:
network:
hostname: talos-vm
hostname: {{hostname}}

View File

@@ -1,4 +1,4 @@
---
machine:
install:
disk: /dev/vda
disk: {{installDisk}}

View File

@@ -2,10 +2,10 @@
machine:
network:
interfaces:
- interface: eth0
- interface: {{interface}}
dhcp: false
addresses:
- 192.168.1.2
- {{ip}}
routes:
- network: 0.0.0.0/0
gateway: 192.168.1.1
gateway: {{gateway}}

View File

@@ -2,6 +2,6 @@
machine:
network:
interfaces:
- interface: eth0
- interface: {{interface}}
vip:
ip: 192.168.1.100
ip: {{controlplaneIp}}

View File

@@ -1,2 +1,3 @@
PyYAML==6.0.3
requests==2.32.5
Jinja2==3.1.6

View File

@@ -8,9 +8,29 @@ import pathlib
import requests
import yaml
from jinja2 import Environment, FileSystemLoader, StrictUndefined, Template
NODES = pathlib.Path("nodes")
SCHEMATICS = pathlib.Path("schematics")
PATCHES = Environment(loader=FileSystemLoader("patches"), undefined=StrictUndefined)
TEMPLATES = Environment(loader=FileSystemLoader("templates"), undefined=StrictUndefined)
def node_encoder(node: dict):
class Inner(json.JSONEncoder):
def default(self, o):
if isinstance(o, Template):
try:
rendered = o.render(node)
except Exception as e:
e.add_note(f"While rendering for: {node['hostname']}")
raise e
# Parse the rendered yaml and convert it to a json patch
return json.dumps(yaml.safe_load(rendered))
return super().default(o)
return Inner
@functools.cache
@@ -24,18 +44,28 @@ def get_schematic_id(schematic: str):
def schematic_constructor(loader: yaml.SafeLoader, node: yaml.nodes.ScalarNode):
"""Load specified schematic file and get the assocatied schematic id"""
filename = loader.construct_scalar(node)
schematic_name = loader.construct_yaml_str(node)
try:
schematic = SCHEMATICS.joinpath(filename).with_suffix(".yaml").read_text()
schematic = SCHEMATICS.joinpath(schematic_name).with_suffix(".yaml").read_text()
return get_schematic_id(schematic)
except Exception:
raise yaml.MarkedYAMLError("Failed to load schematic", node.start_mark)
def patch_constructor(loader: yaml.SafeLoader, node: yaml.nodes.ScalarNode):
patch_name = loader.construct_scalar(node)
try:
template = PATCHES.get_template(f"{patch_name}.yaml")
return template
except Exception:
raise yaml.MarkedYAMLError("Failed to load patch", node.start_mark)
def get_loader():
"""Add special constructors to yaml loader"""
loader = yaml.SafeLoader
loader.add_constructor("!schematic", schematic_constructor)
loader.add_constructor("!patch", patch_constructor)
return loader
@@ -65,7 +95,7 @@ def walk_files(root: pathlib.Path):
def main():
data = []
nodes = []
for fullname in walk_files(NODES):
filename = str(fullname.relative_to(NODES).parent) + "/" + fullname.stem
@@ -74,10 +104,15 @@ def main():
yml_data = get_defaults(fullname.parent, NODES) | yml_data
yml_data["hostname"] = fullname.stem
yml_data["filename"] = filename
data.append(yml_data)
nodes.append(yml_data)
final_nodes = []
for node in nodes:
# Quick and dirty way to resolve all the templates using a custom encoder
final_nodes.append(json.loads(json.dumps(node, cls=node_encoder(node))))
# Dump everything to json
print(json.dumps(data, indent=4))
print(json.dumps(final_nodes, indent=4))
if __name__ == "__main__":