From 74c09097366e9b549b3f52e086daa916a25a746b Mon Sep 17 00:00:00 2001 From: Arthur Sengileyev Date: Fri, 2 Dec 2022 11:21:05 +0200 Subject: [PATCH 1/2] Add gvproxy to Windows packages Updated build scripts and installer build scripts to include gvproxy.exe. Includes tutorial on setting up a Podman VM with QEMU and gvproxy on Windows. Signed-off-by: Arthur Sengileyev --- Makefile | 15 ++- contrib/msi/podman.wxs | 4 + contrib/win-installer/build.ps1 | 1 + contrib/win-installer/podman.wxs | 4 + contrib/win-installer/process-release.ps1 | 7 +- docs/remote-docs.sh | 2 +- docs/tutorials/qemu-remote-tutorial.md | 132 ++++++++++++++++++++++ hack/markdown-preprocess | 5 +- 8 files changed, 160 insertions(+), 10 deletions(-) create mode 100644 docs/tutorials/qemu-remote-tutorial.md diff --git a/Makefile b/Makefile index 65735e06e1..6d0c55911d 100644 --- a/Makefile +++ b/Makefile @@ -477,7 +477,7 @@ $(MANPAGES): %: %.md .install.md2man docdir -e 's/\[\([^]]*\)](http[^)]\+)/\1/g' \ -e 's;<\(/\)\?\(a\|a\s\+[^>]*\|sup\)>;;g' \ -e 's/\\$$/ /g' $< |\ - $(GOMD2MAN) -in /dev/stdin -out $(subst source/markdown,build/man,$@) + $(GOMD2MAN) -out $(subst source/markdown,build/man,$@) .PHONY: docdir docdir: @@ -731,7 +731,7 @@ podman-remote-release-%.zip: test/version/version ## Build podman-remote for %=$ $(MAKE) $(GOPLAT) podman-remote; \ fi if [[ "$(GOOS)" == "windows" ]]; then \ - $(MAKE) $(GOPLAT) TMPDIR="" win-sshproxy; \ + $(MAKE) $(GOPLAT) TMPDIR="" win-gvproxy; \ fi if [[ "$(GOOS)" == "darwin" ]]; then \ $(MAKE) $(GOPLAT) podman-mac-helper;\ @@ -751,7 +751,7 @@ podman.msi: test/version/version ## Build podman-remote, package for installati podman-v%.msi: test/version/version # Passing explicitly OS and ARCH, because ARM is not supported by wixl https://gitlab.gnome.org/GNOME/msitools/-/blob/master/tools/wixl/builder.vala#L3 $(MAKE) GOOS=windows GOARCH=amd64 podman-remote-windows-docs - $(MAKE) GOOS=windows GOARCH=amd64 clean-binaries podman-remote podman-winpath win-sshproxy + $(MAKE) GOOS=windows GOARCH=amd64 clean-binaries podman-remote podman-winpath win-gvproxy $(eval DOCFILE := docs/build/remote/windows) find $(DOCFILE) -print | \ wixl-heat --var var.ManSourceDir --component-group ManFiles \ @@ -761,16 +761,17 @@ podman-v%.msi: test/version/version -o $@ contrib/msi/podman.wxs $(DOCFILE)/pages.wsx --arch x64 # Checks out and builds win-sshproxy helper. See comment on GV_GITURL declaration -.PHONY: win-sshproxy -win-sshproxy: test/version/version +.PHONY: win-gvproxy +win-gvproxy: test/version/version rm -rf tmp-gv; mkdir tmp-gv (cd tmp-gv; \ git init; \ git remote add origin $(GV_GITURL); \ git fetch --depth 1 origin $(GV_SHA); \ - git checkout FETCH_HEAD; make win-sshproxy) + git checkout FETCH_HEAD; make win-gvproxy win-sshproxy) mkdir -p bin/windows/ cp tmp-gv/bin/win-sshproxy.exe bin/windows/ + cp tmp-gv/bin/gvproxy.exe bin/windows/ rm -rf tmp-gv .PHONY: package @@ -804,6 +805,8 @@ install.remote: $(DESTDIR)$(BINDIR)/podman$(BINSFX) test "${GOOS}" != "windows" || \ install -m 755 $(SRCBINDIR)/win-sshproxy.exe $(DESTDIR)$(BINDIR) + test "${GOOS}" != "windows" || \ + install -m 755 $(SRCBINDIR)/gvproxy.exe $(DESTDIR)$(BINDIR) test "${GOOS}" != "darwin" || \ install -m 755 $(SRCBINDIR)/podman-mac-helper $(DESTDIR)$(BINDIR) test -z "${SELINUXOPT}" || \ diff --git a/contrib/msi/podman.wxs b/contrib/msi/podman.wxs index ac2b5f3284..7d5df81159 100644 --- a/contrib/msi/podman.wxs +++ b/contrib/msi/podman.wxs @@ -34,6 +34,9 @@ + + + @@ -47,6 +50,7 @@ + diff --git a/contrib/win-installer/build.ps1 b/contrib/win-installer/build.ps1 index ba1b975481..1e840f2d60 100644 --- a/contrib/win-installer/build.ps1 +++ b/contrib/win-installer/build.ps1 @@ -132,6 +132,7 @@ FetchPanel .\build-hooks.bat; ExitOnError SignItem @("artifacts/win-sshproxy.exe", + "artifacts/gvproxy.exe", "artifacts/podman.exe", "artifacts/podman-msihooks.dll", "artifacts/podman-wslkerninst.exe") diff --git a/contrib/win-installer/podman.wxs b/contrib/win-installer/podman.wxs index 2dfa802875..944db1bba7 100644 --- a/contrib/win-installer/podman.wxs +++ b/contrib/win-installer/podman.wxs @@ -29,6 +29,9 @@ + + + @@ -60,6 +63,7 @@ + diff --git a/contrib/win-installer/process-release.ps1 b/contrib/win-installer/process-release.ps1 index ba7b47f4b7..d9a5464292 100644 --- a/contrib/win-installer/process-release.ps1 +++ b/contrib/win-installer/process-release.ps1 @@ -123,8 +123,13 @@ try { Remove-Item -Recurse -Force -Path expand } + $loc = Get-ChildItem -Recurse -Path . -Name gvproxy.exe + if (!$loc) { + throw "Could not obtain gvproxy.exe" + } + Write-Host "Copying artifacts" - Foreach ($fileName in "win-sshproxy.exe", "podman.exe") { + Foreach ($fileName in "gvproxy.exe", "win-sshproxy.exe", "podman.exe") { Copy-Artifact($fileName) } diff --git a/docs/remote-docs.sh b/docs/remote-docs.sh index 83ecd66026..33d1595f4d 100755 --- a/docs/remote-docs.sh +++ b/docs/remote-docs.sh @@ -10,7 +10,7 @@ SOURCES=${@:3} ## directories to find markdown files # invoked in a cross-compilation environment, so even if PLATFORM=windows # we need an actual executable that we can invoke). if [[ -z "$PODMAN" ]]; then - DETECTED_OS=$(env -i HOME="$HOME" PATH="$PATH" go env GOOS) + DETECTED_OS=$(env -i HOME="$HOME" PATH="$PATH" GOROOT="$GOROOT" go env GOOS) case $DETECTED_OS in windows) PODMAN=bin/windows/podman.exe ;; diff --git a/docs/tutorials/qemu-remote-tutorial.md b/docs/tutorials/qemu-remote-tutorial.md new file mode 100644 index 0000000000..94805f902d --- /dev/null +++ b/docs/tutorials/qemu-remote-tutorial.md @@ -0,0 +1,132 @@ +# Podman-remote client for Windows with QEMU VM + +*** +**_NOTE:_** For running Podman on Windows, refer to the [Podman for Windows](podman-for-windows.md) guide, which uses the recommended approach of a Podman-managed Linux backend. For Mac, see the [Podman installation instructions](https://podman.io/getting-started/installation). This guide covers the advanced usage of Podman with a custom Linux VM. +*** + +## Introduction + +This is an experimental setup using QEMU VM for running Podman for the already supported [Podman-remote](https://docs.podman.io/en/latest/markdown/podman-remote.1.html) client on Windows. +The officially supported and recommended way of running Podman on Windows is using [Podman machine](https://docs.podman.io/en/latest/markdown/podman-machine.1.html). + +## Prerequisites + +* Windows 10 Build 18362 or later (Build 19044/Version 21H2 or later recommended) +* SSH client feature installed on the machine +* Hyper-V acceleration should be operational on the machine +* Direcroty `C:\qemu-remote\` will be used for storing needed assets +* Port `57561` is free to use for ssh over a loopback interface + +## Obtaining and installing + +### QEMU + +Download QEMU (7.2.0 minimal) from https://qemu.weilnetz.de/w64/ + +Then download the Fedora CoreOS (FCOS) image for QEMU from https://getfedora.org/coreos/download?tab=metal_virtualized&stream=testing&arch=x86_64 + +One will need `.xz` format extraction tool like xz itself or 7-zip. Use it to extract the `.qcow2` image to C:\qemu-remote\fedora-coreos-37.20221127.2.0-qemu.x86_64.qcow2 + +With xz the command line (when run from the same directory) will be +``` +xz -d fedora-coreos-37.20221127.2.0-qemu.x86_64.qcow2.xz +``` + +### Podman + +Download and install the latest release of Podman for Windows. Podman releases can be obtained from the official Podman GitHub release page: https://github.com/containers/podman/releases + +#### Older Podman releases + +When using older Podman releases (4.3.x and earlier), where `gvproxy.exe` is missing from the installation directory, +it could be obtained from the official releases https://github.com/containers/gvisor-tap-vsock/releases +One would need version `0.5.0` or a more recent release. Download `gvproxy-windows.exe` and copy it to +the Podman installation directory (or any other location, which is added to the PATH environment variable) +renaming the binary to `gvproxy.exe`. + +### SSH + +Generate ssh keys with an empty passphrase + +ssh-keygen -t ed25519 -f C:\qemu-remote\remote + +### Ingition for FCOS + +Create ignition file C:\qemu-remote\remote.ign with the content of +``` +{"ignition":{"config":{"replace":{"verification":{}}},"proxy":{},"security":{"tls":{}},"timeouts":{},"version":"3.2.0"},"passwd":{"users":[{"name":"core","sshAuthorizedKeys":["YOURSSHKEYHERE"],"uid":501},{"name":"root","sshAuthorizedKeys":["YOURSSHKEYHERE"]}]},"storage":{"directories":[{"group":{"name":"core"},"path":"/home/core/.config","user":{"name":"core"},"mode":493},{"group":{"name":"core"},"path":"/home/core/.config/containers","user":{"name":"core"},"mode":493},{"group":{"name":"core"},"path":"/home/core/.config/systemd","user":{"name":"core"},"mode":493},{"group":{"name":"core"},"path":"/home/core/.config/systemd/user","user":{"name":"core"},"mode":493},{"group":{"name":"core"},"path":"/home/core/.config/systemd/user/default.target.wants","user":{"name":"core"},"mode":493},{"group":{"name":"root"},"path":"/etc/containers/registries.conf.d","user":{"name":"root"},"mode":493},{"group":{"name":"root"},"path":"/etc/systemd/system.conf.d","user":{"name":"root"},"mode":493},{"group":{"name":"root"},"path":"/etc/environment.d","user":{"name":"root"},"mode":493}],"files":[{"group":{"name":"core"},"path":"/home/core/.config/systemd/user/linger-example.service","user":{"name":"core"},"contents":{"source":"data:,%5BUnit%5D%0ADescription=A%20systemd%20user%20unit%20demo%0AAfter=network-online.target%0AWants=network-online.target%20podman.socket%0A%5BService%5D%0AExecStart=%2Fusr%2Fbin%2Fsleep%20infinity%0A","verification":{}},"mode":484},{"group":{"name":"core"},"path":"/home/core/.config/containers/containers.conf","user":{"name":"core"},"contents":{"source":"data:,%5Bcontainers%5D%0Anetns=%22bridge%22%0A","verification":{}},"mode":484},{"group":{"name":"root"},"overwrite":true,"path":"/etc/subuid","user":{"name":"root"},"contents":{"source":"data:,core:100000:1000000","verification":{}},"mode":484},{"group":{"name":"root"},"overwrite":true,"path":"/etc/subgid","user":{"name":"root"},"contents":{"source":"data:,core:100000:1000000","verification":{}},"mode":484},{"group":{"name":"root"},"path":"/etc/systemd/system/user@.service.d/delegate.conf","user":{"name":"root"},"contents":{"source":"data:,%5BService%5D%0ADelegate=memory%20pids%20cpu%20io%0A","verification":{}},"mode":420},{"group":{"name":"core"},"path":"/var/lib/systemd/linger/core","user":{"name":"core"},"contents":{"verification":{}},"mode":420},{"group":{"name":"root"},"path":"/etc/containers/containers.conf","user":{"name":"root"},"contents":{"source":"data:,%5Bengine%5D%0Amachine_enabled=true%0A","verification":{}},"mode":420},{"group":{"name":"root"},"path":"/etc/containers/podman-machine","user":{"name":"root"},"contents":{"source":"data:,qemu%0A","verification":{}},"mode":420},{"group":{"name":"root"},"path":"/etc/containers/registries.conf.d/999-podman-machine.conf","user":{"name":"root"},"contents":{"source":"data:,unqualified-search-registries=%5B%22docker.io%22%5D%0A","verification":{}},"mode":420},{"group":{},"path":"/etc/tmpfiles.d/podman-docker.conf","user":{},"contents":{"source":"data:,L+%20%20%2Frun%2Fdocker.sock%20%20%20-%20%20%20%20-%20%20%20%20-%20%20%20%20%20-%20%20%20%2Frun%2Fpodman%2Fpodman.sock%0A","verification":{}},"mode":420},{"group":{"name":"root"},"path":"/etc/profile.d/docker-host.sh","user":{"name":"root"},"contents":{"source":"data:,export%20DOCKER_HOST=%22unix:%2F%2F$%28podman%20info%20-f%20%22%7B%7B.Host.RemoteSocket.Path%7D%7D%22%29%22%0A","verification":{}},"mode":420}],"links":[{"group":{"name":"core"},"path":"/home/core/.config/systemd/user/default.target.wants/linger-example.service","user":{"name":"core"},"hard":false,"target":"/home/core/.config/systemd/user/linger-example.service"},{"group":{"name":"root"},"overwrite":true,"path":"/usr/local/bin/docker","user":{"name":"root"},"hard":false,"target":"/usr/bin/podman"},{"group":{"name":"root"},"overwrite":false,"path":"/etc/localtime","user":{"name":"root"},"hard":false,"target":"\\usr\\share\\zoneinfo"}]},"systemd":{"units":[{"enabled":true,"name":"podman.socket"},{"contents":"[Unit]\nRequires=dev-virtio\\\\x2dports-vport1p1.device\nAfter=remove-moby.service sshd.socket sshd.service\nOnFailure=emergency.target\nOnFailureJobMode=isolate\n[Service]\nType=oneshot\nRemainAfterExit=yes\nExecStart=/bin/sh -c '/usr/bin/echo Ready \u003e/dev/vport1p1'\n[Install]\nRequiredBy=default.target\n","enabled":true,"name":"ready.service"},{"enabled":false,"mask":true,"name":"docker.service"},{"enabled":false,"mask":true,"name":"docker.socket"},{"contents":"[Unit]\nDescription=Remove moby-engine\n# Run once for the machine\nAfter=systemd-machine-id-commit.service\nBefore=zincati.service\nConditionPathExists=!/var/lib/%N.stamp\n\n[Service]\nType=oneshot\nRemainAfterExit=yes\nExecStart=/usr/bin/rpm-ostree override remove moby-engine\nExecStart=/usr/bin/rpm-ostree ex apply-live --allow-replacement\nExecStartPost=/bin/touch /var/lib/%N.stamp\n\n[Install]\nWantedBy=default.target\n","enabled":true,"name":"remove-moby.service"},{"contents":"[Unit]\nDescription=Environment setter from QEMU FW_CFG\n[Service]\nType=oneshot\nRemainAfterExit=yes\nEnvironment=FWCFGRAW=/sys/firmware/qemu_fw_cfg/by_name/opt/com.coreos/environment/raw\nEnvironment=SYSTEMD_CONF=/etc/systemd/system.conf.d/default-env.conf\nEnvironment=ENVD_CONF=/etc/environment.d/default-env.conf\nEnvironment=PROFILE_CONF=/etc/profile.d/default-env.sh\nExecStart=/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} \u0026\u0026\\\n\techo \"[Manager]\\n#Got from QEMU FW_CFG\\nDefaultEnvironment=$(/usr/bin/base64 -d ${FWCFGRAW} | sed -e \"s+|+ +g\")\\n\" \u003e ${SYSTEMD_CONF} ||\\\n\techo \"[Manager]\\n#Got nothing from QEMU FW_CFG\\n#DefaultEnvironment=\\n\" \u003e ${SYSTEMD_CONF}'\nExecStart=/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} \u0026\u0026 (\\\n\techo \"#Got from QEMU FW_CFG\"\u003e ${ENVD_CONF};\\\n\tIFS=\"|\";\\\n\tfor iprxy in $(/usr/bin/base64 -d ${FWCFGRAW}); do\\\n\t\techo \"$iprxy\" \u003e\u003e ${ENVD_CONF}; done ) || \\\n\techo \"#Got nothing from QEMU FW_CFG\"\u003e ${ENVD_CONF}'\nExecStart=/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} \u0026\u0026 (\\\n\techo \"#Got from QEMU FW_CFG\"\u003e ${PROFILE_CONF};\\\n\tIFS=\"|\";\\\n\tfor iprxy in $(/usr/bin/base64 -d ${FWCFGRAW}); do\\\n\t\techo \"export $iprxy\" \u003e\u003e ${PROFILE_CONF}; done ) || \\\n\techo \"#Got nothing from QEMU FW_CFG\"\u003e ${PROFILE_CONF}'\nExecStartPost=/usr/bin/systemctl daemon-reload\n[Install]\nWantedBy=sysinit.target\n","enabled":true,"name":"envset-fwcfg.service"}]}} +``` + +Replace "YOURSSHKEYHERE" with the actual pub keys you generated. + +## Launching + +### gvproxy + +One needs to run gvproxy first to make it ready for the QEMU VM launched afterward. Run it with the command below: +``` +gvproxy.exe -listen-qemu unix://C:/qemu-remote/vlan_remote.sock -pid-file C:\qemu-remote\proxy.pid -ssh-port 57561 -forward-sock C:\qemu-remote\podman.sock -forward-dest /run/user/501/podman/podman.sock -forward-user core -forward-identity C:\qemu-remote\remote +``` + +### QEMU + +Launch QEMU with the following command (the following configures it to use 4 CPUs and 8 GB RAM, but it could be adjusted for less): + +``` +qemu-system-x86_64w.exe -m 8192 -smp 4 -fw_cfg name=opt/com.coreos/config,file=C:\qemu-remote\remote.ign -netdev stream,id=vlan,server=off,addr.type=unix,addr.path=C:\qemu-remote\vlan_remote.sock -device virtio-net-pci,netdev=vlan,mac=5a:94:ef:e4:0c:ee -device virtio-serial -chardev socket,path=C:\qemu-remote\ready.sock,server=on,wait=off,id=apodman-machine-default_ready -device virtserialport,chardev=apodman-machine-default_ready,name=org.fedoraproject.port.0 -pidfile C:\qemu-remote\vm.pid -machine q35,accel=whpx:tcg -cpu max,vmx=off,monitor=off -drive if=virtio,file=C:\qemu-remote\fedora-coreos-37.20221127.2.0-qemu.x86_64.qcow2 +``` + +### First time launch extras + +Observe QEMU loading and wait for the message of SSH keys being provisioned to the machine. Next, before making the first ssh connection, one would need to add it to known hosts. +We are using `127.0.0.1` instead of `localhost` to force IPv4. + +``` +ssh-keyscan -p 57561 127.0.0.1 >> %USERPROFILE%\.ssh\known_hosts +``` + +### Add new connection to Podman + +Create a connection named "qemuremote" + +``` +podman system connection add --identity C:\qemu-remote\remote -p 57561 qemuremote ssh://core@127.0.0.1 +``` + +#### Optional + +Make it default for simplicity of operation/testing + +``` +podman system connection default qemuremote +``` + +## Using Podman + +Choose the active connection to be "qemuremote" (not needed if one made it default). + +Run some basic network enabled workload: + +``` +podman run -d --rm -p 8080:80 nginx +``` + +Test it with + +``` +curl http -v http://localhost:8080 +``` + +## Shutting down the machine + +The built-in machinery of Podman machine will not work for a custom machine. One needs to gracefully shut it down by connecting via SSH: + +``` +ssh -i C:\qemu-remote\remote -p 57561 core@127.0.0.1 +``` + +And then executing + +``` +sudo poweroff +``` diff --git a/hack/markdown-preprocess b/hack/markdown-preprocess index 119799bacf..30547756c0 100755 --- a/hack/markdown-preprocess +++ b/hack/markdown-preprocess @@ -38,7 +38,7 @@ class Preprocessor(): outfile = os.path.splitext(infile)[0] outfile_tmp = outfile + '.tmp.' + str(os.getpid()) - with open(infile, 'r', encoding='utf-8') as fh_in, open(outfile_tmp, 'w', encoding='utf-8') as fh_out: + with open(infile, 'r', encoding='utf-8') as fh_in, open(outfile_tmp, 'w', encoding='utf-8', newline='\n') as fh_out: for line in fh_in: # '@@option foo' -> include file options/foo.md if line.startswith('@@option '): @@ -71,7 +71,7 @@ class Preprocessor(): """ for optionfile in self.used_by: tmpfile = optionfile + '.tmp' - with open(optionfile, 'r', encoding='utf-8') as fh_in, open(tmpfile, 'w', encoding='utf-8') as fh_out: + with open(optionfile, 'r', encoding='utf-8') as fh_in, open(tmpfile, 'w', encoding='utf-8', newline='\n') as fh_out: fh_out.write("####> This option file is used in:\n") used_by = ', '.join(x for x in self.used_by[optionfile]) fh_out.write(f"####> podman {used_by}\n") @@ -82,6 +82,7 @@ class Preprocessor(): fh_out.write(line) # Compare files; only rewrite if the new one differs if not filecmp.cmp(optionfile, tmpfile): + os.unlink(optionfile) os.rename(tmpfile, optionfile) else: os.unlink(tmpfile) From 387f0ea2f68cc2805dae1368fe9acc814309145e Mon Sep 17 00:00:00 2001 From: Arthur Sengileyev Date: Sun, 29 Jan 2023 21:26:25 +0200 Subject: [PATCH 2/2] Making gvproxy.exe optional for building Windows installer Signed-off-by: Arthur Sengileyev --- contrib/win-installer/build.ps1 | 7 ++++++- contrib/win-installer/podman.wxs | 12 +++++++++++- contrib/win-installer/process-release.ps1 | 14 ++++++++------ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/contrib/win-installer/build.ps1 b/contrib/win-installer/build.ps1 index 1e840f2d60..e006e97c76 100644 --- a/contrib/win-installer/build.ps1 +++ b/contrib/win-installer/build.ps1 @@ -132,10 +132,15 @@ FetchPanel .\build-hooks.bat; ExitOnError SignItem @("artifacts/win-sshproxy.exe", - "artifacts/gvproxy.exe", "artifacts/podman.exe", "artifacts/podman-msihooks.dll", "artifacts/podman-wslkerninst.exe") +$gvExists = Test-Path "artifacts/gvproxy.exe" +if ($gvExists) { + SignItem @("artifacts/gvproxy.exe") +} else { + $env:UseGVProxy = "Skip" +} .\build-msi.bat $ENV:INSTVER; ExitOnError SignItem @("podman.msi") diff --git a/contrib/win-installer/podman.wxs b/contrib/win-installer/podman.wxs index 944db1bba7..9c4fa2780e 100644 --- a/contrib/win-installer/podman.wxs +++ b/contrib/win-installer/podman.wxs @@ -6,6 +6,12 @@ + + + + + + @@ -30,9 +36,11 @@ - + + + @@ -63,7 +71,9 @@ + + diff --git a/contrib/win-installer/process-release.ps1 b/contrib/win-installer/process-release.ps1 index d9a5464292..5706558a6d 100644 --- a/contrib/win-installer/process-release.ps1 +++ b/contrib/win-installer/process-release.ps1 @@ -123,16 +123,18 @@ try { Remove-Item -Recurse -Force -Path expand } - $loc = Get-ChildItem -Recurse -Path . -Name gvproxy.exe - if (!$loc) { - throw "Could not obtain gvproxy.exe" - } - Write-Host "Copying artifacts" - Foreach ($fileName in "gvproxy.exe", "win-sshproxy.exe", "podman.exe") { + Foreach ($fileName in "win-sshproxy.exe", "podman.exe") { Copy-Artifact($fileName) } + $loc = Get-ChildItem -Recurse -Path . -Name gvproxy.exe + if (!$loc) { + Write-Host "Skipping gvproxy.exe artifact" + } else { + Copy-Artifact("gvproxy.exe") + } + $docsloc = Get-ChildItem -Path . -Name docs -Recurse $loc = Get-ChildItem -Recurse -Path . -Name podman-for-windows.html if (!$loc) {