Skip to content

Commit b148ab2

Browse files
support helm 3 using exec
- uses 'helm template' for update - uses 'helm get' to retrieve releases and revisions
1 parent 99b8474 commit b148ab2

File tree

7 files changed

+319
-9
lines changed

7 files changed

+319
-9
lines changed

cmd/helm3.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package cmd
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"os/exec"
7+
"strconv"
8+
)
9+
10+
func getRelease(release, namespace string) ([]byte, error) {
11+
args := []string{"get", "manifest", release}
12+
if namespace != "" {
13+
args = append(args, "--namespace", namespace)
14+
}
15+
cmd := exec.Command(os.Getenv("HELM_BIN"), args...)
16+
return cmd.Output()
17+
}
18+
19+
func getHooks(release, namespace string) ([]byte, error) {
20+
args := []string{"get", "hooks", release}
21+
if namespace != "" {
22+
args = append(args, "--namespace", namespace)
23+
}
24+
cmd := exec.Command(os.Getenv("HELM_BIN"), args...)
25+
return cmd.Output()
26+
}
27+
28+
func getRevision(release string, revision int, namespace string) ([]byte, error) {
29+
args := []string{"get", "manifest", release, "--revision", strconv.Itoa(revision)}
30+
if namespace != "" {
31+
args = append(args, "--namespace", namespace)
32+
}
33+
cmd := exec.Command(os.Getenv("HELM_BIN"), args...)
34+
return cmd.Output()
35+
}
36+
37+
func getChart(release, namespace string) (string, error) {
38+
args := []string{"get", release, "--template", "{{.Release.Chart.Name}}"}
39+
if namespace != "" {
40+
args = append(args, "--namespace", namespace)
41+
}
42+
cmd := exec.Command(os.Getenv("HELM_BIN"), args...)
43+
out, err := cmd.Output()
44+
if err != nil {
45+
return "", err
46+
}
47+
return string(out), nil
48+
}
49+
50+
func (d *diffCmd) template() ([]byte, error) {
51+
flags := []string{}
52+
if d.devel {
53+
flags = append(flags, "--devel")
54+
}
55+
if d.noHooks {
56+
flags = append(flags, "--no-hooks")
57+
}
58+
if d.chartVersion != "" {
59+
flags = append(flags, "--version", d.chartVersion)
60+
}
61+
if d.namespace != "" {
62+
flags = append(flags, "--namespace", d.namespace)
63+
}
64+
if !d.resetValues {
65+
if d.reuseValues {
66+
tmpfile, err := ioutil.TempFile("", "existing-values")
67+
if err != nil {
68+
return nil, err
69+
}
70+
defer os.Remove(tmpfile.Name())
71+
flags = append(flags, "--values", tmpfile.Name())
72+
}
73+
for _, value := range d.values {
74+
flags = append(flags, "--set", value)
75+
}
76+
for _, stringValue := range d.stringValues {
77+
flags = append(flags, "--set-string", stringValue)
78+
}
79+
for _, valueFile := range d.valueFiles {
80+
flags = append(flags, "--values", valueFile)
81+
}
82+
for _, fileValue := range d.fileValues {
83+
flags = append(flags, "--set-file", fileValue)
84+
}
85+
}
86+
87+
args := []string{"template", d.release, d.chart}
88+
args = append(args, flags...)
89+
cmd := exec.Command(os.Getenv("HELM_BIN"), args...)
90+
return cmd.Output()
91+
}
92+
93+
func (d *diffCmd) existingValues(f *os.File) error {
94+
cmd := exec.Command(os.Getenv("HELM_BIN"), "get", "values", d.release, "--all")
95+
defer f.Close()
96+
cmd.Stdout = f
97+
return cmd.Run()
98+
}

cmd/helpers.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ var (
2424
DefaultHelmHome = filepath.Join(homedir.HomeDir(), ".helm")
2525
)
2626

27+
func isHelm3() bool {
28+
return os.Getenv("TILLER_HOST") == ""
29+
}
30+
2731
func addCommonCmdOptions(f *flag.FlagSet) {
2832
settings.AddFlagsTLS(f)
2933
settings.InitTLS(f)

cmd/release.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ func releaseCmd() *cobra.Command {
6060
}
6161

6262
diff.releases = args[0:]
63+
if isHelm3() {
64+
return diff.differentiateHelm3()
65+
}
6366
if diff.client == nil {
6467
diff.client = createHelmClient()
6568
}
@@ -70,14 +73,55 @@ func releaseCmd() *cobra.Command {
7073
releaseCmd.Flags().BoolP("suppress-secrets", "q", false, "suppress secrets in the output")
7174
releaseCmd.Flags().StringArrayVar(&diff.suppressedKinds, "suppress", []string{}, "allows suppression of the values listed in the diff output")
7275
releaseCmd.Flags().IntVarP(&diff.outputContext, "context", "C", -1, "output NUM lines of context around changes")
73-
releaseCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
76+
if !isHelm3() {
77+
releaseCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
78+
}
7479
releaseCmd.SuggestionsMinimumDistance = 1
7580

7681
addCommonCmdOptions(releaseCmd.Flags())
7782

7883
return releaseCmd
7984
}
8085

86+
func (d *release) differentiateHelm3() error {
87+
releaseResponse1, err := getRelease(d.releases[0], "")
88+
if err != nil {
89+
return err
90+
}
91+
releaseChart1, err := getChart(d.releases[0], "")
92+
if err != nil {
93+
return err
94+
}
95+
96+
releaseResponse2, err := getRelease(d.releases[1], "")
97+
if err != nil {
98+
return err
99+
}
100+
releaseChart2, err := getChart(d.releases[1], "")
101+
if err != nil {
102+
return err
103+
}
104+
105+
if releaseChart1 == releaseChart2 {
106+
seenAnyChanges := diff.Releases(
107+
manifest.Parse(string(releaseResponse1), ""),
108+
manifest.Parse(string(releaseResponse2), ""),
109+
d.suppressedKinds,
110+
d.outputContext,
111+
os.Stdout)
112+
113+
if d.detailedExitCode && seenAnyChanges {
114+
return Error{
115+
error: errors.New("identified at least one change, exiting with non-zero exit code (detailed-exitcode parameter enabled)"),
116+
Code: 2,
117+
}
118+
}
119+
} else {
120+
fmt.Printf("Error : Incomparable Releases \n Unable to compare releases from two different charts \"%s\", \"%s\". \n try helm diff release --help to know more \n", releaseChart1, releaseChart2)
121+
}
122+
return nil
123+
}
124+
81125
func (d *release) differentiate() error {
82126

83127
releaseResponse1, err := d.client.ReleaseContent(d.releases[0])

cmd/revision.go

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ func revisionCmd() *cobra.Command {
7070

7171
diff.release = args[0]
7272
diff.revisions = args[1:]
73+
if isHelm3() {
74+
return diff.differentiateHelm3()
75+
}
7376
if diff.client == nil {
7477
diff.client = createHelmClient()
7578
}
@@ -80,14 +83,76 @@ func revisionCmd() *cobra.Command {
8083
revisionCmd.Flags().BoolP("suppress-secrets", "q", false, "suppress secrets in the output")
8184
revisionCmd.Flags().StringArrayVar(&diff.suppressedKinds, "suppress", []string{}, "allows suppression of the values listed in the diff output")
8285
revisionCmd.Flags().IntVarP(&diff.outputContext, "context", "C", -1, "output NUM lines of context around changes")
83-
revisionCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
86+
if !isHelm3() {
87+
revisionCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
88+
}
8489
revisionCmd.SuggestionsMinimumDistance = 1
8590

8691
addCommonCmdOptions(revisionCmd.Flags())
8792

8893
return revisionCmd
8994
}
9095

96+
func (d *revision) differentiateHelm3() error {
97+
switch len(d.revisions) {
98+
case 1:
99+
releaseResponse, err := getRelease(d.release, "")
100+
101+
if err != nil {
102+
return err
103+
}
104+
105+
revision, _ := strconv.Atoi(d.revisions[0])
106+
revisionResponse, err := getRevision(d.release, revision, "")
107+
if err != nil {
108+
return err
109+
}
110+
111+
diff.Manifests(
112+
manifest.Parse(string(revisionResponse), ""),
113+
manifest.Parse(string(releaseResponse), ""),
114+
d.suppressedKinds,
115+
d.outputContext,
116+
os.Stdout)
117+
118+
case 2:
119+
revision1, _ := strconv.Atoi(d.revisions[0])
120+
revision2, _ := strconv.Atoi(d.revisions[1])
121+
if revision1 > revision2 {
122+
revision1, revision2 = revision2, revision1
123+
}
124+
125+
revisionResponse1, err := getRevision(d.release, revision1, "")
126+
if err != nil {
127+
return prettyError(err)
128+
}
129+
130+
revisionResponse2, err := getRevision(d.release, revision2, "")
131+
if err != nil {
132+
return prettyError(err)
133+
}
134+
135+
seenAnyChanges := diff.Manifests(
136+
manifest.Parse(string(revisionResponse1), ""),
137+
manifest.Parse(string(revisionResponse2), ""),
138+
d.suppressedKinds,
139+
d.outputContext,
140+
os.Stdout)
141+
142+
if d.detailedExitCode && seenAnyChanges {
143+
return Error{
144+
error: errors.New("identified at least one change, exiting with non-zero exit code (detailed-exitcode parameter enabled)"),
145+
Code: 2,
146+
}
147+
}
148+
149+
default:
150+
return errors.New("Invalid Arguments")
151+
}
152+
153+
return nil
154+
}
155+
91156
func (d *revision) differentiate() error {
92157

93158
switch len(d.revisions) {

cmd/rollback.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ func rollbackCmd() *cobra.Command {
6060
diff.release = args[0]
6161
diff.revisions = args[1:]
6262

63+
if isHelm3() {
64+
return diff.backcastHelm3()
65+
}
66+
6367
if diff.client == nil {
6468
diff.client = createHelmClient()
6569
}
@@ -71,14 +75,49 @@ func rollbackCmd() *cobra.Command {
7175
rollbackCmd.Flags().BoolP("suppress-secrets", "q", false, "suppress secrets in the output")
7276
rollbackCmd.Flags().StringArrayVar(&diff.suppressedKinds, "suppress", []string{}, "allows suppression of the values listed in the diff output")
7377
rollbackCmd.Flags().IntVarP(&diff.outputContext, "context", "C", -1, "output NUM lines of context around changes")
74-
rollbackCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
78+
if !isHelm3() {
79+
rollbackCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
80+
}
7581
rollbackCmd.SuggestionsMinimumDistance = 1
7682

7783
addCommonCmdOptions(rollbackCmd.Flags())
7884

7985
return rollbackCmd
8086
}
8187

88+
func (d *rollback) backcastHelm3() error {
89+
// get manifest of the latest release
90+
releaseResponse, err := getRelease(d.release, "")
91+
92+
if err != nil {
93+
return err
94+
}
95+
96+
// get manifest of the release to rollback
97+
revision, _ := strconv.Atoi(d.revisions[0])
98+
revisionResponse, err := getRevision(d.release, revision, "")
99+
if err != nil {
100+
return err
101+
}
102+
103+
// create a diff between the current manifest and the version of the manifest that a user is intended to rollback
104+
seenAnyChanges := diff.Manifests(
105+
manifest.Parse(string(releaseResponse), ""),
106+
manifest.Parse(string(revisionResponse), ""),
107+
d.suppressedKinds,
108+
d.outputContext,
109+
os.Stdout)
110+
111+
if d.detailedExitCode && seenAnyChanges {
112+
return Error{
113+
error: errors.New("identified at least one change, exiting with non-zero exit code (detailed-exitcode parameter enabled)"),
114+
Code: 2,
115+
}
116+
}
117+
118+
return nil
119+
}
120+
82121
func (d *rollback) backcast() error {
83122

84123
// get manifest of the latest release

0 commit comments

Comments
 (0)