kubeadm: further improve the dynamic version population

Panicing if not running in a test and if the component-base/version
variables are empty is not ideal. At some point sections
of kubeadm could be exposed as a library and if these sections
import the constants package, they would panic on the library
users unless they set the version information in component-base
with ldflags.

Instead:
- If the component-base version is empty, return a placeholder version
that should indicate to users that build kubeadm that something is not
right (e.g. they did not use 'make'). During library usage or unit
tests this version should not be relevant.
- Update unit tests to use hardcoded versions instead of the versions
from the constants package. Using the constants package for testing
is good but during unit tests these versions are already placeholders
since unit tests do not populate the actual component-base versions
(e.g. 1.23).
This commit is contained in:
Lubomir I. Ivanov 2021-08-12 19:53:45 +03:00
parent 98e526390d
commit 096c3e8f2d
7 changed files with 97 additions and 116 deletions

View File

@ -489,44 +489,29 @@ var (
Jitter: 0.1, Jitter: 0.1,
} }
// defaultKubernetesVersionForTests is the default version used for unit tests. // defaultKubernetesPlaceholderVersion is a placeholder version in case the component-base
// The MINOR should be at least 3 as some tests subtract 3 from the MINOR version. // version was not populated during build.
defaultKubernetesVersionForTests = version.MustParseSemantic("v1.3.0") defaultKubernetesPlaceholderVersion = version.MustParseSemantic("v1.0.0-placeholder-version")
) )
// isRunningInTest can be used to determine if the code in this file is being run in a test.
func isRunningInTest() bool {
return strings.HasSuffix(os.Args[0], ".test")
}
// getSkewedKubernetesVersion returns the current MAJOR.(MINOR+n).0 Kubernetes version with a skew of 'n' // getSkewedKubernetesVersion returns the current MAJOR.(MINOR+n).0 Kubernetes version with a skew of 'n'
// It uses the kubeadm version provided by the 'component-base/version' package. This version must be populated // It uses the kubeadm version provided by the 'component-base/version' package. This version must be populated
// by passing linker flags during the kubeadm build process. If the version is empty, assume that kubeadm // by passing linker flags during the kubeadm build process. If the version is empty, assume that kubeadm
// was either build incorrectly or this code is running in unit tests. // was either build incorrectly or this code is running in unit tests.
func getSkewedKubernetesVersion(n int) *version.Version { func getSkewedKubernetesVersion(n int) *version.Version {
versionInfo := componentversion.Get() versionInfo := componentversion.Get()
ver := getSkewedKubernetesVersionImpl(&versionInfo, n, isRunningInTest) return getSkewedKubernetesVersionImpl(&versionInfo, n)
if ver == nil {
panic("kubeadm is not build properly using 'make ...': missing component version information")
}
return ver
} }
func getSkewedKubernetesVersionImpl(versionInfo *apimachineryversion.Info, n int, isRunningInTestFunc func() bool) *version.Version { func getSkewedKubernetesVersionImpl(versionInfo *apimachineryversion.Info, n int) *version.Version {
// TODO: update if the kubeadm version gets decoupled from the Kubernetes version. // TODO: update if the kubeadm version gets decoupled from the Kubernetes version.
// This would require keeping track of the supported skew in a table. // This would require keeping track of the supported skew in a table.
// More changes would be required if the kubelet version one day decouples from that of Kubernetes. // More changes would be required if the kubelet version one day decouples from that of Kubernetes.
var ver *version.Version var ver *version.Version
if len(versionInfo.Major) == 0 { if len(versionInfo.Major) == 0 {
if isRunningInTestFunc() { return defaultKubernetesPlaceholderVersion
ver = defaultKubernetesVersionForTests // An arbitrary version for testing purposes
} else {
// If this is not running in tests assume that the kubeadm binary is not build properly
return nil
}
} else {
ver = version.MustParseSemantic(versionInfo.GitVersion)
} }
ver = version.MustParseSemantic(versionInfo.GitVersion)
// Append the MINOR version skew. // Append the MINOR version skew.
// TODO: handle the case of Kubernetes moving to v2.0 or having MAJOR version updates in the future. // TODO: handle the case of Kubernetes moving to v2.0 or having MAJOR version updates in the future.
// This would require keeping track (in a table) of the last MINOR for a particular MAJOR. // This would require keeping track (in a table) of the last MINOR for a particular MAJOR.

View File

@ -241,22 +241,15 @@ func TestGetKubernetesServiceCIDR(t *testing.T) {
func TestGetSkewedKubernetesVersionImpl(t *testing.T) { func TestGetSkewedKubernetesVersionImpl(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
versionInfo *apimachineryversion.Info versionInfo *apimachineryversion.Info
n int n int
isRunningInTestFunc func() bool expectedResult *version.Version
expectedResult *version.Version
}{ }{
{ {
name: "invalid versionInfo; running in test", name: "invalid versionInfo; placeholder version is returned",
versionInfo: &apimachineryversion.Info{}, versionInfo: &apimachineryversion.Info{},
expectedResult: defaultKubernetesVersionForTests, expectedResult: defaultKubernetesPlaceholderVersion,
},
{
name: "invalid versionInfo; not running in test",
versionInfo: &apimachineryversion.Info{},
isRunningInTestFunc: func() bool { return false },
expectedResult: nil,
}, },
{ {
name: "valid skew of -1", name: "valid skew of -1",
@ -280,16 +273,7 @@ func TestGetSkewedKubernetesVersionImpl(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
if tc.isRunningInTestFunc == nil { result := getSkewedKubernetesVersionImpl(tc.versionInfo, tc.n)
tc.isRunningInTestFunc = func() bool { return true }
}
result := getSkewedKubernetesVersionImpl(tc.versionInfo, tc.n, tc.isRunningInTestFunc)
if (tc.expectedResult == nil) != (result == nil) {
t.Errorf("expected result: %v, got: %v", tc.expectedResult, result)
}
if result == nil {
return
}
if cmp, _ := result.Compare(tc.expectedResult.String()); cmp != 0 { if cmp, _ := result.Compare(tc.expectedResult.String()); cmp != 0 {
t.Errorf("expected result: %v, got %v", tc.expectedResult, result) t.Errorf("expected result: %v, got %v", tc.expectedResult, result)
} }

View File

@ -29,6 +29,7 @@ import (
apps "k8s.io/api/apps/v1" apps "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/version"
versionutil "k8s.io/apimachinery/pkg/util/version" versionutil "k8s.io/apimachinery/pkg/util/version"
clientsetfake "k8s.io/client-go/kubernetes/fake" clientsetfake "k8s.io/client-go/kubernetes/fake"
) )
@ -97,11 +98,11 @@ func TestGetAvailableUpgrades(t *testing.T) {
// variables are in the form v{MAJOR}{MINOR}{PATCH}, where MINOR is a variable so test are automatically uptodate to the latest MinimumControlPlaneVersion/ // variables are in the form v{MAJOR}{MINOR}{PATCH}, where MINOR is a variable so test are automatically uptodate to the latest MinimumControlPlaneVersion/
// v1.X series, e.g. v1.14 // v1.X series, e.g. v1.14
v1X0 := constants.MinimumControlPlaneVersion.WithMinor(constants.MinimumControlPlaneVersion.Minor() - 1) v1X0 := version.MustParseSemantic("v1.14.0")
v1X5 := v1X0.WithPatch(5) v1X5 := v1X0.WithPatch(5)
// v1.Y series, where Y = X+1, e.g. v1.15 // v1.Y series, where Y = X+1, e.g. v1.15
v1Y0 := constants.MinimumControlPlaneVersion v1Y0 := version.MustParseSemantic("v1.15.0")
v1Y0alpha0 := v1Y0.WithPreRelease("alpha.0") v1Y0alpha0 := v1Y0.WithPreRelease("alpha.0")
v1Y0alpha1 := v1Y0.WithPreRelease("alpha.1") v1Y0alpha1 := v1Y0.WithPreRelease("alpha.1")
v1Y1 := v1Y0.WithPatch(1) v1Y1 := v1Y0.WithPatch(1)
@ -110,7 +111,7 @@ func TestGetAvailableUpgrades(t *testing.T) {
v1Y5 := v1Y0.WithPatch(5) v1Y5 := v1Y0.WithPatch(5)
// v1.Z series, where Z = Y+1, e.g. v1.16 // v1.Z series, where Z = Y+1, e.g. v1.16
v1Z0 := constants.CurrentKubernetesVersion v1Z0 := version.MustParseSemantic("v1.16.0")
v1Z0alpha1 := v1Z0.WithPreRelease("alpha.1") v1Z0alpha1 := v1Z0.WithPreRelease("alpha.1")
v1Z0alpha2 := v1Z0.WithPreRelease("alpha.2") v1Z0alpha2 := v1Z0.WithPreRelease("alpha.2")
v1Z0beta1 := v1Z0.WithPreRelease("beta.1") v1Z0beta1 := v1Z0.WithPreRelease("beta.1")

View File

@ -19,12 +19,13 @@ package upgrade
import ( import (
"testing" "testing"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/apimachinery/pkg/util/version" "k8s.io/apimachinery/pkg/util/version"
) )
func TestEnforceVersionPolicies(t *testing.T) { func TestEnforceVersionPolicies(t *testing.T) {
minimumKubeletVersion := version.MustParseSemantic("v1.3.0")
minimumControlPlaneVersion := version.MustParseSemantic("v1.3.0")
currentKubernetesVersion := version.MustParseSemantic("v1.4.0")
tests := []struct { tests := []struct {
name string name string
vg *fakeVersionGetter vg *fakeVersionGetter
@ -36,38 +37,38 @@ func TestEnforceVersionPolicies(t *testing.T) {
{ {
name: "minor upgrade", name: "minor upgrade",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), kubeletVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(), kubeadmVersion: minimumControlPlaneVersion.WithPatch(5).String(),
}, },
newK8sVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(), newK8sVersion: minimumControlPlaneVersion.WithPatch(5).String(),
}, },
{ {
name: "major upgrade", name: "major upgrade",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(), kubeletVersion: minimumControlPlaneVersion.WithPatch(2).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPatch(1).String(), kubeadmVersion: currentKubernetesVersion.WithPatch(1).String(),
}, },
newK8sVersion: constants.CurrentKubernetesVersion.String(), newK8sVersion: currentKubernetesVersion.String(),
}, },
{ {
name: "downgrade", name: "downgrade",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.String(), kubeletVersion: minimumKubeletVersion.String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), kubeadmVersion: minimumControlPlaneVersion.WithPatch(3).String(),
}, },
newK8sVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(), newK8sVersion: minimumControlPlaneVersion.WithPatch(2).String(),
}, },
{ {
name: "same version upgrade", name: "same version upgrade",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(), kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), kubeadmVersion: minimumControlPlaneVersion.WithPatch(3).String(),
}, },
newK8sVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), newK8sVersion: minimumControlPlaneVersion.WithPatch(3).String(),
}, },
{ {
name: "new version must be higher than v1.12.0", name: "new version must be higher than v1.12.0",
@ -94,31 +95,31 @@ func TestEnforceVersionPolicies(t *testing.T) {
{ {
name: "downgrading two minor versions in one go is not supported", name: "downgrading two minor versions in one go is not supported",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.CurrentKubernetesVersion.WithMinor(constants.CurrentKubernetesVersion.Minor() + 2).String(), clusterVersion: currentKubernetesVersion.WithMinor(currentKubernetesVersion.Minor() + 2).String(),
kubeletVersion: constants.CurrentKubernetesVersion.WithMinor(constants.CurrentKubernetesVersion.Minor() + 2).String(), kubeletVersion: currentKubernetesVersion.WithMinor(currentKubernetesVersion.Minor() + 2).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.String(), kubeadmVersion: currentKubernetesVersion.String(),
}, },
newK8sVersion: constants.CurrentKubernetesVersion.String(), newK8sVersion: currentKubernetesVersion.String(),
expectedMandatoryErrs: 1, // can't downgrade two minor versions expectedMandatoryErrs: 1, // can't downgrade two minor versions
}, },
{ {
name: "kubeadm version must be higher than the new kube version. However, patch version skews may be forced", name: "kubeadm version must be higher than the new kube version. However, patch version skews may be forced",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(), kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), kubeadmVersion: minimumControlPlaneVersion.WithPatch(3).String(),
}, },
newK8sVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(), newK8sVersion: minimumControlPlaneVersion.WithPatch(5).String(),
expectedSkippableErrs: 1, expectedSkippableErrs: 1,
}, },
{ {
name: "kubeadm version must be higher than the new kube version. Trying to upgrade k8s to a higher minor version than kubeadm itself should never be supported", name: "kubeadm version must be higher than the new kube version. Trying to upgrade k8s to a higher minor version than kubeadm itself should never be supported",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(), kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), kubeadmVersion: minimumControlPlaneVersion.WithPatch(3).String(),
}, },
newK8sVersion: constants.CurrentKubernetesVersion.String(), newK8sVersion: currentKubernetesVersion.String(),
expectedMandatoryErrs: 1, expectedMandatoryErrs: 1,
}, },
{ {
@ -134,72 +135,72 @@ func TestEnforceVersionPolicies(t *testing.T) {
{ {
name: "experimental upgrades supported if the flag is set", name: "experimental upgrades supported if the flag is set",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(), kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("beta.1").String(), kubeadmVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
}, },
newK8sVersion: constants.CurrentKubernetesVersion.WithPreRelease("beta.1").String(), newK8sVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
allowExperimental: true, allowExperimental: true,
}, },
{ {
name: "release candidate upgrades supported if the flag is set", name: "release candidate upgrades supported if the flag is set",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(), kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(), kubeadmVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
}, },
newK8sVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(), newK8sVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
allowRCs: true, allowRCs: true,
}, },
{ {
name: "release candidate upgrades supported if the flag is set", name: "release candidate upgrades supported if the flag is set",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(), kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(), kubeadmVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
}, },
newK8sVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(), newK8sVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
allowExperimental: true, allowExperimental: true,
}, },
{ {
name: "the user should not be able to upgrade to an experimental version if they haven't opted into that", name: "the user should not be able to upgrade to an experimental version if they haven't opted into that",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(), kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("beta.1").String(), kubeadmVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
}, },
newK8sVersion: constants.CurrentKubernetesVersion.WithPreRelease("beta.1").String(), newK8sVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
allowRCs: true, allowRCs: true,
expectedSkippableErrs: 1, expectedSkippableErrs: 1,
}, },
{ {
name: "the user should not be able to upgrade to an release candidate version if they haven't opted into that", name: "the user should not be able to upgrade to an release candidate version if they haven't opted into that",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(), kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(), kubeadmVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
}, },
newK8sVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(), newK8sVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
expectedSkippableErrs: 1, expectedSkippableErrs: 1,
}, },
{ {
name: "the user can't use a newer minor version of kubeadm to upgrade an older version of kubeadm", name: "the user can't use a newer minor version of kubeadm to upgrade an older version of kubeadm",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(), clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(), kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.String(), kubeadmVersion: currentKubernetesVersion.String(),
}, },
newK8sVersion: constants.MinimumControlPlaneVersion.WithPatch(6).String(), newK8sVersion: minimumControlPlaneVersion.WithPatch(6).String(),
expectedSkippableErrs: 1, // can't upgrade old k8s with newer kubeadm expectedSkippableErrs: 1, // can't upgrade old k8s with newer kubeadm
}, },
{ {
name: "build release supported at MinimumControlPlaneVersion", name: "build release supported at MinimumControlPlaneVersion",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.String(), clusterVersion: minimumControlPlaneVersion.String(),
kubeletVersion: constants.MinimumControlPlaneVersion.String(), kubeletVersion: minimumControlPlaneVersion.String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithBuildMetadata("build").String(), kubeadmVersion: minimumControlPlaneVersion.WithBuildMetadata("build").String(),
}, },
newK8sVersion: constants.MinimumControlPlaneVersion.WithBuildMetadata("build").String(), newK8sVersion: minimumControlPlaneVersion.WithBuildMetadata("build").String(),
}, },
} }

View File

@ -464,7 +464,7 @@ func TestStaticPodControlPlane(t *testing.T) {
} }
defer os.RemoveAll(tmpEtcdDataDir) defer os.RemoveAll(tmpEtcdDataDir)
oldcfg, err := getConfig(constants.MinimumControlPlaneVersion.String(), tempCertsDir, tmpEtcdDataDir) oldcfg, err := getConfig("v1.3.0", tempCertsDir, tmpEtcdDataDir)
if err != nil { if err != nil {
t.Fatalf("couldn't create config: %v", err) t.Fatalf("couldn't create config: %v", err)
} }

View File

@ -35,6 +35,7 @@ import (
"time" "time"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/images" "k8s.io/kubernetes/cmd/kubeadm/app/images"
"k8s.io/kubernetes/cmd/kubeadm/app/util/initsystem" "k8s.io/kubernetes/cmd/kubeadm/app/util/initsystem"
@ -44,6 +45,7 @@ import (
netutil "k8s.io/apimachinery/pkg/util/net" netutil "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/version"
versionutil "k8s.io/apimachinery/pkg/util/version" versionutil "k8s.io/apimachinery/pkg/util/version"
kubeadmversion "k8s.io/component-base/version" kubeadmversion "k8s.io/component-base/version"
"k8s.io/klog/v2" "k8s.io/klog/v2"
@ -604,6 +606,7 @@ func (kubever KubernetesVersionCheck) Check() (warnings, errorList []error) {
// KubeletVersionCheck validates installed kubelet version // KubeletVersionCheck validates installed kubelet version
type KubeletVersionCheck struct { type KubeletVersionCheck struct {
KubernetesVersion string KubernetesVersion string
minKubeletVersion *version.Version
exec utilsexec.Interface exec utilsexec.Interface
} }
@ -619,7 +622,10 @@ func (kubever KubeletVersionCheck) Check() (warnings, errorList []error) {
if err != nil { if err != nil {
return nil, []error{errors.Wrap(err, "couldn't get kubelet version")} return nil, []error{errors.Wrap(err, "couldn't get kubelet version")}
} }
if kubeletVersion.LessThan(kubeadmconstants.MinimumKubeletVersion) { if kubever.minKubeletVersion == nil {
kubever.minKubeletVersion = constants.MinimumKubeletVersion
}
if kubeletVersion.LessThan(kubever.minKubeletVersion) {
return nil, []error{errors.Errorf("Kubelet version %q is lower than kubeadm can support. Please upgrade kubelet", kubeletVersion)} return nil, []error{errors.Errorf("Kubelet version %q is lower than kubeadm can support. Please upgrade kubelet", kubeletVersion)}
} }

View File

@ -33,6 +33,7 @@ import (
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/utils/exec" "k8s.io/utils/exec"
fakeexec "k8s.io/utils/exec/testing" fakeexec "k8s.io/utils/exec/testing"
@ -786,19 +787,22 @@ func restoreEnv(e map[string]string) {
} }
func TestKubeletVersionCheck(t *testing.T) { func TestKubeletVersionCheck(t *testing.T) {
minimumKubeletVersion := version.MustParseSemantic("v1.3.0")
minimumControlPlaneVersion := version.MustParseSemantic("v1.3.0")
currentKubernetesVersion := version.MustParseSemantic("v1.4.0")
cases := []struct { cases := []struct {
kubeletVersion string kubeletVersion string
k8sVersion string k8sVersion string
expectErrors bool expectErrors bool
expectWarnings bool expectWarnings bool
}{ }{
{"v" + constants.CurrentKubernetesVersion.WithPatch(2).String(), "", false, false}, // check minimally supported version when there is no information about control plane {"v" + currentKubernetesVersion.WithPatch(2).String(), "", false, false}, // check minimally supported version when there is no information about control plane
{"v1.1.0", "v1.11.8", true, false}, // too old kubelet, should fail. {"v1.1.0", "v1.11.8", true, false}, // too old kubelet, should fail.
{"v" + constants.MinimumKubeletVersion.String(), constants.MinimumControlPlaneVersion.WithPatch(5).String(), false, false}, // kubelet within same major.minor as control plane {"v" + minimumKubeletVersion.String(), minimumControlPlaneVersion.WithPatch(5).String(), false, false}, // kubelet within same major.minor as control plane
{"v" + constants.MinimumKubeletVersion.WithPatch(5).String(), constants.MinimumControlPlaneVersion.WithPatch(1).String(), false, false}, // kubelet is newer, but still within same major.minor as control plane {"v" + minimumKubeletVersion.WithPatch(5).String(), minimumControlPlaneVersion.WithPatch(1).String(), false, false}, // kubelet is newer, but still within same major.minor as control plane
{"v" + constants.MinimumKubeletVersion.String(), constants.CurrentKubernetesVersion.WithPatch(1).String(), false, false}, // kubelet is lower than control plane, but newer than minimally supported {"v" + minimumKubeletVersion.String(), currentKubernetesVersion.WithPatch(1).String(), false, false}, // kubelet is lower than control plane, but newer than minimally supported
{"v" + constants.CurrentKubernetesVersion.WithPreRelease("alpha.1").String(), constants.MinimumControlPlaneVersion.WithPatch(1).String(), true, false}, // kubelet is newer (development build) than control plane, should fail. {"v" + currentKubernetesVersion.WithPreRelease("alpha.1").String(), minimumControlPlaneVersion.WithPatch(1).String(), true, false}, // kubelet is newer (development build) than control plane, should fail.
{"v" + constants.CurrentKubernetesVersion.String(), constants.MinimumControlPlaneVersion.WithPatch(5).String(), true, false}, // kubelet is newer (release) than control plane, should fail. {"v" + currentKubernetesVersion.String(), minimumControlPlaneVersion.WithPatch(5).String(), true, false}, // kubelet is newer (release) than control plane, should fail.
} }
for _, tc := range cases { for _, tc := range cases {
@ -814,7 +818,7 @@ func TestKubeletVersionCheck(t *testing.T) {
}, },
} }
check := KubeletVersionCheck{KubernetesVersion: tc.k8sVersion, exec: fexec} check := KubeletVersionCheck{KubernetesVersion: tc.k8sVersion, exec: fexec, minKubeletVersion: minimumKubeletVersion}
warnings, errors := check.Check() warnings, errors := check.Check()
switch { switch {