Skip to content

Commit 77d5074

Browse files
committed
Add volumesnapshot content deletion policy
This PR adds DeletionPolicy which describes a policy for end-of-life maintenance of volume snapshot contents. There are two types of policies, delete and retain. By default, the policy is delete. In this case, when volume snaphsot is deleted, the volume snapshot content for it should be deleted, as well as the physical snapshot. If the policy is set the retain, the volume snapshot content will remain even if the volume snapshot it binds to is deleted.
1 parent c4337de commit 77d5074

File tree

7 files changed

+122
-60
lines changed

7 files changed

+122
-60
lines changed

pkg/apis/volumesnapshot/v1alpha1/types.go

+20
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ type VolumeSnapshotClass struct {
141141
// to the snapshotter.
142142
// +optional
143143
Parameters map[string]string `json:"parameters,omitempty" protobuf:"bytes,3,rep,name=parameters"`
144+
145+
// Optional: what happens to a snapshot content when released from its snapshot.
146+
// +optional
147+
DeletionPolicy *DeletionPolicy `json:"deletionPolicy,omitempty" protobuf:"bytes,4,opt,name=deletionPolicy"`
144148
}
145149

146150
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
@@ -204,6 +208,10 @@ type VolumeSnapshotContentSpec struct {
204208
// be used if it is available.
205209
// +optional
206210
VolumeSnapshotClassName *string `json:"snapshotClassName" protobuf:"bytes,4,opt,name=snapshotClassName"`
211+
212+
// Optional: what happens to a snapshot content when released from its snapshot.
213+
// +optional
214+
DeletionPolicy *DeletionPolicy `json:"deletionPolicy" protobuf:"bytes,5,opt,name=deletionPolicy"`
207215
}
208216

209217
// VolumeSnapshotSource represents the actual location and type of the snapshot. Only one of its members may be specified.
@@ -241,3 +249,15 @@ type CSIVolumeSnapshotSource struct {
241249
// +optional
242250
RestoreSize *int64 `json:"restoreSize,omitempty" protobuf:"bytes,4,opt,name=restoreSize"`
243251
}
252+
253+
// DeletionPolicy describes a policy for end-of-life maintenance of volume snapshot contents
254+
type DeletionPolicy string
255+
256+
const (
257+
// VolumeSnapshotContentDelete means the snapshot content will be deleted from Kubernetes on release from its volume snapshot.
258+
// The volume plugin must support Deletion.
259+
VolumeSnapshotContentDelete DeletionPolicy = "Delete"
260+
// VolumeSnapshotContentRetain means the volume will be left in its current phase (Released) for manual reclamation by the administrator.
261+
// The default policy is Retain.
262+
VolumeSnapshotContentRetain DeletionPolicy = "Retain"
263+
)

pkg/controller/framework_test.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ func newTestController(kubeClient kubernetes.Interface, clientset clientset.Inte
745745
}
746746

747747
// newContent returns a new content with given attributes
748-
func newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, size *int64, creationTime *int64) *crdv1.VolumeSnapshotContent {
748+
func newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, deletionPolicy *crdv1.DeletionPolicy, size *int64, creationTime *int64) *crdv1.VolumeSnapshotContent {
749749
content := crdv1.VolumeSnapshotContent{
750750
ObjectMeta: metav1.ObjectMeta{
751751
Name: name,
@@ -767,6 +767,7 @@ func newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToS
767767
UID: types.UID(volumeUID),
768768
Name: volumeName,
769769
},
770+
DeletionPolicy: deletionPolicy,
770771
},
771772
}
772773
if boundToSnapshotName != "" {
@@ -782,14 +783,14 @@ func newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToS
782783
return &content
783784
}
784785

785-
func newContentArray(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, size *int64, creationTime *int64) []*crdv1.VolumeSnapshotContent {
786+
func newContentArray(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, deletionPolicy *crdv1.DeletionPolicy, size *int64, creationTime *int64) []*crdv1.VolumeSnapshotContent {
786787
return []*crdv1.VolumeSnapshotContent{
787-
newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, size, creationTime),
788+
newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, deletionPolicy, size, creationTime),
788789
}
789790
}
790791

791-
func newContentWithUnmatchDriverArray(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, size *int64, creationTime *int64) []*crdv1.VolumeSnapshotContent {
792-
content := newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, size, creationTime)
792+
func newContentWithUnmatchDriverArray(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, deletionPolicy *crdv1.DeletionPolicy, size *int64, creationTime *int64) []*crdv1.VolumeSnapshotContent {
793+
content := newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, deletionPolicy, size, creationTime)
793794
content.Spec.VolumeSnapshotSource.CSI.Driver = "fake"
794795
return []*crdv1.VolumeSnapshotContent{
795796
content,

pkg/controller/snapshot_controller.go

+17-3
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,21 @@ func (ctrl *csiSnapshotController) syncContent(content *crdv1.VolumeSnapshotCont
125125
snapshot = nil
126126
}
127127
if snapshot == nil {
128-
ctrl.deleteSnapshotContent(content)
128+
if content.Spec.DeletionPolicy != nil {
129+
switch *content.Spec.DeletionPolicy {
130+
case crdv1.VolumeSnapshotContentRetain:
131+
glog.V(4).Infof("VolumeSnapshotContent[%s]: policy is Retain, nothing to do", content.Name)
132+
133+
case crdv1.VolumeSnapshotContentDelete:
134+
glog.V(4).Infof("VolumeSnapshotContent[%s]: policy is Delete", content.Name)
135+
ctrl.deleteSnapshotContent(content)
136+
default:
137+
// Unknown PersistentVolumeReclaimPolicy
138+
ctrl.eventRecorder.Event(content, v1.EventTypeWarning, "SnapshotUnknownDeletionPolicy", "Volume Snapshot Content has unrecognized deletion policy")
139+
}
140+
return nil
141+
}
129142
}
130-
131143
return nil
132144
}
133145

@@ -531,8 +543,10 @@ func (ctrl *csiSnapshotController) createSnapshotOperation(snapshot *crdv1.Volum
531543
},
532544
},
533545
VolumeSnapshotClassName: &(class.Name),
546+
DeletionPolicy: class.DeletionPolicy,
534547
},
535548
}
549+
glog.V(3).Infof("volume snapshot content %%v", snapshotContent)
536550
// Try to create the VolumeSnapshotContent object several times
537551
for i := 0; i < ctrl.createSnapshotContentRetryCount; i++ {
538552
glog.V(5).Infof("createSnapshot [%s]: trying to save volume snapshot content %s", snapshotKey(snapshot), snapshotContent.Name)
@@ -542,7 +556,7 @@ func (ctrl *csiSnapshotController) createSnapshotOperation(snapshot *crdv1.Volum
542556
glog.V(3).Infof("volume snapshot content %q for snapshot %q already exists, reusing", snapshotContent.Name, snapshotKey(snapshot))
543557
err = nil
544558
} else {
545-
glog.V(3).Infof("volume snapshot content %q for snapshot %q saved", snapshotContent.Name, snapshotKey(snapshot))
559+
glog.V(3).Infof("volume snapshot content %q for snapshot %q saved, %v", snapshotContent.Name, snapshotKey(snapshot), snapshotContent)
546560
}
547561
break
548562
}

pkg/controller/snapshot_controller_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
)
2424

2525
func storeVersion(t *testing.T, prefix string, c cache.Store, version string, expectedReturn bool) {
26-
content := newContent("contentName", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil)
26+
content := newContent("contentName", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil, nil)
2727
content.ResourceVersion = version
2828
ret, err := storeObjectUpdate(c, content, "content")
2929
if err != nil {
@@ -82,7 +82,7 @@ func TestControllerCacheParsingError(t *testing.T) {
8282
// There must be something in the cache to compare with
8383
storeVersion(t, "Step1", c, "1", true)
8484

85-
content := newContent("contentName", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil)
85+
content := newContent("contentName", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil, nil)
8686
content.ResourceVersion = "xxx"
8787
_, err := storeObjectUpdate(c, content, "content")
8888
if err == nil {

pkg/controller/snapshot_create_test.go

+10-7
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"testing"
2222
"time"
2323

24+
crdv1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1"
2425
"github.com/container-storage-interface/spec/lib/go/csi/v0"
2526
"k8s.io/api/core/v1"
2627
storage "k8s.io/api/storage/v1"
@@ -34,7 +35,8 @@ var metaTimeNowUnix = &metav1.Time{
3435
}
3536

3637
var defaultSize int64 = 1000
37-
38+
var deletePolicy = crdv1.VolumeSnapshotContentDelete
39+
var retainPolicy = crdv1.VolumeSnapshotContentRetain
3840
var sameDriverStorageClass = &storage.StorageClass{
3941
TypeMeta: metav1.TypeMeta{
4042
Kind: "StorageClass",
@@ -62,11 +64,12 @@ var diffDriverStorageClass = &storage.StorageClass{
6264
// 2. Call the SyncSnapshot *once*.
6365
// 3. Compare resulting contents with expected contents.
6466
func TestCreateSnapshotSync(t *testing.T) {
67+
6568
tests := []controllerTest{
6669
{
6770
name: "6-1 - successful create snapshot with snapshot class gold",
6871
initialContents: nocontents,
69-
expectedContents: newContentArray("snapcontent-snapuid6-1", classGold, "sid6-1", "pv-uid6-1", "volume6-1", "snapuid6-1", "snap6-1", &defaultSize, &timeNow),
72+
expectedContents: newContentArray("snapcontent-snapuid6-1", classGold, "sid6-1", "pv-uid6-1", "volume6-1", "snapuid6-1", "snap6-1", nil, &defaultSize, &timeNow),
7073
initialSnapshots: newSnapshotArray("snap6-1", classGold, "", "snapuid6-1", "claim6-1", false, nil, nil, nil),
7174
expectedSnapshots: newSnapshotArray("snap6-1", classGold, "snapcontent-snapuid6-1", "snapuid6-1", "claim6-1", false, nil, metaTimeNowUnix, getSize(defaultSize)),
7275
initialClaims: newClaimArray("claim6-1", "pvc-uid6-1", "1Gi", "volume6-1", v1.ClaimBound, &classEmpty),
@@ -93,7 +96,7 @@ func TestCreateSnapshotSync(t *testing.T) {
9396
{
9497
name: "6-2 - successful create snapshot with snapshot class silver",
9598
initialContents: nocontents,
96-
expectedContents: newContentArray("snapcontent-snapuid6-2", classSilver, "sid6-2", "pv-uid6-2", "volume6-2", "snapuid6-2", "snap6-2", &defaultSize, &timeNow),
99+
expectedContents: newContentArray("snapcontent-snapuid6-2", classSilver, "sid6-2", "pv-uid6-2", "volume6-2", "snapuid6-2", "snap6-2", nil, &defaultSize, &timeNow),
97100
initialSnapshots: newSnapshotArray("snap6-2", classSilver, "", "snapuid6-2", "claim6-2", false, nil, nil, nil),
98101
expectedSnapshots: newSnapshotArray("snap6-2", classSilver, "snapcontent-snapuid6-2", "snapuid6-2", "claim6-2", false, nil, metaTimeNowUnix, getSize(defaultSize)),
99102
initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
@@ -120,7 +123,7 @@ func TestCreateSnapshotSync(t *testing.T) {
120123
{
121124
name: "6-3 - successful create snapshot with snapshot class valid-secret-class",
122125
initialContents: nocontents,
123-
expectedContents: newContentArray("snapcontent-snapuid6-3", validSecretClass, "sid6-3", "pv-uid6-3", "volume6-3", "snapuid6-3", "snap6-3", &defaultSize, &timeNow),
126+
expectedContents: newContentArray("snapcontent-snapuid6-3", validSecretClass, "sid6-3", "pv-uid6-3", "volume6-3", "snapuid6-3", "snap6-3", nil, &defaultSize, &timeNow),
124127
initialSnapshots: newSnapshotArray("snap6-3", validSecretClass, "", "snapuid6-3", "claim6-3", false, nil, nil, nil),
125128
expectedSnapshots: newSnapshotArray("snap6-3", validSecretClass, "snapcontent-snapuid6-3", "snapuid6-3", "claim6-3", false, nil, metaTimeNowUnix, getSize(defaultSize)),
126129
initialClaims: newClaimArray("claim6-3", "pvc-uid6-3", "1Gi", "volume6-3", v1.ClaimBound, &classEmpty),
@@ -149,7 +152,7 @@ func TestCreateSnapshotSync(t *testing.T) {
149152
{
150153
name: "6-4 - successful create snapshot with snapshot class empty-secret-class",
151154
initialContents: nocontents,
152-
expectedContents: newContentArray("snapcontent-snapuid6-4", emptySecretClass, "sid6-4", "pv-uid6-4", "volume6-4", "snapuid6-4", "snap6-4", &defaultSize, &timeNow),
155+
expectedContents: newContentArray("snapcontent-snapuid6-4", emptySecretClass, "sid6-4", "pv-uid6-4", "volume6-4", "snapuid6-4", "snap6-4", nil, &defaultSize, &timeNow),
153156
initialSnapshots: newSnapshotArray("snap6-4", emptySecretClass, "", "snapuid6-4", "claim6-4", false, nil, nil, nil),
154157
expectedSnapshots: newSnapshotArray("snap6-4", emptySecretClass, "snapcontent-snapuid6-4", "snapuid6-4", "claim6-4", false, nil, metaTimeNowUnix, getSize(defaultSize)),
155158
initialClaims: newClaimArray("claim6-4", "pvc-uid6-4", "1Gi", "volume6-4", v1.ClaimBound, &classEmpty),
@@ -178,7 +181,7 @@ func TestCreateSnapshotSync(t *testing.T) {
178181
{
179182
name: "6-5 - successful create snapshot with status uploading",
180183
initialContents: nocontents,
181-
expectedContents: newContentArray("snapcontent-snapuid6-5", classGold, "sid6-5", "pv-uid6-5", "volume6-5", "snapuid6-5", "snap6-5", &defaultSize, &timeNow),
184+
expectedContents: newContentArray("snapcontent-snapuid6-5", classGold, "sid6-5", "pv-uid6-5", "volume6-5", "snapuid6-5", "snap6-5", nil, &defaultSize, &timeNow),
182185
initialSnapshots: newSnapshotArray("snap6-5", classGold, "", "snapuid6-5", "claim6-5", false, nil, nil, nil),
183186
expectedSnapshots: newSnapshotArray("snap6-5", classGold, "snapcontent-snapuid6-5", "snapuid6-5", "claim6-5", false, nil, metaTimeNowUnix, getSize(defaultSize)),
184187
initialClaims: newClaimArray("claim6-5", "pvc-uid6-5", "1Gi", "volume6-5", v1.ClaimBound, &classEmpty),
@@ -205,7 +208,7 @@ func TestCreateSnapshotSync(t *testing.T) {
205208
{
206209
name: "6-6 - successful create snapshot with status error uploading",
207210
initialContents: nocontents,
208-
expectedContents: newContentArray("snapcontent-snapuid6-6", classGold, "sid6-6", "pv-uid6-6", "volume6-6", "snapuid6-6", "snap6-6", &defaultSize, &timeNow),
211+
expectedContents: newContentArray("snapcontent-snapuid6-6", classGold, "sid6-6", "pv-uid6-6", "volume6-6", "snapuid6-6", "snap6-6", nil, &defaultSize, &timeNow),
209212
initialSnapshots: newSnapshotArray("snap6-6", classGold, "", "snapuid6-6", "claim6-6", false, nil, nil, nil),
210213
expectedSnapshots: newSnapshotArray("snap6-6", classGold, "snapcontent-snapuid6-6", "snapuid6-6", "claim6-6", false, nil, metaTimeNowUnix, getSize(defaultSize)),
211214
initialClaims: newClaimArray("claim6-6", "pvc-uid6-6", "1Gi", "volume6-6", v1.ClaimBound, &classEmpty),

0 commit comments

Comments
 (0)