Skip to content
This repository was archived by the owner on Oct 22, 2024. It is now read-only.

Commit 1bc573f

Browse files
committed
Controller: Return appropriate error code in case of failure
DeleteVolume should return FailedPrecondition if volume is in use.
1 parent 368d73d commit 1bc573f

File tree

5 files changed

+101
-15
lines changed

5 files changed

+101
-15
lines changed

pkg/pmem-csi-driver/controllerserver-master.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ func (cs *masterController) DeleteVolume(ctx context.Context, req *csi.DeleteVol
299299
defer conn.Close() // nolint:errcheck
300300
klog.V(4).Infof("Asking node %s to delete volume name:%s id:%s", node, vol.name, vol.id)
301301
if _, err := csi.NewControllerClient(conn).DeleteVolume(ctx, req); err != nil {
302-
return nil, status.Error(codes.Internal, "Failed to delete volume name:"+vol.name+" id:"+vol.id+" on "+node+": "+err.Error())
302+
return nil, err
303303
}
304304
}
305305
cs.mutex.Lock()

pkg/pmem-csi-driver/controllerserver-node.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import (
1212
"fmt"
1313
"strconv"
1414
"sync"
15+
"syscall"
1516

17+
"github.com/pkg/errors"
1618
"golang.org/x/net/context"
1719
"google.golang.org/grpc"
1820
"google.golang.org/grpc/codes"
@@ -273,6 +275,9 @@ func (cs *nodeControllerServer) DeleteVolume(ctx context.Context, req *csi.Delet
273275
}
274276

275277
if err := cs.dm.DeleteDevice(req.VolumeId, eraseafter); err != nil {
278+
if errors.Cause(err) == syscall.EBUSY {
279+
return nil, status.Errorf(codes.FailedPrecondition, err.Error())
280+
}
276281
return nil, status.Errorf(codes.Internal, "Failed to delete volume: %s", err.Error())
277282
}
278283
if cs.sm != nil {

pkg/pmem-device-manager/pmd-util.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import (
77
"time"
88

99
pmemexec "github.com/intel/pmem-csi/pkg/pmem-exec"
10+
"github.com/pkg/errors"
11+
"golang.org/x/sys/unix"
1012
"k8s.io/klog"
11-
"k8s.io/kubernetes/pkg/volume/util/hostutil"
1213
)
1314

1415
const (
@@ -33,17 +34,20 @@ func ClearDevice(dev PmemDeviceInfo, flush bool) error {
3334
klog.Errorf("ClearDevice: %s does not exist", dev.Path)
3435
return err
3536
}
37+
38+
// Check if device
3639
if (fileinfo.Mode() & os.ModeDevice) == 0 {
3740
klog.Errorf("ClearDevice: %s is not device", dev.Path)
3841
return fmt.Errorf("%s is not device", dev.Path)
3942
}
40-
devOpen, err := hostutil.NewHostUtil().DeviceOpened(dev.Path)
43+
44+
fd, err := unix.Open(dev.Path, unix.O_RDONLY|unix.O_EXCL|unix.O_CLOEXEC, 0)
45+
defer unix.Close(fd)
46+
4147
if err != nil {
42-
return err
43-
}
44-
if devOpen {
45-
return fmt.Errorf("%s is in use", dev.Path)
48+
return errors.Wrapf(err, "%s is in use", dev.Path)
4649
}
50+
4751
if blocks == 0 {
4852
klog.V(5).Infof("Wiping entire device: %s", dev.Path)
4953
// use one iteration instead of shred's default=3 for speed

pkg/pmem-device-manager/pmme-lvm_test.go

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import (
1010
"io/ioutil"
1111
"math/rand"
1212
"os"
13+
"syscall"
1314
"testing"
1415

1516
pmdmanager "github.com/intel/pmem-csi/pkg/pmem-device-manager"
1617
pmemexec "github.com/intel/pmem-csi/pkg/pmem-exec"
1718
. "github.com/onsi/ginkgo"
1819
. "github.com/onsi/gomega"
20+
"github.com/pkg/errors"
1921
losetup "gopkg.in/freddierice/go-losetup.v1"
2022
)
2123

@@ -58,7 +60,7 @@ var _ = Describe("DeviceManage LVM", func() {
5860

5961
dev, err := dm.GetDevice(name)
6062
Expect(err).Should(BeNil(), "Failed to retrieve device info")
61-
Expect(dev.Name).Should(Equal(name), "Name mismatch")
63+
Expect(dev.VolumeId).Should(Equal(name), "Name mismatch")
6264
Expect(dev.Size >= size).Should(BeTrue(), "Size mismatch")
6365
Expect(dev.Path).ShouldNot(BeNil(), "Null device path")
6466
})
@@ -89,8 +91,8 @@ var _ = Describe("DeviceManage LVM", func() {
8991
Expect(err).Should(BeNil(), "Failed to list devices")
9092
Expect(len(list)).Should(BeEquivalentTo(max_devices), "count mismatch")
9193
for _, dev := range list {
92-
size, ok := sizes[dev.Name]
93-
Expect(ok).Should(BeTrue(), "Unexpected device name:"+dev.Name)
94+
size, ok := sizes[dev.VolumeId]
95+
Expect(ok).Should(BeTrue(), "Unexpected device name:"+dev.VolumeId)
9496
Expect(dev.Size >= size).Should(BeTrue(), "Device size mismatch")
9597
}
9698

@@ -106,8 +108,8 @@ var _ = Describe("DeviceManage LVM", func() {
106108
Expect(err).Should(BeNil(), "Failed to list devices")
107109
Expect(len(list)).Should(BeEquivalentTo(max_devices-max_deletes), "count mismatch")
108110
for _, dev := range list {
109-
size, ok := sizes[dev.Name]
110-
Expect(ok).Should(BeTrue(), "Unexpected device name:"+dev.Name)
111+
size, ok := sizes[dev.VolumeId]
112+
Expect(ok).Should(BeTrue(), "Unexpected device name:"+dev.VolumeId)
111113
Expect(dev.Size >= size).Should(BeTrue(), "Device size mismatch")
112114
}
113115
})
@@ -120,10 +122,27 @@ var _ = Describe("DeviceManage LVM", func() {
120122

121123
dev, err := dm.GetDevice(name)
122124
Expect(err).Should(BeNil(), "Failed to retrieve device info")
123-
Expect(dev.Name).Should(Equal(name), "Name mismatch")
125+
Expect(dev.VolumeId).Should(Equal(name), "Name mismatch")
124126
Expect(dev.Size >= size).Should(BeTrue(), "Size mismatch")
125127
Expect(dev.Path).ShouldNot(BeNil(), "Null device path")
126128

129+
mountPath, err := mountDevice(&dev)
130+
Expect(err).Should(BeNil(), "Failed to create mount path: %s", mountPath)
131+
132+
defer unmount(mountPath)
133+
134+
out, _ := pmemexec.RunCommand("df")
135+
fmt.Println(out)
136+
137+
// Delete should fail as the device is in use
138+
err = dm.DeleteDevice(name, true)
139+
Expect(err).ShouldNot(BeNil(), "Error expected when deleting device in use: %s", dev.VolumeId)
140+
Expect(errors.Cause(err)).Should(BeEquivalentTo(syscall.EBUSY), "Expected device busy error: %s", dev.VolumeId)
141+
142+
err = unmount(mountPath)
143+
Expect(err).Should(BeNil(), "Failed to unmount the device: %s", dev.VolumeId)
144+
145+
// Delete should succeed
127146
err = dm.DeleteDevice(name, true)
128147
Expect(err).Should(BeNil(), "Failed to delete device")
129148

@@ -132,9 +151,12 @@ var _ = Describe("DeviceManage LVM", func() {
132151
//Expect(os.IsNotExist(errors.Cause())).Should(BeTrue(), "expected error is os.ErrNotExist")
133152
//Expect(dev).Should(BeNil(), "returned device should be nil")
134153

154+
// Delete call should not return any error on non-existing device
135155
err = dm.DeleteDevice(name, true)
136156
Expect(err).Should(BeNil(), "DeleteDevice() is not idempotent")
157+
137158
})
159+
138160
})
139161
})
140162

@@ -227,3 +249,36 @@ func (vg *testVGS) Clean() error {
227249

228250
return nil
229251
}
252+
253+
func mountDevice(device *pmdmanager.PmemDeviceInfo) (string, error) {
254+
targetPath, err := ioutil.TempDir("/tmp", "lmv-mnt-path-")
255+
if err != nil {
256+
return "", err
257+
}
258+
259+
cmd := "mkfs.ext4"
260+
args := []string{"-b 4096", "-F", device.Path}
261+
262+
if _, err := pmemexec.RunCommand(cmd, args...); err != nil {
263+
os.Remove(targetPath)
264+
return "", err
265+
}
266+
267+
cmd = "mount"
268+
args = []string{"-c", device.Path, targetPath}
269+
270+
if _, err := pmemexec.RunCommand(cmd, args...); err != nil {
271+
os.Remove(targetPath)
272+
return "", err
273+
}
274+
275+
return targetPath, nil
276+
}
277+
278+
func unmount(path string) error {
279+
args := []string{path}
280+
if _, err := pmemexec.RunCommand("umount", args...); err != nil {
281+
return err
282+
}
283+
return os.Remove(path)
284+
}

test/e2e/storage/sanity.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import (
3434
"github.com/kubernetes-csi/csi-test/pkg/sanity"
3535
sanityutils "github.com/kubernetes-csi/csi-test/utils"
3636
"google.golang.org/grpc"
37+
"google.golang.org/grpc/codes"
38+
"google.golang.org/grpc/status"
3739
appsv1 "k8s.io/api/apps/v1"
3840
v1 "k8s.io/api/core/v1"
3941
"k8s.io/apimachinery/pkg/api/resource"
@@ -43,9 +45,9 @@ import (
4345
clientset "k8s.io/client-go/kubernetes"
4446
clientexec "k8s.io/client-go/util/exec"
4547
"k8s.io/kubernetes/test/e2e/framework"
46-
testutils "k8s.io/kubernetes/test/utils"
4748
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
4849
e2essh "k8s.io/kubernetes/test/e2e/framework/ssh"
50+
testutils "k8s.io/kubernetes/test/utils"
4951

5052
. "github.com/onsi/ginkgo"
5153
. "github.com/onsi/gomega"
@@ -67,7 +69,7 @@ var _ = Describe("sanity", func() {
6769
// and deletes all extra entries that it does not know about.
6870
TargetPath: "/var/lib/kubelet/plugins/kubernetes.io/csi/pv/pmem-sanity-target.XXXXXX",
6971
StagingPath: "/var/lib/kubelet/plugins/kubernetes.io/csi/pv/pmem-sanity-staging.XXXXXX",
70-
IDGen: &sanity.DefaultIDGenerator{},
72+
IDGen: &sanity.DefaultIDGenerator{},
7173
}
7274

7375
f := framework.NewDefaultFramework("pmem")
@@ -352,6 +354,26 @@ var _ = Describe("sanity", func() {
352354
Expect(resp.AvailableCapacity).To(Equal(nodeCapacity), "capacity mismatch")
353355
})
354356

357+
It("delete volume should fail with appropriate error", func() {
358+
v.namePrefix = "delete-volume"
359+
360+
name, vol := v.create(2*1024*1024, nodeID)
361+
// Publish for the second time.
362+
nodeID := v.publish(name, vol)
363+
364+
_, err := v.cc.DeleteVolume(v.ctx, &csi.DeleteVolumeRequest{
365+
VolumeId: vol.GetVolumeId(),
366+
})
367+
Expect(err).ShouldNot(BeNil(), fmt.Sprintf("Volume(%s) in use cannot be deleted", name))
368+
s, ok := status.FromError(err)
369+
Expect(ok).Should(BeTrue(), "Expected a status error")
370+
Expect(s.Code()).Should(BeEquivalentTo(codes.FailedPrecondition), "Expected device busy error")
371+
372+
v.unpublish(vol, nodeID)
373+
374+
v.remove(vol, name)
375+
})
376+
355377
var (
356378
numWorkers = flag.Int("pmem.sanity.workers", 10, "number of worker creating volumes in parallel and thus also the maximum number of volumes at any time")
357379
numVolumes = flag.Int("pmem.sanity.volumes",

0 commit comments

Comments
 (0)