diff --git a/Makefile b/Makefile index 944bc51b..ed4cd3a4 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,8 @@ include tools/tools.mk build: out/vfkit -test: - go test ./pkg/... +test: build + @go test ./pkg/... ./test clean: rm -rf out diff --git a/go.mod b/go.mod index a03a8fbc..9606f026 100644 --- a/go.mod +++ b/go.mod @@ -4,43 +4,67 @@ go 1.18 require ( github.com/Code-Hex/vz/v3 v3.0.6 - github.com/docker/go-units v0.4.0 + github.com/cavaliergopher/grab/v3 v3.0.1 + github.com/crc-org/crc/v2 v2.26.1-0.20230912045325-f76e4b9eac99 + github.com/docker/go-units v0.5.0 github.com/gin-gonic/gin v1.9.0 github.com/prashantgupta24/mac-sleep-notifier v1.0.1 - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.1 - golang.org/x/sys v0.5.0 + github.com/stretchr/testify v1.8.4 + golang.org/x/crypto v0.12.0 + golang.org/x/sys v0.11.0 inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 ) require ( github.com/Code-Hex/go-infinity-channel v1.0.0 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/VividCortex/ewma v1.2.0 // indirect github.com/bytedance/sonic v1.8.0 // indirect + github.com/cheggaaa/pb/v3 v3.1.4 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/crc-org/machine v0.0.0-20221028075518-f9b43442196b // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fatih/color v1.15.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.11.2 // indirect github.com/goccy/go-json v0.10.0 // indirect + github.com/h2non/filetype v1.1.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/leodido/go-urn v1.2.1 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect - github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/pelletier/go-toml/v2 v2.0.9 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/shirou/gopsutil/v3 v3.23.6 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/tklauser/go-sysconf v0.3.11 // indirect + github.com/tklauser/numcpus v0.6.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.9 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/crypto v0.5.0 // indirect - golang.org/x/mod v0.9.0 // indirect - golang.org/x/net v0.7.0 // indirect - golang.org/x/text v0.7.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect + golang.org/x/mod v0.10.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/term v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect + google.golang.org/protobuf v1.30.0 // 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 64494861..405c0be6 100644 --- a/go.sum +++ b/go.sum @@ -2,23 +2,39 @@ github.com/Code-Hex/go-infinity-channel v1.0.0 h1:M8BWlfDOxq9or9yvF9+YkceoTkDI1p github.com/Code-Hex/go-infinity-channel v1.0.0/go.mod h1:5yUVg/Fqao9dAjcpzoQ33WwfdMWmISOrQloDRn3bsvY= github.com/Code-Hex/vz/v3 v3.0.6 h1:YoW0ZHbdb9G1lYDw9h/QrbBC5lAI1k9LAZMmTGR/Rpw= github.com/Code-Hex/vz/v3 v3.0.6/go.mod h1:xUfvg1VJ5A6ZQNuzQERwXJ7l2ZdTnY6eCy9CIS6/DYQ= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= +github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/armon/go-proxyproto v0.0.0-20210323213023-7e956b284f0a/go.mod h1:QmP9hvJ91BbJmGVGSbutW19IC0Q9phDCLGaomwTJbgU= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4= +github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4= +github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo= +github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4iUXmSA= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crc-org/crc/v2 v2.26.1-0.20230912045325-f76e4b9eac99 h1:LF4BYyV4Gqvv63WLNJDLhzXXN0hDVEUcue0U9nsOsZk= +github.com/crc-org/crc/v2 v2.26.1-0.20230912045325-f76e4b9eac99/go.mod h1:iduslMIUQJD601VDcITPeL7eJBMuAd0dHN16jbiXc+s= +github.com/crc-org/machine v0.0.0-20221028075518-f9b43442196b h1:VPbW5D21B1WToPvEA/EGwhi4e3lXevmRff9M1lUTc5g= +github.com/crc-org/machine v0.0.0-20221028075518-f9b43442196b/go.mod h1:9bEsvgLE3LIPfvGATt9Mo73gG1CKKS6A/++VqOONKqc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= 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.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -29,35 +45,63 @@ github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVL github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= -github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= +github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantgupta24/mac-sleep-notifier v1.0.1 h1:xd1lPtnn1gxGNjD2tCoVDoOtiQcQ8B9KNFhcWgGqreQ= github.com/prashantgupta24/mac-sleep-notifier v1.0.1/go.mod h1:bcfTio1xW+rjjZzdF0kbMEs9mcCEmrOBOSK+Jeml7zM= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/shirou/gopsutil/v3 v3.23.6 h1:5y46WPI9QBKBbK7EEccUPNXpJpNrvPuTD0O2zHEHT08= +github.com/shirou/gopsutil/v3 v3.23.6/go.mod h1:j7QX50DrXYggrpN30W0Mo+I4/8U2UUIQrnrhqUeWrAU= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +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.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -70,33 +114,51 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= +github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= +github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= +github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= -golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= 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= diff --git a/test/osprovider.go b/test/osprovider.go new file mode 100644 index 00000000..865de792 --- /dev/null +++ b/test/osprovider.go @@ -0,0 +1,176 @@ +package test + +import ( + "compress/gzip" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "runtime" + "strings" + + "github.com/crc-org/vfkit/pkg/config" + + "github.com/cavaliergopher/grab/v3" + "github.com/crc-org/crc/v2/pkg/extract" + log "github.com/sirupsen/logrus" + "golang.org/x/crypto/ssh" +) + +func kernelArch() string { + switch runtime.GOARCH { + case "amd64": + return "x86_64" + case "arm64": + return "aarch64" + default: + return "invalid" + } +} + +func downloadPuipui(destDir string) ([]string, error) { + const puipuiVersion = "0.0.1" + var puipuiURL = fmt.Sprintf("https://github.com/Code-Hex/puipui-linux/releases/download/v%s/puipui_linux_v%s_%s.tar.gz", puipuiVersion, puipuiVersion, kernelArch()) + + // https://github.com/cavaliergopher/grab/issues/104 + grab.DefaultClient.UserAgent="vfkit" + resp, err := grab.Get(destDir, puipuiURL) + if err != nil { + return nil, err + } + return extract.Uncompress(resp.Filename, destDir) +} + +type OsProvider interface { + Fetch(destDir string) error + ToVirtualMachine() (*config.VirtualMachine, error) + SSHConfig() *ssh.ClientConfig + SSHAccessMethods() []SSHAccessMethod +} + +type SSHAccessMethod struct { + network string + port int +} + +type PuiPuiProvider struct { + vmlinuz string + initramfs string + kernelArgs string +} + +func NewPuipuiProvider() *PuiPuiProvider { + return &PuiPuiProvider{} +} + +func findFile(files []string, filename string) (string, error) { + for _, f := range files { + if filepath.Base(f) == filename { + return f, nil + } + } + + return "", fmt.Errorf("could not find %s", filename) +} + +func ungz(gzFile string) (string, error) { + reader, err := os.Open(gzFile) + if err != nil { + return "", err + } + defer reader.Close() + gzReader, err := gzip.NewReader(reader) + if err != nil { + return "", err + } + defer gzReader.Close() + destFile, _ := strings.CutSuffix(gzFile, ".gz") + writer, err := os.OpenFile(destFile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + return "", err + } + defer writer.Close() + + // https://stackoverflow.com/questions/67327323/g110-potential-dos-vulnerability-via-decompression-bomb-gosec + for { + _, err = io.CopyN(writer, gzReader, 1024*1024) + if err != nil { + if errors.Is(err, io.EOF) { + break + } + return "", err + } + } + return destFile, nil +} + +func findKernel(files []string) (string, error) { + switch runtime.GOARCH { + case "amd64": + return findFile(files, "bzImage") + case "arm64": + compressed, err := findFile(files, "Image.gz") + if err != nil { + return "", err + } + return ungz(compressed) + default: + return "", fmt.Errorf("unsupported architecture '%s'", runtime.GOARCH) + } +} + +func (puipui *PuiPuiProvider) Fetch(destDir string) error { + log.Infof("downloading puipui to %s", destDir) + files, err := downloadPuipui(destDir) + if err != nil { + return err + } + + puipui.vmlinuz, err = findKernel(files) + if err != nil { + return err + } + log.Infof("puipui kernel: %s", puipui.vmlinuz) + puipui.initramfs, err = findFile(files, "initramfs.cpio.gz") + if err != nil { + return err + } + log.Infof("puipui initramfs: %s", puipui.initramfs) + puipui.kernelArgs = "console=hvc0" + log.Infof("puipui kernel command line: %s", puipui.kernelArgs) + + return nil +} + +const puipuiMemoryBytes = 1 * 1024 // MiB +const puipuiCPUs = 2 + +func (puipui *PuiPuiProvider) ToVirtualMachine() (*config.VirtualMachine, error) { + bootloader := config.NewLinuxBootloader(puipui.vmlinuz, puipui.kernelArgs, puipui.initramfs) + vm := config.NewVirtualMachine(puipuiCPUs, puipuiMemoryBytes, bootloader) + + return vm, nil +} + +func (puipui *PuiPuiProvider) SSHConfig() *ssh.ClientConfig { + return &ssh.ClientConfig{ + User: "root", + Auth: []ssh.AuthMethod{ssh.Password("passwd")}, + // #nosec 106 -- the host SSH key of the VM will change each time it boots + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + } +} + +func (puipui *PuiPuiProvider) SSHAccessMethods() []SSHAccessMethod { + return []SSHAccessMethod{ + { + network: "tcp", + port: 22, + }, + { + network: "vsock", + port: 2222, + }, + } +} diff --git a/test/vm_helpers.go b/test/vm_helpers.go new file mode 100644 index 00000000..4b87dec4 --- /dev/null +++ b/test/vm_helpers.go @@ -0,0 +1,229 @@ +package test + +import ( + "fmt" + "net" + "os/exec" + "path/filepath" + "strconv" + "testing" + "time" + + "github.com/crc-org/vfkit/pkg/config" + + vfkithelpers "github.com/crc-org/crc/v2/pkg/drivers/vfkit" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" + "golang.org/x/crypto/ssh" +) + +func sshOverTCP(macAddress string, sshPort int, sshConfig *ssh.ClientConfig) (*ssh.Client, error) { + var ( + err error + ip string + ) + + for i := 0; i < 100; i++ { + ip, err = vfkithelpers.GetIPAddressByMACAddress(macAddress) + if err == nil { + break + } + + time.Sleep(time.Second) + } + if err != nil { + return nil, err + } + log.Infof("found IP address %s for MAC %s", ip, macAddress) + + var sshClient *ssh.Client + for i := 0; i < 10; i++ { + sshClient, err = ssh.Dial("tcp", net.JoinHostPort(ip, strconv.Itoa(sshPort)), sshConfig) + if err == nil { + break + } + time.Sleep(time.Second) + } + log.Infof("established SSH connection to %s:%d over TCP", ip, sshPort) + return sshClient, err +} + +func sshOverVsock(unixSocket string, sshConfig *ssh.ClientConfig) (*ssh.Client, error) { + var ( + sshClient *ssh.Client + err error + ) + for i := 0; i < 100; i++ { + sshClient, err = ssh.Dial("unix", unixSocket, sshConfig) + if err == nil { + break + } + time.Sleep(time.Second) + } + log.Infof("established SSH connection over Unix socket %s", unixSocket) + return sshClient, err +} + +type vfkitRunner struct { + *exec.Cmd + gracefullyShutdown bool +} + +func startVfkit(t *testing.T, vm *config.VirtualMachine) *vfkitRunner { + const vfkitRelativePath = "../out/vfkit" + + binaryPath, err := exec.LookPath(vfkitRelativePath) + require.NoError(t, err) + + log.Infof("starting %s", binaryPath) + vfkitCmd, err := vm.Cmd(binaryPath) + require.NoError(t, err) + + err = vfkitCmd.Start() + require.NoError(t, err) + + return &vfkitRunner{ + vfkitCmd, + false, + } +} + +func (cmd *vfkitRunner) Wait(t *testing.T) { + err := cmd.Cmd.Wait() + require.NoError(t, err) + cmd.gracefullyShutdown = true +} + +func (cmd *vfkitRunner) Close() { + if cmd != nil && !cmd.gracefullyShutdown { + log.Infof("killing left-over vfkit process") + err := cmd.Cmd.Process.Kill() + if err != nil { + log.Warnf("failed to kill vfkit process: %v", err) + } + } +} + +type testVM struct { + provider OsProvider + config *config.VirtualMachine + + sshNetwork string + macAddress string // for SSH over TCP + port int + vsockPath string // for SSH over vsock + sshClient *ssh.Client + + vfkitCmd *vfkitRunner +} + +func NewTestVM(t *testing.T, provider OsProvider) *testVM { //nolint:revive + vm := &testVM{ + provider: provider, + } + vmConfig, err := provider.ToVirtualMachine() + require.NoError(t, err) + vm.config = vmConfig + + return vm +} + +func (vm *testVM) findSSHAccessMethod(t *testing.T, network string) *SSHAccessMethod { + switch network { + case "any": + accessMethods := vm.provider.SSHAccessMethods() + require.NotZero(t, len(accessMethods)) + return &accessMethods[0] + default: + for _, accessMethod := range vm.provider.SSHAccessMethods() { + if accessMethod.network == network { + return &accessMethod + } + } + } + + t.FailNow() + return nil +} + +func (vm *testVM) AddSSH(t *testing.T, network string) { + const vmMacAddress = "56:46:4b:49:54:01" + var ( + dev config.VirtioDevice + err error + ) + method := vm.findSSHAccessMethod(t, network) + switch network { + case "tcp": + log.Infof("adding virtio-net device (MAC: %s)", vmMacAddress) + vm.sshNetwork = "tcp" + vm.macAddress = vmMacAddress + vm.port = method.port + dev, err = config.VirtioNetNew(vm.macAddress) + require.NoError(t, err) + case "vsock": + log.Infof("adding virtio-vsock device (port: %d)", method.port) + vm.sshNetwork = "vsock" + vm.vsockPath = filepath.Join(t.TempDir(), fmt.Sprintf("vsock-%d.sock", method.port)) + dev, err = config.VirtioVsockNew(uint(method.port), vm.vsockPath, false) + require.NoError(t, err) + default: + t.FailNow() + } + + vm.AddDevice(t, dev) +} + +func (vm *testVM) AddDevice(t *testing.T, dev config.VirtioDevice) { + err := vm.config.AddDevice(dev) + require.NoError(t, err) +} + +func (vm *testVM) Start(t *testing.T) { + vm.vfkitCmd = startVfkit(t, vm.config) +} + +func (vm *testVM) Stop(t *testing.T) { + vm.SSHRun(t, "poweroff") + vm.vfkitCmd.Wait(t) +} + +func (vm *testVM) Close(_ *testing.T) { + if vm.sshClient != nil { + vm.sshClient.Close() + } + vm.vfkitCmd.Close() +} + +func (vm *testVM) WaitForSSH(t *testing.T) { + var ( + sshClient *ssh.Client + err error + ) + switch vm.sshNetwork { + case "tcp": + sshClient, err = sshOverTCP(vm.macAddress, vm.port, vm.provider.SSHConfig()) + require.NoError(t, err) + case "vsock": + sshClient, err = sshOverVsock(vm.vsockPath, vm.provider.SSHConfig()) + require.NoError(t, err) + default: + t.FailNow() + } + + vm.sshClient = sshClient +} + +func (vm *testVM) SSHRun(t *testing.T, command string) { + sshSession, err := vm.sshClient.NewSession() + require.NoError(t, err) + defer sshSession.Close() + _ = sshSession.Run(command) +} + +func (vm *testVM) SSHCombinedOutput(t *testing.T, command string) ([]byte, error) { + sshSession, err := vm.sshClient.NewSession() + require.NoError(t, err) + defer sshSession.Close() + return sshSession.CombinedOutput(command) +} diff --git a/test/vm_test.go b/test/vm_test.go new file mode 100644 index 00000000..a6c699c7 --- /dev/null +++ b/test/vm_test.go @@ -0,0 +1,260 @@ +package test + +import ( + "fmt" + "io" + "net" + "os" + "path/filepath" + "regexp" + "testing" + "time" + + "github.com/crc-org/vfkit/pkg/config" + + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" +) + +func testSSHAccess(t *testing.T, vm *testVM, network string) { + log.Infof("testing SSH access over %s", network) + vm.AddSSH(t, network) + vm.Start(t) + + log.Infof("waiting for SSH") + vm.WaitForSSH(t) + + log.Infof("shutting down VM") + vm.Stop(t) +} + +func TestSSHAccess(t *testing.T) { + puipuiProvider := NewPuipuiProvider() + log.Info("fetching os image") + err := puipuiProvider.Fetch(t.TempDir()) + require.NoError(t, err) + + for _, accessMethod := range puipuiProvider.SSHAccessMethods() { + t.Run(accessMethod.network, func(t *testing.T) { + vm := NewTestVM(t, puipuiProvider) + defer vm.Close(t) + require.NotNil(t, vm) + testSSHAccess(t, vm, accessMethod.network) + }) + } +} + +// guest listens over vsock, host connects to the guest +func TestVsockConnect(t *testing.T) { + puipuiProvider := NewPuipuiProvider() + log.Info("fetching os image") + err := puipuiProvider.Fetch(t.TempDir()) + require.NoError(t, err) + + vm := NewTestVM(t, puipuiProvider) + defer vm.Close(t) + require.NotNil(t, vm) + + vm.AddSSH(t, "tcp") + + tempDir := t.TempDir() + vsockConnectPath := filepath.Join(tempDir, "vsock-connect.sock") + dev, err := config.VirtioVsockNew(1234, vsockConnectPath, false) + require.NoError(t, err) + vm.AddDevice(t, dev) + + vm.Start(t) + vm.WaitForSSH(t) + + log.Infof("path to vsock socket: %s", vsockConnectPath) + go func() { + for i := 0; i < 5; i++ { + conn, err := net.DialTimeout("unix", vsockConnectPath, time.Second) + require.NoError(t, err) + defer conn.Close() + data, err := io.ReadAll(conn) + require.NoError(t, err) + if len(data) != 0 { + log.Infof("read data from guest: %v", string(data)) + require.Equal(t, []byte("hello host"), data) + break + } + } + }() + log.Infof("running socat") + vm.SSHRun(t, "echo -n 'hello host' | socat - VSOCK-LISTEN:1234") + + log.Infof("stopping VM") + vm.Stop(t) +} + +// host listens over vsock, guest connects to the host +func TestVsockListen(t *testing.T) { + puipuiProvider := NewPuipuiProvider() + log.Info("fetching os image") + err := puipuiProvider.Fetch(t.TempDir()) + require.NoError(t, err) + + vm := NewTestVM(t, puipuiProvider) + defer vm.Close(t) + require.NotNil(t, vm) + + vm.AddSSH(t, "tcp") + + tempDir := t.TempDir() + vsockListenPath := filepath.Join(tempDir, "vsock-listen.sock") + ln, err := net.Listen("unix", vsockListenPath) + require.NoError(t, err) + go func() { + conn, err := ln.Accept() + // call ln.Close() after a timeout to unblock Accept() and fail the test? + require.NoError(t, err) + data, err := io.ReadAll(conn) + require.NoError(t, err) + log.Infof("read %v", string(data)) + require.Equal(t, []byte("hello host"), data) + }() + log.Infof("path to vsock socket: %s", vsockListenPath) + dev, err := config.VirtioVsockNew(1235, vsockListenPath, true) + require.NoError(t, err) + vm.AddDevice(t, dev) + + vm.Start(t) + vm.WaitForSSH(t) + + vm.SSHRun(t, "echo -n 'hello host' | socat -T 2 STDIN VSOCK-CONNECT:2:1235") + + vm.Stop(t) +} + +func TestFileSharing(t *testing.T) { + puipuiProvider := NewPuipuiProvider() + log.Info("fetching os image") + tempDir := t.TempDir() + err := puipuiProvider.Fetch(tempDir) + require.NoError(t, err) + + vm := NewTestVM(t, puipuiProvider) + defer vm.Close(t) + require.NotNil(t, vm) + + vm.AddSSH(t, "tcp") + + sharedDir := t.TempDir() + share, err := config.VirtioFsNew(sharedDir, "vfkit-test-share") + require.NoError(t, err) + vm.AddDevice(t, share) + log.Infof("shared directory: %s", sharedDir) + + vm.Start(t) + vm.WaitForSSH(t) + + vm.SSHRun(t, "mkdir /mnt") + vm.SSHRun(t, "mount -t virtiofs vfkit-test-share /mnt") + + err = os.WriteFile(filepath.Join(sharedDir, "from-host.txt"), []byte("data from host"), 0600) + require.NoError(t, err) + data, err := vm.SSHCombinedOutput(t, "cat /mnt/from-host.txt") + require.NoError(t, err) + require.Equal(t, "data from host", string(data)) + + vm.SSHRun(t, "echo -n 'data from guest' > /mnt/from-guest.txt") + data, err = os.ReadFile(filepath.Join(sharedDir, "from-guest.txt")) + require.NoError(t, err) + require.Equal(t, "data from guest", string(data)) + + vm.Stop(t) +} + +type createDevFunc func(t *testing.T) (config.VirtioDevice, error) +type pciidTest struct { + vendorID int + deviceID int + createDev createDevFunc +} + +var pciidTests = map[string]pciidTest{ + "virtio-net": { + vendorID: 0x1af4, // Red Hat + deviceID: 0x1041, + createDev: func(t *testing.T) (config.VirtioDevice, error) { + return config.VirtioNetNew("") + }, + }, + "virtio-serial": { + vendorID: 0x1af4, // Red Hat + deviceID: 0x1043, + createDev: func(t *testing.T) (config.VirtioDevice, error) { + return config.VirtioSerialNew(filepath.Join(t.TempDir(), "serial.log")) + }, + }, + "virtio-rng": { + vendorID: 0x1af4, // Red Hat + deviceID: 0x1044, + createDev: func(t *testing.T) (config.VirtioDevice, error) { + return config.VirtioRngNew() + }, + }, + "virtio-fs": { + vendorID: 0x1af4, // Red Hat + deviceID: 0x105a, + createDev: func(t *testing.T) (config.VirtioDevice, error) { + return config.VirtioFsNew("./", "vfkit-share-test") + }, + }, + "virtio-gpu": { + vendorID: 0x1af4, // Red Hat + deviceID: 0x1050, + createDev: func(t *testing.T) (config.VirtioDevice, error) { + return config.VirtioGPUNew() + }, + }, + "virtio-input/pointing-device": { + vendorID: 0x106b, // Apple + deviceID: 0x1a06, + createDev: func(t *testing.T) (config.VirtioDevice, error) { + return config.VirtioInputNew("pointing") + }, + }, + "virtio-input/keyboard": { + vendorID: 0x106b, // Apple + deviceID: 0x1a06, + createDev: func(t *testing.T) (config.VirtioDevice, error) { + return config.VirtioInputNew("keyboard") + }, + }, +} + +func TestPCIIds(t *testing.T) { + puipuiProvider := NewPuipuiProvider() + log.Info("fetching os image") + tempDir := t.TempDir() + err := puipuiProvider.Fetch(tempDir) + require.NoError(t, err) + + for name, test := range pciidTests { + t.Run(name, func(t *testing.T) { + vm := NewTestVM(t, puipuiProvider) + defer vm.Close(t) + require.NotNil(t, vm) + + vm.AddSSH(t, "tcp") + dev, err := test.createDev(t) + require.NoError(t, err) + vm.AddDevice(t, dev) + + vm.Start(t) + vm.WaitForSSH(t) + checkPCIDevice(t, vm, test.vendorID, test.deviceID) + vm.Stop(t) + }) + } +} + +func checkPCIDevice(t *testing.T, vm *testVM, vendorID, deviceID int) { + re := regexp.MustCompile(fmt.Sprintf("(?m)[[:blank:]]%04x:%04x\n", vendorID, deviceID)) + lspci, err := vm.SSHCombinedOutput(t, "lspci") + log.Infof("lspci: %s", string(lspci)) + require.NoError(t, err) + require.Regexp(t, re, string(lspci)) +}