Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add finalizer before CreateVolume and remove it after PV is provisioned #673

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/csi-provisioner/csi-provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ func main() {
// Listers
// Create informer to prevent hit the API server for all resource request
scLister := factory.Storage().V1().StorageClasses().Lister()
pvLister := factory.Core().V1().PersistentVolumes().Lister()
claimLister := factory.Core().V1().PersistentVolumeClaims().Lister()

var vaLister storagelistersv1.VolumeAttachmentLister
Expand Down Expand Up @@ -486,6 +487,7 @@ func main() {

csiClaimController := ctrl.NewCloningProtectionController(
clientset,
pvLister,
claimLister,
claimInformer,
claimQueue,
Expand Down
88 changes: 65 additions & 23 deletions pkg/controller/clone_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,31 @@ import (
// CloningProtectionController is storing all related interfaces
// to handle cloning protection finalizer removal after CSI cloning is finished
type CloningProtectionController struct {
client kubernetes.Interface
claimLister corelisters.PersistentVolumeClaimLister
claimInformer cache.SharedInformer
claimQueue workqueue.RateLimitingInterface
client kubernetes.Interface
pvLister corelisters.PersistentVolumeLister
claimLister corelisters.PersistentVolumeClaimLister
claimInformer cache.SharedInformer
claimQueue workqueue.RateLimitingInterface
controllerCapabilities rpc.ControllerCapabilitySet
}

// NewCloningProtectionController creates new controller for additional CSI claim protection capabilities
func NewCloningProtectionController(
client kubernetes.Interface,
pvLister corelisters.PersistentVolumeLister,
claimLister corelisters.PersistentVolumeClaimLister,
claimInformer cache.SharedInformer,
claimQueue workqueue.RateLimitingInterface,
controllerCapabilities rpc.ControllerCapabilitySet,
) *CloningProtectionController {
if !controllerCapabilities[csi.ControllerServiceCapability_RPC_CLONE_VOLUME] {
return nil
}
controller := &CloningProtectionController{
client: client,
claimLister: claimLister,
claimInformer: claimInformer,
claimQueue: claimQueue,
return &CloningProtectionController{
client: client,
pvLister: pvLister,
claimLister: claimLister,
claimInformer: claimInformer,
claimQueue: claimQueue,
controllerCapabilities: controllerCapabilities,
}
return controller
}

// Run is a main CloningProtectionController handler
Expand Down Expand Up @@ -132,9 +133,9 @@ func (p *CloningProtectionController) enqueueClaimUpdate(ctx context.Context, ob
}

// Timestamp didn't appear
if new.DeletionTimestamp == nil {
return
}
// if new.DeletionTimestamp == nil {
// return
// }

key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
if err != nil {
Expand Down Expand Up @@ -168,6 +169,32 @@ func (p *CloningProtectionController) syncClaimHandler(ctx context.Context, key

// syncClaim removes finalizers from a PVC, when cloning is finished
func (p *CloningProtectionController) syncClaim(ctx context.Context, claim *v1.PersistentVolumeClaim) error {
err := p.removeCloneFinalizer(claim)
if err != nil {
return err
}

err = p.removeProvisioningFinalizer(claim)
if err != nil {
return err
}

if _, err = p.client.CoreV1().PersistentVolumeClaims(claim.Namespace).Update(ctx, claim, metav1.UpdateOptions{}); err != nil {
if !apierrs.IsNotFound(err) {
// Couldn't remove finalizer and the object still exists, the controller may
// try to remove the finalizer again on the next update
klog.Infof("failed to remove clone finalizer from PVC %v", claim.Name)
return err
}
}

return nil
}

func (p *CloningProtectionController) removeCloneFinalizer(claim *v1.PersistentVolumeClaim) error {
if !p.controllerCapabilities[csi.ControllerServiceCapability_RPC_CLONE_VOLUME] {
return nil
}
if !checkFinalizer(claim, pvcCloneFinalizer) {
return nil
}
Expand All @@ -177,7 +204,6 @@ func (p *CloningProtectionController) syncClaim(ctx context.Context, claim *v1.P
if err != nil {
return err
}

// Check for pvc state with DataSource pointing to claim
for _, pvc := range pvcList {
if pvc.Spec.DataSource == nil {
Expand All @@ -199,16 +225,32 @@ func (p *CloningProtectionController) syncClaim(ctx context.Context, claim *v1.P
finalizers = append(finalizers, finalizer)
}
}
claim.ObjectMeta.Finalizers = finalizers
claim.Finalizers = finalizers

if _, err = p.client.CoreV1().PersistentVolumeClaims(claim.Namespace).Update(ctx, claim, metav1.UpdateOptions{}); err != nil {
if !apierrs.IsNotFound(err) {
// Couldn't remove finalizer and the object still exists, the controller may
// try to remove the finalizer again on the next update
klog.Infof("failed to remove clone finalizer from PVC %v", claim.Name)
return nil
}

func (p *CloningProtectionController) removeProvisioningFinalizer(claim *v1.PersistentVolumeClaim) error {
if !checkFinalizer(claim, pvcProvisioningFinalizer) {
return nil
}

_, err := p.pvLister.Get(claim.Spec.VolumeName)
if err != nil {
if apierrs.IsNotFound(err) {
return err
}
return err
}

// Apparently the PV was created, so it's time to remove the finalizer
finalizers := make([]string, 0)
for _, finalizer := range claim.ObjectMeta.Finalizers {
if finalizer != pvcProvisioningFinalizer {
finalizers = append(finalizers, finalizer)
}
}
claim.Finalizers = finalizers

return nil
}
23 changes: 22 additions & 1 deletion pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ const (

snapshotNotBound = "snapshot %s not bound"

pvcCloneFinalizer = "provisioner.storage.kubernetes.io/cloning-protection"
pvcCloneFinalizer = "provisioner.storage.kubernetes.io/cloning-protection"
pvcProvisioningFinalizer = "provisioner.storage.kubernetes.io/provisioning-protection"
)

var (
Expand Down Expand Up @@ -612,6 +613,11 @@ func (p *csiProvisioner) prepareProvision(ctx context.Context, claim *v1.Persist
req.VolumeContentSource = volumeContentSource
}

err = p.setProvisioningFinalizer(ctx, claim, pvcProvisioningFinalizer)
if err != nil {
return nil, controller.ProvisioningNoChange, err
}

if claim.Spec.DataSource != nil && rc.clone {
err = p.setCloneFinalizer(ctx, claim)
if err != nil {
Expand Down Expand Up @@ -890,6 +896,21 @@ func (p *csiProvisioner) setCloneFinalizer(ctx context.Context, pvc *v1.Persiste
return nil
}

func (p *csiProvisioner) setProvisioningFinalizer(ctx context.Context, pvc *v1.PersistentVolumeClaim, finalizer string) error {
claim, err := p.claimLister.PersistentVolumeClaims(pvc.Namespace).Get(pvc.Name)
if err != nil {
return err
}

if !checkFinalizer(claim, finalizer) {
claim.Finalizers = append(claim.Finalizers, finalizer)
_, err := p.client.CoreV1().PersistentVolumeClaims(claim.Namespace).Update(ctx, claim, metav1.UpdateOptions{})
return err
}

return nil
}

func (p *csiProvisioner) supportsTopology() bool {
return SupportsTopology(p.pluginCapabilities)
}
Expand Down