diff --git a/pkg/action/hooks.go b/pkg/action/hooks.go index 2490613c4..a050b466a 100644 --- a/pkg/action/hooks.go +++ b/pkg/action/hooks.go @@ -80,12 +80,15 @@ func (cfg *Configuration) execHook(ctx context.Context, rl *release.Release, hoo return errors.Wrapf(err, "warning: Hook %s %s failed", hook, h.Path) } - ctxInterface, ok := cfg.KubeClient.(kube.ContextInterface) - if !ok { - panic("KubeClient does not satisfies kube.ContextInterface") + // Check if kube.Interface implementation satisfies kube.ContextInterface interface. + // If it doesn't log a warning and move on, nothing we can do. + if kubeClient, ok := cfg.KubeClient.(kube.ContextInterface); ok { + // Watch hook resources until they have completed + err = kubeClient.WatchUntilReadyWithContext(ctx, resources) + } else { + cfg.Log("WARNING: kube.ContextInterface not satisfied") } - // Watch hook resources until they have completed - err = ctxInterface.WatchUntilReadyWithContext(ctx, resources) + // Note the time of success/failure h.LastRun.CompletedAt = helmtime.Now() // Mark hook as succeeded or failed diff --git a/pkg/action/install.go b/pkg/action/install.go index 2283bb9ef..4e9b7a2b5 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -204,7 +204,6 @@ func (i *Install) installCRDs(crds []chart.CRD) error { // Run executes the installation // // If DryRun is set to true, this will prepare the release, but not install it - func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.Release, error) { ctx, cancel := context.WithTimeout(context.TODO(), i.Timeout) defer cancel() @@ -379,11 +378,10 @@ func (i *Install) RunWithContext(ctx context.Context, chrt *chart.Chart, vals ma } func (i *Install) performInstall(ctx context.Context, rel *release.Release, toBeAdopted, resources kube.ResourceList) (*release.Release, error) { - // pre-install hooks if !i.DisableHooks { if err := i.cfg.execHook(ctx, rel, release.HookPreInstall); err != nil { - return i.failRelease(rel, fmt.Errorf("failed pre-install: %w", err)) + return i.failRelease(ctx, rel, fmt.Errorf("failed pre-install: %w", err)) } } @@ -392,31 +390,31 @@ func (i *Install) performInstall(ctx context.Context, rel *release.Release, toBe // to true, since that is basically an upgrade operation. if len(toBeAdopted) == 0 && len(resources) > 0 { if _, err := i.cfg.KubeClient.Create(resources); err != nil { - return i.failRelease(rel, err) + return i.failRelease(ctx, rel, err) } } else if len(resources) > 0 { if _, err := i.cfg.KubeClient.Update(toBeAdopted, resources, i.Force); err != nil { - return i.failRelease(rel, err) + return i.failRelease(ctx, rel, err) } } - if i.Wait { - kubeClient := i.cfg.KubeClient.(kube.ContextInterface) - + // Check if kube.Interface implementation, also satisfies kube.ContextInterface. + kubeClient, ok := i.cfg.KubeClient.(kube.ContextInterface) + if i.Wait && ok { if i.WaitForJobs { if err := kubeClient.WaitWithJobsContext(ctx, resources); err != nil { - return i.failRelease(rel, err) + return i.failRelease(ctx, rel, err) } } else { if err := kubeClient.WaitWithContext(ctx, resources); err != nil { - return i.failRelease(rel, err) + return i.failRelease(ctx, rel, err) } } } if !i.DisableHooks { if err := i.cfg.execHook(ctx, rel, release.HookPostInstall); err != nil { - return i.failRelease(rel, fmt.Errorf("failed post-install: %w", err)) + return i.failRelease(ctx, rel, fmt.Errorf("failed post-install: %w", err)) } } @@ -440,15 +438,18 @@ func (i *Install) performInstall(ctx context.Context, rel *release.Release, toBe return rel, nil } -func (i *Install) failRelease(rel *release.Release, err error) (*release.Release, error) { +func (i *Install) failRelease(ctx context.Context, rel *release.Release, err error) (*release.Release, error) { rel.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", i.ReleaseName, err.Error())) if i.Atomic { i.cfg.Log("Install failed and atomic is set, uninstalling release") uninstall := NewUninstall(i.cfg) uninstall.DisableHooks = i.DisableHooks uninstall.KeepHistory = false + // TODO: Not sure if a new ctx should be created by the timeout field, + // because Timeout will be replaced by contexts. Should a background ctx be used + // so we don't timeout while uninstalling? uninstall.Timeout = i.Timeout - if _, uninstallErr := uninstall.Run(i.ReleaseName); uninstallErr != nil { + if _, uninstallErr := uninstall.RunWithContext(context.Background(), i.ReleaseName); uninstallErr != nil { return rel, errors.Wrapf(uninstallErr, "an error occurred while uninstalling the release. original install error: %s", err) } return rel, errors.Wrapf(err, "release %s failed, and has been uninstalled due to atomic being set", i.ReleaseName) diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 078608803..ca48e6cde 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -103,7 +103,8 @@ func TestInstallReleaseWithValues(t *testing.T) { "simpleKey": "simpleValue", }, } - res, err := instAction.Run(buildChart(withSampleValues()), userVals) + + res, err := instAction.RunWithContext(context.Background(), buildChart(withSampleValues()), userVals) if err != nil { t.Fatalf("Failed install: %s", err) } @@ -129,7 +130,7 @@ func TestInstallReleaseClientOnly(t *testing.T) { is := assert.New(t) instAction := installAction(t) instAction.ClientOnly = true - instAction.Run(buildChart(), nil) // disregard output + instAction.RunWithContext(context.Background(), buildChart(), nil) // disregard output is.Equal(instAction.cfg.Capabilities, chartutil.DefaultCapabilities) is.Equal(instAction.cfg.KubeClient, &kubefake.PrintingKubeClient{Out: io.Discard}) @@ -139,7 +140,7 @@ func TestInstallRelease_NoName(t *testing.T) { instAction := installAction(t) instAction.ReleaseName = "" vals := map[string]interface{}{} - _, err := instAction.Run(buildChart(), vals) + _, err := instAction.RunWithContext(context.Background(), buildChart(), vals) if err == nil { t.Fatal("expected failure when no name is specified") } @@ -151,7 +152,8 @@ func TestInstallRelease_WithNotes(t *testing.T) { instAction := installAction(t) instAction.ReleaseName = "with-notes" vals := map[string]interface{}{} - res, err := instAction.Run(buildChart(withNotes("note here")), vals) + + res, err := instAction.RunWithContext(context.Background(), buildChart(withNotes("note here")), vals) if err != nil { t.Fatalf("Failed install: %s", err) } @@ -178,7 +180,8 @@ func TestInstallRelease_WithNotesRendered(t *testing.T) { instAction := installAction(t) instAction.ReleaseName = "with-notes" vals := map[string]interface{}{} - res, err := instAction.Run(buildChart(withNotes("got-{{.Release.Name}}")), vals) + + res, err := instAction.RunWithContext(context.Background(), buildChart(withNotes("got-{{.Release.Name}}")), vals) if err != nil { t.Fatalf("Failed install: %s", err) } @@ -197,7 +200,8 @@ func TestInstallRelease_WithChartAndDependencyParentNotes(t *testing.T) { instAction := installAction(t) instAction.ReleaseName = "with-notes" vals := map[string]interface{}{} - res, err := instAction.Run(buildChart(withNotes("parent"), withDependency(withNotes("child"))), vals) + + res, err := instAction.RunWithContext(context.Background(), buildChart(withNotes("parent"), withDependency(withNotes("child"))), vals) if err != nil { t.Fatalf("Failed install: %s", err) } @@ -215,8 +219,9 @@ func TestInstallRelease_WithChartAndDependencyAllNotes(t *testing.T) { instAction := installAction(t) instAction.ReleaseName = "with-notes" instAction.SubNotes = true + vals := map[string]interface{}{} - res, err := instAction.Run(buildChart(withNotes("parent"), withDependency(withNotes("child"))), vals) + res, err := instAction.RunWithContext(context.Background(), buildChart(withNotes("parent"), withDependency(withNotes("child"))), vals) if err != nil { t.Fatalf("Failed install: %s", err) } @@ -236,7 +241,7 @@ func TestInstallRelease_DryRun(t *testing.T) { instAction := installAction(t) instAction.DryRun = true vals := map[string]interface{}{} - res, err := instAction.Run(buildChart(withSampleTemplates()), vals) + res, err := instAction.RunWithContext(context.Background(), buildChart(withSampleTemplates()), vals) if err != nil { t.Fatalf("Failed install: %s", err) } @@ -267,7 +272,7 @@ func TestInstallRelease_DryRun_Lookup(t *testing.T) { Data: []byte(`goodbye: {{ lookup "v1" "Namespace" "" "___" }}`), }) - res, err := instAction.Run(mockChart, vals) + res, err := instAction.RunWithContext(context.Background(), mockChart, vals) if err != nil { t.Fatalf("Failed install: %s", err) } @@ -280,7 +285,7 @@ func TestInstallReleaseIncorrectTemplate_DryRun(t *testing.T) { instAction := installAction(t) instAction.DryRun = true vals := map[string]interface{}{} - _, err := instAction.Run(buildChart(withSampleIncludingIncorrectTemplates()), vals) + _, err := instAction.RunWithContext(context.Background(), buildChart(withSampleIncludingIncorrectTemplates()), vals) expectedErr := "\"hello/templates/incorrect\" at <.Values.bad.doh>: nil pointer evaluating interface {}.doh" if err == nil { t.Fatalf("Install should fail containing error: %s", expectedErr) @@ -298,7 +303,7 @@ func TestInstallRelease_NoHooks(t *testing.T) { instAction.cfg.Releases.Create(releaseStub()) vals := map[string]interface{}{} - res, err := instAction.Run(buildChart(), vals) + res, err := instAction.RunWithContext(context.Background(), buildChart(), vals) if err != nil { t.Fatalf("Failed install: %s", err) } @@ -315,7 +320,7 @@ func TestInstallRelease_FailedHooks(t *testing.T) { instAction.cfg.KubeClient = failer vals := map[string]interface{}{} - res, err := instAction.Run(buildChart(), vals) + res, err := instAction.RunWithContext(context.Background(), buildChart(), vals) is.Error(err) is.Contains(res.Info.Description, "failed post-install") is.Equal(release.StatusFailed, res.Info.Status) @@ -332,7 +337,8 @@ func TestInstallRelease_ReplaceRelease(t *testing.T) { instAction.ReleaseName = rel.Name vals := map[string]interface{}{} - res, err := instAction.Run(buildChart(), vals) + + res, err := instAction.RunWithContext(context.Background(), buildChart(), vals) is.NoError(err) // This should have been auto-incremented @@ -348,13 +354,15 @@ func TestInstallRelease_KubeVersion(t *testing.T) { is := assert.New(t) instAction := installAction(t) vals := map[string]interface{}{} - _, err := instAction.Run(buildChart(withKube(">=0.0.0")), vals) + + _, err := instAction.RunWithContext(context.Background(), buildChart(withKube(">=0.0.0")), vals) is.NoError(err) // This should fail for a few hundred years instAction.ReleaseName = "should-fail" vals = map[string]interface{}{} - _, err = instAction.Run(buildChart(withKube(">=99.0.0")), vals) + + _, err = instAction.RunWithContext(context.Background(), buildChart(withKube(">=99.0.0")), vals) is.Error(err) is.Contains(err.Error(), "chart requires kubeVersion") } @@ -369,7 +377,7 @@ func TestInstallRelease_Wait(t *testing.T) { instAction.Wait = true vals := map[string]interface{}{} - res, err := instAction.Run(buildChart(), vals) + res, err := instAction.RunWithContext(context.Background(), buildChart(), vals) is.Error(err) is.Contains(res.Info.Description, "I timed out") is.Equal(res.Info.Status, release.StatusFailed) @@ -379,15 +387,13 @@ func TestInstallRelease_Wait_Interrupted(t *testing.T) { instAction := installAction(t) instAction.ReleaseName = "interrupted-release" failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient) - failer.WaitDuration = 10 * time.Second instAction.cfg.KubeClient = failer instAction.Wait = true vals := map[string]interface{}{} ctx := context.Background() ctx, cancel := context.WithCancel(ctx) - time.AfterFunc(time.Second, cancel) - //cancel() + cancel() res, err := instAction.RunWithContext(ctx, buildChart(), vals) is.Error(err) @@ -405,7 +411,7 @@ func TestInstallRelease_WaitForJobs(t *testing.T) { instAction.WaitForJobs = true vals := map[string]interface{}{} - res, err := instAction.Run(buildChart(), vals) + res, err := instAction.RunWithContext(context.Background(), buildChart(), vals) is.Error(err) is.Contains(res.Info.Description, "I timed out") is.Equal(res.Info.Status, release.StatusFailed) @@ -421,9 +427,10 @@ func TestInstallRelease_Atomic(t *testing.T) { failer.WaitError = fmt.Errorf("I timed out") instAction.cfg.KubeClient = failer instAction.Atomic = true + vals := map[string]interface{}{} - res, err := instAction.Run(buildChart(), vals) + res, err := instAction.RunWithContext(context.Background(), buildChart(), vals) is.Error(err) is.Contains(err.Error(), "I timed out") is.Contains(err.Error(), "atomic") @@ -444,7 +451,7 @@ func TestInstallRelease_Atomic(t *testing.T) { instAction.Atomic = true vals := map[string]interface{}{} - _, err := instAction.Run(buildChart(), vals) + _, err := instAction.RunWithContext(context.Background(), buildChart(), vals) is.Error(err) is.Contains(err.Error(), "I timed out") is.Contains(err.Error(), "uninstall fail") @@ -457,14 +464,13 @@ func TestInstallRelease_Atomic_Interrupted(t *testing.T) { instAction := installAction(t) instAction.ReleaseName = "interrupted-release" failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient) - failer.WaitDuration = 10 * time.Second instAction.cfg.KubeClient = failer instAction.Atomic = true vals := map[string]interface{}{} ctx := context.Background() ctx, cancel := context.WithCancel(ctx) - time.AfterFunc(time.Second, cancel) + cancel() res, err := instAction.RunWithContext(ctx, buildChart(), vals) is.Error(err) @@ -556,7 +562,7 @@ func TestInstallReleaseOutputDir(t *testing.T) { instAction.OutputDir = dir - _, err := instAction.Run(buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals) + _, err := instAction.RunWithContext(context.Background(), buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals) if err != nil { t.Fatalf("Failed install: %s", err) } @@ -592,7 +598,7 @@ func TestInstallOutputDirWithReleaseName(t *testing.T) { newDir := filepath.Join(dir, instAction.ReleaseName) - _, err := instAction.Run(buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals) + _, err := instAction.RunWithContext(context.Background(), buildChart(withSampleTemplates(), withMultipleManifestTemplate()), vals) if err != nil { t.Fatalf("Failed install: %s", err) } diff --git a/pkg/action/uninstall_test.go b/pkg/action/uninstall_test.go index 311a34923..741abc7da 100644 --- a/pkg/action/uninstall_test.go +++ b/pkg/action/uninstall_test.go @@ -17,6 +17,7 @@ limitations under the License. package action import ( + "context" "fmt" "testing" @@ -57,7 +58,10 @@ func TestUninstallRelease_deleteRelease(t *testing.T) { } }` unAction.cfg.Releases.Create(rel) - res, err := unAction.Run(rel.Name) + + ctx := context.Background() + + res, err := unAction.RunWithContext(ctx, rel.Name) is.NoError(err) expected := `These resources were kept due to the resource policy: [Secret] secret @@ -90,7 +94,10 @@ func TestUninstallRelease_Wait(t *testing.T) { failer := unAction.cfg.KubeClient.(*kubefake.FailingKubeClient) failer.WaitError = fmt.Errorf("U timed out") unAction.cfg.KubeClient = failer - res, err := unAction.Run(rel.Name) + + ctx := context.Background() + + res, err := unAction.RunWithContext(ctx, rel.Name) is.Error(err) is.Contains(err.Error(), "U timed out") is.Equal(res.Release.Info.Status, release.StatusUninstalled) @@ -123,7 +130,10 @@ func TestUninstallRelease_Cascade(t *testing.T) { failer.DeleteWithPropagationError = fmt.Errorf("Uninstall with cascade failed") failer.BuildDummy = true unAction.cfg.KubeClient = failer - _, err := unAction.Run(rel.Name) + + ctx := context.Background() + + _, err := unAction.RunWithContext(ctx, rel.Name) is.Error(err) is.Contains(err.Error(), "failed to delete release: come-fail-away") } diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 975c5f7e7..cdad2e121 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -364,17 +364,18 @@ func (u *Upgrade) releasingUpgrade(ctx context.Context, upgradedRelease *release } } - if u.Wait { + kubeClient, ok := u.cfg.KubeClient.(kube.ContextInterface) + if u.Wait && ok { u.cfg.Log( "waiting for release %s resources (created: %d updated: %d deleted: %d)", upgradedRelease.Name, len(results.Created), len(results.Updated), len(results.Deleted)) if u.WaitForJobs { - if err := u.cfg.KubeClient.WaitWithJobs(target, u.Timeout); err != nil { + if err := kubeClient.WaitWithJobsContext(ctx, target); err != nil { u.cfg.recordRelease(originalRelease) return u.failRelease(upgradedRelease, results.Created, err) } } else { - if err := u.cfg.KubeClient.Wait(target, u.Timeout); err != nil { + if err := kubeClient.WaitWithContext(ctx, target); err != nil { u.cfg.recordRelease(originalRelease) return u.failRelease(upgradedRelease, results.Created, err) } diff --git a/pkg/action/upgrade_test.go b/pkg/action/upgrade_test.go index 62922b373..22cb1042a 100644 --- a/pkg/action/upgrade_test.go +++ b/pkg/action/upgrade_test.go @@ -54,6 +54,7 @@ func TestUpgradeRelease_Success(t *testing.T) { vals := map[string]interface{}{} ctx, done := context.WithCancel(context.Background()) + res, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) done() req.NoError(err) @@ -83,7 +84,9 @@ func TestUpgradeRelease_Wait(t *testing.T) { upAction.Wait = true vals := map[string]interface{}{} - res, err := upAction.Run(rel.Name, buildChart(), vals) + ctx := context.Background() + + res, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) req.Error(err) is.Contains(res.Info.Description, "I timed out") is.Equal(res.Info.Status, release.StatusFailed) @@ -106,7 +109,9 @@ func TestUpgradeRelease_WaitForJobs(t *testing.T) { upAction.WaitForJobs = true vals := map[string]interface{}{} - res, err := upAction.Run(rel.Name, buildChart(), vals) + ctx := context.Background() + + res, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) req.Error(err) is.Contains(res.Info.Description, "I timed out") is.Equal(res.Info.Status, release.StatusFailed) @@ -130,7 +135,9 @@ func TestUpgradeRelease_CleanupOnFail(t *testing.T) { upAction.CleanupOnFail = true vals := map[string]interface{}{} - res, err := upAction.Run(rel.Name, buildChart(), vals) + ctx := context.Background() + + res, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) req.Error(err) is.NotContains(err.Error(), "unable to cleanup resources") is.Contains(res.Info.Description, "I timed out") @@ -156,7 +163,9 @@ func TestUpgradeRelease_Atomic(t *testing.T) { upAction.Atomic = true vals := map[string]interface{}{} - res, err := upAction.Run(rel.Name, buildChart(), vals) + ctx := context.Background() + + res, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) req.Error(err) is.Contains(err.Error(), "arming key removed") is.Contains(err.Error(), "atomic") @@ -181,7 +190,9 @@ func TestUpgradeRelease_Atomic(t *testing.T) { upAction.Atomic = true vals := map[string]interface{}{} - _, err := upAction.Run(rel.Name, buildChart(), vals) + ctx := context.Background() + + _, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) req.Error(err) is.Contains(err.Error(), "update fail") is.Contains(err.Error(), "an error occurred while rolling back the release") @@ -220,8 +231,11 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { is.NoError(err) upAction.ReuseValues = true + + ctx := context.Background() + // setting newValues and upgrading - res, err := upAction.Run(rel.Name, buildChart(), newValues) + res, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), newValues) is.NoError(err) // Now make sure it is actually upgraded @@ -282,8 +296,11 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { withDependency(withName("subchart")), withMetadataDependency(dependency), ) + + ctx := context.Background() + // reusing values and upgrading - res, err := upAction.Run(rel.Name, sampleChartWithSubChart, map[string]interface{}{}) + res, err := upAction.RunWithContext(ctx, rel.Name, sampleChartWithSubChart, map[string]interface{}{}) is.NoError(err) // Now get the upgraded release @@ -322,7 +339,9 @@ func TestUpgradeRelease_Pending(t *testing.T) { vals := map[string]interface{}{} - _, err := upAction.Run(rel.Name, buildChart(), vals) + ctx := context.Background() + + _, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) req.Contains(err.Error(), "progress", err) } @@ -338,14 +357,13 @@ func TestUpgradeRelease_Interrupted_Wait(t *testing.T) { upAction.cfg.Releases.Create(rel) failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient) - failer.WaitDuration = 10 * time.Second upAction.cfg.KubeClient = failer upAction.Wait = true vals := map[string]interface{}{} ctx := context.Background() ctx, cancel := context.WithCancel(ctx) - time.AfterFunc(time.Second, cancel) + cancel() res, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) @@ -367,14 +385,13 @@ func TestUpgradeRelease_Interrupted_Atomic(t *testing.T) { upAction.cfg.Releases.Create(rel) failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient) - failer.WaitDuration = 5 * time.Second upAction.cfg.KubeClient = failer upAction.Atomic = true vals := map[string]interface{}{} ctx := context.Background() ctx, cancel := context.WithCancel(ctx) - time.AfterFunc(time.Second, cancel) + cancel() res, err := upAction.RunWithContext(ctx, rel.Name, buildChart(), vals) diff --git a/pkg/kube/fake/fake.go b/pkg/kube/fake/fake.go index 820518ed9..a2a5186e3 100644 --- a/pkg/kube/fake/fake.go +++ b/pkg/kube/fake/fake.go @@ -77,11 +77,15 @@ func (f *FailingKubeClient) Wait(resources kube.ResourceList, d time.Duration) e // Waits the amount of time defined on f.WaitDuration, then returns the configured error if set or prints. func (f *FailingKubeClient) WaitWithContext(ctx context.Context, resources kube.ResourceList) error { - time.Sleep(f.WaitDuration) if f.WaitError != nil { return f.WaitError } - return f.PrintingKubeClient.Wait(resources, 0) + + if err := ctx.Err(); err != nil { + return err + } + + return f.PrintingKubeClient.WaitWithContext(ctx, resources) } // WaitWithJobs returns the configured error if set or prints @@ -97,6 +101,11 @@ func (f *FailingKubeClient) WaitWithJobsContext(ctx context.Context, resources k if f.WaitError != nil { return f.WaitError } + + if err := ctx.Err(); err != nil { + return err + } + return f.PrintingKubeClient.WaitWithJobsContext(ctx, resources) } @@ -113,7 +122,12 @@ func (f *FailingKubeClient) WaitForDeleteWithContext(ctx context.Context, resour if f.WaitError != nil { return f.WaitError } - return f.PrintingKubeClient.WaitForDelete(resources, 0) + + if err := ctx.Err(); err != nil { + return err + } + + return f.PrintingKubeClient.WaitForDeleteWithContext(ctx, resources) } // Delete returns the configured error if set or prints @@ -172,7 +186,8 @@ func (f *FailingKubeClient) WaitAndGetCompletedPodPhaseWithContext(ctx context.C if f.WaitAndGetCompletedPodPhaseError != nil { return v1.PodSucceeded, f.WaitAndGetCompletedPodPhaseError } - return f.PrintingKubeClient.WaitAndGetCompletedPodPhase(s, 0) + + return f.PrintingKubeClient.WaitAndGetCompletedPodPhaseWithContext(ctx, s) } // DeleteWithPropagationPolicy returns the configured error if set or prints @@ -188,6 +203,10 @@ func (f *FailingKubeClient) WatchUntilReadyWithContext(ctx context.Context, reso return f.WatchUntilReadyError } + if err := ctx.Err(); err != nil { + return err + } + return f.PrintingKubeClient.WatchUntilReady(resources, 0) } diff --git a/pkg/kube/interface.go b/pkg/kube/interface.go index 35ce5a271..1c844dd1f 100644 --- a/pkg/kube/interface.go +++ b/pkg/kube/interface.go @@ -79,10 +79,22 @@ type Interface interface { type ContextInterface interface { // WaitWithContext waits till a ctx timeout for the specified resources to be ready. WaitWithContext(ctx context.Context, resources ResourceList) error - // WaitWithJobsContext wait up to the given ctx timeout for the specified resources to be ready, including jobs. + // WaitWithJobsContext waits till a ctx timeout for the specified resources to be ready, including jobs. WaitWithJobsContext(ctx context.Context, resources ResourceList) error + // WatchUntilReadyWithContext watches the resources given and waits until it is ready. + // + // This method is mainly for hook implementations. It watches for a resource to + // hit a particular milestone. The milestone depends on the Kind. + // + // For Jobs, "ready" means the Job ran to completion (exited without error). + // For Pods, "ready" means the Pod phase is marked "succeeded". + // For all other kinds, it means the kind was created or modified without + // error. WatchUntilReadyWithContext(context.Context, ResourceList) error + // WaitAndGetCompletedPodPhaseWithContext waits up to a timeout until a pod enters a completed phase + // and returns said phase (PodSucceeded or PodFailed qualify). WaitAndGetCompletedPodPhaseWithContext(context.Context, string) (v1.PodPhase, error) + // WaitForDeleteWithContext waits till a ctx timeout for the specified resources to be deleted. WaitForDeleteWithContext(context.Context, ResourceList) error }