44 "context"
55 "fmt"
66 "math/rand"
7+ "sync"
78
89 "github.com/container-storage-interface/spec/lib/go/csi"
910 "google.golang.org/grpc/codes"
@@ -24,12 +25,14 @@ var onlyVolumeCapAccessMode = csi.VolumeCapability_AccessMode{
2425type controllerServer struct {
2526 csi.UnimplementedControllerServer
2627 connector cloud.Interface
28+ locks map [string ]* sync.Mutex
2729}
2830
2931// NewControllerServer creates a new Controller gRPC server.
3032func NewControllerServer (connector cloud.Interface ) csi.ControllerServer {
3133 return & controllerServer {
3234 connector : connector ,
35+ locks : make (map [string ]* sync.Mutex ),
3336 }
3437}
3538
@@ -215,6 +218,15 @@ func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *cs
215218 }
216219 nodeID := req .GetNodeId ()
217220
221+ //Ensure only one node is processing at same time
222+ lock , ok := cs .locks [nodeID ]
223+ if ! ok {
224+ lock = & sync.Mutex {}
225+ cs .locks [nodeID ] = lock
226+ }
227+ lock .Lock ()
228+ defer lock .Unlock ()
229+
218230 if req .GetReadonly () {
219231 return nil , status .Error (codes .InvalidArgument , "Readonly not possible" )
220232 }
@@ -236,11 +248,11 @@ func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *cs
236248 }
237249
238250 if vol .VirtualMachineID != "" && vol .VirtualMachineID != nodeID {
239- return nil , status .Error (codes .AlreadyExists , "Volume already assigned" )
251+ return nil , status .Error (codes .AlreadyExists , "Volume already assigned to another node " )
240252 }
241253
242254 if _ , err := cs .connector .GetVMByID (ctx , nodeID ); err == cloud .ErrNotFound {
243- return nil , status .Errorf (codes .NotFound , "VM %v not found" , volumeID )
255+ return nil , status .Errorf (codes .NotFound , "VM %v not found" , nodeID )
244256 } else if err != nil {
245257 // Error with CloudStack
246258 return nil , status .Errorf (codes .Internal , "Error %v" , err )
@@ -273,39 +285,30 @@ func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req *
273285 return nil , status .Error (codes .InvalidArgument , "Volume ID missing in request" )
274286 }
275287 volumeID := req .GetVolumeId ()
276-
277- if req .GetNodeId () == "" {
278- return nil , status .Error (codes .InvalidArgument , "Node ID missing in request" )
279- }
280288 nodeID := req .GetNodeId ()
281289
282290 // Check volume
283291 if vol , err := cs .connector .GetVolumeByID (ctx , volumeID ); err == cloud .ErrNotFound {
284- return nil , status .Errorf (codes .NotFound , "Volume %v not found" , volumeID )
292+ // Volume does not exist in CloudStack. We can safely assume this volume is no longer attached
293+ // The spec requires us to return OK here
294+ return & csi.ControllerUnpublishVolumeResponse {}, nil
285295 } else if err != nil {
286296 // Error with CloudStack
287297 return nil , status .Errorf (codes .Internal , "Error %v" , err )
288- } else if vol .VirtualMachineID != nodeID {
289- // Nothing to do
298+ } else if nodeID != "" && vol .VirtualMachineID != nodeID {
299+ // Volume is present but not attached to this particular nodeID
290300 return & csi.ControllerUnpublishVolumeResponse {}, nil
291301 }
292302
293303 // Check VM existence
294- if _ , err := cs .connector .GetVolumeByID (ctx , volumeID ); err == cloud .ErrNotFound {
295- return nil , status .Errorf (codes .NotFound , "Volume %v not found" , volumeID )
296- } else if err != nil {
297- // Error with CloudStack
298- return nil , status .Errorf (codes .Internal , "Error %v" , err )
299- }
300-
301304 if _ , err := cs .connector .GetVMByID (ctx , nodeID ); err == cloud .ErrNotFound {
302- return nil , status .Errorf (codes .NotFound , "VM %v not found" , volumeID )
305+ return nil , status .Errorf (codes .NotFound , "VM %v not found" , nodeID )
303306 } else if err != nil {
304307 // Error with CloudStack
305308 return nil , status .Errorf (codes .Internal , "Error %v" , err )
306309 }
307310
308- err := cs .connector .DetachVolume (ctx , volumeID )
311+ err := cs .connector .DetachVolume (ctx , volumeID , nodeID )
309312 if err != nil {
310313 return nil , status .Errorf (codes .Internal , "Cannot detach volume %s: %s" , volumeID , err .Error ())
311314 }
0 commit comments