From 8129e2ac72a52a242132a99db81de00df7ab01b8 Mon Sep 17 00:00:00 2001 From: Blake Pettersson Date: Wed, 23 Apr 2025 23:16:23 +0200 Subject: [PATCH] feat: add kube version option for `helm install` This is to make `helm install --dry-run` consistent with `helm template`. `helm template` can set `kube-version`, `helm install` up until now could not. In order for this to work as intended, we also need to set `client.clientOnly`. This could not be set before due to backwards compatability concerns but for v4 this should be fine. Related to #12740. Signed-off-by: Blake Pettersson --- pkg/cmd/install.go | 18 +++ pkg/cmd/install_test.go | 5 + .../install-dry-run-with-kube-version.txt | 125 ++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 pkg/cmd/testdata/output/install-dry-run-with-kube-version.txt diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go index e35df7801..214aa8b8b 100644 --- a/pkg/cmd/install.go +++ b/pkg/cmd/install.go @@ -31,6 +31,8 @@ import ( "github.com/spf13/cobra" "github.com/spf13/pflag" + chartutil "helm.sh/helm/v4/pkg/chart/v2/util" + "helm.sh/helm/v4/pkg/action" chart "helm.sh/helm/v4/pkg/chart/v2" "helm.sh/helm/v4/pkg/chart/v2/loader" @@ -134,6 +136,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewInstall(cfg) valueOpts := &values.Options{} var outfmt output.Format + var kubeVersion string cmd := &cobra.Command{ Use: "install [NAME] [CHART]", @@ -144,6 +147,14 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return compInstall(args, toComplete, client) }, RunE: func(_ *cobra.Command, args []string) error { + if kubeVersion != "" { + parsedKubeVersion, err := chartutil.ParseKubeVersion(kubeVersion) + if err != nil { + return fmt.Errorf("invalid kube version '%s': %s", kubeVersion, err) + } + client.KubeVersion = parsedKubeVersion + } + registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password) if err != nil { @@ -157,6 +168,12 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { if client.DryRunOption == "" { client.DryRunOption = "none" } + + // If the user has set the dry-run option to client, we'll enforce that this indeed runs only on the client + if client.DryRunOption == "client" { + client.ClientOnly = true + } + rel, err := runInstall(args, client, valueOpts, out) if err != nil { return errors.Wrap(err, "INSTALLATION FAILED") @@ -176,6 +193,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { // it is added separately f := cmd.Flags() f.BoolVar(&client.HideSecret, "hide-secret", false, "hide Kubernetes Secrets when also using the --dry-run flag") + f.StringVar(&kubeVersion, "kube-version", "", "Kubernetes version used for Capabilities.KubeVersion when also using the --dry-run flag") bindOutputFlag(cmd, &outfmt) bindPostRenderFlag(cmd, &client.PostRenderer) diff --git a/pkg/cmd/install_test.go b/pkg/cmd/install_test.go index 9cd244e84..53ea5cfab 100644 --- a/pkg/cmd/install_test.go +++ b/pkg/cmd/install_test.go @@ -274,6 +274,11 @@ func TestInstall(t *testing.T) { wantError: true, golden: "output/install-hide-secret.txt", }, + { + name: "check kube version with dry-run", + cmd: "install secrets testdata/testcharts/subchart --dry-run --kube-version 1.16.0", + golden: "output/install-dry-run-with-kube-version.txt", + }, } runTestCmd(t, tests) diff --git a/pkg/cmd/testdata/output/install-dry-run-with-kube-version.txt b/pkg/cmd/testdata/output/install-dry-run-with-kube-version.txt new file mode 100644 index 000000000..f6152f134 --- /dev/null +++ b/pkg/cmd/testdata/output/install-dry-run-with-kube-version.txt @@ -0,0 +1,125 @@ +NAME: secrets +LAST DEPLOYED: Fri Sep 2 22:04:05 1977 +NAMESPACE: default +STATUS: pending-install +REVISION: 1 +DESCRIPTION: Dry run complete +HOOKS: +--- +# Source: subchart/templates/tests/test-config.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: "secrets-testconfig" + annotations: + "helm.sh/hook": test +data: + message: Hello World +--- +# Source: subchart/templates/tests/test-nothing.yaml +apiVersion: v1 +kind: Pod +metadata: + name: "secrets-test" + annotations: + "helm.sh/hook": test +spec: + containers: + - name: test + image: "alpine:latest" + envFrom: + - configMapRef: + name: "secrets-testconfig" + command: + - echo + - "$message" + restartPolicy: Never +MANIFEST: +--- +# Source: subchart/templates/subdir/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: subchart-sa +--- +# Source: subchart/templates/subdir/role.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: subchart-role +rules: +- apiGroups: [""] + resources: ["pods"] + verbs: ["get","list","watch"] +--- +# Source: subchart/templates/subdir/rolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: subchart-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: subchart-role +subjects: +- kind: ServiceAccount + name: subchart-sa + namespace: default +--- +# Source: subchart/charts/subcharta/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: subcharta + labels: + helm.sh/chart: "subcharta-0.1.0" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: apache + selector: + app.kubernetes.io/name: subcharta +--- +# Source: subchart/charts/subchartb/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: subchartb + labels: + helm.sh/chart: "subchartb-0.1.0" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: nginx + selector: + app.kubernetes.io/name: subchartb +--- +# Source: subchart/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: subchart + labels: + helm.sh/chart: "subchart-0.1.0" + app.kubernetes.io/instance: "secrets" + kube-version/major: "1" + kube-version/minor: "16" + kube-version/version: "v1.16.0" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: nginx + selector: + app.kubernetes.io/name: subchart + +NOTES: +Sample notes for subchart