mirror of
https://github.com/helm/helm.git
synced 2026-02-03 20:39:45 -05:00
build: set kube version via debug.BuildInfo
Signed-off-by: Branch Vincent <branchevincent@gmail.com> Signed-off-by: George Jenkins <gvjenkins@gmail.com>
This commit is contained in:
parent
4d1150d2af
commit
c6d9a5bdc2
12 changed files with 187 additions and 106 deletions
14
Makefile
14
Makefile
|
|
@ -58,20 +58,6 @@ LDFLAGS += -X helm.sh/helm/v4/internal/version.gitCommit=${GIT_COMMIT}
|
|||
LDFLAGS += -X helm.sh/helm/v4/internal/version.gitTreeState=${GIT_DIRTY}
|
||||
LDFLAGS += $(EXT_LDFLAGS)
|
||||
|
||||
# Define constants based on the client-go version
|
||||
K8S_MODULES_VER=$(subst ., ,$(subst v,,$(shell go list -f '{{.Version}}' -m k8s.io/client-go)))
|
||||
K8S_MODULES_MAJOR_VER=$(shell echo $$(($(firstword $(K8S_MODULES_VER)) + 1)))
|
||||
K8S_MODULES_MINOR_VER=$(word 2,$(K8S_MODULES_VER))
|
||||
|
||||
LDFLAGS += -X helm.sh/helm/v4/pkg/chart/v2/lint/rules.k8sVersionMajor=$(K8S_MODULES_MAJOR_VER)
|
||||
LDFLAGS += -X helm.sh/helm/v4/pkg/chart/v2/lint/rules.k8sVersionMinor=$(K8S_MODULES_MINOR_VER)
|
||||
LDFLAGS += -X helm.sh/helm/v4/pkg/internal/v3/lint/rules.k8sVersionMajor=$(K8S_MODULES_MAJOR_VER)
|
||||
LDFLAGS += -X helm.sh/helm/v4/pkg/internal/v3/lint/rules.k8sVersionMinor=$(K8S_MODULES_MINOR_VER)
|
||||
LDFLAGS += -X helm.sh/helm/v4/pkg/chart/common.k8sVersionMajor=$(K8S_MODULES_MAJOR_VER)
|
||||
LDFLAGS += -X helm.sh/helm/v4/pkg/chart/common.k8sVersionMinor=$(K8S_MODULES_MINOR_VER)
|
||||
LDFLAGS += -X helm.sh/helm/v4/internal/version.kubeClientVersionMajor=$(K8S_MODULES_MAJOR_VER)
|
||||
LDFLAGS += -X helm.sh/helm/v4/internal/version.kubeClientVersionMinor=$(K8S_MODULES_MINOR_VER)
|
||||
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
|
|
|
|||
|
|
@ -175,16 +175,6 @@ func TestHelmCreateChart(t *testing.T) {
|
|||
//
|
||||
// Resources like hpa and ingress, which are disabled by default in values.yaml are enabled here using the equivalent
|
||||
// of the `--set` flag.
|
||||
//
|
||||
// Note: This test requires the following ldflags to be set per the current Kubernetes version to avoid false-positive
|
||||
// results.
|
||||
// 1. -X helm.sh/helm/v4/pkg/lint/rules.k8sVersionMajor=<k8s-major-version>
|
||||
// 2. -X helm.sh/helm/v4/pkg/lint/rules.k8sVersionMinor=<k8s-minor-version>
|
||||
// or directly use '$(LDFLAGS)' in Makefile.
|
||||
//
|
||||
// When run without ldflags, the test passes giving a false-positive result. This is because the variables
|
||||
// `k8sVersionMajor` and `k8sVersionMinor` by default are set to an older version of Kubernetes, with which, there
|
||||
// might not be the deprecation warning.
|
||||
func TestHelmCreateChart_CheckDeprecatedWarnings(t *testing.T) {
|
||||
createdChart, err := chartutil.Create("checkdeprecatedwarnings", t.TempDir())
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -28,15 +28,7 @@ import (
|
|||
kscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
var (
|
||||
// This should be set in the Makefile based on the version of client-go being imported.
|
||||
// These constants will be overwritten with LDFLAGS. The version components must be
|
||||
// strings in order for LDFLAGS to set them.
|
||||
k8sVersionMajor = "1"
|
||||
k8sVersionMinor = "20"
|
||||
)
|
||||
|
||||
// deprecatedAPIError indicates that an API is deprecated in Kubernetes
|
||||
// deprecatedAPIError indicates than an API is deprecated in Kubernetes
|
||||
type deprecatedAPIError struct {
|
||||
Deprecated string
|
||||
Message string
|
||||
|
|
@ -56,12 +48,17 @@ func validateNoDeprecations(resource *k8sYamlStruct, kubeVersion *common.KubeVer
|
|||
return nil
|
||||
}
|
||||
|
||||
majorVersion := k8sVersionMajor
|
||||
minorVersion := k8sVersionMinor
|
||||
if kubeVersion == nil {
|
||||
kubeVersion = &common.DefaultCapabilities.KubeVersion
|
||||
}
|
||||
|
||||
if kubeVersion != nil {
|
||||
majorVersion = kubeVersion.Major
|
||||
minorVersion = kubeVersion.Minor
|
||||
kubeVersionMajor, err := strconv.Atoi(kubeVersion.Major)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kubeVersionMinor, err := strconv.Atoi(kubeVersion.Minor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtimeObject, err := resourceToRuntimeObject(resource)
|
||||
|
|
@ -73,16 +70,7 @@ func validateNoDeprecations(resource *k8sYamlStruct, kubeVersion *common.KubeVer
|
|||
return err
|
||||
}
|
||||
|
||||
major, err := strconv.Atoi(majorVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
minor, err := strconv.Atoi(minorVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deprecation.IsDeprecated(runtimeObject, major, minor) {
|
||||
if !deprecation.IsDeprecated(runtimeObject, kubeVersionMajor, kubeVersionMinor) {
|
||||
return nil
|
||||
}
|
||||
gvk := fmt.Sprintf("%s %s", resource.APIVersion, resource.Kind)
|
||||
|
|
|
|||
44
internal/version/clientgo.go
Normal file
44
internal/version/clientgo.go
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"slices"
|
||||
|
||||
_ "k8s.io/client-go/kubernetes" // Force k8s.io/client-go to be included in the build
|
||||
)
|
||||
|
||||
func K8sIOClientGoModVersion() (string, error) {
|
||||
info, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return "", fmt.Errorf("failed to read build info")
|
||||
}
|
||||
|
||||
idx := slices.IndexFunc(info.Deps, func(m *debug.Module) bool {
|
||||
return m.Path == "k8s.io/client-go"
|
||||
})
|
||||
|
||||
if idx == -1 {
|
||||
return "", fmt.Errorf("k8s.io/client-go not found in build info")
|
||||
}
|
||||
|
||||
m := info.Deps[idx]
|
||||
|
||||
return m.Version, nil
|
||||
}
|
||||
30
internal/version/clientgo_test.go
Normal file
30
internal/version/clientgo_test.go
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package version
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestK8sClientGoModVersion(t *testing.T) {
|
||||
// Unfortunately, test builds don't include debug info / module info
|
||||
// So we expect "K8sIOClientGoModVersion" to return error
|
||||
_, err := K8sIOClientGoModVersion()
|
||||
require.ErrorContains(t, err, "k8s.io/client-go not found in build info")
|
||||
}
|
||||
|
|
@ -14,13 +14,17 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package version // import "helm.sh/helm/v4/internal/version"
|
||||
package version
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -38,11 +42,10 @@ var (
|
|||
gitCommit = ""
|
||||
// gitTreeState is the state of the git tree
|
||||
gitTreeState = ""
|
||||
)
|
||||
|
||||
// The Kubernetes version can be set by LDFLAGS. In order to do that the value
|
||||
// must be a string.
|
||||
kubeClientVersionMajor = ""
|
||||
kubeClientVersionMinor = ""
|
||||
const (
|
||||
kubeClientGoVersionTesting = "v1.20"
|
||||
)
|
||||
|
||||
// BuildInfo describes the compile time information.
|
||||
|
|
@ -74,12 +77,39 @@ func GetUserAgent() string {
|
|||
|
||||
// Get returns build info
|
||||
func Get() BuildInfo {
|
||||
|
||||
makeKubeClientVersionString := func() string {
|
||||
// Test builds don't include debug info / module info
|
||||
// (And even if they did, we probably want a stable version during tests anyway)
|
||||
// Return a default value for test builds
|
||||
if testing.Testing() {
|
||||
return kubeClientGoVersionTesting
|
||||
}
|
||||
|
||||
vstr, err := K8sIOClientGoModVersion()
|
||||
if err != nil {
|
||||
slog.Error("failed to retrieve k8s.io/client-go version", slog.Any("error", err))
|
||||
return ""
|
||||
}
|
||||
|
||||
v, err := semver.NewVersion(vstr)
|
||||
if err != nil {
|
||||
slog.Error("unable to parse k8s.io/client-go version", slog.String("version", vstr), slog.Any("error", err))
|
||||
return ""
|
||||
}
|
||||
|
||||
kubeClientVersionMajor := v.Major() + 1
|
||||
kubeClientVersionMinor := v.Minor()
|
||||
|
||||
return fmt.Sprintf("v%d.%d", kubeClientVersionMajor, kubeClientVersionMinor)
|
||||
}
|
||||
|
||||
v := BuildInfo{
|
||||
Version: GetVersion(),
|
||||
GitCommit: gitCommit,
|
||||
GitTreeState: gitTreeState,
|
||||
GoVersion: runtime.Version(),
|
||||
KubeClientVersion: fmt.Sprintf("v%s.%s", kubeClientVersionMajor, kubeClientVersionMinor),
|
||||
KubeClientVersion: makeKubeClientVersionString(),
|
||||
}
|
||||
|
||||
// HACK(bacongobbler): strip out GoVersion during a test run for consistent test output
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ import (
|
|||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
|
|
@ -30,27 +32,23 @@ import (
|
|||
helmversion "helm.sh/helm/v4/internal/version"
|
||||
)
|
||||
|
||||
var (
|
||||
// The Kubernetes version can be set by LDFLAGS. In order to do that the value
|
||||
// must be a string.
|
||||
k8sVersionMajor = "1"
|
||||
k8sVersionMinor = "20"
|
||||
const (
|
||||
kubeVersionMajorTesting = 1
|
||||
kubeVersionMinorTesting = 20
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultVersionSet is the default version set, which includes only Core V1 ("v1").
|
||||
DefaultVersionSet = allKnownVersions()
|
||||
|
||||
// DefaultCapabilities is the default set of capabilities.
|
||||
version = fmt.Sprintf("v%s.%s.0", k8sVersionMajor, k8sVersionMinor)
|
||||
DefaultCapabilities = &Capabilities{
|
||||
KubeVersion: KubeVersion{
|
||||
Version: version,
|
||||
normalizedVersion: version,
|
||||
Major: k8sVersionMajor,
|
||||
Minor: k8sVersionMinor,
|
||||
},
|
||||
APIVersions: DefaultVersionSet,
|
||||
HelmVersion: helmversion.Get(),
|
||||
}
|
||||
DefaultCapabilities = func() *Capabilities {
|
||||
caps, err := makeDefaultCapabilities()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to create default capabilities: %v", err))
|
||||
}
|
||||
return caps
|
||||
|
||||
}()
|
||||
)
|
||||
|
||||
// Capabilities describes the capabilities of the Kubernetes cluster.
|
||||
|
|
@ -143,3 +141,42 @@ func allKnownVersions() VersionSet {
|
|||
}
|
||||
return vs
|
||||
}
|
||||
|
||||
func makeDefaultCapabilities() (*Capabilities, error) {
|
||||
// Test builds don't include debug info / module info
|
||||
// (And even if they did, we probably want stable capabilities for tests anyway)
|
||||
// Return a default value for test builds
|
||||
if testing.Testing() {
|
||||
return newCapabilities(kubeVersionMajorTesting, kubeVersionMinorTesting)
|
||||
}
|
||||
|
||||
vstr, err := helmversion.K8sIOClientGoModVersion()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve k8s.io/client-go version: %w", err)
|
||||
}
|
||||
|
||||
v, err := semver.NewVersion(vstr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse k8s.io/client-go version %q: %v", vstr, err)
|
||||
}
|
||||
|
||||
kubeVersionMajor := v.Major() + 1
|
||||
kubeVersionMinor := v.Minor()
|
||||
|
||||
return newCapabilities(kubeVersionMajor, kubeVersionMinor)
|
||||
}
|
||||
|
||||
func newCapabilities(kubeVersionMajor, kubeVersionMinor uint64) (*Capabilities, error) {
|
||||
|
||||
version := fmt.Sprintf("v%d.%d.0", kubeVersionMajor, kubeVersionMinor)
|
||||
return &Capabilities{
|
||||
KubeVersion: KubeVersion{
|
||||
Version: version,
|
||||
normalizedVersion: version,
|
||||
Major: fmt.Sprintf("%d", kubeVersionMajor),
|
||||
Minor: fmt.Sprintf("%d", kubeVersionMinor),
|
||||
},
|
||||
APIVersions: DefaultVersionSet,
|
||||
HelmVersion: helmversion.Get(),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ func TestDefaultVersionSet(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDefaultCapabilities(t *testing.T) {
|
||||
kv := DefaultCapabilities.KubeVersion
|
||||
caps := DefaultCapabilities
|
||||
kv := caps.KubeVersion
|
||||
if kv.String() != "v1.20.0" {
|
||||
t.Errorf("Expected default KubeVersion.String() to be v1.20.0, got %q", kv.String())
|
||||
}
|
||||
|
|
@ -57,11 +58,8 @@ func TestDefaultCapabilities(t *testing.T) {
|
|||
if kv.Minor != "20" {
|
||||
t.Errorf("Expected default KubeVersion.Minor to be 20, got %q", kv.Minor)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultCapabilitiesHelmVersion(t *testing.T) {
|
||||
hv := DefaultCapabilities.HelmVersion
|
||||
|
||||
hv := caps.HelmVersion
|
||||
if hv.Version != "v4.1" {
|
||||
t.Errorf("Expected default HelmVersion to be v4.1, got %q", hv.Version)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,16 +179,6 @@ func TestHelmCreateChart(t *testing.T) {
|
|||
//
|
||||
// Resources like hpa and ingress, which are disabled by default in values.yaml are enabled here using the equivalent
|
||||
// of the `--set` flag.
|
||||
//
|
||||
// Note: This test requires the following ldflags to be set per the current Kubernetes version to avoid false-positive
|
||||
// results.
|
||||
// 1. -X helm.sh/helm/v4/pkg/lint/rules.k8sVersionMajor=<k8s-major-version>
|
||||
// 2. -X helm.sh/helm/v4/pkg/lint/rules.k8sVersionMinor=<k8s-minor-version>
|
||||
// or directly use '$(LDFLAGS)' in Makefile.
|
||||
//
|
||||
// When run without ldflags, the test passes giving a false-positive result. This is because the variables
|
||||
// `k8sVersionMajor` and `k8sVersionMinor` by default are set to an older version of Kubernetes, with which, there
|
||||
// might not be the deprecation warning.
|
||||
func TestHelmCreateChart_CheckDeprecatedWarnings(t *testing.T) {
|
||||
createdChart, err := chartutil.Create("checkdeprecatedwarnings", t.TempDir())
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -28,15 +28,7 @@ import (
|
|||
kscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
var (
|
||||
// This should be set in the Makefile based on the version of client-go being imported.
|
||||
// These constants will be overwritten with LDFLAGS. The version components must be
|
||||
// strings in order for LDFLAGS to set them.
|
||||
k8sVersionMajor = "1"
|
||||
k8sVersionMinor = "20"
|
||||
)
|
||||
|
||||
// deprecatedAPIError indicates that an API is deprecated in Kubernetes
|
||||
// deprecatedAPIError indicates than an API is deprecated in Kubernetes
|
||||
type deprecatedAPIError struct {
|
||||
Deprecated string
|
||||
Message string
|
||||
|
|
@ -56,12 +48,8 @@ func validateNoDeprecations(resource *k8sYamlStruct, kubeVersion *common.KubeVer
|
|||
return nil
|
||||
}
|
||||
|
||||
majorVersion := k8sVersionMajor
|
||||
minorVersion := k8sVersionMinor
|
||||
|
||||
if kubeVersion != nil {
|
||||
majorVersion = kubeVersion.Major
|
||||
minorVersion = kubeVersion.Minor
|
||||
if kubeVersion == nil {
|
||||
kubeVersion = &common.DefaultCapabilities.KubeVersion
|
||||
}
|
||||
|
||||
runtimeObject, err := resourceToRuntimeObject(resource)
|
||||
|
|
@ -73,16 +61,16 @@ func validateNoDeprecations(resource *k8sYamlStruct, kubeVersion *common.KubeVer
|
|||
return err
|
||||
}
|
||||
|
||||
major, err := strconv.Atoi(majorVersion)
|
||||
kubeVersionMajor, err := strconv.Atoi(kubeVersion.Major)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
minor, err := strconv.Atoi(minorVersion)
|
||||
kubeVersionMinor, err := strconv.Atoi(kubeVersion.Minor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deprecation.IsDeprecated(runtimeObject, major, minor) {
|
||||
if !deprecation.IsDeprecated(runtimeObject, kubeVersionMajor, kubeVersionMinor) {
|
||||
return nil
|
||||
}
|
||||
gvk := fmt.Sprintf("%s %s", resource.APIVersion, resource.Kind)
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ func TestLintCmdWithKubeVersionFlag(t *testing.T) {
|
|||
golden: "output/lint-chart-with-deprecated-api-strict.txt",
|
||||
wantError: true,
|
||||
}, {
|
||||
// the test builds will use the default k8sVersionMinor const in deprecations.go and capabilities.go
|
||||
// the test builds will use the kubeVersionMinorTesting const in capabilities.go
|
||||
// which is "20"
|
||||
name: "lint chart with deprecated api version without kube version",
|
||||
cmd: fmt.Sprintf("lint %s", testChart),
|
||||
|
|
|
|||
2
pkg/cmd/testdata/output/version.txt
vendored
2
pkg/cmd/testdata/output/version.txt
vendored
|
|
@ -1 +1 @@
|
|||
version.BuildInfo{Version:"v4.1", GitCommit:"", GitTreeState:"", GoVersion:"", KubeClientVersion:"v."}
|
||||
version.BuildInfo{Version:"v4.1", GitCommit:"", GitTreeState:"", GoVersion:"", KubeClientVersion:"v1.20"}
|
||||
|
|
|
|||
Loading…
Reference in a new issue