From a0cd640ffe49b14ea345bd7aabb97dc34616739f Mon Sep 17 00:00:00 2001 From: Guofang Date: Sun, 30 Aug 2026 22:41:05 +0800 Subject: [PATCH] Add Fedora 44 GNOME virtual machine --- README.md | 24 +++++ run-fedora44.sh | 153 ++++++++++++++++++++++++++++++++ seediso/README.md | 3 +- seediso/fedora44/.gitignore | 2 + seediso/fedora44/README.md | 14 +++ seediso/fedora44/build-seed.sh | 28 ++++++ seediso/fedora44/meta-data | 2 + seediso/fedora44/network-config | 10 +++ seediso/fedora44/user-data | 31 +++++++ vm-images | 2 +- 10 files changed, 267 insertions(+), 2 deletions(-) create mode 100755 run-fedora44.sh create mode 100644 seediso/fedora44/.gitignore create mode 100644 seediso/fedora44/README.md create mode 100755 seediso/fedora44/build-seed.sh create mode 100644 seediso/fedora44/meta-data create mode 100644 seediso/fedora44/network-config create mode 100644 seediso/fedora44/user-data diff --git a/README.md b/README.md index 829b892..dbe9428 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Start the required operating system with its distribution-specific launcher: ```bash ./run-debian13.sh ./run-almalinux10.sh +./run-fedora44.sh ./run-windows11.sh ``` @@ -71,6 +72,29 @@ 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`. +## Fedora 44 + +Start a Fedora 44 Cloud Base VM with: + +```bash +./run-fedora44.sh +``` + +The launcher downloads the `fedora44` image through the shared helper when it +is missing, creates `.vm/fedora44/disk.qcow2`, and builds its NoCloud seed from +`seediso/fedora44/`. SSH is forwarded to host port `2224` by default: + +```bash +ssh -p 2224 guofang@localhost +``` + +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` +for the complete list of overrides. + ## Windows 11 23H2 On first boot, the Windows 11 launcher creates a writable system-disk overlay diff --git a/run-fedora44.sh b/run-fedora44.sh new file mode 100755 index 0000000..072c3a0 --- /dev/null +++ b/run-fedora44.sh @@ -0,0 +1,153 @@ +#!/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/seediso/README.md b/seediso/README.md index afad59c..7590060 100644 --- a/seediso/README.md +++ b/seediso/README.md @@ -6,7 +6,8 @@ Each operating system has an independent NoCloud configuration and generated ```text seediso/ ├── debian13/ -└── almalinux10/ +├── almalinux10/ +└── fedora44/ ``` Keeping per-OS metadata separate allows each VM to use a distinct hostname and diff --git a/seediso/fedora44/.gitignore b/seediso/fedora44/.gitignore new file mode 100644 index 0000000..0115591 --- /dev/null +++ b/seediso/fedora44/.gitignore @@ -0,0 +1,2 @@ +seed.iso +*.iso diff --git a/seediso/fedora44/README.md b/seediso/fedora44/README.md new file mode 100644 index 0000000..5b7f1f7 --- /dev/null +++ b/seediso/fedora44/README.md @@ -0,0 +1,14 @@ +# 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 +GNOME package group and reboots the guest. + +After changing `user-data`, `meta-data`, or `network-config`, remove the old +`seed.iso` and rebuild it: + +```bash +./seediso/fedora44/build-seed.sh +``` + +Use a unique `instance-id` when cloning this configuration for another VM. diff --git a/seediso/fedora44/build-seed.sh b/seediso/fedora44/build-seed.sh new file mode 100755 index 0000000..72d89fc --- /dev/null +++ b/seediso/fedora44/build-seed.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +output="${1:-${script_dir}/seed.iso}" +files=(user-data meta-data) + +mkdir -p "$(dirname -- "$output")" +if [[ -f "${script_dir}/network-config" ]]; then + files+=(network-config) +fi + +if command -v cloud-localds >/dev/null 2>&1; then + args=() + [[ -f "${script_dir}/network-config" ]] && args+=(--network-config="${script_dir}/network-config") + cloud-localds "${args[@]}" "$output" "${script_dir}/user-data" "${script_dir}/meta-data" +elif command -v xorriso >/dev/null 2>&1; then + xorriso -as mkisofs -quiet -volid cidata -joliet -rock -output "$output" "${files[@]/#/${script_dir}/}" +elif command -v genisoimage >/dev/null 2>&1; then + genisoimage -quiet -output "$output" -volid cidata -joliet -rock "${files[@]/#/${script_dir}/}" +elif command -v mkisofs >/dev/null 2>&1; then + mkisofs -quiet -output "$output" -volid cidata -joliet -rock "${files[@]/#/${script_dir}/}" +else + printf 'Error: install cloud-image-utils, xorriso, genisoimage, or mkisofs.\n' >&2 + exit 1 +fi + +printf 'Created %s\n' "$output" diff --git a/seediso/fedora44/meta-data b/seediso/fedora44/meta-data new file mode 100644 index 0000000..9f3fa38 --- /dev/null +++ b/seediso/fedora44/meta-data @@ -0,0 +1,2 @@ +instance-id: fedora44-host-001 +local-hostname: fedora44-host diff --git a/seediso/fedora44/network-config b/seediso/fedora44/network-config new file mode 100644 index 0000000..fa9a6d7 --- /dev/null +++ b/seediso/fedora44/network-config @@ -0,0 +1,10 @@ +version: 2 +ethernets: + all-en: + match: + name: "en*" + dhcp4: true + all-eth: + match: + name: "eth*" + dhcp4: true diff --git a/seediso/fedora44/user-data b/seediso/fedora44/user-data new file mode 100644 index 0000000..0427cee --- /dev/null +++ b/seediso/fedora44/user-data @@ -0,0 +1,31 @@ +#cloud-config +preserve_hostname: false +manage_etc_hosts: true +ssh_pwauth: true + +users: + - name: guofang + gecos: Guofang + groups: [wheel] + shell: /bin/bash + sudo: "ALL=(ALL) NOPASSWD: ALL" + lock_passwd: false + hashed_passwd: $6$0NtCERV3eO12t9oJ$nlFE2sSc66nFfuD5X0xMnOla1cuzOnHfeGNRY5X7dCDHg.WzWVmuRe7M17Puj44.eCWLnJAWt4WNjd9vP9X0D0 + +chpasswd: + expire: false + +package_update: true + +packages: + - "@gnome-desktop" + +runcmd: + - [systemctl, set-default, graphical.target] +# - [systemctl, enable, gdm.service] + +power_state: + delay: now + mode: reboot + message: "GNOME installation completed; rebooting into graphical mode." + condition: true diff --git a/vm-images b/vm-images index 04c0109..d2b4606 160000 --- a/vm-images +++ b/vm-images @@ -1 +1 @@ -Subproject commit 04c0109baae421d59e79e6b5489aa209192f8686 +Subproject commit d2b46066d4557e6e7f58fd9391ddea86658a47fb