| /* |
| 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 upgrade |
| |
| import ( |
| "fmt" |
| "reflect" |
| "testing" |
| "time" |
| |
| "github.com/coreos/etcd/clientv3" |
| "github.com/pkg/errors" |
| apps "k8s.io/api/apps/v1" |
| "k8s.io/api/core/v1" |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| versionutil "k8s.io/apimachinery/pkg/util/version" |
| clientsetfake "k8s.io/client-go/kubernetes/fake" |
| kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" |
| "k8s.io/kubernetes/cmd/kubeadm/app/constants" |
| etcdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd" |
| ) |
| |
| type fakeVersionGetter struct { |
| clusterVersion, kubeadmVersion, stableVersion, latestVersion, latestDevBranchVersion, stablePatchVersion, kubeletVersion string |
| } |
| |
| var _ VersionGetter = &fakeVersionGetter{} |
| |
| // ClusterVersion gets a fake API server version |
| func (f *fakeVersionGetter) ClusterVersion() (string, *versionutil.Version, error) { |
| return f.clusterVersion, versionutil.MustParseSemantic(f.clusterVersion), nil |
| } |
| |
| // KubeadmVersion gets a fake kubeadm version |
| func (f *fakeVersionGetter) KubeadmVersion() (string, *versionutil.Version, error) { |
| return f.kubeadmVersion, versionutil.MustParseSemantic(f.kubeadmVersion), nil |
| } |
| |
| // VersionFromCILabel gets fake latest versions from CI |
| func (f *fakeVersionGetter) VersionFromCILabel(ciVersionLabel, _ string) (string, *versionutil.Version, error) { |
| if ciVersionLabel == "stable" { |
| return f.stableVersion, versionutil.MustParseSemantic(f.stableVersion), nil |
| } |
| if ciVersionLabel == "latest" { |
| return f.latestVersion, versionutil.MustParseSemantic(f.latestVersion), nil |
| } |
| if ciVersionLabel == "latest-1.11" { |
| return f.latestDevBranchVersion, versionutil.MustParseSemantic(f.latestDevBranchVersion), nil |
| } |
| return f.stablePatchVersion, versionutil.MustParseSemantic(f.stablePatchVersion), nil |
| } |
| |
| // KubeletVersions gets the versions of the kubelets in the cluster |
| func (f *fakeVersionGetter) KubeletVersions() (map[string]uint16, error) { |
| return map[string]uint16{ |
| f.kubeletVersion: 1, |
| }, nil |
| } |
| |
| type fakeEtcdClient struct { |
| TLS bool |
| mismatchedVersions bool |
| } |
| |
| func (f fakeEtcdClient) HasTLS() bool { return f.TLS } |
| |
| func (f fakeEtcdClient) ClusterAvailable() (bool, error) { return true, nil } |
| |
| func (f fakeEtcdClient) WaitForClusterAvailable(delay time.Duration, retries int, retryInterval time.Duration) (bool, error) { |
| return true, nil |
| } |
| |
| func (f fakeEtcdClient) GetClusterStatus() (map[string]*clientv3.StatusResponse, error) { |
| return make(map[string]*clientv3.StatusResponse), nil |
| } |
| |
| func (f fakeEtcdClient) GetVersion() (string, error) { |
| versions, _ := f.GetClusterVersions() |
| if f.mismatchedVersions { |
| return "", errors.Errorf("etcd cluster contains endpoints with mismatched versions: %v", versions) |
| } |
| return "3.1.12", nil |
| } |
| |
| func (f fakeEtcdClient) GetClusterVersions() (map[string]string, error) { |
| if f.mismatchedVersions { |
| return map[string]string{ |
| "foo": "3.1.12", |
| "bar": "3.2.0", |
| }, nil |
| } |
| return map[string]string{ |
| "foo": "3.1.12", |
| "bar": "3.1.12", |
| }, nil |
| } |
| |
| func (f fakeEtcdClient) Sync() error { return nil } |
| |
| func (f fakeEtcdClient) AddMember(name string, peerAddrs string) ([]etcdutil.Member, error) { |
| return []etcdutil.Member{}, nil |
| } |
| |
| func TestGetAvailableUpgrades(t *testing.T) { |
| etcdClient := fakeEtcdClient{} |
| tests := []struct { |
| name string |
| vg VersionGetter |
| expectedUpgrades []Upgrade |
| allowExperimental, allowRCs bool |
| errExpected bool |
| etcdClient etcdutil.ClusterInterrogator |
| beforeDNSType kubeadmapi.DNSAddOnType |
| beforeDNSVersion string |
| dnsType kubeadmapi.DNSAddOnType |
| }{ |
| { |
| name: "no action needed, already up-to-date", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.10.3", |
| kubeletVersion: "v1.10.3", |
| kubeadmVersion: "v1.10.3", |
| |
| stablePatchVersion: "v1.10.3", |
| stableVersion: "v1.10.3", |
| }, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "v1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{}, |
| allowExperimental: false, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "simple patch version upgrade", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.10.1", |
| kubeletVersion: "v1.10.1", // the kubelet are on the same version as the control plane |
| kubeadmVersion: "v1.10.2", |
| |
| stablePatchVersion: "v1.10.3", |
| stableVersion: "v1.10.3", |
| }, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "version in the v1.10 series", |
| Before: ClusterState{ |
| KubeVersion: "v1.10.1", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.1": 1, |
| }, |
| KubeadmVersion: "v1.10.2", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.10.3", |
| KubeadmVersion: "v1.10.3", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.1.12", |
| }, |
| }, |
| }, |
| allowExperimental: false, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "no version provided to offline version getter does not change behavior", |
| vg: NewOfflineVersionGetter(&fakeVersionGetter{ |
| clusterVersion: "v1.10.1", |
| kubeletVersion: "v1.10.1", // the kubelet are on the same version as the control plane |
| kubeadmVersion: "v1.10.2", |
| |
| stablePatchVersion: "v1.10.3", |
| stableVersion: "v1.10.3", |
| }, ""), |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "version in the v1.10 series", |
| Before: ClusterState{ |
| KubeVersion: "v1.10.1", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.1": 1, |
| }, |
| KubeadmVersion: "v1.10.2", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.10.3", |
| KubeadmVersion: "v1.10.3", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.1.12", |
| }, |
| }, |
| }, |
| allowExperimental: false, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "minor version upgrade only", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.10.1", |
| kubeletVersion: "v1.10.1", // the kubelet are on the same version as the control plane |
| kubeadmVersion: "v1.11.0", |
| |
| stablePatchVersion: "v1.10.1", |
| stableVersion: "v1.11.0", |
| }, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "stable version", |
| Before: ClusterState{ |
| KubeVersion: "v1.10.1", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.1": 1, |
| }, |
| KubeadmVersion: "v1.11.0", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.11.0", |
| KubeadmVersion: "v1.11.0", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.2.18", |
| }, |
| }, |
| }, |
| allowExperimental: false, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "both minor version upgrade and patch version upgrade available", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.10.3", |
| kubeletVersion: "v1.10.3", // the kubelet are on the same version as the control plane |
| kubeadmVersion: "v1.10.5", |
| |
| stablePatchVersion: "v1.10.5", |
| stableVersion: "v1.11.1", |
| }, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "version in the v1.10 series", |
| Before: ClusterState{ |
| KubeVersion: "v1.10.3", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.3": 1, |
| }, |
| KubeadmVersion: "v1.10.5", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.10.5", |
| KubeadmVersion: "v1.10.5", // Note: The kubeadm version mustn't be "downgraded" here |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.1.12", |
| }, |
| }, |
| { |
| Description: "stable version", |
| Before: ClusterState{ |
| KubeVersion: "v1.10.3", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.3": 1, |
| }, |
| KubeadmVersion: "v1.10.5", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.11.1", |
| KubeadmVersion: "v1.11.1", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.2.18", |
| }, |
| }, |
| }, |
| allowExperimental: false, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "allow experimental upgrades, but no upgrade available", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.11.0-alpha.2", |
| kubeletVersion: "v1.10.5", |
| kubeadmVersion: "v1.10.5", |
| |
| stablePatchVersion: "v1.10.5", |
| stableVersion: "v1.10.5", |
| latestVersion: "v1.11.0-alpha.2", |
| }, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "v1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{}, |
| allowExperimental: true, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "upgrade to an unstable version should be supported", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.10.5", |
| kubeletVersion: "v1.10.5", |
| kubeadmVersion: "v1.10.5", |
| |
| stablePatchVersion: "v1.10.5", |
| stableVersion: "v1.10.5", |
| latestVersion: "v1.11.0-alpha.2", |
| }, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "experimental version", |
| Before: ClusterState{ |
| KubeVersion: "v1.10.5", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.5": 1, |
| }, |
| KubeadmVersion: "v1.10.5", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.11.0-alpha.2", |
| KubeadmVersion: "v1.11.0-alpha.2", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.2.18", |
| }, |
| }, |
| }, |
| allowExperimental: true, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "upgrade from an unstable version to an unstable version should be supported", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.11.0-alpha.1", |
| kubeletVersion: "v1.10.5", |
| kubeadmVersion: "v1.10.5", |
| |
| stablePatchVersion: "v1.10.5", |
| stableVersion: "v1.10.5", |
| latestVersion: "v1.11.0-alpha.2", |
| }, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "experimental version", |
| Before: ClusterState{ |
| KubeVersion: "v1.11.0-alpha.1", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.5": 1, |
| }, |
| KubeadmVersion: "v1.10.5", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.11.0-alpha.2", |
| KubeadmVersion: "v1.11.0-alpha.2", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.2.18", |
| }, |
| }, |
| }, |
| allowExperimental: true, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "v1.X.0-alpha.0 should be ignored", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.10.5", |
| kubeletVersion: "v1.10.5", |
| kubeadmVersion: "v1.10.5", |
| |
| stablePatchVersion: "v1.10.5", |
| stableVersion: "v1.10.5", |
| latestDevBranchVersion: "v1.11.0-beta.1", |
| latestVersion: "v1.12.0-alpha.0", |
| }, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "experimental version", |
| Before: ClusterState{ |
| KubeVersion: "v1.10.5", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.5": 1, |
| }, |
| KubeadmVersion: "v1.10.5", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.11.0-beta.1", |
| KubeadmVersion: "v1.11.0-beta.1", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.2.18", |
| }, |
| }, |
| }, |
| allowExperimental: true, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "upgrade to an RC version should be supported", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.10.5", |
| kubeletVersion: "v1.10.5", |
| kubeadmVersion: "v1.10.5", |
| |
| stablePatchVersion: "v1.10.5", |
| stableVersion: "v1.10.5", |
| latestDevBranchVersion: "v1.11.0-rc.1", |
| latestVersion: "v1.12.0-alpha.1", |
| }, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "release candidate version", |
| Before: ClusterState{ |
| KubeVersion: "v1.10.5", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.5": 1, |
| }, |
| KubeadmVersion: "v1.10.5", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.11.0-rc.1", |
| KubeadmVersion: "v1.11.0-rc.1", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.2.18", |
| }, |
| }, |
| }, |
| allowRCs: true, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "it is possible (but very uncommon) that the latest version from the previous branch is an rc and the current latest version is alpha.0. In that case, show the RC", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.10.5", |
| kubeletVersion: "v1.10.5", |
| kubeadmVersion: "v1.10.5", |
| |
| stablePatchVersion: "v1.10.5", |
| stableVersion: "v1.10.5", |
| latestDevBranchVersion: "v1.11.6-rc.1", |
| latestVersion: "v1.12.1-alpha.0", |
| }, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "experimental version", // Note that this is considered an experimental version in this uncommon scenario |
| Before: ClusterState{ |
| KubeVersion: "v1.10.5", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.5": 1, |
| }, |
| KubeadmVersion: "v1.10.5", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.11.6-rc.1", |
| KubeadmVersion: "v1.11.6-rc.1", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.2.18", |
| }, |
| }, |
| }, |
| allowExperimental: true, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "upgrade to an RC version should be supported. There may also be an even newer unstable version.", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.10.5", |
| kubeletVersion: "v1.10.5", |
| kubeadmVersion: "v1.10.5", |
| |
| stablePatchVersion: "v1.10.5", |
| stableVersion: "v1.10.5", |
| latestDevBranchVersion: "v1.11.0-rc.1", |
| latestVersion: "v1.12.0-alpha.2", |
| }, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "release candidate version", |
| Before: ClusterState{ |
| KubeVersion: "v1.10.5", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.5": 1, |
| }, |
| KubeadmVersion: "v1.10.5", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.11.0-rc.1", |
| KubeadmVersion: "v1.11.0-rc.1", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.2.18", |
| }, |
| }, |
| { |
| Description: "experimental version", |
| Before: ClusterState{ |
| KubeVersion: "v1.10.5", |
| KubeletVersions: map[string]uint16{ |
| "v1.10.5": 1, |
| }, |
| KubeadmVersion: "v1.10.5", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.12.0-alpha.2", |
| KubeadmVersion: "v1.12.0-alpha.2", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.2.24", |
| }, |
| }, |
| }, |
| allowRCs: true, |
| allowExperimental: true, |
| errExpected: false, |
| etcdClient: etcdClient, |
| }, |
| { |
| name: "Upgrades with external etcd with mismatched versions should not be allowed.", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.10.3", |
| kubeletVersion: "v1.10.3", |
| kubeadmVersion: "v1.10.3", |
| stablePatchVersion: "v1.10.3", |
| stableVersion: "v1.10.3", |
| }, |
| allowRCs: false, |
| allowExperimental: false, |
| etcdClient: fakeEtcdClient{mismatchedVersions: true}, |
| expectedUpgrades: []Upgrade{}, |
| errExpected: true, |
| }, |
| { |
| name: "offline version getter", |
| vg: NewOfflineVersionGetter(&fakeVersionGetter{ |
| clusterVersion: "v1.11.1", |
| kubeletVersion: "v1.11.0", |
| kubeadmVersion: "v1.11.1", |
| }, "v1.12.1"), |
| etcdClient: etcdClient, |
| beforeDNSType: kubeadmapi.CoreDNS, |
| beforeDNSVersion: "1.0.6", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "version in the v1.11 series", |
| Before: ClusterState{ |
| KubeVersion: "v1.11.1", |
| KubeletVersions: map[string]uint16{ |
| "v1.11.0": 1, |
| }, |
| KubeadmVersion: "v1.11.1", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.0.6", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.12.1", |
| KubeadmVersion: "v1.12.1", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.2.24", |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "kubedns to coredns", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.11.2", |
| kubeletVersion: "v1.11.2", // the kubelet are on the same version as the control plane |
| kubeadmVersion: "v1.12.0", |
| |
| stablePatchVersion: "v1.12.0", |
| stableVersion: "v1.12.0", |
| }, |
| etcdClient: etcdClient, |
| beforeDNSType: kubeadmapi.KubeDNS, |
| beforeDNSVersion: "1.14.7", |
| dnsType: kubeadmapi.CoreDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "version in the v1.11 series", |
| Before: ClusterState{ |
| KubeVersion: "v1.11.2", |
| KubeletVersions: map[string]uint16{ |
| "v1.11.2": 1, |
| }, |
| KubeadmVersion: "v1.12.0", |
| DNSType: kubeadmapi.KubeDNS, |
| DNSVersion: "1.14.7", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.12.0", |
| KubeadmVersion: "v1.12.0", |
| DNSType: kubeadmapi.CoreDNS, |
| DNSVersion: "1.2.6", |
| EtcdVersion: "3.2.24", |
| }, |
| }, |
| }, |
| }, |
| { |
| name: "keep coredns", |
| vg: &fakeVersionGetter{ |
| clusterVersion: "v1.11.2", |
| kubeletVersion: "v1.11.2", // the kubelet are on the same version as the control plane |
| kubeadmVersion: "v1.12.0", |
| |
| stablePatchVersion: "v1.12.0", |
| stableVersion: "v1.12.0", |
| }, |
| etcdClient: etcdClient, |
| beforeDNSType: kubeadmapi.KubeDNS, |
| beforeDNSVersion: "1.14.7", |
| dnsType: kubeadmapi.KubeDNS, |
| expectedUpgrades: []Upgrade{ |
| { |
| Description: "version in the v1.11 series", |
| Before: ClusterState{ |
| KubeVersion: "v1.11.2", |
| KubeletVersions: map[string]uint16{ |
| "v1.11.2": 1, |
| }, |
| KubeadmVersion: "v1.12.0", |
| DNSType: kubeadmapi.KubeDNS, |
| DNSVersion: "1.14.7", |
| EtcdVersion: "3.1.12", |
| }, |
| After: ClusterState{ |
| KubeVersion: "v1.12.0", |
| KubeadmVersion: "v1.12.0", |
| DNSType: kubeadmapi.KubeDNS, |
| DNSVersion: "1.14.13", |
| EtcdVersion: "3.2.24", |
| }, |
| }, |
| }, |
| }, |
| } |
| |
| // Instantiating a fake etcd cluster for being able to get etcd version for a corresponding |
| // Kubernetes release. |
| for _, rt := range tests { |
| t.Run(rt.name, func(t *testing.T) { |
| |
| dnsName := constants.CoreDNSDeploymentName |
| if rt.beforeDNSType == kubeadmapi.KubeDNS { |
| dnsName = constants.KubeDNSDeploymentName |
| } |
| |
| client := clientsetfake.NewSimpleClientset(&apps.Deployment{ |
| TypeMeta: metav1.TypeMeta{ |
| Kind: "Deployment", |
| APIVersion: "apps/v1", |
| }, |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: dnsName, |
| Namespace: "kube-system", |
| Labels: map[string]string{ |
| "k8s-app": "kube-dns", |
| }, |
| }, |
| Spec: apps.DeploymentSpec{ |
| Template: v1.PodTemplateSpec{ |
| Spec: v1.PodSpec{ |
| Containers: []v1.Container{ |
| { |
| Image: "test:" + rt.beforeDNSVersion, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }) |
| |
| actualUpgrades, actualErr := GetAvailableUpgrades(rt.vg, rt.allowExperimental, rt.allowRCs, rt.etcdClient, rt.dnsType, client) |
| if !reflect.DeepEqual(actualUpgrades, rt.expectedUpgrades) { |
| t.Errorf("failed TestGetAvailableUpgrades\n\texpected upgrades: %v\n\tgot: %v", rt.expectedUpgrades, actualUpgrades) |
| } |
| if (actualErr != nil) != rt.errExpected { |
| fmt.Printf("Hello error") |
| t.Errorf("failed TestGetAvailableUpgrades\n\texpected error: %t\n\tgot error: %t", rt.errExpected, (actualErr != nil)) |
| } |
| if !reflect.DeepEqual(actualUpgrades, rt.expectedUpgrades) { |
| t.Errorf("failed TestGetAvailableUpgrades\n\texpected upgrades: %v\n\tgot: %v", rt.expectedUpgrades, actualUpgrades) |
| } |
| }) |
| } |
| } |
| |
| func TestKubeletUpgrade(t *testing.T) { |
| tests := []struct { |
| before map[string]uint16 |
| after string |
| expected bool |
| }{ |
| { // upgrade available |
| before: map[string]uint16{ |
| "v1.10.1": 1, |
| }, |
| after: "v1.10.3", |
| expected: true, |
| }, |
| { // upgrade available |
| before: map[string]uint16{ |
| "v1.10.1": 1, |
| "v1.10.3": 100, |
| }, |
| after: "v1.10.3", |
| expected: true, |
| }, |
| { // upgrade not available |
| before: map[string]uint16{ |
| "v1.10.3": 1, |
| }, |
| after: "v1.10.3", |
| expected: false, |
| }, |
| { // upgrade not available |
| before: map[string]uint16{ |
| "v1.10.3": 100, |
| }, |
| after: "v1.10.3", |
| expected: false, |
| }, |
| { // upgrade not available if we don't know anything about the earlier state |
| before: map[string]uint16{}, |
| after: "v1.10.3", |
| expected: false, |
| }, |
| } |
| |
| for _, rt := range tests { |
| |
| upgrade := Upgrade{ |
| Before: ClusterState{ |
| KubeletVersions: rt.before, |
| }, |
| After: ClusterState{ |
| KubeVersion: rt.after, |
| }, |
| } |
| actual := upgrade.CanUpgradeKubelets() |
| if actual != rt.expected { |
| t.Errorf("failed TestKubeletUpgrade\n\texpected: %t\n\tgot: %t\n\ttest object: %v", rt.expected, actual, upgrade) |
| } |
| } |
| } |
| |
| func TestGetBranchFromVersion(t *testing.T) { |
| testCases := []struct { |
| version string |
| expectedVersion string |
| }{ |
| { |
| version: "v1.9.5", |
| expectedVersion: "1.9", |
| }, |
| { |
| version: "v1.9.0-alpha.2", |
| expectedVersion: "1.9", |
| }, |
| { |
| version: "v1.9.0-beta.0", |
| expectedVersion: "1.9", |
| }, |
| { |
| version: "v1.9.0-rc.1", |
| expectedVersion: "1.9", |
| }, |
| { |
| version: "v1.12.5", |
| expectedVersion: "1.12", |
| }, |
| { |
| version: "v1.11.0-alpha.0", |
| expectedVersion: "1.11", |
| }, |
| |
| { |
| version: "v1.11.0-beta.1", |
| expectedVersion: "1.11", |
| }, |
| { |
| version: "v1.11.0-rc.0", |
| expectedVersion: "1.11", |
| }, |
| { |
| version: "1.12.5", |
| expectedVersion: "1.12", |
| }, |
| } |
| |
| for _, tc := range testCases { |
| v := getBranchFromVersion(tc.version) |
| if v != tc.expectedVersion { |
| t.Errorf("expected version %s, got %s", tc.expectedVersion, v) |
| } |
| } |
| |
| } |