-
Notifications
You must be signed in to change notification settings - Fork 201
Cleanup PVC finalizers added by cnsnodevmattachment #3837
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,6 +27,7 @@ import ( | |
| ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" | ||
| "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
| cnsoperatorv1alpha1 "sigs.k8s.io/vsphere-csi-driver/v3/pkg/apis/cnsoperator" | ||
| nodeattachv1a1 "sigs.k8s.io/vsphere-csi-driver/v3/pkg/apis/cnsoperator/cnsnodevmattachment/v1alpha1" | ||
| batchattachv1a1 "sigs.k8s.io/vsphere-csi-driver/v3/pkg/apis/cnsoperator/cnsnodevmbatchattachment/v1alpha1" | ||
| cnsregistervolumev1alpha1 "sigs.k8s.io/vsphere-csi-driver/v3/pkg/apis/cnsoperator/cnsregistervolume/v1alpha1" | ||
| cnsunregistervolumev1alpha1 "sigs.k8s.io/vsphere-csi-driver/v3/pkg/apis/cnsoperator/cnsunregistervolume/v1alpha1" | ||
|
|
@@ -234,3 +235,99 @@ func cleanupOrphanedBatchAttachPVCs(ctx context.Context, config rest.Config) { | |
| } | ||
| } | ||
| } | ||
|
|
||
| // cleanupOrphanedNodeAttachPVCs removes the `CNSPvcFinalizer` from the PVCs in cases | ||
| // where the CnsNodeVmAttachment CR gets deleted before the PVCs. | ||
| // This is EXTREMELY UNLIKELY to happen but in case of concurrent updates and deletes of the CR, | ||
| // it was observed that the CRs could sometime lose track of the PVCs that could lead to this. | ||
| // This routine is a SAFETY GUARDRAIL to avoid situations where namespaces could remain stuck in terminating state. | ||
| // This routine usually runs every 10 minutes. | ||
| func cleanupOrphanedNodeAttachPVCs(ctx context.Context, config rest.Config) { | ||
| log := logger.GetLogger(ctx) | ||
|
|
||
| pvcList := commonco.ContainerOrchestratorUtility.ListPVCs(ctx, "") | ||
| if len(pvcList) == 0 { | ||
| log.Debug("no PVCs found in cluster, skipping node attach cleanup cycle") | ||
| return | ||
| } | ||
|
|
||
| // map to hold all the PVCs that are orphaned by CnsNodeVmAttachment reconciler. | ||
| // structure of the map follows the logical grouping kubernetes uses. | ||
| // namespace -> pvc -> struct{}{} | ||
| orphanPVCs := make(map[string]map[string]struct{}) | ||
|
|
||
| for _, pvc := range pvcList { | ||
| if pvc.DeletionTimestamp == nil { | ||
| // PVC is not being deleted. Can be ignored. | ||
| continue | ||
| } | ||
|
|
||
| if !controllerutil.ContainsFinalizer(pvc, cnsoperatortypes.CNSPvcFinalizer) { | ||
| // not a PVC that is attached to or being attached to a VM. Can be ignored. | ||
| continue | ||
| } | ||
|
|
||
| // For CnsNodeVmAttachment, we need to check if there's a corresponding CR | ||
| // that references this PVC. Unlike batch attach, node attach doesn't use | ||
| // specific annotations, so we'll identify orphaned PVCs by checking if | ||
| // any CnsNodeVmAttachment CR exists that could be managing this PVC. | ||
|
|
||
| if _, ok := orphanPVCs[pvc.Namespace]; !ok { | ||
| orphanPVCs[pvc.Namespace] = map[string]struct{}{} | ||
| } | ||
| orphanPVCs[pvc.Namespace][pvc.Name] = struct{}{} | ||
| } | ||
|
|
||
| if len(orphanPVCs) == 0 { | ||
| log.Debug("no orphan PVCs found in cluster, skipping node attach cleanup cycle") | ||
| return | ||
| } | ||
|
|
||
| cnsClient, err := newClientForGroup(ctx, &config, cnsoperatorv1alpha1.GroupName) | ||
| if err != nil { | ||
| log.Error("failed to create cns operator client") | ||
| return | ||
| } | ||
|
|
||
| // Iterate over namespaces that have candidate orphan PVCs | ||
| for namespace := range orphanPVCs { | ||
| nodeAttachList := nodeattachv1a1.CnsNodeVmAttachmentList{} | ||
| err = cnsClient.List(ctx, &nodeAttachList, ctrlclient.InNamespace(namespace)) | ||
| if err != nil { | ||
|
Member
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. The code skips cleanup for an entire namespace if ANY CnsNodeVmAttachment CR exists. This means truly orphaned PVCs will never be cleaned up as long as there's at least one CR in the namespace. |
||
| log.With("kind", nodeAttachList.Kind).With("namespace", namespace).Error("listing failed") | ||
| continue | ||
| } | ||
|
|
||
| // If there are any CnsNodeVmAttachment CRs in the namespace, we need to be careful | ||
| // about which PVCs to clean up. For now, we'll take a conservative approach: | ||
| // Only clean up PVCs if there are NO CnsNodeVmAttachment CRs in the namespace. | ||
| // This ensures we don't accidentally remove finalizers from PVCs that might | ||
| // still be managed by existing CRs. | ||
| if len(nodeAttachList.Items) > 0 { | ||
xing-yang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| log.With("namespace", namespace).With("nodeAttachCRCount", len(nodeAttachList.Items)). | ||
| Debug("skipping PVC cleanup in namespace with existing CnsNodeVmAttachment CRs") | ||
| delete(orphanPVCs, namespace) | ||
| } | ||
| } | ||
|
|
||
| c, err := newForConfig(&config) | ||
| if err != nil { | ||
| log.Error("failed to create core API client") | ||
| return | ||
| } | ||
|
|
||
| // All the PVCs that are remaining in the map are eligible orphans whose finalizer can be removed. | ||
| for namespace, pvcs := range orphanPVCs { | ||
| for name := range pvcs { | ||
| err := k8s.RemoveFinalizerFromPVC(ctx, c, name, namespace, cnsoperatortypes.CNSPvcFinalizer) | ||
|
Member
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. we need to make sure this routine is not having race with clean up routine in batchattach |
||
| if err != nil { | ||
| log.With("name", name).With("namespace", namespace). | ||
| Error("failed to remove the finalizer") | ||
| // safe to continue as failure to remove finalizer of a pvc doesn't influence others | ||
| continue | ||
xing-yang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| log.With("name", name).With("namespace", namespace). | ||
| Info("successfully removed CNS PVC finalizer from orphaned PVC") | ||
| } | ||
| } | ||
| } | ||
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.
Using map[string]map[string]struct{} loses the PVC object reference, which could be useful for additional validation.