2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-21 15:18:19 +00:00
Commit Graph

7257 Commits

Author SHA1 Message Date
Vinícius Ferrão 9ecde2b838 fix(imgport): take the image lock for a statelite import
imgimport took the image lock only when the bundle had a rootimg. A
statelite bundle has a rootimgtree instead, so its import extracted the
tree while genimage, packimage, liteimg or rmimage could change the same
image. imgimport now locks the directory of the first of the rootimg,
rootimgtree, kernel and ramdisk that the bundle has.
2026-10-16 18:38:00 -03:00
Vinícius Ferrão c6ff6f6b77 fix(imgport): place the boot files of an image before its definition
imgimport wrote the image definition before it published the root
image. When the publication failed, as when another host held the
publication lock, the import failed with the new definition and the
previous files.

imgimport now places the root image, kernel and ramdisk first, then
writes the image definition, then places the other files. A later
failure leaves the definition that matches the published boot files,
as before. Before it writes anything, imgimport also opens the tables
of the image definition without autocommit, as it writes them. A table
that it cannot open then leaves the files as they were.
2026-10-16 18:37:59 -03:00
Vinícius Ferrão de36cffe8e fix(imgport): check the files of a bundle before the import writes
imgimport moved the boot files and kits of a bundle without a check,
and copied the extra files after it had already written the image. A
bundle without its kernel or a kit then gave a broken image without
an error. A missing extra file failed the import after it published
the root image and wrote the image definition.

imgimport now checks the boot files, kits, extra files and raw image
files that the manifest names. It does this before it writes anything,
and reports each missing file.
2026-10-16 18:35:25 -03:00
Vinícius Ferrão 7838c3240a fix(imgport): check the nodes of an import before it writes anything
imgimport -n checked its nodes when it set their postscripts. By then
it had published the root image, placed the other files and written the
image definition. An undefined node then left a half-imported image.

imgimport now checks the nodes before it writes anything, and fails
with the same error.
2026-10-16 18:35:25 -03:00
Daniel Hilst cf170b36c4 Merge pull request #7942 from VersatusHPC/feat/rootimg-sha256
feat(netboot): check the root image against its SHA-256 checksum
2026-10-16 18:18:10 -03:00
Daniel Hilst fb9541ffde Merge pull request #7949 from VersatusHPC/fix/table-commands
fix(table): refuse extra tabrestore fields and unknown chtab -d tables
2026-10-16 18:17:31 -03:00
Daniel Hilst b17d37380a Merge pull request #7912 from VersatusHPC/fix/kvm-aarch64-guest-arch
fix(kvm): mkvm builds an aarch64 node as an x86_64 domain
2026-10-16 11:03:20 -03:00
Vinícius Ferrão 3856dbeee8 refactor(boot): remove the private Genesis selector name 2026-10-14 13:30:00 -03:00
Vinícius Ferrão 3b50ed9036 refactor(boot): expose the Genesis file selector 2026-10-14 13:30:00 -03:00
Vinícius Ferrão a4066f75e3 refactor(mknb): stage Genesis artifacts with File::Temp 2026-10-14 13:29:22 -03:00
Vinícius Ferrão 937f6895f0 refactor(http): share port suffix formatting across boot callers 2026-10-14 13:29:22 -03:00
Vinícius Ferrão 6713d01af3 refactor(boot): share Genesis artifact selection 2026-10-14 13:29:22 -03:00
Daniel Hilst ba4824ef62 Merge pull request #7940 from VersatusHPC/fix/imgexport-destination
fix(imgport): write the imgexport bundle to its destination
2026-10-14 12:05:47 -03:00
Daniel Hilst bdd2a51efc Merge pull request #7945 from VersatusHPC/fix/imgimport-litefile-lookup
fix(imgport): quote the image column of the litefile lookup
2026-10-14 12:04:38 -03:00
Daniel Hilst c8a20a1ea2 Merge pull request #7950 from VersatusHPC/fix/kit-rhel-release
fix(kit): compare the RHEL release as a number
2026-10-14 11:53:59 -03:00
Daniel Hilst 675c9f3dfd Merge pull request #7946 from VersatusHPC/fix/kit-lock
fix(kit): refuse a kit command while another process holds the kit lock
2026-10-14 11:51:23 -03:00
Daniel Hilst 5c0944854f Merge pull request #7944 from VersatusHPC/fix/imgimport-extra-destination
fix(imgport): copy an extra file into its destination directory
2026-10-14 11:49:02 -03:00
Daniel Hilst b1fd47ae17 Merge pull request #7938 from VersatusHPC/fix/packimage-image-dir-glob
fix(packimage): refuse an image directory that the shell would split
2026-10-14 11:46:58 -03:00
Daniel Hilst 74ec6acdde Merge pull request #7900 from VersatusHPC/fix/x86-unstable-cases
fix(xcat-core): x86_64 CLI cases report failures the product does not have
2026-10-14 11:04:10 -03:00
Daniel Hilst 7594786fcf fix(kvm): an aarch64 guest gets vga when the hypervisor offers no usable model
preferred_video_model returned vga whenever no preferred model was
found, also when the hypervisor did not offer vga, did not support video,
or the capability query failed. Under native aarch64 KVM, vga and the
other PCI framebuffer models do not display correctly.

An aarch64 guest now takes the first offered model of virtio and ramfb
under KVM, or of virtio, vga and ramfb under TCG. When video is
unsupported or no wanted model is offered, build_xmldesc writes no
<video> and no <graphics>, and the guest uses its serial console. When
the capabilities are unavailable, build_xmldesc returns an error that
names the query error and vm.vidmodel.

vm.vidmodel still overrides the choice. Other architectures do not
query the capabilities and keep their fixed model.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-14 05:40:19 -03:00
Vinícius Ferrão 5cb09ab21e fix(tabutils): refuse a tabrestore row with a field after the last column
tabrestore stripped the comma after each field, so a comma after the
field of the last column left nothing to report. A row with one more
empty field was restored as if it fit the columns. A last extra field
of 0 also passed, because the check tested the rest of the line for
truth.

tabrestore now refuses a row whose last column field ends with a comma,
or that has any text left, and rolls back the restore.
2026-10-14 02:04:09 -03:00
Vinícius Ferrão bb94a545ff fix(kit): compare the RHEL release as a number
The kit commands refuse RHEL 8 and later, but compared the release as a
string. "10.1" sorts before "8", so the kit commands ran on RHEL 10.
They now compare the major release as a number.
2026-10-14 01:21:01 -03:00
Vinícius Ferrão 085ee7991d fix(imgport): copy an extra file into its destination directory
imgexport records an extra file with its destination directory. When
that directory did not exist, imgimport copied the file to the path of
the directory, so the file took the name of the directory. When a file
was at that path, imgimport replaced it.

imgimport now creates the destination directory and its missing
parents, as it does for an extra directory. A file at that path fails
the import and stays as it was. The copy runs without a shell, so a
file name with glob characters cannot match another file. A failed
backup of the previous file now fails the import.
2026-10-14 00:46:24 -03:00
Vinícius Ferrão bb885f2767 fix(kit): refuse a kit command while another process holds the kit lock
kit.pm tested the bareword locked instead of $locked. The test was
always false, so a kit command never took the kit lock, and it ran also
while another process held the lock.

A kit command now takes the lock in one step, and fails while another
process holds it. The is_locked probe is gone, because its release
removed the lock file that another kit command could then hold. A kit
command that another kit command runs goes on under the lock of that
command.
2026-10-13 23:34:38 -03:00
Vinícius Ferrão 9bfdadeaac fix(imgport): quote the image column of the litefile lookup
imgimport looked up the litefile entries for all images with "image" =
'ALL'. MySQL takes a double-quoted name for a string, so the lookup
found nothing, and imgimport added entries that an ALL entry already
covered. The lookup now quotes the column the way the database needs.
2026-10-13 23:22:01 -03:00
Vinícius Ferrão 87c58da302 fix(packimage): take the image directory literally when removing files
The removal of abandoned stages, the removal of the other archive
formats after a publication, and rmimage found their files with glob.
glob splits a pattern at a space, so for an image directory such as
"/install/custom images/node" the first word named another path.
rmtree then removed that directory, with its images. glob also takes a
wildcard character in the path of the image directory as a pattern.

image_dir_entries now lists the image directory itself and matches the
names of its entries, and these removals use it.
2026-10-13 16:51:34 -03:00
Vinícius Ferrão c0f3d212f5 fix(packimage): keep a checksum symlink through a failed publication
A failed publication put back only the content of the previous checksum
file. A checksum symlink became a regular file, which a later switch of
the symlinks would leave stale.

publish_rootimg now keeps the previous checksum entry, and a rollback
renames it back. When that rename fails, the previous content goes
back, and the error reports it.
2026-10-13 16:51:34 -03:00
Vinícius Ferrão e06910c1de fix(packimage): keep the staging that holds the previous archive
When a failed publication could not put back the previous archive or
metainfo, it moved them to a .rootimg-previous-* directory. When that
move failed too, they stayed in the staging directory, which packimage,
liteimg and imgimport then removed. The only copy of the previous files
was lost.

Staging that keeps a previous file now stays, and the error names it.
The removal of abandoned stages leaves it, and rmimage removes it with
the image. A publication removes its previous files from staging
otherwise, so only a failed one leaves them.
2026-10-13 16:51:33 -03:00
Vinícius Ferrão 989b9f4645 fix(packimage): keep the previous metainfo that a rollback cannot put back
When a publication failed, the rollback put back the previous metainfo
and checksum without checking either step. A metainfo that could not go
back stayed in staging, which cleanup then removed, and the rollback
reported nothing. The rollback now checks each step. It moves a previous
metainfo that cannot go back next to the image, as it does with a
previous archive, and reports where. It also reports a checksum that it
cannot put back.
2026-10-13 16:51:33 -03:00
Vinícius Ferrão a95ca8bf6e fix(packimage): remove a first archive whose publication fails
When no archive was published before, as for the first pack or a change
of format, and the metainfo rename failed after the archive rename, the
rollback looked for a previous archive that did not exist. It reported
that archive as kept in an empty directory, and left the new archive and
its checksum published. The rollback now removes the new archive and its
checksum.
2026-10-13 16:51:32 -03:00
Vinícius Ferrão 2ec6029c95 fix(rmimage): remove the statelite archive and the checksum files
rmimage removed rootimg.* from the image directory. That missed rootimg-
statelite.gz with its checksum and metainfo, and the .rootimgcheck
marker of the initial ramdisk. A temporary directory that an interrupted
packimage, liteimg or imgimport left on this host also stayed, with a
partial archive in it.

rmimage now removes these files, the temporary directories that writers
on this host abandoned, and the .rootimg-previous-* directories that
failed publications kept. rootimg_stage and rmimage share this cleanup
through remove_abandoned_rootimg_stages.
2026-10-13 16:51:32 -03:00
Vinícius Ferrão 810e3bf66d fix(nodeset): copy the initial ramdisk that SLES statelite ramdisk nodes boot
A SLES statelite ramdisk image built with dracut boots
initrd-stateless.gz, but nodeset copied only initrd-statelite.gz to the
TFTP directory and checked only for that file. Nodes requested an initial
ramdisk that nodeset never copied, or one that an older nodeset left.

nodeset now chooses the initial ramdisk once, then copies, checks and
boots that file, as it does on Red Hat.
2026-10-13 16:51:32 -03:00
Vinícius Ferrão d9fb4703f9 fix(nodeset): give Ubuntu statelite ramdisk nodes the root image URL
The statelite branch of debian.pm tested rootfstype without its $, so it
compared the string rootfstype with ramdisk and always took the NFS root
branch. Ubuntu statelite ramdisk nodes got an NFS root and no imgurl, so
they never downloaded rootimg-statelite.gz.

nodeset now tests $rootfstype, and Ubuntu statelite ramdisk nodes get
the imgurl of rootimg-statelite.gz, as on Red Hat and SUSE.
2026-10-13 16:51:31 -03:00
Vinícius Ferrão 459c13bbc9 feat(xcatconfig): keep the images of an upgrade unchecked
The root image check is on by default, so an upgrade from a release
without it would turn it on for every existing stateless and statelite
image. Their nodes would then need a checksum and an initial ramdisk
that can check.

On an upgrade, while site.rootimgchecksum is not set, xcatconfig sets
the rootimgchecksum attribute to no for each of these images that does
not set it, and then sets site.rootimgchecksum to yes. The existing
images keep booting unchecked, and new images get the check. A later
upgrade finds the site attribute set and changes nothing. A new
installation sets site.rootimgchecksum to yes.
2026-10-13 15:29:22 -03:00
Vinícius Ferrão f8469e2074 feat(nodeset): tell nodes the root image checksum setting
Nodes could not know whether an image turned the root image checksum on.
An initial ramdisk built before the check booted the image unchecked,
and nothing reported it. An archive packed before the check had no
checksum for a new initial ramdisk to find.

When the image or the site turns the checksum on, nodeset adds
rootimgchecksum=yes to the kernel command line of the node. This applies
to stateless and statelite ramdisk nodes. genimage writes
<initrd>.rootimgcheck next to an initial ramdisk that can check. The
marker holds the SHA-256 checksum of the initial ramdisk, so a replaced
ramdisk does not match it. imgexport and imgimport carry the marker with
the ramdisk.

When the checksum is on, nodeset warns once for each image whose initial
ramdisk has no matching marker. Its nodes may boot the image unchecked.
nodeset judges the initial ramdisk in TFTP after it copies the boot
files, because nodes boot that copy, also with --noupdateinitrd. A copy
that fails is now an error for the node, instead of a boot entry for the
previous boot files.

genimage and nodeset write a checksum for each archive of the image
directory that has none, also when the check is off. Nodes with older
boot entries still check. genimage does it before it copies a new
initial ramdisk to TFTP, and nodeset before it copies the boot files of
a node. Both hold the publication lock while they write. When they
cannot write the checksum, they keep the boot files that nodes use now
and report how to recover. With the check off, nodeset reports it as a
warning instead, and still sets up the node. nodeset marks the boot
files of an image as copied only after this step succeeds. When the
first node of an image fails it, the next node copies them.

The change covers the Red Hat, SUSE and Ubuntu nodeset plugins, which
share one helper in xCAT::SvrUtils.
2026-10-13 15:29:22 -03:00
Vinícius Ferrão 883549fea2 feat(statelite): publish the liteimg ramdisk archive with its checksum
liteimg deleted rootimg-statelite.gz before it packed a statelite
ramdisk image, and wrote the new archive in place. It ignored a failed
pack, so nodes could get no image or a partial one. It took no image
lock. --tracker took no value, so the metainfo named the tracker 1, and
it described rootimg.gz instead of the new archive.

liteimg now takes the image lock and packs into the temporary directory
that packimage uses. It fails when a command of the pack fails. It
writes the SHA-256 checksum, and publishes it with the archive through
publish_rootimg. --tracker takes the tracker URL, as it does for
packimage, and the metainfo describes the new archive. Nodes keep
downloading the previous archive until the new one replaces it.
2026-10-13 15:29:21 -03:00
Vinícius Ferrão 529d25f96c feat(imgport): publish an imported root image the way packimage does
imgimport moved the published root image away, then moved the copy from
the bundle in. When the bundle was on another file system, that move was
a copy. Nodes could get no image or a partial one. The checksum that
packimage had published for the previous image also stayed.

imgimport now takes the image lock that genimage, packimage and rmimage
use. It stages the imported image and its checksum in the image
directory. It publishes both with the packimage helper, under the same
publication lock. It writes the checksum whatever the rootimgchecksum
attribute of the imported image, as packimage does. The previous image
stays as .ORIG through a hard link, and its metainfo is removed.

imgimport also places the root image before the kernel and ramdisk now.
When it cannot publish the root image, it stops, so the kernel and
ramdisk keep matching the published image. It takes the image lock
before it imports the image definition, so an import that another image
command blocks changes nothing.
2026-10-13 15:29:20 -03:00
Vinícius Ferrão 6660ca7a06 feat(packimage): publish the SHA-256 checksum of the root image archive
A node could not tell a damaged root image download from a good one,
because packimage published nothing to check it against.

packimage now writes rootimg.<suffix>.sha256 in sha256sum format next to
the archive. It builds the checksum in the temporary directory with the
archive, and publish_rootimg publishes both under the publication lock.
A pack that fails before publication keeps the previous archive and
checksum. When packimage removes the other formats, it keeps their
checksums, so a node that already downloads one can still check it.

Until the archive is replaced, the checksum file lists the new and the
previous archive. publish_rootimg computes the line of a previous
archive that has none. The published archive then matches a line of it
at each step, also when the publisher is killed. The previous metainfo
leaves first, so it never describes the new archive. publish_rootimg
keeps a link to the previous archive, or a copy with its mode without
hard links. When a step fails, the previous archive, checksum and
metainfo stay or come back. When it can keep the previous archive in
neither way, it publishes nothing. When it cannot put the previous
archive back, it keeps it in a .rootimg-previous-* directory and names
that directory in the error.

The new site.rootimgchecksum attribute is yes by default, and the
rootimgchecksum attribute of an osimage overrides it. They tell nodeset
whether nodes check the archive. packimage publishes the checksum
whatever their value, because nodes with older boot entries can still
check.
2026-10-13 15:29:20 -03:00
Vinícius Ferrão bc69dedf64 refactor(packimage): move root image staging and publication to SvrUtils
imgimport must replace a root image the way packimage does. Move the
host-scoped temporary directory and the locked publication from
packimage to xCAT::SvrUtils, so both commands can share them. The
publication still covers the archive and its metainfo. The behavior of
packimage does not change.
2026-10-13 12:00:11 -03:00
Daniel Hilst 84f693f493 refactor(kvm): move guest XML decisions into xCAT::KVMUtils
build_xmldesc, build_diskstruct and createstorage made their domain
decisions inline, so the unit tests could reach them only by loading the
whole plugin. kvm.pm now calls xCAT::KVMUtils for each decision and keeps
the libvirt calls, the table updates and the globals. $updatetable,
$confdata, $hypconn and $node are lexicals again.

The domain XML, the disk list and the volume names are unchanged.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-13 11:59:53 -03:00
Vinícius Ferrão 0c6bd1ba1f fix(imgport): write the imgexport bundle to its destination
A local imgexport wrote the bundle to the current working directory and
kept only the file name of the destination, so a destination such as
/backup/images/compute.tgz went to ./compute.tgz. A destination in a
missing directory failed only after the image was copied.

imgexport now writes the bundle to the destination, and takes a
relative path from the current working directory. It checks the
directory before it copies the image. tar and scp take the path as an
argument without a shell, so a path with a space works.
2026-10-13 11:40:16 -03:00
Vinícius Ferrão 1a71d9d33c fix(packimage): refuse an image directory that the shell would split
packimage passes the image directory to shell commands without quotes,
such as the rm -rf of the xcatpost directory. It finds its abandoned
stages with glob. For an image directory such as
"/install/custom images/node", the shell and glob split the path at the
space, so packimage removed /install/custom with the images in it.

packimage now refuses an image directory whose path has a space or a
shell character, before it runs any command.
2026-10-13 11:38:51 -03:00
Daniel Hilst fc6668d972 test(kvm): kvm_guest_arch.t tests a copy of the kvm.pm routines
kvm_guest_arch.t cut build_xmldesc and five other routines out of
kvm.pm with a regex and ran them with eval in a scratch package. The
test passed when kvm.pm changed in a way the regex did not see, and
it failed when kvm.pm was reformatted.

The test now loads kvm.pm with require and calls
xCAT_plugin::kvm::build_xmldesc and build_diskstruct. Sys::Virt and
the monitoring plugin are stubbed in %INC. kvm.pm declares
$updatetable, $confdata, $hypconn and $node with our instead of my,
so that the test can set them with local. The test sets XCATROOT to
the checkout and asserts that no module loads from /opt/xcat.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-12 13:45:53 -03:00
Vinícius Ferrão 49ffae9862 fix(packimage): replace the root image archive only after a complete pack
packimage deleted every rootimg.* file before it packed, and wrote the new
cpio or tar archive under its final name with mode 0600. Until the pack
finished, a node that booted got HTTP 403 for its image. When the pack
failed, the image was gone or left truncated, and no node could boot until
a later pack succeeded.

Build every archive in a temporary directory inside the image directory,
and rename the archive over the final name only after the pack succeeds,
as the openEuler path already did with a temporary file. With --tracker,
ctorrent builds the metainfo in the same directory, from the new archive
under its final name. The previous metainfo is removed before the archive
is renamed, and the new metainfo is renamed after it, so no failure
leaves a metainfo that describes another archive. The other rootimg.*
files are removed after the rename. The next pack on the same host
removes a temporary directory that an interrupted pack left. Image locks
are per host, so temporary directories of other hosts that share the
directory stay.

A pack now also fails when find cannot list the image or cpio cannot read
a file, as on the openEuler path. Before, only the compressor status
counted, and such a pack published an incomplete archive.

Every failure after packimage switches a StateLite tree to stateless files
now switches it back. That includes a failure to create the temporary
directory or the squashfs staging directory, which File::Temp reports
with die. packimage records each file that it moves and checks each move. When
a file cannot be moved back, the original stays in .statebackup,
packimage reports it, and the next pack refuses to run until the files
are restored. The new archive replaces the previous one only after the
StateLite files are back. Before, a failed pack left the tree switched,
and a retry overwrote the saved StateLite files.

The image lock is per host, and service nodes mount a shared image
directory without NFS locks. So a pack also holds the directory
.packimage-publish while it replaces the archive and removes the other
formats. mkdir is atomic for every host, also on NFS without locks. When
the lock is older than 60 seconds, or stays held for 60 seconds, the pack
fails, names the holder, and keeps the previous archive. packimage does
not take the lock over, because its holder can still be running.

A ctorrent failure now fails the pack, and the previous archive and
metainfo stay. Before, a failed ctorrent left a partial metainfo, and
nodeset pointed nodes at it.
2026-10-12 12:15:51 -03:00
Daniel Hilst ae9fd7912a Merge pull request #7932 from VersatusHPC/refactor/r26-string-trim
refactor(xcat): reuse whitespace trimming in blade and credential paths
2026-10-12 10:23:11 -03:00
Vinícius Ferrão 4879eef80b refactor(xcat): reuse whitespace trimming in blade and credential paths 2026-10-10 21:13:41 -03:00
Vinícius Ferrão 729b1b9aaa refactor(dhcp): reuse the hardware-address delete formatter 2026-10-10 17:41:20 -03:00
Daniel Hilst ff4fb0d660 fix(kvm): an ARM guest asks its hypervisor for a video model it has
The aarch64 profile named one video model for every hypervisor. A model is not
a property of the architecture: the emulator build decides it. On a host whose
aarch64 emulator carries no virtio-gpu device, libvirt answers "domain
configuration does not support video model 'virtio'" and mkvm cannot define the
node, while the riscv64 emulator of the same host offers virtio.

build_xmldesc() now reads the domain capabilities of the hypervisor and
preferred_video_model() returns the first model the profile wants that the
hypervisor offers. An aarch64 guest wants virtio and falls back to vga, which
is what an emulator with no virtio-gpu device offers. vm.vidmodel still
overrides both, and an architecture with no preference list makes no libvirt
call.

Measured on a hypervisor whose aarch64 emulator has no virtio-gpu device: the
builder picks vga and virsh define accepts the domain. The same builder asking
for virtio is refused there.

Three assertions in kvm_guest_arch.t fail without this change.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-08 12:31:29 -03:00
Daniel Hilst f59aceb0df fix(kvm): an ARM guest takes the accelerator and CPU of its hypervisor
guest_arch_profile() gave every aarch64 guest domain type qemu and the
cortex-a57 CPU model, so an aarch64 hypervisor ran its own guests under
emulation. The profile now reads both architectures: an aarch64 guest on an
aarch64 hypervisor is a kvm domain with CPU mode host-passthrough, which is the
only CPU KVM runs on ARM, and every other hypervisor keeps the emulated case
with the custom cortex-a57 model.

build_xmldesc() read the hypervisor cpumodel alone for the CPU model, the CPU
topology and the qemu-system-ppc64 emulator, so an aarch64 guest on a POWER
hypervisor received a POWER CPU model, a pseries topology and a ppc64 emulator.
The profile now marks a pseries guest and those three settings follow the mark.
libvirt resolves the emulator of an ARM guest from its own capabilities.

A cpumode from vm.othersettings reached a domain of either type. Both
host-passthrough and host-model read the host CPU, which an emulated guest does
not run, and libvirt reports both as unsupported for an emulated aarch64
domain. An explicit mode now reaches a kvm domain only.

The video model is virtio, as it is for a riscv64 virt guest. The aarch64 virt
machine supports virtio video; the earlier refusal came from an emulator build
with no virtio-gpu device.

kvm_guest_arch.t covers the four host and guest pairs and the explicit CPU
modes. Ten of its assertions fail without this change.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-08 12:18:01 -03:00
Daniel Hilst 02a266c236 fix(kvm): mkvm builds an aarch64 node as an x86_64 domain
guest_arch_profile() in the kvm plugin has an arm for riscv64 and an arm for
POWER, and none for aarch64. A node whose nodetype.arch is aarch64 therefore
keeps the x86 defaults, and mkvm defines a domain with os/type/@arch x86_64 and
machine pc-i440fx. The compute node gets its lease, loads the x86 iPXE ROM,
fetches the grub2.aarch64 image that nodeset staged, and answers "Could not
boot image: Exec format error". It then falls through to the empty disk.

guest_arch_profile() now returns an aarch64 profile: domain type qemu, os arch
aarch64, machine virt, UEFI firmware, no x86 features and no SeaBIOS serial
option, no USB tablet, and scsi disks with the sd prefix. machine is the
unversioned alias, so libvirt resolves the version the hypervisor has. The
video model stays vga, unlike riscv64: the aarch64 virt machine offers no
virtio video model, and libvirt refuses the domain that asks for one.

The profile also names a CPU model, which riscv64 did not need. With no <cpu>
element libvirt passes -cpu max, which under TCG turns on SVE, and the guest
stays in its firmware. build_xmldesc writes the model only when nothing else
built a cpu element, so vm.cpumode and a pseries guest keep theirs.

kvm_guest_arch.t covers the new arm. Eleven of its assertions fail without this
change.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-10-08 03:35:05 -03:00