2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-04 20:17:55 +00:00

Merge pull request #7782 from VersatusHPC/fix/template-install-device

fix(template): honour installnic when the kickstart names the install device
This commit is contained in:
Daniel Hilst
2026-09-01 18:35:45 -03:00
committed by GitHub
2 changed files with 200 additions and 7 deletions
+44 -7
View File
@@ -1052,13 +1052,23 @@ sub kickstartnetwork {
unless ($mactab) { $tmplerr = "mac table should always exist prior to template processing when doing autoula"; return; }
my $ent = $mactab->getNodeAttribs($node, ['mac'], prefetchcache => 1);
unless ($ent and $ent->{mac}) { $tmplerr = "missing mac data for $node"; return; }
my $suffix = xCAT::Utils->parseMacTabEntry($ent->{mac}, $node);
$suffix = lc($suffix);
my ($installnic, $primarynic);
my $nrtab = xCAT::Table->new('noderes', -create => 0);
if ($nrtab) {
my $nrent = $nrtab->getNodeAttribs($node, [ 'installnic', 'primarynic' ], prefetchcache => 1);
if ($nrent) {
$installnic = $nrent->{installnic};
$primarynic = $nrent->{primarynic};
}
}
my $params = install_device_params($installnic, $primarynic, $ent->{mac}, $node);
my $macaddr = defined($params->{mac}) ? lc($params->{mac}) : '';
my $suffix = defined($params->{nicname}) ? $params->{nicname} : $macaddr;
if ($::XCATSITEVALS{managedaddressmode} eq "autoula") {
unless ($hoststab) { $hoststab = xCAT::Table->new('hosts', -create => 1); }
$line .= "static --device=$suffix --noipv4 --ipv6=";
my $ulaaddr = autoulaaddress($suffix);
my $ulaaddr = autoulaaddress($macaddr);
$hoststab->setNodeAttribs($node, { ip => $ulaaddr });
$line .= $ulaaddr;
} elsif ($::XCATSITEVALS{managedaddressmode} =~ /static/) {
@@ -1664,19 +1674,47 @@ sub crydb_or_locked
#--------------------------------------------------------------------------------
=head3 subiquity_install_netcfg
=head3 install_device_params
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.
particular an install template never re-derives any part of it in shell.
Every install template that has to name the install device shares this resolution, so the
device an installer configures cannot disagree with the device the netboot kernel parameters
name. The resolution carries no boot loader dependency of any kind.
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:
the hash reference from gen_net_boot_params. Of interest to install templates:
nicname - the interface name, set only when installnic/primarynic names an interface
mac - the address, set whenever one is known
=cut
#--------------------------------------------------------------------------------
sub install_device_params {
my ($installnic, $primarynic, $macentry, $nodename) = @_;
my $macmac = xCAT::Utils->parseMacTabEntry(defined($macentry) ? $macentry : '', $nodename);
return xCAT::NetworkUtils->gen_net_boot_params($installnic, $primarynic, $macmac);
}
#--------------------------------------------------------------------------------
=head3 subiquity_install_netcfg
Shape install_device_params for netplan, which matches a device by MAC and optionally renames
it.
Arguments:
as install_device_params
Returns:
($setname, $macaddress)
$setname - the name netplan must rename the matched device to, empty when the device is
@@ -1689,8 +1727,7 @@ sub crydb_or_locked
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 $params = install_device_params($installnic, $primarynic, $macentry, $nodename);
my $setname = defined($params->{nicname}) ? $params->{nicname} : '';
my $macaddress = defined($params->{mac}) ? lc($params->{mac}) : '';
+156
View File
@@ -0,0 +1,156 @@
#!/usr/bin/env perl
use strict;
use warnings;
use File::Spec;
use FindBin;
use Test::More;
BEGIN {
push @INC,
File::Spec->catdir( $FindBin::Bin, '..', '..', 'perl-xCAT' ),
File::Spec->catdir( $FindBin::Bin, '..', '..', 'xCAT-server', 'lib', 'perl' );
}
eval { require xCAT::Template; 1 }
or plan skip_all => "xCAT::Template not loadable: $@";
my $NODE = 'n1';
my $MAC1 = 'AA:BB:CC:DD:EE:01';
my $MAC2 = 'AA:BB:CC:DD:EE:02';
# The order is installnic, then primarynic, then mac.mac. Either attribute may
# name an interface or carry an address.
my $p = xCAT::Template::install_device_params( '', '', $MAC1, $NODE );
is( $p->{mac}, $MAC1, 'with neither attribute set the address comes from mac.mac' );
is( $p->{nicname}, undef, 'with neither attribute set no interface is named' );
$p = xCAT::Template::install_device_params( 'eth1', '', $MAC1, $NODE );
is( $p->{nicname}, 'eth1', 'installnic naming an interface wins' );
is( $p->{mac}, $MAC1, 'the address is still resolved alongside the interface' );
$p = xCAT::Template::install_device_params( '', 'eth2', $MAC1, $NODE );
is( $p->{nicname}, 'eth2', 'primarynic is used when installnic is not set' );
$p = xCAT::Template::install_device_params( 'eth1', 'eth2', $MAC1, $NODE );
is( $p->{nicname}, 'eth1', 'installnic beats primarynic' );
$p = xCAT::Template::install_device_params( $MAC2, '', $MAC1, $NODE );
is( $p->{mac}, $MAC2, 'installnic carrying an address names that address' );
is( $p->{nicname}, undef, 'installnic carrying an address names no interface' );
$p = xCAT::Template::install_device_params( 'mac', '', $MAC1, $NODE );
is( $p->{mac}, $MAC1, 'the keyword mac falls back to mac.mac' );
is( $p->{nicname}, undef, 'the keyword mac names no interface' );
# A mac.mac entry may hold several addresses. The entry tagged with the node
# name is the one that belongs to the node.
$p = xCAT::Template::install_device_params( '', '', "$MAC1!$NODE|$MAC2!other", $NODE );
is( $p->{mac}, $MAC1, 'the tagged entry for the node is selected' );
# Ubuntu keeps its own return shape over the same resolution.
my ( $setname, $macaddress ) =
xCAT::Template::subiquity_install_netcfg( 'eth1', '', $MAC1, $NODE );
is( $setname, 'eth1', 'netplan is given the interface to rename to' );
is( $macaddress, lc($MAC1), 'netplan is given the address, lower cased' );
( $setname, $macaddress ) =
xCAT::Template::subiquity_install_netcfg( '', '', $MAC1, $NODE );
is( $setname, '', 'netplan renames nothing when no interface is named' );
is( $macaddress, lc($MAC1), 'netplan still matches on the address' );
{
package Local::TemplateInstallTable;
sub getNodeAttribs {
my ($self) = @_;
return $self->{row};
}
sub setNodeAttribs {
my ( $self, undef, $attrs ) = @_;
$self->{written} = { %{$attrs} };
return 1;
}
}
# Exercise kickstartnetwork itself with in-memory table objects. This verifies
# the generated kickstart line rather than the text of Template.pm.
sub kickstart_network {
my ( $installnic, $primarynic, $macentry, $mode ) = @_;
my $mactab = bless { row => { mac => $macentry } }, 'Local::TemplateInstallTable';
my $nrtab = bless {
row => {
installnic => $installnic,
primarynic => $primarynic,
}
},
'Local::TemplateInstallTable';
my $hoststab = bless {}, 'Local::TemplateInstallTable';
my $autoula_mac;
no warnings qw(redefine once);
local *xCAT::Table::new = sub {
my ( undef, $table ) = @_;
return $mactab if $table eq 'mac';
return $nrtab if $table eq 'noderes';
return $hoststab if $table eq 'hosts';
die "Unexpected table $table";
};
local *xCAT::Template::autoulaaddress = sub {
($autoula_mac) = @_;
return 'fd00::1';
};
local $::XCATSITEVALS{managedaddressmode} = $mode || 'dhcp';
my $line = xCAT::Template::kickstartnetwork();
return ( $line, $autoula_mac, $hoststab->{written} );
}
sub ks_device {
my ($line) = kickstart_network(@_);
return $line =~ /--device=(\S+)/ ? $1 : undef;
}
is( ks_device( '', '', $MAC1 ), lc($MAC1),
'a node setting neither attribute keeps the address it has today' );
is( ks_device( 'eth1', '', $MAC1 ), 'eth1',
'a node setting installnic names that interface' );
is( ks_device( $MAC2, '', $MAC1 ), lc($MAC2),
'a node whose installnic carries an address names that address' );
# The defect this closes: a bare multi address entry resolves to the LAST
# address, which need not be the adapter that deploys the node. Setting
# installnic must override that.
my $BARE = "$MAC1|$MAC2";
is( ks_device( '', '', $BARE ), lc($MAC2),
'a bare multi address entry alone still resolves to the last address' );
is( ks_device( 'eth0', '', $BARE ), 'eth0',
'installnic overrides a bare multi address entry' );
# An interface name is case sensitive. A node on POWER carries names such as
# enP1p12s0f0, which no longer name a device once they are lower cased. Only
# an address may be lower cased.
my $MIXED = 'enP1p12s0f0';
is( ks_device( $MIXED, '', $MAC1 ), $MIXED,
'the kickstart keeps the case of the interface name' );
is( ks_device( '', $MIXED, $MAC1 ), $MIXED,
'the kickstart keeps the case of a primarynic interface name' );
my ($mixedset) = xCAT::Template::subiquity_install_netcfg( $MIXED, '', $MAC1, $NODE );
is( $mixedset, $MIXED, 'Ubuntu keeps the case of the interface name too' );
is( ks_device( '', '', uc($MAC1) ), lc($MAC1),
'an address is still lower cased' );
# autoula must derive the address from the hardware address even when the
# kickstart selects an interface by name.
my ( $autoula_line, $autoula_mac, $hostattrs ) =
kickstart_network( $MIXED, '', $MAC1, 'autoula' );
is( $autoula_line,
"network --onboot=yes --bootproto=static --device=$MIXED --noipv4 --ipv6=fd00::1",
'autoula keeps the selected interface in the kickstart line' );
is( $autoula_mac, lc($MAC1),
'autoula derives the address from the MAC, not the interface name' );
is( $hostattrs->{ip}, 'fd00::1', 'the generated ULA is saved in the hosts table' );
done_testing();