From 5958521f352625b23baba11859aa383e5676c8f4 Mon Sep 17 00:00:00 2001 From: Justin Nauman Date: Wed, 22 Nov 2017 11:39:57 -0600 Subject: [PATCH 1/3] New Install diff - Allows the ability to `diff` against a brand new chart in the cluster instead of erroring --- main.go | 52 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/main.go b/main.go index cc0beb60..f226822a 100644 --- a/main.go +++ b/main.go @@ -3,11 +3,11 @@ package main import ( "fmt" "os" + "strings" + "github.com/databus23/helm-diff/manifest" "github.com/spf13/cobra" "k8s.io/helm/pkg/helm" - - "github.com/databus23/helm-diff/manifest" ) const globalUsage = ` @@ -33,7 +33,6 @@ type diffCmd struct { } func main() { - diff := diffCmd{} cmd := &cobra.Command{ @@ -45,6 +44,7 @@ func main() { fmt.Println(Version) return nil } + if err := checkArgsLength(len(args), "release name", "chart path"); err != nil { return err } @@ -82,23 +82,47 @@ func (d *diffCmd) run() error { releaseResponse, err := d.client.ReleaseContent(d.release) - if err != nil { - return prettyError(err) + var newInstall bool + if err != nil && strings.Contains(err.Error(), fmt.Sprintf("release: %q not found", d.release)) { + fmt.Println("Release Not Found was caught...") + newInstall = true + err = nil } - upgradeResponse, err := d.client.UpdateRelease( - d.release, - chartPath, - helm.UpdateValueOverrides(rawVals), - helm.ReuseValues(d.reuseValues), - helm.UpgradeDryRun(true), - ) if err != nil { return prettyError(err) } - currentSpecs := manifest.Parse(releaseResponse.Release.Manifest) - newSpecs := manifest.Parse(upgradeResponse.Release.Manifest) + var currentSpecs, newSpecs map[string]string + if newInstall { + installResponse, err := d.client.InstallRelease( + chartPath, + "default", + helm.ReleaseName(d.release), + helm.ValueOverrides(rawVals), + helm.InstallDryRun(true), + ) + if err != nil { + return prettyError(err) + } + + currentSpecs = make(map[string]string) + newSpecs = manifest.Parse(installResponse.Release.Manifest) + } else { + upgradeResponse, err := d.client.UpdateRelease( + d.release, + chartPath, + helm.UpdateValueOverrides(rawVals), + helm.ReuseValues(d.reuseValues), + helm.UpgradeDryRun(true), + ) + if err != nil { + return prettyError(err) + } + + currentSpecs = manifest.Parse(releaseResponse.Release.Manifest) + newSpecs = manifest.Parse(upgradeResponse.Release.Manifest) + } diffManifests(currentSpecs, newSpecs, os.Stdout) From 370036e717cbf27fd6dbd9fa4dd52bc6413fc7fc Mon Sep 17 00:00:00 2001 From: Justin Nauman Date: Wed, 22 Nov 2017 11:45:32 -0600 Subject: [PATCH 2/3] Merging in changes for both PRs --- diff.go | 23 ++++++++++++++++------- main.go | 30 ++++++++++++++++++------------ manifest/parse.go | 16 +++++++++++++--- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/diff.go b/diff.go index eaa91ead..e944b306 100644 --- a/diff.go +++ b/diff.go @@ -7,20 +7,22 @@ import ( "github.com/aryann/difflib" "github.com/mgutz/ansi" + + "github.com/databus23/helm-diff/manifest" ) -func diffManifests(oldIndex, newIndex map[string]string, to io.Writer) { +func diffManifests(oldIndex, newIndex map[string]*manifest.MappingResult, suppressedKinds []string, to io.Writer) { for key, oldContent := range oldIndex { if newContent, ok := newIndex[key]; ok { - if oldContent != newContent { + if oldContent.Content != newContent.Content { // modified fmt.Fprintf(to, ansi.Color("%s has changed:", "yellow")+"\n", key) - printDiff(oldContent, newContent, to) + printDiff(suppressedKinds, oldContent.Kind, oldContent.Content, newContent.Content, to) } } else { // removed fmt.Fprintf(to, ansi.Color("%s has been removed:", "yellow")+"\n", key) - printDiff(oldContent, "", to) + printDiff(suppressedKinds, oldContent.Kind, oldContent.Content, "", to) } } @@ -28,14 +30,22 @@ func diffManifests(oldIndex, newIndex map[string]string, to io.Writer) { if _, ok := oldIndex[key]; !ok { // added fmt.Fprintf(to, ansi.Color("%s has been added:", "yellow")+"\n", key) - printDiff("", newContent, to) + printDiff(suppressedKinds, newContent.Kind, "", newContent.Content, to) } } } -func printDiff(before, after string, to io.Writer) { +func printDiff(suppressedKinds []string, kind, before, after string, to io.Writer) { diffs := difflib.Diff(strings.Split(before, "\n"), strings.Split(after, "\n")) + for _, ckind := range suppressedKinds { + if ckind == kind { + str := fmt.Sprintf("+ Changes suppressed on sensitive content of type %s\n", kind) + fmt.Fprintf(to, ansi.Color(str, "yellow")) + return + } + } + for _, diff := range diffs { text := diff.Payload @@ -48,5 +58,4 @@ func printDiff(before, after string, to io.Writer) { fmt.Fprintf(to, "%s\n", " "+text) } } - } diff --git a/main.go b/main.go index f226822a..4da9a46c 100644 --- a/main.go +++ b/main.go @@ -19,17 +19,17 @@ This can be used visualize what changes a helm upgrade will perform. ` -var Version string = "HEAD" +// Version identifier populated via the CI/CD process. +var Version = "HEAD" type diffCmd struct { - release string - chart string - // out io.Writer - client helm.Interface - // version int32 - valueFiles valueFiles - values []string - reuseValues bool + release string + chart string + client helm.Interface + valueFiles valueFiles + values []string + reuseValues bool + suppressedKinds []string } func main() { @@ -49,6 +49,10 @@ func main() { return err } + if q, _ := cmd.Flags().GetBool("suppress-secrets"); q { + diff.suppressedKinds = append(diff.suppressedKinds, "Secret") + } + diff.release = args[0] diff.chart = args[1] if diff.client == nil { @@ -60,9 +64,11 @@ func main() { f := cmd.Flags() f.BoolP("version", "v", false, "show version") + f.BoolP("suppress-secrets", "q", false, "suppress secrets in the output") f.VarP(&diff.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)") f.StringArrayVar(&diff.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") f.BoolVar(&diff.reuseValues, "reuse-values", false, "reuse the last release's values and merge in any new values") + f.StringArrayVar(&diff.suppressedKinds, "suppress", []string{}, "allows suppression of the values listed in the diff output") if err := cmd.Execute(); err != nil { os.Exit(1) @@ -93,7 +99,7 @@ func (d *diffCmd) run() error { return prettyError(err) } - var currentSpecs, newSpecs map[string]string + var currentSpecs, newSpecs map[string]*manifest.MappingResult if newInstall { installResponse, err := d.client.InstallRelease( chartPath, @@ -106,7 +112,7 @@ func (d *diffCmd) run() error { return prettyError(err) } - currentSpecs = make(map[string]string) + currentSpecs = make(map[string]*manifest.MappingResult) newSpecs = manifest.Parse(installResponse.Release.Manifest) } else { upgradeResponse, err := d.client.UpdateRelease( @@ -124,7 +130,7 @@ func (d *diffCmd) run() error { newSpecs = manifest.Parse(upgradeResponse.Release.Manifest) } - diffManifests(currentSpecs, newSpecs, os.Stdout) + diffManifests(currentSpecs, newSpecs, d.suppressedKinds, os.Stdout) return nil } diff --git a/manifest/parse.go b/manifest/parse.go index d8ce6eda..b513fa00 100644 --- a/manifest/parse.go +++ b/manifest/parse.go @@ -12,6 +12,12 @@ import ( var yamlSeperator = []byte("\n---\n") +type MappingResult struct { + Name string + Kind string + Content string +} + type metadata struct { ApiVersion string `yaml:"apiVersion"` Kind string @@ -47,7 +53,7 @@ func splitSpec(token string) (string, string) { return "", "" } -func Parse(manifest string) map[string]string { +func Parse(manifest string) map[string]*MappingResult { scanner := bufio.NewScanner(strings.NewReader(manifest)) scanner.Split(scanYamlSpecs) //Allow for tokens (specs) up to 1M in size @@ -55,7 +61,7 @@ func Parse(manifest string) map[string]string { //Discard the first result, we only care about everything after the first seperator scanner.Scan() - result := make(map[string]string) + result := make(map[string]*MappingResult) for scanner.Scan() { content := scanner.Text() @@ -70,7 +76,11 @@ func Parse(manifest string) map[string]string { if _, ok := result[name]; ok { log.Println("Error: Found duplicate key %#v in manifest", name) } else { - result[name] = content + result[name] = &MappingResult{ + Name: name, + Kind: metadata.Kind, + Content: content, + } } } return result From 54de90ccb11b283c122ca8f67b419ee9cd54bd61 Mon Sep 17 00:00:00 2001 From: Justin Nauman Date: Wed, 22 Nov 2017 11:59:07 -0600 Subject: [PATCH 3/3] Adding in more descriptive help message --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 4da9a46c..a09f0d4d 100644 --- a/main.go +++ b/main.go @@ -90,7 +90,7 @@ func (d *diffCmd) run() error { var newInstall bool if err != nil && strings.Contains(err.Error(), fmt.Sprintf("release: %q not found", d.release)) { - fmt.Println("Release Not Found was caught...") + fmt.Println("Release was not present in Helm. Diff will show entire contents as new.") newInstall = true err = nil }