cluster_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. /*
  2. Copyright 2018 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 config
  14. import (
  15. "context"
  16. "io/ioutil"
  17. "os"
  18. "path/filepath"
  19. "strings"
  20. "testing"
  21. v1 "k8s.io/api/core/v1"
  22. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. "k8s.io/apimachinery/pkg/util/version"
  24. clientset "k8s.io/client-go/kubernetes"
  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/componentconfigs"
  28. kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
  29. "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
  30. )
  31. var k8sVersionString = kubeadmconstants.MinimumControlPlaneVersion.String()
  32. var k8sVersion = version.MustParseGeneric(k8sVersionString)
  33. var nodeName = "mynode"
  34. var cfgFiles = map[string][]byte{
  35. "InitConfiguration_v1beta1": []byte(`
  36. apiVersion: kubeadm.k8s.io/v1beta1
  37. kind: InitConfiguration
  38. `),
  39. "ClusterConfiguration_v1beta1": []byte(`
  40. apiVersion: kubeadm.k8s.io/v1beta1
  41. kind: ClusterConfiguration
  42. kubernetesVersion: ` + k8sVersionString + `
  43. `),
  44. "ClusterStatus_v1beta1": []byte(`
  45. apiVersion: kubeadm.k8s.io/v1beta1
  46. kind: ClusterStatus
  47. apiEndpoints:
  48. ` + nodeName + `:
  49. advertiseAddress: 1.2.3.4
  50. bindPort: 1234
  51. `),
  52. "ClusterStatus_v1beta1_Without_APIEndpoints": []byte(`
  53. apiVersion: kubeadm.k8s.io/v1beta1
  54. kind: ClusterStatus
  55. `),
  56. "InitConfiguration_v1beta2": []byte(`
  57. apiVersion: kubeadm.k8s.io/v1beta2
  58. kind: InitConfiguration
  59. `),
  60. "ClusterConfiguration_v1beta2": []byte(`
  61. apiVersion: kubeadm.k8s.io/v1beta2
  62. kind: ClusterConfiguration
  63. kubernetesVersion: ` + k8sVersionString + `
  64. `),
  65. "ClusterStatus_v1beta2": []byte(`
  66. apiVersion: kubeadm.k8s.io/v1beta2
  67. kind: ClusterStatus
  68. apiEndpoints:
  69. ` + nodeName + `:
  70. advertiseAddress: 1.2.3.4
  71. bindPort: 1234
  72. `),
  73. "ClusterStatus_v1beta2_Without_APIEndpoints": []byte(`
  74. apiVersion: kubeadm.k8s.io/v1beta2
  75. kind: ClusterStatus
  76. `),
  77. "Kube-proxy_componentconfig": []byte(`
  78. apiVersion: kubeproxy.config.k8s.io/v1alpha1
  79. kind: KubeProxyConfiguration
  80. `),
  81. "Kubelet_componentconfig": []byte(`
  82. apiVersion: kubelet.config.k8s.io/v1beta1
  83. kind: KubeletConfiguration
  84. `),
  85. }
  86. var kubeletConfFiles = map[string][]byte{
  87. "withoutX509Cert": []byte(`
  88. apiVersion: v1
  89. clusters:
  90. - cluster:
  91. server: https://10.0.2.15:6443
  92. name: kubernetes
  93. contexts:
  94. - context:
  95. cluster: kubernetes
  96. user: system:node:mynode
  97. name: system:node:mynode@kubernetes
  98. current-context: system:node:mynode@kubernetes
  99. kind: Config
  100. preferences: {}
  101. users:
  102. - name: system:node:mynode
  103. user:
  104. `),
  105. "configWithEmbeddedCert": []byte(`
  106. apiVersion: v1
  107. clusters:
  108. - cluster:
  109. server: https://10.0.2.15:6443
  110. name: kubernetes
  111. contexts:
  112. - context:
  113. cluster: kubernetes
  114. user: system:node:mynode
  115. name: system:node:mynode@kubernetes
  116. current-context: system:node:mynode@kubernetes
  117. kind: Config
  118. preferences: {}
  119. users:
  120. - name: system:node:mynode
  121. user:
  122. client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJQWl3VURhYk5vZ1F3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T0RBNU1ERXhOVE14TWpaYUZ3MHhPVEE1TURFeE5qQXhOVGxhTURReApGVEFUQmdOVkJBb1RESE41YzNSbGJUcHViMlJsY3pFYk1Ca0dBMVVFQXhNU2MzbHpkR1Z0T201dlpHVTZiWGx1CmIyUmxNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQWs2UXUzeStyNEZYUzZ4VkoKWU1vNE9kSkt3R1d1MHY4TEJIUnhhOUhvVHo1RXZLQnB1OVJoemt5dStUaFczb0xta2ZTRmNJcitHa0M5MW0zOApFelRmVE5JY2dsL0V5YkpmR1QvdGdUazZYd1kxY1UrUUdmSEFNNTBCVzFXTFVHc25CSllJZjA5eENnZTVoTkxLCnREeUJOWWNQZzg1bUJpOU9CNFJ2UlgyQVFRMjJwZ0xrQUpJWklOU0FEdUFrODN2b051SXM2YVY2bHBkR2Vva3YKdDlpTFdNR3p3a3ZTZUZQTlNGeWZ3Q055eENjb1FDQUNtSnJRS3NoeUE2bWNzdVhORWVXdlRQdVVFSWZPVFl4dwpxdkszRVBOK0xUYlA2anhUMWtTcFJUOSt4Z29uSlFhU0RsbUNBd20zRGJkSVppWUt3R2ppMkxKL0kvYWc0cTlzCjNLb0J2UUlEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFLcVVrU21jdW85OG5EK015b005VFdEV0pyTndySXpQTUNqRQpCSkdyREhVaHIwcEZlRjc0RHViODNzRXlaNjFxNUVQd2Y0enNLSzdzdDRUTzZhcE9pZWJYVmN3dnZoa09HQ2dFCmFVdGNOMjFhUGxtU0tOd0c4ai8yK3ZhbU80bGplK1NnZzRUUVB0eDZWejh5VXN2RFhxSUZycjNNd1gzSDA1RW4KWXAzN05JYkhKbGxHUW5LVHA5aTg5aXF4WXVhSERqZldiVHlEY3B5NldNVjdVaFYvY1plc3lGL0NBamNHd1V6YgowRlo5bW5tMnFONlBGWHZ4RmdMSGFWZzN2SVVCbkNmVVVyY1BDNE94VFNPK21aUmUxazh3eUFpVWovSk0rZllvCkcrMi9sbThUYVZqb1U3Rmk1S2E1RzVIWTJHTGFSN1ArSXhZY3JNSENsNjJZN1JxY3JuYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
  123. `),
  124. "configWithLinkedCert": []byte(`
  125. apiVersion: v1
  126. clusters:
  127. - cluster:
  128. server: https://10.0.2.15:6443
  129. name: kubernetes
  130. contexts:
  131. - context:
  132. cluster: kubernetes
  133. user: system:node:mynode
  134. name: system:node:mynode@kubernetes
  135. current-context: system:node:mynode@kubernetes
  136. kind: Config
  137. preferences: {}
  138. users:
  139. - name: system:node:mynode
  140. user:
  141. client-certificate: kubelet.pem
  142. `),
  143. "configWithInvalidContext": []byte(`
  144. apiVersion: v1
  145. clusters:
  146. - cluster:
  147. server: https://10.0.2.15:6443
  148. name: kubernetes
  149. contexts:
  150. - context:
  151. cluster: kubernetes
  152. user: system:node:mynode
  153. name: system:node:mynode@kubernetes
  154. current-context: invalidContext
  155. kind: Config
  156. preferences: {}
  157. users:
  158. - name: system:node:mynode
  159. user:
  160. client-certificate: kubelet.pem
  161. `),
  162. "configWithInvalidUser": []byte(`
  163. apiVersion: v1
  164. clusters:
  165. - cluster:
  166. server: https://10.0.2.15:6443
  167. name: kubernetes
  168. contexts:
  169. - context:
  170. cluster: kubernetes
  171. user: invalidUser
  172. name: system:node:mynode@kubernetes
  173. current-context: system:node:mynode@kubernetes
  174. kind: Config
  175. preferences: {}
  176. users:
  177. - name: system:node:mynode
  178. user:
  179. client-certificate: kubelet.pem
  180. `),
  181. }
  182. var pemFiles = map[string][]byte{
  183. "mynode.pem": []byte(`
  184. -----BEGIN CERTIFICATE-----
  185. MIIC8jCCAdqgAwIBAgIIAiwUDabNogQwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
  186. AxMKa3ViZXJuZXRlczAeFw0xODA5MDExNTMxMjZaFw0xOTA5MDExNjAxNTlaMDQx
  187. FTATBgNVBAoTDHN5c3RlbTpub2RlczEbMBkGA1UEAxMSc3lzdGVtOm5vZGU6bXlu
  188. b2RlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk6Qu3y+r4FXS6xVJ
  189. YMo4OdJKwGWu0v8LBHRxa9HoTz5EvKBpu9Rhzkyu+ThW3oLmkfSFcIr+GkC91m38
  190. EzTfTNIcgl/EybJfGT/tgTk6XwY1cU+QGfHAM50BW1WLUGsnBJYIf09xCge5hNLK
  191. tDyBNYcPg85mBi9OB4RvRX2AQQ22pgLkAJIZINSADuAk83voNuIs6aV6lpdGeokv
  192. t9iLWMGzwkvSeFPNSFyfwCNyxCcoQCACmJrQKshyA6mcsuXNEeWvTPuUEIfOTYxw
  193. qvK3EPN+LTbP6jxT1kSpRT9+xgonJQaSDlmCAwm3DbdIZiYKwGji2LJ/I/ag4q9s
  194. 3KoBvQIDAQABoycwJTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUH
  195. AwIwDQYJKoZIhvcNAQELBQADggEBAKqUkSmcuo98nD+MyoM9TWDWJrNwrIzPMCjE
  196. BJGrDHUhr0pFeF74Dub83sEyZ61q5EPwf4zsKK7st4TO6apOiebXVcwvvhkOGCgE
  197. aUtcN21aPlmSKNwG8j/2+vamO4lje+Sgg4TQPtx6Vz8yUsvDXqIFrr3MwX3H05En
  198. Yp37NIbHJllGQnKTp9i89iqxYuaHDjfWbTyDcpy6WMV7UhV/cZesyF/CAjcGwUzb
  199. 0FZ9mnm2qN6PFXvxFgLHaVg3vIUBnCfUUrcPC4OxTSO+mZRe1k8wyAiUj/JM+fYo
  200. G+2/lm8TaVjoU7Fi5Ka5G5HY2GLaR7P+IxYcrMHCl62Y7Rqcrnc=
  201. -----END CERTIFICATE-----
  202. `),
  203. }
  204. func TestGetNodeNameFromKubeletConfig(t *testing.T) {
  205. tmpdir, err := ioutil.TempDir("", "")
  206. if err != nil {
  207. t.Fatalf("Couldn't create tmpdir")
  208. }
  209. defer os.RemoveAll(tmpdir)
  210. var tests = []struct {
  211. name string
  212. kubeconfigContent []byte
  213. pemContent []byte
  214. expectedError bool
  215. }{
  216. {
  217. name: "valid - with embedded cert",
  218. kubeconfigContent: kubeletConfFiles["configWithEmbeddedCert"],
  219. },
  220. {
  221. name: "invalid - linked cert missing",
  222. kubeconfigContent: kubeletConfFiles["configWithLinkedCert"],
  223. expectedError: true,
  224. },
  225. {
  226. name: "valid - with linked cert",
  227. kubeconfigContent: kubeletConfFiles["configWithLinkedCert"],
  228. pemContent: pemFiles["mynode.pem"],
  229. },
  230. {
  231. name: "invalid - without embedded or linked X509Cert",
  232. kubeconfigContent: kubeletConfFiles["withoutX509Cert"],
  233. expectedError: true,
  234. },
  235. {
  236. name: "invalid - the current context is invalid",
  237. kubeconfigContent: kubeletConfFiles["configWithInvalidContext"],
  238. expectedError: true,
  239. },
  240. {
  241. name: "invalid - the user of the current context is invalid",
  242. kubeconfigContent: kubeletConfFiles["configWithInvalidUser"],
  243. expectedError: true,
  244. },
  245. }
  246. for _, rt := range tests {
  247. t.Run(rt.name, func(t2 *testing.T) {
  248. if len(rt.pemContent) > 0 {
  249. pemPath := filepath.Join(tmpdir, "kubelet.pem")
  250. err := ioutil.WriteFile(pemPath, rt.pemContent, 0644)
  251. if err != nil {
  252. t.Errorf("Couldn't create pem file: %v", err)
  253. return
  254. }
  255. rt.kubeconfigContent = []byte(strings.Replace(string(rt.kubeconfigContent), "kubelet.pem", pemPath, -1))
  256. }
  257. kubeconfigPath := filepath.Join(tmpdir, kubeadmconstants.KubeletKubeConfigFileName)
  258. err := ioutil.WriteFile(kubeconfigPath, rt.kubeconfigContent, 0644)
  259. if err != nil {
  260. t.Errorf("Couldn't create kubeconfig: %v", err)
  261. return
  262. }
  263. name, err := getNodeNameFromKubeletConfig(tmpdir)
  264. if rt.expectedError != (err != nil) {
  265. t.Errorf("unexpected return err from getNodeRegistration: %v", err)
  266. return
  267. }
  268. if rt.expectedError {
  269. return
  270. }
  271. if name != nodeName {
  272. t.Errorf("invalid name")
  273. }
  274. })
  275. }
  276. }
  277. func TestGetNodeRegistration(t *testing.T) {
  278. tmpdir, err := ioutil.TempDir("", "")
  279. if err != nil {
  280. t.Fatalf("Couldn't create tmpdir")
  281. }
  282. defer os.RemoveAll(tmpdir)
  283. var tests = []struct {
  284. name string
  285. fileContents []byte
  286. node *v1.Node
  287. expectedError bool
  288. }{
  289. {
  290. name: "invalid - no kubelet.conf",
  291. expectedError: true,
  292. },
  293. {
  294. name: "valid",
  295. fileContents: kubeletConfFiles["configWithEmbeddedCert"],
  296. node: &v1.Node{
  297. ObjectMeta: metav1.ObjectMeta{
  298. Name: nodeName,
  299. Annotations: map[string]string{
  300. kubeadmconstants.AnnotationKubeadmCRISocket: "myCRIsocket",
  301. },
  302. },
  303. Spec: v1.NodeSpec{
  304. Taints: []v1.Taint{kubeadmconstants.ControlPlaneTaint},
  305. },
  306. },
  307. },
  308. {
  309. name: "invalid - no node",
  310. fileContents: kubeletConfFiles["configWithEmbeddedCert"],
  311. expectedError: true,
  312. },
  313. }
  314. for _, rt := range tests {
  315. t.Run(rt.name, func(t2 *testing.T) {
  316. cfgPath := filepath.Join(tmpdir, kubeadmconstants.KubeletKubeConfigFileName)
  317. if len(rt.fileContents) > 0 {
  318. err := ioutil.WriteFile(cfgPath, rt.fileContents, 0644)
  319. if err != nil {
  320. t.Errorf("Couldn't create file")
  321. return
  322. }
  323. }
  324. client := clientsetfake.NewSimpleClientset()
  325. if rt.node != nil {
  326. _, err := client.CoreV1().Nodes().Create(context.TODO(), rt.node, metav1.CreateOptions{})
  327. if err != nil {
  328. t.Errorf("couldn't create Node")
  329. return
  330. }
  331. }
  332. cfg := &kubeadmapi.InitConfiguration{}
  333. err = getNodeRegistration(tmpdir, client, &cfg.NodeRegistration)
  334. if rt.expectedError != (err != nil) {
  335. t.Errorf("unexpected return err from getNodeRegistration: %v", err)
  336. return
  337. }
  338. if rt.expectedError {
  339. return
  340. }
  341. if cfg.NodeRegistration.Name != nodeName {
  342. t.Errorf("invalid cfg.NodeRegistration.Name")
  343. }
  344. if cfg.NodeRegistration.CRISocket != "myCRIsocket" {
  345. t.Errorf("invalid cfg.NodeRegistration.CRISocket")
  346. }
  347. if len(cfg.NodeRegistration.Taints) != 1 {
  348. t.Errorf("invalid cfg.NodeRegistration.Taints")
  349. }
  350. })
  351. }
  352. }
  353. func TestGetAPIEndpoint(t *testing.T) {
  354. var tests = []struct {
  355. name string
  356. configMap fakeConfigMap
  357. expectedError bool
  358. }{
  359. {
  360. name: "valid v1beta1",
  361. configMap: fakeConfigMap{
  362. name: kubeadmconstants.KubeadmConfigConfigMap, // ClusterConfiguration from kubeadm-config.
  363. data: map[string]string{
  364. kubeadmconstants.ClusterStatusConfigMapKey: string(cfgFiles["ClusterStatus_v1beta1"]),
  365. },
  366. },
  367. },
  368. {
  369. name: "invalid v1beta1 - No ClusterStatus in kubeadm-config ConfigMap",
  370. configMap: fakeConfigMap{
  371. name: kubeadmconstants.KubeadmConfigConfigMap, // ClusterConfiguration from kubeadm-config.
  372. data: map[string]string{},
  373. },
  374. expectedError: true,
  375. },
  376. {
  377. name: "invalid v1beta1 - ClusterStatus without APIEndopoints",
  378. configMap: fakeConfigMap{
  379. name: kubeadmconstants.KubeadmConfigConfigMap, // ClusterConfiguration from kubeadm-config.
  380. data: map[string]string{
  381. kubeadmconstants.ClusterStatusConfigMapKey: string(cfgFiles["ClusterStatus_v1beta1_Without_APIEndpoints"]),
  382. },
  383. },
  384. expectedError: true,
  385. },
  386. {
  387. name: "valid v1beta2",
  388. configMap: fakeConfigMap{
  389. name: kubeadmconstants.KubeadmConfigConfigMap, // ClusterConfiguration from kubeadm-config.
  390. data: map[string]string{
  391. kubeadmconstants.ClusterStatusConfigMapKey: string(cfgFiles["ClusterStatus_v1beta2"]),
  392. },
  393. },
  394. },
  395. {
  396. name: "invalid v1beta2 - No ClusterStatus in kubeadm-config ConfigMap",
  397. configMap: fakeConfigMap{
  398. name: kubeadmconstants.KubeadmConfigConfigMap, // ClusterConfiguration from kubeadm-config.
  399. data: map[string]string{},
  400. },
  401. expectedError: true,
  402. },
  403. {
  404. name: "invalid v1beta2 - ClusterStatus without APIEndopoints",
  405. configMap: fakeConfigMap{
  406. name: kubeadmconstants.KubeadmConfigConfigMap, // ClusterConfiguration from kubeadm-config.
  407. data: map[string]string{
  408. kubeadmconstants.ClusterStatusConfigMapKey: string(cfgFiles["ClusterStatus_v1beta2_Without_APIEndpoints"]),
  409. },
  410. },
  411. expectedError: true,
  412. },
  413. }
  414. for _, rt := range tests {
  415. t.Run(rt.name, func(t *testing.T) {
  416. cfg := &kubeadmapi.InitConfiguration{}
  417. err := getAPIEndpoint(rt.configMap.data, nodeName, &cfg.LocalAPIEndpoint)
  418. if rt.expectedError != (err != nil) {
  419. t.Errorf("unexpected return err from getInitConfigurationFromCluster: %v", err)
  420. return
  421. }
  422. if rt.expectedError {
  423. return
  424. }
  425. if cfg.LocalAPIEndpoint.AdvertiseAddress != "1.2.3.4" || cfg.LocalAPIEndpoint.BindPort != 1234 {
  426. t.Errorf("invalid cfg.APIEndpoint")
  427. }
  428. })
  429. }
  430. }
  431. func TestGetInitConfigurationFromCluster(t *testing.T) {
  432. tmpdir, err := ioutil.TempDir("", "")
  433. if err != nil {
  434. t.Fatalf("Couldn't create tmpdir")
  435. }
  436. defer os.RemoveAll(tmpdir)
  437. var tests = []struct {
  438. name string
  439. fileContents []byte
  440. node *v1.Node
  441. configMaps []fakeConfigMap
  442. newControlPlane bool
  443. expectedError bool
  444. }{
  445. {
  446. name: "invalid - No kubeadm-config ConfigMap",
  447. expectedError: true,
  448. },
  449. {
  450. name: "invalid - No ClusterConfiguration in kubeadm-config ConfigMap",
  451. configMaps: []fakeConfigMap{
  452. {
  453. name: kubeadmconstants.KubeadmConfigConfigMap, // ClusterConfiguration from kubeadm-config.
  454. data: map[string]string{},
  455. },
  456. },
  457. expectedError: true,
  458. },
  459. {
  460. name: "valid v1beta1 - new control plane == false", // InitConfiguration composed with data from different places, with also node specific information from ClusterStatus and node
  461. configMaps: []fakeConfigMap{
  462. {
  463. name: kubeadmconstants.KubeadmConfigConfigMap, // ClusterConfiguration from kubeadm-config.
  464. data: map[string]string{
  465. kubeadmconstants.ClusterConfigurationConfigMapKey: string(cfgFiles["ClusterConfiguration_v1beta1"]),
  466. kubeadmconstants.ClusterStatusConfigMapKey: string(cfgFiles["ClusterStatus_v1beta1"]),
  467. },
  468. },
  469. {
  470. name: kubeadmconstants.KubeProxyConfigMap, // Kube-proxy component config from corresponding ConfigMap.
  471. data: map[string]string{
  472. kubeadmconstants.KubeProxyConfigMapKey: string(cfgFiles["Kube-proxy_componentconfig"]),
  473. },
  474. },
  475. {
  476. name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion), // Kubelet component config from corresponding ConfigMap.
  477. data: map[string]string{
  478. kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
  479. },
  480. },
  481. },
  482. fileContents: kubeletConfFiles["configWithEmbeddedCert"],
  483. node: &v1.Node{
  484. ObjectMeta: metav1.ObjectMeta{
  485. Name: nodeName,
  486. Annotations: map[string]string{
  487. kubeadmconstants.AnnotationKubeadmCRISocket: "myCRIsocket",
  488. },
  489. },
  490. Spec: v1.NodeSpec{
  491. Taints: []v1.Taint{kubeadmconstants.ControlPlaneTaint},
  492. },
  493. },
  494. },
  495. {
  496. name: "valid v1beta1 - new control plane == true", // InitConfiguration composed with data from different places, without node specific information
  497. configMaps: []fakeConfigMap{
  498. {
  499. name: kubeadmconstants.KubeadmConfigConfigMap, // ClusterConfiguration from kubeadm-config.
  500. data: map[string]string{
  501. kubeadmconstants.ClusterConfigurationConfigMapKey: string(cfgFiles["ClusterConfiguration_v1beta1"]),
  502. },
  503. },
  504. {
  505. name: kubeadmconstants.KubeProxyConfigMap, // Kube-proxy component config from corresponding ConfigMap.
  506. data: map[string]string{
  507. kubeadmconstants.KubeProxyConfigMapKey: string(cfgFiles["Kube-proxy_componentconfig"]),
  508. },
  509. },
  510. {
  511. name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion), // Kubelet component config from corresponding ConfigMap.
  512. data: map[string]string{
  513. kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
  514. },
  515. },
  516. },
  517. newControlPlane: true,
  518. },
  519. {
  520. name: "valid v1beta2 - new control plane == false", // InitConfiguration composed with data from different places, with also node specific information from ClusterStatus and node
  521. configMaps: []fakeConfigMap{
  522. {
  523. name: kubeadmconstants.KubeadmConfigConfigMap, // ClusterConfiguration from kubeadm-config.
  524. data: map[string]string{
  525. kubeadmconstants.ClusterConfigurationConfigMapKey: string(cfgFiles["ClusterConfiguration_v1beta2"]),
  526. kubeadmconstants.ClusterStatusConfigMapKey: string(cfgFiles["ClusterStatus_v1beta2"]),
  527. },
  528. },
  529. {
  530. name: kubeadmconstants.KubeProxyConfigMap, // Kube-proxy component config from corresponding ConfigMap.
  531. data: map[string]string{
  532. kubeadmconstants.KubeProxyConfigMapKey: string(cfgFiles["Kube-proxy_componentconfig"]),
  533. },
  534. },
  535. {
  536. name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion), // Kubelet component config from corresponding ConfigMap.
  537. data: map[string]string{
  538. kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
  539. },
  540. },
  541. },
  542. fileContents: kubeletConfFiles["configWithEmbeddedCert"],
  543. node: &v1.Node{
  544. ObjectMeta: metav1.ObjectMeta{
  545. Name: nodeName,
  546. Annotations: map[string]string{
  547. kubeadmconstants.AnnotationKubeadmCRISocket: "myCRIsocket",
  548. },
  549. },
  550. Spec: v1.NodeSpec{
  551. Taints: []v1.Taint{kubeadmconstants.ControlPlaneTaint},
  552. },
  553. },
  554. },
  555. {
  556. name: "valid v1beta2 - new control plane == true", // InitConfiguration composed with data from different places, without node specific information
  557. configMaps: []fakeConfigMap{
  558. {
  559. name: kubeadmconstants.KubeadmConfigConfigMap, // ClusterConfiguration from kubeadm-config.
  560. data: map[string]string{
  561. kubeadmconstants.ClusterConfigurationConfigMapKey: string(cfgFiles["ClusterConfiguration_v1beta2"]),
  562. },
  563. },
  564. {
  565. name: kubeadmconstants.KubeProxyConfigMap, // Kube-proxy component config from corresponding ConfigMap.
  566. data: map[string]string{
  567. kubeadmconstants.KubeProxyConfigMapKey: string(cfgFiles["Kube-proxy_componentconfig"]),
  568. },
  569. },
  570. {
  571. name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion), // Kubelet component config from corresponding ConfigMap.
  572. data: map[string]string{
  573. kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
  574. },
  575. },
  576. },
  577. newControlPlane: true,
  578. },
  579. }
  580. for _, rt := range tests {
  581. t.Run(rt.name, func(t *testing.T) {
  582. cfgPath := filepath.Join(tmpdir, kubeadmconstants.KubeletKubeConfigFileName)
  583. if len(rt.fileContents) > 0 {
  584. err := ioutil.WriteFile(cfgPath, rt.fileContents, 0644)
  585. if err != nil {
  586. t.Errorf("Couldn't create file")
  587. return
  588. }
  589. }
  590. client := clientsetfake.NewSimpleClientset()
  591. if rt.node != nil {
  592. _, err := client.CoreV1().Nodes().Create(context.TODO(), rt.node, metav1.CreateOptions{})
  593. if err != nil {
  594. t.Errorf("couldn't create Node")
  595. return
  596. }
  597. }
  598. for _, c := range rt.configMaps {
  599. err := c.create(client)
  600. if err != nil {
  601. t.Errorf("couldn't create ConfigMap %s", c.name)
  602. return
  603. }
  604. }
  605. cfg, err := getInitConfigurationFromCluster(tmpdir, client, rt.newControlPlane)
  606. if rt.expectedError != (err != nil) {
  607. t.Errorf("unexpected return err from getInitConfigurationFromCluster: %v", err)
  608. return
  609. }
  610. if rt.expectedError {
  611. return
  612. }
  613. // Test expected values in InitConfiguration
  614. if cfg == nil {
  615. t.Errorf("unexpected nil return value")
  616. }
  617. if cfg.ClusterConfiguration.KubernetesVersion != k8sVersionString {
  618. t.Errorf("invalid ClusterConfiguration.KubernetesVersion")
  619. }
  620. if !rt.newControlPlane && (cfg.LocalAPIEndpoint.AdvertiseAddress != "1.2.3.4" || cfg.LocalAPIEndpoint.BindPort != 1234) {
  621. t.Errorf("invalid cfg.LocalAPIEndpoint")
  622. }
  623. if _, ok := cfg.ComponentConfigs[componentconfigs.KubeletGroup]; !ok {
  624. t.Errorf("no cfg.ComponentConfigs[%q]", componentconfigs.KubeletGroup)
  625. }
  626. if _, ok := cfg.ComponentConfigs[componentconfigs.KubeProxyGroup]; !ok {
  627. t.Errorf("no cfg.ComponentConfigs[%q]", componentconfigs.KubeProxyGroup)
  628. }
  629. })
  630. }
  631. }
  632. func TestGetGetClusterStatus(t *testing.T) {
  633. var tests = []struct {
  634. name string
  635. configMaps []fakeConfigMap
  636. expectedEndpoints int
  637. expectedError bool
  638. }{
  639. {
  640. name: "invalid missing config map",
  641. expectedEndpoints: 0,
  642. },
  643. {
  644. name: "valid v1beta1",
  645. configMaps: []fakeConfigMap{
  646. {
  647. name: kubeadmconstants.KubeadmConfigConfigMap,
  648. data: map[string]string{
  649. kubeadmconstants.ClusterStatusConfigMapKey: string(cfgFiles["ClusterStatus_v1beta1"]),
  650. },
  651. },
  652. },
  653. expectedEndpoints: 1,
  654. },
  655. {
  656. name: "valid v1beta2",
  657. configMaps: []fakeConfigMap{
  658. {
  659. name: kubeadmconstants.KubeadmConfigConfigMap,
  660. data: map[string]string{
  661. kubeadmconstants.ClusterStatusConfigMapKey: string(cfgFiles["ClusterStatus_v1beta2"]),
  662. },
  663. },
  664. },
  665. expectedEndpoints: 1,
  666. },
  667. {
  668. name: "invalid missing ClusterStatusConfigMapKey in the config map",
  669. configMaps: []fakeConfigMap{
  670. {
  671. name: kubeadmconstants.KubeadmConfigConfigMap,
  672. data: map[string]string{},
  673. },
  674. },
  675. expectedError: true,
  676. },
  677. {
  678. name: "invalid wrong value in the config map",
  679. configMaps: []fakeConfigMap{
  680. {
  681. name: kubeadmconstants.KubeadmConfigConfigMap,
  682. data: map[string]string{
  683. kubeadmconstants.ClusterStatusConfigMapKey: "not a kubeadm type",
  684. },
  685. },
  686. },
  687. expectedError: true,
  688. },
  689. }
  690. for _, rt := range tests {
  691. t.Run(rt.name, func(t *testing.T) {
  692. client := clientsetfake.NewSimpleClientset()
  693. for _, c := range rt.configMaps {
  694. err := c.create(client)
  695. if err != nil {
  696. t.Errorf("couldn't create ConfigMap %s", c.name)
  697. return
  698. }
  699. }
  700. clusterStatus, err := GetClusterStatus(client)
  701. if rt.expectedError != (err != nil) {
  702. t.Errorf("unexpected return err from GetClusterStatus: %v", err)
  703. return
  704. }
  705. if rt.expectedError {
  706. return
  707. }
  708. // Test expected values in clusterStatus
  709. if len(clusterStatus.APIEndpoints) != rt.expectedEndpoints {
  710. t.Errorf("unexpected ClusterStatus return value")
  711. }
  712. })
  713. }
  714. }
  715. type fakeConfigMap struct {
  716. name string
  717. data map[string]string
  718. }
  719. func (c *fakeConfigMap) create(client clientset.Interface) error {
  720. return apiclient.CreateOrUpdateConfigMap(client, &v1.ConfigMap{
  721. ObjectMeta: metav1.ObjectMeta{
  722. Name: c.name,
  723. Namespace: metav1.NamespaceSystem,
  724. },
  725. Data: c.data,
  726. })
  727. }