Merge pull request #6011 from thomastaylor312/feat/atomic

feat(*) Adds atomic flag to v3
pull/6059/head
Taylor Thomas 5 years ago committed by GitHub
commit 2c397b6879
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

469
Gopkg.lock generated

File diff suppressed because it is too large Load Diff

@ -113,11 +113,11 @@ $(GOIMPORTS):
# install vendored dependencies
vendor: Gopkg.lock
$(DEP) ensure -v --vendor-only
$(DEP) ensure --vendor-only
# update vendored dependencies
Gopkg.lock: Gopkg.toml
$(DEP) ensure -v --no-vendor
$(DEP) ensure --no-vendor
Gopkg.toml: $(DEP)

@ -31,7 +31,7 @@ import (
"helm.sh/helm/pkg/action"
"helm.sh/helm/pkg/chartutil"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/kube"
kubefake "helm.sh/helm/pkg/kube/fake"
"helm.sh/helm/pkg/release"
"helm.sh/helm/pkg/repo"
"helm.sh/helm/pkg/storage"
@ -116,7 +116,7 @@ func executeActionCommandC(store *storage.Storage, cmd string) (*cobra.Command,
actionConfig := &action.Configuration{
Releases: store,
KubeClient: &kube.PrintingKubeClient{Out: ioutil.Discard},
KubeClient: &kubefake.PrintingKubeClient{Out: ioutil.Discard},
Capabilities: chartutil.DefaultCapabilities,
Log: func(format string, v ...interface{}) {},
}

@ -128,6 +128,7 @@ func addInstallFlags(f *pflag.FlagSet, client *action.Install) {
f.StringVar(&client.NameTemplate, "name-template", "", "specify template used to name the release")
f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
f.BoolVar(&client.DependencyUpdate, "dependency-update", false, "run helm dependency update before installing the chart")
f.BoolVar(&client.Atomic, "atomic", false, "if set, installation process purges chart on fail. The --wait flag will be set automatically if --atomic is used")
addValueOptionsFlags(f, &client.ValueOptions)
addChartPathOptionsFlags(f, &client.ChartPathOptions)
}

@ -28,7 +28,7 @@ import (
"helm.sh/helm/cmd/helm/require"
"helm.sh/helm/pkg/action"
"helm.sh/helm/pkg/chartutil"
"helm.sh/helm/pkg/kube"
kubefake "helm.sh/helm/pkg/kube/fake"
"helm.sh/helm/pkg/storage"
"helm.sh/helm/pkg/storage/driver"
)
@ -46,7 +46,7 @@ func newTemplateCmd(out io.Writer) *cobra.Command {
customConfig := &action.Configuration{
// Add mock objects in here so it doesn't use Kube API server
Releases: storage.Init(driver.NewMemory()),
KubeClient: &kube.PrintingKubeClient{Out: ioutil.Discard},
KubeClient: &kubefake.PrintingKubeClient{Out: ioutil.Discard},
Capabilities: chartutil.DefaultCapabilities,
Log: func(format string, v ...interface{}) {
fmt.Fprintf(out, format, v...)

@ -96,6 +96,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
instClient.Wait = client.Wait
instClient.Devel = client.Devel
instClient.Namespace = client.Namespace
instClient.Atomic = client.Atomic
_, err := runInstall(args, instClient, out)
return err
@ -147,6 +148,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.BoolVar(&client.ResetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart")
f.BoolVar(&client.ReuseValues, "reuse-values", false, "when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored.")
f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout")
f.BoolVar(&client.Atomic, "atomic", false, "if set, upgrade process rolls back changes made in case of failed upgrade. The --wait flag will be set automatically if --atomic is used")
f.IntVar(&client.MaxHistory, "history-max", 0, "limit the maximum number of revisions saved per release. Use 0 for no limit.")
addChartPathOptionsFlags(f, &client.ChartPathOptions)
addValueOptionsFlags(f, &client.ValueOptions)

@ -17,17 +17,15 @@ package action
import (
"flag"
"io"
"io/ioutil"
"testing"
"time"
"github.com/pkg/errors"
fakeclientset "k8s.io/client-go/kubernetes/fake"
"helm.sh/helm/pkg/chart"
"helm.sh/helm/pkg/chartutil"
"helm.sh/helm/pkg/kube"
kubefake "helm.sh/helm/pkg/kube/fake"
"helm.sh/helm/pkg/release"
"helm.sh/helm/pkg/storage"
"helm.sh/helm/pkg/storage/driver"
@ -40,7 +38,7 @@ func actionConfigFixture(t *testing.T) *Configuration {
return &Configuration{
Releases: storage.Init(driver.NewMemory()),
KubeClient: &kube.PrintingKubeClient{Out: ioutil.Discard},
KubeClient: &kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: ioutil.Discard}},
Capabilities: chartutil.DefaultCapabilities,
Log: func(format string, v ...interface{}) {
t.Helper()
@ -55,7 +53,7 @@ var manifestWithHook = `kind: ConfigMap
metadata:
name: test-cm
annotations:
"helm.sh/hook": post-install,pre-delete
"helm.sh/hook": post-install,pre-delete,post-upgrade
data:
name: value`
@ -210,20 +208,6 @@ func namedReleaseStub(name string, status release.Status) *release.Release {
}
}
func newHookFailingKubeClient() *hookFailingKubeClient {
return &hookFailingKubeClient{
PrintingKubeClient: kube.PrintingKubeClient{Out: ioutil.Discard},
}
}
type hookFailingKubeClient struct {
kube.PrintingKubeClient
}
func (h *hookFailingKubeClient) WatchUntilReady(r io.Reader, timeout time.Duration) error {
return errors.New("Failed watch")
}
func TestGetVersionSet(t *testing.T) {
client := fakeclientset.NewSimpleClientset()

@ -82,6 +82,7 @@ type Install struct {
GenerateName bool
NameTemplate string
OutputDir string
Atomic bool
}
type ValueOptions struct {
@ -118,6 +119,10 @@ func (i *Install) Run(chrt *chart.Chart) (*release.Release, error) {
return nil, err
}
// Make sure if Atomic is set, that wait is set as well. This makes it so
// the user doesn't have to specify both
i.Wait = i.Wait || i.Atomic
caps, err := i.cfg.getCapabilities()
if err != nil {
return nil, err
@ -178,9 +183,7 @@ func (i *Install) Run(chrt *chart.Chart) (*release.Release, error) {
// pre-install hooks
if !i.DisableHooks {
if err := i.execHook(rel.Hooks, hooks.PreInstall); err != nil {
rel.SetStatus(release.StatusFailed, "failed pre-install: "+err.Error())
_ = i.replaceRelease(rel)
return rel, err
return i.failRelease(rel, fmt.Errorf("failed pre-install: %s", err))
}
}
@ -189,26 +192,20 @@ func (i *Install) Run(chrt *chart.Chart) (*release.Release, error) {
// to true, since that is basically an upgrade operation.
buf := bytes.NewBufferString(rel.Manifest)
if err := i.cfg.KubeClient.Create(buf); err != nil {
rel.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", i.ReleaseName, err.Error()))
i.recordRelease(rel) // Ignore the error, since we have another error to deal with.
return rel, errors.Wrapf(err, "release %s failed", i.ReleaseName)
return i.failRelease(rel, err)
}
if i.Wait {
buf := bytes.NewBufferString(rel.Manifest)
if err := i.cfg.KubeClient.Wait(buf, i.Timeout); err != nil {
rel.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", i.ReleaseName, err.Error()))
i.recordRelease(rel) // Ignore the error, since we have another error to deal with.
return rel, errors.Wrapf(err, "release %s failed", i.ReleaseName)
return i.failRelease(rel, err)
}
}
if !i.DisableHooks {
if err := i.execHook(rel.Hooks, hooks.PostInstall); err != nil {
rel.SetStatus(release.StatusFailed, "failed post-install: "+err.Error())
_ = i.replaceRelease(rel)
return rel, err
return i.failRelease(rel, fmt.Errorf("failed post-install: %s", err))
}
}
@ -226,6 +223,23 @@ func (i *Install) Run(chrt *chart.Chart) (*release.Release, error) {
return rel, nil
}
func (i *Install) failRelease(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
uninstall.Timeout = i.Timeout
if _, uninstallErr := uninstall.Run(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)
}
i.recordRelease(rel) // Ignore the error, since we have another error to deal with.
return rel, err
}
// availableName tests whether a name is available
//
// Roughly, this will return an error if name is

@ -30,6 +30,8 @@ import (
"helm.sh/helm/internal/test"
"helm.sh/helm/pkg/release"
"helm.sh/helm/pkg/storage/driver"
kubefake "helm.sh/helm/pkg/kube/fake"
)
type nameTemplateTestCase struct {
@ -189,7 +191,9 @@ func TestInstallRelease_FailedHooks(t *testing.T) {
is := assert.New(t)
instAction := installAction(t)
instAction.ReleaseName = "failed-hooks"
instAction.cfg.KubeClient = newHookFailingKubeClient()
failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.WatchUntilReadyError = fmt.Errorf("Failed watch")
instAction.cfg.KubeClient = failer
instAction.rawValues = map[string]interface{}{}
res, err := instAction.Run(buildChart())
@ -236,6 +240,63 @@ func TestInstallRelease_KubeVersion(t *testing.T) {
is.Contains(err.Error(), "chart requires kubernetesVersion")
}
func TestInstallRelease_Wait(t *testing.T) {
is := assert.New(t)
instAction := installAction(t)
instAction.ReleaseName = "come-fail-away"
failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
instAction.cfg.KubeClient = failer
instAction.Wait = true
instAction.rawValues = map[string]interface{}{}
res, err := instAction.Run(buildChart())
is.Error(err)
is.Contains(res.Info.Description, "I timed out")
is.Equal(res.Info.Status, release.StatusFailed)
}
func TestInstallRelease_Atomic(t *testing.T) {
is := assert.New(t)
t.Run("atomic uninstall succeeds", func(t *testing.T) {
instAction := installAction(t)
instAction.ReleaseName = "come-fail-away"
failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
instAction.cfg.KubeClient = failer
instAction.Atomic = true
instAction.rawValues = map[string]interface{}{}
res, err := instAction.Run(buildChart())
is.Error(err)
is.Contains(err.Error(), "I timed out")
is.Contains(err.Error(), "atomic")
// Now make sure it isn't in storage any more
_, err = instAction.cfg.Releases.Get(res.Name, res.Version)
is.Error(err)
is.Equal(err, driver.ErrReleaseNotFound)
})
t.Run("atomic uninstall fails", func(t *testing.T) {
instAction := installAction(t)
instAction.ReleaseName = "come-fail-away-with-me"
failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
failer.DeleteError = fmt.Errorf("uninstall fail")
instAction.cfg.KubeClient = failer
instAction.Atomic = true
instAction.rawValues = map[string]interface{}{}
_, err := instAction.Run(buildChart())
is.Error(err)
is.Contains(err.Error(), "I timed out")
is.Contains(err.Error(), "uninstall fail")
is.Contains(err.Error(), "an error occurred while uninstalling the release")
})
}
func TestNameTemplate(t *testing.T) {
testCases := []nameTemplateTestCase{
// Just a straight up nop please

@ -1,3 +1,19 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package action
import (

@ -122,7 +122,16 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
if !u.KeepHistory {
u.cfg.Log("purge requested for %s", name)
err := u.purgeReleases(rels...)
return res, errors.Wrap(err, "uninstall: Failed to purge the release")
if err != nil {
errs = append(errs, errors.Wrap(err, "uninstall: Failed to purge the release"))
}
// Return the errors that occurred while deleting the release, if any
if len(errs) > 0 {
return res, errors.Errorf("uninstallation completed with %d error(s): %s", len(errs), joinErrors(errs))
}
return res, nil
}
if err := u.cfg.Releases.Update(rel); err != nil {

@ -29,6 +29,7 @@ import (
"helm.sh/helm/pkg/hooks"
"helm.sh/helm/pkg/kube"
"helm.sh/helm/pkg/release"
"helm.sh/helm/pkg/releaseutil"
)
// Upgrade is the action for upgrading releases.
@ -54,6 +55,7 @@ type Upgrade struct {
Recreate bool
// MaxHistory limits the maximum number of revisions saved per release
MaxHistory int
Atomic bool
}
// NewUpgrade creates a new Upgrade object with the given configuration.
@ -69,6 +71,10 @@ func (u *Upgrade) Run(name string, chart *chart.Chart) (*release.Release, error)
return nil, err
}
// Make sure if Atomic is set, that wait is set as well. This makes it so
// the user doesn't have to specify both
u.Wait = u.Wait || u.Atomic
if err := validateReleaseName(name); err != nil {
return nil, errors.Errorf("upgradeRelease: Release name is invalid: %s", name)
}
@ -196,35 +202,28 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
// pre-upgrade hooks
if !u.DisableHooks {
if err := u.execHook(upgradedRelease.Hooks, hooks.PreUpgrade); err != nil {
return upgradedRelease, err
return u.failRelease(upgradedRelease, fmt.Errorf("pre-upgrade hooks failed: %s", err))
}
} else {
u.cfg.Log("upgrade hooks disabled for %s", upgradedRelease.Name)
}
if err := u.upgradeRelease(originalRelease, upgradedRelease); err != nil {
msg := fmt.Sprintf("Upgrade %q failed: %s", upgradedRelease.Name, err)
u.cfg.Log("warning: %s", msg)
upgradedRelease.Info.Status = release.StatusFailed
upgradedRelease.Info.Description = msg
u.cfg.recordRelease(originalRelease)
u.cfg.recordRelease(upgradedRelease)
return upgradedRelease, err
return u.failRelease(upgradedRelease, err)
}
if u.Wait {
buf := bytes.NewBufferString(upgradedRelease.Manifest)
if err := u.cfg.KubeClient.Wait(buf, u.Timeout); err != nil {
upgradedRelease.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", upgradedRelease.Name, err.Error()))
u.cfg.recordRelease(originalRelease)
u.cfg.recordRelease(upgradedRelease)
return upgradedRelease, errors.Wrapf(err, "release %s failed", upgradedRelease.Name)
return u.failRelease(upgradedRelease, err)
}
}
// post-upgrade hooks
if !u.DisableHooks {
if err := u.execHook(upgradedRelease.Hooks, hooks.PostUpgrade); err != nil {
return upgradedRelease, err
return u.failRelease(upgradedRelease, fmt.Errorf("post-upgrade hooks failed: %s", err))
}
}
@ -237,6 +236,52 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
return upgradedRelease, nil
}
func (u *Upgrade) failRelease(rel *release.Release, err error) (*release.Release, error) {
msg := fmt.Sprintf("Upgrade %q failed: %s", rel.Name, err)
u.cfg.Log("warning: %s", msg)
rel.Info.Status = release.StatusFailed
rel.Info.Description = msg
u.cfg.recordRelease(rel)
if u.Atomic {
u.cfg.Log("Upgrade failed and atomic is set, rolling back to last successful release")
// As a protection, get the last successful release before rollback.
// If there are no successful releases, bail out
hist := NewHistory(u.cfg)
fullHistory, herr := hist.Run(rel.Name)
if herr != nil {
return rel, errors.Wrapf(herr, "an error occurred while finding last successful release. original upgrade error: %s", err)
}
// There isn't a way to tell if a previous release was successful, but
// generally failed releases do not get superseded unless the next
// release is successful, so this should be relatively safe
filteredHistory := releaseutil.FilterFunc(func(r *release.Release) bool {
return r.Info.Status == release.StatusSuperseded || r.Info.Status == release.StatusDeployed
}).Filter(fullHistory)
if len(filteredHistory) == 0 {
return rel, errors.Wrap(err, "unable to find a previously successful release when attempting to rollback. original upgrade error")
}
releaseutil.Reverse(filteredHistory, releaseutil.SortByRevision)
rollin := NewRollback(u.cfg)
rollin.Version = filteredHistory[0].Version
rollin.Wait = true
rollin.DisableHooks = u.DisableHooks
rollin.Recreate = u.Recreate
rollin.Force = u.Force
rollin.Timeout = u.Timeout
if _, rollErr := rollin.Run(rel.Name); rollErr != nil {
return rel, errors.Wrapf(rollErr, "an error occurred while rolling back the release. original upgrade error: %s", err)
}
return rel, errors.Wrapf(err, "release %s failed, and has been rolled back due to atomic being set", rel.Name)
}
return rel, err
}
// upgradeRelease performs an upgrade from current to target release
func (u *Upgrade) upgradeRelease(current, target *release.Release) error {
cm := bytes.NewBufferString(current.Manifest)
@ -303,7 +348,6 @@ func (u *Upgrade) execHook(hs []*release.Hook, hook string) error {
}
sort.Sort(hookByWeight(executingHooks))
for _, h := range executingHooks {
if err := deleteHookByPolicy(u.cfg, h, hooks.BeforeHookCreation); err != nil {
return err

@ -0,0 +1,109 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package action
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
kubefake "helm.sh/helm/pkg/kube/fake"
"helm.sh/helm/pkg/release"
)
func upgradeAction(t *testing.T) *Upgrade {
config := actionConfigFixture(t)
upAction := NewUpgrade(config)
upAction.Namespace = "spaced"
return upAction
}
func TestUpgradeRelease_Wait(t *testing.T) {
is := assert.New(t)
req := require.New(t)
upAction := upgradeAction(t)
rel := releaseStub()
rel.Name = "come-fail-away"
rel.Info.Status = release.StatusDeployed
upAction.cfg.Releases.Create(rel)
failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
upAction.cfg.KubeClient = failer
upAction.Wait = true
upAction.rawValues = map[string]interface{}{}
res, err := upAction.Run(rel.Name, buildChart())
req.Error(err)
is.Contains(res.Info.Description, "I timed out")
is.Equal(res.Info.Status, release.StatusFailed)
}
func TestUpgradeRelease_Atomic(t *testing.T) {
is := assert.New(t)
req := require.New(t)
t.Run("atomic rollback succeeds", func(t *testing.T) {
upAction := upgradeAction(t)
rel := releaseStub()
rel.Name = "nuketown"
rel.Info.Status = release.StatusDeployed
upAction.cfg.Releases.Create(rel)
failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
// We can't make Update error because then the rollback won't work
failer.WatchUntilReadyError = fmt.Errorf("arming key removed")
upAction.cfg.KubeClient = failer
upAction.Atomic = true
upAction.rawValues = map[string]interface{}{}
res, err := upAction.Run(rel.Name, buildChart())
req.Error(err)
is.Contains(err.Error(), "arming key removed")
is.Contains(err.Error(), "atomic")
// Now make sure it is actually upgraded
updatedRes, err := upAction.cfg.Releases.Get(res.Name, 3)
is.NoError(err)
// Should have rolled back to the previous
is.Equal(updatedRes.Info.Status, release.StatusDeployed)
})
t.Run("atomic uninstall fails", func(t *testing.T) {
upAction := upgradeAction(t)
rel := releaseStub()
rel.Name = "fallout"
rel.Info.Status = release.StatusDeployed
upAction.cfg.Releases.Create(rel)
failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer.UpdateError = fmt.Errorf("update fail")
upAction.cfg.KubeClient = failer
upAction.Atomic = true
upAction.rawValues = map[string]interface{}{}
_, err := upAction.Run(rel.Name, buildChart())
req.Error(err)
is.Contains(err.Error(), "update fail")
is.Contains(err.Error(), "an error occurred while rolling back the release")
})
}

@ -0,0 +1,116 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package fake implements various fake KubeClients for use in testing
package fake
import (
"io"
"time"
v1 "k8s.io/api/core/v1"
"k8s.io/cli-runtime/pkg/resource"
"helm.sh/helm/pkg/kube"
)
// FailingKubeClient implements KubeClient for testing purposes. It also has
// additional errors you can set to fail different functions, otherwise it
// delegates all its calls to `PrintingKubeClient`
type FailingKubeClient struct {
PrintingKubeClient
CreateError error
WaitError error
GetError error
DeleteError error
WatchUntilReadyError error
UpdateError error
BuildError error
BuildUnstructuredError error
WaitAndGetCompletedPodPhaseError error
}
// Create returns the configured error if set or prints
func (f *FailingKubeClient) Create(r io.Reader) error {
if f.CreateError != nil {
return f.CreateError
}
return f.PrintingKubeClient.Create(r)
}
// Wait returns the configured error if set or prints
func (f *FailingKubeClient) Wait(r io.Reader, d time.Duration) error {
if f.WaitError != nil {
return f.WaitError
}
return f.PrintingKubeClient.Wait(r, d)
}
// Create returns the configured error if set or prints
func (f *FailingKubeClient) Get(r io.Reader) (string, error) {
if f.GetError != nil {
return "", f.GetError
}
return f.PrintingKubeClient.Get(r)
}
// Delete returns the configured error if set or prints
func (f *FailingKubeClient) Delete(r io.Reader) error {
if f.DeleteError != nil {
return f.DeleteError
}
return f.PrintingKubeClient.Delete(r)
}
// WatchUntilReady returns the configured error if set or prints
func (f *FailingKubeClient) WatchUntilReady(r io.Reader, d time.Duration) error {
if f.WatchUntilReadyError != nil {
return f.WatchUntilReadyError
}
return f.PrintingKubeClient.WatchUntilReady(r, d)
}
// Update returns the configured error if set or prints
func (f *FailingKubeClient) Update(r, modifiedReader io.Reader, not, needed bool) error {
if f.UpdateError != nil {
return f.UpdateError
}
return f.PrintingKubeClient.Update(r, modifiedReader, not, needed)
}
// Build returns the configured error if set or prints
func (f *FailingKubeClient) Build(r io.Reader) (kube.Result, error) {
if f.BuildError != nil {
return []*resource.Info{}, f.BuildError
}
return f.PrintingKubeClient.Build(r)
}
// BuildUnstructured returns the configured error if set or prints
func (f *FailingKubeClient) BuildUnstructured(r io.Reader) (kube.Result, error) {
if f.BuildUnstructuredError != nil {
return []*resource.Info{}, f.BuildUnstructuredError
}
return f.PrintingKubeClient.Build(r)
}
// WaitAndGetCompletedPodPhase returns the configured error if set or prints
func (f *FailingKubeClient) WaitAndGetCompletedPodPhase(s string, d time.Duration) (v1.PodPhase, error) {
if f.WaitAndGetCompletedPodPhaseError != nil {
return v1.PodSucceeded, f.WaitAndGetCompletedPodPhaseError
}
return f.PrintingKubeClient.WaitAndGetCompletedPodPhase(s, d)
}

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package kube
package fake
import (
"io"
@ -22,6 +22,8 @@ import (
v1 "k8s.io/api/core/v1"
"k8s.io/cli-runtime/pkg/resource"
"helm.sh/helm/pkg/kube"
)
// PrintingKubeClient implements KubeClient, but simply prints the reader to
@ -68,11 +70,11 @@ func (p *PrintingKubeClient) Update(_, modifiedReader io.Reader, _, _ bool) erro
}
// Build implements KubeClient Build.
func (p *PrintingKubeClient) Build(_ io.Reader) (Result, error) {
func (p *PrintingKubeClient) Build(_ io.Reader) (kube.Result, error) {
return []*resource.Info{}, nil
}
func (p *PrintingKubeClient) BuildUnstructured(_ io.Reader) (Result, error) {
func (p *PrintingKubeClient) BuildUnstructured(_ io.Reader) (kube.Result, error) {
return p.Build(nil)
}
Loading…
Cancel
Save