Merge pull request #88373 from SataQiu/fix-kubeadm-20200220

kubeadm: fallback to a known etcd version if an unknown k8s version is passed
This commit is contained in:
Kubernetes Prow Robot 2020-02-24 05:14:47 -08:00 committed by GitHub
commit 20e3288277
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 92 additions and 47 deletions

View File

@ -45,6 +45,5 @@ go_test(
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)

View File

@ -27,6 +27,7 @@ import (
"time"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/apimachinery/pkg/util/wait"
@ -456,21 +457,45 @@ var (
)
// EtcdSupportedVersion returns officially supported version of etcd for a specific Kubernetes release
// if passed version is not listed, the function returns nil and an error
func EtcdSupportedVersion(versionString string) (*version.Version, error) {
// If passed version is not in the given list, the function returns the nearest version with a warning
func EtcdSupportedVersion(supportedEtcdVersion map[uint8]string, versionString string) (etcdVersion *version.Version, warning, err error) {
kubernetesVersion, err := version.ParseSemantic(versionString)
if err != nil {
return nil, err
return nil, nil, err
}
desiredVersion, etcdStringVersion := uint8(kubernetesVersion.Minor()), ""
min, max := ^uint8(0), uint8(0)
for k, v := range supportedEtcdVersion {
if desiredVersion == k {
etcdStringVersion = v
break
}
if k < min {
min = k
}
if k > max {
max = k
}
}
if etcdStringVersion, ok := SupportedEtcdVersion[uint8(kubernetesVersion.Minor())]; ok {
etcdVersion, err := version.ParseSemantic(etcdStringVersion)
if err != nil {
return nil, err
if len(etcdStringVersion) == 0 {
if desiredVersion < min {
etcdStringVersion = supportedEtcdVersion[min]
}
return etcdVersion, nil
if desiredVersion > max {
etcdStringVersion = supportedEtcdVersion[max]
}
warning = fmt.Errorf("could not find officially supported version of etcd for Kubernetes %s, falling back to the nearest etcd version (%s)",
versionString, etcdStringVersion)
}
return nil, errors.Errorf("unsupported or unknown Kubernetes version(%v)", kubernetesVersion)
etcdVersion, err = version.ParseSemantic(etcdStringVersion)
if err != nil {
return nil, nil, err
}
return etcdVersion, warning, nil
}
// GetStaticPodDirectory returns the location on the disk where the Static Pod should be present

View File

@ -18,11 +18,8 @@ package constants
import (
"path/filepath"
"strings"
"testing"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/version"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
)
@ -149,50 +146,62 @@ func TestAddSelfHostedPrefix(t *testing.T) {
}
func TestEtcdSupportedVersion(t *testing.T) {
var supportedEtcdVersion = map[uint8]string{
13: "3.2.24",
14: "3.3.10",
15: "3.3.10",
16: "3.3.17-0",
17: "3.4.3-0",
18: "3.4.3-0",
}
var tests = []struct {
kubernetesVersion string
expectedVersion *version.Version
expectedError error
expectedWarning bool
expectedError bool
}{
{
kubernetesVersion: "1.99.0",
kubernetesVersion: "1.x.1",
expectedVersion: nil,
expectedError: errors.New("unsupported or unknown Kubernetes version(1.99.0)"),
expectedWarning: false,
expectedError: true,
},
{
kubernetesVersion: MinimumControlPlaneVersion.WithPatch(1).String(),
expectedVersion: version.MustParseSemantic(SupportedEtcdVersion[uint8(MinimumControlPlaneVersion.Minor())]),
expectedError: nil,
kubernetesVersion: "1.10.1",
expectedVersion: version.MustParseSemantic("3.2.24"),
expectedWarning: true,
expectedError: false,
},
{
kubernetesVersion: CurrentKubernetesVersion.String(),
expectedVersion: version.MustParseSemantic(SupportedEtcdVersion[uint8(CurrentKubernetesVersion.Minor())]),
expectedError: nil,
kubernetesVersion: "1.99.0",
expectedVersion: version.MustParseSemantic("3.4.3-0"),
expectedWarning: true,
expectedError: false,
},
{
kubernetesVersion: "v1.16.0",
expectedVersion: version.MustParseSemantic("3.3.17-0"),
expectedWarning: false,
expectedError: false,
},
{
kubernetesVersion: "1.17.2",
expectedVersion: version.MustParseSemantic("3.4.3-0"),
expectedWarning: false,
expectedError: false,
},
}
for _, rt := range tests {
t.Run(rt.kubernetesVersion, func(t *testing.T) {
actualVersion, actualError := EtcdSupportedVersion(rt.kubernetesVersion)
if actualError != nil {
if rt.expectedError == nil {
t.Errorf("failed EtcdSupportedVersion:\n\texpected no error, but got: %v", actualError)
} else if actualError.Error() != rt.expectedError.Error() {
t.Errorf(
"failed EtcdSupportedVersion:\n\texpected error: %v\n\t actual error: %v",
rt.expectedError,
actualError,
)
}
} else {
if rt.expectedError != nil {
t.Errorf("failed EtcdSupportedVersion:\n\texpected error: %v, but got no error", rt.expectedError)
} else if strings.Compare(actualVersion.String(), rt.expectedVersion.String()) != 0 {
t.Errorf(
"failed EtcdSupportedVersion:\n\texpected version: %s\n\t actual version: %s",
rt.expectedVersion.String(),
actualVersion.String(),
)
}
actualVersion, actualWarning, actualError := EtcdSupportedVersion(supportedEtcdVersion, rt.kubernetesVersion)
if (actualError != nil) != rt.expectedError {
t.Fatalf("expected error %v, got %v", rt.expectedError, actualError != nil)
}
if (actualWarning != nil) != rt.expectedWarning {
t.Fatalf("expected warning %v, got %v", rt.expectedWarning, actualWarning != nil)
}
if actualError == nil && actualVersion.String() != rt.expectedVersion.String() {
t.Errorf("expected version %s, got %s", rt.expectedVersion.String(), actualVersion.String())
}
})
}

View File

@ -73,10 +73,13 @@ func GetEtcdImage(cfg *kubeadmapi.ClusterConfiguration) string {
}
// Etcd uses an imageTag that corresponds to the etcd version matching the Kubernetes version
etcdImageTag := constants.DefaultEtcdVersion
etcdVersion, err := constants.EtcdSupportedVersion(cfg.KubernetesVersion)
etcdVersion, warning, err := constants.EtcdSupportedVersion(constants.SupportedEtcdVersion, cfg.KubernetesVersion)
if err == nil {
etcdImageTag = etcdVersion.String()
}
if warning != nil {
klog.Warningln(warning)
}
// unless an override is specified
if cfg.Etcd.Local != nil && cfg.Etcd.Local.ImageTag != "" {
etcdImageTag = cfg.Etcd.Local.ImageTag

View File

@ -22,6 +22,7 @@ import (
versionutil "k8s.io/apimachinery/pkg/util/version"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/klog"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
@ -300,10 +301,13 @@ func minorUpgradePossibleWithPatchRelease(stableVersion, patchVersion *versionut
}
func getSuggestedEtcdVersion(kubernetesVersion string) string {
etcdVersion, err := kubeadmconstants.EtcdSupportedVersion(kubernetesVersion)
etcdVersion, warning, err := kubeadmconstants.EtcdSupportedVersion(kubeadmconstants.SupportedEtcdVersion, kubernetesVersion)
if err != nil {
fmt.Printf("[upgrade/versions] WARNING: No recommended etcd for requested Kubernetes version (%s)\n", kubernetesVersion)
klog.Warningf("[upgrade/versions] could not retrieve an etcd version for the target Kubernetes version: %v", err)
return "N/A"
}
if warning != nil {
klog.Warningf("[upgrade/versions] %v", warning)
}
return etcdVersion.String()
}

View File

@ -24,9 +24,11 @@ import (
"time"
"github.com/pkg/errors"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/version"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/klog"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
@ -281,10 +283,13 @@ func performEtcdStaticPodUpgrade(certsRenewMgr *renewal.Manager, client clientse
}
// Need to check currently used version and version from constants, if differs then upgrade
desiredEtcdVersion, err := constants.EtcdSupportedVersion(cfg.KubernetesVersion)
desiredEtcdVersion, warning, err := constants.EtcdSupportedVersion(constants.SupportedEtcdVersion, cfg.KubernetesVersion)
if err != nil {
return true, errors.Wrap(err, "failed to retrieve an etcd version for the target Kubernetes version")
}
if warning != nil {
klog.Warningf("[upgrade/etcd] %v", warning)
}
// gets the etcd version of the local/stacked etcd member running on the current machine
currentEtcdVersions, err := oldEtcdClient.GetClusterVersions()