Skip to content
Open
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
31 changes: 25 additions & 6 deletions docs/skills/ddi-installer.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ metadata:

## Architecture

The installer is offline, self-contained, and systemd-native. The OS DDI payload
(`bluefin-server-ddi.bst`) is embedded as a data partition on the installer
media at build time. No network access is required at install time.
The installer is systemd-native and offline by default. The OS DDI payload
(`bluefin-server-ddi.bst`) is embedded as a data partition on installer media
at build time, while PXE users may opt into downloading it over HTTPS.

The installer UI is systemd's built-in `systemd-sysinstall` which provides a
terminal-based interactive installation that:
Expand Down Expand Up @@ -154,10 +154,29 @@ clients can add `unattended` to the installer command line, for example:
systemd.unit=system-install.target console=tty0 console=ttyS0,115200 rw unattended
```

The DDI is still required on `bluefin-installer-data`; standalone network DDI
fetching is not supported yet. Use the raw installer image for complete,
For offline installs, the DDI remains on `bluefin-installer-data`; PXE installs
may use `inst.ddi_url` instead. Use the raw installer image for complete,
offline installation.

## PXE network installs

PXE clients may boot standalone kernel and initrd with optional kernel parameters:

- `inst.ddi_url=<https-url>` downloads zstd-compressed DDI instead of using
embedded installer partition.
- `inst.ddi_sha256=<hex>` verifies download before touching target disk.
- `inst.target_disk=/dev/...` selects explicit target disk.

Without `inst.ddi_url`, behavior remains unchanged and uses embedded DDI.
Network or checksum failures abort before partitioning. Example:

```text
kernel bluefin-server-pxe-vmlinuz systemd.unit=system-install.target rw unattended \
inst.ddi_url=https://pxe.example/ddi.raw.zst inst.ddi_sha256=<sha256>
initrd bluefin-server-pxe-initrd.cpio.gz
boot
```

## Common Rationalizations

| Rationalization | Reality |
Expand All @@ -168,7 +187,7 @@ offline installation.
| "Initrd archive tools (gzip, cpio) are in base-stack." | In FSDK 26.08, gzip and cpio are standalone components; elements packing or unpacking initrds must explicitly declare `components/gzip.bst` and `components/cpio.bst` in `build-depends`. |
| "Use knuckle instead." | knuckle is deprecated in favor of native `systemd-sysinstall` (systemd 261+). |
| "Hardcode `root=/dev/vda2` for QEMU." | Bare metal has different device names. Always use PARTUUID. |
| "Pull the DDI from the network at install time." | Network failures = broken installs. The DDI is embedded in the installer media. |
| "Pull the DDI from the network at install time." | Network pull is opt-in; failures abort before disk changes, while embedded media remains default. |
| "Put the DDI in the initrd cpio." | The DDI is 2 GiB+. The initrd cpio step must run before the DDI is placed in `/layer`. |
| "Store the DDI in the ESP (FAT32)." | FAT32 has a 4 GiB per-file limit. Use a separate XFS partition. |
| "Add an 8 GiB minimum size floor to the DDI." | The rootfs is immutable. It never grows in-place. Content + overhead is enough. |
Expand Down
4 changes: 4 additions & 0 deletions elements/installer/installer-stack.bst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ depends:
- freedesktop-sdk.bst:components/xfsprogs.bst
- freedesktop-sdk.bst:components/dosfstools.bst

# Network DDI fetching for PXE installs
- freedesktop-sdk.bst:components/curl.bst
- freedesktop-sdk.bst:components/sed.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
52 changes: 48 additions & 4 deletions elements/oci/bluefin-server-installer.bst
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,58 @@ config:
modprobe -q nvme_core || true
udevadm settle --timeout=15 || true

CMDLINE="$(< /proc/cmdline)"
DDI_URL=""
DDI_SHA256=""
TARGET_DISK_OVERRIDE=""
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=*) TARGET_DISK_OVERRIDE="${arg#inst.target_disk=}" ;;
esac
done

# PXE installs use a downloaded raw DDI and a temporary repart override.
if [ -n "${DDI_URL}" ]; then
mkdir -p /run/installer /usr/lib/repart.sysinstall.d
echo "==> Fetching DDI from ${DDI_URL}..."
if command -v systemd-networkd-wait-online >/dev/null 2>&1; then
systemd-networkd-wait-online --timeout=60 || {
echo "ERROR: Network did not become ready for DDI download." >&2
exit 1
}
fi
curl --fail --silent --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 "ERROR: Downloaded DDI SHA256 mismatch." >&2
exit 1
}
fi
zstd --decompress --rm /run/installer/bluefin-server-ddi.raw.zst \
-o /run/installer/bluefin-server-ddi.raw
cp /usr/lib/repart.d/10-esp.conf /usr/lib/repart.sysinstall.d/
sed 's#CopyBlocks=/dev/disk/by-partlabel/bluefin-installer-data#CopyBlocks=/run/installer/bluefin-server-ddi.raw#' \
/usr/lib/repart.d/20-root-a.conf \
> /usr/lib/repart.sysinstall.d/20-root-a.conf
cp /usr/lib/repart.d/30-var.conf /usr/lib/repart.sysinstall.d/
fi

# 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)"
if [ -n "${TARGET_DISK_OVERRIDE}" ]; then
if [ ! -b "${TARGET_DISK_OVERRIDE}" ]; then
echo "ERROR: inst.target_disk is not a block device: ${TARGET_DISK_OVERRIDE}" >&2
exit 1
fi
TARGET_DISK="${TARGET_DISK_OVERRIDE}"
fi

while read -r name type ro size; do
while [ -z "${TARGET_DISK}" ] && read -r name type ro size; do
[ "${type}" = "disk" ] || continue
[ "${ro}" = "0" ] || continue
[ "${size}" -gt 0 ] || continue
Expand Down Expand Up @@ -247,9 +294,6 @@ config:
fi
fi
}

# Check for unattended in kernel command line
CMDLINE="$(< /proc/cmdline)"
if [[ " ${CMDLINE} " == *" unattended "* ]]; then
echo "==> Running in UNATTENDED mode..."
if [ -n "${TARGET_DISK}" ]; then
Expand Down