From 3561fc672950b27efc792e3a19791042b008b5c6 Mon Sep 17 00:00:00 2001 From: Guofang Date: Wed, 30 Sep 2026 09:22:40 +0800 Subject: [PATCH] Remove shell VM launchers in favor of the Python ones Delete run-*.sh and point the documentation at run-*.py. The seediso build-seed.sh helpers stay, as the Python launchers call them. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01HL6bzSwWGNwru9bDS9ZCLg --- README.md | 34 +++--- run-almalinux10.py | 2 +- run-almalinux10.sh | 169 ------------------------------ run-debian13.py | 2 +- run-debian13.sh | 167 ----------------------------- run-fedora44.py | 2 +- run-fedora44.sh | 153 --------------------------- run-windows11.py | 2 +- run-windows11.sh | 192 ---------------------------------- seediso/almalinux10/README.md | 2 +- seediso/debian13/README.md | 2 +- seediso/fedora44/README.md | 2 +- 12 files changed, 24 insertions(+), 705 deletions(-) delete mode 100755 run-almalinux10.sh delete mode 100755 run-debian13.sh delete mode 100755 run-fedora44.sh delete mode 100755 run-windows11.sh diff --git a/README.md b/README.md index a9b7825..5692b80 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ Start the required operating system with its distribution-specific launcher: ```bash -./run-debian13.sh -./run-almalinux10.sh -./run-fedora44.sh -./run-windows11.sh +./run-debian13.py +./run-almalinux10.py +./run-fedora44.py +./run-windows11.py ``` All virtual machines use OVMF/UEFI firmware. Each launcher creates a private, @@ -16,16 +16,16 @@ Closing the QEMU window stops a foreground VM. To keep the launcher in the background while still showing the graphical window: ```bash -./run-debian13.sh --daemon +./run-debian13.py --daemon ``` -The script uses KVM when `/dev/kvm` is accessible, forwards host port `2222` +The launcher uses KVM when `/dev/kvm` is accessible, forwards host port `2222` to guest port `22`, and creates `.vm/debian13/disk.qcow2` as a 20G writable overlay with the original qcow2 image as its backing file. The base image therefore stays unchanged. Resource settings can be overridden with environment variables; -run `./run-debian13.sh --help` for the full list. +run `./run-debian13.py --help` for the full list. -The Python launchers (`run-*.py`) accept `--state-dir DIR` to keep +The launchers accept `--state-dir DIR` to keep the VM disk, seed ISO, UEFI variables, PID file and console log in `DIR` instead of the default `.vm//`. The option takes precedence over the corresponding `*_STATE_DIR` environment variable: @@ -58,7 +58,7 @@ helper with `debian13`. Start an AlmaLinux 10 Generic Cloud VM with: ```bash -./run-almalinux10.sh +./run-almalinux10.py ``` When the shared AlmaLinux image is missing, the launcher calls the selected @@ -73,10 +73,10 @@ ssh -p 2223 guofang@localhost AlmaLinux settings use the `ALMA_VM_` prefix. For example: ```bash -ALMA_VM_MEMORY=4G ALMA_VM_CPUS=4 ALMA_VM_SSH_PORT=2224 ./run-almalinux10.sh +ALMA_VM_MEMORY=4G ALMA_VM_CPUS=4 ALMA_VM_SSH_PORT=2224 ./run-almalinux10.py ``` -Run `./run-almalinux10.sh --help` for all supported settings. The seed ISO is +Run `./run-almalinux10.py --help` for all supported settings. The seed ISO is stored alongside the VM disk at `.vm/almalinux10/seed.iso`. If it already exists after editing its source files, rebuild it explicitly with `./seediso/almalinux10/build-seed.sh .vm/almalinux10/seed.iso`. @@ -86,7 +86,7 @@ exists after editing its source files, rebuild it explicitly with Start a Fedora 44 Cloud Base VM with: ```bash -./run-fedora44.sh +./run-fedora44.py ``` The launcher downloads the `fedora44` image through the shared helper when it @@ -101,7 +101,7 @@ On the first boot, cloud-init updates package metadata and installs Fedora's GNOME package group through its native package module, then reboots the guest. Keep the VM running until this initial installation and reboot have completed. -Fedora settings use the `FEDORA_VM_` prefix. Run `./run-fedora44.sh --help` +Fedora settings use the `FEDORA_VM_` prefix. Run `./run-fedora44.py --help` for the complete list of overrides. ## Windows 11 23H2 @@ -110,7 +110,7 @@ On first boot, the Windows 11 launcher creates a writable system-disk overlay from the shared Windows 11 QCOW2 base image: ```bash -./run-windows11.sh +./run-windows11.py ``` It creates a persistent 64G disk at `.vm/windows11/disk.qcow2`, automatically @@ -126,15 +126,15 @@ exposes the vdagent channel for host/guest clipboard integration and the QEMU Gu The generated answer-file ISO is stored beside the disk as `.vm/windows11/seed.iso`. -To install from the Windows ISO instead, use `./run-windows11.sh +To install from the Windows ISO instead, use `./run-windows11.py --install-from-iso`. This choice only applies while creating a missing system disk; subsequent starts always boot the existing system disk normally. During ISO installation, the launcher resolves its tools ISO through the shared image helper and downloads it when missing. Override the base QCOW2, source ISO, tools ISO, resources, RDP port, or SSH port with the `WIN11_VM_` environment -variables shown by `./run-windows11.sh --help`. For example, when the VirtIO ISO +variables shown by `./run-windows11.py --help`. For example, when the VirtIO ISO is elsewhere: ```bash -WIN11_VM_TOOLS_ISO=/custom/path/virtio-win.iso ./run-windows11.sh --install-from-iso +WIN11_VM_TOOLS_ISO=/custom/path/virtio-win.iso ./run-windows11.py --install-from-iso ``` diff --git a/run-almalinux10.py b/run-almalinux10.py index 7c48969..0b90477 100755 --- a/run-almalinux10.py +++ b/run-almalinux10.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Start the AlmaLinux 10 virtual machine (Python port of run-almalinux10.sh).""" +"""Start the AlmaLinux 10 virtual machine.""" import os import platform diff --git a/run-almalinux10.sh b/run-almalinux10.sh deleted file mode 100755 index e770845..0000000 --- a/run-almalinux10.sh +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" -if [[ -n "${VM_IMAGE_HELPER:-}" ]]; then - image_downloader="$VM_IMAGE_HELPER" -elif [[ -x "${script_dir}/vm-images/download-images.sh" ]]; then - image_downloader="${script_dir}/vm-images/download-images.sh" -else - image_downloader="${script_dir}/../vm-images/download-images.sh" -fi -uses_shared_base_image=false -if [[ -n "${ALMA_VM_BASE_IMAGE:-}" ]]; then - base_image="$ALMA_VM_BASE_IMAGE" -else - [[ -x "$image_downloader" ]] || { printf 'Error: shared image helper is unavailable: %s\n' "$image_downloader" >&2; exit 1; } - base_image="$("$image_downloader" --print-path almalinux10)" - uses_shared_base_image=true -fi -state_dir="${ALMA_VM_STATE_DIR:-${script_dir}/.vm/almalinux10}" -disk_image="${ALMA_VM_DISK_IMAGE:-${state_dir}/disk.qcow2}" -seed_image="${ALMA_VM_SEED_IMAGE:-$(dirname -- "$disk_image")/seed.iso}" -disk_size="${ALMA_VM_DISK_SIZE:-20G}" -memory="${ALMA_VM_MEMORY:-8G}" -cpus="${ALMA_VM_CPUS:-8}" -ssh_port="${ALMA_VM_SSH_PORT:-2223}" -uefi_code="${ALMA_VM_UEFI_CODE:-/usr/share/OVMF/OVMF_CODE_4M.fd}" -uefi_vars_template="${ALMA_VM_UEFI_VARS:-/usr/share/OVMF/OVMF_VARS_4M.fd}" -uefi_vars="${state_dir}/OVMF_VARS_4M.fd" -pid_file="${state_dir}/qemu.pid" -log_file="${state_dir}/console.log" -daemonize=false -extra_args=() - -usage() { - cat <&2 - usage >&2 - exit 2 - ;; - esac -done - -for command_name in qemu-system-x86_64 qemu-img; do - if ! command -v "$command_name" >/dev/null 2>&1; then - printf 'Error: %s is not installed.\n' "$command_name" >&2 - exit 1 - fi -done - -if [[ ! -f "$base_image" ]]; then - if [[ "$uses_shared_base_image" == true ]]; then - "$image_downloader" almalinux10 - else - printf 'Error: AlmaLinux base image was not found: %s\n' "$base_image" >&2 - exit 1 - fi -fi -[[ -f "$base_image" ]] || { printf 'Error: downloader did not create: %s\n' "$base_image" >&2; exit 1; } -for firmware_file in "$uefi_code" "$uefi_vars_template"; do - [[ -f "$firmware_file" ]] || { printf 'Error: required UEFI firmware was not found: %s\n' "$firmware_file" >&2; exit 1; } -done - -if [[ ! -f "$seed_image" ]]; then - seed_builder="${script_dir}/seediso/almalinux10/build-seed.sh" - if [[ ! -x "$seed_builder" ]]; then - printf 'Error: seed image is missing and builder is unavailable: %s\n' \ - "$seed_builder" >&2 - exit 1 - fi - printf 'Seed image not found; building %s...\n' "$seed_image" - "$seed_builder" "$seed_image" -fi - -mkdir -p "$state_dir" -[[ -f "$uefi_vars" ]] || cp -- "$uefi_vars_template" "$uefi_vars" - -if [[ -f "$pid_file" ]]; then - old_pid="$(<"$pid_file")" - if [[ "$old_pid" =~ ^[0-9]+$ ]] && kill -0 "$old_pid" 2>/dev/null; then - printf 'Error: the AlmaLinux virtual machine is already running (PID %s).\n' \ - "$old_pid" >&2 - exit 1 - fi - rm -f "$pid_file" -fi - -if [[ ! -f "$disk_image" ]]; then - qemu-img create -q -f qcow2 -F qcow2 -b "$base_image" "$disk_image" "$disk_size" - printf 'Created writable disk overlay: %s\n' "$disk_image" -fi - -qemu_args=( - -name almalinux10 - -machine q35 - -display gtk - -m "$memory" - -smp "$cpus" - -drive "if=pflash,format=raw,readonly=on,file=${uefi_code}" - -drive "if=pflash,format=raw,file=${uefi_vars}" - -drive "file=${disk_image},if=virtio,format=qcow2" - -drive "file=${seed_image},media=cdrom,readonly=on" - -nic "user,model=virtio-net-pci,hostfwd=tcp::${ssh_port}-:22" -) - -if [[ -r /dev/kvm && -w /dev/kvm ]]; then - qemu_args+=(-enable-kvm -cpu host) - accelerator=KVM -else - qemu_args+=(-accel tcg -cpu max) - accelerator=TCG -fi - -printf 'Starting AlmaLinux 10 with %s acceleration; SSH is forwarded to localhost:%s.\n' \ - "$accelerator" "$ssh_port" - -if [[ "$daemonize" == true ]]; then - : >"$log_file" - qemu_args+=( - -serial "file:${log_file}" - -monitor none - -daemonize - -pidfile "$pid_file" - ) - qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}" - printf 'VM started (PID %s); console log: %s\n' "$(<"$pid_file")" "$log_file" -else - exec qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}" -fi diff --git a/run-debian13.py b/run-debian13.py index b336b0b..7caede1 100755 --- a/run-debian13.py +++ b/run-debian13.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Start the Debian 13 virtual machine (Python port of run-debian13.sh).""" +"""Start the Debian 13 virtual machine.""" import os import platform diff --git a/run-debian13.sh b/run-debian13.sh deleted file mode 100755 index 0439d38..0000000 --- a/run-debian13.sh +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" -if [[ -n "${VM_IMAGE_HELPER:-}" ]]; then - image_downloader="$VM_IMAGE_HELPER" -elif [[ -x "${script_dir}/vm-images/download-images.sh" ]]; then - image_downloader="${script_dir}/vm-images/download-images.sh" -else - image_downloader="${script_dir}/../vm-images/download-images.sh" -fi -uses_shared_base_image=false -if [[ -n "${VM_BASE_IMAGE:-}" ]]; then - base_image="$VM_BASE_IMAGE" -else - [[ -x "$image_downloader" ]] || { printf 'Error: shared image helper is unavailable: %s\n' "$image_downloader" >&2; exit 1; } - base_image="$("$image_downloader" --print-path debian13)" - uses_shared_base_image=true -fi -state_dir="${VM_STATE_DIR:-${script_dir}/.vm/debian13}" -disk_image="${VM_DISK_IMAGE:-${state_dir}/disk.qcow2}" -seed_image="${VM_SEED_IMAGE:-$(dirname -- "$disk_image")/seed.iso}" -disk_size="${VM_DISK_SIZE:-20G}" -memory="${VM_MEMORY:-8G}" -cpus="${VM_CPUS:-8}" -ssh_port="${VM_SSH_PORT:-2222}" -uefi_code="${VM_UEFI_CODE:-/usr/share/OVMF/OVMF_CODE_4M.fd}" -uefi_vars_template="${VM_UEFI_VARS:-/usr/share/OVMF/OVMF_VARS_4M.fd}" -uefi_vars="${state_dir}/OVMF_VARS_4M.fd" -pid_file="${state_dir}/qemu.pid" -log_file="${state_dir}/console.log" -daemonize=false -extra_args=() - -usage() { - cat <&2 - usage >&2 - exit 2 - ;; - esac -done - -for command_name in qemu-system-x86_64 qemu-img; do - if ! command -v "$command_name" >/dev/null 2>&1; then - printf 'Error: %s is not installed.\n' "$command_name" >&2 - exit 1 - fi -done - -if [[ ! -f "$base_image" ]]; then - if [[ "$uses_shared_base_image" == true ]]; then - "$image_downloader" debian13 - else - printf 'Error: Debian base image was not found: %s\n' "$base_image" >&2 - exit 1 - fi -fi -[[ -f "$base_image" ]] || { printf 'Error: downloader did not create: %s\n' "$base_image" >&2; exit 1; } -for firmware_file in "$uefi_code" "$uefi_vars_template"; do - [[ -f "$firmware_file" ]] || { printf 'Error: required UEFI firmware was not found: %s\n' "$firmware_file" >&2; exit 1; } -done - -if [[ ! -f "$seed_image" ]]; then - seed_builder="${script_dir}/seediso/debian13/build-seed.sh" - if [[ ! -x "$seed_builder" ]]; then - printf 'Error: seed image is missing and builder is unavailable: %s\n' \ - "$seed_builder" >&2 - exit 1 - fi - printf 'Seed image not found; building %s...\n' "$seed_image" - "$seed_builder" "$seed_image" -fi - -mkdir -p "$state_dir" -[[ -f "$uefi_vars" ]] || cp -- "$uefi_vars_template" "$uefi_vars" - -if [[ -f "$pid_file" ]]; then - old_pid="$(<"$pid_file")" - if [[ "$old_pid" =~ ^[0-9]+$ ]] && kill -0 "$old_pid" 2>/dev/null; then - printf 'Error: the virtual machine is already running (PID %s).\n' "$old_pid" >&2 - exit 1 - fi - rm -f "$pid_file" -fi - -if [[ ! -f "$disk_image" ]]; then - qemu-img create -q -f qcow2 -F qcow2 -b "$base_image" "$disk_image" "$disk_size" - printf 'Created writable disk overlay: %s\n' "$disk_image" -fi - -qemu_args=( - -name debian13 - -machine q35 - -display gtk - -m "$memory" - -smp "$cpus" - -drive "if=pflash,format=raw,readonly=on,file=${uefi_code}" - -drive "if=pflash,format=raw,file=${uefi_vars}" - -drive "file=${disk_image},if=virtio,format=qcow2" - -drive "file=${seed_image},media=cdrom,readonly=on" - -nic "user,model=virtio-net-pci,hostfwd=tcp::${ssh_port}-:22" -) - -if [[ -r /dev/kvm && -w /dev/kvm ]]; then - qemu_args+=(-enable-kvm -cpu host) - accelerator=KVM -else - qemu_args+=(-accel tcg -cpu max) - accelerator=TCG -fi - -printf 'Starting VM with %s acceleration; SSH is forwarded to localhost:%s.\n' \ - "$accelerator" "$ssh_port" - -if [[ "$daemonize" == true ]]; then - : >"$log_file" - qemu_args+=( - -serial "file:${log_file}" - -monitor none - -daemonize - -pidfile "$pid_file" - ) - qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}" - printf 'VM started (PID %s); console log: %s\n' "$(<"$pid_file")" "$log_file" -else - exec qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}" -fi diff --git a/run-fedora44.py b/run-fedora44.py index 0fb385a..a2ad359 100755 --- a/run-fedora44.py +++ b/run-fedora44.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Start the Fedora 44 virtual machine (Python port of run-fedora44.sh).""" +"""Start the Fedora 44 virtual machine.""" import os import platform diff --git a/run-fedora44.sh b/run-fedora44.sh deleted file mode 100755 index 072c3a0..0000000 --- a/run-fedora44.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" -if [[ -n "${VM_IMAGE_HELPER:-}" ]]; then - image_downloader="$VM_IMAGE_HELPER" -elif [[ -x "${script_dir}/vm-images/download-images.sh" ]]; then - image_downloader="${script_dir}/vm-images/download-images.sh" -else - image_downloader="${script_dir}/../vm-images/download-images.sh" -fi -uses_shared_base_image=false -if [[ -n "${FEDORA_VM_BASE_IMAGE:-}" ]]; then - base_image="$FEDORA_VM_BASE_IMAGE" -else - [[ -x "$image_downloader" ]] || { printf 'Error: shared image helper is unavailable: %s\n' "$image_downloader" >&2; exit 1; } - base_image="$("$image_downloader" --print-path fedora44)" - uses_shared_base_image=true -fi -state_dir="${FEDORA_VM_STATE_DIR:-${script_dir}/.vm/fedora44}" -disk_image="${FEDORA_VM_DISK_IMAGE:-${state_dir}/disk.qcow2}" -seed_image="${FEDORA_VM_SEED_IMAGE:-$(dirname -- "$disk_image")/seed.iso}" -disk_size="${FEDORA_VM_DISK_SIZE:-20G}" -memory="${FEDORA_VM_MEMORY:-8G}" -cpus="${FEDORA_VM_CPUS:-8}" -ssh_port="${FEDORA_VM_SSH_PORT:-2224}" -uefi_code="${FEDORA_VM_UEFI_CODE:-/usr/share/OVMF/OVMF_CODE_4M.fd}" -uefi_vars_template="${FEDORA_VM_UEFI_VARS:-/usr/share/OVMF/OVMF_VARS_4M.fd}" -uefi_vars="${state_dir}/OVMF_VARS_4M.fd" -pid_file="${state_dir}/qemu.pid" -log_file="${state_dir}/console.log" -daemonize=false -extra_args=() - -usage() { - cat <&2; usage >&2; exit 2 ;; - esac -done - -for command_name in qemu-system-x86_64 qemu-img; do - if ! command -v "$command_name" >/dev/null 2>&1; then - printf 'Error: %s is not installed.\n' "$command_name" >&2 - exit 1 - fi -done - -if [[ ! -f "$base_image" ]]; then - if [[ "$uses_shared_base_image" == true ]]; then - "$image_downloader" fedora44 - else - printf 'Error: Fedora base image was not found: %s\n' "$base_image" >&2 - exit 1 - fi -fi -[[ -f "$base_image" ]] || { printf 'Error: downloader did not create: %s\n' "$base_image" >&2; exit 1; } -for firmware_file in "$uefi_code" "$uefi_vars_template"; do - [[ -f "$firmware_file" ]] || { printf 'Error: required UEFI firmware was not found: %s\n' "$firmware_file" >&2; exit 1; } -done - -if [[ ! -f "$seed_image" ]]; then - seed_builder="${script_dir}/seediso/fedora44/build-seed.sh" - if [[ ! -x "$seed_builder" ]]; then - printf 'Error: seed image is missing and builder is unavailable: %s\n' "$seed_builder" >&2 - exit 1 - fi - printf 'Seed image not found; building %s...\n' "$seed_image" - "$seed_builder" "$seed_image" -fi - -mkdir -p "$state_dir" -[[ -f "$uefi_vars" ]] || cp -- "$uefi_vars_template" "$uefi_vars" - -if [[ -f "$pid_file" ]]; then - old_pid="$(<"$pid_file")" - if [[ "$old_pid" =~ ^[0-9]+$ ]] && kill -0 "$old_pid" 2>/dev/null; then - printf 'Error: the Fedora virtual machine is already running (PID %s).\n' "$old_pid" >&2 - exit 1 - fi - rm -f "$pid_file" -fi - -if [[ ! -f "$disk_image" ]]; then - qemu-img create -q -f qcow2 -F qcow2 -b "$base_image" "$disk_image" "$disk_size" - printf 'Created writable disk overlay: %s\n' "$disk_image" -fi - -qemu_args=( - -name fedora44 - -machine q35 - -display gtk - -m "$memory" - -smp "$cpus" - -drive "if=pflash,format=raw,readonly=on,file=${uefi_code}" - -drive "if=pflash,format=raw,file=${uefi_vars}" - -drive "file=${disk_image},if=virtio,format=qcow2" - -drive "file=${seed_image},media=cdrom,readonly=on" - -nic "user,model=virtio-net-pci,hostfwd=tcp::${ssh_port}-:22" -) - -if [[ -r /dev/kvm && -w /dev/kvm ]]; then - qemu_args+=(-enable-kvm -cpu host) - accelerator=KVM -else - qemu_args+=(-accel tcg -cpu max) - accelerator=TCG -fi - -printf 'Starting Fedora 44 with %s acceleration; SSH is forwarded to localhost:%s.\n' \ - "$accelerator" "$ssh_port" - -if [[ "$daemonize" == true ]]; then - : >"$log_file" - qemu_args+=( - -serial "file:${log_file}" - -monitor none - -daemonize - -pidfile "$pid_file" - ) - qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}" - printf 'VM started (PID %s); console log: %s\n' "$(<"$pid_file")" "$log_file" -else - exec qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}" -fi diff --git a/run-windows11.py b/run-windows11.py index 156acec..3dea4d4 100755 --- a/run-windows11.py +++ b/run-windows11.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Start the Windows 11 virtual machine (Python port of run-windows11.sh).""" +"""Start the Windows 11 virtual machine.""" import os import platform diff --git a/run-windows11.sh b/run-windows11.sh deleted file mode 100755 index c16c61d..0000000 --- a/run-windows11.sh +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" -state_dir="${WIN11_VM_STATE_DIR:-${script_dir}/.vm/windows11}" -disk_image="${WIN11_VM_DISK_IMAGE:-${state_dir}/disk.qcow2}" -seed_iso="${WIN11_VM_SEED_ISO:-$(dirname -- "$disk_image")/seed.iso}" -disk_size="${WIN11_VM_DISK_SIZE:-64G}" -memory="${WIN11_VM_MEMORY:-8G}" -cpus="${WIN11_VM_CPUS:-8}" -rdp_port="${WIN11_VM_RDP_PORT:-3389}" -ssh_port="${WIN11_VM_SSH_PORT:-2222}" -uefi_code="${WIN11_VM_UEFI_CODE:-/usr/share/OVMF/OVMF_CODE_4M.fd}" -uefi_vars_template="${WIN11_VM_UEFI_VARS:-/usr/share/OVMF/OVMF_VARS_4M.fd}" -uefi_vars="${state_dir}/OVMF_VARS_4M.fd" -pid_file="${state_dir}/qemu.pid" -log_file="${state_dir}/console.log" -monitor_socket="${state_dir}/qemu-monitor.sock" -guest_agent_socket="${state_dir}/qemu-guest-agent.sock" -daemonize=false -install_from_iso=false -extra_args=() - -usage() { - cat <&2; usage >&2; exit 2 ;; - esac -done - -installing=false -if [[ ! -f "$disk_image" ]]; then - installing=true - if [[ -n "${VM_IMAGE_HELPER:-}" ]]; then - image_downloader="$VM_IMAGE_HELPER" - elif [[ -x "${script_dir}/vm-images/download-images.sh" ]]; then - image_downloader="${script_dir}/vm-images/download-images.sh" - else - image_downloader="${script_dir}/../vm-images/download-images.sh" - fi - [[ -x "$image_downloader" ]] || { printf 'Error: shared image helper is unavailable: %s\n' "$image_downloader" >&2; exit 1; } - if [[ "$install_from_iso" == true ]]; then - install_iso="${WIN11_VM_INSTALL_ISO:-$("$image_downloader" --print-path windows11 --iso)}" - uses_shared_tools_iso=false - if [[ -n "${WIN11_VM_TOOLS_ISO:-}" ]]; then - tools_iso="$WIN11_VM_TOOLS_ISO" - else - tools_iso="$("$image_downloader" --print-path virtio-win)" - uses_shared_tools_iso=true - fi - else - base_image="${WIN11_VM_BASE_IMAGE:-$("$image_downloader" --print-path windows11)}" - fi -fi - -for command_name in qemu-system-x86_64; do - command -v "$command_name" >/dev/null 2>&1 || { printf 'Error: %s is not installed.\n' "$command_name" >&2; exit 1; } -done -if [[ "$installing" == true ]]; then - command -v qemu-img >/dev/null 2>&1 || { printf 'Error: qemu-img is not installed.\n' >&2; exit 1; } - if [[ "$install_from_iso" == true ]]; then - [[ -f "$install_iso" ]] || { printf 'Error: Windows 11 ISO was not found: %s\n' "$install_iso" >&2; exit 1; } - else - [[ -f "$base_image" ]] || { printf 'Error: Windows 11 base QCOW2 image was not found: %s\n' "$base_image" >&2; exit 1; } - fi -fi -for firmware_file in "$uefi_code" "$uefi_vars_template"; do - [[ -f "$firmware_file" ]] || { printf 'Error: required UEFI firmware was not found: %s\n' "$firmware_file" >&2; exit 1; } -done - -mkdir -p "$state_dir" -if [[ "$installing" == true && "$install_from_iso" == true ]]; then - if [[ ! -f "$tools_iso" ]]; then - if [[ "$uses_shared_tools_iso" == true ]]; then - "$image_downloader" virtio-win - else - printf 'Error: VirtIO Windows tools ISO was not found: %s\n' "$tools_iso" >&2 - exit 1 - fi - fi - [[ -f "$tools_iso" ]] || { printf 'Error: downloader did not create: %s\n' "$tools_iso" >&2; exit 1; } - - if [[ ! -f "$seed_iso" || - "${script_dir}/seediso/windows11/Autounattend.xml" -nt "$seed_iso" || - "${script_dir}/seediso/windows11/Configure-Windows.ps1" -nt "$seed_iso" ]]; then - "${script_dir}/seediso/windows11/build-seed.sh" "$seed_iso" - fi -fi -if [[ -f "$pid_file" ]]; then - old_pid="$(<"$pid_file")" - if [[ "$old_pid" =~ ^[0-9]+$ ]] && kill -0 "$old_pid" 2>/dev/null; then - printf 'Error: Windows 11 VM is already running (PID %s).\n' "$old_pid" >&2 - exit 1 - fi - rm -f "$pid_file" -fi -rm -f "$monitor_socket" "$guest_agent_socket" -[[ -f "$uefi_vars" ]] || cp -- "$uefi_vars_template" "$uefi_vars" -if [[ "$installing" == true ]]; then - if [[ "$install_from_iso" == true ]]; then - qemu-img create -q -f qcow2 "$disk_image" "$disk_size" - else - qemu-img create -q -f qcow2 -F qcow2 -b "$base_image" "$disk_image" "$disk_size" - fi - printf 'Created Windows 11 system disk: %s\n' "$disk_image" -fi - -qemu_args=( - -name windows11 -machine q35 -m "$memory" -smp "$cpus" - -display gtk - # -display none -spice port=5900,addr=127.0.0.1,disable-ticketing=on,agent-mouse=off -device virtio-vga - -drive "if=pflash,format=raw,readonly=on,file=${uefi_code}" - -drive "if=pflash,format=raw,file=${uefi_vars}" - -drive "file=${disk_image},if=none,id=system_disk,format=qcow2" - -device "ide-hd,drive=system_disk,bus=ide.0,bootindex=1" - -nic "user,model=e1000e,hostfwd=tcp::${rdp_port}-:3389,hostfwd=tcp::${ssh_port}-:22" - -device "virtio-serial-pci,id=virtio_serial" - -chardev "qemu-vdagent,id=vdagent,name=vdagent,clipboard=on,mouse=off" - -device "virtserialport,chardev=vdagent,name=com.redhat.spice.0" - # Register the USB tablet after vdagent so QEMU selects it as the active pointer. - -device "qemu-xhci,id=usb_controller" -device "usb-tablet,bus=usb_controller.0" - -chardev "socket,path=${guest_agent_socket},server=on,wait=off,id=qga" - -device "virtserialport,chardev=qga,name=org.qemu.guest_agent.0" - -monitor "unix:${monitor_socket},server=on,wait=off" -) -if [[ "$installing" == true && "$install_from_iso" == true ]]; then - qemu_args+=( - -drive "file=${install_iso},if=none,id=install_media,media=cdrom,readonly=on" - -device "ide-cd,drive=install_media,bus=ide.1,bootindex=2" - -drive "file=${seed_iso},if=none,id=answer_media,media=cdrom,readonly=on" - -device "ide-cd,drive=answer_media,bus=ide.2,bootindex=3" - -drive "file=${tools_iso},if=none,id=tools_media,media=cdrom,readonly=on" - -device "ide-cd,drive=tools_media,bus=ide.3,bootindex=4" - ) -fi -if [[ -r /dev/kvm && -w /dev/kvm ]]; then - qemu_args+=(-enable-kvm -cpu host) - accelerator=KVM -else - qemu_args+=(-accel tcg -cpu max) - accelerator=TCG -fi -if [[ "$installing" == true && "$install_from_iso" == true ]]; then - printf 'Starting Windows 11 automatic installation with %s acceleration.\n' "$accelerator" -elif [[ "$installing" == true ]]; then - printf 'Starting Windows 11 from the QCOW2 base image with %s acceleration.\n' "$accelerator" -else - printf 'Starting Windows 11 normally with %s acceleration.\n' "$accelerator" -fi -printf 'Account: guofang / password; RDP: localhost:%s; SSH: localhost:%s\n' "$rdp_port" "$ssh_port" - -if [[ "$daemonize" == true ]]; then - : >"$log_file" - qemu_args+=(-serial "file:${log_file}" -daemonize -pidfile "$pid_file") - qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}" - printf 'VM started (PID %s); console log: %s\n' "$(<"$pid_file")" "$log_file" -else - exec qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}" -fi diff --git a/seediso/almalinux10/README.md b/seediso/almalinux10/README.md index 8c2316e..eb5ec03 100644 --- a/seediso/almalinux10/README.md +++ b/seediso/almalinux10/README.md @@ -1,7 +1,7 @@ # AlmaLinux 10 seed.iso This directory contains the cloud-init NoCloud configuration used by -`run-almalinux10.sh`. +`run-almalinux10.py`. After changing `user-data`, `meta-data`, or `network-config`, remove the old `seed.iso` and rebuild it: diff --git a/seediso/debian13/README.md b/seediso/debian13/README.md index 9f12dab..a59a909 100644 --- a/seediso/debian13/README.md +++ b/seediso/debian13/README.md @@ -1,7 +1,7 @@ # Debian 13 seed.iso This directory contains the cloud-init NoCloud configuration used by -`run-debian13.sh`. +`run-debian13.py`. 1. Edit `user-data`, `meta-data`, and (if needed) `network-config`. 2. Build the image: diff --git a/seediso/fedora44/README.md b/seediso/fedora44/README.md index 5b7f1f7..f55cfe8 100644 --- a/seediso/fedora44/README.md +++ b/seediso/fedora44/README.md @@ -1,7 +1,7 @@ # Fedora 44 seed.iso This directory contains the cloud-init NoCloud configuration used by -`run-fedora44.sh`. On first boot, cloud-init's package module installs Fedora's +`run-fedora44.py`. On first boot, cloud-init's package module installs Fedora's GNOME package group and reboots the guest. After changing `user-data`, `meta-data`, or `network-config`, remove the old