mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-08-13 07:36:52 +00:00
refactor(ci): customize cloud image on nested PVE instead of container
Move virt-customize to run on the nested PVE host (which already has libguestfs) instead of inside the CI container. This removes libguestfs-tools, linux-image-generic, and qemu-utils from the Dockerfile, shrinking the image from ~1.2GB to ~770MB. - prepare-test-vm.sh: downloads Debian cloud image on nested PVE, runs virt-customize there to install qemu-guest-agent, then creates VM with imported disk + cloud-init - Remove build-test-image.sh (no longer needed) - Remove /opt/pve-images volume mount Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -101,7 +101,6 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
volumes:
|
||||
- /opt/pve-isos:/opt/pve-isos
|
||||
- /opt/pve-images:/opt/pve-images
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
@@ -246,12 +245,6 @@ jobs:
|
||||
|
||||
# ── Prepare test Linux VM ────────────────────────────────────────
|
||||
|
||||
- name: Build Alpine test image (cached on host volume)
|
||||
if: inputs.skip_provision != true
|
||||
shell: bash
|
||||
run: |
|
||||
bash ${SCRIPTS_DIR}/build-test-image.sh /opt/pve-images/alpine-guest-agent.qcow2
|
||||
|
||||
- name: Deploy test Linux VM to nested PVE
|
||||
if: inputs.skip_provision != true
|
||||
id: linux_vm
|
||||
@@ -260,7 +253,6 @@ jobs:
|
||||
OUTPUT=$(bash ${SCRIPTS_DIR}/prepare-test-vm.sh \
|
||||
"${{ steps.provision.outputs.host }}" \
|
||||
"${PVE_PASSWORD}" \
|
||||
"/opt/pve-images/alpine-guest-agent.qcow2" \
|
||||
200)
|
||||
LINUX_VMID=$(echo "$OUTPUT" | grep "^LINUX_VMID=" | cut -d= -f2)
|
||||
echo "linux_vmid=${LINUX_VMID}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
@@ -15,9 +15,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
lsb-release \
|
||||
ca-certificates \
|
||||
python3 \
|
||||
libguestfs-tools \
|
||||
linux-image-generic \
|
||||
qemu-utils \
|
||||
xorriso \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -64,7 +61,5 @@ RUN echo "=== Tool verification ===" && \
|
||||
curl --version | head -1 && \
|
||||
jq --version && \
|
||||
python3 --version && \
|
||||
virt-customize --version && \
|
||||
ssh -V 2>&1 && \
|
||||
scp 2>&1 | head -1 || true && \
|
||||
echo "=== All tools verified ==="
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Builds a small Alpine Linux cloud image with qemu-guest-agent pre-installed.
|
||||
# The image is cached on the runner so it only needs to be built once.
|
||||
#
|
||||
# Prerequisites: libguestfs-tools (virt-customize), curl, qemu-utils
|
||||
# Install on Debian/Ubuntu: apt-get install -y libguestfs-tools curl qemu-utils
|
||||
#
|
||||
# Usage: build-test-image.sh <output-path>
|
||||
# e.g.: build-test-image.sh /opt/pve-images/alpine-guest-agent.qcow2
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
OUTPUT="${1:?Usage: build-test-image.sh <output-path>}"
|
||||
|
||||
# Skip if image already exists
|
||||
if [ -f "$OUTPUT" ]; then
|
||||
echo "Image already exists at $OUTPUT, skipping build"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ALPINE_VERSION="3.21"
|
||||
ALPINE_RELEASE="3.21.3"
|
||||
IMAGE_URL="https://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VERSION}/releases/cloud/nocloud_alpine-${ALPINE_RELEASE}-x86_64-bios-cloudinit-r0.qcow2"
|
||||
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
TEMP_IMAGE="${TEMP_DIR}/alpine-cloud.qcow2"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$TEMP_DIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "=== Building Alpine test image ==="
|
||||
echo "Downloading Alpine ${ALPINE_RELEASE} cloud image..."
|
||||
curl -sL -o "$TEMP_IMAGE" "$IMAGE_URL"
|
||||
|
||||
echo "Customizing image (installing qemu-guest-agent)..."
|
||||
# virt-customize modifies the image in place:
|
||||
# - Install qemu-guest-agent package
|
||||
# - Enable the service on boot (OpenRC)
|
||||
# - Ensure the virtio serial device is available for guest agent communication
|
||||
virt-customize -a "$TEMP_IMAGE" \
|
||||
--install qemu-guest-agent \
|
||||
--run-command 'rc-update add qemu-guest-agent default' \
|
||||
--run-command 'echo "GA_PATH=/dev/vport2p1" >> /etc/conf.d/qemu-guest-agent'
|
||||
|
||||
# Move to final location
|
||||
mkdir -p "$(dirname "$OUTPUT")"
|
||||
mv "$TEMP_IMAGE" "$OUTPUT"
|
||||
echo "Image ready at $OUTPUT ($(du -h "$OUTPUT" | cut -f1))"
|
||||
@@ -1,54 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
# Deploys the pre-built Alpine test image to a nested PVE instance and creates
|
||||
# a VM with guest agent enabled. Waits for the guest agent to respond.
|
||||
# Downloads a Debian cloud image, installs qemu-guest-agent via
|
||||
# virt-customize (which is already available on the nested PVE host),
|
||||
# creates a VM with the customized disk, and waits for the guest agent.
|
||||
#
|
||||
# The VM gets:
|
||||
# - The Alpine cloud image imported as its boot disk
|
||||
# - Cloud-init drive for initial configuration
|
||||
# - Guest agent enabled (agent=1)
|
||||
# - DHCP networking on vmbr0
|
||||
# All heavy lifting happens on the nested PVE via SSH — no libguestfs
|
||||
# or large dependencies needed in the CI container.
|
||||
#
|
||||
# Usage: prepare-test-vm.sh <nested-pve-ip> <root-password> <image-path> <vm-id>
|
||||
# Usage: prepare-test-vm.sh <nested-pve-ip> <root-password> <vm-id>
|
||||
#
|
||||
# Outputs (to stdout, for capture by caller):
|
||||
# LINUX_VMID=<vm-id>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
NESTED_IP="${1:?Usage: prepare-test-vm.sh <ip> <password> <image-path> <vm-id>}"
|
||||
NESTED_IP="${1:?Usage: prepare-test-vm.sh <ip> <password> <vm-id>}"
|
||||
ROOT_PASS="$2"
|
||||
IMAGE_PATH="$3"
|
||||
VMID="$4"
|
||||
VMID="$3"
|
||||
|
||||
CLOUD_IMAGE_URL="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2"
|
||||
|
||||
SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR"
|
||||
SSH_CMD="sshpass -p ${ROOT_PASS} ssh ${SSH_OPTS} root@${NESTED_IP}"
|
||||
SCP_CMD="sshpass -p ${ROOT_PASS} scp ${SSH_OPTS}"
|
||||
|
||||
echo "=== Preparing test Linux VM (VMID ${VMID}) on ${NESTED_IP} ==="
|
||||
|
||||
# Copy image to nested PVE
|
||||
echo "Uploading Alpine image to nested PVE..."
|
||||
${SCP_CMD} "${IMAGE_PATH}" "root@${NESTED_IP}:/tmp/alpine-test.qcow2"
|
||||
|
||||
# Create VM and import disk
|
||||
echo "Creating VM and importing disk..."
|
||||
# Download image, customize, create VM — all on the nested PVE
|
||||
echo "Downloading and customizing Debian cloud image on nested PVE..."
|
||||
${SSH_CMD} bash <<REMOTE
|
||||
set -e
|
||||
|
||||
# Create the VM shell
|
||||
# Download the cloud image
|
||||
echo "Downloading Debian cloud image..."
|
||||
curl -sL -o /tmp/debian-cloud.qcow2 "${CLOUD_IMAGE_URL}"
|
||||
|
||||
# Install qemu-guest-agent into the image using PVE's built-in libguestfs
|
||||
echo "Installing qemu-guest-agent into image..."
|
||||
virt-customize -a /tmp/debian-cloud.qcow2 \
|
||||
--install qemu-guest-agent \
|
||||
--run-command 'systemctl enable qemu-guest-agent'
|
||||
|
||||
# Create the VM
|
||||
echo "Creating VM ${VMID}..."
|
||||
qm create ${VMID} \
|
||||
--name alpine-test \
|
||||
--memory 256 \
|
||||
--name debian-test \
|
||||
--memory 512 \
|
||||
--cores 1 \
|
||||
--net0 virtio,bridge=vmbr0 \
|
||||
--agent 1 \
|
||||
--ostype l26 \
|
||||
--scsihw virtio-scsi-single
|
||||
|
||||
# Import the disk image to local-lvm
|
||||
qm importdisk ${VMID} /tmp/alpine-test.qcow2 local-lvm 2>&1 | tail -1
|
||||
# Import the customized disk
|
||||
echo "Importing disk..."
|
||||
qm importdisk ${VMID} /tmp/debian-cloud.qcow2 local-lvm 2>&1 | tail -1
|
||||
|
||||
# Attach the imported disk and configure boot
|
||||
# Attach disk and configure boot
|
||||
qm set ${VMID} \
|
||||
--scsi0 local-lvm:vm-${VMID}-disk-0 \
|
||||
--boot order=scsi0 \
|
||||
@@ -57,22 +63,23 @@ qm set ${VMID} \
|
||||
# Add cloud-init drive
|
||||
qm set ${VMID} --ide2 local-lvm:cloudinit
|
||||
|
||||
# Set cloud-init config (root user with password)
|
||||
# Set cloud-init config
|
||||
qm set ${VMID} \
|
||||
--ciuser root \
|
||||
--cipassword "${ROOT_PASS}" \
|
||||
--ipconfig0 ip=dhcp
|
||||
|
||||
# Start the VM
|
||||
echo "Starting VM ${VMID}..."
|
||||
qm start ${VMID}
|
||||
|
||||
# Clean up uploaded image
|
||||
rm -f /tmp/alpine-test.qcow2
|
||||
# Clean up
|
||||
rm -f /tmp/debian-cloud.qcow2
|
||||
REMOTE
|
||||
|
||||
# Wait for guest agent to respond
|
||||
echo "Waiting for guest agent on VM ${VMID}..."
|
||||
TIMEOUT=120
|
||||
TIMEOUT=180
|
||||
ELAPSED=0
|
||||
while [ $ELAPSED -lt $TIMEOUT ]; do
|
||||
if ${SSH_CMD} "qm agent ${VMID} ping" 2>/dev/null; then
|
||||
|
||||
Reference in New Issue
Block a user