diff --git a/.gitignore b/.gitignore index e8d9b53..7746d5a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -# QEMU runtime state and writable overlays -.vm +# QEMU runtime state and writable overlays (vm/ in the repository root) +/vm/ # VM disk and generated installation/seed images *.qcow2 diff --git a/README.md b/README.md index cf41101..164f085 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ background while still showing the graphical window: ``` 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 +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. Run `./run-debian13.py --help` for the supported environment variables. @@ -32,14 +32,14 @@ architecture-specific devices are in `qemu/debian13--.ini` (os `linux` or `darwin`, arch `amd64` or `arm64`), together with the accelerators. Edit these files to change the settings. The launcher fills in the `${...}` file path placeholders of `qemu/debian13.ini`, -writes the result to `.vm/debian13/qemu.ini` and starts QEMU with +writes the result to `vm/debian13/qemu.ini` and starts QEMU with `-readconfig` for that file followed by the one for the host system and guest architecture. QEMU arguments given after `--` override the config files, for example `./run-debian13.py -- -m 4G -smp 4`. 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 +instead of the default `vm//`. The option takes precedence over the corresponding `*_STATE_DIR` environment variable: ```bash @@ -55,7 +55,7 @@ for Windows 11 (whose installation ISO and base QCOW2 are supplied manually): ./run-fedora44.py --download-only ``` -If `.vm/debian13/seed.iso` is missing, the launcher automatically builds it +If `vm/debian13/seed.iso` is missing, the launcher automatically builds it from `seediso/debian13/user-data`, `seediso/debian13/meta-data`, and `seediso/debian13/network-config` before starting the VM. @@ -84,7 +84,7 @@ Start an AlmaLinux 10 Generic Cloud VM with: When the shared AlmaLinux image is missing, the launcher calls the selected image helper with `almalinux10`. It creates the writable -overlay `.vm/almalinux10/disk.qcow2` and uses the NoCloud configuration in +overlay `vm/almalinux10/disk.qcow2` and uses the NoCloud configuration in `seediso/almalinux10/`. SSH is forwarded to host port `2223` by default: ```bash @@ -98,9 +98,9 @@ ALMA_VM_MEMORY=4G ALMA_VM_CPUS=4 ALMA_VM_SSH_PORT=2224 ./run-almalinux10.py ``` 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 +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`. +`./seediso/almalinux10/build-seed.sh vm/almalinux10/seed.iso`. ## Fedora 44 @@ -111,7 +111,7 @@ Start a Fedora 44 Cloud Base VM with: ``` 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 +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 @@ -136,7 +136,7 @@ Start an Ubuntu 26.04 LTS (Resolute Raccoon) cloud image VM with: ``` The launcher downloads the `ubuntu2604` image through the shared helper when -it is missing, creates `.vm/ubuntu2604/disk.qcow2`, and builds its NoCloud seed +it is missing, creates `vm/ubuntu2604/disk.qcow2`, and builds its NoCloud seed from `seediso/ubuntu2604/`. Like the Debian seed, it injects the current user's SSH public key and points APT at the USTC mirror (`ubuntu-ports` on arm64). SSH is forwarded to host port `2225` by default: @@ -165,7 +165,7 @@ from the shared Windows 11 QCOW2 base image: ./run-windows11.py ``` -It creates a persistent 64G disk at `.vm/windows11/disk.qcow2`, automatically +It creates a persistent 64G disk at `vm/windows11/disk.qcow2`, automatically partitions it, completes OOBE, creates the local administrator `guofang` with the initial password `wang`, and enables Remote Desktop on `localhost:3389`. During the first login it also silently installs the VirtIO @@ -173,7 +173,7 @@ drivers (the guest tools installer on amd64, the Arm64 driver packages from the VirtIO ISO with `pnputil` on arm64), without which the guest has no network on arm64. The installer includes the VirtIO drivers, SPICE vdagent, and QEMU Guest Agent. The launcher exposes the vdagent channel for host/guest clipboard -integration and the QEMU Guest Agent at `.vm/windows11/qemu-guest-agent.sock`. +integration and the QEMU Guest Agent at `vm/windows11/qemu-guest-agent.sock`. Change the password after first login. The OpenSSH Server is installed during the first logon from the Win32-OpenSSH zip for the host architecture, which the seed ISO carries (downloaded by `vm-images/download-images.sh openssh-win`), so @@ -184,11 +184,11 @@ administrator login. The Windows VM hardware (8G memory, 8 CPUs, system disk, devices) is defined in `qemu/windows11.ini`, with the accelerators and machine type in `qemu/windows11--.ini`; the launcher renders the former to -`.vm/windows11/qemu.ini` and loads both with `-readconfig`. Only the network +`vm/windows11/qemu.ini` and loads both with `-readconfig`. Only the network and the installation media are still set by the launcher. QEMU arguments after `--` override the config files, for example `./run-windows11.py -- -m 4G -smp 4`. The generated answer-file ISO is stored beside the disk as -`.vm/windows11/seed.iso`. +`vm/windows11/seed.iso`. To install from the Windows ISO instead, use `./run-windows11.py --install-from-iso`. This choice only applies while creating a missing system diff --git a/run-almalinux10.py b/run-almalinux10.py index ce0d75f..603315a 100755 --- a/run-almalinux10.py +++ b/run-almalinux10.py @@ -51,7 +51,7 @@ else: base_image = Path(result.stdout.rstrip("\n")) uses_shared_base_image = True -state_dir = Path(env("ALMA_VM_STATE_DIR") or script_dir / ".vm" / "almalinux10") +state_dir = Path(env("ALMA_VM_STATE_DIR") or script_dir / "vm" / "almalinux10") disk_size = env("ALMA_VM_DISK_SIZE") or "20G" memory = env("ALMA_VM_MEMORY") or "8G" cpus = env("ALMA_VM_CPUS") or "8" @@ -132,7 +132,7 @@ Options: --daemon Run in the background while keeping the graphical window --download-only Download the base image if it is missing, then exit --state-dir DIR Directory for the VM disk, seed ISO and runtime files - (default: .vm/almalinux10; overrides ALMA_VM_STATE_DIR) + (default: vm/almalinux10; overrides ALMA_VM_STATE_DIR) -h, --help Show this help Environment variables: @@ -141,7 +141,7 @@ Environment variables: ALMA_VM_SSH_PORT Host port forwarded to guest SSH (default: 2223) ALMA_VM_BASE_IMAGE Base qcow2 image path (default: resolved by shared image helper) ALMA_VM_SEED_IMAGE cloud-init seed ISO path (default: alongside the VM disk) - ALMA_VM_STATE_DIR Runtime state directory (default: .vm/almalinux10) + ALMA_VM_STATE_DIR Runtime state directory (default: vm/almalinux10) ALMA_VM_DISK_IMAGE Writable overlay path ALMA_VM_DISK_SIZE New overlay virtual capacity (default: 20G) VM_IMAGE_ARCH Guest/host architecture: arm64 or amd64 (default: auto-detected from the host) diff --git a/run-debian13.py b/run-debian13.py index 5fea77e..041f09f 100755 --- a/run-debian13.py +++ b/run-debian13.py @@ -53,7 +53,7 @@ else: base_image = Path(result.stdout.rstrip("\n")) uses_shared_base_image = True -state_dir = Path(env("VM_STATE_DIR") or script_dir / ".vm" / "debian13") +state_dir = Path(env("VM_STATE_DIR") or script_dir / "vm" / "debian13") disk_size = env("VM_DISK_SIZE") or "20G" @@ -124,7 +124,7 @@ def usage(stream=sys.stdout): Usage: {Path(sys.argv[0]).name} [--daemon] [--download-only] [--state-dir DIR] [-- QEMU_ARGUMENT ...] Start the Debian 13 virtual machine. A writable overlay is created in the state -directory (default: .vm/debian13/), so the downloaded base image is never +directory (default: vm/debian13/), so the downloaded base image is never modified. The VM hardware (memory, CPUs, SSH port forward, ...) is defined in qemu/debian13.ini, which is rendered to qemu.ini in the state directory and loaded with QEMU's -readconfig, followed by qemu/debian13--.ini (os is linux or darwin, arch is amd64 or arm64). Later @@ -134,13 +134,13 @@ Options: --daemon Run in the background while keeping the graphical window --download-only Download the base image if it is missing, then exit --state-dir DIR Directory for the VM disk, seed ISO and runtime files - (default: .vm/debian13; overrides VM_STATE_DIR) + (default: vm/debian13; overrides VM_STATE_DIR) -h, --help Show this help Environment variables: VM_BASE_IMAGE Base qcow2 image path (default: resolved by shared image helper) VM_SEED_IMAGE cloud-init seed ISO path (default: alongside the VM disk) - VM_STATE_DIR Runtime state directory (default: .vm/debian13) + VM_STATE_DIR Runtime state directory (default: vm/debian13) VM_DISK_IMAGE Writable overlay path VM_DISK_SIZE New overlay virtual capacity (default: 20G) VM_IMAGE_ARCH Guest/host architecture: arm64 or amd64 (default: auto-detected from the host) diff --git a/run-fedora44.py b/run-fedora44.py index ec2a52c..50a179b 100755 --- a/run-fedora44.py +++ b/run-fedora44.py @@ -53,7 +53,7 @@ else: base_image = Path(result.stdout.rstrip("\n")) uses_shared_base_image = True -state_dir = Path(env("FEDORA_VM_STATE_DIR") or script_dir / ".vm" / "fedora44") +state_dir = Path(env("FEDORA_VM_STATE_DIR") or script_dir / "vm" / "fedora44") disk_size = env("FEDORA_VM_DISK_SIZE") or "20G" @@ -136,13 +136,13 @@ Options: --daemon Run in the background while keeping the graphical window --download-only Download the base image if it is missing, then exit --state-dir DIR Directory for the VM disk, seed ISO and runtime files - (default: .vm/fedora44; overrides FEDORA_VM_STATE_DIR) + (default: vm/fedora44; overrides FEDORA_VM_STATE_DIR) -h, --help Show this help Environment variables: FEDORA_VM_BASE_IMAGE Base qcow2 image path (default: resolved by shared image helper) FEDORA_VM_SEED_IMAGE cloud-init seed ISO path (default: alongside the VM disk) - FEDORA_VM_STATE_DIR Runtime state directory (default: .vm/fedora44) + FEDORA_VM_STATE_DIR Runtime state directory (default: vm/fedora44) FEDORA_VM_DISK_IMAGE Writable overlay path FEDORA_VM_DISK_SIZE New overlay virtual capacity (default: 20G) VM_IMAGE_ARCH Guest/host architecture: arm64 or amd64 (default: auto-detected from the host) diff --git a/run-ubuntu2604.py b/run-ubuntu2604.py index db81a73..de06bd8 100755 --- a/run-ubuntu2604.py +++ b/run-ubuntu2604.py @@ -53,7 +53,7 @@ else: base_image = Path(result.stdout.rstrip("\n")) uses_shared_base_image = True -state_dir = Path(env("UBUNTU_VM_STATE_DIR") or script_dir / ".vm" / "ubuntu2604") +state_dir = Path(env("UBUNTU_VM_STATE_DIR") or script_dir / "vm" / "ubuntu2604") disk_size = env("UBUNTU_VM_DISK_SIZE") or "20G" @@ -125,7 +125,7 @@ def usage(stream=sys.stdout): Usage: {Path(sys.argv[0]).name} [--daemon] [--download-only] [--state-dir DIR] [-- QEMU_ARGUMENT ...] Start an Ubuntu 26.04 LTS cloud image virtual machine. A writable overlay is -created in the state directory (default: .vm/ubuntu2604/), so the downloaded +created in the state directory (default: vm/ubuntu2604/), so the downloaded base image is never modified. The VM hardware (memory, CPUs, SSH port forward, ...) is defined in qemu/ubuntu2604.ini, which is rendered to qemu.ini in the state directory and loaded with QEMU's -readconfig, followed by @@ -136,13 +136,13 @@ Options: --daemon Run in the background while keeping the graphical window --download-only Download the base image if it is missing, then exit --state-dir DIR Directory for the VM disk, seed ISO and runtime files - (default: .vm/ubuntu2604; overrides UBUNTU_VM_STATE_DIR) + (default: vm/ubuntu2604; overrides UBUNTU_VM_STATE_DIR) -h, --help Show this help Environment variables: UBUNTU_VM_BASE_IMAGE Base qcow2 image path (default: resolved by shared image helper) UBUNTU_VM_SEED_IMAGE cloud-init seed ISO path (default: alongside the VM disk) - UBUNTU_VM_STATE_DIR Runtime state directory (default: .vm/ubuntu2604) + UBUNTU_VM_STATE_DIR Runtime state directory (default: vm/ubuntu2604) UBUNTU_VM_DISK_IMAGE Writable overlay path UBUNTU_VM_DISK_SIZE New overlay virtual capacity (default: 20G) VM_IMAGE_ARCH Guest/host architecture: arm64 or amd64 (default: auto-detected from the host) diff --git a/run-windows11.py b/run-windows11.py index 504373f..b67df7e 100755 --- a/run-windows11.py +++ b/run-windows11.py @@ -61,7 +61,7 @@ def find_image_downloader(): return image_downloader -state_dir = Path(env("WIN11_VM_STATE_DIR") or script_dir / ".vm" / "windows11") +state_dir = Path(env("WIN11_VM_STATE_DIR") or script_dir / "vm" / "windows11") disk_size = env("WIN11_VM_DISK_SIZE") or "64G" rdp_port = env("WIN11_VM_RDP_PORT") or "3389" ssh_port = env("WIN11_VM_SSH_PORT") or "2222" @@ -116,7 +116,7 @@ Options: overrides VM_IMAGE_ARCH). A guest that differs from the host runs under slow TCG emulation --state-dir DIR Directory for the VM disk, seed ISO and runtime files - (default: .vm/windows11; overrides WIN11_VM_STATE_DIR) + (default: vm/windows11; overrides WIN11_VM_STATE_DIR) --rdp-port PORT Host port forwarded to guest RDP (default: 3389; overrides WIN11_VM_RDP_PORT) --ssh-port PORT Host port forwarded to guest SSH (default: 2222; @@ -130,7 +130,7 @@ Environment variables: WIN11_VM_TOOLS_ISO VirtIO Windows tools ISO (default: resolved by shared image helper) WIN11_VM_RDP_PORT Host RDP port (default: 3389) WIN11_VM_SSH_PORT Host SSH port (default: 2222) - WIN11_VM_STATE_DIR Runtime directory (default: .vm/windows11) + WIN11_VM_STATE_DIR Runtime directory (default: vm/windows11) WIN11_VM_DISK_IMAGE System disk path WIN11_VM_DISK_SIZE New system disk size (default: 64G) WIN11_VM_SEED_ISO Answer-file ISO path (default: alongside the VM disk)