mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2026-10-24 13:57:40 -05:00
Add a Debian 13 guest option to the RADIUS harness
LAB_GUEST_OS selects the Linux guest image: ubuntu (default) or debian. The Debian image is pinned to a date-stamped trixie genericcloud build with its SHA-512 from SHA512SUMS, and virt-install --os-variant is derived from the guest OS with a LAB_OS_VARIANT override for hosts whose osinfo database does not know debian13. user-data installs libelf1t64, which is the current package name on both Ubuntu 24.04 and Debian 13.
This commit is contained in:
1 parent
a14c6d1ded
commit
3e0c1f29f3
5 files changed
+160
-17
No files matched your search
@@ -0,0 +1,84 @@
|
||||
# Debian 13 Support Plan
|
||||
|
||||
Status: in progress (branch `debian13_support`)
|
||||
|
||||
## Goal
|
||||
|
||||
Run LibreQoS v2.2 on Debian 13 ("trixie") with the same support level the
|
||||
Ubuntu 24.04 path has today: buildable from source, installable as a `.deb`,
|
||||
and covered by the disposable RADIUS VM harness.
|
||||
|
||||
## Deliverables
|
||||
|
||||
1. `src/build_prereqs.sh` — shared, distro-aware build prerequisite helper.
|
||||
2. `src/build_rust_debian.sh` — Debian front-end for `build_rust.sh`.
|
||||
3. `src/build_pkg_debian.sh` — Debian front-end for `build_dpkg.sh`.
|
||||
4. `src/build_dpkg.sh` — runtime dependency fixes for Debian minimal installs.
|
||||
5. `radius-harness` — `LAB_GUEST_OS=debian` guest support with a pinned trixie image.
|
||||
6. Documentation updates (contributor docs now; operator docs after the VM run passes).
|
||||
|
||||
## Design decisions
|
||||
|
||||
- One implementation, two front-ends. `build_rust.sh` and `build_dpkg.sh` remain the
|
||||
source of truth; the Debian scripts export `LQOS_DISTRO=debian` and delegate. This
|
||||
keeps the paths from drifting, which AGENTS.md and the packaging skill call out as
|
||||
a recurring failure mode.
|
||||
- Distro detection is a fallback, not a requirement. `LQOS_DISTRO` overrides
|
||||
`/etc/os-release`, so the Debian scripts work on derivatives and on hosts where
|
||||
detection is ambiguous.
|
||||
- The packaging script is distro-neutral once the dependency fix lands. The Debian
|
||||
front-end pins the flavor, installs Debian prerequisites, and serves as the
|
||||
documented packaging entry point for Debian hosts.
|
||||
- Harness guest OS is a variable defaulting to Ubuntu, so the existing workflow does
|
||||
not change.
|
||||
|
||||
## Compatibility fixes in scope
|
||||
|
||||
### Build (currently broken on Debian)
|
||||
|
||||
| Problem | Fix |
|
||||
| --- | --- |
|
||||
| `linux-tools-common` and `linux-tools-$(uname -r)` do not exist in Debian, and `apt install` aborts the whole transaction when a name is unknown | Debian list installs `bpftool` (required by `lqos_sys/build.rs`) and `linux-perf` |
|
||||
| `make` and `pkg-config` are hard requirements of the vendored libbpf build and are not in the Ubuntu list | Add them to both distro lists |
|
||||
| `apt install` without `-y` in a scripted path | Use `apt-get install -y` |
|
||||
|
||||
### Packaging
|
||||
|
||||
| Problem | Fix |
|
||||
| --- | --- |
|
||||
| `lqosd` links `libelf.so.1`, `libssl.so.3`, `libzstd.so.1`, `libz.so.1`; a minimal Debian install may lack `libelf1t64` | Add `libelf1t64, libssl3t64, libzstd1, zlib1g` to `Depends` |
|
||||
| `lqos_setup` network apply requires netplan; Ubuntu ships it, Debian does not | `Recommends: netplan.io, ethtool` |
|
||||
|
||||
### Verified fine (no changes needed)
|
||||
|
||||
- Debian 13 kernel (cloud and generic): `CONFIG_DEBUG_INFO_BTF=y` for CO-RE, BPF/JIT/XDP/TC-BPF, `sch_cake=m`, veth/bridge/VLAN/virtio-net.
|
||||
- FreeRADIUS 3.2.7 still uses `/etc/freeradius/3.0`, so harness paths are unchanged.
|
||||
- `liblqos_python.so` is PyO3 `abi3-py310` and loads under Debian's Python 3.13; no removed-stdlib usage in `src/*.py`.
|
||||
- The Ubuntu systemd hotfix is inert on Debian (`is_supported_os` guard) and does not block the package postinst.
|
||||
- Host-built binaries run against trixie's glibc 2.41 and OpenSSL 3.5.
|
||||
|
||||
## Phases
|
||||
|
||||
- [ ] Phase 0: branch and this plan.
|
||||
- [ ] Phase 1: shared prerequisite helper and `build_rust_debian.sh`.
|
||||
- [ ] Phase 2: `build_dpkg.sh` dependency fixes and `build_pkg_debian.sh`.
|
||||
- [ ] Phase 3: harness Debian guest support (`lab.env`, `lab`, `user-data.yaml`, README).
|
||||
- [ ] Phase 4: static validation (`bash -n` on touched scripts, harness smoke checks).
|
||||
- [ ] Phase 5: VM validation: `lab init` / `up` / `configure` / `test` with `LAB_GUEST_OS=debian`.
|
||||
- [ ] Phase 6 (stretch): install a `build_pkg_debian.sh` artifact inside the Debian guest and re-run the lifecycle test.
|
||||
- [ ] Phase 7: operator docs and review agents (heckler, reaper, thomas, beck, jonas).
|
||||
|
||||
## Validation checklist
|
||||
|
||||
- `bash -n` passes for every touched script.
|
||||
- `LQOS_DISTRO` detection returns `ubuntu` on this host and `debian` under the override.
|
||||
- The harness image pin verifies against Debian's `SHA512SUMS`.
|
||||
- The Debian guest reaches the same three RADIUS lifecycle assertions as Ubuntu.
|
||||
- `lqosd` starts on the Debian guest and pins maps under `/sys/fs/bpf`.
|
||||
- The default Ubuntu harness path is unchanged (`LAB_GUEST_OS=ubuntu`).
|
||||
|
||||
## Risks and open questions
|
||||
|
||||
- Host `osinfo-db` may not know `debian13`; the `LAB_OS_VARIANT` override covers that.
|
||||
- The RouterOS console password step is interactive; the VM run needs an operator at `lab console` once.
|
||||
- Whether to declare Debian 13 supported in operator-facing docs is a product decision. This branch proves the technical path first.
|
||||
@@ -5,6 +5,10 @@ end: a RouterOS CHR NAS authenticates a PPPoE client with FreeRADIUS, sends
|
||||
accounting to a root-run LibreQoS guest, and the test verifies dynamic-circuit
|
||||
creation, profile selection, Interim-Update, and removal on disconnect.
|
||||
|
||||
The Linux guests default to Ubuntu 24.04. Set `LAB_GUEST_OS=debian` to run them
|
||||
on Debian 13 instead; the guest image and its checksum are pinned in
|
||||
[lab.env](lab.env).
|
||||
|
||||
It creates `radius-*` libvirt domains and networks, sparse qcow2 overlays, and
|
||||
temporary `vbr-r*` host-side bridge interfaces for its isolated networks.
|
||||
`./radius-harness/lab down` removes them with the overlays and VMs. `purge`
|
||||
@@ -29,7 +33,11 @@ firmware elsewhere, set `OVMF_CODE_PATH` and `OVMF_VARS_PATH` in the environment
|
||||
before `up`.
|
||||
|
||||
The pinned image hashes are in [lab.env](lab.env). Review and update the URL,
|
||||
version, and SHA-256 together when changing an image.
|
||||
version, and SHA-256 together when changing an image. Debian publishes SHA-512
|
||||
digests in `SHA512SUMS`, so the Debian image pins a SHA-512 value instead.
|
||||
|
||||
The harness builds the LibreQoS runtime bundle on the host and copies it into
|
||||
the guest, so the host toolchain must produce binaries the guest can run.
|
||||
|
||||
## Run
|
||||
|
||||
@@ -49,10 +57,14 @@ export RADIUS_SHARED_SECRET='a-lab-radius-secret'
|
||||
./radius-harness/lab down
|
||||
```
|
||||
|
||||
`init` downloads the pinned Ubuntu and RouterOS bases once and builds `lqosd`
|
||||
`init` downloads the pinned guest and RouterOS bases once and builds `lqosd`
|
||||
and `lqos_python` on the host. The guest receives only the resulting runtime
|
||||
bundle, not the Rust build tree.
|
||||
|
||||
To run the Linux guests on Debian 13 instead of Ubuntu, set
|
||||
`LAB_GUEST_OS=debian` before `init`. If the host osinfo database does not know
|
||||
`debian13`, set `LAB_OS_VARIANT=debian12` (or `generic`) as well.
|
||||
|
||||
The test covers three cases:
|
||||
|
||||
1. A RADIUS rate-limit attribute supplies the queue speed.
|
||||
|
||||
+49
-14
@@ -5,7 +5,28 @@ LAB_ROOT=$(cd -- "$(dirname -- "$0")" && pwd)
|
||||
source "$LAB_ROOT/lib/common.sh"
|
||||
source "$LAB_ROOT/lab.env"
|
||||
|
||||
readonly UBUNTU_BASE="$IMAGE_DIR/$(basename "$UBUNTU_IMAGE_URL")"
|
||||
GUEST_OS=${LAB_GUEST_OS:-ubuntu}
|
||||
case "$GUEST_OS" in
|
||||
ubuntu)
|
||||
GUEST_IMAGE_URL=$UBUNTU_IMAGE_URL
|
||||
GUEST_IMAGE_SHA256=$UBUNTU_IMAGE_SHA256
|
||||
GUEST_IMAGE_SHA512=
|
||||
DEFAULT_GUEST_OS_VARIANT=ubuntu24.04
|
||||
;;
|
||||
debian)
|
||||
GUEST_IMAGE_URL=$DEBIAN_IMAGE_URL
|
||||
GUEST_IMAGE_SHA256=
|
||||
GUEST_IMAGE_SHA512=$DEBIAN_IMAGE_SHA512
|
||||
DEFAULT_GUEST_OS_VARIANT=debian13
|
||||
;;
|
||||
*)
|
||||
die "unsupported LAB_GUEST_OS '$GUEST_OS'; expected ubuntu or debian"
|
||||
;;
|
||||
esac
|
||||
GUEST_OS_VARIANT=${LAB_OS_VARIANT:-$DEFAULT_GUEST_OS_VARIANT}
|
||||
|
||||
readonly GUEST_OS GUEST_IMAGE_URL GUEST_IMAGE_SHA256 GUEST_IMAGE_SHA512 GUEST_OS_VARIANT
|
||||
readonly GUEST_BASE="$IMAGE_DIR/$(basename "$GUEST_IMAGE_URL")"
|
||||
readonly ROUTER_ARCHIVE="$IMAGE_DIR/chr-$ROUTEROS_VERSION.img.zip"
|
||||
readonly ROUTER_BASE="$IMAGE_DIR/chr-$ROUTEROS_VERSION.qcow2"
|
||||
readonly SSH_KEY="$RUN_DIR/id_ed25519"
|
||||
@@ -17,11 +38,15 @@ usage() {
|
||||
Usage: ./radius-harness/lab <command>
|
||||
|
||||
Commands: init up status configure test down purge console
|
||||
|
||||
Environment:
|
||||
LAB_GUEST_OS Guest OS for the Linux VMs: ubuntu (default) or debian.
|
||||
LAB_OS_VARIANT Override the virt-install --os-variant value.
|
||||
EOF
|
||||
}
|
||||
|
||||
require_host_tools() {
|
||||
for tool in virsh virt-install qemu-img cloud-localds curl unzip sha256sum rsync ssh scp; do require_command "$tool"; done
|
||||
for tool in virsh virt-install qemu-img cloud-localds curl unzip sha256sum sha512sum rsync ssh scp; do require_command "$tool"; done
|
||||
}
|
||||
|
||||
ensure_ssh_key() {
|
||||
@@ -70,15 +95,25 @@ download_routeros() {
|
||||
fi
|
||||
}
|
||||
|
||||
download_ubuntu() {
|
||||
[[ -n ${UBUNTU_IMAGE_SHA256:-} ]] || die "set UBUNTU_IMAGE_SHA256 in lab.env before downloading Ubuntu"
|
||||
if [[ ! -f $UBUNTU_BASE ]]; then
|
||||
note "downloading Ubuntu 24.04 cloud image"
|
||||
curl --fail --location --output "$UBUNTU_BASE.partial" "$UBUNTU_IMAGE_URL"
|
||||
printf '%s %s\n' "$UBUNTU_IMAGE_SHA256" "$UBUNTU_BASE.partial" | sha256sum --check --status || die "Ubuntu image checksum did not match"
|
||||
mv "$UBUNTU_BASE.partial" "$UBUNTU_BASE"
|
||||
verify_guest_image() {
|
||||
local file=$1
|
||||
if [[ -n $GUEST_IMAGE_SHA256 ]]; then
|
||||
printf '%s %s\n' "$GUEST_IMAGE_SHA256" "$file" | sha256sum --check --status || die "guest image checksum did not match"
|
||||
elif [[ -n $GUEST_IMAGE_SHA512 ]]; then
|
||||
printf '%s %s\n' "$GUEST_IMAGE_SHA512" "$file" | sha512sum --check --status || die "guest image checksum did not match"
|
||||
else
|
||||
die "no checksum configured for guest image $(basename "$GUEST_IMAGE_URL")"
|
||||
fi
|
||||
printf '%s %s\n' "$UBUNTU_IMAGE_SHA256" "$UBUNTU_BASE" | sha256sum --check --status || die "cached Ubuntu image checksum did not match"
|
||||
}
|
||||
|
||||
download_guest_image() {
|
||||
if [[ ! -f $GUEST_BASE ]]; then
|
||||
note "downloading $GUEST_OS guest image $(basename "$GUEST_IMAGE_URL")"
|
||||
curl --fail --location --output "$GUEST_BASE.partial" "$GUEST_IMAGE_URL"
|
||||
verify_guest_image "$GUEST_BASE.partial"
|
||||
mv "$GUEST_BASE.partial" "$GUEST_BASE"
|
||||
fi
|
||||
verify_guest_image "$GUEST_BASE"
|
||||
}
|
||||
|
||||
build_runtime_bundle() {
|
||||
@@ -105,11 +140,11 @@ render_cloud_init() {
|
||||
install_linux_domain() {
|
||||
local name=$1 memory=$2 vcpus=$3 network_args=$4
|
||||
install -m 0644 "$OVMF_VARS" "$RUN_DIR/$name-vars.fd"
|
||||
virt-install --connect "$LIBVIRT_URI" --name "$name" --memory "$memory" --vcpus "$vcpus" --import --boot "loader=$OVMF_CODE,loader.type=pflash,loader.readonly=yes,loader.secure=no,nvram=$RUN_DIR/$name-vars.fd" --disk "path=$RUN_DIR/$name.qcow2,format=qcow2,bus=virtio" --disk "path=$RUN_DIR/$name-seed.iso,device=cdrom" --os-variant ubuntu24.04 --graphics vnc,listen=127.0.0.1 --noautoconsole $network_args
|
||||
virt-install --connect "$LIBVIRT_URI" --name "$name" --memory "$memory" --vcpus "$vcpus" --import --boot "loader=$OVMF_CODE,loader.type=pflash,loader.readonly=yes,loader.secure=no,nvram=$RUN_DIR/$name-vars.fd" --disk "path=$RUN_DIR/$name.qcow2,format=qcow2,bus=virtio" --disk "path=$RUN_DIR/$name-seed.iso,device=cdrom" --os-variant "$GUEST_OS_VARIANT" --graphics vnc,listen=127.0.0.1 --noautoconsole $network_args
|
||||
}
|
||||
|
||||
create_domains() {
|
||||
create_overlay "$LQOS_DOMAIN" "$UBUNTU_BASE" 8G; create_overlay "$RADIUS_DOMAIN" "$UBUNTU_BASE" 8G; create_overlay "$CLIENT_DOMAIN" "$UBUNTU_BASE" 8G; create_overlay "$ROUTER_DOMAIN" "$ROUTER_BASE"
|
||||
create_overlay "$LQOS_DOMAIN" "$GUEST_BASE" 8G; create_overlay "$RADIUS_DOMAIN" "$GUEST_BASE" 8G; create_overlay "$CLIENT_DOMAIN" "$GUEST_BASE" 8G; create_overlay "$ROUTER_DOMAIN" "$ROUTER_BASE"
|
||||
install_linux_domain "$LQOS_DOMAIN" 4096 2 "--network network=$MANAGEMENT_NETWORK,model=virtio,mac=52:54:00:10:00:10 --network network=$CONTROL_NETWORK,model=virtio,mac=52:54:00:10:00:11 --network network=$TRANSIT_NETWORK,model=virtio,mac=52:54:00:10:00:12"
|
||||
install_linux_domain "$RADIUS_DOMAIN" 512 1 "--network network=$MANAGEMENT_NETWORK,model=virtio,mac=52:54:00:20:00:10 --network network=$CONTROL_NETWORK,model=virtio,mac=52:54:00:20:00:11"
|
||||
install_linux_domain "$CLIENT_DOMAIN" 512 1 "--network network=$MANAGEMENT_NETWORK,model=virtio,mac=52:54:00:30:00:10 --network network=$ACCESS_NETWORK,model=virtio,mac=02:00:00:00:00:42"
|
||||
@@ -118,9 +153,9 @@ create_domains() {
|
||||
}
|
||||
|
||||
destroy_domain() { local name=$1; if domain_exists "$name"; then virsh_lab destroy "$name" >/dev/null 2>&1 || true; virsh_lab undefine "$name" --nvram >/dev/null 2>&1 || virsh_lab undefine "$name"; fi; }
|
||||
cmd_init() { require_host_tools; mkdir -p "$IMAGE_DIR" "$RUN_DIR"; download_ubuntu; download_routeros; build_runtime_bundle; note "lab bases and runtime bundle are ready"; }
|
||||
cmd_init() { require_host_tools; mkdir -p "$IMAGE_DIR" "$RUN_DIR"; download_guest_image; download_routeros; build_runtime_bundle; note "lab bases and runtime bundle are ready"; }
|
||||
cmd_up() {
|
||||
require_host_tools; resolve_ovmf; [[ -f $UBUNTU_BASE && -f $ROUTER_BASE && -x $RUNTIME_DIR/bin/lqosd ]] || die "run ./radius-harness/lab init first"; ensure_lab_stopped
|
||||
require_host_tools; resolve_ovmf; [[ -f $GUEST_BASE && -f $ROUTER_BASE && -x $RUNTIME_DIR/bin/lqosd ]] || die "run ./radius-harness/lab init first"; ensure_lab_stopped
|
||||
trap 'status=$?; trap - ERR; note "lab creation failed; removing partial resources"; cmd_down || true; exit "$status"' ERR
|
||||
safe_remove "$RUN_DIR"; mkdir -p "$RUN_DIR"; ensure_ssh_key
|
||||
for guest in lqos radius client; do cp "$LAB_ROOT/templates/$guest-network.yaml" "$RUN_DIR/$guest-network.yaml"; done
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# Guest OS for the Linux VMs: ubuntu (default) or debian.
|
||||
LAB_GUEST_OS=${LAB_GUEST_OS:-ubuntu}
|
||||
|
||||
# Optional override for the virt-install --os-variant value. Set this when the
|
||||
# host osinfo database does not know the guest release (for example debian13).
|
||||
# export LAB_OS_VARIANT=generic
|
||||
|
||||
# Pinned RouterOS long-term CHR release. Update version, URL, and SHA together.
|
||||
ROUTEROS_VERSION=7.21.5
|
||||
ROUTEROS_CHR_URL=https://download.mikrotik.com/routeros/7.21.5/chr-7.21.5.img.zip
|
||||
@@ -7,6 +14,11 @@ ROUTEROS_CHR_SHA256=dbb8f1739da73a68e5167fcbc731a5ba3d50f9d9b195731b96f96fcc5890
|
||||
UBUNTU_IMAGE_URL=https://cloud-images.ubuntu.com/releases/noble/release-20260518/ubuntu-24.04-server-cloudimg-amd64.img
|
||||
UBUNTU_IMAGE_SHA256=53fdde898feed8b027d94baa9cfe8229867f330a1d9c49dc7d84465ee7f229f7
|
||||
|
||||
# Pinned Debian 13 "trixie" genericcloud image. Debian publishes SHA-512
|
||||
# digests in SHA512SUMS; update the date-stamped URL and digest together.
|
||||
DEBIAN_IMAGE_URL=https://cloud.debian.org/images/cloud/trixie/20260914-2601/debian-13-genericcloud-amd64-20260914-2601.qcow2
|
||||
DEBIAN_IMAGE_SHA512=95e110dfcdbd0ed8a82a75ed9579802f9950cabf51a810dcc6388e81bc778188713878b9f28d583a0ea602fbf48b35996ae9ad37f584166d8fbd6489df248f53
|
||||
|
||||
# Set these before `./radius-harness/lab configure`; they are deliberately not
|
||||
# committed here:
|
||||
# export ROUTEROS_ADMIN_PASSWORD='choose-a-password'
|
||||
|
||||
@@ -7,6 +7,6 @@ users:
|
||||
ssh_authorized_keys:
|
||||
- __LAB_SSH_KEY__
|
||||
package_update: true
|
||||
packages: [libelf1, nftables, ppp, pppoe, python3-chardet, python3-deepdiff, python3-psutil, freeradius, freeradius-utils]
|
||||
packages: [libelf1t64, nftables, ppp, pppoe, python3-chardet, python3-deepdiff, python3-psutil, freeradius, freeradius-utils]
|
||||
runcmd:
|
||||
- systemctl disable --now freeradius || true
|
||||
Reference in new issue
Block a user