1
16
17 package upgrade
18
19 import (
20 "testing"
21
22 "k8s.io/apimachinery/pkg/util/version"
23 )
24
25 func TestEnforceVersionPolicies(t *testing.T) {
26 minimumKubeletVersion := version.MustParseSemantic("v1.3.0")
27 minimumControlPlaneVersion := version.MustParseSemantic("v1.3.0")
28 currentKubernetesVersion := version.MustParseSemantic("v1.4.0")
29 tests := []struct {
30 name string
31 vg *fakeVersionGetter
32 expectedMandatoryErrs int
33 expectedSkippableErrs int
34 allowExperimental, allowRCs bool
35 newK8sVersion string
36 }{
37 {
38 name: "minor upgrade",
39 vg: &fakeVersionGetter{
40 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
41 kubeletVersion: minimumControlPlaneVersion.WithPatch(3).String(),
42 kubeadmVersion: minimumControlPlaneVersion.WithPatch(5).String(),
43 },
44 newK8sVersion: minimumControlPlaneVersion.WithPatch(5).String(),
45 },
46 {
47 name: "major upgrade",
48 vg: &fakeVersionGetter{
49 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
50 kubeletVersion: minimumControlPlaneVersion.WithPatch(2).String(),
51 kubeadmVersion: currentKubernetesVersion.WithPatch(1).String(),
52 },
53 newK8sVersion: currentKubernetesVersion.String(),
54 },
55 {
56 name: "downgrade",
57 vg: &fakeVersionGetter{
58 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
59 kubeletVersion: minimumKubeletVersion.String(),
60 kubeadmVersion: minimumControlPlaneVersion.WithPatch(3).String(),
61 },
62 newK8sVersion: minimumControlPlaneVersion.WithPatch(2).String(),
63 },
64 {
65 name: "same version upgrade",
66 vg: &fakeVersionGetter{
67 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
68 kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
69 kubeadmVersion: minimumControlPlaneVersion.WithPatch(3).String(),
70 },
71 newK8sVersion: minimumControlPlaneVersion.WithPatch(3).String(),
72 },
73 {
74 name: "new version must be higher than v1.12.0",
75 vg: &fakeVersionGetter{
76 clusterVersion: "v1.12.3",
77 kubeletVersion: "v1.12.3",
78 kubeadmVersion: "v1.12.3",
79 },
80 newK8sVersion: "v1.10.10",
81 expectedMandatoryErrs: 1,
82 expectedSkippableErrs: 1,
83 },
84 {
85 name: "upgrading two minor versions in one go is not supported",
86 vg: &fakeVersionGetter{
87 clusterVersion: "v1.11.3",
88 kubeletVersion: "v1.11.3",
89 kubeadmVersion: "v1.13.0",
90 },
91 newK8sVersion: "v1.13.0",
92 expectedMandatoryErrs: 1,
93 },
94 {
95 name: "upgrading with n-3 kubelet is supported",
96 vg: &fakeVersionGetter{
97 clusterVersion: "v1.14.3",
98 kubeletVersion: "v1.12.3",
99 kubeadmVersion: "v1.15.0",
100 },
101 newK8sVersion: "v1.15.0",
102 },
103 {
104 name: "upgrading with n-4 kubelet is not supported",
105 vg: &fakeVersionGetter{
106 clusterVersion: "v1.14.3",
107 kubeletVersion: "v1.11.3",
108 kubeadmVersion: "v1.15.0",
109 },
110 newK8sVersion: "v1.15.0",
111 expectedSkippableErrs: 1,
112 },
113 {
114 name: "downgrading two minor versions in one go is not supported",
115 vg: &fakeVersionGetter{
116 clusterVersion: currentKubernetesVersion.WithMinor(currentKubernetesVersion.Minor() + 2).String(),
117 kubeletVersion: currentKubernetesVersion.WithMinor(currentKubernetesVersion.Minor() + 2).String(),
118 kubeadmVersion: currentKubernetesVersion.String(),
119 },
120 newK8sVersion: currentKubernetesVersion.String(),
121 expectedMandatoryErrs: 1,
122 },
123 {
124 name: "kubeadm version must be higher than the new kube version. However, patch version skews may be forced",
125 vg: &fakeVersionGetter{
126 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
127 kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
128 kubeadmVersion: minimumControlPlaneVersion.WithPatch(3).String(),
129 },
130 newK8sVersion: minimumControlPlaneVersion.WithPatch(5).String(),
131 expectedSkippableErrs: 1,
132 },
133 {
134 name: "kubeadm version must be higher than the new kube version. Trying to upgrade k8s to a higher minor version than kubeadm itself should never be supported",
135 vg: &fakeVersionGetter{
136 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
137 kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
138 kubeadmVersion: minimumControlPlaneVersion.WithPatch(3).String(),
139 },
140 newK8sVersion: currentKubernetesVersion.String(),
141 expectedMandatoryErrs: 1,
142 },
143 {
144 name: "the maximum skew between the cluster version and the kubelet versions should be three minor version.",
145 vg: &fakeVersionGetter{
146 clusterVersion: "v1.13.0",
147 kubeletVersion: "v1.10.8",
148 kubeadmVersion: "v1.13.0",
149 },
150 newK8sVersion: "v1.13.0",
151 },
152 {
153 name: "the maximum skew between the cluster version and the kubelet versions should be three minor version. This may be forced through though.",
154 vg: &fakeVersionGetter{
155 clusterVersion: "v1.14.0",
156 kubeletVersion: "v1.10.8",
157 kubeadmVersion: "v1.14.0",
158 },
159 newK8sVersion: "v1.14.0",
160 expectedSkippableErrs: 1,
161 },
162 {
163 name: "experimental upgrades supported if the flag is set",
164 vg: &fakeVersionGetter{
165 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
166 kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
167 kubeadmVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
168 },
169 newK8sVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
170 allowExperimental: true,
171 },
172 {
173 name: "release candidate upgrades supported if the flag is set",
174 vg: &fakeVersionGetter{
175 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
176 kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
177 kubeadmVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
178 },
179 newK8sVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
180 allowRCs: true,
181 },
182 {
183 name: "release candidate upgrades supported if the flag is set",
184 vg: &fakeVersionGetter{
185 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
186 kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
187 kubeadmVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
188 },
189 newK8sVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
190 allowExperimental: true,
191 },
192 {
193 name: "the user should not be able to upgrade to an experimental version if they haven't opted into that",
194 vg: &fakeVersionGetter{
195 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
196 kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
197 kubeadmVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
198 },
199 newK8sVersion: currentKubernetesVersion.WithPreRelease("beta.1").String(),
200 allowRCs: true,
201 expectedSkippableErrs: 1,
202 },
203 {
204 name: "the user should not be able to upgrade to an release candidate version if they haven't opted into that",
205 vg: &fakeVersionGetter{
206 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
207 kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
208 kubeadmVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
209 },
210 newK8sVersion: currentKubernetesVersion.WithPreRelease("rc.1").String(),
211 expectedSkippableErrs: 1,
212 },
213 {
214 name: "the user can't use a newer minor version of kubeadm to upgrade an older version of kubeadm",
215 vg: &fakeVersionGetter{
216 clusterVersion: minimumControlPlaneVersion.WithPatch(3).String(),
217 kubeletVersion: minimumKubeletVersion.WithPatch(3).String(),
218 kubeadmVersion: currentKubernetesVersion.String(),
219 },
220 newK8sVersion: minimumControlPlaneVersion.WithPatch(6).String(),
221 expectedSkippableErrs: 1,
222 },
223 {
224 name: "build release supported at MinimumControlPlaneVersion",
225 vg: &fakeVersionGetter{
226 clusterVersion: minimumControlPlaneVersion.String(),
227 kubeletVersion: minimumControlPlaneVersion.String(),
228 kubeadmVersion: minimumControlPlaneVersion.WithBuildMetadata("build").String(),
229 },
230 newK8sVersion: minimumControlPlaneVersion.WithBuildMetadata("build").String(),
231 },
232 }
233
234 for _, rt := range tests {
235 t.Run(rt.name, func(t *testing.T) {
236
237 newK8sVer, err := version.ParseSemantic(rt.newK8sVersion)
238 if err != nil {
239 t.Fatalf("couldn't parse version %s: %v", rt.newK8sVersion, err)
240 }
241
242 actualSkewErrs := EnforceVersionPolicies(rt.vg, rt.newK8sVersion, newK8sVer, rt.allowExperimental, rt.allowRCs)
243 if actualSkewErrs == nil {
244
245 if rt.expectedMandatoryErrs+rt.expectedSkippableErrs > 0 {
246 t.Errorf("failed TestEnforceVersionPolicies\n\texpected errors but got none")
247 }
248
249 return
250 }
251
252 if len(actualSkewErrs.Skippable) != rt.expectedSkippableErrs {
253 t.Errorf("failed TestEnforceVersionPolicies\n\texpected skippable errors: %d\n\tgot skippable errors: %d\n%#v\n%#v", rt.expectedSkippableErrs, len(actualSkewErrs.Skippable), *rt.vg, actualSkewErrs)
254 }
255 if len(actualSkewErrs.Mandatory) != rt.expectedMandatoryErrs {
256 t.Errorf("failed TestEnforceVersionPolicies\n\texpected mandatory errors: %d\n\tgot mandatory errors: %d\n%#v\n%#v", rt.expectedMandatoryErrs, len(actualSkewErrs.Mandatory), *rt.vg, actualSkewErrs)
257 }
258 })
259 }
260 }
261
View as plain text