Compare commits

..

58 Commits

Author SHA1 Message Date
fa1a621d03 --wip-- [skip ci] 2026-03-21 02:08:55 +01:00
08c1d0c605 feat: Added config validation 2026-02-20 05:33:50 +01:00
7b29763230 feat: Add yaml schema pre-commit check to patches 2026-02-20 05:21:59 +01:00
95de53206e feat: Add schema comments to patches
These comments ensure that we get proper yaml language server support
in the patch files.
Also fixes all the resulting language server errors.
2026-02-20 05:19:59 +01:00
940b01a7dc feat: Remove v version prefix in node config
This allows for better checking if the provided version string adheres
to semver.
2026-02-20 04:56:15 +01:00
b6c201775a feat: Added gateway api 2025-12-17 02:29:08 +01:00
be9dc8438b feat: Enable metrics server 2025-12-16 23:47:36 +01:00
873e73c310 feat: Added volume for local-path-provisioner 2025-12-09 02:38:51 +01:00
5c8cda5cc4 feat: Switched to longhorn 2025-12-09 02:21:43 +01:00
ac0d5244d3 feat: Added openebs patch 2025-12-09 02:21:42 +01:00
92345e5f1e chore: Added pre-commit hooks 2025-12-09 02:21:42 +01:00
47b85437e3 fix: Increase available resources 2025-12-09 02:21:37 +01:00
9c3c4005ed Configure talos for spegel 2025-12-02 02:45:26 +01:00
5eeba518a9 Added cluster variables for flux substitutions 2025-12-02 02:18:46 +01:00
f5798dae4c Added sops keys 2025-12-01 02:19:52 +01:00
1da24905ef Added helper function to load file content as base64 2025-12-01 01:59:08 +01:00
b0a1d04d7d Make route advertising configurable 2025-12-01 01:58:48 +01:00
7d5b09c623 Automatically add tailscale tag for cluster 2025-12-01 01:58:26 +01:00
e4f6c46fc3 Renamed production cluster to titan 2025-11-22 00:39:40 +01:00
b24feec37a Prepare cluster for cilium deployment 2025-11-22 00:16:31 +01:00
b57381afcb Added instruction for upgrading kubernetes 2025-11-22 00:16:14 +01:00
3200aaebaa Deepmerge node configs 2025-11-12 04:20:21 +01:00
f4d08c3516 Switched yaml to 2 space indent 2025-11-12 03:20:35 +01:00
b69ce72e79 Use uv for python 2025-11-12 03:18:43 +01:00
3b0a49f12e Added tailscale
Also routes the whole subnet of the cluster over tailscale so it can act
as an entry point to my home network even when not at home.
2025-11-11 04:18:18 +01:00
a75a0c8722 Access node parameters through node instead of directly 2025-11-11 04:17:47 +01:00
2dda3cc465 Also load config settings from secrets.yaml 2025-11-11 04:17:45 +01:00
c121533161 Pass config to node renderer 2025-11-11 03:41:59 +01:00
14e88a6734 Use ip in vm range 2025-11-11 02:27:39 +01:00
c406514cb1 Added option to auto install talos 2025-11-11 02:27:39 +01:00
3328fb053c PXE boot over http 2025-11-11 02:27:39 +01:00
cc421f69de Set correct endpoins in talosconfig 2025-11-09 05:10:26 +01:00
db43cf50fd Improve how talosconfig is set during config generation 2025-11-09 05:10:12 +01:00
73c8797dfc Fix vm ethernet interface name 2025-11-09 04:31:39 +01:00
b6633591bb Try to delete network even if vm does not exist 2025-11-09 04:15:19 +01:00
d9def74cf3 Made secrets file configurable 2025-11-09 04:15:19 +01:00
1931ab71ca Added yaml constructor that get the realpath of a file 2025-11-09 04:15:19 +01:00
498b0ba480 Improved how the cluster is defined 2025-11-09 04:15:18 +01:00
244c982b17 Fixed wornding of control plane 2025-11-09 04:15:18 +01:00
d3f3b8b972 Removed unneeded --- from patches 2025-11-09 04:15:18 +01:00
4b72bdb60d Added source script to set environment variables 2025-11-09 04:15:18 +01:00
ea3d1bf0fa Made repo root available for templates
This allows for embedding the repo root inside of, for example, scripts
to make them function properly no matter where they are run from.
2025-11-09 04:15:18 +01:00
81e861ef14 Find root of repo that contains the actual script
This makes it possible to run the render script from anywhere and have
it still function correctly.
2025-11-09 04:15:18 +01:00
453d952b8f Moved logic for getting clusters to render script 2025-11-09 04:15:18 +01:00
eb36060ef5 Made yaml template loader more generic 2025-11-09 04:15:18 +01:00
0f4fb2c5df Store template resolved nodes back in nodes object 2025-11-09 04:15:18 +01:00
83848a3624 Added template for config generation script 2025-11-09 04:15:18 +01:00
a477e5c4c2 Store patches as objects instead of strings 2025-11-09 04:15:17 +01:00
a8c51ce84b Added node types 2025-11-09 04:15:17 +01:00
969725ecff Added kubernetes version 2025-11-09 04:15:17 +01:00
7460bb19db Added jinja2 do extensions 2025-11-09 04:15:17 +01:00
69e7a46a3c Use consistent capitalization 2025-11-09 04:15:17 +01:00
e4644d1161 Moved around node config params 2025-11-09 04:15:17 +01:00
121f28e987 Make python script runnable from anywhere 2025-11-09 04:15:17 +01:00
d30b080098 Render all template using python and jinja 2025-11-09 04:15:17 +01:00
3290a76193 Turn talos patches into templates and resolve them 2025-11-08 05:47:24 +01:00
0642fde397 Prettyprint JSON 2025-11-08 04:28:45 +01:00
d163e0b9bc Improved how schematics are loaded 2025-11-08 04:26:32 +01:00
63 changed files with 440 additions and 225 deletions

View File

@@ -5,8 +5,4 @@ indent_style = tab
[*.yaml]
indent_style = space
indent_size = 4
[{*.py,tools/merge}]
indent_style = space
indent_size = 4
indent_size = 2

1
.gitattributes vendored
View File

@@ -1 +1,2 @@
*.key filter=git-crypt diff=git-crypt
secrets.yaml filter=git-crypt diff=git-crypt

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.ipxe/
rendered/
configs/
*.egg-info

48
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,48 @@
default_install_hook_types:
- pre-commit
- commit-msg
default_stages:
- pre-commit
repos:
- repo: meta
hooks:
- id: check-hooks-apply
- id: check-useless-excludes
- repo: builtin
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: check-added-large-files
- id: check-merge-conflict
- id: check-executables-have-shebangs
- repo: https://github.com/jmlrt/check-yamlschema
rev: v0.0.7
hooks:
- id: check-yamlschema
files: ^patches/.*\.yaml$
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
hooks:
- id: prettier
- repo: https://github.com/crate-ci/typos
rev: v1.40.0
hooks:
- id: typos
- repo: https://github.com/sirwart/ripsecrets
rev: v0.1.11
hooks:
- id: ripsecrets-system
- repo: https://github.com/crate-ci/committed
rev: v1.1.8
hooks:
- id: committed

3
.prettierrc Normal file
View File

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

2
.secretsignore Normal file
View File

@@ -0,0 +1,2 @@
secrets.yaml
*.key

View File

@@ -65,3 +65,9 @@ Upgrading talos or changing the schematic:
```bash
talosctl upgrade --nodes <node_id> --image factory.talos.dev/metal-installer/<schematic_id>:<version>
```
To upgrade kubernetes or inline manifests, first apply the updated controlplane configs, then run:
```bash
talosctl upgrade-k8s
```

2
committed.toml Normal file
View File

@@ -0,0 +1,2 @@
style = "conventional"
ignore_author_re = "Flux"

View File

@@ -1,2 +0,0 @@
dhcp:
tftpIp: 10.0.0.3

View File

@@ -1,21 +0,0 @@
schematicID: !schematic "_schematic.yaml"
arch: amd64
talosVersion: v1.11.3
kernelArgs:
- talos.platform=metal
- console=tty0
- init_on_alloc=1
- init_on_free=1
- slab_nomerge
- pti=on
- consoleblank=0
- nvme_core.io_timeout=4294967295
- printk.devkmsg=on
- selinux=1
- lockdown=confidentiality
extraKernelArgs: []
dns:
- 1.1.1.1
- 8.8.8.8
ntp: nl.pool.ntp.org
install: false

View File

@@ -1,7 +0,0 @@
customization:
systemExtensions:
officialExtensions:
- siderolabs/iscsi-tools
- siderolabs/util-linux-tools
- siderolabs/intel-ucode
- siderolabs/i915

View File

@@ -1,3 +0,0 @@
netmask: 255.255.252.0
gateway: 10.0.0.1
install: true

View File

@@ -1,3 +0,0 @@
serial: 5CZ7NX2
interface: enp2s0
ip: 10.0.0.202

View File

@@ -1,3 +0,0 @@
serial: F3PKRH2
interface: enp3s0
ip: 10.0.0.201

View File

@@ -1,3 +0,0 @@
serial: J33CHY2
interface: enp2s0
ip: 10.0.0.203

View File

@@ -1,2 +0,0 @@
netmask: 255.255.255.0
gateway: 192.168.1.1

View File

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

View File

@@ -1,3 +0,0 @@
---
cluster:
allowSchedulingOnControlPlanes: true

View File

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

View File

@@ -1,4 +0,0 @@
---
machine:
install:
disk: /dev/vda

View File

@@ -1,11 +0,0 @@
---
machine:
network:
interfaces:
- interface: eth0
dhcp: false
addresses:
- 192.168.1.2
routes:
- network: 0.0.0.0/0
gateway: 192.168.1.1

View File

@@ -1,7 +0,0 @@
---
machine:
network:
interfaces:
- interface: eth0
vip:
ip: 192.168.1.100

View File

@@ -1,2 +0,0 @@
PyYAML==6.0.3
requests==2.32.5

Binary file not shown.

View File

@@ -0,0 +1,53 @@
# yaml-language-server: $schema=../../schemas/cluster.json
version:
kubernetes: 1.34.1
talos: 1.11.3
base:
kernelArgs:
- talos.platform=metal
- console=tty0
- init_on_alloc=1
- init_on_free=1
- slab_nomerge
- pti=on
- consoleblank=0
- nvme_core.io_timeout=4294967295
- printk.devkmsg=on
- selinux=1
- lockdown=confidentiality
patches:
all:
- system/hostname.yaml
- system/install-disk.yaml
- system/network.yaml
- networking/vip.yaml
- networking/tailscale.yaml
- networking/cilium.yaml
- spegel.yaml
- storage/longhorn.yaml
- storage/longhorn/user-volume.yaml
- storage/local-path-provisioner/user-volume.yaml
- storage/limit-ephemeral.yaml
- metrics/all.yaml
controlPlane:
- system/allow-control-plane-workloads.yaml
- sops.yaml
- flux/cluster-variables.yaml
- metrics/control-plane.yaml
- networking/gateway-api.yaml
default:
arch: amd64
schematic: default.yaml
network:
dns:
- 1.1.1.1
- 8.8.8.8
tailscale:
server: https://headscale.huizinga.dev
authKey:
file: tailscale.key
advertiseRoutes: true
ntp: nl.pool.ntp.org
install:
auto: true

View File

@@ -0,0 +1,16 @@
# yaml-language-server: $schema=../../schemas/cluster.json
clusterEnv: staging
controlPlaneIp: 192.168.1.100
secretsFile: testing/secrets.yaml
nodes:
- testing/talos-vm
default:
network:
interface: enp1s0
netmask: 255.255.255.0
gateway: 192.168.1.1
sops:
file: testing/age.key
install:
disk: /dev/vda

17
talos/clusters/titan.yaml Normal file
View File

@@ -0,0 +1,17 @@
# yaml-language-server: $schema=../../schemas/cluster.json
clusterEnv: production
controlPlaneIp: 10.0.2.1
secretsFile: titan/secrets.yaml
nodes:
- titan/hyperion
- titan/helios
- titan/selene
default:
network:
netmask: 255.255.252.0
gateway: 10.0.0.1
sops:
file: titan/age.key
install:
disk: /dev/sda

View File

@@ -0,0 +1,6 @@
# yaml-language-server: $schema=../../../schemas/node.json
type: controlPlane
install:
serial: talos-vm
network:
ip: 192.168.1.2

View File

@@ -0,0 +1,7 @@
# yaml-language-server: $schema=../../../schemas/node.json
type: controlPlane
install:
serial: 5CZ7NX2
network:
interface: enp2s0
ip: 10.0.0.202

View File

@@ -0,0 +1,7 @@
# yaml-language-server: $schema=../../../schemas/node.json
type: controlPlane
install:
serial: F3PKRH2
network:
interface: enp3s0
ip: 10.0.0.201

View File

@@ -0,0 +1,7 @@
# yaml-language-server: $schema=../../../schemas/node.json
type: controlPlane
install:
serial: J33CHY2
network:
interface: enp2s0
ip: 10.0.0.203

View File

@@ -0,0 +1,18 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
cluster:
inlineManifests:
- name: cluster-variables
contents: |
---
apiVersion: v1
kind: Namespace
metadata:
name: flux-system
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-variables
namespace: flux-system
data:
cluster_env: {{ cluster.clusterEnv }}

View File

@@ -0,0 +1,5 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
kubelet:
extraArgs:
rotate-server-certificates: "true"

View File

@@ -0,0 +1,5 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
cluster:
extraManifests:
- https://raw.githubusercontent.com/alex1989hu/kubelet-serving-cert-approver/main/deploy/standalone-install.yaml
- https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

View File

@@ -0,0 +1,12 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
features:
hostDNS:
# This option is enabled by default and causes issues with cilium
forwardKubeDNSToHost: false
cluster:
network:
cni:
name: none
proxy:
disabled: true

View File

@@ -0,0 +1,4 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
cluster:
extraManifests:
- https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.1/standard-install.yaml

View File

@@ -0,0 +1,8 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
apiVersion: v1alpha1
kind: ExtensionServiceConfig
name: tailscale
environment:
- TS_AUTHKEY={{ node.network.tailscale.authKey }}
- TS_EXTRA_ARGS={% if node.network.tailscale.server %}--login-server {{ node.network.tailscale.server }} {% endif %}--advertise-tags=tag:cluster-{{ cluster.name }}
- TS_ROUTES={% if node.network.tailscale.advertiseRoutes %}{{node.network.ip}}/{{ node.network.netmask | to_prefix }}{% endif %}

View File

@@ -0,0 +1,7 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
network:
interfaces:
- interface: "{{node.network.interface}}"
vip:
ip: "{{cluster.controlPlaneIp}}"

18
talos/patches/sops.yaml Normal file
View File

@@ -0,0 +1,18 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
cluster:
inlineManifests:
- name: sops-key
contents: |
apiVersion: v1
kind: Namespace
metadata:
name: flux-system
---
apiVersion: v1
kind: Secret
metadata:
name: sops-gpg
namespace: flux-system
data:
age.agekey: |
{{ node.sops | indent(6*2) }}

View File

@@ -0,0 +1,8 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
files:
- path: /etc/cri/conf.d/20-customization.part
op: create
content: |
[plugins."io.containerd.cri.v1.images"]
discard_unpacked_layers = false

View File

@@ -0,0 +1,6 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
apiVersion: v1alpha1
kind: VolumeConfig
name: EPHEMERAL
provisioning:
maxSize: 30GB

View File

@@ -0,0 +1,9 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
apiVersion: v1alpha1
kind: UserVolumeConfig
name: local-path-provisioner
provisioning:
diskSelector:
match: system_disk
grow: true
maxSize: 10GB

View File

@@ -0,0 +1,11 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
kubelet:
extraMounts:
- destination: /var/lib/longhorn
type: bind
source: /var/lib/longhorn
options:
- bind
- rshared
- rw

View File

@@ -0,0 +1,9 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
apiVersion: v1alpha1
kind: UserVolumeConfig
name: longhorn
provisioning:
diskSelector:
match: system_disk
grow: true
maxSize: 2000GB

View File

@@ -0,0 +1,17 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
# This is only needed on nodes that will have storage
sysctls:
vm.nr_hugepages: "1024"
nodeLabels:
openebs.io/engine: mayastor
# This is needed on ALL nodes
kubelet:
extraMounts:
- destination: /var/local
type: bind
source: /var/local
options:
- bind
- rshared
- rw

View File

@@ -0,0 +1,3 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
cluster:
allowSchedulingOnControlPlanes: true

View File

@@ -0,0 +1,4 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
network:
hostname: "{{node.hostname}}"

View File

@@ -0,0 +1,4 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
install:
disk: "{{node.install.disk}}"

View File

@@ -0,0 +1,11 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.11/website/content/v1.11/schemas/config.schema.json
machine:
network:
interfaces:
- interface: "{{node.network.interface}}"
dhcp: false
addresses:
- "{{node.network.ip}}"
routes:
- network: 0.0.0.0/0
gateway: "{{node.network.gateway}}"

View File

@@ -0,0 +1,8 @@
customization:
systemExtensions:
officialExtensions:
- siderolabs/iscsi-tools
- siderolabs/util-linux-tools
- siderolabs/intel-ucode
- siderolabs/i915
- siderolabs/tailscale

BIN
talos/secrets/tailscale.key Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
talos/secrets/titan/age.key Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -1,25 +1,23 @@
{% set httpUrl = "http://192.168.1.1:8000" -%}
#!ipxe
dhcp
echo Starting ${serial}
:start
# Is a known serial is set, execute that
# If an unknown serial is set, exit
# If no serial is set, ask the user
goto node_${serial} || shell
goto node_${serial} || exit
# Default behavior (non install mode) is to exit iPXE script
{{ range datasource "nodes" }}
{{- if .install }}
# {{ .filename }}
:node_{{ .serial }}
{{- $ipArg := printf "ip=%s::%s:%s:%s:%s::%s:%s:%s" .ip .gateway .netmask .hostname .interface (index .dns 0) (index .dns 1) .ntp }}
{{- $kernelArgs := printf "%s %s %s" $ipArg (join .kernelArgs " ") (join .extraKernelArgs " ") }}
{% for cluster in clusters%}
{% for node in cluster.nodes %}
{%- if node.install.serial -%}
# {{ cluster.name }}/{{ node.hostname }}
:node_{{ node.install.serial }}
{% set ipArg = "ip=" ~ [node.network.ip, "" , node.network.gateway, node.network.netmask, node.hostname, node.network.interface, "", node.network.dns[0], node.network.dns[1], node.ntp]|join(":") -%}
imgfree
kernel https://pxe.factory.talos.dev/image/{{ .schematicID }}/{{ .talosVersion }}/kernel-{{ .arch }} {{ $kernelArgs }}
initrd https://pxe.factory.talos.dev/image/{{ .schematicID }}/{{ .talosVersion }}/initramfs-{{ .arch }}.xz
kernel https://pxe.factory.talos.dev/image/{{ node.schematic }}/v{{ cluster.version.talos }}/kernel-{{ node.arch }} {{ ipArg }} {{ node.kernelArgs|join(" ") }} {% if node.install.auto %}talos.config={{httpUrl}}/configs/{{cluster.name}}/{{node.hostname}}.yaml{% endif +%}
initrd https://pxe.factory.talos.dev/image/{{ node.schematic }}/v{{ cluster.version.talos }}/initramfs-{{ node.arch }}.xz
boot
{{- end }}
{{ end }}
{% endif %}
{% endfor %}
{% endfor %}

View File

@@ -1,4 +1,4 @@
{{ $tftpIp := (ds "config").dhcp.tftpIp -}}
{% set tftpIp = "192.168.1.1" -%}
enable-tftp
tftp-root=/tftproot
@@ -9,9 +9,9 @@ dhcp-vendorclass=UEFI,PXEClient:Arch:00007
dhcp-vendorclass=UEFI64,PXEClient:Arch:00009
# 1st stage: pxe rom boot on ipxe
dhcp-boot=net:BIOS,ipxe.pxe,{{ $tftpIp }},{{ $tftpIp }}
dhcp-boot=net:UEFI,ipxe.efi,{{ $tftpIp }},{{ $tftpIp }}
dhcp-boot=net:UEFI64,ipxe.efi,{{ $tftpIp }},{{ $tftpIp }}
dhcp-boot=net:BIOS,ipxe.pxe,{{ tftpIp }},{{ tftpIp }}
dhcp-boot=net:UEFI,ipxe.efi,{{ tftpIp }},{{ tftpIp }}
dhcp-boot=net:UEFI64,ipxe.efi,{{ tftpIp }},{{ tftpIp }}
# Based on logic in https://gist.github.com/robinsmidsrod/4008017
# iPXE sends a 175 option, checking suboptions
@@ -30,11 +30,11 @@ tag-if=set:ipxe-ok,tag:ipxe-http,tag:ipxe-https
# these create option 43 cruft, which is required in proxy mode
# TFTP IP is required on all dhcp-boot lines (unless dnsmasq itself acts as tftp server?)
pxe-service=tag:!ipxe-ok,X86PC,PXE,undionly.kpxe,{{ $tftpIp }}
pxe-service=tag:!ipxe-ok,IA32_EFI,PXE,snponlyx32.efi,{{ $tftpIp }}
pxe-service=tag:!ipxe-ok,BC_EFI,PXE,snponly.efi,{{ $tftpIp }}
pxe-service=tag:!ipxe-ok,X86-64_EFI,PXE,snponly.efi,{{ $tftpIp }}
pxe-service=tag:!ipxe-ok,X86PC,PXE,undionly.kpxe,{{ tftpIp }}
pxe-service=tag:!ipxe-ok,IA32_EFI,PXE,snponlyx32.efi,{{ tftpIp }}
pxe-service=tag:!ipxe-ok,BC_EFI,PXE,snponly.efi,{{ tftpIp }}
pxe-service=tag:!ipxe-ok,X86-64_EFI,PXE,snponly.efi,{{ tftpIp }}
# later match overrides previous, keep ipxe script last
# server address must be non zero, but can be anything as long as iPXE script is not fetched over TFTP
dhcp-boot=tag:ipxe-ok,boot.ipxe,,{{ $tftpIp }}
dhcp-boot=tag:ipxe-ok,boot.ipxe,,{{ tftpIp }}

View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail
CONFIGS={{ root }}/configs
TALOSCONFIG=${CONFIGS}/talosconfig
rm -f ${CONFIGS}
# Generate the configuration for each node
{% for cluster in clusters %}
{% for node in cluster.nodes -%}
talosctl gen config {{ cluster.name }} https://{{ cluster.controlPlaneIp }}:6443 -f \
--with-secrets {{ cluster.secretsFile }} \
--talos-version v{{ cluster.version.talos }} \
--kubernetes-version v{{ cluster.version.kubernetes }} \
--output-types {{ node.type }} \
--install-image factory.talos.dev/metal-installer/{{ node.schematic }}:v{{ cluster.version.talos }} \
{% for patch in node.patches.all -%}
{# The double call to tojson is needed to properly escape the patch (object -> json -> string) -#}
--config-patch {{ patch|tojson|tojson }} \
{% endfor -%}
{% for patch in node.patches.controlPlane -%}
--config-patch-control-plane {{ patch|tojson|tojson }} \
{% endfor -%}
--with-docs=false \
--with-examples=false \
-o ${CONFIGS}/{{ cluster.name }}/{{ node.hostname }}.yaml
{% endfor %}
# Generate the talosconfig file for each cluster
talosctl gen config {{ cluster.name }} https://{{ cluster.controlPlaneIp }}:6443 -f \
--with-secrets {{ cluster.secretsFile }} \
--output-types talosconfig \
-o ${CONFIGS}/{{ cluster.name }}/talosconfig
# Create merged talosconfig
talosctl config --talosconfig=${CONFIGS}/{{ cluster.name }}/talosconfig endpoint {{ cluster.controlPlaneIp }}
talosctl config --talosconfig=${TALOSCONFIG} merge ${CONFIGS}/{{ cluster.name }}/talosconfig
{% endfor %}

2
templates/source.sh Normal file
View File

@@ -0,0 +1,2 @@
export TALOSCONFIG={{ root }}/configs/talosconfig
export KUBECONFIG={{ clusters|map(attribute='name')|kubeconfig|join(":") }}

View File

@@ -1,96 +0,0 @@
#!/usr/bin/env python3
# Adapted from: https://enix.io/en/blog/pxe-talos/
import argparse
import functools
import json
import pathlib
import requests
import yaml
@functools.cache
def get_schematic_id(schematic: str):
"""Lookup the schematic id associated with a given schematic"""
r = requests.post("https://factory.talos.dev/schematics", data=schematic)
r.raise_for_status()
data = r.json()
return data["id"]
def schematic_constructor(directory: pathlib.Path):
"""Load specified schematic file and get the assocatied schematic id"""
def constructor(loader: yaml.SafeLoader, node: yaml.nodes.ScalarNode):
filename = str(loader.construct_scalar(node))
try:
schematic = directory.joinpath(filename).read_text()
return get_schematic_id(schematic)
except Exception:
raise yaml.MarkedYAMLError("Failed to load schematic", node.start_mark)
return constructor
def get_loader(directory: pathlib.Path):
"""Add special constructors to yaml loader"""
loader = yaml.SafeLoader
loader.add_constructor("!schematic", schematic_constructor(directory))
return loader
@functools.cache
def get_defaults(directory: pathlib.Path, root: pathlib.Path):
"""Compute the defaults from the provided directory and parents."""
try:
with open(directory.joinpath("_defaults.yaml")) as fyaml:
yml_data = yaml.load(fyaml, Loader=get_loader(directory))
except OSError:
yml_data = {}
# Stop recursion when reaching root directory
if directory != root:
return get_defaults(directory.parent, root) | yml_data
else:
return yml_data
def walk_files(root: pathlib.Path):
"""Get all files that do not start with and underscore"""
for dirpath, _dirnames, filenames in root.walk():
for fn in filenames:
if not fn.startswith("_"):
yield dirpath.joinpath(fn)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("directory", type=pathlib.Path)
parser.add_argument("-f", "--filter")
args = parser.parse_args()
data = []
for fullname in walk_files(args.directory):
filename = (
str(fullname.relative_to(args.directory).parent) + "/" + fullname.stem
)
if args.filter is not None and not filename.startswith(args.filter):
continue
with open(fullname) as fyaml:
yml_data = yaml.load(fyaml, Loader=get_loader(fullname.parent))
yml_data = get_defaults(fullname.parent, args.directory) | yml_data
yml_data["hostname"] = fullname.stem
yml_data["filename"] = filename
data.append(yml_data)
# Dump everything to json
print(json.dumps(data))
if __name__ == "__main__":
main()

View File

@@ -1,11 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT=$(git rev-parse --show-toplevel)
RENDERED=${ROOT}/rendered
TEMPLATES=${ROOT}/templates
${ROOT}/tools/merge ./nodes > ${RENDERED}/nodes.json
gomplate --input-dir ${TEMPLATES} --output-dir ${RENDERED} \
-d nodes=file://${RENDERED}/nodes.json \
-d config=${ROOT}/config.yaml \

View File

@@ -6,6 +6,7 @@ IPXE_VERSION=b41bda4413bf286d7b7a449bc05e1531da1eec2e
IPXE_BIN=(bin/ipxe.pxe bin-x86_64-efi/ipxe.efi)
IPXE_DIR=${ROOT}/.ipxe/ipxe-${IPXE_VERSION}
HTTP_URL=$(cat ${ROOT}/config.yaml | yq .server.httpUrl)
function download_ipxe() {
base_dir=$(dirname ${IPXE_DIR})
@@ -25,7 +26,8 @@ function patch_ipxe() {
#!ipxe
dhcp
chain boot.ipxe || shell
chain ${HTTP_URL}/boot.ipxe || shell
# chain boot.ipxe || shell
EOF
cd - > /dev/null
@@ -44,6 +46,7 @@ function build_ipxe() {
function render() {
${ROOT}/tools/render
${ROOT}/rendered/generate_configs.sh
}
function host_tftp() {
@@ -64,8 +67,30 @@ function host_tftp() {
sudo in.tftpd --verbosity 100 --permissive -L --secure ${TFTP_DIR}
}
function host_http() {
HTTP_DIR=$(mktemp --tmpdir -d http.XXX)
chmod 755 ${HTTP_DIR}
function cleanup() {
rm -rf ${HTTP_DIR}
}
trap cleanup EXIT
ln -s ${ROOT}/rendered/boot.ipxe ${HTTP_DIR}
for bin in "${IPXE_BIN[@]}"; do
path=${IPXE_DIR}/src/${bin}
ln -s ${path} ${HTTP_DIR}
done
ln -s ${ROOT}/configs ${HTTP_DIR}
echo "Starting http"
cd ${HTTP_DIR}
python -m http.server 8000
cd -
}
download_ipxe
patch_ipxe
build_ipxe
render
host_tftp
host_http

View File

@@ -3,9 +3,9 @@ set -euo pipefail
ROOT=$(git rev-parse --show-toplevel)
VM_NAME="talos-vm"
VCPUS="2"
RAM_MB="2048"
DISK_GB="10"
VCPUS="6"
RAM_MB="16384"
DISK_GB="100"
NETWORK=talos
CONNECTION="qemu:///system"
@@ -21,7 +21,7 @@ function define_network() {
<ip address="192.168.1.1" netmask="255.255.255.0">
<dhcp>
<range start="192.168.1.2" end="192.168.1.254"/>
<bootp file='ipxe.pxe'/>
<bootp file='http://192.168.1.1:8000/ipxe.pxe'/>
</dhcp>
</ip>
</network>
@@ -111,13 +111,12 @@ function delete() {
virsh --connect="${CONNECTION}" destroy "${VM_NAME}"
fi
virsh --connect="${CONNECTION}" undefine "${VM_NAME}" --remove-all-storage
else
echo "VM doest not exists"
exit -1
fi
if [[ $(virsh --connect="${CONNECTION}" net-list --all | grep -c "${NETWORK}") > "0" ]]; then
virsh --connect="${CONNECTION}" net-destroy "${NETWORK}"
if [[ $(virsh --connect="${CONNECTION}" list | grep -c "${VM_NAME}") > "0" ]]; then
virsh --connect="${CONNECTION}" net-destroy "${NETWORK}"
fi
virsh --connect="${CONNECTION}" net-undefine "${NETWORK}"
fi
}