Merge pull request #104338 from neolit123/1.23-use-dynamic-versions

kubeadm: further improve the dynamic version population
This commit is contained in:
Kubernetes Prow Robot 2021-08-13 03:04:22 -07:00 committed by GitHub
commit fd9c24fc5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 97 additions and 116 deletions

View File

@ -489,44 +489,29 @@ var (
Jitter: 0.1,
}
// defaultKubernetesVersionForTests is the default version used for unit tests.
// The MINOR should be at least 3 as some tests subtract 3 from the MINOR version.
defaultKubernetesVersionForTests = version.MustParseSemantic("v1.3.0")
// defaultKubernetesPlaceholderVersion is a placeholder version in case the component-base
// version was not populated during build.
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'
// 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
// was either build incorrectly or this code is running in unit tests.
func getSkewedKubernetesVersion(n int) *version.Version {
versionInfo := componentversion.Get()
ver := getSkewedKubernetesVersionImpl(&versionInfo, n, isRunningInTest)
if ver == nil {
panic("kubeadm is not build properly using 'make ...': missing component version information")
}
return ver
return getSkewedKubernetesVersionImpl(&versionInfo, n)
}
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.
// 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.
var ver *version.Version
if len(versionInfo.Major) == 0 {
if isRunningInTestFunc() {
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)
return defaultKubernetesPlaceholderVersion
}
ver = version.MustParseSemantic(versionInfo.GitVersion)
// Append the MINOR version skew.
// 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.

View File

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

View File

@ -29,6 +29,7 @@ import (
apps "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/version"
versionutil "k8s.io/apimachinery/pkg/util/version"
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/
// 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)
// 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")
v1Y0alpha1 := v1Y0.WithPreRelease("alpha.1")
v1Y1 := v1Y0.WithPatch(1)
@ -110,7 +111,7 @@ func TestGetAvailableUpgrades(t *testing.T) {
v1Y5 := v1Y0.WithPatch(5)
// 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")
v1Z0alpha2 := v1Z0.WithPreRelease("alpha.2")
v1Z0beta1 := v1Z0.WithPreRelease("beta.1")

View File

@ -19,12 +19,13 @@ package upgrade
import (
"testing"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/apimachinery/pkg/util/version"
)
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 {
name string
vg *fakeVersionGetter
@ -36,38 +37,38 @@ func TestEnforceVersionPolicies(t *testing.T) {
{
name: "minor upgrade",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeadmVersion: minimumControlPlaneVersion.WithPatch(5).String(),
},
newK8sVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
newK8sVersion: minimumControlPlaneVersion.WithPatch(5).String(),
},
{
name: "major upgrade",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPatch(1).String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumControlPlaneVersion.WithPatch(2).String(),
kubeadmVersion: currentKubernetesVersion.WithPatch(1).String(),
},
newK8sVersion: constants.CurrentKubernetesVersion.String(),
newK8sVersion: currentKubernetesVersion.String(),
},
{
name: "downgrade",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumKubeletVersion.String(),
kubeadmVersion: minimumControlPlaneVersion.WithPatch(3).String(),
},
newK8sVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(),
newK8sVersion: minimumControlPlaneVersion.WithPatch(2).String(),
},
{
name: "same version upgrade",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumKubeletVersion.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",
@ -94,31 +95,31 @@ func TestEnforceVersionPolicies(t *testing.T) {
{
name: "downgrading two minor versions in one go is not supported",
vg: &fakeVersionGetter{
clusterVersion: constants.CurrentKubernetesVersion.WithMinor(constants.CurrentKubernetesVersion.Minor() + 2).String(),
kubeletVersion: constants.CurrentKubernetesVersion.WithMinor(constants.CurrentKubernetesVersion.Minor() + 2).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.String(),
clusterVersion: currentKubernetesVersion.WithMinor(currentKubernetesVersion.Minor() + 2).String(),
kubeletVersion: currentKubernetesVersion.WithMinor(currentKubernetesVersion.Minor() + 2).String(),
kubeadmVersion: currentKubernetesVersion.String(),
},
newK8sVersion: constants.CurrentKubernetesVersion.String(),
newK8sVersion: currentKubernetesVersion.String(),
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",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: minimumControlPlaneVersion.WithPatch(3).String(),
},
newK8sVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
newK8sVersion: minimumControlPlaneVersion.WithPatch(5).String(),
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",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: minimumControlPlaneVersion.WithPatch(3).String(),
},
newK8sVersion: constants.CurrentKubernetesVersion.String(),
newK8sVersion: currentKubernetesVersion.String(),
expectedMandatoryErrs: 1,
},
{
@ -134,72 +135,72 @@ func TestEnforceVersionPolicies(t *testing.T) {
{
name: "experimental upgrades supported if the flag is set",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("beta.1").String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
},
newK8sVersion: constants.CurrentKubernetesVersion.WithPreRelease("beta.1").String(),
newK8sVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
allowExperimental: true,
},
{
name: "release candidate upgrades supported if the flag is set",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
},
newK8sVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(),
newK8sVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
allowRCs: true,
},
{
name: "release candidate upgrades supported if the flag is set",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
},
newK8sVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(),
newK8sVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
allowExperimental: true,
},
{
name: "the user should not be able to upgrade to an experimental version if they haven't opted into that",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("beta.1").String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
},
newK8sVersion: constants.CurrentKubernetesVersion.WithPreRelease("beta.1").String(),
newK8sVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
allowRCs: true,
expectedSkippableErrs: 1,
},
{
name: "the user should not be able to upgrade to an release candidate version if they haven't opted into that",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
},
newK8sVersion: constants.CurrentKubernetesVersion.WithPreRelease("rc.1").String(),
newK8sVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
expectedSkippableErrs: 1,
},
{
name: "the user can't use a newer minor version of kubeadm to upgrade an older version of kubeadm",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(),
kubeadmVersion: constants.CurrentKubernetesVersion.String(),
clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
kubeletVersion: minimumKubeletVersion.WithPatch(3).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
},
{
name: "build release supported at MinimumControlPlaneVersion",
vg: &fakeVersionGetter{
clusterVersion: constants.MinimumControlPlaneVersion.String(),
kubeletVersion: constants.MinimumControlPlaneVersion.String(),
kubeadmVersion: constants.MinimumControlPlaneVersion.WithBuildMetadata("build").String(),
clusterVersion: minimumControlPlaneVersion.String(),
kubeletVersion: minimumControlPlaneVersion.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)
oldcfg, err := getConfig(constants.MinimumControlPlaneVersion.String(), tempCertsDir, tmpEtcdDataDir)
oldcfg, err := getConfig("v1.3.0", tempCertsDir, tmpEtcdDataDir)
if err != nil {
t.Fatalf("couldn't create config: %v", err)
}

View File

@ -35,6 +35,7 @@ import (
"time"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"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/util/initsystem"
@ -44,6 +45,7 @@ import (
netutil "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/version"
versionutil "k8s.io/apimachinery/pkg/util/version"
kubeadmversion "k8s.io/component-base/version"
"k8s.io/klog/v2"
@ -604,6 +606,7 @@ func (kubever KubernetesVersionCheck) Check() (warnings, errorList []error) {
// KubeletVersionCheck validates installed kubelet version
type KubeletVersionCheck struct {
KubernetesVersion string
minKubeletVersion *version.Version
exec utilsexec.Interface
}
@ -619,7 +622,10 @@ func (kubever KubeletVersionCheck) Check() (warnings, errorList []error) {
if err != nil {
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)}
}

View File

@ -33,6 +33,7 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/utils/exec"
fakeexec "k8s.io/utils/exec/testing"
@ -786,19 +787,22 @@ func restoreEnv(e map[string]string) {
}
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 {
kubeletVersion string
k8sVersion string
expectErrors bool
expectWarnings bool
}{
{"v" + constants.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.
{"v" + constants.MinimumKubeletVersion.String(), constants.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" + constants.MinimumKubeletVersion.String(), constants.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" + constants.CurrentKubernetesVersion.String(), constants.MinimumControlPlaneVersion.WithPatch(5).String(), true, false}, // kubelet is newer (release) than control plane, should fail.
{"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.
{"v" + minimumKubeletVersion.String(), minimumControlPlaneVersion.WithPatch(5).String(), false, false}, // kubelet 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" + minimumKubeletVersion.String(), currentKubernetesVersion.WithPatch(1).String(), false, false}, // kubelet is lower than control plane, but newer than minimally supported
{"v" + currentKubernetesVersion.WithPreRelease("alpha.1").String(), minimumControlPlaneVersion.WithPatch(1).String(), true, false}, // kubelet is newer (development build) 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 {
@ -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()
switch {