Skip to content

Commit b5e06f5

Browse files
authored
Merge pull request #1225 from leonardoce/ownership-alpha
Use ownership to identify volume group snapshot members
2 parents d6a0ca4 + c70f946 commit b5e06f5

File tree

9 files changed

+451
-28
lines changed

9 files changed

+451
-28
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ require (
2121
k8s.io/component-base v0.31.0
2222
k8s.io/component-helpers v0.31.0
2323
k8s.io/klog/v2 v2.130.1
24+
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
2425
)
2526

2627
require (
@@ -72,7 +73,6 @@ require (
7273
gopkg.in/yaml.v2 v2.4.0 // indirect
7374
gopkg.in/yaml.v3 v3.0.1 // indirect
7475
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
75-
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
7676
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
7777
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
7878
sigs.k8s.io/yaml v1.4.0 // indirect

pkg/common-controller/framework_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,15 +1728,15 @@ func newVolumeError(message string) *crdv1.VolumeSnapshotError {
17281728
}
17291729

17301730
func testSyncSnapshot(ctrl *csiSnapshotCommonController, reactor *snapshotReactor, test controllerTest) error {
1731-
return ctrl.syncSnapshot(test.initialSnapshots[0])
1731+
return ctrl.syncSnapshot(context.TODO(), test.initialSnapshots[0])
17321732
}
17331733

17341734
func testSyncGroupSnapshot(ctrl *csiSnapshotCommonController, reactor *snapshotReactor, test controllerTest) error {
17351735
return ctrl.syncGroupSnapshot(context.TODO(), test.initialGroupSnapshots[0])
17361736
}
17371737

17381738
func testSyncSnapshotError(ctrl *csiSnapshotCommonController, reactor *snapshotReactor, test controllerTest) error {
1739-
err := ctrl.syncSnapshot(test.initialSnapshots[0])
1739+
err := ctrl.syncSnapshot(context.TODO(), test.initialSnapshots[0])
17401740
if err != nil {
17411741
return nil
17421742
}

pkg/common-controller/groupsnapshot_controller_helper.go

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
apierrs "k8s.io/apimachinery/pkg/api/errors"
2828
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2929
"k8s.io/apimachinery/pkg/labels"
30+
"k8s.io/apimachinery/pkg/types"
3031
"k8s.io/client-go/kubernetes/scheme"
3132
ref "k8s.io/client-go/tools/reference"
3233
klog "k8s.io/klog/v2"
@@ -301,7 +302,7 @@ func (ctrl *csiSnapshotCommonController) syncGroupSnapshot(ctx context.Context,
301302

302303
// Proceed with group snapshot deletion and remove finalizers when needed
303304
if groupSnapshot.ObjectMeta.DeletionTimestamp != nil {
304-
return ctrl.processGroupSnapshotWithDeletionTimestamp(groupSnapshot)
305+
return ctrl.processGroupSnapshotWithDeletionTimestamp(ctx, groupSnapshot)
305306
}
306307

307308
klog.V(5).Infof("syncGroupSnapshot[%s]: validate group snapshot to make sure source has been correctly specified", utils.GroupSnapshotKey(groupSnapshot))
@@ -599,8 +600,8 @@ func (ctrl *csiSnapshotCommonController) createSnapshotsForGroupSnapshotContent(
599600
ObjectMeta: metav1.ObjectMeta{
600601
Name: volumeSnapshotName,
601602
Namespace: volumeSnapshotNamespace,
602-
Labels: map[string]string{
603-
utils.VolumeGroupSnapshotNameLabel: groupSnapshotContent.Spec.VolumeGroupSnapshotRef.Name,
603+
OwnerReferences: []metav1.OwnerReference{
604+
utils.BuildVolumeGroupSnapshotOwnerReference(groupSnapshot),
604605
},
605606
Finalizers: []string{utils.VolumeSnapshotInGroupFinalizer},
606607
},
@@ -1376,7 +1377,7 @@ func (ctrl *csiSnapshotCommonController) addGroupSnapshotFinalizer(groupSnapshot
13761377
// with information obtained from step 1. This function name is very long but the
13771378
// name suggests what it does. It determines whether to remove finalizers on group
13781379
// snapshot and whether to delete group snapshot content.
1379-
func (ctrl *csiSnapshotCommonController) processGroupSnapshotWithDeletionTimestamp(groupSnapshot *crdv1alpha1.VolumeGroupSnapshot) error {
1380+
func (ctrl *csiSnapshotCommonController) processGroupSnapshotWithDeletionTimestamp(ctx context.Context, groupSnapshot *crdv1alpha1.VolumeGroupSnapshot) error {
13801381
klog.V(5).Infof("processGroupSnapshotWithDeletionTimestamp VolumeGroupSnapshot[%s]: %s", utils.GroupSnapshotKey(groupSnapshot), utils.GetGroupSnapshotStatusForLogging(groupSnapshot))
13811382

13821383
driverName, err := ctrl.getGroupSnapshotDriverName(groupSnapshot)
@@ -1435,11 +1436,13 @@ func (ctrl *csiSnapshotCommonController) processGroupSnapshotWithDeletionTimesta
14351436
return nil
14361437
}
14371438

1438-
snapshotMembers, err := ctrl.snapshotLister.List(labels.SelectorFromSet(
1439-
labels.Set{
1440-
utils.VolumeGroupSnapshotNameLabel: groupSnapshot.Name,
1439+
// Look up for members of this volume group snapshot
1440+
snapshotMembers, err := ctrl.findGroupSnapshotMembers(
1441+
types.NamespacedName{
1442+
Name: groupSnapshot.Name,
1443+
Namespace: groupSnapshot.Namespace,
14411444
},
1442-
))
1445+
)
14431446
if err != nil {
14441447
klog.Errorf(
14451448
"processGroupSnapshotWithDeletionTimestamp[%s]: Failed to look for snapshot members: %v",
@@ -1489,7 +1492,7 @@ func (ctrl *csiSnapshotCommonController) processGroupSnapshotWithDeletionTimesta
14891492
// VolumeGroupSnapshotContent won't be deleted immediately due to the VolumeGroupSnapshotContentFinalizer
14901493
if groupSnapshotContent != nil && deleteGroupSnapshotContent {
14911494
klog.V(5).Infof("processGroupSnapshotWithDeletionTimestamp[%s]: set DeletionTimeStamp on group snapshot content [%s].", utils.GroupSnapshotKey(groupSnapshot), groupSnapshotContent.Name)
1492-
err := ctrl.clientset.GroupsnapshotV1alpha1().VolumeGroupSnapshotContents().Delete(context.TODO(), groupSnapshotContent.Name, metav1.DeleteOptions{})
1495+
err := ctrl.clientset.GroupsnapshotV1alpha1().VolumeGroupSnapshotContents().Delete(ctx, groupSnapshotContent.Name, metav1.DeleteOptions{})
14931496
if err != nil {
14941497
ctrl.eventRecorder.Event(groupSnapshot, v1.EventTypeWarning, "GroupSnapshotContentObjectDeleteError", "Failed to delete group snapshot content API object")
14951498
return fmt.Errorf("failed to delete VolumeGroupSnapshotContent %s from API server: %q", groupSnapshotContent.Name, err)
@@ -1561,6 +1564,32 @@ func (ctrl *csiSnapshotCommonController) setAnnVolumeGroupSnapshotBeingDeleted(g
15611564
return groupSnapshotContent, nil
15621565
}
15631566

1567+
// findGroupSnapshotMembers get the list of members of a group snapshot
1568+
// using the local cache and indexer
1569+
func (ctrl *csiSnapshotCommonController) findGroupSnapshotMembers(groupSnapshotName types.NamespacedName) ([]*crdv1.VolumeSnapshot, error) {
1570+
// Look up for the members of this volume group snapshot
1571+
snapshotMembers, err := ctrl.snapshotIndexer.ByIndex(
1572+
utils.VolumeSnapshotParentGroupIndex,
1573+
utils.VolumeSnapshotParentGroupKeyFuncByComponents(
1574+
groupSnapshotName,
1575+
),
1576+
)
1577+
if err != nil {
1578+
return nil, err
1579+
}
1580+
1581+
result := make([]*crdv1.VolumeSnapshot, len(snapshotMembers))
1582+
for i := range snapshotMembers {
1583+
var ok bool
1584+
result[i], ok = snapshotMembers[i].(*crdv1.VolumeSnapshot)
1585+
if !ok {
1586+
return nil, fmt.Errorf("unexpected content found in snapshot index: %v", snapshotMembers[i])
1587+
}
1588+
}
1589+
1590+
return result, nil
1591+
}
1592+
15641593
// removeGroupSnapshotFinalizer removes a Finalizer for VolumeGroupSnapshot.
15651594
func (ctrl *csiSnapshotCommonController) removeGroupSnapshotFinalizer(groupSnapshot *crdv1alpha1.VolumeGroupSnapshot, removeBoundFinalizer bool) error {
15661595
if !removeBoundFinalizer {

pkg/common-controller/snapshot_controller.go

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func (ctrl *csiSnapshotCommonController) syncContent(content *crdv1.VolumeSnapsh
173173
// created, updated or periodically synced. We do not differentiate between
174174
// these events.
175175
// For easier readability, it is split into syncUnreadySnapshot and syncReadySnapshot
176-
func (ctrl *csiSnapshotCommonController) syncSnapshot(snapshot *crdv1.VolumeSnapshot) error {
176+
func (ctrl *csiSnapshotCommonController) syncSnapshot(ctx context.Context, snapshot *crdv1.VolumeSnapshot) error {
177177
klog.V(5).Infof("synchronizing VolumeSnapshot[%s]: %s", utils.SnapshotKey(snapshot), utils.GetSnapshotStatusForLogging(snapshot))
178178

179179
klog.V(5).Infof("syncSnapshot [%s]: check if we should remove finalizer on snapshot PVC source and remove it if we can", utils.SnapshotKey(snapshot))
@@ -214,7 +214,7 @@ func (ctrl *csiSnapshotCommonController) syncSnapshot(snapshot *crdv1.VolumeSnap
214214
if !utils.IsSnapshotReady(snapshot) || !utils.IsBoundVolumeSnapshotContentNameSet(snapshot) {
215215
return ctrl.syncUnreadySnapshot(snapshot)
216216
}
217-
return ctrl.syncReadySnapshot(snapshot)
217+
return ctrl.syncReadySnapshot(ctx, snapshot)
218218
}
219219

220220
// processSnapshotWithDeletionTimestamp processes finalizers and deletes the content when appropriate. It has the following steps:
@@ -395,7 +395,7 @@ func (ctrl *csiSnapshotCommonController) checkandAddSnapshotFinalizers(snapshot
395395

396396
// syncReadySnapshot checks the snapshot which has been bound to snapshot content successfully before.
397397
// If there is any problem with the binding (e.g., snapshot points to a non-existent snapshot content), update the snapshot status and emit event.
398-
func (ctrl *csiSnapshotCommonController) syncReadySnapshot(snapshot *crdv1.VolumeSnapshot) error {
398+
func (ctrl *csiSnapshotCommonController) syncReadySnapshot(ctx context.Context, snapshot *crdv1.VolumeSnapshot) error {
399399
if !utils.IsBoundVolumeSnapshotContentNameSet(snapshot) {
400400
return fmt.Errorf("snapshot %s is not bound to a content", utils.SnapshotKey(snapshot))
401401
}
@@ -415,10 +415,56 @@ func (ctrl *csiSnapshotCommonController) syncReadySnapshot(snapshot *crdv1.Volum
415415
return ctrl.updateSnapshotErrorStatusWithEvent(snapshot, true, v1.EventTypeWarning, "SnapshotMisbound", "VolumeSnapshotContent is not bound to the VolumeSnapshot correctly")
416416
}
417417

418+
// If this snapshot is a member of a volume group snapshot, ensure we have
419+
// the correct ownership. This happens when the user
420+
// statically provisioned volume group snapshot members.
421+
if utils.NeedToAddVolumeGroupSnapshotOwnership(snapshot) {
422+
if _, err := ctrl.addVolumeGroupSnapshotOwnership(ctx, snapshot); err != nil {
423+
return err
424+
}
425+
}
426+
418427
// everything is verified, return
419428
return nil
420429
}
421430

431+
// addVolumeGroupSnapshotOwnership adds the ownership information to a statically provisioned VolumeSnapshot
432+
// that is a member of a volume group snapshot
433+
func (ctrl *csiSnapshotCommonController) addVolumeGroupSnapshotOwnership(ctx context.Context, snapshot *crdv1.VolumeSnapshot) (*crdv1.VolumeSnapshot, error) {
434+
klog.V(4).Infof("addVolumeGroupSnapshotOwnership[%s]: adding ownership information", utils.SnapshotKey(snapshot))
435+
if snapshot.Status == nil || snapshot.Status.VolumeGroupSnapshotName == nil {
436+
klog.V(4).Infof("addVolumeGroupSnapshotOwnership[%s]: no need to add ownership information, empty volumeGroupSnapshotName", utils.SnapshotKey(snapshot))
437+
return nil, nil
438+
}
439+
parentObjectName := *snapshot.Status.VolumeGroupSnapshotName
440+
441+
parentGroup, err := ctrl.groupSnapshotLister.VolumeGroupSnapshots(snapshot.Namespace).Get(parentObjectName)
442+
if err != nil {
443+
klog.V(4).Infof("addVolumeGroupSnapshotOwnership[%s]: error while looking for parent group %v", utils.SnapshotKey(snapshot), err)
444+
return nil, err
445+
}
446+
if parentGroup == nil {
447+
klog.V(4).Infof("addVolumeGroupSnapshotOwnership[%s]: parent group not found %v", utils.SnapshotKey(snapshot), err)
448+
return nil, fmt.Errorf("missing parent group for snapshot %v", utils.SnapshotKey(snapshot))
449+
}
450+
451+
updatedSnapshot := snapshot.DeepCopy()
452+
updatedSnapshot.ObjectMeta.OwnerReferences = append(
453+
snapshot.ObjectMeta.OwnerReferences,
454+
utils.BuildVolumeGroupSnapshotOwnerReference(parentGroup),
455+
)
456+
457+
newSnapshot, err := ctrl.clientset.SnapshotV1().VolumeSnapshots(snapshot.Namespace).Update(ctx, updatedSnapshot, metav1.UpdateOptions{})
458+
if err != nil {
459+
klog.V(4).Infof("addVolumeGroupSnapshotOwnership[%s]: error when updating VolumeSnapshot %v", utils.SnapshotKey(snapshot), err)
460+
return nil, err
461+
}
462+
463+
klog.V(4).Infof("addVolumeGroupSnapshotOwnership[%s]: updated ownership", utils.SnapshotKey(snapshot))
464+
465+
return newSnapshot, nil
466+
}
467+
422468
// syncUnreadySnapshot is the main controller method to decide what to do with a snapshot which is not set to ready.
423469
func (ctrl *csiSnapshotCommonController) syncUnreadySnapshot(snapshot *crdv1.VolumeSnapshot) error {
424470
uniqueSnapshotName := utils.SnapshotKey(snapshot)
@@ -483,7 +529,7 @@ func (ctrl *csiSnapshotCommonController) syncUnreadySnapshot(snapshot *crdv1.Vol
483529
}
484530

485531
// member of a dynamically provisioned volume group snapshot
486-
if _, ok := snapshot.Labels[utils.VolumeGroupSnapshotNameLabel]; ok {
532+
if utils.IsVolumeGroupSnapshotMember(snapshot) {
487533
if snapshot.Status == nil || snapshot.Status.BoundVolumeSnapshotContentName == nil {
488534
klog.V(5).Infof(
489535
"syncUnreadySnapshot [%s]: detected group snapshot member with no content, retrying",
@@ -1422,7 +1468,7 @@ func (ctrl *csiSnapshotCommonController) SetDefaultSnapshotClass(snapshot *crdv1
14221468
return nil, snapshot, nil
14231469
}
14241470

1425-
if _, ok := snapshot.Labels[utils.VolumeGroupSnapshotNameLabel]; ok {
1471+
if utils.IsVolumeGroupSnapshotMember(snapshot) {
14261472
// don't return error for volume group snapshot members
14271473
klog.V(5).Infof("Don't need to find SnapshotClass for volume group snapshot member [%s]", snapshot.Name)
14281474
return nil, snapshot, nil

pkg/common-controller/snapshot_controller_base.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ type csiSnapshotCommonController struct {
8787
preventVolumeModeConversion bool
8888
enableVolumeGroupSnapshots bool
8989

90-
pvIndexer cache.Indexer
90+
pvIndexer cache.Indexer
91+
snapshotIndexer cache.Indexer
9192
}
9293

9394
// NewCSISnapshotController returns a new *csiSnapshotCommonController
@@ -158,8 +159,20 @@ func NewCSISnapshotCommonController(
158159
},
159160
ctrl.resyncPeriod,
160161
)
162+
volumeSnapshotInformer.Informer().AddIndexers(map[string]cache.IndexFunc{
163+
utils.VolumeSnapshotParentGroupIndex: func(obj interface{}) ([]string, error) {
164+
if snapshot, ok := obj.(*crdv1.VolumeSnapshot); ok {
165+
if key := utils.VolumeSnapshotParentGroupKeyFunc(snapshot); key != "" {
166+
return []string{key}, nil
167+
}
168+
}
169+
170+
return nil, nil
171+
},
172+
})
161173
ctrl.snapshotLister = volumeSnapshotInformer.Lister()
162174
ctrl.snapshotListerSynced = volumeSnapshotInformer.Informer().HasSynced
175+
ctrl.snapshotIndexer = volumeSnapshotInformer.Informer().GetIndexer()
163176

164177
volumeSnapshotContentInformer.Informer().AddEventHandlerWithResyncPeriod(
165178
cache.ResourceEventHandlerFuncs{
@@ -323,6 +336,7 @@ func (ctrl *csiSnapshotCommonController) snapshotWorker() {
323336

324337
// syncSnapshotByKey processes a VolumeSnapshot request.
325338
func (ctrl *csiSnapshotCommonController) syncSnapshotByKey(key string) error {
339+
ctx := context.Background()
326340
klog.V(5).Infof("syncSnapshotByKey[%s]", key)
327341

328342
namespace, name, err := cache.SplitMetaNamespaceKey(key)
@@ -344,7 +358,7 @@ func (ctrl *csiSnapshotCommonController) syncSnapshotByKey(key string) error {
344358
klog.V(5).Infof("Snapshot %q is being deleted. SnapshotClass has already been removed", key)
345359
}
346360
klog.V(5).Infof("Updating snapshot %q", key)
347-
return ctrl.updateSnapshot(newSnapshot)
361+
return ctrl.updateSnapshot(ctx, newSnapshot)
348362
}
349363
return err
350364
}
@@ -476,7 +490,7 @@ func (ctrl *csiSnapshotCommonController) checkAndUpdateSnapshotClass(snapshot *c
476490

477491
// updateSnapshot runs in worker thread and handles "snapshot added",
478492
// "snapshot updated" and "periodic sync" events.
479-
func (ctrl *csiSnapshotCommonController) updateSnapshot(snapshot *crdv1.VolumeSnapshot) error {
493+
func (ctrl *csiSnapshotCommonController) updateSnapshot(ctx context.Context, snapshot *crdv1.VolumeSnapshot) error {
480494
// Store the new snapshot version in the cache and do not process it if this is
481495
// an old version.
482496
klog.V(5).Infof("updateSnapshot %q", utils.SnapshotKey(snapshot))
@@ -488,7 +502,7 @@ func (ctrl *csiSnapshotCommonController) updateSnapshot(snapshot *crdv1.VolumeSn
488502
return nil
489503
}
490504

491-
err = ctrl.syncSnapshot(snapshot)
505+
err = ctrl.syncSnapshot(ctx, snapshot)
492506
if err != nil {
493507
if errors.IsConflict(err) {
494508
// Version conflict error happens quite often and the controller

pkg/sidecar-controller/groupsnapshot_helper.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,18 @@ func (ctrl *csiSnapshotSideCarController) deleteCSIGroupSnapshotOperation(groupS
246246
return fmt.Errorf("failed to get input parameters to delete group snapshot for group snapshot content %s: %q", groupSnapshotContent.Name, err)
247247
}
248248

249+
// Collect the snapshot ids considering both dynamic and static provisioning.
250+
// For dynamic provisioning, they can be found in groupContent.Status.VolumeSnapshotHandlePairList
251+
// For static provisioning, they can be found in groupContent.Spec.Source.GroupSnapshotHandles.VolumeSnapshotHandles
249252
var snapshotIDs []string
250-
if groupSnapshotContent.Status != nil && len(groupSnapshotContent.Status.VolumeSnapshotHandlePairList) != 0 {
251-
for _, contentRef := range groupSnapshotContent.Status.VolumeSnapshotHandlePairList {
252-
snapshotIDs = append(snapshotIDs, contentRef.SnapshotHandle)
253+
if groupSnapshotContent.Status != nil {
254+
if len(groupSnapshotContent.Status.VolumeSnapshotHandlePairList) != 0 {
255+
for _, contentRef := range groupSnapshotContent.Status.VolumeSnapshotHandlePairList {
256+
snapshotIDs = append(snapshotIDs, contentRef.SnapshotHandle)
257+
}
258+
} else if groupSnapshotContent.Spec.Source.GroupSnapshotHandles != nil {
259+
ids := groupSnapshotContent.Spec.Source.GroupSnapshotHandles.VolumeSnapshotHandles
260+
snapshotIDs = slices.Clone(ids)
253261
}
254262
}
255263

pkg/utils/util.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,6 @@ const (
146146
AnnDeletionGroupSecretRefName = "groupsnapshot.storage.kubernetes.io/deletion-secret-name"
147147
AnnDeletionGroupSecretRefNamespace = "groupsnapshot.storage.kubernetes.io/deletion-secret-namespace"
148148

149-
// VolumeGroupSnapshotNameLabel is applied to VolumeSnapshots that are member
150-
// of a VolumeGroupSnapshot, and indicates the name of the latter.
151-
VolumeGroupSnapshotNameLabel = "groupsnapshot.storage.k8s.io/volumeGroupSnapshotName"
152-
153149
// VolumeGroupSnapshotHandleAnnotation is applied to VolumeSnapshotContents that are member
154150
// of a VolumeGroupSnapshotContent, and indicates the handle of the latter.
155151
//

0 commit comments

Comments
 (0)