Skip to content

Commit 30499dc

Browse files
committed
Fix --kubernetes-version for upgrading cluster to correct version
This PR fix the issue of checking kubernetes-version and upgrading it. The fix now will do the following * Not specifying the --kubernetes-version flag means just use the currently deployed version. * If an update is available inform the user that they may use --kubernetes-version=<version>. * When --kubernetes-version is specifically set, upgrade the cluster. Also add integration testing to test upgrading and downgrading
1 parent e611b38 commit 30499dc

File tree

3 files changed

+181
-7
lines changed

3 files changed

+181
-7
lines changed

cmd/minikube/cmd/start.go

+19-7
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func initMinikubeFlags() {
178178

179179
// initKubernetesFlags inits the commandline flags for kubernetes related options
180180
func initKubernetesFlags() {
181-
startCmd.Flags().String(kubernetesVersion, constants.DefaultKubernetesVersion, "The kubernetes version that the minikube VM will use (ex: v1.2.3)")
181+
startCmd.Flags().String(kubernetesVersion, "", "The kubernetes version that the minikube VM will use (ex: v1.2.3)")
182182
startCmd.Flags().Var(&extraOptions, "extra-config",
183183
`A set of key=value pairs that describe configuration that may be passed to different components.
184184
The key should be '.' separated, and the first part before the dot is the component to apply the configuration to.
@@ -1110,15 +1110,20 @@ func tryRegistry(r command.Runner) {
11101110

11111111
// getKubernetesVersion ensures that the requested version is reasonable
11121112
func getKubernetesVersion(old *cfg.MachineConfig) (string, bool) {
1113-
rawVersion := viper.GetString(kubernetesVersion)
1113+
paramVersion := viper.GetString(kubernetesVersion)
11141114
isUpgrade := false
1115-
if rawVersion == "" {
1116-
rawVersion = constants.DefaultKubernetesVersion
1115+
1116+
if paramVersion == "" { // if the user did not specify any version then ...
1117+
if old != nil { // .. use the old version from config
1118+
paramVersion = old.KubernetesConfig.KubernetesVersion
1119+
} else { // .. otherwise use the default version
1120+
paramVersion = constants.DefaultKubernetesVersion
1121+
}
11171122
}
11181123

1119-
nvs, err := semver.Make(strings.TrimPrefix(rawVersion, version.VersionPrefix))
1124+
nvs, err := semver.Make(strings.TrimPrefix(paramVersion, version.VersionPrefix))
11201125
if err != nil {
1121-
exit.WithCodeT(exit.Data, `Unable to parse "{{.kubernetes_version}}": {{.error}}`, out.V{"kubernetes_version": rawVersion, "error": err})
1126+
exit.WithCodeT(exit.Data, `Unable to parse "{{.kubernetes_version}}": {{.error}}`, out.V{"kubernetes_version": paramVersion, "error": err})
11221127
}
11231128
nv := version.VersionPrefix + nvs.String()
11241129

@@ -1130,6 +1135,10 @@ func getKubernetesVersion(old *cfg.MachineConfig) (string, bool) {
11301135
if err != nil {
11311136
exit.WithCodeT(exit.Data, "Unable to parse oldest Kubernetes version from constants: {{.error}}", out.V{"error": err})
11321137
}
1138+
defaultVersion, err := semver.Make(strings.TrimPrefix(constants.DefaultKubernetesVersion, version.VersionPrefix))
1139+
if err != nil {
1140+
exit.WithCodeT(exit.Data, "Unable to parse default Kubernetes version from constants: {{.error}}", out.V{"error": err})
1141+
}
11331142

11341143
if nvs.LT(oldestVersion) {
11351144
out.WarningT("Specified Kubernetes version {{.specified}} is less than the oldest supported version: {{.oldest}}", out.V{"specified": nvs, "oldest": constants.OldestKubernetesVersion})
@@ -1158,8 +1167,11 @@ func getKubernetesVersion(old *cfg.MachineConfig) (string, bool) {
11581167
* Reuse the existing cluster with Kubernetes v{{.old}} or newer: Run "minikube start {{.profile}} --kubernetes-version={{.old}}"`, out.V{"new": nvs, "old": ovs, "profile": profileArg})
11591168

11601169
}
1170+
if defaultVersion.GT(nvs) {
1171+
out.T(out.ThumbsUp, "Kubernetes {{.new}} is now available. If you would like to upgrade, specify: --kubernetes-version={{.new}}", out.V{"new": defaultVersion})
1172+
}
1173+
11611174
if nvs.GT(ovs) {
1162-
out.T(out.ThumbsUp, "Upgrading from Kubernetes {{.old}} to {{.new}}", out.V{"old": ovs, "new": nvs})
11631175
isUpgrade = true
11641176
}
11651177
return nv, isUpgrade

cmd/minikube/cmd/start_test.go

+55
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,64 @@ import (
2222

2323
"github.com/spf13/cobra"
2424
"github.com/spf13/viper"
25+
cfg "k8s.io/minikube/pkg/minikube/config"
2526
"k8s.io/minikube/pkg/minikube/constants"
2627
)
2728

29+
func TestGetKuberneterVersion(t *testing.T) {
30+
var tests = []struct {
31+
description string
32+
expectedVersion string
33+
paramVersion string
34+
upgrade bool
35+
cfg *cfg.MachineConfig
36+
}{
37+
{
38+
description: "kubernetes-version not given, no config",
39+
expectedVersion: constants.DefaultKubernetesVersion,
40+
paramVersion: "",
41+
upgrade: false,
42+
},
43+
{
44+
description: "kubernetes-version not given, config available",
45+
expectedVersion: "v1.15.0",
46+
paramVersion: "",
47+
upgrade: false,
48+
cfg: &cfg.MachineConfig{KubernetesConfig: cfg.KubernetesConfig{KubernetesVersion: "v1.15.0"}},
49+
},
50+
{
51+
description: "kubernetes-version given, no config",
52+
expectedVersion: "v1.15.0",
53+
paramVersion: "v1.15.0",
54+
upgrade: false,
55+
},
56+
{
57+
description: "kubernetes-version given, config available",
58+
expectedVersion: "v1.16.0",
59+
paramVersion: "v1.16.0",
60+
upgrade: true,
61+
cfg: &cfg.MachineConfig{KubernetesConfig: cfg.KubernetesConfig{KubernetesVersion: "v1.15.0"}},
62+
},
63+
}
64+
65+
for _, test := range tests {
66+
t.Run(test.description, func(t *testing.T) {
67+
viper.SetDefault(kubernetesVersion, test.paramVersion)
68+
version, upgrade := getKubernetesVersion(test.cfg)
69+
70+
// check whether we are getting the expected version
71+
if version != test.expectedVersion {
72+
t.Fatalf("test failed because the expected version %s is not returned", test.expectedVersion)
73+
}
74+
75+
// check whether the upgrade flag is correct
76+
if test.upgrade != upgrade {
77+
t.Fatalf("test failed expected upgrade is %t", test.upgrade)
78+
}
79+
})
80+
}
81+
}
82+
2883
func TestGenerateCfgFromFlagsHTTPProxyHandling(t *testing.T) {
2984
viper.SetDefault(memory, defaultMemorySize)
3085
viper.SetDefault(humanReadableDiskSize, defaultDiskSize)

test/integration/version_upgrade_test.go

+107
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,113 @@ import (
3535
pkgutil "k8s.io/minikube/pkg/util"
3636
)
3737

38+
// TestDifferentVersionUpgrade test installation of different version of Kubernetes.
39+
// Start with installing from v1.13.0 then to v1.15.0 and then try to downgrade it
40+
// to v1.13.0
41+
// Following are the test cases that the function is doing
42+
// 1. Start with specific version
43+
// ./out/minikube start -p vupgrade --kubernetes-version=v1.13.0
44+
// 2. Upgrade with newer version
45+
// ./out/minikube start -p vupgrade --kubernetes-version=v1.13.0
46+
// 3. Downgrade with older version (this will spit out error and test the error message)
47+
// ./out/minikube start -p vupgrade --kubernetes-version=v1.13.0
48+
func TestDifferentVersionUpgrade(t *testing.T) {
49+
MaybeParallel(t)
50+
WaitForStartSlot(t)
51+
profile := UniqueProfileName("testkubernetestversions")
52+
53+
ctx, cancel := context.WithTimeout(context.Background(), 55*time.Minute)
54+
defer CleanupWithLogs(t, profile, cancel)
55+
56+
// create a temporary file
57+
tf, err := ioutil.TempFile("", "minikube-release.*.exe")
58+
if err != nil {
59+
t.Fatalf("tempfile: %v", err)
60+
}
61+
defer os.Remove(tf.Name())
62+
tf.Close()
63+
64+
// download minikube
65+
url := pkgutil.GetBinaryDownloadURL("latest", runtime.GOOS)
66+
67+
// chmod the binary (when Linux)
68+
if runtime.GOOS != "windows" {
69+
if err := os.Chmod(tf.Name(), 0700); err != nil {
70+
t.Errorf("chmod: %v", err)
71+
}
72+
}
73+
74+
// download the file
75+
if err := retry.Expo(func() error { return getter.GetFile(tf.Name(), url) }, 3*time.Second, 3*time.Minute); err != nil {
76+
t.Fatalf("get failed: %v", err)
77+
}
78+
79+
t.Run("parallel", func(t *testing.T) {
80+
tests := []struct {
81+
name string
82+
message string
83+
kubernetesversion string
84+
expectstartupfailure bool
85+
}{
86+
{"fresh install kubernetes v1.13.0", "v1.13.0", "v1.13.0", false},
87+
{"upgrade kubernetes to v 1.14.0", "v1.14.0", "v1.14.0", false},
88+
{"downgrade kubernetes to v 1.12.0", "Non-destructive downgrades are not supported", "v1.12.0", true},
89+
}
90+
for _, tc := range tests {
91+
tc := tc
92+
t.Run(tc.name, func(t *testing.T) {
93+
// instruct to install kubernetes v1.13.0
94+
args := append([]string{"start", "-p", profile, fmt.Sprintf("--kubernetes-version=%s", tc.kubernetesversion), "--alsologtostderr", "-v=1"}, StartArgs()...)
95+
96+
rr := &RunResult{}
97+
var startingFunc = func() error {
98+
rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), args...))
99+
return err
100+
}
101+
102+
// if the test expect failure the function is different
103+
if tc.expectstartupfailure {
104+
startingFunc = func() error {
105+
rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), args...))
106+
stderr := rr.Stderr.String()
107+
if !strings.Contains(stderr, tc.message) {
108+
t.Fatalf("test failed as no message %s detected", tc.message)
109+
return err
110+
}
111+
return nil
112+
}
113+
}
114+
115+
err := retry.Expo(startingFunc, 1*time.Second, 30*time.Minute, 3)
116+
117+
// as the text expect failure there is no need to continue the flow
118+
if tc.expectstartupfailure {
119+
return
120+
}
121+
122+
if err != nil {
123+
t.Fatalf("release start failed: %v", err)
124+
}
125+
126+
// grab the Stdout for checking...
127+
ss := rr.Stdout.String()
128+
129+
// fail if it does not contain the string
130+
if !strings.Contains(ss, tc.message) {
131+
t.Fatalf("test failed as no message %s detected", tc.message)
132+
}
133+
134+
// stop minikube
135+
rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), "stop", "-p", profile))
136+
if err != nil {
137+
t.Fatalf("%s failed: %v", rr.Args, err)
138+
}
139+
})
140+
}
141+
})
142+
143+
}
144+
38145
// TestVersionUpgrade downloads latest version of minikube and runs with
39146
// the odlest supported k8s version and then runs the current head minikube
40147
// and it tries to upgrade from the older supported k8s to news supported k8s

0 commit comments

Comments
 (0)