From f0519021734828a6f68ce0a848b9cc9190be52cf Mon Sep 17 00:00:00 2001 From: Daniel Hilst <392820+dhilst@users.noreply.github.com> Date: Mon, 24 Aug 2026 14:34:14 -0300 Subject: [PATCH 1/4] test(xcat-core): capture Subiquity install failing when installnic is unset The Ubuntu diskful (Subiquity) install fails on any node that does not set noderes.installnic. compute.subiquity.tmpl resolves #TABLE:noderes:$NODE:installnic#, and Template.pm's tabdb raises "Unable to find requested field from table " when the value is absent, aborting with "Failed to generate xnba configurations" so the compute node never enters the installer. EL and SLES pass the identical case because their statefull templates never reference installnic (gen_net_boot_params defaults to the boot MAC). Assert that the template uses the non-fatal #TABLEBLANKOKAY# token for installnic and treats an empty installnic the same as "mac" (match by MAC, no NIC rename). These assertions fail on the current template, capturing the defect. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com> --- xCAT-test/unit/ubuntu_subiquity_template.t | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/xCAT-test/unit/ubuntu_subiquity_template.t b/xCAT-test/unit/ubuntu_subiquity_template.t index 2af9692aa..77f80a356 100644 --- a/xCAT-test/unit/ubuntu_subiquity_template.t +++ b/xCAT-test/unit/ubuntu_subiquity_template.t @@ -36,7 +36,20 @@ unlike($tmpl, qr/echo.*GRUB_CMDLINE.*\\"/, 'no escaped double quotes in echo GRU unlike($tmpl, qr/\\\\x22/, 'template does not rely on non-portable printf hex escapes'); like($tmpl, qr/printf ''%s\\n'' ''GRUB_CMDLINE_LINUX="#TABLEBLANKOKAY:bootparams:\$NODE:kcmdline#"''/, 'GRUB line uses portable printf quoting'); like($tmpl, qr/\/target\/etc\/netplan\/00-xcat-install\.yaml/, 'template writes an xCAT-owned target netplan file'); -like($tmpl, qr/installnic="#TABLE:noderes:\$NODE:installnic#"/, 'target netplan uses node installnic'); +# Regression: an UNSET noderes.installnic must not fatally break Subiquity xnba +# generation. The EL/SLES statefull templates never reference installnic, so they default +# gracefully; this template resolved #TABLE:noderes:$NODE:installnic#, and Template.pm's tabdb +# raises "Unable to find requested field from table " -> "Failed to +# generate xnba configurations" when the node carries no installnic value, so the Ubuntu +# diskful install never starts. The template must use the non-fatal #TABLEBLANKOKAY# token +# (renders blank when unset) and treat an empty installnic the same as "mac" -- match by MAC +# with no NIC rename, which is the EL-equivalent default. +unlike($tmpl, qr/installnic="#TABLE:noderes:\$NODE:installnic#"/, + 'installnic does NOT use the fatal #TABLE# token (it errors when installnic is unset)'); +like($tmpl, qr/installnic="#TABLEBLANKOKAY:noderes:\$NODE:installnic#"/, + 'installnic uses the non-fatal #TABLEBLANKOKAY# token so an unset installnic renders blank'); +like($tmpl, qr/if \[ "\$\{installnic\}" = "mac" \] \|\| \[ -z "\$\{installnic\}" \]; then/, + 'an empty installnic is handled like "mac" (match by MAC, no set-name rename)'); like($tmpl, qr/installmac="#TABLE:mac:\$NODE:mac#"/, 'target netplan uses node MAC'); like($tmpl, qr/installmac="\$\(printf ''%s'' "\$\{installmac\}".*\| tr ''A-F'' ''a-f''\)"/, 'target netplan normalizes MAC case'); like($tmpl, qr/installmac="\$\(printf ''%s'' "\$\{installmac\}" \| cut -d''\|'' -f1 \| cut -d''!'' -f1/, 'target netplan strips mac table suffixes before matching'); From 62ab9caead77c65616b87d00b9819bd4c167f684 Mon Sep 17 00:00:00 2001 From: Daniel Hilst <392820+dhilst@users.noreply.github.com> Date: Mon, 24 Aug 2026 14:34:21 -0300 Subject: [PATCH 2/4] fix(xcat-core): default Subiquity installnic to match-by-MAC when unset Resolve installnic with the non-fatal #TABLEBLANKOKAY# token so an absent noderes.installnic renders blank instead of aborting xnba generation, and treat an empty installnic exactly like "mac": match the interface by its boot MAC address and do not rename it. That is the same default EL and SLES already get, since their statefull templates never reference installnic at all. Nodes that do set noderes.installnic are unaffected -- the set-name branch is unchanged. The diskless/netboot path never referenced installnic and is untouched. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com> --- xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl b/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl index 31a978cbc..2740dec81 100644 --- a/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl +++ b/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl @@ -74,11 +74,11 @@ autoinstall: - mkdir -p /target/var/log/xcat/ - '{ cat /tmp/pre-install.log >> /target/var/log/xcat/xcat.log; - installnic="#TABLE:noderes:$NODE:installnic#"; + installnic="#TABLEBLANKOKAY:noderes:$NODE:installnic#"; installmac="#TABLE:mac:$NODE:mac#"; installmac="$(printf ''%s'' "${installmac}" | cut -d''|'' -f1 | cut -d''!'' -f1 | tr ''A-F'' ''a-f'')"; mkdir -p /target/etc/netplan; - if [ "${installnic}" = "mac" ]; then + if [ "${installnic}" = "mac" ] || [ -z "${installnic}" ]; then printf ''%s\n'' "network:" " version: 2" " ethernets:" " xcat-install:" " match:" " macaddress: \"${installmac}\"" " dhcp4: true" >/target/etc/netplan/00-xcat-install.yaml; else printf ''%s\n'' "network:" " version: 2" " ethernets:" " xcat-install:" " match:" " macaddress: \"${installmac}\"" " set-name: ${installnic}" " dhcp4: true" >/target/etc/netplan/00-xcat-install.yaml; From f021fe74fe8afa851baf57cf4654f826deeccf1a Mon Sep 17 00:00:00 2001 From: Daniel Hilst <392820+dhilst@users.noreply.github.com> Date: Mon, 24 Aug 2026 18:14:40 -0300 Subject: [PATCH 3/4] test(xcat-core): capture primarynic being skipped when installnic is unset xCAT resolves the provisioning interface as installnic -> primarynic -> mac.mac, and either attribute may hold an interface NAME or a MAC address; xCAT::NetworkUtils::gen_net_boot_params owns that order for the netboot kernel parameters. The Subiquity template short-circuits it: an empty installnic is treated as "mac" straight away, so a node that configures only primarynic is installed with a netplan that matches on mac.mac and never renames the interface, and a primarynic holding a MAC address is ignored entirely. Assert the full order against a resolver in xCAT::Template -- installnic as a name, installnic as a MAC, installnic empty with primarynic as a name, empty with primarynic as a MAC, both empty, and the literal "mac" -- plus multi-entry mac.mac resolution, and then run the template's own netplan late-command with the resolved values and compare the file it writes. These fail on the current template, which carries the resolution in shell and has no resolver to call. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com> --- xCAT-test/unit/ubuntu_subiquity_installnic.t | 141 +++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 xCAT-test/unit/ubuntu_subiquity_installnic.t diff --git a/xCAT-test/unit/ubuntu_subiquity_installnic.t b/xCAT-test/unit/ubuntu_subiquity_installnic.t new file mode 100644 index 000000000..83d5ee498 --- /dev/null +++ b/xCAT-test/unit/ubuntu_subiquity_installnic.t @@ -0,0 +1,141 @@ +#!/usr/bin/env perl +# The interface the INSTALLED system brings up must be resolved in xCAT's own order -- +# noderes.installnic, else noderes.primarynic, else match on mac.mac -- and either attribute may +# hold an interface NAME or a MAC address. Treating an empty installnic as "mac" straight away +# skips primarynic entirely, so a node that configures only primarynic is provisioned with a +# netplan that matches on mac.mac and never renames the interface. +# +# Two halves are covered: the resolution itself (xCAT::Template, which delegates the order to +# xCAT::NetworkUtils::gen_net_boot_params rather than re-deriving it), and the netplan the +# template's late-command actually writes once rendered with the resolved values. +use strict; +use warnings; + +use FindBin; +use lib "$FindBin::Bin/../../perl-xCAT"; +use lib "$FindBin::Bin/../../xCAT-server/lib/perl"; +use File::Temp qw(tempdir); +use Test::More; +use xCAT::Template; + +my $NODE = 'node01'; +my $NODE_MAC = 'AA:BB:CC:DD:EE:01'; + +# ---- resolution: installnic -> primarynic -> mac.mac, each of which may be a name or a MAC ------ +my @cases = ( + { + name => 'installnic names an interface', + installnic => 'ens4', + primarynic => 'eno1', + setname => 'ens4', + macaddress => 'aa:bb:cc:dd:ee:01', + why => 'renames the device matched by mac.mac', + }, + { + name => 'installnic holds a MAC address', + installnic => 'aa:bb:cc:dd:ee:02', + primarynic => 'eno1', + setname => '', + macaddress => 'aa:bb:cc:dd:ee:02', + why => 'matches that MAC and renames nothing', + }, + { + name => 'installnic empty, primarynic names an interface', + installnic => '', + primarynic => 'eno1', + setname => 'eno1', + macaddress => 'aa:bb:cc:dd:ee:01', + why => 'falls back to primarynic instead of skipping to mac', + }, + { + name => 'installnic empty, primarynic holds a MAC address', + installnic => '', + primarynic => 'aa:bb:cc:dd:ee:03', + setname => '', + macaddress => 'aa:bb:cc:dd:ee:03', + why => 'falls back to the primarynic MAC', + }, + { + name => 'installnic and primarynic both unset', + installnic => '', + primarynic => '', + setname => '', + macaddress => 'aa:bb:cc:dd:ee:01', + why => 'finally falls back to mac.mac', + }, + { + name => 'installnic set to the literal "mac"', + installnic => 'mac', + primarynic => 'eno1', + setname => '', + macaddress => 'aa:bb:cc:dd:ee:01', + why => 'is an explicit request to match by MAC, so primarynic is not consulted', + }, +); + +for my $case (@cases) { + my ($setname, $macaddress) = xCAT::Template::subiquity_install_netcfg( + $case->{installnic}, $case->{primarynic}, $NODE_MAC, $NODE); + is($setname, $case->{setname}, "$case->{name}: $case->{why} (set-name)"); + is($macaddress, $case->{macaddress}, "$case->{name}: $case->{why} (macaddress)"); +} + +# mac.mac carries |-separated, !hostname-suffixed entries; the netplan must match this node's. +{ + my $entry = "aa:bb:cc:dd:ee:09!other|aa:bb:cc:dd:ee:0a!$NODE"; + my (undef, $macaddress) = + xCAT::Template::subiquity_install_netcfg('', '', $entry, $NODE); + is($macaddress, 'aa:bb:cc:dd:ee:0a', + 'a multi-entry mac.mac resolves to this node\'s address, lower-cased'); +} + +# ---- rendering: run the template's own late-command and read the netplan it writes -------------- +my $tmpl_path = defined $ENV{XCATROOT} + ? "$ENV{XCATROOT}/share/xcat/install/ubuntu/compute.subiquity.tmpl" : ''; +$tmpl_path = 'xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl' + unless -f $tmpl_path; +$tmpl_path = "$FindBin::Bin/../../xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl" + unless -f $tmpl_path; + +SKIP: { + skip 'compute.subiquity.tmpl not found', 4 unless -f $tmpl_path; + my $tmpl = do { local $/; open my $fh, '<', $tmpl_path or die $!; <$fh> }; + + # The netplan-writing part of late-commands, verbatim: from the resolved values down to the + # chmod. Rendering it here is what proves the shell branches on what Perl resolved. + my ($snippet) = $tmpl =~ /(installnic="#SUBIQUITYINSTALLNIC#".*?fi;)/s; + ok($snippet, 'the netplan late-command is rendered from the resolved values'); + + skip 'netplan late-command not found in the template', 3 unless $snippet; + $snippet =~ s/''/'/g; # undo the YAML single-quote escaping + + for my $case ( + { name => 'a resolved interface name', setname => 'eno1', mac => 'aa:bb:cc:dd:ee:01' }, + { name => 'no interface name', setname => '', mac => 'aa:bb:cc:dd:ee:03' }, + ) + { + my $dir = tempdir(CLEANUP => 1); + my $script = $snippet; + $script =~ s/#SUBIQUITYINSTALLNIC#/$case->{setname}/g; + $script =~ s/#SUBIQUITYINSTALLMAC#/$case->{mac}/g; + $script =~ s{/target/}{$dir/target/}g; + system('sh', '-c', "set -e\n$script") == 0 + or die "netplan late-command failed for $case->{name}\n"; + + my $netplan = do { + local $/; + open my $fh, '<', "$dir/target/etc/netplan/00-xcat-install.yaml" or die $!; + <$fh>; + }; + my @expected = ( + 'network:', ' version: 2', ' ethernets:', ' xcat-install:', + ' match:', qq( macaddress: "$case->{mac}"), + ($case->{setname} ne '' ? " set-name: $case->{setname}" : ()), + ' dhcp4: true', + ); + is($netplan, join("\n", @expected) . "\n", + "the netplan written for $case->{name} matches the resolved values"); + } +} + +done_testing(); From 4844528860ba1898e07dd3435bf1a47cc820d698 Mon Sep 17 00:00:00 2001 From: Daniel Hilst <392820+dhilst@users.noreply.github.com> Date: Mon, 24 Aug 2026 18:17:08 -0300 Subject: [PATCH 4/4] fix(xcat-core): resolve the Subiquity install NIC in xCAT's own fallback order Treating an empty noderes.installnic as "mac" skipped noderes.primarynic: a node that configures only primarynic was installed with a netplan matching on mac.mac that never renamed the interface, and a primarynic holding a MAC address was ignored. The order xCAT uses everywhere else is installnic -> primarynic -> mac.mac, with either attribute allowed to hold an interface name or a MAC address, and xCAT::NetworkUtils::gen_net_boot_params already implements it for the netboot kernel parameters. Resolve it in Perl and hand the template the answer: - xCAT::Template::subiquity_install_netcfg() delegates the order to gen_net_boot_params and returns the netplan set-name (empty when the device is matched by MAC alone) and the address to match on, with mac.mac parsed by xCAT::Utils::parseMacTabEntry so |-separated, !hostname-suffixed entries resolve to THIS node rather than to whichever entry came first. - #SUBIQUITYINSTALLNIC# / #SUBIQUITYINSTALLMAC# render those two values. installnic and primarynic are read blank-okay -- a node that sets neither is normal, and is exactly what "match on mac.mac" means -- while mac.mac stays a required lookup, as it was when the template read it directly. - compute.subiquity.tmpl consumes the resolved values. No part of the fallback, and no mac.mac parsing, is left in shell: it only chooses whether to emit set-name, based on whether a name was resolved. ubuntu_subiquity_installnic.t now passes: the six resolution cases, multi-entry mac.mac, and the netplan the template's own late-command writes for a resolved name and for none. ubuntu_subiquity_template.t asserts the template no longer reads installnic/primarynic or parses MACs itself. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com> --- xCAT-server/lib/perl/xCAT/Template.pm | 67 +++++++++++++++++++ .../install/ubuntu/compute.subiquity.tmpl | 7 +- xCAT-test/unit/ubuntu_subiquity_template.t | 37 +++++----- 3 files changed, 90 insertions(+), 21 deletions(-) diff --git a/xCAT-server/lib/perl/xCAT/Template.pm b/xCAT-server/lib/perl/xCAT/Template.pm index bcf37d647..ea45ea0e7 100644 --- a/xCAT-server/lib/perl/xCAT/Template.pm +++ b/xCAT-server/lib/perl/xCAT/Template.pm @@ -372,6 +372,8 @@ sub subvars { $inc =~ s/#XCATVAR:([^#]+)#/envvar($1)/eg; $inc =~ s/#ENV:([^#]+)#/envvar($1)/eg; $inc =~ s/#UBUNTU_SUBIQUITY_APT_CONFIG#/ubuntu_subiquity_apt_config($media_dir)/eg; + $inc =~ s/#SUBIQUITYINSTALLNIC#/subiquity_install_nic()/eg; + $inc =~ s/#SUBIQUITYINSTALLMAC#/subiquity_install_mac()/eg; $inc =~ s/#MACHINEPASSWORD#/machinepassword()/eg; $inc =~ s/#CRYPT:([^:]+):([^:]+):([^#]+)#/crydb($1,$2,$3)/eg; $inc =~ s/#CRYPTORLOCKED:([^:]+):([^:]+):([^#]+)#/crydb_or_locked($1,$2,$3)/eg; @@ -1654,6 +1656,71 @@ sub crydb_or_locked return '*'; } +#-------------------------------------------------------------------------------- + +=head3 subiquity_install_netcfg + + Resolve the interface the INSTALLED system must bring up, in xCAT's own order: + noderes.installnic, else noderes.primarynic, else match on mac.mac. Either attribute may name + an interface OR carry a MAC address. xCAT::NetworkUtils::gen_net_boot_params already owns that + order for the netboot kernel parameters, so it is reused here rather than re-derived -- and in + particular the install template never re-derives any part of it in shell. + + Arguments: + $installnic - noderes.installnic (may be undef or empty) + $primarynic - noderes.primarynic (may be undef or empty) + $macentry - the raw mac.mac entry (may hold |-separated, !hostname-suffixed entries) + $nodename - the node the entry is resolved for + Returns: + ($setname, $macaddress) + $setname - the name netplan must rename the matched device to, empty when the device is + matched by MAC alone (installnic unset/"mac", or a MAC address given) + $macaddress - the address netplan matches on, lower-cased + +=cut + +#-------------------------------------------------------------------------------- +sub subiquity_install_netcfg { + my ($installnic, $primarynic, $macentry, $nodename) = @_; + + my $macmac = xCAT::Utils->parseMacTabEntry(defined($macentry) ? $macentry : '', $nodename); + my $params = xCAT::NetworkUtils->gen_net_boot_params($installnic, $primarynic, $macmac); + + my $setname = defined($params->{nicname}) ? $params->{nicname} : ''; + my $macaddress = defined($params->{mac}) ? lc($params->{mac}) : ''; + return ($setname, $macaddress); +} + +#-------------------------------------------------------------------------------- + +=head3 subiquity_install_nic / subiquity_install_mac + + Render #SUBIQUITYINSTALLNIC# / #SUBIQUITYINSTALLMAC# for the node being templated. installnic + and primarynic are read blank-okay (a node that sets neither is normal, and is what + "match on mac.mac" means); mac.mac stays a required lookup, as it was when the template read it + directly -- a node with no MAC cannot be matched by netplan at all. + +=cut + +#-------------------------------------------------------------------------------- +sub subiquity_install_netcfg_for_node { + return subiquity_install_netcfg( + tabdb('noderes', '$NODE', 'installnic', 1), + tabdb('noderes', '$NODE', 'primarynic', 1), + tabdb('mac', '$NODE', 'mac'), + $node); +} + +sub subiquity_install_nic { + my ($setname) = subiquity_install_netcfg_for_node(); + return $setname; +} + +sub subiquity_install_mac { + my (undef, $macaddress) = subiquity_install_netcfg_for_node(); + return $macaddress; +} + sub ubuntu_subiquity_apt_mirror { # Apt mirror for Subiquity installs. site.ubuntu_apt_mirror overrides; otherwise default to the diff --git a/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl b/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl index 2740dec81..8399cef6c 100644 --- a/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl +++ b/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl @@ -74,11 +74,10 @@ autoinstall: - mkdir -p /target/var/log/xcat/ - '{ cat /tmp/pre-install.log >> /target/var/log/xcat/xcat.log; - installnic="#TABLEBLANKOKAY:noderes:$NODE:installnic#"; - installmac="#TABLE:mac:$NODE:mac#"; - installmac="$(printf ''%s'' "${installmac}" | cut -d''|'' -f1 | cut -d''!'' -f1 | tr ''A-F'' ''a-f'')"; + installnic="#SUBIQUITYINSTALLNIC#"; + installmac="#SUBIQUITYINSTALLMAC#"; mkdir -p /target/etc/netplan; - if [ "${installnic}" = "mac" ] || [ -z "${installnic}" ]; then + if [ -z "${installnic}" ]; then printf ''%s\n'' "network:" " version: 2" " ethernets:" " xcat-install:" " match:" " macaddress: \"${installmac}\"" " dhcp4: true" >/target/etc/netplan/00-xcat-install.yaml; else printf ''%s\n'' "network:" " version: 2" " ethernets:" " xcat-install:" " match:" " macaddress: \"${installmac}\"" " set-name: ${installnic}" " dhcp4: true" >/target/etc/netplan/00-xcat-install.yaml; diff --git a/xCAT-test/unit/ubuntu_subiquity_template.t b/xCAT-test/unit/ubuntu_subiquity_template.t index 77f80a356..140dfaf39 100644 --- a/xCAT-test/unit/ubuntu_subiquity_template.t +++ b/xCAT-test/unit/ubuntu_subiquity_template.t @@ -36,23 +36,26 @@ unlike($tmpl, qr/echo.*GRUB_CMDLINE.*\\"/, 'no escaped double quotes in echo GRU unlike($tmpl, qr/\\\\x22/, 'template does not rely on non-portable printf hex escapes'); like($tmpl, qr/printf ''%s\\n'' ''GRUB_CMDLINE_LINUX="#TABLEBLANKOKAY:bootparams:\$NODE:kcmdline#"''/, 'GRUB line uses portable printf quoting'); like($tmpl, qr/\/target\/etc\/netplan\/00-xcat-install\.yaml/, 'template writes an xCAT-owned target netplan file'); -# Regression: an UNSET noderes.installnic must not fatally break Subiquity xnba -# generation. The EL/SLES statefull templates never reference installnic, so they default -# gracefully; this template resolved #TABLE:noderes:$NODE:installnic#, and Template.pm's tabdb -# raises "Unable to find requested field from table " -> "Failed to -# generate xnba configurations" when the node carries no installnic value, so the Ubuntu -# diskful install never starts. The template must use the non-fatal #TABLEBLANKOKAY# token -# (renders blank when unset) and treat an empty installnic the same as "mac" -- match by MAC -# with no NIC rename, which is the EL-equivalent default. -unlike($tmpl, qr/installnic="#TABLE:noderes:\$NODE:installnic#"/, - 'installnic does NOT use the fatal #TABLE# token (it errors when installnic is unset)'); -like($tmpl, qr/installnic="#TABLEBLANKOKAY:noderes:\$NODE:installnic#"/, - 'installnic uses the non-fatal #TABLEBLANKOKAY# token so an unset installnic renders blank'); -like($tmpl, qr/if \[ "\$\{installnic\}" = "mac" \] \|\| \[ -z "\$\{installnic\}" \]; then/, - 'an empty installnic is handled like "mac" (match by MAC, no set-name rename)'); -like($tmpl, qr/installmac="#TABLE:mac:\$NODE:mac#"/, 'target netplan uses node MAC'); -like($tmpl, qr/installmac="\$\(printf ''%s'' "\$\{installmac\}".*\| tr ''A-F'' ''a-f''\)"/, 'target netplan normalizes MAC case'); -like($tmpl, qr/installmac="\$\(printf ''%s'' "\$\{installmac\}" \| cut -d''\|'' -f1 \| cut -d''!'' -f1/, 'target netplan strips mac table suffixes before matching'); +# Regression: an UNSET noderes.installnic must not fatally break Subiquity xnba generation, and +# the interface must still be resolved in xCAT's order (installnic -> primarynic -> mac.mac). The +# template read #TABLE:noderes:$NODE:installnic#, and Template.pm's tabdb raises "Unable to find +# requested field from table " -> "Failed to generate xnba configurations" +# when the node carries no installnic, so the Ubuntu diskful install never started. The resolution +# now happens in Perl (xCAT::Template, via xCAT::NetworkUtils::gen_net_boot_params) and reaches the +# template already resolved, so no part of that order is re-derived in shell. The resolution itself +# and the netplan it produces are covered by ubuntu_subiquity_installnic.t. +unlike($tmpl, qr/noderes:\$NODE:(?:installnic|primarynic)/, + 'the template does not read installnic/primarynic itself (fatal when unset, and it would have to redo the fallback)'); +like($tmpl, qr/installnic="#SUBIQUITYINSTALLNIC#"/, + 'the target netplan uses the interface name xCAT resolved for this node'); +like($tmpl, qr/installmac="#SUBIQUITYINSTALLMAC#"/, + 'the target netplan uses the MAC address xCAT resolved for this node'); +like($tmpl, qr/if \[ -z "\$\{installnic\}" \]; then/, + 'no resolved interface name means match by MAC alone, with no set-name rename'); +unlike($tmpl, qr/tr ''A-F'' ''a-f''/, + 'the shell no longer normalizes the MAC (Template.pm resolves mac.mac entries)'); +unlike($tmpl, qr/cut -d''\|'' -f1/, + 'the shell no longer splits mac.mac entries (Template.pm resolves them for this node)'); like($tmpl, qr/printf ''%s\\n'' "network:" " version: 2" " ethernets:" " xcat-install:" " match:" " macaddress: \\"\$\{installmac\}\\"" " set-name: \$\{installnic\}" " dhcp4: true" >\/target\/etc\/netplan\/00-xcat-install\.yaml;/, 'target netplan printf stays on one shell line'); like($tmpl, qr/" macaddress: \\"\$\{installmac\}\\""/, 'target netplan matches by MAC address'); like($tmpl, qr/" set-name: \$\{installnic\}"/, 'target netplan sets the expected installnic name');