|
82 | 82 | # VM Recipes |
83 | 83 | # ============================================ |
84 | 84 |
|
| 85 | +# Build qcow2 disk image using bootc install (fastest method for testing) |
| 86 | +[group('VM')] |
| 87 | +build-qcow2-fast: |
| 88 | + #!/usr/bin/bash |
| 89 | + set -euo pipefail |
| 90 | + |
| 91 | + LOCAL_IMAGE="localhost/{{ image_name }}:{{ fedora_version }}" |
| 92 | + OUTPUT_DIR="${PWD}/.vm" |
| 93 | + RAW_FILE="${OUTPUT_DIR}/{{ image_name }}.raw" |
| 94 | + QCOW2_FILE="${OUTPUT_DIR}/{{ image_name }}.qcow2" |
| 95 | + DISK_SIZE="64G" |
| 96 | + |
| 97 | + echo "Building qcow2 from ${LOCAL_IMAGE} using bootc install..." |
| 98 | + |
| 99 | + # Check if image exists |
| 100 | + if ! {{ PODMAN }} image exists "${LOCAL_IMAGE}"; then |
| 101 | + echo "Error: Image ${LOCAL_IMAGE} not found. Run 'just build' first." |
| 102 | + exit 1 |
| 103 | + fi |
| 104 | + |
| 105 | + mkdir -p "${OUTPUT_DIR}" |
| 106 | + |
| 107 | + # Remove existing disks to start fresh |
| 108 | + rm -f "${RAW_FILE}" "${QCOW2_FILE}" |
| 109 | + |
| 110 | + # Create a raw disk image (loopback works properly with raw) |
| 111 | + echo "Creating ${DISK_SIZE} raw disk image..." |
| 112 | + truncate -s "${DISK_SIZE}" "${RAW_FILE}" |
| 113 | + |
| 114 | + # Use bootc install to-disk from within the container |
| 115 | + # This is much faster than bootc-image-builder as it directly installs |
| 116 | + {{ SUDO }} {{ PODMAN }} run \ |
| 117 | + --rm \ |
| 118 | + -it \ |
| 119 | + --privileged \ |
| 120 | + --pid=host \ |
| 121 | + --security-opt label=type:unconfined_t \ |
| 122 | + -v /var/lib/containers/storage:/var/lib/containers/storage \ |
| 123 | + -v "${RAW_FILE}":/disk.raw \ |
| 124 | + -v /dev:/dev \ |
| 125 | + "${LOCAL_IMAGE}" \ |
| 126 | + bootc install to-disk --skip-fetch-check --generic-image --via-loopback --filesystem btrfs /disk.raw |
| 127 | + |
| 128 | + # Convert raw to qcow2 (sparse, much smaller) |
| 129 | + echo "Converting to qcow2..." |
| 130 | + qemu-img convert -f raw -O qcow2 "${RAW_FILE}" "${QCOW2_FILE}" |
| 131 | + rm -f "${RAW_FILE}" |
| 132 | + |
| 133 | + # Fix ownership |
| 134 | + if [[ "${UID}" -gt 0 ]]; then |
| 135 | + {{ SUDO }} chown "${UID}:$(id -g)" "${QCOW2_FILE}" |
| 136 | + fi |
| 137 | + |
| 138 | + echo "" |
| 139 | + echo "========================================" |
| 140 | + echo "qcow2 built: ${QCOW2_FILE}" |
| 141 | + echo "Run 'just run-qcow2' to test" |
| 142 | + echo "========================================" |
| 143 | + |
| 144 | +# Build qcow2 disk image using bootc-image-builder (slower, more options) |
| 145 | +[group('VM')] |
| 146 | +build-qcow2: |
| 147 | + #!/usr/bin/bash |
| 148 | + set -euo pipefail |
| 149 | + |
| 150 | + LOCAL_IMAGE="localhost/{{ image_name }}:{{ fedora_version }}" |
| 151 | + OUTPUT_DIR="${PWD}/.vm" |
| 152 | + QCOW2_FILE="${OUTPUT_DIR}/{{ image_name }}.qcow2" |
| 153 | + |
| 154 | + echo "Building qcow2 from ${LOCAL_IMAGE}..." |
| 155 | + |
| 156 | + # Check if image exists |
| 157 | + if ! {{ PODMAN }} image exists "${LOCAL_IMAGE}"; then |
| 158 | + echo "Error: Image ${LOCAL_IMAGE} not found. Run 'just build' first." |
| 159 | + exit 1 |
| 160 | + fi |
| 161 | + |
| 162 | + mkdir -p "${OUTPUT_DIR}" |
| 163 | + |
| 164 | + # Copy image to root storage if needed |
| 165 | + if [[ "${UID}" -gt 0 ]]; then |
| 166 | + echo "Copying image to root podman storage..." |
| 167 | + COPYTMP=$(mktemp -p "${PWD}" -d -t podman_scp.XXXXXXXXXX) |
| 168 | + {{ SUDO }} TMPDIR=${COPYTMP} {{ PODMAN }} image scp "${UID}@localhost::${LOCAL_IMAGE}" root@localhost::"${LOCAL_IMAGE}" |
| 169 | + rm -rf "${COPYTMP}" |
| 170 | + fi |
| 171 | + |
| 172 | + # Create cache directories for faster rebuilds |
| 173 | + CACHE_DIR="${PWD}/.cache/bootc-image-builder" |
| 174 | + mkdir -p "${CACHE_DIR}/store" "${CACHE_DIR}/rpmmd" |
| 175 | + |
| 176 | + # Build qcow2 using bootc-image-builder |
| 177 | + {{ SUDO }} {{ PODMAN }} run \ |
| 178 | + --rm \ |
| 179 | + -it \ |
| 180 | + --privileged \ |
| 181 | + --pull=newer \ |
| 182 | + --security-opt label=type:unconfined_t \ |
| 183 | + -v "${OUTPUT_DIR}":/output \ |
| 184 | + -v /var/lib/containers/storage:/var/lib/containers/storage \ |
| 185 | + -v "${CACHE_DIR}/store":/store \ |
| 186 | + -v "${CACHE_DIR}/rpmmd":/rpmmd \ |
| 187 | + quay.io/centos-bootc/bootc-image-builder:latest \ |
| 188 | + --type qcow2 \ |
| 189 | + --rootfs btrfs \ |
| 190 | + --use-librepo=True \ |
| 191 | + "${LOCAL_IMAGE}" |
| 192 | + |
| 193 | + # Fix ownership |
| 194 | + if [[ "${UID}" -gt 0 ]]; then |
| 195 | + {{ SUDO }} chown -R "${UID}:$(id -g)" "${OUTPUT_DIR}" |
| 196 | + fi |
| 197 | + |
| 198 | + # Move to expected location |
| 199 | + if [[ -f "${OUTPUT_DIR}/qcow2/disk.qcow2" ]]; then |
| 200 | + mv "${OUTPUT_DIR}/qcow2/disk.qcow2" "${QCOW2_FILE}" |
| 201 | + rm -rf "${OUTPUT_DIR}/qcow2" |
| 202 | + echo "" |
| 203 | + echo "========================================" |
| 204 | + echo "qcow2 built: ${QCOW2_FILE}" |
| 205 | + echo "Run 'just run-qcow2' to test" |
| 206 | + echo "========================================" |
| 207 | + else |
| 208 | + echo "Error: qcow2 build failed" |
| 209 | + exit 1 |
| 210 | + fi |
| 211 | + |
| 212 | +# Run qcow2 in VM with virt-manager |
| 213 | +[group('VM')] |
| 214 | +run-qcow2: |
| 215 | + #!/usr/bin/bash |
| 216 | + set -euo pipefail |
| 217 | + |
| 218 | + VM_NAME="hypercube-qcow2" |
| 219 | + QCOW2_FILE="${PWD}/.vm/{{ image_name }}.qcow2" |
| 220 | + |
| 221 | + if [[ ! -f "${QCOW2_FILE}" ]]; then |
| 222 | + echo "Error: qcow2 not found at ${QCOW2_FILE}" |
| 223 | + echo "Run 'just build-qcow2' first." |
| 224 | + exit 1 |
| 225 | + fi |
| 226 | + |
| 227 | + # RAM and CPU settings |
| 228 | + ram_size=16 |
| 229 | + vcpus=8 |
| 230 | + |
| 231 | + echo "VM: ${VM_NAME}" |
| 232 | + echo "Disk: ${QCOW2_FILE}" |
| 233 | + echo "RAM: ${ram_size}GB, vCPUs: ${vcpus}" |
| 234 | + |
| 235 | + # Check if VM already exists |
| 236 | + if virsh dominfo "${VM_NAME}" &>/dev/null; then |
| 237 | + echo "Starting existing VM..." |
| 238 | + virsh start "${VM_NAME}" 2>/dev/null || true |
| 239 | + virt-manager --connect qemu:///system --show-domain-console "${VM_NAME}" |
| 240 | + exit 0 |
| 241 | + fi |
| 242 | + |
| 243 | + echo "Creating new VM..." |
| 244 | + virt-install \ |
| 245 | + --name "${VM_NAME}" \ |
| 246 | + --memory $(( ram_size * 1024 )) \ |
| 247 | + --vcpus ${vcpus} \ |
| 248 | + --import \ |
| 249 | + --disk path="${QCOW2_FILE}",format=qcow2,bus=virtio \ |
| 250 | + --os-variant fedora-unknown \ |
| 251 | + --boot uefi \ |
| 252 | + --autoconsole graphical |
| 253 | + |
| 254 | +# Delete the qcow2 test VM |
| 255 | +[group('VM')] |
| 256 | +delete-qcow2-vm: |
| 257 | + #!/usr/bin/bash |
| 258 | + set -euo pipefail |
| 259 | + VM_NAME="hypercube-qcow2" |
| 260 | + |
| 261 | + echo "Stopping VM if running..." |
| 262 | + virsh destroy "${VM_NAME}" 2>/dev/null || true |
| 263 | + |
| 264 | + echo "Removing VM definition..." |
| 265 | + virsh undefine "${VM_NAME}" --nvram 2>/dev/null || true |
| 266 | + |
| 267 | + echo "qcow2 VM deleted (disk preserved in .vm/)" |
| 268 | + |
85 | 269 | # Run ISO in local VM with virt-manager (persistent disk for testing installs) |
86 | 270 | [group('VM')] |
87 | 271 | run-iso-local iso_file: |
@@ -228,11 +412,12 @@ build-iso-local: _titanoboa-setup |
228 | 412 | exit 1 |
229 | 413 | fi |
230 | 414 |
|
231 | | - # Cleanup function |
| 415 | + # Cleanup function (container has --rm so stop is enough) |
232 | 416 | cleanup() { |
233 | 417 | echo "Stopping local registry..." |
234 | | - {{ SUDO }} {{ PODMAN }} stop "${REGISTRY_NAME}" 2>/dev/null || true |
235 | | - {{ SUDO }} {{ PODMAN }} rm "${REGISTRY_NAME}" 2>/dev/null || true |
| 418 | + if {{ SUDO }} {{ PODMAN }} container exists "${REGISTRY_NAME}" 2>/dev/null; then |
| 419 | + {{ SUDO }} {{ PODMAN }} stop "${REGISTRY_NAME}" 2>/dev/null || : |
| 420 | + fi |
236 | 421 | } |
237 | 422 | trap cleanup EXIT |
238 | 423 |
|
@@ -297,6 +482,11 @@ build-iso-local: _titanoboa-setup |
297 | 482 | cleanup |
298 | 483 | trap - EXIT |
299 | 484 |
|
| 485 | + # Fix ownership of _titanoboa directory (must happen before mv) |
| 486 | + if [[ "${UID}" -gt 0 ]]; then |
| 487 | + {{ SUDO }} chown -R "${UID}:$(id -g)" "${PWD}" |
| 488 | + fi |
| 489 | + |
300 | 490 | # Move ISO to project root |
301 | 491 | if [[ -f "output.iso" ]]; then |
302 | 492 | mv output.iso "${PROJECT_ROOT}/${ISO_NAME}" |
|
0 commit comments