Skip to content

Commit 592640e

Browse files
authored
Merge pull request #151 from jonasrutishauser/helm3-exec
support helm 3 using exec
2 parents 99b8474 + 2448af6 commit 592640e

File tree

9 files changed

+399
-12
lines changed

9 files changed

+399
-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: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ const (
1616
tlsCaCertDefault = "$HELM_HOME/ca.pem"
1717
tlsCertDefault = "$HELM_HOME/cert.pem"
1818
tlsKeyDefault = "$HELM_HOME/key.pem"
19+
20+
helm2TestSuccessHook = "test-success"
21+
helm3TestHook = "test"
1922
)
2023

2124
var (
@@ -24,6 +27,10 @@ var (
2427
DefaultHelmHome = filepath.Join(homedir.HomeDir(), ".helm")
2528
)
2629

30+
func isHelm3() bool {
31+
return os.Getenv("TILLER_HOST") == ""
32+
}
33+
2734
func addCommonCmdOptions(f *flag.FlagSet) {
2835
settings.AddFlagsTLS(f)
2936
settings.InitTLS(f)

cmd/release.go

Lines changed: 50 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
}
@@ -73,11 +76,57 @@ func releaseCmd() *cobra.Command {
7376
releaseCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
7477
releaseCmd.SuggestionsMinimumDistance = 1
7578

76-
addCommonCmdOptions(releaseCmd.Flags())
79+
if !isHelm3() {
80+
addCommonCmdOptions(releaseCmd.Flags())
81+
}
7782

7883
return releaseCmd
7984
}
8085

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

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

cmd/revision.go

Lines changed: 71 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
}
@@ -83,11 +86,78 @@ func revisionCmd() *cobra.Command {
8386
revisionCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
8487
revisionCmd.SuggestionsMinimumDistance = 1
8588

86-
addCommonCmdOptions(revisionCmd.Flags())
89+
if !isHelm3() {
90+
addCommonCmdOptions(revisionCmd.Flags())
91+
}
8792

8893
return revisionCmd
8994
}
9095

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

93163
switch len(d.revisions) {

cmd/rollback.go

Lines changed: 45 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
}
@@ -74,11 +78,51 @@ func rollbackCmd() *cobra.Command {
7478
rollbackCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
7579
rollbackCmd.SuggestionsMinimumDistance = 1
7680

77-
addCommonCmdOptions(rollbackCmd.Flags())
81+
if !isHelm3() {
82+
addCommonCmdOptions(rollbackCmd.Flags())
83+
}
7884

7985
return rollbackCmd
8086
}
8187

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

84128
// get manifest of the latest release

0 commit comments

Comments
 (0)