chore: complete implementation

Signed-off-by: Paul Brousseau <object88@gmail.com>
pull/8785/head
Paul Brousseau 5 years ago
parent 9ac7d9e2fd
commit bff2215e1b

@ -35,6 +35,7 @@ import (
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli"
"helm.sh/helm/v3/pkg/gates"
"helm.sh/helm/v3/pkg/kube"
kubefake "helm.sh/helm/v3/pkg/kube/fake"
"helm.sh/helm/v3/pkg/release"
"helm.sh/helm/v3/pkg/storage/driver"
@ -130,7 +131,9 @@ func loadReleasesInMemory(actionConfig *action.Configuration) {
return
}
actionConfig.KubeClient = &kubefake.PrintingKubeClient{Out: ioutil.Discard}
actionConfig.GetKubeClient = func(namespace string) kube.Interface {
return &kubefake.PrintingKubeClient{Out: ioutil.Discard}
}
for _, path := range filePaths {
b, err := ioutil.ReadFile(path)

@ -112,11 +112,11 @@ func executeActionCommandStdinC(store *storage.Storage, in *os.File, cmd string)
fake := &kubefake.PrintingKubeClient{Out: ioutil.Discard}
actionConfig := &action.Configuration{
Do: func(namespace string) kube.Interface {
GetKubeClient: func(namespace string) kube.Interface {
return fake
},
Releases: store,
KubeClient: fake,
KubeClient: nil,
Capabilities: chartutil.DefaultCapabilities,
Log: func(format string, v ...interface{}) {},
}

@ -77,19 +77,21 @@ var (
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
var ValidName = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`)
type DoMake func(namespace string) kube.Interface
// GetKubeClientFunc returns a Kube client with the specified namespace
type GetKubeClientFunc func(namespace string) kube.Interface
// Configuration injects the dependencies that all actions share.
type Configuration struct {
// RESTClientGetter is an interface that loads Kubernetes clients.
RESTClientGetter genericclioptions.RESTClientGetter
Do DoMake
// GetKubeClient returns an instance of a Kubernetes API client.
GetKubeClient GetKubeClientFunc
// Releases stores records of releases.
Releases *storage.Storage
// KubeClient is a Kubernetes API client.
// Deprecated: KubeClient should not be used; use GetKubeClient instead
KubeClient kube.Interface
// RegistryClient is a client for working with registries
@ -416,13 +418,13 @@ func (c *Configuration) Init(getter genericclioptions.RESTClientGetter, namespac
}
c.RESTClientGetter = getter
c.Do = func(namespace string) kube.Interface {
c.GetKubeClient = func(namespace string) kube.Interface {
client := kube.New(c.RESTClientGetter)
client.Log = c.Log
client.Namespace = namespace
return client
}
c.KubeClient = kc
c.KubeClient = nil
c.Releases = store
c.Log = log

@ -30,6 +30,7 @@ import (
"helm.sh/helm/v3/internal/experimental/registry"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/kube"
kubefake "helm.sh/helm/v3/pkg/kube/fake"
"helm.sh/helm/v3/pkg/release"
"helm.sh/helm/v3/pkg/storage"
@ -80,9 +81,12 @@ func actionConfigFixture(t *testing.T) *Configuration {
t.Fatal(err)
}
fake := &kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: ioutil.Discard}}
return &Configuration{
Releases: storage.Init(driver.NewMemory()),
KubeClient: &kubefake.FailingKubeClient{PrintingKubeClient: kubefake.PrintingKubeClient{Out: ioutil.Discard}},
Releases: storage.Init(driver.NewMemory()),
GetKubeClient: func(namespace string) kube.Interface {
return fake
},
Capabilities: chartutil.DefaultCapabilities,
RegistryClient: registryClient,
Log: func(format string, v ...interface{}) {

@ -39,7 +39,7 @@ func NewGet(cfg *Configuration) *Get {
// Run executes 'helm get' against the given release.
func (g *Get) Run(name string) (*release.Release, error) {
if err := g.cfg.KubeClient.IsReachable(); err != nil {
if err := g.cfg.GetKubeClient("").IsReachable(); err != nil {
return nil, err
}

@ -39,7 +39,7 @@ func NewGetValues(cfg *Configuration) *GetValues {
// Run executes 'helm get values' against the given release.
func (g *GetValues) Run(name string) (map[string]interface{}, error) {
if err := g.cfg.KubeClient.IsReachable(); err != nil {
if err := g.cfg.GetKubeClient("").IsReachable(); err != nil {
return nil, err
}

@ -42,7 +42,7 @@ func NewHistory(cfg *Configuration) *History {
// Run executes 'helm history' against the given release.
func (h *History) Run(name string) ([]*release.Release, error) {
if err := h.cfg.KubeClient.IsReachable(); err != nil {
if err := h.cfg.GetKubeClient("").IsReachable(); err != nil {
return nil, err
}

@ -55,7 +55,8 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent,
return err
}
resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest), true)
client := cfg.GetKubeClient(rl.Namespace)
resources, err := client.Build(bytes.NewBufferString(h.Manifest), true)
if err != nil {
return errors.Wrapf(err, "unable to build kubernetes object for %s hook %s", hook, h.Path)
}
@ -73,14 +74,14 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent,
h.LastRun.Phase = release.HookPhaseUnknown
// Create hook resources
if _, err := cfg.KubeClient.Create(resources); err != nil {
if _, err := client.Create(resources); err != nil {
h.LastRun.CompletedAt = helmtime.Now()
h.LastRun.Phase = release.HookPhaseFailed
return errors.Wrapf(err, "warning: Hook %s %s failed", hook, h.Path)
}
// Watch hook resources until they have completed
err = cfg.KubeClient.WatchUntilReady(resources, timeout)
err = client.WatchUntilReady(resources, timeout)
// Note the time of success/failure
h.LastRun.CompletedAt = helmtime.Now()
// Mark hook as succeeded or failed
@ -127,11 +128,12 @@ func (cfg *Configuration) deleteHookByPolicy(h *release.Hook, policy release.Hoo
return nil
}
if hookHasDeletePolicy(h, policy) {
resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest), false)
client := cfg.GetKubeClient("")
resources, err := client.Build(bytes.NewBufferString(h.Manifest), false)
if err != nil {
return errors.Wrapf(err, "unable to build kubernetes object for deleting hook %s", h.Path)
}
_, errs := cfg.KubeClient.Delete(resources)
_, errs := client.Delete(resources)
if len(errs) > 0 {
return errors.New(joinErrors(errs))
}

@ -171,7 +171,7 @@ func (i *Install) installCRDs(crds []chart.CRD) error {
//
// 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) {
i.client = i.cfg.Do(i.Namespace)
i.client = i.cfg.GetKubeClient(i.Namespace)
// Check reachability of cluster unless in client-only mode (e.g. `helm template` without `--validate`)
if !i.ClientOnly {

@ -31,7 +31,6 @@ import (
"helm.sh/helm/v3/internal/test"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/kube"
kubefake "helm.sh/helm/v3/pkg/kube/fake"
"helm.sh/helm/v3/pkg/release"
"helm.sh/helm/v3/pkg/storage/driver"
@ -47,9 +46,6 @@ type nameTemplateTestCase struct {
func installAction(t *testing.T) *Install {
config := actionConfigFixture(t)
instAction := NewInstall(config)
instAction.cfg.Do = func(namespace string) kube.Interface {
return config.KubeClient
}
instAction.Namespace = "spaced"
instAction.ReleaseName = "test-install-release"
@ -301,9 +297,9 @@ func TestInstallRelease_FailedHooks(t *testing.T) {
is := assert.New(t)
instAction := installAction(t)
instAction.ReleaseName = "failed-hooks"
failer := instAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer := instAction.cfg.GetKubeClient("").(*kubefake.FailingKubeClient)
failer.WatchUntilReadyError = fmt.Errorf("Failed watch")
instAction.cfg.KubeClient = failer
// instAction.cfg.KubeClient = failer
vals := map[string]interface{}{}
res, err := instAction.Run(buildChart(), vals)
@ -354,9 +350,9 @@ 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 := instAction.cfg.GetKubeClient("").(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
instAction.cfg.KubeClient = failer
// instAction.cfg.KubeClient = failer
instAction.Wait = true
vals := map[string]interface{}{}
@ -372,9 +368,9 @@ func TestInstallRelease_Atomic(t *testing.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 := instAction.cfg.GetKubeClient("").(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
instAction.cfg.KubeClient = failer
// instAction.cfg.KubeClient = failer
instAction.Atomic = true
vals := map[string]interface{}{}
@ -392,10 +388,10 @@ func TestInstallRelease_Atomic(t *testing.T) {
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 := instAction.cfg.GetKubeClient("").(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
failer.DeleteError = fmt.Errorf("uninstall fail")
instAction.cfg.KubeClient = failer
// instAction.cfg.KubeClient = failer
instAction.Atomic = true
vals := map[string]interface{}{}

@ -141,7 +141,7 @@ func NewList(cfg *Configuration) *List {
// Run executes the list command, returning a set of matches.
func (l *List) Run() ([]*release.Release, error) {
if err := l.cfg.KubeClient.IsReachable(); err != nil {
if err := l.cfg.GetKubeClient("").IsReachable(); err != nil {
return nil, err
}

@ -48,7 +48,7 @@ func NewReleaseTesting(cfg *Configuration) *ReleaseTesting {
// Run executes 'helm test' against the given release.
func (r *ReleaseTesting) Run(name string) (*release.Release, error) {
if err := r.cfg.KubeClient.IsReachable(); err != nil {
if err := r.cfg.GetKubeClient("").IsReachable(); err != nil {
return nil, err
}

@ -55,7 +55,7 @@ func NewRollback(cfg *Configuration) *Rollback {
// Run executes 'helm rollback' against the given release.
func (r *Rollback) Run(name string) error {
if err := r.cfg.KubeClient.IsReachable(); err != nil {
if err := r.cfg.GetKubeClient("").IsReachable(); err != nil {
return err
}
@ -145,11 +145,13 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas
return targetRelease, nil
}
current, err := r.cfg.KubeClient.Build(bytes.NewBufferString(currentRelease.Manifest), false)
client := r.cfg.GetKubeClient(currentRelease.Namespace)
current, err := client.Build(bytes.NewBufferString(currentRelease.Manifest), false)
if err != nil {
return targetRelease, errors.Wrap(err, "unable to build kubernetes objects from current release manifest")
}
target, err := r.cfg.KubeClient.Build(bytes.NewBufferString(targetRelease.Manifest), false)
target, err := client.Build(bytes.NewBufferString(targetRelease.Manifest), false)
if err != nil {
return targetRelease, errors.Wrap(err, "unable to build kubernetes objects from new release manifest")
}
@ -163,7 +165,7 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas
r.cfg.Log("rollback hooks disabled for %s", targetRelease.Name)
}
results, err := r.cfg.KubeClient.Update(current, target, r.Force)
results, err := client.Update(current, target, r.Force)
if err != nil {
msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err)
@ -175,7 +177,7 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas
r.cfg.recordRelease(targetRelease)
if r.CleanupOnFail {
r.cfg.Log("Cleanup on fail set, cleaning up %d resources", len(results.Created))
_, errs := r.cfg.KubeClient.Delete(results.Created)
_, errs := client.Delete(results.Created)
if errs != nil {
var errorList []string
for _, e := range errs {
@ -199,7 +201,7 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas
}
if r.Wait {
if err := r.cfg.KubeClient.Wait(target, r.Timeout); err != nil {
if err := client.Wait(target, r.Timeout); err != nil {
targetRelease.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", targetRelease.Name, err.Error()))
r.cfg.recordRelease(currentRelease)
r.cfg.recordRelease(targetRelease)

@ -43,7 +43,7 @@ func NewStatus(cfg *Configuration) *Status {
// Run executes 'helm status' against the given release.
func (s *Status) Run(name string) (*release.Release, error) {
if err := s.cfg.KubeClient.IsReachable(); err != nil {
if err := s.cfg.GetKubeClient("").IsReachable(); err != nil {
return nil, err
}

@ -50,7 +50,7 @@ func NewUninstall(cfg *Configuration) *Uninstall {
// Run uninstalls the given release.
func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error) {
if err := u.cfg.KubeClient.IsReachable(); err != nil {
if err := u.cfg.GetKubeClient("").IsReachable(); err != nil {
return nil, err
}
@ -197,12 +197,14 @@ func (u *Uninstall) deleteRelease(rel *release.Release) (string, []error) {
builder.WriteString("\n---\n" + file.Content)
}
resources, err := u.cfg.KubeClient.Build(strings.NewReader(builder.String()), false)
client := u.cfg.GetKubeClient(rel.Namespace)
resources, err := client.Build(strings.NewReader(builder.String()), false)
if err != nil {
return "", []error{errors.Wrap(err, "unable to build kubernetes objects for delete")}
}
if len(resources) > 0 {
_, errs = u.cfg.KubeClient.Delete(resources)
_, errs = client.Delete(resources)
}
return kept, errs
}

@ -40,7 +40,8 @@ import (
//
// It provides the implementation of 'helm upgrade'.
type Upgrade struct {
cfg *Configuration
cfg *Configuration
client kube.Interface
ChartPathOptions
@ -107,7 +108,9 @@ func NewUpgrade(cfg *Configuration) *Upgrade {
// Run executes the upgrade on the given release.
func (u *Upgrade) Run(name string, chart *chart.Chart, vals map[string]interface{}) (*release.Release, error) {
if err := u.cfg.KubeClient.IsReachable(); err != nil {
u.client = u.cfg.GetKubeClient(u.Namespace)
if err := u.client.IsReachable(); err != nil {
return nil, err
}
@ -235,12 +238,12 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin
if len(notesTxt) > 0 {
upgradedRelease.Info.Notes = notesTxt
}
err = validateManifest(u.cfg.KubeClient, manifestDoc.Bytes(), !u.DisableOpenAPIValidation)
err = validateManifest(u.client, manifestDoc.Bytes(), !u.DisableOpenAPIValidation)
return currentRelease, upgradedRelease, err
}
func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Release) (*release.Release, error) {
current, err := u.cfg.KubeClient.Build(bytes.NewBufferString(originalRelease.Manifest), false)
current, err := u.client.Build(bytes.NewBufferString(originalRelease.Manifest), false)
if err != nil {
// Checking for removed Kubernetes API error so can provide a more informative error message to the user
// Ref: https://github.com/helm/helm/issues/7219
@ -251,7 +254,7 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
}
return upgradedRelease, errors.Wrap(err, "unable to build kubernetes objects from current release manifest")
}
target, err := u.cfg.KubeClient.Build(bytes.NewBufferString(upgradedRelease.Manifest), !u.DisableOpenAPIValidation)
target, err := u.client.Build(bytes.NewBufferString(upgradedRelease.Manifest), !u.DisableOpenAPIValidation)
if err != nil {
return upgradedRelease, errors.Wrap(err, "unable to build kubernetes objects from new release manifest")
}
@ -312,7 +315,7 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
u.cfg.Log("upgrade hooks disabled for %s", upgradedRelease.Name)
}
results, err := u.cfg.KubeClient.Update(current, target, u.Force)
results, err := u.client.Update(current, target, u.Force)
if err != nil {
u.cfg.recordRelease(originalRelease)
return u.failRelease(upgradedRelease, results.Created, err)
@ -329,7 +332,7 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
}
if u.Wait {
if err := u.cfg.KubeClient.Wait(target, u.Timeout); err != nil {
if err := u.client.Wait(target, u.Timeout); err != nil {
u.cfg.recordRelease(originalRelease)
return u.failRelease(upgradedRelease, results.Created, err)
}
@ -364,7 +367,7 @@ func (u *Upgrade) failRelease(rel *release.Release, created kube.ResourceList, e
u.cfg.recordRelease(rel)
if u.CleanupOnFail && len(created) > 0 {
u.cfg.Log("Cleanup on fail set, cleaning up %d resources", len(created))
_, errs := u.cfg.KubeClient.Delete(created)
_, errs := u.client.Delete(created)
if errs != nil {
var errorList []string
for _, e := range errs {

@ -48,9 +48,9 @@ func TestUpgradeRelease_Wait(t *testing.T) {
rel.Info.Status = release.StatusDeployed
upAction.cfg.Releases.Create(rel)
failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer := upAction.cfg.GetKubeClient("").(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
upAction.cfg.KubeClient = failer
// upAction.cfg.KubeClient = failer
upAction.Wait = true
vals := map[string]interface{}{}
@ -70,10 +70,10 @@ func TestUpgradeRelease_CleanupOnFail(t *testing.T) {
rel.Info.Status = release.StatusDeployed
upAction.cfg.Releases.Create(rel)
failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer := upAction.cfg.GetKubeClient("").(*kubefake.FailingKubeClient)
failer.WaitError = fmt.Errorf("I timed out")
failer.DeleteError = fmt.Errorf("I tried to delete nil")
upAction.cfg.KubeClient = failer
// upAction.cfg.KubeClient = failer
upAction.Wait = true
upAction.CleanupOnFail = true
vals := map[string]interface{}{}
@ -97,10 +97,10 @@ func TestUpgradeRelease_Atomic(t *testing.T) {
rel.Info.Status = release.StatusDeployed
upAction.cfg.Releases.Create(rel)
failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer := upAction.cfg.GetKubeClient("").(*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.cfg.KubeClient = failer
upAction.Atomic = true
vals := map[string]interface{}{}
@ -123,9 +123,9 @@ func TestUpgradeRelease_Atomic(t *testing.T) {
rel.Info.Status = release.StatusDeployed
upAction.cfg.Releases.Create(rel)
failer := upAction.cfg.KubeClient.(*kubefake.FailingKubeClient)
failer := upAction.cfg.GetKubeClient("").(*kubefake.FailingKubeClient)
failer.UpdateError = fmt.Errorf("update fail")
upAction.cfg.KubeClient = failer
// upAction.cfg.KubeClient = failer
upAction.Atomic = true
vals := map[string]interface{}{}

Loading…
Cancel
Save