Add support for Release Namespace definition to be created during Helm chart install.

Signed-off-by: Illya Chekrygin <illya.chekrygin@gmail.com>
pull/6795/head
Illya Chekrygin 6 years ago
parent 0dce5c1418
commit 9e44577768
No known key found for this signature in database
GPG Key ID: EB1222EF859CB6A9

@ -29,6 +29,7 @@ require (
github.com/stretchr/testify v1.4.0
github.com/xeipuuv/gojsonschema v1.1.0
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc // indirect
k8s.io/api v0.17.2
k8s.io/apiextensions-apiserver v0.17.2
k8s.io/apimachinery v0.17.2

@ -38,6 +38,7 @@ import (
"helm.sh/helm/v3/pkg/downloader"
"helm.sh/helm/v3/pkg/engine"
"helm.sh/helm/v3/pkg/getter"
"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/releaseutil"
@ -259,6 +260,11 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
return rel, nil
}
// Check if chart contains definition for namespace resource which matches release namespace
if resources, err = checkReleaseNamespace(i.cfg.KubeClient, resources, i.Namespace); err != nil {
return i.failRelease(rel, err)
}
// If Replace is true, we need to supercede the last release.
if i.Replace {
if err := i.replaceRelease(rel); err != nil {
@ -322,6 +328,25 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
return rel, nil
}
// checkReleaseNamepace checks if the release namespace is included as template resource.
// if it is:
// 1. attempt to create a namespace returning any/all errors
// 2. upon successful creation - remove release namespace template resource from the provided list
// if it is not: noop
func checkReleaseNamespace(kubeClient kube.Interface, resources kube.ResourceList, namespace string) (kube.ResourceList, error) {
for i, r := range resources {
ok := r.Object.GetObjectKind()
if gvk := ok.GroupVersionKind(); gvk.Kind == "Namespace" && r.Name == namespace {
// If matching namespace resource found create namespace and remove this resource from the resource list
if _, err := kubeClient.Create(kube.ResourceList{r}); err != nil {
return resources, err
}
return append(resources[:i], resources[i+1:]...), nil
}
}
return resources, 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 {

@ -26,10 +26,18 @@ import (
"strings"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/resource"
"helm.sh/helm/v3/internal/test"
"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"
@ -614,3 +622,127 @@ func TestNameAndChartGenerateName(t *testing.T) {
})
}
}
func Test_checkReleaseNamespace(t *testing.T) {
type args struct {
kubeClient kube.Interface
resources kube.ResourceList
namespace string
}
type want struct {
err error
resources kube.ResourceList
}
testResource := func(o runtime.Object, name string) *resource.Info {
gvk := o.GetObjectKind().GroupVersionKind()
return &resource.Info{
Name: name,
Mapping: &meta.RESTMapping{
Resource: schema.GroupVersionResource{Group: gvk.Group, Version: gvk.Version, Resource: gvk.Kind},
},
Object: o,
}
}
tests := map[string]struct {
args args
want want
}{
"NilResourceList": {
args: args{
kubeClient: nil,
resources: nil,
namespace: "test",
},
want: want{
resources: nil,
},
},
"EmptyResourceList": {
args: args{
kubeClient: nil,
resources: kube.ResourceList{},
namespace: "test",
},
want: want{
resources: kube.ResourceList{},
},
},
"ReleaseNamespaceIsNotDefined": {
args: args{
kubeClient: nil,
resources: kube.ResourceList{testResource(&corev1.Pod{}, "test")},
namespace: "test",
},
want: want{
resources: kube.ResourceList{testResource(&corev1.Pod{}, "test")},
},
},
"ReleaseNamespaceIsDefinedButNotTheRelease": {
args: args{
kubeClient: nil,
resources: kube.ResourceList{
testResource(&corev1.Pod{}, "test"),
testResource(&corev1.Namespace{TypeMeta: metav1.TypeMeta{Kind: "Namespace"}}, "foo"),
},
namespace: "test",
},
want: want{
resources: kube.ResourceList{
testResource(&corev1.Pod{}, "test"),
testResource(&corev1.Namespace{TypeMeta: metav1.TypeMeta{Kind: "Namespace"}}, "foo"),
},
},
},
"ReleaseNamespaceIsDefinedButFailedToCreate": {
args: args{
kubeClient: &kubefake.FailingKubeClient{CreateError: errors.New("create-error")},
resources: kube.ResourceList{
testResource(&corev1.Pod{}, "test"),
testResource(&corev1.Namespace{TypeMeta: metav1.TypeMeta{Kind: "Namespace"}}, "foo"),
testResource(&corev1.Namespace{TypeMeta: metav1.TypeMeta{Kind: "Namespace"}}, "test"),
},
namespace: "test",
},
want: want{
err: errors.New("create-error"),
resources: kube.ResourceList{
testResource(&corev1.Pod{}, "test"),
testResource(&corev1.Namespace{TypeMeta: metav1.TypeMeta{Kind: "Namespace"}}, "foo"),
testResource(&corev1.Namespace{TypeMeta: metav1.TypeMeta{Kind: "Namespace"}}, "test"),
},
},
},
"ReleaseNamespaceIsDefinedSuccessfulCreate": {
args: args{
kubeClient: &kubefake.PrintingKubeClient{Out: ioutil.Discard},
resources: kube.ResourceList{
testResource(&corev1.Pod{}, "test"),
testResource(&corev1.Namespace{TypeMeta: metav1.TypeMeta{Kind: "Namespace"}}, "foo"),
testResource(&corev1.Namespace{TypeMeta: metav1.TypeMeta{Kind: "Namespace"}}, "test"),
},
namespace: "test",
},
want: want{
resources: kube.ResourceList{
testResource(&corev1.Pod{}, "test"),
testResource(&corev1.Namespace{TypeMeta: metav1.TypeMeta{Kind: "Namespace"}}, "foo"),
},
},
},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
is := assert.New(t)
res, err := checkReleaseNamespace(tt.args.kubeClient, tt.args.resources, tt.args.namespace)
if tt.want.err == nil {
is.Nil(err)
} else {
is.EqualError(err, tt.want.err.Error())
}
is.Equal(tt.want.resources, res)
})
}
}

Loading…
Cancel
Save