From d8c4cbb0e0e31276241d87d6386aad8d90011117 Mon Sep 17 00:00:00 2001 From: Arash Deshmeh Date: Tue, 3 Apr 2018 17:35:07 -0400 Subject: [PATCH] feat(helm): Added the ability to handle custom description to client side for install, upgrade, rollback, and delete commands. Updated the documentation according to the changes. Signed-off-by: Arash Deshmeh --- cmd/helm/delete.go | 3 +++ cmd/helm/delete_test.go | 8 ++++++++ cmd/helm/install.go | 5 ++++- cmd/helm/install_test.go | 7 +++++++ cmd/helm/rollback.go | 5 ++++- cmd/helm/rollback_test.go | 6 ++++++ cmd/helm/upgrade.go | 6 +++++- cmd/helm/upgrade_test.go | 16 ++++++++++++++++ docs/helm/helm_delete.md | 3 ++- docs/helm/helm_install.md | 3 ++- docs/helm/helm_rollback.md | 3 ++- docs/helm/helm_upgrade.md | 1 + pkg/helm/fake.go | 21 ++++++++++++++------- pkg/helm/fake_test.go | 17 +++++++++++++++++ pkg/helm/option.go | 28 ++++++++++++++++++++++++++++ 15 files changed, 119 insertions(+), 13 deletions(-) diff --git a/cmd/helm/delete.go b/cmd/helm/delete.go index e0ac8c4f6..46c7abcb1 100755 --- a/cmd/helm/delete.go +++ b/cmd/helm/delete.go @@ -40,6 +40,7 @@ type deleteCmd struct { disableHooks bool purge bool timeout int64 + description string out io.Writer client helm.Interface @@ -81,6 +82,7 @@ func newDeleteCmd(c helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&del.disableHooks, "no-hooks", false, "prevent hooks from running during deletion") f.BoolVar(&del.purge, "purge", false, "remove the release from the store and make its name free for later use") f.Int64Var(&del.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") + f.StringVar(&del.description, "description", "", "specify a description for the release") return cmd } @@ -91,6 +93,7 @@ func (d *deleteCmd) run() error { helm.DeleteDisableHooks(d.disableHooks), helm.DeletePurge(d.purge), helm.DeleteTimeout(d.timeout), + helm.DeleteDescription(d.description), } res, err := d.client.DeleteRelease(d.name, opts...) if res != nil && res.Info != "" { diff --git a/cmd/helm/delete_test.go b/cmd/helm/delete_test.go index 829d17906..6b5c444b1 100644 --- a/cmd/helm/delete_test.go +++ b/cmd/helm/delete_test.go @@ -61,6 +61,14 @@ func TestDelete(t *testing.T) { resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})}, }, + { + name: "delete with description", + args: []string{"aeneas"}, + flags: []string{"--description", "foo"}, + expected: "", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"}), + rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "aeneas"})}, + }, { name: "delete without release", args: []string{}, diff --git a/cmd/helm/install.go b/cmd/helm/install.go index d1c24c213..6a2107b92 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -129,6 +129,7 @@ type installCmd struct { password string devel bool depUp bool + description string certFile string keyFile string @@ -209,6 +210,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { f.StringVar(&inst.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.BoolVar(&inst.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.") f.BoolVar(&inst.depUp, "dep-up", false, "run helm dependency update before installing the chart") + f.StringVar(&inst.description, "description", "", "specify a description for the release") return cmd } @@ -277,7 +279,8 @@ func (i *installCmd) run() error { helm.InstallDisableHooks(i.disableHooks), helm.InstallDisableCRDHook(i.disableCRDHook), helm.InstallTimeout(i.timeout), - helm.InstallWait(i.wait)) + helm.InstallWait(i.wait), + helm.InstallDescription(i.description)) if err != nil { return prettyError(err) } diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index aa828c6ce..236174bec 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -115,6 +115,13 @@ func TestInstall(t *testing.T) { expected: "FOOBAR", resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "FOOBAR"}), }, + { + name: "install with custom description", + args: []string{"testdata/testcharts/alpine"}, + flags: []string{"--name", "virgil", "--description", "foobar"}, + expected: "virgil", + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil", Description: "foobar"}), + }, // Install, perform chart verification along the way. { name: "install with verification, missing provenance", diff --git a/cmd/helm/rollback.go b/cmd/helm/rollback.go index 889b6ae28..370807cb4 100644 --- a/cmd/helm/rollback.go +++ b/cmd/helm/rollback.go @@ -45,6 +45,7 @@ type rollbackCmd struct { client helm.Interface timeout int64 wait bool + description string } func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command { @@ -83,6 +84,7 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&rollback.disableHooks, "no-hooks", false, "prevent hooks from running during rollback") f.Int64Var(&rollback.timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&rollback.wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout") + f.StringVar(&rollback.description, "description", "", "specify a description for the release") return cmd } @@ -96,7 +98,8 @@ func (r *rollbackCmd) run() error { helm.RollbackDisableHooks(r.disableHooks), helm.RollbackVersion(r.revision), helm.RollbackTimeout(r.timeout), - helm.RollbackWait(r.wait)) + helm.RollbackWait(r.wait), + helm.RollbackDescription(r.description)) if err != nil { return prettyError(err) } diff --git a/cmd/helm/rollback_test.go b/cmd/helm/rollback_test.go index f1479b2eb..62bfd6477 100644 --- a/cmd/helm/rollback_test.go +++ b/cmd/helm/rollback_test.go @@ -45,6 +45,12 @@ func TestRollbackCmd(t *testing.T) { flags: []string{"--wait"}, expected: "Rollback was a success! Happy Helming!", }, + { + name: "rollback a release with description", + args: []string{"funny-honey", "1"}, + flags: []string{"--description", "foo"}, + expected: "Rollback was a success! Happy Helming!", + }, { name: "rollback a release without revision", args: []string{"funny-honey"}, diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 4dd433a39..aaf87b7d0 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -78,6 +78,7 @@ type upgradeCmd struct { username string password string devel bool + description string certFile string keyFile string @@ -139,6 +140,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { f.StringVar(&upgrade.keyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&upgrade.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.BoolVar(&upgrade.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.") + f.StringVar(&upgrade.description, "description", "", "specify the description to use for the upgrade, rather than the default") f.MarkDeprecated("disable-hooks", "use --no-hooks instead") @@ -190,6 +192,7 @@ func (u *upgradeCmd) run() error { namespace: u.namespace, timeout: u.timeout, wait: u.wait, + description: u.description, } return ic.run() } @@ -224,7 +227,8 @@ func (u *upgradeCmd) run() error { helm.UpgradeTimeout(u.timeout), helm.ResetValues(u.resetValues), helm.ReuseValues(u.reuseValues), - helm.UpgradeWait(u.wait)) + helm.UpgradeWait(u.wait), + helm.UpgradeDescription(u.description)) if err != nil { return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err)) } diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go index 187d3593e..032df2f32 100644 --- a/cmd/helm/upgrade_test.go +++ b/cmd/helm/upgrade_test.go @@ -139,6 +139,14 @@ func TestUpgradeCmd(t *testing.T) { expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 1, Chart: ch})}, }, + { + name: "install a release with 'upgrade --install' and custom description", + args: []string{"crazy-bunny", chartPath}, + flags: []string{"-i", "--description", "foo"}, + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 1, Chart: ch, Description: "foo"}), + expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 1, Chart: ch, Description: "foo"})}, + }, { name: "upgrade a release with wait", args: []string{"crazy-bunny", chartPath}, @@ -147,6 +155,14 @@ func TestUpgradeCmd(t *testing.T) { expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 2, Chart: ch2})}, }, + { + name: "upgrade a release with description", + args: []string{"crazy-bunny", chartPath}, + flags: []string{"--description", "foo"}, + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 2, Chart: ch2}), + expected: "Release \"crazy-bunny\" has been upgraded. Happy Helming!\n", + rels: []*release.Release{helm.ReleaseMock(&helm.MockReleaseOptions{Name: "crazy-bunny", Version: 2, Chart: ch2, Description: "foo"})}, + }, { name: "upgrade a release with missing dependencies", args: []string{"bonkers-bunny", missingDepsPath}, diff --git a/docs/helm/helm_delete.md b/docs/helm/helm_delete.md index 5d41cd7ea..9eee6e8ec 100644 --- a/docs/helm/helm_delete.md +++ b/docs/helm/helm_delete.md @@ -20,6 +20,7 @@ helm delete [flags] RELEASE_NAME [...] ### Options ``` + --description string specify a description for the release --dry-run simulate a delete --no-hooks prevent hooks from running during deletion --purge remove the release from the store and make its name free for later use @@ -45,4 +46,4 @@ helm delete [flags] RELEASE_NAME [...] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 13-Apr-2018 diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index 9f1ad86b0..62d02cc38 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -77,6 +77,7 @@ helm install [CHART] --ca-file string verify certificates of HTTPS-enabled servers using this CA bundle --cert-file string identify HTTPS client using this SSL certificate file --dep-up run helm dependency update before installing the chart + --description string specify a description for the release --devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored. --dry-run simulate an install --key-file string identify HTTPS client using this SSL key file @@ -118,4 +119,4 @@ helm install [CHART] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 27-Apr-2018 +###### Auto generated by spf13/cobra on 5-Jun-2018 diff --git a/docs/helm/helm_rollback.md b/docs/helm/helm_rollback.md index 4b6dcbbb2..ae64a0a26 100644 --- a/docs/helm/helm_rollback.md +++ b/docs/helm/helm_rollback.md @@ -20,6 +20,7 @@ helm rollback [flags] [RELEASE] [REVISION] ### Options ``` + --description string specify a description for the release --dry-run simulate a rollback --force force resource update through delete/recreate if needed --no-hooks prevent hooks from running during rollback @@ -47,4 +48,4 @@ helm rollback [flags] [RELEASE] [REVISION] ### SEE ALSO * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 8-Mar-2018 +###### Auto generated by spf13/cobra on 13-Apr-2018 diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index c2882265e..b952624a5 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -39,6 +39,7 @@ helm upgrade [RELEASE] [CHART] ``` --ca-file string verify certificates of HTTPS-enabled servers using this CA bundle --cert-file string identify HTTPS client using this SSL certificate file + --description string specify the description to use for the upgrade, rather than the default --devel use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored. --dry-run simulate an upgrade --force force resource update through delete/recreate if needed diff --git a/pkg/helm/fake.go b/pkg/helm/fake.go index 0a9e77c44..aa2bbb4e9 100644 --- a/pkg/helm/fake.go +++ b/pkg/helm/fake.go @@ -69,6 +69,7 @@ func (c *FakeClient) InstallReleaseFromChart(chart *chart.Chart, ns string, opts } releaseName := c.Opts.instReq.Name + releaseDescription := c.Opts.instReq.Description // Check to see if the release already exists. rel, err := c.ReleaseStatus(releaseName, nil) @@ -76,7 +77,7 @@ func (c *FakeClient) InstallReleaseFromChart(chart *chart.Chart, ns string, opts return nil, errors.New("cannot re-use a name that is still in use") } - release := ReleaseMock(&MockReleaseOptions{Name: releaseName, Namespace: ns}) + release := ReleaseMock(&MockReleaseOptions{Name: releaseName, Namespace: ns, Description: releaseDescription}) c.Rels = append(c.Rels, release) return &rls.InstallReleaseResponse{ @@ -206,11 +207,12 @@ metadata: // MockReleaseOptions allows for user-configurable options on mock release objects. type MockReleaseOptions struct { - Name string - Version int32 - Chart *chart.Chart - StatusCode release.Status_Code - Namespace string + Name string + Version int32 + Chart *chart.Chart + StatusCode release.Status_Code + Namespace string + Description string } // ReleaseMock creates a mock release object based on options set by MockReleaseOptions. This function should typically not be used outside of testing. @@ -232,6 +234,11 @@ func ReleaseMock(opts *MockReleaseOptions) *release.Release { namespace = "default" } + description := opts.Description + if description == "" { + description = "Release mock" + } + ch := opts.Chart if opts.Chart == nil { ch = &chart.Chart{ @@ -256,7 +263,7 @@ func ReleaseMock(opts *MockReleaseOptions) *release.Release { FirstDeployed: &date, LastDeployed: &date, Status: &release.Status{Code: scode}, - Description: "Release mock", + Description: description, }, Chart: ch, Config: &chart.Config{Raw: `name: "value"`}, diff --git a/pkg/helm/fake_test.go b/pkg/helm/fake_test.go index 9c0a53759..f6de572b5 100644 --- a/pkg/helm/fake_test.go +++ b/pkg/helm/fake_test.go @@ -150,6 +150,23 @@ func TestFakeClient_InstallReleaseFromChart(t *testing.T) { }, wantErr: false, }, + { + name: "Add release with description.", + fields: fields{ + Rels: []*release.Release{}, + }, + args: args{ + ns: "default", + opts: []InstallOption{ReleaseName("new-release"), InstallDescription("foo-bar")}, + }, + want: &rls.InstallReleaseResponse{ + Release: ReleaseMock(&MockReleaseOptions{Name: "new-release", Description: "foo-bar"}), + }, + relsAfter: []*release.Release{ + ReleaseMock(&MockReleaseOptions{Name: "new-release", Description: "foo-bar"}), + }, + wantErr: false, + }, { name: "Try to add a release where the name already exists.", fields: fields{ diff --git a/pkg/helm/option.go b/pkg/helm/option.go index 602e1e3a3..4babec073 100644 --- a/pkg/helm/option.go +++ b/pkg/helm/option.go @@ -262,6 +262,34 @@ func UpdateValueOverrides(raw []byte) UpdateOption { } } +// InstallDescription specifies the description for the release +func InstallDescription(description string) InstallOption { + return func(opts *options) { + opts.instReq.Description = description + } +} + +// UpgradeDescription specifies the description for the update +func UpgradeDescription(description string) UpdateOption { + return func(opts *options) { + opts.updateReq.Description = description + } +} + +// RollbackDescription specifies the description for the release +func RollbackDescription(description string) RollbackOption { + return func(opts *options) { + opts.rollbackReq.Description = description + } +} + +// DeleteDescription specifies the description for the release +func DeleteDescription(description string) DeleteOption { + return func(opts *options) { + opts.uninstallReq.Description = description + } +} + // DeleteDisableHooks will disable hooks for a deletion operation. func DeleteDisableHooks(disable bool) DeleteOption { return func(opts *options) {