Compare commits

60 Commits

Author SHA1 Message Date
Dreaded_X bfa8b929f2 feat: TESTING 2026-04-17 21:47:04 +02:00
Dreaded_X a44417fb67 feat: Update to talos and kubernetes 2026-04-17 21:43:17 +02:00
Dreaded_X 30a385b1e6 feat: Use new headscale auth keys 2026-04-17 21:43:16 +02:00
Dreaded_X 557dc4f861 feat: Use vagrant for managing vm 2026-04-17 21:43:15 +02:00
Dreaded_X 5f146a3fa5 chore: Update gpg key 2026-04-17 21:43:14 +02:00
Dreaded_X 3a3d741781 feat: Rewrote render tool in rust
This also came with a big rework of the configuration format that should
make everything a bit less hacky to work with.
2026-04-17 21:43:12 +02:00
Dreaded_X 08c1d0c605 feat: Added config validation 2026-02-20 05:33:50 +01:00
Dreaded_X 7b29763230 feat: Add yaml schema pre-commit check to patches 2026-02-20 05:21:59 +01:00
Dreaded_X 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
Dreaded_X 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
Dreaded_X b6c201775a feat: Added gateway api 2025-12-17 02:29:08 +01:00
Dreaded_X be9dc8438b feat: Enable metrics server 2025-12-16 23:47:36 +01:00
Dreaded_X 873e73c310 feat: Added volume for local-path-provisioner 2025-12-09 02:38:51 +01:00
Dreaded_X 5c8cda5cc4 feat: Switched to longhorn 2025-12-09 02:21:43 +01:00
Dreaded_X ac0d5244d3 feat: Added openebs patch 2025-12-09 02:21:42 +01:00
Dreaded_X 92345e5f1e chore: Added pre-commit hooks 2025-12-09 02:21:42 +01:00
Dreaded_X 47b85437e3 fix: Increase available resources 2025-12-09 02:21:37 +01:00
Dreaded_X 9c3c4005ed Configure talos for spegel 2025-12-02 02:45:26 +01:00
Dreaded_X 5eeba518a9 Added cluster variables for flux substitutions 2025-12-02 02:18:46 +01:00
Dreaded_X f5798dae4c Added sops keys 2025-12-01 02:19:52 +01:00
Dreaded_X 1da24905ef Added helper function to load file content as base64 2025-12-01 01:59:08 +01:00
Dreaded_X b0a1d04d7d Make route advertising configurable 2025-12-01 01:58:48 +01:00
Dreaded_X 7d5b09c623 Automatically add tailscale tag for cluster 2025-12-01 01:58:26 +01:00
Dreaded_X e4f6c46fc3 Renamed production cluster to titan 2025-11-22 00:39:40 +01:00
Dreaded_X b24feec37a Prepare cluster for cilium deployment 2025-11-22 00:16:31 +01:00
Dreaded_X b57381afcb Added instruction for upgrading kubernetes 2025-11-22 00:16:14 +01:00
Dreaded_X 3200aaebaa Deepmerge node configs 2025-11-12 04:20:21 +01:00
Dreaded_X f4d08c3516 Switched yaml to 2 space indent 2025-11-12 03:20:35 +01:00
Dreaded_X b69ce72e79 Use uv for python 2025-11-12 03:18:43 +01:00
Dreaded_X 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
Dreaded_X a75a0c8722 Access node parameters through node instead of directly 2025-11-11 04:17:47 +01:00
Dreaded_X 2dda3cc465 Also load config settings from secrets.yaml 2025-11-11 04:17:45 +01:00
Dreaded_X c121533161 Pass config to node renderer 2025-11-11 03:41:59 +01:00
Dreaded_X 14e88a6734 Use ip in vm range 2025-11-11 02:27:39 +01:00
Dreaded_X c406514cb1 Added option to auto install talos 2025-11-11 02:27:39 +01:00
Dreaded_X 3328fb053c PXE boot over http 2025-11-11 02:27:39 +01:00
Dreaded_X cc421f69de Set correct endpoins in talosconfig 2025-11-09 05:10:26 +01:00
Dreaded_X db43cf50fd Improve how talosconfig is set during config generation 2025-11-09 05:10:12 +01:00
Dreaded_X 73c8797dfc Fix vm ethernet interface name 2025-11-09 04:31:39 +01:00
Dreaded_X b6633591bb Try to delete network even if vm does not exist 2025-11-09 04:15:19 +01:00
Dreaded_X d9def74cf3 Made secrets file configurable 2025-11-09 04:15:19 +01:00
Dreaded_X 1931ab71ca Added yaml constructor that get the realpath of a file 2025-11-09 04:15:19 +01:00
Dreaded_X 498b0ba480 Improved how the cluster is defined 2025-11-09 04:15:18 +01:00
Dreaded_X 244c982b17 Fixed wornding of control plane 2025-11-09 04:15:18 +01:00
Dreaded_X d3f3b8b972 Removed unneeded --- from patches 2025-11-09 04:15:18 +01:00
Dreaded_X 4b72bdb60d Added source script to set environment variables 2025-11-09 04:15:18 +01:00
Dreaded_X 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
Dreaded_X 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
Dreaded_X 453d952b8f Moved logic for getting clusters to render script 2025-11-09 04:15:18 +01:00
Dreaded_X eb36060ef5 Made yaml template loader more generic 2025-11-09 04:15:18 +01:00
Dreaded_X 0f4fb2c5df Store template resolved nodes back in nodes object 2025-11-09 04:15:18 +01:00
Dreaded_X 83848a3624 Added template for config generation script 2025-11-09 04:15:18 +01:00
Dreaded_X a477e5c4c2 Store patches as objects instead of strings 2025-11-09 04:15:17 +01:00
Dreaded_X a8c51ce84b Added node types 2025-11-09 04:15:17 +01:00
Dreaded_X 969725ecff Added kubernetes version 2025-11-09 04:15:17 +01:00
Dreaded_X 7460bb19db Added jinja2 do extensions 2025-11-09 04:15:17 +01:00
Dreaded_X 69e7a46a3c Use consistent capitalization 2025-11-09 04:15:17 +01:00
Dreaded_X e4644d1161 Moved around node config params 2025-11-09 04:15:17 +01:00
Dreaded_X 121f28e987 Make python script runnable from anywhere 2025-11-09 04:15:17 +01:00
Dreaded_X d30b080098 Render all template using python and jinja 2025-11-09 04:15:17 +01:00
66 changed files with 457 additions and 406 deletions
+1 -5
View File
@@ -5,8 +5,4 @@ indent_style = tab
[*.yaml] [*.yaml]
indent_style = space indent_style = space
indent_size = 4 indent_size = 2
[{*.py,tools/render}]
indent_style = space
indent_size = 4
+1
View File
@@ -1 +1,2 @@
*.key filter=git-crypt diff=git-crypt
secrets.yaml filter=git-crypt diff=git-crypt secrets.yaml filter=git-crypt diff=git-crypt
+1
View File
@@ -1,3 +1,4 @@
.ipxe/ .ipxe/
rendered/ rendered/
configs/ configs/
.vagrant/
+67
View File
@@ -0,0 +1,67 @@
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/python-jsonschema/check-jsonschema
rev: 0.37.1
hooks:
- id: check-jsonschema
files: ^talos/patches/.*\.y(a?)ml$
args:
[
"--schemafile",
"https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json",
]
- id: check-jsonschema
files: ^talos/nodes/.*\.y(a?)ml$
args:
[
"--schemafile",
"https://git.huizinga.dev/infra/crete/raw/branch/main/schemas/node.json",
]
- id: check-jsonschema
files: ^talos/clusters/.*\.y(a?)ml$
args:
[
"--schemafile",
"https://git.huizinga.dev/infra/crete/raw/branch/main/schemas/cluster.json",
]
- 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
+2
View File
@@ -0,0 +1,2 @@
secrets.yaml
*.key
+6
View File
@@ -65,3 +65,9 @@ Upgrading talos or changing the schematic:
```bash ```bash
talosctl upgrade --nodes <node_id> --image factory.talos.dev/metal-installer/<schematic_id>:<version> 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
```
Vendored
+28
View File
@@ -0,0 +1,28 @@
Vagrant.configure("2") do |config|
config.vm.define "talos-vm" do |vm|
vm.vm.network :private_network,
:type => "dhcp",
:libvirt__network_address => "192.168.1.0",
:libvirt__netmask => "255.255.255.0",
# :libvirt__dhcp_bootp_file => "ipxe.pxe"
:libvirt__dhcp_bootp_file => "http://192.168.1.1:8000/ipxe.pxe"
vm.vm.hostname = "talos"
vm.vm.provider :libvirt do |domain|
domain.cpus = 6
domain.memory = 16 * 1024
domain.storage :file, :size => '100G', :type => 'raw'
domain.mgmt_attach = false
domain.boot "hd"
domain.boot "network"
domain.sysinfo = {
"system": {
"serial": "talos-vm"
}
}
end
end
end
+2
View File
@@ -0,0 +1,2 @@
style = "conventional"
ignore_author_re = "Flux"
-2
View File
@@ -1,2 +0,0 @@
dhcp:
tftpIp: 10.0.0.3
+2
View File
@@ -0,0 +1,2 @@
[env]
VAGRANT_DEFAULT_PROVIDER = "libvirt"
-29
View File
@@ -1,29 +0,0 @@
schematicID: !schematic default
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
installDisk: /dev/sda
install: false
patches:
- !patch hostname
- !patch install-disk
- !patch network
- !patch vip
patchesControlplane:
- !patch allow-controlplane-workloads
-4
View File
@@ -1,4 +0,0 @@
netmask: 255.255.252.0
gateway: 10.0.0.1
install: true
controlplaneIp: 10.0.2.1
-3
View File
@@ -1,3 +0,0 @@
serial: 5CZ7NX2
interface: enp2s0
ip: 10.0.0.202
-3
View File
@@ -1,3 +0,0 @@
serial: F3PKRH2
interface: enp3s0
ip: 10.0.0.201
-3
View File
@@ -1,3 +0,0 @@
serial: J33CHY2
interface: enp2s0
ip: 10.0.0.203
-5
View File
@@ -1,5 +0,0 @@
netmask: 255.255.255.0
gateway: 192.168.1.1
clusterName: testing
controlplaneIp: 192.168.1.100
instalDisk: /dev/vda
-4
View File
@@ -1,4 +0,0 @@
serial: talos-vm
interface: eth0
ip: 192.168.1.2
install: true
@@ -1,3 +0,0 @@
---
cluster:
allowSchedulingOnControlPlanes: true
-4
View File
@@ -1,4 +0,0 @@
---
machine:
network:
hostname: {{hostname}}
-4
View File
@@ -1,4 +0,0 @@
---
machine:
install:
disk: {{installDisk}}
-11
View File
@@ -1,11 +0,0 @@
---
machine:
network:
interfaces:
- interface: {{interface}}
dhcp: false
addresses:
- {{ip}}
routes:
- network: 0.0.0.0/0
gateway: {{gateway}}
-7
View File
@@ -1,7 +0,0 @@
---
machine:
network:
interfaces:
- interface: {{interface}}
vip:
ip: {{controlplaneIp}}
-4
View File
@@ -1,4 +0,0 @@
PyYAML==6.0.3
requests==2.32.5
Jinja2==3.1.6
GitPython==3.1.45
-7
View File
@@ -1,7 +0,0 @@
customization:
systemExtensions:
officialExtensions:
- siderolabs/iscsi-tools
- siderolabs/util-linux-tools
- siderolabs/intel-ucode
- siderolabs/i915
BIN
View File
Binary file not shown.
+52
View File
@@ -0,0 +1,52 @@
# yaml-language-server: $schema=https://git.huizinga.dev/infra/crete/raw/branch/main/schemas/cluster.json
version:
kubernetes: 1.35.3
talos: 1.12.6
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.jinja
- system/ntp.yaml
- system/dns.yaml.jinja
- 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
ntp: nl.pool.ntp.org
install:
auto: true
+19
View File
@@ -0,0 +1,19 @@
# yaml-language-server: $schema=https://git.huizinga.dev/infra/crete/raw/branch/main/schemas/cluster.json
clusterEnv: staging
controlPlaneIp: 192.168.1.100
secretsFile: testing/secrets.yaml
nodes:
- testing/talos-vm
default:
network:
interface: ens5
netmask: 255.255.255.0
gateway: 192.168.1.1
tailscale:
authKey:
file: testing/tailscale.key
sops:
file: testing/age.key
install:
disk: /dev/vda
+20
View File
@@ -0,0 +1,20 @@
# yaml-language-server: $schema=https://git.huizinga.dev/infra/crete/raw/branch/main/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
tailscale:
authKey:
file: testing/tailscale.key
sops:
file: titan/age.key
install:
disk: /dev/sda
+8
View File
@@ -0,0 +1,8 @@
# yaml-language-server: $schema=https://git.huizinga.dev/infra/crete/raw/branch/main/schemas/node.json
type: controlPlane
install:
serial: talos-vm
network:
ip: 192.168.1.2
tailscale:
advertiseRoutes: true
+7
View File
@@ -0,0 +1,7 @@
# yaml-language-server: $schema=https://git.huizinga.dev/infra/crete/raw/branch/main/schemas/node.json
type: controlPlane
install:
serial: 5CZ7NX2
network:
interface: enp2s0
ip: 10.0.0.202
+7
View File
@@ -0,0 +1,7 @@
# yaml-language-server: $schema=https://git.huizinga.dev/infra/crete/raw/branch/main/schemas/node.json
type: controlPlane
install:
serial: F3PKRH2
network:
interface: enp3s0
ip: 10.0.0.201
+7
View File
@@ -0,0 +1,7 @@
# yaml-language-server: $schema=https://git.huizinga.dev/infra/crete/raw/branch/main/schemas/node.json
type: controlPlane
install:
serial: J33CHY2
network:
interface: enp2s0
ip: 10.0.0.203
+18
View File
@@ -0,0 +1,18 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/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 }}
+5
View File
@@ -0,0 +1,5 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
machine:
kubelet:
extraArgs:
rotate-server-certificates: "true"
+5
View File
@@ -0,0 +1,5 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/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
+12
View File
@@ -0,0 +1,12 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/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
@@ -0,0 +1,4 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
cluster:
extraManifests:
- https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.1/standard-install.yaml
+8
View File
@@ -0,0 +1,8 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/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 +%}
- TS_ROUTES={% if node.network.tailscale.advertiseRoutes %}{{node.network.ip}}/{{ node.network.netmask | to_prefix }}{% endif %}
+5
View File
@@ -0,0 +1,5 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
apiVersion: v1alpha1
kind: Layer2VIPConfig
name: "{{ cluster.controlPlaneIp }}"
link: "{{ node.network.interface }}"
+18
View File
@@ -0,0 +1,18 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/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
stringData:
age.agekey: |
{{ node.sops | indent(6*2) }}
+8
View File
@@ -0,0 +1,8 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/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
@@ -0,0 +1,6 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
apiVersion: v1alpha1
kind: VolumeConfig
name: EPHEMERAL
provisioning:
maxSize: 30GB
@@ -0,0 +1,9 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
apiVersion: v1alpha1
kind: UserVolumeConfig
name: local-path-provisioner
provisioning:
diskSelector:
match: system_disk
grow: true
maxSize: 10GB
+11
View File
@@ -0,0 +1,11 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
machine:
kubelet:
extraMounts:
- destination: /var/lib/longhorn
type: bind
source: /var/lib/longhorn
options:
- bind
- rshared
- rw
@@ -0,0 +1,20 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
apiVersion: v1alpha1
kind: UserVolumeConfig
name: longhorn
provisioning:
diskSelector:
match: system_disk
grow: true
maxSize: 2000GB
# # yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
# apiVersion: v1alpha1
# kind: UserVolumeConfig
# name: longhorn
# # We want to take the whole distk
# # TODO: Add second disk to virtual machine
# volumeType: "disk"
# provisioning:
# diskSelector:
# # TODO: UPDATE THIS
# # match: system_disk
+17
View File
@@ -0,0 +1,17 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/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
@@ -0,0 +1,3 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
cluster:
allowSchedulingOnControlPlanes: true
+7
View File
@@ -0,0 +1,7 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
apiVersion: v1alpha1
kind: ResolverConfig
nameservers:
{% for dns in node.network.dns %}
- address: {{ dns }}
{% endfor %}
+5
View File
@@ -0,0 +1,5 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
apiVersion: v1alpha1
kind: HostnameConfig
hostname: "{{node.hostname}}"
auto: "off"
+4
View File
@@ -0,0 +1,4 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
machine:
install:
disk: "{{node.install.disk}}"
+10
View File
@@ -0,0 +1,10 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/siderolabs/talos/refs/heads/release-1.12/website/content/v1.12/schemas/config.schema.json
apiVersion: v1alpha1
kind: LinkConfig
name: "{{node.network.interface}}"
up: true
mtu: 9000
addresses:
- address: "{{node.network.ip}}/{{ node.network.netmask | to_prefix }}"
routes:
- gateway: "{{node.network.gateway}}"
+5
View File
@@ -0,0 +1,5 @@
apiVersion: v1alpha1
kind: TimeSyncConfig
ntp:
servers:
- "{{ node.ntp }}"
+8
View File
@@ -0,0 +1,8 @@
customization:
systemExtensions:
officialExtensions:
- siderolabs/iscsi-tools
- siderolabs/util-linux-tools
- siderolabs/intel-ucode
- siderolabs/i915
- siderolabs/tailscale
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+9 -9
View File
@@ -1,5 +1,5 @@
{% set httpUrl = "http://192.168.1.1:8000" -%}
#!ipxe #!ipxe
dhcp dhcp
echo Starting ${serial} echo Starting ${serial}
@@ -8,15 +8,15 @@ echo Starting ${serial}
goto node_${serial} || exit goto node_${serial} || exit
# Default behavior (non install mode) is to exit iPXE script # Default behavior (non install mode) is to exit iPXE script
{% for node in nodes %} {% for cluster in clusters%}
{%- if node.install -%} {% for node in cluster.nodes %}
# {{ node.filename }} {%- if node.install.serial -%}
:node_{{ node.serial }} # {{ cluster.name }}/{{ node.hostname }}
{% set ipArg = "ip=" ~ node.ip ~ "::" ~ node.gateway ~ ":" ~ node.netmask ~ ":" ~ node.hostname ~ ":" ~ node.interface ~ "::" ~ node.dns[0] ~ ":" ~ node.dns[1] ~ ":" ~ node.ntp -%} :node_{{ node.install.serial }}
{% set kernelArgs = ipArg ~ " " ~ node.kernelArgs ~ " " ~ node.extraKernelArgs -%}
imgfree imgfree
kernel https://pxe.factory.talos.dev/image/{{ node.schematicID }}/{{ node.talosVersion }}/kernel-{{ node.arch }} {{ kernelArgs }} kernel https://pxe.factory.talos.dev/image/{{ node.schematic }}/v{{ cluster.version.talos }}/kernel-{{ node.arch }} {{ 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.schematicID }}/{{ node.talosVersion }}/initramfs-{{ node.arch }}.xz initrd https://pxe.factory.talos.dev/image/{{ node.schematic }}/v{{ cluster.version.talos }}/initramfs-{{ node.arch }}.xz
boot boot
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% endfor %}
+1 -1
View File
@@ -1,4 +1,4 @@
{% set tftpIp = config.dhcp.tftpIp -%} {% set tftpIp = "192.168.1.1" -%}
enable-tftp enable-tftp
tftp-root=/tftproot tftp-root=/tftproot
+2
View File
@@ -0,0 +1,2 @@
export TALOSCONFIG={{ root }}/configs/talosconfig
export KUBECONFIG={{ clusters|map(attribute='name')|kubeconfig|join(":") }}
-138
View File
@@ -1,138 +0,0 @@
#!/usr/bin/env python3
# Adapted from: https://enix.io/en/blog/pxe-talos/
import functools
import json
import pathlib
import git
import requests
import yaml
from jinja2 import Environment, FileSystemLoader, StrictUndefined, Template
REPO = git.Repo(".", search_parent_directories=True)
assert REPO.working_dir is not None
ROOT = pathlib.Path(REPO.working_dir)
NODES = ROOT.joinpath("nodes")
SCHEMATICS = ROOT.joinpath("schematics")
RENDERED = ROOT.joinpath("rendered")
PATCHES = Environment(
loader=FileSystemLoader(ROOT.joinpath("patches")), undefined=StrictUndefined
)
TEMPLATES = Environment(
loader=FileSystemLoader(ROOT.joinpath("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
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(loader: yaml.SafeLoader, node: yaml.nodes.ScalarNode):
"""Load specified schematic file and get the assocatied schematic id"""
schematic_name = loader.construct_yaml_str(node)
try:
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
@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())
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():
nodes = []
for fullname in walk_files(NODES):
filename = str(fullname.relative_to(NODES).parent) + "/" + fullname.stem
with open(fullname) as fyaml:
yml_data = yaml.load(fyaml, Loader=get_loader())
yml_data = get_defaults(fullname.parent, NODES) | yml_data
yml_data["hostname"] = fullname.stem
yml_data["filename"] = filename
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))))
with open(ROOT.joinpath("config.yaml")) as fyaml:
config = yaml.safe_load(fyaml)
RENDERED.mkdir(exist_ok=True)
for template_name in TEMPLATES.list_templates():
template = TEMPLATES.get_template(template_name)
rendered = template.render(nodes=final_nodes, config=config)
with open(RENDERED.joinpath(template_name), "w") as f:
f.write(rendered)
if __name__ == "__main__":
main()
+27 -6
View File
@@ -6,6 +6,7 @@ IPXE_VERSION=b41bda4413bf286d7b7a449bc05e1531da1eec2e
IPXE_BIN=(bin/ipxe.pxe bin-x86_64-efi/ipxe.efi) IPXE_BIN=(bin/ipxe.pxe bin-x86_64-efi/ipxe.efi)
IPXE_DIR=${ROOT}/.ipxe/ipxe-${IPXE_VERSION} IPXE_DIR=${ROOT}/.ipxe/ipxe-${IPXE_VERSION}
HTTP_URL="http://192.168.1.1:8000"
function download_ipxe() { function download_ipxe() {
base_dir=$(dirname ${IPXE_DIR}) base_dir=$(dirname ${IPXE_DIR})
@@ -25,7 +26,8 @@ function patch_ipxe() {
#!ipxe #!ipxe
dhcp dhcp
chain boot.ipxe || shell chain ${HTTP_URL}/boot.ipxe || shell
# chain boot.ipxe || shell
EOF EOF
cd - > /dev/null cd - > /dev/null
@@ -42,9 +44,6 @@ function build_ipxe() {
cd - > /dev/null cd - > /dev/null
} }
function render() {
${ROOT}/tools/render
}
function host_tftp() { function host_tftp() {
TFTP_DIR=$(mktemp --tmpdir -d tftp.XXX) TFTP_DIR=$(mktemp --tmpdir -d tftp.XXX)
@@ -64,8 +63,30 @@ function host_tftp() {
sudo in.tftpd --verbosity 100 --permissive -L --secure ${TFTP_DIR} 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 download_ipxe
patch_ipxe patch_ipxe
build_ipxe build_ipxe
render crete generate
host_tftp host_http
-154
View File
@@ -1,154 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT=$(git rev-parse --show-toplevel)
VM_NAME="talos-vm"
VCPUS="2"
RAM_MB="2048"
DISK_GB="10"
NETWORK=talos
CONNECTION="qemu:///system"
function define_network() {
config_file=$(mktemp)
cat > ${config_file} << EOF
<network>
<name>${NETWORK}</name>
<bridge name="talos0" stp="on" delay="0"/>
<forward mode='nat'>
<nat/>
</forward>
<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'/>
</dhcp>
</ip>
</network>
EOF
function cleanup() {
rm ${config_file}
}
trap cleanup EXIT
if [[ $(virsh --connect="${CONNECTION}" net-list --all | grep -c "${NETWORK}") == "0" ]]; then
virsh --connect="${CONNECTION}" net-define "${config_file}"
virsh --connect="${CONNECTION}" net-start "${NETWORK}"
virsh --connect="${CONNECTION}" net-autostart "${NETWORK}"
fi
trap - EXIT
cleanup
}
function create() {
define_network
if [[ $(virsh --connect="${CONNECTION}" list --all | grep -c "${VM_NAME}") == "0" ]]; then
virt-install --connect="${CONNECTION}" --name="${VM_NAME}" --vcpus="${VCPUS}" --memory="${RAM_MB}" \
--os-variant="linux2022" \
--disk="size=${DISK_GB}" \
--pxe \
--sysinfo system.serial=${VM_NAME} \
--network network="${NETWORK}"
else
echo -n "VM already exists, start it with:
${0} start
"
exit -1
fi
}
function start() {
if [[ $(virsh --connect="${CONNECTION}" list --all | grep -c "${VM_NAME}") > "0" ]]; then
virsh --connect="${CONNECTION}" start ${VM_NAME}
virt-viewer --connect="${CONNECTION}" ${VM_NAME}
else
echo -n "VM doest not exists yet, create it with:
${0} create
"
exit -1
fi
}
function connect() {
if [[ $(virsh --connect="${CONNECTION}" list | grep -c "${VM_NAME}") > "0" ]]; then
virt-viewer --connect="${CONNECTION}" ${VM_NAME}
else
echo "VM is not running"
exit -1
fi
}
function stop() {
if [[ $(virsh --connect="${CONNECTION}" list | grep -c "${VM_NAME}") > "0" ]]; then
virsh --connect="${CONNECTION}" shutdown ${VM_NAME}
WAIT=240
for i in $(seq 0 1 ${WAIT}); do
echo -en "\rWaiting for VM to shutdown... (${i}/${WAIT})"
if [[ $(virsh --connect="${CONNECTION}" list | grep -c "${VM_NAME}") == "0" ]]; then
echo -e "\nVM successfully shutdown"
exit
fi
sleep 1
done
echo -e "\nDestroying VM"
virsh --connect="${CONNECTION}" destroy ${VM_NAME}
else
echo "VM is not running"
exit -1
fi
}
function delete() {
if [[ $(virsh --connect="${CONNECTION}" list --all | grep -c "${VM_NAME}") > "0" ]]; then
if [[ $(virsh --connect="${CONNECTION}" list | grep -c "${VM_NAME}") > "0" ]]; then
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}"
virsh --connect="${CONNECTION}" net-undefine "${NETWORK}"
fi
}
function help() {
echo -n "Available commands:
start
stop
remove
connect
"
}
COMMAND=${1:-}
case ${COMMAND} in
create)
create Create the vm and perform first install
;;
start)
start Start the vm
;;
stop)
stop Stop the vm
;;
delete)
delete Delete the vm
;;
connect)
connect Connect to an already running vm
;;
*)
help
;;
esac