mirror of https://github.com/k3s-io/k3s
Detect major version mismatches between kubeadm and kubelet.
Kubeadm supports only one minor release back, thus for 1.9 it requires minimum kubelet from 1.8. Fixes: kubernetes/kubeadm#430pull/6/head
parent
b188868fd9
commit
521c84aa89
|
@ -20,9 +20,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/renstrom/dedent"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -220,11 +218,11 @@ func (j *Join) Run(out io.Writer) error {
|
|||
kubeconfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletBootstrapKubeConfigFileName)
|
||||
|
||||
// Depending on the kubelet version, we might perform the TLS bootstrap or not
|
||||
kubeletVersionBytes, err := exec.Command("sh", "-c", "kubelet --version").Output()
|
||||
kubeletVersion, err := preflight.GetKubeletVersion()
|
||||
// In case the command executed successfully and returned v1.7-something, we'll perform TLS Bootstrapping
|
||||
// Otherwise, just assume v1.8
|
||||
// TODO: In the beginning of the v1.9 cycle, we can remove the logic as we then don't support v1.7 anymore
|
||||
if err == nil && strings.HasPrefix(string(kubeletVersionBytes), "Kubernetes v1.7") {
|
||||
if err == nil && kubeletVersion.Major() == 1 && kubeletVersion.Minor() == 7 {
|
||||
hostname := nodeutil.GetHostname(j.cfg.NodeName)
|
||||
if err := kubeadmnode.PerformTLSBootstrap(cfg, hostname); err != nil {
|
||||
return err
|
||||
|
|
|
@ -211,6 +211,9 @@ var (
|
|||
// UseEnableBootstrapTokenAuthFlagVersion defines the first version where the API server supports the --enable-bootstrap-token-auth flag instead of the old and deprecated flag.
|
||||
// TODO: Remove this when the v1.9 cycle starts and we bump the minimum supported version to v1.8.0
|
||||
UseEnableBootstrapTokenAuthFlagVersion = version.MustParseSemantic("v1.8.0-beta.0")
|
||||
|
||||
// MinimumKubeletVersion specifies the minimum version of kubelet which kubeadm supports
|
||||
MinimumKubeletVersion = version.MustParseSemantic("v1.8.0-beta.0")
|
||||
)
|
||||
|
||||
// GetStaticPodDirectory returns the location on the disk where the Static Pod should be present
|
||||
|
|
|
@ -8,7 +8,10 @@ load(
|
|||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["checks.go"],
|
||||
srcs = [
|
||||
"checks.go",
|
||||
"utils.go",
|
||||
],
|
||||
deps = [
|
||||
"//cmd/kube-apiserver/app/options:go_default_library",
|
||||
"//cmd/kube-controller-manager/app/options:go_default_library",
|
||||
|
@ -29,7 +32,10 @@ go_library(
|
|||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["checks_test.go"],
|
||||
srcs = [
|
||||
"checks_test.go",
|
||||
"utils_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
|
|
|
@ -449,6 +449,21 @@ func (kubever KubernetesVersionCheck) Check() (warnings, errors []error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// KubeletVersionCheck validates installed kubelet version
|
||||
type KubeletVersionCheck struct{}
|
||||
|
||||
// Check validates kubelet version. It should be not less than minimal supported version
|
||||
func (kubever KubeletVersionCheck) Check() (warnings, errors []error) {
|
||||
kubeletVersion, err := GetKubeletVersion()
|
||||
if err != nil {
|
||||
return nil, []error{fmt.Errorf("couldn't get kubelet version: %v", err)}
|
||||
}
|
||||
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{}
|
||||
}
|
||||
|
||||
// SwapCheck warns if swap is enabled
|
||||
type SwapCheck struct{}
|
||||
|
||||
|
@ -625,6 +640,7 @@ func RunInitMasterChecks(cfg *kubeadmapi.MasterConfiguration) error {
|
|||
SystemVerificationCheck{},
|
||||
IsRootCheck{},
|
||||
HostnameCheck{nodeName: cfg.NodeName},
|
||||
KubeletVersionCheck{},
|
||||
ServiceCheck{Service: "kubelet", CheckIfActive: false},
|
||||
ServiceCheck{Service: "docker", CheckIfActive: true},
|
||||
FirewalldCheck{ports: []int{int(cfg.API.BindPort), 10250}},
|
||||
|
@ -690,6 +706,7 @@ func RunJoinNodeChecks(cfg *kubeadmapi.NodeConfiguration) error {
|
|||
SystemVerificationCheck{},
|
||||
IsRootCheck{},
|
||||
HostnameCheck{cfg.NodeName},
|
||||
KubeletVersionCheck{},
|
||||
ServiceCheck{Service: "kubelet", CheckIfActive: false},
|
||||
ServiceCheck{Service: "docker", CheckIfActive: true},
|
||||
PortOpenCheck{port: 10250},
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes 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 preflight
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
// GetKubeletVersion is helper function that returns version of kubelet available in $PATH
|
||||
func GetKubeletVersion() (*version.Version, error) {
|
||||
kubeletVersionRegex := regexp.MustCompile(`^\s*Kubernetes v((0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)([-0-9a-zA-Z_\.+]*)?)\s*$`)
|
||||
|
||||
out, err := exec.Command("kubelet", "--version").Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cleanOutput := strings.TrimSpace(string(out))
|
||||
subs := kubeletVersionRegex.FindAllStringSubmatch(cleanOutput, -1)
|
||||
if len(subs) != 1 || len(subs[0]) < 2 {
|
||||
return nil, fmt.Errorf("Unable to parse output from Kubelet: %q", cleanOutput)
|
||||
}
|
||||
return version.ParseSemantic(subs[0][1])
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes 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 preflight
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetKubeletVersion(t *testing.T) {
|
||||
type T struct {
|
||||
output string
|
||||
expected string
|
||||
valid bool
|
||||
}
|
||||
|
||||
cases := []T{
|
||||
{"v1.7.0", "1.7.0", true},
|
||||
{"v1.8.0-alpha.2.1231+afabd012389d53a", "1.8.0-alpha.2.1231+afabd012389d53a", true},
|
||||
{"something-invalid", "", false},
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "test-kubelet-version")
|
||||
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)
|
||||
|
||||
// First test case, kubelet not present, should be getting error
|
||||
ver, err := GetKubeletVersion()
|
||||
if err == nil {
|
||||
t.Errorf("failed GetKubeletVersion: expected failure when kubelet not in PATH. Result: %v", ver)
|
||||
}
|
||||
|
||||
kubeletFn := filepath.Join(dir, "kubelet")
|
||||
for _, tc := range cases {
|
||||
|
||||
content := []byte(fmt.Sprintf("#!/bin/sh\necho 'Kubernetes %s'", tc.output))
|
||||
if err := ioutil.WriteFile(kubeletFn, content, 0755); err != nil {
|
||||
t.Errorf("Error creating test stub file %s: %v", kubeletFn, err)
|
||||
}
|
||||
|
||||
ver, err := GetKubeletVersion()
|
||||
switch {
|
||||
case err != nil && tc.valid:
|
||||
t.Errorf("GetKubeletVersion: unexpected error for %q. Error: %v", tc.output, err)
|
||||
case err == nil && !tc.valid:
|
||||
t.Errorf("GetKubeletVersion: error expected for key %q, but result is %q", tc.output, ver)
|
||||
case ver != nil && ver.String() != tc.expected:
|
||||
t.Errorf("GetKubeletVersion: unexpected version result for key %q. Expected: %q Actual: %q", tc.output, tc.expected, ver)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue