diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 960869a73ab..9829bd23118 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -189,7 +189,7 @@ jobs: - name: Integration tests (WSL2, Windows host) run: | $env:PATH = "$pwd\_output\bin;" + 'C:\msys64\usr\bin;' + $env:PATH - pacman -Sy --noconfirm openbsd-netcat diffutils + pacman -Sy --noconfirm openbsd-netcat diffutils socat $env:MSYS2_ENV_CONV_EXCL = 'HOME_HOST;HOME_GUEST;_LIMA_WINDOWS_EXTRA_PATH' $env:HOME_HOST = $(cygpath.exe "$env:USERPROFILE") $env:HOME_GUEST = "/mnt$env:HOME_HOST" @@ -218,7 +218,7 @@ jobs: - name: Integration tests (QEMU, Windows host) run: | $env:PATH = "$pwd\_output\bin;" + 'C:\msys64\usr\bin;' + 'C:\Program Files\QEMU;' + $env:PATH - pacman -Sy --noconfirm openbsd-netcat diffutils + pacman -Sy --noconfirm openbsd-netcat diffutils socat $env:MSYS2_ENV_CONV_EXCL = 'HOME_HOST;HOME_GUEST;_LIMA_WINDOWS_EXTRA_PATH' $env:HOME_HOST = $(cygpath.exe "$env:USERPROFILE") $env:HOME_GUEST = "$env:HOME_HOST" @@ -251,7 +251,8 @@ jobs: # bash: required by test-templates.sh (OS version of bash is too old) # coreutils: required by test-templates.sh for the "timeout" command # w3m : required by test-templates.sh for port forwarding tests - run: brew install qemu bash coreutils w3m + # socat: required by test-templates.sh for port forwarding tests + run: brew install qemu bash coreutils w3m socat - name: "Adjust LIMACTL_CREATE_ARGS" run: echo "LIMACTL_CREATE_ARGS=${LIMACTL_CREATE_ARGS} --vm-type=qemu" >>$GITHUB_ENV - name: "Inject `no_timer_check` to kernel cmdline" @@ -316,7 +317,7 @@ jobs: run: | sudo apt-get update sudo ./hack/install-qemu.sh - sudo apt-get install -y --no-install-recommends w3m + sudo apt-get install -y --no-install-recommends socat w3m - name: Install ansible-playbook run: | sudo apt-get install -y --no-install-recommends ansible @@ -438,7 +439,7 @@ jobs: with: template: templates/default.yaml - name: Install test dependencies - run: brew install qemu bash coreutils w3m + run: brew install qemu bash coreutils w3m socat - name: Install socket_vmnet env: SOCKET_VMNET_VERSION: v1.2.0 @@ -533,7 +534,7 @@ jobs: with: template: templates/${{ matrix.template }} - name: Install test dependencies - run: brew install bash coreutils w3m + run: brew install bash coreutils w3m socat - name: Uninstall qemu run: brew uninstall --ignore-dependencies --force qemu - name: Test diff --git a/hack/test-port-forwarding.pl b/hack/test-port-forwarding.pl index 4dc747d2383..269b10a8e4c 100755 --- a/hack/test-port-forwarding.pl +++ b/hack/test-port-forwarding.pl @@ -8,7 +8,7 @@ # ./hack/test-port-forwarding.pl templates/default.yaml # limactl --tty=false start templates/default.yaml # git restore templates/default.yaml -# ./hack/test-port-forwarding.pl default +# ./hack/test-port-forwarding.pl default [nc|socat [nc|socat]] [timeout] # # TODO: support for ipv6 host addresses @@ -21,7 +21,23 @@ use Socket qw(inet_ntoa); use Sys::Hostname qw(hostname); +my $connectionTimeout = 1; # seconds + my $instance = shift; +my $listener; +my $writer; +while (my $arg = shift) { + if ($arg eq "nc" || $arg eq "socat") { + $listener = $arg unless defined $listener; + $writer = $arg if defined $listener && !defined $writer; + } elsif ($arg =~ /^\d+$/) { + $connectionTimeout = $arg; + } else { + die "Usage: $0 [instance|yaml-file] [nc|socat [nc|socat]] [timeout]\n"; + } +} +$listener ||= "nc"; +$writer ||= $listener; my $addr = scalar gethostbyname(hostname()); # If hostname address cannot be determines, use localhost to trigger fallback to system_profiler lookup @@ -146,7 +162,8 @@ set -e cd $HOME sudo pkill -x nc || true -rm -f nc.* +sudo pkill -x socat || true +rm -f nc.* socat.* EOF # Give the hostagent some time to remove any port forwards from a previous (crashed?) test run @@ -161,13 +178,19 @@ # Setup a netcat listener on the guest for each test foreach my $id (0..@test-1) { my $test = $test[$id]; - my $nc = "nc -l $test->{guest_ip} $test->{guest_port}"; - if ($instance =~ /^alpine/) { - $nc = "nc -l -s $test->{guest_ip} -p $test->{guest_port}"; + my $cmd; + if ($listener eq "nc") { + $cmd = "nc -l $test->{guest_ip} $test->{guest_port}"; + if ($instance =~ /^alpine/) { + $cmd = "nc -l -s $test->{guest_ip} -p $test->{guest_port}"; + } + } elsif ($listener eq "socat") { + my $proto = $test->{guest_ip} =~ /:/ ? "TCP6" : "TCP"; + $cmd = "socat -u $proto-LISTEN:$test->{guest_port},bind=$test->{guest_ip} STDOUT"; } my $sudo = $test->{guest_port} < 1024 ? "sudo " : ""; - print $lima "${sudo}${nc} >nc.${id} 2>/dev/null &\n"; + print $lima "${sudo}${cmd} >$listener.${id} 2>/dev/null &\n"; } # Make sure the guest- and hostagents had enough time to set up the forwards @@ -176,8 +199,20 @@ # Try to reach each listener from the host foreach my $test (@test) { next if $test->{host_port} == $sshLocalPort; - my $nc = $test->{host_socket} eq "" ? "nc -w 1 $test->{host_ip} $test->{host_port}" : "nc -w 1 -U $test->{host_socket}"; - open(my $netcat, "| $nc") or die "Can't run '$nc': $!"; + my $cmd; + if ($writer eq "nc") { + if ($Config{osname} eq "darwin") { + # macOS nc doesn't support -w for connection timeout, so use -G instead + $cmd = $test->{host_socket} eq "" ? "nc -G $connectionTimeout $test->{host_ip} $test->{host_port}" : "nc -G $connectionTimeout -U $test->{host_socket}"; + } else { + $cmd = $test->{host_socket} eq "" ? "nc -w $connectionTimeout $test->{host_ip} $test->{host_port}" : "nc -w $connectionTimeout -U $test->{host_socket}"; + } + } elsif ($writer eq "socat") { + my $tcp_dest = $test->{host_ip} =~ /:/ ? "TCP6:[$test->{host_ip}]:$test->{host_port}" : "TCP:$test->{host_ip}:$test->{host_port}"; + $cmd = $test->{host_socket} eq "" ? "socat -u STDIN $tcp_dest,connect-timeout=$connectionTimeout" : "socat -u STDIN UNIX-CONNECT:$test->{host_socket}"; + } + print "Running: $cmd\n"; + open(my $netcat, "| $cmd") or die "Can't run '$cmd': $!"; print $netcat "$test->{log_msg}\n"; # Don't check for errors on close; macOS nc seems to return non-zero exit code even on success close($netcat); @@ -204,7 +239,7 @@ unless ($seen{$test->{log_msg}}) { $err .= "\n Message missing from ha.stderr.log"; } - my $log = qx(limactl shell --workdir / $instance sh -c "cd; cat nc.$id"); + my $log = qx(limactl shell --workdir / $instance sh -c "cd; cat $listener.$id"); chomp $log; if ($test->{mode} eq "forward" && $test->{log_msg} ne $log) { $err .= "\n Guest received: '$log'"; @@ -241,7 +276,7 @@ } # Cleanup remaining netcat instances (and port forwards) -print $lima "sudo pkill -x nc"; +print $lima "sudo pkill -x $listener"; exit $rc; diff --git a/hack/test-templates.sh b/hack/test-templates.sh index af7e1cc492e..61b73622dcd 100755 --- a/hack/test-templates.sh +++ b/hack/test-templates.sh @@ -152,6 +152,7 @@ function diagnose() { mkdir -p failure-logs cp -pf "$HOME_HOST/.lima/${NAME}"/*.log failure-logs/ limactl shell "$NAME" sudo cat /var/log/cloud-init-output.log | tee failure-logs/cloud-init-output.log + limactl shell "$NAME" sh -c "command -v journalctl >/dev/null && sudo journalctl -b --no-pager" >failure-logs/journal.log set +x -e } @@ -432,24 +433,34 @@ if [[ -n ${CHECKS["container-engine"]} ]]; then fi if [[ -n ${CHECKS["port-forwards"]} ]]; then - INFO "Testing port forwarding rules using netcat" + PORT_FORWARDING_CONNECTION_TIMEOUT=1 + INFO "Testing port forwarding rules using netcat and socat with connection timeout ${PORT_FORWARDING_CONNECTION_TIMEOUT}s" set -x - if [ "${NAME}" = "archlinux" ]; then - limactl shell "$NAME" sudo pacman -Syu --noconfirm openbsd-netcat + if [[ ${NAME} == "alpine"* ]]; then + limactl shell "${NAME}" sudo apk add socat fi - if [ "${NAME}" = "debian" ]; then - limactl shell "$NAME" sudo apt-get install -y netcat-openbsd + if [[ ${NAME} == "archlinux" ]]; then + limactl shell "${NAME}" sudo pacman -Syu --noconfirm openbsd-netcat socat fi - if [ "${NAME}" == "fedora" ]; then - limactl shell "$NAME" sudo dnf install -y nc + if [[ ${NAME} == "debian" || ${NAME} == "default" || ${NAME} == "docker" || ${NAME} == "test-misc" ]]; then + limactl shell "${NAME}" sudo apt-get install -y netcat-openbsd socat fi - if [ "${NAME}" = "opensuse" ]; then - limactl shell "$NAME" sudo zypper in -y netcat-openbsd + if [[ ${NAME} == "fedora" || ${NAME} == "wsl2" ]]; then + limactl shell "${NAME}" sudo dnf install -y nc socat fi - if limactl shell "$NAME" command -v dnf; then - limactl shell "$NAME" sudo dnf install -y nc + if [[ ${NAME} == "opensuse" ]]; then + limactl shell "${NAME}" sudo zypper in -y netcat-openbsd socat + fi + if limactl shell "${NAME}" command -v dnf; then + limactl shell "${NAME}" sudo dnf install -y nc socat + fi + if "${scriptdir}/test-port-forwarding.pl" "${NAME}" socat $PORT_FORWARDING_CONNECTION_TIMEOUT; then + INFO "Port forwarding rules work" + else + ERROR "Port forwarding rules do not work with socat" + diagnose "$NAME" + exit 1 fi - "${scriptdir}/test-port-forwarding.pl" "${NAME}" if [[ -n ${CHECKS["container-engine"]} || ${NAME} == "alpine"* ]]; then INFO "Testing that \"${CONTAINER_ENGINE} run\" binds to 0.0.0.0 and is forwarded to the host (non-default behavior, configured via test-port-forwarding.pl)"