diff --git a/cmd/csi-provisioner/csi-provisioner.go b/cmd/csi-provisioner/csi-provisioner.go index 43b1d38b91..c0163367f2 100644 --- a/cmd/csi-provisioner/csi-provisioner.go +++ b/cmd/csi-provisioner/csi-provisioner.go @@ -202,7 +202,13 @@ func main() { claimLister := factory.Core().V1().PersistentVolumeClaims().Lister() var csiNodeLister storagelistersv1.CSINodeLister - vaLister := factory.Storage().V1().VolumeAttachments().Lister() + var vaLister storagelistersv1.VolumeAttachmentLister + if controllerCapabilities[csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME] { + klog.Info("CSI driver supports PUBLISH_UNPUBLISH_VOLUME, watching VolumeAttachments") + vaLister = factory.Storage().V1().VolumeAttachments().Lister() + } else { + klog.Info("CSI driver does not support PUBLISH_UNPUBLISH_VOLUME, not watching VolumeAttachments") + } var nodeLister v1.NodeLister if ctrl.SupportsTopology(pluginCapabilities) { csiNodeLister = factory.Storage().V1().CSINodes().Lister() diff --git a/deploy/kubernetes/rbac.yaml b/deploy/kubernetes/rbac.yaml index 48450f89ac..92fa4920b8 100644 --- a/deploy/kubernetes/rbac.yaml +++ b/deploy/kubernetes/rbac.yaml @@ -50,6 +50,10 @@ rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list", "watch"] + # Access to volumeattachments is only needed when the CSI driver + # has the PUBLISH_UNPUBLISH_VOLUME controller capability. + # In that case, external-provisioner will watch volumeattachments + # to determine when it is safe to delete a volume. - apiGroups: ["storage.k8s.io"] resources: ["volumeattachments"] verbs: ["get", "list", "watch"] diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 9c0cb33762..2385c4d628 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -271,7 +271,10 @@ func GetDriverCapabilities(conn *grpc.ClientConn, timeout time.Duration) (rpc.Pl return pluginCapabilities, controllerCapabilities, nil } -// NewCSIProvisioner creates new CSI provisioner +// NewCSIProvisioner creates new CSI provisioner. +// +// vaLister is optional and only needed when VolumeAttachments are +// meant to be checked before deleting a volume. func NewCSIProvisioner(client kubernetes.Interface, connectionTimeout time.Duration, identity string, @@ -1046,6 +1049,21 @@ func (p *csiProvisioner) Delete(ctx context.Context, volume *v1.PersistentVolume deleteCtx, cancel := context.WithTimeout(ctx, p.timeout) defer cancel() + if err := p.canDeleteVolume(volume); err != nil { + return err + } + + _, err = p.csiClient.DeleteVolume(deleteCtx, &req) + + return err +} + +func (p *csiProvisioner) canDeleteVolume(volume *v1.PersistentVolume) error { + if p.vaLister == nil { + // Nothing to check. + return nil + } + // Verify if volume is attached to a node before proceeding with deletion vaList, err := p.vaLister.List(labels.Everything()) if err != nil { @@ -1058,9 +1076,7 @@ func (p *csiProvisioner) Delete(ctx context.Context, volume *v1.PersistentVolume } } - _, err = p.csiClient.DeleteVolume(deleteCtx, &req) - - return err + return nil } func (p *csiProvisioner) SupportsBlock(ctx context.Context) bool {