-
Notifications
You must be signed in to change notification settings - Fork 199
Enhancement - Implement Snapshot Informer Cache for Volume Unregistration Workflow #3760
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
Open
kolluria
wants to merge
8
commits into
kubernetes-sigs:master
Choose a base branch
from
kolluria:cache-usages
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,087
−81
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
961ec42
Initial implementation of using informer caches for snapshots
kolluria 00fd7a3
Updated Listen logic of informer manager to start snapshot sync
kolluria 604c9fc
Implemented handlers for snapshot create and delete events
kolluria eddf93b
Refactoring
kolluria e838277
Added add, get and remove methods on the pvcToSnapshotsMap
kolluria 205905d
Removed update event handler as it's not required
kolluria b565b5b
Refactor snapshot retrieval to use ContainerOrchestratorUtility
kolluria a3aefcd
Removed pointer reference to RWMutext of pvcToSnapshotsMap
kolluria File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,7 @@ import ( | |
| "sync/atomic" | ||
| "time" | ||
|
|
||
| snapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1" | ||
| "google.golang.org/grpc/codes" | ||
| "k8s.io/client-go/util/retry" | ||
|
|
||
|
|
@@ -239,6 +240,71 @@ func (m *volumeIDToNameMap) get(volumeID string) (string, bool) { | |
| return volumeName, found | ||
| } | ||
|
|
||
| // pvcToSnapshotsMap maps a PVC to its snapshots. | ||
| // The primary key is the namespaced name of the PVC and value is a map. | ||
| // The key of the inner map is the name of the snapshot. | ||
| type pvcToSnapshotsMap struct { | ||
| sync.RWMutex | ||
| items map[k8stypes.NamespacedName]map[string]struct{} | ||
| } | ||
|
|
||
| func (m *pvcToSnapshotsMap) add(pvc, snapshot, namespace string) { | ||
| m.Lock() | ||
| defer m.Unlock() | ||
|
|
||
| pvcKey := k8stypes.NamespacedName{ | ||
| Namespace: namespace, | ||
| Name: pvc, | ||
| } | ||
| if _, ok := m.items[pvcKey]; !ok { | ||
| m.items[pvcKey] = make(map[string]struct{}) | ||
| } | ||
| m.items[pvcKey][snapshot] = struct{}{} | ||
| } | ||
|
|
||
| func (m *pvcToSnapshotsMap) get(pvc, namespace string) []string { | ||
| m.RLock() | ||
| defer m.RUnlock() | ||
|
|
||
| pvcKey := k8stypes.NamespacedName{ | ||
| Namespace: namespace, | ||
| Name: pvc, | ||
| } | ||
| snapMap, ok := m.items[pvcKey] | ||
| if !ok { | ||
| return []string{} | ||
| } | ||
|
|
||
| snaps := make([]string, 0, len(snapMap)) | ||
| for snap := range snapMap { | ||
| snaps = append(snaps, snap) | ||
| } | ||
| return snaps | ||
| } | ||
|
|
||
| func (m *pvcToSnapshotsMap) delete(pvc, snapshot, namespace string) { | ||
| m.Lock() | ||
| defer m.Unlock() | ||
|
|
||
| pvcKey := k8stypes.NamespacedName{ | ||
| Namespace: namespace, | ||
| Name: pvc, | ||
| } | ||
| snapMap, ok := m.items[pvcKey] | ||
| if !ok { | ||
| return | ||
| } | ||
|
|
||
| delete(snapMap, snapshot) | ||
| if len(snapMap) != 0 { | ||
| m.items[pvcKey] = snapMap | ||
| return | ||
| } | ||
|
|
||
| // delete pvc entry if no snapshots are present | ||
| delete(m.items, pvcKey) | ||
| } | ||
|
|
||
| // K8sOrchestrator defines set of properties specific to K8s. | ||
| type K8sOrchestrator struct { | ||
| supervisorFSS FSSConfigMapInfo | ||
|
|
@@ -251,6 +317,7 @@ type K8sOrchestrator struct { | |
| nodeIDToNameMap *nodeIDToNameMap | ||
| volumeNameToNodesMap *volumeNameToNodesMap // used when ListVolume FSS is enabled | ||
| volumeIDToNameMap *volumeIDToNameMap // used when ListVolume FSS is enabled | ||
| pvcToSnapshotsMap pvcToSnapshotsMap | ||
| k8sClient clientset.Interface | ||
| snapshotterClient snapshotterClientSet.Interface | ||
| // pvcUIDCache maps PVC UID to its namespaced name (namespace/name). | ||
|
|
@@ -319,7 +386,7 @@ func Newk8sOrchestrator(ctx context.Context, controllerClusterFlavor cnstypes.Cn | |
| k8sOrchestratorInstance.clusterFlavor = controllerClusterFlavor | ||
| k8sOrchestratorInstance.k8sClient = k8sClient | ||
| k8sOrchestratorInstance.snapshotterClient = snapshotterClient | ||
| k8sOrchestratorInstance.informerManager = k8s.NewInformer(ctx, k8sClient, true) | ||
| k8sOrchestratorInstance.informerManager = k8s.NewInformer(ctx, k8sClient, snapshotterClient) | ||
| coInstanceErr = initFSS(ctx, k8sClient, controllerClusterFlavor, params) | ||
| if coInstanceErr != nil { | ||
| log.Errorf("Failed to initialize the orchestrator. Error: %v", coInstanceErr) | ||
|
|
@@ -381,6 +448,11 @@ func Newk8sOrchestrator(ctx context.Context, controllerClusterFlavor cnstypes.Cn | |
| } | ||
| } | ||
|
|
||
| err := initPVCToSnapshotsMap(ctx, controllerClusterFlavor) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to create PVC to snapshots map. Error: %v", err) | ||
| } | ||
|
|
||
| k8sOrchestratorInstance.informerManager.Listen() | ||
| atomic.StoreUint32(&k8sOrchestratorInstanceInitialized, 1) | ||
| log.Info("k8sOrchestratorInstance initialized") | ||
|
|
@@ -1945,6 +2017,75 @@ func nodeRemove(obj interface{}) { | |
| k8sOrchestratorInstance.nodeIDToNameMap.remove(nodeMoID) | ||
| } | ||
|
|
||
| // handleSnapshotAdded handles the snapshot add event by adding it to the pvcToSnapshotsMap cache. | ||
| func handleSnapshotAdded(ctx context.Context, obj any, pvcMap *pvcToSnapshotsMap) { | ||
| log := logger.GetLogger(ctx) | ||
| snap, ok := obj.(*snapshotv1.VolumeSnapshot) | ||
| if !ok || snap == nil { | ||
| log.Warnf("unrecognized object %+v", obj) | ||
| return | ||
| } | ||
|
|
||
| if snap.Spec.Source.PersistentVolumeClaimName == nil { | ||
| log.Warnf("snapshot is not associated with any PVC. Ignoring it...") | ||
| return | ||
| } | ||
|
|
||
| pvcMap.add(*snap.Spec.Source.PersistentVolumeClaimName, snap.Name, snap.Namespace) | ||
| log.With("pvc", *snap.Spec.Source.PersistentVolumeClaimName).With("snapshot", snap.Name). | ||
| With("namespace", snap.Namespace).Debug("successfully added the snapshot to the cache") | ||
| } | ||
|
|
||
| // handleSnapshotDeleted handles the snapshot delete event by removing it from the pvcToSnapshotsMap cache. | ||
| func handleSnapshotDeleted(ctx context.Context, obj any, pvcMap *pvcToSnapshotsMap) { | ||
| log := logger.GetLogger(ctx) | ||
| snap, ok := obj.(*snapshotv1.VolumeSnapshot) | ||
| if !ok || snap == nil { | ||
| log.Warnf("unrecognized object %+v", obj) | ||
| return | ||
| } | ||
|
|
||
| if snap.Spec.Source.PersistentVolumeClaimName == nil { | ||
| log.Warnf("snapshot is not associated with any PVC. Ignoring it...") | ||
| return | ||
| } | ||
|
|
||
| pvcMap.delete(*snap.Spec.Source.PersistentVolumeClaimName, snap.Name, snap.Namespace) | ||
| log.With("pvc", *snap.Spec.Source.PersistentVolumeClaimName).With("snapshot", snap.Name). | ||
| With("namespace", snap.Namespace).Debug("successfully removed the snapshot from the cache") | ||
| } | ||
|
|
||
| func initPVCToSnapshotsMap(ctx context.Context, controllerClusterFlavor cnstypes.CnsClusterFlavor) error { | ||
| log := logger.GetLogger(ctx) | ||
| // TODO: check if we need to check the FSS as well | ||
| if controllerClusterFlavor != cnstypes.CnsClusterFlavorWorkload { | ||
| // PVC to VolumeSnapshot cache is only required for WCP for now. | ||
| log.Info("non WCP cluster detected. skipping initialising PVC to Snapshot cache.") | ||
| return nil | ||
| } | ||
|
|
||
| k8sOrchestratorInstance.pvcToSnapshotsMap = pvcToSnapshotsMap{ | ||
| RWMutex: sync.RWMutex{}, | ||
| items: make(map[k8stypes.NamespacedName]map[string]struct{}), | ||
| } | ||
|
|
||
| err := k8sOrchestratorInstance.informerManager.AddSnapshotListener(ctx, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This informer should be conditionally added. In Vanilla cluster, VolumeSnapshot CRD may not be installed.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @xing-yang great catch! Let me fix that |
||
| func(obj any) { | ||
| handleSnapshotAdded(ctx, obj, &k8sOrchestratorInstance.pvcToSnapshotsMap) | ||
| }, | ||
| // Since the name of PVC associated with a snapshot is immutable, | ||
| // update events do not have any impact on the state of the cache. | ||
| nil, | ||
| func(obj any) { | ||
| handleSnapshotDeleted(ctx, obj, &k8sOrchestratorInstance.pvcToSnapshotsMap) | ||
| }) | ||
| if err != nil { | ||
| return logger.LogNewErrorf(log, "failed to listen on volumesnapshots. Error: %v", err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // GetNodeIDtoNameMap returns a map containing the nodeID to node name | ||
| func (c *K8sOrchestrator) GetNodeIDtoNameMap(ctx context.Context) map[string]string { | ||
| return c.nodeIDToNameMap.items | ||
|
|
@@ -2259,6 +2400,11 @@ func (c *K8sOrchestrator) GetPVCNamespacedNameByUID(uid string) (k8stypes.Namesp | |
| return nsName, true | ||
| } | ||
|
|
||
| // GetSnapshotsForPVC returns the names of the snapshots for the given PVC | ||
| func (c *K8sOrchestrator) GetSnapshotsForPVC(ctx context.Context, pvc, namespace string) []string { | ||
| return c.pvcToSnapshotsMap.get(pvc, namespace) | ||
| } | ||
|
|
||
| // GetPVCDataSource Retrieves the VolumeSnapshot source when a PVC from VolumeSnapshot is being created. | ||
| func GetPVCDataSource(ctx context.Context, claim *v1.PersistentVolumeClaim) (*v1.ObjectReference, error) { | ||
| var dataSource v1.ObjectReference | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@divyenpatel ^