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
12 changes: 12 additions & 0 deletions .github/actions/truenas-appliance-runner/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@
alike cannot give, such as a disk big enough to mirror the boot pool
onto. Not for an HA pair.
default: ''
spare-nics:
description: >-
NICs besides the one the API is reached on, 0 to 9, each alone on a
qemu hub: no DHCP, no route, nothing on the other end. For a suite to
apply interface changes on without cutting itself off. Their MACs,
52:54:00:e2:e0:01 and up, are in TN_SPARE_NICS. Not for an HA pair.

Check notice on line 77 in .github/actions/truenas-appliance-runner/action.yml

View workflow job for this annotation

GitHub Actions / claude-review / Automatic PR review

LOW: TN_SPARE_NICS reaches the caller only through GITHUB_ENV and has no action output, so with export-env 'false' the caller cannot read the spare NICs' MACs

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOW: The MACs only show up in TN_SPARE_NICS when export-env is 'true'. start prints the line, but the only thing that passes it on is grep '^TN_' >> "$GITHUB_ENV", and there's no action output for it the way ssh has one. A caller with export-env: 'false' and spare-nics: 1 gets the NIC but no way to read its MAC. This is the same as TN_DOMAIN and the other TN_* values that have no output, so it isn't a defect. The description could say it depends on export-env, or the action could add a spare-nics output.

default: '0'
ssh:
description: '`true` enables ssh for the admin, on TN_SSH.'
default: 'false'
Expand Down Expand Up @@ -114,6 +121,7 @@
APPLIANCE_DATA_DISKS: ${{ inputs.data-disk-count }}
APPLIANCE_DATA_DISK_GB: ${{ inputs.data-disk-gb }}
APPLIANCE_EXTRA_DISK_GB: ${{ inputs.extra-disk-gb }}
APPLIANCE_SPARE_NICS: ${{ inputs.spare-nics }}
APPLIANCE_SSH: ${{ inputs.ssh }}
APPLIANCE_DISK_INPUT: ${{ inputs.disk }}
EXPORT_ENV: ${{ inputs.export-env }}
Expand All @@ -128,6 +136,10 @@
echo "::error::extra-disk-gb is for one appliance; an HA pair has only the data-disk-count disks its nodes share"
exit 1
fi
if [ "$HA" = true ] && [ "${APPLIANCE_SPARE_NICS:-0}" != 0 ]; then
echo "::error::spare-nics is for one appliance; ha.sh wires an HA pair's NICs itself"
exit 1
fi
export APPLIANCE_DIR="$RUNNER_TEMP/truenas-appliance"
# The password is made here, so it is masked before anything can
# print it.
Expand Down
32 changes: 30 additions & 2 deletions .github/actions/truenas-appliance-runner/appliance.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
# APPLIANCE_DATA_DISKS 10 APPLIANCE_DATA_DISK_GB 10 (sparse)
# APPLIANCE_EXTRA_DISK_GB more sparse disks after those, one per size in
# GB, space-separated: "32", "12 12 15" (default none)
# APPLIANCE_SPARE_NICS 0: NICs after the one the API is reached on, each
# alone on a qemu hub of its own, so no DHCP, no
# route and no peer: for a suite to reconfigure
# without cutting itself off
# APPLIANCE_HTTP_PORT 8080 APPLIANCE_HTTPS_PORT 8443
# APPLIANCE_SSH_PORT 2222 APPLIANCE_SSH false
# APPLIANCE_BASELINE fresh-install: the snapshot start takes; empty
Expand All @@ -49,7 +53,8 @@
# start prints TN_PROFILE, TN_HOST (host:https port), TN_HOST_HTTP,
# TN_USERNAME, TN_PASSWORD, TN_DOMAIN, TN_BASELINE (the suite's contract,
# as the lab's claim action gives it, less its TN_GUEST_ISO), TN_SSH when
# APPLIANCE_SSH is true, and what it measured:
# APPLIANCE_SSH is true, TN_SPARE_NICS (the spare NICs' MAC addresses,
# space-separated) when there are any, and what it measured:
# APPLIANCE_BOOT_SECONDS, APPLIANCE_SNAPSHOT_SECONDS.

set -euo pipefail
Expand Down Expand Up @@ -101,6 +106,7 @@ start() {
local ndata="${APPLIANCE_DATA_DISKS:-10}" datagb="${APPLIANCE_DATA_DISK_GB:-10}"
local extragb=()
read -r -a extragb <<< "${APPLIANCE_EXTRA_DISK_GB:-}"
local nspare="${APPLIANCE_SPARE_NICS:-0}"
local http="${APPLIANCE_HTTP_PORT:-8080}" https="${APPLIANCE_HTTPS_PORT:-8443}" sshp="${APPLIANCE_SSH_PORT:-2222}"
local baseline="${APPLIANCE_BASELINE-fresh-install}"
local password="${APPLIANCE_PASSWORD:-$(head -c 15 /dev/urandom | base64 | tr -d '/+=')}"
Expand All @@ -111,6 +117,7 @@ start() {
for gb in "${extragb[@]}"; do
[[ "$gb" =~ ^[1-9][0-9]*$ ]] || die "APPLIANCE_EXTRA_DISK_GB: \"$gb\" is not a whole number of GB"
done
[[ "$nspare" =~ ^[0-9]$ ]] || die "APPLIANCE_SPARE_NICS: \"$nspare\" is not a number of NICs from 0 to 9"
needs qemu-system-x86_64 qemu-system-x86 qemu-img qemu-utils python3 python3
ovmf
local accel="${APPLIANCE_ACCEL:-kvm}" cpu=host
Expand Down Expand Up @@ -157,9 +164,26 @@ start() {
extrasaid=", and $nextra more of $(printf '%sG ' "${extragb[@]}")"
extrasaid="${extrasaid% }"
fi
# After the NIC the API is reached on, so that one keeps its PCI slot,
# and with it its name, whatever the count. Each on a hub with no other
# port: its link is up, and nothing ever answers on it. qemu warns
# "hub N is not connected to host network" for each, which is the
# point. The MACs are fixed, for a suite to tell these NICs apart by.
local nics=() spare_macs=()
for i in $(seq 1 "$nspare"); do
spare_macs+=("52:54:00:e2:e0:0$i")
nics+=(-netdev "hubport,id=spare$i,hubid=$i"
-device "virtio-net-pci,netdev=spare$i,mac=52:54:00:e2:e0:0$i")
done
local nicssaid=""
if [ "$nspare" -eq 1 ]; then
nicssaid=", 1 spare NIC"
elif [ "$nspare" -gt 1 ]; then
nicssaid=", $nspare spare NICs"
fi

local booted t0
say "booting $disk as $name: ${memory} MB, $vcpus vCPUs, $ndata data disks of ${datagb}G$extrasaid"
say "booting $disk as $name: ${memory} MB, $vcpus vCPUs, $ndata data disks of ${datagb}G$extrasaid$nicssaid"
t0=$(date +%s.%N)
qemu-system-x86_64 -name "$name" -machine "q35,accel=$accel" -cpu "$cpu" -smp "$vcpus" -m "$memory" \
-smbios "type=1,serial=$name" \
Expand All @@ -169,6 +193,7 @@ start() {
-device "virtio-blk-pci,drive=os,serial=os,bootindex=0" \
"${drives[@]}" \
-nic "user,model=virtio-net-pci$(hostfwd 80 "$http")$(hostfwd 443 "$https")$(hostfwd 22 "$sshp")" \
"${nics[@]}" \
-device virtio-rng-pci \
-qmp "unix:$QMP,server=on,wait=off" \
-display none -serial "file:$DIR/console.log" \
Expand Down Expand Up @@ -222,6 +247,9 @@ EOF
if [ "${APPLIANCE_SSH:-false}" = true ]; then
echo "TN_SSH=127.0.0.1:$sshp"
fi
if [ "$nspare" -gt 0 ]; then
echo "TN_SPARE_NICS=${spare_macs[*]}"
fi
}

snapshot() {
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ jobs:
| `memory-mb`, `vcpus` | `6144`, `4` | The appliance's; the runner's flavor needs room for it and the job |
| `data-disk-count`, `data-disk-gb` | `10`, `10` | Sparse qcow2 files |
| `extra-disk-gb` | none | More sparse disks after the data disks, one per size in GB: `'32'`, `'12 12 15'`. Not for an HA pair |
| `spare-nics` | `'0'` | NICs after the one the API is reached on, each alone on a qemu hub: no DHCP, no route. For applying interface changes without losing the appliance. MACs `52:54:00:e2:e0:01` and up, in `TN_SPARE_NICS`. Not for an HA pair |
| `ssh` | `'false'` | `true` enables ssh for the admin, on `TN_SSH` |
| `disk` | the attached one | Found by its serial, `virtio-truenas_appliance`, where the box keeps it; TrueNAS replaces it, so otherwise the one disk besides the root disk that holds a ZFS `boot-pool` |
| `export-env` | `'true'` | Write `TN_*` to the job environment |
Expand Down
Loading