fix(template): add helpful hint to kubeVersion error when using defaults

On Slack a user reported that he didn't understand why `helm template`
was reporting v1.20.0. He had no Kubernetes cluster connection. This is
because we fallback on default Kube version in capabilities.go.

This change tracks whether the KubeVersion is a default fallback and
adds a helpful hint to the error message only when the default is used
(not when users explicitly set --kube-version).

Before:
```
Error: chart requires kubeVersion: >= 1.28.0-0 which is incompatible with Kubernetes v1.20.0
```

After (with default):
```
Error: chart requires kubeVersion: >= 1.28.0-0 which is incompatible with Kubernetes v1.20.0 (no cluster connected, using default version; specify target version with --kube-version)
```

After (with explicit --kube-version 1.27.0):
```
Error: chart requires kubeVersion: >= 1.28.0-0 which is incompatible with Kubernetes v1.27.0
```

Testing:
```sh
$ bin/helm template test-release /tmp/test-chart
Error: chart requires kubeVersion: >= 1.28.0-0 which is incompatible with Kubernetes v1.20.0 (no cluster connected, using default version; specify target version with --kube-version)

$ bin/helm template test-release /tmp/test-chart --kube-version 1.27.0
Error: chart requires kubeVersion: >= 1.28.0-0 which is incompatible with Kubernetes v1.27.0

$ bin/helm template test-release /tmp/test-chart --kube-version 1.20.0
Error: chart requires kubeVersion: >= 1.28.0-0 which is incompatible with Kubernetes v1.20.0

$ bin/helm template test-release /tmp/test-chart --kube-version 1.28.0
---
apiVersion: v1
kind: ConfigMap
...
```

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>
pull/31501/head
Benoit Tigeot 11 months ago
parent 1da2b0a6d4
commit 0f92ef3379
No known key found for this signature in database
GPG Key ID: 8E6D4FC8AEBDA62C

@ -204,7 +204,11 @@ func (cfg *Configuration) renderResources(ch *chart.Chart, values common.Values,
if ch.Metadata.KubeVersion != "" {
if !chartutil.IsCompatibleRange(ch.Metadata.KubeVersion, caps.KubeVersion.String()) {
return hs, b, "", fmt.Errorf("chart requires kubeVersion: %s which is incompatible with Kubernetes %s", ch.Metadata.KubeVersion, caps.KubeVersion.String())
errMsg := fmt.Sprintf("chart requires kubeVersion: %s which is incompatible with Kubernetes %s", ch.Metadata.KubeVersion, caps.KubeVersion.String())
if caps.IsDefaultKubeVersion {
errMsg += " (no cluster connected, using default version; specify target version with --kube-version)"
}
return hs, b, "", fmt.Errorf("%s", errMsg)
}
}
@ -383,15 +387,14 @@ func (cfg *Configuration) getCapabilities() (*common.Capabilities, error) {
}
}
cfg.Capabilities = &common.Capabilities{
APIVersions: apiVersions,
KubeVersion: common.KubeVersion{
cfg.Capabilities = common.NewCapabilitiesFromCluster(
common.KubeVersion{
Version: kubeVersion.GitVersion,
Major: kubeVersion.Major,
Minor: kubeVersion.Minor,
},
HelmVersion: common.DefaultCapabilities.HelmVersion,
}
apiVersions,
)
return cfg.Capabilities, nil
}

@ -304,7 +304,7 @@ func (i *Install) RunWithContext(ctx context.Context, ch ci.Charter, vals map[st
// NOTE(bacongobbler): used for `helm template`
i.cfg.Capabilities = common.DefaultCapabilities.Copy()
if i.KubeVersion != nil {
i.cfg.Capabilities.KubeVersion = *i.KubeVersion
i.cfg.Capabilities = i.cfg.Capabilities.WithKubeVersion(*i.KubeVersion)
}
i.cfg.Capabilities.APIVersions = append(i.cfg.Capabilities.APIVersions, i.APIVersions...)
i.cfg.KubeClient = &kubefake.PrintingKubeClient{Out: io.Discard}

@ -45,8 +45,9 @@ var (
Major: k8sVersionMajor,
Minor: k8sVersionMinor,
},
APIVersions: DefaultVersionSet,
HelmVersion: helmversion.Get(),
APIVersions: DefaultVersionSet,
HelmVersion: helmversion.Get(),
IsDefaultKubeVersion: true,
}
)
@ -58,13 +59,37 @@ type Capabilities struct {
APIVersions VersionSet
// HelmVersion is the build information for this helm version
HelmVersion helmversion.BuildInfo
// IsDefaultKubeVersion indicates if KubeVersion is a default fallback value
// (not from a real cluster or user-provided --kube-version flag)
IsDefaultKubeVersion bool
}
func (capabilities *Capabilities) Copy() *Capabilities {
return &Capabilities{
KubeVersion: capabilities.KubeVersion,
APIVersions: capabilities.APIVersions,
HelmVersion: capabilities.HelmVersion,
KubeVersion: capabilities.KubeVersion,
APIVersions: capabilities.APIVersions,
HelmVersion: capabilities.HelmVersion,
IsDefaultKubeVersion: capabilities.IsDefaultKubeVersion,
}
}
// WithKubeVersion returns a copy of Capabilities with a custom KubeVersion.
// Sets IsDefaultKubeVersion to false since this is an explicit override.
func (capabilities *Capabilities) WithKubeVersion(kv KubeVersion) *Capabilities {
c := capabilities.Copy()
c.KubeVersion = kv
c.IsDefaultKubeVersion = false
return c
}
// NewCapabilitiesFromCluster creates a Capabilities from cluster discovery information.
// IsDefaultKubeVersion is set to false since this comes from a real cluster.
func NewCapabilitiesFromCluster(kubeVersion KubeVersion, apiVersions VersionSet) *Capabilities {
return &Capabilities{
KubeVersion: kubeVersion,
APIVersions: apiVersions,
HelmVersion: DefaultCapabilities.HelmVersion,
IsDefaultKubeVersion: false,
}
}

Loading…
Cancel
Save