refactor to create second kube interface

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

@ -32,6 +32,7 @@ import (
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/cli"
"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"
@ -108,9 +109,14 @@ func executeActionCommandStdinC(store *storage.Storage, in *os.File, cmd string)
buf := new(bytes.Buffer)
fake := &kubefake.PrintingKubeClient{Out: ioutil.Discard}
actionConfig := &action.Configuration{
Do: func(namespace string) kube.Interface {
return fake
},
Releases: store,
KubeClient: &kubefake.PrintingKubeClient{Out: ioutil.Discard},
KubeClient: fake,
Capabilities: chartutil.DefaultCapabilities,
Log: func(format string, v ...interface{}) {},
}

@ -77,10 +77,14 @@ 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
// Configuration injects the dependencies that all actions share.
type Configuration struct {
// RESTClientGetter is an interface that loads Kubernetes clients.
RESTClientGetter RESTClientGetter
RESTClientGetter genericclioptions.RESTClientGetter
Do DoMake
// Releases stores records of releases.
Releases *storage.Storage
@ -365,7 +369,6 @@ func (c *Configuration) recordRelease(r *release.Release) {
func (c *Configuration) Init(getter genericclioptions.RESTClientGetter, namespace, helmDriver string, log DebugLog) error {
kc := kube.New(getter)
kc.Log = log
kc.Namespace = namespace
lazyClient := &lazyClient{
namespace: namespace,
@ -413,6 +416,12 @@ func (c *Configuration) Init(getter genericclioptions.RESTClientGetter, namespac
}
c.RESTClientGetter = getter
c.Do = func(namespace string) kube.Interface {
client := kube.New(c.RESTClientGetter)
client.Log = c.Log
client.Namespace = namespace
return client
}
c.KubeClient = kc
c.Releases = store
c.Log = log

@ -67,7 +67,8 @@ const defaultDirectoryPermission = 0755
// Install performs an installation operation.
type Install struct {
cfg *Configuration
cfg *Configuration
client kube.Interface
ChartPathOptions
@ -128,13 +129,13 @@ func (i *Install) installCRDs(crds []chart.CRD) error {
totalItems := []*resource.Info{}
for _, obj := range crds {
// Read in the resources
res, err := i.cfg.KubeClient.Build(bytes.NewBuffer(obj.File.Data), false)
res, err := i.client.Build(bytes.NewBuffer(obj.File.Data), false)
if err != nil {
return errors.Wrapf(err, "failed to install CRD %s", obj.Name)
}
// Send them to Kube
if _, err := i.cfg.KubeClient.Create(res); err != nil {
if _, err := i.client.Create(res); err != nil {
// If the error is CRD already exists, continue.
if apierrors.IsAlreadyExists(err) {
crdName := res[0].Name
@ -156,7 +157,7 @@ func (i *Install) installCRDs(crds []chart.CRD) error {
discoveryClient.Invalidate()
// Give time for the CRD to be recognized.
if err := i.cfg.KubeClient.Wait(totalItems, 60*time.Second); err != nil {
if err := i.client.Wait(totalItems, 60*time.Second); err != nil {
return err
}
@ -170,9 +171,11 @@ 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)
// Check reachability of cluster unless in client-only mode (e.g. `helm template` without `--validate`)
if !i.ClientOnly {
if err := i.cfg.KubeClient.IsReachable(); err != nil {
if err := i.client.IsReachable(); err != nil {
return nil, err
}
}
@ -197,7 +200,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
// NOTE(bacongobbler): used for `helm template`
i.cfg.Capabilities = chartutil.DefaultCapabilities
i.cfg.Capabilities.APIVersions = append(i.cfg.Capabilities.APIVersions, i.APIVersions...)
i.cfg.KubeClient = &kubefake.PrintingKubeClient{Out: ioutil.Discard}
i.client = &kubefake.PrintingKubeClient{Out: ioutil.Discard}
mem := driver.NewMemory()
mem.SetNamespace(i.Namespace)
@ -252,7 +255,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
rel.SetStatus(release.StatusPendingInstall, "Initial install underway")
var toBeAdopted kube.ResourceList
resources, err := i.cfg.KubeClient.Build(bytes.NewBufferString(rel.Manifest), !i.DisableOpenAPIValidation)
resources, err := i.client.Build(bytes.NewBufferString(rel.Manifest), !i.DisableOpenAPIValidation)
if err != nil {
return nil, errors.Wrap(err, "unable to build kubernetes objects from release manifest")
}
@ -299,11 +302,11 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
if err != nil {
return nil, err
}
resourceList, err := i.cfg.KubeClient.Build(bytes.NewBuffer(buf), true)
resourceList, err := i.client.Build(bytes.NewBuffer(buf), true)
if err != nil {
return nil, err
}
if _, err := i.cfg.KubeClient.Create(resourceList); err != nil && !apierrors.IsAlreadyExists(err) {
if _, err := i.client.Create(resourceList); err != nil && !apierrors.IsAlreadyExists(err) {
return nil, err
}
}
@ -335,17 +338,17 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
// do an update, but it's not clear whether we WANT to do an update if the re-use is set
// 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 {
if _, err := i.client.Create(resources); err != nil {
return i.failRelease(rel, err)
}
} else if len(resources) > 0 {
if _, err := i.cfg.KubeClient.Update(toBeAdopted, resources, false); err != nil {
if _, err := i.client.Update(toBeAdopted, resources, false); err != nil {
return i.failRelease(rel, err)
}
}
if i.Wait {
if err := i.cfg.KubeClient.Wait(resources, i.Timeout); err != nil {
if err := i.client.Wait(resources, i.Timeout); err != nil {
return i.failRelease(rel, err)
}

@ -31,6 +31,7 @@ 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"
@ -46,6 +47,9 @@ 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"
@ -119,7 +123,7 @@ func TestInstallReleaseClientOnly(t *testing.T) {
instAction.Run(buildChart(), nil) // disregard output
is.Equal(instAction.cfg.Capabilities, chartutil.DefaultCapabilities)
is.Equal(instAction.cfg.KubeClient, &kubefake.PrintingKubeClient{Out: ioutil.Discard})
is.Equal(instAction.client, &kubefake.PrintingKubeClient{Out: ioutil.Discard})
}
func TestInstallRelease_NoName(t *testing.T) {

@ -21,11 +21,9 @@ import (
"io"
"io/ioutil"
"net/http"
"os"
"strings"
"testing"
"helm.sh/helm/v3/pkg/cli"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -255,84 +253,6 @@ func TestBuild(t *testing.T) {
}
}
func TestNamespace(t *testing.T) {
reset := func() func() {
var originalHelmNamespace *string
origEnv := os.Environ()
for _, pair := range origEnv {
kv := strings.SplitN(pair, "=", 2)
if kv[0] == "HELM_NAMESPACE" {
o := kv[1]
originalHelmNamespace = &o
break
}
}
return func() {
os.Unsetenv("HELM_NAMESPACE")
if originalHelmNamespace != nil {
os.Setenv("HELM_NAMESPACE", *originalHelmNamespace)
}
}
}
refstring := func(s string) *string {
return &s
}
tcs := []struct {
name string
envNamespace string
namespace *string
expectedNamespace string
}{
{
name: "unset-namespace",
envNamespace: v1.NamespaceDefault,
namespace: nil,
expectedNamespace: v1.NamespaceDefault,
}, {
name: "test-namespace",
envNamespace: v1.NamespaceDefault,
namespace: refstring("test"),
expectedNamespace: "test",
}, {
name: "non-default-env-namespace",
envNamespace: "test",
namespace: nil,
expectedNamespace: "test",
}, {
name: "non-default-env-and-test-namespace",
envNamespace: "stage",
namespace: refstring("test"),
expectedNamespace: "test",
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
defer reset()()
os.Setenv("HELM_NAMESPACE", tc.envNamespace)
c := New(cli.New().RESTClientGetter())
if tc.namespace != nil {
c.Namespace = *tc.namespace
}
reslist, err := c.Build(strings.NewReader(testServiceManifest), true)
if err != nil {
t.Errorf("unexpected error from Build: %v", err)
}
if len(reslist) != 1 {
t.Errorf("expected 1 resource; got %d", len(reslist))
}
res := reslist[0]
t.Logf("%#v\n", res)
if res.Namespace != tc.expectedNamespace {
t.Errorf("Incorrect namespace: expected '%s', got '%s'", tc.expectedNamespace, res.Namespace)
}
})
}
}
func TestPerform(t *testing.T) {
tests := []struct {
name string

Loading…
Cancel
Save