Skip to content

Commit 9478f63

Browse files
committed
fix(dataprotection): simplify restored PV validation
1 parent 985bbc0 commit 9478f63

3 files changed

Lines changed: 44 additions & 207 deletions

File tree

controllers/dataprotection/types.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,6 @@ const (
8080
// annotation keys
8181
AnnSelectedNode = "volume.kubernetes.io/selected-node"
8282
AnnPopulateFrom = "dataprotection.kubeblocks.io/populate-from"
83-
// AnnPopulationAttempt records the immutable identity of the target PVC
84-
// population attempt that performed a PV rebind.
85-
AnnPopulationAttempt = "dataprotection.kubeblocks.io/population-attempt"
8683

8784
// event reason
8885
ReasonStartToVolumePopulate = "StartToVolumePopulate"

controllers/dataprotection/volumepopulator_controller.go

Lines changed: 20 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,8 @@ import (
6363
// VolumePopulatorReconciler reconciles Backup dataSource PVCs.
6464
type VolumePopulatorReconciler struct {
6565
client.Client
66-
APIReader client.Reader
67-
Scheme *runtime.Scheme
68-
Recorder record.EventRecorder
66+
Scheme *runtime.Scheme
67+
Recorder record.EventRecorder
6968
}
7069

7170
type pvcRestoreMode string
@@ -139,9 +138,6 @@ func (r *VolumePopulatorReconciler) handleSyncPVCError(reqCtx intctrlutil.Reques
139138

140139
// SetupWithManager sets up the controller with the Manager.
141140
func (r *VolumePopulatorReconciler) SetupWithManager(mgr ctrl.Manager) error {
142-
if r.APIReader == nil {
143-
r.APIReader = mgr.GetAPIReader()
144-
}
145141
return intctrlutil.NewControllerManagedBy(mgr).
146142
For(&corev1.PersistentVolumeClaim{}).
147143
Watches(&dpv1alpha1.Restore{}, handler.EnqueueRequestsFromMapFunc(r.mapRestoreToPVCs),
@@ -1244,97 +1240,36 @@ func (r *VolumePopulatorReconciler) completeBoundPVCIfNeeded(reqCtx intctrlutil.
12441240
}
12451241

12461242
// validateBoundTargetPV verifies that an already-bound target PVC points to
1247-
// the PV rebound by this populator. Use the direct API reader when available so
1248-
// informer ordering between the PV and PVC updates cannot create a permanent
1249-
// false failure.
1243+
// the PV rebound by this populator.
12501244
func (r *VolumePopulatorReconciler) validateBoundTargetPV(reqCtx intctrlutil.RequestCtx,
12511245
pvc *corev1.PersistentVolumeClaim) error {
12521246
if pvc.Spec.VolumeName == "" {
12531247
return intctrlutil.NewRequeueError(reconcileInterval, "waiting for target PVC to bind")
12541248
}
1255-
reader := client.Reader(r.Client)
1256-
if r.APIReader != nil {
1257-
reader = r.APIReader
1258-
}
12591249
pv := &corev1.PersistentVolume{}
1260-
if err := reader.Get(reqCtx.Ctx, types.NamespacedName{Name: pvc.Spec.VolumeName}, pv); err != nil {
1250+
if err := r.Client.Get(reqCtx.Ctx, types.NamespacedName{Name: pvc.Spec.VolumeName}, pv); err != nil {
12611251
if apierrors.IsNotFound(err) {
12621252
return intctrlutil.NewRequeueError(reconcileInterval,
12631253
fmt.Sprintf("waiting for target PV %s for PVC %s/%s", pvc.Spec.VolumeName, pvc.Namespace, pvc.Name))
12641254
}
12651255
return err
12661256
}
1267-
claimRef := pv.Spec.ClaimRef
1268-
claimMatches := claimRef != nil && claimRef.Namespace == pvc.Namespace && claimRef.Name == pvc.Name
1269-
if claimMatches && pvc.UID != "" {
1270-
claimMatches = claimRef.UID == pvc.UID
1271-
}
1272-
if !claimMatches {
1257+
if !pvClaimRefMatchesPVC(pv.Spec.ClaimRef, pvc) {
12731258
return intctrlutil.NewFatalError(fmt.Sprintf(
12741259
"target PVC %s/%s is bound to PV %s whose claimRef does not identify the restore target",
12751260
pvc.Namespace, pvc.Name, pv.Name))
12761261
}
1277-
expectedAttempt, err := populationAttemptIdentity(pvc)
1278-
if err != nil {
1279-
return intctrlutil.NewFatalError(err.Error())
1280-
}
1281-
if actualAttempt := pv.Annotations[AnnPopulationAttempt]; actualAttempt != "" {
1282-
if actualAttempt == expectedAttempt {
1283-
return nil
1284-
}
1262+
if pvc.Spec.DataSourceRef == nil || pvc.Spec.DataSourceRef.Name == "" {
12851263
return intctrlutil.NewFatalError(fmt.Sprintf(
1286-
"target PVC %s/%s is bound to PV %s from population attempt %q, expected %q",
1287-
pvc.Namespace, pvc.Name, pv.Name, actualAttempt, expectedAttempt))
1264+
"target PVC %s/%s has no dataSourceRef", pvc.Namespace, pvc.Name))
12881265
}
1289-
1290-
// Compatibility for an in-flight rebind started by an older controller:
1291-
// the old marker recorded only the source name. Accept it only while the
1292-
// exact helper PVC still points at this PV. A provisioner-bound empty PV
1293-
// cannot satisfy this relationship.
12941266
expectedSource := pvc.Spec.DataSourceRef.Name
1295-
if expectedSource != "" && pv.Annotations[AnnPopulateFrom] == expectedSource {
1296-
helper := &corev1.PersistentVolumeClaim{}
1297-
helperKey := types.NamespacedName{Namespace: pvc.Namespace, Name: getPopulatePVCName(pvc.UID)}
1298-
if err := reader.Get(reqCtx.Ctx, helperKey, helper); err == nil && helper.Spec.VolumeName == pv.Name {
1299-
return nil
1300-
} else if err != nil && apierrors.IsNotFound(err) && pvcBindingCompleted(pvc) {
1301-
// An older controller wrote AnnPopulateFrom before deleting the helper
1302-
// and before recording population success. If Kubernetes has already
1303-
// completed the target binding, the exact target ClaimRef validated
1304-
// above plus the legacy marker is sufficient to resume after an upgrade.
1305-
return nil
1306-
} else if err != nil && !apierrors.IsNotFound(err) {
1307-
return err
1308-
}
1309-
}
1310-
return intctrlutil.NewFatalError(fmt.Sprintf(
1311-
"target PVC %s/%s is bound to PV %s without expected population provenance %s=%q",
1312-
pvc.Namespace, pvc.Name, pv.Name, AnnPopulationAttempt, expectedAttempt))
1313-
}
1314-
1315-
func populationAttemptIdentity(pvc *corev1.PersistentVolumeClaim) (string, error) {
1316-
if pvc.UID == "" {
1317-
return "", fmt.Errorf("target PVC %s/%s has no UID", pvc.Namespace, pvc.Name)
1318-
}
1319-
if pvc.Spec.DataSourceRef == nil || pvc.Spec.DataSourceRef.Name == "" {
1320-
return "", fmt.Errorf("target PVC %s/%s has no dataSourceRef identity", pvc.Namespace, pvc.Name)
1321-
}
1322-
apiGroup := ""
1323-
if pvc.Spec.DataSourceRef.APIGroup != nil {
1324-
apiGroup = *pvc.Spec.DataSourceRef.APIGroup
1325-
}
1326-
sourceNamespace := pvc.Namespace
1327-
if pvc.Spec.DataSourceRef.Kind == dptypes.BackupKind {
1328-
var err error
1329-
sourceNamespace, err = backupNamespaceFromPVC(pvc)
1330-
if err != nil {
1331-
return "", err
1332-
}
1333-
} else if pvc.Spec.DataSourceRef.Namespace != nil && *pvc.Spec.DataSourceRef.Namespace != "" {
1334-
sourceNamespace = *pvc.Spec.DataSourceRef.Namespace
1267+
if pv.Annotations[AnnPopulateFrom] != expectedSource {
1268+
return intctrlutil.NewFatalError(fmt.Sprintf(
1269+
"target PVC %s/%s is bound to PV %s without expected population provenance %s=%q",
1270+
pvc.Namespace, pvc.Name, pv.Name, AnnPopulateFrom, expectedSource))
13351271
}
1336-
return fmt.Sprintf("v1|%s|%s|%s|%s|%s", pvc.UID, apiGroup, pvc.Spec.DataSourceRef.Kind,
1337-
sourceNamespace, pvc.Spec.DataSourceRef.Name), nil
1272+
return nil
13381273
}
13391274

13401275
func (r *VolumePopulatorReconciler) waitForSerialPredecessors(reqCtx intctrlutil.RequestCtx,
@@ -2089,16 +2024,12 @@ func (r *VolumePopulatorReconciler) rebindPVCAndPV(reqCtx intctrlutil.RequestCtx
20892024
if populatePVC.Spec.VolumeName == "" {
20902025
return false, nil
20912026
}
2092-
attempt, err := populationAttemptIdentity(pvc)
2093-
if err != nil {
2094-
return false, intctrlutil.NewFatalError(err.Error())
2095-
}
2096-
reader := client.Reader(r.Client)
2097-
if r.APIReader != nil {
2098-
reader = r.APIReader
2027+
if pvc.Spec.DataSourceRef == nil || pvc.Spec.DataSourceRef.Name == "" {
2028+
return false, intctrlutil.NewFatalError(fmt.Sprintf(
2029+
"target PVC %s/%s has no dataSourceRef", pvc.Namespace, pvc.Name))
20992030
}
21002031
pv := &corev1.PersistentVolume{}
2101-
if err := reader.Get(reqCtx.Ctx, types.NamespacedName{Name: populatePVC.Spec.VolumeName}, pv); err != nil {
2032+
if err := r.Client.Get(reqCtx.Ctx, types.NamespacedName{Name: populatePVC.Spec.VolumeName}, pv); err != nil {
21022033
if !apierrors.IsNotFound(err) {
21032034
return false, err
21042035
}
@@ -2108,28 +2039,10 @@ func (r *VolumePopulatorReconciler) rebindPVCAndPV(reqCtx intctrlutil.RequestCtx
21082039
// Examine the claimref for the PV and see if it's bound to the correct PVC
21092040
claimRef := pv.Spec.ClaimRef
21102041
if pvClaimRefMatchesPVC(claimRef, pvc) {
2111-
actualAttempt := pv.Annotations[AnnPopulationAttempt]
2112-
if actualAttempt != attempt {
2113-
legacyRebind := actualAttempt == "" &&
2114-
pv.Annotations[AnnPopulateFrom] == pvc.Spec.DataSourceRef.Name &&
2115-
populatePVC.Namespace == pvc.Namespace &&
2116-
populatePVC.Name == getPopulatePVCName(pvc.UID) &&
2117-
populatePVC.Spec.VolumeName == pv.Name
2118-
if !legacyRebind {
2119-
return false, intctrlutil.NewFatalError(fmt.Sprintf(
2120-
"PV %s already identifies target PVC %s/%s but does not carry population attempt %q",
2121-
pv.Name, pvc.Namespace, pvc.Name, attempt))
2122-
}
2123-
// Resume an old controller that patched the PV ClaimRef and legacy
2124-
// marker, then crashed before writing targetPVC.spec.volumeName.
2125-
patchPV := client.MergeFromWithOptions(pv.DeepCopy(), client.MergeFromWithOptimisticLock{})
2126-
if pv.Annotations == nil {
2127-
pv.Annotations = map[string]string{}
2128-
}
2129-
pv.Annotations[AnnPopulationAttempt] = attempt
2130-
if err := r.Client.Patch(reqCtx.Ctx, pv, patchPV); err != nil {
2131-
return false, requeuePVRebindConflict(err, pv, pvc)
2132-
}
2042+
if pv.Annotations[AnnPopulateFrom] != pvc.Spec.DataSourceRef.Name {
2043+
return false, intctrlutil.NewFatalError(fmt.Sprintf(
2044+
"PV %s already identifies target PVC %s/%s without expected population provenance %s=%q",
2045+
pv.Name, pvc.Namespace, pvc.Name, AnnPopulateFrom, pvc.Spec.DataSourceRef.Name))
21332046
}
21342047
return true, r.bindTargetPVCToPV(reqCtx, pvc, pv.Name)
21352048
}
@@ -2150,7 +2063,6 @@ func (r *VolumePopulatorReconciler) rebindPVCAndPV(reqCtx intctrlutil.RequestCtx
21502063
pv.Annotations = map[string]string{}
21512064
}
21522065
pv.Annotations[AnnPopulateFrom] = pvc.Spec.DataSourceRef.Name
2153-
pv.Annotations[AnnPopulationAttempt] = attempt
21542066
if err := r.Client.Patch(reqCtx.Ctx, pv, patchPV); err != nil {
21552067
return false, requeuePVRebindConflict(err, pv, pvc)
21562068
}

0 commit comments

Comments
 (0)