Cleanup and improvements
This commit is contained in:
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
|
||||
[*.yaml]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[{*.py,tools/merge}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,2 @@
|
||||
ipxe/
|
||||
.ipxe/
|
||||
rendered/
|
||||
tftp/
|
||||
|
||||
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"]
|
||||
2
config.yaml
Normal file
2
config.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
dhcp:
|
||||
tftpIp: 10.0.0.3
|
||||
@@ -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
|
||||
@@ -6,4 +6,3 @@ dns0: 1.1.1.1
|
||||
dns1: 8.8.8.8
|
||||
ntp: nl.pool.ntp.org
|
||||
install: false
|
||||
upgradeIPXE: false
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
customization:
|
||||
systemExtensions:
|
||||
officialExtensions:
|
||||
- siderolabs/iscsi-tools
|
||||
- siderolabs/util-linux-tools
|
||||
systemExtensions:
|
||||
officialExtensions:
|
||||
- siderolabs/iscsi-tools
|
||||
- siderolabs/util-linux-tools
|
||||
- siderolabs/intel-ucode
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
netmask: 255.255.255.0
|
||||
gateway: 192.168.1.1
|
||||
upgradeIPXE: ipxe.pxe
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
serial: vm
|
||||
serial: talos-vm
|
||||
interface: enp1s0
|
||||
ip: 192.168.1.2
|
||||
install: true
|
||||
@@ -2,35 +2,24 @@
|
||||
|
||||
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} || shell
|
||||
# Default behavior (non install mode) is to exit iPXE script
|
||||
|
||||
{{ range (datasource "nodes" | jsonArray) }}
|
||||
{{ range datasource "nodes" }}
|
||||
{{- 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 }}
|
||||
imgfree
|
||||
kernel https://pxe.factory.talos.dev/image/{{ .schematicID }}/{{ .talosVersion }}/kernel-{{ .arch }} {{ $kernelArgs }} {{- if .upgradeIPXE }} || boot {{ .upgradeIPXE }} {{- end }}
|
||||
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
|
||||
{{- 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{{ $tftpIp := (ds "dhcp").tftpIp -}}
|
||||
{{ $tftpIp := (ds "config").dhcp.tftpIp -}}
|
||||
|
||||
enable-tftp
|
||||
tftp-root=/tftproot
|
||||
|
||||
11
tools/render
Executable file
11
tools/render
Executable 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 \
|
||||
71
tools/tftpd
Executable file
71
tools/tftpd
Executable file
@@ -0,0 +1,71 @@
|
||||
#!/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}
|
||||
|
||||
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 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
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
download_ipxe
|
||||
patch_ipxe
|
||||
build_ipxe
|
||||
render
|
||||
host_tftp
|
||||
154
tools/vm
Executable file
154
tools/vm
Executable 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
|
||||
@@ -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