Enforce not using newer kubeadm to upgrade older kubeadm

This commit is contained in:
liz 2018-04-13 16:52:24 -07:00
parent 55f28a662d
commit 3c92e358f7
No known key found for this signature in database
GPG Key ID: 42D1F3A8C4A02586
2 changed files with 70 additions and 36 deletions

View File

@ -116,6 +116,12 @@ func EnforceVersionPolicies(versionGetter VersionGetter, newK8sVersionStr string
} }
} }
if kubeadmVersion.Major() > newK8sVersion.Major() ||
kubeadmVersion.Minor() > newK8sVersion.Minor() {
skewErrors.Mandatory = append(skewErrors.Mandatory, fmt.Errorf("Kubeadm version %s can only be used to upgrade to Kubernetes versions %d.%d", kubeadmVersionStr, kubeadmVersion.Major(), kubeadmVersion.Minor()))
}
// Detect if the version is unstable and the user didn't allow that // Detect if the version is unstable and the user didn't allow that
if err = detectUnstableVersionError(newK8sVersion, newK8sVersionStr, allowExperimentalUpgrades, allowRCUpgrades); err != nil { if err = detectUnstableVersionError(newK8sVersion, newK8sVersionStr, allowExperimentalUpgrades, allowRCUpgrades); err != nil {
skewErrors.Skippable = append(skewErrors.Skippable, err) skewErrors.Skippable = append(skewErrors.Skippable, err)

View File

@ -24,13 +24,15 @@ import (
func TestEnforceVersionPolicies(t *testing.T) { func TestEnforceVersionPolicies(t *testing.T) {
tests := []struct { tests := []struct {
name string
vg *fakeVersionGetter vg *fakeVersionGetter
expectedMandatoryErrs int expectedMandatoryErrs int
expectedSkippableErrs int expectedSkippableErrs int
allowExperimental, allowRCs bool allowExperimental, allowRCs bool
newK8sVersion string newK8sVersion string
}{ }{
{ // everything ok {
name: "minor upgrade",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
@ -38,7 +40,8 @@ func TestEnforceVersionPolicies(t *testing.T) {
}, },
newK8sVersion: "v1.9.5", newK8sVersion: "v1.9.5",
}, },
{ // everything ok {
name: "major upgrade",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.2", kubeletVersion: "v1.9.2",
@ -46,7 +49,8 @@ func TestEnforceVersionPolicies(t *testing.T) {
}, },
newK8sVersion: "v1.10.0", newK8sVersion: "v1.10.0",
}, },
{ // downgrades ok {
name: "downgrade",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
@ -54,7 +58,8 @@ func TestEnforceVersionPolicies(t *testing.T) {
}, },
newK8sVersion: "v1.9.2", newK8sVersion: "v1.9.2",
}, },
{ // upgrades without bumping the version number ok {
name: "same version upgrade",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
@ -62,16 +67,18 @@ func TestEnforceVersionPolicies(t *testing.T) {
}, },
newK8sVersion: "v1.9.3", newK8sVersion: "v1.9.3",
}, },
{ // new version must be higher than v1.9.0 {
name: "new version must be higher than v1.9.0",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
kubeadmVersion: "v1.9.3", kubeadmVersion: "v1.9.3",
}, },
newK8sVersion: "v1.8.10", newK8sVersion: "v1.8.10",
expectedMandatoryErrs: 1, // version must be higher than v1.9.0 expectedMandatoryErrs: 2, // version must be higher than v1.9.0, can't upgrade old k8s with newer kubeadm
}, },
{ // upgrading two minor versions in one go is not supported {
name: "upgrading two minor versions in one go is not supported",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
@ -81,16 +88,18 @@ func TestEnforceVersionPolicies(t *testing.T) {
expectedMandatoryErrs: 1, // can't upgrade two minor versions expectedMandatoryErrs: 1, // can't upgrade two minor versions
expectedSkippableErrs: 1, // kubelet <-> apiserver skew too large expectedSkippableErrs: 1, // kubelet <-> apiserver skew too large
}, },
{ // 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: "v1.11.3", clusterVersion: "v1.11.3",
kubeletVersion: "v1.11.3", kubeletVersion: "v1.11.3",
kubeadmVersion: "v1.11.0", kubeadmVersion: "v1.11.0",
}, },
newK8sVersion: "v1.9.3", newK8sVersion: "v1.9.3",
expectedMandatoryErrs: 1, // can't downgrade two minor versions expectedMandatoryErrs: 2, // can't downgrade two minor versions, can't upgrade old k8s with newer kubeadm
}, },
{ // 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: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
@ -99,7 +108,8 @@ func TestEnforceVersionPolicies(t *testing.T) {
newK8sVersion: "v1.9.5", newK8sVersion: "v1.9.5",
expectedSkippableErrs: 1, expectedSkippableErrs: 1,
}, },
{ // 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: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
@ -108,7 +118,8 @@ func TestEnforceVersionPolicies(t *testing.T) {
newK8sVersion: "v1.10.0", newK8sVersion: "v1.10.0",
expectedMandatoryErrs: 1, expectedMandatoryErrs: 1,
}, },
{ // the maximum skew between the cluster version and the kubelet versions should be one minor version. This may be forced through though. {
name: "the maximum skew between the cluster version and the kubelet versions should be one minor version. This may be forced through though.",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.8.8", kubeletVersion: "v1.8.8",
@ -117,7 +128,8 @@ func TestEnforceVersionPolicies(t *testing.T) {
newK8sVersion: "v1.10.0", newK8sVersion: "v1.10.0",
expectedSkippableErrs: 1, expectedSkippableErrs: 1,
}, },
{ // experimental upgrades supported if the flag is set {
name: "experimental upgrades supported if the flag is set",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
@ -126,7 +138,8 @@ func TestEnforceVersionPolicies(t *testing.T) {
newK8sVersion: "v1.10.0-beta.1", newK8sVersion: "v1.10.0-beta.1",
allowExperimental: true, allowExperimental: true,
}, },
{ // release candidate upgrades supported if the flag is set {
name: "release candidate upgrades supported if the flag is set",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
@ -135,7 +148,8 @@ func TestEnforceVersionPolicies(t *testing.T) {
newK8sVersion: "v1.10.0-rc.1", newK8sVersion: "v1.10.0-rc.1",
allowRCs: true, allowRCs: true,
}, },
{ // release candidate upgrades supported if the flag is set {
name: "release candidate upgrades supported if the flag is set",
vg: &fakeVersionGetter{ vg: &fakeVersionGetter{
clusterVersion: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
@ -144,7 +158,8 @@ func TestEnforceVersionPolicies(t *testing.T) {
newK8sVersion: "v1.10.0-rc.1", newK8sVersion: "v1.10.0-rc.1",
allowExperimental: true, allowExperimental: true,
}, },
{ // 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: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
@ -154,7 +169,8 @@ func TestEnforceVersionPolicies(t *testing.T) {
allowRCs: true, allowRCs: true,
expectedSkippableErrs: 1, expectedSkippableErrs: 1,
}, },
{ // 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: "v1.9.3", clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3", kubeletVersion: "v1.9.3",
@ -163,30 +179,42 @@ func TestEnforceVersionPolicies(t *testing.T) {
newK8sVersion: "v1.10.0-rc.1", newK8sVersion: "v1.10.0-rc.1",
expectedSkippableErrs: 1, expectedSkippableErrs: 1,
}, },
{
name: "the user can't use a newer minor version of kubeadm to upgrade an older version of kubeadm",
vg: &fakeVersionGetter{
clusterVersion: "v1.9.3",
kubeletVersion: "v1.9.3",
kubeadmVersion: "v1.10.0",
},
newK8sVersion: "v1.9.6",
expectedMandatoryErrs: 1, // can't upgrade old k8s with newer kubeadm
},
} }
for _, rt := range tests { for _, rt := range tests {
t.Run(rt.name, func(t *testing.T) {
newK8sVer, err := version.ParseSemantic(rt.newK8sVersion) newK8sVer, err := version.ParseSemantic(rt.newK8sVersion)
if err != nil { if err != nil {
t.Fatalf("couldn't parse version %s: %v", rt.newK8sVersion, err) t.Fatalf("couldn't parse version %s: %v", rt.newK8sVersion, err)
}
actualSkewErrs := EnforceVersionPolicies(rt.vg, rt.newK8sVersion, newK8sVer, rt.allowExperimental, rt.allowRCs)
if actualSkewErrs == nil {
// No errors were seen. Report unit test failure if we expected to see errors
if rt.expectedMandatoryErrs+rt.expectedSkippableErrs > 0 {
t.Errorf("failed TestEnforceVersionPolicies\n\texpected errors but got none")
} }
// Otherwise, just move on with the next test
continue
}
if len(actualSkewErrs.Skippable) != rt.expectedSkippableErrs { actualSkewErrs := EnforceVersionPolicies(rt.vg, rt.newK8sVersion, newK8sVer, rt.allowExperimental, rt.allowRCs)
t.Errorf("failed TestEnforceVersionPolicies\n\texpected skippable errors: %d\n\tgot skippable errors: %d %v", rt.expectedSkippableErrs, len(actualSkewErrs.Skippable), *rt.vg) if actualSkewErrs == nil {
} // No errors were seen. Report unit test failure if we expected to see errors
if len(actualSkewErrs.Mandatory) != rt.expectedMandatoryErrs { if rt.expectedMandatoryErrs+rt.expectedSkippableErrs > 0 {
t.Errorf("failed TestEnforceVersionPolicies\n\texpected mandatory errors: %d\n\tgot mandatory errors: %d %v", rt.expectedMandatoryErrs, len(actualSkewErrs.Mandatory), *rt.vg) t.Errorf("failed TestEnforceVersionPolicies\n\texpected errors but got none")
} }
// Otherwise, just move on with the next test
return
}
if len(actualSkewErrs.Skippable) != rt.expectedSkippableErrs {
t.Errorf("failed TestEnforceVersionPolicies\n\texpected skippable errors: %d\n\tgot skippable errors: %d %v", rt.expectedSkippableErrs, len(actualSkewErrs.Skippable), *rt.vg)
}
if len(actualSkewErrs.Mandatory) != rt.expectedMandatoryErrs {
t.Errorf("failed TestEnforceVersionPolicies\n\texpected mandatory errors: %d\n\tgot mandatory errors: %d %v", rt.expectedMandatoryErrs, len(actualSkewErrs.Mandatory), *rt.vg)
}
})
} }
} }