From 63b40a7a5e0d3f00ef2b4c1de9f50fb7d6df4ead Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Thu, 22 Jan 2026 09:12:53 -0500 Subject: [PATCH 1/2] use logger with waiter Signed-off-by: Austin Abro --- pkg/kube/client.go | 7 ++-- pkg/kube/statuswait.go | 20 ++++++----- pkg/kube/statuswait_test.go | 71 +++++++++++++++++++++---------------- 3 files changed, 56 insertions(+), 42 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index ad8f851d1..c4ea1e596 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -166,7 +166,8 @@ func (c *Client) newStatusWatcher(opts ...WaitOption) (*statusWaiter, error) { if waitContext == nil { waitContext = c.WaitContext } - return &statusWaiter{ + + sw := &statusWaiter{ restMapper: restMapper, client: dynamicClient, ctx: waitContext, @@ -175,7 +176,9 @@ func (c *Client) newStatusWatcher(opts ...WaitOption) (*statusWaiter, error) { waitWithJobsCtx: o.waitWithJobsCtx, waitForDeleteCtx: o.waitForDeleteCtx, readers: o.statusReaders, - }, nil + } + sw.SetLogger(c.Logger().Handler()) + return sw, nil } func (c *Client) GetWaiter(ws WaitStrategy) (Waiter, error) { diff --git a/pkg/kube/statuswait.go b/pkg/kube/statuswait.go index 84819492b..01024afa6 100644 --- a/pkg/kube/statuswait.go +++ b/pkg/kube/statuswait.go @@ -38,6 +38,7 @@ import ( "k8s.io/client-go/dynamic" watchtools "k8s.io/client-go/tools/watch" + "helm.sh/helm/v4/internal/logging" helmStatusReaders "helm.sh/helm/v4/internal/statusreaders" ) @@ -50,6 +51,7 @@ type statusWaiter struct { waitWithJobsCtx context.Context waitForDeleteCtx context.Context readers []engine.StatusReader + logging.LogHolder } // DefaultStatusWatcherTimeout is the timeout used by the status waiter when a @@ -72,7 +74,7 @@ func (w *statusWaiter) WatchUntilReady(resourceList ResourceList, timeout time.D } ctx, cancel := w.contextWithTimeout(w.watchUntilReadyCtx, timeout) defer cancel() - slog.Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) + w.Logger().Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) sw := watcher.NewDefaultStatusWatcher(w.client, w.restMapper) jobSR := helmStatusReaders.NewCustomJobStatusReader(w.restMapper) podSR := helmStatusReaders.NewCustomPodStatusReader(w.restMapper) @@ -94,7 +96,7 @@ func (w *statusWaiter) Wait(resourceList ResourceList, timeout time.Duration) er } ctx, cancel := w.contextWithTimeout(w.waitCtx, timeout) defer cancel() - slog.Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) + w.Logger().Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) sw := watcher.NewDefaultStatusWatcher(w.client, w.restMapper) sw.StatusReader = statusreaders.NewStatusReader(w.restMapper, w.readers...) return w.wait(ctx, resourceList, sw) @@ -106,7 +108,7 @@ func (w *statusWaiter) WaitWithJobs(resourceList ResourceList, timeout time.Dura } ctx, cancel := w.contextWithTimeout(w.waitWithJobsCtx, timeout) defer cancel() - slog.Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) + w.Logger().Debug("waiting for resources", "count", len(resourceList), "timeout", timeout) sw := watcher.NewDefaultStatusWatcher(w.client, w.restMapper) newCustomJobStatusReader := helmStatusReaders.NewCustomJobStatusReader(w.restMapper) readers := append([]engine.StatusReader(nil), w.readers...) @@ -122,7 +124,7 @@ func (w *statusWaiter) WaitForDelete(resourceList ResourceList, timeout time.Dur } ctx, cancel := w.contextWithTimeout(w.waitForDeleteCtx, timeout) defer cancel() - slog.Debug("waiting for resources to be deleted", "count", len(resourceList), "timeout", timeout) + w.Logger().Debug("waiting for resources to be deleted", "count", len(resourceList), "timeout", timeout) sw := watcher.NewDefaultStatusWatcher(w.client, w.restMapper) return w.waitForDelete(ctx, resourceList, sw) } @@ -142,7 +144,7 @@ func (w *statusWaiter) waitForDelete(ctx context.Context, resourceList ResourceL RESTScopeStrategy: watcher.RESTScopeNamespace, }) statusCollector := collector.NewResourceStatusCollector(resources) - done := statusCollector.ListenWithObserver(eventCh, statusObserver(cancel, status.NotFoundStatus)) + done := statusCollector.ListenWithObserver(eventCh, statusObserver(cancel, status.NotFoundStatus, w.Logger())) <-done if statusCollector.Error != nil { @@ -189,7 +191,7 @@ func (w *statusWaiter) wait(ctx context.Context, resourceList ResourceList, sw w RESTScopeStrategy: watcher.RESTScopeNamespace, }) statusCollector := collector.NewResourceStatusCollector(resources) - done := statusCollector.ListenWithObserver(eventCh, statusObserver(cancel, status.CurrentStatus)) + done := statusCollector.ListenWithObserver(eventCh, statusObserver(cancel, status.CurrentStatus, w.Logger())) <-done if statusCollector.Error != nil { @@ -228,7 +230,7 @@ func contextWithTimeout(ctx context.Context, timeout time.Duration) (context.Con return watchtools.ContextWithOptionalTimeout(ctx, timeout) } -func statusObserver(cancel context.CancelFunc, desired status.Status) collector.ObserverFunc { +func statusObserver(cancel context.CancelFunc, desired status.Status, logger *slog.Logger) collector.ObserverFunc { return func(statusCollector *collector.ResourceStatusCollector, _ event.Event) { var rss []*event.ResourceStatus var nonDesiredResources []*event.ResourceStatus @@ -253,7 +255,7 @@ func statusObserver(cancel context.CancelFunc, desired status.Status) collector. } if aggregator.AggregateStatus(rss, desired) == desired { - slog.Debug("all resources achieved desired status", "desiredStatus", desired, "resourceCount", len(rss)) + logger.Debug("all resources achieved desired status", "desiredStatus", desired, "resourceCount", len(rss)) cancel() return } @@ -264,7 +266,7 @@ func statusObserver(cancel context.CancelFunc, desired status.Status) collector. return nonDesiredResources[i].Identifier.Name < nonDesiredResources[j].Identifier.Name }) first := nonDesiredResources[0] - slog.Debug("waiting for resource", "namespace", first.Identifier.Namespace, "name", first.Identifier.Name, "kind", first.Identifier.GroupKind.Kind, "expectedStatus", desired, "actualStatus", first.Status) + logger.Debug("waiting for resource", "namespace", first.Identifier.Namespace, "name", first.Identifier.Name, "kind", first.Identifier.GroupKind.Kind, "expectedStatus", desired, "actualStatus", first.Status) } } } diff --git a/pkg/kube/statuswait_test.go b/pkg/kube/statuswait_test.go index 83aaa357a..d2dd57872 100644 --- a/pkg/kube/statuswait_test.go +++ b/pkg/kube/statuswait_test.go @@ -20,6 +20,7 @@ import ( "context" "errors" "fmt" + "log/slog" "strings" "sync/atomic" "testing" @@ -326,6 +327,7 @@ func TestStatusWaitForDelete(t *testing.T) { restMapper: fakeMapper, client: fakeClient, } + statusWaiter.SetLogger(slog.Default().Handler()) objsToCreate := getRuntimeObjFromManifests(t, tt.manifestsToCreate) for _, objToCreate := range objsToCreate { u := objToCreate.(*unstructured.Unstructured) @@ -369,6 +371,7 @@ func TestStatusWaitForDeleteNonExistentObject(t *testing.T) { restMapper: fakeMapper, client: fakeClient, } + statusWaiter.SetLogger(slog.Default().Handler()) // Don't create the object to test that the wait for delete works when the object doesn't exist objManifest := getRuntimeObjFromManifests(t, []string{podCurrentManifest}) resourceList := getResourceListFromRuntimeObjs(t, c, objManifest) @@ -425,6 +428,7 @@ func TestStatusWait(t *testing.T) { client: fakeClient, restMapper: fakeMapper, } + statusWaiter.SetLogger(slog.Default().Handler()) objs := getRuntimeObjFromManifests(t, tt.objManifests) for _, obj := range objs { u := obj.(*unstructured.Unstructured) @@ -481,6 +485,7 @@ func TestWaitForJobComplete(t *testing.T) { client: fakeClient, restMapper: fakeMapper, } + statusWaiter.SetLogger(slog.Default().Handler()) objs := getRuntimeObjFromManifests(t, tt.objManifests) for _, obj := range objs { u := obj.(*unstructured.Unstructured) @@ -543,6 +548,7 @@ func TestWatchForReady(t *testing.T) { client: fakeClient, restMapper: fakeMapper, } + statusWaiter.SetLogger(slog.Default().Handler()) objs := getRuntimeObjFromManifests(t, tt.objManifests) for _, obj := range objs { u := obj.(*unstructured.Unstructured) @@ -570,19 +576,19 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { name string objManifests []string expectErrStrs []string - testFunc func(statusWaiter, ResourceList, time.Duration) error + testFunc func(*statusWaiter, ResourceList, time.Duration) error }{ { name: "pods in multiple namespaces", objManifests: []string{podNamespace1Manifest, podNamespace2Manifest}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, { name: "hooks in multiple namespaces", objManifests: []string{jobNamespace1CompleteManifest, podNamespace2SucceededManifest}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.WatchUntilReady(rl, timeout) }, }, @@ -590,42 +596,42 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { name: "error when resource not ready in one namespace", objManifests: []string{podNamespace1NoStatusManifest, podNamespace2Manifest}, expectErrStrs: []string{"resource Pod/namespace-1/pod-ns1 not ready. status: InProgress", "context deadline exceeded"}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, { name: "delete resources in multiple namespaces", objManifests: []string{podNamespace1Manifest, podNamespace2Manifest}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.WaitForDelete(rl, timeout) }, }, { name: "cluster-scoped resources work correctly with unrestricted permissions", objManifests: []string{podNamespace1Manifest, clusterRoleManifest}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, { name: "namespace-scoped and cluster-scoped resources work together", objManifests: []string{podNamespace1Manifest, podNamespace2Manifest, clusterRoleManifest}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, { name: "delete cluster-scoped resources works correctly", objManifests: []string{podNamespace1Manifest, namespaceManifest}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.WaitForDelete(rl, timeout) }, }, { name: "watch cluster-scoped resources works correctly", objManifests: []string{clusterRoleManifest}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.WatchUntilReady(rl, timeout) }, }, @@ -646,6 +652,7 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { client: fakeClient, restMapper: fakeMapper, } + sw.SetLogger(slog.Default().Handler()) objs := getRuntimeObjFromManifests(t, tt.objManifests) for _, obj := range objs { u := obj.(*unstructured.Unstructured) @@ -668,7 +675,7 @@ func TestStatusWaitMultipleNamespaces(t *testing.T) { } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := tt.testFunc(sw, resourceList, time.Second*3) + err := tt.testFunc(&sw, resourceList, time.Second*3) if tt.expectErrStrs != nil { require.Error(t, err) for _, expectedErrStr := range tt.expectErrStrs { @@ -756,13 +763,13 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { objManifests []string allowedNamespaces []string expectErrs []error - testFunc func(statusWaiter, ResourceList, time.Duration) error + testFunc func(*statusWaiter, ResourceList, time.Duration) error }{ { name: "pods in multiple namespaces with namespace permissions", objManifests: []string{podNamespace1Manifest, podNamespace2Manifest}, allowedNamespaces: []string{"namespace-1", "namespace-2"}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, @@ -770,7 +777,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { name: "delete pods in multiple namespaces with namespace permissions", objManifests: []string{podNamespace1Manifest, podNamespace2Manifest}, allowedNamespaces: []string{"namespace-1", "namespace-2"}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.WaitForDelete(rl, timeout) }, }, @@ -778,7 +785,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { name: "hooks in multiple namespaces with namespace permissions", objManifests: []string{jobNamespace1CompleteManifest, podNamespace2SucceededManifest}, allowedNamespaces: []string{"namespace-1", "namespace-2"}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.WatchUntilReady(rl, timeout) }, }, @@ -787,7 +794,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { objManifests: []string{podNamespace1Manifest, clusterRoleManifest}, allowedNamespaces: []string{"namespace-1"}, expectErrs: []error{fmt.Errorf("user does not have cluster-wide LIST permissions for cluster-scoped resources")}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, @@ -796,7 +803,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { objManifests: []string{podNamespace1Manifest, namespaceManifest}, allowedNamespaces: []string{"namespace-1"}, expectErrs: []error{fmt.Errorf("user does not have cluster-wide LIST permissions for cluster-scoped resources")}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.WaitForDelete(rl, timeout) }, }, @@ -805,7 +812,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { objManifests: []string{podNamespace1Manifest, podNamespace2Manifest}, allowedNamespaces: []string{"namespace-1"}, expectErrs: []error{fmt.Errorf("user does not have LIST permissions in namespace %q", "namespace-2")}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, @@ -827,6 +834,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { client: baseFakeClient, restMapper: fakeMapper, } + sw.SetLogger(slog.Default().Handler()) objs := getRuntimeObjFromManifests(t, tt.objManifests) for _, obj := range objs { u := obj.(*unstructured.Unstructured) @@ -849,7 +857,7 @@ func TestStatusWaitRestrictedRBAC(t *testing.T) { } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := tt.testFunc(sw, resourceList, time.Second*3) + err := tt.testFunc(&sw, resourceList, time.Second*3) if tt.expectErrs != nil { require.Error(t, err) for _, expectedErr := range tt.expectErrs { @@ -870,13 +878,13 @@ func TestStatusWaitMixedResources(t *testing.T) { objManifests []string allowedNamespaces []string expectErrs []error - testFunc func(statusWaiter, ResourceList, time.Duration) error + testFunc func(*statusWaiter, ResourceList, time.Duration) error }{ { name: "wait succeeds with namespace-scoped resources only", objManifests: []string{podNamespace1Manifest, podNamespace2Manifest}, allowedNamespaces: []string{"namespace-1", "namespace-2"}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, @@ -885,7 +893,7 @@ func TestStatusWaitMixedResources(t *testing.T) { objManifests: []string{podNamespace1Manifest, clusterRoleManifest}, allowedNamespaces: []string{"namespace-1"}, expectErrs: []error{fmt.Errorf("user does not have cluster-wide LIST permissions for cluster-scoped resources")}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, @@ -894,7 +902,7 @@ func TestStatusWaitMixedResources(t *testing.T) { objManifests: []string{podNamespace1Manifest, clusterRoleManifest}, allowedNamespaces: []string{"namespace-1"}, expectErrs: []error{fmt.Errorf("user does not have cluster-wide LIST permissions for cluster-scoped resources")}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.WaitForDelete(rl, timeout) }, }, @@ -903,7 +911,7 @@ func TestStatusWaitMixedResources(t *testing.T) { objManifests: []string{podNamespace1Manifest, namespaceManifest}, allowedNamespaces: []string{"namespace-1"}, expectErrs: []error{fmt.Errorf("user does not have cluster-wide LIST permissions for cluster-scoped resources")}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, @@ -912,7 +920,7 @@ func TestStatusWaitMixedResources(t *testing.T) { objManifests: []string{podNamespace1Manifest, podNamespace2Manifest}, allowedNamespaces: []string{"namespace-1"}, expectErrs: []error{fmt.Errorf("user does not have LIST permissions in namespace %q", "namespace-2")}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, @@ -934,6 +942,7 @@ func TestStatusWaitMixedResources(t *testing.T) { client: baseFakeClient, restMapper: fakeMapper, } + sw.SetLogger(slog.Default().Handler()) objs := getRuntimeObjFromManifests(t, tt.objManifests) for _, obj := range objs { u := obj.(*unstructured.Unstructured) @@ -956,7 +965,7 @@ func TestStatusWaitMixedResources(t *testing.T) { } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := tt.testFunc(sw, resourceList, time.Second*3) + err := tt.testFunc(&sw, resourceList, time.Second*3) if tt.expectErrs != nil { require.Error(t, err) for _, expectedErr := range tt.expectErrs { @@ -1151,7 +1160,7 @@ func TestStatusWaitWithFailedResources(t *testing.T) { objManifests []string customReader *mockStatusReader expectErrStrs []string - testFunc func(statusWaiter, ResourceList, time.Duration) error + testFunc func(*statusWaiter, ResourceList, time.Duration) error }{ { name: "Wait returns error when resource has failed", @@ -1161,7 +1170,7 @@ func TestStatusWaitWithFailedResources(t *testing.T) { status: status.FailedStatus, }, expectErrStrs: []string{"resource Pod/ns/in-progress-pod not ready. status: Failed, message: mock status reader"}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, @@ -1172,7 +1181,7 @@ func TestStatusWaitWithFailedResources(t *testing.T) { expectErrStrs: []string{ "resource Job/default/failed-job not ready. status: Failed", }, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.WaitWithJobs(rl, timeout) }, }, @@ -1188,7 +1197,7 @@ func TestStatusWaitWithFailedResources(t *testing.T) { "resource Pod/ns/in-progress-pod not ready. status: Failed, message: mock status reader", "resource Pod/ns/current-pod not ready. status: Failed, message: mock status reader", }, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.Wait(rl, timeout) }, }, @@ -1201,7 +1210,7 @@ func TestStatusWaitWithFailedResources(t *testing.T) { }, // WatchUntilReady also waits for CurrentStatus, so failed resources should return error expectErrStrs: []string{"resource Pod/ns/in-progress-pod not ready. status: Failed, message: mock status reader"}, - testFunc: func(sw statusWaiter, rl ResourceList, timeout time.Duration) error { + testFunc: func(sw *statusWaiter, rl ResourceList, timeout time.Duration) error { return sw.WatchUntilReady(rl, timeout) }, }, @@ -1233,7 +1242,7 @@ func TestStatusWaitWithFailedResources(t *testing.T) { assert.NoError(t, err) } resourceList := getResourceListFromRuntimeObjs(t, c, objs) - err := tt.testFunc(sw, resourceList, time.Second*3) + err := tt.testFunc(&sw, resourceList, time.Second*3) if tt.expectErrStrs != nil { require.Error(t, err) for _, expectedErrStr := range tt.expectErrStrs { From ec0726523e52448eb05c8b5b3faae969e3a79266 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Thu, 22 Jan 2026 15:45:29 -0500 Subject: [PATCH 2/2] whitespace Signed-off-by: Austin Abro --- pkg/kube/client.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index c4ea1e596..fc706496d 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -166,7 +166,6 @@ func (c *Client) newStatusWatcher(opts ...WaitOption) (*statusWaiter, error) { if waitContext == nil { waitContext = c.WaitContext } - sw := &statusWaiter{ restMapper: restMapper, client: dynamicClient,