From e0b324b69b1d962fb1bdc494ce3e732be328ed21 Mon Sep 17 00:00:00 2001 From: Justin Nauman Date: Thu, 17 Aug 2017 23:49:06 -0500 Subject: [PATCH 1/3] Adding in diff plugin execution - Simple copy-paste for the most part from sync job. I had started down the path of adding in a meta PluginCommand directive and trying to make it more modular, but in the end there are some small differences between the execution that were a bit difficult to model and it just got ugly. Figured keeping it simple would be easier to manage --- helmexec/exec.go | 12 ++++++++++++ helmexec/helmexec.go | 1 + main.go | 39 +++++++++++++++++++++++++++++++++++++++ state/state.go | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+) diff --git a/helmexec/exec.go b/helmexec/exec.go index 29f1d1ce..9fbf8eb8 100644 --- a/helmexec/exec.go +++ b/helmexec/exec.go @@ -76,6 +76,18 @@ func (helm *execer) SyncChart(name, chart string, flags ...string) error { return err } +func (helm *execer) DiffChart(name, chart string, flags ...string) error { + chart, err := normalizeChart(chart) + if err != nil { + return err + } + out, err := helm.exec(append([]string{"diff", name, chart}, flags...)...) + if helm.writer != nil { + helm.writer.Write(out) + } + return err +} + func (helm *execer) DeleteChart(name string) error { out, err := helm.exec("delete", name) if helm.writer != nil { diff --git a/helmexec/helmexec.go b/helmexec/helmexec.go index 72150663..b62fb70e 100644 --- a/helmexec/helmexec.go +++ b/helmexec/helmexec.go @@ -7,5 +7,6 @@ type Interface interface { UpdateRepo() error SyncChart(name, chart string, flags ...string) error + DiffChart(name, chart string, flags ...string) error DeleteChart(name string) error } diff --git a/main.go b/main.go index 05dd4f5e..8079f716 100644 --- a/main.go +++ b/main.go @@ -107,6 +107,45 @@ func main() { return nil }, }, + { + Name: "diff", + Usage: "diff charts from state file against env (helm diff)", + Flags: []cli.Flag{ + cli.StringSliceFlag{ + Name: "values", + Usage: "additional value files to be merged into the command", + }, + cli.BoolFlag{ + Name: "sync-repos", + Usage: "enable a repo sync prior to diffing", + }, + }, + Action: func(c *cli.Context) error { + state, helm, err := before(c) + if err != nil { + return err + } + + if c.Bool("sync-repos") { + if errs := state.SyncRepos(helm); errs != nil && len(errs) > 0 { + for _, err := range errs { + fmt.Printf("err: %s\n", err.Error()) + } + os.Exit(1) + } + } + + values := c.StringSlice("values") + + if errs := state.DiffCharts(helm, values); errs != nil && len(errs) > 0 { + for _, err := range errs { + fmt.Printf("err: %s\n", err.Error()) + } + os.Exit(1) + } + return nil + }, + }, { Name: "sync", Usage: "sync all resources from state file (repos && charts)", diff --git a/state/state.go b/state/state.go index f620f99b..435456d9 100644 --- a/state/state.go +++ b/state/state.go @@ -115,6 +115,44 @@ func (state *HelmState) SyncCharts(helm helmexec.Interface, additonalValues []st return nil } +func (state *HelmState) DiffCharts(helm helmexec.Interface, additonalValues []string) []error { + var wg sync.WaitGroup + errs := []error{} + + for _, chart := range state.Charts { + wg.Add(1) + go func(wg *sync.WaitGroup, chart ChartSpec) { + // Plugin command doesn't support explicit namespace + chart.Namespace = "" + flags, flagsErr := flagsForChart(&chart) + if flagsErr != nil { + errs = append(errs, flagsErr) + } + for _, value := range additonalValues { + wd, wdErr := os.Getwd() + if wdErr != nil { + errs = append(errs, wdErr) + } + valfile := filepath.Join(wd, value) + flags = append(flags, "--values", valfile) + } + if len(errs) == 0 { + if err := helm.DiffChart(chart.Name, chart.Chart, flags...); err != nil { + errs = append(errs, err) + } + } + wg.Done() + }(&wg, chart) + } + wg.Wait() + + if len(errs) != 0 { + return errs + } + + return nil +} + func (state *HelmState) DeleteCharts(helm helmexec.Interface) []error { var wg sync.WaitGroup errs := []error{} From 53408e18b325c8920da58822ab05550fd254ed66 Mon Sep 17 00:00:00 2001 From: Justin Nauman Date: Mon, 28 Aug 2017 17:38:32 -0500 Subject: [PATCH 2/3] Adding in details around the diff subcommand --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8883d5ae..cc8f0b18 100644 --- a/README.md +++ b/README.md @@ -49,12 +49,10 @@ NAME: USAGE: main [global options] command [command options] [arguments...] -VERSION: - 0.1.0 - COMMANDS: repos sync repositories from state file (helm repo add && helm repo update) charts sync charts from state file (helm repo upgrade --install) + diff diff charts from state file against env (helm diff) sync sync all resources from state file (repos && charts) delete delete charts from state file (helm delete) @@ -65,3 +63,12 @@ GLOBAL OPTIONS: --help, -h show help --version, -v print the version ``` + +### diff + +The `helmfile diff` sub-command executes the [helm-diff](https://github.com/databus23/helm-diff) plugin across all of +the charts/releases defined in the manifest. + +Under the covers Helmfile is simply using the `helm diff` plugin, so that needs to be installed prior. For Helm 2.3+ +you should be able to simply execute `helm plugin install https://github.com/databus23/helm-diff`. For more details +please look at their [documentation](https://github.com/databus23/helm-diff#helm-diff-plugin). From 6585bf18423b72d633216d52e6e413032ca763fa Mon Sep 17 00:00:00 2001 From: Justin Nauman Date: Thu, 31 Aug 2017 16:56:39 -0500 Subject: [PATCH 3/3] Adding in option to pass in --args --- main.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/main.go b/main.go index 8079f716..b7460058 100644 --- a/main.go +++ b/main.go @@ -111,6 +111,11 @@ func main() { Name: "diff", Usage: "diff charts from state file against env (helm diff)", Flags: []cli.Flag{ + cli.StringFlag{ + Name: "args", + Value: "", + Usage: "pass args to helm exec", + }, cli.StringSliceFlag{ Name: "values", Usage: "additional value files to be merged into the command", @@ -126,6 +131,11 @@ func main() { return err } + args := c.String("args") + if len(args) > 0 { + helm.SetExtraArgs(strings.Split(args, " ")...) + } + if c.Bool("sync-repos") { if errs := state.SyncRepos(helm); errs != nil && len(errs) > 0 { for _, err := range errs {