compute_test.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package upgrade
  14. import (
  15. "fmt"
  16. "reflect"
  17. "testing"
  18. "time"
  19. "github.com/coreos/etcd/clientv3"
  20. "github.com/pkg/errors"
  21. apps "k8s.io/api/apps/v1"
  22. v1 "k8s.io/api/core/v1"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. versionutil "k8s.io/apimachinery/pkg/util/version"
  25. clientsetfake "k8s.io/client-go/kubernetes/fake"
  26. kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
  27. "k8s.io/kubernetes/cmd/kubeadm/app/constants"
  28. etcdutil "k8s.io/kubernetes/cmd/kubeadm/app/util/etcd"
  29. )
  30. type fakeVersionGetter struct {
  31. clusterVersion, kubeadmVersion, stableVersion, latestVersion, latestDevBranchVersion, stablePatchVersion, kubeletVersion string
  32. }
  33. var _ VersionGetter = &fakeVersionGetter{}
  34. // ClusterVersion gets a fake API server version
  35. func (f *fakeVersionGetter) ClusterVersion() (string, *versionutil.Version, error) {
  36. return f.clusterVersion, versionutil.MustParseSemantic(f.clusterVersion), nil
  37. }
  38. // KubeadmVersion gets a fake kubeadm version
  39. func (f *fakeVersionGetter) KubeadmVersion() (string, *versionutil.Version, error) {
  40. return f.kubeadmVersion, versionutil.MustParseSemantic(f.kubeadmVersion), nil
  41. }
  42. // VersionFromCILabel gets fake latest versions from CI
  43. func (f *fakeVersionGetter) VersionFromCILabel(ciVersionLabel, _ string) (string, *versionutil.Version, error) {
  44. if ciVersionLabel == "stable" {
  45. return f.stableVersion, versionutil.MustParseSemantic(f.stableVersion), nil
  46. }
  47. if ciVersionLabel == "latest" {
  48. return f.latestVersion, versionutil.MustParseSemantic(f.latestVersion), nil
  49. }
  50. if ciVersionLabel == "latest-1.11" {
  51. return f.latestDevBranchVersion, versionutil.MustParseSemantic(f.latestDevBranchVersion), nil
  52. }
  53. return f.stablePatchVersion, versionutil.MustParseSemantic(f.stablePatchVersion), nil
  54. }
  55. // KubeletVersions gets the versions of the kubelets in the cluster
  56. func (f *fakeVersionGetter) KubeletVersions() (map[string]uint16, error) {
  57. return map[string]uint16{
  58. f.kubeletVersion: 1,
  59. }, nil
  60. }
  61. type fakeEtcdClient struct {
  62. TLS bool
  63. mismatchedVersions bool
  64. }
  65. func (f fakeEtcdClient) ClusterAvailable() (bool, error) { return true, nil }
  66. func (f fakeEtcdClient) WaitForClusterAvailable(retries int, retryInterval time.Duration) (bool, error) {
  67. return true, nil
  68. }
  69. func (f fakeEtcdClient) GetClusterStatus() (map[string]*clientv3.StatusResponse, error) {
  70. return make(map[string]*clientv3.StatusResponse), nil
  71. }
  72. func (f fakeEtcdClient) GetVersion() (string, error) {
  73. versions, _ := f.GetClusterVersions()
  74. if f.mismatchedVersions {
  75. return "", errors.Errorf("etcd cluster contains endpoints with mismatched versions: %v", versions)
  76. }
  77. return "3.1.12", nil
  78. }
  79. func (f fakeEtcdClient) GetClusterVersions() (map[string]string, error) {
  80. if f.mismatchedVersions {
  81. return map[string]string{
  82. "foo": "3.1.12",
  83. "bar": "3.2.0",
  84. }, nil
  85. }
  86. return map[string]string{
  87. "foo": "3.1.12",
  88. "bar": "3.1.12",
  89. }, nil
  90. }
  91. func (f fakeEtcdClient) Sync() error { return nil }
  92. func (f fakeEtcdClient) AddMember(name string, peerAddrs string) ([]etcdutil.Member, error) {
  93. return []etcdutil.Member{}, nil
  94. }
  95. func (f fakeEtcdClient) GetMemberID(peerURL string) (uint64, error) {
  96. return 0, nil
  97. }
  98. func (f fakeEtcdClient) RemoveMember(id uint64) ([]etcdutil.Member, error) {
  99. return []etcdutil.Member{}, nil
  100. }
  101. func getEtcdVersion(v *versionutil.Version) string {
  102. return constants.SupportedEtcdVersion[uint8(v.Minor())]
  103. }
  104. func TestGetAvailableUpgrades(t *testing.T) {
  105. etcdClient := fakeEtcdClient{}
  106. tests := []struct {
  107. name string
  108. vg VersionGetter
  109. expectedUpgrades []Upgrade
  110. allowExperimental, allowRCs bool
  111. errExpected bool
  112. etcdClient etcdutil.ClusterInterrogator
  113. beforeDNSType kubeadmapi.DNSAddOnType
  114. beforeDNSVersion string
  115. dnsType kubeadmapi.DNSAddOnType
  116. }{
  117. {
  118. name: "no action needed, already up-to-date",
  119. vg: &fakeVersionGetter{
  120. clusterVersion: constants.MinimumControlPlaneVersion.String(),
  121. kubeletVersion: constants.MinimumKubeletVersion.String(),
  122. kubeadmVersion: constants.MinimumControlPlaneVersion.String(),
  123. stablePatchVersion: constants.MinimumControlPlaneVersion.String(),
  124. stableVersion: constants.MinimumControlPlaneVersion.String(),
  125. },
  126. beforeDNSType: kubeadmapi.CoreDNS,
  127. beforeDNSVersion: "v1.0.6",
  128. dnsType: kubeadmapi.CoreDNS,
  129. expectedUpgrades: []Upgrade{},
  130. allowExperimental: false,
  131. errExpected: false,
  132. etcdClient: etcdClient,
  133. },
  134. {
  135. name: "simple patch version upgrade",
  136. vg: &fakeVersionGetter{
  137. clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(1).String(),
  138. kubeletVersion: constants.MinimumKubeletVersion.WithPatch(1).String(), // the kubelet are on the same version as the control plane
  139. kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(),
  140. stablePatchVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  141. stableVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  142. },
  143. beforeDNSType: kubeadmapi.CoreDNS,
  144. beforeDNSVersion: "1.0.6",
  145. dnsType: kubeadmapi.CoreDNS,
  146. expectedUpgrades: []Upgrade{
  147. {
  148. Description: fmt.Sprintf("version in the v%d.%d series", constants.MinimumControlPlaneVersion.Major(), constants.MinimumControlPlaneVersion.Minor()),
  149. Before: ClusterState{
  150. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(1).String(),
  151. KubeletVersions: map[string]uint16{
  152. constants.MinimumKubeletVersion.WithPatch(1).String(): 1,
  153. },
  154. KubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(),
  155. DNSType: kubeadmapi.CoreDNS,
  156. DNSVersion: "1.0.6",
  157. EtcdVersion: "3.1.12",
  158. },
  159. After: ClusterState{
  160. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  161. KubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  162. DNSType: kubeadmapi.CoreDNS,
  163. DNSVersion: "1.3.1",
  164. EtcdVersion: getEtcdVersion(constants.MinimumControlPlaneVersion),
  165. },
  166. },
  167. },
  168. allowExperimental: false,
  169. errExpected: false,
  170. etcdClient: etcdClient,
  171. },
  172. {
  173. name: "no version provided to offline version getter does not change behavior",
  174. vg: NewOfflineVersionGetter(&fakeVersionGetter{
  175. clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(1).String(),
  176. kubeletVersion: constants.MinimumKubeletVersion.WithPatch(1).String(), // the kubelet are on the same version as the control plane
  177. kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(),
  178. stablePatchVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  179. stableVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  180. }, ""),
  181. beforeDNSType: kubeadmapi.CoreDNS,
  182. beforeDNSVersion: "1.0.6",
  183. dnsType: kubeadmapi.CoreDNS,
  184. expectedUpgrades: []Upgrade{
  185. {
  186. Description: fmt.Sprintf("version in the v%d.%d series", constants.MinimumControlPlaneVersion.Major(), constants.MinimumControlPlaneVersion.Minor()),
  187. Before: ClusterState{
  188. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(1).String(),
  189. KubeletVersions: map[string]uint16{
  190. constants.MinimumKubeletVersion.WithPatch(1).String(): 1,
  191. },
  192. KubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(),
  193. DNSType: kubeadmapi.CoreDNS,
  194. DNSVersion: "1.0.6",
  195. EtcdVersion: "3.1.12",
  196. },
  197. After: ClusterState{
  198. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  199. KubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  200. DNSType: kubeadmapi.CoreDNS,
  201. DNSVersion: "1.3.1",
  202. EtcdVersion: getEtcdVersion(constants.MinimumControlPlaneVersion),
  203. },
  204. },
  205. },
  206. allowExperimental: false,
  207. errExpected: false,
  208. etcdClient: etcdClient,
  209. },
  210. {
  211. name: "minor version upgrade only",
  212. vg: &fakeVersionGetter{
  213. clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(1).String(),
  214. kubeletVersion: constants.MinimumKubeletVersion.WithPatch(1).String(), // the kubelet are on the same version as the control plane
  215. kubeadmVersion: constants.CurrentKubernetesVersion.String(),
  216. stablePatchVersion: constants.MinimumControlPlaneVersion.WithPatch(1).String(),
  217. stableVersion: constants.CurrentKubernetesVersion.String(),
  218. },
  219. beforeDNSType: kubeadmapi.CoreDNS,
  220. beforeDNSVersion: "1.0.6",
  221. dnsType: kubeadmapi.CoreDNS,
  222. expectedUpgrades: []Upgrade{
  223. {
  224. Description: "stable version",
  225. Before: ClusterState{
  226. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(1).String(),
  227. KubeletVersions: map[string]uint16{
  228. constants.MinimumKubeletVersion.WithPatch(1).String(): 1,
  229. },
  230. KubeadmVersion: constants.CurrentKubernetesVersion.String(),
  231. DNSType: kubeadmapi.CoreDNS,
  232. DNSVersion: "1.0.6",
  233. EtcdVersion: "3.1.12",
  234. },
  235. After: ClusterState{
  236. KubeVersion: constants.CurrentKubernetesVersion.String(),
  237. KubeadmVersion: constants.CurrentKubernetesVersion.String(),
  238. DNSType: kubeadmapi.CoreDNS,
  239. DNSVersion: "1.3.1",
  240. EtcdVersion: getEtcdVersion(constants.CurrentKubernetesVersion),
  241. },
  242. },
  243. },
  244. allowExperimental: false,
  245. errExpected: false,
  246. etcdClient: etcdClient,
  247. },
  248. {
  249. name: "both minor version upgrade and patch version upgrade available",
  250. vg: &fakeVersionGetter{
  251. clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  252. kubeletVersion: constants.MinimumKubeletVersion.WithPatch(3).String(), // the kubelet are on the same version as the control plane
  253. kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  254. stablePatchVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  255. stableVersion: constants.CurrentKubernetesVersion.WithPatch(1).String(),
  256. },
  257. beforeDNSType: kubeadmapi.CoreDNS,
  258. beforeDNSVersion: "1.0.6",
  259. dnsType: kubeadmapi.CoreDNS,
  260. expectedUpgrades: []Upgrade{
  261. {
  262. Description: fmt.Sprintf("version in the v%d.%d series", constants.MinimumControlPlaneVersion.Major(), constants.MinimumControlPlaneVersion.Minor()),
  263. Before: ClusterState{
  264. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  265. KubeletVersions: map[string]uint16{
  266. constants.MinimumKubeletVersion.WithPatch(3).String(): 1,
  267. },
  268. KubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  269. DNSType: kubeadmapi.CoreDNS,
  270. DNSVersion: "1.0.6",
  271. EtcdVersion: "3.1.12",
  272. },
  273. After: ClusterState{
  274. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  275. KubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(), // Note: The kubeadm version mustn't be "downgraded" here
  276. DNSType: kubeadmapi.CoreDNS,
  277. DNSVersion: "1.3.1",
  278. EtcdVersion: getEtcdVersion(constants.MinimumControlPlaneVersion),
  279. },
  280. },
  281. {
  282. Description: "stable version",
  283. Before: ClusterState{
  284. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  285. KubeletVersions: map[string]uint16{
  286. constants.MinimumKubeletVersion.WithPatch(3).String(): 1,
  287. },
  288. KubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  289. DNSType: kubeadmapi.CoreDNS,
  290. DNSVersion: "1.0.6",
  291. EtcdVersion: "3.1.12",
  292. },
  293. After: ClusterState{
  294. KubeVersion: constants.CurrentKubernetesVersion.WithPatch(1).String(),
  295. KubeadmVersion: constants.CurrentKubernetesVersion.WithPatch(1).String(),
  296. DNSType: kubeadmapi.CoreDNS,
  297. DNSVersion: "1.3.1",
  298. EtcdVersion: getEtcdVersion(constants.CurrentKubernetesVersion),
  299. },
  300. },
  301. },
  302. allowExperimental: false,
  303. errExpected: false,
  304. etcdClient: etcdClient,
  305. },
  306. {
  307. name: "allow experimental upgrades, but no upgrade available",
  308. vg: &fakeVersionGetter{
  309. clusterVersion: "v1.11.0-alpha.2",
  310. kubeletVersion: "v1.10.5",
  311. kubeadmVersion: "v1.10.5",
  312. stablePatchVersion: "v1.10.5",
  313. stableVersion: "v1.10.5",
  314. latestVersion: "v1.11.0-alpha.2",
  315. },
  316. beforeDNSType: kubeadmapi.CoreDNS,
  317. beforeDNSVersion: "v1.0.6",
  318. dnsType: kubeadmapi.CoreDNS,
  319. expectedUpgrades: []Upgrade{},
  320. allowExperimental: true,
  321. errExpected: false,
  322. etcdClient: etcdClient,
  323. },
  324. {
  325. name: "upgrade to an unstable version should be supported",
  326. vg: &fakeVersionGetter{
  327. clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  328. kubeletVersion: constants.MinimumKubeletVersion.WithPatch(5).String(),
  329. kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  330. stablePatchVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  331. stableVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  332. latestVersion: constants.CurrentKubernetesVersion.WithPreRelease("alpha.2").String(),
  333. },
  334. beforeDNSType: kubeadmapi.CoreDNS,
  335. beforeDNSVersion: "1.0.6",
  336. dnsType: kubeadmapi.CoreDNS,
  337. expectedUpgrades: []Upgrade{
  338. {
  339. Description: "experimental version",
  340. Before: ClusterState{
  341. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  342. KubeletVersions: map[string]uint16{
  343. constants.MinimumControlPlaneVersion.WithPatch(5).String(): 1,
  344. },
  345. KubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  346. DNSType: kubeadmapi.CoreDNS,
  347. DNSVersion: "1.0.6",
  348. EtcdVersion: "3.1.12",
  349. },
  350. After: ClusterState{
  351. KubeVersion: constants.CurrentKubernetesVersion.WithPreRelease("alpha.2").String(),
  352. KubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("alpha.2").String(),
  353. DNSType: kubeadmapi.CoreDNS,
  354. DNSVersion: "1.3.1",
  355. EtcdVersion: getEtcdVersion(constants.CurrentKubernetesVersion),
  356. },
  357. },
  358. },
  359. allowExperimental: true,
  360. errExpected: false,
  361. etcdClient: etcdClient,
  362. },
  363. {
  364. name: "upgrade from an unstable version to an unstable version should be supported",
  365. vg: &fakeVersionGetter{
  366. clusterVersion: constants.CurrentKubernetesVersion.WithPreRelease("alpha.1").String(),
  367. kubeletVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  368. kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  369. stablePatchVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  370. stableVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  371. latestVersion: constants.CurrentKubernetesVersion.WithPreRelease("alpha.2").String(),
  372. },
  373. beforeDNSType: kubeadmapi.CoreDNS,
  374. beforeDNSVersion: "1.0.6",
  375. dnsType: kubeadmapi.CoreDNS,
  376. expectedUpgrades: []Upgrade{
  377. {
  378. Description: "experimental version",
  379. Before: ClusterState{
  380. KubeVersion: constants.CurrentKubernetesVersion.WithPreRelease("alpha.1").String(),
  381. KubeletVersions: map[string]uint16{
  382. constants.MinimumControlPlaneVersion.WithPatch(5).String(): 1,
  383. },
  384. KubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(5).String(),
  385. DNSType: kubeadmapi.CoreDNS,
  386. DNSVersion: "1.0.6",
  387. EtcdVersion: "3.1.12",
  388. },
  389. After: ClusterState{
  390. KubeVersion: constants.CurrentKubernetesVersion.WithPreRelease("alpha.2").String(),
  391. KubeadmVersion: constants.CurrentKubernetesVersion.WithPreRelease("alpha.2").String(),
  392. DNSType: kubeadmapi.CoreDNS,
  393. DNSVersion: "1.3.1",
  394. EtcdVersion: getEtcdVersion(constants.CurrentKubernetesVersion),
  395. },
  396. },
  397. },
  398. allowExperimental: true,
  399. errExpected: false,
  400. etcdClient: etcdClient,
  401. },
  402. {
  403. name: "v1.X.0-alpha.0 should be ignored",
  404. vg: &fakeVersionGetter{
  405. clusterVersion: "v1.11.5",
  406. kubeletVersion: "v1.11.5",
  407. kubeadmVersion: "v1.11.5",
  408. stablePatchVersion: "v1.11.5",
  409. stableVersion: "v1.11.5",
  410. latestDevBranchVersion: "v1.13.0-beta.1",
  411. latestVersion: "v1.12.0-alpha.0",
  412. },
  413. beforeDNSType: kubeadmapi.CoreDNS,
  414. beforeDNSVersion: "1.0.6",
  415. dnsType: kubeadmapi.CoreDNS,
  416. expectedUpgrades: []Upgrade{
  417. {
  418. Description: "experimental version",
  419. Before: ClusterState{
  420. KubeVersion: "v1.11.5",
  421. KubeletVersions: map[string]uint16{
  422. "v1.11.5": 1,
  423. },
  424. KubeadmVersion: "v1.11.5",
  425. DNSType: kubeadmapi.CoreDNS,
  426. DNSVersion: "1.0.6",
  427. EtcdVersion: "3.1.12",
  428. },
  429. After: ClusterState{
  430. KubeVersion: "v1.13.0-beta.1",
  431. KubeadmVersion: "v1.13.0-beta.1",
  432. DNSType: kubeadmapi.CoreDNS,
  433. DNSVersion: "1.3.1",
  434. EtcdVersion: "3.2.24",
  435. },
  436. },
  437. },
  438. allowExperimental: true,
  439. errExpected: false,
  440. etcdClient: etcdClient,
  441. },
  442. {
  443. name: "upgrade to an RC version should be supported",
  444. vg: &fakeVersionGetter{
  445. clusterVersion: "v1.11.5",
  446. kubeletVersion: "v1.11.5",
  447. kubeadmVersion: "v1.11.5",
  448. stablePatchVersion: "v1.11.5",
  449. stableVersion: "v1.11.5",
  450. latestDevBranchVersion: "v1.13.0-rc.1",
  451. latestVersion: "v1.12.0-alpha.1",
  452. },
  453. beforeDNSType: kubeadmapi.CoreDNS,
  454. beforeDNSVersion: "1.0.6",
  455. dnsType: kubeadmapi.CoreDNS,
  456. expectedUpgrades: []Upgrade{
  457. {
  458. Description: "release candidate version",
  459. Before: ClusterState{
  460. KubeVersion: "v1.11.5",
  461. KubeletVersions: map[string]uint16{
  462. "v1.11.5": 1,
  463. },
  464. KubeadmVersion: "v1.11.5",
  465. DNSType: kubeadmapi.CoreDNS,
  466. DNSVersion: "1.0.6",
  467. EtcdVersion: "3.1.12",
  468. },
  469. After: ClusterState{
  470. KubeVersion: "v1.13.0-rc.1",
  471. KubeadmVersion: "v1.13.0-rc.1",
  472. DNSType: kubeadmapi.CoreDNS,
  473. DNSVersion: "1.3.1",
  474. EtcdVersion: "3.2.24",
  475. },
  476. },
  477. },
  478. allowRCs: true,
  479. errExpected: false,
  480. etcdClient: etcdClient,
  481. },
  482. {
  483. 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",
  484. vg: &fakeVersionGetter{
  485. clusterVersion: "v1.11.5",
  486. kubeletVersion: "v1.11.5",
  487. kubeadmVersion: "v1.11.5",
  488. stablePatchVersion: "v1.11.5",
  489. stableVersion: "v1.11.5",
  490. latestDevBranchVersion: "v1.13.6-rc.1",
  491. latestVersion: "v1.12.1-alpha.0",
  492. },
  493. beforeDNSType: kubeadmapi.CoreDNS,
  494. beforeDNSVersion: "1.0.6",
  495. dnsType: kubeadmapi.CoreDNS,
  496. expectedUpgrades: []Upgrade{
  497. {
  498. Description: "experimental version", // Note that this is considered an experimental version in this uncommon scenario
  499. Before: ClusterState{
  500. KubeVersion: "v1.11.5",
  501. KubeletVersions: map[string]uint16{
  502. "v1.11.5": 1,
  503. },
  504. KubeadmVersion: "v1.11.5",
  505. DNSType: kubeadmapi.CoreDNS,
  506. DNSVersion: "1.0.6",
  507. EtcdVersion: "3.1.12",
  508. },
  509. After: ClusterState{
  510. KubeVersion: "v1.13.6-rc.1",
  511. KubeadmVersion: "v1.13.6-rc.1",
  512. DNSType: kubeadmapi.CoreDNS,
  513. DNSVersion: "1.3.1",
  514. EtcdVersion: "3.2.24",
  515. },
  516. },
  517. },
  518. allowExperimental: true,
  519. errExpected: false,
  520. etcdClient: etcdClient,
  521. },
  522. {
  523. name: "upgrade to an RC version should be supported. There may also be an even newer unstable version.",
  524. vg: &fakeVersionGetter{
  525. clusterVersion: "v1.11.5",
  526. kubeletVersion: "v1.11.5",
  527. kubeadmVersion: "v1.11.5",
  528. stablePatchVersion: "v1.11.5",
  529. stableVersion: "v1.11.5",
  530. latestDevBranchVersion: "v1.13.0-rc.1",
  531. latestVersion: "v1.12.0-alpha.2",
  532. },
  533. beforeDNSType: kubeadmapi.CoreDNS,
  534. beforeDNSVersion: "1.0.6",
  535. dnsType: kubeadmapi.CoreDNS,
  536. expectedUpgrades: []Upgrade{
  537. {
  538. Description: "release candidate version",
  539. Before: ClusterState{
  540. KubeVersion: "v1.11.5",
  541. KubeletVersions: map[string]uint16{
  542. "v1.11.5": 1,
  543. },
  544. KubeadmVersion: "v1.11.5",
  545. DNSType: kubeadmapi.CoreDNS,
  546. DNSVersion: "1.0.6",
  547. EtcdVersion: "3.1.12",
  548. },
  549. After: ClusterState{
  550. KubeVersion: "v1.13.0-rc.1",
  551. KubeadmVersion: "v1.13.0-rc.1",
  552. DNSType: kubeadmapi.CoreDNS,
  553. DNSVersion: "1.3.1",
  554. EtcdVersion: "3.2.24",
  555. },
  556. },
  557. {
  558. Description: "experimental version",
  559. Before: ClusterState{
  560. KubeVersion: "v1.11.5",
  561. KubeletVersions: map[string]uint16{
  562. "v1.11.5": 1,
  563. },
  564. KubeadmVersion: "v1.11.5",
  565. DNSType: kubeadmapi.CoreDNS,
  566. DNSVersion: "1.0.6",
  567. EtcdVersion: "3.1.12",
  568. },
  569. After: ClusterState{
  570. KubeVersion: "v1.12.0-alpha.2",
  571. KubeadmVersion: "v1.12.0-alpha.2",
  572. DNSType: kubeadmapi.CoreDNS,
  573. DNSVersion: "1.3.1",
  574. EtcdVersion: "3.2.24",
  575. },
  576. },
  577. },
  578. allowRCs: true,
  579. allowExperimental: true,
  580. errExpected: false,
  581. etcdClient: etcdClient,
  582. },
  583. {
  584. name: "Upgrades with external etcd with mismatched versions should not be allowed.",
  585. vg: &fakeVersionGetter{
  586. clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  587. kubeletVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  588. kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  589. stablePatchVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  590. stableVersion: constants.MinimumControlPlaneVersion.WithPatch(3).String(),
  591. },
  592. allowRCs: false,
  593. allowExperimental: false,
  594. etcdClient: fakeEtcdClient{mismatchedVersions: true},
  595. expectedUpgrades: []Upgrade{},
  596. errExpected: true,
  597. },
  598. {
  599. name: "offline version getter",
  600. vg: NewOfflineVersionGetter(&fakeVersionGetter{
  601. clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(1).String(),
  602. kubeletVersion: constants.MinimumKubeletVersion.String(),
  603. kubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(1).String(),
  604. }, constants.CurrentKubernetesVersion.WithPatch(1).String()),
  605. etcdClient: etcdClient,
  606. beforeDNSType: kubeadmapi.CoreDNS,
  607. beforeDNSVersion: "1.0.6",
  608. dnsType: kubeadmapi.CoreDNS,
  609. expectedUpgrades: []Upgrade{
  610. {
  611. Description: fmt.Sprintf("version in the v%d.%d series", constants.MinimumControlPlaneVersion.Major(), constants.MinimumControlPlaneVersion.Minor()),
  612. Before: ClusterState{
  613. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(1).String(),
  614. KubeletVersions: map[string]uint16{
  615. constants.MinimumKubeletVersion.String(): 1,
  616. },
  617. KubeadmVersion: constants.MinimumControlPlaneVersion.WithPatch(1).String(),
  618. DNSType: kubeadmapi.CoreDNS,
  619. DNSVersion: "1.0.6",
  620. EtcdVersion: "3.1.12",
  621. },
  622. After: ClusterState{
  623. KubeVersion: constants.CurrentKubernetesVersion.WithPatch(1).String(),
  624. KubeadmVersion: constants.CurrentKubernetesVersion.WithPatch(1).String(),
  625. DNSType: kubeadmapi.CoreDNS,
  626. DNSVersion: "1.3.1",
  627. EtcdVersion: getEtcdVersion(constants.CurrentKubernetesVersion),
  628. },
  629. },
  630. },
  631. },
  632. {
  633. name: "kubedns to coredns",
  634. vg: &fakeVersionGetter{
  635. clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(),
  636. kubeletVersion: constants.MinimumKubeletVersion.WithPatch(2).String(), // the kubelet are on the same version as the control plane
  637. kubeadmVersion: constants.CurrentKubernetesVersion.String(),
  638. stablePatchVersion: constants.CurrentKubernetesVersion.String(),
  639. stableVersion: constants.CurrentKubernetesVersion.String(),
  640. },
  641. etcdClient: etcdClient,
  642. beforeDNSType: kubeadmapi.KubeDNS,
  643. beforeDNSVersion: "1.14.7",
  644. dnsType: kubeadmapi.CoreDNS,
  645. expectedUpgrades: []Upgrade{
  646. {
  647. Description: fmt.Sprintf("version in the v%d.%d series", constants.MinimumControlPlaneVersion.Major(), constants.MinimumControlPlaneVersion.Minor()),
  648. Before: ClusterState{
  649. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(),
  650. KubeletVersions: map[string]uint16{
  651. constants.MinimumControlPlaneVersion.WithPatch(2).String(): 1,
  652. },
  653. KubeadmVersion: constants.CurrentKubernetesVersion.String(),
  654. DNSType: kubeadmapi.KubeDNS,
  655. DNSVersion: "1.14.7",
  656. EtcdVersion: "3.1.12",
  657. },
  658. After: ClusterState{
  659. KubeVersion: constants.CurrentKubernetesVersion.String(),
  660. KubeadmVersion: constants.CurrentKubernetesVersion.String(),
  661. DNSType: kubeadmapi.CoreDNS,
  662. DNSVersion: "1.3.1",
  663. EtcdVersion: getEtcdVersion(constants.CurrentKubernetesVersion),
  664. },
  665. },
  666. },
  667. },
  668. {
  669. name: "keep coredns",
  670. vg: &fakeVersionGetter{
  671. clusterVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(),
  672. kubeletVersion: constants.MinimumKubeletVersion.WithPatch(2).String(), // the kubelet are on the same version as the control plane
  673. kubeadmVersion: constants.CurrentKubernetesVersion.String(),
  674. stablePatchVersion: constants.CurrentKubernetesVersion.String(),
  675. stableVersion: constants.CurrentKubernetesVersion.String(),
  676. },
  677. etcdClient: etcdClient,
  678. beforeDNSType: kubeadmapi.KubeDNS,
  679. beforeDNSVersion: "1.14.7",
  680. dnsType: kubeadmapi.KubeDNS,
  681. expectedUpgrades: []Upgrade{
  682. {
  683. Description: fmt.Sprintf("version in the v%d.%d series", constants.MinimumControlPlaneVersion.Major(), constants.MinimumControlPlaneVersion.Minor()),
  684. Before: ClusterState{
  685. KubeVersion: constants.MinimumControlPlaneVersion.WithPatch(2).String(),
  686. KubeletVersions: map[string]uint16{
  687. constants.MinimumControlPlaneVersion.WithPatch(2).String(): 1,
  688. },
  689. KubeadmVersion: constants.CurrentKubernetesVersion.String(),
  690. DNSType: kubeadmapi.KubeDNS,
  691. DNSVersion: "1.14.7",
  692. EtcdVersion: "3.1.12",
  693. },
  694. After: ClusterState{
  695. KubeVersion: constants.CurrentKubernetesVersion.String(),
  696. KubeadmVersion: constants.CurrentKubernetesVersion.String(),
  697. DNSType: kubeadmapi.KubeDNS,
  698. DNSVersion: "1.14.13",
  699. EtcdVersion: getEtcdVersion(constants.CurrentKubernetesVersion),
  700. },
  701. },
  702. },
  703. },
  704. }
  705. // Instantiating a fake etcd cluster for being able to get etcd version for a corresponding
  706. // Kubernetes release.
  707. for _, rt := range tests {
  708. t.Run(rt.name, func(t *testing.T) {
  709. dnsName := constants.CoreDNSDeploymentName
  710. if rt.beforeDNSType == kubeadmapi.KubeDNS {
  711. dnsName = constants.KubeDNSDeploymentName
  712. }
  713. client := clientsetfake.NewSimpleClientset(&apps.Deployment{
  714. TypeMeta: metav1.TypeMeta{
  715. Kind: "Deployment",
  716. APIVersion: "apps/v1",
  717. },
  718. ObjectMeta: metav1.ObjectMeta{
  719. Name: dnsName,
  720. Namespace: "kube-system",
  721. Labels: map[string]string{
  722. "k8s-app": "kube-dns",
  723. },
  724. },
  725. Spec: apps.DeploymentSpec{
  726. Template: v1.PodTemplateSpec{
  727. Spec: v1.PodSpec{
  728. Containers: []v1.Container{
  729. {
  730. Image: "test:" + rt.beforeDNSVersion,
  731. },
  732. },
  733. },
  734. },
  735. },
  736. })
  737. actualUpgrades, actualErr := GetAvailableUpgrades(rt.vg, rt.allowExperimental, rt.allowRCs, rt.etcdClient, rt.dnsType, client)
  738. if !reflect.DeepEqual(actualUpgrades, rt.expectedUpgrades) {
  739. t.Errorf("failed TestGetAvailableUpgrades\n\texpected upgrades: %v\n\tgot: %v", rt.expectedUpgrades, actualUpgrades)
  740. }
  741. if (actualErr != nil) != rt.errExpected {
  742. fmt.Printf("Hello error")
  743. t.Errorf("failed TestGetAvailableUpgrades\n\texpected error: %t\n\tgot error: %t", rt.errExpected, (actualErr != nil))
  744. }
  745. if !reflect.DeepEqual(actualUpgrades, rt.expectedUpgrades) {
  746. t.Errorf("failed TestGetAvailableUpgrades\n\texpected upgrades: %v\n\tgot: %v", rt.expectedUpgrades, actualUpgrades)
  747. }
  748. })
  749. }
  750. }
  751. func TestKubeletUpgrade(t *testing.T) {
  752. tests := []struct {
  753. name string
  754. before map[string]uint16
  755. after string
  756. expected bool
  757. }{
  758. {
  759. name: "upgrade from v1.10.1 to v1.10.3 is available",
  760. before: map[string]uint16{
  761. "v1.10.1": 1,
  762. },
  763. after: "v1.10.3",
  764. expected: true,
  765. },
  766. {
  767. name: "upgrade from v1.10.1 and v1.10.3/100 to v1.10.3 is available",
  768. before: map[string]uint16{
  769. "v1.10.1": 1,
  770. "v1.10.3": 100,
  771. },
  772. after: "v1.10.3",
  773. expected: true,
  774. },
  775. {
  776. name: "upgrade from v1.10.3 to v1.10.3 is not available",
  777. before: map[string]uint16{
  778. "v1.10.3": 1,
  779. },
  780. after: "v1.10.3",
  781. expected: false,
  782. },
  783. {
  784. name: "upgrade from v1.10.3/100 to v1.10.3 is not available",
  785. before: map[string]uint16{
  786. "v1.10.3": 100,
  787. },
  788. after: "v1.10.3",
  789. expected: false,
  790. },
  791. {
  792. name: "upgrade is not available if we don't know anything about the earlier state",
  793. before: map[string]uint16{},
  794. after: "v1.10.3",
  795. expected: false,
  796. },
  797. }
  798. for _, rt := range tests {
  799. t.Run(rt.name, func(t *testing.T) {
  800. upgrade := Upgrade{
  801. Before: ClusterState{
  802. KubeletVersions: rt.before,
  803. },
  804. After: ClusterState{
  805. KubeVersion: rt.after,
  806. },
  807. }
  808. actual := upgrade.CanUpgradeKubelets()
  809. if actual != rt.expected {
  810. t.Errorf("failed TestKubeletUpgrade\n\texpected: %t\n\tgot: %t\n\ttest object: %v", rt.expected, actual, upgrade)
  811. }
  812. })
  813. }
  814. }
  815. func TestGetBranchFromVersion(t *testing.T) {
  816. testCases := []struct {
  817. version string
  818. expectedVersion string
  819. }{
  820. {
  821. version: "v1.9.5",
  822. expectedVersion: "1.9",
  823. },
  824. {
  825. version: "v1.9.0-alpha.2",
  826. expectedVersion: "1.9",
  827. },
  828. {
  829. version: "v1.9.0-beta.0",
  830. expectedVersion: "1.9",
  831. },
  832. {
  833. version: "v1.9.0-rc.1",
  834. expectedVersion: "1.9",
  835. },
  836. {
  837. version: "v1.11.0-alpha.0",
  838. expectedVersion: "1.11",
  839. },
  840. {
  841. version: "v1.11.0-beta.1",
  842. expectedVersion: "1.11",
  843. },
  844. {
  845. version: "v1.11.0-rc.0",
  846. expectedVersion: "1.11",
  847. },
  848. {
  849. version: "1.12.5",
  850. expectedVersion: "1.12",
  851. },
  852. }
  853. for _, tc := range testCases {
  854. t.Run(tc.version, func(t *testing.T) {
  855. v := getBranchFromVersion(tc.version)
  856. if v != tc.expectedVersion {
  857. t.Errorf("expected version %s, got %s", tc.expectedVersion, v)
  858. }
  859. })
  860. }
  861. }