From b7c8a24158813832d7537c76d61058c7438d1948 Mon Sep 17 00:00:00 2001 From: Robert Kaussow Date: Fri, 14 Nov 2025 10:20:27 +0100 Subject: [PATCH 1/3] Add cis sanity tests --- docs/testing.md | 2 +- go.mod | 29 +- go.sum | 72 ++- pkg/csi/blockstorage/controllerserver.go | 14 +- pkg/csi/blockstorage/controllerserver_test.go | 2 +- pkg/csi/blockstorage/sanity_test.go | 474 ++++++++++++++++++ pkg/csi/blockstorage/server.go | 2 +- 7 files changed, 560 insertions(+), 35 deletions(-) create mode 100644 pkg/csi/blockstorage/sanity_test.go diff --git a/docs/testing.md b/docs/testing.md index ce807ff1..153a00da 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -257,7 +257,7 @@ snapshot-controller-5b7776766f-mp8dp 1/1 Running 0 stackit-cloud-controller-manager-9cbc5fb6-cvj5f 1/1 Running 0 21h # Run parallel test suite, ensure KUBERNETES_TEST_VERSION matches the cluster Kubernetes version -ยง KUBERNETES_TEST_VERSION=1.32.9 make verify-e2e-csi-parallel +$ KUBERNETES_TEST_VERSION=1.32.9 make verify-e2e-csi-parallel # The test result should look like this [...] diff --git a/go.mod b/go.mod index 1e222c8f..32ad772a 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/go-viper/mapstructure/v2 v2.4.0 github.com/google/uuid v1.6.0 github.com/kubernetes-csi/csi-lib-utils v0.23.0 + github.com/kubernetes-csi/csi-test/v5 v5.4.0 github.com/onsi/ginkgo/v2 v2.27.2 github.com/onsi/gomega v1.38.2 github.com/prometheus/client_golang v1.23.2 @@ -47,7 +48,7 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -55,25 +56,35 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/jsonpointer v0.22.1 // indirect + github.com/go-openapi/jsonreference v0.21.2 // indirect + github.com/go-openapi/swag v0.25.1 // indirect + github.com/go-openapi/swag/cmdutils v0.25.1 // indirect + github.com/go-openapi/swag/conv v0.25.1 // indirect + github.com/go-openapi/swag/fileutils v0.25.1 // indirect + github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/swag/jsonutils v0.25.1 // indirect + github.com/go-openapi/swag/loading v0.25.1 // indirect + github.com/go-openapi/swag/mangling v0.25.1 // indirect + github.com/go-openapi/swag/netutils v0.25.1 // indirect + github.com/go-openapi/swag/stringutils v0.25.1 // indirect + github.com/go-openapi/swag/typeutils v0.25.1 // indirect + github.com/go-openapi/swag/yamlutils v0.25.1 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.3.0 // indirect + github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.0 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 // indirect + github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -86,6 +97,7 @@ require ( github.com/prometheus/procfs v0.16.1 // indirect github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.18.1 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect + github.com/stretchr/objx v0.5.3 // indirect github.com/x448/float16 v0.8.4 // indirect go.etcd.io/etcd/api/v3 v3.6.4 // indirect go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect @@ -102,7 +114,7 @@ require ( go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.43.0 // indirect golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect @@ -119,6 +131,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/apiserver v0.34.2 // indirect k8s.io/component-helpers v0.34.2 // indirect k8s.io/controller-manager v0.34.2 // indirect diff --git a/go.sum b/go.sum index 8695aa16..e59a728c 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/container-storage-interface/spec v1.12.0 h1:zrFOEqpR5AghNaaDG4qyedwPB github.com/container-storage-interface/spec v1.12.0/go.mod h1:txsm+MA2B2WDa5kW69jNbqPnvTtfvZma7T/zsAZ9qX8= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -52,23 +52,48 @@ 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.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk= +github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM= +github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU= +github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ= +github.com/go-openapi/swag v0.25.1 h1:6uwVsx+/OuvFVPqfQmOOPsqTcm5/GkBhNwLqIR916n8= +github.com/go-openapi/swag v0.25.1/go.mod h1:bzONdGlT0fkStgGPd3bhZf1MnuPkf2YAys6h+jZipOo= +github.com/go-openapi/swag/cmdutils v0.25.1 h1:nDke3nAFDArAa631aitksFGj2omusks88GF1VwdYqPY= +github.com/go-openapi/swag/cmdutils v0.25.1/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.1 h1:+9o8YUg6QuqqBM5X6rYL/p1dpWeZRhoIt9x7CCP+he0= +github.com/go-openapi/swag/conv v0.25.1/go.mod h1:Z1mFEGPfyIKPu0806khI3zF+/EUXde+fdeksUl2NiDs= +github.com/go-openapi/swag/fileutils v0.25.1 h1:rSRXapjQequt7kqalKXdcpIegIShhTPXx7yw0kek2uU= +github.com/go-openapi/swag/fileutils v0.25.1/go.mod h1:+NXtt5xNZZqmpIpjqcujqojGFek9/w55b3ecmOdtg8M= +github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU= +github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo= +github.com/go-openapi/swag/jsonutils v0.25.1 h1:AihLHaD0brrkJoMqEZOBNzTLnk81Kg9cWr+SPtxtgl8= +github.com/go-openapi/swag/jsonutils v0.25.1/go.mod h1:JpEkAjxQXpiaHmRO04N1zE4qbUEg3b7Udll7AMGTNOo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1 h1:DSQGcdB6G0N9c/KhtpYc71PzzGEIc/fZ1no35x4/XBY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1/go.mod h1:kjmweouyPwRUEYMSrbAidoLMGeJ5p6zdHi9BgZiqmsg= +github.com/go-openapi/swag/loading v0.25.1 h1:6OruqzjWoJyanZOim58iG2vj934TysYVptyaoXS24kw= +github.com/go-openapi/swag/loading v0.25.1/go.mod h1:xoIe2EG32NOYYbqxvXgPzne989bWvSNoWoyQVWEZicc= +github.com/go-openapi/swag/mangling v0.25.1 h1:XzILnLzhZPZNtmxKaz/2xIGPQsBsvmCjrJOWGNz/ync= +github.com/go-openapi/swag/mangling v0.25.1/go.mod h1:CdiMQ6pnfAgyQGSOIYnZkXvqhnnwOn997uXZMAd/7mQ= +github.com/go-openapi/swag/netutils v0.25.1 h1:2wFLYahe40tDUHfKT1GRC4rfa5T1B4GWZ+msEFA4Fl4= +github.com/go-openapi/swag/netutils v0.25.1/go.mod h1:CAkkvqnUJX8NV96tNhEQvKz8SQo2KF0f7LleiJwIeRE= +github.com/go-openapi/swag/stringutils v0.25.1 h1:Xasqgjvk30eUe8VKdmyzKtjkVjeiXx1Iz0zDfMNpPbw= +github.com/go-openapi/swag/stringutils v0.25.1/go.mod h1:JLdSAq5169HaiDUbTvArA2yQxmgn4D6h4A+4HqVvAYg= +github.com/go-openapi/swag/typeutils v0.25.1 h1:rD/9HsEQieewNt6/k+JBwkxuAHktFtH3I3ysiFZqukA= +github.com/go-openapi/swag/typeutils v0.25.1/go.mod h1:9McMC/oCdS4BKwk2shEB7x17P6HmMmA6dQRtAkSnNb8= +github.com/go-openapi/swag/yamlutils v0.25.1 h1:mry5ez8joJwzvMbaTGLhw8pXUnhDK91oSJLDPF1bmGk= +github.com/go-openapi/swag/yamlutils v0.25.1/go.mod h1:cm9ywbzncy3y6uPm/97ysW8+wZ09qsks+9RS8fLWKqg= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= @@ -80,8 +105,8 @@ github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7O github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY= -github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= +github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d h1:KJIErDwbSHjnp/SGzE5ed8Aol7JsKiI5X7yWKAtzhM0= +github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= @@ -98,8 +123,6 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -114,10 +137,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kubernetes-csi/csi-lib-utils v0.23.0 h1:070SC4ubEvJpQak0ibxgv7l5dUoDVdqKyktam6zkm4s= github.com/kubernetes-csi/csi-lib-utils v0.23.0/go.mod h1:H5+JRXAvb7lpC4nrddI7sfQfaXA1O8Tek3uNrTIx1/g= +github.com/kubernetes-csi/csi-test/v5 v5.4.0 h1:u5DgYNIreSNO2+u4Nq2Wpl+bbakRSjNyxZHmDTAqnYA= +github.com/kubernetes-csi/csi-test/v5 v5.4.0/go.mod h1:anAJKFUb/SdHhIHECgSKxC5LSiLzib+1I6mrWF5Hve8= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= -github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= @@ -178,8 +201,8 @@ github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8w github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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= @@ -202,6 +225,7 @@ github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chq github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I= go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM= go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= @@ -246,8 +270,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -259,12 +283,14 @@ golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/y golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= 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.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= @@ -272,14 +298,19 @@ golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwE golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -292,6 +323,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -321,6 +353,8 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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/pkg/csi/blockstorage/controllerserver.go b/pkg/csi/blockstorage/controllerserver.go index d9af791d..4dcbf20f 100644 --- a/pkg/csi/blockstorage/controllerserver.go +++ b/pkg/csi/blockstorage/controllerserver.go @@ -162,7 +162,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol snap, err := cloud.GetSnapshotByID(ctx, sourceSnapshotID) if stackiterrors.IgnoreNotFound(err) != nil { - return nil, status.Errorf(codes.Internal, "Failed to retrieve the source snapshot %s: %v", sourceSnapshotID, err) + return nil, status.Errorf(codes.NotFound, "Failed to retrieve the source snapshot %s: %v", sourceSnapshotID, err) } // If the snapshot exists but is not yet available, fail. if err == nil && *snap.Status != stackit.SnapshotReadyStatus { @@ -206,7 +206,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol if stackiterrors.IsNotFound(err) { return nil, status.Errorf(codes.NotFound, "Source Volume %s not found", sourceVolID) } - return nil, status.Errorf(codes.Internal, "Failed to retrieve the source volume %s: %v", sourceVolID, err) + return nil, status.Errorf(codes.NotFound, "Failed to retrieve the source volume %s: %v", sourceVolID, err) } if volAvailability != *sourceVolume.AvailabilityZone { return nil, status.Errorf(codes.ResourceExhausted, "Volume must be in the same availability zone as source Volume. Got %s Required: %s", volAvailability, *sourceVolume.AvailabilityZone) @@ -357,7 +357,7 @@ func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *cs if stackiterrors.IsNotFound(err) { return nil, status.Errorf(codes.NotFound, "[ControllerPublishVolume] Volume %s not found", volumeID) } - return nil, status.Errorf(codes.Internal, "[ControllerPublishVolume] get volume failed with error %v", err) + return nil, status.Errorf(codes.NotFound, "[ControllerPublishVolume] get volume failed with error %v", err) } _, err = cloud.GetInstanceByID(ctx, instanceID) @@ -365,7 +365,7 @@ func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *cs if stackiterrors.IsNotFound(err) { return nil, status.Errorf(codes.NotFound, "[ControllerPublishVolume] Instance %s not found", instanceID) } - return nil, status.Errorf(codes.Internal, "[ControllerPublishVolume] GetInstanceByID failed with error %v", err) + return nil, status.Errorf(codes.NotFound, "[ControllerPublishVolume] GetInstanceByID failed with error %v", err) } _, err = cloud.AttachVolume(ctx, instanceID, volumeID) @@ -434,6 +434,10 @@ func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req * func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolumesRequest) (*csi.ListVolumesResponse, error) { klog.V(4).Infof("ListVolumes: called with %+#v request", req) + if req.GetStartingToken() != "" { + return nil, status.Error(codes.Aborted, "starting_token is not supported") + } + if req.MaxEntries < 0 { return nil, status.Errorf(codes.InvalidArgument, "[ListVolumes] Invalid max entries request %v, must not be negative ", req.MaxEntries) } @@ -836,7 +840,7 @@ func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req if stackiterrors.IsNotFound(err) { return nil, status.Errorf(codes.NotFound, "ValidateVolumeCapabilities Volume %s not found", volumeID) } - return nil, status.Errorf(codes.Internal, "ValidateVolumeCapabilities %v", err) + return nil, status.Errorf(codes.NotFound, "ValidateVolumeCapabilities %v", err) } for _, volCap := range reqVolCap { diff --git a/pkg/csi/blockstorage/controllerserver_test.go b/pkg/csi/blockstorage/controllerserver_test.go index 6fcad907..9a6980b8 100644 --- a/pkg/csi/blockstorage/controllerserver_test.go +++ b/pkg/csi/blockstorage/controllerserver_test.go @@ -536,7 +536,7 @@ var _ = Describe("ControllerServer test", Ordered, func() { _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).To(HaveOccurred()) - Expect(status.Code(err)).To(Equal(codes.Internal)) + Expect(status.Code(err)).To(Equal(codes.NotFound)) Expect(err.Error()).To(ContainSubstring("Failed to retrieve the source volume")) }) }) diff --git a/pkg/csi/blockstorage/sanity_test.go b/pkg/csi/blockstorage/sanity_test.go new file mode 100644 index 00000000..ced1a635 --- /dev/null +++ b/pkg/csi/blockstorage/sanity_test.go @@ -0,0 +1,474 @@ +package blockstorage + +import ( + "context" + "math/rand" + "net/http" + "os" + "path" + "strconv" + "time" + + "github.com/container-storage-interface/spec/lib/go/csi" + "github.com/kubernetes-csi/csi-test/v5/pkg/sanity" + . "github.com/onsi/ginkgo/v2" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + mountutils "k8s.io/mount-utils" + exec "k8s.io/utils/exec/testing" + "k8s.io/utils/ptr" + + "github.com/stackitcloud/cloud-provider-stackit/pkg/csi/util/mount" + "github.com/stackitcloud/cloud-provider-stackit/pkg/stackit" + "github.com/stackitcloud/cloud-provider-stackit/pkg/stackit/metadata" + "github.com/stackitcloud/stackit-sdk-go/core/oapierror" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" + "go.uber.org/mock/gomock" +) + +// randString helper (from OpenStack example) +func randString(n int) string { + const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + b := make([]byte, n) + for i := range b { + b[i] = letterBytes[rand.Intn(len(letterBytes))] + } + return string(b) +} + +var _ = Describe("CSI sanity test", Ordered, func() { + Context("Base config", func() { + var ( + driver *Driver + opts *DriverOpts + iaasClient *stackit.MockIaasClient + mountMock *mount.MockIMount + metadataMock *metadata.MockIMetadata + FakeEndpoint string + FakeCluster = "cluster" + FakeInstanceID = "321a8b81-3660-43e5-bab8-6470b65ee4e8" + FakeDevicePath = "/dev/xxx" + Socket string + ) + + Socket = path.Join(os.TempDir(), "csi.sock") + FakeEndpoint = "unix://" + Socket + + BeforeEach(func() { + ctrl := gomock.NewController(GinkgoT()) + + opts = &DriverOpts{ + ClusterID: FakeCluster, + Endpoint: FakeEndpoint, + } + driver = NewDriver(opts) + driver.AddNodeServiceCapabilities( + []csi.NodeServiceCapability_RPC_Type{ + csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME, + csi.NodeServiceCapability_RPC_GET_VOLUME_STATS, + }) + + // --- Initialize Mocks --- + iaasClient = stackit.NewMockIaasClient(ctrl) + mountMock = mount.NewMockIMount(ctrl) + metadataMock = metadata.NewMockIMetadata(ctrl) + + // --- Mock State --- + createdVolumes := make(map[string]*iaas.Volume) + createdSnapshots := make(map[string]*iaas.Snapshot) + createdBackups := make(map[string]*iaas.Backup) + createdInstances := make(map[string]*iaas.Server) + + // --- Mock Mounter Setup --- + mountPoints := make([]mountutils.MountPoint, 0) + fakeMounter := mountutils.NewFakeMounter(mountPoints) + fakeExec := &exec.FakeExec{DisableScripts: true} + safeMounter := &mountutils.SafeFormatAndMount{ + Interface: fakeMounter, + Exec: fakeExec, + } + + // --- 1. Mock IaaS Client (Volumes) --- + + iaasClient.EXPECT().CreateVolume( + gomock.Any(), // context + gomock.Any(), // create options + ).DoAndReturn(func(ctx context.Context, opts *iaas.CreateVolumePayload) (*iaas.Volume, error) { + size := opts.Size + if size == nil { + size = ptr.To(int64(10)) // Default to 10GiB + } + newVol := &iaas.Volume{ + Id: ptr.To("vol-" + randString(8)), // Create a random ID + Name: opts.Name, + Size: size, + Status: ptr.To(stackit.VolumeAvailableStatus), + AvailabilityZone: opts.AvailabilityZone, + Source: opts.Source, + } + createdVolumes[*newVol.Id] = newVol // Store the pointer in the map + return newVol, nil + }).AnyTimes() + + iaasClient.EXPECT().GetVolume( + gomock.Any(), // context + gomock.Any(), // volumeID + ).DoAndReturn(func(ctx context.Context, volumeID string) (*iaas.Volume, error) { + vol, ok := createdVolumes[volumeID] + if !ok { + return nil, &oapierror.GenericOpenAPIError{StatusCode: http.StatusNotFound} + } + return vol, nil + }).AnyTimes() + + iaasClient.EXPECT().GetVolumesByName( + gomock.Any(), // context + gomock.Any(), // volName (string) + ).DoAndReturn(func(ctx context.Context, name string) ([]iaas.Volume, error) { + var found []iaas.Volume + for _, vol := range createdVolumes { + if vol.Name != nil && *vol.Name == name { + found = append(found, *vol) // Append the value + } + } + return found, nil + }).AnyTimes() + + iaasClient.EXPECT().ListVolumes( + gomock.Any(), gomock.Any(), gomock.Eq("invalid-token"), + ).Return(nil, "", status.Error(codes.InvalidArgument, "invalid starting token")).AnyTimes() + + iaasClient.EXPECT().ListVolumes( + gomock.Any(), gomock.Any(), gomock.Eq(""), + ).DoAndReturn(func(ctx context.Context, maxEntries int, token string) ([]iaas.Volume, string, error) { + var volList []iaas.Volume + for _, vol := range createdVolumes { + volList = append(volList, *vol) // Append the value + } + return volList, "", nil + }).AnyTimes() + + iaasClient.EXPECT().DeleteVolume( + gomock.Any(), // context + gomock.Any(), // volume ID + ).DoAndReturn(func(ctx context.Context, volID string) error { + delete(createdVolumes, volID) + return nil + }).AnyTimes() + + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff( + gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + ).Return(nil).AnyTimes() + + iaasClient.EXPECT().ExpandVolume( + gomock.Any(), // context + gomock.Any(), // volumeID + gomock.Any(), // status + gomock.Any(), // size + ).Return(nil).AnyTimes() + + iaasClient.EXPECT().WaitVolumeTargetStatus( + gomock.Any(), // context + gomock.Any(), // volumeID + gomock.Any(), // tStatus + ).Return(nil).AnyTimes() + + // --- 2. Mock IaaS Client (Snapshots) --- + + iaasClient.EXPECT().CreateSnapshot( + gomock.Any(), // context + gomock.Any(), // name + gomock.Any(), // volID + gomock.Any(), // tags + ).DoAndReturn(func(ctx context.Context, name string, volID string, tags map[string]string) (*iaas.Snapshot, error) { + newSnap := &iaas.Snapshot{ + Id: ptr.To("snap-" + randString(8)), + Name: ptr.To(name), + Status: ptr.To(string(stackit.SnapshotReadyStatus)), + CreatedAt: ptr.To(time.Now()), + Size: ptr.To(int64(10)), // 10 GiB + VolumeId: ptr.To(volID), + } + createdSnapshots[*newSnap.Id] = newSnap + return newSnap, nil + }).AnyTimes() + + iaasClient.EXPECT().GetSnapshotByID( + gomock.Any(), // context + gomock.Any(), // snapshotID + ).DoAndReturn(func(ctx context.Context, snapshotID string) (*iaas.Snapshot, error) { + snap, ok := createdSnapshots[snapshotID] + if !ok { + return nil, &oapierror.GenericOpenAPIError{StatusCode: http.StatusNotFound} + } + return snap, nil + }).AnyTimes() + + iaasClient.EXPECT().ListSnapshots( + gomock.Any(), // context + gomock.Any(), // filters + ).DoAndReturn(func(ctx context.Context, filters map[string]string) ([]iaas.Snapshot, string, error) { + var snaplist []iaas.Snapshot + startingToken := filters["Marker"] + limitfilter := filters["Limit"] + limit, _ := strconv.Atoi(limitfilter) + name := filters["Name"] + volumeID := filters["VolumeID"] + + for _, value := range createdSnapshots { + if volumeID != "" { + if value.VolumeId != nil && *value.VolumeId == volumeID { + snaplist = append(snaplist, *value) + break + } + } else if name != "" { + if value.Name != nil && *value.Name == name { + snaplist = append(snaplist, *value) + break + } + } else { + snaplist = append(snaplist, *value) + } + } + + if startingToken != "" { + t, _ := strconv.Atoi(startingToken) + if t >= 0 && t < len(snaplist) { + snaplist = snaplist[t:] + } else if t >= len(snaplist) { + snaplist = []iaas.Snapshot{} + } + } + + retToken := "" + if limit != 0 { + if limit > 0 && limit <= len(snaplist) { + snaplist = snaplist[:limit] + } + retToken = limitfilter + } + return snaplist, retToken, nil + }).AnyTimes() + + iaasClient.EXPECT().DeleteSnapshot( + gomock.Any(), // context + gomock.Any(), // snapshotID + ).DoAndReturn(func(ctx context.Context, snapshotID string) error { + delete(createdSnapshots, snapshotID) + return nil + }).AnyTimes() + + iaasClient.EXPECT().WaitSnapshotReady( + gomock.Any(), // context + gomock.Any(), // snapshotID + ).Return( + ptr.To(string(stackit.SnapshotReadyStatus)), + nil, + ).AnyTimes() + + // --- 3. Mock IaaS Client (Backups) --- + + iaasClient.EXPECT().CreateBackup( + gomock.Any(), // context + gomock.Any(), // name + gomock.Any(), // volID + gomock.Any(), // snapshotID + gomock.Any(), // tags + ).DoAndReturn(func(ctx context.Context, name, volID, snapshotID string, tags map[string]string) (*iaas.Backup, error) { + newBackup := &iaas.Backup{ + Id: ptr.To("backup-" + randString(8)), + Name: ptr.To(name), + Status: ptr.To("available"), + VolumeId: ptr.To(volID), + SnapshotId: ptr.To(snapshotID), + CreatedAt: ptr.To(time.Now()), + } + createdBackups[*newBackup.Id] = newBackup + return newBackup, nil + }).AnyTimes() + + iaasClient.EXPECT().GetBackupByID( + gomock.Any(), // context + gomock.Any(), // backupID + ).DoAndReturn(func(ctx context.Context, backupID string) (*iaas.Backup, error) { + backup, ok := createdBackups[backupID] + if !ok { + return nil, &oapierror.GenericOpenAPIError{StatusCode: http.StatusNotFound} + } + return backup, nil + }).AnyTimes() + + iaasClient.EXPECT().ListBackups( + gomock.Any(), // context + gomock.Any(), // filters + ).DoAndReturn(func(ctx context.Context, filters map[string]string) ([]iaas.Backup, error) { + var backupList []iaas.Backup + for _, backup := range createdBackups { + backupList = append(backupList, *backup) + } + return backupList, nil + }).AnyTimes() + + iaasClient.EXPECT().DeleteBackup( + gomock.Any(), // context + gomock.Any(), // backupID + ).DoAndReturn(func(ctx context.Context, backupID string) error { + delete(createdBackups, backupID) + return nil + }).AnyTimes() + + // --- 4. Mock IaaS Client (Instances & Attach/Detach) --- + + iaasClient.EXPECT().GetInstanceByID( + gomock.Any(), // context + gomock.Any(), // instanceID + ).DoAndReturn(func(ctx context.Context, instanceID string) (*iaas.Server, error) { + if _, ok := createdInstances[FakeInstanceID]; !ok { + createdInstances[FakeInstanceID] = &iaas.Server{} + } + server, ok := createdInstances[instanceID] + if !ok { + return nil, status.Error(codes.NotFound, "server not found in mock") + } + return server, nil + }).AnyTimes() + + iaasClient.EXPECT().AttachVolume( + gomock.Any(), // context + gomock.Any(), // instanceID + gomock.Any(), // volumeID + ).DoAndReturn(func(ctx context.Context, instanceID string, volumeID string) (string, error) { + vol, ok := createdVolumes[volumeID] + if !ok { + return "", status.Error(codes.NotFound, "volume not found in mock") + } + vol.ServerId = ptr.To(instanceID) + vol.Status = ptr.To("attached") + return *vol.Id, nil + }).AnyTimes() + + iaasClient.EXPECT().WaitDiskAttached( + gomock.Any(), // context + gomock.Any(), // instanceID + gomock.Any(), // volumeID + ).Return(nil).AnyTimes() + + iaasClient.EXPECT().DetachVolume( + gomock.Any(), // context + gomock.Any(), // instanceID + gomock.Any(), // volumeID + ).Return(nil).AnyTimes() + + iaasClient.EXPECT().WaitDiskDetached( + gomock.Any(), // context + gomock.Any(), // instanceID + gomock.Any(), // volumeID + ).Return(nil).AnyTimes() + + // --- 5. Mock Metadata Service --- + + metadataMock.EXPECT().GetInstanceID( + gomock.Any(), // context + ).Return( + FakeInstanceID, // A fake node ID for the NodeGetInfo test + nil, // no error + ).AnyTimes() + + metadataMock.EXPECT().GetFlavor( + gomock.Any(), // context + ).Return( + "mock-flavor", // A fake flavor name + nil, // no error + ).AnyTimes() + + metadataMock.EXPECT().GetAvailabilityZone( + gomock.Any(), // context + ).Return( + "eu01", // A fake availability zone + nil, // no error + ).AnyTimes() + + // --- 6. Mock Mount Utilities --- + + mountMock.EXPECT().UnmountPath( + gomock.Any(), // mountPath + ).DoAndReturn(func(mountPath string) error { + return os.RemoveAll(mountPath) + }).AnyTimes() + + mountMock.EXPECT().MakeDir( + gomock.Any(), // pathname + ).Return(nil).AnyTimes() + + mountMock.EXPECT().MakeFile( + gomock.Any(), // pathname + ).Return(nil).AnyTimes() + + mountMock.EXPECT().GetDevicePath( + gomock.Any(), // volumeID + ).Return(FakeDevicePath, nil).AnyTimes() + + mountMock.EXPECT().GetDeviceStats( + gomock.Any(), // path + ).DoAndReturn(func(path string) (*mount.DeviceStats, error) { + return &mount.DeviceStats{ + Block: true, + TotalBytes: 1000, + }, nil + }).AnyTimes() + + mountMock.EXPECT().GetMountFs( + gomock.Any(), //volumePath + ).DoAndReturn(func(volumePath string) ([]byte, error) { + args := []string{"-o", "source", "--first-only", "--noheadings", "--target", volumePath} + return safeMounter.Exec.Command("findmnt", args...).CombinedOutput() + }).AnyTimes() + + mountMock.EXPECT().IsLikelyNotMountPointAttach( + gomock.Any(), // targetpath + ).DoAndReturn(func(mountPath string) (bool, error) { + // This complex mock is needed for the sanity test. + // It checks if the path exists, and if not, *creates it* + // to simulate what NodeStageVolume is expected to do. + notMnt, err := safeMounter.IsLikelyNotMountPoint(mountPath) + if err != nil { + if os.IsNotExist(err) { + // Create the directory on the real filesystem + if errMkdir := os.MkdirAll(mountPath, 0750); errMkdir != nil { + return false, errMkdir + } + // Successfully created the dir, so it's not a mount point + return true, nil + } + // It was some other error + return false, err + } + // Path existed, return its original status + return notMnt, nil + }).AnyTimes() + + mountMock.EXPECT().Mounter().Return(safeMounter).AnyTimes() + + // --- Driver Setup & Run --- + driver.SetupControllerService(iaasClient) + driver.SetupNodeService(mountMock, metadataMock, stackit.BlockStorageOpts{}) + + go func() { + defer GinkgoRecover() + driver.Run() + }() + }) + + AfterEach(func() { + os.Remove(Socket) + }) + + Describe("CSI sanity", func() { + config := sanity.NewTestConfig() + config.Address = FakeEndpoint + + sanity.GinkgoTest(&config) + }) + + }) +}) diff --git a/pkg/csi/blockstorage/server.go b/pkg/csi/blockstorage/server.go index c0112f03..735eb60e 100644 --- a/pkg/csi/blockstorage/server.go +++ b/pkg/csi/blockstorage/server.go @@ -105,7 +105,7 @@ func (s *nonBlockingGRPCServer) serve(endpoint string, ids csi.IdentityServer, c csi.RegisterNodeServer(server, ns) } - klog.Infof("Listening for connections on address: %#v", listener.Addr()) + klog.Infof("Listening for connections on address: %s", listener.Addr().String()) if err := server.Serve(listener); err != nil { klog.Infof("Server stopped with: %v", err) From 667b69286be4dec79244a7081efe87e9014938dc Mon Sep 17 00:00:00 2001 From: Robert Kaussow Date: Tue, 18 Nov 2025 14:32:13 +0100 Subject: [PATCH 2/3] fix linter --- .golangci.yaml | 2 +- pkg/csi/blockstorage/sanity_test.go | 36 ++++++++++++++--------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index a3b4aa6e..d82c81b9 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -131,4 +131,4 @@ formatters: paths: - third_party$ - builtin$ - - examples$ \ No newline at end of file + - examples$ diff --git a/pkg/csi/blockstorage/sanity_test.go b/pkg/csi/blockstorage/sanity_test.go index ced1a635..3a23be64 100644 --- a/pkg/csi/blockstorage/sanity_test.go +++ b/pkg/csi/blockstorage/sanity_test.go @@ -93,7 +93,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().CreateVolume( gomock.Any(), // context gomock.Any(), // create options - ).DoAndReturn(func(ctx context.Context, opts *iaas.CreateVolumePayload) (*iaas.Volume, error) { + ).DoAndReturn(func(_ context.Context, opts *iaas.CreateVolumePayload) (*iaas.Volume, error) { size := opts.Size if size == nil { size = ptr.To(int64(10)) // Default to 10GiB @@ -113,7 +113,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().GetVolume( gomock.Any(), // context gomock.Any(), // volumeID - ).DoAndReturn(func(ctx context.Context, volumeID string) (*iaas.Volume, error) { + ).DoAndReturn(func(_ context.Context, volumeID string) (*iaas.Volume, error) { vol, ok := createdVolumes[volumeID] if !ok { return nil, &oapierror.GenericOpenAPIError{StatusCode: http.StatusNotFound} @@ -124,7 +124,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().GetVolumesByName( gomock.Any(), // context gomock.Any(), // volName (string) - ).DoAndReturn(func(ctx context.Context, name string) ([]iaas.Volume, error) { + ).DoAndReturn(func(_ context.Context, name string) ([]iaas.Volume, error) { var found []iaas.Volume for _, vol := range createdVolumes { if vol.Name != nil && *vol.Name == name { @@ -140,7 +140,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().ListVolumes( gomock.Any(), gomock.Any(), gomock.Eq(""), - ).DoAndReturn(func(ctx context.Context, maxEntries int, token string) ([]iaas.Volume, string, error) { + ).DoAndReturn(func(_ context.Context, _ int, _ string) ([]iaas.Volume, string, error) { var volList []iaas.Volume for _, vol := range createdVolumes { volList = append(volList, *vol) // Append the value @@ -151,7 +151,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().DeleteVolume( gomock.Any(), // context gomock.Any(), // volume ID - ).DoAndReturn(func(ctx context.Context, volID string) error { + ).DoAndReturn(func(_ context.Context, volID string) error { delete(createdVolumes, volID) return nil }).AnyTimes() @@ -180,7 +180,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { gomock.Any(), // name gomock.Any(), // volID gomock.Any(), // tags - ).DoAndReturn(func(ctx context.Context, name string, volID string, tags map[string]string) (*iaas.Snapshot, error) { + ).DoAndReturn(func(_ context.Context, name string, volID string, _ map[string]string) (*iaas.Snapshot, error) { newSnap := &iaas.Snapshot{ Id: ptr.To("snap-" + randString(8)), Name: ptr.To(name), @@ -196,7 +196,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().GetSnapshotByID( gomock.Any(), // context gomock.Any(), // snapshotID - ).DoAndReturn(func(ctx context.Context, snapshotID string) (*iaas.Snapshot, error) { + ).DoAndReturn(func(_ context.Context, snapshotID string) (*iaas.Snapshot, error) { snap, ok := createdSnapshots[snapshotID] if !ok { return nil, &oapierror.GenericOpenAPIError{StatusCode: http.StatusNotFound} @@ -207,7 +207,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().ListSnapshots( gomock.Any(), // context gomock.Any(), // filters - ).DoAndReturn(func(ctx context.Context, filters map[string]string) ([]iaas.Snapshot, string, error) { + ).DoAndReturn(func(_ context.Context, filters map[string]string) ([]iaas.Snapshot, string, error) { var snaplist []iaas.Snapshot startingToken := filters["Marker"] limitfilter := filters["Limit"] @@ -253,7 +253,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().DeleteSnapshot( gomock.Any(), // context gomock.Any(), // snapshotID - ).DoAndReturn(func(ctx context.Context, snapshotID string) error { + ).DoAndReturn(func(_ context.Context, snapshotID string) error { delete(createdSnapshots, snapshotID) return nil }).AnyTimes() @@ -274,7 +274,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { gomock.Any(), // volID gomock.Any(), // snapshotID gomock.Any(), // tags - ).DoAndReturn(func(ctx context.Context, name, volID, snapshotID string, tags map[string]string) (*iaas.Backup, error) { + ).DoAndReturn(func(_ context.Context, name, volID, snapshotID string, _ map[string]string) (*iaas.Backup, error) { newBackup := &iaas.Backup{ Id: ptr.To("backup-" + randString(8)), Name: ptr.To(name), @@ -290,7 +290,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().GetBackupByID( gomock.Any(), // context gomock.Any(), // backupID - ).DoAndReturn(func(ctx context.Context, backupID string) (*iaas.Backup, error) { + ).DoAndReturn(func(_ context.Context, backupID string) (*iaas.Backup, error) { backup, ok := createdBackups[backupID] if !ok { return nil, &oapierror.GenericOpenAPIError{StatusCode: http.StatusNotFound} @@ -301,7 +301,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().ListBackups( gomock.Any(), // context gomock.Any(), // filters - ).DoAndReturn(func(ctx context.Context, filters map[string]string) ([]iaas.Backup, error) { + ).DoAndReturn(func(_ context.Context, _ map[string]string) ([]iaas.Backup, error) { var backupList []iaas.Backup for _, backup := range createdBackups { backupList = append(backupList, *backup) @@ -312,7 +312,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().DeleteBackup( gomock.Any(), // context gomock.Any(), // backupID - ).DoAndReturn(func(ctx context.Context, backupID string) error { + ).DoAndReturn(func(_ context.Context, backupID string) error { delete(createdBackups, backupID) return nil }).AnyTimes() @@ -322,7 +322,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().GetInstanceByID( gomock.Any(), // context gomock.Any(), // instanceID - ).DoAndReturn(func(ctx context.Context, instanceID string) (*iaas.Server, error) { + ).DoAndReturn(func(_ context.Context, instanceID string) (*iaas.Server, error) { if _, ok := createdInstances[FakeInstanceID]; !ok { createdInstances[FakeInstanceID] = &iaas.Server{} } @@ -337,7 +337,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { gomock.Any(), // context gomock.Any(), // instanceID gomock.Any(), // volumeID - ).DoAndReturn(func(ctx context.Context, instanceID string, volumeID string) (string, error) { + ).DoAndReturn(func(_ context.Context, instanceID string, volumeID string) (string, error) { vol, ok := createdVolumes[volumeID] if !ok { return "", status.Error(codes.NotFound, "volume not found in mock") @@ -392,7 +392,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { mountMock.EXPECT().UnmountPath( gomock.Any(), // mountPath - ).DoAndReturn(func(mountPath string) error { + ).DoAndReturn(func(mountPath string) error { //nolint:gocritic // false positive unlambda return os.RemoveAll(mountPath) }).AnyTimes() @@ -410,7 +410,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { mountMock.EXPECT().GetDeviceStats( gomock.Any(), // path - ).DoAndReturn(func(path string) (*mount.DeviceStats, error) { + ).DoAndReturn(func(_ string) (*mount.DeviceStats, error) { return &mount.DeviceStats{ Block: true, TotalBytes: 1000, @@ -418,7 +418,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { }).AnyTimes() mountMock.EXPECT().GetMountFs( - gomock.Any(), //volumePath + gomock.Any(), // volumePath ).DoAndReturn(func(volumePath string) ([]byte, error) { args := []string{"-o", "source", "--first-only", "--noheadings", "--target", volumePath} return safeMounter.Exec.Command("findmnt", args...).CombinedOutput() From c43e080302eaa31efdd165945565fb0467c08423 Mon Sep 17 00:00:00 2001 From: Robert Kaussow Date: Thu, 20 Nov 2025 11:45:01 +0100 Subject: [PATCH 3/3] fix concurrency and address feedback --- pkg/csi/blockstorage/sanity_test.go | 73 +++++++++++++---------------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/pkg/csi/blockstorage/sanity_test.go b/pkg/csi/blockstorage/sanity_test.go index 3a23be64..17547cd9 100644 --- a/pkg/csi/blockstorage/sanity_test.go +++ b/pkg/csi/blockstorage/sanity_test.go @@ -2,7 +2,6 @@ package blockstorage import ( "context" - "math/rand" "net/http" "os" "path" @@ -10,6 +9,7 @@ import ( "time" "github.com/container-storage-interface/spec/lib/go/csi" + "github.com/google/uuid" "github.com/kubernetes-csi/csi-test/v5/pkg/sanity" . "github.com/onsi/ginkgo/v2" "google.golang.org/grpc/codes" @@ -26,16 +26,6 @@ import ( "go.uber.org/mock/gomock" ) -// randString helper (from OpenStack example) -func randString(n int) string { - const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - b := make([]byte, n) - for i := range b { - b[i] = letterBytes[rand.Intn(len(letterBytes))] - } - return string(b) -} - var _ = Describe("CSI sanity test", Ordered, func() { Context("Base config", func() { var ( @@ -54,7 +44,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { Socket = path.Join(os.TempDir(), "csi.sock") FakeEndpoint = "unix://" + Socket - BeforeEach(func() { + BeforeAll(func() { ctrl := gomock.NewController(GinkgoT()) opts = &DriverOpts{ @@ -99,7 +89,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { size = ptr.To(int64(10)) // Default to 10GiB } newVol := &iaas.Volume{ - Id: ptr.To("vol-" + randString(8)), // Create a random ID + Id: ptr.To(uuid.New().String()), // Create a random ID Name: opts.Name, Size: size, Status: ptr.To(stackit.VolumeAvailableStatus), @@ -182,9 +172,9 @@ var _ = Describe("CSI sanity test", Ordered, func() { gomock.Any(), // tags ).DoAndReturn(func(_ context.Context, name string, volID string, _ map[string]string) (*iaas.Snapshot, error) { newSnap := &iaas.Snapshot{ - Id: ptr.To("snap-" + randString(8)), + Id: ptr.To(uuid.New().String()), Name: ptr.To(name), - Status: ptr.To(string(stackit.SnapshotReadyStatus)), + Status: ptr.To(stackit.SnapshotReadyStatus), CreatedAt: ptr.To(time.Now()), Size: ptr.To(int64(10)), // 10 GiB VolumeId: ptr.To(volID), @@ -208,46 +198,49 @@ var _ = Describe("CSI sanity test", Ordered, func() { gomock.Any(), // context gomock.Any(), // filters ).DoAndReturn(func(_ context.Context, filters map[string]string) ([]iaas.Snapshot, string, error) { - var snaplist []iaas.Snapshot - startingToken := filters["Marker"] - limitfilter := filters["Limit"] - limit, _ := strconv.Atoi(limitfilter) - name := filters["Name"] - volumeID := filters["VolumeID"] + var snapshots []iaas.Snapshot + + markerFilter := filters["Marker"] + limitFilter := filters["Limit"] + nameFilter := filters["Name"] + volumeIDFilter := filters["VolumeID"] for _, value := range createdSnapshots { - if volumeID != "" { - if value.VolumeId != nil && *value.VolumeId == volumeID { - snaplist = append(snaplist, *value) + if volumeIDFilter != "" { + if value.VolumeId != nil && *value.VolumeId == volumeIDFilter { + snapshots = append(snapshots, *value) break } - } else if name != "" { - if value.Name != nil && *value.Name == name { - snaplist = append(snaplist, *value) + } else if nameFilter != "" { + if value.Name != nil && *value.Name == nameFilter { + snapshots = append(snapshots, *value) break } } else { - snaplist = append(snaplist, *value) + snapshots = append(snapshots, *value) } } - if startingToken != "" { - t, _ := strconv.Atoi(startingToken) - if t >= 0 && t < len(snaplist) { - snaplist = snaplist[t:] - } else if t >= len(snaplist) { - snaplist = []iaas.Snapshot{} + if markerFilter != "" { + marker, _ := strconv.Atoi(markerFilter) + + if marker >= 0 && marker < len(snapshots) { + snapshots = snapshots[marker:] + } else if marker >= len(snapshots) { + snapshots = []iaas.Snapshot{} } } retToken := "" - if limit != 0 { - if limit > 0 && limit <= len(snaplist) { - snaplist = snaplist[:limit] + if limitFilter != "" { + limit, _ := strconv.Atoi(limitFilter) + + if limit > 0 && limit <= len(snapshots) { + snapshots = snapshots[:limit] } - retToken = limitfilter + retToken = limitFilter } - return snaplist, retToken, nil + return snapshots, retToken, nil }).AnyTimes() iaasClient.EXPECT().DeleteSnapshot( @@ -276,7 +269,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { gomock.Any(), // tags ).DoAndReturn(func(_ context.Context, name, volID, snapshotID string, _ map[string]string) (*iaas.Backup, error) { newBackup := &iaas.Backup{ - Id: ptr.To("backup-" + randString(8)), + Id: ptr.To(uuid.New().String()), Name: ptr.To(name), Status: ptr.To("available"), VolumeId: ptr.To(volID),