From 5aa1cda179473eb36aea4abc6b3707a60e3db39c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Fri, 1 May 2026 23:51:04 -0300 Subject: [PATCH] feat: add openSUSE Leap 15 provisioning support --- xCAT-server/etc/init.d/xcatd | 46 +++- xCAT-server/lib/perl/xCAT/SvrUtils.pm | 98 ++++++-- xCAT-server/lib/perl/xCAT/Template.pm | 39 ++-- xCAT-server/lib/xcat/plugins/AAsn.pm | 10 + xCAT-server/lib/xcat/plugins/dhcp.pm | 55 +++-- xCAT-server/lib/xcat/plugins/genimage.pm | 4 + xCAT-server/lib/xcat/plugins/packimage.pm | 14 +- xCAT-server/lib/xcat/plugins/sles.pm | 120 +++++++++- .../xcat/install/scripts/post.sles.common | 4 + .../xcat/install/sles/compute.leap15.pkglist | 12 + .../xcat/install/sles/compute.leap15.tmpl | 90 ++++++++ .../xcat/install/sles/service.leap15.pkglist | 15 ++ .../xcat/install/sles/service.leap15.tmpl | 90 ++++++++ .../share/xcat/netboot/imgutils/imgutils.pm | 8 + .../xcat/netboot/sles/compute.leap15.pkglist | 49 ++++ .../netboot/sles/compute.leap15.postinstall | 14 ++ .../xcat/netboot/sles/compute.sle15.pkglist | 1 + .../netboot/sles/dracut_033/install.netboot | 2 +- .../netboot/sles/dracut_033/install.statelite | 2 +- xCAT-server/share/xcat/netboot/sles/genimage | 24 +- xCAT-test/unit/dhcp_kea_plugin_intent.t | 68 ++++++ xCAT-test/unit/opensuse_leap_support.t | 215 ++++++++++++++++++ 22 files changed, 897 insertions(+), 83 deletions(-) create mode 100644 xCAT-server/share/xcat/install/sles/compute.leap15.pkglist create mode 100644 xCAT-server/share/xcat/install/sles/compute.leap15.tmpl create mode 100644 xCAT-server/share/xcat/install/sles/service.leap15.pkglist create mode 100644 xCAT-server/share/xcat/install/sles/service.leap15.tmpl create mode 100644 xCAT-server/share/xcat/netboot/sles/compute.leap15.pkglist create mode 100755 xCAT-server/share/xcat/netboot/sles/compute.leap15.postinstall create mode 100644 xCAT-test/unit/opensuse_leap_support.t diff --git a/xCAT-server/etc/init.d/xcatd b/xCAT-server/etc/init.d/xcatd index 27aa99d35..ae51e60cf 100755 --- a/xCAT-server/etc/init.d/xcatd +++ b/xCAT-server/etc/init.d/xcatd @@ -53,6 +53,37 @@ MStatus() return $RVAL } +SUSESuccess() +{ + rc_failed 0 + rc_status -v +} + +SUSEFailure() +{ + rc_failed 1 + rc_status -v +} + +SUSEWarning() +{ + rc_failed 0 + rc_status -v +} + +IsSUSEFamily() +{ + [ -f /etc/SuSE-release ] && return 0 + [ -r /etc/os-release ] || return 1 + + . /etc/os-release + case " $ID $ID_LIKE " in + *"sles"*|*"sled"*|*"suse"*|*"opensuse"*) return 0 ;; + esac + + return 1 +} + if [ -f /etc/init.d/functions ]; then # EL8- . /etc/init.d/functions @@ -76,6 +107,18 @@ elif [ -f /lib/lsb/init-functions ]; then LOG_SUCCESS=log_success_msg LOG_FAILURE=log_failure_msg LOG_WARNING=log_warning_msg +elif IsSUSEFamily && [ -f /etc/rc.status ]; then + # Use SUSE's native SysV status helpers when Red Hat/Debian helpers are absent. + . /etc/rc.status + type rc_reset >/dev/null 2>&1 && type rc_failed >/dev/null 2>&1 && type rc_status >/dev/null 2>&1 || { + echo "Error, SUSE status helper functions are unavailable" + exit 1 + } + rc_reset + STATUS=MStatus + LOG_SUCCESS=SUSESuccess + LOG_FAILURE=SUSEFailure + LOG_WARNING=SUSEWarning else echo "Error, don't know how to start on this platform" exit 1 @@ -159,6 +202,3 @@ start) ;; esac - - - diff --git a/xCAT-server/lib/perl/xCAT/SvrUtils.pm b/xCAT-server/lib/perl/xCAT/SvrUtils.pm index 2b581ee01..3bb5aa32b 100644 --- a/xCAT-server/lib/perl/xCAT/SvrUtils.pm +++ b/xCAT-server/lib/perl/xCAT/SvrUtils.pm @@ -503,9 +503,31 @@ sub get_os_search_list { } push(@list, join('.', @word)); + # openSUSE Leap 15.x uses the same AutoYaST asset layout as SLES 15. + # Do not extend this to Leap 16 without validating its installer path. + if ($baseos =~ /^(leap15)(?:\..*)?$/) { + push(@list, "sle15"); + } + return @list; } +sub _profile_file_matches { + my ($filename, $osver, $shortosver, $genos, $arch) = @_; + + # osver and arch specific, for example compute.sle15.x86_64.pkglist + if ($filename =~ /[^\.]*\.([^\.]*)\.([^\.]*)\./) { + return (($1 eq $osver || $1 eq $shortosver || $1 eq $genos) && $2 eq $arch); + } + + # osver or arch specific, for example compute.sle15.pkglist + if ($filename =~ /[^\.]*\.([^\.]*)\./) { + return ($1 eq $osver || $1 eq $shortosver || $1 eq $genos || $1 eq $arch); + } + + return 1; +} + sub get_file_name { my ($searchpath, $extension, $profile, $os, $arch, $genos) = @_; @@ -581,6 +603,7 @@ sub get_postinstall_file_name { my $profile = shift; my $os = shift; my $arch = shift; + my $genos = shift; my $extension = "postinstall"; my $dotpos = rindex($os, "."); my $osbase = substr($os, 0, $dotpos); @@ -637,6 +660,13 @@ sub get_postinstall_file_name { } } + if (($genos) && (-x "$searchpath/$profile.$genos.$arch.$extension")) { + return "$searchpath/$profile.$genos.$arch.$extension"; + } + if (($genos) && (-x "$searchpath/$profile.$genos.$extension")) { + return "$searchpath/$profile.$genos.$extension"; + } + if (-x "$searchpath/$profile.$arch.$extension") { return "$searchpath/$profile.$arch.$extension"; } @@ -689,7 +719,7 @@ sub update_tables_with_templates $osver = shift; } my $shortosver = $osver; - $shortosver =~ s/\..*//; + $shortosver =~ s/\..*//; # for major-version assets, for example leap15.6 -> leap15 my $arch = shift; #like ppc64, x86, x86_64 my $ospkgdir = shift; my $osdistroname = shift; @@ -707,6 +737,8 @@ sub update_tables_with_templates $osname = "hyperv"; $ostype = "Windows"; $imagetype = "windows"; + } elsif ($osver =~ /^leap15/) { + $osname = "sles"; } else { until (-r "$::XCATROOT/share/xcat/install/$osname/" or not $osname) { chop($osname); @@ -729,7 +761,11 @@ sub update_tables_with_templates $genos = "subiquity"; } } + } elsif ($osver =~ /^leap15/) { + $genos = "sle15"; } + # For Leap, let get_os_search_list prefer leap15 assets before the sle15 fallback. + my $file_lookup_genos = ($osver =~ /^leap15/) ? undef : $genos; #print "osver=$osver, arch=$arch, osname=$osname, genos=$genos\n"; my $installroot = xCAT::TableUtils->getInstallDir(); @@ -755,12 +791,10 @@ sub update_tables_with_templates foreach (@tmplfiles) { my $tmpf = basename($_); + #skip template files for other OS or architecture suffixes + next unless _profile_file_matches($tmpf, $osver, $shortosver, $genos, $arch); + #get the profile name out of the file, TODO: this does not work if the profile name contains the '.' - if ($tmpf =~ /[^\.]*\.([^\.]*)\.([^\.]*)\./) { # osver *and* arch specific, make sure they match - unless (($1 eq $osver or $1 eq $shortosver) and $2 eq $arch) { next; } - } elsif ($tmpf =~ /[^\.]*\.([^\.]*)\./) { #osver *or* arch specific, make sure one matches - unless ($1 eq $osver or $1 eq $shortosver or $2 eq $arch) { next; } - } $tmpf =~ /^([^\.]*)\..*$/; $tmpf = $1; @@ -771,12 +805,10 @@ sub update_tables_with_templates foreach (@tmplfiles) { my $tmpf = basename($_); + #skip template files for other OS or architecture suffixes + next unless _profile_file_matches($tmpf, $osver, $shortosver, $genos, $arch); + #get the profile name out of the file, TODO: this does not work if the profile name contains the '.' - if ($tmpf =~ /[^\.]*\.([^\.]*)\.([^\.]*)\./) { # osver *and* arch specific, make sure they match - unless (($1 eq $osver or $1 eq $shortosver) and $2 eq $arch) { next; } - } elsif ($tmpf =~ /[^\.]*\.([^\.]*)\./) { #osver *or* arch specific, make sure one matches - unless ($1 eq $osver or $1 eq $shortosver or $1 eq $arch) { next; } - } $tmpf =~ /^([^\.]*)\..*$/; $tmpf = $1; $profiles{$tmpf} = 1; @@ -797,20 +829,20 @@ sub update_tables_with_templates #print "profile=$profile\n"; #get template file - my $tmplfile = get_tmpl_file_name($cuspath, $profile, $osver, $arch, $genos); - if (!$tmplfile) { $tmplfile = get_tmpl_file_name($defpath, $profile, $osver, $arch, $genos); } + my $tmplfile = get_tmpl_file_name($cuspath, $profile, $osver, $arch, $file_lookup_genos); + if (!$tmplfile) { $tmplfile = get_tmpl_file_name($defpath, $profile, $osver, $arch, $file_lookup_genos); } if (!$tmplfile) { next; } #get otherpkgs.pkglist file - my $otherpkgsfile = get_otherpkgs_pkglist_file_name($cuspath, $profile, $osver, $arch); - if (!$otherpkgsfile) { $otherpkgsfile = get_otherpkgs_pkglist_file_name($defpath, $profile, $osver, $arch); } + my $otherpkgsfile = get_otherpkgs_pkglist_file_name($cuspath, $profile, $osver, $arch, $file_lookup_genos); + if (!$otherpkgsfile) { $otherpkgsfile = get_otherpkgs_pkglist_file_name($defpath, $profile, $osver, $arch, $file_lookup_genos); } #get synclist file my $synclistfile = xCAT::SvrUtils->getsynclistfile(undef, $osver, $arch, $profile, "netboot"); #get the pkglist file - my $pkglistfile = get_pkglist_file_name($cuspath, $profile, $osver, $arch); - if (!$pkglistfile) { $pkglistfile = get_pkglist_file_name($defpath, $profile, $osver, $arch, $genos); } + my $pkglistfile = get_pkglist_file_name($cuspath, $profile, $osver, $arch, $file_lookup_genos); + if (!$pkglistfile) { $pkglistfile = get_pkglist_file_name($defpath, $profile, $osver, $arch, $file_lookup_genos); } #now update the db if (!$osimagetab) { @@ -928,6 +960,8 @@ sub update_tables_with_mgt_image $osname = "hyperv"; $ostype = "Windows"; $imagetype = "windows"; + } elsif ($osver =~ /^leap15/) { + $osname = "sles"; } else { until (-r "$::XCATROOT/share/xcat/install/$osname/" or not $osname) { chop($osname); @@ -1131,6 +1165,8 @@ sub update_tables_with_diskless_image my $mode = shift; my $ospkgdir = shift; my $osdistroname = shift; + my $shortosver = $osver; + $shortosver =~ s/\..*//; # for major-version assets, for example leap15.6 -> leap15 my $provm = "netboot"; if ($mode) { $provm = $mode; } @@ -1142,6 +1178,8 @@ sub update_tables_with_diskless_image $osname = "windows"; $ostype = "Windows"; $imagetype = "windows"; + } elsif ($osver =~ /^leap15/) { + $osname = "sles"; } else { until (-r "$::XCATROOT/share/xcat/netboot/$osname/" or not $osname) { chop($osname); @@ -1156,7 +1194,11 @@ sub update_tables_with_diskless_image $genos =~ s/\..*//; if ($genos =~ /rh.*s(\d*)/) { $genos = "rhels$1"; + } elsif ($osver =~ /^leap15/) { + $genos = "sle15"; } + # For Leap, let get_os_search_list prefer leap15 assets before the sle15 fallback. + my $file_lookup_genos = ($osver =~ /^leap15/) ? undef : $genos; #print "osver=$osver, arch=$arch, osname=$osname, genos=$genos, profile=$profile\n"; my $installroot = xCAT::TableUtils->getInstallDir(); @@ -1186,6 +1228,9 @@ sub update_tables_with_diskless_image foreach (@tmplfiles) { my $tmpf = basename($_); + #skip pkglist files for other OS or architecture suffixes + next unless _profile_file_matches($tmpf, $osver, $shortosver, $genos, $arch); + #get the profile name out of the file, TODO: this does not work if the profile name contains the '.' $tmpf =~ /^([^\.]*)\..*$/; $tmpf = $1; @@ -1195,6 +1240,9 @@ sub update_tables_with_diskless_image foreach (@tmplfiles) { my $tmpf = basename($_); + #skip pkglist files for other OS or architecture suffixes + next unless _profile_file_matches($tmpf, $osver, $shortosver, $genos, $arch); + #get the profile name out of the file, TODO: this does not work if the profile name contains the '.' $tmpf =~ /^([^\.]*)\..*$/; $tmpf = $1; @@ -1204,26 +1252,26 @@ sub update_tables_with_diskless_image foreach my $profile (keys %profiles) { #get the pkglist file - my $pkglistfile = get_pkglist_file_name($cuspath, $profile, $osver, $arch); - if (!$pkglistfile) { $pkglistfile = get_pkglist_file_name($defpath, $profile, $osver, $arch); } + my $pkglistfile = get_pkglist_file_name($cuspath, $profile, $osver, $arch, $file_lookup_genos); + if (!$pkglistfile) { $pkglistfile = get_pkglist_file_name($defpath, $profile, $osver, $arch, $file_lookup_genos); } #print "pkglistfile=$pkglistfile\n"; if (!$pkglistfile) { next; } #get otherpkgs.pkglist file - my $otherpkgsfile = get_otherpkgs_pkglist_file_name($cuspath, $profile, $osver, $arch); - if (!$otherpkgsfile) { $otherpkgsfile = get_otherpkgs_pkglist_file_name($defpath, $profile, $osver, $arch); } + my $otherpkgsfile = get_otherpkgs_pkglist_file_name($cuspath, $profile, $osver, $arch, $file_lookup_genos); + if (!$otherpkgsfile) { $otherpkgsfile = get_otherpkgs_pkglist_file_name($defpath, $profile, $osver, $arch, $file_lookup_genos); } #get synclist file my $synclistfile = xCAT::SvrUtils->getsynclistfile(undef, $osver, $arch, $profile, "netboot"); #get the exlist file - my $exlistfile = get_exlist_file_name($cuspath, $profile, $osver, $arch); - if (!$exlistfile) { $exlistfile = get_exlist_file_name($defpath, $profile, $osver, $arch); } + my $exlistfile = get_exlist_file_name($cuspath, $profile, $osver, $arch, $file_lookup_genos); + if (!$exlistfile) { $exlistfile = get_exlist_file_name($defpath, $profile, $osver, $arch, $file_lookup_genos); } #get postinstall script file name - my $postfile = get_postinstall_file_name($cuspath, $profile, $osver, $arch); - if (!$postfile) { $postfile = get_postinstall_file_name($defpath, $profile, $osver, $arch); } + my $postfile = get_postinstall_file_name($cuspath, $profile, $osver, $arch, $genos); + if (!$postfile) { $postfile = get_postinstall_file_name($defpath, $profile, $osver, $arch, $genos); } #now update the db diff --git a/xCAT-server/lib/perl/xCAT/Template.pm b/xCAT-server/lib/perl/xCAT/Template.pm index 306b29074..d7ee2826c 100644 --- a/xCAT-server/lib/perl/xCAT/Template.pm +++ b/xCAT-server/lib/perl/xCAT/Template.pm @@ -326,7 +326,7 @@ sub subvars { $writerepo .="$repo_in_post\n"; $writerepo .="EOF\n"; } - } elsif ($platform =~ /^(sles|suse)/) { + } elsif ($platform =~ /^(sles|suse|leap15)/) { my $http = "http://#TABLE:noderes:\$NODE:nfsserver#$httpportsuffix/$pkgdir"; $source .= " $http @@ -341,18 +341,8 @@ sub subvars { opendir(DIR,$pkgdir); my @subpkgdir=grep(!/\.\.?$|^media.1$/, readdir DIR); foreach my $subdir (@subpkgdir){ - my $product_name; - my $product_dir; - $product_dir=$subdir; - if($subdir =~ /^Module-/){ - $product_name="sle-".lc($subdir); - }elsif($subdir =~ /^Product-SUSE-Manager-Server|^Product-SLES_SAP|^Product-SLED/){ - # Skip product directories that are not "SLES", causes conflict on SLE15.2 - next; - }elsif($subdir =~ /^Product-/){ - $subdir=~s/Product-//; - $product_name=$subdir; - } + my $product_name = _sle15_install_product_name($subdir); + my $product_dir = $subdir; if (defined($product_name) && defined($product_dir)){ $source .="\n$space12http://XCATNEXTSERVERHOOK$httpportsuffix$pkgdir\n$space12$product_name\n$space12/$product_dir\n$space12\n$space10"; } @@ -2003,6 +1993,29 @@ sub getNM_GW() return (undef, undef); } +sub _sle15_install_product_name { + my ($subdir) = @_; + + if ($subdir =~ /^Module-SAP-/) { + return; + } + + if ($subdir =~ /^Module-/) { + return "sle-" . lc($subdir); + } + + if ($subdir =~ /^Product-SUSE-Manager-Server|^Product-SLES_SAP|^Product-SLED/) { + # Skip product directories that are not generic SLES; these can conflict with SLE 15 installs. + return; + } + + if ($subdir =~ /^Product-(.+)$/) { + return $1; + } + + return; +} + 1; diff --git a/xCAT-server/lib/xcat/plugins/AAsn.pm b/xCAT-server/lib/xcat/plugins/AAsn.pm index 201167ecf..188d7ebdc 100644 --- a/xCAT-server/lib/xcat/plugins/AAsn.pm +++ b/xCAT-server/lib/xcat/plugins/AAsn.pm @@ -1410,6 +1410,14 @@ sub stop_TFTP return 0; } +sub in_tftpd_is_atftpd +{ + return 0 unless -x "/usr/sbin/in.tftpd"; + + my $help = `/usr/sbin/in.tftpd --help 2>&1`; + return ($help =~ /--daemon/ && $help =~ /--group/ && $help =~ /--logfile/) ? 1 : 0; +} + #----------------------------------------------------------------------------- # #=head3 enable_TFTP @@ -1465,6 +1473,8 @@ sub enable_TFTP my $startcmd = "/usr/sbin/in.tftpd $v4only -v -l -s $tftpdir -m /etc/tftpmapfile4xcat.conf"; if ($tftpflags) { $startcmd = "/usr/sbin/in.tftpd $v4only $tftpflags"; + } elsif (in_tftpd_is_atftpd()) { + $startcmd = "/usr/sbin/in.tftpd --daemon --user nobody --group nogroup $tftpdir"; } if ( -x "/usr/sbin/in.tftpd") { diff --git a/xCAT-server/lib/xcat/plugins/dhcp.pm b/xCAT-server/lib/xcat/plugins/dhcp.pm index 5812a2190..9f2fcec5d 100644 --- a/xCAT-server/lib/xcat/plugins/dhcp.pm +++ b/xCAT-server/lib/xcat/plugins/dhcp.pm @@ -1641,11 +1641,8 @@ sub process_request } else { - my @nsrnoutput = split /\n/, `/bin/netstat -rn`; - splice @nsrnoutput, 0, 2; - foreach (@nsrnoutput) { #scan netstat - my @parts = split /\s+/; - push @nrn, $parts[0] . ":" . $parts[7] . ":" . $parts[2] . ":" . $parts[3]; + foreach my $route (local_ipv4_routes()) { + push @nrn, join(':', @{$route}); } my @ip6routes = `ip -6 route`; foreach (@ip6routes) { @@ -1734,10 +1731,7 @@ sub process_request # For SLES11+ and RHEL7+ Operating system releases, the # dhcpd/dhcpd6 configuration is stored in the same file - my $os_ver = $os; - $os_ver =~ s/[^0-9.^0-9]//g; - if (($os =~ /sles/i && $os_ver >= 11) || - ($os =~ /rhels?/i && $os_ver >= 7)) { + if (dhcpd_sysconfig_uses_interface_key($os)) { $dhcpd_key = "DHCPD_INTERFACE"; if ($usingipv6 and $dhcpver eq "dhcpd6") { @@ -1805,10 +1799,7 @@ sub process_request if ($usingipv6) { # sles11.3 and rhels7 has dhcpd and dhcpd6 config in the dhcp file - my $os_ver = $os; - $os_ver =~ s/[^0-9.^0-9]//g; - if (($os =~ /sles/i && $os_ver >= 11) || - ($os =~ /rhels?/i && $os_ver >= 7)) { + if (dhcpd_sysconfig_uses_interface_key($os)) { if ($missingfiles{dhcpd}) { $callback->({ error => ["The file /etc/sysconfig/dhcpd doesn't exist, check the dhcp server"] }); } @@ -2612,6 +2603,17 @@ sub kea_apply_ddns_behavior $intent->{'ddns-update-on-renew'} = JSON::true; } +sub dhcpd_sysconfig_uses_interface_key +{ + my $os = shift || ""; + my $os_ver = $os; + $os_ver =~ s/[^0-9.^0-9]//g; + + return 1 if $os =~ /(sles|opensuse[-_]?leap|leap)/i && $os_ver >= 11; + return 1 if $os =~ /rhels?/i && $os_ver >= 7; + return 0; +} + sub kea_ddns_enabled { return defined($::XCATSITEVALS{dnshandler}) && $::XCATSITEVALS{dnshandler} =~ /ddns/ ? 1 : 0; @@ -2643,6 +2645,24 @@ sub kea_ipv4_routes my @vnets = @_; my @routes; + push @routes, local_ipv4_routes(); + + foreach (@vnets) { + my $n = $_->{net}; + my $if = $_->{mgtifname}; + my $nm = $_->{mask}; + if ($if =~ /!remote!/ and $n !~ /:/) { + push @routes, [ $n, $if, $nm, '' ]; + } + } + + return @routes; +} + +sub local_ipv4_routes +{ + my @routes; + my $ipcmd = kea_command_path('ip'); if ($ipcmd) { my @route_output = split /\n/, `$ipcmd -4 route show 2>/dev/null`; @@ -2667,15 +2687,6 @@ sub kea_ipv4_routes } } - foreach (@vnets) { - my $n = $_->{net}; - my $if = $_->{mgtifname}; - my $nm = $_->{mask}; - if ($if =~ /!remote!/ and $n !~ /:/) { - push @routes, [ $n, $if, $nm, '' ]; - } - } - return @routes; } diff --git a/xCAT-server/lib/xcat/plugins/genimage.pm b/xCAT-server/lib/xcat/plugins/genimage.pm index 0b97fec64..d2a5e7bee 100644 --- a/xCAT-server/lib/xcat/plugins/genimage.pm +++ b/xCAT-server/lib/xcat/plugins/genimage.pm @@ -285,6 +285,10 @@ sub process_request { if ($osfamily =~ /sles/ && $osfamily =~ /sp/) { $osfamily = "sles"; } + # openSUSE Leap 15.x reuses the existing SLES diskless image scripts. + if ($osver =~ /^leap15/) { + $osfamily = "sles"; + } $osfamily =~ s/ //g; diff --git a/xCAT-server/lib/xcat/plugins/packimage.pm b/xCAT-server/lib/xcat/plugins/packimage.pm index 412f786fc..5c10ea80e 100644 --- a/xCAT-server/lib/xcat/plugins/packimage.pm +++ b/xCAT-server/lib/xcat/plugins/packimage.pm @@ -217,8 +217,12 @@ sub process_request { } my $distname = $osver; - until (-r "$::XCATROOT/share/xcat/netboot/$distname/" or not $distname) { - chop($distname); + if ($osver =~ /^leap15/) { + $distname = "sles"; + } else { + until (-r "$::XCATROOT/share/xcat/netboot/$distname/" or not $distname) { + chop($distname); + } } unless ($distname) { $callback->({ error => ["Unable to find $::XCATROOT/share/xcat/netboot directory for $osver"], errorcode => [1] }); @@ -326,7 +330,11 @@ sub process_request { if (-e "$rootimg_dir/usr/lib/dracut/modules.d/97xcat/install") { xCAT::Utils->runcmd("mv $rootimg_dir/usr/lib/dracut/modules.d/97xcat/install $rootimg_dir/.statebackup/install", 0, 1); } - xCAT::Utils->runcmd("cp /opt/xcat/share/xcat/netboot/rh/dracut_033/install.netboot $rootimg_dir/usr/lib/dracut/modules.d/97xcat/install", 0, 1); + my $dracut_install = "$::XCATROOT/share/xcat/netboot/$distname/dracut_033/install.netboot"; + if (!-r $dracut_install) { + $dracut_install = "$::XCATROOT/share/xcat/netboot/rh/dracut_033/install.netboot"; + } + xCAT::Utils->runcmd("cp $dracut_install $rootimg_dir/usr/lib/dracut/modules.d/97xcat/install", 0, 1); # timedatectl requires /etc/localtime link to the zoneinfo in /usr/share/zoneinfo diff --git a/xCAT-server/lib/xcat/plugins/sles.pm b/xCAT-server/lib/xcat/plugins/sles.pm index 9bfbb9238..077d2442c 100644 --- a/xCAT-server/lib/xcat/plugins/sles.pm +++ b/xCAT-server/lib/xcat/plugins/sles.pm @@ -37,10 +37,10 @@ sub handled_commands { return { copycd => "sles", - mknetboot => "nodetype:os=(sle.*)|(suse.*)", - mkinstall => "nodetype:os=(sle.*)|(suse.*)", - mkstatelite => "nodetype:os=(sle.*)", - mksysclone => "nodetype:os=(sle.*)|(suse.*)" + mknetboot => "nodetype:os=(sle.*)|(suse.*)|(leap15.*)", + mkinstall => "nodetype:os=(sle.*)|(suse.*)|(leap15.*)", + mkstatelite => "nodetype:os=(sle.*)|(leap15.*)", + mksysclone => "nodetype:os=(sle.*)|(suse.*)|(leap15.*)" }; } @@ -297,7 +297,7 @@ sub mknetboot # TODO: should get the $pkgdir value from the linuximage table $pkgdir = "$installroot/$osver/$arch"; - } elsif ($osver =~ /suse.*/) { + } elsif ($osver =~ /suse.*/ or $osver =~ /leap15.*/) { $platform = "sles"; } @@ -875,6 +875,8 @@ sub mkinstall $plat = "sle"; } elsif ($os =~ /suse.*/) { $plat = "suse"; + } elsif ($os =~ /leap15.*/) { + $plat = "sles"; } else { $plat = "foobar"; print "You should never get here! Programmer error!"; @@ -1103,6 +1105,9 @@ sub mkinstall . " install=$httpmethod://" . $netserver . ":" . $httpport . "$httpprefix/1"; + if ($os =~ /^leap15/) { + $kcmdline .= " self_update=0"; + } my $installnic; my $primarynic; @@ -1566,6 +1571,78 @@ sub using_dracut } } +sub _opensuse_leap_distname +{ + my $version = shift; + return unless defined $version; + return unless $version =~ /^(15(?:\.\d+)?)/; + return "leap$1"; +} + +sub _detect_opensuse_leap_treeinfo +{ + my $mntpath = shift; + my $treeinfo = "$mntpath/.treeinfo"; + return unless -r $treeinfo; + + my %section; + my $section = ""; + open(my $fh, "<", $treeinfo) or return; + while (my $line = <$fh>) { + chomp($line); + if ($line =~ /^\s*\[([^\]]+)\]\s*$/) { + $section = $1; + next; + } + next unless $line =~ /^\s*([^=\s]+)\s*=\s*(.*?)\s*$/; + $section{$section}{$1} = $2; + } + close($fh); + + my $name = $section{release}{name} || $section{general}{family} || $section{general}{name}; + return unless defined $name and $name =~ /openSUSE\s+Leap/i; + + my $distname = _opensuse_leap_distname($section{release}{version} || $section{general}{version}); + return unless $distname; + + return ($distname, $section{general}{arch}); +} + +sub _detect_opensuse_leap_media +{ + my ($media, $products) = @_; + $media = "" unless defined $media; + $products = "" unless defined $products; + + return unless "$media\n$products" =~ /openSUSE[-\s]+Leap/i; + + my $version; + if ($products =~ /openSUSE[-\s]+Leap\s+(\d+(?:\.\d+)?)/i) { + $version = $1; + } elsif ($media =~ /openSUSE[-\s]+Leap[-\s]+(\d+(?:\.\d+)?)/i) { + $version = $1; + } + + my $distname = _opensuse_leap_distname($version); + return unless $distname; + + my $arch; + if ("$media\n$products" =~ /(x86_64|ppc64le|ppc64el|s390x|aarch64)/) { + $arch = $1; + } + + return ($distname, $arch); +} + +sub _copycd_distname_supported +{ + my $distname = shift; + return 1 unless $distname; + return 1 if $distname =~ /^(?:sle|suse)/; + return 1 if $distname =~ /^leap15(?:\..*)?$/; + return; +} + sub copycd { my $request = shift; @@ -1621,10 +1698,10 @@ sub copycd $path =~ s,//*,/,g; } - if ($distname and $distname !~ /^sle|^suse/) + if (!_copycd_distname_supported($distname)) { - #If they say to call it something other than SLES or SUSE, give up? + # If they say to call it something other than SLE, SUSE, or Leap, give up. return; } @@ -1632,7 +1709,16 @@ sub copycd my $discnumber; my $darch; my $linktwo = 0; - if (-r $mntpath . "/content") + + my ($opensuse_distname, $opensuse_arch) = _detect_opensuse_leap_treeinfo($mntpath); + if ($opensuse_distname) { + $detdistname = $opensuse_distname; + $distname = $opensuse_distname unless $distname; + $darch = $opensuse_arch if $opensuse_arch; + $discnumber = 1; + } + + if (!$discnumber and -r $mntpath . "/content") { my $dinfo; open($dinfo, $mntpath . "/content"); @@ -1743,16 +1829,30 @@ sub copycd } closedir($dirh); - } elsif (-r $mntpath . "/media.1/media") { + } elsif (!$discnumber and -r $mntpath . "/media.1/media") { my $dinfo; open($dinfo, $mntpath . "/media.1/media"); my $dsc = <$dinfo>; + close($dinfo); + my $prod = ""; + if (-r "$mntpath/media.1/products") { + open(my $prod_fh, "<", "$mntpath/media.1/products"); + local $/; + $prod = <$prod_fh>; + close($prod_fh); + } if ($dsc =~ /x86_64/) { $darch = "x86_64"; } elsif ($dsc =~ /ppc64le/) { $darch = "ppc64le" ; } - if ($dsc =~ /Installer/ and $dsc =~ /SLE-15/) { + my ($opensuse_media_distname, $opensuse_media_arch) = _detect_opensuse_leap_media($dsc, $prod); + if ($opensuse_media_distname) { + $discnumber = 1; + $detdistname = $opensuse_media_distname; + $distname = $opensuse_media_distname unless $distname; + $darch = $opensuse_media_arch if $opensuse_media_arch; + } elsif ($dsc =~ /Installer/ and $dsc =~ /SLE-15/) { $discnumber = 1; unless ($distname) { if ($dsc =~ /SLE-15-SP(\d)/) { diff --git a/xCAT-server/share/xcat/install/scripts/post.sles.common b/xCAT-server/share/xcat/install/scripts/post.sles.common index 2e0a48dc1..e5b0765c5 100755 --- a/xCAT-server/share/xcat/install/scripts/post.sles.common +++ b/xCAT-server/share/xcat/install/scripts/post.sles.common @@ -42,6 +42,10 @@ echo "DHCLIENT_PRIMARY_DEVICE=yes" >> ifcfg-$PRINIC fi perl -pi -e 's/^FIREWALL="yes"/FIREWALL="no"/' /etc/sysconfig/network/config +if command -v systemctl >/dev/null 2>&1 && systemctl list-unit-files firewalld.service >/dev/null 2>&1; then + systemctl stop firewalld.service >/dev/null 2>&1 || true + systemctl disable firewalld.service >/dev/null 2>&1 || true +fi service network restart RAND=$(perl -e 'print int(rand(50)). "\n"') diff --git a/xCAT-server/share/xcat/install/sles/compute.leap15.pkglist b/xCAT-server/share/xcat/install/sles/compute.leap15.pkglist new file mode 100644 index 000000000..d2e64d998 --- /dev/null +++ b/xCAT-server/share/xcat/install/sles/compute.leap15.pkglist @@ -0,0 +1,12 @@ +@base +iputils +vim +openssl +rsync +net-tools +rsyslog +nfs-client +wget +openssh +zypper +chrony diff --git a/xCAT-server/share/xcat/install/sles/compute.leap15.tmpl b/xCAT-server/share/xcat/install/sles/compute.leap15.tmpl new file mode 100644 index 000000000..e90ad1955 --- /dev/null +++ b/xCAT-server/share/xcat/install/sles/compute.leap15.tmpl @@ -0,0 +1,90 @@ + + + + + + true + #XCATVAR:PERSKCMDLINE# + + + + + false + false + + false + + true + true + true + true + + + + UTC + #TABLE:site:key=timezone:value# + + + english-us + + + en_US + + + + + XCATPARTITIONHOOK + true + all + + + + + + #INSTALL_SOURCES# + + + + + Leap + + false + + #INCLUDE_DEFAULT_PTRNLIST_S# + + + #INCLUDE_DEFAULT_PKGLIST_S# + + + + + root + #CRYPT:passwd:key=system,username=root:password# + true + + + + + + + true + linux + + + + dhcp + eth0 + onboot + + + true + + false + + + + #INCLUDE:#ENV:XCATROOT#/share/xcat/install/scripts/pre.sle# + #INCLUDE:#ENV:XCATROOT#/share/xcat/install/scripts/chroot.sles# + #INCLUDE:#ENV:XCATROOT#/share/xcat/install/scripts/post.sle# + + diff --git a/xCAT-server/share/xcat/install/sles/service.leap15.pkglist b/xCAT-server/share/xcat/install/sles/service.leap15.pkglist new file mode 100644 index 000000000..5fe67617e --- /dev/null +++ b/xCAT-server/share/xcat/install/sles/service.leap15.pkglist @@ -0,0 +1,15 @@ +@base +@x11 +openssl +iputils +chrony +rsync +rsyslog +net-tools +vsftpd +perl-IO-Tty +perl-SNMP +perl-Net-DNS +mariadb-client +vim +wget diff --git a/xCAT-server/share/xcat/install/sles/service.leap15.tmpl b/xCAT-server/share/xcat/install/sles/service.leap15.tmpl new file mode 100644 index 000000000..e90ad1955 --- /dev/null +++ b/xCAT-server/share/xcat/install/sles/service.leap15.tmpl @@ -0,0 +1,90 @@ + + + + + + true + #XCATVAR:PERSKCMDLINE# + + + + + false + false + + false + + true + true + true + true + + + + UTC + #TABLE:site:key=timezone:value# + + + english-us + + + en_US + + + + + XCATPARTITIONHOOK + true + all + + + + + + #INSTALL_SOURCES# + + + + + Leap + + false + + #INCLUDE_DEFAULT_PTRNLIST_S# + + + #INCLUDE_DEFAULT_PKGLIST_S# + + + + + root + #CRYPT:passwd:key=system,username=root:password# + true + + + + + + + true + linux + + + + dhcp + eth0 + onboot + + + true + + false + + + + #INCLUDE:#ENV:XCATROOT#/share/xcat/install/scripts/pre.sle# + #INCLUDE:#ENV:XCATROOT#/share/xcat/install/scripts/chroot.sles# + #INCLUDE:#ENV:XCATROOT#/share/xcat/install/scripts/post.sle# + + diff --git a/xCAT-server/share/xcat/netboot/imgutils/imgutils.pm b/xCAT-server/share/xcat/netboot/imgutils/imgutils.pm index e8cc25445..e28626817 100644 --- a/xCAT-server/share/xcat/netboot/imgutils/imgutils.pm +++ b/xCAT-server/share/xcat/netboot/imgutils/imgutils.pm @@ -50,16 +50,24 @@ sub get_profile_def_filename { } my $osbase = substr($osver, 0, $dotpos); + my $fallbackos; + if ($osver =~ /^leap15/) { + $fallbackos = "sle15"; + } if (-r "$base/$profile.$osver.$arch.$ext") { return "$base/$profile.$osver.$arch.$ext"; } elsif (-r "$base/$profile.$osbase.$arch.$ext") { return "$base/$profile.$osbase.$arch.$ext"; + } elsif ($fallbackos && -r "$base/$profile.$fallbackos.$arch.$ext") { + return "$base/$profile.$fallbackos.$arch.$ext"; } elsif (-r "$base/$profile.$arch.$ext") { return "$base/$profile.$arch.$ext"; } elsif (-r "$base/$profile.$osver.$ext") { return "$base/$profile.$osver.$ext"; } elsif (-r "$base/$profile.$osbase.$ext") { return "$base/$profile.$osbase.$ext"; + } elsif ($fallbackos && -r "$base/$profile.$fallbackos.$ext") { + return "$base/$profile.$fallbackos.$ext"; } elsif (-r "$base/$profile.$ext") { return "$base/$profile.$ext"; } diff --git a/xCAT-server/share/xcat/netboot/sles/compute.leap15.pkglist b/xCAT-server/share/xcat/netboot/sles/compute.leap15.pkglist new file mode 100644 index 000000000..a96fb41e6 --- /dev/null +++ b/xCAT-server/share/xcat/netboot/sles/compute.leap15.pkglist @@ -0,0 +1,49 @@ +aaa_base +coreutils +bash +dbus-1 +wicked +device-mapper +dracut +nfs-kernel-server +keyutils +lvm2 +openssl +dhcp-client +openssh +procps +psmisc +wget +sysconfig +rsyslog +vim +rsync +timezone +bc +chrony +gzip +e2fsprogs +parted +xfsprogs +binutils +tar +open-iscsi +curl +btrfsprogs +cryptsetup +dmraid +mdadm +multipath-tools +gpg2 +which +cifs-utils +util-linux-systemd +systemd +udev +kernel-default +kernel-firmware-all +adaptec-firmware +xz +net-tools +rsyslog +iputils diff --git a/xCAT-server/share/xcat/netboot/sles/compute.leap15.postinstall b/xCAT-server/share/xcat/netboot/sles/compute.leap15.postinstall new file mode 100755 index 000000000..d9c335d32 --- /dev/null +++ b/xCAT-server/share/xcat/netboot/sles/compute.leap15.postinstall @@ -0,0 +1,14 @@ +#!/bin/sh + +installroot=$1 +arch=$3 +profile=$4 + +cat <"$installroot/etc/fstab" +proc /proc proc rw 0 0 +sysfs /sys sysfs rw 0 0 +devpts /dev/pts devpts rw,gid=5,mode=620 0 0 +${profile}_${arch} / tmpfs rw 0 1 +none /tmp tmpfs defaults,size=10m 0 2 +none /var/tmp tmpfs defaults,size=10m 0 2 +END diff --git a/xCAT-server/share/xcat/netboot/sles/compute.sle15.pkglist b/xCAT-server/share/xcat/netboot/sles/compute.sle15.pkglist index 20e05e5e8..5160b2529 100644 --- a/xCAT-server/share/xcat/netboot/sles/compute.sle15.pkglist +++ b/xCAT-server/share/xcat/netboot/sles/compute.sle15.pkglist @@ -24,6 +24,7 @@ ntp gzip e2fsprogs parted +xfsprogs binutils tar open-iscsi diff --git a/xCAT-server/share/xcat/netboot/sles/dracut_033/install.netboot b/xCAT-server/share/xcat/netboot/sles/dracut_033/install.netboot index 7fad93458..fdc60c623 100755 --- a/xCAT-server/share/xcat/netboot/sles/dracut_033/install.netboot +++ b/xCAT-server/share/xcat/netboot/sles/dracut_033/install.netboot @@ -1,7 +1,7 @@ #!/bin/sh echo $drivers dracut_install wget tar cpio gzip modprobe touch echo cut wc xz -dracut_install grep ifconfig ip hostname awk egrep grep dirname expr +dracut_install grep ip hostname awk egrep grep dirname expr dracut_install mount.nfs dracut_install parted mke2fs bc mkswap swapon chmod mkfs mkfs.ext4 mkfs.xfs xfs_db inst "$moddir/xcat-updateflag" "/tmp/updateflag" diff --git a/xCAT-server/share/xcat/netboot/sles/dracut_033/install.statelite b/xCAT-server/share/xcat/netboot/sles/dracut_033/install.statelite index f63f58b18..61bd284cb 100755 --- a/xCAT-server/share/xcat/netboot/sles/dracut_033/install.statelite +++ b/xCAT-server/share/xcat/netboot/sles/dracut_033/install.statelite @@ -1,7 +1,7 @@ #!/bin/sh echo $drivers dracut_install wget cpio gzip modprobe wc touch echo cut -dracut_install grep ifconfig ip hostname awk egrep grep dirname expr logger +dracut_install grep ip hostname awk egrep grep dirname expr logger dracut_install parted mke2fs bc mkswap swapon chmod mkfs mkfs.ext4 mkfs.xfs xfs_db inst "$moddir/xcat-updateflag" "/tmp/updateflag" inst_hook pre-mount 5 "$moddir/xcat-premount.sh" diff --git a/xCAT-server/share/xcat/netboot/sles/genimage b/xCAT-server/share/xcat/netboot/sles/genimage index 9daeed130..9eed0bbed 100755 --- a/xCAT-server/share/xcat/netboot/sles/genimage +++ b/xCAT-server/share/xcat/netboot/sles/genimage @@ -909,7 +909,9 @@ unless (-l "$rootimg_dir/var/lib/dhcpcd") { } #keyctl moved to /bin for newer release -system("cd $rootimg_dir/usr/bin/; ln -s ../../bin/keyctl $rootimg_dir/usr/bin/keyctl"); +unless (-e "$rootimg_dir/usr/bin/keyctl") { + system("cd $rootimg_dir/usr/bin/; ln -s ../../bin/keyctl $rootimg_dir/usr/bin/keyctl"); +} # which is different from the Redhat family @@ -933,10 +935,15 @@ if (@new_order) { } # add drivers for local disk support -push @ndrivers, ("ext3.ko", "ext4.ko", "virtio_pci.ko", "virtio_blk.ko", "libata.ko", "scsi_mod.ko", "scsi_dh.ko", "ahci.ko", "megaraid_sas.ko", "sd_mod.ko"); +push @ndrivers, ("ext3.ko", "ext4.ko", "virtio_pci.ko", "virtio_blk.ko", "libata.ko", "scsi_mod.ko", "ahci.ko", "megaraid_sas.ko", "sd_mod.ko"); +if (glob("$rootimg_dir/lib/modules/$kernelver/kernel/drivers/scsi/device_handler/scsi_dh.ko*")) { + push @ndrivers, "scsi_dh.ko"; +} if ($osver_host >= 12) { - push @ndrivers, ("ibmvscsi.ko"); + if ($arch =~ /ppc/) { + push @ndrivers, ("ibmvscsi.ko"); + } } else { # for sles11 or lower push @ndrivers, ("ibmvscsic.ko", "ata_piix.ko", "pcieport.ko"); } @@ -2124,9 +2131,17 @@ sub generic_post { # This function is meant to leave the image in a state approx foreach my $service (@services) { my $cmd = "chroot $rootimg_dir "; - if (-r "$rootimg_dir/etc/init.d/$service") { + if ((-r "$rootimg_dir/etc/init.d/$service") && (-x "$rootimg_dir/sbin/insserv")) { $cmd = $cmd . "insserv -f $service"; system("$cmd"); + } elsif (($service eq "network") && (-r "$rootimg_dir/usr/lib/systemd/system/wicked.service")) { + $cmd = $cmd . "systemctl enable wicked.service"; + system("$cmd"); + } elsif (-r "$rootimg_dir/usr/lib/systemd/system/$service.service") { + $cmd = $cmd . "systemctl enable $service.service"; + system("$cmd"); + } elsif (-r "$rootimg_dir/etc/init.d/$service") { + print "[genimage] skipping $service init script enablement because insserv is unavailable\n"; } else { $cmd = $cmd . "systemctl enable $service.service"; @@ -2490,4 +2505,3 @@ sub usage { print " genimage -i eth0 -n tg3,bnx2 -o sles11 -p compute --permission 777\n"; return 0; } - diff --git a/xCAT-test/unit/dhcp_kea_plugin_intent.t b/xCAT-test/unit/dhcp_kea_plugin_intent.t index 704f56af7..1973bf308 100644 --- a/xCAT-test/unit/dhcp_kea_plugin_intent.t +++ b/xCAT-test/unit/dhcp_kea_plugin_intent.t @@ -1,10 +1,12 @@ use strict; use warnings; +## no critic (Modules::RequireFilenameMatchesPackage, TestingAndDebugging::ProhibitNoStrict, TestingAndDebugging::ProhibitNoWarnings) no warnings 'once'; use FindBin; use lib "$FindBin::Bin/../../perl-xCAT"; +use File::Temp qw(tempdir); use Test::More; BEGIN { @@ -81,6 +83,72 @@ my %network_entry = ( tftpserver => '', ); +ok(xCAT_plugin::dhcp::dhcpd_sysconfig_uses_interface_key('opensuse-leap15.6'), 'openSUSE Leap head node uses SUSE dhcpd interface key'); +ok(xCAT_plugin::dhcp::dhcpd_sysconfig_uses_interface_key('leap15.6'), 'Leap head node osver uses SUSE dhcpd interface key'); +ok(!xCAT_plugin::dhcp::dhcpd_sysconfig_uses_interface_key('opensuse-tumbleweed'), 'generic openSUSE names do not enable Leap-specific dhcpd handling'); + +{ + my $tmpdir = tempdir(CLEANUP => 1); + my $fake_ip = "$tmpdir/ip"; + open(my $ip_fh, '>', $fake_ip) or die "Cannot write fake ip command: $!"; + print {$ip_fh} "#!/bin/sh\n"; + print {$ip_fh} "cat <<'EOF'\n"; + print {$ip_fh} "default via 192.168.1.1 dev eth1 proto dhcp\n"; + print {$ip_fh} "10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.1\n"; + print {$ip_fh} "192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.20\n"; + print {$ip_fh} "EOF\n"; + close($ip_fh); + chmod 0755, $fake_ip; + + no warnings 'redefine'; + local *xCAT_plugin::dhcp::kea_command_path = sub { + my ($command) = @_; + return $fake_ip if $command eq 'ip'; + return; + }; + + is_deeply( + [ xCAT_plugin::dhcp::local_ipv4_routes() ], + [ + [ '0.0.0.0', 'eth1', '0.0.0.0', 'G' ], + [ '10.0.0.0', 'eth0', '255.255.255.0', '' ], + [ '192.168.1.0', 'eth1', '255.255.255.0', '' ], + ], + 'local IPv4 route detection prefers ip route output' + ); +} + +{ + my $tmpdir = tempdir(CLEANUP => 1); + my $fake_netstat = "$tmpdir/netstat"; + open(my $netstat_fh, '>', $fake_netstat) or die "Cannot write fake netstat command: $!"; + print {$netstat_fh} "#!/bin/sh\n"; + print {$netstat_fh} "cat <<'EOF'\n"; + print {$netstat_fh} "Kernel IP routing table\n"; + print {$netstat_fh} "Destination Gateway Genmask Flags MSS Window irtt Iface\n"; + print {$netstat_fh} "0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth1\n"; + print {$netstat_fh} "10.0.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0\n"; + print {$netstat_fh} "EOF\n"; + close($netstat_fh); + chmod 0755, $fake_netstat; + + no warnings 'redefine'; + local *xCAT_plugin::dhcp::kea_command_path = sub { + my ($command) = @_; + return $fake_netstat if $command eq 'netstat'; + return; + }; + + is_deeply( + [ xCAT_plugin::dhcp::local_ipv4_routes() ], + [ + [ '0.0.0.0', 'eth1', '0.0.0.0', 'UG' ], + [ '10.0.0.0', 'eth0', '255.255.255.0', 'U' ], + ], + 'local IPv4 route detection falls back to netstat output' + ); +} + { no warnings 'redefine'; local *xCAT_plugin::dhcp::kea_ipv4_routes = sub { diff --git a/xCAT-test/unit/opensuse_leap_support.t b/xCAT-test/unit/opensuse_leap_support.t new file mode 100644 index 000000000..797c07397 --- /dev/null +++ b/xCAT-test/unit/opensuse_leap_support.t @@ -0,0 +1,215 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use Test::More; +use File::Temp qw(tempdir); +use FindBin; +use Cwd qw(realpath); + +use lib "$FindBin::Bin/../../perl-xCAT"; +use lib "$FindBin::Bin/../../xCAT-server/lib/perl"; +use lib "$FindBin::Bin/../../xCAT-server/lib/xcat/plugins"; +use lib "$FindBin::Bin/../../xCAT-server/share/xcat/netboot/imgutils"; + +require sles; +use xCAT::SvrUtils; +use xCAT::Template; +use imgutils; + +my $leap_compute_template_path = "$FindBin::Bin/../../xCAT-server/share/xcat/install/sles/compute.leap15.tmpl"; +open(my $leap_compute_template_fh, '<', $leap_compute_template_path) or die "Cannot read Leap compute template: $!"; +my $leap_compute_template = do { local $/; <$leap_compute_template_fh> }; +close($leap_compute_template_fh); + +like($leap_compute_template, qr/Leap<\/product>/, 'Leap install template selects Leap base product'); +like($leap_compute_template, qr/false<\/self_update>/, 'Leap install template disables installer self-update'); +like($leap_compute_template, qr/false<\/do_online_update>/, 'Leap install template disables online update'); + +my $leap_compute_pkglist_path = "$FindBin::Bin/../../xCAT-server/share/xcat/install/sles/compute.leap15.pkglist"; +open(my $leap_compute_pkglist_fh, '<', $leap_compute_pkglist_path) or die "Cannot read Leap compute pkglist: $!"; +my $leap_compute_pkglist = do { local $/; <$leap_compute_pkglist_fh> }; +close($leap_compute_pkglist_fh); + +like($leap_compute_pkglist, qr/^\@base$/m, 'Leap compute install pkglist requests a non-empty base pattern'); +unlike($leap_compute_pkglist, qr/^(?:insserv-compat|net-tools-deprecated|ntp)$/m, 'Leap compute install pkglist avoids unavailable SLE package names'); + +my $sle15_netboot_pkglist_path = "$FindBin::Bin/../../xCAT-server/share/xcat/netboot/sles/compute.sle15.pkglist"; +open(my $sle15_netboot_pkglist_fh, '<', $sle15_netboot_pkglist_path) or die "Cannot read SLE 15 netboot pkglist: $!"; +my $sle15_netboot_pkglist = do { local $/; <$sle15_netboot_pkglist_fh> }; +close($sle15_netboot_pkglist_fh); + +like($sle15_netboot_pkglist, qr/^xfsprogs$/m, 'SLE 15 netboot pkglist includes xfs tools required by the xCAT dracut module'); +is(xCAT::Template::_sle15_install_product_name('Product-SLES'), 'SLES', 'SLE 15 install source keeps the generic SLES product'); +is(xCAT::Template::_sle15_install_product_name('Module-Basesystem'), 'sle-module-basesystem', 'SLE 15 install source keeps regular modules'); +is(xCAT::Template::_sle15_install_product_name('Module-SAP-Applications'), undef, 'SLE 15 install source skips SAP application module'); +is(xCAT::Template::_sle15_install_product_name('Module-SAP-Business-One'), undef, 'SLE 15 install source skips SAP Business One module'); +is(xCAT::Template::_sle15_install_product_name('Product-SLES_SAP'), undef, 'SLE 15 install source skips SAP product media'); + +my $sle_post_common_path = "$FindBin::Bin/../../xCAT-server/share/xcat/install/scripts/post.sles.common"; +open(my $sle_post_common_fh, '<', $sle_post_common_path) or die "Cannot read SLE post-install script: $!"; +my $sle_post_common = do { local $/; <$sle_post_common_fh> }; +close($sle_post_common_fh); + +like($sle_post_common, qr/systemctl stop firewalld\.service/, 'SLE post-install script stops firewalld on systemd releases'); +like($sle_post_common, qr/systemctl disable firewalld\.service/, 'SLE post-install script disables firewalld after stateful install'); + +my $tmpdir = tempdir(CLEANUP => 1); + +open(my $treeinfo, '>', "$tmpdir/.treeinfo") or die "Cannot write .treeinfo: $!"; +print {$treeinfo} <<'EOF'; +[release] +name = openSUSE Leap +version = 15.6 + +[general] +arch = x86_64 +family = openSUSE Leap +name = openSUSE Leap 15.6 +version = 15.6 +platforms = x86_64,xen + +[images-x86_64] +kernel = boot/x86_64/loader/linux +initrd = boot/x86_64/loader/initrd +EOF +close($treeinfo); + +my ($tree_dist, $tree_arch) = xCAT_plugin::sles::_detect_opensuse_leap_treeinfo($tmpdir); +is($tree_dist, 'leap15.6', 'detects openSUSE Leap distname from .treeinfo'); +is($tree_arch, 'x86_64', 'detects openSUSE Leap arch from .treeinfo'); + +my $media = <<'EOF'; +openSUSE - openSUSE-Leap-15.6-NET-x86_64-Build710.3-Media +openSUSE-Leap-15.6-NET-x86_64-Build710.3 +1 +EOF +my $products = "/ openSUSE-Leap 15.6-1\n"; +my ($media_dist, $media_arch) = xCAT_plugin::sles::_detect_opensuse_leap_media($media, $products); +is($media_dist, 'leap15.6', 'detects openSUSE Leap distname from media files'); +is($media_arch, 'x86_64', 'detects openSUSE Leap arch from media files'); + +my ($unsupported_dist) = xCAT_plugin::sles::_detect_opensuse_leap_media( + "openSUSE - openSUSE-Leap-16.0-NET-x86_64-Media\n", + "/ openSUSE-Leap 16.0-1\n" +); +is($unsupported_dist, undef, 'does not detect unvalidated openSUSE Leap 16 media as supported'); +ok(xCAT_plugin::sles::_copycd_distname_supported('leap15.6'), 'copycd accepts explicit Leap distname override'); +ok(!xCAT_plugin::sles::_copycd_distname_supported('leap16.0'), 'copycd rejects unvalidated Leap 16 distname override'); +ok(!xCAT_plugin::sles::_copycd_distname_supported('opensuse15.6'), 'copycd does not accept generic openSUSE distname override'); + +my %commands = %{ xCAT_plugin::sles->handled_commands }; +like($commands{mkinstall}, qr/leap15\.\*/, 'mkinstall handles openSUSE Leap 15 nodes'); +like($commands{mknetboot}, qr/leap15\.\*/, 'mknetboot handles openSUSE Leap 15 nodes'); +like($commands{mkstatelite}, qr/leap15\.\*/, 'mkstatelite handles openSUSE Leap 15 nodes'); + +my @os_search = xCAT::SvrUtils::get_os_search_list('leap15.6'); +is_deeply( + \@os_search, + [qw(leap15.6 leap15.5 leap15.4 leap15.3 leap15.2 leap15.1 leap15.0 leap15 sle15)], + 'openSUSE Leap 15.x searches exact, minor, major, then SLE 15 fallback' +); + +my @unsupported_os_search = xCAT::SvrUtils::get_os_search_list('leap16.0'); +unlike( + join(' ', @unsupported_os_search), + qr/\bsle16\b/, + 'openSUSE Leap 16 does not silently use an unvalidated SLE 16 fallback' +); + +my $install_dir = tempdir(CLEANUP => 1); +open(my $tmpl, '>', "$install_dir/compute.leap15.tmpl") or die "Cannot write openSUSE template: $!"; +print {$tmpl} "opensuse template\n"; +close($tmpl); +open(my $compute_fallback_tmpl, '>', "$install_dir/compute.sle15.tmpl") or die "Cannot write compute SLE template: $!"; +print {$compute_fallback_tmpl} "sles template\n"; +close($compute_fallback_tmpl); +open(my $fallback_tmpl, '>', "$install_dir/service.sle15.tmpl") or die "Cannot write SLE template: $!"; +print {$fallback_tmpl} "sles template\n"; +close($fallback_tmpl); +open(my $install_pkglist, '>', "$install_dir/compute.leap15.pkglist") or die "Cannot write openSUSE install pkglist: $!"; +print {$install_pkglist} "chrony\n"; +close($install_pkglist); +open(my $install_fallback_pkglist, '>', "$install_dir/service.sle15.pkglist") or die "Cannot write SLE install pkglist: $!"; +print {$install_fallback_pkglist} "ntp\n"; +close($install_fallback_pkglist); + +is( + xCAT::SvrUtils::get_tmpl_file_name($install_dir, 'compute', 'leap15.6', 'x86_64'), + "$install_dir/compute.leap15.tmpl", + 'openSUSE template lookup prefers leap15 over SLE 15' +); +is( + xCAT::SvrUtils::get_tmpl_file_name($install_dir, 'service', 'leap15.6', 'x86_64'), + "$install_dir/service.sle15.tmpl", + 'openSUSE template lookup can fall back to SLE 15' +); +is( + xCAT::SvrUtils::get_pkglist_file_name($install_dir, 'compute', 'leap15.6', 'x86_64'), + "$install_dir/compute.leap15.pkglist", + 'openSUSE install pkglist lookup prefers leap15 over SLE 15' +); +is( + xCAT::SvrUtils::get_pkglist_file_name($install_dir, 'service', 'leap15.6', 'x86_64'), + "$install_dir/service.sle15.pkglist", + 'openSUSE install pkglist lookup can fall back to SLE 15' +); + +my $table_netboot_dir = tempdir(CLEANUP => 1); +open(my $table_opensuse_pkglist, '>', "$table_netboot_dir/compute.leap15.pkglist") or die "Cannot write openSUSE table pkglist: $!"; +print {$table_opensuse_pkglist} "zypper\n"; +close($table_opensuse_pkglist); +open(my $table_pkglist, '>', "$table_netboot_dir/compute.sle15.pkglist") or die "Cannot write table pkglist: $!"; +print {$table_pkglist} "aaa_base\n"; +close($table_pkglist); +open(my $table_exlist, '>', "$table_netboot_dir/compute.sle15.exlist") or die "Cannot write table exlist: $!"; +print {$table_exlist} "/tmp\n"; +close($table_exlist); +open(my $table_postinstall, '>', "$table_netboot_dir/compute.sle15.postinstall") or die "Cannot write table postinstall: $!"; +print {$table_postinstall} "#!/bin/sh\n"; +close($table_postinstall); +chmod 0755, "$table_netboot_dir/compute.sle15.postinstall"; + +is( + xCAT::SvrUtils::get_pkglist_file_name($table_netboot_dir, 'compute', 'leap15.6', 'x86_64'), + "$table_netboot_dir/compute.leap15.pkglist", + 'openSUSE diskless table lookup prefers leap15 pkglist over SLE 15' +); +unlink "$table_netboot_dir/compute.leap15.pkglist"; +is( + xCAT::SvrUtils::get_pkglist_file_name($table_netboot_dir, 'compute', 'leap15.6', 'x86_64', 'sle15'), + "$table_netboot_dir/compute.sle15.pkglist", + 'openSUSE diskless table lookup can fall back to SLE 15 pkglist' +); +is( + xCAT::SvrUtils::get_exlist_file_name($table_netboot_dir, 'compute', 'leap15.6', 'x86_64', 'sle15'), + "$table_netboot_dir/compute.sle15.exlist", + 'openSUSE diskless table lookup can fall back to SLE 15 exlist' +); +is( + xCAT::SvrUtils::get_postinstall_file_name($table_netboot_dir, 'compute', 'leap15.6', 'x86_64', 'sle15'), + "$table_netboot_dir/compute.sle15.postinstall", + 'openSUSE diskless table lookup can fall back to SLE 15 postinstall' +); + +my $netboot_dir = tempdir(CLEANUP => 1); +open(my $opensuse_pkglist, '>', "$netboot_dir/compute.leap15.pkglist") or die "Cannot write openSUSE pkglist: $!"; +print {$opensuse_pkglist} "zypper\n"; +close($opensuse_pkglist); +open(my $pkglist, '>', "$netboot_dir/compute.sle15.pkglist") or die "Cannot write SLE pkglist: $!"; +print {$pkglist} "aaa_base\n"; +close($pkglist); +my $real_netboot_dir = realpath($netboot_dir) || $netboot_dir; + +is( + imgutils::get_profile_def_filename('leap15.6', 'compute', 'x86_64', $netboot_dir, 'pkglist'), + "$real_netboot_dir/compute.leap15.pkglist", + 'openSUSE diskless profile lookup prefers leap15 pkglist over SLE 15' +); +unlink "$netboot_dir/compute.leap15.pkglist"; +is( + imgutils::get_profile_def_filename('leap15.6', 'compute', 'x86_64', $netboot_dir, 'pkglist'), + "$real_netboot_dir/compute.sle15.pkglist", + 'openSUSE diskless profile lookup falls back to SLE 15 pkglist' +); + +done_testing();