Fix switch case ordering bug in filterBackupOwnerReferences (#10161)

* Fix switch case ordering in filterBackupOwnerReferences (Issue #10160)

When client.Get returns a transient (non-NotFound) error, the previous
case ordering caused the UID mismatch case to fire against a zero-value
struct, silently dropping the owner reference and logging a misleading
'mismatched UIDs' warning instead of the intended error log.

Fix: move the general error handler before the UID mismatch check so
it is evaluated while err is still relevant. The UID check now only
runs when err == nil (i.e. the Schedule was successfully fetched).

Also add a test case that injects a transient Get error via the fake
client interceptor to verify the owner reference is preserved.

Signed-off-by: aftab <aftab123215@gmail.com>

* Add changelog for #10160

Signed-off-by: aftab <aftab123215@gmail.com>

---------

Signed-off-by: aftab <aftab123215@gmail.com>
This commit is contained in:
AftAb-25
2026-08-12 15:12:58 +08:00
committed by GitHub
parent 2aa5175594
commit 9a1d2e6eb0
3 changed files with 47 additions and 2 deletions
@@ -36,6 +36,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
ctrlClient "sigs.k8s.io/controller-runtime/pkg/client"
ctrlfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
@@ -914,4 +915,47 @@ var _ = Describe("Backup Sync Reconciler", func() {
})
}
})
It("filterBackupOwnerReferences preserves owner reference on transient API error", func() {
// This test verifies the fix for the switch case ordering bug:
// When client.Get returns a non-NotFound error (e.g. transient API failure),
// the owner reference must be kept on the backup rather than silently dropped
// due to an incorrect UID comparison against a zero-value struct.
scheduleUID := types.UID("schedule-uid-1")
backup := &velerov1api.Backup{
ObjectMeta: metav1.ObjectMeta{
Name: "test-backup",
Namespace: "test-namespace",
OwnerReferences: []metav1.OwnerReference{
{
Kind: "Schedule",
Name: "my-schedule",
UID: scheduleUID,
},
},
},
}
// Build a fake client that returns a generic (non-NotFound) error on Get,
// simulating a transient API server failure.
transientErr := fmt.Errorf("transient connection error")
fakeClient := ctrlfake.NewClientBuilder().
WithInterceptorFuncs(interceptor.Funcs{
Get: func(ctx context.Context, c ctrlClient.WithWatch, key ctrlClient.ObjectKey, obj ctrlClient.Object, opts ...ctrlClient.GetOption) error {
return transientErr
},
}).
Build()
b := backupSyncReconciler{
client: fakeClient,
}
logger := velerotest.NewLogger()
references := b.filterBackupOwnerReferences(context.Background(), backup, logger)
// The owner reference must be preserved when a transient error occurs.
Expect(references).To(HaveLen(1))
Expect(references[0].UID).To(Equal(scheduleUID))
})
})