diff --git a/build-ubunturepo b/build-ubunturepo index 8a849b6d1..35305e11a 100755 --- a/build-ubunturepo +++ b/build-ubunturepo @@ -104,8 +104,8 @@ for package in ${packages[@]}; do fi done -# Supported distributions -dists="saucy trusty utopic xenial bionic focal jammy" +# Supported distributions. Set DISTS="jammy noble resolute" to limit local validation builds. +dists="${DISTS:-saucy trusty utopic xenial bionic focal jammy noble resolute}" c_flag= # xcat-core (trunk-delvel) path d_flag= # xcat-dep (trunk) path diff --git a/docs/source/developers/guides/code/dhcp_backend_validation_matrix.rst b/docs/source/developers/guides/code/dhcp_backend_validation_matrix.rst index 657b54b6c..8bb769b15 100644 --- a/docs/source/developers/guides/code/dhcp_backend_validation_matrix.rst +++ b/docs/source/developers/guides/code/dhcp_backend_validation_matrix.rst @@ -122,6 +122,13 @@ The following matrix is the default live validation gate for DHCP backend work. - ``makedhcp -n``; ``kea-dhcp4 -t``; reservation add/query/delete; xNBA shell boot; compute-image boot artifact handoff through kernel, initrd, and root image when image validation is in scope + * - Ubuntu 26.04 LTS + - ``x86_64`` + - ``Kea`` + - ``xNBA shell`` and compute-image handoff + - ``makedhcp -n``; ``kea-dhcp4 -t``; reservation add/query/delete; + xNBA shell boot; stateful subiquity and stateless compute-image handoff + through kernel, initrd, and root image when image validation is in scope Kea Boot and Reservation Regression Matrix ------------------------------------------ @@ -212,18 +219,20 @@ paths. - ``POWER GRUB handoff`` - DHCP offer; boot file handoff; POWER boot-path correctness; Genesis shell when Genesis payload validation is in scope + * - Ubuntu 26.04 LTS + - ``ppc64le`` + - ``Kea`` + - ``POWER GRUB handoff`` + - package installation on ``ppc64el``; DHCP offer; boot file handoff; + POWER boot-path correctness; Genesis shell when live validation is in + scope Current Lab Baseline -------------------- -The current KVM validation hosts are: - -* ``rome01.local.versatushpc.com.br`` for ``x86_64`` -* ``power.local.versatushpc.com.br`` for ``ppc64le`` - -Validation access should use the ``builder`` account and the -``id_ed25519_reposync`` SSH key. Avoid relying on ad-hoc root login or -one-off cloud-init keys when recording repeatable validation procedure. +KVM validation should cover both ``x86_64`` and ``ppc64le`` hosts. Record the +repeatable lab access method privately with the validation run instead of +embedding site-specific hostnames or credentials in this repository. Full Ubuntu 24.04 ``x86_64`` stateless KVM validation required Ubuntu ``genimage`` fixes for early BOOTIF handling and a lean initrd driver set. @@ -240,14 +249,14 @@ rendering. Current exceptions: -* Ubuntu 22.04 LTS ISC OMAPI/``omshell`` host reservation updates are blocked by - xCAT3 issue ``#11``. The failure reproduces on upstream ``master`` and is not - caused by the Kea backend work. ``site.dhcpbackend=auto`` therefore selects - Kea for Ubuntu 22.04 and newer releases; live Ubuntu 22.04 Kea validation - remains a follow-up matrix row. +* Ubuntu 22.04 LTS ISC OMAPI/``omshell`` host reservation updates are + unreliable on current upstream code and are not caused by the Kea backend + work. ``site.dhcpbackend=auto`` therefore selects Kea for Ubuntu 22.04 and + newer releases; live Ubuntu 22.04 Kea validation remains a follow-up matrix + row. * Ubuntu ``ppc64le`` package installation is missing required boot packages such as ``goconserver``, ``grub2-xcat``, and ``xcat-genesis-base-ppc64``. This is - tracked by xCAT3 issue ``#13`` and is separate from Kea DHCP behavior. + tracked separately and is not a Kea DHCP behavior issue. Current PR Validation Snapshot ------------------------------ @@ -319,8 +328,7 @@ backend scope described above. - Raw DHCP fixture on the KVM provisioning bridge sent option 93 ``0x0010`` from the reserved outside-pool node MAC and received lease ``10.241.10.22`` with boot file ``xcat/xnba.efi``; no - ``ALLOC_FAIL_NO_POOLS`` was observed. xCAT3 issue ``#17`` is closed as - completed. + ``ALLOC_FAIL_NO_POOLS`` was observed. * - Ubuntu 24.04 LTS - ``x86_64`` - ``Kea 2.4.1`` @@ -339,9 +347,9 @@ backend scope described above. ``genesis.kernel.ppc64`` and ``genesis.fs.ppc64.gz`` reached xCAT ``shell`` state after replacing the broken ``grub2-xcat 1.0-3`` ppc GRUB core/module tree with the coherent - ``2.02-0.76.el7.1.snap201905160255`` tree. The remaining xCAT3 issue - ``#16`` follow-up is package provenance for ``grub2-xcat``, not DHCP or - Genesis payload behavior. + ``2.02-0.76.el7.1.snap201905160255`` tree. The remaining follow-up is + package provenance for ``grub2-xcat``, not DHCP or Genesis payload + behavior. * - Ubuntu 24.04 LTS - ``ppc64le`` - ``Kea 2.4.1`` @@ -354,24 +362,28 @@ backend scope described above. Ubuntu LTS KVM Validation Snapshot ---------------------------------- -As of April 29, 2026, the Ubuntu LTS KVM validation for the Ubuntu +As of May 1, 2026, the Ubuntu LTS KVM validation for the Ubuntu provisioning restoration work has the following result: .. list-table:: :header-rows: 1 - :widths: 14 10 10 12 12 42 + :widths: 14 9 9 12 12 12 12 30 * - Platform - Arch - Backend - - BIOS - - UEFI + - BIOS Stateless + - BIOS Stateful + - UEFI Stateless + - UEFI Stateful - Notes * - Ubuntu 18.04 LTS - ``x86_64`` - ``ISC`` - Pass - Pass + - Pass + - Pass - Stateless and stateful compute boots passed against an Ubuntu 18.04 headnode. The 18.04 debian-installer initrd did not include ``virtio_blk`` in this KVM environment, so stateful VMs used @@ -384,6 +396,8 @@ provisioning restoration work has the following result: - ``ISC`` - Pass - Pass + - Pass + - Pass - Stateless and stateful compute boots passed. Stateful validation used a manual static reservation workaround for the known forced-ISC OMAPI issue. @@ -392,6 +406,8 @@ provisioning restoration work has the following result: - ``Kea`` - Pass - Pass + - Pass + - Pass - Stateless and stateful compute boots passed. Kea 2.0.2 configuration validation with ``kea-dhcp4 -t`` passed on the Ubuntu 22.04 headnode. ``makedns -n`` starts ``bind9`` successfully, and the DHCP section of @@ -401,40 +417,30 @@ provisioning restoration work has the following result: - ``Kea`` - Pass - Pass + - Pass + - Pass - Stateless and stateful compute boots passed. Kea 2.4.1 configuration validation with ``kea-dhcp4 -t`` passed on the Ubuntu 24.04 headnode. ``makedns -n`` starts ``bind9`` successfully, and the DHCP section of ``xcatprobe xcatmn`` passed on consecutive runs. UEFI validation used OVMF Secure Boot disabled. - -Skipped Rows ------------- - -The following rows are intentionally not counted in the current PR acceptance -table: - -.. list-table:: - :header-rows: 1 - :widths: 18 10 12 60 - - * - Platform - - Arch - - Backend - - Reason - * - Ubuntu 22.04 LTS + * - Ubuntu 26.04 LTS - ``x86_64`` - ``Kea`` - - Skipped in this PR. Unit coverage now pins Ubuntu 22.04 to Kea by - default because ISC OMAPI/``omshell`` is blocked by xCAT3 issue ``#11``; - live KVM validation remains a follow-up row. - * - Ubuntu 22.04 LTS - - ``ppc64le`` - - ``Kea`` - - Skipped for the same Ubuntu 22.04 Kea follow-up validation reason as the - ``x86_64`` row. + - Pass + - Pass + - Pass + - Pass + - Stateless and stateful compute boots passed against an Ubuntu 26.04 + headnode. Kea 3.0.3 configuration validation with ``kea-dhcp4 -t`` + passed. Stateless BIOS and UEFI nodes reached ``sshd`` after the + netboot image was repacked with the recursive postscript download fix; + stateful BIOS and UEFI nodes completed Subiquity install and booted from + disk. Kea logs showed no ``ALLOC_FAIL_NO_POOLS``. UEFI validation used + OVMF Secure Boot disabled. -External Follow-up Tracking ---------------------------- +Follow-up Tracking +------------------ These issues are outside the DHCP acceptance result but must be referenced when reporting this validation run: @@ -446,12 +452,12 @@ reporting this validation run: * - Issue - Area - Impact - * - xCAT3 ``#13`` + * - Ubuntu ``ppc64le`` packages - Ubuntu ``ppc64le`` packages - Missing ``goconserver``, ``grub2-xcat``, and ``xcat-genesis-base-ppc64`` block clean Ubuntu ppc64le package installation. - * - xCAT3 ``#16`` + * - ``ppc64le`` GRUB package - ``ppc64le`` GRUB package - EL10 ppc64le fails with ``grub2-xcat 1.0-3`` because its POWER GRUB core/module tree cannot load the ppc64le Genesis kernel. The live row is diff --git a/docs/source/developers/guides/code/kea_dhcp_backend_plan.rst b/docs/source/developers/guides/code/kea_dhcp_backend_plan.rst index 16c6e0ce6..cf077e37e 100644 --- a/docs/source/developers/guides/code/kea_dhcp_backend_plan.rst +++ b/docs/source/developers/guides/code/kea_dhcp_backend_plan.rst @@ -310,7 +310,7 @@ Backend selection tests: * ``auto`` uses ISC on EL9 * ``auto`` uses ISC on Ubuntu 20.04 * ``auto`` uses Kea on EL10 -* ``auto`` uses Kea on Ubuntu 22.04 and Ubuntu 24.04 +* ``auto`` uses Kea on Ubuntu 22.04 and newer * forced ``kea`` works on EL9 when Kea packages are installed * forced unavailable backend fails clearly @@ -323,6 +323,7 @@ Integration matrix: * Ubuntu 20.04 plus ISC * Ubuntu 22.04 plus Kea * Ubuntu 24.04 plus Kea +* Ubuntu 26.04 plus Kea Semantic parity tests: @@ -348,21 +349,18 @@ Test Infrastructure ------------------- Existing container-based EL8, EL9, and EL10 tests should be extended for backend -coverage. The libvirt/KVM infrastructure on ``rome01.local.versatushpc.com.br`` -can be used for network and PXE smoke tests that are difficult to validate in -ordinary containers. +coverage. Libvirt/KVM infrastructure can be used for network and PXE smoke +tests that are difficult to validate in ordinary containers. Open test infrastructure details to confirm: -* SSH access method and user for ``rome01.local.versatushpc.com.br`` * available base images for EL9, EL10, Ubuntu 18.04, Ubuntu 20.04, Ubuntu - 22.04, and Ubuntu 24.04 + 22.04, Ubuntu 24.04, and Ubuntu 26.04 * libvirt network names and whether isolated DHCP test networks are already available * whether nested or privileged test guests can run DHCP client and PXE tests * cleanup expectations for temporary VMs, networks, and storage volumes -* the ``builder`` account and ``id_ed25519_reposync`` SSH key are available for - repeatable validation access +* repeatable validation access method and credentials Manual Validation Snapshot -------------------------- diff --git a/perl-xCAT/xCAT/DHCP/Backend/Kea.pm b/perl-xCAT/xCAT/DHCP/Backend/Kea.pm index 79c98cc91..b89c8cd84 100644 --- a/perl-xCAT/xCAT/DHCP/Backend/Kea.pm +++ b/perl-xCAT/xCAT/DHCP/Backend/Kea.pm @@ -154,19 +154,19 @@ sub render_ctrl_agent_config { my %sockets = ( dhcp4 => { 'socket-type' => 'unix', - 'socket-name' => $intent->{'dhcp4-socket'} || '/var/run/kea/kea4-ctrl-socket', + 'socket-name' => $intent->{'dhcp4-socket'} || $self->_kea_control_socket('kea4-ctrl-socket'), }, ); if ( $intent->{dhcp6} || $intent->{'dhcp6-socket'} ) { $sockets{dhcp6} = { 'socket-type' => 'unix', - 'socket-name' => $intent->{'dhcp6-socket'} || '/var/run/kea/kea6-ctrl-socket', + 'socket-name' => $intent->{'dhcp6-socket'} || $self->_kea_control_socket('kea6-ctrl-socket'), }; } if ( $intent->{ddns} || $intent->{'ddns-socket'} ) { $sockets{d2} = { 'socket-type' => 'unix', - 'socket-name' => $intent->{'ddns-socket'} || '/var/run/kea/kea-ddns-ctrl-socket', + 'socket-name' => $intent->{'ddns-socket'} || $self->_kea_control_socket('kea-ddns-ctrl-socket'), }; } @@ -218,7 +218,7 @@ sub load_dhcp4_config { my $content = <$fh>; close($fh); - my $json = eval { decode_json( _strip_json_comments($content) ) }; + my $json = eval { _decode_kea_json($content) }; return { error => "Unable to parse $path as JSON: $@" } if $@; $json->{Dhcp4}{subnet4} ||= []; @@ -236,7 +236,7 @@ sub load_dhcp6_config { my $content = <$fh>; close($fh); - my $json = eval { decode_json( _strip_json_comments($content) ) }; + my $json = eval { _decode_kea_json($content) }; return { error => "Unable to parse $path as JSON: $@" } if $@; $json->{Dhcp6}{subnet6} ||= []; @@ -334,6 +334,15 @@ sub encode_config { return JSON->new->canonical->pretty->encode($config); } +sub _decode_kea_json { + my ($content) = @_; + + # Kea accepts JSON with C/C++ comments and trailing commas. JSON->relaxed + # is backend-dependent, so normalize these Kea extensions explicitly before + # handing the content to the strict decoder. + return decode_json( _strip_json_trailing_commas( _strip_json_comments($content) ) ); +} + sub _strip_json_comments { my ($content) = @_; @@ -387,6 +396,48 @@ sub _strip_json_comments { return $out; } +sub _strip_json_trailing_commas { + my ($content) = @_; + + my $out = ''; + my $in_string = 0; + my $escaped = 0; + my $length = length($content); + + for ( my $idx = 0; $idx < $length; $idx++ ) { + my $char = substr( $content, $idx, 1 ); + + if ($in_string) { + $out .= $char; + if ($escaped) { + $escaped = 0; + } elsif ($char eq '\\') { + $escaped = 1; + } elsif ($char eq '"') { + $in_string = 0; + } + next; + } + + if ($char eq '"') { + $in_string = 1; + $out .= $char; + next; + } + + if ($char eq ',') { + my $lookahead = $idx + 1; + $lookahead++ while $lookahead < $length && substr( $content, $lookahead, 1 ) =~ /\s/; + my $next = $lookahead < $length ? substr( $content, $lookahead, 1 ) : ''; + next if $next eq '}' || $next eq ']'; + } + + $out .= $char; + } + + return $out; +} + sub write_ctrl_agent_config { my ( $self, $intent, %opts ) = @_; @@ -425,7 +476,17 @@ sub _validate_config_with { my $kea = _command_path($command); return { error => "Unable to validate $label configuration: $command was not found." } unless $kea; - my $cmd = "$kea -t " . _shell_quote($path) . " 2>&1"; + my $prefix = ''; + if ( $> == 0 ) { + my $kea_user = _kea_user(); + my $runuser = _command_path('runuser'); + # Validate as the daemon user when possible so root does not hide + # packaged Kea runtime-directory or config-readability failures. + $prefix = _shell_quote($runuser) . ' -u ' . _shell_quote($kea_user) . ' -- ' + if $kea_user && $runuser; + } + + my $cmd = $prefix . _shell_quote($kea) . " -t " . _shell_quote($path) . " 2>&1"; my $output = `$cmd`; my $rc = $? >> 8; return { error => "$label configuration validation failed: $output" } if $rc != 0; @@ -918,6 +979,15 @@ sub _kea_group { return; } +sub _kea_user { + foreach my $user ( 'kea', '_kea' ) { + my @entry = getpwnam($user); + return $entry[0] if @entry; + } + + return; +} + sub _kea_service { my ( $self, $service ) = @_; @@ -953,6 +1023,28 @@ sub _systemd_unit_dirs { ]; } +sub _kea_socket_dir { + my ($self) = @_; + + return $self->{kea_socket_dir} if defined $self->{kea_socket_dir}; + + # Kea validates Control Agent sockets against its packaged runtime + # directory, and newer packages reject /var/run/kea even when it resolves + # to /run/kea. Keep the legacy path as the unknown-state fallback for + # older Kea builds that validate before the runtime directory exists. + foreach my $dir ( @{ $self->{kea_socket_dirs} || [ '/run/kea', '/var/run/kea' ] } ) { + return $dir if -d $dir; + } + + return '/var/run/kea'; +} + +sub _kea_control_socket { + my ( $self, $socket_name ) = @_; + + return $self->_kea_socket_dir() . "/$socket_name"; +} + sub _command_path { my ($command) = @_; diff --git a/xCAT-server/lib/perl/xCAT/Template.pm b/xCAT-server/lib/perl/xCAT/Template.pm index a9bb1d62d..306b29074 100644 --- a/xCAT-server/lib/perl/xCAT/Template.pm +++ b/xCAT-server/lib/perl/xCAT/Template.pm @@ -37,6 +37,8 @@ my $key; my $field; my $idir; my $node; +my $master; +my $httpportsuffix; my %loggedrealms; my $lastmachinepassdata; my $localadminenabled; #indicate whether Windows template has local logins enabled or not @@ -86,7 +88,7 @@ sub subvars { ## 1, the "xcatmaster" attribute of the node ## 2, the ip address of the mn/sn facing the compute node ## 3, the site.master - my $master; + $master = undef; #the "xcatmaster" attribute of the node if ($tmpl_hash->{'xcatmaster'}) { @@ -146,7 +148,7 @@ sub subvars { } $ENV{HTTPPORT} = $httpport; - my $httpportsuffix=":$httpport"; + $httpportsuffix=":$httpport"; #replace the env with the right value so that correct include files can be found $inc =~ s/#ENV:([^#]+)#/envvar($1)/eg; my $res; @@ -364,6 +366,7 @@ sub subvars { $inc =~ s/#INSTALL_SOURCES_IN_PRE#/$source_in_pre/g; if (("ubuntu" eq $platform) || ("debian" eq $platform)) { $inc =~ s/#INCLUDE_OSIMAGE_PKGDIR#/$pkgdirs[-1]/; + $inc =~ s/#UBUNTU_SUBIQUITY_APT_CONFIG#/ubuntu_subiquity_apt_config($media_dir)/eg; } $inc =~ s/#WRITEREPO#/$writerepo/g; } @@ -376,8 +379,10 @@ sub subvars { $inc =~ s/#INCLUDE_NOP:([^#^\n]+)#/includefile($1,1,0)/eg; $inc =~ s/#XCATVAR:([^#]+)#/envvar($1)/eg; $inc =~ s/#ENV:([^#]+)#/envvar($1)/eg; + $inc =~ s/#UBUNTU_SUBIQUITY_APT_CONFIG#/ubuntu_subiquity_apt_config($media_dir)/eg; $inc =~ s/#MACHINEPASSWORD#/machinepassword()/eg; $inc =~ s/#CRYPT:([^:]+):([^:]+):([^#]+)#/crydb($1,$2,$3)/eg; + $inc =~ s/#CRYPTORLOCKED:([^:]+):([^:]+):([^#]+)#/crydb_or_locked($1,$2,$3)/eg; $inc =~ s/#COMMAND:([^#]+)#/command($1)/eg; $inc =~ s/#KICKSTARTNET#/kickstartnetwork()/eg; $inc =~ s/#MIRRORSPEC#/mirrorspec()/eg; @@ -1647,6 +1652,158 @@ sub crydb return xCAT::PasswordUtils::crypt_system_password($table, $kp, \@fields); } +sub crydb_or_locked +{ + my ( $table, $key, $field ) = @_; + my $crypted = crydb( $table, $key, $field ); + return $crypted if defined($crypted) && length($crypted); + return '*'; +} + +sub ubuntu_subiquity_apt_config +{ + my ($media_dir) = @_; + my $use_deb822 = ubuntu_subiquity_uses_deb822_sources($media_dir); + my @otherpkg_sources = ubuntu_subiquity_otherpkg_sources(); + + my @lines = ( + ' apt:', + ' preserve_sources_list: false', + ' fallback: offline-install', + ' geoip: false', + ' disable_suites:', + ' - updates', + ' - backports', + ' - security', + ); + + if ($use_deb822) { + if (ubuntu_subiquity_uses_generated_cdrom_source($media_dir)) { + # Ubuntu 26.04 and newer Subiquity overlays provide cdrom.sources. + # Rendering a second file:///cdrom source triggers apt option conflicts. + # Curtin still requires a valid Deb822 template, so write an inactive source. + push @lines, ' sources_list: |'; + push @lines, ' Types: deb'; + push @lines, ' URIs: http://xcat.invalid/disabled'; + push @lines, ' Suites: $RELEASE'; + push @lines, ' Components: main'; + push @lines, ' Enabled: no'; + } else { + push @lines, ' sources_list: |'; + push @lines, ' Types: deb'; + push @lines, ' URIs: file:///cdrom'; + push @lines, ' Suites: $RELEASE'; + push @lines, ' Components: main universe restricted multiverse'; + push @lines, ' Check-Date: no'; + } + + foreach my $source (@otherpkg_sources) { + push @lines, ''; + push @lines, ' Types: deb'; + push @lines, " URIs: $source"; + push @lines, ' Suites: ./'; + push @lines, ' Components:'; + push @lines, ' Trusted: yes'; + } + } else { + push @lines, ' mirror-selection:'; + push @lines, ' primary:'; + push @lines, ' - uri: file:/cdrom'; + + if (@otherpkg_sources) { + push @lines, ' sources:'; + my $index = 0; + foreach my $source (@otherpkg_sources) { + push @lines, " xcat-otherpkgs-$index.list:"; + push @lines, qq( source: "deb [trusted=yes] $source ./"); + $index++; + } + } + } + + return join( "\n", @lines ); +} + +sub ubuntu_subiquity_otherpkg_sources +{ + my $nodetype_tab = xCAT::Table->new('nodetype'); + return unless $nodetype_tab; + + my $nodetype_ent = $nodetype_tab->getNodeAttribs( $node, ['provmethod'] ); + return unless $nodetype_ent && $nodetype_ent->{provmethod}; + + my $linuximage_tab = xCAT::Table->new('linuximage'); + return unless $linuximage_tab; + + my $linuximage_ent = $linuximage_tab->getAttribs( { imagename => $nodetype_ent->{provmethod} }, 'otherpkgdir' ); + return unless $linuximage_ent && $linuximage_ent->{otherpkgdir}; + + my @sources; + foreach my $otherpkgdir ( split( /,/, $linuximage_ent->{otherpkgdir} ) ) { + $otherpkgdir =~ s/^\s+|\s+$//g; + next unless $otherpkgdir; + next if $otherpkgdir !~ m{^https?://} && !ubuntu_subiquity_local_apt_repo($otherpkgdir); + + my $uri = ubuntu_subiquity_pkgdir_uri($otherpkgdir); + push @sources, $uri; + } + + return @sources; +} + +sub ubuntu_subiquity_uses_deb822_sources +{ + my ($media_dir) = @_; + my $release = ubuntu_subiquity_release($media_dir); + + return 1 if $release =~ m{ubuntu([2-9][4-9]|[3-9][0-9])\.\d+}; + return 0; +} + +sub ubuntu_subiquity_uses_generated_cdrom_source +{ + my ($media_dir) = @_; + my $release = ubuntu_subiquity_release($media_dir); + + return 1 if $release =~ m{ubuntu([2-9][6-9]|[3-9][0-9])\.\d+}; + return 0; +} + +sub ubuntu_subiquity_release +{ + my ($media_dir) = @_; + my $release = $media_dir || ''; + + if ( !$release ) { + my $nodetype_tab = xCAT::Table->new('nodetype'); + my $nodetype_ent = $nodetype_tab ? $nodetype_tab->getNodeAttribs( $node, ['os'] ) : undef; + $release = $nodetype_ent->{os} if $nodetype_ent && $nodetype_ent->{os}; + } + + return $release; +} + +sub ubuntu_subiquity_local_apt_repo +{ + my ($path) = @_; + return 0 unless $path && -d $path; + return 1 if ( -f "$path/Packages" || -f "$path/Packages.gz" ) && -f "$path/Release"; + return 0; +} + +sub ubuntu_subiquity_pkgdir_uri +{ + my ($path) = @_; + $path ||= '/install'; + $path =~ s/\s+$//; + $path =~ s{/+$}{}; + + return $path if $path =~ m{^https?://}; + + $path = "/$path" if $path !~ m{^/}; + return "http://$master$httpportsuffix$path"; +} + sub tabdb { my $table = shift; diff --git a/xCAT-server/share/xcat/install/scripts/post.xcat b/xCAT-server/share/xcat/install/scripts/post.xcat index 369ac66ec..060dd6709 100755 --- a/xCAT-server/share/xcat/install/scripts/post.xcat +++ b/xCAT-server/share/xcat/install/scripts/post.xcat @@ -100,7 +100,10 @@ if [ ! -x /usr/bin/wget ]; then sleep 36500d fi -wget -l inf -N -r --waitretry=10 --random-wait --retry-connrefused -e robots=off -nH --cut-dirs=2 --reject "index.html*" --no-parent -t 20 -T 60 http://${MASTER_IP}:${HTTPPORT}${INSTALLDIR}/postscripts/ -P /xcatpost 2> /tmp/wget.log +# These dispatcher scripts are not needed by the legacy post.xcat path. Newer +# wget parses HTML-looking regex strings inside downloaded scripts and fails the +# whole recursive download on bogus URLs. +wget -l inf -N -r --waitretry=10 --random-wait --retry-connrefused -e robots=off -nH --cut-dirs=2 --reject "index.html*,post.xcat.ng,post.xcat.rhels10" --no-parent -t 20 -T 60 http://${MASTER_IP}:${HTTPPORT}${INSTALLDIR}/postscripts/ -P /xcatpost 2> /tmp/wget.log if [ "$?" != "0" ]; then msgutil_r "$MASTER_IP" "error" "failed to download postscripts from http://$MASTER_IP$INSTALLDIR/postscripts/,check /tmp/wget.log on the node, halt ..." "/var/log/xcat/xcat.log" "$log_label" /tmp/updateflag $MASTER $XCATIPORT "installstatus failed" diff --git a/xCAT-server/share/xcat/install/scripts/pre.ubuntu.subiquity b/xCAT-server/share/xcat/install/scripts/pre.ubuntu.subiquity index fe5206525..663cceb97 100644 --- a/xCAT-server/share/xcat/install/scripts/pre.ubuntu.subiquity +++ b/xCAT-server/share/xcat/install/scripts/pre.ubuntu.subiquity @@ -10,13 +10,14 @@ systemctl stop syslog.socket systemctl stop rsyslog # however, lets make sure . . . [ -e /var/run/rsyslogd.pid ] && kill -TERM $(cat /var/run/rsyslogd.pid) -# bare minimum rsyslog.conf to support UDP forwarding -cat < /tmp/rsyslog.conf +# bare minimum rsyslog.conf to support UDP forwarding. Newer Ubuntu releases +# run rsyslog under AppArmor and do not allow a config file from /tmp. +cat < /etc/rsyslog.conf module(load="imuxsock") module(load="imklog" permitnonkernelfacility="on") *.* @#XCATVAR:XCATMASTER# EOF -rsyslogd -f /tmp/rsyslog.conf +rsyslogd -f /etc/rsyslog.conf log_label="xcat.deployment" logger -t $log_label -p "info" "============deployment starting============" logger -t $log_label -p "info" "Running preseeding early_command Installation script..." diff --git a/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl b/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl index 5ed8d4327..15b644596 100644 --- a/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl +++ b/xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl @@ -12,13 +12,7 @@ autoinstall: allow-pw: true authorized-keys: [] install-server: true - apt: - fallback: offline-install - geoip: false - disable_suites: - - updates - - backports - - security +#UBUNTU_SUBIQUITY_APT_CONFIG# kernel: package: linux-generic user-data: @@ -28,13 +22,20 @@ autoinstall: package_upgrade: false timezone: #TABLE:site:key=timezone:value# chpasswd: - list: | - root:#CRYPT:passwd:key=system,username=root:password# + list: + - "root:#CRYPTORLOCKED:passwd:key=system,username=root:password#" expire: false packages: - openssh-server - openssh-client - wget + - vim + - rsync + - busybox-static + - gawk + - bind9-dnsutils + - chrony + - gpg early-commands: - | exec >/tmp/pre-install.log 2>&1 @@ -90,4 +91,4 @@ autoinstall: curtin in-target --target /target /root/post.script; } >>/target/var/log/xcat/xcat.log 2>&1' error-commands: - - tar -c --transform='s/^/#HOSTNAME#-logs\//' /var/crash /var/log/installer /tmp/pre-install.log /autoinstall.yaml 2>/dev/null |nc -l 8080 + - tar -c --ignore-failed-read --transform='s/^/#HOSTNAME#-logs\//' /var/crash /var/log/installer /tmp/pre-install.log /autoinstall.yaml 2>/dev/null |nc -l 8080 diff --git a/xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.ppc64el.pkglist b/xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.ppc64el.pkglist new file mode 100644 index 000000000..813cb2bc2 --- /dev/null +++ b/xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.ppc64el.pkglist @@ -0,0 +1,15 @@ +bash +nfs-common +openssl +isc-dhcp-client +libc-bin +openssh-server +openssh-client +wget +vim +rsync +busybox-static +gawk +bind9-dnsutils +chrony +gpg diff --git a/xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.ppc64le.pkglist b/xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.ppc64le.pkglist new file mode 120000 index 000000000..e01f0892a --- /dev/null +++ b/xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.ppc64le.pkglist @@ -0,0 +1 @@ +compute.ubuntu26.04.ppc64el.pkglist \ No newline at end of file diff --git a/xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.x86_64.pkglist b/xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.x86_64.pkglist new file mode 100644 index 000000000..813cb2bc2 --- /dev/null +++ b/xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.x86_64.pkglist @@ -0,0 +1,15 @@ +bash +nfs-common +openssl +isc-dhcp-client +libc-bin +openssh-server +openssh-client +wget +vim +rsync +busybox-static +gawk +bind9-dnsutils +chrony +gpg diff --git a/xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.ppc64el.pkglist b/xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.ppc64el.pkglist new file mode 100644 index 000000000..f8eaecec0 --- /dev/null +++ b/xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.ppc64el.pkglist @@ -0,0 +1,20 @@ +bash +ifupdown +nfs-common +openssl +isc-dhcp-client +libc-bin +linux-image-generic +openssh-server +openssh-client +wget +vim +rsync +busybox-static +gawk +bind9-dnsutils +tar +gzip +xz-utils +cpio +chrony diff --git a/xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.ppc64le.pkglist b/xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.ppc64le.pkglist new file mode 120000 index 000000000..e01f0892a --- /dev/null +++ b/xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.ppc64le.pkglist @@ -0,0 +1 @@ +compute.ubuntu26.04.ppc64el.pkglist \ No newline at end of file diff --git a/xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.x86_64.pkglist b/xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.x86_64.pkglist new file mode 100644 index 000000000..ef2f26fe1 --- /dev/null +++ b/xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.x86_64.pkglist @@ -0,0 +1,18 @@ +bash +nfs-common +openssl +isc-dhcp-client +libc-bin +linux-image-generic +openssh-server +openssh-client +wget +rsync +busybox-static +gawk +bind9-dnsutils +tar +gzip +xz-utils +cpio +chrony diff --git a/xCAT-server/share/xcat/netboot/ubuntu/genimage b/xCAT-server/share/xcat/netboot/ubuntu/genimage index bbc3986ab..8e15bd80e 100755 --- a/xCAT-server/share/xcat/netboot/ubuntu/genimage +++ b/xCAT-server/share/xcat/netboot/ubuntu/genimage @@ -273,7 +273,7 @@ unless ($onlyinitrd) { open($aptconfig, ">", "/tmp/genimage.$$.apt.list"); my $repnum = 0; foreach $tmpsrcdir (@aptdirs) { - print $aptconfig "deb file://$tmpsrcdir main stable\n\n"; + print $aptconfig "deb [trusted=yes] file://$tmpsrcdir main stable\n\n"; $repnum += 1; } $repnum -= 1; @@ -357,14 +357,18 @@ unless ($onlyinitrd) { open($aptconfig, ">", "$rootimg_dir/etc/apt/sources.list"); if ($srcdir) { - print $aptconfig "deb http://$masternode:$httpport$srcdir $dist main restricted universe\n"; + print $aptconfig "deb [trusted=yes] http://$masternode:$httpport$srcdir $dist main restricted universe\n"; } foreach (@pkgdir_internet) { print $aptconfig "deb $_\n"; } foreach (@pkgdir_local) { - print $aptconfig "deb $_\n"; + if (/^(http:\/\/\S+)\s+(\S.*)$/) { + print $aptconfig "deb [trusted=yes] $1 $2\n"; + } else { + print $aptconfig "deb $_\n"; + } } close($aptconfig); @@ -1254,10 +1258,10 @@ for i in `cat /proc/cmdline`; do done if [ -z "\$IFACE" ]; then - if iface_exists "\$BOOTIF"; then - IFACE=\$BOOTIF - elif iface_exists "\$NETDEV"; then + if iface_exists "\$NETDEV"; then IFACE=\$NETDEV + elif iface_exists "\$BOOTIF"; then + IFACE=\$BOOTIF elif iface_exists "\$PRINIC"; then IFACE=\$PRINIC else diff --git a/xCAT-test/unit/dhcp_kea_renderer.t b/xCAT-test/unit/dhcp_kea_renderer.t index c3a5de13e..3099dd26e 100644 --- a/xCAT-test/unit/dhcp_kea_renderer.t +++ b/xCAT-test/unit/dhcp_kea_renderer.t @@ -209,6 +209,16 @@ is( $reservation_policy_config->{Dhcp4}{'reservations-in-subnet'}, JSON::false, is( $reservation_policy_config->{Dhcp4}{'reservations-out-of-pool'}, JSON::false, 'reservation out-of-pool policy can be overridden' ); is( $reservation_policy_config->{Dhcp4}{'match-client-id'}, JSON::true, 'client-id lease matching policy can be overridden' ); +my $client_id_policy_json = $backend->render_dhcp4_config( + { + interfaces => ['eth0'], + match_client_id => 1, + subnets => [], + } +); +my $client_id_policy_config = decode_json($client_id_policy_json); +is( $client_id_policy_config->{Dhcp4}{'match-client-id'}, JSON::true, 'DHCPv4 client-id matching can be explicitly restored' ); + my $comment_dir = tempdir(CLEANUP => 1); my $commented_config = "$comment_dir/kea-dhcp4.conf"; my $commented_content = <<'COMMENTED_JSON'; @@ -220,9 +230,21 @@ my $commented_content = <<'COMMENTED_JSON'; { "id": 1, "subnet": "10.20.0.0/24", - "pools": [] // Keep URLs such as "http://server/path" intact. + "pools": [], // Keep URLs such as "http://server/path" intact. } - ] + ], + "loggers": [ + { + "name": "kea-dhcp4", + "output-options": [ + { + "output": "stdout", + "pattern": "%-5p %m\n", + // "flush": false + }, + ], + }, + ], } } COMMENTED_JSON @@ -374,6 +396,27 @@ is( $ddns_config->{DhcpDdns}{'forward-ddns'}{'ddns-domains'}[0]{name}, 'cluster. my $ctrl_agent_config = decode_json($backend->render_ctrl_agent_config({ 'http-port' => '8000' })); is( $ctrl_agent_config->{'Control-agent'}{'http-port'}, 8000, 'Control Agent HTTP port is numeric' ); +my $runtime_socket_dir = "$unit_dir/run/kea"; +mkdir "$unit_dir/run" or die "Unable to create $unit_dir/run: $!"; +mkdir $runtime_socket_dir or die "Unable to create $runtime_socket_dir: $!"; + +my $runtime_socket_backend = xCAT::DHCP::Backend::Kea->new( kea_socket_dirs => [ $runtime_socket_dir, "$unit_dir/var/run/kea" ] ); +my $runtime_socket_config = decode_json($runtime_socket_backend->render_ctrl_agent_config({})); +is( $runtime_socket_config->{'Control-agent'}{'control-sockets'}{dhcp4}{'socket-name'}, "$runtime_socket_dir/kea4-ctrl-socket", 'Control Agent socket uses the detected runtime directory' ); + +my $legacy_socket_backend = xCAT::DHCP::Backend::Kea->new( kea_socket_dirs => [] ); +my $legacy_socket_config = decode_json($legacy_socket_backend->render_ctrl_agent_config({})); +is( $legacy_socket_config->{'Control-agent'}{'control-sockets'}{dhcp4}{'socket-name'}, '/var/run/kea/kea4-ctrl-socket', 'Control Agent socket falls back to the legacy runtime path when no runtime directory exists' ); + +my $socket_backend = xCAT::DHCP::Backend::Kea->new( kea_socket_dir => '/run/kea' ); +my $ctrl_agent_socket_config = decode_json($socket_backend->render_ctrl_agent_config({ dhcp6 => 1, ddns => 1 })); +is( $ctrl_agent_socket_config->{'Control-agent'}{'control-sockets'}{dhcp4}{'socket-name'}, '/run/kea/kea4-ctrl-socket', 'Control Agent DHCPv4 socket uses the detected Kea socket directory' ); +is( $ctrl_agent_socket_config->{'Control-agent'}{'control-sockets'}{dhcp6}{'socket-name'}, '/run/kea/kea6-ctrl-socket', 'Control Agent DHCPv6 socket uses the detected Kea socket directory' ); +is( $ctrl_agent_socket_config->{'Control-agent'}{'control-sockets'}{d2}{'socket-name'}, '/run/kea/kea-ddns-ctrl-socket', 'Control Agent DDNS socket uses the detected Kea socket directory' ); + +my $explicit_socket_config = decode_json($socket_backend->render_ctrl_agent_config({ 'dhcp4-socket' => '/tmp/kea4.sock' })); +is( $explicit_socket_config->{'Control-agent'}{'control-sockets'}{dhcp4}{'socket-name'}, '/tmp/kea4.sock', 'explicit Control Agent socket path overrides the default' ); + my @commands; my $ca_backend = xCAT::DHCP::Backend::Kea->new( control_agent_handler => sub { diff --git a/xCAT-test/unit/post_xcat_download_policy.t b/xCAT-test/unit/post_xcat_download_policy.t new file mode 100644 index 000000000..7cbf70492 --- /dev/null +++ b/xCAT-test/unit/post_xcat_download_policy.t @@ -0,0 +1,48 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use FindBin; +use File::Spec; +use Test::More; + +my $repo_root = File::Spec->catdir( $FindBin::Bin, '..', '..' ); +my %scripts = ( + 'legacy install post.xcat' => File::Spec->catfile( + $repo_root, + 'xCAT-server/share/xcat/install/scripts/post.xcat' + ), + 'legacy netboot xcatdsklspost' => File::Spec->catfile( + $repo_root, + 'xCAT/postscripts/xcatdsklspost' + ), +); + +foreach my $path ( values %scripts ) { + plan skip_all => "$path not found" unless -r $path; +} + +foreach my $name ( sort keys %scripts ) { + my $path = $scripts{$name}; + open( my $fh, '<', $path ) or die "Unable to read $path: $!"; + my $script = do { local $/; <$fh> }; + close($fh); + + like( + $script, + qr/--reject\s+"index\.html\*,post\.xcat\.ng,post\.xcat\.rhels10"/, + "$name recursive wget ignores dispatcher scripts that contain literal HTML-link regexes" + ); + like( + $script, + qr/Newer\s+(?:#\s+)?wget\s+parses\s+HTML-looking\s+regex\s+strings/s, + "$name download policy documents why dispatcher scripts are excluded" + ); + unlike( + $script, + qr/catdir( $FindBin::Bin, '..', '..' ); + +my @pkglist_files = qw( + xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.ppc64el.pkglist + xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.x86_64.pkglist + xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.ppc64el.pkglist + xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.x86_64.pkglist +); + +foreach my $file (@pkglist_files) { + my $path = File::Spec->catfile( $repo_root, $file ); + ok( -r $path, "$file exists" ); + + open( my $fh, '<', $path ) or die "Unable to read $path: $!"; + my @packages = grep { /\S/ && !/^\s*#/ } map { chomp; $_ } <$fh>; + close($fh); + + my %packages = map { $_ => 1 } @packages; + ok( $packages{'bind9-dnsutils'}, "$file uses bind9-dnsutils" ); + ok( $packages{'chrony'}, "$file uses chrony" ); + ok( !$packages{'dnsutils'}, "$file avoids removed dnsutils package" ); + ok( !$packages{'ntp'}, "$file avoids removed ntp package" ); + ok( !$packages{'ntpdate'}, "$file avoids removed ntpdate package" ); +} + +foreach my $file (qw( + xCAT-server/share/xcat/install/ubuntu/compute.ubuntu26.04.ppc64le.pkglist + xCAT-server/share/xcat/netboot/ubuntu/compute.ubuntu26.04.ppc64le.pkglist +)) { + my $path = File::Spec->catfile( $repo_root, $file ); + ok( -l $path, "$file aliases ppc64le to ppc64el" ); +} + +my $subiquity_template = File::Spec->catfile( + $repo_root, + 'xCAT-server/share/xcat/install/ubuntu/compute.subiquity.tmpl' +); +open( my $tmpl_fh, '<', $subiquity_template ) or die "Unable to read $subiquity_template: $!"; +my $template = do { local $/; <$tmpl_fh> }; +close($tmpl_fh); + +like( $template, qr/\n\s+- bind9-dnsutils\n/, 'subiquity template uses bind9-dnsutils' ); +unlike( $template, qr/\n\s+- dnsutils\n/, 'subiquity template avoids removed dnsutils package' ); +like( $template, qr/\n\s+- "root:#CRYPTORLOCKED:passwd:key=system,username=root:password#"\n/, 'subiquity uses a locked root password marker when unset' ); +like( $template, qr/#UBUNTU_SUBIQUITY_APT_CONFIG#/, 'subiquity apt configuration is rendered from osimage package sources' ); +like( $template, qr/package_update: false/, 'subiquity install does not require online package update' ); +like( $template, qr/package_upgrade: false/, 'subiquity install does not require online package upgrade' ); + +my $template_module = File::Spec->catfile( $repo_root, 'xCAT-server/lib/perl/xCAT/Template.pm' ); +open( my $module_fh, '<', $template_module ) or die "Unable to read $template_module: $!"; +my $module = do { local $/; <$module_fh> }; +close($module_fh); + +like( $module, qr/URIs: http:\/\/xcat\.invalid\/disabled.*Enabled: no/s, 'subiquity renderer disables duplicate archive sources when Subiquity provides cdrom.sources' ); +like( $module, qr/sources_list: \|/, 'subiquity renderer owns Deb822 install media sources when Subiquity does not provide cdrom.sources' ); +like( $module, qr/URIs: file:\/\/\/cdrom/, 'subiquity renderer can use the mounted install media as the primary mirror' ); +like( $module, qr/Check-Date: no/, 'subiquity renderer avoids cdrom Check-Date conflicts' ); +like( $module, qr/fallback: offline-install/, 'subiquity renderer can complete without external apt mirrors' ); +like( $module, qr/geoip: false/, 'subiquity renderer does not require external geoip lookup' ); +like( $module, qr/- updates.*- backports.*- security/s, 'subiquity renderer disables online update suites' ); +like( $module, qr/mirror-selection:/, 'subiquity renderer keeps classic mirror-selection fallback for older Ubuntu releases' ); +like( $module, qr/Types: deb.*URIs: \$source.*Suites: \.\/.*Components:.*Trusted: yes/s, 'subiquity renderer includes trusted local xCAT otherpkgdir repositories in Deb822 sources_list' ); +like( $module, qr/deb \[trusted=yes\] \$source \.\/"/, 'subiquity renderer keeps classic source-list fallback for older Ubuntu releases' ); +like( $module, qr/-f "\$path\/Release"/, 'subiquity renderer requires indexed otherpkgdir repositories' ); + +my $subiquity_pre = File::Spec->catfile( + $repo_root, + 'xCAT-server/share/xcat/install/scripts/pre.ubuntu.subiquity' +); +open( my $pre_fh, '<', $subiquity_pre ) or die "Unable to read $subiquity_pre: $!"; +my $pre = do { local $/; <$pre_fh> }; +close($pre_fh); + +like( $pre, qr/id: efi-part\s+type: partition\s+device: disk-detected\s+size: 512M\s+flag: boot\s+number: 1\s+preserve: false\s+grub_device: true/s, 'subiquity UEFI storage marks the EFI partition as grub device' ); +like( $pre, qr/id: efi-part-fs\s+type: format\s+fstype: fat32\s+volume: efi-part/s, 'subiquity UEFI storage formats ESP as fat32' ); + +my $repo_builder = File::Spec->catfile( $repo_root, 'build-ubunturepo' ); +open( my $builder_fh, '<', $repo_builder ) or die "Unable to read $repo_builder: $!"; +my $builder = do { local $/; <$builder_fh> }; +close($builder_fh); + +like( $builder, qr/dists="\$\{DISTS:-[^"]*\bresolute\b[^"]*\}"/, 'Ubuntu repo builder includes resolute by default' ); + +done_testing(); diff --git a/xCAT-test/unit/ubuntu_subiquity_template.t b/xCAT-test/unit/ubuntu_subiquity_template.t index 2691d8627..a06ba2ae2 100644 --- a/xCAT-test/unit/ubuntu_subiquity_template.t +++ b/xCAT-test/unit/ubuntu_subiquity_template.t @@ -18,11 +18,11 @@ like($tmpl, qr/version:\s*1/, 'template has version: 1'); unlike($tmpl, qr/^\s*identity:/m, 'template must not have identity section (use user-data instead)'); like($tmpl, qr/kernel:/, 'template has kernel section'); like($tmpl, qr/package:\s*linux-generic/, 'template specifies linux-generic kernel'); -like($tmpl, qr/apt:/, 'template has apt section'); -like($tmpl, qr/fallback:\s*offline-install/, 'template uses offline-install fallback'); +like($tmpl, qr/#UBUNTU_SUBIQUITY_APT_CONFIG#/, 'template renders apt section from osimage context'); +unlike($tmpl, qr/^\s*apt:/m, 'template does not carry a static apt section'); unlike($tmpl, qr/WARN: no partitionfile/, 'template does not silently fall back when xCAT pre-script fails'); unlike($tmpl, qr/INSTALL_DISK=""/, 'template does not guess an install disk in early-commands'); -like($tmpl, qr/geoip:\s*false/, 'template disables geoip'); +unlike($tmpl, qr/geoip:\s*true/, 'template does not enable geoip'); like($tmpl, qr/ssh:/, 'template has ssh section'); like($tmpl, qr/install-server:\s*true/, 'template enables ssh install-server'); @@ -57,10 +57,9 @@ unlike($tmpl, qr/wget .*?\|\| true/, 'xCAT control artifact downloads are not ma unlike($tmpl, qr/if \[ -x \/tmp\/getinstdisk \]/, 'getinstdisk not checked with -x'); unlike($tmpl, qr/if \[ -x \/tmp\/pre\.sh \]/, 'pre.sh not checked with -x'); -# Regression: disable_suites must be release-independent (no noble-*, jammy-*, etc.) -unlike($tmpl, qr/noble-|jammy-|focal-/, 'disable_suites uses release-independent names'); -like($tmpl, qr/- updates/, 'disable_suites includes updates'); -like($tmpl, qr/- backports/, 'disable_suites includes backports'); -like($tmpl, qr/- security/, 'disable_suites includes security'); +# Regression: apt configuration is generated by Template.pm so release-specific +# Subiquity behavior can be handled without cloning this template per release. +unlike($tmpl, qr/noble-|jammy-|focal-/, 'template avoids release-specific apt suite names'); +like($tmpl, qr/#UBUNTU_SUBIQUITY_APT_CONFIG#/, 'template keeps dynamic apt renderer marker'); done_testing(); diff --git a/xCAT/postscripts/xcatdsklspost b/xCAT/postscripts/xcatdsklspost index 4ffb02f77..988fc8c2e 100755 --- a/xCAT/postscripts/xcatdsklspost +++ b/xCAT/postscripts/xcatdsklspost @@ -108,7 +108,10 @@ download_postscripts() rm -rf "$xcatpost" fi - export LANG=C; wget -l inf -nH -N -r --waitretry=10 --random-wait -e robots=off -T 60 -nH --cut-dirs=2 --reject "index.html*" --no-parent http://$server$INSTALLDIR/postscripts/ -P /$xcatpost 2> /tmp/wget.log + # These dispatcher scripts are not needed by the legacy netboot post + # path. Newer wget parses HTML-looking regex strings inside downloaded + # scripts and fails the whole recursive download on bogus URLs. + export LANG=C; wget -l inf -nH -N -r --waitretry=10 --random-wait -e robots=off -T 60 -nH --cut-dirs=2 --reject "index.html*,post.xcat.ng,post.xcat.rhels10" --no-parent http://$server$INSTALLDIR/postscripts/ -P /$xcatpost 2> /tmp/wget.log rc=$? if [ $rc -eq 0 ]; then # return from wget was 0 but some OS do not return errors, so we