Skip to content

Commit

Permalink
Merge pull request #60 from digitalocean/handle-not-found
Browse files Browse the repository at this point in the history
driver: handle non existing volumes and nodes
  • Loading branch information
fatih authored Aug 22, 2018
2 parents 07f32d9 + 8a50f61 commit e4142fa
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 40 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
* Remove description to allow users to reuse volumes that were created by the
UI/API
[[GH-59]](https://github.com/digitalocean/csi-digitalocean/pull/59)
* Handle edge cases from external action, such as Volume deletion via UI more
gracefully. We're not very strict anymore in cases we don't need to be, but
we're also returning a better error in cases we need to be.
[[GH-60]](https://github.com/digitalocean/csi-digitalocean/pull/60)

## v0.1.3 - August 3rd 2018

Expand Down
46 changes: 46 additions & 0 deletions driver/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,24 @@ func (d *Driver) ControllerPublishVolume(ctx context.Context, req *csi.Controlle
})
ll.Info("controller publish volume called")

// check if volume exist before trying to attach it
_, resp, err := d.doClient.Storage.GetVolume(ctx, req.VolumeId)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
return nil, status.Errorf(codes.NotFound, "volume %q not found", req.VolumeId)
}
return nil, err
}

// check if droplet exist before trying to attach the volume to the droplet
_, resp, err = d.doClient.Droplets.Get(ctx, dropletID)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
return nil, status.Errorf(codes.NotFound, "droplet %q not found", dropletID)
}
return nil, err
}

action, resp, err := d.doClient.StorageActions.Attach(ctx, req.VolumeId, dropletID)
if err != nil {
// don't do anything if attached
Expand Down Expand Up @@ -224,6 +242,25 @@ func (d *Driver) ControllerUnpublishVolume(ctx context.Context, req *csi.Control
})
ll.Info("controller unpublish volume called")

// check if volume exist before trying to detach it
_, resp, err := d.doClient.Storage.GetVolume(ctx, req.VolumeId)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
// assume it's detached
return &csi.ControllerUnpublishVolumeResponse{}, nil
}
return nil, err
}

// check if droplet exist before trying to detach the volume from the droplet
_, resp, err = d.doClient.Droplets.Get(ctx, dropletID)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
return nil, status.Errorf(codes.NotFound, "droplet %q not found", dropletID)
}
return nil, err
}

action, resp, err := d.doClient.StorageActions.DetachByDropletID(ctx, req.VolumeId, dropletID)
if err != nil {
if (resp != nil && resp.StatusCode == http.StatusUnprocessableEntity) || strings.Contains(err.Error(), "Attachment not found") {
Expand Down Expand Up @@ -275,6 +312,15 @@ func (d *Driver) ValidateVolumeCapabilities(ctx context.Context, req *csi.Valida
})
ll.Info("validate volume capabilities called")

// check if volume exist before trying to validate it it
_, volResp, err := d.doClient.Storage.GetVolume(ctx, req.VolumeId)
if err != nil {
if volResp != nil && volResp.StatusCode == http.StatusNotFound {
return nil, status.Errorf(codes.NotFound, "volume %q not found", req.VolumeId)
}
return nil, err
}

hasSupport := func(mode csi.VolumeCapability_AccessMode_Mode) bool {
for _, m := range vcaps {
if mode == m.Mode {
Expand Down
2 changes: 1 addition & 1 deletion driver/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,6 @@ func (f *fakeMounter) Unmount(target string) error {
func (f *fakeMounter) IsFormatted(source string) (bool, error) {
return true, nil
}
func (f *fakeMounter) IsMounted(source, target string) (bool, error) {
func (f *fakeMounter) IsMounted(target string) (bool, error) {
return true, nil
}
26 changes: 13 additions & 13 deletions driver/mounter.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,10 @@ type Mounter interface {
// returns true if the source device is already formatted.
IsFormatted(source string) (bool, error)

// IsMounted checks whether the source device is mounted to the target path
// in a correct way (i.e: propagated). It returns true if it's mounted. An
// error is returned in case of system errors or if it's mounted
// incorrectly.
IsMounted(source, target string) (bool, error)
// IsMounted checks whether the target path is a correct mount (i.e:
// propagated). It returns true if it's mounted. An error is returned in
// case of system errors or if it's mounted incorrectly.
IsMounted(target string) (bool, error)
}

// TODO(arslan): this is Linux only for now. Refactor this into a package with
Expand Down Expand Up @@ -215,11 +214,7 @@ func (m *mounter) IsFormatted(source string) (bool, error) {
return true, nil
}

func (m *mounter) IsMounted(source, target string) (bool, error) {
if source == "" {
return false, errors.New("source is not specified for checking the mount")
}

func (m *mounter) IsMounted(target string) (bool, error) {
if target == "" {
return false, errors.New("target is not specified for checking the mount")
}
Expand All @@ -233,12 +228,12 @@ func (m *mounter) IsMounted(source, target string) (bool, error) {
return false, err
}

findmntArgs := []string{"-o", "TARGET,PROPAGATION,FSTYPE,OPTIONS", source, "-J"}
findmntArgs := []string{"-o", "TARGET,PROPAGATION,FSTYPE,OPTIONS", "-M", target, "-J"}

m.log.WithFields(logrus.Fields{
"cmd": findmntCmd,
"args": findmntArgs,
}).Info("checking if source is mounted")
}).Info("checking if target is mounted")

out, err := exec.Command(findmntCmd, findmntArgs...).CombinedOutput()
if err != nil {
Expand All @@ -251,6 +246,11 @@ func (m *mounter) IsMounted(source, target string) (bool, error) {
err, findmntCmd, string(out))
}

// no response means there is no mount
if string(out) == "" {
return false, nil
}

var resp *findmntResponse
err = json.Unmarshal(out, &resp)
if err != nil {
Expand All @@ -261,7 +261,7 @@ func (m *mounter) IsMounted(source, target string) (bool, error) {
for _, fs := range resp.FileSystems {
// check if the mount is propagated correctly. It should be set to shared.
if fs.Propagation != "shared" {
return true, fmt.Errorf("mount propagation for target %q is not enabled or the block device %q does not exist anymore", target, source)
return true, fmt.Errorf("mount propagation for target %q is not enabled", target)
}

// the mountpoint should match as well
Expand Down
35 changes: 9 additions & 26 deletions driver/node.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e4142fa

Please sign in to comment.