diff --git a/go.mod b/go.mod index 72eb11eaa..6c2b43c99 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,6 @@ require ( k8s.io/code-generator v0.29.0 k8s.io/component-base v0.29.0 k8s.io/klog/v2 v2.110.1 - sigs.k8s.io/controller-runtime v0.16.0 sigs.k8s.io/yaml v1.4.0 ) @@ -46,7 +45,6 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/gibson042/canonicaljson-go v1.0.3 // indirect github.com/go-logr/logr v1.3.0 // indirect @@ -93,17 +91,17 @@ require ( go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.25.0 // indirect - golang.org/x/crypto v0.14.0 // indirect + golang.org/x/crypto v0.18.0 // indirect golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.20.0 // indirect golang.org/x/oauth2 v0.12.0 // indirect - golang.org/x/sync v0.4.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/term v0.16.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/tools v0.17.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect @@ -114,7 +112,6 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.29.0 // indirect k8s.io/apiserver v0.29.0 // indirect k8s.io/component-helpers v0.29.0 // indirect k8s.io/controller-manager v0.29.0 // indirect @@ -123,6 +120,7 @@ require ( k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 // indirect + sigs.k8s.io/controller-runtime v0.14.5 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/go.sum b/go.sum index 37708b562..58dc34c9e 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,6 @@ github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7 github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -71,8 +69,8 @@ github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= -github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= +github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= @@ -144,7 +142,6 @@ github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -194,7 +191,6 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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 v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -297,15 +293,15 @@ go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o= golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -315,8 +311,8 @@ golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -324,8 +320,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -336,17 +332,17 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -357,14 +353,12 @@ golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= -gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= @@ -405,8 +399,6 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA= k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= -k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0= -k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc= k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g= k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= @@ -441,8 +433,8 @@ k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSn k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 h1:TgtAeesdhpm2SGwkQasmbeqDo8th5wOBA5h/AjTKA4I= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y= -sigs.k8s.io/controller-runtime v0.16.0 h1:5koYaaRVBHDr0LZAJjO5dWzUjMsh6cwa7q1Mmusrdvk= -sigs.k8s.io/controller-runtime v0.16.0/go.mod h1:77DnuwA8+J7AO0njzv3wbNlMOnGuLrwFr8JPNwx3J7g= +sigs.k8s.io/controller-runtime v0.14.5 h1:6xaWFqzT5KuAQ9ufgUaj1G/+C4Y1GRkhrxl+BJ9i+5s= +sigs.k8s.io/controller-runtime v0.14.5/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= diff --git a/pkg/cloudprovider/vsphereparavirtual/instances.go b/pkg/cloudprovider/vsphereparavirtual/instances.go index 37bb8bcd9..694ec777e 100644 --- a/pkg/cloudprovider/vsphereparavirtual/instances.go +++ b/pkg/cloudprovider/vsphereparavirtual/instances.go @@ -27,17 +27,17 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" - "sigs.k8s.io/controller-runtime/pkg/client" cloudprovider "k8s.io/cloud-provider" "k8s.io/klog/v2" vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" + vmop "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator" "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmservice" ) type instances struct { - vmClient client.Client + vmClient vmop.Interface namespace string } diff --git a/pkg/cloudprovider/vsphereparavirtual/instances_test.go b/pkg/cloudprovider/vsphereparavirtual/instances_test.go index 31988feed..a9f3e0f12 100644 --- a/pkg/cloudprovider/vsphereparavirtual/instances_test.go +++ b/pkg/cloudprovider/vsphereparavirtual/instances_test.go @@ -27,11 +27,12 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" + clientgotesting "k8s.io/client-go/testing" cloudprovider "k8s.io/cloud-provider" - "k8s.io/cloud-provider-vsphere/pkg/util" - "sigs.k8s.io/controller-runtime/pkg/client" - fakeClient "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/envtest" + vmopclient "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator/client" + + dynamicfake "k8s.io/client-go/dynamic/fake" ) var ( @@ -69,41 +70,36 @@ func createTestVMWithVMIPAndHost(name, namespace, biosUUID string) *vmopv1alpha1 func TestNewInstances(t *testing.T) { testCases := []struct { name string - testEnv *envtest.Environment + config *rest.Config expectedErr error }{ { name: "NewInstance: when everything is ok", - testEnv: &envtest.Environment{}, + config: &rest.Config{}, expectedErr: nil, }, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - cfg, err := testCase.testEnv.Start() - assert.NoError(t, err) - - _, err = NewInstances(testClusterNameSpace, cfg) + _, err := NewInstances(testClusterNameSpace, testCase.config) assert.NoError(t, err) assert.Equal(t, testCase.expectedErr, err) - - err = testCase.testEnv.Stop() - assert.NoError(t, err) }) } } -func initTest(testVM *vmopv1alpha1.VirtualMachine) (*instances, *util.FakeClientWrapper) { +func initTest(testVM *vmopv1alpha1.VirtualMachine) (*instances, *dynamicfake.FakeDynamicClient, error) { scheme := runtime.NewScheme() _ = vmopv1alpha1.AddToScheme(scheme) - fc := fakeClient.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(testVM).Build() - fcw := util.NewFakeClientWrapper(fc) + fc := dynamicfake.NewSimpleDynamicClient(scheme) + fcw := vmopclient.NewFakeClientSet(fc) instance := &instances{ vmClient: fcw, namespace: testClusterNameSpace, } - return instance, fcw + _, err := fcw.V1alpha1().VirtualMachines(testVM.Namespace).Create(context.TODO(), testVM, metav1.CreateOptions{}) + return instance, fc, err } func TestInstanceID(t *testing.T) { @@ -142,7 +138,8 @@ func TestInstanceID(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - instance, _ := initTest(testCase.testVM) + instance, _, err := initTest(testCase.testVM) + assert.NoError(t, err) instanceID, err := instance.InstanceID(context.Background(), testVMName) assert.Equal(t, testCase.expectedErr, err) assert.Equal(t, testCase.expectedInstanceID, instanceID) @@ -165,11 +162,11 @@ func TestInstanceIDThrowsErr(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - instance, fcw := initTest(testCase.testVM) - fcw.GetFunc = func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - return fmt.Errorf("Internal error getting VMs") - } - + instance, fc, err := initTest(testCase.testVM) + assert.NoError(t, err) + fc.PrependReactor("get", "virtualmachines", func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, fmt.Errorf("Internal error getting VMs") + }) instanceID, err := instance.InstanceID(context.Background(), testVMName) assert.NotEqual(t, nil, err) assert.NotEqual(t, cloudprovider.InstanceNotFound, err) @@ -201,7 +198,8 @@ func TestInstanceExistsByProviderID(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - instance, _ := initTest(testCase.testVM) + instance, _, err := initTest(testCase.testVM) + assert.NoError(t, err) providerID, err := instance.InstanceExistsByProviderID(context.Background(), testProviderID) assert.Equal(t, testCase.expectedErr, err) assert.Equal(t, testCase.expectedResult, providerID) @@ -255,7 +253,8 @@ func TestInstanceShutdownByProviderID(t *testing.T) { testCase.testVM.Status.PowerState = vmopv1alpha1.VirtualMachinePoweredOff } - instance, _ := initTest(testCase.testVM) + instance, _, err := initTest(testCase.testVM) + assert.NoError(t, err) ret, err := instance.InstanceShutdownByProviderID(context.Background(), testProviderID) assert.Equal(t, testCase.expectedErr, err) assert.Equal(t, testCase.expectedResult, ret) @@ -301,7 +300,8 @@ func TestNodeAddressesByProviderID(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - instance, _ := initTest(testCase.testVM) + instance, _, err := initTest(testCase.testVM) + assert.NoError(t, err) ret, err := instance.NodeAddressesByProviderID(context.Background(), testProviderID) assert.Equal(t, testCase.expectedErr, err) assert.Equal(t, testCase.expectedNodeAddress, ret) @@ -324,11 +324,11 @@ func TestNodeAddressesByProviderIDInternalErr(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - instance, fcw := initTest(testCase.testVM) - fcw.ListFunc = func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { - return fmt.Errorf("Internal error listing VMs") - } - + instance, fc, err := initTest(testCase.testVM) + assert.NoError(t, err) + fc.PrependReactor("list", "virtualmachines", func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, fmt.Errorf("Internal error listing VMs") + }) ret, err := instance.NodeAddressesByProviderID(context.Background(), testProviderID) assert.NotEqual(t, nil, err) assert.NotEqual(t, cloudprovider.InstanceNotFound, err) @@ -375,7 +375,8 @@ func TestNodeAddresses(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - instance, _ := initTest(testCase.testVM) + instance, _, err := initTest(testCase.testVM) + assert.NoError(t, err) ret, err := instance.NodeAddresses(context.Background(), testVMName) assert.Equal(t, testCase.expectedErr, err) assert.Equal(t, testCase.expectedNodeAddress, ret) @@ -398,11 +399,11 @@ func TestNodeAddressesInternalErr(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - instance, fcw := initTest(testCase.testVM) - fcw.GetFunc = func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - return fmt.Errorf("Internal error getting VMs") - } - + instance, fc, err := initTest(testCase.testVM) + assert.NoError(t, err) + fc.PrependReactor("get", "virtualmachines", func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, fmt.Errorf("Internal error getting VMs") + }) ret, err := instance.NodeAddresses(context.Background(), testVMName) assert.NotEqual(t, nil, err) assert.NotEqual(t, cloudprovider.InstanceNotFound, err) diff --git a/pkg/cloudprovider/vsphereparavirtual/loadbalancer_test.go b/pkg/cloudprovider/vsphereparavirtual/loadbalancer_test.go index b3de904b8..ed62da98e 100644 --- a/pkg/cloudprovider/vsphereparavirtual/loadbalancer_test.go +++ b/pkg/cloudprovider/vsphereparavirtual/loadbalancer_test.go @@ -26,16 +26,18 @@ import ( v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + dynamicfake "k8s.io/client-go/dynamic/fake" + "k8s.io/client-go/rest" + clientgotesting "k8s.io/client-go/testing" cloudprovider "k8s.io/cloud-provider" - "sigs.k8s.io/controller-runtime/pkg/client" - fakeClient "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/envtest" "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmservice" - "k8s.io/cloud-provider-vsphere/pkg/util" vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" + + vmopclient "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator/client" ) var ( @@ -51,40 +53,33 @@ var ( } ) -func newTestLoadBalancer() (cloudprovider.LoadBalancer, *util.FakeClientWrapper) { +func newTestLoadBalancer() (cloudprovider.LoadBalancer, *dynamicfake.FakeDynamicClient) { scheme := runtime.NewScheme() _ = vmopv1alpha1.AddToScheme(scheme) - fc := fakeClient.NewClientBuilder().WithScheme(scheme).Build() - fcw := util.NewFakeClientWrapper(fc) + fc := dynamicfake.NewSimpleDynamicClient(scheme) + fcw := vmopclient.NewFakeClientSet(fc) + vms := vmservice.NewVMService(fcw, testClusterNameSpace, &testOwnerReference) - return &loadBalancer{ - vmService: vms, - }, fcw + return &loadBalancer{vmService: vms}, fc } func TestNewLoadBalancer(t *testing.T) { testCases := []struct { - name string - testEnv *envtest.Environment - err error + name string + config *rest.Config + err error }{ { - name: "NewLoadBalancer: when everything is ok", - testEnv: &envtest.Environment{}, - err: nil, + name: "NewLoadBalancer: when everything is ok", + config: &rest.Config{}, + err: nil, }, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - cfg, err := testCase.testEnv.Start() - assert.NoError(t, err) - - _, err = NewLoadBalancer(testClusterNameSpace, cfg, &testOwnerReference) + _, err := NewLoadBalancer(testClusterNameSpace, testCase.config, &testOwnerReference) assert.Equal(t, testCase.err, err) - - err = testCase.testEnv.Stop() - assert.NoError(t, err) }) } } @@ -155,7 +150,7 @@ func TestUpdateLoadBalancer(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - lb, fcw := newTestLoadBalancer() + lb, fc := newTestLoadBalancer() testK8sService := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: testK8sServiceName, @@ -181,9 +176,9 @@ func TestUpdateLoadBalancer(t *testing.T) { if testCase.expectErr { // Ensure that the client Update call returns an error on update - fcw.UpdateFunc = func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { - return fmt.Errorf("Some undefined update error") - } + fc.PrependReactor("update", "virtualmachineservices", func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, fmt.Errorf("Some undefined update error") + }) err = lb.UpdateLoadBalancer(context.Background(), testClustername, testK8sService, []*v1.Node{}) assert.Error(t, err) } else { @@ -195,7 +190,7 @@ func TestUpdateLoadBalancer(t *testing.T) { } func TestEnsureLoadBalancer_VMServiceExternalTrafficPolicyLocal(t *testing.T) { - lb, fcw := newTestLoadBalancer() + lb, fc := newTestLoadBalancer() testK8sService := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: testK8sServiceName, @@ -205,8 +200,9 @@ func TestEnsureLoadBalancer_VMServiceExternalTrafficPolicyLocal(t *testing.T) { ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal, }, } - fcw.CreateFunc = func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { - vms := &vmopv1alpha1.VirtualMachineService{ + + fc.PrependReactor("create", "virtualmachineservices", func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + unstructuredObj, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(&vmopv1alpha1.VirtualMachineService{ Status: vmopv1alpha1.VirtualMachineServiceStatus{ LoadBalancer: vmopv1alpha1.LoadBalancerStatus{ Ingress: []vmopv1alpha1.LoadBalancerIngress{ @@ -216,10 +212,9 @@ func TestEnsureLoadBalancer_VMServiceExternalTrafficPolicyLocal(t *testing.T) { }, }, }, - } - vms.DeepCopyInto(obj.(*vmopv1alpha1.VirtualMachineService)) - return nil - } + }) + return true, &unstructured.Unstructured{Object: unstructuredObj}, nil + }) _, ensureErr := lb.EnsureLoadBalancer(context.Background(), testClustername, testK8sService, []*v1.Node{}) assert.NoError(t, ensureErr) @@ -231,17 +226,20 @@ func TestEnsureLoadBalancer_VMServiceExternalTrafficPolicyLocal(t *testing.T) { func TestEnsureLoadBalancer(t *testing.T) { testCases := []struct { name string - createFunc func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error + createFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) expectErr error }{ { - name: "when VMService is created but IP not found", + name: "when VMService is created but IP not found", + createFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + return true, &vmopv1alpha1.VirtualMachineService{}, fmt.Errorf(vmservice.ErrVMServiceIPNotFound.Error()) + }, expectErr: vmservice.ErrVMServiceIPNotFound, }, { name: "when VMService creation failed", - createFunc: func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { - return fmt.Errorf(vmservice.ErrCreateVMService.Error()) + createFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + return true, &vmopv1alpha1.VirtualMachineService{}, fmt.Errorf(vmservice.ErrCreateVMService.Error()) }, expectErr: vmservice.ErrCreateVMService, }, @@ -249,14 +247,14 @@ func TestEnsureLoadBalancer(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - lb, fcw := newTestLoadBalancer() + lb, fc := newTestLoadBalancer() testK8sService := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: testK8sServiceName, Namespace: testK8sServiceNameSpace, }, } - fcw.CreateFunc = testCase.createFunc + fc.PrependReactor("create", "virtualmachineservices", testCase.createFunc) _, ensureErr := lb.EnsureLoadBalancer(context.Background(), testClustername, testK8sService, []*v1.Node{}) assert.Equal(t, ensureErr.Error(), testCase.expectErr.Error()) @@ -268,7 +266,7 @@ func TestEnsureLoadBalancer(t *testing.T) { } func TestEnsureLoadBalancer_VMServiceCreatedIPFound(t *testing.T) { - lb, fcw := newTestLoadBalancer() + lb, fc := newTestLoadBalancer() testK8sService := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: testK8sServiceName, @@ -276,8 +274,8 @@ func TestEnsureLoadBalancer_VMServiceCreatedIPFound(t *testing.T) { }, } // Ensure that the client Create call returns a VMService with a valid IP - fcw.CreateFunc = func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { - vms := &vmopv1alpha1.VirtualMachineService{ + fc.PrependReactor("create", "virtualmachineservices", func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + unstructuredObj, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(&vmopv1alpha1.VirtualMachineService{ Status: vmopv1alpha1.VirtualMachineServiceStatus{ LoadBalancer: vmopv1alpha1.LoadBalancerStatus{ Ingress: []vmopv1alpha1.LoadBalancerIngress{ @@ -308,10 +306,10 @@ func TestEnsureLoadBalancer_VMServiceCreatedIPFound(t *testing.T) { vmservice.NodeSelectorKey: vmservice.NodeRole, }, }, - } - vms.DeepCopyInto(obj.(*vmopv1alpha1.VirtualMachineService)) - return nil - } + }) + + return true, &unstructured.Unstructured{Object: unstructuredObj}, nil + }) status, ensureErr := lb.EnsureLoadBalancer(context.Background(), testClustername, testK8sService, []*v1.Node{}) assert.NoError(t, ensureErr) @@ -324,19 +322,19 @@ func TestEnsureLoadBalancer_VMServiceCreatedIPFound(t *testing.T) { func TestEnsureLoadBalancer_DeleteLB(t *testing.T) { testCases := []struct { name string - deleteFunc func(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error + deleteFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) expectErr string }{ { name: "should ignore not found error", - deleteFunc: func(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { - return apierrors.NewNotFound(vmopv1alpha1.Resource("virtualmachineservice"), testClustername) + deleteFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, apierrors.NewNotFound(vmopv1alpha1.Resource("virtualmachineservice"), testClustername) }, }, { name: "should return error", - deleteFunc: func(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { - return fmt.Errorf("an error occurred while deleting load balancer") + deleteFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, fmt.Errorf("an error occurred while deleting load balancer") }, expectErr: "an error occurred while deleting load balancer", }, @@ -344,7 +342,7 @@ func TestEnsureLoadBalancer_DeleteLB(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - lb, fcw := newTestLoadBalancer() + lb, fc := newTestLoadBalancer() testK8sService := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: testK8sServiceName, @@ -356,7 +354,8 @@ func TestEnsureLoadBalancer_DeleteLB(t *testing.T) { err := lb.EnsureLoadBalancerDeleted(context.Background(), testClustername, testK8sService) assert.NoError(t, err) - fcw.DeleteFunc = testCase.deleteFunc + fc.PrependReactor("delete", "virtualmachineservices", testCase.deleteFunc) + err = lb.EnsureLoadBalancerDeleted(context.Background(), "test", testK8sService) if err != nil { assert.Equal(t, err.Error(), testCase.expectErr) diff --git a/pkg/cloudprovider/vsphereparavirtual/vmoperator.go b/pkg/cloudprovider/vsphereparavirtual/vmoperator.go index f4ed891bb..d34ff9a0f 100644 --- a/pkg/cloudprovider/vsphereparavirtual/vmoperator.go +++ b/pkg/cloudprovider/vsphereparavirtual/vmoperator.go @@ -5,14 +5,16 @@ import ( vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/cloud-provider-vsphere/pkg/util" - "sigs.k8s.io/controller-runtime/pkg/client" + + vmop "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator" ) // discoverNodeByProviderID takes a ProviderID and returns a VirtualMachine if one exists, or nil otherwise // VirtualMachine not found is not an error -func discoverNodeByProviderID(ctx context.Context, providerID string, namespace string, vmClient client.Client) (*vmopv1alpha1.VirtualMachine, error) { +func discoverNodeByProviderID(ctx context.Context, providerID string, namespace string, vmClient vmop.Interface) (*vmopv1alpha1.VirtualMachine, error) { var discoveredNode *vmopv1alpha1.VirtualMachine = nil // Adding Retry here because there is no retry in caller from node controller @@ -22,10 +24,7 @@ func discoverNodeByProviderID(ctx context.Context, providerID string, namespace checkError, func() error { uuid := GetUUIDFromProviderID(providerID) - vms := vmopv1alpha1.VirtualMachineList{} - err := vmClient.List(ctx, &vms, &client.ListOptions{ - Namespace: namespace, - }) + vms, err := vmClient.V1alpha1().VirtualMachines(namespace).List(ctx, metav1.ListOptions{}) if err != nil { return err } @@ -45,7 +44,7 @@ func discoverNodeByProviderID(ctx context.Context, providerID string, namespace // discoverNodeByName takes a node name and returns a VirtualMachine if one exists, or nil otherwise // VirtualMachine not found is not an error -func discoverNodeByName(ctx context.Context, name types.NodeName, namespace string, vmClient client.Client) (*vmopv1alpha1.VirtualMachine, error) { +func discoverNodeByName(ctx context.Context, name types.NodeName, namespace string, vmClient vmop.Interface) (*vmopv1alpha1.VirtualMachine, error) { var discoveredNode *vmopv1alpha1.VirtualMachine = nil // Adding Retry here because there is no retry in caller from node controller @@ -54,16 +53,14 @@ func discoverNodeByName(ctx context.Context, name types.NodeName, namespace stri DiscoverNodeBackoff, checkError, func() error { - vmKey := types.NamespacedName{Name: string(name), Namespace: namespace} - vm := vmopv1alpha1.VirtualMachine{} - err := vmClient.Get(ctx, vmKey, &vm) + vm, err := vmClient.V1alpha1().VirtualMachines(namespace).Get(ctx, string(name), metav1.GetOptions{}) if err != nil { if apierrors.IsNotFound(err) { return nil } return err } - discoveredNode = &vm + discoveredNode = vm return nil }) diff --git a/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/client.go b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/client.go new file mode 100644 index 000000000..9119006b0 --- /dev/null +++ b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/client.go @@ -0,0 +1,79 @@ +package client + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + + vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" + + "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator" +) + +var ( + // VirtualMachineServiceGVR has virtualmachineservice resource info. + VirtualMachineServiceGVR = schema.GroupVersionResource{ + Group: "vmoperator.vmware.com", + Version: "v1alpha1", + Resource: "virtualmachineservices", + } + // VirtualMachineGVR has virtualmachine resource info. + VirtualMachineGVR = schema.GroupVersionResource{ + Group: "vmoperator.vmware.com", + Version: "v1alpha1", + Resource: "virtualmachines", + } +) + +// Clientset contains the clients for groups. Each group has exactly one +// version included in a Clientset. +type Clientset struct { + vmopv1alpha1 *VmoperatorV1alpha1Client +} + +// V1alpha1 retrieves the VmoperatorV1alpha1Client +func (c *Clientset) V1alpha1() vmoperator.V1alpha1Interface { + return c.vmopv1alpha1 +} + +// VmoperatorV1alpha1Client contains the dynamic client for vm operator group +type VmoperatorV1alpha1Client struct { + dynamicClient *dynamic.DynamicClient +} + +// VirtualMachines retrieves the virtualmachine client +func (c *VmoperatorV1alpha1Client) VirtualMachines(namespace string) vmoperator.VirtualMachineInterface { + return newVirtualMachines(c, namespace) +} + +// VirtualMachineServices retrieves the virtualmachineservice client +func (c *VmoperatorV1alpha1Client) VirtualMachineServices(namespace string) vmoperator.VirtualMachineServiceInterface { + return newVirtualMachineServices(c, namespace) +} + +// Client retrieves the dynamic client +func (c *VmoperatorV1alpha1Client) Client() dynamic.Interface { + if c == nil { + return nil + } + return c.dynamicClient +} + +// NewForConfig creates a new client for the given config. +func NewForConfig(c *rest.Config) (*Clientset, error) { + scheme := runtime.NewScheme() + _ = vmopv1alpha1.AddToScheme(scheme) + + dynamicClient, err := dynamic.NewForConfig(c) + if err != nil { + return nil, err + } + + clientSet := &Clientset{ + vmopv1alpha1: &VmoperatorV1alpha1Client{ + dynamicClient: dynamicClient, + }, + } + return clientSet, nil +} diff --git a/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/fake_client.go b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/fake_client.go new file mode 100644 index 000000000..2192ec291 --- /dev/null +++ b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/fake_client.go @@ -0,0 +1,52 @@ +package client + +import ( + "k8s.io/client-go/dynamic" + dynamicfake "k8s.io/client-go/dynamic/fake" + + "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator" +) + +// FakeClientSet contains the fake clients for groups. Each group has exactly one +// version included in a Clientset. +type FakeClientSet struct { + FakeClient *FakeClient +} + +// V1alpha1 retrieves the fake VmoperatorV1alpha1Client +func (c *FakeClientSet) V1alpha1() vmoperator.V1alpha1Interface { + return c.FakeClient +} + +// NewFakeClientSet creates a FakeClientWrapper +func NewFakeClientSet(fakeClient *dynamicfake.FakeDynamicClient) *FakeClientSet { + fcw := &FakeClientSet{ + FakeClient: &FakeClient{ + DynamicClient: fakeClient, + }, + } + return fcw +} + +// FakeClient contains the fake dynamic client for vm operator group +type FakeClient struct { + DynamicClient *dynamicfake.FakeDynamicClient +} + +// VirtualMachines retrieves the virtualmachine client +func (c *FakeClient) VirtualMachines(namespace string) vmoperator.VirtualMachineInterface { + return newVirtualMachines(c, namespace) +} + +// VirtualMachineServices retrieves the virtualmachineservice client +func (c *FakeClient) VirtualMachineServices(namespace string) vmoperator.VirtualMachineServiceInterface { + return newVirtualMachineServices(c, namespace) +} + +// Client retrieves the dynamic client +func (c *FakeClient) Client() dynamic.Interface { + if c == nil { + return nil + } + return c.DynamicClient +} diff --git a/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachine_client.go b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachine_client.go new file mode 100644 index 000000000..4dea14b16 --- /dev/null +++ b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachine_client.go @@ -0,0 +1,87 @@ +package client + +import ( + "context" + + vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator" +) + +// virtualMachines implements VirtualMachineInterface +type virtualMachines struct { + client dynamic.Interface + ns string +} + +func newVirtualMachines(c vmoperator.V1alpha1Interface, namespace string) *virtualMachines { + return &virtualMachines{ + client: c.Client(), + ns: namespace, + } +} + +func (v *virtualMachines) Create(ctx context.Context, virtualMachine *vmopv1alpha1.VirtualMachine, opts v1.CreateOptions) (*vmopv1alpha1.VirtualMachine, error) { + unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(virtualMachine) + if err != nil { + return nil, err + } + + obj, err := v.client.Resource(VirtualMachineGVR).Namespace(v.ns).Create(ctx, &unstructured.Unstructured{Object: unstructuredObj}, opts) + if err != nil { + return nil, err + } + + createdVirtualMachine := &vmopv1alpha1.VirtualMachine{} + if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), createdVirtualMachine); err != nil { + return nil, err + } + return createdVirtualMachine, nil +} + +func (v *virtualMachines) Update(ctx context.Context, virtualMachine *vmopv1alpha1.VirtualMachine, opts v1.UpdateOptions) (*vmopv1alpha1.VirtualMachine, error) { + unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(virtualMachine) + if err != nil { + return nil, err + } + + obj, err := v.client.Resource(VirtualMachineGVR).Namespace(v.ns).Update(ctx, &unstructured.Unstructured{Object: unstructuredObj}, opts) + if err != nil { + return nil, err + } + + updatedVirtualMachine := &vmopv1alpha1.VirtualMachine{} + if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), updatedVirtualMachine); err != nil { + return nil, err + } + return updatedVirtualMachine, nil +} + +func (v *virtualMachines) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return v.client.Resource(VirtualMachineGVR).Namespace(v.ns).Delete(ctx, name, opts) +} + +func (v *virtualMachines) Get(ctx context.Context, name string, opts v1.GetOptions) (*vmopv1alpha1.VirtualMachine, error) { + virtualMachine := &vmopv1alpha1.VirtualMachine{} + if obj, err := v.client.Resource(VirtualMachineGVR).Namespace(v.ns).Get(ctx, name, opts); err != nil { + return nil, err + } else if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), virtualMachine); err != nil { + return nil, err + } + return virtualMachine, nil +} + +func (v *virtualMachines) List(ctx context.Context, opts v1.ListOptions) (*vmopv1alpha1.VirtualMachineList, error) { + virtualMachineList := &vmopv1alpha1.VirtualMachineList{} + if obj, err := v.client.Resource(VirtualMachineGVR).Namespace(v.ns).List(ctx, opts); err != nil { + return nil, err + } else if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), virtualMachineList); err != nil { + return nil, err + } + return virtualMachineList, nil +} diff --git a/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachine_client_test.go b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachine_client_test.go new file mode 100644 index 000000000..029c6d2cc --- /dev/null +++ b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachine_client_test.go @@ -0,0 +1,367 @@ +package client + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + clientgotesting "k8s.io/client-go/testing" + + dynamicfake "k8s.io/client-go/dynamic/fake" +) + +func initVMTest() (*virtualMachines, *dynamicfake.FakeDynamicClient) { + scheme := runtime.NewScheme() + _ = vmopv1alpha1.AddToScheme(scheme) + fc := dynamicfake.NewSimpleDynamicClient(scheme) + vms := newVirtualMachines(NewFakeClientSet(fc).V1alpha1(), "test-ns") + return vms, fc +} + +func TestVMCreate(t *testing.T) { + testCases := []struct { + name string + virtualMachine *vmopv1alpha1.VirtualMachine + createFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) + expectedVM *vmopv1alpha1.VirtualMachine + expectedErr bool + }{ + { + name: "Create: when everything is ok", + virtualMachine: &vmopv1alpha1.VirtualMachine{ + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + expectedVM: &vmopv1alpha1.VirtualMachine{ + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + }, + { + name: "Create: when create error", + virtualMachine: &vmopv1alpha1.VirtualMachine{ + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + createFunc: func(action clientgotesting.Action) (bool, runtime.Object, error) { + return true, nil, fmt.Errorf("test error") + }, + expectedVM: nil, + expectedErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + vms, fc := initVMTest() + if testCase.createFunc != nil { + fc.PrependReactor("create", "*", testCase.createFunc) + } + actualVM, err := vms.Create(context.Background(), testCase.virtualMachine, metav1.CreateOptions{}) + if testCase.expectedErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, testCase.expectedVM.Spec, actualVM.Spec) + } + }) + } +} + +func TestVMUpdate(t *testing.T) { + testCases := []struct { + name string + oldVM *vmopv1alpha1.VirtualMachine + newVM *vmopv1alpha1.VirtualMachine + updateFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) + expectedVM *vmopv1alpha1.VirtualMachine + expectedErr bool + }{ + { + name: "Update: when everything is ok", + oldVM: &vmopv1alpha1.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + newVM: &vmopv1alpha1.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image-2", + }, + }, + expectedVM: &vmopv1alpha1.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image-2", + }, + }, + }, + { + name: "Update: when update error", + oldVM: &vmopv1alpha1.VirtualMachine{ + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + newVM: &vmopv1alpha1.VirtualMachine{ + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + updateFunc: func(action clientgotesting.Action) (bool, runtime.Object, error) { + return true, nil, fmt.Errorf("test error") + }, + expectedVM: nil, + expectedErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + vms, fc := initVMTest() + _, err := vms.Create(context.Background(), testCase.oldVM, metav1.CreateOptions{}) + assert.NoError(t, err) + if testCase.updateFunc != nil { + fc.PrependReactor("update", "*", testCase.updateFunc) + } + updatedVM, err := vms.Update(context.Background(), testCase.newVM, metav1.UpdateOptions{}) + if testCase.expectedErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, testCase.expectedVM.Spec, updatedVM.Spec) + } + }) + } +} + +func TestVMDelete(t *testing.T) { + testCases := []struct { + name string + virtualMachine *vmopv1alpha1.VirtualMachine + deleteFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) + expectedErr bool + }{ + { + name: "Delete: when everything is ok", + virtualMachine: &vmopv1alpha1.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + }, + { + name: "Delete: when delete error", + virtualMachine: &vmopv1alpha1.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + deleteFunc: func(action clientgotesting.Action) (bool, runtime.Object, error) { + return true, nil, fmt.Errorf("test error") + }, + expectedErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + vms, fc := initVMTest() + _, err := vms.Create(context.Background(), testCase.virtualMachine, metav1.CreateOptions{}) + assert.NoError(t, err) + if testCase.deleteFunc != nil { + fc.PrependReactor("delete", "*", testCase.deleteFunc) + } + err = vms.Delete(context.Background(), testCase.virtualMachine.Name, metav1.DeleteOptions{}) + if testCase.expectedErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestVMGet(t *testing.T) { + testCases := []struct { + name string + virtualMachine *vmopv1alpha1.VirtualMachine + getFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) + expectedVM *vmopv1alpha1.VirtualMachine + expectedErr bool + }{ + { + name: "Get: when everything is ok", + virtualMachine: &vmopv1alpha1.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + expectedVM: &vmopv1alpha1.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + }, + { + name: "Get: when get error", + virtualMachine: &vmopv1alpha1.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm-error", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + getFunc: func(action clientgotesting.Action) (bool, runtime.Object, error) { + return true, nil, fmt.Errorf("test error") + }, + expectedVM: nil, + expectedErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + vms, fc := initVMTest() + _, err := vms.Create(context.Background(), testCase.virtualMachine, metav1.CreateOptions{}) + assert.NoError(t, err) + if testCase.getFunc != nil { + fc.PrependReactor("get", "*", testCase.getFunc) + } + actualVM, err := vms.Get(context.Background(), testCase.virtualMachine.Name, metav1.GetOptions{}) + if testCase.expectedErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, testCase.expectedVM.Spec, actualVM.Spec) + } + }) + } +} + +func TestVMList(t *testing.T) { + testCases := []struct { + name string + virtualMachineList *vmopv1alpha1.VirtualMachineList + listFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) + expectedVMNum int + expectedErr bool + }{ + { + name: "List: when there is one virtual machine, list should be ok", + virtualMachineList: &vmopv1alpha1.VirtualMachineList{ + Items: []vmopv1alpha1.VirtualMachine{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + }, + }, + expectedVMNum: 1, + }, + { + name: "List: when there is 2 virtual machines, list should be ok", + virtualMachineList: &vmopv1alpha1.VirtualMachineList{ + Items: []vmopv1alpha1.VirtualMachine{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm-2", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + }, + }, + expectedVMNum: 2, + }, + { + name: "List: when there is 0 virtual machine, list should be ok", + virtualMachineList: &vmopv1alpha1.VirtualMachineList{ + Items: []vmopv1alpha1.VirtualMachine{}, + }, + expectedVMNum: 0, + }, + { + name: "List: when list error", + virtualMachineList: &vmopv1alpha1.VirtualMachineList{ + Items: []vmopv1alpha1.VirtualMachine{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineSpec{ + ImageName: "test-image", + }, + }, + }, + }, + listFunc: func(action clientgotesting.Action) (bool, runtime.Object, error) { + return true, nil, fmt.Errorf("test error") + }, + expectedVMNum: 0, + expectedErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + vms, fc := initVMTest() + for _, vm := range testCase.virtualMachineList.Items { + _, err := vms.Create(context.Background(), &vm, metav1.CreateOptions{}) + assert.NoError(t, err) + if testCase.listFunc != nil { + fc.PrependReactor("list", "*", testCase.listFunc) + } + } + + vmList, err := vms.List(context.Background(), metav1.ListOptions{}) + if testCase.expectedErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, testCase.expectedVMNum, len(vmList.Items)) + } + }) + } +} diff --git a/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachineservice_client.go b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachineservice_client.go new file mode 100644 index 000000000..56e3a9845 --- /dev/null +++ b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachineservice_client.go @@ -0,0 +1,87 @@ +package client + +import ( + "context" + + vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic" + + "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator" +) + +// virtualMachineServices implements VirtualMachineServiceInterface +type virtualMachineServices struct { + client dynamic.Interface + ns string +} + +// newVirtualMachineServices returns a VirtualMachineServices +func newVirtualMachineServices(c vmoperator.V1alpha1Interface, namespace string) *virtualMachineServices { + return &virtualMachineServices{ + client: c.Client(), + ns: namespace, + } +} + +func (v *virtualMachineServices) Create(ctx context.Context, virtualMachineService *vmopv1alpha1.VirtualMachineService, opts v1.CreateOptions) (*vmopv1alpha1.VirtualMachineService, error) { + unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(virtualMachineService) + if err != nil { + return nil, err + } + + obj, err := v.client.Resource(VirtualMachineServiceGVR).Namespace(v.ns).Create(ctx, &unstructured.Unstructured{Object: unstructuredObj}, opts) + if err != nil { + return nil, err + } + + createdVirtualMachineService := &vmopv1alpha1.VirtualMachineService{} + if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), createdVirtualMachineService); err != nil { + return nil, err + } + return createdVirtualMachineService, nil +} + +func (v *virtualMachineServices) Update(ctx context.Context, virtualMachineService *vmopv1alpha1.VirtualMachineService, opts v1.UpdateOptions) (*vmopv1alpha1.VirtualMachineService, error) { + unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(virtualMachineService) + if err != nil { + return nil, err + } + + obj, err := v.client.Resource(VirtualMachineServiceGVR).Namespace(v.ns).Update(ctx, &unstructured.Unstructured{Object: unstructuredObj}, opts) + if err != nil { + return nil, err + } + + updatedVirtualMachineService := &vmopv1alpha1.VirtualMachineService{} + if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), updatedVirtualMachineService); err != nil { + return nil, err + } + return updatedVirtualMachineService, nil +} + +func (v *virtualMachineServices) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return v.client.Resource(VirtualMachineServiceGVR).Namespace(v.ns).Delete(ctx, name, opts) +} + +func (v *virtualMachineServices) Get(ctx context.Context, name string, opts v1.GetOptions) (*vmopv1alpha1.VirtualMachineService, error) { + virtualMachineService := &vmopv1alpha1.VirtualMachineService{} + if obj, err := v.client.Resource(VirtualMachineServiceGVR).Namespace(v.ns).Get(ctx, name, opts); err != nil { + return nil, err + } else if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), virtualMachineService); err != nil { + return nil, err + } + return virtualMachineService, nil +} + +func (v *virtualMachineServices) List(ctx context.Context, opts v1.ListOptions) (*vmopv1alpha1.VirtualMachineServiceList, error) { + virtualMachineServiceList := &vmopv1alpha1.VirtualMachineServiceList{} + if obj, err := v.client.Resource(VirtualMachineServiceGVR).Namespace(v.ns).List(ctx, opts); err != nil { + return nil, err + } else if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), virtualMachineServiceList); err != nil { + return nil, err + } + return virtualMachineServiceList, nil +} diff --git a/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachineservice_client_test.go b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachineservice_client_test.go new file mode 100644 index 000000000..671633761 --- /dev/null +++ b/pkg/cloudprovider/vsphereparavirtual/vmoperator/client/virtualmachineservice_client_test.go @@ -0,0 +1,367 @@ +package client + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + clientgotesting "k8s.io/client-go/testing" + + dynamicfake "k8s.io/client-go/dynamic/fake" +) + +func initVMServiceTest() (*virtualMachineServices, *dynamicfake.FakeDynamicClient) { + scheme := runtime.NewScheme() + _ = vmopv1alpha1.AddToScheme(scheme) + fc := dynamicfake.NewSimpleDynamicClient(scheme) + vms := newVirtualMachineServices(NewFakeClientSet(fc).V1alpha1(), "test-ns") + return vms, fc +} + +func TestVMServiceCreate(t *testing.T) { + testCases := []struct { + name string + virtualMachineService *vmopv1alpha1.VirtualMachineService + createFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) + expectedVMService *vmopv1alpha1.VirtualMachineService + expectedErr bool + }{ + { + name: "Create: when everything is ok", + virtualMachineService: &vmopv1alpha1.VirtualMachineService{ + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + expectedVMService: &vmopv1alpha1.VirtualMachineService{ + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + }, + { + name: "Create: when create error", + virtualMachineService: &vmopv1alpha1.VirtualMachineService{ + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + createFunc: func(action clientgotesting.Action) (bool, runtime.Object, error) { + return true, nil, fmt.Errorf("test error") + }, + expectedVMService: nil, + expectedErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + vms, fc := initVMServiceTest() + if testCase.createFunc != nil { + fc.PrependReactor("create", "*", testCase.createFunc) + } + actualVM, err := vms.Create(context.Background(), testCase.virtualMachineService, metav1.CreateOptions{}) + if testCase.expectedErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, testCase.expectedVMService.Spec, actualVM.Spec) + } + }) + } +} + +func TestVMServiceUpdate(t *testing.T) { + testCases := []struct { + name string + oldVMService *vmopv1alpha1.VirtualMachineService + newVMService *vmopv1alpha1.VirtualMachineService + updateFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) + expectedVMService *vmopv1alpha1.VirtualMachineService + expectedErr bool + }{ + { + name: "Update: when everything is ok", + oldVMService: &vmopv1alpha1.VirtualMachineService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + newVMService: &vmopv1alpha1.VirtualMachineService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + expectedVMService: &vmopv1alpha1.VirtualMachineService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + }, + { + name: "Update: when update error", + oldVMService: &vmopv1alpha1.VirtualMachineService{ + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + newVMService: &vmopv1alpha1.VirtualMachineService{ + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + updateFunc: func(action clientgotesting.Action) (bool, runtime.Object, error) { + return true, nil, fmt.Errorf("test error") + }, + expectedVMService: nil, + expectedErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + vms, fc := initVMServiceTest() + _, err := vms.Create(context.Background(), testCase.oldVMService, metav1.CreateOptions{}) + assert.NoError(t, err) + if testCase.updateFunc != nil { + fc.PrependReactor("update", "*", testCase.updateFunc) + } + updatedVM, err := vms.Update(context.Background(), testCase.newVMService, metav1.UpdateOptions{}) + if testCase.expectedErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, testCase.expectedVMService.Spec, updatedVM.Spec) + } + }) + } +} + +func TestVMServiceDelete(t *testing.T) { + testCases := []struct { + name string + virtualMachineService *vmopv1alpha1.VirtualMachineService + deleteFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) + expectedErr bool + }{ + { + name: "Delete: when everything is ok", + virtualMachineService: &vmopv1alpha1.VirtualMachineService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + }, + { + name: "Delete: when delete error", + virtualMachineService: &vmopv1alpha1.VirtualMachineService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + deleteFunc: func(action clientgotesting.Action) (bool, runtime.Object, error) { + return true, nil, fmt.Errorf("test error") + }, + expectedErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + vms, fc := initVMServiceTest() + _, err := vms.Create(context.Background(), testCase.virtualMachineService, metav1.CreateOptions{}) + assert.NoError(t, err) + if testCase.deleteFunc != nil { + fc.PrependReactor("delete", "*", testCase.deleteFunc) + } + err = vms.Delete(context.Background(), testCase.virtualMachineService.Name, metav1.DeleteOptions{}) + if testCase.expectedErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestVMServiceGet(t *testing.T) { + testCases := []struct { + name string + virtualMachineService *vmopv1alpha1.VirtualMachineService + getFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) + expectedVMService *vmopv1alpha1.VirtualMachineService + expectedErr bool + }{ + { + name: "Get: when everything is ok", + virtualMachineService: &vmopv1alpha1.VirtualMachineService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + expectedVMService: &vmopv1alpha1.VirtualMachineService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + }, + { + name: "Get: when get error", + virtualMachineService: &vmopv1alpha1.VirtualMachineService{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm-error", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + getFunc: func(action clientgotesting.Action) (bool, runtime.Object, error) { + return true, nil, fmt.Errorf("test error") + }, + expectedVMService: nil, + expectedErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + vms, fc := initVMServiceTest() + _, err := vms.Create(context.Background(), testCase.virtualMachineService, metav1.CreateOptions{}) + assert.NoError(t, err) + if testCase.getFunc != nil { + fc.PrependReactor("get", "*", testCase.getFunc) + } + actualVM, err := vms.Get(context.Background(), testCase.virtualMachineService.Name, metav1.GetOptions{}) + if testCase.expectedErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, testCase.expectedVMService.Spec, actualVM.Spec) + } + }) + } +} + +func TestVMServiceList(t *testing.T) { + testCases := []struct { + name string + virtualMachineServiceList *vmopv1alpha1.VirtualMachineServiceList + listFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) + expectedVMServiceNum int + expectedErr bool + }{ + { + name: "List: when there is one virtual machine service, list should be ok", + virtualMachineServiceList: &vmopv1alpha1.VirtualMachineServiceList{ + Items: []vmopv1alpha1.VirtualMachineService{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + }, + }, + expectedVMServiceNum: 1, + }, + { + name: "List: when there is 2 virtual machine services, list should be ok", + virtualMachineServiceList: &vmopv1alpha1.VirtualMachineServiceList{ + Items: []vmopv1alpha1.VirtualMachineService{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm-2", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + }, + }, + expectedVMServiceNum: 2, + }, + { + name: "List: when there is 0 virtual machine service, list should be ok", + virtualMachineServiceList: &vmopv1alpha1.VirtualMachineServiceList{ + Items: []vmopv1alpha1.VirtualMachineService{}, + }, + expectedVMServiceNum: 0, + }, + { + name: "List: when list error", + virtualMachineServiceList: &vmopv1alpha1.VirtualMachineServiceList{ + Items: []vmopv1alpha1.VirtualMachineService{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + }, + Spec: vmopv1alpha1.VirtualMachineServiceSpec{ + Type: "NodePort", + }, + }, + }, + }, + listFunc: func(action clientgotesting.Action) (bool, runtime.Object, error) { + return true, nil, fmt.Errorf("test error") + }, + expectedVMServiceNum: 0, + expectedErr: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + vms, fc := initVMServiceTest() + for _, vmservice := range testCase.virtualMachineServiceList.Items { + _, err := vms.Create(context.Background(), &vmservice, metav1.CreateOptions{}) + assert.NoError(t, err) + if testCase.listFunc != nil { + fc.PrependReactor("list", "*", testCase.listFunc) + } + } + + vmServiceList, err := vms.List(context.Background(), metav1.ListOptions{}) + if testCase.expectedErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, testCase.expectedVMServiceNum, len(vmServiceList.Items)) + } + }) + } +} diff --git a/pkg/cloudprovider/vsphereparavirtual/vmoperator/interface.go b/pkg/cloudprovider/vsphereparavirtual/vmoperator/interface.go new file mode 100644 index 000000000..76421fd35 --- /dev/null +++ b/pkg/cloudprovider/vsphereparavirtual/vmoperator/interface.go @@ -0,0 +1,40 @@ +package vmoperator + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/dynamic" + + vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" +) + +// Interface has methods to work with Vmoperator resources. +type Interface interface { + V1alpha1() V1alpha1Interface +} + +// V1alpha1Interface has methods to work with Vmoperator V1alpha1 resources. +type V1alpha1Interface interface { + Client() dynamic.Interface + VirtualMachines(namespace string) VirtualMachineInterface + VirtualMachineServices(namespace string) VirtualMachineServiceInterface +} + +// VirtualMachineInterface has methods to work with VirtualMachineService resources. +type VirtualMachineInterface interface { + Create(ctx context.Context, virtualMachine *vmopv1alpha1.VirtualMachine, opts v1.CreateOptions) (*vmopv1alpha1.VirtualMachine, error) + Update(ctx context.Context, virtualMachine *vmopv1alpha1.VirtualMachine, opts v1.UpdateOptions) (*vmopv1alpha1.VirtualMachine, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*vmopv1alpha1.VirtualMachine, error) + List(ctx context.Context, opts v1.ListOptions) (*vmopv1alpha1.VirtualMachineList, error) +} + +// VirtualMachineServiceInterface has methods to work with VirtualMachineService resources. +type VirtualMachineServiceInterface interface { + Create(ctx context.Context, virtualMachineService *vmopv1alpha1.VirtualMachineService, opts v1.CreateOptions) (*vmopv1alpha1.VirtualMachineService, error) + Update(ctx context.Context, virtualMachineService *vmopv1alpha1.VirtualMachineService, opts v1.UpdateOptions) (*vmopv1alpha1.VirtualMachineService, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*vmopv1alpha1.VirtualMachineService, error) + List(ctx context.Context, opts v1.ListOptions) (*vmopv1alpha1.VirtualMachineServiceList, error) +} diff --git a/pkg/cloudprovider/vsphereparavirtual/vmservice/types.go b/pkg/cloudprovider/vsphereparavirtual/vmservice/types.go index 556e9bb16..ef4cd2342 100644 --- a/pkg/cloudprovider/vsphereparavirtual/vmservice/types.go +++ b/pkg/cloudprovider/vsphereparavirtual/vmservice/types.go @@ -22,9 +22,9 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog/v2/klogr" - "sigs.k8s.io/controller-runtime/pkg/client" "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" + vmop "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator" ) var log = klogr.New().WithName("vmservice") @@ -41,7 +41,7 @@ type VMService interface { // vmService takes care of mapping of LB type of service to VM service in supervisor cluster type vmService struct { - vmClient client.Client + vmClient vmop.Interface namespace string ownerReference *metav1.OwnerReference } diff --git a/pkg/cloudprovider/vsphereparavirtual/vmservice/vmservice.go b/pkg/cloudprovider/vsphereparavirtual/vmservice/vmservice.go index d5cc12120..bd014a294 100644 --- a/pkg/cloudprovider/vsphereparavirtual/vmservice/vmservice.go +++ b/pkg/cloudprovider/vsphereparavirtual/vmservice/vmservice.go @@ -28,12 +28,11 @@ import ( v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" rest "k8s.io/client-go/rest" - client "sigs.k8s.io/controller-runtime/pkg/client" vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" + vmop "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator" + vmopclient "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator/client" ) const ( @@ -89,17 +88,12 @@ var ( // GetVmopClient gets a vm-operator-api client // This is separate from NewVMService so that a fake client can be injected for testing -func GetVmopClient(config *rest.Config) (client.Client, error) { - scheme := runtime.NewScheme() - _ = vmopv1alpha1.AddToScheme(scheme) - client, err := client.New(config, client.Options{ - Scheme: scheme, - }) - return client, err +func GetVmopClient(config *rest.Config) (vmop.Interface, error) { + return vmopclient.NewForConfig(config) } // NewVMService creates a vmService object -func NewVMService(vmClient client.Client, ns string, ownerRef *metav1.OwnerReference) VMService { +func NewVMService(vmClient vmop.Interface, ns string, ownerRef *metav1.OwnerReference) VMService { return &vmService{ vmClient: vmClient, namespace: ns, @@ -135,10 +129,8 @@ func (s *vmService) Get(ctx context.Context, service *v1.Service, clusterName st logger := log.WithValues("name", service.Name, "namespace", service.Namespace) logger.V(2).Info("Attempting to get VirtualMachineService") - vmService := vmopv1alpha1.VirtualMachineService{} - vmServiceKey := types.NamespacedName{Name: s.GetVMServiceName(service, clusterName), Namespace: s.namespace} - - if err := s.vmClient.Get(ctx, vmServiceKey, &vmService); err != nil { + vmService, err := s.vmClient.V1alpha1().VirtualMachineServices(s.namespace).Get(ctx, s.GetVMServiceName(service, clusterName), metav1.GetOptions{}) + if err != nil { if apierrors.IsNotFound(err) { return nil, nil } @@ -146,7 +138,7 @@ func (s *vmService) Get(ctx context.Context, service *v1.Service, clusterName st return nil, err } - return &vmService, nil + return vmService, nil } // Create creates a vmservice to map to the given lb type of service, it should be called if vmservice not found @@ -160,8 +152,8 @@ func (s *vmService) Create(ctx context.Context, service *v1.Service, clusterName return nil, err } - vmService.Namespace = s.namespace - if err = s.vmClient.Create(ctx, vmService); err != nil { + vmService, err = s.vmClient.V1alpha1().VirtualMachineServices(s.namespace).Create(ctx, vmService, metav1.CreateOptions{}) + if err != nil { logger.Error(ErrCreateVMService, fmt.Sprintf("%v", err)) return nil, err } @@ -258,7 +250,8 @@ func (s *vmService) Update(ctx context.Context, service *v1.Service, clusterName } if needsUpdate { - if err := s.vmClient.Update(ctx, newVMService); err != nil { + newVMService, err = s.vmClient.V1alpha1().VirtualMachineServices(s.namespace).Update(ctx, newVMService, metav1.UpdateOptions{}) + if err != nil { logger.Error(ErrUpdateVMService, fmt.Sprintf("%v", err)) return nil, err } @@ -275,11 +268,8 @@ func (s *vmService) Delete(ctx context.Context, service *v1.Service, clusterName logger := log.WithValues("name", service.Name, "namespace", service.Namespace) logger.V(2).Info("Attempting to delete VirtualMachineService") - vmService := vmopv1alpha1.VirtualMachineService{} - vmService.Name = s.GetVMServiceName(service, clusterName) - vmService.Namespace = s.namespace - - if err := s.vmClient.Delete(ctx, &vmService); err != nil { + err := s.vmClient.V1alpha1().VirtualMachineServices(s.namespace).Delete(ctx, s.GetVMServiceName(service, clusterName), metav1.DeleteOptions{}) + if err != nil { logger.Error(ErrDeleteVMService, fmt.Sprintf("%v", err)) return err } diff --git a/pkg/cloudprovider/vsphereparavirtual/vmservice/vmservice_test.go b/pkg/cloudprovider/vsphereparavirtual/vmservice/vmservice_test.go index 0436dc825..2f8c8991b 100644 --- a/pkg/cloudprovider/vsphereparavirtual/vmservice/vmservice_test.go +++ b/pkg/cloudprovider/vsphereparavirtual/vmservice/vmservice_test.go @@ -24,19 +24,19 @@ import ( "github.com/stretchr/testify/assert" + vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" v1 "k8s.io/api/core/v1" "k8s.io/api/node/v1alpha1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/intstr" - "sigs.k8s.io/controller-runtime/pkg/client" - fakeClient "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/envtest" + runtime "k8s.io/apimachinery/pkg/runtime" + rest "k8s.io/client-go/rest" + clientgotesting "k8s.io/client-go/testing" - vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" + "k8s.io/apimachinery/pkg/util/intstr" + dynamicfake "k8s.io/client-go/dynamic/fake" - "k8s.io/cloud-provider-vsphere/pkg/util" + vmopclient "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator/client" ) var ( @@ -52,12 +52,9 @@ var ( } vms VMService fakeLBIP = "1.1.1.1" - - // FakeClientWrapper allows functions to be replaced for fault injection - fcw *util.FakeClientWrapper ) -func initTest() (*v1.Service, VMService, *util.FakeClientWrapper) { +func initTest() (*v1.Service, VMService, *dynamicfake.FakeDynamicClient) { testK8sService := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: testK8sServiceName, @@ -78,42 +75,35 @@ func initTest() (*v1.Service, VMService, *util.FakeClientWrapper) { }, }, } + scheme := runtime.NewScheme() _ = vmopv1alpha1.AddToScheme(scheme) - fc := fakeClient.NewClientBuilder().WithScheme(scheme).Build() - fcw = util.NewFakeClientWrapper(fc) - vms = NewVMService(fcw, testClusterNameSpace, &testOwnerReference) - - return testK8sService, vms, fcw + fc := dynamicfake.NewSimpleDynamicClient(scheme) + vms = NewVMService(vmopclient.NewFakeClientSet(fc), testClusterNameSpace, &testOwnerReference) + return testK8sService, vms, fc } func TestNewVMService(t *testing.T) { testCases := []struct { - name string - testEnv *envtest.Environment - err error + name string + config *rest.Config + err error }{ { - name: "NewVMService: when everything is ok", - testEnv: &envtest.Environment{}, - err: nil, + name: "NewVMService: when everything is ok", + config: &rest.Config{}, + err: nil, }, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - cfg, err := testCase.testEnv.Start() - assert.NoError(t, err) - - client, err := GetVmopClient(cfg) + client, err := GetVmopClient(testCase.config) assert.NoError(t, err) assert.NotEqual(t, client, nil) realVms := NewVMService(client, testClusterNameSpace, &testOwnerReference) assert.NotEqual(t, realVms, nil) - - err = testCase.testEnv.Stop() - assert.NoError(t, err) }) } } @@ -155,7 +145,6 @@ func TestGetVMService(t *testing.T) { } // create a fake VMService createdVMService, _ := vms.Create(context.Background(), k8sService, testClustername) - vmService, err := vms.Get(context.Background(), k8sService, testClustername) assert.NoError(t, err) assert.Equal(t, (*vmService).Spec, (*createdVMService).Spec) @@ -408,20 +397,20 @@ func TestCreateOrUpdateVMService(t *testing.T) { func TestCreateOrUpdateVMService_RedefineGetFunc(t *testing.T) { testCases := []struct { name string - getFunc func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error + getFunc func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) expectedErr error }{ { name: "failed to create VirtualMachineService", - getFunc: func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - return fmt.Errorf("failed to get VirtualMachineService") + getFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, fmt.Errorf("failed to get VirtualMachineService") }, expectedErr: ErrGetVMService, }, { name: "when VMService does not exist", - getFunc: func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - return apierrors.NewNotFound(v1alpha1.Resource("virtualmachineservice"), testClustername) + getFunc: func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, apierrors.NewNotFound(v1alpha1.Resource("virtualmachineservice"), testClustername) }, expectedErr: ErrVMServiceIPNotFound, }, @@ -429,9 +418,9 @@ func TestCreateOrUpdateVMService_RedefineGetFunc(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - testK8sService, vms, fcw := initTest() + testK8sService, vms, fc := initTest() // Redefine Get in the client to return an error - fcw.GetFunc = testCase.getFunc + fc.PrependReactor("get", "virtualmachineservices", testCase.getFunc) _, err := vms.CreateOrUpdate(context.Background(), testK8sService, testClustername) assert.Equal(t, testCase.expectedErr.Error(), err.Error()) }) @@ -439,11 +428,11 @@ func TestCreateOrUpdateVMService_RedefineGetFunc(t *testing.T) { } func TestCreateOrUpdateVMService_RedefineCreateFunc(t *testing.T) { - testK8sService, vms, fcw := initTest() + testK8sService, vms, fc := initTest() // Redefine Create in the client to return an error - fcw.CreateFunc = func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { - return fmt.Errorf("failed to create VirtualMachineService") - } + fc.PrependReactor("create", "virtualmachineservices", func(action clientgotesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, fmt.Errorf("failed to create VirtualMachineService") + }) _, err := vms.CreateOrUpdate(context.Background(), testK8sService, testClustername) assert.Equal(t, ErrCreateVMService.Error(), err.Error()) } diff --git a/pkg/cloudprovider/vsphereparavirtual/zone.go b/pkg/cloudprovider/vsphereparavirtual/zone.go index 7f896d0b5..e0756c5ee 100644 --- a/pkg/cloudprovider/vsphereparavirtual/zone.go +++ b/pkg/cloudprovider/vsphereparavirtual/zone.go @@ -4,16 +4,17 @@ import ( "context" vmopv1alpha1 "github.com/vmware-tanzu/vm-operator-api/api/v1alpha1" + vmop "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/rest" cloudprovider "k8s.io/cloud-provider" "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmservice" "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" ) type zones struct { - vmClient client.Client + vmClient vmop.Interface namespace string } diff --git a/pkg/cloudprovider/vsphereparavirtual/zone_test.go b/pkg/cloudprovider/vsphereparavirtual/zone_test.go index f898705b0..ae8b972e7 100644 --- a/pkg/cloudprovider/vsphereparavirtual/zone_test.go +++ b/pkg/cloudprovider/vsphereparavirtual/zone_test.go @@ -9,10 +9,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + dynamicfake "k8s.io/client-go/dynamic/fake" + "k8s.io/client-go/rest" cloudprovider "k8s.io/cloud-provider" - "k8s.io/cloud-provider-vsphere/pkg/util" - fakeClient "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/envtest" + + vmopclient "k8s.io/cloud-provider-vsphere/pkg/cloudprovider/vsphereparavirtual/vmoperator/client" ) var ( @@ -25,13 +26,13 @@ var ( func TestNewZones(t *testing.T) { testCases := []struct { name string - testEnv *envtest.Environment + config *rest.Config expectedErr error testVM *vmopv1alpha1.VirtualMachine }{ { name: "NewZone: when everything is ok", - testEnv: &envtest.Environment{}, + config: &rest.Config{}, testVM: createTestVMWithZone(string(vmName), testClusterNameSpace), expectedErr: nil, }, @@ -39,15 +40,10 @@ func TestNewZones(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - cfg, err := testCase.testEnv.Start() - assert.NoError(t, err) //initVMopClient(testCase.testVM) - _, err = NewZones(testClusterNameSpace, cfg) + _, err := NewZones(testClusterNameSpace, testCase.config) assert.NoError(t, err) assert.Equal(t, testCase.expectedErr, err) - - err = testCase.testEnv.Stop() - assert.NoError(t, err) }) } } @@ -55,7 +51,6 @@ func TestNewZones(t *testing.T) { func TestZonesByProviderID(t *testing.T) { testCases := []struct { name string - testEnv *envtest.Environment expectedResult string expectedErr error testVM *vmopv1alpha1.VirtualMachine @@ -78,7 +73,8 @@ func TestZonesByProviderID(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { ctx := context.Background() - zone, _ := initVMopClient(testCase.testVM) + zone, _, err := initVMopClient(testCase.testVM) + assert.NoError(t, err) z, err := zone.GetZoneByProviderID(ctx, providerid) if testCase.expectedErr != nil { @@ -95,7 +91,6 @@ func TestZonesByProviderID(t *testing.T) { func TestZonesByNodeName(t *testing.T) { testCases := []struct { name string - testEnv *envtest.Environment expectedResult string expectedErr error testVM *vmopv1alpha1.VirtualMachine @@ -121,7 +116,8 @@ func TestZonesByNodeName(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { ctx := context.Background() - zone, _ := initVMopClient(testCase.testVM) + zone, _, err := initVMopClient(testCase.testVM) + assert.NoError(t, err) z, err := zone.GetZoneByNodeName(ctx, testCase.vmName) if testCase.expectedErr != nil { @@ -135,16 +131,17 @@ func TestZonesByNodeName(t *testing.T) { } } -func initVMopClient(testVM *vmopv1alpha1.VirtualMachine) (zones, *util.FakeClientWrapper) { +func initVMopClient(testVM *vmopv1alpha1.VirtualMachine) (zones, *dynamicfake.FakeDynamicClient, error) { scheme := runtime.NewScheme() _ = vmopv1alpha1.AddToScheme(scheme) - fc := fakeClient.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(testVM).Build() - fcw := util.NewFakeClientWrapper(fc) + fc := dynamicfake.NewSimpleDynamicClient(scheme) + fcw := vmopclient.NewFakeClientSet(fc) zone := zones{ vmClient: fcw, namespace: testClusterNameSpace, } - return zone, fcw + _, err := fcw.V1alpha1().VirtualMachines(testVM.Namespace).Create(context.TODO(), testVM, metav1.CreateOptions{}) + return zone, fc, err } func createTestVMWithZone(name, namespace string) *vmopv1alpha1.VirtualMachine { diff --git a/pkg/util/fake_client_wrapper.go b/pkg/util/fake_client_wrapper.go deleted file mode 100644 index f39b81fdc..000000000 --- a/pkg/util/fake_client_wrapper.go +++ /dev/null @@ -1,126 +0,0 @@ -/* -Copyright 2021 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import ( - "context" - - "k8s.io/apimachinery/pkg/runtime/schema" - - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime" - - client "sigs.k8s.io/controller-runtime/pkg/client" -) - -// FakeClientWrapper allows functions to be replaced for fault injection -type FakeClientWrapper struct { - fakeClient client.Client - // Set these functions if you want to override the default fakeClient behavior - GetFunc func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error - CreateFunc func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error - UpdateFunc func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error - DeleteFunc func(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error - ListFunc func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error -} - -// Scheme invokes the fakeClient's Scheme -func (w *FakeClientWrapper) Scheme() *runtime.Scheme { - return w.fakeClient.Scheme() -} - -// RESTMapper invokes the fakeClient's RESTMapper -func (w *FakeClientWrapper) RESTMapper() meta.RESTMapper { - return w.fakeClient.RESTMapper() -} - -// NewFakeClientWrapper creates a FakeClientWrapper -func NewFakeClientWrapper(fakeClient client.Client) *FakeClientWrapper { - fcw := FakeClientWrapper{} - fcw.fakeClient = fakeClient - return &fcw -} - -// Get retrieves an obj for the given object key from the Kubernetes Cluster. -func (w *FakeClientWrapper) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - if w.GetFunc != nil { - return w.GetFunc(ctx, key, obj, opts...) - } - return w.fakeClient.Get(ctx, key, obj, opts...) -} - -// List retrieves list of objects for a given namespace and list options. -func (w *FakeClientWrapper) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { - if w.ListFunc != nil { - return w.ListFunc(ctx, list, opts...) - } - return w.fakeClient.List(ctx, list, opts...) -} - -// Create saves the object obj in the Kubernetes cluster. -func (w *FakeClientWrapper) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error { - if w.CreateFunc != nil { - return w.CreateFunc(ctx, obj, opts...) - } - return w.fakeClient.Create(ctx, obj, opts...) -} - -// Delete deletes the given obj from Kubernetes cluster. -func (w *FakeClientWrapper) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error { - if w.DeleteFunc != nil { - return w.DeleteFunc(ctx, obj, opts...) - } - return w.fakeClient.Delete(ctx, obj, opts...) -} - -// Update updates the given obj in the Kubernetes cluster. -func (w *FakeClientWrapper) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { - if w.UpdateFunc != nil { - return w.UpdateFunc(ctx, obj, opts...) - } - return w.fakeClient.Update(ctx, obj, opts...) -} - -// Patch patches the given obj in the Kubernetes cluster. -func (w *FakeClientWrapper) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { - return w.fakeClient.Patch(ctx, obj, patch, opts...) -} - -// DeleteAllOf deletes all objects of the given type matching the given options. -func (w *FakeClientWrapper) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error { - return w.fakeClient.DeleteAllOf(ctx, obj, opts...) -} - -// Status returns a StatusWriter which knows how to update status subresource of a Kubernetes object. -func (w *FakeClientWrapper) Status() client.StatusWriter { - return w.fakeClient.Status() -} - -// SubResource returns a SubResourceClient for the resource. -func (w *FakeClientWrapper) SubResource(subResource string) client.SubResourceClient { - return w.fakeClient.SubResource(subResource) -} - -// GroupVersionKindFor returns the GroupVersionKind for the given object. -func (w *FakeClientWrapper) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) { - return w.fakeClient.GroupVersionKindFor(obj) -} - -// IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced. -func (w *FakeClientWrapper) IsObjectNamespaced(obj runtime.Object) (bool, error) { - return w.fakeClient.IsObjectNamespaced(obj) -}