Attach the cloud-init seed ISO only when the VM disk is created

cloud-init reads the seed on the first boot only, so the Linux launchers now
mount it just for the run that creates the overlay disk. The seed drive moves
from the config files to the launcher arguments.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GuofangandClaude Sonnet 5.5 committed 2026-11-02 11:19:48 +08:00
1 parent b149dd4bc3
commit fe7250870e
7 files changed
+40 -46

No files matched your search

-11
View File
@@ -39,17 +39,6 @@
driver = "virtio-blk-pci" driver = "virtio-blk-pci"
drive = "disk0" drive = "disk0"
# cloud-init seed ISO.
[drive "seed0"]
if = "none"
format = "raw"
readonly = "on"
file = "${seed_image}"
[device "seed0-dev"]
driver = "virtio-blk-pci"
drive = "seed0"
# The NIC is attached to the user-mode network "net0", which the launcher # The NIC is attached to the user-mode network "net0", which the launcher
# defines with -netdev from qemu/debian13/forwards.conf because a config file # defines with -netdev from qemu/debian13/forwards.conf because a config file
# section cannot hold more than one hostfwd. # section cannot hold more than one hostfwd.
-11
View File
@@ -39,17 +39,6 @@
driver = "virtio-blk-pci" driver = "virtio-blk-pci"
drive = "disk0" drive = "disk0"
# cloud-init seed ISO.
[drive "seed0"]
if = "none"
format = "raw"
readonly = "on"
file = "${seed_image}"
[device "seed0-dev"]
driver = "virtio-blk-pci"
drive = "seed0"
# The NIC is attached to the user-mode network "net0", which the launcher # The NIC is attached to the user-mode network "net0", which the launcher
# defines with -netdev from qemu/fedora44/forwards.conf because a config file # defines with -netdev from qemu/fedora44/forwards.conf because a config file
# section cannot hold more than one hostfwd. # section cannot hold more than one hostfwd.
-11
View File
@@ -39,17 +39,6 @@
driver = "virtio-blk-pci" driver = "virtio-blk-pci"
drive = "disk0" drive = "disk0"
# cloud-init seed ISO.
[drive "seed0"]
if = "none"
format = "raw"
readonly = "on"
file = "${seed_image}"
[device "seed0-dev"]
driver = "virtio-blk-pci"
drive = "seed0"
# The NIC is attached to the user-mode network "net0", which the launcher # The NIC is attached to the user-mode network "net0", which the launcher
# defines with -netdev from qemu/ubuntu2604/forwards.conf because a config file # defines with -netdev from qemu/ubuntu2604/forwards.conf because a config file
# section cannot hold more than one hostfwd. # section cannot hold more than one hostfwd.
+10 -4
View File
@@ -208,7 +208,8 @@ for firmware_file in (uefi_code, uefi_vars_template):
if not firmware_file.is_file(): if not firmware_file.is_file():
die(f"required UEFI firmware was not found: {firmware_file}") die(f"required UEFI firmware was not found: {firmware_file}")
if not seed_image.is_file(): creating = not disk_image.is_file()
if creating and not seed_image.is_file():
seed_builder = script_dir / "seediso" / "almalinux10" / "build-seed.sh" seed_builder = script_dir / "seediso" / "almalinux10" / "build-seed.sh"
if not is_executable(seed_builder): if not is_executable(seed_builder):
die(f"seed image is missing and builder is unavailable: {seed_builder}") die(f"seed image is missing and builder is unavailable: {seed_builder}")
@@ -240,7 +241,7 @@ if pid_file.is_file():
die(f"the AlmaLinux virtual machine is already running (PID {old_pid}).") die(f"the AlmaLinux virtual machine is already running (PID {old_pid}).")
pid_file.unlink(missing_ok=True) pid_file.unlink(missing_ok=True)
if not disk_image.is_file(): if creating:
run(["qemu-img", "create", "-q", "-f", "qcow2", "-F", "qcow2", run(["qemu-img", "create", "-q", "-f", "qcow2", "-F", "qcow2",
"-b", str(base_image), str(disk_image), disk_size]) "-b", str(base_image), str(disk_image), disk_size])
print(f"Created writable disk overlay: {disk_image}") print(f"Created writable disk overlay: {disk_image}")
@@ -261,12 +262,17 @@ qemu_args = [
"-drive", f"if=pflash,format=raw,file={uefi_vars}", "-drive", f"if=pflash,format=raw,file={uefi_vars}",
"-drive", f"file={disk_image},if=none,id=disk0,format=qcow2", "-drive", f"file={disk_image},if=none,id=disk0,format=qcow2",
"-device", "virtio-blk-pci,drive=disk0", "-device", "virtio-blk-pci,drive=disk0",
"-drive", f"file={seed_image},if=none,id=seed0,format=raw,readonly=on",
"-device", "virtio-blk-pci,drive=seed0",
"-netdev", vmforwards.netdev_argument(forwards), "-netdev", vmforwards.netdev_argument(forwards),
"-device", "virtio-net-pci,netdev=net0", "-device", "virtio-net-pci,netdev=net0",
] ]
if creating:
# cloud-init reads the seed ISO on the first boot only (the users, keys,
# network and packages it sets up stay on the disk), so it is attached only
# when the disk is created.
qemu_args += ["-drive", f"file={seed_image},if=none,id=seed0,format=raw,readonly=on",
"-device", "virtio-blk-pci,drive=seed0"]
if machine_type == "virt": if machine_type == "virt":
# Unlike q35, the "virt" machine has no default GPU or USB input devices. # Unlike q35, the "virt" machine has no default GPU or USB input devices.
qemu_args += [ qemu_args += [
+10 -3
View File
@@ -208,7 +208,8 @@ for firmware_file in (uefi_code, uefi_vars_template):
if not firmware_file.is_file(): if not firmware_file.is_file():
die(f"required UEFI firmware was not found: {firmware_file}") die(f"required UEFI firmware was not found: {firmware_file}")
if not seed_image.is_file(): creating = not disk_image.is_file()
if creating and not seed_image.is_file():
seed_builder = script_dir / "seediso" / "debian13" / "build-seed.sh" seed_builder = script_dir / "seediso" / "debian13" / "build-seed.sh"
if not is_executable(seed_builder): if not is_executable(seed_builder):
die(f"seed image is missing and builder is unavailable: {seed_builder}") die(f"seed image is missing and builder is unavailable: {seed_builder}")
@@ -240,7 +241,7 @@ if pid_file.is_file():
die(f"the virtual machine is already running (PID {old_pid}).") die(f"the virtual machine is already running (PID {old_pid}).")
pid_file.unlink(missing_ok=True) pid_file.unlink(missing_ok=True)
if not disk_image.is_file(): if creating:
run(["qemu-img", "create", "-q", "-f", "qcow2", "-F", "qcow2", run(["qemu-img", "create", "-q", "-f", "qcow2", "-F", "qcow2",
"-b", str(base_image), str(disk_image), disk_size]) "-b", str(base_image), str(disk_image), disk_size])
print(f"Created writable disk overlay: {disk_image}") print(f"Created writable disk overlay: {disk_image}")
@@ -254,7 +255,6 @@ config_values = {
"uefi_code": uefi_code_flash, "uefi_code": uefi_code_flash,
"uefi_vars": uefi_vars, "uefi_vars": uefi_vars,
"disk_image": disk_image, "disk_image": disk_image,
"seed_image": seed_image,
} }
for key, value in config_values.items(): for key, value in config_values.items():
# QEMU's config file parser has no escape syntax for quoted values. # QEMU's config file parser has no escape syntax for quoted values.
@@ -285,6 +285,13 @@ qemu_args = [
"-display", display_backend, "-display", display_backend,
] ]
if creating:
# cloud-init reads the seed ISO on the first boot only (the users, keys,
# network and packages it sets up stay on the disk), so it is attached only
# when the disk is created.
qemu_args += ["-drive", f"file={seed_image},if=none,id=seed0,format=raw,readonly=on",
"-device", "virtio-blk-pci,drive=seed0"]
print(f"Starting {host_arch} VM from {qemu_config_template} " print(f"Starting {host_arch} VM from {qemu_config_template} "
f"and {qemu_platform_config}.", flush=True) f"and {qemu_platform_config}.", flush=True)
vmforwards.print_forwards(forwards) vmforwards.print_forwards(forwards)
+10 -3
View File
@@ -210,7 +210,8 @@ for firmware_file in (uefi_code, uefi_vars_template):
if not firmware_file.is_file(): if not firmware_file.is_file():
die(f"required UEFI firmware was not found: {firmware_file}") die(f"required UEFI firmware was not found: {firmware_file}")
if not seed_image.is_file(): creating = not disk_image.is_file()
if creating and not seed_image.is_file():
seed_builder = script_dir / "seediso" / "fedora44" / "build-seed.sh" seed_builder = script_dir / "seediso" / "fedora44" / "build-seed.sh"
if not is_executable(seed_builder): if not is_executable(seed_builder):
die(f"seed image is missing and builder is unavailable: {seed_builder}") die(f"seed image is missing and builder is unavailable: {seed_builder}")
@@ -242,7 +243,7 @@ if pid_file.is_file():
die(f"the Fedora virtual machine is already running (PID {old_pid}).") die(f"the Fedora virtual machine is already running (PID {old_pid}).")
pid_file.unlink(missing_ok=True) pid_file.unlink(missing_ok=True)
if not disk_image.is_file(): if creating:
run(["qemu-img", "create", "-q", "-f", "qcow2", "-F", "qcow2", run(["qemu-img", "create", "-q", "-f", "qcow2", "-F", "qcow2",
"-b", str(base_image), str(disk_image), disk_size]) "-b", str(base_image), str(disk_image), disk_size])
print(f"Created writable disk overlay: {disk_image}") print(f"Created writable disk overlay: {disk_image}")
@@ -256,7 +257,6 @@ config_values = {
"uefi_code": uefi_code_flash, "uefi_code": uefi_code_flash,
"uefi_vars": uefi_vars, "uefi_vars": uefi_vars,
"disk_image": disk_image, "disk_image": disk_image,
"seed_image": seed_image,
} }
for key, value in config_values.items(): for key, value in config_values.items():
# QEMU's config file parser has no escape syntax for quoted values. # QEMU's config file parser has no escape syntax for quoted values.
@@ -287,6 +287,13 @@ qemu_args = [
"-display", display_backend, "-display", display_backend,
] ]
if creating:
# cloud-init reads the seed ISO on the first boot only (the users, keys,
# network and packages it sets up stay on the disk), so it is attached only
# when the disk is created.
qemu_args += ["-drive", f"file={seed_image},if=none,id=seed0,format=raw,readonly=on",
"-device", "virtio-blk-pci,drive=seed0"]
print(f"Starting Fedora 44 ({host_arch}) from {qemu_config_template} " print(f"Starting Fedora 44 ({host_arch}) from {qemu_config_template} "
f"and {qemu_platform_config}.", flush=True) f"and {qemu_platform_config}.", flush=True)
vmforwards.print_forwards(forwards) vmforwards.print_forwards(forwards)
+10 -3
View File
@@ -210,7 +210,8 @@ for firmware_file in (uefi_code, uefi_vars_template):
if not firmware_file.is_file(): if not firmware_file.is_file():
die(f"required UEFI firmware was not found: {firmware_file}") die(f"required UEFI firmware was not found: {firmware_file}")
if not seed_image.is_file(): creating = not disk_image.is_file()
if creating and not seed_image.is_file():
seed_builder = script_dir / "seediso" / "ubuntu2604" / "build-seed.sh" seed_builder = script_dir / "seediso" / "ubuntu2604" / "build-seed.sh"
if not is_executable(seed_builder): if not is_executable(seed_builder):
die(f"seed image is missing and builder is unavailable: {seed_builder}") die(f"seed image is missing and builder is unavailable: {seed_builder}")
@@ -242,7 +243,7 @@ if pid_file.is_file():
die(f"the Ubuntu virtual machine is already running (PID {old_pid}).") die(f"the Ubuntu virtual machine is already running (PID {old_pid}).")
pid_file.unlink(missing_ok=True) pid_file.unlink(missing_ok=True)
if not disk_image.is_file(): if creating:
run(["qemu-img", "create", "-q", "-f", "qcow2", "-F", "qcow2", run(["qemu-img", "create", "-q", "-f", "qcow2", "-F", "qcow2",
"-b", str(base_image), str(disk_image), disk_size]) "-b", str(base_image), str(disk_image), disk_size])
print(f"Created writable disk overlay: {disk_image}") print(f"Created writable disk overlay: {disk_image}")
@@ -256,7 +257,6 @@ config_values = {
"uefi_code": uefi_code_flash, "uefi_code": uefi_code_flash,
"uefi_vars": uefi_vars, "uefi_vars": uefi_vars,
"disk_image": disk_image, "disk_image": disk_image,
"seed_image": seed_image,
} }
for key, value in config_values.items(): for key, value in config_values.items():
# QEMU's config file parser has no escape syntax for quoted values. # QEMU's config file parser has no escape syntax for quoted values.
@@ -287,6 +287,13 @@ qemu_args = [
"-display", display_backend, "-display", display_backend,
] ]
if creating:
# cloud-init reads the seed ISO on the first boot only (the users, keys,
# network and packages it sets up stay on the disk), so it is attached only
# when the disk is created.
qemu_args += ["-drive", f"file={seed_image},if=none,id=seed0,format=raw,readonly=on",
"-device", "virtio-blk-pci,drive=seed0"]
print(f"Starting Ubuntu 26.04 ({host_arch}) from {qemu_config_template} " print(f"Starting Ubuntu 26.04 ({host_arch}) from {qemu_config_template} "
f"and {qemu_platform_config}.", flush=True) f"and {qemu_platform_config}.", flush=True)
vmforwards.print_forwards(forwards) vmforwards.print_forwards(forwards)