From e4fa70239eb30dfaa0e1597bf09effddc31fad84 Mon Sep 17 00:00:00 2001 From: Erin Call Date: Mon, 16 Dec 2019 16:55:05 -0800 Subject: [PATCH 1/3] Implement config flags for `helm upgrade` --- internal/run/upgrade.go | 37 +++++++++++++++++++--- internal/run/upgrade_test.go | 59 ++++++++++++++++++++++++++++++------ 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/internal/run/upgrade.go b/internal/run/upgrade.go index 9fa6180..c0c40a8 100644 --- a/internal/run/upgrade.go +++ b/internal/run/upgrade.go @@ -10,6 +10,7 @@ type Upgrade struct { Release string ChartVersion string + DryRun bool Wait bool ReuseValues bool Timeout string @@ -30,13 +31,41 @@ func (u *Upgrade) Prepare(cfg Config) error { if cfg.Namespace != "" { args = append(args, "--namespace", cfg.Namespace) } - - args = append(args, "upgrade", "--install", u.Release, u.Chart) - if cfg.Debug { - args = append([]string{"--debug"}, args...) + args = append(args, "--debug") } + args = append(args, "upgrade", "--install") + + if u.ChartVersion != "" { + args = append(args, "--version", u.ChartVersion) + } + if u.DryRun { + args = append(args, "--dry-run") + } + if u.Wait { + args = append(args, "--wait") + } + if u.ReuseValues { + args = append(args, "--reuse-values") + } + if u.Timeout != "" { + args = append(args, "--timeout", u.Timeout) + } + if u.Force { + args = append(args, "--force") + } + if cfg.Values != "" { + args = append(args, "--set", cfg.Values) + } + if cfg.StringValues != "" { + args = append(args, "--set-string", cfg.StringValues) + } + for _, vFile := range cfg.ValuesFiles { + args = append(args, "--values", vFile) + } + + args = append(args, u.Release, u.Chart) u.cmd = command(helmBin, args...) u.cmd.Stdout(cfg.Stdout) u.cmd.Stderr(cfg.Stderr) diff --git a/internal/run/upgrade_test.go b/internal/run/upgrade_test.go index 19b84b9..c1922f4 100644 --- a/internal/run/upgrade_test.go +++ b/internal/run/upgrade_test.go @@ -31,7 +31,7 @@ func TestUpgradeTestSuite(t *testing.T) { suite.Run(t, new(UpgradeTestSuite)) } -func (suite *UpgradeTestSuite) TestPrepare() { +func (suite *UpgradeTestSuite) TestPrepareAndExecute() { defer suite.ctrl.Finish() u := Upgrade{ @@ -79,12 +79,8 @@ func (suite *UpgradeTestSuite) TestPrepareNamespaceFlag() { return suite.mockCmd } - suite.mockCmd.EXPECT(). - Stdout(gomock.Any()) - suite.mockCmd.EXPECT(). - Stderr(gomock.Any()) - suite.mockCmd.EXPECT(). - Run() + suite.mockCmd.EXPECT().Stdout(gomock.Any()) + suite.mockCmd.EXPECT().Stderr(gomock.Any()) cfg := Config{ Namespace: "melt", @@ -92,7 +88,52 @@ func (suite *UpgradeTestSuite) TestPrepareNamespaceFlag() { } err := u.Prepare(cfg) suite.Require().Nil(err) - u.Execute(cfg) +} + +func (suite *UpgradeTestSuite) TestPrepareWithUpgradeFlags() { + defer suite.ctrl.Finish() + + u := Upgrade{ + Chart: "hot_ac", + Release: "maroon_5_memories", + ChartVersion: "radio_edit", //-version + DryRun: true, //-run + Wait: true, //-wait + ReuseValues: true, //-values + Timeout: "sit_in_the_corner", //-timeout + Force: true, //-force + } + + cfg := Config{ + KubeConfig: "/root/.kube/config", + Values: "age=35", + StringValues: "height=5ft10in", + ValuesFiles: []string{"/usr/local/stats", "/usr/local/grades"}, + } + + command = func(path string, args ...string) cmd { + suite.Equal(helmBin, path) + suite.Equal([]string{"--kubeconfig", "/root/.kube/config", "upgrade", "--install", + "--version", "radio_edit", + "--dry-run", + "--wait", + "--reuse-values", + "--timeout", "sit_in_the_corner", + "--force", + "--set", "age=35", + "--set-string", "height=5ft10in", + "--values", "/usr/local/stats", + "--values", "/usr/local/grades", + "maroon_5_memories", "hot_ac"}, args) + + return suite.mockCmd + } + + suite.mockCmd.EXPECT().Stdout(gomock.Any()) + suite.mockCmd.EXPECT().Stderr(gomock.Any()) + + err := u.Prepare(cfg) + suite.Require().Nil(err) } func (suite *UpgradeTestSuite) TestPrepareDebugFlag() { @@ -125,7 +166,7 @@ func (suite *UpgradeTestSuite) TestPrepareDebugFlag() { u.Prepare(cfg) - want := fmt.Sprintf("Generated command: '%s --debug --kubeconfig /root/.kube/config upgrade "+ + want := fmt.Sprintf("Generated command: '%s --kubeconfig /root/.kube/config --debug upgrade "+ "--install lewis_capaldi_someone_you_loved at40'\n", helmBin) suite.Equal(want, stderr.String()) suite.Equal("", stdout.String()) From 1560c05100a7009671b6bc63295bd032b22c3259 Mon Sep 17 00:00:00 2001 From: Erin Call Date: Mon, 16 Dec 2019 16:55:54 -0800 Subject: [PATCH 2/3] Fail early if chart or release is missing --- README.md | 2 +- internal/run/upgrade.go | 7 +++++++ internal/run/upgrade_test.go | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a39eb59..0cd5772 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ TODO: * [x] Make `golint` part of the build process (and make it pass) * [x] Implement debug output * [x] Flesh out `helm upgrade` until it's capable of working -* [ ] Implement config settings for `upgrade` +* [x] Implement config settings for `upgrade` * [ ] Implement `helm lint` * [ ] Implement `helm delete` * [ ] EKS support diff --git a/internal/run/upgrade.go b/internal/run/upgrade.go index c0c40a8..cff2c70 100644 --- a/internal/run/upgrade.go +++ b/internal/run/upgrade.go @@ -26,6 +26,13 @@ func (u *Upgrade) Execute(_ Config) error { // Prepare gets the Upgrade ready to execute. func (u *Upgrade) Prepare(cfg Config) error { + if u.Chart == "" { + return fmt.Errorf("chart is required") + } + if u.Release == "" { + return fmt.Errorf("release is required") + } + args := []string{"--kubeconfig", cfg.KubeConfig} if cfg.Namespace != "" { diff --git a/internal/run/upgrade_test.go b/internal/run/upgrade_test.go index c1922f4..13b2080 100644 --- a/internal/run/upgrade_test.go +++ b/internal/run/upgrade_test.go @@ -136,6 +136,26 @@ func (suite *UpgradeTestSuite) TestPrepareWithUpgradeFlags() { suite.Require().Nil(err) } +func (suite *UpgradeTestSuite) TestRequiresChartAndRelease() { + // These aren't really expected, but allowing them gives clearer test-failure messages + suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes() + suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes() + + u := Upgrade{ + Release: "seth_everman_unskippable_cutscene", + } + + err := u.Prepare(Config{}) + suite.EqualError(err, "chart is required", "Chart should be mandatory") + + u = Upgrade{ + Chart: "billboard_top_zero", + } + + err = u.Prepare(Config{}) + suite.EqualError(err, "release is required", "Release should be mandatory") +} + func (suite *UpgradeTestSuite) TestPrepareDebugFlag() { u := Upgrade{ Chart: "at40", From aa04830600cee9f2c44b087fe7231c0a2e9ab147 Mon Sep 17 00:00:00 2001 From: Erin Call Date: Tue, 17 Dec 2019 09:23:44 -0800 Subject: [PATCH 3/3] Populate DryRun when building an Upgrade step --- internal/helm/plan.go | 1 + internal/helm/plan_test.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/internal/helm/plan.go b/internal/helm/plan.go index 1364112..ea184f3 100644 --- a/internal/helm/plan.go +++ b/internal/helm/plan.go @@ -106,6 +106,7 @@ var upgrade = func(cfg Config) []Step { Chart: cfg.Chart, Release: cfg.Release, ChartVersion: cfg.ChartVersion, + DryRun: cfg.DryRun, Wait: cfg.Wait, ReuseValues: cfg.ReuseValues, Timeout: cfg.Timeout, diff --git a/internal/helm/plan_test.go b/internal/helm/plan_test.go index c34bc48..716a27c 100644 --- a/internal/helm/plan_test.go +++ b/internal/helm/plan_test.go @@ -93,6 +93,7 @@ func (suite *PlanTestSuite) TestUpgrade() { APIServer: "123.456.78.9", ServiceAccount: "helmet", ChartVersion: "seventeen", + DryRun: true, Wait: true, ReuseValues: true, Timeout: "go sit in the corner", @@ -126,6 +127,7 @@ func (suite *PlanTestSuite) TestUpgrade() { Chart: cfg.Chart, Release: cfg.Release, ChartVersion: cfg.ChartVersion, + DryRun: true, Wait: cfg.Wait, ReuseValues: cfg.ReuseValues, Timeout: cfg.Timeout,