Skip to content

Commit f0000d4

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 588446a commit f0000d4

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.
@@ -1114,15 +1114,20 @@ func tryRegistry(r command.Runner) {
11141114

11151115
// getKubernetesVersion ensures that the requested version is reasonable
11161116
func getKubernetesVersion(old *cfg.MachineConfig) (string, bool) {
1117-
rawVersion := viper.GetString(kubernetesVersion)
1117+
paramVersion := viper.GetString(kubernetesVersion)
11181118
isUpgrade := false
1119-
if rawVersion == "" {
1120-
rawVersion = constants.DefaultKubernetesVersion
1119+
1120+
if paramVersion == "" { // if the user did not specify any version then ...
1121+
if old != nil { // .. use the old version from config
1122+
paramVersion = old.KubernetesConfig.KubernetesVersion
1123+
} else { // .. otherwise use the default version
1124+
paramVersion = constants.DefaultKubernetesVersion
1125+
}
11211126
}
11221127

1123-
nvs, err := semver.Make(strings.TrimPrefix(rawVersion, version.VersionPrefix))
1128+
nvs, err := semver.Make(strings.TrimPrefix(paramVersion, version.VersionPrefix))
11241129
if err != nil {
1125-
exit.WithCodeT(exit.Data, `Unable to parse "{{.kubernetes_version}}": {{.error}}`, out.V{"kubernetes_version": rawVersion, "error": err})
1130+
exit.WithCodeT(exit.Data, `Unable to parse "{{.kubernetes_version}}": {{.error}}`, out.V{"kubernetes_version": paramVersion, "error": err})
11261131
}
11271132
nv := version.VersionPrefix + nvs.String()
11281133

@@ -1134,6 +1139,10 @@ func getKubernetesVersion(old *cfg.MachineConfig) (string, bool) {
11341139
if err != nil {
11351140
exit.WithCodeT(exit.Data, "Unable to parse oldest Kubernetes version from constants: {{.error}}", out.V{"error": err})
11361141
}
1142+
defaultVersion, err := semver.Make(strings.TrimPrefix(constants.DefaultKubernetesVersion, version.VersionPrefix))
1143+
if err != nil {
1144+
exit.WithCodeT(exit.Data, "Unable to parse default Kubernetes version from constants: {{.error}}", out.V{"error": err})
1145+
}
11371146

11381147
if nvs.LT(oldestVersion) {
11391148
out.WarningT("Specified Kubernetes version {{.specified}} is less than the oldest supported version: {{.oldest}}", out.V{"specified": nvs, "oldest": constants.OldestKubernetesVersion})
@@ -1162,8 +1171,11 @@ func getKubernetesVersion(old *cfg.MachineConfig) (string, bool) {
11621171
* 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})
11631172

11641173
}
1174+
if defaultVersion.GT(nvs) {
1175+
out.T(out.ThumbsUp, "Kubernetes {{.new}} is now available. If you would like to upgrade, specify: --kubernetes-version={{.new}}", out.V{"new": defaultVersion})
1176+
}
1177+
11651178
if nvs.GT(ovs) {
1166-
out.T(out.ThumbsUp, "Upgrading from Kubernetes {{.old}} to {{.new}}", out.V{"old": ovs, "new": nvs})
11671179
isUpgrade = true
11681180
}
11691181
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)