mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-05-09 10:10:09 +00:00
Fix Kea UEFI reservation boot policy
This commit is contained in:
@@ -15,13 +15,37 @@ Use this matrix for:
|
||||
* DDNS and service-management changes
|
||||
* PXE, xNBA, or boot-policy changes
|
||||
|
||||
Acceptance Scope
|
||||
----------------
|
||||
|
||||
The validation result for this matrix is scoped to DHCP backend behavior and
|
||||
boot handoff:
|
||||
|
||||
* backend selection matches the platform policy
|
||||
* generated backend configuration validates with the backend-native validator
|
||||
* static reservations allocate correctly, including Kea reservations outside
|
||||
``networks.dynamicrange``
|
||||
* dynamic pools are emitted only by the DHCP server that owns the network
|
||||
* the expected bootloader, node script, kernel, initrd, or root image artifacts
|
||||
are offered and fetched for the row under test
|
||||
* shell-oriented rows reach the expected xNBA or Genesis shell state
|
||||
|
||||
Failures after the expected boot artifacts have been delivered are image,
|
||||
initrd, kernel, userspace, or packaging follow-up work. They must be tracked,
|
||||
but they do not turn the DHCP backend acceptance row red unless the failure is
|
||||
caused by DHCP policy, allocation, or boot option rendering.
|
||||
|
||||
Secure Boot is not part of this matrix. Secure OVMF builds such as
|
||||
``OVMF_CODE.secboot.fd`` and ``OVMF_VARS.secboot.fd`` must be treated as
|
||||
unsupported unless xCAT explicitly adds Secure Boot support.
|
||||
|
||||
Backend Policy
|
||||
--------------
|
||||
|
||||
The default backend split is:
|
||||
|
||||
* EL9, Ubuntu 22.04 LTS, and older supported releases: ``ISC DHCP``
|
||||
* EL10, Ubuntu 24.04 LTS, and newer supported releases: ``Kea``
|
||||
* EL9, Ubuntu 20.04 LTS, and older supported releases: ``ISC DHCP``
|
||||
* EL10, Ubuntu 22.04 LTS, and newer supported releases: ``Kea``
|
||||
|
||||
``site.dhcpbackend=auto`` must follow that rule. Explicit ``isc`` and ``kea``
|
||||
overrides remain available for development and troubleshooting.
|
||||
@@ -40,6 +64,8 @@ Run these checks for every DHCP backend change before live validation:
|
||||
``require-client-classes``
|
||||
* Kea 3.x output must use ``only-in-additional-list`` and
|
||||
``evaluate-additional-classes``
|
||||
* Kea UEFI x86_64 boot classes must cover PXE architecture ids ``0x0007``
|
||||
and ``0x0009`` plus UEFI HTTP boot architecture id ``0x0010``
|
||||
|
||||
* backend-native configuration validation:
|
||||
|
||||
@@ -69,26 +95,100 @@ The following matrix is the default live validation gate for DHCP backend work.
|
||||
- ``xNBA shell``
|
||||
- ``makedhcp -n``; ``dhcpd -t``; reservation add/query/delete; DHCP/TFTP;
|
||||
node-specific xNBA handoff; Genesis fetch
|
||||
* - Ubuntu 22.04 LTS
|
||||
* - Ubuntu 20.04 LTS
|
||||
- ``x86_64``
|
||||
- ``ISC``
|
||||
- ``xNBA shell``
|
||||
- ``makedhcp -n``; ``dhcpd -t``; reservation add/query/delete; DHCP/TFTP;
|
||||
node-specific xNBA handoff; Genesis fetch
|
||||
* - Ubuntu 22.04 LTS
|
||||
- ``x86_64``
|
||||
- ``Kea``
|
||||
- ``xNBA shell`` and compute-image handoff
|
||||
- ``makedhcp -n``; ``kea-dhcp4 -t``; reservation add/query/delete;
|
||||
xNBA shell boot; compute-image boot artifact handoff through kernel,
|
||||
initrd, and root image when image validation is in scope
|
||||
* - EL10
|
||||
- ``x86_64``
|
||||
- ``Kea``
|
||||
- ``xNBA shell`` and ``full netboot image``
|
||||
- ``xNBA shell`` and compute-image handoff
|
||||
- ``makedhcp -n``; ``kea-dhcp4 -t``; reservation add/query/delete;
|
||||
xNBA shell boot; full compute-image boot through kernel, initrd, and
|
||||
root image
|
||||
xNBA shell boot; compute-image boot artifact handoff through kernel,
|
||||
initrd, and root image when image validation is in scope
|
||||
* - Ubuntu 24.04 LTS
|
||||
- ``x86_64``
|
||||
- ``Kea``
|
||||
- ``xNBA shell`` and ``full netboot image``
|
||||
- ``xNBA shell`` and compute-image handoff
|
||||
- ``makedhcp -n``; ``kea-dhcp4 -t``; reservation add/query/delete;
|
||||
xNBA shell boot; full compute-image boot through kernel, initrd, and
|
||||
root image
|
||||
xNBA shell boot; compute-image boot artifact handoff through kernel,
|
||||
initrd, and root image when image validation is in scope
|
||||
|
||||
Kea Boot and Reservation Regression Matrix
|
||||
------------------------------------------
|
||||
|
||||
Run this matrix whenever a change touches Kea boot policy, client
|
||||
classification, address pools, or host reservations.
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 20 18 62
|
||||
|
||||
* - Scenario
|
||||
- Backend Scope
|
||||
- Minimum Required Checks
|
||||
* - BIOS PXE/xNBA
|
||||
- ``ISC`` and ``Kea`` when touched
|
||||
- DHCP offer for architecture ``0x0000``; expected BIOS loader
|
||||
``pxelinux.0`` or ``xcat/xnba.kpxe``; xNBA second-stage URL when the
|
||||
client returns with user-class ``xNBA``.
|
||||
* - UEFI PXE architecture ``0x0007``
|
||||
- ``Kea``
|
||||
- Client matches ``xcat-uefi-x64``; offer includes ``xcat/xnba.efi``;
|
||||
node-specific xNBA UEFI second-stage class returns the ``.uefi`` node
|
||||
script URL.
|
||||
* - UEFI PXE architecture ``0x0009``
|
||||
- ``Kea``
|
||||
- Same checks as ``0x0007``. This is the alternate x86_64 UEFI PXE
|
||||
architecture id observed in the existing xCAT DHCP logic.
|
||||
* - UEFI HTTP architecture ``0x0010``
|
||||
- ``Kea``
|
||||
- Client matches ``xcat-uefi-x64`` and the xNBA UEFI second-stage class;
|
||||
validate the DHCP offer against real UEFI HTTP firmware or an
|
||||
equivalent DHCP client fixture. The April 26, 2026 validation used a raw
|
||||
DHCP fixture with option 93 set to ``0x0010`` and confirmed Kea offered
|
||||
the reserved outside-pool address and ``xcat/xnba.efi`` without
|
||||
``ALLOC_FAIL_NO_POOLS``.
|
||||
* - Static reservation outside dynamic pool
|
||||
- ``Kea``
|
||||
- Node address is inside the Kea subnet and outside
|
||||
``networks.dynamicrange``; generated reservation includes
|
||||
``ip-address``; DHCP ACK uses the reserved address; Kea logs do not
|
||||
contain ``ALLOC_FAIL_NO_POOLS``.
|
||||
* - Static reservation inside dynamic pool
|
||||
- ``Kea``
|
||||
- Record the expected behavior explicitly. Current ``makedhcp`` treats
|
||||
node IPs overlapping ``networks.dynamicrange`` as dynamic and does not
|
||||
render a fixed ``ip-address`` reservation. Any change that supports
|
||||
in-pool fixed reservations must add live allocation coverage.
|
||||
* - Dynamic pool ownership in hierarchy
|
||||
- ``Kea``
|
||||
- When ``networks.dhcpserver`` is set, only the owning DHCP server renders
|
||||
``networks.dynamicrange`` as Kea pools. Non-owning service nodes may
|
||||
render the subnet for reservations and options, but must not render
|
||||
duplicate dynamic pools.
|
||||
* - Stateful netboot image
|
||||
- ``ISC`` and ``Kea`` when touched
|
||||
- DHCP/TFTP/HTTP handoff reaches kernel, initrd, root image, and the
|
||||
expected xCAT node state.
|
||||
* - Stateless netboot image
|
||||
- ``ISC`` and ``Kea`` when touched
|
||||
- DHCP/TFTP/HTTP handoff reaches the stateless image and validates
|
||||
post-boot xCAT state.
|
||||
* - ``ALLOC_FAIL_NO_POOLS`` regression
|
||||
- ``Kea``
|
||||
- Reproduce a node with static reservation and no usable dynamic pool;
|
||||
confirm Kea still allocates the reserved address and no allocation
|
||||
failure is logged.
|
||||
|
||||
Extended Architecture Matrix
|
||||
----------------------------
|
||||
@@ -109,9 +209,9 @@ paths.
|
||||
* - EL10
|
||||
- ``ppc64le``
|
||||
- ``Kea``
|
||||
- ``Genesis handoff``
|
||||
- DHCP offer; boot file handoff; xCAT Genesis reachability; POWER boot-path
|
||||
correctness
|
||||
- ``POWER GRUB handoff``
|
||||
- DHCP offer; boot file handoff; POWER boot-path correctness; Genesis
|
||||
shell when Genesis payload validation is in scope
|
||||
|
||||
Current Lab Baseline
|
||||
--------------------
|
||||
@@ -125,76 +225,183 @@ Validation access should use the ``builder`` account and the
|
||||
``id_ed25519_reposync`` SSH key. Avoid relying on ad-hoc root login or
|
||||
one-off cloud-init keys when recording repeatable validation procedure.
|
||||
|
||||
Full Ubuntu 24.04 ``x86_64`` stateless KVM validation required Ubuntu
|
||||
``genimage`` fixes for early BOOTIF handling and a lean initrd driver set.
|
||||
Those image-generation fixes are tracked separately from the Kea DHCP backend
|
||||
policy changes.
|
||||
|
||||
Known Exceptions
|
||||
----------------
|
||||
|
||||
Known blockers do not remove the matrix requirement. They must be recorded
|
||||
explicitly in the validation result.
|
||||
explicitly in the validation result. A blocker only turns a DHCP acceptance row
|
||||
red when the root cause is DHCP backend policy, allocation, or boot option
|
||||
rendering.
|
||||
|
||||
Current exceptions:
|
||||
|
||||
* Ubuntu 22.04 LTS ISC OMAPI/``omshell`` host reservation updates are blocked by
|
||||
issue ``#11``. The failure reproduces on upstream ``master`` and is not caused
|
||||
by the Kea backend work.
|
||||
* EL10 ``ppc64le`` Kea configuration and DHCP unit validation pass. Full POWER
|
||||
image boot validation can still be blocked by a ``genesis.kernel.ppc64``
|
||||
invalid-ELF issue unrelated to Kea. Initial triage showed the installed
|
||||
``/tftpboot/xcat/genesis.kernel.ppc64`` is a PowerPC/OpenPOWER ELF, not an
|
||||
``x86_64`` binary, and is the package payload from
|
||||
``xCAT-genesis-base-ppc64-2.18.0-RC1`` built on
|
||||
``xcat-dev-server-ppc.cluster.local`` on March 30, 2026. The likely change
|
||||
area is the Genesis rebuild work merged before this PR, especially PR ``#8``
|
||||
/ merge ``40a7e4c43`` and commits ``d691c5ccd`` (Genesis base source
|
||||
package generation), ``4a1905171`` (ppc64le Genesis boot changes), and
|
||||
``baa2380cd`` (moving the dracut call into the spec).
|
||||
xCAT3 issue ``#11``. The failure reproduces on upstream ``master`` and is not
|
||||
caused by the Kea backend work. ``site.dhcpbackend=auto`` therefore selects
|
||||
Kea for Ubuntu 22.04 and newer releases; live Ubuntu 22.04 Kea validation
|
||||
remains a follow-up matrix row.
|
||||
* Ubuntu ``ppc64le`` package installation is missing required boot packages such
|
||||
as ``goconserver``, ``grub2-xcat``, and ``xcat-genesis-base-ppc64``. This is
|
||||
tracked by xCAT3 issue ``#13`` and is separate from Kea DHCP behavior.
|
||||
|
||||
Current PR Validation Snapshot
|
||||
------------------------------
|
||||
|
||||
As of April 23, 2026, the ``kea-dhcp-backend`` PR has the following DHCP
|
||||
backend validation result:
|
||||
As of April 26, 2026, this PR has the following DHCP backend acceptance result
|
||||
for the supported KVM rows. All rows in this table are green for the DHCP
|
||||
backend scope described above.
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 16 10 10 20 44
|
||||
:widths: 16 10 12 18 12 32
|
||||
|
||||
* - Platform
|
||||
- Arch
|
||||
- Backend
|
||||
- Boot Path
|
||||
- Result
|
||||
- Notes
|
||||
* - EL9
|
||||
- ``x86_64``
|
||||
- ``ISC``
|
||||
- BIOS PXE/xNBA
|
||||
- Pass
|
||||
- ``site.dhcpbackend=auto`` selected ``isc``; legacy DHCP unit subset
|
||||
passed.
|
||||
* - Ubuntu 22.04 LTS
|
||||
- DHCP/TFTP, node-specific xNBA handoff, Genesis shell, and compute-image
|
||||
validation passed.
|
||||
* - EL9
|
||||
- ``x86_64``
|
||||
- ``ISC``
|
||||
- Pass with known exception
|
||||
- ``site.dhcpbackend=auto`` selected ``isc``; legacy DHCP unit subset
|
||||
passed. OMAPI reservation updates remain tracked by issue ``#11``.
|
||||
- UEFI PXE/xNBA
|
||||
- Pass
|
||||
- Non-Secure-Boot UEFI DHCP/TFTP, node-specific xNBA handoff, Genesis
|
||||
shell, and compute-image validation passed.
|
||||
* - EL9
|
||||
- ``ppc64le``
|
||||
- ``ISC``
|
||||
- POWER GRUB/Genesis
|
||||
- Pass
|
||||
- DHCP/TFTP/GRUB handoff fetched ``genesis.kernel.ppc64`` and
|
||||
``genesis.fs.ppc64.gz``; node reached the Genesis shell.
|
||||
* - EL10
|
||||
- ``x86_64``
|
||||
- ``Kea 3.0.1``
|
||||
- BIOS PXE/xNBA
|
||||
- Pass
|
||||
- Renderer emitted ``evaluate-additional-classes`` and
|
||||
``only-in-additional-list``; ``kea-dhcp4 -t`` passed.
|
||||
- Static reservation outside ``networks.dynamicrange`` allocated; no
|
||||
``ALLOC_FAIL_NO_POOLS``; xNBA shell passed; regenerated compute-image
|
||||
boot reached ``sshd`` with ``selinux=0`` in the command line.
|
||||
* - Ubuntu 24.04 LTS
|
||||
- ``x86_64``
|
||||
- ``Kea 2.4.1``
|
||||
- BIOS PXE/xNBA
|
||||
- Pass
|
||||
- Renderer emitted ``require-client-classes`` and ``only-if-required``;
|
||||
full DHCP unit suite and ``kea-dhcp4 -t`` passed.
|
||||
- Static reservation outside ``networks.dynamicrange`` allocated; no
|
||||
``ALLOC_FAIL_NO_POOLS``; xNBA shell passed; compute-image boot fetched
|
||||
``rootimg.cpio.gz`` and reached ``sshd`` with ``netdrivers=overlay``.
|
||||
* - EL10
|
||||
- ``x86_64``
|
||||
- ``Kea 3.0.1``
|
||||
- UEFI PXE/xNBA
|
||||
- Pass
|
||||
- Non-Secure-Boot UEFI path matched the Kea x86_64 UEFI boot policy;
|
||||
regenerated compute-image boot reached ``sshd`` with ``selinux=0`` in
|
||||
the command line.
|
||||
* - EL10
|
||||
- ``x86_64``
|
||||
- ``Kea 3.0.1``
|
||||
- UEFI HTTP arch ``0x0010``
|
||||
- Pass
|
||||
- Raw DHCP fixture on the KVM provisioning bridge sent option 93
|
||||
``0x0010`` from the reserved outside-pool node MAC and received lease
|
||||
``10.241.10.22`` with boot file ``xcat/xnba.efi``; no
|
||||
``ALLOC_FAIL_NO_POOLS`` was observed. xCAT3 issue ``#17`` is closed as
|
||||
completed.
|
||||
* - Ubuntu 24.04 LTS
|
||||
- ``x86_64``
|
||||
- ``Kea 2.4.1``
|
||||
- UEFI PXE/xNBA
|
||||
- Pass
|
||||
- Non-Secure-Boot UEFI path matched the Kea x86_64 UEFI boot policy;
|
||||
xNBA shell passed; compute-image boot fetched ``rootimg.cpio.gz`` and
|
||||
reached ``sshd`` with the separate Ubuntu ``genimage`` fixes applied.
|
||||
* - EL10
|
||||
- ``ppc64le``
|
||||
- ``Kea 3.0.1``
|
||||
- POWER GRUB/Genesis
|
||||
- Pass
|
||||
- Renderer emitted ``evaluate-additional-classes`` and
|
||||
``only-in-additional-list``; full DHCP unit suite and ``kea-dhcp4 -t``
|
||||
passed. Full image boot remains blocked after GRUB by the separate
|
||||
Genesis ppc64 kernel issue described above.
|
||||
- Static reservation outside ``networks.dynamicrange`` allocated; no
|
||||
``ALLOC_FAIL_NO_POOLS``; TFTP/GRUB handoff passed; original EL10
|
||||
``genesis.kernel.ppc64`` and ``genesis.fs.ppc64.gz`` reached xCAT
|
||||
``shell`` state after replacing the broken ``grub2-xcat 1.0-3`` ppc
|
||||
GRUB core/module tree with the coherent
|
||||
``2.02-0.76.el7.1.snap201905160255`` tree. The remaining xCAT3 issue
|
||||
``#16`` follow-up is package provenance for ``grub2-xcat``, not DHCP or
|
||||
Genesis payload behavior.
|
||||
* - Ubuntu 24.04 LTS
|
||||
- ``ppc64le``
|
||||
- ``Kea 2.4.1``
|
||||
- POWER GRUB/Genesis
|
||||
- Pass
|
||||
- Static reservation outside ``networks.dynamicrange`` allocated; no
|
||||
``ALLOC_FAIL_NO_POOLS``; DHCP/TFTP/GRUB handoff passed and the node
|
||||
reached Genesis with the temporary EL9 ppc64le payload workaround.
|
||||
|
||||
Skipped Rows
|
||||
------------
|
||||
|
||||
The following rows are intentionally not counted in the current PR acceptance
|
||||
table:
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 18 10 12 60
|
||||
|
||||
* - Platform
|
||||
- Arch
|
||||
- Backend
|
||||
- Reason
|
||||
* - Ubuntu 22.04 LTS
|
||||
- ``x86_64``
|
||||
- ``Kea``
|
||||
- Skipped in this PR. Unit coverage now pins Ubuntu 22.04 to Kea by
|
||||
default because ISC OMAPI/``omshell`` is blocked by xCAT3 issue ``#11``;
|
||||
live KVM validation remains a follow-up row.
|
||||
* - Ubuntu 22.04 LTS
|
||||
- ``ppc64le``
|
||||
- ``Kea``
|
||||
- Skipped for the same Ubuntu 22.04 Kea follow-up validation reason as the
|
||||
``x86_64`` row.
|
||||
|
||||
External Follow-up Tracking
|
||||
---------------------------
|
||||
|
||||
These issues are outside the DHCP acceptance result but must be referenced when
|
||||
reporting this validation run:
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 12 22 66
|
||||
|
||||
* - Issue
|
||||
- Area
|
||||
- Impact
|
||||
* - xCAT3 ``#13``
|
||||
- Ubuntu ``ppc64le`` packages
|
||||
- Missing ``goconserver``, ``grub2-xcat``, and
|
||||
``xcat-genesis-base-ppc64`` block clean Ubuntu ppc64le package
|
||||
installation.
|
||||
* - xCAT3 ``#16``
|
||||
- ``ppc64le`` GRUB package
|
||||
- EL10 ppc64le fails with ``grub2-xcat 1.0-3`` because its POWER GRUB
|
||||
core/module tree cannot load the ppc64le Genesis kernel. The live row is
|
||||
green after hotpatching the TFTP GRUB tree to
|
||||
``2.02-0.76.el7.1.snap201905160255`` while keeping the original EL10
|
||||
Genesis payload.
|
||||
|
||||
Reporting Rule
|
||||
--------------
|
||||
|
||||
@@ -7,7 +7,7 @@ Purpose
|
||||
xCAT currently integrates DHCP through ISC DHCP. That behavior should remain the
|
||||
default on platforms where ISC DHCP is still available and supported. Kea DHCP
|
||||
will be added as a second backend for platforms that need it, starting with EL10
|
||||
and Ubuntu 24.04.
|
||||
and Ubuntu 22.04.
|
||||
|
||||
The public xCAT contract remains ``makedhcp``. The implementation underneath
|
||||
``makedhcp`` will select an ISC or Kea backend based on site configuration and
|
||||
@@ -20,7 +20,7 @@ The ``kea-dhcp-backend`` work implements the Kea backend foundation:
|
||||
|
||||
* backend selection through ``site.dhcpbackend``
|
||||
* ISC as the preserved default on platforms that still support it
|
||||
* Kea as the automatic default for EL10 and Ubuntu 24.04+
|
||||
* Kea as the automatic default for EL10 and Ubuntu 22.04+
|
||||
* Kea DHCPv4 and DHCPv6 JSON rendering with Perl's ``JSON`` module
|
||||
* Kea DHCPv4, DHCPv6, Control Agent, and DHCP-DDNS configuration validation
|
||||
before install
|
||||
@@ -46,7 +46,7 @@ Remaining work is validation and hardening:
|
||||
* full PXE boot validation on real hardware or nested guests for every
|
||||
supported architecture
|
||||
* complete service-node and disjoint-DHCP scenario validation
|
||||
* CI integration for EL10 and Ubuntu 24.04 containers
|
||||
* CI integration for EL10 and Ubuntu 22.04+ containers
|
||||
|
||||
Backend Selection
|
||||
-----------------
|
||||
@@ -58,8 +58,8 @@ Add a site attribute:
|
||||
Selection rules:
|
||||
|
||||
* ``auto`` keeps ISC DHCP on existing supported platforms such as EL8, EL9,
|
||||
older Ubuntu/Debian releases, and SLES.
|
||||
* ``auto`` selects Kea DHCP on EL10 and Ubuntu 24.04.
|
||||
Ubuntu 20.04 and older Ubuntu/Debian releases, and SLES.
|
||||
* ``auto`` selects Kea DHCP on EL10 and Ubuntu 22.04+.
|
||||
* ``isc`` forces the ISC backend.
|
||||
* ``kea`` forces the Kea backend.
|
||||
* A forced backend that is unavailable must fail with a clear error.
|
||||
@@ -159,10 +159,10 @@ ISC services:
|
||||
|
||||
Kea services:
|
||||
|
||||
* ``kea-dhcp4``
|
||||
* optional ``kea-dhcp6``
|
||||
* ``kea-dhcp4`` or Debian-style ``kea-dhcp4-server``
|
||||
* optional ``kea-dhcp6`` or Debian-style ``kea-dhcp6-server``
|
||||
* optional ``kea-ctrl-agent``
|
||||
* optional ``kea-dhcp-ddns``
|
||||
* optional ``kea-dhcp-ddns`` or Debian-style ``kea-dhcp-ddns-server``
|
||||
|
||||
Control Agent must be running before REST operations are attempted. D2 should
|
||||
only be managed when Kea DDNS support is configured.
|
||||
@@ -187,7 +187,8 @@ Backends render the same intent as:
|
||||
Boot coverage must include:
|
||||
|
||||
* x86 BIOS
|
||||
* x86_64 UEFI
|
||||
* x86_64 UEFI PXE architecture ids ``0x0007`` and ``0x0009``
|
||||
* x86_64 UEFI HTTP boot architecture id ``0x0010``
|
||||
* ARM64
|
||||
* OpenPOWER/OPAL
|
||||
* ONIE
|
||||
@@ -205,10 +206,28 @@ Baseline Kea behavior should be deterministic and not depend on optional hooks:
|
||||
* validate generated configuration
|
||||
* reload Kea
|
||||
|
||||
Kea reservation policy must map xCAT's existing ``makedhcp`` semantics
|
||||
explicitly:
|
||||
|
||||
* ``networks.dynamicrange`` renders as Kea dynamic address pools.
|
||||
* Node addresses outside ``networks.dynamicrange`` render as static
|
||||
``ip-address`` host reservations.
|
||||
* Node addresses inside ``networks.dynamicrange`` are currently treated as
|
||||
dynamic by ``makedhcp`` and do not render fixed ``ip-address`` reservations;
|
||||
enabling in-pool fixed reservations is a separate behavior change that needs
|
||||
explicit live validation.
|
||||
* DHCPv4 output should keep Kea subnet host reservations enabled with
|
||||
``reservations-in-subnet`` set to ``true`` and should not switch globally to
|
||||
out-of-pool-only mode unless all fixed reservations are known to be outside
|
||||
dynamic pools.
|
||||
* In hierarchical deployments, ``networks.dhcpserver`` ownership must be
|
||||
honored before rendering ``networks.dynamicrange`` as Kea pools, matching
|
||||
the legacy ISC behavior that prevents duplicate dynamic leases.
|
||||
|
||||
Optimized behavior can use Kea Control Agent plus host-commands when available.
|
||||
This requires verifying that the target distribution packages include the host
|
||||
commands hook library, such as ``libdhcp_host_cmds.so``. Do not assume this
|
||||
library is present in EL10 or Ubuntu 24.04 without testing the actual packages.
|
||||
library is present in EL10 or Ubuntu 22.04+ without testing the actual packages.
|
||||
|
||||
If host-commands are unavailable, the JSON render and reload path must still
|
||||
work.
|
||||
@@ -240,7 +259,7 @@ dependencies only for platforms using Kea.
|
||||
Known areas:
|
||||
|
||||
* ``xCAT.spec`` and ``xCATsn.spec`` currently depend on ``/usr/sbin/dhcpd``.
|
||||
* EL10 and Ubuntu 24.04 packaging should depend on the correct Kea server
|
||||
* EL10 and Ubuntu 22.04+ packaging should depend on the correct Kea server
|
||||
packages.
|
||||
* ``dhclient`` and ``dhcp-client`` are separate client-side genesis/netboot
|
||||
issues and should not be conflated with the server backend.
|
||||
@@ -270,6 +289,8 @@ Unit tests:
|
||||
* Kea JSON renderer coverage
|
||||
* host reservation formatting
|
||||
* subnet and pool mapping
|
||||
* Kea reservation policy flags for subnet reservations and out-of-pool-only
|
||||
overrides
|
||||
* backend selection and override behavior
|
||||
|
||||
Configuration validation tests:
|
||||
@@ -287,8 +308,9 @@ Configuration validation tests:
|
||||
Backend selection tests:
|
||||
|
||||
* ``auto`` uses ISC on EL9
|
||||
* ``auto`` uses ISC on Ubuntu 20.04
|
||||
* ``auto`` uses Kea on EL10
|
||||
* ``auto`` uses Kea on Ubuntu 24.04
|
||||
* ``auto`` uses Kea on Ubuntu 22.04 and Ubuntu 24.04
|
||||
* forced ``kea`` works on EL9 when Kea packages are installed
|
||||
* forced unavailable backend fails clearly
|
||||
|
||||
@@ -297,6 +319,7 @@ Integration matrix:
|
||||
* EL9 plus ISC
|
||||
* EL9 plus forced Kea
|
||||
* EL10 plus Kea
|
||||
* Ubuntu 22.04 plus Kea
|
||||
* Ubuntu 24.04 plus Kea
|
||||
|
||||
Semantic parity tests:
|
||||
@@ -315,6 +338,8 @@ Functional smoke tests:
|
||||
* ``XCAT_KEA_LIVE_SMOKE=1`` validates live Control Agent host-commands when
|
||||
Kea and the host-commands hook are installed
|
||||
* DHCP offers contain expected boot options
|
||||
* Kea static reservations outside dynamic pools allocate without
|
||||
``ALLOC_FAIL_NO_POOLS``
|
||||
* real PXE boot behavior is validated for each supported architecture
|
||||
|
||||
Test Infrastructure
|
||||
@@ -328,7 +353,7 @@ ordinary containers.
|
||||
Open test infrastructure details to confirm:
|
||||
|
||||
* SSH access method and user for ``rome01.local.versatushpc.com.br``
|
||||
* available base images for EL9, EL10, and Ubuntu 24.04
|
||||
* available base images for EL9, EL10, Ubuntu 22.04, and Ubuntu 24.04
|
||||
* libvirt network names and whether isolated DHCP test networks are already
|
||||
available
|
||||
* whether nested or privileged test guests can run DHCP client and PXE tests
|
||||
@@ -339,21 +364,26 @@ Open test infrastructure details to confirm:
|
||||
Manual Validation Snapshot
|
||||
--------------------------
|
||||
|
||||
As of April 23, 2026, the branch has been exercised on KVM guests across ISC
|
||||
As of April 26, 2026, the branch has been exercised on KVM guests across ISC
|
||||
and Kea backends:
|
||||
|
||||
* EL10 plus Kea on x86_64: passed end-to-end xNBA netboot with a Rocky 10.1
|
||||
compute image. The node fetched the xNBA script, kernel, initrd, and rootimg,
|
||||
then reached xCAT ``netbooting`` state.
|
||||
* Ubuntu 24.04 plus Kea on x86_64: passed xNBA shell boot and full netboot
|
||||
image fetch. The node downloaded the node script, Genesis artifacts, and the
|
||||
generated root image, and Kea reservation queries succeeded.
|
||||
* Ubuntu 24.04 plus Kea on x86_64: passed BIOS and non-Secure-Boot UEFI xNBA
|
||||
shell boot and full stateless compute-image boot. The nodes downloaded the
|
||||
node script, kernel, initrd, and generated root image, then reached ``sshd``.
|
||||
Kea allocated static reservations outside ``networks.dynamicrange`` without
|
||||
``ALLOC_FAIL_NO_POOLS``. The KVM osimage used ``netdrivers=overlay`` because
|
||||
``virtio_net`` is built into the Ubuntu 24.04 generic kernel.
|
||||
* EL9 plus ISC on x86_64: passed legacy ISC plus xNBA shell boot, including
|
||||
DHCP, TFTP, node-script handoff, and Genesis fetch.
|
||||
* Ubuntu 22.04 plus ISC on x86_64: passed legacy ISC DHCP, TFTP, generated
|
||||
* Ubuntu 22.04 plus forced ISC on x86_64: passed legacy ISC DHCP, TFTP, generated
|
||||
xNBA network script, and Genesis fetch. Per-node OMAPI reservation updates on
|
||||
Jammy still fail with ``omshell`` descriptor errors and appear to be a
|
||||
preexisting Ubuntu-specific ISC issue outside the Kea scope.
|
||||
preexisting Ubuntu-specific ISC issue outside the Kea scope. Because of that
|
||||
issue, ``site.dhcpbackend=auto`` now selects Kea on Ubuntu 22.04 and newer
|
||||
Ubuntu releases.
|
||||
* EL10 plus Kea on ppc64le: passed Kea 3.x renderer validation with
|
||||
``evaluate-additional-classes`` and ``only-in-additional-list``; passed
|
||||
``kea-dhcp4 -t``; passed the full DHCP unit suite on ppc64le after installing
|
||||
@@ -392,5 +422,6 @@ Guiding Rule
|
||||
------------
|
||||
|
||||
``makedhcp`` remains the stable xCAT interface. ISC remains the default backend
|
||||
where it works. Kea is added as a backend for platforms that need it, with shared
|
||||
DHCP intent and backend-specific rendering and control.
|
||||
where it works and remains supported. Kea is added as a backend for platforms
|
||||
that need it, with shared DHCP intent and backend-specific rendering and
|
||||
control.
|
||||
|
||||
@@ -59,7 +59,7 @@ sub default_backend {
|
||||
|
||||
my $os_name = exists $args{os_name} ? $args{os_name} : $class->_osver('os');
|
||||
my $version = exists $args{version} ? $args{version} : $class->_osver('version');
|
||||
if ( defined($os_name) && $os_name =~ /^ubuntu$/i && _version_at_least( $version, '24.04' ) ) {
|
||||
if ( defined($os_name) && $os_name =~ /^ubuntu$/i && _version_at_least( $version, '22.04' ) ) {
|
||||
return 'kea';
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ sub _command_exists {
|
||||
sub _version_at_least {
|
||||
my ( $version, $minimum ) = @_;
|
||||
|
||||
return 0 unless defined($version) && $version =~ /^\d+(?:\.\d+)*/;
|
||||
return 0 unless defined($version) && $version =~ /^\d+\.\d+(?:\.\d+)*$/;
|
||||
|
||||
my @version_parts = split /\./, $version;
|
||||
my @minimum_parts = split /\./, $minimum;
|
||||
|
||||
@@ -10,6 +10,13 @@ use Math::BigInt;
|
||||
use xCAT::DHCP::Range;
|
||||
use xCAT::NetworkUtils;
|
||||
|
||||
my %KEA_SERVICE_CANDIDATES = (
|
||||
'kea-dhcp4' => [ 'kea-dhcp4', 'kea-dhcp4-server' ],
|
||||
'kea-dhcp6' => [ 'kea-dhcp6', 'kea-dhcp6-server' ],
|
||||
'kea-dhcp-ddns' => [ 'kea-dhcp-ddns', 'kea-dhcp-ddns-server' ],
|
||||
'kea-ctrl-agent' => [ 'kea-ctrl-agent' ],
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $class, %args ) = @_;
|
||||
return bless \%args, $class;
|
||||
@@ -56,8 +63,10 @@ sub render_dhcp4_config {
|
||||
type => 'memfile',
|
||||
name => '/var/lib/kea/kea-leases4.csv',
|
||||
},
|
||||
'valid-lifetime' => _integer( _first_defined( $intent->{'valid-lifetime'}, $intent->{valid_lifetime}, 43200 ) ),
|
||||
subnet4 => [ map { $self->_render_subnet4($_) } @{ _first_defined( $intent->{subnet4}, $intent->{subnets}, [] ) } ],
|
||||
'valid-lifetime' => _integer( _first_defined( $intent->{'valid-lifetime'}, $intent->{valid_lifetime}, 43200 ) ),
|
||||
'reservations-in-subnet' => _json_bool( _first_defined( $intent->{'reservations-in-subnet'}, $intent->{reservations_in_subnet}, 1 ) ),
|
||||
'reservations-out-of-pool' => _json_bool( _first_defined( $intent->{'reservations-out-of-pool'}, $intent->{reservations_out_of_pool}, 1 ) ),
|
||||
subnet4 => [ map { $self->_render_subnet4($_) } @{ _first_defined( $intent->{subnet4}, $intent->{subnets}, [] ) } ],
|
||||
);
|
||||
|
||||
$dhcp4{'control-socket'} = $intent->{'control-socket'} if $intent->{'control-socket'};
|
||||
@@ -434,16 +443,19 @@ sub restart_services {
|
||||
push @services, 'kea-dhcp6' if $opts{ipv6};
|
||||
push @services, 'kea-ctrl-agent' if $opts{ctrl_agent};
|
||||
|
||||
my @units;
|
||||
foreach my $service (@services) {
|
||||
my $unit = $self->_kea_service($service);
|
||||
push @units, $unit;
|
||||
if ( $opts{enable} ) {
|
||||
my $enable_ret = xCAT::Utils->enableservice($service);
|
||||
return { error => "Failed to enable $service." } if $enable_ret != 0;
|
||||
my $enable_ret = xCAT::Utils->enableservice($unit);
|
||||
return { error => "Failed to enable $unit." } if $enable_ret != 0;
|
||||
}
|
||||
my $ret = xCAT::Utils->restartservice($service);
|
||||
return { error => "Failed to restart $service." } if $ret != 0;
|
||||
my $ret = xCAT::Utils->restartservice($unit);
|
||||
return { error => "Failed to restart $unit." } if $ret != 0;
|
||||
}
|
||||
|
||||
return { services => \@services };
|
||||
return { services => \@units };
|
||||
}
|
||||
|
||||
sub check_services {
|
||||
@@ -454,12 +466,15 @@ sub check_services {
|
||||
my @services = ('kea-dhcp4');
|
||||
push @services, 'kea-dhcp6' if $opts{ipv6};
|
||||
|
||||
my @units;
|
||||
foreach my $service (@services) {
|
||||
my $ret = xCAT::Utils->checkservicestatus($service);
|
||||
return { error => "$service is not running. Please start the Kea DHCP service." } if $ret != 0;
|
||||
my $unit = $self->_kea_service($service);
|
||||
push @units, $unit;
|
||||
my $ret = xCAT::Utils->checkservicestatus($unit);
|
||||
return { error => "$unit is not running. Please start the Kea DHCP service." } if $ret != 0;
|
||||
}
|
||||
|
||||
return { services => \@services };
|
||||
return { services => \@units };
|
||||
}
|
||||
|
||||
sub upsert_reservations {
|
||||
@@ -867,6 +882,13 @@ sub _integer {
|
||||
return 0 + $value;
|
||||
}
|
||||
|
||||
sub _json_bool {
|
||||
my ($value) = @_;
|
||||
|
||||
return $value if ref($value) eq 'JSON::PP::Boolean' || ref($value) eq 'JSON::Boolean';
|
||||
return $value ? JSON::true : JSON::false;
|
||||
}
|
||||
|
||||
sub _set_config_permissions {
|
||||
my ($path) = @_;
|
||||
|
||||
@@ -895,6 +917,41 @@ sub _kea_group {
|
||||
return;
|
||||
}
|
||||
|
||||
sub _kea_service {
|
||||
my ( $self, $service ) = @_;
|
||||
|
||||
# Kea service names are package-specific, not strictly distribution-specific.
|
||||
# Prefer the unit that is actually installed so derivatives, backports, and
|
||||
# locally rebuilt packages do not need a distro/version decision tree here.
|
||||
foreach my $candidate ( @{ $KEA_SERVICE_CANDIDATES{$service} || [$service] } ) {
|
||||
return $candidate if $self->_service_available($candidate);
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
sub _service_available {
|
||||
my ( $self, $service ) = @_;
|
||||
|
||||
my $unit = "$service.service";
|
||||
foreach my $dir ( @{ $self->{service_unit_dirs} || _systemd_unit_dirs() } ) {
|
||||
return 1 if -e "$dir/$unit";
|
||||
}
|
||||
|
||||
return 1 if -x "/etc/init.d/$service";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub _systemd_unit_dirs {
|
||||
return [
|
||||
'/etc/systemd/system',
|
||||
'/run/systemd/system',
|
||||
'/usr/lib/systemd/system',
|
||||
'/lib/systemd/system',
|
||||
];
|
||||
}
|
||||
|
||||
sub _command_path {
|
||||
my ($command) = @_;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ sub kea_client_classes {
|
||||
my ( $class, %opts ) = @_;
|
||||
|
||||
my $xnba_user_class = xnba_user_class_test();
|
||||
my $uefi_x64_arch_match = uefi_x64_client_architecture_match_expr();
|
||||
my $bios_boot = $opts{xnba_kpxe} ? 'xcat/xnba.kpxe' : 'pxelinux.0';
|
||||
my $uefi_boot = $opts{xnba_efi} ? 'xcat/xnba.efi' : '';
|
||||
my @classes;
|
||||
@@ -24,7 +25,7 @@ sub kea_client_classes {
|
||||
if ($uefi_boot ne '') {
|
||||
push @classes, {
|
||||
name => 'xcat-uefi-x64',
|
||||
test => "(option[93].hex == 0x0007 or option[93].hex == 0x0009) and not ($xnba_user_class)",
|
||||
test => "($uefi_x64_arch_match) and not ($xnba_user_class)",
|
||||
'boot-file-name' => $uefi_boot,
|
||||
};
|
||||
}
|
||||
@@ -55,6 +56,7 @@ sub kea_xnba_node_classes {
|
||||
|
||||
my $nodes = $opts{nodes} || [];
|
||||
my $xnba_user_class = xnba_user_class_test();
|
||||
my $uefi_x64_arch_match = uefi_x64_client_architecture_match_expr();
|
||||
my @classes;
|
||||
|
||||
foreach my $node (@$nodes) {
|
||||
@@ -73,7 +75,7 @@ sub kea_xnba_node_classes {
|
||||
if ( $opts{xnba_efi} ) {
|
||||
push @classes, {
|
||||
name => "$class_base-uefi",
|
||||
test => "$xnba_user_class and option[93].hex == 0x0009 and $mac_test",
|
||||
test => "$xnba_user_class and ($uefi_x64_arch_match) and $mac_test",
|
||||
'boot-file-name' => "$base_url.uefi",
|
||||
'user-context' => _xnba_user_context($node),
|
||||
};
|
||||
@@ -87,6 +89,10 @@ sub xnba_user_class_test {
|
||||
return "(option[77].exists and (option[77].text == 'xNBA' or option[77].hex == 0x784e4241 or substring(option[77].hex,1,4) == 'xNBA'))";
|
||||
}
|
||||
|
||||
sub uefi_x64_client_architecture_match_expr {
|
||||
return "option[93].hex == 0x0007 or option[93].hex == 0x0009 or option[93].hex == 0x0010";
|
||||
}
|
||||
|
||||
sub _xnba_class_base {
|
||||
my ( $node, $mac ) = @_;
|
||||
|
||||
|
||||
@@ -762,7 +762,7 @@ sub mknetboot
|
||||
}
|
||||
|
||||
# turn off the selinux
|
||||
if ($osver =~ m/(fedora12|fedora13|rhels7|rhels8|ol7|ol8|alma8|rocky8)/) {
|
||||
if ($osver =~ m/(fedora12|fedora13|(?:rhels|ol|alma|rocky)(?:[7-9]|10))/) {
|
||||
$kcmdline .= " selinux=0 ";
|
||||
}
|
||||
|
||||
|
||||
@@ -2359,9 +2359,6 @@ sub kea_build_dhcp4_intent
|
||||
%netcfgs = ();
|
||||
@alldomains = ();
|
||||
|
||||
my @interfaces = grep { $_ ne '!remote!' && $_ !~ /!remote!/ } sort keys %$activenics;
|
||||
@interfaces = ('*') unless @interfaces;
|
||||
|
||||
my $httpport = "80";
|
||||
my @hports = xCAT::TableUtils->get_site_attribute("httpport");
|
||||
if ($hports[0]) {
|
||||
@@ -2387,6 +2384,23 @@ sub kea_build_dhcp4_intent
|
||||
}
|
||||
|
||||
my @routes = kea_ipv4_routes(@vnets);
|
||||
my %dhcp_interfaces = %$activenics;
|
||||
if (!keys %dhcp_interfaces) {
|
||||
my %configured_local_interfaces = map { $_->{mgtifname} => 1 } grep { $_->{mgtifname} && $_->{mgtifname} !~ /!remote!/ } @vnets;
|
||||
foreach my $route (@routes) {
|
||||
my ( $net, $netif, undef, $flags ) = @$route;
|
||||
next if kea_skip_ipv4_network($net);
|
||||
next if defined($flags) && $flags =~ /G/;
|
||||
next if $netif =~ /!remote!/;
|
||||
$dhcp_interfaces{$netif} = 1 if $configured_local_interfaces{$netif};
|
||||
}
|
||||
}
|
||||
|
||||
my @interfaces = grep { $_ ne '!remote!' && $_ !~ /!remote!/ } sort keys %dhcp_interfaces;
|
||||
if (!@interfaces && !$dhcp_interfaces{'!remote!'}) {
|
||||
return { error => "Unable to infer local Kea DHCP interfaces. Set site.dhcpinterfaces to the intended provisioning interface." };
|
||||
}
|
||||
|
||||
my @subnets;
|
||||
my @opal_classes;
|
||||
my $id = 1;
|
||||
@@ -2400,9 +2414,9 @@ sub kea_build_dhcp4_intent
|
||||
if ($interface =~ /!remote!\S*/) {
|
||||
$remote = 1;
|
||||
$interface =~ s/!remote!\s*(.*)$/$1/;
|
||||
next unless $activenics->{'!remote!'};
|
||||
next unless $dhcp_interfaces{'!remote!'};
|
||||
} else {
|
||||
next unless $activenics->{$interface};
|
||||
next unless $dhcp_interfaces{$interface};
|
||||
}
|
||||
|
||||
my $subnet = kea_subnet4_intent($nettab, $net, $mask, $interface, $remote, $id, $httpport);
|
||||
@@ -2767,11 +2781,16 @@ sub kea_subnet4_intent
|
||||
push @option_data, { name => 'domain-search', data => $domainstring } if $domainstring;
|
||||
|
||||
my $prefix = kea_mask_to_prefix($mask);
|
||||
my $dynamicrange = $ent ? $ent->{dynamicrange} : undef;
|
||||
if ( $dynamicrange && $ent->{dhcpserver} && xCAT::NetworkUtils->thishostisnot( $ent->{dhcpserver} ) ) {
|
||||
$dynamicrange = undef;
|
||||
}
|
||||
|
||||
my $opal_class = kea_opal_client_class($net, $prefix, $tftp, $httpport);
|
||||
my %subnet = (
|
||||
id => $id,
|
||||
subnet => "$net/$prefix",
|
||||
dynamicrange => $ent ? $ent->{dynamicrange} : undef,
|
||||
dynamicrange => $dynamicrange,
|
||||
option_data => \@option_data,
|
||||
next_server => $tftp,
|
||||
);
|
||||
|
||||
@@ -45,8 +45,14 @@ is(
|
||||
|
||||
is(
|
||||
xCAT::DHCP::Backend->default_backend( platform => '', os => 'ubuntu22.04', os_name => 'ubuntu', version => '22.04' ),
|
||||
'kea',
|
||||
'Ubuntu 22.04 defaults to Kea'
|
||||
);
|
||||
|
||||
is(
|
||||
xCAT::DHCP::Backend->default_backend( platform => '', os => 'ubuntu20.04', os_name => 'ubuntu', version => '20.04' ),
|
||||
'isc',
|
||||
'Ubuntu 22.04 defaults to ISC'
|
||||
'Ubuntu 20.04 defaults to ISC'
|
||||
);
|
||||
|
||||
is(
|
||||
@@ -55,6 +61,18 @@ is(
|
||||
'Ubuntu 24.04 defaults to Kea'
|
||||
);
|
||||
|
||||
is(
|
||||
xCAT::DHCP::Backend->default_backend( platform => '', os => 'ubuntu24.04', os_name => 'ubuntu', version => '24.04.4' ),
|
||||
'kea',
|
||||
'Ubuntu 24.04 point releases default to Kea'
|
||||
);
|
||||
|
||||
is(
|
||||
xCAT::DHCP::Backend->default_backend( platform => '', os => 'ubuntu24.04', os_name => 'ubuntu', version => '24' ),
|
||||
'isc',
|
||||
'Ubuntu major-only version is not treated as a date-based release'
|
||||
);
|
||||
|
||||
is(
|
||||
xCAT::DHCP::Backend->default_backend( platform => '', os => 'ubuntu24.10', os_name => 'ubuntu', version => '24.10' ),
|
||||
'kea',
|
||||
@@ -97,6 +115,12 @@ is(
|
||||
'auto selects Kea on Ubuntu 24.04'
|
||||
);
|
||||
|
||||
is(
|
||||
xCAT::DHCP::Backend->choose( requested => 'auto', os => 'ubuntu22.04', os_name => 'ubuntu', version => '22.04' )->{name},
|
||||
'kea',
|
||||
'auto selects Kea on Ubuntu 22.04'
|
||||
);
|
||||
|
||||
like(
|
||||
xCAT::DHCP::Backend->choose( requested => 'invalid' )->{error},
|
||||
qr/Invalid site\.dhcpbackend/,
|
||||
|
||||
@@ -22,6 +22,7 @@ is( $by_name{'xcat-bios'}{'boot-file-name'}, 'xcat/xnba.kpxe', 'BIOS clients rec
|
||||
like( $by_name{'xcat-bios'}{test}, qr/not \(\(option\[77\]\.exists/, 'generic BIOS class excludes xNBA second-stage clients' );
|
||||
like( $by_name{'xcat-uefi-x64'}{test}, qr/0x0007/, 'UEFI x64 class matches architecture 7' );
|
||||
like( $by_name{'xcat-uefi-x64'}{test}, qr/0x0009/, 'UEFI x64 class matches architecture 9' );
|
||||
like( $by_name{'xcat-uefi-x64'}{test}, qr/0x0010/, 'UEFI x64 class matches HTTP boot architecture 16' );
|
||||
like( $by_name{'xcat-uefi-x64'}{test}, qr/not \(\(option\[77\]\.exists/, 'generic UEFI class excludes xNBA second-stage clients' );
|
||||
is( $by_name{'xcat-aarch64'}{'boot-file-name'}, 'boot/grub2/grub2.aarch64', 'AArch64 clients receive grub2 boot file' );
|
||||
is( $by_name{'xcat-ppc64'}{'boot-file-name'}, '/boot/grub2/grub2.ppc', 'POWER clients receive grub2 Open Firmware boot file' );
|
||||
@@ -48,6 +49,9 @@ like( $xnba_bios->{test}, qr/pkt4\.mac == 0x52544b100011/, 'xNBA second-stage cl
|
||||
is( $xnba_bios->{'boot-file-name'}, 'http://10.241.10.1:80/tftpboot/xcat/xnba/nodes/cn01', 'xNBA BIOS class returns the node script URL' );
|
||||
is( $xnba_bios->{'user-context'}{'xcat-purpose'}, 'xnba-second-stage', 'xNBA class carries removable user-context' );
|
||||
is( $xnba_by_name{'xcat-xnba-cn01-52544b100011-uefi'}{'boot-file-name'}, 'http://10.241.10.1:80/tftpboot/xcat/xnba/nodes/cn01.uefi', 'xNBA UEFI class returns the UEFI node script URL' );
|
||||
like( $xnba_by_name{'xcat-xnba-cn01-52544b100011-uefi'}{test}, qr/0x0007/, 'xNBA UEFI class matches standard UEFI PXE architecture 7' );
|
||||
like( $xnba_by_name{'xcat-xnba-cn01-52544b100011-uefi'}{test}, qr/0x0009/, 'xNBA UEFI class matches alternate UEFI PXE architecture 9' );
|
||||
like( $xnba_by_name{'xcat-xnba-cn01-52544b100011-uefi'}{test}, qr/0x0010/, 'xNBA UEFI class matches UEFI HTTP boot architecture 16' );
|
||||
|
||||
my $combined_classes = xCAT::DHCP::BootPolicy->kea_client_classes(
|
||||
xnba_kpxe => 1,
|
||||
|
||||
@@ -42,7 +42,7 @@ my $json = $backend->render_dhcp4_config(
|
||||
},
|
||||
{
|
||||
name => 'xcat-uefi-x64',
|
||||
test => "(option[93].hex == 0x0007 or option[93].hex == 0x0009) and not ((option[77].exists and (option[77].text == 'xNBA' or option[77].hex == 0x784e4241 or substring(option[77].hex,1,4) == 'xNBA')))",
|
||||
test => "(option[93].hex == 0x0007 or option[93].hex == 0x0009 or option[93].hex == 0x0010) and not ((option[77].exists and (option[77].text == 'xNBA' or option[77].hex == 0x784e4241 or substring(option[77].hex,1,4) == 'xNBA')))",
|
||||
'boot-file-name' => 'xcat/xnba.efi',
|
||||
},
|
||||
],
|
||||
@@ -82,6 +82,18 @@ my $json = $backend->render_dhcp4_config(
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id => 2,
|
||||
subnet => '192.168.123.0/24',
|
||||
pools => [],
|
||||
reservations => [
|
||||
{
|
||||
'hw-address' => '52:54:00:65:43:21',
|
||||
'ip-address' => '192.168.123.50',
|
||||
hostname => 'node02',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
no warnings 'once';
|
||||
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../../perl-xCAT";
|
||||
|
||||
use Test::More;
|
||||
|
||||
BEGIN {
|
||||
package xCAT::Table;
|
||||
our $networks;
|
||||
sub new {
|
||||
my ( $class, $name ) = @_;
|
||||
return $name eq 'networks' ? $networks : undef;
|
||||
}
|
||||
$INC{'xCAT/Table.pm'} = __FILE__;
|
||||
|
||||
package xCAT::TableUtils;
|
||||
sub getTftpDir { return '/tftpboot'; }
|
||||
sub get_site_attribute { return; }
|
||||
$INC{'xCAT/TableUtils.pm'} = __FILE__;
|
||||
|
||||
package xCAT::Utils;
|
||||
sub osver { return 'rhels9'; }
|
||||
sub runcmd { return; }
|
||||
$INC{'xCAT/Utils.pm'} = __FILE__;
|
||||
|
||||
package xCAT::NetworkUtils;
|
||||
sub import {
|
||||
my $caller = caller;
|
||||
no strict 'refs';
|
||||
*{"${caller}::getipaddr"} = \&getipaddr;
|
||||
}
|
||||
sub getipaddr { return '10.0.0.1'; }
|
||||
sub my_ip_facing { return ( 0, '10.0.0.1' ); }
|
||||
sub thishostisnot { return 0; }
|
||||
sub ip_forwarding_enabled { return 0; }
|
||||
sub nodeonmynet { return 1; }
|
||||
$INC{'xCAT/NetworkUtils.pm'} = __FILE__;
|
||||
|
||||
package xCAT::ServiceNodeUtils;
|
||||
sub getSNList { return; }
|
||||
$INC{'xCAT/ServiceNodeUtils.pm'} = __FILE__;
|
||||
|
||||
package xCAT::NodeRange;
|
||||
$INC{'xCAT/NodeRange.pm'} = __FILE__;
|
||||
}
|
||||
|
||||
require "$FindBin::Bin/../../xCAT-server/lib/xcat/plugins/dhcp.pm";
|
||||
|
||||
{
|
||||
package DHCPKeaIntentNetTable;
|
||||
sub new {
|
||||
my ( $class, $entry ) = @_;
|
||||
return bless { entry => $entry }, $class;
|
||||
}
|
||||
sub getAllAttribs {
|
||||
my ( $self, @attrs ) = @_;
|
||||
return { domain => $self->{entry}{domain} } if @attrs == 1 && $attrs[0] eq 'domain';
|
||||
return { %{ $self->{entry} } };
|
||||
}
|
||||
sub getAttribs {
|
||||
my ($self) = @_;
|
||||
return { %{ $self->{entry} } };
|
||||
}
|
||||
sub close { return; }
|
||||
}
|
||||
|
||||
my %network_entry = (
|
||||
net => '10.0.0.0',
|
||||
mask => '255.255.255.0',
|
||||
mgtifname => 'eth0',
|
||||
dynamicrange => '10.0.0.100-10.0.0.150',
|
||||
domain => 'cluster.test',
|
||||
tftpserver => '<xcatmaster>',
|
||||
);
|
||||
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *xCAT_plugin::dhcp::kea_ipv4_routes = sub {
|
||||
return (
|
||||
[ '10.0.0.0', 'eth0', '255.255.255.0', '' ],
|
||||
[ '192.168.1.0', 'enp3s0', '255.255.255.0', '' ],
|
||||
);
|
||||
};
|
||||
local *xCAT_plugin::dhcp::kea_boot_client_classes = sub { return []; };
|
||||
local *xCAT_plugin::dhcp::kea_option_defs = sub { return []; };
|
||||
local *xCAT_plugin::dhcp::kea_global_option_data = sub { return []; };
|
||||
local *xCAT_plugin::dhcp::kea_dhcp_lease_time = sub { return 43200; };
|
||||
local *xCAT_plugin::dhcp::kea_control_agent_enabled = sub { return 0; };
|
||||
|
||||
local $xCAT::Table::networks = DHCPKeaIntentNetTable->new( \%network_entry );
|
||||
|
||||
my $intent = xCAT_plugin::dhcp::kea_build_dhcp4_intent( bless({}, 'DHCPKeaIntentBackend'), {} );
|
||||
|
||||
is_deeply( $intent->{interfaces}, ['eth0'], 'empty dhcpinterfaces infers the local provisioning interface' );
|
||||
is( scalar @{ $intent->{subnets} }, 1, 'empty dhcpinterfaces still renders local routed subnet' );
|
||||
is( $intent->{subnets}[0]{subnet}, '10.0.0.0/24', 'rendered subnet comes from local route' );
|
||||
}
|
||||
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *xCAT::NetworkUtils::thishostisnot = sub { return 1; };
|
||||
|
||||
my $nettab = DHCPKeaIntentNetTable->new(
|
||||
{
|
||||
%network_entry,
|
||||
dhcpserver => 'service-node-a',
|
||||
}
|
||||
);
|
||||
|
||||
my $subnet = xCAT_plugin::dhcp::kea_subnet4_intent( $nettab, '10.0.0.0', '255.255.255.0', 'eth0', 0, 1, 80 );
|
||||
ok( !defined( $subnet->{dynamicrange} ), 'non-owning Kea server does not render dynamic pool' );
|
||||
}
|
||||
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *xCAT::NetworkUtils::thishostisnot = sub { return 0; };
|
||||
|
||||
my $nettab = DHCPKeaIntentNetTable->new(
|
||||
{
|
||||
%network_entry,
|
||||
dhcpserver => 'service-node-a',
|
||||
}
|
||||
);
|
||||
|
||||
my $subnet = xCAT_plugin::dhcp::kea_subnet4_intent( $nettab, '10.0.0.0', '255.255.255.0', 'eth0', 0, 1, 80 );
|
||||
is( $subnet->{dynamicrange}, $network_entry{dynamicrange}, 'owning Kea server renders dynamic pool' );
|
||||
}
|
||||
|
||||
done_testing();
|
||||
@@ -11,6 +11,21 @@ use Test::More;
|
||||
use xCAT::DHCP::Backend::Kea;
|
||||
|
||||
my $backend = xCAT::DHCP::Backend::Kea->new( kea_version => '2.4.1' );
|
||||
my $unit_dir = tempdir( CLEANUP => 1 );
|
||||
foreach my $unit (qw/kea-dhcp4-server.service kea-dhcp6-server.service kea-dhcp-ddns-server.service kea-ctrl-agent.service/) {
|
||||
open( my $unit_fh, '>', "$unit_dir/$unit" ) or die "Unable to write $unit_dir/$unit: $!";
|
||||
close($unit_fh);
|
||||
}
|
||||
my $service_backend = xCAT::DHCP::Backend::Kea->new( service_unit_dirs => [$unit_dir] );
|
||||
is( $service_backend->_kea_service('kea-dhcp4'), 'kea-dhcp4-server', 'Debian-style DHCPv4 service name is detected' );
|
||||
is( $service_backend->_kea_service('kea-dhcp6'), 'kea-dhcp6-server', 'Debian-style DHCPv6 service name is detected' );
|
||||
is( $service_backend->_kea_service('kea-dhcp-ddns'), 'kea-dhcp-ddns-server', 'Debian-style DHCP-DDNS service name is detected' );
|
||||
is( $service_backend->_kea_service('kea-ctrl-agent'), 'kea-ctrl-agent', 'control agent service keeps canonical name' );
|
||||
|
||||
open( my $canonical_unit_fh, '>', "$unit_dir/kea-dhcp4.service" ) or die "Unable to write canonical Kea unit: $!";
|
||||
close($canonical_unit_fh);
|
||||
is( $service_backend->_kea_service('kea-dhcp4'), 'kea-dhcp4', 'canonical Kea service name is preferred when present' );
|
||||
|
||||
my $json = $backend->render_dhcp4_config(
|
||||
{
|
||||
interfaces => ['eth0'],
|
||||
@@ -60,6 +75,8 @@ ok( $config->{Dhcp4}, 'renderer creates a Dhcp4 document' );
|
||||
is_deeply( $config->{Dhcp4}{'interfaces-config'}{interfaces}, ['eth0'], 'interfaces are rendered' );
|
||||
is( $config->{Dhcp4}{'valid-lifetime'}, 600, 'valid lifetime is rendered' );
|
||||
is( $config->{Dhcp4}{'lease-database'}{type}, 'memfile', 'memfile lease backend is the default' );
|
||||
is( $config->{Dhcp4}{'reservations-in-subnet'}, JSON::true, 'subnet host reservations are enabled by default' );
|
||||
is( $config->{Dhcp4}{'reservations-out-of-pool'}, JSON::true, 'out-of-pool host reservations are enabled by default' );
|
||||
|
||||
my $subnet = $config->{Dhcp4}{subnet4}[0];
|
||||
is( $subnet->{id}, 1, 'subnet id is rendered' );
|
||||
@@ -172,6 +189,23 @@ my $empty_boot_subnet = decode_json($empty_boot_json)->{Dhcp4}{subnet4}[0];
|
||||
is( $empty_boot_subnet->{'next-server'}, '0.0.0.0', 'false-looking next-server value is preserved' );
|
||||
is( $empty_boot_subnet->{'boot-file-name'}, '', 'empty boot-file-name is preserved' );
|
||||
|
||||
my $reservation_policy_json = $backend->render_dhcp4_config(
|
||||
{
|
||||
'reservations-in-subnet' => 1,
|
||||
'reservations-out-of-pool' => 1,
|
||||
subnets => [
|
||||
{
|
||||
id => 9,
|
||||
subnet => '10.0.9.0/24',
|
||||
pools => [],
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
my $reservation_policy_config = decode_json($reservation_policy_json);
|
||||
is( $reservation_policy_config->{Dhcp4}{'reservations-in-subnet'}, JSON::true, 'reservation in-subnet policy can be overridden' );
|
||||
is( $reservation_policy_config->{Dhcp4}{'reservations-out-of-pool'}, JSON::true, 'reservation out-of-pool policy can be overridden' );
|
||||
|
||||
my $comment_dir = tempdir(CLEANUP => 1);
|
||||
my $commented_config = "$comment_dir/kea-dhcp4.conf";
|
||||
my $commented_content = <<'COMMENTED_JSON';
|
||||
@@ -222,6 +256,7 @@ $backend->upsert_reservations(
|
||||
]
|
||||
);
|
||||
is( scalar @{ $reservation_config->{Dhcp4}{subnet4}[0]{reservations} }, 1, 'reservation is added to matching subnet' );
|
||||
is_deeply( $reservation_config->{Dhcp4}{subnet4}[0]{pools}, [], 'out-of-pool static reservation does not require a dynamic pool' );
|
||||
|
||||
$backend->upsert_reservations(
|
||||
$reservation_config,
|
||||
|
||||
Reference in New Issue
Block a user