From 58839d6b9397784e0eee58009b92cf7154b5eaf6 Mon Sep 17 00:00:00 2001 From: Azuna <36605286+azunaVT@users.noreply.github.com> Date: Sun, 22 Jun 2025 22:29:20 +0000 Subject: [PATCH 1/2] Added manual daemon mode with sleep and kill management to auto-kill dnsmasq after some time --- src/flint-pxe.sh | 61 +++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/src/flint-pxe.sh b/src/flint-pxe.sh index 002315d..07e9b1d 100755 --- a/src/flint-pxe.sh +++ b/src/flint-pxe.sh @@ -11,6 +11,7 @@ SCHEMATIC_ID="376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba" TEST_MODE=false TALOS_VERSION="1.10.4" PLATFORM="metal" +WAIT_TIME=-1 help(){ echo "Usage:" @@ -20,12 +21,13 @@ help(){ echo -e "\t\t-a,--arch \t\tArchitecture to use from the Image Factory" echo -e "\t\t-b,--base-url \t\tBase url to get the ipxe script from" echo -e "\t\t-d,--dhcp-server \t\tSpecifies the upstream dhcp server IP address using CIDR notation" + echo -e "\t\t-h,--help\t\tPrints help message" echo -e "\t\t-m,--mac-address \t\tMAC address to wake on lan, can be used multiple times" echo -e "\t\t-o,--ipxe-url-override \t\tOverride the full url for the iPXE script." echo -e "\t\t-s,--schematic-id \t\tSchematic ID from Talos Image factory" echo -e "\t\t-t,--test\t\tEnables test mode, basically dry-runs the script" echo -e "\t\t-v,--talos-version \t\tTalos version number to use" - echo -e "\t\t-h,--help\t\tPrints help message" + echo -e "\t\t-w,--wait \t\tRun as daemon and wait for number-of-seconds before terminating dnsmasq" echo echo "Examples:" echo -e "\t docker run -it --rm ghcr.io/feenx-lab/fint-pxe" @@ -102,6 +104,16 @@ while [[ $# -gt 0 ]]; do shift # skip argument shift # skip value ;; + -w|--wait) + if [[ $2 =~ ^[0-9]+$ ]]; then + WAIT_TIME=$2 + else + echo "Invalid wait time, only specify number of seconds" + exit 1 + fi + shift # skip argument + shift # skip value + ;; -*|--*) echo "Unknown option $1" exit 1 @@ -136,30 +148,31 @@ if [[ -n "$IPXE_URL_OVERRIDE" ]]; then IPXE_SCRIPT_URL="${IPXE_URL_OVERRIDE}" fi -if [[ "${TEST_MODE}" = true ]]; then - cat << EOF -/usr/sbin/dnsmasq -d -q \\ - --port=0 \\ - --dhcp-range=${DHCP_SERVER_IP},proxy,${NETMASK} \\ - --enable-tftp --tftp-root=/var/lib/tftpboot \\ - --dhcp-userclass=set:ipxe,iPXE \\ - --pxe-service=tag:#ipxe,x86PC,"PXE chainload to iPXE",undionly.kpxe \\ - --pxe-service=tag:ipxe,x86PC,"iPXE",$IPXE_SCRIPT_URL \\ - --pxe-service=tag:#ipxe,X86-64_EFI,"PXE chainload to iPXE UEFI",ipxe.efi \\ - --pxe-service=tag:ipxe,X86-64_EFI,"iPXE UEFI",$IPXE_SCRIPT_URL \\ - --log-queries \\ +command=$(cat << EOF +/usr/sbin/dnsmasq -d -q + --port=0 + --dhcp-range=${DHCP_SERVER_IP},proxy,${NETMASK} + --enable-tftp --tftp-root=/var/lib/tftpboot + --dhcp-userclass=set:ipxe,iPXE + --pxe-service=tag:#ipxe,x86PC,"PXE chainload to iPXE",undionly.kpxe + --pxe-service=tag:ipxe,x86PC,"iPXE",$IPXE_SCRIPT_URL + --pxe-service=tag:#ipxe,X86-64_EFI,"PXE chainload to iPXE UEFI",ipxe.efi + --pxe-service=tag:ipxe,X86-64_EFI,"iPXE UEFI",$IPXE_SCRIPT_URL + --log-queries --log-dhcp EOF +) + +if [[ "${TEST_MODE}" = true ]]; then + echo "$command" +elif [[ $WAIT_TIME -ge 0 ]]; then + eval $command & + DAEMON_PID=$! + sleep $WAIT_TIME + if kill -0 "$DAEMON_PID" 2>/dev/null; then + echo "Daemon still running, killing it..." + kill "$DAEMON_PID" + fi else - /usr/sbin/dnsmasq -d -q \ - --port=0 \ - --dhcp-range=${DHCP_SERVER_IP},proxy,${NETMASK} \ - --enable-tftp --tftp-root=/var/lib/tftpboot \ - --dhcp-userclass=set:ipxe,iPXE \ - --pxe-service=tag:#ipxe,x86PC,"PXE chainload to iPXE",undionly.kpxe \ - --pxe-service=tag:ipxe,x86PC,"iPXE",$IPXE_SCRIPT_URL \ - --pxe-service=tag:#ipxe,X86-64_EFI,"PXE chainload to iPXE UEFI",ipxe.efi \ - --pxe-service=tag:ipxe,X86-64_EFI,"iPXE UEFI",$IPXE_SCRIPT_URL \ - --log-queries \ - --log-dhcp + eval $command fi \ No newline at end of file From 87209c62abe99fd04caed802a9b6b5664a1ff38d Mon Sep 17 00:00:00 2001 From: Azuna <36605286+azunaVT@users.noreply.github.com> Date: Mon, 23 Jun 2025 00:50:44 +0000 Subject: [PATCH 2/2] Changed arguments to be more intuitive, added --wait and updated README --- .github/workflows/build-test-push.yml | 2 +- README.md | 16 +++++------ src/flint-pxe.sh | 41 +++++++++++++++------------ 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/.github/workflows/build-test-push.yml b/.github/workflows/build-test-push.yml index 5e80ef1..0d72168 100644 --- a/.github/workflows/build-test-push.yml +++ b/.github/workflows/build-test-push.yml @@ -57,7 +57,7 @@ jobs: id: test run: | docker run --rm ${{ env.TEST_TAG }} -h - docker run --rm ${{ env.TEST_TAG }} -d 192.168.1.1/24 -t + docker run --rm ${{ env.TEST_TAG }} -n 192.168.1.0/24 -t - name: Build and push id: push diff --git a/README.md b/README.md index 3b84617..448aad7 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,9 @@ ## 🛠️ Get Started -To start a PXE server using the default options: +To start a PXE server using the default options in your `192.168.1.0/24` subnet: ```bash -docker run -it --rm --cap-add=NET_ADMIN --net=host ghcr.io/feenx-lab/flint-pxe +docker run -it --rm --cap-add=NET_ADMIN --net=host ghcr.io/feenx-lab/flint-pxe --network 192.168.1.0/24 ``` > [!IMPORTANT] @@ -86,7 +86,7 @@ It’s meant to be a fast, ephemeral, local PXE boot solution to stand up Talos | Flag | Description | |----------------------------------|--------------------------------------------------------------------| -| `--dhcp-server`, `-d` | Upstream DHCP server IP in CIDR notation (e.g: `192.168.1.1/24`) | +| `--network`, `-n` | Subnet in CIDR notation (e.g: `192.168.1.0/24`) | ### Optional @@ -95,12 +95,12 @@ It’s meant to be a fast, ephemeral, local PXE boot solution to stand up Talos |----------------------------------|---------------------------------------------------------------------------------------------------------------------------------| | `--arch`, `-a` | Architecture to use from the Image Factory (default: `amd64`) | | `--base-url`, `-b` | Base URL to fetch the iPXE script from (default: `https://pxe.factory.talos.dev/pxe`) | +| `--dry-run`, `-d` | Enables test mode (dry-run, no changes applied) (default: `false`) | +| `--help`, `-h` | Prints help message | | `--mac-address`, `-m` | MAC address for Wake-on-LAN. Can be used multiple times (default: none) | | `--ipxe-url-override`, `-o` | Override the full URL for the iPXE script (default: none) | | `--schematic-id`, `-s` | The Talos Image Factory schematic ID to boot from (default: `376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba`) | | `--talos-version`, `-v` | Talos version number to use (default: `1.10.4`) | -| `--test`, `-t` | Enables test mode (dry-run, no changes applied) (default: `false`) | -| `--help`, `-h` | Prints help message | ## 🧪 Examples @@ -110,7 +110,7 @@ It’s meant to be a fast, ephemeral, local PXE boot solution to stand up Talos ```bash docker run -it --rm --cap-add=NET_ADMIN --net=host \ ghcr.io/feenx-lab/flint-pxe \ - --dhcp-server 192.168.1.1/24 + --network 192.168.1.0/24 ``` ### 2. Run flint-pxe + Wake target machines @@ -118,7 +118,7 @@ docker run -it --rm --cap-add=NET_ADMIN --net=host \ ```bash docker run -it --rm --cap-add=NET_ADMIN --net=host \ ghcr.io/feenx-lab/flint-pxe \ - --dhcp-server 192.168.1.1/24 \ + --network 192.168.1.0/24 \ --mac-address aa:bb:cc:dd:ee:ff \ --mac-address a1:b2:c3:d4:e5:f6 ``` @@ -128,7 +128,7 @@ docker run -it --rm --cap-add=NET_ADMIN --net=host \ ```bash docker run -it --rm --cap-add=NET_ADMIN --net=host \ ghcr.io/feenx-lab/flint-pxe \ - --dhcp-server 192.168.1.1/24 \ + --network 192.168.1.0/24 \ --arch arm64 \ --schematic-id 09dbcadc567d93b02a1610c70d651fadbe56aeac3aaca36bc488a38f3fffe99d ``` diff --git a/src/flint-pxe.sh b/src/flint-pxe.sh index 07e9b1d..513bd3a 100755 --- a/src/flint-pxe.sh +++ b/src/flint-pxe.sh @@ -4,7 +4,7 @@ P_ARGS=() ARCH="amd64" BASE_URL="https://pxe.factory.talos.dev/pxe" -DHCP_SERVER="" +CIDR_SUBNET="" MAC_ADDRESSES=() IPXE_URL_OVERRIDE="" SCHEMATIC_ID="376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba" @@ -20,20 +20,20 @@ help(){ echo "Options:" echo -e "\t\t-a,--arch \t\tArchitecture to use from the Image Factory" echo -e "\t\t-b,--base-url \t\tBase url to get the ipxe script from" - echo -e "\t\t-d,--dhcp-server \t\tSpecifies the upstream dhcp server IP address using CIDR notation" + echo -e "\t\t-d,--dry-run\t\tEnables dry-run mode" echo -e "\t\t-h,--help\t\tPrints help message" + echo -e "\t\t-n,--network \t\tSpecifies the subnet address using CIDR notation" echo -e "\t\t-m,--mac-address \t\tMAC address to wake on lan, can be used multiple times" echo -e "\t\t-o,--ipxe-url-override \t\tOverride the full url for the iPXE script." echo -e "\t\t-s,--schematic-id \t\tSchematic ID from Talos Image factory" - echo -e "\t\t-t,--test\t\tEnables test mode, basically dry-runs the script" echo -e "\t\t-v,--talos-version \t\tTalos version number to use" echo -e "\t\t-w,--wait \t\tRun as daemon and wait for number-of-seconds before terminating dnsmasq" echo echo "Examples:" echo -e "\t docker run -it --rm ghcr.io/feenx-lab/fint-pxe" echo -e "\t docker run -it --rm ghcr.io/feenx-lab/fint-pxe --schematic-id 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba" - echo -e "\t docker run -it --rm ghcr.io/feenx-lab/fint-pxe --dhcp-server 192.168.1.1/24 --schematic-id 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba --talos-version 1.10.4" - echo -e "\t docker run -it --rm ghcr.io/feenx-lab/fint-pxe -d 192.168.1.1/24 --s 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba -v 1.10.4" + echo -e "\t docker run -it --rm ghcr.io/feenx-lab/fint-pxe --network 192.168.1.0/24 --schematic-id 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba --talos-version 1.10.4" + echo -e "\t docker run -it --rm ghcr.io/feenx-lab/fint-pxe -n 192.168.1.1/24 --s 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba -v 1.10.4" } # Print help if no args are given @@ -55,9 +55,9 @@ while [[ $# -gt 0 ]]; do shift # skip argument shift # skip value ;; - -d|--dhcp-server) + -n|--network) if ipcalc -cs $2; then - DHCP_SERVER=$2 + CIDR_SUBNET=$2 else echo "Invalid IP." exit 1 @@ -128,14 +128,14 @@ done # Reset positional args set -- "${P_ARGS[@]}" -if [[ -z "$DHCP_SERVER" ]]; then +if [[ -z "$CIDR_SUBNET" ]]; then echo "Error: No DHCP server specified" exit 1 fi # Split up the dhcp server IP and netmask -DHCP_SERVER_IP=$(ipcalc $DHCP_SERVER | grep Address: | awk '{print $2}') -NETMASK=$(ipcalc $DHCP_SERVER | grep Netmask | sed 's/ =.*//' | awk '{print $2}') +SUBNET=$(ipcalc $CIDR_SUBNET | grep Address: | awk '{print $2}') +NETMASK=$(ipcalc $CIDR_SUBNET | grep Netmask | sed 's/ =.*//' | awk '{print $2}') # Send magic packtes to given mac addresses for m in "${MAC_ADDRESSES[@]}"; do @@ -151,7 +151,7 @@ fi command=$(cat << EOF /usr/sbin/dnsmasq -d -q --port=0 - --dhcp-range=${DHCP_SERVER_IP},proxy,${NETMASK} + --dhcp-range=${SUBNET},proxy,${NETMASK} --enable-tftp --tftp-root=/var/lib/tftpboot --dhcp-userclass=set:ipxe,iPXE --pxe-service=tag:#ipxe,x86PC,"PXE chainload to iPXE",undionly.kpxe @@ -166,13 +166,18 @@ EOF if [[ "${TEST_MODE}" = true ]]; then echo "$command" elif [[ $WAIT_TIME -ge 0 ]]; then + # Create a job for the command to run eval $command & - DAEMON_PID=$! - sleep $WAIT_TIME - if kill -0 "$DAEMON_PID" 2>/dev/null; then - echo "Daemon still running, killing it..." - kill "$DAEMON_PID" - fi + command_pid=$! + + # Create a sleep job + sleep $WAIT_TIME & + sleep_pid=$! + + # Wait on both jobs, first one to finish will return its exit code. + wait -n $command_pid $sleep_pid + exit $? else - eval $command + eval $command & + wait -n fi \ No newline at end of file