From 2ef358b0ec1f2e146cd8d9036420cae75c8e9f92 Mon Sep 17 00:00:00 2001 From: tstromberg Date: Wed, 26 Feb 2020 14:58:50 -0800 Subject: [PATCH 1/5] Add helm3 support --- pkg/skaffold/deploy/helm.go | 61 ++++++++---- pkg/skaffold/deploy/helm_test.go | 158 ++++++++++++++++++------------- 2 files changed, 132 insertions(+), 87 deletions(-) diff --git a/pkg/skaffold/deploy/helm.go b/pkg/skaffold/deploy/helm.go index 0c0e503fd63..dcc2464f9aa 100644 --- a/pkg/skaffold/deploy/helm.go +++ b/pkg/skaffold/deploy/helm.go @@ -26,6 +26,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "sort" "strconv" "strings" @@ -47,6 +48,11 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/warnings" ) +var ( + // versionRe extracts version from "helm version --client", for instance: "2.14.0-rc.2" + versionRe = regexp.MustCompile(`\"v(\d[\w\.\-\.]+)`) +) + // HelmDeployer deploys workflows using the helm CLI type HelmDeployer struct { *latest.HelmDeploy @@ -84,9 +90,7 @@ func (h *HelmDeployer) Deploy(ctx context.Context, out io.Writer, builds []build hv, err := h.binVer(ctx) if err != nil { - logrus.Debugf("failed to parse binary version: %v", err) - } else { - logrus.Debugf("deploying with helm version %v", hv) + return NewDeployErrorResult(errors.Wrapf(err, "failed to determine binary version")) } var dRes []Artifact @@ -95,7 +99,7 @@ func (h *HelmDeployer) Deploy(ctx context.Context, out io.Writer, builds []build // Deploy every release for _, r := range h.Releases { - results, err := h.deployRelease(ctx, out, r, builds, valuesSet) + results, err := h.deployRelease(ctx, out, r, builds, valuesSet, hv) if err != nil { releaseName, _ := expand(r.Name, nil) @@ -179,13 +183,22 @@ func (h *HelmDeployer) Dependencies() ([]string, error) { // Cleanup deletes what was deployed by calling Deploy. func (h *HelmDeployer) Cleanup(ctx context.Context, out io.Writer) error { + hv, err := h.binVer(ctx) + if err != nil { + return errors.Wrap(err, "binary version") + } + for _, r := range h.Releases { releaseName, err := expand(r.Name, nil) if err != nil { return errors.Wrap(err, "cannot parse the release name template") } - if err := h.exec(ctx, out, false, "delete", releaseName, "--purge"); err != nil { + args := []string{"delete", releaseName} + if hv.LT(semver.MustParse("3.0.0")) { + args = append(args, "--purge") + } + if err := h.exec(ctx, out, false, args...); err != nil { return errors.Wrapf(err, "deleting %s", releaseName) } } @@ -220,7 +233,7 @@ func (h *HelmDeployer) exec(ctx context.Context, out io.Writer, useSecrets bool, } // deployRelease deploys a single release -func (h *HelmDeployer) deployRelease(ctx context.Context, out io.Writer, r latest.HelmRelease, builds []build.Artifact, valuesSet map[string]bool) ([]Artifact, error) { +func (h *HelmDeployer) deployRelease(ctx context.Context, out io.Writer, r latest.HelmRelease, builds []build.Artifact, valuesSet map[string]bool, helmVersion semver.Version) ([]Artifact, error) { releaseName, err := expand(r.Name, nil) if err != nil { return nil, errors.Wrap(err, "cannot parse the release name template") @@ -232,9 +245,10 @@ func (h *HelmDeployer) deployRelease(ctx context.Context, out io.Writer, r lates flags: h.Flags.Upgrade, force: h.forceDeploy, chartPath: r.ChartPath, + helmVersion: helmVersion, } - if err := h.exec(ctx, ioutil.Discard, false, getArgs(releaseName)...); err != nil { + if err := h.exec(ctx, ioutil.Discard, false, getArgs(helmVersion, releaseName)...); err != nil { color.Yellow.Fprintf(out, "Helm release %s not installed. Installing...\n", releaseName) opts.upgrade = false @@ -291,7 +305,7 @@ func (h *HelmDeployer) deployRelease(ctx context.Context, out io.Writer, r lates var b bytes.Buffer // Be accepting of failure - if err := h.exec(ctx, &b, false, getArgs(releaseName)...); err != nil { + if err := h.exec(ctx, &b, false, getArgs(helmVersion, releaseName)...); err != nil { logrus.Warnf(err.Error()) return nil, nil } @@ -308,24 +322,20 @@ func (h *HelmDeployer) binVer(ctx context.Context) (semver.Version, error) { } var b bytes.Buffer - if err := h.exec(ctx, &b, false, "version", "--short", "-c"); err != nil { + if err := h.exec(ctx, &b, false, "version", "--client"); err != nil { return semver.Version{}, errors.Wrap(err, "helm version") } bs := b.Bytes() - // raw for 3.1: "v3.1.0+gb29d20b" - // raw for 2.15: "Client: v2.15.1+gcf1de4f" raw := string(bs) - idx := strings.Index(raw, "v") - if idx < 0 { - return semver.Version{}, fmt.Errorf("v not found in output: %q", raw) + matches := versionRe.FindStringSubmatch(raw) + if len(matches) == 0 { + return semver.Version{}, fmt.Errorf("unable to parse output: %q", raw) } - // Only read up to a + sign if provided: semver does not understand + notation. - rv := strings.Split(raw[idx+1:], "+")[0] - v, err := semver.Make(rv) + v, err := semver.Make(matches[1]) if err != nil { - return semver.Version{}, errors.Wrap(err, "semver make") + return semver.Version{}, errors.Wrapf(err, "semver make: %q", matches[1]) } h.bV = v @@ -340,6 +350,7 @@ type installOpts struct { chartPath string upgrade bool force bool + helmVersion semver.Version } // installArgs calculates the correct arguments to "helm install" @@ -357,7 +368,11 @@ func installArgs(r latest.HelmRelease, builds []build.Artifact, valuesSet map[st args = append(args, "--recreate-pods") } } else { - args = append(args, "install", "--name", o.releaseName) + args = append(args, "install") + if o.helmVersion.LT(semver.MustParse("3.0.0")) { + args = append(args, "--name") + } + args = append(args, o.releaseName) args = append(args, o.flags...) } @@ -466,8 +481,12 @@ func installArgs(r latest.HelmRelease, builds []build.Artifact, valuesSet map[st } // getArgs calculates the correct arguments to "helm get" -func getArgs(releaseName string) []string { - return []string{"get", releaseName} +func getArgs(v semver.Version, releaseName string) []string { + args := []string{"get"} + if v.GTE(semver.MustParse("3.0.0")) { + args = append(args, "all") + } + return append(args, releaseName) } // envVarForImage creates an environment map for an image and digest tag (fqn) diff --git a/pkg/skaffold/deploy/helm_test.go b/pkg/skaffold/deploy/helm_test.go index 138eab31a79..fa12bae5c48 100644 --- a/pkg/skaffold/deploy/helm_test.go +++ b/pkg/skaffold/deploy/helm_test.go @@ -21,11 +21,8 @@ import ( "fmt" "io/ioutil" "os" - "path/filepath" "testing" - "github.com/blang/semver" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/config" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/event" @@ -323,6 +320,15 @@ HOOKS: MANIFEST: ` +var ( + // Output strings to emulate different versions of Helm + version20 = `Client: &version.Version{SemVer:"v2.15.1", GitCommit:"cf1de4f8ba70eded310918a8af3a96bfe8e7683b", GitTreeState:"clean"}` + version21 = `Client: &version.Version{SemVer:"v2.15.1", GitCommit:"cf1de4f8ba70eded310918a8af3a96bfe8e7683b", GitTreeState:"clean"}` + version21rc = `Client: &version.Version{SemVer:"v2.14.0-rc.2", GitCommit:"05811b84a3f93603dd6c2fcfe57944dfa7ab7fd0", GitTreeState:"clean"}` + version30 = `version.BuildInfo{Version:"v3.0.0", GitCommit:"e29ce2a54e96cd02ccfce88bee4f58bb6e2a28b6", GitTreeState:"clean", GoVersion:"go1.13.4"}` + version31 = `version.BuildInfo{Version:"v3.1.1", GitCommit:"afe70585407b420d0097d07b21c47dc511525ac8", GitTreeState:"clean", GoVersion:"go1.13.8"}` +) + func TestHelmDeploy(t *testing.T) { tmpDir := os.TempDir() tests := []struct { @@ -336,7 +342,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy success", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -344,10 +350,39 @@ func TestHelmDeploy(t *testing.T) { runContext: makeRunContext(testDeployConfig, false), builds: testBuilds, }, + { + description: "helm3.0 deploy success", + commands: testutil. + CmdRunWithOutput("helm version --client", version30). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, + }, + { + description: "helm3.1 deploy success", + commands: testutil. + CmdRunWithOutput("helm version --client", version31). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, + }, + { + description: "helm3 unparseable version", + commands: testutil.CmdRunWithOutput("helm version --client", "gobbledygook"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, + shouldErr: true, + }, { description: "deploy success with recreatePods", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21rc). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm --recreate-pods examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -358,7 +393,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy success with skipBuildDependencies", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21rc). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"), @@ -368,7 +403,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy should error for unmatched parameter", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -380,7 +415,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy success remote chart with skipBuildDependencies", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm stable/chartmuseum --namespace testNamespace --set-string image.tag=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"), @@ -390,7 +425,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy error remote chart without skipBuildDependencies", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get skaffold-helm-remote --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext dep build stable/chartmuseum --kubeconfig kubeconfig", fmt.Errorf("building helm dependencies")), runContext: makeRunContext(testDeployRemoteChart, false), @@ -400,7 +435,7 @@ func TestHelmDeploy(t *testing.T) { { description: "get failure should install not upgrade", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRunErr("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext install --name skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -408,10 +443,21 @@ func TestHelmDeploy(t *testing.T) { runContext: makeRunContext(testDeployConfig, false), builds: testBuilds, }, + { + description: "helm3 get failure should install not upgrade", + commands: testutil. + CmdRunWithOutput("helm version --client", version31). + AndRunErr("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). + AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext install skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, + }, { description: "get failure should install not upgrade with helm image strategy", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRunErr("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext install --name skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image.repository=docker.io:5000/skaffold-helm,image.tag=3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -422,7 +468,7 @@ func TestHelmDeploy(t *testing.T) { { description: "helm image strategy with explicit registry should set the Helm registry value", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRunErr("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext install --name skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image.registry=docker.io:5000,image.repository=skaffold-helm,image.tag=3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -433,7 +479,7 @@ func TestHelmDeploy(t *testing.T) { { description: "get success should upgrade by force, not install", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm --force examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -444,7 +490,7 @@ func TestHelmDeploy(t *testing.T) { { description: "get success should upgrade without force, not install", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -455,7 +501,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy error", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig", fmt.Errorf("unexpected error")). @@ -467,7 +513,7 @@ func TestHelmDeploy(t *testing.T) { { description: "dep build error", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig", fmt.Errorf("unexpected error")). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -479,11 +525,11 @@ func TestHelmDeploy(t *testing.T) { { description: "should package chart and deploy", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get foo --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build testdata/foo --kubeconfig kubeconfig"). - AndRunWithOutput("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", "Packaged to "+filepath.Join(tmpDir, "foo-0.1.2.tgz")). - AndRun("helm --kube-context kubecontext upgrade foo " + filepath.Join(tmpDir, "foo-0.1.2.tgz") + " --namespace testNamespace --set-string image=foo:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --kubeconfig kubeconfig"). + AndRunWithOutput("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", "Packaged to /tmp/foo-0.1.2.tgz"). + AndRun("helm --kube-context kubecontext upgrade foo " + tmpDir + "/foo-0.1.2.tgz --namespace testNamespace --set-string image=foo:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext get foo --kubeconfig kubeconfig"), shouldErr: false, runContext: makeRunContext(testDeployFooWithPackaged, false), @@ -492,7 +538,7 @@ func TestHelmDeploy(t *testing.T) { { description: "should fail to deploy when packaging fails", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get foo --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build testdata/foo --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", fmt.Errorf("packaging failed")), @@ -503,7 +549,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy and get templated release name", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get -skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade -skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image.tag=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -514,7 +560,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy with templated values", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set image.name=skaffold-helm --set image.tag=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set missing.key= --set other.key=FOOBAR --set some.key=somevalue --kubeconfig kubeconfig"). @@ -525,7 +571,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy with valuesFiles templated", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 -f /some/file-FOOBAR.yaml --kubeconfig kubeconfig"). @@ -536,7 +582,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy without actual tags", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace --kubeconfig kubeconfig"). @@ -552,7 +598,7 @@ func TestHelmDeploy(t *testing.T) { { description: "first release without tag, second with tag", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version --client", version21). AndRun("helm --kube-context kubecontext get other --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade other examples/test --namespace testNamespace --kubeconfig kubeconfig"). @@ -583,48 +629,30 @@ func TestHelmDeploy(t *testing.T) { } } -func TestPackageHelmChart(t *testing.T) { - -} - -// TODO(tstromberg): Remove private function test once there are side-effects in a public function -func TestBinVer(t *testing.T) { +func TestHelmCleanup(t *testing.T) { tests := []struct { - description string - commands util.Command - runContext *runcontext.RunContext - want semver.Version - shouldErr bool + description string + commands util.Command + runContext *runcontext.RunContext + builds []build.Artifact + shouldErr bool + expectedWarnings []string }{ { - description: "helm 2.15.1", - commands: testutil.CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"), - runContext: makeRunContext(testDeployConfig, false), - want: semver.MustParse("2.15.1"), - }, - { - description: "helm 3.1.0", - commands: testutil.CmdRunWithOutput("helm version --short -c", "v3.1.0+gb29d20b"), - runContext: makeRunContext(testDeployConfig, false), - want: semver.MustParse("3.1.0"), - }, - { - description: "helm 2.14.0-rc.2", - commands: testutil.CmdRunWithOutput("helm version --short -c", "Client: v2.14.0-rc.2+g05811b8"), - runContext: makeRunContext(testDeployConfig, false), - want: semver.MustParse("2.14.0-rc.2"), - }, - { - description: "helm 3.0.0", - commands: testutil.CmdRunWithOutput("helm version --short -c", "v3.0.0+ge29ce2a"), - runContext: makeRunContext(testDeployConfig, false), - want: semver.MustParse("3.0.0"), + description: "cleanup success", + commands: testutil. + CmdRunWithOutput("helm version --client", version21). + AndRun("helm --kube-context kubecontext delete skaffold-helm --purge --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, }, { - description: "garbage", - commands: testutil.CmdRunWithOutput("helm version --short -c", "WUTWUT?"), - runContext: makeRunContext(testDeployConfig, false), - shouldErr: true, + description: "helm3 cleanup success", + commands: testutil. + CmdRunWithOutput("helm version --client", version31). + AndRun("helm --kube-context kubecontext delete skaffold-helm --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, }, } for _, test := range tests { @@ -637,11 +665,9 @@ func TestBinVer(t *testing.T) { event.InitializeState(test.runContext.Cfg.Build) deployer := NewHelmDeployer(test.runContext) - got, err := deployer.binVer(context.Background()) + err := deployer.Cleanup(context.Background(), ioutil.Discard) t.CheckError(test.shouldErr, err) - if got.NE(test.want) { - t.Errorf("got version %q, want %q", got, test.want) - } + t.CheckDeepEqual(test.expectedWarnings, fakeWarner.Warnings) }) } } From 7cf0d977c8aef5cac72b24a4e179bb23a7afc661 Mon Sep 17 00:00:00 2001 From: tstromberg Date: Wed, 26 Feb 2020 15:47:22 -0800 Subject: [PATCH 2/5] Test against v2.0.0 --- pkg/skaffold/deploy/helm_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/skaffold/deploy/helm_test.go b/pkg/skaffold/deploy/helm_test.go index fa12bae5c48..fb6904ef7a7 100644 --- a/pkg/skaffold/deploy/helm_test.go +++ b/pkg/skaffold/deploy/helm_test.go @@ -571,7 +571,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy with valuesFiles templated", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version --client", version20). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 -f /some/file-FOOBAR.yaml --kubeconfig kubeconfig"). @@ -582,7 +582,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy without actual tags", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version --client", version20). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace --kubeconfig kubeconfig"). From 19e453063ebc454883a2bbc1eb4efe2d38a11b7c Mon Sep 17 00:00:00 2001 From: tstromberg Date: Wed, 26 Feb 2020 16:01:03 -0800 Subject: [PATCH 3/5] Improve packageChart error messages --- pkg/skaffold/deploy/helm.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/skaffold/deploy/helm.go b/pkg/skaffold/deploy/helm.go index dcc2464f9aa..39cda96238f 100644 --- a/pkg/skaffold/deploy/helm.go +++ b/pkg/skaffold/deploy/helm.go @@ -519,7 +519,7 @@ func (h *HelmDeployer) packageChart(ctx context.Context, r latest.HelmRelease) ( if r.Packaged.Version != "" { v, err := expand(r.Packaged.Version, nil) if err != nil { - return "", errors.Wrap(err, `concretize "packaged.version" template`) + return "", errors.Wrap(err, `packaged.version template`) } packageArgs = append(packageArgs, "--version", v) } @@ -527,7 +527,7 @@ func (h *HelmDeployer) packageChart(ctx context.Context, r latest.HelmRelease) ( if r.Packaged.AppVersion != "" { av, err := expand(r.Packaged.AppVersion, nil) if err != nil { - return "", errors.Wrap(err, `concretize "packaged.appVersion" template`) + return "", errors.Wrap(err, `packaged.appVersion template`) } packageArgs = append(packageArgs, "--app-version", av) } @@ -543,11 +543,12 @@ func (h *HelmDeployer) packageChart(ctx context.Context, r latest.HelmRelease) ( idx := strings.Index(output, tmpDir) if idx == -1 { - return "", errors.New("cannot locate packaged chart archive") + return "", fmt.Errorf("unable to find %s in output: %s", tmpDir, output) } - fpath := output[idx+len(tmpDir):] - return filepath.Join(tmpDir, fpath), nil + fpath := output[idx:] + logrus.Infof("file path: %s", fpath) + return fpath, nil } // imageSetFromConfig calculates the --set-string value from the helm config From fd03d07ed9a966414f82593dfdc9875d6e80533e Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Thu, 27 Feb 2020 11:55:12 -0800 Subject: [PATCH 4/5] Add support for helm 3.0.0-beta.0 --- pkg/skaffold/deploy/helm.go | 16 +++--- pkg/skaffold/deploy/helm_test.go | 98 ++++++++++++++++++++++---------- 2 files changed, 76 insertions(+), 38 deletions(-) diff --git a/pkg/skaffold/deploy/helm.go b/pkg/skaffold/deploy/helm.go index 696b4cfa376..cbd6baa3052 100644 --- a/pkg/skaffold/deploy/helm.go +++ b/pkg/skaffold/deploy/helm.go @@ -95,6 +95,7 @@ func (h *HelmDeployer) Deploy(ctx context.Context, out io.Writer, builds []build if err != nil { return NewDeployErrorResult(errors.Wrapf(err, "failed to determine binary version")) } + logrus.Infof("Deploying with helm v%s ...", hv) var dRes []Artifact nsMap := map[string]struct{}{} @@ -198,7 +199,7 @@ func (h *HelmDeployer) Cleanup(ctx context.Context, out io.Writer) error { } args := []string{"delete", releaseName} - if hv.LT(semver.MustParse("3.0.0")) { + if hv.LT(semver.MustParse("3.0.0-beta.0")) { args = append(args, "--purge") } if err := h.exec(ctx, out, false, args...); err != nil { @@ -325,12 +326,11 @@ func (h *HelmDeployer) binVer(ctx context.Context) (semver.Version, error) { } var b bytes.Buffer - if err := h.exec(ctx, &b, false, "version", "--client"); err != nil { - return semver.Version{}, errors.Wrap(err, "helm version") + // Omits --client & --short, as some versions do not support it (v3.0.0-beta, for instance) + if err := h.exec(ctx, &b, false, "version"); err != nil { + return semver.Version{}, errors.Wrapf(err, "helm version command failed: %s", b.String()) } - bs := b.Bytes() - - raw := string(bs) + raw := b.String() matches := versionRe.FindStringSubmatch(raw) if len(matches) == 0 { return semver.Version{}, fmt.Errorf("unable to parse output: %q", raw) @@ -372,7 +372,7 @@ func installArgs(r latest.HelmRelease, builds []build.Artifact, valuesSet map[st } } else { args = append(args, "install") - if o.helmVersion.LT(semver.MustParse("3.0.0")) { + if o.helmVersion.LT(semver.MustParse("3.0.0-beta.0")) { args = append(args, "--name") } args = append(args, o.releaseName) @@ -486,7 +486,7 @@ func installArgs(r latest.HelmRelease, builds []build.Artifact, valuesSet map[st // getArgs calculates the correct arguments to "helm get" func getArgs(v semver.Version, releaseName string) []string { args := []string{"get"} - if v.GTE(semver.MustParse("3.0.0")) { + if v.GTE(semver.MustParse("3.0.0-beta.0")) { args = append(args, "all") } return append(args, releaseName) diff --git a/pkg/skaffold/deploy/helm_test.go b/pkg/skaffold/deploy/helm_test.go index 15a23f97a88..83a1a3109b3 100644 --- a/pkg/skaffold/deploy/helm_test.go +++ b/pkg/skaffold/deploy/helm_test.go @@ -322,9 +322,10 @@ MANIFEST: var ( // Output strings to emulate different versions of Helm - version20 = `Client: &version.Version{SemVer:"v2.15.1", GitCommit:"cf1de4f8ba70eded310918a8af3a96bfe8e7683b", GitTreeState:"clean"}` - version21 = `Client: &version.Version{SemVer:"v2.15.1", GitCommit:"cf1de4f8ba70eded310918a8af3a96bfe8e7683b", GitTreeState:"clean"}` - version21rc = `Client: &version.Version{SemVer:"v2.14.0-rc.2", GitCommit:"05811b84a3f93603dd6c2fcfe57944dfa7ab7fd0", GitTreeState:"clean"}` + version20 = `Client: &version.Version{SemVer:"v2.15.1", GitCommit:"cf1de4f8ba70eded310918a8af3a96bfe8e7683b", GitTreeState:"clean"}\nError: cannot connect to Tiller\n` + version21 = `Client: &version.Version{SemVer:"v2.15.1", GitCommit:"cf1de4f8ba70eded310918a8af3a96bfe8e7683b", GitTreeState:"clean"}\nServer: &version.Version{SemVer:"v2.16.1", GitCommit:"bbdfe5e7803a12bbdf97e94cd847859890cf4050", GitTreeState:"clean"}\n` + version21rc = `Client: &version.Version{SemVer:"v2.14.0-rc.2", GitCommit:"05811b84a3f93603dd6c2fcfe57944dfa7ab7fd0", GitTreeState:"clean"}\nServer: &version.Version{SemVer:"v2.16.1", GitCommit:"bbdfe5e7803a12bbdf97e94cd847859890cf4050", GitTreeState:"clean"}\n` + version30b = `version.BuildInfo{Version:"v3.0.0-beta.3", GitCommit:"5cb923eecbe80d1ad76399aee234717c11931d9a", GitTreeState:"clean", GoVersion:"go1.12.9"}` version30 = `version.BuildInfo{Version:"v3.0.0", GitCommit:"e29ce2a54e96cd02ccfce88bee4f58bb6e2a28b6", GitTreeState:"clean", GoVersion:"go1.13.4"}` version31 = `version.BuildInfo{Version:"v3.1.1", GitCommit:"afe70585407b420d0097d07b21c47dc511525ac8", GitTreeState:"clean", GoVersion:"go1.13.8"}` ) @@ -346,7 +347,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy success", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -354,10 +355,21 @@ func TestHelmDeploy(t *testing.T) { runContext: makeRunContext(testDeployConfig, false), builds: testBuilds, }, + { + description: "helm3.0beta deploy success", + commands: testutil. + CmdRunWithOutput("helm version", version30b). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, + }, { description: "helm3.0 deploy success", commands: testutil. - CmdRunWithOutput("helm version --client", version30). + CmdRunWithOutput("helm version", version30). AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -368,7 +380,7 @@ func TestHelmDeploy(t *testing.T) { { description: "helm3.1 deploy success", commands: testutil. - CmdRunWithOutput("helm version --client", version31). + CmdRunWithOutput("helm version", version31). AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -378,7 +390,7 @@ func TestHelmDeploy(t *testing.T) { }, { description: "helm3 unparseable version", - commands: testutil.CmdRunWithOutput("helm version --client", "gobbledygook"), + commands: testutil.CmdRunWithOutput("helm version", "gobbledygook"), runContext: makeRunContext(testDeployConfig, false), builds: testBuilds, shouldErr: true, @@ -386,7 +398,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy success with recreatePods", commands: testutil. - CmdRunWithOutput("helm version --client", version21rc). + CmdRunWithOutput("helm version", version21rc). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm --recreate-pods examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -397,7 +409,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy success with skipBuildDependencies", commands: testutil. - CmdRunWithOutput("helm version --client", version21rc). + CmdRunWithOutput("helm version", version21rc). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"), @@ -407,7 +419,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy should error for unmatched parameter", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -419,7 +431,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy success remote chart with skipBuildDependencies", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm stable/chartmuseum --namespace testNamespace --set-string image.tag=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"), @@ -429,7 +441,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy error remote chart without skipBuildDependencies", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm-remote --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext dep build stable/chartmuseum --kubeconfig kubeconfig", fmt.Errorf("building helm dependencies")), runContext: makeRunContext(testDeployRemoteChart, false), @@ -439,7 +451,7 @@ func TestHelmDeploy(t *testing.T) { { description: "get failure should install not upgrade", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRunErr("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext install --name skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -450,7 +462,7 @@ func TestHelmDeploy(t *testing.T) { { description: "helm3 get failure should install not upgrade", commands: testutil. - CmdRunWithOutput("helm version --client", version31). + CmdRunWithOutput("helm version", version31). AndRunErr("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext install skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -461,7 +473,7 @@ func TestHelmDeploy(t *testing.T) { { description: "get failure should install not upgrade with helm image strategy", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRunErr("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext install --name skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image.repository=docker.io:5000/skaffold-helm,image.tag=3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -472,7 +484,7 @@ func TestHelmDeploy(t *testing.T) { { description: "helm image strategy with explicit registry should set the Helm registry value", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRunErr("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext install --name skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image.registry=docker.io:5000,image.repository=skaffold-helm,image.tag=3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -483,7 +495,7 @@ func TestHelmDeploy(t *testing.T) { { description: "get success should upgrade by force, not install", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm --force examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -494,7 +506,7 @@ func TestHelmDeploy(t *testing.T) { { description: "get success should upgrade without force, not install", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -505,7 +517,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy error", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig", fmt.Errorf("unexpected error")). @@ -517,7 +529,7 @@ func TestHelmDeploy(t *testing.T) { { description: "dep build error", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig", fmt.Errorf("unexpected error")). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -527,9 +539,9 @@ func TestHelmDeploy(t *testing.T) { builds: testBuilds, }, { - description: "should package chart and deploy", + description: "helm 2.0 should package chart and deploy", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version20). AndRun("helm --kube-context kubecontext get foo --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build testdata/foo --kubeconfig kubeconfig"). AndRunWithOutput("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", fmt.Sprintf("Packaged to %s", filepath.Join(tmpDir, "foo-0.1.2.tgz"))). @@ -539,10 +551,36 @@ func TestHelmDeploy(t *testing.T) { runContext: makeRunContext(testDeployFooWithPackaged, false), builds: testBuildsFoo, }, + { + description: "helm 3.0 beta should package chart and deploy", + commands: testutil. + CmdRunWithOutput("helm version", version30b). + AndRun("helm --kube-context kubecontext get all foo --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext dep build testdata/foo --kubeconfig kubeconfig"). + AndRunWithOutput("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", fmt.Sprintf("Packaged to %s", filepath.Join(tmpDir, "foo-0.1.2.tgz"))). + AndRun("helm --kube-context kubecontext upgrade foo " + filepath.Join(tmpDir, "foo-0.1.2.tgz") + " --namespace testNamespace --set-string image=foo:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all foo --kubeconfig kubeconfig"), + shouldErr: false, + runContext: makeRunContext(testDeployFooWithPackaged, false), + builds: testBuildsFoo, + }, + { + description: "helm 3.1 should package chart and deploy", + commands: testutil. + CmdRunWithOutput("helm version", version31). + AndRun("helm --kube-context kubecontext get all foo --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext dep build testdata/foo --kubeconfig kubeconfig"). + AndRunWithOutput("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", fmt.Sprintf("Packaged to %s", filepath.Join(tmpDir, "foo-0.1.2.tgz"))). + AndRun("helm --kube-context kubecontext upgrade foo " + filepath.Join(tmpDir, "foo-0.1.2.tgz") + " --namespace testNamespace --set-string image=foo:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all foo --kubeconfig kubeconfig"), + shouldErr: false, + runContext: makeRunContext(testDeployFooWithPackaged, false), + builds: testBuildsFoo, + }, { description: "should fail to deploy when packaging fails", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get foo --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build testdata/foo --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", fmt.Errorf("packaging failed")), @@ -553,7 +591,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy and get templated release name", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get -skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade -skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image.tag=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -564,7 +602,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy with templated values", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set image.name=skaffold-helm --set image.tag=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set missing.key= --set other.key=FOOBAR --set some.key=somevalue --kubeconfig kubeconfig"). @@ -575,7 +613,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy with valuesFiles templated", commands: testutil. - CmdRunWithOutput("helm version --client", version20). + CmdRunWithOutput("helm version", version20). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 -f /some/file-FOOBAR.yaml --kubeconfig kubeconfig"). @@ -586,7 +624,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy without actual tags", commands: testutil. - CmdRunWithOutput("helm version --client", version20). + CmdRunWithOutput("helm version", version20). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace --kubeconfig kubeconfig"). @@ -602,7 +640,7 @@ func TestHelmDeploy(t *testing.T) { { description: "first release without tag, second with tag", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get other --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade other examples/test --namespace testNamespace --kubeconfig kubeconfig"). @@ -646,7 +684,7 @@ func TestHelmCleanup(t *testing.T) { { description: "cleanup success", commands: testutil. - CmdRunWithOutput("helm version --client", version21). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext delete skaffold-helm --purge --kubeconfig kubeconfig"), runContext: makeRunContext(testDeployConfig, false), builds: testBuilds, @@ -654,7 +692,7 @@ func TestHelmCleanup(t *testing.T) { { description: "helm3 cleanup success", commands: testutil. - CmdRunWithOutput("helm version --client", version31). + CmdRunWithOutput("helm version", version31). AndRun("helm --kube-context kubecontext delete skaffold-helm --kubeconfig kubeconfig"), runContext: makeRunContext(testDeployConfig, false), builds: testBuilds, From ece5c73c096071605fe8500dbef2e8854099ea47 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Thu, 27 Feb 2020 13:30:11 -0800 Subject: [PATCH 5/5] Store helm3 version as a variable, rename versionRe --- pkg/skaffold/deploy/helm.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pkg/skaffold/deploy/helm.go b/pkg/skaffold/deploy/helm.go index cbd6baa3052..ee1a7d2366d 100644 --- a/pkg/skaffold/deploy/helm.go +++ b/pkg/skaffold/deploy/helm.go @@ -49,8 +49,11 @@ import ( ) var ( - // versionRe extracts version from "helm version --client", for instance: "2.14.0-rc.2" - versionRe = regexp.MustCompile(`\"v(\d[\w\.\-\.]+)`) + // versionRegex extracts version from "helm version --client", for instance: "2.14.0-rc.2" + versionRegex = regexp.MustCompile(`\"v(\d[\w\.\-\.]+)`) + + // helm3Version represents the version cut-off for helm3 behavior + helm3Version = semver.MustParse("3.0.0-beta.0") ) // HelmDeployer deploys workflows using the helm CLI @@ -199,7 +202,7 @@ func (h *HelmDeployer) Cleanup(ctx context.Context, out io.Writer) error { } args := []string{"delete", releaseName} - if hv.LT(semver.MustParse("3.0.0-beta.0")) { + if hv.LT(helm3Version) { args = append(args, "--purge") } if err := h.exec(ctx, out, false, args...); err != nil { @@ -331,7 +334,7 @@ func (h *HelmDeployer) binVer(ctx context.Context) (semver.Version, error) { return semver.Version{}, errors.Wrapf(err, "helm version command failed: %s", b.String()) } raw := b.String() - matches := versionRe.FindStringSubmatch(raw) + matches := versionRegex.FindStringSubmatch(raw) if len(matches) == 0 { return semver.Version{}, fmt.Errorf("unable to parse output: %q", raw) } @@ -372,7 +375,7 @@ func installArgs(r latest.HelmRelease, builds []build.Artifact, valuesSet map[st } } else { args = append(args, "install") - if o.helmVersion.LT(semver.MustParse("3.0.0-beta.0")) { + if o.helmVersion.LT(helm3Version) { args = append(args, "--name") } args = append(args, o.releaseName) @@ -486,7 +489,7 @@ func installArgs(r latest.HelmRelease, builds []build.Artifact, valuesSet map[st // getArgs calculates the correct arguments to "helm get" func getArgs(v semver.Version, releaseName string) []string { args := []string{"get"} - if v.GTE(semver.MustParse("3.0.0-beta.0")) { + if v.GTE(helm3Version) { args = append(args, "all") } return append(args, releaseName)