Merge pull request #54868 from kad/kubeadm-issue-496

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

kubeadm: Extended KubeletVersionCheck

**What this PR does / why we need it**:
KubeletVersionCheck now able to detect if kubelet version
is higher than control plane. As this might lead to malfunctional
cluster setups, kubeadm will give warning.

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes kubernetes/kubeadm#496

**Special notes for your reviewer**:
/sig cluster-lifecycle
/area kubeadm

**Release note**:
```release-note
- kubeadm will produce error if kubelet too new for control plane
```
This commit is contained in:
Kubernetes Submit Queue 2017-11-09 04:12:49 -08:00 committed by GitHub
commit 065e45087b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 3 deletions

View File

@ -498,7 +498,9 @@ func (kubever KubernetesVersionCheck) Check() (warnings, errors []error) {
}
// KubeletVersionCheck validates installed kubelet version
type KubeletVersionCheck struct{}
type KubeletVersionCheck struct {
KubernetesVersion string
}
// Check validates kubelet version. It should be not less than minimal supported version
func (kubever KubeletVersionCheck) Check() (warnings, errors []error) {
@ -509,7 +511,17 @@ func (kubever KubeletVersionCheck) Check() (warnings, errors []error) {
if kubeletVersion.LessThan(kubeadmconstants.MinimumKubeletVersion) {
return nil, []error{fmt.Errorf("Kubelet version %q is lower than kubadm can support. Please upgrade kubelet", kubeletVersion)}
}
return nil, []error{}
if kubever.KubernetesVersion != "" {
k8sVersion, err := versionutil.ParseSemantic(kubever.KubernetesVersion)
if err != nil {
return nil, []error{fmt.Errorf("couldn't parse kubernetes version %q: %v", kubever.KubernetesVersion, err)}
}
if kubeletVersion.Major() > k8sVersion.Major() || kubeletVersion.Minor() > k8sVersion.Minor() {
return nil, []error{fmt.Errorf("the kubelet version is higher than the control plane version. This is not a supported version skew and may lead to a malfunctional cluster. Kubelet version: %q Control plane version: %q", kubeletVersion, k8sVersion)}
}
}
return nil, nil
}
// SwapCheck warns if swap is enabled
@ -688,7 +700,7 @@ func RunInitMasterChecks(cfg *kubeadmapi.MasterConfiguration) error {
SystemVerificationCheck{},
IsPrivilegedUserCheck{},
HostnameCheck{nodeName: cfg.NodeName},
KubeletVersionCheck{},
KubeletVersionCheck{KubernetesVersion: cfg.KubernetesVersion},
ServiceCheck{Service: "kubelet", CheckIfActive: false},
ServiceCheck{Service: "docker", CheckIfActive: true},
FirewalldCheck{ports: []int{int(cfg.API.BindPort), 10250}},

View File

@ -20,6 +20,7 @@ import (
"bytes"
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"testing"
@ -556,3 +557,59 @@ func restoreEnv(e map[string]string) {
os.Setenv(k, v)
}
}
func TestKubeletVersionCheck(t *testing.T) {
type T struct {
kubeletVersion string
k8sVersion string
expectErrors bool
expectWarnings bool
}
cases := []T{
{"v1.10.2", "", false, false}, // check minimally supported version when there is no information about control plane
{"v1.7.3", "v1.7.8", true, false}, // too old kubelet (older than kubeadmconstants.MinimumKubeletVersion), should fail.
{"v1.9.0", "v1.9.5", false, false}, // kubelet within same major.minor as control plane
{"v1.9.5", "v1.9.1", false, false}, // kubelet is newer, but still within same major.minor as control plane
{"v1.9.0", "v1.10.1", false, false}, // kubelet is lower than control plane, but newer than minimally supported
{"v1.10.0-alpha.1", "v1.9.1", true, false}, // kubelet is newer (development build) than control plane, should fail.
{"v1.10.0", "v1.9.5", true, false}, // kubelet is newer (release) than control plane, should fail.
}
dir, err := ioutil.TempDir("", "test-kubelet-version-check")
if err != nil {
t.Errorf("Failed to create directory for testing GetKubeletVersion: %v", err)
}
defer os.RemoveAll(dir)
// We don't want to call real kubelet or something else in $PATH
oldPATH := os.Getenv("PATH")
defer os.Setenv("PATH", oldPATH)
os.Setenv("PATH", dir)
kubeletFn := filepath.Join(dir, "kubelet")
for _, tc := range cases {
content := []byte(fmt.Sprintf("#!/bin/sh\necho 'Kubernetes %s'", tc.kubeletVersion))
if err := ioutil.WriteFile(kubeletFn, content, 0755); err != nil {
t.Errorf("Error creating test stub file %s: %v", kubeletFn, err)
}
check := KubeletVersionCheck{KubernetesVersion: tc.k8sVersion}
warnings, errors := check.Check()
switch {
case warnings != nil && !tc.expectWarnings:
t.Errorf("KubeletVersionCheck: unexpected warnings for kubelet version %q and kubernetes version %q. Warnings: %v", tc.kubeletVersion, tc.k8sVersion, warnings)
case warnings == nil && tc.expectWarnings:
t.Errorf("KubeletVersionCheck: expected warnings for kubelet version %q and kubernetes version %q but got nothing", tc.kubeletVersion, tc.k8sVersion)
case errors != nil && !tc.expectErrors:
t.Errorf("KubeletVersionCheck: unexpected errors for kubelet version %q and kubernetes version %q. errors: %v", tc.kubeletVersion, tc.k8sVersion, errors)
case errors == nil && tc.expectErrors:
t.Errorf("KubeletVersionCheck: expected errors for kubelet version %q and kubernetes version %q but got nothing", tc.kubeletVersion, tc.k8sVersion)
}
}
}