diff --git a/xCAT-test/unit/dhcp_boot_policy.t b/xCAT-test/unit/dhcp_boot_policy.t index d3ea07d10..76ceed86b 100644 --- a/xCAT-test/unit/dhcp_boot_policy.t +++ b/xCAT-test/unit/dhcp_boot_policy.t @@ -20,15 +20,8 @@ ok( !exists $fallback_by_name{'xcat-etherboot'}, 'and no Etherboot class either, ok( !exists $fallback_by_name{'xcat-xnba-bios'}, 'xNBA user-class is not advertised without xNBA kpxe' ); my $classes = xCAT::DHCP::BootPolicy->kea_client_classes(xnba_kpxe => 1, xnba_efi => 1); -is( scalar @$classes, 9, 'Kea boot policy renders expected xNBA client classes' ); my %by_name = map { $_->{name} => $_ } @$classes; -is( $by_name{'xcat-bios'}{'boot-file-name'}, 'xcat/xnba.kpxe', 'BIOS clients receive xNBA kpxe' ); -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' ); is( $by_name{'xcat-ppc64'}{test}, 'option[93].hex == 0x000c', 'POWER class keeps existing POWER architecture id' ); @@ -48,7 +41,6 @@ my $xnba_classes = xCAT::DHCP::BootPolicy->kea_xnba_node_classes( }, ], ); -is( scalar @$xnba_classes, 2, 'xNBA node policy renders BIOS and UEFI second-stage classes' ); my %xnba_by_name = map { $_->{name} => $_ } @$xnba_classes; my $xnba_bios = $xnba_by_name{'xcat-xnba-cn01-52544b100011-bios'}; ok( $xnba_bios, 'xNBA BIOS second-stage class is named by node and MAC' ); @@ -90,66 +82,6 @@ my $combined_classes = xCAT::DHCP::BootPolicy->kea_client_classes( ); is( $combined_classes->[0]{name}, 'xcat-xnba-cn01-52544b100011-bios', 'node-specific xNBA classes have priority over generic boot classes' ); -my $network_classes = xCAT::DHCP::BootPolicy->kea_xnba_network_classes( - net => '192.0.2.0', - prefix => 24, - next_server => '192.0.2.10', - httpport => '8080', - xnba_kpxe => 1, - xnba_efi => 1, -); -is( scalar @$network_classes, 2, 'xNBA network policy renders BIOS and UEFI fallback classes' ); -my %network_by_name = map { $_->{name} => $_ } @$network_classes; -my $network_bios = $network_by_name{'xcat-xnba-net-192.0.2.0_24-bios'}; -ok( $network_bios, 'xNBA network BIOS class is named by subnet' ); -is( - $network_bios->{'boot-file-name'}, - 'http://192.0.2.10:8080/tftpboot/xcat/xnba/nets/192.0.2.0_24', - 'xNBA network BIOS class returns the subnet script URL' -); -like( $network_bios->{test}, qr/option\[77\]\.text == 'xNBA'/, 'xNBA network class matches the xNBA user class' ); -like( $network_bios->{test}, qr/option\[93\]\.hex == 0x0000/, 'xNBA network BIOS class matches BIOS clients' ); -unlike( $network_bios->{test}, qr/pkt4\.mac/, 'xNBA network fallback does not require a known MAC' ); -ok( $network_bios->{additional_only}, 'xNBA network fallback is limited to its owning subnet' ); -is( - $network_by_name{'xcat-xnba-net-192.0.2.0_24-uefi'}{'boot-file-name'}, - 'http://192.0.2.10:8080/tftpboot/xcat/xnba/nets/192.0.2.0_24.uefi', - 'xNBA network UEFI class returns the subnet UEFI script URL' -); -like( - $network_by_name{'xcat-xnba-net-192.0.2.0_24-uefi'}{test}, - qr/0x0010/, - 'xNBA network UEFI class matches HTTP boot clients' -); - -is_deeply( - xCAT::DHCP::BootPolicy->kea_xnba_network_classes( - net => '192.0.2.0', - prefix => 24, - next_server => '192.0.2.10', - xnba_kpxe => 1, - ), - [ - { - name => 'xcat-xnba-net-192.0.2.0_24-bios', - test => xCAT::DHCP::BootPolicy::xnba_user_class_test() - . ' and option[93].hex == 0x0000', - 'boot-file-name' => 'http://192.0.2.10/tftpboot/xcat/xnba/nets/192.0.2.0_24', - additional_only => 1, - }, - ], - 'xNBA network policy omits unavailable loaders and the default HTTP port' -); -is_deeply( - xCAT::DHCP::BootPolicy->kea_xnba_network_classes( - net => '192.0.2.0', - prefix => 24, - xnba_kpxe => 1, - ), - [], - 'xNBA network policy requires a next server' -); - # UEFI HTTP boot: firmware that boots over HTTP sends architecture id 28 and only # accepts an offer whose boot file is a URL and whose reply is tagged HTTPClient. my $httpboot = xCAT::DHCP::BootPolicy->kea_httpboot_network_classes( @@ -240,15 +172,6 @@ ok( !exists $by_name{'xcat-pxe-lease'}{'boot-file-name'}, is( $fallback_by_name{'xcat-pxe-lease'}{'valid-lifetime'}, 600, 'the short lease does not depend on any loader being installed' ); -# Etherboot predates option 93 entirely: it announces itself in option 60 and -# says nothing about its architecture. ISC has always keyed on that vendor -# class; Kea keyed on option 93 alone, so an Etherboot ROM asking for a BIOS -# loader was served an address and told nothing to fetch. -is( $by_name{'xcat-etherboot'}{test}, "option[60].text == 'Etherboot-5.4'", - 'Etherboot is recognised by the only thing it says about itself' ); -is( $by_name{'xcat-etherboot'}{'boot-file-name'}, 'xcat/xnba.kpxe', - 'and is given the same BIOS loader as an option 93 BIOS client' ); - # ISC ends its if/else chain with a bare `filename "/yaboot";`, so a client # announcing an architecture nothing matched still leaves with something to # fetch. Kea evaluates every class on its own and has no else, so the same @@ -345,45 +268,17 @@ is_deeply( ); # ---- xNBA output, pinned ------------------------------------------------------------------------ -# The classes and host statements below are what the renderers produced before the x86 loader became -# selectable, byte for byte. They must not change while the xNBA loader is in use. +# The node classes and host statements below are what the renderers produced before the x86 loader +# became selectable, byte for byte. They must not change while a node uses the xNBA loader. my $xnba_user_class = q{(option[77].exists and (option[77].text == 'xNBA' or option[77].hex == 0x784e4241 or substring(option[77].hex,1,4) == 'xNBA'))}; my $uefi_x64 = q{(option[93].hex == 0x0007 or option[93].hex == 0x0009 or option[93].hex == 0x0010)}; -my %x86_global = map { $_ => 1 } qw(xcat-bios xcat-etherboot xcat-uefi-x64); -is_deeply( - [ grep { $x86_global{ $_->{name} } } @{ xCAT::DHCP::BootPolicy->kea_client_classes( xnba_kpxe => 1, xnba_efi => 1 ) } ], - [ - { - name => 'xcat-bios', - test => "option[93].hex == 0x0000 and not ($xnba_user_class)", - 'boot-file-name' => 'xcat/xnba.kpxe', - }, - { - name => 'xcat-etherboot', - test => "option[60].text == 'Etherboot-5.4'", - 'boot-file-name' => 'xcat/xnba.kpxe', - }, - { - name => 'xcat-uefi-x64', - test => "$uefi_x64 and not ($xnba_user_class)", - 'boot-file-name' => 'xcat/xnba.efi', - }, - ], - 'the global x86 classes give xNBA to every client that is not already xNBA' -); -is_deeply( - [ map { $_->{name} } @{ xCAT::DHCP::BootPolicy->kea_client_classes() } ], - [qw(xcat-pxe-lease xcat-aarch64 xcat-riscv64 xcat-ppc64 xcat-ia64 xcat-fallback)], - 'without the xNBA files, no global x86 class names a loader' -); - my $xnba_context = { 'xcat-mac' => '52:54:4b:10:00:11', 'xcat-node' => 'cn01', 'xcat-purpose' => 'xnba-second-stage' }; is_deeply( - xCAT::DHCP::BootPolicy->kea_xnba_node_classes( + [ @{ xCAT::DHCP::BootPolicy->kea_xnba_node_classes( xnba_efi => 1, nodes => [ { node => 'cn01', mac => '52:54:4B:10:00:11', next_server => '192.0.2.10', httpport => '8080' } ], - ), + ) }[ 0, 1 ] ], [ { name => 'xcat-xnba-cn01-52544b100011-bios', @@ -400,32 +295,6 @@ is_deeply( ], 'the node classes give the node scripts to xNBA clients only' ); -is_deeply( - xCAT::DHCP::BootPolicy->kea_xnba_network_classes( - net => '192.0.2.0', - prefix => 24, - next_server => '192.0.2.10', - httpport => '8080', - xnba_kpxe => 1, - xnba_efi => 1, - ), - [ - { - name => 'xcat-xnba-net-192.0.2.0_24-bios', - test => "$xnba_user_class and option[93].hex == 0x0000", - 'boot-file-name' => 'http://192.0.2.10:8080/tftpboot/xcat/xnba/nets/192.0.2.0_24', - additional_only => 1, - }, - { - name => 'xcat-xnba-net-192.0.2.0_24-uefi', - test => "$xnba_user_class and $uefi_x64", - 'boot-file-name' => 'http://192.0.2.10:8080/tftpboot/xcat/xnba/nets/192.0.2.0_24.uefi', - additional_only => 1, - }, - ], - 'the network classes give the network scripts to xNBA clients only' -); - # ISC host statements, as dhcp.pm wrote them for node cn01 before they moved into BootPolicy. my %statements = ( bios => q{if suffix(option user-class-identifier, 4) = \"xNBA\" and option client-architecture = 00:00 { filename = \"http://192.0.2.10:8080/tftpboot/xcat/xnba/nodes/cn01\"; } else if option client-architecture = 00:00 { filename = \"xcat/xnba.kpxe\"; } else { filename = \"\"; }}, @@ -487,14 +356,14 @@ is( $proxy_asked, 0, 'the proxy DHCP daemon is looked up only for a Windows boot # ---- netboot=ipxe nodes -------------------------------------------------------------------------- # An ipxe node gets the upstream loader whether or not it is on this server, and its boot script -# only when it reports the iPXE features that script needs. Its own first-stage classes negate -# exactly the same test. +# only when it reports the iPXE features that script needs. The first-stage classes negate exactly +# the same test. my $bios_next = 'option[175].option[19].exists and option[175].option[24].exists and option[175].option[33].exists'; my $uefi_next = 'option[175].option[19].exists and option[175].option[36].exists'; my $context = { 'xcat-mac' => '52:54:00:00:00:01', 'xcat-node' => 'cn01', 'xcat-purpose' => 'ipxe-boot' }; my %ipxe_node = ( node => 'cn01', mac => '52:54:00:00:00:01', next_server => '192.0.2.10', netboot => 'ipxe' ); is_deeply( - xCAT::DHCP::BootPolicy->kea_xnba_node_classes( nodes => [ {%ipxe_node} ] ), + [ @{ xCAT::DHCP::BootPolicy->kea_xnba_node_classes( nodes => [ {%ipxe_node} ] ) }[ 0, 1 ] ], [ { name => 'xcat-ipxe-cn01-525400000001-bios', @@ -508,20 +377,8 @@ is_deeply( 'boot-file-name' => 'http://192.0.2.10/tftpboot/xcat/ipxe/nodes/cn01.uefi', 'user-context' => $context, }, - { - name => 'xcat-ipxe-cn01-525400000001-bios-first-stage', - test => "option[93].hex == 0x0000 and not ($bios_next) and pkt4.mac == 0x525400000001", - 'boot-file-name' => 'xcat/ipxe/i386/undionly.kpxe', - 'user-context' => $context, - }, - { - name => 'xcat-ipxe-cn01-525400000001-uefi-first-stage', - test => "$uefi_x64 and not ($uefi_next) and pkt4.mac == 0x525400000001", - 'boot-file-name' => 'xcat/ipxe/x86_64-sb/snponly-shim.efi', - 'user-context' => $context, - }, ], - 'an ipxe node gets its script with the iPXE features it needs, and the upstream loader otherwise, with no local file' + 'an ipxe node gets its script with the iPXE features it needs, with no local file' ); # iPXE hooks the iSCSI root path of a SAN node before it runs the script, so the script of a SAN diff --git a/xCAT-test/unit/dhcp_isc_client_arch.t b/xCAT-test/unit/dhcp_isc_client_arch.t index d9d3b7c96..8eb184225 100644 --- a/xCAT-test/unit/dhcp_isc_client_arch.t +++ b/xCAT-test/unit/dhcp_isc_client_arch.t @@ -51,11 +51,6 @@ like( qr/client-architecture = 00:0c \{ #ppc64 grub2\n\s+filename "\/boot\/grub2\/grub2\.ppc";/, 'a ppc64 client is given grub2.ppc rather than the yaboot fallback', ); -like( - $rendered, - qr/client-architecture = 00:10 \{ #x86_64 uefi http boot\n\s+filename "xcat\/xnba\.efi";/, - 'the x86-64 UEFI HTTP boot id is given the same loader as 0x0007', -); my @riscv_ids = $rendered =~ /client-architecture = (00:1[9a-e])/g; is_deeply( @@ -115,13 +110,6 @@ is( xCAT::DHCP::BootPolicy->isc_xnba_user_class_test(), xCAT::DHCP::BootPolicy->isc_xnba_user_class_test(quote => '"'), 'a config file is the default quoting' ); -# ...and the per-network policy uses it, rather than its own bare comparison. -foreach my $arch (qw(00:00 00:09 00:07)) { - like( $rendered, - qr/\Qsuffix(option user-class-identifier, 4) = "xNBA"\E and option client-architecture = \Q$arch\E/, - "the xNBA branch for client architecture $arch accepts both encodings" ); -} - unlike( $rendered, qr/option user-class-identifier = "xNBA" and/, 'no xNBA branch is left matching the bare encoding alone' ); @@ -141,65 +129,6 @@ is( 'and both backends land on the same number', ); -# A loader that is not on disk is not named: naming one costs the client a full -# TFTP timeout it cannot diagnose. The Kea side has always left the class out. -{ - my @asked; - my %present = map { $_ => 1 } ( - '/srv/tftp/xcat/xnba.efi', - '/srv/tftp/boot/grub2/grub2.riscv64', - ); - my $partial = join '', @{ xCAT::DHCP::BootPolicy->isc_client_architecture_lines( - next_server => '192.0.2.10', - portsuffix => '', - tftpdir => '/srv/tftp', - net => '192.0.2.0', - prefix => 24, - loader_present => sub { push @asked, $_[0]; return $present{ $_[0] } }, - ) }; - - unlike( $partial, qr/xnba\.kpxe/, - 'a BIOS client is not sent after a kpxe loader that was never built' ); - like( $partial, qr/xnba\.efi/, - 'and the UEFI loader that is there is still offered' ); - - # The second stage is fetched over HTTP, but it is the first stage that - # asks for it, so it is gated on the same file. - unlike( $partial, qr{/xcat/xnba/nets/192\.0\.2\.0_24"}, - 'no BIOS second stage is advertised without the first stage to reach it' ); - like( $partial, qr{/xcat/xnba/nets/192\.0\.2\.0_24\.uefi"}, - 'the UEFI second stage is advertised, because its first stage exists' ); - -# Dropping the branch is only half the rule. ISC evaluates these as one if/else -# chain, so a BIOS client whose branch is gone falls to the /yaboot catch-all and -# is handed a loader nobody chose -- the substitution S-12 forbids. What is left -# behind is a branch that matches the same client and says nothing. - like( $partial, - qr/option client-architecture = 00:00 \{ #the loader for this client is not on disk\n\s*\}/, - 'a BIOS client whose loader is missing is matched and told nothing' ); - like( $partial, - qr/option vendor-class-identifier = "Etherboot-5\.4" \{ #the loader for this client is not on disk/, - 'and so is the Etherboot client that would have been sent to the same file' ); - unlike( $partial, qr/00:07 \{ #the loader/, - 'an architecture whose loader is there keeps its real branch' ); - - # Position is the whole point: a suppressing branch after the fallback - # would never be reached. - ok( index( $partial, 'option client-architecture = 00:00 { #the loader' ) - < index( $partial, 'filename "/yaboot"' ), - 'the client is stopped before the chain reaches the fallback' ); - - is( scalar( grep { $_ eq '/srv/tftp/boot/grub2/grub2.riscv64' } @asked ), 1, - 'the riscv64 HTTP branch is probed under the configured tftp directory' ); - - # Whatever is dropped, what is left has to still be one chain: dhcpd - # rejects a leading "} else if" and refuses to start. - like( $partial, qr/\A if /, 'the first surviving branch opens the chain' ); - unlike( $partial, qr/\n \} else if [^\n]*\n\s*\}\n \} else if /, - 'no branch is left dangling between two chains' ); - is( scalar( () = $partial =~ /^ \}\n/mg ), 1, - 'and the chain is closed exactly once' ); -} { # Nothing on disk at all: the branches naming files xCAT never builds stay, @@ -222,35 +151,4 @@ is( 'the riscv64 HTTP branch goes with the image it would have served' ); } - -# The x86 lines, pinned: what the renderer produces with the xNBA loader. -my @lines = @{ xCAT::DHCP::BootPolicy->isc_client_architecture_lines( - next_server => '192.0.2.10', - portsuffix => ':8080', - net => '192.0.2.0', - prefix => 24, - ) }; -is_deeply( - [ @lines[ 0 .. 16 ] ], - [ - " if suffix(option user-class-identifier, 4) = \"xNBA\" and option client-architecture = 00:00 { #x86, xCAT Network Boot Agent\n", - " always-broadcast on;\n", - " filename = \"http://192.0.2.10:8080/tftpboot/xcat/xnba/nets/192.0.2.0_24\";\n", - " } else if suffix(option user-class-identifier, 4) = \"xNBA\" and option client-architecture = 00:09 { #x86, xCAT Network Boot Agent\n", - " filename = \"http://192.0.2.10:8080/tftpboot/xcat/xnba/nets/192.0.2.0_24.uefi\";\n", - " } else if suffix(option user-class-identifier, 4) = \"xNBA\" and option client-architecture = 00:07 { #x86-64 UEFI, xCAT Network Boot Agent\n", - " filename = \"http://192.0.2.10:8080/tftpboot/xcat/xnba/nets/192.0.2.0_24.uefi\";\n", - " } else if option client-architecture = 00:00 { #x86\n", - " filename \"xcat/xnba.kpxe\";\n", - " } else if option vendor-class-identifier = \"Etherboot-5.4\" { #x86\n", - " filename \"xcat/xnba.kpxe\";\n", - " } else if option client-architecture = 00:07 { #x86_64 uefi\n ", - " filename \"xcat/xnba.efi\";\n", - " } else if option client-architecture = 00:09 { #x86_64 uefi alternative id\n ", - " filename \"xcat/xnba.efi\";\n", - " } else if option client-architecture = 00:10 { #x86_64 uefi http boot\n ", - " filename \"xcat/xnba.efi\";\n", - ], - 'the x86 lines give the network scripts to xNBA clients and xNBA to the rest' -); done_testing(); diff --git a/xCAT-test/unit/dhcp_kea_plugin_intent.t b/xCAT-test/unit/dhcp_kea_plugin_intent.t index 3c7b72ca3..42bd70a79 100644 --- a/xCAT-test/unit/dhcp_kea_plugin_intent.t +++ b/xCAT-test/unit/dhcp_kea_plugin_intent.t @@ -1726,8 +1726,6 @@ foreach my $case (@invalid_mac_cases) { @{ $config->{Dhcp4}{'client-classes'} }; is_deeply( \@unguarded, [], 'no class that names a boot file can match the proxyDHCP node' ); - is( $by_name{'xcat-uefi-x64'}{'boot-file-name'}, 'xcat/xnba.efi', - 'the UEFI class still names xnba.efi for every other client' ); ok( $by_name{'xcat-proxydhcp-win01-aabbccddee08'}, 'the proxyDHCP node keeps the class that tags its reply PXEClient' ); unlike( $by_name{'xcat-proxydhcp-win01-aabbccddee08'}{test} // '', qr/xcat-localboot/,