Add ability to use go-getter for fetching remote manifests directory as chart (#1374)

This, in combination with #1172, allows you to use `go-getter`-supported URL for K8s manifests on `chart`, so that Helmfile automatically fetches it and then turning it into a temporary local chart, which is then installed by Helmfile as similar as standard Helm charts.

An example usecase of this is to install cert-manager CRDs which is distributed separately from the chart:

```
releases:
- name: cert-manager-crds
  chart: git::http://github.com/jetstack/cert-manager.git@deploy/crds?ref=v0.15.2
```

I'm adding this based on discussion with @lukasmrtvy. He was trying to install cert-manager and prometheus-opreator with Helmfile, and this combined with #1373 should do the job. Thanks for the input!
This commit is contained in:
KUOKA Yusuke 2020-07-23 00:30:16 +09:00 committed by GitHub
parent 4fde6e13db
commit b5830a3011
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 189 additions and 123 deletions

View File

@ -2373,16 +2373,16 @@ func TestTemplate_SingleStateFile(t *testing.T) {
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: myrelease1 - name: myrelease1
chart: mychart1 chart: stable/mychart1
- name: myrelease2 - name: myrelease2
chart: mychart2 chart: stable/mychart2
`, `,
} }
var helm = &mockHelmExec{} var helm = &mockHelmExec{}
var wantReleases = []mockTemplates{ var wantReleases = []mockTemplates{
{name: "myrelease1", chart: "mychart1", flags: []string{"--namespace", "testNamespace", "--set", "foo=a", "--set", "bar=b", "--output-dir", "output/subdir/helmfile-[a-z0-9]{8}-myrelease1"}}, {name: "myrelease1", chart: "stable/mychart1", flags: []string{"--namespace", "testNamespace", "--set", "foo=a", "--set", "bar=b", "--output-dir", "output/subdir/helmfile-[a-z0-9]{8}-myrelease1"}},
{name: "myrelease2", chart: "mychart2", flags: []string{"--namespace", "testNamespace", "--set", "foo=a", "--set", "bar=b", "--output-dir", "output/subdir/helmfile-[a-z0-9]{8}-myrelease2"}}, {name: "myrelease2", chart: "stable/mychart2", flags: []string{"--namespace", "testNamespace", "--set", "foo=a", "--set", "bar=b", "--output-dir", "output/subdir/helmfile-[a-z0-9]{8}-myrelease2"}},
} }
var buffer bytes.Buffer var buffer bytes.Buffer
@ -2407,7 +2407,9 @@ releases:
valsRuntime: valsRuntime, valsRuntime: valsRuntime,
}, files) }, files)
app.Template(configImpl{set: []string{"foo=a", "bar=b"}}) if err := app.Template(configImpl{set: []string{"foo=a", "bar=b"}}); err != nil {
t.Fatalf("%v", err)
}
for i := range wantReleases { for i := range wantReleases {
if wantReleases[i].name != helm.templated[i].name { if wantReleases[i].name != helm.templated[i].name {
@ -2438,13 +2440,13 @@ apiVersions:
- helmfile.test/v2 - helmfile.test/v2
releases: releases:
- name: myrelease1 - name: myrelease1
chart: mychart1 chart: stable/mychart1
`, `,
} }
var helm = &mockHelmExec{} var helm = &mockHelmExec{}
var wantReleases = []mockTemplates{ var wantReleases = []mockTemplates{
{name: "myrelease1", chart: "mychart1", flags: []string{"--api-versions", "helmfile.test/v1", "--api-versions", "helmfile.test/v2", "--namespace", "testNamespace", "--output-dir", "output/subdir/helmfile-[a-z0-9]{8}-myrelease1"}}, {name: "myrelease1", chart: "stable/mychart1", flags: []string{"--api-versions", "helmfile.test/v1", "--api-versions", "helmfile.test/v2", "--namespace", "testNamespace", "--output-dir", "output/subdir/helmfile-[a-z0-9]{8}-myrelease1"}},
} }
var buffer bytes.Buffer var buffer bytes.Buffer
@ -2469,7 +2471,9 @@ releases:
valsRuntime: valsRuntime, valsRuntime: valsRuntime,
}, files) }, files)
app.Template(configImpl{}) if err := app.Template(configImpl{}); err != nil {
t.Fatalf("%v", err)
}
for i := range wantReleases { for i := range wantReleases {
if wantReleases[i].name != helm.templated[i].name { if wantReleases[i].name != helm.templated[i].name {
@ -2803,16 +2807,16 @@ backend-v1
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
installed: false installed: false
needs: needs:
- bar - bar
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: nil, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: nil,
}, },
lists: map[exectest.ListKey]string{ lists: map[exectest.ListKey]string{
exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: ``, exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: ``,
@ -2833,19 +2837,19 @@ bar 4 Fri Nov 1 08:40:07 2019 DEPLOYED mychart2-3.1.0 3.1.0 defau
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: baz - name: baz
chart: mychart3 chart: stable/mychart3
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
needs: needs:
- bar - bar
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "baz", Chart: "mychart3", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "baz", Chart: "stable/mychart3", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
lists: map[exectest.ListKey]string{}, lists: map[exectest.ListKey]string{},
upgraded: []exectest.Release{ upgraded: []exectest.Release{
@ -2862,13 +2866,13 @@ first-pass rendering output of "helmfile.yaml.part.0":
0: 0:
1: releases: 1: releases:
2: - name: baz 2: - name: baz
3: chart: mychart3 3: chart: stable/mychart3
4: - name: foo 4: - name: foo
5: chart: mychart1 5: chart: stable/mychart1
6: needs: 6: needs:
7: - bar 7: - bar
8: - name: bar 8: - name: bar
9: chart: mychart2 9: chart: stable/mychart2
10: 10:
first-pass produced: &{default map[] map[]} first-pass produced: &{default map[] map[]}
@ -2880,22 +2884,22 @@ second-pass rendering result of "helmfile.yaml.part.0":
0: 0:
1: releases: 1: releases:
2: - name: baz 2: - name: baz
3: chart: mychart3 3: chart: stable/mychart3
4: - name: foo 4: - name: foo
5: chart: mychart1 5: chart: stable/mychart1
6: needs: 6: needs:
7: - bar 7: - bar
8: - name: bar 8: - name: bar
9: chart: mychart2 9: chart: stable/mychart2
10: 10:
merged environment: &{default map[] map[]} merged environment: &{default map[] map[]}
3 release(s) found in helmfile.yaml 3 release(s) found in helmfile.yaml
Affected releases are: Affected releases are:
bar (mychart2) UPDATED bar (stable/mychart2) UPDATED
baz (mychart3) UPDATED baz (stable/mychart3) UPDATED
foo (mychart1) UPDATED foo (stable/mychart1) UPDATED
processing 2 groups of releases in this order: processing 2 groups of releases in this order:
GROUP RELEASES GROUP RELEASES
@ -2909,10 +2913,10 @@ processing releases in group 2/2: foo
getting deployed release version failed:unexpected list key: {^foo$ --kube-contextdefault--deployed--failed--pending} getting deployed release version failed:unexpected list key: {^foo$ --kube-contextdefault--deployed--failed--pending}
UPDATED RELEASES: UPDATED RELEASES:
NAME CHART VERSION NAME CHART VERSION
baz mychart3 baz stable/mychart3
bar mychart2 bar stable/mychart2
foo mychart1 foo stable/mychart1
`, `,
}, },
@ -2926,16 +2930,16 @@ foo mychart1
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
needs: needs:
- bar - bar
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
upgraded: []exectest.Release{ upgraded: []exectest.Release{
{Name: "bar", Flags: []string{}}, {Name: "bar", Flags: []string{}},
@ -2949,16 +2953,16 @@ releases:
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
needs: needs:
- foo - foo
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
upgraded: []exectest.Release{ upgraded: []exectest.Release{
{Name: "foo", Flags: []string{}}, {Name: "foo", Flags: []string{}},
@ -2973,16 +2977,16 @@ releases:
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
needs: needs:
- bar - bar
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--namespacetestNamespace--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--namespacetestNamespace--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--namespacetestNamespace--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--namespacetestNamespace--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
upgraded: []exectest.Release{ upgraded: []exectest.Release{
{Name: "bar", Flags: []string{}}, {Name: "bar", Flags: []string{}},
@ -2997,16 +3001,16 @@ releases:
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
needs: needs:
- foo - foo
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--namespacetestNamespace--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--namespacetestNamespace--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--namespacetestNamespace--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--namespacetestNamespace--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
upgraded: []exectest.Release{ upgraded: []exectest.Release{
{Name: "foo", Flags: []string{}}, {Name: "foo", Flags: []string{}},
@ -3020,18 +3024,18 @@ releases:
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
namespace: ns1 namespace: ns1
needs: needs:
- ns2/bar - ns2/bar
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
namespace: ns2 namespace: ns2
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--namespacens2--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--namespacens2--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
upgraded: []exectest.Release{ upgraded: []exectest.Release{
{Name: "bar", Flags: []string{"--kube-context", "default", "--namespace", "ns2"}}, {Name: "bar", Flags: []string{"--kube-context", "default", "--namespace", "ns2"}},
@ -3045,18 +3049,18 @@ releases:
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
namespace: ns2 namespace: ns2
needs: needs:
- ns1/foo - ns1/foo
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
namespace: ns1 namespace: ns1
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--namespacens2--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--namespacens2--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
upgraded: []exectest.Release{ upgraded: []exectest.Release{
{Name: "foo", Flags: []string{"--kube-context", "default", "--namespace", "ns1"}}, {Name: "foo", Flags: []string{"--kube-context", "default", "--namespace", "ns1"}},
@ -3071,20 +3075,20 @@ releases:
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
namespace: ns1 namespace: ns1
tillerNamespace: tns1 tillerNamespace: tns1
needs: needs:
- tns2/ns2/bar - tns2/ns2/bar
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
namespace: ns2 namespace: ns2
tillerNamespace: tns2 tillerNamespace: tns2
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--tiller-namespacetns2--kube-contextdefault--namespacens2--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--tiller-namespacetns2--kube-contextdefault--namespacens2--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--tiller-namespacetns1--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--tiller-namespacetns1--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
upgraded: []exectest.Release{ upgraded: []exectest.Release{
{Name: "bar", Flags: []string{"--tiller-namespace", "tns2", "--kube-context", "default", "--namespace", "ns2"}}, {Name: "bar", Flags: []string{"--tiller-namespace", "tns2", "--kube-context", "default", "--namespace", "ns2"}},
@ -3098,20 +3102,20 @@ releases:
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
namespace: ns2 namespace: ns2
tillerNamespace: tns2 tillerNamespace: tns2
needs: needs:
- tns1/ns1/foo - tns1/ns1/foo
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
namespace: ns1 namespace: ns1
tillerNamespace: tns1 tillerNamespace: tns1
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--tiller-namespacetns2--kube-contextdefault--namespacens2--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--tiller-namespacetns2--kube-contextdefault--namespacens2--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--tiller-namespacetns1--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--tiller-namespacetns1--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
upgraded: []exectest.Release{ upgraded: []exectest.Release{
{Name: "foo", Flags: []string{"--tiller-namespace", "tns1", "--kube-context", "default", "--namespace", "ns1"}}, {Name: "foo", Flags: []string{"--tiller-namespace", "tns1", "--kube-context", "default", "--namespace", "ns1"}},
@ -3126,13 +3130,13 @@ first-pass rendering output of "helmfile.yaml.part.0":
0: 0:
1: releases: 1: releases:
2: - name: bar 2: - name: bar
3: chart: mychart2 3: chart: stable/mychart2
4: namespace: ns2 4: namespace: ns2
5: tillerNamespace: tns2 5: tillerNamespace: tns2
6: needs: 6: needs:
7: - tns1/ns1/foo 7: - tns1/ns1/foo
8: - name: foo 8: - name: foo
9: chart: mychart1 9: chart: stable/mychart1
10: namespace: ns1 10: namespace: ns1
11: tillerNamespace: tns1 11: tillerNamespace: tns1
12: 12:
@ -3146,13 +3150,13 @@ second-pass rendering result of "helmfile.yaml.part.0":
0: 0:
1: releases: 1: releases:
2: - name: bar 2: - name: bar
3: chart: mychart2 3: chart: stable/mychart2
4: namespace: ns2 4: namespace: ns2
5: tillerNamespace: tns2 5: tillerNamespace: tns2
6: needs: 6: needs:
7: - tns1/ns1/foo 7: - tns1/ns1/foo
8: - name: foo 8: - name: foo
9: chart: mychart1 9: chart: stable/mychart1
10: namespace: ns1 10: namespace: ns1
11: tillerNamespace: tns1 11: tillerNamespace: tns1
12: 12:
@ -3161,8 +3165,8 @@ merged environment: &{default map[] map[]}
2 release(s) found in helmfile.yaml 2 release(s) found in helmfile.yaml
Affected releases are: Affected releases are:
bar (mychart2) UPDATED bar (stable/mychart2) UPDATED
foo (mychart1) UPDATED foo (stable/mychart1) UPDATED
processing 2 groups of releases in this order: processing 2 groups of releases in this order:
GROUP RELEASES GROUP RELEASES
@ -3175,9 +3179,9 @@ processing releases in group 2/2: tns2/ns2/bar
getting deployed release version failed:unexpected list key: {^bar$ --tiller-namespacetns2--kube-contextdefault--deployed--failed--pending} getting deployed release version failed:unexpected list key: {^bar$ --tiller-namespacetns2--kube-contextdefault--deployed--failed--pending}
UPDATED RELEASES: UPDATED RELEASES:
NAME CHART VERSION NAME CHART VERSION
foo mychart1 foo stable/mychart1
bar mychart2 bar stable/mychart2
`, `,
}, },
@ -3191,18 +3195,18 @@ bar mychart2
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
installed: false installed: false
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
installed: false installed: false
needs: needs:
- bar - bar
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
lists: map[exectest.ListKey]string{ lists: map[exectest.ListKey]string{
exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
@ -3224,18 +3228,18 @@ bar 4 Fri Nov 1 08:40:07 2019 DEPLOYED mychart2-3.1.0 3.1.0 defau
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
installed: false installed: false
needs: needs:
- foo - foo
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
installed: false installed: false
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
lists: map[exectest.ListKey]string{ lists: map[exectest.ListKey]string{
exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
@ -3260,17 +3264,17 @@ bar 4 Fri Nov 1 08:40:07 2019 DEPLOYED mychart2-3.1.0 3.1.0 defau
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
installed: false installed: false
needs: needs:
- bar - bar
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
lists: map[exectest.ListKey]string{ lists: map[exectest.ListKey]string{
exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
@ -3294,17 +3298,17 @@ bar 4 Fri Nov 1 08:40:07 2019 DEPLOYED mychart2-3.1.0 3.1.0 defau
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
installed: false installed: false
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
needs: needs:
- bar - bar
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
lists: map[exectest.ListKey]string{ lists: map[exectest.ListKey]string{
exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
@ -3328,17 +3332,17 @@ bar 4 Fri Nov 1 08:40:07 2019 DEPLOYED mychart2-3.1.0 3.1.0 defau
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
installed: false installed: false
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
needs: needs:
- foo - foo
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
lists: map[exectest.ListKey]string{ lists: map[exectest.ListKey]string{
exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
@ -3362,17 +3366,17 @@ bar 4 Fri Nov 1 08:40:07 2019 DEPLOYED mychart2-3.1.0 3.1.0 defau
"/path/to/helmfile.yaml": ` "/path/to/helmfile.yaml": `
releases: releases:
- name: foo - name: foo
chart: mychart1 chart: stable/mychart1
- name: bar - name: bar
chart: mychart2 chart: stable/mychart2
installed: false installed: false
needs: needs:
- foo - foo
`, `,
}, },
diffs: map[exectest.DiffKey]error{ diffs: map[exectest.DiffKey]error{
exectest.DiffKey{Name: "bar", Chart: "mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "bar", Chart: "stable/mychart2", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2}, exectest.DiffKey{Name: "foo", Chart: "stable/mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
}, },
lists: map[exectest.ListKey]string{ lists: map[exectest.ListKey]string{
exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE exectest.ListKey{Filter: "^foo$", Flags: "--kube-contextdefault--deployed--failed--pending"}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE

View File

@ -1,7 +1,9 @@
package state package state
import ( import (
"fmt"
"github.com/roboll/helmfile/pkg/helmexec" "github.com/roboll/helmfile/pkg/helmexec"
"github.com/roboll/helmfile/pkg/remote"
"github.com/variantdev/chartify" "github.com/variantdev/chartify"
"os" "os"
"path/filepath" "path/filepath"
@ -22,20 +24,66 @@ func (st *HelmState) appendHelmXFlags(flags []string, release *ReleaseSpec) ([]s
return flags, nil return flags, nil
} }
func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSpec, workerIndex int) (bool, *chartify.ChartifyOpts, func(), error) { func fileExistsAt(path string) bool {
var opts chartify.ChartifyOpts fileInfo, err := os.Stat(path)
return err == nil && fileInfo.Mode().IsRegular()
}
opts.WorkaroundOutputDirIssue = true func directoryExistsAt(path string) bool {
fileInfo, err := os.Stat(path)
return err == nil && fileInfo.Mode().IsDir()
}
type Chartify struct {
Opts *chartify.ChartifyOpts
Chart string
Clean func()
}
func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSpec, workerIndex int) (*Chartify, func(), error) {
chartify := &Chartify{
Opts: &chartify.ChartifyOpts{
WorkaroundOutputDirIssue: true,
EnableKustomizeAlphaPlugins: true,
ChartVersion: release.Version,
Namespace: release.Namespace,
},
}
var filesNeedCleaning []string
clean := func() {
st.removeFiles(filesNeedCleaning)
}
var shouldRun bool var shouldRun bool
opts.EnableKustomizeAlphaPlugins = true chart := release.Chart
if release.Directory != "" && chart == "" {
chart = release.Directory
}
opts.ChartVersion = release.Version _, err := remote.Parse(chart)
if err != nil {
if release.ForceGoGetter {
return nil, clean, fmt.Errorf("Parsing url from directory of release %q failed due to error %q.\nContinuing the process assuming this is a regular Helm chart or a local directory.", release.Name, err.Error())
}
} else {
r := remote.NewRemote(st.logger, st.basePath, st.readFile, directoryExistsAt, fileExistsAt)
opts.Namespace = release.Namespace fetchedDir, err := r.Fetch(chart)
if err != nil {
return nil, clean, fmt.Errorf("fetching %q: %v", chart, err)
}
dir := filepath.Join(st.basePath, release.Chart) chart = fetchedDir
filesNeedCleaning = append(filesNeedCleaning, fetchedDir)
}
chartify.Chart = chart
dir := filepath.Join(st.basePath, chart)
if stat, _ := os.Stat(dir); stat != nil && stat.IsDir() { if stat, _ := os.Stat(dir); stat != nil && stat.IsDir() {
if exists, err := st.fileExists(filepath.Join(dir, "Chart.yaml")); err == nil && !exists { if exists, err := st.fileExists(filepath.Join(dir, "Chart.yaml")); err == nil && !exists {
shouldRun = true shouldRun = true
@ -61,28 +109,22 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp
dep += ":" + d.Version dep += ":" + d.Version
} }
opts.AdhocChartDependencies = append(opts.AdhocChartDependencies, dep) chartify.Opts.AdhocChartDependencies = append(chartify.Opts.AdhocChartDependencies, dep)
shouldRun = true shouldRun = true
} }
var filesNeedCleaning []string
clean := func() {
st.removeFiles(filesNeedCleaning)
}
jsonPatches := release.JSONPatches jsonPatches := release.JSONPatches
if len(jsonPatches) > 0 { if len(jsonPatches) > 0 {
generatedFiles, err := st.generateTemporaryValuesFiles(jsonPatches, release.MissingFileHandler) generatedFiles, err := st.generateTemporaryValuesFiles(jsonPatches, release.MissingFileHandler)
if err != nil { if err != nil {
return false, nil, clean, err return nil, clean, err
} }
filesNeedCleaning = append(filesNeedCleaning, generatedFiles...) filesNeedCleaning = append(filesNeedCleaning, generatedFiles...)
for _, f := range generatedFiles { for _, f := range generatedFiles {
opts.JsonPatches = append(opts.JsonPatches, f) chartify.Opts.JsonPatches = append(chartify.Opts.JsonPatches, f)
} }
shouldRun = true shouldRun = true
@ -92,11 +134,11 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp
if len(strategicMergePatches) > 0 { if len(strategicMergePatches) > 0 {
generatedFiles, err := st.generateTemporaryValuesFiles(strategicMergePatches, release.MissingFileHandler) generatedFiles, err := st.generateTemporaryValuesFiles(strategicMergePatches, release.MissingFileHandler)
if err != nil { if err != nil {
return false, nil, clean, err return nil, clean, err
} }
for _, f := range generatedFiles { for _, f := range generatedFiles {
opts.StrategicMergePatches = append(opts.StrategicMergePatches, f) chartify.Opts.StrategicMergePatches = append(chartify.Opts.StrategicMergePatches, f)
} }
filesNeedCleaning = append(filesNeedCleaning, generatedFiles...) filesNeedCleaning = append(filesNeedCleaning, generatedFiles...)
@ -107,13 +149,15 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp
if shouldRun { if shouldRun {
generatedFiles, err := st.generateValuesFiles(helm, release, workerIndex) generatedFiles, err := st.generateValuesFiles(helm, release, workerIndex)
if err != nil { if err != nil {
return false, nil, clean, err return nil, clean, err
} }
filesNeedCleaning = append(filesNeedCleaning, generatedFiles...) filesNeedCleaning = append(filesNeedCleaning, generatedFiles...)
opts.ValuesFiles = generatedFiles chartify.Opts.ValuesFiles = generatedFiles
return chartify, clean, nil
} }
return shouldRun, &opts, clean, nil return nil, clean, nil
} }

View File

@ -150,9 +150,15 @@ type RepositorySpec struct {
// ReleaseSpec defines the structure of a helm release // ReleaseSpec defines the structure of a helm release
type ReleaseSpec struct { type ReleaseSpec struct {
// Chart is the name of the chart being installed to create this release // Chart is the name of the chart being installed to create this release
Chart string `yaml:"chart,omitempty"` Chart string `yaml:"chart,omitempty"`
// Directory is an alias to Chart which may be of more fit when you want to use a local/remote directory containing
// K8s manifests or Kustomization as a chart
Directory string `yaml:"directory,omitempty"`
// Version is the semver version or version constraint for the chart
Version string `yaml:"version,omitempty"` Version string `yaml:"version,omitempty"`
Verify *bool `yaml:"verify,omitempty"` // Verify enables signature verification on fetched chart.
// Beware some (or many?) chart repositories and charts don't seem to support it.
Verify *bool `yaml:"verify,omitempty"`
// Devel, when set to true, use development versions, too. Equivalent to version '>0.0.0-0' // Devel, when set to true, use development versions, too. Equivalent to version '>0.0.0-0'
Devel *bool `yaml:"devel,omitempty"` Devel *bool `yaml:"devel,omitempty"`
// Wait, if set to true, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful // Wait, if set to true, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful
@ -237,6 +243,13 @@ type ReleaseSpec struct {
//version of the chart that has really been installed cause desired version may be fuzzy (~2.0.0) //version of the chart that has really been installed cause desired version may be fuzzy (~2.0.0)
installedVersion string installedVersion string
// ForceGoGetter forces the use of go-getter for fetching remote directory as maniefsts/chart/kustomization
// by parsing the url from `chart` field of the release.
// This is handy when getting the go-getter url parsing error when it doesn't work as expected.
// Without this, any error in url parsing result in silently falling-back to normal process of treating `chart:` as the regular
// helm chart name.
ForceGoGetter bool `yaml:"forceGoGetter,omitempty"`
} }
type Release struct { type Release struct {
@ -534,6 +547,7 @@ func (st *HelmState) DeleteReleasesForSync(affectedReleases *AffectedReleases, h
} }
deletionFlags := st.appendConnectionFlags(args, release) deletionFlags := st.appendConnectionFlags(args, release)
m.Lock() m.Lock()
if err := helm.DeleteRelease(context, release.Name, deletionFlags...); err != nil { if err := helm.DeleteRelease(context, release.Name, deletionFlags...); err != nil {
affectedReleases.Failed = append(affectedReleases.Failed, release) affectedReleases.Failed = append(affectedReleases.Failed, release)
relErr = newReleaseFailedError(release, err) relErr = newReleaseFailedError(release, err)
@ -638,6 +652,7 @@ func (st *HelmState) SyncReleases(affectedReleases *AffectedReleases, helm helme
} }
deletionFlags := st.appendConnectionFlags(args, release) deletionFlags := st.appendConnectionFlags(args, release)
m.Lock() m.Lock()
if err := helm.DeleteRelease(context, release.Name, deletionFlags...); err != nil { if err := helm.DeleteRelease(context, release.Name, deletionFlags...); err != nil {
affectedReleases.Failed = append(affectedReleases.Failed, release) affectedReleases.Failed = append(affectedReleases.Failed, release)
relErr = newReleaseFailedError(release, err) relErr = newReleaseFailedError(release, err)
@ -745,6 +760,7 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
chartPath string chartPath string
err error err error
} }
errs := []error{} errs := []error{}
jobQueue := make(chan *ReleaseSpec, len(st.Releases)) jobQueue := make(chan *ReleaseSpec, len(st.Releases))
@ -769,22 +785,23 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
for release := range jobQueue { for release := range jobQueue {
var chartPath string var chartPath string
shouldChartify, opts, clean, err := st.PrepareChartify(helm, release, workerIndex) chartification, clean, err := st.PrepareChartify(helm, release, workerIndex)
defer clean() defer clean()
if err != nil { if err != nil {
results <- &downloadResults{err: err} results <- &downloadResults{err: err}
return return
} }
if shouldChartify { if chartification != nil {
c := chartify.New( c := chartify.New(
chartify.HelmBin(st.DefaultHelmBinary), chartify.HelmBin(st.DefaultHelmBinary),
chartify.UseHelm3(helm3), chartify.UseHelm3(helm3),
) )
out, err := c.Chartify(release.Name, release.Chart, chartify.WithChartifyOpts(opts)) out, err := c.Chartify(release.Name, chartification.Chart, chartify.WithChartifyOpts(chartification.Opts))
if err != nil { if err != nil {
errs = append(errs, err) results <- &downloadResults{err: err}
return
} else { } else {
// TODO Chartify // TODO Chartify
chartPath = out chartPath = out
@ -810,7 +827,8 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
if _, err := os.Stat(chartPath); os.IsNotExist(err) { if _, err := os.Stat(chartPath); os.IsNotExist(err) {
fetchFlags = append(fetchFlags, "--untar", "--untardir", chartPath) fetchFlags = append(fetchFlags, "--untar", "--untardir", chartPath)
if err := helm.Fetch(release.Chart, fetchFlags...); err != nil { if err := helm.Fetch(release.Chart, fetchFlags...); err != nil {
errs = append(errs, err) results <- &downloadResults{err: err}
return
} }
} }
// Set chartPath to be the path containing Chart.yaml, if found // Set chartPath to be the path containing Chart.yaml, if found