Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-test-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@
## 🛠️ Get Started

<a id="get-started"></a>
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]
Expand Down Expand Up @@ -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

Expand All @@ -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

Expand All @@ -110,15 +110,15 @@ 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

```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
```
Expand All @@ -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
```
Expand Down
86 changes: 52 additions & 34 deletions src/flint-pxe.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
P_ARGS=()
ARCH="amd64"
BASE_URL="https://pxe.factory.talos.dev/pxe"
DHCP_SERVER=""
CIDR_SUBNET=""
MAC_ADDRESSES=()
IPXE_URL_OVERRIDE=""
SCHEMATIC_ID="376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
TEST_MODE=false
TALOS_VERSION="1.10.4"
PLATFORM="metal"
WAIT_TIME=-1

help(){
echo "Usage:"
Expand All @@ -19,19 +20,20 @@ help(){
echo "Options:"
echo -e "\t\t-a,--arch <amd64|arm64>\t\tArchitecture to use from the Image Factory"
echo -e "\t\t-b,--base-url <base-url>\t\tBase url to get the ipxe script from"
echo -e "\t\t-d,--dhcp-server <cidr-dhcp-server-ip>\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 <cidr-subnet>\t\tSpecifies the subnet address using CIDR notation"
echo -e "\t\t-m,--mac-address <mac-address>\t\tMAC address to wake on lan, can be used multiple times"
echo -e "\t\t-o,--ipxe-url-override <ipxe-script-url>\t\tOverride the full url for the iPXE script."
echo -e "\t\t-s,--schematic-id <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 <talos-version>\t\tTalos version number to use"
echo -e "\t\t-h,--help\t\tPrints help message"
echo -e "\t\t-w,--wait <number-of-seconds>\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
Expand All @@ -53,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
Expand Down Expand Up @@ -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
Expand All @@ -116,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
Expand All @@ -136,30 +148,36 @@ 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=${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
--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
# Create a job for the command to run
eval $command &
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
/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 &
wait -n
fi
Loading