diff --git a/Gopkg.lock b/Gopkg.lock index 7f81ef9cc3..5d421072f1 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -412,15 +412,15 @@ version = "v0.6.1" [[projects]] - digest = "1:c9ba37d3709f57185b60f587a6282378feaff2aa3cddc28a56770704e3f96b98" + digest = "1:652c938b1510b21f775fcea8cadd523a9f7706f117e08338e9efdba7edd6662f" name = "github.com/kubernetes-csi/csi-test" packages = [ "pkg/sanity", "utils", ] pruneopts = "UT" - revision = "5b1e3786b7c8f7ca514b40e882a0b5dc36e4c842" - version = "v1.1.0" + revision = "82b05190c167c52bb6d5aaf2e1d7c833fa539783" + version = "v2.2.0" [[projects]] digest = "1:c568d7727aa262c32bdf8a3f7db83614f7af0ed661474b24588de635c20024c7" diff --git a/Gopkg.toml b/Gopkg.toml index 34a084a90c..8d75b2863d 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -92,6 +92,10 @@ name = "github.com/kubernetes-csi/csi-lib-utils" source = "https://github.com/kubernetes-csi/csi-lib-utils" +[[constraint]] + name = "github.com/kubernetes-csi/csi-test" + version = "v2.2.0" + # Picked up from k/k Godeps/Godeps.json [[override]] name = "sigs.k8s.io/structured-merge-diff" diff --git a/Makefile b/Makefile index 68cbc4b950..3187f5d899 100644 --- a/Makefile +++ b/Makefile @@ -137,9 +137,12 @@ unit: depend functional: @echo "$@ not yet implemented" -test-csi-sanity: depend +test-cinder-csi-sanity: depend go test $(GIT_HOST)/$(BASE_DIR)/pkg/csi/cinder/sanity/ +test-manila-csi-sanity: depend + go test $(GIT_HOST)/$(BASE_DIR)/pkg/csi/manila/sanity/ + fmt: hack/verify-gofmt.sh diff --git a/docs/developers-csi-manila.md b/docs/developers-csi-manila.md index 2ea8204b62..6405c275a5 100644 --- a/docs/developers-csi-manila.md +++ b/docs/developers-csi-manila.md @@ -1,5 +1,12 @@ # CSI Manila developer's guide +## Running CSI Sanity tests + +Sanity tests create a real instance of driver with fake Manila client and CSI forwarding node plugin. +See [Sanity check](https://github.com/kubernetes-csi/csi-test/tree/master/pkg/sanity) for more info. + +Run the test suite with `make test-manila-csi-sanity`. + ## Share adapters A share adapter is an interface found here `pkg/csi/manila/shareadapters/shareadapter.go` that forms an adapter between a Manila share and a CSI plugin. diff --git a/docs/using-cinder-csi-plugin.md b/docs/using-cinder-csi-plugin.md index 986bea18fd..87e8666055 100644 --- a/docs/using-cinder-csi-plugin.md +++ b/docs/using-cinder-csi-plugin.md @@ -283,10 +283,10 @@ Filesystem Size Used Avail Use% Mounted on ## Running Sanity Tests -Sanity tests creates a real instance of driver and fake cloud provider. +Sanity tests create a real instance of driver and fake cloud provider. see [Sanity check](https://github.com/kubernetes-csi/csi-test/tree/master/pkg/sanity) for more info. ``` -$ make test-csi-sanity +$ make test-cinder-csi-sanity ``` ## Using CSC tool diff --git a/pkg/csi/cinder/sanity/sanity_test.go b/pkg/csi/cinder/sanity/sanity_test.go index b330b14f7a..1ca6d74712 100644 --- a/pkg/csi/cinder/sanity/sanity_test.go +++ b/pkg/csi/cinder/sanity/sanity_test.go @@ -3,6 +3,7 @@ package sanity import ( "io/ioutil" "os" + "path" "testing" "k8s.io/cloud-provider-openstack/pkg/csi/cinder" @@ -10,10 +11,16 @@ import ( "github.com/kubernetes-csi/csi-test/pkg/sanity" ) -//start sanity test for driver +// start sanity test for driver func TestDriver(t *testing.T) { + basePath, err := ioutil.TempDir("", "cinder.csi.openstack.org") + if err != nil { + t.Fatal(err) + } - socket := "/tmp/csi.sock" + defer os.RemoveAll(basePath) + + socket := path.Join(basePath, "csi.sock") endpoint := "unix://" + socket cluster := "kubernetes" nodeID := "45678" @@ -25,25 +32,13 @@ func TestDriver(t *testing.T) { d.SetupDriver(c, fakemnt, fakemet) - //TODO: Stop call + // TODO: Stop call go d.Run() - mntDir, err := ioutil.TempDir("", "mnt") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(mntDir) - - mntStageDir, err := ioutil.TempDir("", "mnt-stage") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(mntStageDir) - config := &sanity.Config{ - TargetPath: mntDir, - StagingPath: mntStageDir, + TargetPath: path.Join(basePath, "mnt"), + StagingPath: path.Join(basePath, "mnt-stage"), Address: endpoint, } diff --git a/pkg/csi/manila/controllerserver.go b/pkg/csi/manila/controllerserver.go index 5828544cb0..92533fb05b 100644 --- a/pkg/csi/manila/controllerserver.go +++ b/pkg/csi/manila/controllerserver.go @@ -33,6 +33,7 @@ import ( "k8s.io/cloud-provider-openstack/pkg/csi/manila/options" "k8s.io/cloud-provider-openstack/pkg/csi/manila/responsebroker" "k8s.io/cloud-provider-openstack/pkg/csi/manila/shareadapters" + clouderrors "k8s.io/cloud-provider-openstack/pkg/util/errors" "k8s.io/klog" ) @@ -229,7 +230,7 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS // Retrieve the source share if sourceShare, res.err = manilaClient.GetShareByID(req.GetSourceVolumeId()); res.err != nil { - if isManilaErrNotFound(res.err) { + if clouderrors.IsNotFound(res.err) { return nil, status.Errorf(codes.NotFound, "failed to create a snapshot (%s) for share %s because the share doesn't exist: %v", req.GetName(), req.GetSourceVolumeId(), err) } @@ -250,7 +251,7 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS return nil, status.Errorf(codes.DeadlineExceeded, "deadline exceeded while waiting for snapshot %s of share %s to become available", snapshot.ID, req.GetSourceVolumeId()) } - if isManilaErrNotFound(res.err) { + if clouderrors.IsNotFound(res.err) { return nil, status.Errorf(codes.NotFound, "failed to create a snapshot (%s) for share %s because the share doesn't exist: %v", req.GetName(), req.GetSourceVolumeId(), err) } @@ -370,7 +371,7 @@ func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req share, err := manilaClient.GetShareByID(req.GetVolumeId()) if err != nil { - if isManilaErrNotFound(err) { + if clouderrors.IsNotFound(err) { return nil, status.Errorf(codes.NotFound, "share %s not found: %v", req.GetVolumeId(), err) } diff --git a/pkg/csi/manila/nodeserver.go b/pkg/csi/manila/nodeserver.go index d80bcc230a..00ca6a544b 100644 --- a/pkg/csi/manila/nodeserver.go +++ b/pkg/csi/manila/nodeserver.go @@ -28,6 +28,7 @@ import ( "google.golang.org/grpc/status" "k8s.io/cloud-provider-openstack/pkg/csi/manila/options" "k8s.io/cloud-provider-openstack/pkg/csi/manila/shareadapters" + clouderrors "k8s.io/cloud-provider-openstack/pkg/util/errors" "k8s.io/klog" ) @@ -61,12 +62,20 @@ func (ns *nodeServer) buildVolumeContext(volID volumeID, shareOpts *options.Node if shareOpts.ShareID != "" { share, err = manilaClient.GetShareByID(shareOpts.ShareID) if err != nil { - return nil, nil, status.Errorf(codes.InvalidArgument, "failed to retrieve share %s: %v", shareOpts.ShareID, err) + if clouderrors.IsNotFound(err) { + return nil, nil, status.Errorf(codes.NotFound, "share %s not found: %v", shareOpts.ShareID, err) + } + + return nil, nil, status.Errorf(codes.Internal, "failed to retrieve share %s: %v", shareOpts.ShareID, err) } } else { share, err = manilaClient.GetShareByName(shareOpts.ShareName) if err != nil { - return nil, nil, status.Errorf(codes.InvalidArgument, "failed to retrieve share named %s: %v", shareOpts.ShareName, err) + if clouderrors.IsNotFound(err) { + return nil, nil, status.Errorf(codes.NotFound, "no share named %s found: %v", shareOpts.ShareName, err) + } + + return nil, nil, status.Errorf(codes.Internal, "failed to retrieve share named %s: %v", shareOpts.ShareName, err) } } diff --git a/pkg/csi/manila/sanity/fake-secrets.yaml b/pkg/csi/manila/sanity/fake-secrets.yaml new file mode 100644 index 0000000000..4cb4a79885 --- /dev/null +++ b/pkg/csi/manila/sanity/fake-secrets.yaml @@ -0,0 +1,49 @@ +CreateVolumeSecret: + os-authURL: fake-url + os-region: fake-region + os-userID: fake-user-id + os-password: fake-password + os-domainID: fake-domain-id + os-projectID: fake-project-id +DeleteVolumeSecret: + os-authURL: fake-url + os-region: fake-region + os-userID: fake-user-id + os-password: fake-password + os-domainID: fake-domain-id + os-projectID: fake-project-id +CreateSnapshotSecret: + os-authURL: fake-url + os-region: fake-region + os-userID: fake-user-id + os-password: fake-password + os-domainID: fake-domain-id + os-projectID: fake-project-id +DeleteSnapshotSecret: + os-authURL: fake-url + os-region: fake-region + os-userID: fake-user-id + os-password: fake-password + os-domainID: fake-domain-id + os-projectID: fake-project-id +ControllerValidateVolumeCapabilitiesSecret: + os-authURL: fake-url + os-region: fake-region + os-userID: fake-user-id + os-password: fake-password + os-domainID: fake-domain-id + os-projectID: fake-project-id +NodeStageVolumeSecret: + os-authURL: fake-url + os-region: fake-region + os-userID: fake-user-id + os-password: fake-password + os-domainID: fake-domain-id + os-projectID: fake-project-id +NodePublishVolumeSecret: + os-authURL: fake-url + os-region: fake-region + os-userID: fake-user-id + os-password: fake-password + os-domainID: fake-domain-id + os-projectID: fake-project-id diff --git a/pkg/csi/manila/sanity/fakecsiclient.go b/pkg/csi/manila/sanity/fakecsiclient.go new file mode 100644 index 0000000000..e6132e62c3 --- /dev/null +++ b/pkg/csi/manila/sanity/fakecsiclient.go @@ -0,0 +1,85 @@ +/* +Copyright 2019 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 sanity + +import ( + "context" + "time" + + "github.com/container-storage-interface/spec/lib/go/csi" + "google.golang.org/grpc" + "k8s.io/cloud-provider-openstack/pkg/csi/manila/csiclient" +) + +type fakeIdentitySvcClient struct{} + +func (c fakeIdentitySvcClient) GetPluginInfo(context.Context) (*csi.GetPluginInfoResponse, error) { + return &csi.GetPluginInfoResponse{ + Name: "fake-fwd-driver", + VendorVersion: "1.0.0", + }, nil +} + +func (c fakeIdentitySvcClient) ProbeForever(*grpc.ClientConn, time.Duration) error { return nil } + +type fakeNodeSvcClient struct{} + +func (c fakeNodeSvcClient) GetCapabilities(context.Context) (*csi.NodeGetCapabilitiesResponse, error) { + return &csi.NodeGetCapabilitiesResponse{ + Capabilities: []*csi.NodeServiceCapability{ + { + Type: &csi.NodeServiceCapability_Rpc{ + Rpc: &csi.NodeServiceCapability_RPC{ + Type: csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME, + }, + }, + }, + }, + }, nil +} + +func (c fakeNodeSvcClient) StageVolume(context.Context, *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) { + return &csi.NodeStageVolumeResponse{}, nil +} + +func (c fakeNodeSvcClient) UnstageVolume(context.Context, *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) { + return &csi.NodeUnstageVolumeResponse{}, nil +} + +func (c fakeNodeSvcClient) PublishVolume(context.Context, *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) { + return &csi.NodePublishVolumeResponse{}, nil +} + +func (c fakeNodeSvcClient) UnpublishVolume(context.Context, *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) { + return &csi.NodeUnpublishVolumeResponse{}, nil +} + +type fakeCSIClientBuilder struct{} + +func (b fakeCSIClientBuilder) NewConnection(string) (*grpc.ClientConn, error) { return nil, nil } + +func (b fakeCSIClientBuilder) NewConnectionWithContext(context.Context, string) (*grpc.ClientConn, error) { + return nil, nil +} + +func (b fakeCSIClientBuilder) NewNodeServiceClient(conn *grpc.ClientConn) csiclient.Node { + return &fakeNodeSvcClient{} +} + +func (b fakeCSIClientBuilder) NewIdentityServiceClient(conn *grpc.ClientConn) csiclient.Identity { + return &fakeIdentitySvcClient{} +} diff --git a/pkg/csi/manila/sanity/fakemanilaclient.go b/pkg/csi/manila/sanity/fakemanilaclient.go new file mode 100644 index 0000000000..a93b6fadd2 --- /dev/null +++ b/pkg/csi/manila/sanity/fakemanilaclient.go @@ -0,0 +1,224 @@ +/* +Copyright 2019 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 sanity + +import ( + "strconv" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/messages" + "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/shares" + "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/snapshots" + "k8s.io/cloud-provider-openstack/pkg/csi/manila/manilaclient" + "k8s.io/cloud-provider-openstack/pkg/csi/manila/options" +) + +var ( + fakeShareID = 1 + fakeAccessRightID = 1 + fakeSnapshotID = 1 + + fakeShares = make(map[int]*shares.Share) + fakeAccessRights = make(map[int]*shares.AccessRight) + fakeSnapshots = make(map[int]*snapshots.Snapshot) +) + +type fakeManilaClientBuilder struct{} + +func (b fakeManilaClientBuilder) New(o *options.OpenstackOptions) (manilaclient.Interface, error) { + return &fakeManilaClient{}, nil +} + +type fakeManilaClient struct{} + +func optsMapToStruct(optsMap map[string]interface{}, dst interface{}) error { + res := gophercloud.Result{Body: optsMap} + return res.ExtractInto(dst) +} + +func strToInt(s string) int { + n, _ := strconv.Atoi(s) + return n +} + +func intToStr(n int) string { + return strconv.Itoa(n) +} + +func shareExists(shareID string) bool { + _, ok := fakeShares[strToInt(shareID)] + return ok +} + +func (c fakeManilaClient) GetShareByID(shareID string) (*shares.Share, error) { + s, ok := fakeShares[strToInt(shareID)] + if !ok { + return nil, gophercloud.ErrResourceNotFound{} + } + + return s, nil +} + +func (c fakeManilaClient) GetShareByName(shareName string) (*shares.Share, error) { + var shareID string + for _, share := range fakeShares { + if share.Name == shareName { + shareID = share.ID + break + } + } + + if shareID == "" { + return nil, gophercloud.ErrResourceNotFound{} + } + + return c.GetShareByID(shareID) +} + +func (c fakeManilaClient) CreateShare(opts shares.CreateOptsBuilder) (*shares.Share, error) { + var res shares.CreateResult + res.Body = opts + + share := &shares.Share{} + if err := res.ExtractInto(share); err != nil { + return nil, err + } + + share.ID = intToStr(fakeShareID) + share.Status = "available" + fakeShares[fakeShareID] = share + fakeShareID++ + + return share, nil +} + +func (c fakeManilaClient) DeleteShare(shareID string) error { + id := strToInt(shareID) + if _, ok := fakeShares[id]; !ok { + return gophercloud.ErrResourceNotFound{} + } + + delete(fakeShares, id) + return nil +} + +func (c fakeManilaClient) GetExportLocations(shareID string) ([]shares.ExportLocation, error) { + if !shareExists(shareID) { + return nil, gophercloud.ErrResourceNotFound{} + } + + return []shares.ExportLocation{{Path: "fake-server:/fake-path"}}, nil +} + +func (c fakeManilaClient) GetAccessRights(shareID string) ([]shares.AccessRight, error) { + if !shareExists(shareID) { + return nil, gophercloud.ErrResourceNotFound{} + } + + var accessRights []shares.AccessRight + for _, r := range fakeAccessRights { + if r.ShareID == shareID { + accessRights = append(accessRights, *r) + } + } + + return accessRights, nil +} + +func (c fakeManilaClient) GrantAccess(shareID string, opts shares.GrantAccessOptsBuilder) (*shares.AccessRight, error) { + if !shareExists(shareID) { + return nil, gophercloud.ErrResourceNotFound{} + } + + optsMap, err := opts.ToGrantAccessMap() + if err != nil { + return nil, err + } + + accessRight := &shares.AccessRight{} + if err = optsMapToStruct(optsMap, accessRight); err != nil { + return nil, err + } + + accessRight.ID = intToStr(fakeAccessRightID) + accessRight.ShareID = shareID + fakeAccessRights[fakeAccessRightID] = accessRight + fakeAccessRightID++ + + return accessRight, nil +} + +func (c fakeManilaClient) GetSnapshotByID(snapID string) (*snapshots.Snapshot, error) { + s, ok := fakeSnapshots[strToInt(snapID)] + if !ok { + return nil, gophercloud.ErrDefault404{} + } + + return s, nil +} + +func (c fakeManilaClient) GetSnapshotByName(snapName string) (*snapshots.Snapshot, error) { + var snapID string + for _, snap := range fakeSnapshots { + if snap.Name == snapName { + snapID = snap.ID + break + } + } + + if snapID == "" { + return nil, gophercloud.ErrResourceNotFound{} + } + + return c.GetSnapshotByID(snapID) +} + +func (c fakeManilaClient) CreateSnapshot(opts snapshots.CreateOptsBuilder) (*snapshots.Snapshot, error) { + var res snapshots.CreateResult + res.Body = opts + + snap := &snapshots.Snapshot{} + if err := res.ExtractInto(snap); err != nil { + return nil, err + } + + snap.ID = intToStr(fakeSnapshotID) + snap.Status = "available" + + if !shareExists(snap.ShareID) { + return nil, gophercloud.ErrDefault404{} + } + + fakeSnapshots[fakeSnapshotID] = snap + fakeSnapshotID++ + + return snap, nil +} + +func (c fakeManilaClient) DeleteSnapshot(snapID string) error { + id := strToInt(snapID) + if _, ok := fakeSnapshots[id]; !ok { + return gophercloud.ErrResourceNotFound{} + } + + delete(fakeSnapshots, id) + return nil +} + +func (c fakeManilaClient) GetUserMessages(opts messages.ListOptsBuilder) ([]messages.Message, error) { + return nil, nil +} diff --git a/pkg/csi/manila/sanity/sanity_test.go b/pkg/csi/manila/sanity/sanity_test.go new file mode 100644 index 0000000000..2098e22596 --- /dev/null +++ b/pkg/csi/manila/sanity/sanity_test.go @@ -0,0 +1,53 @@ +/* +Copyright 2019 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 sanity + +import ( + "io/ioutil" + "os" + "path" + "testing" + + "github.com/kubernetes-csi/csi-test/pkg/sanity" + "k8s.io/cloud-provider-openstack/pkg/csi/manila" +) + +func TestDriver(t *testing.T) { + basePath, err := ioutil.TempDir("", "manila.csi.openstack.org") + if err != nil { + t.Fatalf("failed create base path in %s: %v", basePath, err) + } + + defer os.RemoveAll(basePath) + + endpoint := path.Join(basePath, "csi.sock") + fwdEndpoint := "unix:///fake-fwd-endpoint" + + d, err := manila.NewDriver("node", "fake.manila.csi.openstack.org", endpoint, fwdEndpoint, "NFS", &fakeManilaClientBuilder{}, &fakeCSIClientBuilder{}) + if err != nil { + t.Fatalf("failed to initialize CSI Manila driver: %v", err) + } + + go d.Run() + + sanity.Test(t, &sanity.Config{ + Address: endpoint, + SecretsFile: "fake-secrets.yaml", + TargetPath: path.Join(basePath, "target"), + StagingPath: path.Join(basePath, "staging"), + }) +} diff --git a/pkg/csi/manila/share.go b/pkg/csi/manila/share.go index 1fd3479617..f82efff148 100644 --- a/pkg/csi/manila/share.go +++ b/pkg/csi/manila/share.go @@ -23,6 +23,7 @@ import ( "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/shares" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/cloud-provider-openstack/pkg/csi/manila/manilaclient" + clouderrors "k8s.io/cloud-provider-openstack/pkg/util/errors" "k8s.io/klog" ) @@ -50,7 +51,7 @@ func getOrCreateShare(shareName string, createOpts *shares.CreateOpts, manilaCli // First, check if the share already exists or needs to be created if share, err = manilaClient.GetShareByName(shareName); err != nil { - if isManilaErrNotFound(err) { + if clouderrors.IsNotFound(err) { // It doesn't exist, create it var createErr error @@ -76,7 +77,7 @@ func getOrCreateShare(shareName string, createOpts *shares.CreateOpts, manilaCli func deleteShare(shareID string, manilaClient manilaclient.Interface) error { if err := manilaClient.DeleteShare(shareID); err != nil { - if isManilaErrNotFound(err) { + if clouderrors.IsNotFound(err) { klog.V(4).Infof("share %s not found, assuming it to be already deleted", shareID) } else { return err @@ -120,7 +121,7 @@ func waitForShareStatus(shareID, currentStatus, desiredStatus string, successOnN share, err = manilaClient.GetShareByID(shareID) if err != nil { - if isManilaErrNotFound(err) && successOnNotFound { + if clouderrors.IsNotFound(err) && successOnNotFound { return true, nil } diff --git a/pkg/csi/manila/snapshot.go b/pkg/csi/manila/snapshot.go index d677fe36de..91e4a92b6a 100644 --- a/pkg/csi/manila/snapshot.go +++ b/pkg/csi/manila/snapshot.go @@ -23,6 +23,7 @@ import ( "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/snapshots" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/cloud-provider-openstack/pkg/csi/manila/manilaclient" + clouderrors "k8s.io/cloud-provider-openstack/pkg/util/errors" "k8s.io/klog" ) @@ -47,7 +48,7 @@ func getOrCreateSnapshot(snapName, sourceShareID string, manilaClient manilaclie // First, check if the snapshot already exists or needs to be created if snapshot, err = manilaClient.GetSnapshotByName(snapName); err != nil { - if isManilaErrNotFound(err) { + if clouderrors.IsNotFound(err) { // It doesn't exist, create it opts := snapshots.CreateOpts{ @@ -74,7 +75,7 @@ func getOrCreateSnapshot(snapName, sourceShareID string, manilaClient manilaclie func deleteSnapshot(snapID string, manilaClient manilaclient.Interface) error { if err := manilaClient.DeleteSnapshot(snapID); err != nil { - if isManilaErrNotFound(err) { + if clouderrors.IsNotFound(err) { klog.V(4).Infof("snapshot %s not found, assuming it to be already deleted", snapID) } else { return err @@ -118,7 +119,7 @@ func waitForSnapshotStatus(snapshotID, currentStatus, desiredStatus string, succ snapshot, err = manilaClient.GetSnapshotByID(snapshotID) if err != nil { - if isManilaErrNotFound(err) && successOnNotFound { + if clouderrors.IsNotFound(err) && successOnNotFound { return true, nil } diff --git a/pkg/csi/manila/util.go b/pkg/csi/manila/util.go index 668eb90445..d9f02e0181 100644 --- a/pkg/csi/manila/util.go +++ b/pkg/csi/manila/util.go @@ -22,7 +22,6 @@ import ( "strings" "github.com/container-storage-interface/spec/lib/go/csi" - "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/messages" "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/shares" "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/snapshots" @@ -177,22 +176,6 @@ func lastResourceError(resourceID string, manilaClient manilaclient.Interface) ( return manilaErrorMessage{message: "unknown error"}, nil } -func isManilaErrNotFound(err error) bool { - if err == nil { - return false - } - - if _, isDefault404 := err.(gophercloud.ErrDefault404); isDefault404 { - return true - } - - if _, isResourceNotFound := err.(gophercloud.ErrResourceNotFound); isResourceNotFound { - return true - } - - return false -} - func compareProtocol(protoA, protoB string) bool { return strings.ToUpper(protoA) == strings.ToUpper(protoB) } diff --git a/pkg/csi/manila/volumesource.go b/pkg/csi/manila/volumesource.go index bff4c7ec02..8b0f59db11 100644 --- a/pkg/csi/manila/volumesource.go +++ b/pkg/csi/manila/volumesource.go @@ -24,6 +24,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/cloud-provider-openstack/pkg/csi/manila/manilaclient" "k8s.io/cloud-provider-openstack/pkg/csi/manila/options" + clouderrors "k8s.io/cloud-provider-openstack/pkg/util/errors" "k8s.io/klog" ) @@ -80,7 +81,7 @@ func (volumeFromSnapshot) create(req *csi.CreateVolumeRequest, shareName string, snapshot, err := manilaClient.GetSnapshotByID(snapshotSource.GetSnapshotId()) if err != nil { - if isManilaErrNotFound(err) { + if clouderrors.IsNotFound(err) { return nil, status.Errorf(codes.NotFound, "source snapshot %s not found: %v", snapshotSource.GetSnapshotId(), err) } diff --git a/pkg/util/errors/errors.go b/pkg/util/errors/errors.go index cce65871d1..4f067d2995 100644 --- a/pkg/util/errors/errors.go +++ b/pkg/util/errors/errors.go @@ -27,6 +27,10 @@ func IsNotFound(err error) bool { return true } + if _, ok := err.(gophercloud.ErrResourceNotFound); ok { + return true + } + if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { if errCode.Actual == http.StatusNotFound { return true