Skip to content

Commit 4b04ee1

Browse files
committed
feat: lima VM testing
1 parent 8553d32 commit 4b04ee1

File tree

4 files changed

+195
-5
lines changed

4 files changed

+195
-5
lines changed

Justfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,15 +221,32 @@ build-all-experimental:
221221

222222
qcow2 variant flavor='base' repo='local':
223223
#!/usr/bin/env bash
224+
set -euo pipefail
224225
if [ "{{ flavor }}" != "base" ]; then
225226
FLAVOR="-{{ flavor }}"
226227
else
227228
FLAVOR=
228229
fi
229230
if [ "{{ repo }}" = "ghcr" ]; then bash ./scripts/build-bootc-diskimage.sh qcow2 ghcr.io/{{ repo_organization }}/{{ variant }}$FLAVOR:{{ default_tag }}
230231
elif [ "{{ repo }}" = "local" ]; then bash ./scripts/build-bootc-diskimage.sh qcow2 localhost/{{ variant }}$FLAVOR:{{ default_tag }}
232+
else echo "DEBUG: repo '{{ repo }}' did not match ghcr or local"; exit 1
231233
fi
232234

235+
test-vm variant flavor='base':
236+
#!/usr/bin/env bash
237+
set -euo pipefail
238+
bash ./scripts/test-vm.sh {{ variant }} {{ flavor }}
239+
240+
debug-vm variant flavor='base' repo='local':
241+
#!/usr/bin/env bash
242+
set -euo pipefail
243+
if [ "{{ repo }}" == "local" ]; then
244+
{{ just }} build {{ variant }} {{ flavor }}
245+
fi
246+
{{ just }} qcow2 {{ variant }} {{ flavor }} {{ repo }}
247+
{{ just }} test-vm {{ variant }} {{ flavor }}
248+
249+
233250
iso variant flavor='base' repo='local' hook_script='iso_files/configure_lts_iso_anaconda.sh' flatpaks_file='system_files/etc/ublue-os/system-flatpaks.list':
234251
#!/usr/bin/env bash
235252
bash ./scripts/build-titanoboa.sh {{ variant }} {{ flavor }} {{ repo }} {{ hook_script }}

scripts/build-bootc-diskimage.sh

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#!/bin/bash
2+
set -euo pipefail
23
# This script is merely a wrapper for bootc-image-builder
34

5+
# Check if running with root privileges
46
# Check if running with root privileges
57
if [ "$EUID" -ne 0 ]; then
6-
echo "Please run as root"
7-
exit
8+
echo "Elevating privileges with sudo..."
9+
exec sudo "$0" "$@"
810
fi
911

1012
# Check if an argument is provided
@@ -53,6 +55,29 @@ else
5355
name = "centos"
5456
password = "centos"
5557
groups = ["wheel"]
58+
EOF
59+
60+
# Try to find an SSH key to inject
61+
SSH_KEY=""
62+
# If running under sudo, finding the real user's home
63+
if [ -n "${SUDO_USER:-}" ]; then
64+
USER_HOME=$(getent passwd "$SUDO_USER" | cut -d: -f6)
65+
else
66+
USER_HOME="$HOME"
67+
fi
68+
69+
if [ -f "$USER_HOME/.ssh/id_ed25519.pub" ]; then
70+
SSH_KEY=$(cat "$USER_HOME/.ssh/id_ed25519.pub")
71+
elif [ -f "$USER_HOME/.ssh/id_rsa.pub" ]; then
72+
SSH_KEY=$(cat "$USER_HOME/.ssh/id_rsa.pub")
73+
fi
74+
75+
if [ -n "$SSH_KEY" ]; then
76+
echo "key = \"$SSH_KEY\"" >> "$TMPDIR/$TOML_FILE"
77+
echo "Injected SSH key for user centos"
78+
fi
79+
80+
cat <<EOF >>"$TMPDIR/$TOML_FILE"
5681
5782
[[customizations.filesystem]]
5883
mountpoint = "/"
@@ -65,13 +90,14 @@ cat "$TMPDIR/$TOML_FILE"
6590
echo ""
6691

6792
echo "Pulling image: $IMAGE_URI"
68-
sudo podman pull "$IMAGE_URI"
93+
podman pull "$IMAGE_URI"
6994

7095
# Run the bootc-image-builder command
7196
echo "Running bootc-image-builder..."
72-
podman run --rm -it --privileged \
97+
podman run --rm -it --privileged --pid=host \
7398
-v "$TMPDIR/output":/output:z \
7499
-v /var/lib/containers/storage:/var/lib/containers/storage \
100+
-v /dev:/dev \
75101
-v "$TMPDIR/$TOML_FILE":/config.toml \
76102
quay.io/centos-bootc/bootc-image-builder:latest \
77103
build --type "$TYPE" \
@@ -83,7 +109,18 @@ IMAGE_NAME=$(echo "$IMAGE_URI" | awk -F'/' '{print $NF}' | awk -F':' '{print $1}
83109
file=$(find "$TMPDIR/output" -type f -name "*.$TYPE")
84110
if [ -f "$file" ]; then
85111
mv "$file" "./${IMAGE_NAME}.$TYPE"
86-
chown "$(id -u):$(id -g)" "./${IMAGE_NAME}.$TYPE"
112+
113+
# Determine target UID/GID for ownership check
114+
# Determine target UID/GID for ownership check
115+
if [ -n "${SUDO_UID:-}" ]; then
116+
TARGET_UID="$SUDO_UID"
117+
TARGET_GID="$SUDO_GID"
118+
else
119+
TARGET_UID="0"
120+
TARGET_GID="0"
121+
fi
122+
123+
chown "${TARGET_UID}:${TARGET_GID}" "./${IMAGE_NAME}.$TYPE"
87124
echo "Image created: ${IMAGE_NAME}.$TYPE"
88125
else
89126
echo "ERROR: Image was not created."

scripts/test-vm.sh

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
# Usage: ./scripts/test-vm.sh <variant> <flavor>
5+
# Example: ./scripts/test-vm.sh yellowfin base
6+
7+
if [ "$#" -ne 2 ]; then
8+
echo "Usage: $0 <variant> <flavor>"
9+
echo "Example: $0 yellowfin base"
10+
exit 1
11+
fi
12+
13+
VARIANT="$1"
14+
FLAVOR="$2"
15+
16+
# Determine Architecture
17+
ARCH=$(uname -m)
18+
if [ "$ARCH" == "arm64" ]; then
19+
LIMA_ARCH="aarch64"
20+
else
21+
LIMA_ARCH="x86_64"
22+
fi
23+
24+
# Construct Image Name
25+
# Matches logic in build-bootc-diskimage.sh / Justfile
26+
# Expected: <variant>[-<flavor>].qcow2
27+
if [ "$FLAVOR" == "base" ]; then
28+
IMAGE_FILENAME="${VARIANT}.qcow2"
29+
VM_NAME="tuna-${VARIANT}"
30+
else
31+
IMAGE_FILENAME="${VARIANT}-${FLAVOR}.qcow2"
32+
VM_NAME="tuna-${VARIANT}-${FLAVOR}"
33+
fi
34+
35+
IMAGE_PATH="$(pwd)/${IMAGE_FILENAME}"
36+
37+
if [ ! -f "$IMAGE_PATH" ]; then
38+
echo "Error: Image not found at $IMAGE_PATH"
39+
echo "Please build the image first (e.g., 'just qcow2 $VARIANT $FLAVOR')"
40+
exit 1
41+
fi
42+
43+
if ! command -v limactl &> /dev/null; then
44+
echo "Error: limactl is not installed."
45+
echo "Please install Lima (https://lima-vm.io/)"
46+
exit 1
47+
fi
48+
49+
echo "--- Preparing Test VM ---"
50+
echo "VM Name: $VM_NAME"
51+
echo "Image: $IMAGE_PATH"
52+
echo "Arch: $LIMA_ARCH"
53+
54+
# Cleanup existing VM
55+
if limactl list -q | grep -q "^${VM_NAME}$"; then
56+
echo "Stopping and deleting existing VM: $VM_NAME"
57+
limactl stop -f "$VM_NAME" 2>/dev/null || true
58+
limactl delete "$VM_NAME"
59+
fi
60+
61+
# Generate Config
62+
TEMPLATE_FILE="tests/lima-template.yaml"
63+
CONFIG_FILE="$(mktemp)"
64+
cp "$TEMPLATE_FILE" "$CONFIG_FILE"
65+
66+
# Replace placeholders
67+
# Use | as delimiter to handle paths with slashes
68+
sed -i "s|__IMAGE_PATH__|$IMAGE_PATH|g" "$CONFIG_FILE"
69+
sed -i "s|__ARCH__|$LIMA_ARCH|g" "$CONFIG_FILE"
70+
71+
echo "Starting VM..."
72+
# Start the VM. We use --tty=false to avoid stealing the terminal if running via just
73+
limactl start --name="$VM_NAME" --tty=false "$CONFIG_FILE"
74+
75+
echo "VM Started!"
76+
77+
# Get VNC Port
78+
# Try strictly parsing the JSON stream (redirecting stderr to /dev/null to avoid WARN logs breaking jq)
79+
VNC_DISPLAY=$(limactl list --json 2>/dev/null | jq -r "select(.name==\"$VM_NAME\") | .video.vnc.display")
80+
81+
# Fallback: check the vncdisplay file directly
82+
if [ -z "$VNC_DISPLAY" ] || [ "$VNC_DISPLAY" == "null" ]; then
83+
VNC_FILE="$HOME/.lima/$VM_NAME/vncdisplay"
84+
if [ -f "$VNC_FILE" ]; then
85+
VNC_DISPLAY=$(cat "$VNC_FILE")
86+
fi
87+
fi
88+
89+
if [ -n "$VNC_DISPLAY" ] && [ "$VNC_DISPLAY" != "null" ]; then
90+
echo "VNC listening at: $VNC_DISPLAY"
91+
92+
# Handle the "127.0.0.1:0,to=9" format (extract everything before comma)
93+
VNC_DISPLAY=${VNC_DISPLAY%%,*}
94+
95+
# Try to open VNC viewer
96+
if command -v xdg-open &> /dev/null; then
97+
echo "Opening Default VNC Viewer..."
98+
xdg-open "vnc://$VNC_DISPLAY" || echo "Failed to open VNC viewer automatically."
99+
elif command -v open &> /dev/null; then
100+
# macOS
101+
echo "Opening Screen Sharing..."
102+
open "vnc://$VNC_DISPLAY" || echo "Failed to open VNC viewer automatically."
103+
else
104+
echo "Could not detect tool to open VNC URI. Please connect manually to $VNC_DISPLAY"
105+
fi
106+
else
107+
echo "Could not determine VNC display address."
108+
fi
109+
110+
echo "---"
111+
echo "To access shell: limactl shell $VM_NAME"
112+
echo "To stop: limactl stop $VM_NAME"

tests/lima-template.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Lima configuration for TunaOS Testing
2+
# This file is a template. The placeholder __IMAGE_PATH__ will be replaced by the test script.
3+
4+
images:
5+
# location is the absolute path to the qcow2 image
6+
- location: "__IMAGE_PATH__"
7+
arch: "__ARCH__"
8+
9+
# Enable VNC
10+
video:
11+
display: "vnc"
12+
13+
# Use the default user 'centos' with password 'centos' (as defined in build-bootc-diskimage.sh)
14+
# Lima will try to inject its own keys, but since we are booting a pre-built image
15+
# without cloud-init (unless we add it), we rely on the baked-in credentials or
16+
# if the image has cloud-init enabled, lima can handle it.
17+
# Our current bootc build might not have cloud-init fully set up for Lima,
18+
# so we might need to rely on the console/VNC or SSH if keys are injected.
19+
# For now, we assume the user will log in via VNC or SSH if configured.
20+
21+
# SSH Configuration
22+
# We attempt to rely on standard Lima key injection if cloud-init is present.
23+
# If not, 'limactl shell' might fail to connect automatically, but the VM will run.
24+

0 commit comments

Comments
 (0)