Skip to content

Commit a990cba

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

File tree

7 files changed

+328
-12
lines changed

7 files changed

+328
-12
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: 48 additions & 2 deletions
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,57 @@ 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

76-
addCommonCmdOptions(releaseCmd.Flags())
81+
if !isHelm3() {
82+
addCommonCmdOptions(releaseCmd.Flags())
83+
}
7784

7885
return releaseCmd
7986
}
8087

88+
func (d *release) differentiateHelm3() error {
89+
releaseResponse1, err := getRelease(d.releases[0], "")
90+
if err != nil {
91+
return err
92+
}
93+
releaseChart1, err := getChart(d.releases[0], "")
94+
if err != nil {
95+
return err
96+
}
97+
98+
releaseResponse2, err := getRelease(d.releases[1], "")
99+
if err != nil {
100+
return err
101+
}
102+
releaseChart2, err := getChart(d.releases[1], "")
103+
if err != nil {
104+
return err
105+
}
106+
107+
if releaseChart1 == releaseChart2 {
108+
seenAnyChanges := diff.Releases(
109+
manifest.Parse(string(releaseResponse1), ""),
110+
manifest.Parse(string(releaseResponse2), ""),
111+
d.suppressedKinds,
112+
d.outputContext,
113+
os.Stdout)
114+
115+
if d.detailedExitCode && seenAnyChanges {
116+
return Error{
117+
error: errors.New("identified at least one change, exiting with non-zero exit code (detailed-exitcode parameter enabled)"),
118+
Code: 2,
119+
}
120+
}
121+
} else {
122+
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)
123+
}
124+
return nil
125+
}
126+
81127
func (d *release) differentiate() error {
82128

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

cmd/revision.go

Lines changed: 69 additions & 2 deletions
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,78 @@ 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

86-
addCommonCmdOptions(revisionCmd.Flags())
91+
if !isHelm3() {
92+
addCommonCmdOptions(revisionCmd.Flags())
93+
}
8794

8895
return revisionCmd
8996
}
9097

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

93160
switch len(d.revisions) {

cmd/rollback.go

Lines changed: 43 additions & 2 deletions
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,51 @@ 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

77-
addCommonCmdOptions(rollbackCmd.Flags())
83+
if !isHelm3() {
84+
addCommonCmdOptions(rollbackCmd.Flags())
85+
}
7886

7987
return rollbackCmd
8088
}
8189

90+
func (d *rollback) backcastHelm3() error {
91+
// get manifest of the latest release
92+
releaseResponse, err := getRelease(d.release, "")
93+
94+
if err != nil {
95+
return err
96+
}
97+
98+
// get manifest of the release to rollback
99+
revision, _ := strconv.Atoi(d.revisions[0])
100+
revisionResponse, err := getRevision(d.release, revision, "")
101+
if err != nil {
102+
return err
103+
}
104+
105+
// create a diff between the current manifest and the version of the manifest that a user is intended to rollback
106+
seenAnyChanges := diff.Manifests(
107+
manifest.Parse(string(releaseResponse), ""),
108+
manifest.Parse(string(revisionResponse), ""),
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+
120+
return nil
121+
}
122+
82123
func (d *rollback) backcast() error {
83124

84125
// get manifest of the latest release

0 commit comments

Comments
 (0)