Skip to content

Commit

Permalink
pkg/sanity: track and delete volumes
Browse files Browse the repository at this point in the history
When a test fails, any volume operations that I may have done should
be reversed. To achieve this, tests can register volumes for
cleanup.

To avoid unnecessary operations, volumes also get unregistered after a
successful removal inside the test itself. Whether
ControllerUnpublishVolume has to be called also gets tracked. For the
sake of simplicity, NodeUnpublishVolume and (if supported)
NodeUnstageVolume always get called. This is okay because they have to
be idempotent and won't fail when called unnecessarily.

testFullWorkflowSuccess gets inlined because that's easier than
passing yet another parameter.

Fixes: #89.
  • Loading branch information
pohly committed Jul 12, 2018
1 parent 437c0f5 commit b6016b3
Show file tree
Hide file tree
Showing 3 changed files with 315 additions and 149 deletions.
126 changes: 126 additions & 0 deletions pkg/sanity/cleanup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
Copyright 2018 Intel Corporation
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"
"log"

"github.com/container-storage-interface/spec/lib/go/csi/v0"

. "github.com/onsi/ginkgo"
)

// VolumeInfo keeps track of the information needed to delete a volume.
type VolumeInfo struct {
// Node on which the volume was published, empty if none
// or publishing is not supported.
NodeID string

// Volume ID assigned by CreateVolume.
VolumeID string
}

// Cleanup keeps track of resources, in particular volumes, which need
// to be freed when testing is done.
type Cleanup struct {
Context *SanityContext
ControllerClient csi.ControllerClient
NodeClient csi.NodeClient
ControllerPublishSupported bool
NodeStageSupported bool

// Maps from volume name to the node ID for which the volume
// is published and the volume ID.
volumes map[string]VolumeInfo
}

// RegisterVolume adds or updates an entry for the volume with the
// given name.
func (cl *Cleanup) RegisterVolume(name string, info VolumeInfo) {
if cl.volumes == nil {
cl.volumes = make(map[string]VolumeInfo)
}
cl.volumes[name] = info
}

// UnregisterVolume removes the entry for the volume with the
// given name, thus preventing all cleanup operations for it.
func (cl *Cleanup) UnregisterVolume(name string) {
if cl.volumes != nil {
delete(cl.volumes, name)
}
}

// DeleteVolumes stops using the registered volumes and tries to delete all of them.
func (cl *Cleanup) DeleteVolumes() {
if cl.volumes == nil {
return
}
logger := log.New(GinkgoWriter, "cleanup: ", 0)
ctx := context.Background()

for name, info := range cl.volumes {
logger.Printf("deleting %s = %s", name, info.VolumeID)
if _, err := cl.NodeClient.NodeUnpublishVolume(
ctx,
&csi.NodeUnpublishVolumeRequest{
VolumeId: info.VolumeID,
TargetPath: cl.Context.Config.TargetPath,
},
); err != nil {
logger.Printf("warning: NodeUnpublishVolume: %s", err)
}

if cl.NodeStageSupported {
if _, err := cl.NodeClient.NodeUnstageVolume(
ctx,
&csi.NodeUnstageVolumeRequest{
VolumeId: info.VolumeID,
StagingTargetPath: cl.Context.Config.StagingPath,
},
); err != nil {
logger.Printf("warning: NodeUnstageVolume: %s", err)
}
}

if cl.ControllerPublishSupported && info.NodeID != "" {
if _, err := cl.ControllerClient.ControllerUnpublishVolume(
ctx,
&csi.ControllerUnpublishVolumeRequest{
VolumeId: info.VolumeID,
NodeId: info.NodeID,
ControllerUnpublishSecrets: cl.Context.Secrets.ControllerUnpublishVolumeSecret,
},
); err != nil {
logger.Printf("warning: ControllerUnpublishVolume: %s", err)
}
}

if _, err := cl.ControllerClient.DeleteVolume(
ctx,
&csi.DeleteVolumeRequest{
VolumeId: info.VolumeID,
ControllerDeleteSecrets: cl.Context.Secrets.DeleteVolumeSecret,
},
); err != nil {
logger.Printf("error: DeleteVolume: %s", err)
}

cl.UnregisterVolume(name)
}
}
56 changes: 43 additions & 13 deletions pkg/sanity/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,23 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
var (
c csi.ControllerClient
n csi.NodeClient

cl *Cleanup
)

BeforeEach(func() {
c = csi.NewControllerClient(sc.Conn)
n = csi.NewNodeClient(sc.Conn)

cl = &Cleanup{
NodeClient: n,
ControllerClient: c,
Context: sc,
}
})

AfterEach(func() {
cl.DeleteVolumes()
})

Describe("ControllerGetCapabilities", func() {
Expand Down Expand Up @@ -213,6 +225,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()})

By("cleaning up deleting the volume")

Expand All @@ -224,6 +237,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name)
})

It("should return appropriate values SingleNodeWriter WithCapacity 1Gi Type:Mount", func() {
Expand Down Expand Up @@ -251,20 +265,17 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret,
},
)
if serverError, ok := status.FromError(err); ok {
if serverError.Code() == codes.OutOfRange || serverError.Code() == codes.Unimplemented {
Skip("Required bytes not supported")
} else {
Expect(err).NotTo(HaveOccurred())
}
} else {

Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty())
Expect(vol.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", TestVolumeSize(sc)))
if serverError, ok := status.FromError(err); ok &&
(serverError.Code() == codes.OutOfRange || serverError.Code() == codes.Unimplemented) {
Skip("Required bytes not supported")
}
Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()})
Expect(vol.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", TestVolumeSize(sc)))

By("cleaning up deleting the volume")

_, err = c.DeleteVolume(
Expand All @@ -275,6 +286,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name)
})
It("should not fail when requesting to create a volume with already exisiting name and same capacity.", func() {

Expand Down Expand Up @@ -306,6 +318,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Expect(vol1).NotTo(BeNil())
Expect(vol1.GetVolume()).NotTo(BeNil())
Expect(vol1.GetVolume().GetId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetId()})
Expect(vol1.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size))

vol2, err := c.CreateVolume(
Expand Down Expand Up @@ -345,6 +358,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name)
})
It("should fail when requesting to create a volume with already exisiting name and different capacity.", func() {

Expand Down Expand Up @@ -377,6 +391,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Expect(vol1).NotTo(BeNil())
Expect(vol1.GetVolume()).NotTo(BeNil())
Expect(vol1.GetVolume().GetId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetId()})
size2 := 2 * TestVolumeSize(sc)

_, err = c.CreateVolume(
Expand Down Expand Up @@ -415,6 +430,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name)
})
})

Expand Down Expand Up @@ -479,6 +495,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()})

// Delete Volume
By("deleting a volume")
Expand All @@ -491,6 +508,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name)
})
})

Expand Down Expand Up @@ -548,6 +566,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()})

// ValidateVolumeCapabilities
By("validating volume capabilities")
Expand Down Expand Up @@ -580,6 +599,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name)
})

It("should fail when the requested volume does not exist", func() {
Expand Down Expand Up @@ -690,6 +710,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()})

By("getting a node id")
nid, err := n.NodeGetId(
Expand Down Expand Up @@ -720,6 +741,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId(), NodeID: nid.GetNodeId()})
Expect(conpubvol).NotTo(BeNil())

By("cleaning up unpublishing the volume")
Expand All @@ -746,6 +768,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name)
})

It("should fail when the volume does not exist", func() {
Expand Down Expand Up @@ -804,6 +827,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()})

// ControllerPublishVolume
By("calling controllerpublish on that volume")
Expand Down Expand Up @@ -842,6 +866,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name)
})

It("should fail when the volume is already published but is incompatible", func() {
Expand Down Expand Up @@ -871,6 +896,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()})

By("getting a node id")
nid, err := n.NodeGetId(
Expand Down Expand Up @@ -938,6 +964,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name)
})
})

Expand Down Expand Up @@ -990,6 +1017,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()})

By("getting a node id")
nid, err := n.NodeGetId(
Expand Down Expand Up @@ -1020,6 +1048,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId(), NodeID: nid.GetNodeId()})
Expect(conpubvol).NotTo(BeNil())

// ControllerUnpublishVolume
Expand Down Expand Up @@ -1047,6 +1076,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
},
)
Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name)
})
})
})
Loading

0 comments on commit b6016b3

Please sign in to comment.