config_test.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950
  1. /*
  2. Copyright 2014 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. "fmt"
  16. "io/ioutil"
  17. "os"
  18. "path"
  19. "reflect"
  20. "strings"
  21. "testing"
  22. apiequality "k8s.io/apimachinery/pkg/api/equality"
  23. "k8s.io/apimachinery/pkg/util/diff"
  24. "k8s.io/cli-runtime/pkg/genericclioptions"
  25. "k8s.io/client-go/tools/clientcmd"
  26. clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
  27. cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
  28. )
  29. func newRedFederalCowHammerConfig() clientcmdapi.Config {
  30. return clientcmdapi.Config{
  31. AuthInfos: map[string]*clientcmdapi.AuthInfo{
  32. "red-user": {Token: "red-token"}},
  33. Clusters: map[string]*clientcmdapi.Cluster{
  34. "cow-cluster": {Server: "http://cow.org:8080"}},
  35. Contexts: map[string]*clientcmdapi.Context{
  36. "federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster"}},
  37. CurrentContext: "federal-context",
  38. }
  39. }
  40. func Example_view() {
  41. expectedConfig := newRedFederalCowHammerConfig()
  42. test := configCommandTest{
  43. args: []string{"view"},
  44. startingConfig: newRedFederalCowHammerConfig(),
  45. expectedConfig: expectedConfig,
  46. }
  47. output := test.run(nil)
  48. fmt.Printf("%v", output)
  49. // Output:
  50. // apiVersion: v1
  51. // clusters:
  52. // - cluster:
  53. // server: http://cow.org:8080
  54. // name: cow-cluster
  55. // contexts:
  56. // - context:
  57. // cluster: cow-cluster
  58. // user: red-user
  59. // name: federal-context
  60. // current-context: federal-context
  61. // kind: Config
  62. // preferences: {}
  63. // users:
  64. // - name: red-user
  65. // user:
  66. // token: red-token
  67. }
  68. func TestCurrentContext(t *testing.T) {
  69. startingConfig := newRedFederalCowHammerConfig()
  70. test := configCommandTest{
  71. args: []string{"current-context"},
  72. startingConfig: startingConfig,
  73. expectedConfig: startingConfig,
  74. expectedOutputs: []string{startingConfig.CurrentContext},
  75. }
  76. test.run(t)
  77. }
  78. func TestSetCurrentContext(t *testing.T) {
  79. expectedConfig := newRedFederalCowHammerConfig()
  80. startingConfig := newRedFederalCowHammerConfig()
  81. newContextName := "the-new-context"
  82. startingConfig.Contexts[newContextName] = clientcmdapi.NewContext()
  83. expectedConfig.Contexts[newContextName] = clientcmdapi.NewContext()
  84. expectedConfig.CurrentContext = newContextName
  85. test := configCommandTest{
  86. args: []string{"use-context", "the-new-context"},
  87. startingConfig: startingConfig,
  88. expectedConfig: expectedConfig,
  89. }
  90. test.run(t)
  91. }
  92. func TestSetNonExistentContext(t *testing.T) {
  93. expectedConfig := newRedFederalCowHammerConfig()
  94. test := configCommandTest{
  95. args: []string{"use-context", "non-existent-config"},
  96. startingConfig: expectedConfig,
  97. expectedConfig: expectedConfig,
  98. }
  99. func() {
  100. defer func() {
  101. // Restore cmdutil behavior.
  102. cmdutil.DefaultBehaviorOnFatal()
  103. }()
  104. // Check exit code.
  105. cmdutil.BehaviorOnFatal(func(e string, code int) {
  106. if code != 1 {
  107. t.Errorf("The exit code is %d, expected 1", code)
  108. }
  109. expectedOutputs := []string{`no context exists with the name: "non-existent-config"`}
  110. test.checkOutput(e, expectedOutputs, t)
  111. })
  112. test.run(t)
  113. }()
  114. }
  115. func TestSetIntoExistingStruct(t *testing.T) {
  116. expectedConfig := newRedFederalCowHammerConfig()
  117. expectedConfig.AuthInfos["red-user"].Password = "new-path-value"
  118. test := configCommandTest{
  119. args: []string{"set", "users.red-user.password", "new-path-value"},
  120. startingConfig: newRedFederalCowHammerConfig(),
  121. expectedConfig: expectedConfig,
  122. }
  123. test.run(t)
  124. }
  125. func TestSetWithPathPrefixIntoExistingStruct(t *testing.T) {
  126. expectedConfig := newRedFederalCowHammerConfig()
  127. expectedConfig.Clusters["cow-cluster"].Server = "http://cow.org:8080/foo/baz"
  128. test := configCommandTest{
  129. args: []string{"set", "clusters.cow-cluster.server", "http://cow.org:8080/foo/baz"},
  130. startingConfig: newRedFederalCowHammerConfig(),
  131. expectedConfig: expectedConfig,
  132. }
  133. test.run(t)
  134. dc := clientcmd.NewDefaultClientConfig(expectedConfig, &clientcmd.ConfigOverrides{})
  135. dcc, err := dc.ClientConfig()
  136. if err != nil {
  137. t.Fatalf("unexpected error: %v", err)
  138. }
  139. expectedHost := "http://cow.org:8080/foo/baz"
  140. if expectedHost != dcc.Host {
  141. t.Fatalf("expected client.Config.Host = %q instead of %q", expectedHost, dcc.Host)
  142. }
  143. }
  144. func TestUnsetStruct(t *testing.T) {
  145. expectedConfig := newRedFederalCowHammerConfig()
  146. delete(expectedConfig.AuthInfos, "red-user")
  147. test := configCommandTest{
  148. args: []string{"unset", "users.red-user"},
  149. startingConfig: newRedFederalCowHammerConfig(),
  150. expectedConfig: expectedConfig,
  151. }
  152. test.run(t)
  153. }
  154. func TestUnsetField(t *testing.T) {
  155. expectedConfig := newRedFederalCowHammerConfig()
  156. expectedConfig.AuthInfos["red-user"] = clientcmdapi.NewAuthInfo()
  157. test := configCommandTest{
  158. args: []string{"unset", "users.red-user.token"},
  159. startingConfig: newRedFederalCowHammerConfig(),
  160. expectedConfig: expectedConfig,
  161. }
  162. test.run(t)
  163. }
  164. func TestSetIntoNewStruct(t *testing.T) {
  165. expectedConfig := newRedFederalCowHammerConfig()
  166. cluster := clientcmdapi.NewCluster()
  167. cluster.Server = "new-server-value"
  168. expectedConfig.Clusters["big-cluster"] = cluster
  169. test := configCommandTest{
  170. args: []string{"set", "clusters.big-cluster.server", "new-server-value"},
  171. startingConfig: newRedFederalCowHammerConfig(),
  172. expectedConfig: expectedConfig,
  173. }
  174. test.run(t)
  175. }
  176. func TestSetBoolean(t *testing.T) {
  177. expectedConfig := newRedFederalCowHammerConfig()
  178. cluster := clientcmdapi.NewCluster()
  179. cluster.InsecureSkipTLSVerify = true
  180. expectedConfig.Clusters["big-cluster"] = cluster
  181. test := configCommandTest{
  182. args: []string{"set", "clusters.big-cluster.insecure-skip-tls-verify", "true"},
  183. startingConfig: newRedFederalCowHammerConfig(),
  184. expectedConfig: expectedConfig,
  185. }
  186. test.run(t)
  187. }
  188. func TestSetIntoNewConfig(t *testing.T) {
  189. expectedConfig := *clientcmdapi.NewConfig()
  190. context := clientcmdapi.NewContext()
  191. context.AuthInfo = "fake-user"
  192. expectedConfig.Contexts["new-context"] = context
  193. test := configCommandTest{
  194. args: []string{"set", "contexts.new-context.user", "fake-user"},
  195. startingConfig: *clientcmdapi.NewConfig(),
  196. expectedConfig: expectedConfig,
  197. }
  198. test.run(t)
  199. }
  200. func TestNewEmptyAuth(t *testing.T) {
  201. expectedConfig := *clientcmdapi.NewConfig()
  202. expectedConfig.AuthInfos["the-user-name"] = clientcmdapi.NewAuthInfo()
  203. test := configCommandTest{
  204. args: []string{"set-credentials", "the-user-name"},
  205. startingConfig: *clientcmdapi.NewConfig(),
  206. expectedConfig: expectedConfig,
  207. }
  208. test.run(t)
  209. }
  210. func TestAdditionalAuth(t *testing.T) {
  211. expectedConfig := newRedFederalCowHammerConfig()
  212. authInfo := clientcmdapi.NewAuthInfo()
  213. authInfo.Token = "token"
  214. expectedConfig.AuthInfos["another-user"] = authInfo
  215. test := configCommandTest{
  216. args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagBearerToken + "=token"},
  217. startingConfig: newRedFederalCowHammerConfig(),
  218. expectedConfig: expectedConfig,
  219. }
  220. test.run(t)
  221. }
  222. func TestEmbedClientCert(t *testing.T) {
  223. fakeCertFile, _ := ioutil.TempFile("", "")
  224. defer os.Remove(fakeCertFile.Name())
  225. fakeData := []byte("fake-data")
  226. ioutil.WriteFile(fakeCertFile.Name(), fakeData, 0600)
  227. expectedConfig := newRedFederalCowHammerConfig()
  228. authInfo := clientcmdapi.NewAuthInfo()
  229. authInfo.ClientCertificateData = fakeData
  230. expectedConfig.AuthInfos["another-user"] = authInfo
  231. test := configCommandTest{
  232. args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=" + fakeCertFile.Name(), "--" + clientcmd.FlagEmbedCerts + "=true"},
  233. startingConfig: newRedFederalCowHammerConfig(),
  234. expectedConfig: expectedConfig,
  235. }
  236. test.run(t)
  237. }
  238. func TestEmbedClientKey(t *testing.T) {
  239. fakeKeyFile, _ := ioutil.TempFile("", "")
  240. defer os.Remove(fakeKeyFile.Name())
  241. fakeData := []byte("fake-data")
  242. ioutil.WriteFile(fakeKeyFile.Name(), fakeData, 0600)
  243. expectedConfig := newRedFederalCowHammerConfig()
  244. authInfo := clientcmdapi.NewAuthInfo()
  245. authInfo.ClientKeyData = fakeData
  246. expectedConfig.AuthInfos["another-user"] = authInfo
  247. test := configCommandTest{
  248. args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagKeyFile + "=" + fakeKeyFile.Name(), "--" + clientcmd.FlagEmbedCerts + "=true"},
  249. startingConfig: newRedFederalCowHammerConfig(),
  250. expectedConfig: expectedConfig,
  251. }
  252. test.run(t)
  253. }
  254. func TestEmbedNoKeyOrCertDisallowed(t *testing.T) {
  255. expectedConfig := newRedFederalCowHammerConfig()
  256. test := configCommandTest{
  257. args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagEmbedCerts + "=true"},
  258. startingConfig: newRedFederalCowHammerConfig(),
  259. expectedConfig: expectedConfig,
  260. }
  261. func() {
  262. defer func() {
  263. // Restore cmdutil behavior.
  264. cmdutil.DefaultBehaviorOnFatal()
  265. }()
  266. // Check exit code.
  267. cmdutil.BehaviorOnFatal(func(e string, code int) {
  268. if code != 1 {
  269. t.Errorf("The exit code is %d, expected 1", code)
  270. }
  271. expectedOutputs := []string{"--client-certificate", "--client-key", "embed"}
  272. test.checkOutput(e, expectedOutputs, t)
  273. })
  274. test.run(t)
  275. }()
  276. }
  277. func TestEmptyTokenAndCertAllowed(t *testing.T) {
  278. fakeCertFile, _ := ioutil.TempFile("", "cert-file")
  279. defer os.Remove(fakeCertFile.Name())
  280. expectedConfig := newRedFederalCowHammerConfig()
  281. authInfo := clientcmdapi.NewAuthInfo()
  282. authInfo.ClientCertificate = path.Base(fakeCertFile.Name())
  283. expectedConfig.AuthInfos["another-user"] = authInfo
  284. test := configCommandTest{
  285. args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=" + fakeCertFile.Name(), "--" + clientcmd.FlagBearerToken + "="},
  286. startingConfig: newRedFederalCowHammerConfig(),
  287. expectedConfig: expectedConfig,
  288. }
  289. test.run(t)
  290. }
  291. func TestTokenAndCertAllowed(t *testing.T) {
  292. expectedConfig := newRedFederalCowHammerConfig()
  293. authInfo := clientcmdapi.NewAuthInfo()
  294. authInfo.Token = "token"
  295. authInfo.ClientCertificate = "/cert-file"
  296. expectedConfig.AuthInfos["another-user"] = authInfo
  297. test := configCommandTest{
  298. args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=/cert-file", "--" + clientcmd.FlagBearerToken + "=token"},
  299. startingConfig: newRedFederalCowHammerConfig(),
  300. expectedConfig: expectedConfig,
  301. }
  302. test.run(t)
  303. }
  304. func TestTokenAndBasicDisallowed(t *testing.T) {
  305. expectedConfig := newRedFederalCowHammerConfig()
  306. test := configCommandTest{
  307. args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagUsername + "=myuser", "--" + clientcmd.FlagBearerToken + "=token"},
  308. startingConfig: newRedFederalCowHammerConfig(),
  309. expectedConfig: expectedConfig,
  310. }
  311. func() {
  312. defer func() {
  313. // Restore cmdutil behavior.
  314. cmdutil.DefaultBehaviorOnFatal()
  315. }()
  316. // Check exit code.
  317. cmdutil.BehaviorOnFatal(func(e string, code int) {
  318. if code != 1 {
  319. t.Errorf("The exit code is %d, expected 1", code)
  320. }
  321. expectedOutputs := []string{"--token", "--username"}
  322. test.checkOutput(e, expectedOutputs, t)
  323. })
  324. test.run(t)
  325. }()
  326. }
  327. func TestBasicClearsToken(t *testing.T) {
  328. authInfoWithToken := clientcmdapi.NewAuthInfo()
  329. authInfoWithToken.Token = "token"
  330. authInfoWithBasic := clientcmdapi.NewAuthInfo()
  331. authInfoWithBasic.Username = "myuser"
  332. authInfoWithBasic.Password = "mypass"
  333. startingConfig := newRedFederalCowHammerConfig()
  334. startingConfig.AuthInfos["another-user"] = authInfoWithToken
  335. expectedConfig := newRedFederalCowHammerConfig()
  336. expectedConfig.AuthInfos["another-user"] = authInfoWithBasic
  337. test := configCommandTest{
  338. args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagUsername + "=myuser", "--" + clientcmd.FlagPassword + "=mypass"},
  339. startingConfig: startingConfig,
  340. expectedConfig: expectedConfig,
  341. }
  342. test.run(t)
  343. }
  344. func TestTokenClearsBasic(t *testing.T) {
  345. authInfoWithBasic := clientcmdapi.NewAuthInfo()
  346. authInfoWithBasic.Username = "myuser"
  347. authInfoWithBasic.Password = "mypass"
  348. authInfoWithToken := clientcmdapi.NewAuthInfo()
  349. authInfoWithToken.Token = "token"
  350. startingConfig := newRedFederalCowHammerConfig()
  351. startingConfig.AuthInfos["another-user"] = authInfoWithBasic
  352. expectedConfig := newRedFederalCowHammerConfig()
  353. expectedConfig.AuthInfos["another-user"] = authInfoWithToken
  354. test := configCommandTest{
  355. args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagBearerToken + "=token"},
  356. startingConfig: startingConfig,
  357. expectedConfig: expectedConfig,
  358. }
  359. test.run(t)
  360. }
  361. func TestTokenLeavesCert(t *testing.T) {
  362. authInfoWithCerts := clientcmdapi.NewAuthInfo()
  363. authInfoWithCerts.ClientCertificate = "cert"
  364. authInfoWithCerts.ClientCertificateData = []byte("certdata")
  365. authInfoWithCerts.ClientKey = "key"
  366. authInfoWithCerts.ClientKeyData = []byte("keydata")
  367. authInfoWithTokenAndCerts := clientcmdapi.NewAuthInfo()
  368. authInfoWithTokenAndCerts.Token = "token"
  369. authInfoWithTokenAndCerts.ClientCertificate = "cert"
  370. authInfoWithTokenAndCerts.ClientCertificateData = []byte("certdata")
  371. authInfoWithTokenAndCerts.ClientKey = "key"
  372. authInfoWithTokenAndCerts.ClientKeyData = []byte("keydata")
  373. startingConfig := newRedFederalCowHammerConfig()
  374. startingConfig.AuthInfos["another-user"] = authInfoWithCerts
  375. expectedConfig := newRedFederalCowHammerConfig()
  376. expectedConfig.AuthInfos["another-user"] = authInfoWithTokenAndCerts
  377. test := configCommandTest{
  378. args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagBearerToken + "=token"},
  379. startingConfig: startingConfig,
  380. expectedConfig: expectedConfig,
  381. }
  382. test.run(t)
  383. }
  384. func TestCertLeavesToken(t *testing.T) {
  385. authInfoWithToken := clientcmdapi.NewAuthInfo()
  386. authInfoWithToken.Token = "token"
  387. authInfoWithTokenAndCerts := clientcmdapi.NewAuthInfo()
  388. authInfoWithTokenAndCerts.Token = "token"
  389. authInfoWithTokenAndCerts.ClientCertificate = "/cert"
  390. authInfoWithTokenAndCerts.ClientKey = "/key"
  391. startingConfig := newRedFederalCowHammerConfig()
  392. startingConfig.AuthInfos["another-user"] = authInfoWithToken
  393. expectedConfig := newRedFederalCowHammerConfig()
  394. expectedConfig.AuthInfos["another-user"] = authInfoWithTokenAndCerts
  395. test := configCommandTest{
  396. args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=/cert", "--" + clientcmd.FlagKeyFile + "=/key"},
  397. startingConfig: startingConfig,
  398. expectedConfig: expectedConfig,
  399. }
  400. test.run(t)
  401. }
  402. func TestSetBytesBad(t *testing.T) {
  403. startingConfig := newRedFederalCowHammerConfig()
  404. startingConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
  405. test := configCommandTest{
  406. args: []string{"set", "clusters.another-cluster.certificate-authority-data", "cadata"},
  407. startingConfig: startingConfig,
  408. expectedConfig: startingConfig,
  409. }
  410. func() {
  411. defer func() {
  412. // Restore cmdutil behavior.
  413. cmdutil.DefaultBehaviorOnFatal()
  414. }()
  415. // Check exit code.
  416. cmdutil.BehaviorOnFatal(func(e string, code int) {
  417. if code != 1 {
  418. t.Errorf("The exit code is %d, expected 1", code)
  419. }
  420. })
  421. test.run(t)
  422. }()
  423. }
  424. func TestSetBytes(t *testing.T) {
  425. clusterInfoWithCAData := clientcmdapi.NewCluster()
  426. clusterInfoWithCAData.CertificateAuthorityData = []byte("cadata")
  427. startingConfig := newRedFederalCowHammerConfig()
  428. startingConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
  429. expectedConfig := newRedFederalCowHammerConfig()
  430. expectedConfig.Clusters["another-cluster"] = clusterInfoWithCAData
  431. test := configCommandTest{
  432. args: []string{"set", "clusters.another-cluster.certificate-authority-data", "cadata", "--set-raw-bytes"},
  433. startingConfig: startingConfig,
  434. expectedConfig: expectedConfig,
  435. }
  436. test.run(t)
  437. }
  438. func TestSetBase64Bytes(t *testing.T) {
  439. clusterInfoWithCAData := clientcmdapi.NewCluster()
  440. clusterInfoWithCAData.CertificateAuthorityData = []byte("cadata")
  441. startingConfig := newRedFederalCowHammerConfig()
  442. startingConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
  443. expectedConfig := newRedFederalCowHammerConfig()
  444. expectedConfig.Clusters["another-cluster"] = clusterInfoWithCAData
  445. test := configCommandTest{
  446. args: []string{"set", "clusters.another-cluster.certificate-authority-data", "Y2FkYXRh"},
  447. startingConfig: startingConfig,
  448. expectedConfig: expectedConfig,
  449. }
  450. test.run(t)
  451. }
  452. func TestUnsetBytes(t *testing.T) {
  453. clusterInfoWithCAData := clientcmdapi.NewCluster()
  454. clusterInfoWithCAData.CertificateAuthorityData = []byte("cadata")
  455. startingConfig := newRedFederalCowHammerConfig()
  456. startingConfig.Clusters["another-cluster"] = clusterInfoWithCAData
  457. expectedConfig := newRedFederalCowHammerConfig()
  458. expectedConfig.Clusters["another-cluster"] = clientcmdapi.NewCluster()
  459. test := configCommandTest{
  460. args: []string{"unset", "clusters.another-cluster.certificate-authority-data"},
  461. startingConfig: startingConfig,
  462. expectedConfig: expectedConfig,
  463. }
  464. test.run(t)
  465. }
  466. func TestCAClearsInsecure(t *testing.T) {
  467. fakeCAFile, _ := ioutil.TempFile("", "ca-file")
  468. defer os.Remove(fakeCAFile.Name())
  469. clusterInfoWithInsecure := clientcmdapi.NewCluster()
  470. clusterInfoWithInsecure.InsecureSkipTLSVerify = true
  471. clusterInfoWithCA := clientcmdapi.NewCluster()
  472. clusterInfoWithCA.CertificateAuthority = path.Base(fakeCAFile.Name())
  473. startingConfig := newRedFederalCowHammerConfig()
  474. startingConfig.Clusters["another-cluster"] = clusterInfoWithInsecure
  475. expectedConfig := newRedFederalCowHammerConfig()
  476. expectedConfig.Clusters["another-cluster"] = clusterInfoWithCA
  477. test := configCommandTest{
  478. args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagCAFile + "=" + fakeCAFile.Name()},
  479. startingConfig: startingConfig,
  480. expectedConfig: expectedConfig,
  481. }
  482. test.run(t)
  483. }
  484. func TestCAClearsCAData(t *testing.T) {
  485. clusterInfoWithCAData := clientcmdapi.NewCluster()
  486. clusterInfoWithCAData.CertificateAuthorityData = []byte("cadata")
  487. clusterInfoWithCA := clientcmdapi.NewCluster()
  488. clusterInfoWithCA.CertificateAuthority = "/cafile"
  489. startingConfig := newRedFederalCowHammerConfig()
  490. startingConfig.Clusters["another-cluster"] = clusterInfoWithCAData
  491. expectedConfig := newRedFederalCowHammerConfig()
  492. expectedConfig.Clusters["another-cluster"] = clusterInfoWithCA
  493. test := configCommandTest{
  494. args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagCAFile + "=/cafile", "--" + clientcmd.FlagInsecure + "=false"},
  495. startingConfig: startingConfig,
  496. expectedConfig: expectedConfig,
  497. }
  498. test.run(t)
  499. }
  500. func TestInsecureClearsCA(t *testing.T) {
  501. clusterInfoWithInsecure := clientcmdapi.NewCluster()
  502. clusterInfoWithInsecure.InsecureSkipTLSVerify = true
  503. clusterInfoWithCA := clientcmdapi.NewCluster()
  504. clusterInfoWithCA.CertificateAuthority = "cafile"
  505. clusterInfoWithCA.CertificateAuthorityData = []byte("cadata")
  506. startingConfig := newRedFederalCowHammerConfig()
  507. startingConfig.Clusters["another-cluster"] = clusterInfoWithCA
  508. expectedConfig := newRedFederalCowHammerConfig()
  509. expectedConfig.Clusters["another-cluster"] = clusterInfoWithInsecure
  510. test := configCommandTest{
  511. args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagInsecure + "=true"},
  512. startingConfig: startingConfig,
  513. expectedConfig: expectedConfig,
  514. }
  515. test.run(t)
  516. }
  517. func TestCADataClearsCA(t *testing.T) {
  518. fakeCAFile, _ := ioutil.TempFile("", "")
  519. defer os.Remove(fakeCAFile.Name())
  520. fakeData := []byte("cadata")
  521. ioutil.WriteFile(fakeCAFile.Name(), fakeData, 0600)
  522. clusterInfoWithCAData := clientcmdapi.NewCluster()
  523. clusterInfoWithCAData.CertificateAuthorityData = fakeData
  524. clusterInfoWithCA := clientcmdapi.NewCluster()
  525. clusterInfoWithCA.CertificateAuthority = "cafile"
  526. startingConfig := newRedFederalCowHammerConfig()
  527. startingConfig.Clusters["another-cluster"] = clusterInfoWithCA
  528. expectedConfig := newRedFederalCowHammerConfig()
  529. expectedConfig.Clusters["another-cluster"] = clusterInfoWithCAData
  530. test := configCommandTest{
  531. args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagCAFile + "=" + fakeCAFile.Name(), "--" + clientcmd.FlagEmbedCerts + "=true"},
  532. startingConfig: startingConfig,
  533. expectedConfig: expectedConfig,
  534. }
  535. test.run(t)
  536. }
  537. func TestEmbedNoCADisallowed(t *testing.T) {
  538. expectedConfig := newRedFederalCowHammerConfig()
  539. test := configCommandTest{
  540. args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagEmbedCerts + "=true"},
  541. startingConfig: newRedFederalCowHammerConfig(),
  542. expectedConfig: expectedConfig,
  543. }
  544. func() {
  545. defer func() {
  546. // Restore cmdutil behavior.
  547. cmdutil.DefaultBehaviorOnFatal()
  548. }()
  549. // Check exit code.
  550. cmdutil.BehaviorOnFatal(func(e string, code int) {
  551. if code != 1 {
  552. t.Errorf("The exit code is %d, expected 1", code)
  553. }
  554. expectedOutputs := []string{"--certificate-authority", "embed"}
  555. test.checkOutput(e, expectedOutputs, t)
  556. })
  557. test.run(t)
  558. }()
  559. }
  560. func TestCAAndInsecureDisallowed(t *testing.T) {
  561. test := configCommandTest{
  562. args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagCAFile + "=cafile", "--" + clientcmd.FlagInsecure + "=true"},
  563. startingConfig: newRedFederalCowHammerConfig(),
  564. expectedConfig: newRedFederalCowHammerConfig(),
  565. }
  566. func() {
  567. defer func() {
  568. // Restore cmdutil behavior.
  569. cmdutil.DefaultBehaviorOnFatal()
  570. }()
  571. // Check exit code.
  572. cmdutil.BehaviorOnFatal(func(e string, code int) {
  573. if code != 1 {
  574. t.Errorf("The exit code is %d, expected 1", code)
  575. }
  576. expectedOutputs := []string{"certificate", "insecure"}
  577. test.checkOutput(e, expectedOutputs, t)
  578. })
  579. test.run(t)
  580. }()
  581. }
  582. func TestMergeExistingAuth(t *testing.T) {
  583. expectedConfig := newRedFederalCowHammerConfig()
  584. authInfo := expectedConfig.AuthInfos["red-user"]
  585. authInfo.ClientKey = "/key"
  586. expectedConfig.AuthInfos["red-user"] = authInfo
  587. test := configCommandTest{
  588. args: []string{"set-credentials", "red-user", "--" + clientcmd.FlagKeyFile + "=/key"},
  589. startingConfig: newRedFederalCowHammerConfig(),
  590. expectedConfig: expectedConfig,
  591. }
  592. test.run(t)
  593. }
  594. func TestNewEmptyCluster(t *testing.T) {
  595. expectedConfig := *clientcmdapi.NewConfig()
  596. expectedConfig.Clusters["new-cluster"] = clientcmdapi.NewCluster()
  597. test := configCommandTest{
  598. args: []string{"set-cluster", "new-cluster"},
  599. startingConfig: *clientcmdapi.NewConfig(),
  600. expectedConfig: expectedConfig,
  601. }
  602. test.run(t)
  603. }
  604. func TestAdditionalCluster(t *testing.T) {
  605. expectedConfig := newRedFederalCowHammerConfig()
  606. cluster := clientcmdapi.NewCluster()
  607. cluster.CertificateAuthority = "/ca-location"
  608. cluster.InsecureSkipTLSVerify = false
  609. cluster.Server = "serverlocation"
  610. expectedConfig.Clusters["different-cluster"] = cluster
  611. test := configCommandTest{
  612. args: []string{"set-cluster", "different-cluster", "--" + clientcmd.FlagAPIServer + "=serverlocation", "--" + clientcmd.FlagInsecure + "=false", "--" + clientcmd.FlagCAFile + "=/ca-location"},
  613. startingConfig: newRedFederalCowHammerConfig(),
  614. expectedConfig: expectedConfig,
  615. }
  616. test.run(t)
  617. }
  618. func TestOverwriteExistingCluster(t *testing.T) {
  619. expectedConfig := newRedFederalCowHammerConfig()
  620. cluster := clientcmdapi.NewCluster()
  621. cluster.Server = "serverlocation"
  622. expectedConfig.Clusters["cow-cluster"] = cluster
  623. test := configCommandTest{
  624. args: []string{"set-cluster", "cow-cluster", "--" + clientcmd.FlagAPIServer + "=serverlocation"},
  625. startingConfig: newRedFederalCowHammerConfig(),
  626. expectedConfig: expectedConfig,
  627. }
  628. test.run(t)
  629. }
  630. func TestNewEmptyContext(t *testing.T) {
  631. expectedConfig := *clientcmdapi.NewConfig()
  632. expectedConfig.Contexts["new-context"] = clientcmdapi.NewContext()
  633. test := configCommandTest{
  634. args: []string{"set-context", "new-context"},
  635. startingConfig: *clientcmdapi.NewConfig(),
  636. expectedConfig: expectedConfig,
  637. }
  638. test.run(t)
  639. }
  640. func TestAdditionalContext(t *testing.T) {
  641. expectedConfig := newRedFederalCowHammerConfig()
  642. context := clientcmdapi.NewContext()
  643. context.Cluster = "some-cluster"
  644. context.AuthInfo = "some-user"
  645. context.Namespace = "different-namespace"
  646. expectedConfig.Contexts["different-context"] = context
  647. test := configCommandTest{
  648. args: []string{"set-context", "different-context", "--" + clientcmd.FlagClusterName + "=some-cluster", "--" + clientcmd.FlagAuthInfoName + "=some-user", "--" + clientcmd.FlagNamespace + "=different-namespace"},
  649. startingConfig: newRedFederalCowHammerConfig(),
  650. expectedConfig: expectedConfig,
  651. }
  652. test.run(t)
  653. }
  654. func TestMergeExistingContext(t *testing.T) {
  655. expectedConfig := newRedFederalCowHammerConfig()
  656. context := expectedConfig.Contexts["federal-context"]
  657. context.Namespace = "hammer"
  658. expectedConfig.Contexts["federal-context"] = context
  659. test := configCommandTest{
  660. args: []string{"set-context", "federal-context", "--" + clientcmd.FlagNamespace + "=hammer"},
  661. startingConfig: newRedFederalCowHammerConfig(),
  662. expectedConfig: expectedConfig,
  663. }
  664. test.run(t)
  665. }
  666. func TestToBool(t *testing.T) {
  667. type test struct {
  668. in string
  669. out bool
  670. err string
  671. }
  672. tests := []test{
  673. {"", false, ""},
  674. {"true", true, ""},
  675. {"on", false, `strconv.ParseBool: parsing "on": invalid syntax`},
  676. }
  677. for _, curr := range tests {
  678. b, err := toBool(curr.in)
  679. if (len(curr.err) != 0) && err == nil {
  680. t.Errorf("Expected error: %v, but got nil", curr.err)
  681. }
  682. if (len(curr.err) == 0) && err != nil {
  683. t.Errorf("Unexpected error: %v", err)
  684. }
  685. if (err != nil) && (err.Error() != curr.err) {
  686. t.Errorf("Expected %v, got %v", curr.err, err)
  687. }
  688. if b != curr.out {
  689. t.Errorf("Expected %v, got %v", curr.out, b)
  690. }
  691. }
  692. }
  693. func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *testing.T) (string, clientcmdapi.Config) {
  694. fakeKubeFile, _ := ioutil.TempFile("", "")
  695. defer os.Remove(fakeKubeFile.Name())
  696. err := clientcmd.WriteToFile(startingConfig, fakeKubeFile.Name())
  697. if err != nil {
  698. t.Fatalf("unexpected error: %v", err)
  699. }
  700. argsToUse := make([]string, 0, 2+len(args))
  701. argsToUse = append(argsToUse, "--kubeconfig="+fakeKubeFile.Name())
  702. argsToUse = append(argsToUse, args...)
  703. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  704. cmd := NewCmdConfig(cmdutil.NewFactory(genericclioptions.NewTestConfigFlags()), clientcmd.NewDefaultPathOptions(), streams)
  705. // "context" is a global flag, inherited from base kubectl command in the real world
  706. cmd.PersistentFlags().String("context", "", "The name of the kubeconfig context to use")
  707. cmd.SetArgs(argsToUse)
  708. cmd.Execute()
  709. config := clientcmd.GetConfigFromFileOrDie(fakeKubeFile.Name())
  710. return buf.String(), *config
  711. }
  712. type configCommandTest struct {
  713. args []string
  714. startingConfig clientcmdapi.Config
  715. expectedConfig clientcmdapi.Config
  716. expectedOutputs []string
  717. }
  718. func (test configCommandTest) checkOutput(out string, expectedOutputs []string, t *testing.T) {
  719. for _, expectedOutput := range expectedOutputs {
  720. if !strings.Contains(out, expectedOutput) {
  721. t.Errorf("expected '%s' in output, got '%s'", expectedOutput, out)
  722. }
  723. }
  724. }
  725. func (test configCommandTest) run(t *testing.T) string {
  726. out, actualConfig := testConfigCommand(test.args, test.startingConfig, t)
  727. testSetNilMapsToEmpties(reflect.ValueOf(&test.expectedConfig))
  728. testSetNilMapsToEmpties(reflect.ValueOf(&actualConfig))
  729. testClearLocationOfOrigin(&actualConfig)
  730. if !apiequality.Semantic.DeepEqual(test.expectedConfig, actualConfig) {
  731. t.Errorf("diff: %v", diff.ObjectDiff(test.expectedConfig, actualConfig))
  732. t.Errorf("expected: %#v\n actual: %#v", test.expectedConfig, actualConfig)
  733. }
  734. test.checkOutput(out, test.expectedOutputs, t)
  735. return out
  736. }
  737. func testClearLocationOfOrigin(config *clientcmdapi.Config) {
  738. for key, obj := range config.AuthInfos {
  739. obj.LocationOfOrigin = ""
  740. config.AuthInfos[key] = obj
  741. }
  742. for key, obj := range config.Clusters {
  743. obj.LocationOfOrigin = ""
  744. config.Clusters[key] = obj
  745. }
  746. for key, obj := range config.Contexts {
  747. obj.LocationOfOrigin = ""
  748. config.Contexts[key] = obj
  749. }
  750. }
  751. func testSetNilMapsToEmpties(curr reflect.Value) {
  752. actualCurrValue := curr
  753. if curr.Kind() == reflect.Ptr {
  754. actualCurrValue = curr.Elem()
  755. }
  756. switch actualCurrValue.Kind() {
  757. case reflect.Map:
  758. for _, mapKey := range actualCurrValue.MapKeys() {
  759. currMapValue := actualCurrValue.MapIndex(mapKey)
  760. testSetNilMapsToEmpties(currMapValue)
  761. }
  762. case reflect.Struct:
  763. for fieldIndex := 0; fieldIndex < actualCurrValue.NumField(); fieldIndex++ {
  764. currFieldValue := actualCurrValue.Field(fieldIndex)
  765. if currFieldValue.Kind() == reflect.Map && currFieldValue.IsNil() {
  766. newValue := reflect.MakeMap(currFieldValue.Type())
  767. currFieldValue.Set(newValue)
  768. } else {
  769. testSetNilMapsToEmpties(currFieldValue.Addr())
  770. }
  771. }
  772. }
  773. }