diff --git a/CHANGELOG.md b/CHANGELOG.md index fed506160..ae3a71e7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ 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) +* Fix attaching multiple volumes to a single pod + [[GH-61]](https://github.com/digitalocean/csi-digitalocean/pull/61) ## v0.1.3 - August 3rd 2018 diff --git a/driver/controller.go b/driver/controller.go index 02702d5da..60b78cf8e 100644 --- a/driver/controller.go +++ b/driver/controller.go @@ -202,12 +202,24 @@ func (d *Driver) ControllerPublishVolume(ctx context.Context, req *csi.Controlle action, resp, err := d.doClient.StorageActions.Attach(ctx, req.VolumeId, dropletID) if err != nil { // don't do anything if attached - if (resp != nil && resp.StatusCode == http.StatusUnprocessableEntity) || strings.Contains(err.Error(), "This volume is already attached") { - ll.WithFields(logrus.Fields{ - "error": err, - "resp": resp, - }).Warn("assuming volume is attached already") - return &csi.ControllerPublishVolumeResponse{}, nil + if resp != nil && resp.StatusCode == http.StatusUnprocessableEntity { + if strings.Contains(err.Error(), "This volume is already attached") { + ll.WithFields(logrus.Fields{ + "error": err, + "resp": resp, + }).Warn("assuming volume is attached already") + return &csi.ControllerPublishVolumeResponse{}, nil + } + + if strings.Contains(err.Error(), "Droplet already has a pending event") { + ll.WithFields(logrus.Fields{ + "error": err, + "resp": resp, + }).Warn("droplet is not able to detach the volume") + // sending an abort makes sure the csi-attacher retries with the next backoff tick + return nil, status.Errorf(codes.Aborted, "volume %q couldn't be attached. droplet %d is in process of another action", + req.VolumeId, dropletID) + } } return nil, err } @@ -263,12 +275,24 @@ func (d *Driver) ControllerUnpublishVolume(ctx context.Context, req *csi.Control 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") { - ll.WithFields(logrus.Fields{ - "error": err, - "resp": resp, - }).Warn("assuming volume is detached already") - return &csi.ControllerUnpublishVolumeResponse{}, nil + if resp != nil && resp.StatusCode == http.StatusUnprocessableEntity { + if strings.Contains(err.Error(), "Attachment not found") { + ll.WithFields(logrus.Fields{ + "error": err, + "resp": resp, + }).Warn("assuming volume is detached already") + return &csi.ControllerUnpublishVolumeResponse{}, nil + } + + if strings.Contains(err.Error(), "Droplet already has a pending event") { + ll.WithFields(logrus.Fields{ + "error": err, + "resp": resp, + }).Warn("droplet is not able to detach the volume") + // sending an abort makes sure the csi-attacher retries with the next backoff tick + return nil, status.Errorf(codes.Aborted, "volume %q couldn't be detached. droplet %d is in process of another action", + req.VolumeId, dropletID) + } } return nil, err }