Wheelhouse docs

The flavor and the branding hooks#

Three files decide what a Wheelhouse image is as distinct from a VyOS image: a flavor file that vyos-build reads, and two live-build hooks that run inside the build. The flavor sets the default configuration the image boots with and takes ownership of /etc/os-release. The chroot hook fixes identity and licence files that no flavor key can reach. The binary hook brands both boot menus. All three are written to fail the build rather than produce an image that still says VyOS, because a boot menu with the wrong name on it is a trademark problem as well as a branding one.

Where these files live at build time#

packaging/iso/build-iso.sh copies them into the vyos-build checkout:

SourceDestination in vyos-build
packaging/iso/wheelhouse.tomldata/build-flavors/wheelhouse.toml, with @VERSION@ and @VYOS_BASE@ substituted
packaging/iso/branding/50-wheelhouse-brand.chrootdata/live-build-config/hooks/live/
packaging/iso/branding/50-wheelhouse-brand.binarydata/live-build-config/hooks/live/
packaging/iso/branding/doc/*.txtdata/live-build-config/includes.chroot/usr/share/doc/wheelhouse/
packaging/iso/branding/splash.pngover both of upstream's copies

build-vyos-image copies data/live-build-config/ wholesale into the live-build configuration directory, which is how the hooks arrive where live-build will run them.

The flavor#

packaging/iso/wheelhouse.toml declares three things.

image_format = "iso"#

default_config#

The configuration the image boots with when /config/config.boot does not exist yet — a live boot, and the first boot after an install. build-vyos-image writes it to config.boot.default, replacing the one vyos-1x ships. It is upstream's own default with four changes, kept otherwise verbatim so the syntax stays upstream's:

ChangeWhy
host-name wheelhouseThe live login prompt, the banner header, the DHCP client identity the upstream router logs, and the common name of the self-signed certificate the agent generates on first boot
NTP from pool.ntp.org, not VyOS' serversA router we sold should not ask the VyOS project for the time forever, and the customer should not see time1.vyos.net on the System page
system login banner setWithout banner post-login, vyos-1x renders its own template into /etc/motd, which opens "Welcome to VyOS", draws the VyOS logo and points at VyOS' support portal — on the console and, through pam_motd, over SSH. Setting the node replaces the template wholesale. The upstream credit stays, one line, at the bottom
system option kernel quietHow the boot of an installed box stops being a screen of the base's systemd unit descriptions. The live boot is handled separately, on the kernel command line, because the bootloader rather than this file decides that one

The body also carries commit-revisions 100, which is where the archived-revision count a rollback works against comes from.

[[includes_chroot]] for /etc/os-release#

ini
PRETTY_NAME="Wheelhouse OS @VERSION@"
NAME="Wheelhouse"
ID=wheelhouse
ID_LIKE="vyos debian"
VERSION="@VERSION@"
VERSION_ID="@VERSION@"
VYOS_VERSION="@VYOS_BASE@"

This is owned in the flavor and nowhere else, and the reason is mechanical: build-vyos-image writes a hardcoded VyOS os-release into config/includes.chroot/etc/os-release, and the [[includes_chroot]] loop runs later in the same function and overwrites it. Nothing else competes for that path — the only other [[includes_chroot]] entries in upstream's data/ are the EULA in the two build types. Setting the flavor's website_url or support_url keys would not work: those are read from the build defaults rather than from the merged build configuration.

ID_LIKE and VYOS_VERSION stay so that support tooling, monitoring and Ansible facts can still see what the base is. The fuller credit is in /usr/share/doc/wheelhouse.

HOME_URL, DOCUMENTATION_URL and SUPPORT_URL name hosts that resolve; BUG_REPORT_URL is deliberately absent, because there is no public issue tracker and an os-release key is optional, so leaving it out is the honest answer.

The chroot hook#

50-wheelhouse-brand.chroot runs from live-build's lb chroot_hooks, which is after lb chroot_includes_after_packages — so everything the flavor and build-iso.sh staged under includes.chroot is already in place. It does four things, and asserts after each.

1. The licence documents are present, and complete#

sh
for f in TERMS.txt THIRD-PARTY.txt SOURCE-OFFER.txt SOURCES.txt; do
    [ -f "${DOC}/${f}" ] || fail "${DOC}/${f} is missing — build-iso.sh did not stage it"
    …
    if grep -qF '<TODO' "${DOC}/${f}"; then … fail "still has an unfilled placeholder"; fi
done

build-iso.sh checks the source copies; this checks what actually landed on the image. These files are the licence and source-code answer a customer gets, so an unfilled placeholder in one is a compliance defect rather than a typo.

The hook also refuses a SOURCE-OFFER.txt that reads like a GPLv2 §3(b) written offer — "write to:", "by post", "three years". The corresponding source is published, which is §3(a); a written offer would need a real postal address standing behind it for three years, and there is none.

2. /usr/share/vyos/EULA points at the Wheelhouse terms#

--build-type release makes vyos-build add an [[includes_chroot]] entry whose body is VyOS Inc.'s commercial end-user licence agreement, installed at /usr/share/vyos/EULA. The flavor cannot outrank it: list values are concatenated as source plus defaults, the flavor is merged last so its entries land first in the list, and the include loop lets the last entry for a path win. Changing the build type does not help, because the development build type carries the same file. The only way to displace it is to get in after the includes are written, which is what this hook is.

So the hook replaces the file with a symlink to ../doc/wheelhouse/TERMS.txt — replaces rather than deletes, because vyos-1x's show license pages that exact path and would otherwise break. It then checks the link resolves and that the target reads like the Wheelhouse terms.

Nothing in the GPL requires shipping another company's commercial EULA, and removing it strips no required notice: every notice is still on the image under /usr/share/doc.

3. /etc/os-release is ours#

sh
grep -q '^ID=wheelhouse$' /etc/os-release \
    || fail "/etc/os-release was not overridden by the flavor (see wheelhouse.toml)"

This is the safety net for the flavor's own override. If upstream ever moves the write or adds a competing entry, the image would otherwise report itself as VyOS to hostnamectl, monitoring agents and Ansible facts. The build fails instead.

The hook then copies /etc/os-release over /usr/lib/os-release through a temporary file, because Debian's /etc/os-release is normally a symlink to the /usr/lib copy and the include may have replaced the symlink with a regular file, leaving the other copy saying VyOS. The round trip is needed because copying a file onto itself would fail under set -e.

4. VyOS' Secure Boot certificate is removed#

build-vyos-image copies the whole of data/certificates into /var/lib/shim-signed/mok, which would put a VyOS trust anchor on every machine sold behind no signing story of our own. It is a public certificate rather than a key, and it is not enrolled in firmware, so this is hygiene rather than a hole — but it is a leftover, not a required notice. The files are removed and the directory kept, because a later upstream hook lists it.

The binary hook#

50-wheelhouse-brand.binary runs from lb binary_hooks with the binary tree as the working directory. That is the only stage late enough to reach everything, because live-build generates two of the three files:

FileWritten byCarries
boot/grub/grub.cfglive-build's binary_grub_cfgLive system (vyos)
isolinux/live.cfglive-build's binary_syslinuxThe same string
isolinux/menu.cfgbuild-vyos-image, arriving through binary_includesVyOS <version> (<flavor>)

A flavor [[includes_binary]] entry could fix the third alone; it cannot reach the two live-build generates. Hence a hook.

The 50- prefix is load-bearing. Hooks run in glob order, and upstream's 01-live-serial.binary rewrites the same lines first, appending " - KVM console" and " - Serial console" with regular expressions that still expect the upstream text. Running after it and replacing the bare substring is what lets those suffixes survive.

The replacements:

UpstreamWheelhouse
Live system (vyos)Install or run Wheelhouse
Live system (vyos fail-safe mode)Install or run Wheelhouse (fail-safe, verbose boot)
menu title …Wheelhouse <version>, read out of version.json

Every substitution is checked, and there is a final sweep:

sh
if grep -E '^[[:space:]]*(menu label|menuentry)' "${f}" | grep -qi vyos; then
    fail "a menu entry in ${f} still mentions VyOS"
fi

The internal syslinux labels (label live-vyos, live-vyos-serial) are not drawn on screen and are left alone, which is why the sweep looks only at the lines that are.

"verbose boot" is in the fail-safe label on purpose. build-iso.sh patches quiet into the normal live boot's kernel command line, so the fail-safe entry — which boots from upstream's --bootappend-live-failsafe, a line with no quiet on it — is the one that shows the messages. build-iso.sh fails the build if upstream ever adds quiet there and makes this label untrue.

A missing version in version.json is a warning rather than a failure — a menu headed just "Wheelhouse" is still ours.

Why the hooks assert at all#

Every one of these checks exists because a silent no-op would ship an image that says VyOS. The pattern is the same throughout the image pipeline: patch the file, then verify the patch took; stage the file, then verify it is there; override the identity, then assert the override won. An upstream change should break the build loudly, on the machine that can still do something about it.

See also#

Checked against#

packaging/iso/wheelhouse.toml · packaging/iso/build-iso.sh · packaging/iso/branding/50-wheelhouse-brand.chroot · packaging/iso/branding/50-wheelhouse-brand.binary · packaging/iso/branding/make-splash.py · packaging/iso/branding/doc/TERMS.txt · packaging/iso/branding/doc/THIRD-PARTY.txt · packaging/firstboot.sh

Updated 2026-09-02 development iso live-build vyos-build branding