Compare commits
65 Commits
14dc5be114
...
feature/ru
| Author | SHA1 | Date | |
|---|---|---|---|
| fa1a621d03 | |||
|
08c1d0c605
|
|||
|
7b29763230
|
|||
|
95de53206e
|
|||
|
940b01a7dc
|
|||
|
b6c201775a
|
|||
|
be9dc8438b
|
|||
|
873e73c310
|
|||
|
5c8cda5cc4
|
|||
|
ac0d5244d3
|
|||
|
92345e5f1e
|
|||
|
47b85437e3
|
|||
|
9c3c4005ed
|
|||
|
5eeba518a9
|
|||
|
f5798dae4c
|
|||
|
1da24905ef
|
|||
|
b0a1d04d7d
|
|||
|
7d5b09c623
|
|||
|
e4f6c46fc3
|
|||
|
b24feec37a
|
|||
|
b57381afcb
|
|||
|
3200aaebaa
|
|||
|
f4d08c3516
|
|||
|
b69ce72e79
|
|||
|
3b0a49f12e
|
|||
|
a75a0c8722
|
|||
|
2dda3cc465
|
|||
|
c121533161
|
|||
|
14e88a6734
|
|||
|
c406514cb1
|
|||
|
3328fb053c
|
|||
|
cc421f69de
|
|||
|
db43cf50fd
|
|||
|
73c8797dfc
|
|||
|
b6633591bb
|
|||
|
d9def74cf3
|
|||
|
1931ab71ca
|
|||
|
498b0ba480
|
|||
|
244c982b17
|
|||
|
d3f3b8b972
|
|||
|
4b72bdb60d
|
|||
|
ea3d1bf0fa
|
|||
|
81e861ef14
|
|||
|
453d952b8f
|
|||
|
eb36060ef5
|
|||
|
0f4fb2c5df
|
|||
|
83848a3624
|
|||
|
a477e5c4c2
|
|||
|
a8c51ce84b
|
|||
|
969725ecff
|
|||
|
7460bb19db
|
|||
|
69e7a46a3c
|
|||
|
e4644d1161
|
|||
|
121f28e987
|
|||
|
d30b080098
|
|||
|
3290a76193
|
|||
|
0642fde397
|
|||
|
d163e0b9bc
|
|||
|
1b4eb34ec4
|
|||
|
ecc0060fba
|
|||
|
ba3db01cb4
|
|||
|
21f98dd5e3
|
|||
|
49b310eff5
|
|||
|
2963735810
|
|||
|
8c53b59671
|
8
.editorconfig
Normal file
8
.editorconfig
Normal file
@@ -0,0 +1,8 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
|
||||
[*.yaml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
4
.git-crypt/.gitattributes
vendored
Normal file
4
.git-crypt/.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# Do not edit this file. To specify the files to encrypt, create your own
|
||||
# .gitattributes file in the directory where your files are.
|
||||
* !filter !diff
|
||||
*.gpg binary
|
||||
Binary file not shown.
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.key filter=git-crypt diff=git-crypt
|
||||
secrets.yaml filter=git-crypt diff=git-crypt
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
ipxe/
|
||||
.ipxe/
|
||||
rendered/
|
||||
tftp/
|
||||
configs/
|
||||
*.egg-info
|
||||
|
||||
48
.pre-commit-config.yaml
Normal file
48
.pre-commit-config.yaml
Normal 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
3
.prettierrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"bracketSpacing": false
|
||||
}
|
||||
2
.secretsignore
Normal file
2
.secretsignore
Normal file
@@ -0,0 +1,2 @@
|
||||
secrets.yaml
|
||||
*.key
|
||||
40
Dockerfile
40
Dockerfile
@@ -1,40 +0,0 @@
|
||||
FROM docker.io/library/debian:stable AS builder-ipxe
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
build-essential \
|
||||
curl \
|
||||
liblzma-dev \
|
||||
genisoimage
|
||||
ARG IPXE_VERSION=b41bda4413bf286d7b7a449bc05e1531da1eec2e
|
||||
RUN curl -L https://github.com/ipxe/ipxe/archive/${IPXE_VERSION}.tar.gz | tar -xz
|
||||
WORKDIR /ipxe-${IPXE_VERSION}/src
|
||||
|
||||
# Enable HTTPS
|
||||
RUN sed -i 's/^#undef[\t ]DOWNLOAD_PROTO_HTTPS.*$/#define DOWNLOAD_PROTO_HTTPS/g' config/general.h
|
||||
|
||||
RUN mkdir /build
|
||||
RUN make -j$(nproc) bin/ipxe.pxe && cp bin/ipxe.pxe /build
|
||||
RUN make -j$(nproc) bin-x86_64-efi/ipxe.efi && cp bin-x86_64-efi/ipxe.efi /build
|
||||
|
||||
FROM docker.io/library/python:3.13-slim AS config-renderer
|
||||
COPY --from=docker.io/hairyhenderson/gomplate:v4.3 /gomplate /bin/gomplate
|
||||
COPY ./requirements.txt /requirements.txt
|
||||
RUN pip install -r /requirements.txt
|
||||
COPY ./generate.sh /generate.sh
|
||||
COPY ./tools /tools
|
||||
COPY ./nodes /nodes
|
||||
COPY ./templates /templates
|
||||
RUN ./generate.sh
|
||||
|
||||
FROM docker.io/library/alpine:3.22.2 AS runtime
|
||||
RUN apk add dnsmasq
|
||||
|
||||
COPY --from=builder-ipxe /build/ipxe.pxe /tftproot/
|
||||
COPY --from=builder-ipxe /build/ipxe.efi /tftproot/
|
||||
COPY --from=config-renderer /rendered/boot.ipxe /tftproot/
|
||||
COPY --from=config-renderer /rendered/dnsmasq.conf /dnsmasq.conf
|
||||
|
||||
EXPOSE 67/udp
|
||||
EXPOSE 69/udp
|
||||
|
||||
CMD ["dnsmasq", "--conf-file=/dnsmasq.conf", "--keep-in-foreground", "--user=root", "--log-facility=-", "--port=0"]
|
||||
73
README.md
Normal file
73
README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Talos
|
||||
|
||||
To decrypt the secrets file:
|
||||
|
||||
```
|
||||
git-crypt unlock
|
||||
```
|
||||
|
||||
Generate the config files:
|
||||
|
||||
```bash
|
||||
talosctl gen config <cluster_name> https://<controlplane_ip>:6443 -f \
|
||||
--with-secrets secrets.yaml \
|
||||
--config-patch @<path_to_patch> \
|
||||
--config-patch-control-plane @<path_to_controlplane_patch> \
|
||||
--install-image factory.talos.dev/metal-installer/<schematic_id>:<version> \
|
||||
-o configs
|
||||
```
|
||||
|
||||
Set TALOSCONFIG:
|
||||
|
||||
```bash
|
||||
export TALOSCONFIG=$(realpath configs/talosconfig)
|
||||
```
|
||||
|
||||
Apply the configs for each node, use worker.yaml for worker nodes:
|
||||
|
||||
```bash
|
||||
talosctl apply-config --insecure --nodes <node_id> --file configs/controlplane.yaml
|
||||
```
|
||||
|
||||
Set endpoint to one of the nodes:
|
||||
|
||||
```bash
|
||||
talosctl config endpoint <node_ip>
|
||||
```
|
||||
|
||||
Bootstrap Kubernetes:
|
||||
|
||||
```bash
|
||||
talosctl -n <node_id> bootstrap
|
||||
```
|
||||
|
||||
Set endpoint to control plane:
|
||||
|
||||
```bash
|
||||
talosctl config endpoint <controlplane_ip>
|
||||
```
|
||||
|
||||
Get kubeconfig and set KUBECONFIG:
|
||||
|
||||
```bash
|
||||
talosctl -n 192.168.1.100 kubeconfig $PWD/configs/kubeconfig
|
||||
export KUBECONFIG=$(realpath configs/kubeconfig)
|
||||
```
|
||||
|
||||
For applying updated config to node:
|
||||
|
||||
```bash
|
||||
talosctl apply-config --nodes <node_id> --file configs/controlplane.yaml
|
||||
```
|
||||
|
||||
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
2
committed.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
style = "conventional"
|
||||
ignore_author_re = "Flux"
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
SCRIPT_DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
|
||||
|
||||
${SCRIPT_DIR}/tools/merge.py ./nodes | gomplate -d nodes=stdin://nodes.json -d dhcp=${SCRIPT_DIR}/dhcp.yaml --input-dir ${SCRIPT_DIR}/templates --output-dir ${SCRIPT_DIR}/rendered
|
||||
@@ -1,9 +0,0 @@
|
||||
schematicID: !schematic "_schematic.yaml"
|
||||
arch: amd64
|
||||
talosVersion: v1.11.3
|
||||
kernelArgs: talos.platform=metal console=tty0 init_on_alloc=1 slab_nomerge pti=on consoleblank=0 nvme_core.io_timeout=4294967295 printk.devkmsg=on selinux=1 lockdown=confidentiality
|
||||
dns0: 1.1.1.1
|
||||
dns1: 8.8.8.8
|
||||
ntp: nl.pool.ntp.org
|
||||
install: false
|
||||
upgradeIPXE: false
|
||||
@@ -1,3 +0,0 @@
|
||||
netmask: 255.255.252.0
|
||||
gateway: 10.0.0.1
|
||||
install: true
|
||||
@@ -1,3 +0,0 @@
|
||||
serial: 5CZ7NX2
|
||||
interface: enp2s0
|
||||
ip: 10.0.0.202
|
||||
@@ -1,3 +0,0 @@
|
||||
serial: F3PKRH2
|
||||
interface: enp3s0
|
||||
ip: 10.0.0.201
|
||||
@@ -1,3 +0,0 @@
|
||||
serial: J33CHY2
|
||||
interface: enp2s0
|
||||
ip: 10.0.0.203
|
||||
@@ -1,3 +0,0 @@
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.1.1
|
||||
upgradeIPXE: ipxe.pxe
|
||||
@@ -1,4 +0,0 @@
|
||||
serial: vm
|
||||
interface: enp1s0
|
||||
ip: 192.168.1.2
|
||||
install: true
|
||||
@@ -1,2 +0,0 @@
|
||||
PyYAML==6.0.3
|
||||
requests==2.32.5
|
||||
53
talos/clusters/default.yaml
Normal file
53
talos/clusters/default.yaml
Normal 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
|
||||
16
talos/clusters/testing.yaml
Normal file
16
talos/clusters/testing.yaml
Normal 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
17
talos/clusters/titan.yaml
Normal 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
|
||||
6
talos/nodes/testing/talos-vm.yaml
Normal file
6
talos/nodes/testing/talos-vm.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
# yaml-language-server: $schema=../../../schemas/node.json
|
||||
type: controlPlane
|
||||
install:
|
||||
serial: talos-vm
|
||||
network:
|
||||
ip: 192.168.1.2
|
||||
7
talos/nodes/titan/helios.yaml
Normal file
7
talos/nodes/titan/helios.yaml
Normal 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
|
||||
7
talos/nodes/titan/hyperion.yaml
Normal file
7
talos/nodes/titan/hyperion.yaml
Normal 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
|
||||
7
talos/nodes/titan/selene.yaml
Normal file
7
talos/nodes/titan/selene.yaml
Normal 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
|
||||
18
talos/patches/flux/cluster-variables.yaml
Normal file
18
talos/patches/flux/cluster-variables.yaml
Normal 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 }}
|
||||
5
talos/patches/metrics/all.yaml
Normal file
5
talos/patches/metrics/all.yaml
Normal 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"
|
||||
5
talos/patches/metrics/control-plane.yaml
Normal file
5
talos/patches/metrics/control-plane.yaml
Normal 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
|
||||
12
talos/patches/networking/cilium.yaml
Normal file
12
talos/patches/networking/cilium.yaml
Normal 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
|
||||
4
talos/patches/networking/gateway-api.yaml
Normal file
4
talos/patches/networking/gateway-api.yaml
Normal 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
|
||||
8
talos/patches/networking/tailscale.yaml
Normal file
8
talos/patches/networking/tailscale.yaml
Normal 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 %}
|
||||
7
talos/patches/networking/vip.yaml
Normal file
7
talos/patches/networking/vip.yaml
Normal 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
18
talos/patches/sops.yaml
Normal 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) }}
|
||||
8
talos/patches/spegel.yaml
Normal file
8
talos/patches/spegel.yaml
Normal 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
|
||||
6
talos/patches/storage/limit-ephemeral.yaml
Normal file
6
talos/patches/storage/limit-ephemeral.yaml
Normal 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
|
||||
@@ -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
|
||||
11
talos/patches/storage/longhorn.yaml
Normal file
11
talos/patches/storage/longhorn.yaml
Normal 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
|
||||
9
talos/patches/storage/longhorn/user-volume.yaml
Normal file
9
talos/patches/storage/longhorn/user-volume.yaml
Normal 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
|
||||
17
talos/patches/storage/openebs.yaml
Normal file
17
talos/patches/storage/openebs.yaml
Normal 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
|
||||
3
talos/patches/system/allow-control-plane-workloads.yaml
Normal file
3
talos/patches/system/allow-control-plane-workloads.yaml
Normal 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
|
||||
4
talos/patches/system/hostname.yaml
Normal file
4
talos/patches/system/hostname.yaml
Normal 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}}"
|
||||
4
talos/patches/system/install-disk.yaml
Normal file
4
talos/patches/system/install-disk.yaml
Normal 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}}"
|
||||
11
talos/patches/system/network.yaml
Normal file
11
talos/patches/system/network.yaml
Normal 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}}"
|
||||
@@ -3,3 +3,6 @@ customization:
|
||||
officialExtensions:
|
||||
- siderolabs/iscsi-tools
|
||||
- siderolabs/util-linux-tools
|
||||
- siderolabs/intel-ucode
|
||||
- siderolabs/i915
|
||||
- siderolabs/tailscale
|
||||
BIN
talos/secrets/tailscale.key
Normal file
BIN
talos/secrets/tailscale.key
Normal file
Binary file not shown.
BIN
talos/secrets/testing/age.key
Normal file
BIN
talos/secrets/testing/age.key
Normal file
Binary file not shown.
BIN
talos/secrets/testing/secrets.yaml
Normal file
BIN
talos/secrets/testing/secrets.yaml
Normal file
Binary file not shown.
BIN
talos/secrets/titan/age.key
Normal file
BIN
talos/secrets/titan/age.key
Normal file
Binary file not shown.
BIN
talos/secrets/titan/secrets.yaml
Normal file
BIN
talos/secrets/titan/secrets.yaml
Normal file
Binary file not shown.
@@ -1,36 +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} || goto manual
|
||||
goto node_${serial} || exit
|
||||
# Default behavior (non install mode) is to exit iPXE script
|
||||
|
||||
{{ range (datasource "nodes" | jsonArray) }}
|
||||
{{- if .install }}
|
||||
# {{ .filename }}
|
||||
:node_{{ .serial }}
|
||||
{{- $ipArg := printf "ip=%s::%s:%s:%s:%s::%s:%s:%s" .ip .gateway .netmask .hostname .interface .dns0 .dns1 .ntp }}
|
||||
{{- $kernelArgs := printf "%s %s" $ipArg .kernelArgs }}
|
||||
{% 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 }} {{- if .upgradeIPXE }} || boot {{ .upgradeIPXE }} {{- end }}
|
||||
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 }}
|
||||
|
||||
:manual
|
||||
menu Select node
|
||||
{{ range (datasource "nodes" | jsonArray) }}
|
||||
item {{ .serial }} {{ .hostname }}
|
||||
{{ end }}
|
||||
choose selected || goto cancel
|
||||
goto node_${selected}
|
||||
|
||||
:cancel
|
||||
echo Type exit to restart script
|
||||
shell
|
||||
goto start
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{{ $tftpIp := (ds "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 }}
|
||||
|
||||
38
templates/generate_configs.sh
Normal file
38
templates/generate_configs.sh
Normal 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
2
templates/source.sh
Normal file
@@ -0,0 +1,2 @@
|
||||
export TALOSCONFIG={{ root }}/configs/talosconfig
|
||||
export KUBECONFIG={{ clusters|map(attribute='name')|kubeconfig|join(":") }}
|
||||
@@ -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()
|
||||
96
tools/server
Executable file
96
tools/server
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
ROOT=$(git rev-parse --show-toplevel)
|
||||
|
||||
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})
|
||||
# Download the iPXE source if needed
|
||||
if [ ! -d "${IPXE_DIR}" ]; then
|
||||
mkdir -p "${base_dir}"
|
||||
curl -L https://github.com/ipxe/ipxe/archive/${IPXE_VERSION}.tar.gz | tar -xz -C "${base_dir}"
|
||||
fi
|
||||
}
|
||||
|
||||
function patch_ipxe() {
|
||||
# Apply patches to iPXE source
|
||||
cd "${IPXE_DIR}/src"
|
||||
sed -i 's/^#undef[\t ]DOWNLOAD_PROTO_HTTPS.*$/#define DOWNLOAD_PROTO_HTTPS/g' config/general.h
|
||||
|
||||
cat > embed.ipxe << EOF
|
||||
#!ipxe
|
||||
|
||||
dhcp
|
||||
chain ${HTTP_URL}/boot.ipxe || shell
|
||||
# chain boot.ipxe || shell
|
||||
EOF
|
||||
|
||||
cd - > /dev/null
|
||||
}
|
||||
|
||||
function build_ipxe() {
|
||||
cd "${IPXE_DIR}/src"
|
||||
for bin in "${IPXE_BIN[@]}"; do
|
||||
path=${IPXE_DIR}/src/${bin}
|
||||
if [ ! -f "${path}" ]; then
|
||||
make -j$(nproc) ${bin} EMBED=embed.ipxe
|
||||
fi
|
||||
done
|
||||
cd - > /dev/null
|
||||
}
|
||||
|
||||
function render() {
|
||||
${ROOT}/tools/render
|
||||
${ROOT}/rendered/generate_configs.sh
|
||||
}
|
||||
|
||||
function host_tftp() {
|
||||
TFTP_DIR=$(mktemp --tmpdir -d tftp.XXX)
|
||||
chmod 755 ${TFTP_DIR}
|
||||
function cleanup() {
|
||||
rm -rf ${TFTP_DIR}
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
cp ${ROOT}/rendered/boot.ipxe ${TFTP_DIR}
|
||||
for bin in "${IPXE_BIN[@]}"; do
|
||||
path=${IPXE_DIR}/src/${bin}
|
||||
cp ${path} ${TFTP_DIR}
|
||||
done
|
||||
|
||||
echo "Starting tftpd"
|
||||
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_http
|
||||
153
tools/vm
Executable file
153
tools/vm
Executable file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
ROOT=$(git rev-parse --show-toplevel)
|
||||
|
||||
VM_NAME="talos-vm"
|
||||
VCPUS="6"
|
||||
RAM_MB="16384"
|
||||
DISK_GB="100"
|
||||
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='http://192.168.1.1:8000/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
|
||||
fi
|
||||
|
||||
if [[ $(virsh --connect="${CONNECTION}" net-list --all | grep -c "${NETWORK}") > "0" ]]; then
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
@@ -1,13 +0,0 @@
|
||||
<network xmlns:dnsmasq='http://libvirt.org/schemas/network/dnsmasq/1.0'>
|
||||
<name>cluster-vm</name>
|
||||
<bridge name="cluster0" 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='boot.ipxe'/>
|
||||
</dhcp>
|
||||
</ip>
|
||||
</network>
|
||||
15
vm/create.sh
15
vm/create.sh
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
SCRIPT_DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
|
||||
source ${SCRIPT_DIR}/helper.sh
|
||||
|
||||
if [[ $(virsh --connect="${CONNECTION}" net-list --all | grep -c "${NETWORK}") == "0" ]]; then
|
||||
virsh --connect="${CONNECTION}" net-define "${SCRIPT_DIR}/${NETWORK}.xml"
|
||||
virsh --connect="${CONNECTION}" net-start "${NETWORK}"
|
||||
virsh --connect="${CONNECTION}" net-autostart "${NETWORK}"
|
||||
fi
|
||||
|
||||
virt-install --connect="${CONNECTION}" --name="${VM_NAME}" --vcpus="${VCPUS}" --memory="${RAM_MB}" \
|
||||
--os-variant="linux2022" \
|
||||
--disk="size=${DISK_GB}" \
|
||||
--pxe \
|
||||
--network network="${NETWORK}"
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
SCRIPT_DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
|
||||
source ${SCRIPT_DIR}/helper.sh
|
||||
|
||||
virsh --connect="${CONNECTION}" destroy "${VM_NAME}"
|
||||
virsh --connect="${CONNECTION}" undefine "${VM_NAME}" --remove-all-storage
|
||||
virsh --connect="${CONNECTION}" net-destroy "${NETWORK}"
|
||||
virsh --connect="${CONNECTION}" net-undefine "${NETWORK}"
|
||||
10
vm/helper.sh
10
vm/helper.sh
@@ -1,10 +0,0 @@
|
||||
set -euxo pipefail
|
||||
VM_NAME="test"
|
||||
VCPUS="2"
|
||||
RAM_MB="2048"
|
||||
DISK_GB="10"
|
||||
NETWORK=cluster-vm
|
||||
CONNECTION="qemu:///system"
|
||||
|
||||
IPXE_VERSION=b41bda4413bf286d7b7a449bc05e1531da1eec2e
|
||||
IPXE_BIN=bin/ipxe.pxe
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
SCRIPT_DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
|
||||
source ${SCRIPT_DIR}/helper.sh
|
||||
|
||||
virsh --connect="${CONNECTION}" start ${VM_NAME}
|
||||
virt-viewer --connect="${CONNECTION}" ${VM_NAME}
|
||||
virsh --connect="${CONNECTION}" shutdown ${VM_NAME}
|
||||
26
vm/tftp.sh
26
vm/tftp.sh
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
SCRIPT_DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
|
||||
source ${SCRIPT_DIR}/helper.sh
|
||||
|
||||
TFTP_DIR=${SCRIPT_DIR}/../tftp
|
||||
rm -rf "${TFTP_DIR}"
|
||||
mkdir -p "${TFTP_DIR}"
|
||||
|
||||
IPXE_DIR=${SCRIPT_DIR}/../ipxe
|
||||
IPXE_FILE=${IPXE_DIR}/ipxe-${IPXE_VERSION}/src/${IPXE_BIN}
|
||||
if [ ! -f "${IPXE_FILE}" ]; then
|
||||
mkdir -p "${IPXE_DIR}"
|
||||
rm -rf "${IPXE_DIR}/ipxe-${IPXE_VERSION}"
|
||||
curl -L https://github.com/ipxe/ipxe/archive/${IPXE_VERSION}.tar.gz | tar -xz -C "${IPXE_DIR}"
|
||||
cd "${IPXE_DIR}/ipxe-${IPXE_VERSION}/src"
|
||||
sed -i 's/^#undef[\t ]DOWNLOAD_PROTO_HTTPS.*$/#define DOWNLOAD_PROTO_HTTPS/g' config/general.h
|
||||
make -j$(nproc) ${IPXE_BIN}
|
||||
cd -
|
||||
fi
|
||||
|
||||
${SCRIPT_DIR}/../generate.sh
|
||||
|
||||
cp ${SCRIPT_DIR}/../rendered/boot.ipxe ${TFTP_DIR}
|
||||
cp ${IPXE_FILE} ${TFTP_DIR}
|
||||
|
||||
sudo in.tftpd -L --secure ./tftp
|
||||
Reference in New Issue
Block a user