During informer cache initialization every watched resource briefly
reports UnknownStatus, and the watcher can deliver its Sync event before
the initial status events. The delete-path observer skipped Unknown
resources, so an all-Unknown set aggregated (over an empty slice) to the
desired NotFound status and cancelled the watch before a single real
status event arrived: a delete wait could report success, or a spurious
'still exists' error, for resources that were never deleted. This is the
race behind the TestStatusWaitForDelete flake.
Unknown cannot simply be treated as pending either: a resource deleted
before the watch starts is absent from the informer's initial LIST and
never receives an event, so it stays Unknown forever and the wait would
hang until the timeout. That regression (#32214, hooks using the
before-hook-creation delete policy) is what got the previous attempt
(#32081) reverted.
waitForDelete now uses a dedicated observer that makes no completion
decision until the watcher delivers its Sync event, and from then on
confirms any resource still reporting Unknown with a live lookup:
NotFound confirms the deletion, while anything else keeps the wait
running until the watcher reports a real status. Lookup errors never
confirm a deletion, so a delete wait fails closed to the timeout instead
of returning early.
New tests pin both directions deterministically: a scripted status
watcher replays the informer-sync window (Sync delivered while every
resource still reports Unknown) and must not complete the wait for
resources that still exist, while an already-deleted hook object must
still complete promptly instead of waiting out the timeout.
Fixes#32261
Refs #32214
Signed-off-by: Bisman-Singh <bismanmadaan1@gmail.com>
// deleteStatusObserver returns an observer for delete waits, where the desired
first:=nonDesiredResources[0]
// status is NotFound.
logger.Debug("waiting for resource","namespace",first.Identifier.Namespace,"name",first.Identifier.Name,"kind",first.Identifier.GroupKind.Kind,"expectedStatus",desired,"actualStatus",first.Status)
//
// UnknownStatus is ambiguous on this path. While the status watcher initializes
// its informer caches, every watched resource briefly reports Unknown, so an
// Unknown-only set must not complete the wait: resources that still exist would
// be reported as deleted before a single real status event arrived (#32261).
// But a resource deleted before the watch started also stays Unknown forever,
// because the watcher never emits an event for an object absent from its
// initial LIST; waiting for a real status event would hang until the timeout
// for resources that are already gone (#32214).
//
// The observer therefore makes no completion decision until the watcher
// delivers its Sync event, which marks the informer caches as populated. From
// then on, any resource still reporting Unknown is confirmed with a live
// lookup: NotFound confirms the deletion, while anything else keeps the wait
// running until the watcher reports a real status for it.
logger.Debug("waiting for resource","namespace",first.Identifier.Namespace,"name",first.Identifier.Name,"kind",first.Identifier.GroupKind.Kind,"expectedStatus",desired,"actualStatus",first.Status)