Compare commits

..

7 Commits

Author SHA1 Message Date
Dreaded_X ae360a5c52 Add 1 git-crypt collaborator
New collaborators:

    CD17A34CBFB21DE9A73D47EB76BDEC4E165D8AD9
        Tim Huizinga <tim@huizinga.dev>
2025-11-08 03:52:55 +01:00
Dreaded_X 14dc5be114 Added README with some basic commands 2025-11-08 03:50:31 +01:00
Dreaded_X f060080694 Added some basic talos config patches and secrets 2025-11-08 03:49:48 +01:00
Dreaded_X 4683b48d24 Add intel gpu microcode 2025-11-08 03:20:45 +01:00
Dreaded_X c3b60772ae Renamed clusters 2025-11-08 03:20:03 +01:00
Dreaded_X c338e69360 Use arrays for kernel args and dns 2025-11-08 03:12:23 +01:00
Dreaded_X 6df2665a22 Cleanup and improvements 2025-11-07 21:38:21 +01:00
70 changed files with 371 additions and 478 deletions
+1 -1
View File
@@ -5,4 +5,4 @@ indent_style = tab
[*.yaml]
indent_style = space
indent_size = 2
indent_size = 4
-1
View File
@@ -1,2 +1 @@
*.key filter=git-crypt diff=git-crypt
secrets.yaml filter=git-crypt diff=git-crypt
-1
View File
@@ -1,4 +1,3 @@
.ipxe/
rendered/
configs/
.vagrant/
-67
View File
@@ -1,67 +0,0 @@
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
-3
View File
@@ -1,3 +0,0 @@
{
"bracketSpacing": false
}
-2
View File
@@ -1,2 +0,0 @@
secrets.yaml
*.key
-6
View File
@@ -65,9 +65,3 @@ 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
```
Vendored
-28
View File
@@ -1,28 +0,0 @@
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
@@ -1,2 +0,0 @@
style = "conventional"
ignore_author_re = "Flux"
+2
View File
@@ -0,0 +1,2 @@
dhcp:
tftpIp: 10.0.0.3
-2
View File
@@ -1,2 +0,0 @@
[env]
VAGRANT_DEFAULT_PROVIDER = "libvirt"
+21
View File
@@ -0,0 +1,21 @@
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
+7
View File
@@ -0,0 +1,7 @@
customization:
systemExtensions:
officialExtensions:
- siderolabs/iscsi-tools
- siderolabs/util-linux-tools
- siderolabs/intel-ucode
- siderolabs/i915
+3
View File
@@ -0,0 +1,3 @@
netmask: 255.255.252.0
gateway: 10.0.0.1
install: true
+3
View File
@@ -0,0 +1,3 @@
serial: 5CZ7NX2
interface: enp2s0
ip: 10.0.0.202
+3
View File
@@ -0,0 +1,3 @@
serial: F3PKRH2
interface: enp3s0
ip: 10.0.0.201
+3
View File
@@ -0,0 +1,3 @@
serial: J33CHY2
interface: enp2s0
ip: 10.0.0.203
+2
View File
@@ -0,0 +1,2 @@
netmask: 255.255.255.0
gateway: 192.168.1.1
+4
View File
@@ -0,0 +1,4 @@
serial: talos-vm
interface: enp1s0
ip: 192.168.1.2
install: true
@@ -0,0 +1,3 @@
---
cluster:
allowSchedulingOnControlPlanes: true
+4
View File
@@ -0,0 +1,4 @@
---
machine:
network:
hostname: talos-vm
+4
View File
@@ -0,0 +1,4 @@
---
machine:
install:
disk: /dev/vda
+11
View File
@@ -0,0 +1,11 @@
---
machine:
network:
interfaces:
- interface: eth0
dhcp: false
addresses:
- 192.168.1.2
routes:
- network: 0.0.0.0/0
gateway: 192.168.1.1
+7
View File
@@ -0,0 +1,7 @@
---
machine:
network:
interfaces:
- interface: eth0
vip:
ip: 192.168.1.100
+2
View File
@@ -0,0 +1,2 @@
PyYAML==6.0.3
requests==2.32.5
BIN
View File
Binary file not shown.
-52
View File
@@ -1,52 +0,0 @@
# 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
-20
View File
@@ -1,20 +0,0 @@
# 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
- testing/phobos
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
@@ -1,20 +0,0 @@
# 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
@@ -1,8 +0,0 @@
# yaml-language-server: $schema=https://git.huizinga.dev/infra/crete/raw/branch/main/schemas/node.json
type: worker
network:
ip: 192.168.178.77
netmask: 255.255.255.0
gateway: 192.168.178.1
install:
disk: /dev/sda
-8
View File
@@ -1,8 +0,0 @@
# 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
@@ -1,7 +0,0 @@
# 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
@@ -1,7 +0,0 @@
# 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
@@ -1,7 +0,0 @@
# 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
@@ -1,18 +0,0 @@
# 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
@@ -1,5 +0,0 @@
# 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
@@ -1,5 +0,0 @@
# 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
@@ -1,12 +0,0 @@
# 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
@@ -1,4 +0,0 @@
# 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
@@ -1,8 +0,0 @@
# 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
@@ -1,5 +0,0 @@
# 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
@@ -1,18 +0,0 @@
# 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
@@ -1,8 +0,0 @@
# 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
@@ -1,6 +0,0 @@
# 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
@@ -1,9 +0,0 @@
# 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
@@ -1,11 +0,0 @@
# 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
@@ -1,9 +0,0 @@
# 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
-17
View File
@@ -1,17 +0,0 @@
# 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
@@ -1,3 +0,0 @@
# 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
@@ -1,7 +0,0 @@
# 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
@@ -1,5 +0,0 @@
# 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
@@ -1,4 +0,0 @@
# 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
@@ -1,10 +0,0 @@
# 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
@@ -1,5 +0,0 @@
apiVersion: v1alpha1
kind: TimeSyncConfig
ntp:
servers:
- "{{ node.ntp }}"
-8
View File
@@ -1,8 +0,0 @@
customization:
systemExtensions:
officialExtensions:
- siderolabs/iscsi-tools
- siderolabs/util-linux-tools
- siderolabs/intel-ucode
- siderolabs/i915
- siderolabs/tailscale
-9
View File
@@ -1,9 +0,0 @@
overlay:
name: rpi_generic
image: siderolabs/sbc-raspberrypi
customization:
systemExtensions:
officialExtensions:
- siderolabs/iscsi-tools
- siderolabs/util-linux-tools
- 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.
+15 -12
View File
@@ -1,22 +1,25 @@
{% set httpUrl = "http://192.168.1.1:8000" -%}
#!ipxe
dhcp
echo Starting ${serial}
:start
goto node_${serial} || exit
# 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
# Default behavior (non install mode) is to exit iPXE script
{% for cluster in clusters%}
{% for node in cluster.nodes %}
{%- if node.install.serial -%}
# {{ cluster.name }}/{{ node.hostname }}
:node_{{ node.install.serial }}
{{ 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 " ") }}
imgfree
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.schematic }}/v{{ cluster.version.talos }}/initramfs-{{ node.arch }}.xz
kernel https://pxe.factory.talos.dev/image/{{ .schematicID }}/{{ .talosVersion }}/kernel-{{ .arch }} {{ $kernelArgs }}
initrd https://pxe.factory.talos.dev/image/{{ .schematicID }}/{{ .talosVersion }}/initramfs-{{ .arch }}.xz
boot
{% endif %}
{% endfor %}
{% endfor %}
{{- end }}
{{ end }}
+9 -9
View File
@@ -1,4 +1,4 @@
{% set tftpIp = "192.168.1.1" -%}
{{ $tftpIp := (ds "config").dhcp.tftpIp -}}
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 }}
-2
View File
@@ -1,2 +0,0 @@
export TALOSCONFIG={{ root }}/configs/talosconfig
export KUBECONFIG={{ clusters|map(attribute='name')|kubeconfig|join(":") }}
Executable
+96
View File
@@ -0,0 +1,96 @@
#!/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()
Executable
+11
View File
@@ -0,0 +1,11 @@
#!/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 \
+6 -27
View File
@@ -6,7 +6,6 @@ IPXE_VERSION=b41bda4413bf286d7b7a449bc05e1531da1eec2e
IPXE_BIN=(bin/ipxe.pxe bin-x86_64-efi/ipxe.efi)
IPXE_DIR=${ROOT}/.ipxe/ipxe-${IPXE_VERSION}
HTTP_URL="http://192.168.1.1:8000"
function download_ipxe() {
base_dir=$(dirname ${IPXE_DIR})
@@ -26,8 +25,7 @@ function patch_ipxe() {
#!ipxe
dhcp
chain ${HTTP_URL}/boot.ipxe || shell
# chain boot.ipxe || shell
chain boot.ipxe || shell
EOF
cd - > /dev/null
@@ -44,6 +42,9 @@ function build_ipxe() {
cd - > /dev/null
}
function render() {
${ROOT}/tools/render
}
function host_tftp() {
TFTP_DIR=$(mktemp --tmpdir -d tftp.XXX)
@@ -63,30 +64,8 @@ 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
crete generate
host_http
render
host_tftp
Executable
+154
View File
@@ -0,0 +1,154 @@
#!/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