From e3a15f8eeec75848adff60732875b945e0e06273 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 May 2025 12:51:01 +0000 Subject: [PATCH 01/21] build(deps): bump github.com/crc-org/crc/v2 from 2.49.0 to 2.51.0 Bumps [github.com/crc-org/crc/v2](https://github.com/crc-org/crc) from 2.49.0 to 2.51.0. - [Release notes](https://github.com/crc-org/crc/releases) - [Changelog](https://github.com/crc-org/crc/blob/main/release-info.json.sample) - [Commits](https://github.com/crc-org/crc/compare/v2.49.0...v2.51.0) --- updated-dependencies: - dependency-name: github.com/crc-org/crc/v2 dependency-version: 2.51.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index ed9a0a3a..24ac6104 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Code-Hex/vz/v3 v3.6.0 github.com/cavaliergopher/grab/v3 v3.0.1 github.com/containers/common v0.62.3 - github.com/crc-org/crc/v2 v2.49.0 + github.com/crc-org/crc/v2 v2.51.0 github.com/gin-gonic/gin v1.10.0 github.com/kdomanski/iso9660 v0.4.0 github.com/pkg/term v1.1.0 @@ -35,7 +35,7 @@ require ( github.com/cloudwego/iasm v0.2.0 // indirect github.com/crc-org/machine v0.0.0-20240926103419-a943b47fd48b // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/ebitengine/purego v0.8.2 // indirect + github.com/ebitengine/purego v0.8.3 // indirect github.com/fatih/color v1.18.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -61,14 +61,14 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/shirou/gopsutil/v4 v4.25.2 // indirect + github.com/shirou/gopsutil/v4 v4.25.4 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/numcpus v0.9.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect golang.org/x/arch v0.8.0 // indirect - golang.org/x/net v0.37.0 // indirect + golang.org/x/net v0.40.0 // indirect golang.org/x/term v0.32.0 // indirect golang.org/x/text v0.25.0 // indirect google.golang.org/protobuf v1.36.5 // indirect diff --git a/go.sum b/go.sum index 23bf9bf5..dc5468d4 100644 --- a/go.sum +++ b/go.sum @@ -22,16 +22,16 @@ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQ github.com/containers/common v0.62.3 h1:aOGryqXfW6aKBbHbqOveH7zB+ihavUN03X/2pUSvWFI= github.com/containers/common v0.62.3/go.mod h1:3R8kDox2prC9uj/a2hmXj/YjZz5sBEUNrcDiw51S0Lo= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/crc-org/crc/v2 v2.49.0 h1:V0N8TS5k1XMZF61Dw/P7yq8SFuCkHUAO2wwlfDuJI3I= -github.com/crc-org/crc/v2 v2.49.0/go.mod h1:uAWz+FS48HtNov/jLTUVQhBLacgZ+Gbv0IyRnQyjadM= +github.com/crc-org/crc/v2 v2.51.0 h1:Alk+nSg3bgkTUfFtuojsqd3MgaENGyqV/QO9zXx9ALg= +github.com/crc-org/crc/v2 v2.51.0/go.mod h1:aX+kLWe5nYlQlMa5PKPG4QXDiIj5eBlfgxwa+l/UXSg= github.com/crc-org/machine v0.0.0-20240926103419-a943b47fd48b h1:5577tKzQcPfd/i0dCekY32R9DUi677sNfhVLYKulBGM= github.com/crc-org/machine v0.0.0-20240926103419-a943b47fd48b/go.mod h1:trWeQimjfE3dJ8qWOxI4ePtYm13aecK42bf01s6h/Nc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I= -github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc= +github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= @@ -103,8 +103,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shirou/gopsutil/v4 v4.25.2 h1:NMscG3l2CqtWFS86kj3vP7soOczqrQYIEhO/pMvvQkk= -github.com/shirou/gopsutil/v4 v4.25.2/go.mod h1:34gBYJzyqCDT11b6bMHP0XCvWeU3J61XRT7a2EmCRTA= +github.com/shirou/gopsutil/v4 v4.25.4 h1:cdtFO363VEOOFrUCjZRh4XVJkb548lyF0q0uTeMqYPw= +github.com/shirou/gopsutil/v4 v4.25.4/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= @@ -140,8 +140,8 @@ golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From 15e5c7fcf5a52d6b3afcc555e0c93f73fe9fb185 Mon Sep 17 00:00:00 2001 From: Gunjan Vyas Date: Tue, 6 May 2025 15:35:59 +0530 Subject: [PATCH 02/21] Add network-config placeholder to cloud-init config map --- cmd/vfkit/main.go | 9 ++++++--- doc/usage.md | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cmd/vfkit/main.go b/cmd/vfkit/main.go index 6ec95d0f..288c4a4d 100644 --- a/cmd/vfkit/main.go +++ b/cmd/vfkit/main.go @@ -289,8 +289,9 @@ func generateCloudInitImage(files []string) (string, error) { } configFiles := map[string]io.Reader{ - "user-data": nil, - "meta-data": nil, + "user-data": nil, + "meta-data": nil, + "network-config": nil, } hasConfigFile := false @@ -306,7 +307,9 @@ func generateCloudInitImage(files []string) (string, error) { filename := filepath.Base(path) if _, ok := configFiles[filename]; ok { - hasConfigFile = true + if filename == "user-data" || filename == "meta-data" { + hasConfigFile = true + } configFiles[filename] = file } } diff --git a/doc/usage.md b/doc/usage.md index d7ae888e..9c7e9974 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -164,7 +164,7 @@ Vfkit can create this ISO image automatically, or you can provide a pre-made ISO ##### Automatic ISO Creation -Vfkit allows you to pass the file paths of your `user-data` and `meta-data` files directly as arguments. +Vfkit allows you to pass the file paths of your `user-data`, `meta-data`, and `network-config` files directly as arguments. It will then handle the creation of the ISO image and the virtio-blk device internally. Example From d3cf9b3b893c45d2af2f9f3fa04d2162aa8e25be Mon Sep 17 00:00:00 2001 From: Gunjan Vyas Date: Tue, 6 May 2025 15:36:22 +0530 Subject: [PATCH 03/21] Add optional support for providing network-config to cloud-init script --- contrib/scripts/start-with-cloud-init.sh | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/contrib/scripts/start-with-cloud-init.sh b/contrib/scripts/start-with-cloud-init.sh index 2953e17e..5da9582f 100755 --- a/contrib/scripts/start-with-cloud-init.sh +++ b/contrib/scripts/start-with-cloud-init.sh @@ -12,13 +12,16 @@ # The $DISK_IMG variable needs to be set by the user to a # valid image path for the VM. # +# The script has optional support for network-config. The user +# can specify a network-config file using $NETWORK_CONFIG variable. +# # Once the VM is running, the user can connect to it using their # provided key. The VM IP can be found in `/var/db/dhcpd_leases` # by searching for the HOST_NAME or MAC address (72:20:43:d4:38:62). # # Example: # $ SSH_USER=test HOST_NAME=vm1 DISK_IMG=Fedora-Cloud-Base-AmazonEC2-41-1.4.aarch64.raw \ -# SSH_PUB_KEY=id_rsa.pub ./contrib/scripts/start-with-cloud-init.sh +# SSH_PUB_KEY=id_rsa.pub NETWORK_CONFIG=network-config ./contrib/scripts/start-with-cloud-init.sh # # $ ssh -i id_rsa test@192.168.64.14 @@ -26,6 +29,7 @@ set -exu HOST_NAME=${HOST_NAME:-"vfkit-vm"} SSH_USER=${SSH_USER:-"test"} +NETWORK_CONFIG=${NETWORK_CONFIG:-} if [ ! -f "$SSH_PUB_KEY" ]; then echo "Error: '$SSH_PUB_KEY' does not exist" @@ -37,6 +41,11 @@ if [ ! -f "$DISK_IMG" ]; then exit 1 fi +if [ -n "$NETWORK_CONFIG" ] && [ ! -f "$NETWORK_CONFIG" ]; then + echo "Error: '$NETWORK_CONFIG' does not exist" + exit 1 +fi + PUBLIC_KEY=$(cat "$SSH_PUB_KEY") mkdir -p out @@ -61,9 +70,14 @@ instance-id: $HOST_NAME local-hostname: $HOST_NAME EOF +CLOUD_INIT_ARGS="out/user-data,out/meta-data" +if [ -n "$NETWORK_CONFIG" ]; then + CLOUD_INIT_ARGS="$CLOUD_INIT_ARGS,$NETWORK_CONFIG" +fi + ./out/vfkit --cpus 2 --memory 2048 \ --bootloader efi,variable-store=out/efistore.nvram,create \ - --cloud-init out/user-data,out/meta-data \ + --cloud-init "$CLOUD_INIT_ARGS" \ --device virtio-blk,path="$DISK_IMG" \ --device virtio-serial,logFilePath=out/cloud-init.log \ --device virtio-net,nat,mac=72:20:43:d4:38:62 \ From 9648e3bc5e7e9dcb421f5f7956866b9142f8af37 Mon Sep 17 00:00:00 2001 From: Gunjan Vyas Date: Wed, 7 May 2025 14:25:27 +0530 Subject: [PATCH 04/21] test: modify cloud-init testcase with network-config --- cmd/vfkit/main_test.go | 1 + test/assets/network-config | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 test/assets/network-config diff --git a/cmd/vfkit/main_test.go b/cmd/vfkit/main_test.go index fb9e9d17..4b4ee3b1 100644 --- a/cmd/vfkit/main_test.go +++ b/cmd/vfkit/main_test.go @@ -70,6 +70,7 @@ func TestGenerateCloudInitImage(t *testing.T) { iso, err := generateCloudInitImage([]string{ filepath.Join(assetsDir, "user-data"), filepath.Join(assetsDir, "meta-data"), + filepath.Join(assetsDir, "network-config"), }) require.NoError(t, err) diff --git a/test/assets/network-config b/test/assets/network-config new file mode 100644 index 00000000..c8daf8df --- /dev/null +++ b/test/assets/network-config @@ -0,0 +1,6 @@ +version: 2 +ethernets: + enp0s1: + dhcp4: false + addresses: + - 192.168.64.50/24 From 465e82cebbb22d16851fd996ebd94e0a3191b3b0 Mon Sep 17 00:00:00 2001 From: djalan <104938738+djalanxyz@users.noreply.github.com> Date: Wed, 28 May 2025 18:11:53 -1000 Subject: [PATCH 05/21] bump version of tcpproxy to github issue#39 --- go.mod | 2 +- go.sum | 4 ++-- pkg/vf/vsock.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index ed9a0a3a..da53eb71 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/containers/common v0.62.3 github.com/crc-org/crc/v2 v2.49.0 github.com/gin-gonic/gin v1.10.0 + github.com/inetaf/tcpproxy v0.0.0-20250222171855-c4b9df066048 github.com/kdomanski/iso9660 v0.4.0 github.com/pkg/term v1.1.0 github.com/prashantgupta24/mac-sleep-notifier v1.0.1 @@ -21,7 +22,6 @@ require ( golang.org/x/crypto v0.38.0 golang.org/x/mod v0.24.0 golang.org/x/sys v0.33.0 - inet.af/tcpproxy v0.0.0-20231102063150-2862066fc2a9 ) require ( diff --git a/go.sum b/go.sum index 23bf9bf5..9ad1ea92 100644 --- a/go.sum +++ b/go.sum @@ -61,6 +61,8 @@ github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inetaf/tcpproxy v0.0.0-20250222171855-c4b9df066048 h1:jaqViOFFlZtkAwqvwZN+id37fosQqR5l3Oki9Dk4hz8= +github.com/inetaf/tcpproxy v0.0.0-20250222171855-c4b9df066048/go.mod h1:Di7LXRyUcnvAcLicFhtM9/MlZl/TNgRSDHORM2c6CMI= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kdomanski/iso9660 v0.4.0 h1:BPKKdcINz3m0MdjIMwS0wx1nofsOjxOq8TOr45WGHFg= @@ -163,7 +165,5 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYs gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -inet.af/tcpproxy v0.0.0-20231102063150-2862066fc2a9 h1:zomTWJvjwLbKRgGameQtpK6DNFUbZ2oNJuWhgUkGp3M= -inet.af/tcpproxy v0.0.0-20231102063150-2862066fc2a9/go.mod h1:Tojt5kmHpDIR2jMojxzZK2w2ZR7OILODmUo2gaSwjrk= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/pkg/vf/vsock.go b/pkg/vf/vsock.go index 3d03934f..8ed9538e 100644 --- a/pkg/vf/vsock.go +++ b/pkg/vf/vsock.go @@ -8,7 +8,7 @@ import ( "net/url" "strconv" - "inet.af/tcpproxy" + "github.com/inetaf/tcpproxy" ) func ExposeVsock(vm *VirtualMachine, port uint32, vsockPath string, listen bool) (io.Closer, error) { From 7b3aaa37c59c81444b69d75f49370a1b481e47bb Mon Sep 17 00:00:00 2001 From: Walter Scott Date: Fri, 30 May 2025 07:05:32 -0500 Subject: [PATCH 06/21] test: fix timeout logic --- test/vm_helpers.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/vm_helpers.go b/test/vm_helpers.go index 15eb3c45..f36a8891 100644 --- a/test/vm_helpers.go +++ b/test/vm_helpers.go @@ -26,6 +26,8 @@ func retryIPFromMAC(errCh chan error, macAddress string) (string, error) { ip string ) + timeout := time.After(10 * time.Second) + for { select { case err := <-errCh: @@ -36,7 +38,7 @@ func retryIPFromMAC(errCh chan error, macAddress string) (string, error) { log.Infof("found IP address %s for MAC %s", ip, macAddress) return ip, nil } - case <-time.After(10 * time.Second): + case <-timeout: return "", fmt.Errorf("timeout getting IP from MAC: %w", err) } } @@ -47,6 +49,9 @@ func retrySSHDial(errCh chan error, scheme string, address string, sshConfig *ss sshClient *ssh.Client err error ) + + timeout := time.After(10 * time.Second) + for { select { case err := <-errCh: @@ -59,7 +64,7 @@ func retrySSHDial(errCh chan error, scheme string, address string, sshConfig *ss return sshClient, nil } log.Debugf("ssh failed: %v", err) - case <-time.After(10 * time.Second): + case <-timeout: return nil, fmt.Errorf("timeout waiting for SSH: %w", err) } } From a0e83dde4480dc12454ee4d921ef2a44088258bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 10:20:54 +0000 Subject: [PATCH 07/21] build(deps): bump github.com/gin-gonic/gin from 1.10.0 to 1.10.1 Bumps [github.com/gin-gonic/gin](https://github.com/gin-gonic/gin) from 1.10.0 to 1.10.1. - [Release notes](https://github.com/gin-gonic/gin/releases) - [Changelog](https://github.com/gin-gonic/gin/blob/master/CHANGELOG.md) - [Commits](https://github.com/gin-gonic/gin/compare/v1.10.0...v1.10.1) --- updated-dependencies: - dependency-name: github.com/gin-gonic/gin dependency-version: 1.10.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3e038c3f..d1a5193e 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/cavaliergopher/grab/v3 v3.0.1 github.com/containers/common v0.62.3 github.com/crc-org/crc/v2 v2.51.0 - github.com/gin-gonic/gin v1.10.0 + github.com/gin-gonic/gin v1.10.1 github.com/inetaf/tcpproxy v0.0.0-20250222171855-c4b9df066048 github.com/kdomanski/iso9660 v0.4.0 github.com/pkg/term v1.1.0 diff --git a/go.sum b/go.sum index 5a4227a8..803ad10b 100644 --- a/go.sum +++ b/go.sum @@ -38,8 +38,8 @@ github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uq github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= -github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= +github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= From 0c5600ee52ffb519f65e0d78e650573e48123b96 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Mon, 26 May 2025 17:02:53 +0200 Subject: [PATCH 08/21] README: Rework it a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clarify a few things, reorder some sections, … Signed-off-by: Christophe Fergeau --- README.md | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f1819ec6..72c670c0 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,22 @@ -vfkit - Simple command line tool to start VMs through the macOS Virtualization framework +vfkit - Command-line tool to start VMs on macOS ==== ### Introduction vfkit offers a command-line interface to start virtual machines using the [macOS Virtualization framework](https://developer.apple.com/documentation/virtualization). It also provides a `github.com/crc-org/vfkit/pkg/config` go package. -This package provides a native Go API to generate the vfkit command line. +This package implements a native Go API to generate the vfkit command line. +### Usage + +See https://github.com/crc-org/vfkit/blob/main/doc/usage.md + + +### Presentations + +`vfkit` has been presented at a few conferences: +- [Containers Plumbing 2023](https://crc.dev/blog/posts/2023-03-22-containers-plumbing/) +- [FOSDEM 2023](https://fosdem.org/2023/schedule/event/govfkit/) ### Installation @@ -20,18 +30,6 @@ brew install vfkit From the root direction of this repository, run `make`. -### Usage - -See https://github.com/crc-org/vfkit/blob/main/doc/usage.md - - -### Presentations - -`vfkit` has been presented at a few conferences: -- [Containers Plumbing 2023](https://crc.dev/blog/posts/2023-03-22-containers-plumbing/) -- [FOSDEM 2023](https://fosdem.org/2023/schedule/event/govfkit/) - - ### Background The work in this repository makes use of https://github.com/Code-Hex/vz which provides go bindings for macOS virtualization framework. From 124d0b98f8f6c1ef426ef249e42eabb4ad68b8f0 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Mon, 2 Jun 2025 18:03:15 +0200 Subject: [PATCH 09/21] doc: Move 'background' from README to usage.md These technical details will be easier to find at more relevant places in usage.md rather than at the end of README.md Signed-off-by: Christophe Fergeau --- README.md | 23 ----------------------- doc/usage.md | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 72c670c0..2510b1c0 100644 --- a/README.md +++ b/README.md @@ -29,26 +29,3 @@ brew install vfkit ### Building From the root direction of this repository, run `make`. - -### Background - -The work in this repository makes use of https://github.com/Code-Hex/vz which provides go bindings for macOS virtualization framework. -The lifetime of virtual machines created using the virtualization framework is tied to the filetime of the process where they were created. -When using `Code-Hex/vz`, this means the virtual machine will be terminated at the end of the go process using these bindings. -Spawning a `vfkit` process gives more flexibility and more control over the lifetime of the virtual machine. - - -The kernel must be uncompressed before use as no bootloader is used, as -documented in https://www.kernel.org/doc/Documentation/arm64/booting.txt - -``` -3. Decompress the kernel image ------------------------------- - -Requirement: OPTIONAL - -The AArch64 kernel does not currently provide a decompressor and therefore -requires decompression (gzip etc.) to be performed by the boot loader if a -compressed Image target (e.g. Image.gz) is used. For bootloaders that do not -implement this requirement, the uncompressed Image target is available instead. -``` diff --git a/doc/usage.md b/doc/usage.md index 9c7e9974..bd8468a3 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -1,7 +1,7 @@ # vfkit Command Line The `vfkit` executable can be used to create a virtual machine (VM) using macOS virtualization framework. -The virtual machine will be terminated as soon as the `vfkit` process exits. +The virtual machine will be started when `vfkit` starts and will be terminated as soon as the `vfkit` process exits. Its configuration can be specified through command line options. Specifying VM bootloader configuration is mandatory. @@ -55,6 +55,21 @@ A bootloader is required to tell vfkit _how_ it should start the guest OS. `--bootloader linux` replaces the legacy `--kernel`, `--kernel-cmdline` and `--initrd` options. It allows to specify which kernel and initrd should be used when starting the VM. +On Apple Silicon hardware (M1 CPUs and newer), when using `--bootloader linux`, the kernel must be uncompressed before use as documented in https://www.kernel.org/doc/Documentation/arm64/booting.txt. `vfkit` will exit with an error if it detects a compressed kernel when running on Apple silicon. There are no such requirements when using `--bootloader efi`. + +Excerpt from the kernel’s `booting.txt`: +``` +3. Decompress the kernel image +------------------------------ + +Requirement: OPTIONAL + +The AArch64 kernel does not currently provide a decompressor and therefore +requires decompression (gzip etc.) to be performed by the boot loader if a +compressed Image target (e.g. Image.gz) is used. For bootloaders that do not +implement this requirement, the uncompressed Image target is available instead. +``` + #### Arguments - `kernel`: path to the kernel to use to start the virtual machine. The kernel *must* be uncompressed or the VM will hang when trying to start. See [the kernel documentation](https://www.kernel.org/doc/Documentation/arm64/booting.txt) for more details. From 88a6608aec144c5b930c0307ae8a3fac90135702 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Mon, 26 May 2025 17:03:29 +0200 Subject: [PATCH 10/21] README: Add "adopters" section This lists the higher level projects which are using vfkit. This fixes https://github.com/crc-org/vfkit/issues/302 Signed-off-by: Christophe Fergeau --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 2510b1c0..b523749b 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,13 @@ See https://github.com/crc-org/vfkit/blob/main/doc/usage.md - [Containers Plumbing 2023](https://crc.dev/blog/posts/2023-03-22-containers-plumbing/) - [FOSDEM 2023](https://fosdem.org/2023/schedule/event/govfkit/) +### Adopters + +- [minikube](https://minikube.sigs.k8s.io/) 1.35.0 and newer - minikube quickly sets up a local Kubernetes cluster +- [podman](https://podman.io/) 5.0 and newer - podman is a free software CLI tool to manage containers, pods and images +- [crc](https://crc.dev/) - crc sets up local OpenShift or MicroShift clusters for development and testing purposes +- [ovm](https://github.com/oomol-lab/ovm) - ovm is used by Oomol Studio to run linux containers on macOS + ### Installation vfkit is available in brew: From 10917c036d6a000fe4890c01b43dfe28f3d1cec3 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Mon, 26 May 2025 17:09:37 +0200 Subject: [PATCH 11/21] usage: Mention gvisor-tap-vsock and vmnet-helper This fixes https://github.com/crc-org/vfkit/issues/291 Signed-off-by: Christophe Fergeau --- doc/usage.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/usage.md b/doc/usage.md index bd8468a3..363240d8 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -288,6 +288,8 @@ This allows to connect to the export of the remote NBD server: The `--device virtio-net` option adds a network interface to the virtual machine. If it gets its IP address through DHCP, its IP can be found in `/var/db/dhcpd_leases` on the host. +vfkit only supports NAT networking on its own. However, it integrates with [gvisor-tap-vsock](https://github.com/containers/gvisor-tap-vsock) for a user-mode networking stack, and [vmnet-helper](https://github.com/nirs/vmnet-helper) for shared/bridged/host networking through vmnet. + #### Arguments - `mac`: optional argument to specify the MAC address of the VM. If it's omitted, a random MAC address will be used. - `fd`: file descriptor to attach to the guest network interface. The file descriptor must be a connected datagram socket. See [VZFileHandleNetworkDeviceAttachment](https://developer.apple.com/documentation/virtualization/vzfilehandlenetworkdeviceattachment?language=objc) for more details. From 170b72937ed6783bfb1b80a2c32ac4bcf8cdd0cd Mon Sep 17 00:00:00 2001 From: Gunjan Vyas Date: Mon, 2 Jun 2025 22:19:49 +0530 Subject: [PATCH 12/21] config: reject qcow2 images in VirtioBlk validation Added validation logic to `VirtioBlk` to detect and reject qcow2 image files based on their magic header ("QFI\xfb"). --- pkg/config/virtio.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/pkg/config/virtio.go b/pkg/config/virtio.go index f388dfbf..35728c73 100644 --- a/pkg/config/virtio.go +++ b/pkg/config/virtio.go @@ -1,6 +1,7 @@ package config import ( + "bytes" "fmt" "math" "net" @@ -25,6 +26,7 @@ const ( // Default VirtioGPU Resolution defaultVirtioGPUResolutionWidth = 800 defaultVirtioGPUResolutionHeight = 600 + qcow2Header = "QFI\xfb" ) // VirtioInput configures an input device, such as a keyboard or pointing device @@ -571,7 +573,10 @@ func (dev *VirtioBlk) FromOptions(options []option) error { } } - return dev.DiskStorageConfig.FromOptions(unhandledOpts) + if err := dev.DiskStorageConfig.FromOptions(unhandledOpts); err != nil { + return err + } + return dev.validate() } func (dev *VirtioBlk) ToCmdLine() ([]string, error) { @@ -588,6 +593,24 @@ func (dev *VirtioBlk) ToCmdLine() ([]string, error) { return cmdLine, nil } +func (dev *VirtioBlk) validate() error { + imgPath := dev.ImagePath + file, err := os.Open(imgPath) + if err != nil { + return fmt.Errorf("failed to open file %s: %v", imgPath, err) + } + defer file.Close() + header := make([]byte, 4) + _, err = file.Read(header) + if err != nil { + return fmt.Errorf("failed to read the header of file %s: %v", imgPath, err) + } + if bytes.Equal(header, []byte(qcow2Header)) { + return fmt.Errorf("vfkit does not support qcow2 image format") + } + return nil +} + // VirtioVsockNew creates a new virtio-vsock device for 2-way communication // between the host and the virtual machine. The communication will happen on // vsock port, and on the host it will use the unix socket at socketURL. From d246f4c241909eae92f046125d14d6f4057f537b Mon Sep 17 00:00:00 2001 From: Gunjan Vyas Date: Mon, 2 Jun 2025 22:21:09 +0530 Subject: [PATCH 13/21] CI: Install qemu-utils for block device validation tests Adds qemu-utils (for qemu-img) to the CI environment to support new tests that validate block devices and reject unsupported qemu image formats. --- .github/workflows/compile.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 624f80e6..086b722f 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -43,6 +43,15 @@ jobs: go-version-file: go.mod - name: Build run: make + + - name: Install qemu-img + run: | + brew update + brew install qemu + + - name: Verify qemu-img is installed + run: qemu-img --version + - name: Test if: matrix.os != 'macOS-14' run: make test From f0dd1e4019b3a5a5a7f540c77172ca215d40291d Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Tue, 3 Jun 2025 14:35:43 +0200 Subject: [PATCH 14/21] doc: Add link to script starting vfkit with helper-vmnet Signed-off-by: Christophe Fergeau --- doc/usage.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/usage.md b/doc/usage.md index 363240d8..52471866 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -311,6 +311,8 @@ This adds a virtio-net device to the VM, and redirects all the network traffic o ``` This is useful in combination with usermode networking stacks such as [gvisor-tap-vsock](https://github.com/containers/gvisor-tap-vsock). +See [this shell script](https://github.com/nirs/vmnet-helper/blob/main/examples/vfkit.sh) for an example of networking using `vmnet-helper`. + ### Serial Port From ef0bb007a1c739f66c68fd9516ce5f0b957e18e8 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Tue, 3 Jun 2025 14:21:18 +0200 Subject: [PATCH 15/21] scripts: Add script to start a VM with gvproxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s meant as an example of how to use vfkit with usermode networking. Signed-off-by: Christophe Fergeau --- contrib/scripts/start-gvproxy.sh | 38 ++++++++++++++++++++++++++++++++ doc/usage.md | 1 + 2 files changed, 39 insertions(+) create mode 100755 contrib/scripts/start-gvproxy.sh diff --git a/contrib/scripts/start-gvproxy.sh b/contrib/scripts/start-gvproxy.sh new file mode 100755 index 00000000..70706c31 --- /dev/null +++ b/contrib/scripts/start-gvproxy.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +# SPDX-FileCopyrightText: The vfkit authors +# SPDX-License-Identifier: Apache-2.0 +# +# This script can be used to start a raw disk image with vfkit using gvproxy +# for usermode networking. +# The mac address must be 5a:94:ef:e4:0c:ee as this is the address expected by gvproxy. +# +# After the VM is running, its ssh port is reachable on port 2223 on localhost (127.0.0.1). +# +# If the path to `--listen-vfkit` is too long (more than ~100 characters), then +# gvproxy/vfkit will fail to start as a unix socket filename must be less than +# that. +# +# This script creates an overlay for the disk image, the disk image is not modified. +# +set -exuo pipefail + +: "${GVPROXY:=gvproxy}" +: "${VFKIT:=./out/vfkit}" + +DISK_IMAGE="${1?Usage: $0 diskimage}" +VM_NAME="$(basename ${DISK_IMAGE})" + +${GVPROXY} -mtu 1500 -ssh-port 2223 -listen-vfkit unixgram://$(pwd)/${VM_NAME}.sock -log-file ${VM_NAME}.gvproxy.log --pid-file ${VM_NAME}.gvproxy.pid & + +TO_REMOVE="${VM_NAME}.sock ${VM_NAME}.gvproxy.pid ${VM_NAME}.overlay.img ${VM_NAME}.efistore.nvram" +trap 'if [[ -f "${VM_NAME}.gvproxy.pid" ]]; then kill $(cat ${VM_NAME}.gvproxy.pid); fi; rm -f ${TO_REMOVE}' EXIT + +cp -c ${DISK_IMAGE} "${VM_NAME}".overlay.img + +${VFKIT} --cpus 2 --memory 2048 \ + --bootloader efi,variable-store=${VM_NAME}.efistore.nvram,create \ + --device virtio-blk,path=${VM_NAME}.overlay.img \ + --device virtio-serial,logFilePath=${VM_NAME}.log \ + --device virtio-net,unixSocketPath=$(pwd)/${VM_NAME}.sock,mac=5a:94:ef:e4:0c:ee \ + --device virtio-rng diff --git a/doc/usage.md b/doc/usage.md index 52471866..8ffbf77d 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -312,6 +312,7 @@ This adds a virtio-net device to the VM, and redirects all the network traffic o This is useful in combination with usermode networking stacks such as [gvisor-tap-vsock](https://github.com/containers/gvisor-tap-vsock). See [this shell script](https://github.com/nirs/vmnet-helper/blob/main/examples/vfkit.sh) for an example of networking using `vmnet-helper`. +See [this shell script](https://github.com/crc-org/vfkit/blob/main/contrib/scripts/start-gvproxy.sh) for an example of networking using `gvproxy`. ### Serial Port From 18261d213dc99e06322cbfa8bf867d624156144c Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Tue, 3 Jun 2025 17:47:02 +0200 Subject: [PATCH 16/21] OWNERS: Add nirs to reviewers Signed-off-by: Christophe Fergeau --- OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/OWNERS b/OWNERS index 1882ebd1..5bcbf550 100644 --- a/OWNERS +++ b/OWNERS @@ -8,4 +8,5 @@ reviewers: - baude - cfergeau - lstocchi + - nirs - praveenkumar From 5437f952faf1a583de1a081490600cef15c39771 Mon Sep 17 00:00:00 2001 From: Gunjan Vyas Date: Mon, 2 Jun 2025 22:22:05 +0530 Subject: [PATCH 17/21] tests: add and update VirtioBlk tests Added unit tests for the new `VirtioBlk.validate` method to ensure qcow2 images are correctly rejected based on their magic header. Updated existing VirtioBlk-related tests to create temporary image files on disk, as the new validation logic checks for file existence and reads the header. This ensures the tests pass with the added file-based validation in place. --- pkg/config/config_test.go | 26 ++ pkg/config/virtio_test.go | 496 +++++++++++++++++++------------------- 2 files changed, 280 insertions(+), 242 deletions(-) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 4b5763c1..d863e338 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -1,6 +1,9 @@ package config import ( + "os" + "os/exec" + "path/filepath" "testing" "github.com/stretchr/testify/assert" @@ -44,3 +47,26 @@ func TestNetworkBlockDevice_NoDevice(t *testing.T) { nbdItem := vm.NetworkBlockDevice("nbd2") require.Nil(t, nbdItem) } + +func TestVirtualMachine_ValidateBlockDevices(t *testing.T) { + vm := &VirtualMachine{} + + tmpDir := t.TempDir() + imagePath := filepath.Join(tmpDir, "disk.qcow2") + size := "1G" + + cmd := exec.Command("qemu-img", "create", "-f", "qcow2", imagePath, size) + err := cmd.Run() + + require.NoError(t, err) + defer os.Remove(imagePath) + + dev, err := VirtioBlkNew(imagePath) + require.NoError(t, err) + vm.Devices = append(vm.Devices, dev) + + err = dev.validate() + require.Error(t, err) + + require.ErrorContains(t, err, "vfkit does not support qcow2 image format") +} diff --git a/pkg/config/virtio_test.go b/pkg/config/virtio_test.go index b6305581..caca6128 100644 --- a/pkg/config/virtio_test.go +++ b/pkg/config/virtio_test.go @@ -1,6 +1,9 @@ package config import ( + "fmt" + "os" + "path/filepath" "testing" "time" @@ -16,247 +19,12 @@ type virtioDevTest struct { errorMsg string } -var virtioDevTests = map[string]virtioDevTest{ - "NewVirtioBlk": { - newDev: func() (VirtioDevice, error) { return VirtioBlkNew("/foo/bar") }, - expectedDev: &VirtioBlk{ - DiskStorageConfig: DiskStorageConfig{ - StorageConfig: StorageConfig{ - DevName: "virtio-blk", - }, - ImagePath: "/foo/bar", - }, - DeviceIdentifier: "", - }, - expectedCmdLine: []string{"--device", "virtio-blk,path=/foo/bar"}, - }, - "NewVirtioBlkWithDevId": { - newDev: func() (VirtioDevice, error) { - dev, err := VirtioBlkNew("/foo/bar") - if err != nil { - return nil, err - } - dev.SetDeviceIdentifier("test") - return dev, nil - }, - expectedDev: &VirtioBlk{ - DiskStorageConfig: DiskStorageConfig{ - StorageConfig: StorageConfig{ - DevName: "virtio-blk", - }, - ImagePath: "/foo/bar", - }, - DeviceIdentifier: "test", - }, - expectedCmdLine: []string{"--device", "virtio-blk,path=/foo/bar,deviceId=test"}, - alternateCmdLine: []string{"--device", "virtio-blk,deviceId=test,path=/foo/bar"}, - }, - "NewNVMe": { - newDev: func() (VirtioDevice, error) { return NVMExpressControllerNew("/foo/bar") }, - expectedDev: &NVMExpressController{ - DiskStorageConfig: DiskStorageConfig{ - StorageConfig: StorageConfig{ - DevName: "nvme", - }, - ImagePath: "/foo/bar", - }, - }, - expectedCmdLine: []string{"--device", "nvme,path=/foo/bar"}, - }, - "NewVirtioFs": { - newDev: func() (VirtioDevice, error) { return VirtioFsNew("/foo/bar", "") }, - expectedDev: &VirtioFs{ - SharedDir: "/foo/bar", - }, - expectedCmdLine: []string{"--device", "virtio-fs,sharedDir=/foo/bar"}, - }, - "NewVirtioFsWithTag": { - newDev: func() (VirtioDevice, error) { return VirtioFsNew("/foo/bar", "myTag") }, - expectedDev: &VirtioFs{ - SharedDir: "/foo/bar", - DirectorySharingConfig: DirectorySharingConfig{ - MountTag: "myTag", - }, - }, - expectedCmdLine: []string{"--device", "virtio-fs,sharedDir=/foo/bar,mountTag=myTag"}, - alternateCmdLine: []string{"--device", "virtio-fs,mountTag=myTag,sharedDir=/foo/bar"}, - }, - "NewRosettaShare": { - newDev: func() (VirtioDevice, error) { return RosettaShareNew("myTag") }, - expectedDev: &RosettaShare{ - DirectorySharingConfig: DirectorySharingConfig{ - MountTag: "myTag", - }, - }, - expectedCmdLine: []string{"--device", "rosetta,mountTag=myTag"}, - }, - "NewVirtioVsock": { - newDev: func() (VirtioDevice, error) { return VirtioVsockNew(1234, "/foo/bar.unix", false) }, - expectedDev: &VirtioVsock{ - Port: 1234, - SocketURL: "/foo/bar.unix", - }, - expectedCmdLine: []string{"--device", "virtio-vsock,port=1234,socketURL=/foo/bar.unix,connect"}, - alternateCmdLine: []string{"--device", "virtio-vsock,socketURL=/foo/bar.unix,connect,port=1234"}, - }, - "NewVirtioVsockWithListen": { - newDev: func() (VirtioDevice, error) { return VirtioVsockNew(1234, "/foo/bar.unix", true) }, - expectedDev: &VirtioVsock{ - Port: 1234, - SocketURL: "/foo/bar.unix", - Listen: true, - }, - expectedCmdLine: []string{"--device", "virtio-vsock,port=1234,socketURL=/foo/bar.unix,listen"}, - alternateCmdLine: []string{"--device", "virtio-vsock,socketURL=/foo/bar.unix,listen,port=1234"}, - }, - "NewVirtioRng": { - newDev: VirtioRngNew, - expectedDev: &VirtioRng{}, - expectedCmdLine: []string{"--device", "virtio-rng"}, - }, - "NewVirtioSerial": { - newDev: func() (VirtioDevice, error) { return VirtioSerialNew("/foo/bar.log") }, - expectedDev: &VirtioSerial{ - LogFile: "/foo/bar.log", - }, - expectedCmdLine: []string{"--device", "virtio-serial,logFilePath=/foo/bar.log"}, - }, - "NewVirtioSerialStdio": { - newDev: VirtioSerialNewStdio, - expectedDev: &VirtioSerial{ - UsesStdio: true, - }, - expectedCmdLine: []string{"--device", "virtio-serial,stdio"}, - }, - "NewVirtioSerialPty": { - newDev: VirtioSerialNewPty, - expectedDev: &VirtioSerial{ - UsesPty: true, - }, - expectedCmdLine: []string{"--device", "virtio-serial,pty"}, - }, - "NewVirtioNet": { - newDev: func() (VirtioDevice, error) { return VirtioNetNew("") }, - expectedDev: &VirtioNet{ - Nat: true, - }, - expectedCmdLine: []string{"--device", "virtio-net,nat"}, - }, - "NewVirtioNetWithPath": { - newDev: func() (VirtioDevice, error) { - dev, err := VirtioNetNew("") - if err != nil { - return nil, err - } - dev.SetUnixSocketPath("/tmp/unix.sock") - return dev, nil - }, - expectedDev: &VirtioNet{ - Nat: false, - UnixSocketPath: "/tmp/unix.sock", - }, - expectedCmdLine: []string{"--device", "virtio-net,unixSocketPath=/tmp/unix.sock"}, - }, - "NewVirtioNetWithMacAddress": { - newDev: func() (VirtioDevice, error) { return VirtioNetNew("00:11:22:33:44:55") }, - expectedDev: &VirtioNet{ - Nat: true, - MacAddress: []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}, - }, - expectedCmdLine: []string{"--device", "virtio-net,nat,mac=00:11:22:33:44:55"}, - alternateCmdLine: []string{"--device", "virtio-net,mac=00:11:22:33:44:55,nat"}, - }, - "NewUSBMassStorage": { - newDev: func() (VirtioDevice, error) { return USBMassStorageNew("/foo/bar") }, - expectedDev: &USBMassStorage{ - DiskStorageConfig: DiskStorageConfig{ - StorageConfig: StorageConfig{ - DevName: "usb-mass-storage", - }, - ImagePath: "/foo/bar", - }, - }, - expectedCmdLine: []string{"--device", "usb-mass-storage,path=/foo/bar"}, - }, - "NewUSBMassStorageReadOnly": { - newDev: func() (VirtioDevice, error) { - dev, err := USBMassStorageNew("/foo/bar") - if err != nil { - return nil, err - } - dev.SetReadOnly(true) - return dev, err - }, - expectedDev: &USBMassStorage{ - DiskStorageConfig: DiskStorageConfig{ - StorageConfig: StorageConfig{ - DevName: "usb-mass-storage", - ReadOnly: true, - }, - ImagePath: "/foo/bar", - }, - }, - expectedCmdLine: []string{"--device", "usb-mass-storage,path=/foo/bar,readonly"}, - }, - "NewVirtioInputWithPointingDevice": { - newDev: func() (VirtioDevice, error) { return VirtioInputNew("pointing") }, - expectedDev: &VirtioInput{ - InputType: "pointing", - }, - expectedCmdLine: []string{"--device", "virtio-input,pointing"}, - }, - "NewVirtioInputWithKeyboardDevice": { - newDev: func() (VirtioDevice, error) { return VirtioInputNew("keyboard") }, - expectedDev: &VirtioInput{ - InputType: "keyboard", - }, - expectedCmdLine: []string{"--device", "virtio-input,keyboard"}, - }, - "NewVirtioGPUDevice": { - newDev: VirtioGPUNew, - expectedDev: &VirtioGPU{ - false, - VirtioGPUResolution{Width: 800, Height: 600}, - }, - expectedCmdLine: []string{"--device", "virtio-gpu,width=800,height=600"}, - }, - "NewVirtioGPUDeviceWithDimensions": { - newDev: func() (VirtioDevice, error) { - dev, err := VirtioGPUNew() - if err != nil { - return nil, err - } - dev.(*VirtioGPU).VirtioGPUResolution = VirtioGPUResolution{Width: 1920, Height: 1080} - return dev, nil - }, - expectedDev: &VirtioGPU{ - false, - VirtioGPUResolution{Width: 1920, Height: 1080}, - }, - expectedCmdLine: []string{"--device", "virtio-gpu,width=1920,height=1080"}, - }, - "NetworkBlockDeviceNew": { - newDev: func() (VirtioDevice, error) { - return NetworkBlockDeviceNew("nbd://1.1.1.1:10000", 1000, SynchronizationNoneMode) - }, - expectedDev: &NetworkBlockDevice{ - NetworkBlockStorageConfig: NetworkBlockStorageConfig{ - StorageConfig: StorageConfig{ - DevName: "nbd", - }, - URI: "nbd://1.1.1.1:10000", - }, - DeviceIdentifier: "", - Timeout: time.Duration(1000 * time.Millisecond), - SynchronizationMode: SynchronizationNoneMode, - }, - expectedCmdLine: []string{"--device", "nbd,uri=nbd://1.1.1.1:10000,timeout=1000,sync=none"}, - }, - "NewVirtioBalloon": { - newDev: VirtioBalloonNew, - expectedDev: &VirtioBalloon{}, - expectedCmdLine: []string{"--device", "virtio-balloon"}, - }, +func getTestVirtioBlkDevice(testImagePath string) (*VirtioBlk, error) { + err := os.WriteFile(testImagePath, []byte{'0', '0', '0', '0'}, 0600) + if err != nil { + return nil, fmt.Errorf("failed to write test image: %v", err) + } + return VirtioBlkNew(testImagePath) } func testVirtioDev(t *testing.T, test *virtioDevTest) { @@ -296,6 +64,251 @@ func testErrorVirtioDev(t *testing.T, test *virtioDevTest) { } func TestVirtioDevices(t *testing.T) { + testImagePath := filepath.Join(t.TempDir(), "test.img") + var virtioDevTests = map[string]virtioDevTest{ + "NewVirtioBlk": { + newDev: func() (VirtioDevice, error) { + return getTestVirtioBlkDevice(testImagePath) + }, + expectedDev: &VirtioBlk{ + DiskStorageConfig: DiskStorageConfig{ + StorageConfig: StorageConfig{ + DevName: "virtio-blk", + }, + ImagePath: testImagePath, + }, + DeviceIdentifier: "", + }, + expectedCmdLine: []string{"--device", fmt.Sprintf("virtio-blk,path=%s", testImagePath)}, + }, + "NewVirtioBlkWithDevId": { + newDev: func() (VirtioDevice, error) { + dev, err := getTestVirtioBlkDevice(testImagePath) + if err != nil { + return nil, err + } + dev.SetDeviceIdentifier("test") + return dev, nil + }, + expectedDev: &VirtioBlk{ + DiskStorageConfig: DiskStorageConfig{ + StorageConfig: StorageConfig{ + DevName: "virtio-blk", + }, + ImagePath: testImagePath, + }, + DeviceIdentifier: "test", + }, + expectedCmdLine: []string{"--device", fmt.Sprintf("virtio-blk,path=%s,deviceId=test", testImagePath)}, + alternateCmdLine: []string{"--device", fmt.Sprintf("virtio-blk,deviceId=test,path=%s", testImagePath)}, + }, + "NewNVMe": { + newDev: func() (VirtioDevice, error) { return NVMExpressControllerNew("/foo/bar") }, + expectedDev: &NVMExpressController{ + DiskStorageConfig: DiskStorageConfig{ + StorageConfig: StorageConfig{ + DevName: "nvme", + }, + ImagePath: "/foo/bar", + }, + }, + expectedCmdLine: []string{"--device", "nvme,path=/foo/bar"}, + }, + "NewVirtioFs": { + newDev: func() (VirtioDevice, error) { return VirtioFsNew("/foo/bar", "") }, + expectedDev: &VirtioFs{ + SharedDir: "/foo/bar", + }, + expectedCmdLine: []string{"--device", "virtio-fs,sharedDir=/foo/bar"}, + }, + "NewVirtioFsWithTag": { + newDev: func() (VirtioDevice, error) { return VirtioFsNew("/foo/bar", "myTag") }, + expectedDev: &VirtioFs{ + SharedDir: "/foo/bar", + DirectorySharingConfig: DirectorySharingConfig{ + MountTag: "myTag", + }, + }, + expectedCmdLine: []string{"--device", "virtio-fs,sharedDir=/foo/bar,mountTag=myTag"}, + alternateCmdLine: []string{"--device", "virtio-fs,mountTag=myTag,sharedDir=/foo/bar"}, + }, + "NewRosettaShare": { + newDev: func() (VirtioDevice, error) { return RosettaShareNew("myTag") }, + expectedDev: &RosettaShare{ + DirectorySharingConfig: DirectorySharingConfig{ + MountTag: "myTag", + }, + }, + expectedCmdLine: []string{"--device", "rosetta,mountTag=myTag"}, + }, + "NewVirtioVsock": { + newDev: func() (VirtioDevice, error) { return VirtioVsockNew(1234, "/foo/bar.unix", false) }, + expectedDev: &VirtioVsock{ + Port: 1234, + SocketURL: "/foo/bar.unix", + }, + expectedCmdLine: []string{"--device", "virtio-vsock,port=1234,socketURL=/foo/bar.unix,connect"}, + alternateCmdLine: []string{"--device", "virtio-vsock,socketURL=/foo/bar.unix,connect,port=1234"}, + }, + "NewVirtioVsockWithListen": { + newDev: func() (VirtioDevice, error) { return VirtioVsockNew(1234, "/foo/bar.unix", true) }, + expectedDev: &VirtioVsock{ + Port: 1234, + SocketURL: "/foo/bar.unix", + Listen: true, + }, + expectedCmdLine: []string{"--device", "virtio-vsock,port=1234,socketURL=/foo/bar.unix,listen"}, + alternateCmdLine: []string{"--device", "virtio-vsock,socketURL=/foo/bar.unix,listen,port=1234"}, + }, + "NewVirtioRng": { + newDev: VirtioRngNew, + expectedDev: &VirtioRng{}, + expectedCmdLine: []string{"--device", "virtio-rng"}, + }, + "NewVirtioSerial": { + newDev: func() (VirtioDevice, error) { return VirtioSerialNew("/foo/bar.log") }, + expectedDev: &VirtioSerial{ + LogFile: "/foo/bar.log", + }, + expectedCmdLine: []string{"--device", "virtio-serial,logFilePath=/foo/bar.log"}, + }, + "NewVirtioSerialStdio": { + newDev: VirtioSerialNewStdio, + expectedDev: &VirtioSerial{ + UsesStdio: true, + }, + expectedCmdLine: []string{"--device", "virtio-serial,stdio"}, + }, + "NewVirtioSerialPty": { + newDev: VirtioSerialNewPty, + expectedDev: &VirtioSerial{ + UsesPty: true, + }, + expectedCmdLine: []string{"--device", "virtio-serial,pty"}, + }, + "NewVirtioNet": { + newDev: func() (VirtioDevice, error) { return VirtioNetNew("") }, + expectedDev: &VirtioNet{ + Nat: true, + }, + expectedCmdLine: []string{"--device", "virtio-net,nat"}, + }, + "NewVirtioNetWithPath": { + newDev: func() (VirtioDevice, error) { + dev, err := VirtioNetNew("") + if err != nil { + return nil, err + } + dev.SetUnixSocketPath("/tmp/unix.sock") + return dev, nil + }, + expectedDev: &VirtioNet{ + Nat: false, + UnixSocketPath: "/tmp/unix.sock", + }, + expectedCmdLine: []string{"--device", "virtio-net,unixSocketPath=/tmp/unix.sock"}, + }, + "NewVirtioNetWithMacAddress": { + newDev: func() (VirtioDevice, error) { return VirtioNetNew("00:11:22:33:44:55") }, + expectedDev: &VirtioNet{ + Nat: true, + MacAddress: []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}, + }, + expectedCmdLine: []string{"--device", "virtio-net,nat,mac=00:11:22:33:44:55"}, + alternateCmdLine: []string{"--device", "virtio-net,mac=00:11:22:33:44:55,nat"}, + }, + "NewUSBMassStorage": { + newDev: func() (VirtioDevice, error) { return USBMassStorageNew("/foo/bar") }, + expectedDev: &USBMassStorage{ + DiskStorageConfig: DiskStorageConfig{ + StorageConfig: StorageConfig{ + DevName: "usb-mass-storage", + }, + ImagePath: "/foo/bar", + }, + }, + expectedCmdLine: []string{"--device", "usb-mass-storage,path=/foo/bar"}, + }, + "NewUSBMassStorageReadOnly": { + newDev: func() (VirtioDevice, error) { + dev, err := USBMassStorageNew("/foo/bar") + if err != nil { + return nil, err + } + dev.SetReadOnly(true) + return dev, err + }, + expectedDev: &USBMassStorage{ + DiskStorageConfig: DiskStorageConfig{ + StorageConfig: StorageConfig{ + DevName: "usb-mass-storage", + ReadOnly: true, + }, + ImagePath: "/foo/bar", + }, + }, + expectedCmdLine: []string{"--device", "usb-mass-storage,path=/foo/bar,readonly"}, + }, + "NewVirtioInputWithPointingDevice": { + newDev: func() (VirtioDevice, error) { return VirtioInputNew("pointing") }, + expectedDev: &VirtioInput{ + InputType: "pointing", + }, + expectedCmdLine: []string{"--device", "virtio-input,pointing"}, + }, + "NewVirtioInputWithKeyboardDevice": { + newDev: func() (VirtioDevice, error) { return VirtioInputNew("keyboard") }, + expectedDev: &VirtioInput{ + InputType: "keyboard", + }, + expectedCmdLine: []string{"--device", "virtio-input,keyboard"}, + }, + "NewVirtioGPUDevice": { + newDev: VirtioGPUNew, + expectedDev: &VirtioGPU{ + false, + VirtioGPUResolution{Width: 800, Height: 600}, + }, + expectedCmdLine: []string{"--device", "virtio-gpu,width=800,height=600"}, + }, + "NewVirtioGPUDeviceWithDimensions": { + newDev: func() (VirtioDevice, error) { + dev, err := VirtioGPUNew() + if err != nil { + return nil, err + } + dev.(*VirtioGPU).VirtioGPUResolution = VirtioGPUResolution{Width: 1920, Height: 1080} + return dev, nil + }, + expectedDev: &VirtioGPU{ + false, + VirtioGPUResolution{Width: 1920, Height: 1080}, + }, + expectedCmdLine: []string{"--device", "virtio-gpu,width=1920,height=1080"}, + }, + "NetworkBlockDeviceNew": { + newDev: func() (VirtioDevice, error) { + return NetworkBlockDeviceNew("nbd://1.1.1.1:10000", 1000, SynchronizationNoneMode) + }, + expectedDev: &NetworkBlockDevice{ + NetworkBlockStorageConfig: NetworkBlockStorageConfig{ + StorageConfig: StorageConfig{ + DevName: "nbd", + }, + URI: "nbd://1.1.1.1:10000", + }, + DeviceIdentifier: "", + Timeout: time.Duration(1000 * time.Millisecond), + SynchronizationMode: SynchronizationNoneMode, + }, + expectedCmdLine: []string{"--device", "nbd,uri=nbd://1.1.1.1:10000,timeout=1000,sync=none"}, + }, + "NewVirtioBalloon": { + newDev: VirtioBalloonNew, + expectedDev: &VirtioBalloon{}, + expectedCmdLine: []string{"--device", "virtio-balloon"}, + }, + } t.Run("virtio-devices", func(t *testing.T) { for name := range virtioDevTests { t.Run(name, func(t *testing.T) { @@ -307,6 +320,5 @@ func TestVirtioDevices(t *testing.T) { } }) } - }) } From df5452264fcd4f6f5771576045f3d5af5240bd82 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 12:34:49 +0000 Subject: [PATCH 18/21] build(deps): bump golang.org/x/crypto from 0.38.0 to 0.39.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.38.0 to 0.39.0. - [Commits](https://github.com/golang/crypto/compare/v0.38.0...v0.39.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.39.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index d1a5193e..6163e951 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,8 @@ require ( github.com/spf13/pflag v1.0.6 github.com/stretchr/testify v1.10.0 github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 - golang.org/x/crypto v0.38.0 - golang.org/x/mod v0.24.0 + golang.org/x/crypto v0.39.0 + golang.org/x/mod v0.25.0 golang.org/x/sys v0.33.0 ) @@ -70,7 +70,7 @@ require ( golang.org/x/arch v0.8.0 // indirect golang.org/x/net v0.40.0 // indirect golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.25.0 // indirect + golang.org/x/text v0.26.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 803ad10b..185dd1ac 100644 --- a/go.sum +++ b/go.sum @@ -138,10 +138,10 @@ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -154,8 +154,8 @@ golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From 50bc6cc5076f9e745a33cc5dcc63f480eccd7410 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 13:18:49 +0000 Subject: [PATCH 19/21] build(deps): bump github.com/Code-Hex/vz/v3 from 3.6.0 to 3.7.0 Bumps [github.com/Code-Hex/vz/v3](https://github.com/Code-Hex/vz) from 3.6.0 to 3.7.0. - [Release notes](https://github.com/Code-Hex/vz/releases) - [Commits](https://github.com/Code-Hex/vz/compare/v3.6.0...v3.7.0) --- updated-dependencies: - dependency-name: github.com/Code-Hex/vz/v3 dependency-version: 3.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d1a5193e..e6796465 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.0 toolchain go1.23.6 require ( - github.com/Code-Hex/vz/v3 v3.6.0 + github.com/Code-Hex/vz/v3 v3.7.0 github.com/cavaliergopher/grab/v3 v3.0.1 github.com/containers/common v0.62.3 github.com/crc-org/crc/v2 v2.51.0 diff --git a/go.sum b/go.sum index 803ad10b..a8f115db 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Code-Hex/go-infinity-channel v1.0.0 h1:M8BWlfDOxq9or9yvF9+YkceoTkDI1pFAqvnP87Zh0Nw= github.com/Code-Hex/go-infinity-channel v1.0.0/go.mod h1:5yUVg/Fqao9dAjcpzoQ33WwfdMWmISOrQloDRn3bsvY= -github.com/Code-Hex/vz/v3 v3.6.0 h1:S79dokzXmaLgC2yR0l0drRTGO/iFL3xwiCNVF80lJ5k= -github.com/Code-Hex/vz/v3 v3.6.0/go.mod h1:1LsW0jqW0r0cQ+IeR4hHbjdqOtSidNCVMWhStMHGho8= +github.com/Code-Hex/vz/v3 v3.7.0 h1:VEkfq5TVKnv85M81gQVPzLH9JzHrUJN/QQMpDZ+odPA= +github.com/Code-Hex/vz/v3 v3.7.0/go.mod h1:1LsW0jqW0r0cQ+IeR4hHbjdqOtSidNCVMWhStMHGho8= github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= From 8297bfcda2adbb1558d09940f1a15295669aaedc Mon Sep 17 00:00:00 2001 From: Gunjan Vyas Date: Mon, 2 Jun 2025 16:39:28 +0530 Subject: [PATCH 20/21] feat: add graceful VM shutdown on exit signals Replace os.Exit() with shutdown func to allow proper VM cleanup. VM now stops gracefully with RequestStop() before forcing termination. --- cmd/vfkit/main.go | 22 ++++++++++++++++++++-- pkg/util/exithandler.go | 14 ++++++++------ pkg/util/exithandler_test.go | 10 +++++++++- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/cmd/vfkit/main.go b/cmd/vfkit/main.go index 288c4a4d..773b02b5 100644 --- a/cmd/vfkit/main.go +++ b/cmd/vfkit/main.go @@ -136,8 +136,6 @@ func runVFKit(vmConfig *config.VirtualMachine, opts *cmdline.Options) error { runtime.LockOSThread() defer runtime.UnlockOSThread() - util.SetupExitSignalHandling() - gpuDevs := vmConfig.VirtioGPUDevices() if opts.UseGUI && len(gpuDevs) > 0 { gpuDevs[0].UsesGUI = true @@ -157,6 +155,26 @@ func runVFKit(vmConfig *config.VirtualMachine, opts *cmdline.Options) error { } srv.Start() } + + shutdownFunc := func() { + log.Debugf("shutting down...") + stopped, err := vfVM.RequestStop() + if err != nil { + log.Errorf("failed to shutdown VM: %v", err) + } else if !stopped { + log.Warnf("VM did not acknowledge stop request") + } + if err := waitForVMState(vfVM, vz.VirtualMachineStateStopped, time.After(5*time.Second)); err != nil { + log.Warnf("failed to wait for VM stop: %v, forcing stop", err) + if forceErr := vfVM.Stop(); forceErr != nil { + log.Errorf("failed to force stop VM: %v", forceErr) + } + } else { + log.Debugf("VM stopped gracefully") + } + + } + util.SetupExitSignalHandling(shutdownFunc) return runVirtualMachine(vmConfig, vfVM) } diff --git a/pkg/util/exithandler.go b/pkg/util/exithandler.go index dd4c30a6..f23dde78 100644 --- a/pkg/util/exithandler.go +++ b/pkg/util/exithandler.go @@ -28,22 +28,24 @@ func RegisterExitHandler(handler func()) { // SetupExitSignalHandling sets up a signal channel to listen for termination or interruption signals. // When one of these signals is received, all the registered exit handlers will be invoked, just // before terminating the program. -func SetupExitSignalHandling() { - setupExitSignalHandling(true) +func SetupExitSignalHandling(shutdownFunc func()) { + setupExitSignalHandling(shutdownFunc) } // setupExitSignalHandling sets up a signal channel to listen for termination or interruption signals. // When one of these signals is received, all the registered exit handlers will be invoked. // It is possible to prevent the program from exiting by setting the doExit param to false (used for testing) -func setupExitSignalHandling(doExit bool) { +func setupExitSignalHandling(shutdownFunc func()) { sigChan := make(chan os.Signal, 2) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGINT) go func() { + defer func() { + signal.Stop(sigChan) + }() for sig := range sigChan { log.Printf("captured %v, calling exit handlers and exiting..", sig) - ExecuteExitHandlers() - if doExit { - os.Exit(1) + if shutdownFunc != nil { + shutdownFunc() } } }() diff --git a/pkg/util/exithandler_test.go b/pkg/util/exithandler_test.go index 97c92d58..6428f890 100644 --- a/pkg/util/exithandler_test.go +++ b/pkg/util/exithandler_test.go @@ -7,7 +7,12 @@ import ( ) func TestExitHandlerCalled(t *testing.T) { - setupExitSignalHandling(false) + shutdownCalled := false + shutDownFunc := func() { + shutdownCalled = true + ExecuteExitHandlers() + } + setupExitSignalHandling(shutDownFunc) ch := make(chan struct{}) RegisterExitHandler(func() { @@ -23,6 +28,9 @@ func TestExitHandlerCalled(t *testing.T) { select { case <-ch: // exit handler was called + if !shutdownCalled { + t.Errorf("exit handler was not called") + } case <-time.After(5 * time.Second): t.Errorf("Exit handler not called - timed out") } From faf7a8947596a0ff90c957702fe5e52c36e526a3 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Fri, 20 Jun 2025 11:39:07 +0200 Subject: [PATCH 21/21] =?UTF-8?q?don=E2=80=99t=20run?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/compile.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 086b722f..f8cdf407 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -46,7 +46,6 @@ jobs: - name: Install qemu-img run: | - brew update brew install qemu - name: Verify qemu-img is installed