diff --git a/xCAT-server/lib/xcat/plugins/debian.pm b/xCAT-server/lib/xcat/plugins/debian.pm index a54a8a3b5..fbae0f344 100644 --- a/xCAT-server/lib/xcat/plugins/debian.pm +++ b/xCAT-server/lib/xcat/plugins/debian.pm @@ -178,6 +178,43 @@ sub using_subiquity return 0; } +# The first readable pair wins, so netboot trees precede live images and a +# hardware-enablement kernel precedes the release one. +my %INSTALL_BOOT_FILES = ( + 'x86' => [ + [ 'install/hwe-netboot/ubuntu-installer/{darch}/linux', 'install/hwe-netboot/ubuntu-installer/{darch}/initrd.gz' ], + [ 'install/netboot/ubuntu-installer/{darch}/linux', 'install/netboot/ubuntu-installer/{darch}/initrd.gz' ], + [ 'install/netboot/vmlinuz', 'install/netboot/initrd.gz' ], + [ 'casper/hwe-vmlinuz', 'casper/hwe-initrd' ], + [ 'casper/vmlinuz', 'casper/initrd' ], + ], + 'ppc64' => [ + [ 'install/netboot/ubuntu-installer/{darch}/vmlinux', 'install/netboot/ubuntu-installer/{darch}/initrd.gz' ], + [ 'install/vmlinux', 'install/netboot/initrd.gz' ], + ], +); + +sub install_boot_files +{ + my ($arch, $darch, $pkgdir) = @_; + return unless defined($arch) && defined($pkgdir); + $darch = '' unless defined $darch; + + my $family = + $arch =~ /x86/i ? 'x86' + : $arch =~ /ppc64/i ? 'ppc64' + : undef; + return unless $family; + + foreach my $candidate (@{ $INSTALL_BOOT_FILES{$family} }) { + my ($kernel, $initrd) = @{$candidate}; + s/\{darch\}/$darch/g for ($kernel, $initrd); + ($kernel, $initrd) = ("$pkgdir/$kernel", "$pkgdir/$initrd"); + return ($kernel, $initrd) if -r $kernel and -r $initrd; + } + return; +} + sub is_ubuntu_live_media { my $media_path = shift; @@ -997,52 +1034,8 @@ sub mkinstall { my $initrdpath; my $maxmem; - if ( - ( - ($arch =~ /x86/ and - ( - (-r "$pkgdir/install/hwe-netboot/ubuntu-installer/$darch/linux" - and $kernpath = "$pkgdir/install/hwe-netboot/ubuntu-installer/$darch/linux" - and -r "$pkgdir/install/hwe-netboot/ubuntu-installer/$darch/initrd.gz" - and $initrdpath = "$pkgdir/install/hwe-netboot/ubuntu-installer/$darch/initrd.gz" - ) or - (-r "$pkgdir/install/netboot/ubuntu-installer/$darch/linux" - and $kernpath = "$pkgdir/install/netboot/ubuntu-installer/$darch/linux" - and -r "$pkgdir/install/netboot/ubuntu-installer/$darch/initrd.gz" - and $initrdpath = "$pkgdir/install/netboot/ubuntu-installer/$darch/initrd.gz" - ) or - (-r "$pkgdir/install/netboot/vmlinuz" - and $kernpath = "$pkgdir/install/netboot/vmlinuz" - and -r "$pkgdir/install/netboot/initrd.gz" - and $initrdpath = "$pkgdir/install/netboot/initrd.gz" - ) or - (-r "$pkgdir/casper/hwe-vmlinuz" - and $kernpath = "$pkgdir/casper/hwe-vmlinuz" - and -r "$pkgdir/casper/hwe-initrd" - and $initrdpath = "$pkgdir/casper/hwe-initrd" - ) or - (-r "$pkgdir/casper/vmlinuz" - and $kernpath = "$pkgdir/casper/vmlinuz" - and -r "$pkgdir/casper/initrd" - and $initrdpath = "$pkgdir/casper/initrd" - ) - ) - ) or ( - $arch =~ /ppc64/i and ( - (-r "$pkgdir/install/netboot/ubuntu-installer/$darch/vmlinux" - and $kernpath = "$pkgdir/install/netboot/ubuntu-installer/$darch/vmlinux" - and -r "$pkgdir/install/netboot/ubuntu-installer/$darch/initrd.gz" - and $initrdpath = "$pkgdir/install/netboot/ubuntu-installer/$darch/initrd.gz" - ) or - (-r "$pkgdir/install/vmlinux" - and $kernpath = "$pkgdir/install/vmlinux" - and -r "$pkgdir/install/netboot/initrd.gz" - and $initrdpath = "$pkgdir/install/netboot/initrd.gz" - ) - ) - ) - ) - ) { + ($kernpath, $initrdpath) = install_boot_files($arch, $darch, $pkgdir); + if ($kernpath) { #TODO: driver slipstream, targetted for network. # Copy the install resource to /tftpboot and check to only copy once diff --git a/xCAT-test/unit/debian_install_boot_files.t b/xCAT-test/unit/debian_install_boot_files.t new file mode 100644 index 000000000..b5783bc94 --- /dev/null +++ b/xCAT-test/unit/debian_install_boot_files.t @@ -0,0 +1,102 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use File::Path qw(make_path); +use File::Temp qw(tempdir); +use FindBin; +use Test::More; + +# The installer kernel and initrd sit in a different place on every Ubuntu media layout: +# netboot trees name them after the Debian architecture, live images keep them under +# casper, and a hardware-enablement kernel ships beside the release one. Build each layout +# on disk and ask the resolver, rather than reading the table that describes them. + +use lib "$FindBin::Bin/../../perl-xCAT"; +use lib "$FindBin::Bin/../../xCAT-server/lib/perl"; +my $plugin = "$FindBin::Bin/../../xCAT-server/lib/xcat/plugins/debian.pm"; +plan skip_all => 'debian.pm not found' unless -r $plugin; +eval { require $plugin; 1 } or plan skip_all => "could not load debian.pm: $@"; + +sub media { + my (@relative) = @_; + my $root = tempdir(CLEANUP => 1); + foreach my $path (@relative) { + my $full = "$root/$path"; + ($full =~ m{^(.*)/[^/]+$}) and make_path($1); + open(my $fh, '>', $full) or die "cannot create $full: $!"; + close($fh); + } + return $root; +} + +sub resolved { + my ($arch, $darch, $root) = @_; + my ($kernel, $initrd) = + xCAT_plugin::debian::install_boot_files($arch, $darch, $root); + return unless defined $kernel; + s/^\Q$root\E\/// for ($kernel, $initrd); + return "$kernel|$initrd"; +} + +# --- x86_64 layouts, in the order the media are probed --------------------- +is( + resolved('x86_64', 'amd64', + media('install/netboot/ubuntu-installer/amd64/linux', + 'install/netboot/ubuntu-installer/amd64/initrd.gz')), + 'install/netboot/ubuntu-installer/amd64/linux|install/netboot/ubuntu-installer/amd64/initrd.gz', + 'a netboot tree is named after the Debian architecture', +); +is( + resolved('x86_64', 'amd64', media('casper/vmlinuz', 'casper/initrd')), + 'casper/vmlinuz|casper/initrd', + 'a live image keeps its kernel under casper', +); +is( + resolved('x86_64', 'amd64', + media('casper/hwe-vmlinuz', 'casper/hwe-initrd', 'casper/vmlinuz', 'casper/initrd')), + 'casper/hwe-vmlinuz|casper/hwe-initrd', + 'the hardware-enablement kernel wins over the release kernel', +); +is( + resolved('x86_64', 'amd64', + media('install/hwe-netboot/ubuntu-installer/amd64/linux', + 'install/hwe-netboot/ubuntu-installer/amd64/initrd.gz', + 'casper/vmlinuz', 'casper/initrd')), + 'install/hwe-netboot/ubuntu-installer/amd64/linux|install/hwe-netboot/ubuntu-installer/amd64/initrd.gz', + 'a netboot tree wins over a live image on the same media', +); +is( + resolved('x86_64', 'amd64', media('install/netboot/vmlinuz', 'install/netboot/initrd.gz')), + 'install/netboot/vmlinuz|install/netboot/initrd.gz', + 'the flat netboot layout resolves', +); + +# --- ppc64 layouts --------------------------------------------------------- +is( + resolved('ppc64', 'ppc64el', + media('install/netboot/ubuntu-installer/ppc64el/vmlinux', + 'install/netboot/ubuntu-installer/ppc64el/initrd.gz')), + 'install/netboot/ubuntu-installer/ppc64el/vmlinux|install/netboot/ubuntu-installer/ppc64el/initrd.gz', + 'POWER keeps a vmlinux in its netboot tree', +); +is( + resolved('ppc64le', 'ppc64el', media('install/vmlinux', 'install/netboot/initrd.gz')), + 'install/vmlinux|install/netboot/initrd.gz', + 'the kernel and the initrd may sit in different directories', +); +is( + resolved('ppc64', 'ppc64el', media('casper/vmlinuz', 'casper/initrd')), + undef, + 'POWER does not accept the x86 live layout', +); + +# --- nothing to boot ------------------------------------------------------- +is(resolved('x86_64', 'amd64', media('casper/vmlinuz')), undef, + 'a kernel without its initrd is not a match'); +is(resolved('x86_64', 'amd64', media('README')), undef, + 'media with no installer resolves to nothing'); +is(resolved('s390x', 's390x', media('casper/vmlinuz', 'casper/initrd')), undef, + 'an architecture the table does not describe resolves to nothing'); + +done_testing();