Skip to content
Closed
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
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ All `just` targets run BuildStream inside the FSDK `bst2` container via `just bs
| Task | Skill |
|---|---|
| Build or debug the installer / DDI | [`docs/skills/ddi-installer.md`](docs/skills/ddi-installer.md), [`docs/skills/ddi-installer-build.md`](docs/skills/ddi-installer-build.md) |
| PXE/netboot installation | [`docs/skills/pxe-netboot.md`](docs/skills/pxe-netboot.md) |
| Factory role, k3s sysext rationale, lab integration | [`docs/skills/factory-integration.md`](docs/skills/factory-integration.md) |
| Work with `systemd-sysext` / `systemd-confext` | [`docs/skills/systemd-sysext-extensions.md`](docs/skills/systemd-sysext-extensions.md) |
| Build or ship the k3s sysext | [`docs/skills/k3s-sysext.md`](docs/skills/k3s-sysext.md), [`docs/skills/k3s-sysext-ops.md`](docs/skills/k3s-sysext-ops.md) |
Expand Down
10 changes: 9 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ cluster-build REF="main":
-n argo \
--watch

# Export the installer disk image + SHA256SUMS to dist/.
# Export the installer disk image, UKI, PXE artifacts + SHA256SUMS to dist/.
# bst artifact checkout requires an empty destination, and dist/ may
# already hold dist/ddi/ or dist/sysext/ from earlier export steps, so
# check out into a clean staging directory and move the files over.
Expand All @@ -115,6 +115,14 @@ export-installer: build-installer
rm -rf dist/installer-checkout
@echo "==> wrote:" && ls -lh dist/

# Export standalone PXE kernel/initrd artifacts to dist/pxe/.
[group('installer')]
export-pxe: export-installer
rm -rf dist/pxe
mkdir -p dist/pxe
cp dist/bluefin-server-pxe-* dist/SHA256SUMS dist/pxe/
@echo "==> wrote PXE artifacts:" && ls -lh dist/pxe/

# -- k3s systemd-sysext -------------------------------------------------------
# Produces a systemd-sysext extension image for k3s.

Expand Down
5 changes: 5 additions & 0 deletions docs/skills/ddi-installer.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ remains stateless.
stack includes `xfsprogs` so the root and `/var` filesystems can grow to fill
their partitions on first boot.

For PXE/netboot, use the standalone kernel and initrd artifacts with the
opt-in `inst.ddi_url` parameters documented in
[pxe-netboot.md](pxe-netboot.md). Without those parameters, installation
continues to use the embedded DDI and requires no network.

## Partition Layout

### Installer media (the USB/raw disk image)
Expand Down
1 change: 1 addition & 0 deletions docs/skills/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ This is the lazy-load routing table for agent skills. Keep this file in memory w
| [`gap-analysis-distros.md`](gap-analysis-distros.md) | Comparing Bluefin Server to other server OSes | Source-verified comparison to Ubuntu, Talos, Flatcar, FCOS. |
| [`k3s-sysext-ops.md`](k3s-sysext-ops.md) | Building the k3s sysext | BuildStream element and publish steps for the k3s sysext. |
| [`k3s-sysext.md`](k3s-sysext.md) | Operating k3s on Bluefin Server | Runtime operation and reboot coordination for k3s. |
| [`pxe-netboot.md`](pxe-netboot.md) | Installing over PXE/netboot | Standalone boot artifacts, DDI URL parameters, and troubleshooting. |
| [`skill-improvement.md`](skill-improvement.md) | Adding, splitting, or refactoring skills | Meta-skill that owns the documentation loop. |
| [`system-containers.md`](system-containers.md) | Running `systemd-nspawn` toolboxes | System container operation with `machinectl`. |
| [`systemd-sysext-extensions.md`](systemd-sysext-extensions.md) | Optional layers via `systemd-sysext` / `systemd-confext` | Extension identity, loading, and Flatcar compatibility. |
Expand Down
34 changes: 34 additions & 0 deletions docs/skills/pxe-netboot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: pxe-netboot
description: PXE/netboot installation using standalone Bluefin Server boot artifacts
---
# PXE/netboot installation

PXE installation is an opt-in variant of the normal offline installer. Releases
publish a kernel (`bluefin-server-pxe-vmlinuz-<version>`) and cpio initrd
(`bluefin-server-pxe-initrd-<version>.cpio.gz`) alongside the installer, DDI,
and signed `SHA256SUMS` manifest.

The PXE loader supplies `inst.ddi_url=https://.../bluefin-server-ddi-<version>.raw.zst`.
Use `inst.ddi_sha256=<sha256-of-compressed-ddi>` to verify the download before
the target disk is touched. `inst.target_disk=/dev/...` can select a specific
disk; without it, unattended mode selects the first writable disk that is not
installer media.

Example iPXE stanza:

```text
#!ipxe
set base https://mirror.example/bluefin
kernel ${base}/bluefin-server-pxe-vmlinuz-<version> systemd.unit=system-install.target console=tty0 console=ttyS0,115200 rw unattended inst.ddi_url=${base}/bluefin-server-ddi-<version>.raw.zst inst.ddi_sha256=<sha256>
initrd ${base}/bluefin-server-pxe-initrd-<version>.cpio.gz
boot
```

The initrd downloads and decompresses the DDI into `/run/installer`, so allow
RAM or writable runtime storage for the expanded DDI. HTTPS requires the
installer CA bundle. DHCP is enabled on Ethernet interfaces; provide a serial
console with `console=ttyS0,115200` when diagnosing DHCP or fetch failures.

Without `inst.ddi_url`, behavior is unchanged: the installer reads the embedded
DDI from `bluefin-installer-data` and needs no network.
3 changes: 3 additions & 0 deletions elements/installer/installer-stack.bst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ depends:
- freedesktop-sdk.bst:components/cryptsetup.bst
- freedesktop-sdk.bst:components/xfsprogs.bst
- freedesktop-sdk.bst:components/dosfstools.bst
# Optional PXE installer path (curl fetches the compressed DDI; zstd expands it).
- freedesktop-sdk.bst:components/curl.bst
- freedesktop-sdk.bst:components/zstd.bst

# Kernel (installer boots from this; vmlinuz used as the UKI --linux= arg)
- freedesktop-sdk.bst:components/linux.bst
Expand Down
59 changes: 58 additions & 1 deletion elements/oci/bluefin-server-installer.bst
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,58 @@ config:
# Auto-detect target disk for unattended install (any raw disk of type "disk" that is not the installer, is not read-only, and has size > 0)
TARGET_DISK=""
INSTALLER_PART="$(readlink -f /dev/disk/by-partlabel/bluefin-installer-data 2>/dev/null || true)"
CMDLINE="$(cat /proc/cmdline 2>/dev/null || true)"

# PXE installs opt in with inst.ddi_url. Keep the compressed download on
# the installer filesystem, then expose the expanded image at the same
# path used by the embedded-media repart definition.
DDI_URL=""
DDI_SHA256=""
REQUESTED_TARGET=""
for arg in ${CMDLINE}; do
case "${arg}" in
inst.ddi_url=*) DDI_URL="${arg#inst.ddi_url=}" ;;
inst.ddi_sha256=*) DDI_SHA256="${arg#inst.ddi_sha256=}" ;;
inst.target_disk=*) REQUESTED_TARGET="${arg#inst.target_disk=}" ;;
esac
done

if [ -n "${DDI_URL}" ]; then
case "${DDI_URL}" in
http://*|https://*) ;;
*) echo "ERROR: inst.ddi_url must use http:// or https://" >&2; exit 1 ;;
esac
mkdir -p /run/installer
echo "==> Fetching DDI from ${DDI_URL}"
curl --fail --show-error --location --retry 3 --output /run/installer/bluefin-server-ddi.raw.zst "${DDI_URL}"
if [ -n "${DDI_SHA256}" ]; then
printf '%s %s\n' "${DDI_SHA256}" /run/installer/bluefin-server-ddi.raw.zst \
| sha256sum --check --status -
echo "==> DDI checksum verified"
fi
zstd --decompress --stdout /run/installer/bluefin-server-ddi.raw.zst \
> /run/installer/bluefin-server-ddi.raw
rm -f /run/installer/bluefin-server-ddi.raw.zst
mkdir -p /dev/disk/by-partlabel
ln -sfn /run/installer/bluefin-server-ddi.raw \
/dev/disk/by-partlabel/bluefin-installer-data
INSTALLER_PART=""
fi

if [ -n "${REQUESTED_TARGET}" ]; then
case "${REQUESTED_TARGET}" in
/dev/*) ;;
*) echo "ERROR: inst.target_disk must be an absolute /dev path" >&2; exit 1 ;;
esac
if [ ! -b "${REQUESTED_TARGET}" ]; then
echo "ERROR: inst.target_disk is not a block device: ${REQUESTED_TARGET}" >&2
exit 1
fi
TARGET_DISK="${REQUESTED_TARGET}"
fi

while read -r name type ro size; do
[ -z "${TARGET_DISK}" ] || break
[ "${type}" = "disk" ] || continue
[ "${ro}" = "0" ] || continue
[ "${size}" -gt 0 ] || continue
Expand All @@ -146,7 +196,6 @@ config:
done < <(lsblk -p -d -n -o NAME,TYPE,RO,SIZE -b)

# Check for unattended in kernel command line
CMDLINE="$(cat /proc/cmdline 2>/dev/null || true)"
if [[ " ${CMDLINE} " == *" unattended "* ]]; then
echo "==> Running in UNATTENDED mode..."
if [ -n "${TARGET_DISK}" ]; then
Expand Down Expand Up @@ -181,6 +230,8 @@ config:
mkdir -p /layer/etc/systemd/system/systemd-sysinstall.service.d
cat > /layer/etc/systemd/system/systemd-sysinstall.service.d/override.conf << 'EOF'
[Unit]
Wants=network-online.target
After=network-online.target
SuccessAction=poweroff
FailureAction=poweroff

Expand Down Expand Up @@ -316,7 +367,13 @@ config:

# Also export the target UKI (.efi) for GitHub Releases and systemd-sysupdate
cp /layer/usr/lib/bluefin-server/bluefin-server.efi "bluefin-server-%{installer-version}.efi"
# Export separate PXE boot artifacts. Their cmdline is supplied by the
# PXE loader, unlike the fixed cmdline embedded in the UKI.
cp /layer/boot/vmlinuz "bluefin-server-pxe-vmlinuz-%{installer-version}"
cp /installer.cpio.gz "bluefin-server-pxe-initrd-%{installer-version}.cpio.gz"

sha256sum --binary "${FNAME}.zst" > SHA256SUMS
sha256sum --binary "bluefin-server-%{installer-version}.efi" >> SHA256SUMS
sha256sum --binary "bluefin-server-pxe-vmlinuz-%{installer-version}" >> SHA256SUMS
sha256sum --binary "bluefin-server-pxe-initrd-%{installer-version}.cpio.gz" >> SHA256SUMS
ls -lh
Loading