2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-21 07:08:12 +00:00
Files
xcat-core/xCAT-test/unit/netboot_ipxe_method.t
T
2026-10-14 13:29:22 -03:00

113 lines
4.9 KiB
Perl

#!/usr/bin/env perl
# netboot=ipxe runs the boot scripts of the xnba method under xcat/ipxe/nodes, and netboot=xnba keeps
# them under xcat/xnba/nodes. nodeset writes them through the real plugins, and the nodeset state
# comes back through SvrUtils, into a scratch TFTP root. Tables, name resolution and the destiny
# subrequest are stand-ins.
use strict;
use warnings;
use File::Temp qw(tempdir);
use FindBin;
use lib "$FindBin::Bin/../../perl-xCAT";
use Test::More;
my $repo = "$FindBin::Bin/../..";
my $tftp = tempdir( CLEANUP => 1 );
our %rows;
BEGIN {
package xCAT::Table;
sub new { my ( $class, $table ) = @_; return bless { table => $table }, $class }
sub getNodesAttribs {
my ( $self, $nodes ) = @_;
return { map { $_ => [ $main::rows{ $self->{table} }{$_} ] } @$nodes };
}
sub getNodeAttribs { my ( $self, $node ) = @_; return $main::rows{ $self->{table} }{$node} }
sub getAttribs { return }
sub close { return }
package xCAT::NetworkUtils;
sub determinehostname { return ('mn') }
sub checkNodeIPaddress { return { ip => '192.0.2.10' } }
sub nodeonmynet { return 1 }
package xCAT::TableUtils;
sub getTftpDir { return $tftp }
sub get_site_attribute { return $_[1] eq 'dhcpsetup' ? ('n') : () } # no makedhcp from nodeset here
package xCAT::MsgUtils;
sub trace { return }
sub message { return }
package main;
for my $module (qw(Table NetworkUtils TableUtils MsgUtils Utils NodeRange Scope ServiceNodeUtils Usage BootUtils)) {
$INC{"xCAT/$module.pm"} = __FILE__;
}
}
# xcatd loads the plugins from their files. SvrUtils loads them by module name, so xCAT_plugin names
# the plugin directory of this checkout.
my $inc = tempdir( CLEANUP => 1 );
symlink( "$repo/xCAT-server/lib/xcat/plugins", "$inc/xCAT_plugin" ) or die "symlink: $!";
unshift @INC, $inc, "$repo/xCAT-server/lib/perl";
require xCAT_plugin::ipxe;
require xCAT::SvrUtils;
# What setdestiny leaves for each node: its currstate, and the kernel that bootparams names.
sub nodeset {
my ( $plugin, $node, %kernel ) = @_;
$rows{noderes}{$node} = { tftpdir => $tftp, netboot => $plugin };
$rows{chain}{$node} = { currstate => "install rhels9-x86_64-compute" };
$rows{nodetype}{$node} = { provmethod => 'install' };
my @calls;
my $subreq = sub {
my ($request) = @_;
push @calls, $request->{command}[0];
$request->{bootparams}{$node} = [ {%kernel} ] if $request->{command}[0] eq 'setdestiny';
return;
};
"xCAT_plugin::$plugin"->can('process_request')->(
{ command => ['nodeset'], node => [$node], arg => ['osimage'] }, sub { }, $subreq );
return @calls;
}
sub content {
my ($path) = @_;
open( my $fh, '<', "$tftp/$path" ) or return;
local $/;
return <$fh>;
}
my %linux = ( kernel => 'xcat/osimage/vmlinuz', initrd => 'xcat/osimage/initrd.img', kcmdline => 'quiet' );
ok( ( grep { $_ eq 'setdestiny' } nodeset( ipxe => 'cn01', %linux ) ), 'nodeset for an ipxe node runs its destiny' );
like( content('xcat/ipxe/nodes/cn01'), qr{imgfetch -n kernel http://\$\{next-server\}/tftpboot/xcat/osimage/vmlinuz},
'the ipxe method writes the BIOS boot script under xcat/ipxe/nodes' );
# Without an EFI stub in the kernel, UEFI boots through elilo, which reads its configuration beside
# the script.
like( content('xcat/ipxe/nodes/cn01.uefi'), qr{-C /tftpboot/xcat/ipxe/nodes/cn01\.elilo$}m,
'the UEFI boot script beside it points elilo at xcat/ipxe/nodes' );
like( content('xcat/ipxe/nodes/cn01.elilo'), qr{image=/tftpboot/xcat/osimage/vmlinuz}, 'where the ipxe method writes it' );
ok( !-e "$tftp/xcat/xnba/nodes/cn01", 'and nothing under xcat/xnba/nodes' );
nodeset( xnba => 'cn02', %linux );
ok( -e "$tftp/xcat/xnba/nodes/cn02" && !-e "$tftp/xcat/ipxe/nodes/cn02",
'an xnba node keeps its boot script under xcat/xnba/nodes after an ipxe node' );
# A kernel that iPXE cannot run chains pxelinux, which reads its configuration beside the script.
nodeset( ipxe => 'cn03', kernel => 'xcat/tools/memdisk', initrd => 'xcat/tools/disk.img' );
like( content('xcat/ipxe/nodes/cn03'), qr{set 209:string xcat/ipxe/nodes/cn03\.pxelinux},
'pxelinux of an ipxe node reads its configuration from xcat/ipxe/nodes' );
ok( -e "$tftp/xcat/ipxe/nodes/cn03.pxelinux", 'where the ipxe method writes that configuration' );
# nodeset stat reads the state that the boot script records, not the chain table.
$rows{chain}{$_} = { currstate => 'boot' } for qw(cn01 cn02);
my %states;
my ($rc) = xCAT::SvrUtils->getNodesetStates( [qw(cn01 cn02)], \%states );
is( $rc, 0, 'SvrUtils reads the nodeset state of ipxe and xnba nodes' );
is_deeply( [ sort @{ $states{install} || [] } ], [qw(cn01 cn02)], 'both nodes report the state their script records' );
is( xCAT::SvrUtils->get_nodeset_state( 'cn01', global_tab_hash => { noderes => { cn01 => $rows{noderes}{cn01} } } ),
'install', 'and the state of one ipxe node' );
done_testing();