2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-22 07:38:08 +00:00
Commit Graph

28090 Commits

Author SHA1 Message Date
Daniel Hilst 58d8aa45eb docs(dhcptest): specify the DHCP behaviour a booting node observes
Write down, as scenarios, what xCAT's DHCP server is supposed to do from the
point of view of a machine booting on a provisioning network: which address it
gets, what it is told to boot, where it fetches the loader from, and what else
the reply has to carry for a deployment to complete.

Read out of the source rather than from the documentation, and cited back to it
line by line, so a scenario that stops matching xCAT is a bug in one of the two
and it is clear which.

Scenarios that cannot be seen from the wire -- a generated file, a daemon's
command line -- are marked [config] and belong to the Perl unit tests instead.
The rest defines the domain the dhcptest wire cases are measured against,
including the ISC/Kea asymmetries the source shows but nothing yet asserts.
2026-09-10 09:45:41 -03:00
Daniel Hilst 4bf66d7c0b fix(dhcp): start dhcpd on the interfaces xCAT serves on Debian
makedhcp wrote the interface list into /etc/default/isc-dhcp-server as

    INTERFACES="..."

which is no longer always the variable the daemon is started with. The
systemd unit sources that file and expands exactly one variable onto dhcpd's
command line, and which one changed with the package:

    14.04  4.2.4-7ubuntu12      sysvinit only   $INTERFACES
    16.04  4.3.3-5ubuntu12      unit            $INTERFACES
    18.04  4.3.5-3ubuntu7       unit            $INTERFACES
    20.04  4.4.1-2.1ubuntu5     unit            $INTERFACES
    22.04  4.4.1-2.3ubuntu2     unit            $INTERFACESv4
    24.04  4.4.3-P1-4ubuntu2    unit            $INTERFACESv4
    26.04  4.4.3-P1-4ubuntu2    unit            $INTERFACESv4

with the matching v6 unit reading $INTERFACES before the change and
$INTERFACESv6 after it. Note the boundary is not an upstream ISC release:
20.04 and 22.04 both ship upstream 4.4.1 and are told apart only by the
Debian revision, so it has to be decided on the whole package version.

The sysvinit script does copy INTERFACES into INTERFACESv4 when the latter is
empty, but the unit is what starts the daemon on any of these releases and it
has no such bridge. So from 22.04 on, the unit ran

    exec dhcpd -user dhcpd -group dhcpd -f -4 ... -cf $CONFIG_FILE $INTERFACESv4

against a variable xCAT never set. An unset variable expands to nothing, so
dhcpd was launched with no interface argument at all. It does not fail for
that: it binds every interface it can find and only warns about the ones with
no subnet declaration. site.dhcpinterfaces and servicenode.dhcpinterfaces
were therefore silently inert -- the provisioning NIC was served because
makedhcp had also emitted a subnet stanza for it, not because anything
honoured the setting, and any other interface on that subnet was served
alongside it.

The line match compounded it. m/^$dhcpd_key/ is not anchored on the
assignment, and INTERFACES is a prefix of both variables the package ships.
Since 18.04 the postinst seeds only INTERFACESv4="" and INTERFACESv6="" --
no INTERFACES line exists to match -- so the rewrite claimed those two lines
instead and overwrote both, discarding whatever debconf or the administrator
had put there and leaving a file with two INTERFACES assignments and nothing
either unit reads.

Pick the variables through a dispatcher keyed on the installed
isc-dhcp-server version, so both behaviours are served rather than one being
traded for the other, and anchor the match on the '=' so a key cannot claim a
line it is merely a prefix of. When the version cannot be established the
dispatcher writes every spelling, since an unset variable is the outcome that
leaves dhcpd bound to everything. Duplicate assignments left behind by the
old writer are collapsed to one, which repairs a file already damaged on an
upgraded management node.

The EL and SLES paths keep their single DHCPDARGS / DHCPD_INTERFACE /
DHCPD6_INTERFACE key and are unchanged.
2026-09-10 09:31:51 -03:00
Daniel Hilst 33bf641a72 test(dhcp): capture makedhcp leaving dhcpd unrestricted on Debian
On Debian and Ubuntu, makedhcp writes the list of interfaces it is serving
into /etc/default/isc-dhcp-server using the key set at dhcp.pm:2296:

    $dhcpd_key = "INTERFACES";

That key stopped being the one the daemon is started with. The variable the
isc-dhcp-server systemd unit expands onto dhcpd's command line changed with
the package; verified by unpacking the archive's own debs:

    trusty  4.2.4-7ubuntu12     sysvinit only   INTERFACES
    xenial  4.3.3-5ubuntu12     unit            $INTERFACES
    bionic  4.3.5-3ubuntu7      unit            $INTERFACES
    focal   4.4.1-2.1ubuntu5    unit            $INTERFACES
    jammy   4.4.1-2.3ubuntu2    unit            $INTERFACESv4
    noble   4.4.3-P1-4ubuntu2   unit            $INTERFACESv4 (+ a v6 unit
                                                reading $INTERFACESv6)

and every package from bionic onward ships a default file whose only
interface variables are INTERFACESv4 and INTERFACESv6, both seeded empty by
postinst. No INTERFACES line ships at all.

Two things go wrong on jammy and later.

The unit runs `exec dhcpd ... -cf $CONFIG_FILE $INTERFACESv4`. That variable
is never set, so it expands to nothing and dhcpd is launched with no
interface argument. dhcpd does not fail for this: it binds every interface
it can find and merely warns about the ones with no subnet declaration. So
site.dhcpinterfaces and servicenode.dhcpinterfaces are silently inert. The
provisioning NIC is served only because makedhcp also emitted a subnet
stanza for it, not because anything honoured the setting, and any other
interface on that same subnet -- a bridge port, a bond member, a second NIC
-- is served too.

The line match is m/^$dhcpd_key/, which is not anchored on the assignment.
"INTERFACES" is a prefix of both variables the package ships, so the rewrite
claims the INTERFACESv4 and INTERFACESv6 lines and overwrites both. The file
is left holding two INTERFACES lines and nothing the units read, discarding
whatever debconf or the administrator had set there.

Extract the rewrite into _sysconfig_interfaces_content() with no change in
behaviour, and add a unit test that asserts the effect rather than the
spelling: it writes the produced file to a temp path and sources it with sh
exactly as the unit does, then checks what would land on dhcpd's command
line. The test is red against the current key and stays red until the writer
sets the variables the daemon is actually started with.
2026-09-10 09:17:38 -03:00
Daniel Hilst 349204f783 fix(dhcptest): make the wire cases runnable from an installed package
Two things would have kept the wire cases from doing anything on a management
node built from the deb.

src/dhcptest was committed without its executable bit. The spec chmods it at
install time, but dh_install copies the source mode straight through, so on a
deb-installed node the fixture's `[ -x ]` check failed and every wire case
stood down with "dhcptest is not installed" -- passing while testing nothing,
which is the exact failure mode the fixture exists to avoid.

Teardown restarted the backend that was running before the fixture started but
left the one the backend-switch case switched to still running. Two servers on
one network answer the same DISCOVER, so the next case to look at that network
would see an offer from a daemon nobody asked for.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-10 08:54:14 -03:00
Daniel Hilst f2112dcafa test(dhcptest): drive xCAT-generated DHCP config from the wire
dhcptest could already assert on what a server puts on the wire, but on a
single-node management node -- the CI runner above all -- there was nothing
for it to talk to, so a wire case would have passed while proving nothing.

dhcpfixture.sh builds the missing network out of a veth pair: the server end
carries the management address and is the only interface named in
site.dhcpinterfaces, the client end has no address, which is the state a
provisioning NIC is in when a machine boots on it. It then defines a network
with a dynamic range and one node with a MAC, runs makedhcp so the
configuration comes from xCAT rather than from hand-editing, and restores
everything from a trap. All the xCAT knowledge lives there, next to the
xcattest cases, so dhcptest itself stays agnostic to it.

The new scenarios assert what a provisioning server has to get right:

  provision-vs-discovery.conf    a known machine gets its reservation and its
                                 own loader, an unknown one gets a pool address
  discovery-bootfile.conf        an unknown machine is told what to boot too
  node-specific-second-stage.conf  the chainloaded stage names its host
  hierarchy-dhcpserver.conf      a subnet whose pool was handed to another
                                 server ignores unknown MACs but still points
                                 known ones at it

Those are four files rather than four scenarios in one because they describe
server configurations that contradict each other, and because --set values are
resolved when a file is loaded, before -s selects anything: an unused
scenario's missing variable would otherwise abort a run that never intended to
use it. ISC dhcpd leaving the unknown-client boot file to the per-host blocks
while Kea puts it on the subnet is exactly such a contradiction, which is why
discovery-bootfile.conf is opt-in and the fixture only asks for it on Kea.

dhcptest_backend_switch reruns the same files after switching site.dhcpbackend
and regenerating, so the backend-agnosticism the tool exists to demonstrate is
itself under test rather than asserted in a comment.

The `in` operator now accepts an inclusive first-last range as well as a CIDR
and a list: a dynamic pool is written as two addresses because it rarely lines
up on a prefix boundary.

Verified against a real dnsmasq in a network namespace: 17/17, 3/3 and 5/5
assertions green, a deliberately wrong expectation failing with expected and
received on one screen, and host networking untouched.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-10 08:51:10 -03:00
Daniel Hilst 008f83d2e4 test(xCAT-test): add dhcptest, a wire-level DHCP client test tool
xCAT's DHCP behaviour is tested from two directions today, neither of which
touches the wire: xCAT-test/unit/dhcp_*.t assert on generated config text, and
xCAT-test/integration/dhcp_{isc,kea}_config_validation.t feed that config to a
real daemon and check it parses. Both stop at "the server accepted our
config". Nothing verifies that a client sending option 93 = 0x000b actually
gets an aarch64 loader back.

The one existing wire tool, xCAT-probe/subcmds/detect_dhcpd, hand-packs a
fixed DISCOVER carrying no option 60, 77 or 93 (so it never reaches any arch
branch), parses replies by regexing tcpdump output, and binds an
IO::Socket::INET to a local address, so it cannot run on a provisioning NIC
that has no address yet.

dhcptest fills that gap. It is a Python 3 tool using only the standard library
plus Scapy, speaking raw Layer 2, driving DHCP transactions declared in INI
files and asserting on what came back:

  dhcptest run      -i eth1 --set net=10.0.0.0/24 conf/full-lease.conf
  dhcptest validate conf/*.conf      # no root, no network, no scapy
  dhcptest list     conf/*.conf
  dhcptest discover -i eth1          # ad-hoc, no conf file

Scenarios cover DISCOVER/OFFER, the full lease, renew and rebind, reserved
versus pooled addresses, deliberate silence, the PXE architecture matrix and
the iPXE user-class split. Assertions are a small DSL -- target, operator,
value -- over message type, BOOTP header fields, options by number or name,
subnet membership, and the boot file a client would actually use (option 67
or the header, since servers differ on which they fill).

Two boundaries are enforced by unit test rather than by convention:

  - The tool is implementation-agnostic. It exchanges packets and checks
    fields; it never reads the xCAT database, never runs an xCAT command, and
    names no DHCP implementation. Anything that differs between servers is
    expressed by whoever writes the .conf.
  - Only runner.py imports scapy, so validate and list stay usable in CI on a
    host with neither scapy nor root.

Host networking is never modified. The client MAC defaults to a synthetic
locally-administered address, everything goes over a raw L2 socket, no leased
address is ever configured, and the ARP responder answers only for addresses
the session was actually granted.

Variables in .conf files are configparser's own BasicInterpolation, %(name)s,
fed from [vars] and --set. $offer.address and friends are resolved separately
at step-execution time, because they name a reply that has not arrived when
the file is read; BasicInterpolation gives $ no meaning, so the two coexist
without escaping.

Packaging and CI:

  - xCAT-test.spec installs dhcptest alongside unit/ and integration/, and
    only recommends python3-scapy: it lives in EPEL on EL, and a hard Requires
    would make xCAT-test uninstallable on a management node without EPEL.
    The deb depends on it outright.
  - github_action_xcat_test.pl runs the unit tests and `dhcptest validate`
    last, after the fast regression.
  - autotest/testcase/dhcptest/cases0 carries the two offline cases plus a
    wire case that stands down with an explanation when no provisioning NIC
    is available.

Verified against a real DHCP server in a network namespace: 34 lease, renew,
rebind, reservation and silence assertions and 22 PXE/iPXE assertions all
pass, and host networking is untouched before and after.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-10 08:19:41 -03:00
Vinícius Ferrão 17126c74a9 Merge pull request #7823 from VersatusHPC/feat/bats-shell-tests
test(xcat-core): Introduce BATS & convert shell scripting tests to it
2026-09-09 19:48:49 -03:00
Daniel Hilst 3cade9651c Merge pull request #7821 from VersatusHPC/feature/ubuntu-riscv64
feat(ubuntu): support riscv64 management and provisioned nodes on 24.04 and 26.04
2026-09-09 10:50:07 -03:00
Vinícius Ferrão 166da7c1b6 test(xCAT-test): cover the install architectures debian.pm accepts
The plugin is loaded and install_darch is called for the architectures
xCAT installs Ubuntu on and two it does not. Against the previous plugin the
test fails on the missing function: the mapping was inline in mkinstall.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:34 -03:00
Vinícius Ferrão a6e69e88a4 fix(debian): stop reporting riscv64 as an unknown install architecture
mkinstall mapped x86_64 and x86 to their Debian names and accepted ppc64le
and ppc64el. Every other architecture, riscv64 included, was logged as
"Unknown arch" on each diskful install, although the install went on with
the name unchanged, which is right for riscv64.

Move the mapping into install_darch, which takes the Debian name from
xCAT::Utils::debian_arch and knows the architectures xCAT installs Ubuntu
on. riscv64 is one of them.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:34 -03:00
Vinícius Ferrão 5a541814df test(xCAT-test): pin what a riscv64 management node installs and serves
The grub-common assertion fails against the previous metapackage. The rest pins
what must NOT change: a riscv64 management node still recommends the x86 boot
payload and the Genesis images of the other architectures, because it serves
them to the nodes it provisions.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:33 -03:00
Vinícius Ferrão f0c7803595 test(xCAT-test): cover the declaration of the loader build tool
Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:33 -03:00
Vinícius Ferrão 53692323b4 fix(xCAT-server): declare the tool copycd builds the riscv64 loader with
copycd builds the riscv64 boot loader by running grub-mkimage, which
grub-common ships on every supported Ubuntu release. Nothing declared it, so a
management or service node installed without that package copies riscv64 media
and produces no loader, while DHCP keeps pointing every riscv64 node at the path
where the loader should be.

The declaration belongs to xcat-server, which carries the plugin that runs the
command, so both metapackages inherit it.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:32 -03:00
Vinícius Ferrão 9f35a4b8cb test(xCAT-test): build the riscv64 loader from real Ubuntu media
The stubbed test proves the decisions copycd makes; this one proves the
artifact. It runs the real grub-mkimage over the grub2 package of copied media
and checks the image against the validation nodeset depends on, so a package
layout change or a grub-mkimage that stops accepting these inputs is caught
where it happens.

It needs media and the grub2 tools, so it skips without
XCAT_TEST_UBUNTU_RISCV64_MEDIA. Run on a management node against the 24.04 and
26.04 riscv64 trees.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:32 -03:00
Vinícius Ferrão 56910729ce test(xCAT-test): drive the mirror choice with the osarch value genimage reads
The mirror assertions passed a Debian architecture straight in and so never
exercised the conversion genimage performs first. They now start from the xCAT
osarch value, which is what let the 32-bit x86 token reach the wrong archive.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:32 -03:00
Vinícius Ferrão a2139d03ed fix(perl-xCAT): map the 32-bit x86 architecture to i386
genimage converts osimage.osarch with debian_arch and uses the result twice: it
picks the apt mirror and it becomes debootstrap --arch. The map knew x86_64 but
not x86, so an image with osarch=x86 selected the ports archive, which carries
no i386, and then asked debootstrap for an architecture it does not know.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:32 -03:00
Vinícius Ferrão 828d0d2fdf test(xCAT-test): capture a riscv64 build depending on the x86 Genesis scripts
Four assertions fail against the previous debian/control: the dependency has no
architecture restriction, and dpkg's own parser still reports it for riscv64.
The last assertion pins that the restriction drops nothing else.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:31 -03:00
Vinícius Ferrão 588a0504bf fix(xCAT): stop a riscv64 management node pulling the x86 Genesis
xcat-genesis-scripts-amd64 is Architecture: all, so the plain Depends installed
the x86 legacy Genesis scripts, and the x86 Genesis base with them, on a riscv64
management node. riscv64 has no legacy Genesis: its image ships as
xcat-genesis-openembedded-riscv64, which the metapackage already recommends and
mknb consumes. xCAT.spec makes the same distinction on the rpm side.

The dependency is now restricted to the architectures that have a legacy
Genesis. amd64 and ppc64el keep it unchanged.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:31 -03:00
Vinícius Ferrão 79cddca53e docs(riscv64): document Ubuntu 24.04 and 26.04 support
The guides said riscv64 covered EL10 only, and the riscv64 page listed
Ubuntu as unsupported. Both support matrices now carry the architecture for
Ubuntu, and the riscv64 page describes the Ubuntu paths: the loader copycd
builds from the media, the installer needing none of the accommodations
EL10 requires, the ports archive the packages come from, and a management
node running on riscv64. The 26.04 media need the RVA23 profile, which is
recorded as a limitation.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:31 -03:00
Vinícius Ferrão c32c941ed7 fix(mknb): say where the riscv64 loader comes from on Ubuntu
The note shown when boot/grub2/grub2.<arch> is missing told the
administrator it comes from grub2-xcat or the EL installation media. On
Ubuntu neither is true: copycd builds the loader from the grub2 package on
the media, because the image the media carry cannot boot over the network.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:31 -03:00
Vinícius Ferrão f9baf6e05b test(xCAT-test): follow the riscv64 netboot values naming Ubuntu
The assertion pinned the EL-only text and failed once the documented values
named Ubuntu as well.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:31 -03:00
Vinícius Ferrão c92a6b1927 fix(perl-xCAT): name Ubuntu in the riscv64 netboot values
The noderes.netboot table gave riscv64 the condition >=el10, so the only
documented way to reach grub2 on the architecture was an EL node, although
lookupNetboot answers grub2 for riscv64 whatever the operating system. The
condition now names Ubuntu as well, the way ppc64 names both of its
families.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:28 -03:00
Vinícius Ferrão 33eba52b96 test(xCAT-test): cover the packages go-xcat installs on riscv64
Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:28 -03:00
Vinícius Ferrão 5957e7125d feat(go-xcat): install xCAT on a riscv64 management node
go-xcat stopped on riscv64 before it reached the package manager, so the
installer xCAT documents could not set up the management node the riscv64
packages are built for. The architecture is now accepted alongside the
others.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:27 -03:00
Vinícius Ferrão 44f125b63d test(xCAT-test): cover the install mirror the template renders
Calls the selection the template performs. Covers the ports archive for
ppc64el and both spellings of ppc64, the main archive for every x86
spelling, an unknown architecture keeping the previous default, and
site.ubuntu_apt_mirror overriding both without an empty value blanking the
mirror.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:27 -03:00
Vinícius Ferrão 5b6120a182 fix(template): take the install mirror from the ports archive off amd64
archive.ubuntu.com publishes amd64 and i386 only, so a ppc64el or riscv64
node was given an apt mirror carrying no package for it and the installer
could not fetch what the minimal live media lacks. The default is now the
ports archive for those architectures, chosen from the osimage's
architecture rather than the package directory, which is whatever path the
administrator configured. site.ubuntu_apt_mirror still overrides it.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:27 -03:00
Vinícius Ferrão 5c4b83b853 test(xCAT-test): cover the grub2 kernel command line quoting
Calls the escaping the plugin performs. Covers the Ubuntu installer seed
keeping the arguments after it, every separator grub2 recognizes, a command
line without one staying byte for byte the same, escaped and quoted values
surviving unchanged, a separator beside a quoted span in the same word, and
a variable reference being left alone so BOOTIF still expands.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:27 -03:00
Vinícius Ferrão 52e468884e fix(grub2): keep the whole kernel command line past a grub2 separator
grub2 reads its configuration as a script, so an unquoted command separator
ends the linux command and everything after it is lost. The Ubuntu
installer seed is written as ds=nocloud-net;s=<url>, so the node booted
without the seed URL and without the arguments that followed it, including
BOOTIF. The installer then found no autoinstall configuration and waited
for someone to answer its questions. A separator that is neither escaped
nor inside a quoted span is now escaped where it stands, which grub2
removes before it hands the line to the kernel. A value the caller escaped
or quoted keeps exactly the form the caller gave it.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:27 -03:00
Vinícius Ferrão 7fed9001e8 test(xCAT-test): cover the riscv64 Ubuntu network drivers
Reads the list imgutils returns. Covers the drivers a node needs to reach
its root filesystem, the overlay module, the architectures that already
worked keeping theirs, and an unknown architecture still getting an empty
list.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 22:01:26 -03:00
Vinícius Ferrão 53709af9b3 feat(imgutils): give riscv64 Ubuntu netboot images their network drivers
The Ubuntu driver table had no riscv64 entry, so genimage was handed an
empty list and built an image carrying no network module. A node whose NIC
is not built into the kernel then has no interface to fetch its root
filesystem with. The architecture now gets the same drivers the enterprise
Linux table lists for it, plus the overlay module every Ubuntu image needs.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:04 -03:00
Vinícius Ferrão 9812d14928 test(xCAT-test): cover the netboot mirror genimage defaults to
Evaluates the selection genimage performs, so the test tracks the script.
Covers the ports archive for ppc64el and riscv64, the main archive for
amd64 and i386, and site.ubuntu_apt_mirror overriding both without an
empty value blanking the mirror.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:04 -03:00
Vinícius Ferrão f1b044f2a8 fix(genimage): take the netboot mirror from the ports archive off amd64
archive.ubuntu.com publishes amd64 and i386 only, so debootstrap could not
find a single package for a ppc64el or riscv64 netboot image and genimage
failed on every architecture except x86. The default mirror is now the
ports archive for those architectures. site.ubuntu_apt_mirror still
overrides it, for a local mirror that serves every architecture.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:04 -03:00
Vinícius Ferrão b0bf36d27a test(xCAT-test): cover the riscv64 Ubuntu management node packaging
Extends the builder tests with the per-package architecture lists and the
architectures a release declares, and adds the generated mklocalrepo.sh
mapping a riscv64 host to its own repository. Also checks that xcat and
xcatsn declare riscv64 without losing amd64 or ppc64el.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:03 -03:00
Vinícius Ferrão 4766f4441f feat(build): build and publish the Ubuntu management node for riscv64
The xcat and xcatsn packages declared only amd64 and ppc64el, and the
builder built and indexed only those two architectures, so a riscv64
management node had no package to install. Both packages are now built for
riscv64, every release the repository serves declares the architecture,
and the generated mklocalrepo.sh maps a riscv64 host to its own repository
instead of amd64. Each package now carries its own architecture list:
xCAT-genesis-scripts keeps the two it has control files for, because
riscv64 Genesis ships as an OpenEmbedded package instead.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:03 -03:00
Vinícius Ferrão 459ec2a8c3 test(xCAT-test): cover the loader copycd builds from Ubuntu media
Drives the build with dpkg-deb and grub-mkimage shadowed by stubs, so the
assertions read the arguments that decide whether the image can boot over
the network: the firmware format, the prefix nodeset writes into, the
module directory, and the network modules. Also covers the warning a node
without a loader gets, an interrupted build leaving nothing behind, a real
riscv64 loader being kept, text, a truncated image, another architecture's
loader, images with nothing to execute and an image built for another boot
path all being replaced, and a rejected loader being gone when the media
cannot replace it.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:03 -03:00
Vinícius Ferrão 01e9ea5152 feat(copycds): build the riscv64 grub2 loader from the Ubuntu media
riscv64 nodes have no boot loader unless one reaches /tftpboot/boot/grub2,
and nothing on an Ubuntu management node puts one there. The grub2 image
the media carry cannot serve: it holds a built-in configuration that looks
for the live filesystem, so a node that loads it drops to a grub prompt
instead of reading the configuration nodeset writes. copycd now builds a
netboot image from the grub2 package the media ship, and warns when it
cannot, because the node has no other source for one. An image already in
place is kept only when it is a whole executable image for the
architecture the firmware loads and carries the prefix this boot path
needs; one that is not is removed, so a rebuild that cannot run leaves
nodeset reporting a missing loader rather than serving an unusable one.
The media of every other architecture are untouched.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:03 -03:00
Vinícius Ferrão fc73cd91f1 test(xCAT-test): cover the riscv64 Ubuntu package lists
Pin that both releases carry a riscv64 list, that it holds what the x86_64 list
holds, and that it keeps the kernel and the NFS client a diskless node needs.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:03 -03:00
Vinícius Ferrão 7d161b822b feat(xCAT-server): add the riscv64 Ubuntu package lists
24.04 and 26.04 had no riscv64 package list, so a diskless image or an install
for the architecture fell back to the generic list and reached debootstrap
without a kernel or the tools the boot scripts call.

The lists hold the same packages as their x86_64 counterparts. Every one of
them is published for riscv64 in noble and resolute, main or universe.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:03 -03:00
Vinícius Ferrão 7a2499fbfb test(xCAT-test): cover the resolver libraries the netboot image takes
Build a root filesystem for each architecture and run genimage's selection over
it, so the riscv64 libraries are taken from their own directory and the other
architectures keep the files they take today.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:03 -03:00
Vinícius Ferrão 75fa389d33 feat(genimage): add the riscv64 resolver libraries to the netboot image
The image carries the name service libraries of its architecture, and riscv64
matched neither the x86_64 nor the ppc64el branch. It fell through to the
generic path, which looks for lib/libnss_dns.so.2, so a riscv64 image shipped
without a resolver and the node could not resolve any name.

Ubuntu keeps them in lib/riscv64-linux-gnu, confirmed in the 24.04.4 riscv64
server filesystem.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:03 -03:00
Vinícius Ferrão d09452c0b9 test(xCAT-test): cover riscv64 Ubuntu media
Pin the kernel and initrd the riscv64 live image carries, that the kernel name
the other live images use is not accepted for it, and that the architecture the
media reports maps to riscv64 in both directions.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:02 -03:00
Vinícius Ferrão 4e36e1a9f2 feat(debian): recognize riscv64 Ubuntu media
The riscv64 live-server image keeps its kernel at casper/vmlinux, where every
other live image keeps casper/vmlinuz, so the probe found no kernel and mkinstall
reported that the install image was missing.

Add the riscv64 candidate pair and let copycd name the architecture the media
reports. Verified against Ubuntu-Server 24.04.4 riscv64, which carries
casper/vmlinux, casper/initrd and casper/install-sources.yaml.

Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
2026-09-08 17:02:02 -03:00
Daniel Hilst a8e770c42e fix(xcat-core): Prevent BATS checks from missing failures
Negative checks could pass when a later command succeeded. The diskless test also read host state and wrote to the host wget log.

The SSH fallback test did not prove that the restart waited for the killed process.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-08 15:28:04 -03:00
Daniel Hilst cd4d903879 Merge pull request #7820 from VersatusHPC/fix/ubuntu-install-pkglists
Make ospkgs and detect_dhcpd work on current Ubuntu releases
2026-09-08 14:13:17 -03:00
Daniel Hilst cc36d25c35 test(xcat-core): Keep xcatdsklspost download local
xcatdsklspost can run before xcatlib.sh is available beside it in stateless and statelite image contexts. Moving download_postscripts into xcatlib.sh could leave the legacy postscript without its callee when it is copied by itself into the image.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-08 13:10:13 -03:00
Daniel Hilst 58c030a8f3 test(xcat-core): Move BATS tests beside unit tests
Shell unit tests were introduced under xCAT-test/autotest/bats, but the existing source-tree unit suite already lives directly under xCAT-test/unit. Keeping the BATS suite under xCAT-test/bats makes the unit-test layout consistent and keeps autotest reserved for xcattest-driven functional cases.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-08 13:03:34 -03:00
Daniel Hilst 3e302e7f19 test(xcat-core): Introduce BATS & convert shell scripting tests to it
The go-xcat shell behavior tests were written as Perl harnesses, which made the shell assertions harder to read and kept shell-specific setup outside a native shell test framework.

Add BATS to the GitHub Actions dependency set, run BATS tests from the same preserved source tree as the Perl unit suite, and move the go-xcat repository checks into xCAT-test/autotest/bats.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
2026-09-08 12:57:16 -03:00
Daniel Hilst 796103c300 Merge pull request #7822 from VersatusHPC/fix/go-xcat-el10-repos
fix(go-xcat): check the EPEL and CRB repositories on EL10 as well
2026-09-08 12:02:19 -03:00
Vinícius Ferrão 107f7b14ec test(xCAT-test): drive detect_dhcpd with tcpdump on PATH
Both scripts run for real with PATH holding one directory that carries a
tcpdump stand-in, which records the path and arguments it was started with.
The plain run stops at the interface step, before any socket or capture. The
capture runs inside a private network and mount namespace, where the loopback
interface is the only one, its default route keeps the DHCP discover on the
host, a tmpfs over /tmp holds the dump file, and /usr/sbin/tcpdump is hidden
so the previous guard fails there on every host. Hosts that cannot create the
namespace skip that part.
2026-09-08 11:43:00 -03:00
Vinícius Ferrão 20eef6d224 fix(detect_dhcpd): find tcpdump through PATH
Both copies refused to run unless /usr/sbin/tcpdump existed. Debian and Ubuntu
install it as /usr/bin/tcpdump, so the rogue DHCP detector never ran there and
the probe reported its tcpdump check as failed.

Resolve tcpdump through PATH and the standard system directories with
CommandUtils::find_executable, run the resolved path, and match that path when
the capture process is killed at the end.
2026-09-08 11:43:00 -03:00