Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package os-autoinst for openSUSE:Factory checked in at 2026-10-06 19:15:39 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/os-autoinst (Old) and /work/SRC/openSUSE:Factory/.os-autoinst.new.3698736 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "os-autoinst" Tue Oct 6 19:15:39 2026 rev:627 rq:1382599 version:5.1790961809.b728c27 Changes: -------- --- /work/SRC/openSUSE:Factory/os-autoinst/os-autoinst.changes 2026-10-01 16:43:54.005131094 +0200 +++ /work/SRC/openSUSE:Factory/.os-autoinst.new.3698736/os-autoinst.changes 2026-10-06 19:16:40.999180864 +0200 @@ -1,0 +2,18 @@ +Mon Oct 05 13:49:26 UTC 2026 - [email protected] + +- Update to version 5.1790961809.b728c27: + * docs: Document generic local and remote verification guidelines + * fix: Avoid MAC address overflow when using custom NICOFFSET + +------------------------------------------------------------------- +Wed Sep 30 09:20:17 UTC 2026 - [email protected] + +- Update to version 5.1790759999.068642e: + * fix(svirt): Fix VMware copy hangs, paths, and large file transfers + * test: Update tests after 111e01b69 was merged + * feat: Record failures during post fail hook "Failed (post)" + * feat: Record info about entering post fail hook + * feat: Record failures during post fail hook as such + * feat: Record failures that happened during `post_fail_hook` + +------------------------------------------------------------------- Old: ---- os-autoinst-5.1790705326.6badaca.obscpio New: ---- os-autoinst-5.1790961809.b728c27.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ os-autoinst-devel-test.spec ++++++ --- /var/tmp/diff_new_pack.UEOXoU/_old 2026-10-06 19:16:42.504243845 +0200 +++ /var/tmp/diff_new_pack.UEOXoU/_new 2026-10-06 19:16:42.505243887 +0200 @@ -18,7 +18,7 @@ %define short_name os-autoinst-devel Name: %{short_name}-test -Version: 5.1790705326.6badaca +Version: 5.1790961809.b728c27 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ os-autoinst-openvswitch-test.spec ++++++ --- /var/tmp/diff_new_pack.UEOXoU/_old 2026-10-06 19:16:42.536245184 +0200 +++ /var/tmp/diff_new_pack.UEOXoU/_new 2026-10-06 19:16:42.537245226 +0200 @@ -19,7 +19,7 @@ %define name_ext -test %define short_name os-autoinst-openvswitch Name: %{short_name}%{?name_ext} -Version: 5.1790705326.6badaca +Version: 5.1790961809.b728c27 Release: 0 Summary: test package for %{short_name} License: GPL-2.0-or-later ++++++ os-autoinst-test.spec ++++++ --- /var/tmp/diff_new_pack.UEOXoU/_old 2026-10-06 19:16:42.564246356 +0200 +++ /var/tmp/diff_new_pack.UEOXoU/_new 2026-10-06 19:16:42.565246397 +0200 @@ -19,7 +19,7 @@ %define name_ext -test %define short_name os-autoinst Name: %{short_name}%{?name_ext} -Version: 5.1790705326.6badaca +Version: 5.1790961809.b728c27 Release: 0 Summary: test package for os-autoinst License: GPL-2.0-or-later ++++++ os-autoinst.spec ++++++ --- /var/tmp/diff_new_pack.UEOXoU/_old 2026-10-06 19:16:42.596247695 +0200 +++ /var/tmp/diff_new_pack.UEOXoU/_new 2026-10-06 19:16:42.598247778 +0200 @@ -17,7 +17,7 @@ Name: os-autoinst -Version: 5.1790705326.6badaca +Version: 5.1790961809.b728c27 Release: 0 Summary: OS-level test automation License: GPL-2.0-or-later ++++++ os-autoinst-5.1790705326.6badaca.obscpio -> os-autoinst-5.1790961809.b728c27.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/os-autoinst-5.1790705326.6badaca/AGENTS.md new/os-autoinst-5.1790961809.b728c27/AGENTS.md --- old/os-autoinst-5.1790705326.6badaca/AGENTS.md 2026-09-29 20:08:46.000000000 +0200 +++ new/os-autoinst-5.1790961809.b728c27/AGENTS.md 2026-10-02 19:23:29.000000000 +0200 @@ -21,6 +21,9 @@ reusing existing failing test modules (e.g. from `t/data/tests`) for integration tests. Prefer self-explanatory test description strings rather than in-file comments. +- **Verification**: See the "Local and remote verification" section in + `README.md` for standard procedures on local execution and remote worker + verification of your changes. - Dependencies: Update `dependencies.yaml` and run `make update-deps`. ## Constraints diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/os-autoinst-5.1790705326.6badaca/README.md new/os-autoinst-5.1790961809.b728c27/README.md --- old/os-autoinst-5.1790705326.6badaca/README.md 2026-09-29 20:08:46.000000000 +0200 +++ new/os-autoinst-5.1790961809.b728c27/README.md 2026-10-02 19:23:29.000000000 +0200 @@ -405,6 +405,39 @@ ISOTOVIDEO="c=/var/lib/openqa/cache/podman_storage && p=\$(pwd)/podman_tmp && mkdir -p \$c \$p/run && env HOME=\$p XDG_RUNTIME_DIR=\$p/run podman --root \$c --runroot \$p/run/containers --storage-opt ignore_chown_errors=true --cgroup-manager=cgroupfs --events-backend=file run --init --rm --entrypoint \"\" --device /dev/kvm -v \$(pwd):/pool -w /pool -v /var/lib/openqa/cache:/var/lib/openqa/cache registry.opensuse.org/devel/openqa/containers/os-autoinst_dev:latest sh -c 'zypper -n in os-autoinst-distri-opensuse-deps && rm -rf os-autoinst && git clone --branch=<your_engine_branch> --depth=1 https://github.com/<your_username>/os-autoinst.git && make -C os-autoinst symlinks && os-autoinst/isotovideo -d'" ``` +## Local and remote verification + +When developing and verifying modifications to `os-autoinst` or the test +distributions, you can verify changes locally on your development machine or +remotely by patching active openQA workers: + +### 1. Local verification +To run `isotovideo` locally against a cloned test-distribution, execute the local +`isotovideo` script from a dedicated local test run directory (where temporary +state files will be written) instead of running directly inside your cloned +test-distribution. This prevents polluting your test-distribution repository with +test execution artifacts: + +```sh +# Run from your dedicated local test run directory: +/path/to/os-autoinst/isotovideo --debug CASEDIR=/path/to/test-distribution [VARIABLES] +``` + +### 2. Remote verification by patching workers +To verify changes on an active, remote openQA worker without waiting +for a package update, copy your modified local Perl modules directly to the +corresponding path on the worker. Since a new `isotovideo` process is spawned +for each job, the next job run will automatically load the newly-patched +modules: + +```sh +# Copy your local modified module to the remote worker: +rsync -v --rsync-path="sudo rsync" consoles/VMWare.pm worker_host:/usr/lib/os-autoinst/consoles/VMWare.pm + +# Or if a jump host (e.g., o3) is required to reach the worker: +rsync -v -e 'ssh -J o3' --rsync-path="sudo rsync" consoles/VMWare.pm worker_host:/usr/lib/os-autoinst/consoles/VMWare.pm +``` + # Running isotovideo as CI check We provide a container to run `isotovideo` which can be used to run diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/os-autoinst-5.1790705326.6badaca/backend/qemu.pm new/os-autoinst-5.1790961809.b728c27/backend/qemu.pm --- old/os-autoinst-5.1790705326.6badaca/backend/qemu.pm 2026-09-29 20:08:46.000000000 +0200 +++ new/os-autoinst-5.1790961809.b728c27/backend/qemu.pm 2026-10-02 19:23:29.000000000 +0200 @@ -828,8 +828,8 @@ for (my $i = 0; $i < $num_networks; $i++) { # ensure MAC addresses differ globally # and allow MAC addresses for more than 256 workers (up to 16384) - my $workerid = $vars->{WORKER_ID}; - $nicmac[$i] //= sprintf '52:54:00:12:%02x:%02x', int($workerid / 256) + $i * $nic_offset, $workerid % 256; + my $workerid = $vars->{WORKER_ID} // 0; + $nicmac[$i] //= sprintf '52:54:00:12:%02x:%02x', (int($workerid / 256) + $i * 64) % 256, $workerid % 256; # always set proper TAPDEV for os-autoinst when using tap network mode my $instance = ($vars->{WORKER_INSTANCE} || 'manual') eq 'manual' ? 255 : $vars->{WORKER_INSTANCE}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/os-autoinst-5.1790705326.6badaca/consoles/VMWare.pm new/os-autoinst-5.1790961809.b728c27/consoles/VMWare.pm --- old/os-autoinst-5.1790705326.6badaca/consoles/VMWare.pm 2026-09-29 20:08:46.000000000 +0200 +++ new/os-autoinst-5.1790961809.b728c27/consoles/VMWare.pm 2026-10-02 19:23:29.000000000 +0200 @@ -173,6 +173,10 @@ for my $checksum_var (sort grep { /^CHECKSUM_/ } keys %bmwqemu::vars) { my $image = $bmwqemu::vars{$checksum_var =~ s/^CHECKSUM_//r}; next unless defined $image && basename($image) eq $file_basename; + # Only return the checksum if the file extension is exactly the same! + # For example, if the expected image name has .xz but we are checking a raw .vmdk, + # then the checksum belongs to the .xz file, not the .vmdk file! + next if $image =~ /\.xz$/ && $file_basename !~ /\.xz$/; my $checksum = $bmwqemu::vars{$checksum_var} // next; # only a plain digest is safe to interpolate into the shell script return lc $checksum if $checksum =~ /^(?:[0-9a-f]{64}|[0-9a-f]{128})$/i; @@ -185,15 +189,18 @@ # A 64 character checksum is either SHA-256 or SHA-512 truncated, so try SHA-256 first # and then the other, in the same order as verify_checksum() of the test distribution. sub _digest_script ($file, $checksum) { - return <<~"EOF" if length($checksum) == 128; - _digest=\$(sha512sum "$file" | awk '{print \$1}') - _digests="SHA-512 \$_digest" - EOF + if (length($checksum) == 128) { + return <<~"EOF"; + _digest=\$(openssl dgst -sha512 "$file" 2>/dev/null | awk '{print \$NF}') + _digests="SHA-512 \$_digest" + EOF + } + return <<~"EOF"; - _digest=\$(sha256sum "$file" | awk '{print \$1}') + _digest=\$(openssl dgst -sha256 "$file" 2>/dev/null | awk '{print \$NF}') _digests="SHA-256 \$_digest" if [ "\$_digest" != "$checksum" ]; then - _digest=\$(sha512sum "$file" | awk '{print \$1}' | cut -c1-64) + _digest=\$(openssl dgst -sha512 "$file" 2>/dev/null | awk '{print \$NF}' | cut -c1-64) _digests="\$_digests, SHA-512 truncated \$_digest" fi EOF @@ -205,7 +212,7 @@ # Note: This script must be in POSIX shell as ESXi uses busybox for /bin/sh sub _atomic_copy_script ($source, $dest, $tmp, $checksum = undef, $failure_note = undef) { my $copy = _replace_notice_script($dest) . <<~"EOF"; - if ! cp "$source" "$tmp"; then + if ! dd if="$source" of="$tmp" bs=1M 2>/dev/null; then rm -f "$tmp" echo "Unable to copy $source to $dest" exit 1 @@ -242,11 +249,11 @@ my $old_record = _verified_record_path($dest); return <<~"EOF"; $notice - if xz --decompress --stdout "$source" > "$tmp" && rm -f "$old_record" && mv "$tmp" "$dest"; then + if dd if="$source" of="$tmp.xz" bs=1M 2>/dev/null && xz --decompress "$tmp.xz" && rm -f "$old_record" && mv "$tmp" "$dest"; then $record echo "Decompressed $source to $dest" else - rm -f "$tmp" + rm -f "$tmp" "$tmp.xz" echo "Unable to decompress $source to $dest" exit 1 fi @@ -321,11 +328,12 @@ } _release_claim() { if [ -n "\$_heartbeat_pid" ]; then - { kill "\$_heartbeat_pid"; wait "\$_heartbeat_pid"; } 2>/dev/null + kill "\$_heartbeat_pid" 2>/dev/null fi if [ -n "\$_claimed" ] && _owns_marker; then rm -rf "$marker" fi + true } trap _release_claim EXIT _seen='' @@ -370,6 +378,7 @@ # expected name of uncompressed image my $baseimage = basename($input_file) =~ s/\.xz$//r; my $dest_image = "$vmware_openqa_datastore/${baseimage}"; + $dest_image =~ s{//+}{/}g; # Use the standard folder for an input file without full path my $file_origin = ($input_file eq $basefile) ? "$base_dir/$vmware_nfs_datastore/$nfs_dir/$basefile" : $input_file; my $dest_xz = "$dest_image.xz"; @@ -380,21 +389,24 @@ # final image also covers the .xz copy, as only the job producing the image needs it. # Note: This script must be in POSIX shell as ESXi uses busybox for /bin/sh my $verified = _indent(_verified_script($checksum)); - my $claim = _indent(_claim_copy_script($dest_image, $name, $checksum)); - my $failure_note = _failure_note_path($dest_image, $name); - my $copy_xz = _indent(_atomic_copy_script($file_origin, $dest_xz, _tmp_image_path($dest_xz, $name), $checksum, $failure_note), 3); - my $decompress = _indent(_atomic_decompress_script($dest_xz, $dest_image, _tmp_image_path($dest_image, $name), $checksum), 2); - my $copy_image = _indent(_atomic_copy_script($file_origin, $dest_image, _tmp_image_path($dest_image, $name), $checksum, $failure_note), 2); + my $claim = _indent(_claim_copy_script('$dest', $name, $checksum)); + my $failure_note = _failure_note_path('$dest', $name); + my $copy_xz = _indent(_atomic_copy_script('$src', '$dest_xz', _tmp_image_path('$dest_xz', $name), $checksum, $failure_note), 3); + my $decompress = _indent(_atomic_decompress_script('$dest_xz', '$dest', _tmp_image_path('$dest', $name), $checksum), 2); + my $copy_image = _indent(_atomic_copy_script('$src', '$dest', _tmp_image_path('$dest', $name), $checksum, $failure_note), 2); my $cmd = <<~"EOF"; $debug input_file="$input_file" + dest="$dest_image" + dest_xz="$dest_xz" + src="$file_origin" $verified $claim - if _verified "$dest_image"; then - echo "VMware image $dest_image ready" + if _verified "\$dest"; then + echo "VMware image \$dest ready" else - if [ "\${input_file##*.}" = "xz" ]; then - if ! _verified "$dest_xz"; then + if [ "\\\${input_file##*.}" = "xz" ]; then + if ! _verified "\$dest_xz"; then $copy_xz fi $decompress @@ -402,11 +414,17 @@ $copy_image fi fi - echo "Done: origin:" $file_origin* " ; dest.:" $dest_image* + echo "Done: origin: \$src ; dest.: \$dest" + exit 0 EOF - my $ret = $svirt->run_cmd($cmd, domain => 'sshVMwareServer'); - croak "Error on VMware image $input_file preparation." if $ret; + my ($ret, $stdout, $stderr) = $svirt->run_cmd($cmd, domain => 'sshVMwareServer', wantarray => 1); + if ($ret) { + $stdout //= ''; # uncoverable statement + $stderr //= ''; # uncoverable statement + bmwqemu::diag "Error on VMware image preparation command. Exit code: $ret\nStdout:\n$stdout\nStderr:\n$stderr" if $stdout || $stderr; # uncoverable statement + croak "Error on VMware image $input_file preparation."; # uncoverable statement + } return $dest_image; } @@ -421,25 +439,34 @@ my $vmware_nfs_datastore = $bmwqemu::vars{VMWARE_NFS_DATASTORE} or die 'Need variable VMWARE_NFS_DATASTORE'; # cmd debugging activable by setting VMWARE_NFS_DATASTORE_DEBUG=1 my $ds_debug = ($bmwqemu::vars{VMWARE_NFS_DATASTORE_DEBUG} // 0) ? 'set -x;' : ''; - my $dest_image = "$vmware_openqa_datastore$file_basename"; + my $dest_image = "$vmware_openqa_datastore/$file_basename"; + $dest_image =~ s{//+}{/}g; my $file_origin = "/vmfs/volumes/$vmware_nfs_datastore/$nfs_dir/$file_basename"; my $checksum = _expected_checksum($file_basename); my $verified = _indent(_verified_script($checksum)); - my $claim = _indent(_claim_copy_script($dest_image, $name, $checksum)); - my $copy_image = _indent(_atomic_copy_script($file_origin, $dest_image, _tmp_image_path($dest_image, $name), $checksum, _failure_note_path($dest_image, $name)), 1); + my $claim = _indent(_claim_copy_script('$dest', $name, $checksum)); + my $copy_image = _indent(_atomic_copy_script('$src', '$dest', _tmp_image_path('$dest', $name), $checksum, _failure_note_path('$dest', $name)), 1); # Note: This script must be in POSIX shell as ESXi uses busybox for /bin/sh my $cmd = <<~"EOF"; $ds_debug + dest="$dest_image" + src="$file_origin" $verified $claim - if _verified "$dest_image"; then - echo "VMware image $dest_image is already present and verified" + if _verified "\$dest"; then + echo "VMware image \$dest is already present and verified" else $copy_image fi + exit 0 EOF - my $retval = $svirt->run_cmd($cmd, domain => 'sshVMwareServer', timeout => $copy_timeout); - die "Can't copy VMware image $file_basename" if $retval; + my ($retval, $stdout, $stderr) = $svirt->run_cmd($cmd, domain => 'sshVMwareServer', timeout => $copy_timeout, wantarray => 1); + if ($retval) { + $stdout //= ''; # uncoverable statement + $stderr //= ''; # uncoverable statement + bmwqemu::diag "Can't copy VMware image. Exit code: $retval\nStdout:\n$stdout\nStderr:\n$stderr" if $stdout || $stderr; # uncoverable statement + die "Can't copy VMware image $file_basename"; # uncoverable statement + } return unless $backingfile; # Power VM off, delete its disk image, and create it again. # Then wait for some time for the VM to *really* turn off. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/os-autoinst-5.1790705326.6badaca/t/18-backend-qemu.t new/os-autoinst-5.1790961809.b728c27/t/18-backend-qemu.t --- old/os-autoinst-5.1790705326.6badaca/t/18-backend-qemu.t 2026-09-29 20:08:46.000000000 +0200 +++ new/os-autoinst-5.1790961809.b728c27/t/18-backend-qemu.t 2026-10-02 19:23:29.000000000 +0200 @@ -770,6 +770,21 @@ $process_mock->called_args_pos_is(3, 2, 'cleanup', 'cleanup event emitted'); } + @qemu_params = (); + $bmwqemu::vars{WORKER_ID} = 4090; + $bmwqemu::vars{TAPDEV} = 'auto,auto'; + $bmwqemu::vars{NICOFFSET} = 1000; + delete $bmwqemu::vars{NICMAC}; + combined_like { $backend->start_qemu } qr{.*}s, 'invoked with multiple tap devices and NICOFFSET=1000'; + $qemu_params = Mojo::Collection->new(\@qemu_params)->flatten->join(' '); + like $qemu_params, qr{tap id=qanet0 ifname=tap2 script=no downscript=no}, 'qanet0 tapdev correct'; + like $qemu_params, qr{tap id=qanet1 ifname=tap1002 script=no downscript=no}, 'qanet1 tapdev offset by NICOFFSET'; + like $qemu_params, qr{netdev=qanet0 mac=52:54:00:12:0f:fa}, 'qanet0 MAC address correct'; + like $qemu_params, qr{netdev=qanet1 mac=52:54:00:12:4f:fa}, 'qanet1 MAC address valid and not overflowed by NICOFFSET'; + delete $bmwqemu::vars{TAPDEV}; + delete $bmwqemu::vars{NICOFFSET}; + $bmwqemu::vars{WORKER_ID} = 42; + $bmwqemu::vars{NICPCIADDR} = 19; $bmwqemu::vars{NICTYPE} = 'user'; combined_like { $backend->start_qemu } qr{.*}s, 'invoked with NICPCIADDR'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/os-autoinst-5.1790705326.6badaca/t/22-svirt.t new/os-autoinst-5.1790961809.b728c27/t/22-svirt.t --- old/os-autoinst-5.1790705326.6badaca/t/22-svirt.t 2026-09-29 20:08:46.000000000 +0200 +++ new/os-autoinst-5.1790961809.b728c27/t/22-svirt.t 2026-10-02 19:23:29.000000000 +0200 @@ -651,9 +651,9 @@ @last_ssh_commands = (); $svirt->add_disk({cdrom => 1, dev_id => $dev_id, file => '/my/path/to/this/file/' . $filename}); my $tmp_file = "$vmware_openqa_datastore$filename." . $svirt->name . '.part'; - like $last_ssh_commands[0], qr%cp\s+"/vmfs/volumes/nfs_data_store/iso/$filename"\s+"\Q$tmp_file\E"%, "Copy iso to temporary file in $vmware_openqa_datastore"; - like $last_ssh_commands[0], qr%mv\s+"\Q$tmp_file\E"\s+"$vmware_openqa_datastore$filename"%, 'Temporary file renamed into place so the copy is atomic'; - like $last_ssh_commands[0], qr%mkdir\s+"$vmware_openqa_datastore$filename\.copying"%, 'Right to copy claimed so jobs arriving together do not all transfer the image'; + like $last_ssh_commands[0], qr%dd if="\$src" of="\$dest\.\Q${\$svirt->name}\E\.part"\s+bs=1M%, "Copy iso to temporary file in $vmware_openqa_datastore"; + like $last_ssh_commands[0], qr%mv "\$dest\.\Q${\$svirt->name}\E\.part"\s+"\$dest"%, 'Temporary file renamed into place so the copy is atomic'; + like $last_ssh_commands[0], qr%mkdir "\$dest\.copying"%, 'Right to copy claimed so jobs arriving together do not all transfer the image'; unlike $last_ssh_commands[0], qr/lsof/, 'No guessing from a process list whether someone else is copying needed anymore'; svirt_xml_validate($svirt, @@ -1066,8 +1066,8 @@ ) { my ($inp, $qry, $qry_xz, $backf_trig) = @$tuple; $svirt->provide_image_vmware_in_ds($inp, $vmware_openqa_datastore, backingfile => $backf_trig); - like $last_run_commands[$n], qr{cp\s.*$qry\"\s\"$vmware_openqa_datastore}, 'vmw-test-1: checking image management script, file origin:' . $n . 'a'; - like $last_run_commands[$n], qr{xz\s.*$vmware_openqa_datastore/$qry_xz}, 'vmw-test-1: checking image management script, file destination: ' . $n . 'b'; + like $last_run_commands[$n], qr{dd\s+if="\$src"\s+of="\$dest(?:_xz)?\.openQA-SUT-1\.part"\s+bs=1M}, 'vmw-test-1: checking image management script, file origin:' . $n . 'a'; + like $last_run_commands[$n], qr{xz\s+--decompress\s+"\$dest(?:_xz)?\.openQA-SUT-1\.part\.xz"}, 'vmw-test-1: checking image management script, file destination: ' . $n . 'b'; $n += 1; } }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/os-autoinst-5.1790705326.6badaca/t/27-consoles-vmware.t new/os-autoinst-5.1790961809.b728c27/t/27-consoles-vmware.t --- old/os-autoinst-5.1790705326.6badaca/t/27-consoles-vmware.t 2026-09-29 20:08:46.000000000 +0200 +++ new/os-autoinst-5.1790961809.b728c27/t/27-consoles-vmware.t 2026-10-02 19:23:29.000000000 +0200 @@ -30,6 +30,12 @@ use Mojo::File qw(tempdir path); use Digest::SHA; +# Maximum safe byte limit for shell scripts executed over SSH on ESXi. +# ESXi's minimal BusyBox ash interpreter fails with a "/bin/sh: File too large" +# kernel error (EFBIG) when parsing command strings via `sh -c` that exceed +# roughly 8 KB (8192 bytes). We limit to 7000 as a conservative safety net. +use constant MAX_ESXI_SHELL_SCRIPT_SIZE => 7000; + use consoles::VMWare; $bmwqemu::topdir = "$Bin/.."; @@ -290,21 +296,22 @@ subtest 'VMware images are verified against their published checksum before publishing' => sub { my $my_test_basedir = tempdir('/tmp/27-vmware-checksum-XXXX'); - my $nfs_ds = 'openqa_checksum'; - my $ds = 'datastore_checksum'; + my $nfs_ds = 'openqa datastore space'; + my $ds = 'datastore checksum space'; $bmwqemu::vars{VMWARE_NFS_DATASTORE_DEBUG} = '0'; $bmwqemu::vars{VIRSH_OPENQA_BASEDIR} = $my_test_basedir; $bmwqemu::vars{VMWARE_NFS_DATASTORE} = $nfs_ds; - my $iso = 'checksum-mock.iso'; + my $iso = 'checksum mock.iso'; my $source = path($my_test_basedir, $nfs_ds, 'iso')->make_path->child($iso); $source->spew('VMware image with a published checksum'); my $vmware_openqa_datastore = path($my_test_basedir, $ds, 'openQA')->make_path; my $dest = path($vmware_openqa_datastore, $iso); my $digest = Digest::SHA->new(256)->addfile($source->to_string)->hexdigest; my $last_output; + my $last_cmd; # stands in for the sshVirtsh console, running the generated script on the local host my $svirt = Test::MockObject->new->set_always(name => 'openQA-SUT-1'); - $svirt->mock(run_cmd => sub ($self, $cmd, %args) { $last_output = qx{($cmd) 2>&1}; $? >> 8 }); + $svirt->mock(run_cmd => sub ($self, $cmd, %args) { $last_cmd = $cmd; $last_output = qx{($cmd) 2>&1}; $? >> 8 }); $bmwqemu::vars{ISO} = "/var/lib/openqa/share/factory/iso/$iso"; my $provide = sub { consoles::VMWare::provide_image_in_datastore($svirt, $source, $vmware_openqa_datastore) }; @@ -314,7 +321,12 @@ lives_ok { $provide->() } 'image provided'; is $dest->slurp, $source->slurp, 'published image matches the source'; like $last_output, qr/Verified .*against its published checksum/, 'verification is reported'; - is_deeply [glob "$dest.*.part"], [], 'no temporary file left behind'; + is_deeply $vmware_openqa_datastore->list->grep(qr/\.part$/)->to_array, [], 'no temporary file left behind'; + + ok length($last_cmd) <= MAX_ESXI_SHELL_SCRIPT_SIZE, 'generated shell script stays under conservative limit ' . MAX_ESXI_SHELL_SCRIPT_SIZE; + unlike $last_cmd, qr/\becho "Done: origin:.*?\*/, 'unsafe shell globbing is avoided in output messages'; + my $path_occurrences = () = $last_cmd =~ /\Q$vmware_openqa_datastore\E/g; + ok $path_occurrences <= 3, 'path interpolation is minimized in favor of shell variables'; }; subtest 'mismatching checksum leaves the destination untouched' => sub { @@ -324,7 +336,16 @@ ok !-e $dest, 'a corrupt image is never published'; like $last_output, qr/Checksum mismatch .*expected b{64} but computed SHA-256 \Q$digest\E/, 'mismatch names both digests'; like path(consoles::VMWare::_failure_note_path($dest, 'openQA-SUT-1'))->slurp, qr/Checksum mismatch .*expected b{64}/, 'the mismatch is left for the jobs waiting for this one'; - is_deeply [glob "$dest.*.part"], [], 'temporary file removed'; + is_deeply $vmware_openqa_datastore->list->grep(qr/\.part$/)->to_array, [], 'temporary file removed'; + }; + + subtest 'mismatching 128 character SHA-512 checksum leaves the destination untouched' => sub { + $dest->remove; + $bmwqemu::vars{CHECKSUM_ISO} = 'b' x 128; + throws_ok { $provide->() } qr/Error on VMware image .* preparation/, 'image preparation fails with SHA-512'; + ok !-e $dest, 'a corrupt image is never published for SHA-512 mismatch'; + like $last_output, qr/Checksum mismatch .*expected b{128} but computed SHA-512 /, 'mismatch names SHA-512 digest'; + is_deeply $vmware_openqa_datastore->list->grep(qr/\.part$/)->to_array, [], 'temporary file removed'; }; subtest 'image without a published checksum is copied unverified' => sub { @@ -369,7 +390,7 @@ throws_ok { $provide->() } qr/Error on VMware image .* preparation/, 'image preparation fails on a mismatch'; is $dest->slurp, 'verified against an older checksum', 'the existing image is left alone'; is path(consoles::VMWare::_verified_record_path($dest))->slurp, 'c' x 64, 'its record still describes it'; - is_deeply [glob "$dest.*.part"], [], 'temporary file removed'; + is_deeply $vmware_openqa_datastore->list->grep(qr/\.part$/)->to_array, [], 'temporary file removed'; }; subtest 'a job without a published checksum keeps using whatever is there' => sub { ++++++ os-autoinst.obsinfo ++++++ --- /var/tmp/diff_new_pack.UEOXoU/_old 2026-10-06 19:16:44.377322226 +0200 +++ /var/tmp/diff_new_pack.UEOXoU/_new 2026-10-06 19:16:44.384322518 +0200 @@ -1,5 +1,5 @@ name: os-autoinst -version: 5.1790705326.6badaca -mtime: 1790705326 -commit: 6badaca44aecd87a345b4bfb44f47c4909a7fbb3 +version: 5.1790961809.b728c27 +mtime: 1790961809 +commit: b728c272762ca2f93a58dc61fb379d2e99d60bc9
