From 4a1376ddbeb011e03b90bb56ac429faa0adafc25 Mon Sep 17 00:00:00 2001 From: crmendes Date: Tue, 25 Jan 2022 16:32:14 +0000 Subject: [PATCH 1/5] HOOKS section should also be parsed when HELM_DIFF_USE_UPGRADE_DRY_RUN=true --- cmd/helm3.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmd/helm3.go b/cmd/helm3.go index cc8fc288..9ef12bce 100644 --- a/cmd/helm3.go +++ b/cmd/helm3.go @@ -175,14 +175,20 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) { return s } - i := bytes.Index(s, []byte("MANIFEST:")) + i := bytes.Index(s, []byte("HOOKS:")) s = s[i:] i = bytes.Index(s, []byte("---")) s = s[i:] + + i = bytes.Index(s, []byte("MANIFEST:")) + j := bytes.Index(s[i:], []byte("---")) + s = append(s[:i], s[i:][j:]...) + i = bytes.Index(s, []byte("\nNOTES:")) if i != -1 { s = s[:i+1] } + return s } } else { From 2d6e3e6d36dd81f9edffdc38c5fbe57b4a80432f Mon Sep 17 00:00:00 2001 From: crmendes Date: Thu, 27 Jan 2022 14:30:48 +0000 Subject: [PATCH 2/5] fix for charts that don't have any hooks --- cmd/helm3.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd/helm3.go b/cmd/helm3.go index 9ef12bce..f3c34cf7 100644 --- a/cmd/helm3.go +++ b/cmd/helm3.go @@ -177,12 +177,16 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) { i := bytes.Index(s, []byte("HOOKS:")) s = s[i:] + i = bytes.Index(s, []byte("---")) s = s[i:] i = bytes.Index(s, []byte("MANIFEST:")) - j := bytes.Index(s[i:], []byte("---")) - s = append(s[:i], s[i:][j:]...) + + if i > -1 { + j := bytes.Index(s[i:], []byte("---")) + s = append(s[:i], s[i:][j:]...) + } i = bytes.Index(s, []byte("\nNOTES:")) if i != -1 { From a50d670facb1c84870a2d19b192e2af16a1e4f24 Mon Sep 17 00:00:00 2001 From: crmendes Date: Thu, 27 Jan 2022 14:47:48 +0000 Subject: [PATCH 3/5] change condition operator on if statement --- cmd/helm3.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm3.go b/cmd/helm3.go index f3c34cf7..5b6208a5 100644 --- a/cmd/helm3.go +++ b/cmd/helm3.go @@ -183,7 +183,7 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) { i = bytes.Index(s, []byte("MANIFEST:")) - if i > -1 { + if i != -1 { j := bytes.Index(s[i:], []byte("---")) s = append(s[:i], s[i:][j:]...) } From 9a750c58d10e6ad8d797024390ab3eae37649085 Mon Sep 17 00:00:00 2001 From: crmendes Date: Fri, 28 Jan 2022 15:27:13 +0000 Subject: [PATCH 4/5] fix sections extract if only HOOKS sections is present --- cmd/helm3.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmd/helm3.go b/cmd/helm3.go index 5b6208a5..c45ec03c 100644 --- a/cmd/helm3.go +++ b/cmd/helm3.go @@ -177,17 +177,18 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) { i := bytes.Index(s, []byte("HOOKS:")) s = s[i:] - i = bytes.Index(s, []byte("---")) s = s[i:] - i = bytes.Index(s, []byte("MANIFEST:")) - if i != -1 { j := bytes.Index(s[i:], []byte("---")) - s = append(s[:i], s[i:][j:]...) - } + if j != -1 { + s = append(s[:i], s[i:][j:]...) + } else { + s = s[:i] + } + } i = bytes.Index(s, []byte("\nNOTES:")) if i != -1 { s = s[:i+1] From 3d4ced1d25945f29fac8cb11dc39b8b319ed0e65 Mon Sep 17 00:00:00 2001 From: Yusuke Kuoka Date: Sun, 13 Feb 2022 02:41:26 +0000 Subject: [PATCH 5/5] fixup! fix sections extract if only HOOKS sections is present --- cmd/helm3.go | 69 ++++++++++++++--------- cmd/helm3_test.go | 137 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 25 deletions(-) create mode 100644 cmd/helm3_test.go diff --git a/cmd/helm3.go b/cmd/helm3.go index c45ec03c..8c147010 100644 --- a/cmd/helm3.go +++ b/cmd/helm3.go @@ -87,7 +87,7 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) { if d.devel { flags = append(flags, "--devel") } - if d.noHooks { + if d.noHooks && !d.useUpgradeDryRun { flags = append(flags, "--no-hooks") } if d.chartVersion != "" { @@ -171,30 +171,7 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) { flags = append(flags, "--dry-run") subcmd = "upgrade" filter = func(s []byte) []byte { - if len(s) == 0 { - return s - } - - i := bytes.Index(s, []byte("HOOKS:")) - s = s[i:] - i = bytes.Index(s, []byte("---")) - s = s[i:] - i = bytes.Index(s, []byte("MANIFEST:")) - if i != -1 { - j := bytes.Index(s[i:], []byte("---")) - - if j != -1 { - s = append(s[:i], s[i:][j:]...) - } else { - s = s[:i] - } - } - i = bytes.Index(s, []byte("\nNOTES:")) - if i != -1 { - s = s[:i+1] - } - - return s + return extractManifestFromHelmUpgradeDryRunOutput(s, d.noHooks) } } else { if !d.disableValidation && !d.dryRun { @@ -231,3 +208,45 @@ func (d *diffCmd) writeExistingValues(f *os.File) error { cmd.Stdout = f return cmd.Run() } + +func extractManifestFromHelmUpgradeDryRunOutput(s []byte, noHooks bool) []byte { + if len(s) == 0 { + return s + } + + i := bytes.Index(s, []byte("HOOKS:")) + hooks := s[i:] + + j := bytes.Index(hooks, []byte("MANIFEST:")) + + manifest := hooks[j:] + hooks = hooks[:j] + + k := bytes.Index(manifest, []byte("\nNOTES:")) + + if k > -1 { + manifest = manifest[:k+1] + } + + if noHooks { + hooks = nil + } else { + a := bytes.Index(hooks, []byte("---")) + if a > -1 { + hooks = hooks[a:] + } else { + hooks = nil + } + } + + a := bytes.Index(manifest, []byte("---")) + if a > -1 { + manifest = manifest[a:] + } + + r := []byte{} + r = append(r, manifest...) + r = append(r, hooks...) + + return r +} diff --git a/cmd/helm3_test.go b/cmd/helm3_test.go new file mode 100644 index 00000000..bd11e086 --- /dev/null +++ b/cmd/helm3_test.go @@ -0,0 +1,137 @@ +package cmd + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestExtractManifestFromHelmUpgradeDryRunOutput(t *testing.T) { + type testdata struct { + description string + + s string + noHooks bool + + want string + } + + manifest := `--- +# Source: mysql/templates/secrets.yaml +apiVersion: v1 +kind: Secret +metadata: + name: my1-mysql + namespace: default + labels: + app: my1-mysql + chart: "mysql-1.6.9" + release: "my1" + heritage: "Helm" +type: Opaque +data: + mysql-root-password: "ZlhEVGJseUhmeg==" + mysql-password: "YnRuU3pPOTJMVg==" +--- +# Source: mysql/templates/tests/test-configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: my1-mysql-test + namespace: default + labels: + app: my1-mysql + chart: "mysql-1.6.9" + heritage: "Helm" + release: "my1" +data: + run.sh: |- + +` + hooks := `--- +# Source: mysql/templates/tests/test.yaml +apiVersion: v1 +kind: Pod +metadata: + name: my1-mysql-test + namespace: default + labels: + app: my1-mysql + chart: "mysql-1.6.9" + heritage: "Helm" + release: "my1" + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: my1-test + image: "bats/bats:1.2.1" + imagePullPolicy: "IfNotPresent" + command: ["/opt/bats/bin/bats", "-t", "/tests/run.sh"] +` + + header := `Release "my1" has been upgraded. Happy Helming! +NAME: my1 +LAST DEPLOYED: Sun Feb 13 02:26:16 2022 +NAMESPACE: default +STATUS: pending-upgrade +REVISION: 2 +HOOKS: +` + + notes := `NOTES: +MySQL can be accessed via port 3306 on the following DNS name from within your cluster: +my1-mysql.default.svc.cluster.local + +*snip* + +To connect to your database directly from outside the K8s cluster: + MYSQL_HOST=127.0.0.1 + MYSQL_PORT=3306 + + # Execute the following command to route the connection: + kubectl port-forward svc/my1-mysql 3306 + + mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD} +` + + outputWithHooks := header + hooks + "MANIFEST:\n" + manifest + notes + outputWithNoHooks := header + "MANIFEST:\n" + manifest + notes + + testcases := []testdata{ + { + description: "should output manifest when noHooks specified", + s: outputWithHooks, + noHooks: true, + want: manifest, + }, + { + description: "should output manifest and hooks when noHooks unspecified", + s: outputWithHooks, + noHooks: false, + want: manifest + hooks, + }, + { + description: "should output manifest if noHooks specified but input did not contain hooks", + s: outputWithNoHooks, + noHooks: true, + want: manifest, + }, + { + description: "should output manifest if noHooks unspecified and input did not contain hooks", + s: outputWithNoHooks, + noHooks: false, + want: manifest, + }, + } + + for _, tc := range testcases { + t.Run(tc.description, func(t *testing.T) { + got := extractManifestFromHelmUpgradeDryRunOutput([]byte(tc.s), tc.noHooks) + + if d := cmp.Diff(tc.want, string(got)); d != "" { + t.Errorf("unexpected diff: %s", d) + } + }) + } +}