Skip to content

Commit c1078f1

Browse files
committed
Add Finalizer for VolumeSnapshot/VolumeSnapshotContent
This PR adds a Finalizer for VolumeSnapshotContent. If the VolumeSnapshotContent is bound to a VolumeSnapshot, the VolumeSnapshotContent is being used and cannot be deleted. This PR also adds a Finalizer for VolumeSnapshot. If a volume is being created from the snapshot, the VolumeSnapshot is being used and cannot be deleted.
1 parent 2840dd8 commit c1078f1

7 files changed

+256
-63
lines changed

pkg/controller/framework_test.go

+18-5
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,16 @@ type reactorError struct {
166166
error error
167167
}
168168

169+
func withSnapshotFinalizer(snapshot *crdv1.VolumeSnapshot) *crdv1.VolumeSnapshot {
170+
snapshot.ObjectMeta.Finalizers = append(snapshot.ObjectMeta.Finalizers, VolumeSnapshotFinalizer)
171+
return snapshot
172+
}
173+
174+
func withContentFinalizer(content *crdv1.VolumeSnapshotContent) *crdv1.VolumeSnapshotContent {
175+
content.ObjectMeta.Finalizers = append(content.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer)
176+
return content
177+
}
178+
169179
// React is a callback called by fake kubeClient from the controller.
170180
// In other words, every snapshot/content change performed by the controller ends
171181
// here.
@@ -744,7 +754,7 @@ func newTestController(kubeClient kubernetes.Interface, clientset clientset.Inte
744754
}
745755

746756
// newContent returns a new content with given attributes
747-
func newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, deletionPolicy *crdv1.DeletionPolicy, size *int64, creationTime *int64) *crdv1.VolumeSnapshotContent {
757+
func newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, deletionPolicy *crdv1.DeletionPolicy, size *int64, creationTime *int64, withFinalizer bool) *crdv1.VolumeSnapshotContent {
748758
content := crdv1.VolumeSnapshotContent{
749759
ObjectMeta: metav1.ObjectMeta{
750760
Name: name,
@@ -779,17 +789,20 @@ func newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToS
779789
}
780790
}
781791

792+
if withFinalizer {
793+
return withContentFinalizer(&content)
794+
}
782795
return &content
783796
}
784797

785-
func newContentArray(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, deletionPolicy *crdv1.DeletionPolicy, size *int64, creationTime *int64) []*crdv1.VolumeSnapshotContent {
798+
func newContentArray(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, deletionPolicy *crdv1.DeletionPolicy, size *int64, creationTime *int64, withFinalizer bool) []*crdv1.VolumeSnapshotContent {
786799
return []*crdv1.VolumeSnapshotContent{
787-
newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, deletionPolicy, size, creationTime),
800+
newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, deletionPolicy, size, creationTime, withFinalizer),
788801
}
789802
}
790803

791804
func newContentWithUnmatchDriverArray(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, deletionPolicy *crdv1.DeletionPolicy, size *int64, creationTime *int64) []*crdv1.VolumeSnapshotContent {
792-
content := newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, deletionPolicy, size, creationTime)
805+
content := newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, deletionPolicy, size, creationTime, false)
793806
content.Spec.VolumeSnapshotSource.CSI.Driver = "fake"
794807
return []*crdv1.VolumeSnapshotContent{
795808
content,
@@ -821,7 +834,7 @@ func newSnapshot(name, className, boundToContent, snapshotUID, claimName string,
821834
},
822835
}
823836

824-
return &snapshot
837+
return withSnapshotFinalizer(&snapshot)
825838
}
826839

827840
func newSnapshotArray(name, className, boundToContent, snapshotUID, claimName string, ready bool, err *storagev1beta1.VolumeError, creationTime *metav1.Time, size *resource.Quantity) []*crdv1.VolumeSnapshot {

pkg/controller/snapshot_controller.go

+155
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
ref "k8s.io/client-go/tools/reference"
3535
"k8s.io/kubernetes/pkg/util/goroutinemap"
3636
"k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff"
37+
"k8s.io/kubernetes/pkg/util/slice"
3738
)
3839

3940
// ==================================================================
@@ -77,6 +78,9 @@ import (
7778

7879
const pvcKind = "PersistentVolumeClaim"
7980
const apiGroup = ""
81+
const snapshotKind = "VolumeSnapshot"
82+
const snapshotAPIGroup = crdv1.GroupName
83+
8084
const controllerUpdateFailMsg = "snapshot controller failed to update"
8185

8286
const IsDefaultSnapshotClassAnnotation = "snapshot.storage.kubernetes.io/is-default-class"
@@ -85,6 +89,23 @@ const IsDefaultSnapshotClassAnnotation = "snapshot.storage.kubernetes.io/is-defa
8589
func (ctrl *csiSnapshotController) syncContent(content *crdv1.VolumeSnapshotContent) error {
8690
glog.V(5).Infof("synchronizing VolumeSnapshotContent[%s]", content.Name)
8791

92+
if isContentDeletionCandidate(content) {
93+
// Volume snapshot content should be deleted. Check if it's used
94+
// and remove finalizer if it's not.
95+
// Check if snapshot content is still bound to a snapshot.
96+
isUsed := ctrl.isSnapshotContentBeingUsed(content)
97+
if !isUsed {
98+
glog.V(5).Infof("syncContent: Remove Finalizer for VolumeSnapshotContent[%s]", content.Name)
99+
return ctrl.removeContentFinalizer(content)
100+
}
101+
}
102+
103+
if needToAddContentFinalizer(content) {
104+
// Content is not being deleted -> it should have the finalizer.
105+
glog.V(5).Infof("syncContent: Add Finalizer for VolumeSnapshotContent[%s]", content.Name)
106+
return ctrl.addContentFinalizer(content)
107+
}
108+
88109
// VolumeSnapshotContent is not bound to any VolumeSnapshot, in this case we just return err
89110
if content.Spec.VolumeSnapshotRef == nil {
90111
// content is not bound
@@ -154,6 +175,23 @@ func (ctrl *csiSnapshotController) syncContent(content *crdv1.VolumeSnapshotCont
154175
func (ctrl *csiSnapshotController) syncSnapshot(snapshot *crdv1.VolumeSnapshot) error {
155176
glog.V(5).Infof("synchonizing VolumeSnapshot[%s]: %s", snapshotKey(snapshot), getSnapshotStatusForLogging(snapshot))
156177

178+
if isSnapshotDeletionCandidate(snapshot) {
179+
// Volume snapshot should be deleted. Check if it's used
180+
// and remove finalizer if it's not.
181+
// Check if a volume is being created from snapshot.
182+
isUsed := ctrl.isVolumeBeingCreatedFromSnapshot(snapshot)
183+
if !isUsed {
184+
glog.V(5).Infof("syncSnapshot: Remove Finalizer for VolumeSnapshot[%s]", snapshot.Name)
185+
return ctrl.removeSnapshotFinalizer(snapshot)
186+
}
187+
}
188+
189+
if needToAddSnapshotFinalizer(snapshot) {
190+
// Snapshot is not being deleted -> it should have the finalizer.
191+
glog.V(5).Infof("syncSnapshot: Add Finalizer for VolumeSnapshot[%s]", snapshot.Name)
192+
return ctrl.addSnapshotFinalizer(snapshot)
193+
}
194+
157195
if !snapshot.Status.Ready {
158196
return ctrl.syncUnreadySnapshot(snapshot)
159197
} else {
@@ -410,6 +448,48 @@ func IsSnapshotBound(snapshot *crdv1.VolumeSnapshot, content *crdv1.VolumeSnapsh
410448
return false
411449
}
412450

451+
// isSnapshotConentBeingUsed checks if snapshot content is bound to snapshot.
452+
func (ctrl *csiSnapshotController) isSnapshotContentBeingUsed(content *crdv1.VolumeSnapshotContent) bool {
453+
if content.Spec.VolumeSnapshotRef != nil {
454+
snapshotObj, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(content.Spec.VolumeSnapshotRef.Namespace).Get(content.Spec.VolumeSnapshotRef.Name, metav1.GetOptions{})
455+
if err != nil {
456+
glog.Infof("isSnapshotContentBeingUsed: Cannot get snapshot %s from api server: [%v]. VolumeSnapshot object may be deleted already.", content.Spec.VolumeSnapshotRef.Name, err)
457+
return false
458+
}
459+
460+
// Check if the snapshot content is bound to the snapshot
461+
if IsSnapshotBound(snapshotObj, content) && snapshotObj.Spec.SnapshotContentName == content.Name {
462+
glog.Infof("isSnapshotContentBeingUsed: VolumeSnapshot %s is bound to volumeSnapshotContent [%s]", snapshotObj.Name, content.Name)
463+
return true
464+
}
465+
}
466+
467+
glog.V(5).Infof("isSnapshotContentBeingUsed: Snapshot content %s is not being used", content.Name)
468+
return false
469+
}
470+
471+
// isVolumeBeingCreatedFromSnapshot checks if an volume is being created from the snapshot.
472+
func (ctrl *csiSnapshotController) isVolumeBeingCreatedFromSnapshot(snapshot *crdv1.VolumeSnapshot) bool {
473+
pvcList, err := ctrl.client.CoreV1().PersistentVolumeClaims(snapshot.Namespace).List(metav1.ListOptions{})
474+
if err != nil {
475+
glog.Errorf("Failed to retrieve PVCs from the API server to check if volume snapshot %s is being used by a volume: %q", snapshot.Name, err)
476+
return false
477+
}
478+
for _, pvc := range pvcList.Items {
479+
if pvc.Spec.DataSource != nil && len(pvc.Spec.DataSource.Name) > 0 && pvc.Spec.DataSource.Name == snapshot.Name {
480+
if pvc.Spec.DataSource.Kind == snapshotKind && *(pvc.Spec.DataSource.APIGroup) == snapshotAPIGroup {
481+
if pvc.Status.Phase == v1.ClaimPending {
482+
// A volume is being created from the snapshot
483+
glog.Infof("isVolumeBeingCreatedFromSnapshot: volume %s is being created from snapshot %s", pvc.Name, pvc.Spec.DataSource.Name)
484+
return true
485+
}
486+
}
487+
}
488+
}
489+
glog.V(5).Infof("isVolumeBeingCreatedFromSnapshot: no volume is being created from snapshot %s", snapshot.Name)
490+
return false
491+
}
492+
413493
// The function checks whether the volumeSnapshotRef in snapshot content matches the given snapshot. If match, it binds the content with the snapshot
414494
func (ctrl *csiSnapshotController) checkandBindSnapshotContent(snapshot *crdv1.VolumeSnapshot, content *crdv1.VolumeSnapshotContent) error {
415495
if content.Spec.VolumeSnapshotRef == nil || content.Spec.VolumeSnapshotRef.Name != snapshot.Name {
@@ -899,3 +979,78 @@ func isControllerUpdateFailError(err *storage.VolumeError) bool {
899979
}
900980
return false
901981
}
982+
983+
// addContentFinalizer adds a Finalizer for VolumeSnapshotContent.
984+
func (ctrl *csiSnapshotController) addContentFinalizer(content *crdv1.VolumeSnapshotContent) error {
985+
contentClone := content.DeepCopy()
986+
contentClone.ObjectMeta.Finalizers = append(contentClone.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer)
987+
988+
_, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone)
989+
if err != nil {
990+
return newControllerUpdateError(content.Name, err.Error())
991+
}
992+
993+
_, err = ctrl.storeContentUpdate(contentClone)
994+
if err != nil {
995+
glog.Errorf("failed to update content store %v", err)
996+
}
997+
998+
glog.V(5).Infof("Added protection finalizer to volume snapshot content %s", content.Name)
999+
return nil
1000+
}
1001+
1002+
// removeContentFinalizer removes a Finalizer for VolumeSnapshotContent.
1003+
func (ctrl *csiSnapshotController) removeContentFinalizer(content *crdv1.VolumeSnapshotContent) error {
1004+
contentClone := content.DeepCopy()
1005+
contentClone.ObjectMeta.Finalizers = slice.RemoveString(contentClone.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer, nil)
1006+
1007+
_, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone)
1008+
if err != nil {
1009+
return newControllerUpdateError(content.Name, err.Error())
1010+
}
1011+
1012+
_, err = ctrl.storeContentUpdate(contentClone)
1013+
if err != nil {
1014+
glog.Errorf("failed to update content store %v", err)
1015+
}
1016+
1017+
glog.V(5).Infof("Removed protection finalizer from volume snapshot content %s", content.Name)
1018+
return nil
1019+
}
1020+
1021+
// addSnapshotFinalizer adds a Finalizer for VolumeSnapshot.
1022+
func (ctrl *csiSnapshotController) addSnapshotFinalizer(snapshot *crdv1.VolumeSnapshot) error {
1023+
snapshotClone := snapshot.DeepCopy()
1024+
snapshotClone.ObjectMeta.Finalizers = append(snapshotClone.ObjectMeta.Finalizers, VolumeSnapshotFinalizer)
1025+
_, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(snapshotClone.Namespace).Update(snapshotClone)
1026+
if err != nil {
1027+
return newControllerUpdateError(snapshot.Name, err.Error())
1028+
}
1029+
1030+
_, err = ctrl.storeSnapshotUpdate(snapshotClone)
1031+
if err != nil {
1032+
glog.Errorf("failed to update snapshot store %v", err)
1033+
}
1034+
1035+
glog.V(5).Infof("Added protection finalizer to volume snapshot %s", snapshot.Name)
1036+
return nil
1037+
}
1038+
1039+
// removeContentFinalizer removes a Finalizer for VolumeSnapshot.
1040+
func (ctrl *csiSnapshotController) removeSnapshotFinalizer(snapshot *crdv1.VolumeSnapshot) error {
1041+
snapshotClone := snapshot.DeepCopy()
1042+
snapshotClone.ObjectMeta.Finalizers = slice.RemoveString(snapshotClone.ObjectMeta.Finalizers, VolumeSnapshotFinalizer, nil)
1043+
1044+
_, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(snapshotClone.Namespace).Update(snapshotClone)
1045+
if err != nil {
1046+
return newControllerUpdateError(snapshot.Name, err.Error())
1047+
}
1048+
1049+
_, err = ctrl.storeSnapshotUpdate(snapshotClone)
1050+
if err != nil {
1051+
glog.Errorf("failed to update snapshot store %v", err)
1052+
}
1053+
1054+
glog.V(5).Infof("Removed protection finalizer from volume snapshot %s", snapshot.Name)
1055+
return nil
1056+
}

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, nil)
26+
content := newContent("contentName", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil, nil, false)
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, nil)
85+
content := newContent("contentName", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil, nil, false)
8686
content.ResourceVersion = "xxx"
8787
_, err := storeObjectUpdate(c, content, "content")
8888
if err == nil {

pkg/controller/snapshot_create_test.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func TestCreateSnapshotSync(t *testing.T) {
6868
{
6969
name: "6-1 - successful create snapshot with snapshot class gold",
7070
initialContents: nocontents,
71-
expectedContents: newContentArray("snapcontent-snapuid6-1", classGold, "sid6-1", "pv-uid6-1", "volume6-1", "snapuid6-1", "snap6-1", &deletePolicy, &defaultSize, &timeNow),
71+
expectedContents: newContentArray("snapcontent-snapuid6-1", classGold, "sid6-1", "pv-uid6-1", "volume6-1", "snapuid6-1", "snap6-1", &deletePolicy, &defaultSize, &timeNow, false),
7272
initialSnapshots: newSnapshotArray("snap6-1", classGold, "", "snapuid6-1", "claim6-1", false, nil, nil, nil),
7373
expectedSnapshots: newSnapshotArray("snap6-1", classGold, "snapcontent-snapuid6-1", "snapuid6-1", "claim6-1", false, nil, metaTimeNowUnix, getSize(defaultSize)),
7474
initialClaims: newClaimArray("claim6-1", "pvc-uid6-1", "1Gi", "volume6-1", v1.ClaimBound, &classEmpty),
@@ -92,7 +92,7 @@ func TestCreateSnapshotSync(t *testing.T) {
9292
{
9393
name: "6-2 - successful create snapshot with snapshot class silver",
9494
initialContents: nocontents,
95-
expectedContents: newContentArray("snapcontent-snapuid6-2", classSilver, "sid6-2", "pv-uid6-2", "volume6-2", "snapuid6-2", "snap6-2", &deletePolicy, &defaultSize, &timeNow),
95+
expectedContents: newContentArray("snapcontent-snapuid6-2", classSilver, "sid6-2", "pv-uid6-2", "volume6-2", "snapuid6-2", "snap6-2", &deletePolicy, &defaultSize, &timeNow, false),
9696
initialSnapshots: newSnapshotArray("snap6-2", classSilver, "", "snapuid6-2", "claim6-2", false, nil, nil, nil),
9797
expectedSnapshots: newSnapshotArray("snap6-2", classSilver, "snapcontent-snapuid6-2", "snapuid6-2", "claim6-2", false, nil, metaTimeNowUnix, getSize(defaultSize)),
9898
initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
@@ -116,7 +116,7 @@ func TestCreateSnapshotSync(t *testing.T) {
116116
{
117117
name: "6-3 - successful create snapshot with snapshot class valid-secret-class",
118118
initialContents: nocontents,
119-
expectedContents: newContentArray("snapcontent-snapuid6-3", validSecretClass, "sid6-3", "pv-uid6-3", "volume6-3", "snapuid6-3", "snap6-3", &deletePolicy, &defaultSize, &timeNow),
119+
expectedContents: newContentArray("snapcontent-snapuid6-3", validSecretClass, "sid6-3", "pv-uid6-3", "volume6-3", "snapuid6-3", "snap6-3", &deletePolicy, &defaultSize, &timeNow, false),
120120
initialSnapshots: newSnapshotArray("snap6-3", validSecretClass, "", "snapuid6-3", "claim6-3", false, nil, nil, nil),
121121
expectedSnapshots: newSnapshotArray("snap6-3", validSecretClass, "snapcontent-snapuid6-3", "snapuid6-3", "claim6-3", false, nil, metaTimeNowUnix, getSize(defaultSize)),
122122
initialClaims: newClaimArray("claim6-3", "pvc-uid6-3", "1Gi", "volume6-3", v1.ClaimBound, &classEmpty),
@@ -142,7 +142,7 @@ func TestCreateSnapshotSync(t *testing.T) {
142142
{
143143
name: "6-4 - successful create snapshot with snapshot class empty-secret-class",
144144
initialContents: nocontents,
145-
expectedContents: newContentArray("snapcontent-snapuid6-4", emptySecretClass, "sid6-4", "pv-uid6-4", "volume6-4", "snapuid6-4", "snap6-4", &deletePolicy, &defaultSize, &timeNow),
145+
expectedContents: newContentArray("snapcontent-snapuid6-4", emptySecretClass, "sid6-4", "pv-uid6-4", "volume6-4", "snapuid6-4", "snap6-4", &deletePolicy, &defaultSize, &timeNow, false),
146146
initialSnapshots: newSnapshotArray("snap6-4", emptySecretClass, "", "snapuid6-4", "claim6-4", false, nil, nil, nil),
147147
expectedSnapshots: newSnapshotArray("snap6-4", emptySecretClass, "snapcontent-snapuid6-4", "snapuid6-4", "claim6-4", false, nil, metaTimeNowUnix, getSize(defaultSize)),
148148
initialClaims: newClaimArray("claim6-4", "pvc-uid6-4", "1Gi", "volume6-4", v1.ClaimBound, &classEmpty),
@@ -168,7 +168,7 @@ func TestCreateSnapshotSync(t *testing.T) {
168168
{
169169
name: "6-5 - successful create snapshot with status uploading",
170170
initialContents: nocontents,
171-
expectedContents: newContentArray("snapcontent-snapuid6-5", classGold, "sid6-5", "pv-uid6-5", "volume6-5", "snapuid6-5", "snap6-5", &deletePolicy, &defaultSize, &timeNow),
171+
expectedContents: newContentArray("snapcontent-snapuid6-5", classGold, "sid6-5", "pv-uid6-5", "volume6-5", "snapuid6-5", "snap6-5", &deletePolicy, &defaultSize, &timeNow, false),
172172
initialSnapshots: newSnapshotArray("snap6-5", classGold, "", "snapuid6-5", "claim6-5", false, nil, nil, nil),
173173
expectedSnapshots: newSnapshotArray("snap6-5", classGold, "snapcontent-snapuid6-5", "snapuid6-5", "claim6-5", false, nil, metaTimeNowUnix, getSize(defaultSize)),
174174
initialClaims: newClaimArray("claim6-5", "pvc-uid6-5", "1Gi", "volume6-5", v1.ClaimBound, &classEmpty),
@@ -192,7 +192,7 @@ func TestCreateSnapshotSync(t *testing.T) {
192192
{
193193
name: "6-6 - successful create snapshot with status error uploading",
194194
initialContents: nocontents,
195-
expectedContents: newContentArray("snapcontent-snapuid6-6", classGold, "sid6-6", "pv-uid6-6", "volume6-6", "snapuid6-6", "snap6-6", &deletePolicy, &defaultSize, &timeNow),
195+
expectedContents: newContentArray("snapcontent-snapuid6-6", classGold, "sid6-6", "pv-uid6-6", "volume6-6", "snapuid6-6", "snap6-6", &deletePolicy, &defaultSize, &timeNow, false),
196196
initialSnapshots: newSnapshotArray("snap6-6", classGold, "", "snapuid6-6", "claim6-6", false, nil, nil, nil),
197197
expectedSnapshots: newSnapshotArray("snap6-6", classGold, "snapcontent-snapuid6-6", "snapuid6-6", "claim6-6", false, nil, metaTimeNowUnix, getSize(defaultSize)),
198198
initialClaims: newClaimArray("claim6-6", "pvc-uid6-6", "1Gi", "volume6-6", v1.ClaimBound, &classEmpty),

0 commit comments

Comments
 (0)