Skip to content

Commit

Permalink
Remove VolumeSnapshotBeingCreated annotation after driver response
Browse files Browse the repository at this point in the history
  • Loading branch information
xing-yang committed Mar 5, 2020
1 parent 8a46721 commit bbc5dc0
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 35 deletions.
79 changes: 51 additions & 28 deletions pkg/sidecar-controller/snapshot_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,25 +332,25 @@ func (ctrl *csiSnapshotSideCarController) createSnapshotOperation(content *crdv1
}

// NOTE(xyang): handle create timeout
// Add annotation and set to Yes to indicate create snapshot request is
// Add annotation to indicate create snapshot request is
// sent to the storage system and wait for a response of success or failure.
// Annotation will be set to No only after storage system has responded
// Annotation will be removed only after storage system has responded
// with success or failure. If the request times out, retry will happen
// and annotation will stay as Yes to avoid leaking of snapshot
// and annotation will remain to avoid leaking of snapshot
// resources on the storage system
err = ctrl.setAnnVolumeSnapshotBeingCreated(content, utils.AnnVolumeSnapshotBeingCreated_Yes)
err = ctrl.setAnnVolumeSnapshotBeingCreated(content)
if err != nil {
return nil, fmt.Errorf("failed to set VolumeSnapshotBeingCreated annotation to Yes on the content %s: %q", content.Name, err)
}

driverName, snapshotID, creationTime, size, readyToUse, err := ctrl.handler.CreateSnapshot(content, class.Parameters, snapshotterCredentials)
if err != nil {
// NOTE(xyang): handle create timeout
// If it is not a timeout error, set annotation to No to indicate
// If it is not a timeout error, remove annotation to indicate
// storage system has responded with an error
errStr := fmt.Sprintf("%q", err)
if !strings.Contains(errStr, "DeadlineExceeded") {
err = ctrl.setAnnVolumeSnapshotBeingCreated(content, utils.AnnVolumeSnapshotBeingCreated_No)
err = ctrl.removeAnnVolumeSnapshotBeingCreated(content)
if err != nil {
return nil, fmt.Errorf("failed to set VolumeSnapshotBeingCreated annotation to No on the content %s: %q", content.Name, err)
}
Expand All @@ -362,14 +362,6 @@ func (ctrl *csiSnapshotSideCarController) createSnapshotOperation(content *crdv1
return nil, fmt.Errorf("failed to take snapshot of the volume, %s: driver name %s returned from the driver is different from driver %s in snapshot class", *content.Spec.Source.VolumeHandle, driverName, class.Driver)
}

// NOTE(xyang): handle create timeout
// Set annotation to No to indicate storage system has successfully
// cut the snapshot
err = ctrl.setAnnVolumeSnapshotBeingCreated(content, utils.AnnVolumeSnapshotBeingCreated_No)
if err != nil {
return nil, fmt.Errorf("failed to set VolumeSnapshotBeingCreated annotation to No on the content %s: %q", content.Name, err)
}

klog.V(5).Infof("Created snapshot: driver %s, snapshotId %s, creationTime %v, size %d, readyToUse %t", driverName, snapshotID, creationTime, size, readyToUse)

timestamp := creationTime.UnixNano()
Expand All @@ -381,6 +373,14 @@ func (ctrl *csiSnapshotSideCarController) createSnapshotOperation(content *crdv1
content = newContent
}

// NOTE(xyang): handle create timeout
// Remove annotation to indicate storage system has successfully
// cut the snapshot
err = ctrl.removeAnnVolumeSnapshotBeingCreated(content)
if err != nil {
return nil, fmt.Errorf("failed to set VolumeSnapshotBeingCreated annotation to No on the content %s: %q", content.Name, err)
}

// Update content in the cache store
_, err = ctrl.storeContentUpdate(content)
if err != nil {
Expand Down Expand Up @@ -607,10 +607,10 @@ func (ctrl *csiSnapshotSideCarController) shouldDelete(content *crdv1.VolumeSnap

// NOTE(xyang): Handle create snapshot timeout
// 2) shouldDelete returns false if AnnVolumeSnapshotBeingCreated
// annotation is set and its value is Yes. This indicates a
// CreateSnapshot CSI RPC has not responded with success or failure.
// annotation is set. This indicates a CreateSnapshot CSI RPC has
// not responded with success or failure.
// We need to keep waiting for a response from the CSI driver.
if metav1.HasAnnotation(content.ObjectMeta, utils.AnnVolumeSnapshotBeingCreated) && content.ObjectMeta.Annotations[utils.AnnVolumeSnapshotBeingCreated] == utils.AnnVolumeSnapshotBeingCreated_Yes {
if metav1.HasAnnotation(content.ObjectMeta, utils.AnnVolumeSnapshotBeingCreated) {
return false
}

Expand All @@ -623,17 +623,15 @@ func (ctrl *csiSnapshotSideCarController) shouldDelete(content *crdv1.VolumeSnap

// setAnnVolumeSnapshotBeingCreated sets VolumeSnapshotBeingCreated annotation
// on VolumeSnapshotContent
// If beingCreated is true, it indicates snapshot is being created
// If beingCreated if false, it indicates CreateSnapshot CSI RPC returns
// success or failure
func (ctrl *csiSnapshotSideCarController) setAnnVolumeSnapshotBeingCreated(content *crdv1.VolumeSnapshotContent, annBeingCreated string) error {
// Set AnnVolumeSnapshotBeingCreated if it is not set yet or if it is
// set but has a different value
if !metav1.HasAnnotation(content.ObjectMeta, utils.AnnVolumeSnapshotBeingCreated) || content.ObjectMeta.Annotations[utils.AnnVolumeSnapshotBeingCreated] != annBeingCreated {
klog.V(5).Infof("setAnnVolumeSnapshotBeingCreated: set annotation [%s:%s] on content [%s].", utils.AnnVolumeSnapshotBeingCreated, annBeingCreated, content.Name)
metav1.SetMetaDataAnnotation(&content.ObjectMeta, utils.AnnVolumeSnapshotBeingCreated, annBeingCreated)

updateContent, err := ctrl.clientset.SnapshotV1beta1().VolumeSnapshotContents().Update(content)
// If set, it indicates snapshot is being created
func (ctrl *csiSnapshotSideCarController) setAnnVolumeSnapshotBeingCreated(content *crdv1.VolumeSnapshotContent) error {
// Set AnnVolumeSnapshotBeingCreated if it is not set yet
if !metav1.HasAnnotation(content.ObjectMeta, utils.AnnVolumeSnapshotBeingCreated) {
klog.V(5).Infof("setAnnVolumeSnapshotBeingCreated: set annotation [%s:yes] on content [%s].", utils.AnnVolumeSnapshotBeingCreated, content.Name)
contentClone := content.DeepCopy()
metav1.SetMetaDataAnnotation(&contentClone.ObjectMeta, utils.AnnVolumeSnapshotBeingCreated, "yes")

updateContent, err := ctrl.clientset.SnapshotV1beta1().VolumeSnapshotContents().Update(contentClone)
if err != nil {
return newControllerUpdateError(content.Name, err.Error())
}
Expand All @@ -649,3 +647,28 @@ func (ctrl *csiSnapshotSideCarController) setAnnVolumeSnapshotBeingCreated(conte
}
return nil
}

// removeAnnVolumeSnapshotBeingCreated removes the VolumeSnapshotBeingCreated
// annotation from a content if there exists one.
func (ctrl csiSnapshotSideCarController) removeAnnVolumeSnapshotBeingCreated(content *crdv1.VolumeSnapshotContent) error {
if !metav1.HasAnnotation(content.ObjectMeta, utils.AnnVolumeSnapshotBeingCreated) {
// the annotation does not exit, return directly
return nil
}
contentClone := content.DeepCopy()
delete(contentClone.ObjectMeta.Annotations, utils.AnnVolumeSnapshotBeingCreated)

updateContent, err := ctrl.clientset.SnapshotV1beta1().VolumeSnapshotContents().Update(contentClone)
if err != nil {
return newControllerUpdateError(content.Name, err.Error())
}
// update content if update is successful
content = updateContent

klog.V(5).Infof("Removed VolumeSnapshotBeingCreated annotation from volume snapshot content %s", content.Name)
_, err = ctrl.storeContentUpdate(content)
if err != nil {
klog.Errorf("failed to update content store %v", err)
}
return nil
}
10 changes: 3 additions & 7 deletions pkg/utils/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,16 @@ const (
AnnVolumeSnapshotBeingDeleted = "snapshot.storage.kubernetes.io/volumesnapshot-being-deleted"

// AnnVolumeSnapshotBeingCreated annotation applies to VolumeSnapshotContents.
// If it is set and value is "yes", it indicates that the csi-snapshotter
// If it is set, it indicates that the csi-snapshotter
// sidecar has sent the create snapshot request to the storage system and
// is waiting for a response of success or failure.
// This annotation will be set to "no" if the driver's CreateSnapshot
// This annotation will be removed if the driver's CreateSnapshot
// CSI function returns success or failure. If the create snapshot
// request times out, retry will happen and the annotation value will
// stay as "yes".
// request times out, retry will happen and the annotation will remain.
// This only applies to dynamic provisioning of snapshots because
// the create snapshot CSI method will not be called for pre-provisioned
// snapshots.
AnnVolumeSnapshotBeingCreated = "snapshot.storage.kubernetes.io/volumesnapshot-being-created"
// VolumeSnapshotBeingCreated annotation values can be "yes" or "no"
AnnVolumeSnapshotBeingCreated_Yes = "yes"
AnnVolumeSnapshotBeingCreated_No = "no"

// Annotation for secret name and namespace will be added to the content
// and used at snapshot content deletion time.
Expand Down

0 comments on commit bbc5dc0

Please sign in to comment.