create_clusterrole_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  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 create
  14. import (
  15. "testing"
  16. rbac "k8s.io/api/rbac/v1"
  17. "k8s.io/apimachinery/pkg/api/equality"
  18. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  19. "k8s.io/apimachinery/pkg/runtime"
  20. "k8s.io/cli-runtime/pkg/genericclioptions"
  21. "k8s.io/client-go/rest/fake"
  22. cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
  23. "k8s.io/kubernetes/pkg/kubectl/scheme"
  24. )
  25. func TestCreateClusterRole(t *testing.T) {
  26. clusterRoleName := "my-cluster-role"
  27. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  28. defer tf.Cleanup()
  29. tf.Client = &fake.RESTClient{}
  30. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  31. tests := map[string]struct {
  32. verbs string
  33. resources string
  34. nonResourceURL string
  35. resourceNames string
  36. aggregationRule string
  37. expectedClusterRole *rbac.ClusterRole
  38. }{
  39. "test-duplicate-resources": {
  40. verbs: "get,watch,list",
  41. resources: "pods,pods",
  42. expectedClusterRole: &rbac.ClusterRole{
  43. TypeMeta: metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
  44. ObjectMeta: metav1.ObjectMeta{
  45. Name: clusterRoleName,
  46. },
  47. Rules: []rbac.PolicyRule{
  48. {
  49. Verbs: []string{"get", "watch", "list"},
  50. Resources: []string{"pods"},
  51. APIGroups: []string{""},
  52. ResourceNames: []string{},
  53. },
  54. },
  55. },
  56. },
  57. "test-valid-case-with-multiple-apigroups": {
  58. verbs: "get,watch,list",
  59. resources: "pods,deployments.extensions",
  60. expectedClusterRole: &rbac.ClusterRole{
  61. TypeMeta: metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
  62. ObjectMeta: metav1.ObjectMeta{
  63. Name: clusterRoleName,
  64. },
  65. Rules: []rbac.PolicyRule{
  66. {
  67. Verbs: []string{"get", "watch", "list"},
  68. Resources: []string{"pods"},
  69. APIGroups: []string{""},
  70. ResourceNames: []string{},
  71. },
  72. {
  73. Verbs: []string{"get", "watch", "list"},
  74. Resources: []string{"deployments"},
  75. APIGroups: []string{"extensions"},
  76. ResourceNames: []string{},
  77. },
  78. },
  79. },
  80. },
  81. "test-non-resource-url": {
  82. verbs: "get",
  83. nonResourceURL: "/logs/,/healthz",
  84. expectedClusterRole: &rbac.ClusterRole{
  85. TypeMeta: metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
  86. ObjectMeta: metav1.ObjectMeta{
  87. Name: clusterRoleName,
  88. },
  89. Rules: []rbac.PolicyRule{
  90. {
  91. Verbs: []string{"get"},
  92. NonResourceURLs: []string{"/logs/", "/healthz"},
  93. },
  94. },
  95. },
  96. },
  97. "test-resource-and-non-resource-url": {
  98. verbs: "get",
  99. nonResourceURL: "/logs/,/healthz",
  100. resources: "pods",
  101. expectedClusterRole: &rbac.ClusterRole{
  102. TypeMeta: metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
  103. ObjectMeta: metav1.ObjectMeta{
  104. Name: clusterRoleName,
  105. },
  106. Rules: []rbac.PolicyRule{
  107. {
  108. Verbs: []string{"get"},
  109. Resources: []string{"pods"},
  110. APIGroups: []string{""},
  111. ResourceNames: []string{},
  112. },
  113. {
  114. Verbs: []string{"get"},
  115. NonResourceURLs: []string{"/logs/", "/healthz"},
  116. },
  117. },
  118. },
  119. },
  120. "test-aggregation-rules": {
  121. aggregationRule: "foo1=foo2,foo3=foo4",
  122. expectedClusterRole: &rbac.ClusterRole{
  123. TypeMeta: metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
  124. ObjectMeta: metav1.ObjectMeta{
  125. Name: clusterRoleName,
  126. },
  127. AggregationRule: &rbac.AggregationRule{
  128. ClusterRoleSelectors: []metav1.LabelSelector{
  129. {
  130. MatchLabels: map[string]string{
  131. "foo1": "foo2",
  132. "foo3": "foo4",
  133. },
  134. },
  135. },
  136. },
  137. },
  138. },
  139. }
  140. for name, test := range tests {
  141. ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
  142. cmd := NewCmdCreateClusterRole(tf, ioStreams)
  143. cmd.Flags().Set("dry-run", "true")
  144. cmd.Flags().Set("output", "yaml")
  145. cmd.Flags().Set("verb", test.verbs)
  146. cmd.Flags().Set("resource", test.resources)
  147. cmd.Flags().Set("non-resource-url", test.nonResourceURL)
  148. cmd.Flags().Set("aggregation-rule", test.aggregationRule)
  149. if test.resourceNames != "" {
  150. cmd.Flags().Set("resource-name", test.resourceNames)
  151. }
  152. cmd.Run(cmd, []string{clusterRoleName})
  153. actual := &rbac.ClusterRole{}
  154. if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), buf.Bytes(), actual); err != nil {
  155. t.Log(string(buf.Bytes()))
  156. t.Fatal(err)
  157. }
  158. if !equality.Semantic.DeepEqual(test.expectedClusterRole, actual) {
  159. t.Errorf("%s:\nexpected:\n%#v\nsaw:\n%#v", name, test.expectedClusterRole, actual)
  160. }
  161. }
  162. }
  163. func TestClusterRoleValidate(t *testing.T) {
  164. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  165. defer tf.Cleanup()
  166. tests := map[string]struct {
  167. clusterRoleOptions *CreateClusterRoleOptions
  168. expectErr bool
  169. }{
  170. "test-missing-name": {
  171. clusterRoleOptions: &CreateClusterRoleOptions{
  172. CreateRoleOptions: &CreateRoleOptions{},
  173. },
  174. expectErr: true,
  175. },
  176. "test-missing-verb": {
  177. clusterRoleOptions: &CreateClusterRoleOptions{
  178. CreateRoleOptions: &CreateRoleOptions{
  179. Name: "my-clusterrole",
  180. },
  181. },
  182. expectErr: true,
  183. },
  184. "test-missing-resource": {
  185. clusterRoleOptions: &CreateClusterRoleOptions{
  186. CreateRoleOptions: &CreateRoleOptions{
  187. Name: "my-clusterrole",
  188. Verbs: []string{"get"},
  189. },
  190. },
  191. expectErr: true,
  192. },
  193. "test-missing-resource-existing-apigroup": {
  194. clusterRoleOptions: &CreateClusterRoleOptions{
  195. CreateRoleOptions: &CreateRoleOptions{
  196. Name: "my-clusterrole",
  197. Verbs: []string{"get"},
  198. Resources: []ResourceOptions{
  199. {
  200. Group: "extensions",
  201. },
  202. },
  203. },
  204. },
  205. expectErr: true,
  206. },
  207. "test-missing-resource-existing-subresource": {
  208. clusterRoleOptions: &CreateClusterRoleOptions{
  209. CreateRoleOptions: &CreateRoleOptions{
  210. Name: "my-clusterrole",
  211. Verbs: []string{"get"},
  212. Resources: []ResourceOptions{
  213. {
  214. SubResource: "scale",
  215. },
  216. },
  217. },
  218. },
  219. expectErr: true,
  220. },
  221. "test-invalid-verb": {
  222. clusterRoleOptions: &CreateClusterRoleOptions{
  223. CreateRoleOptions: &CreateRoleOptions{
  224. Name: "my-clusterrole",
  225. Verbs: []string{"invalid-verb"},
  226. Resources: []ResourceOptions{
  227. {
  228. Resource: "pods",
  229. },
  230. },
  231. },
  232. },
  233. expectErr: true,
  234. },
  235. "test-nonresource-verb": {
  236. clusterRoleOptions: &CreateClusterRoleOptions{
  237. CreateRoleOptions: &CreateRoleOptions{
  238. Name: "my-clusterrole",
  239. Verbs: []string{"post"},
  240. Resources: []ResourceOptions{
  241. {
  242. Resource: "pods",
  243. },
  244. },
  245. },
  246. },
  247. expectErr: true,
  248. },
  249. "test-special-verb": {
  250. clusterRoleOptions: &CreateClusterRoleOptions{
  251. CreateRoleOptions: &CreateRoleOptions{
  252. Name: "my-clusterrole",
  253. Verbs: []string{"use"},
  254. Resources: []ResourceOptions{
  255. {
  256. Resource: "pods",
  257. },
  258. },
  259. },
  260. },
  261. expectErr: true,
  262. },
  263. "test-mix-verbs": {
  264. clusterRoleOptions: &CreateClusterRoleOptions{
  265. CreateRoleOptions: &CreateRoleOptions{
  266. Name: "my-clusterrole",
  267. Verbs: []string{"impersonate", "use"},
  268. Resources: []ResourceOptions{
  269. {
  270. Resource: "userextras",
  271. SubResource: "scopes",
  272. },
  273. },
  274. },
  275. },
  276. expectErr: true,
  277. },
  278. "test-special-verb-with-wrong-apigroup": {
  279. clusterRoleOptions: &CreateClusterRoleOptions{
  280. CreateRoleOptions: &CreateRoleOptions{
  281. Name: "my-clusterrole",
  282. Verbs: []string{"impersonate"},
  283. Resources: []ResourceOptions{
  284. {
  285. Resource: "userextras",
  286. SubResource: "scopes",
  287. Group: "extensions",
  288. },
  289. },
  290. },
  291. },
  292. expectErr: true,
  293. },
  294. "test-invalid-resource": {
  295. clusterRoleOptions: &CreateClusterRoleOptions{
  296. CreateRoleOptions: &CreateRoleOptions{
  297. Name: "my-clusterrole",
  298. Verbs: []string{"get"},
  299. Resources: []ResourceOptions{
  300. {
  301. Resource: "invalid-resource",
  302. },
  303. },
  304. },
  305. },
  306. expectErr: true,
  307. },
  308. "test-resource-name-with-multiple-resources": {
  309. clusterRoleOptions: &CreateClusterRoleOptions{
  310. CreateRoleOptions: &CreateRoleOptions{
  311. Name: "my-clusterrole",
  312. Verbs: []string{"get"},
  313. Resources: []ResourceOptions{
  314. {
  315. Resource: "pods",
  316. },
  317. {
  318. Resource: "deployments",
  319. Group: "extensions",
  320. },
  321. },
  322. },
  323. },
  324. expectErr: false,
  325. },
  326. "test-valid-case": {
  327. clusterRoleOptions: &CreateClusterRoleOptions{
  328. CreateRoleOptions: &CreateRoleOptions{
  329. Name: "role-binder",
  330. Verbs: []string{"get", "list", "bind"},
  331. Resources: []ResourceOptions{
  332. {
  333. Resource: "roles",
  334. Group: "rbac.authorization.k8s.io",
  335. },
  336. },
  337. },
  338. },
  339. expectErr: false,
  340. },
  341. "test-valid-case-with-subresource": {
  342. clusterRoleOptions: &CreateClusterRoleOptions{
  343. CreateRoleOptions: &CreateRoleOptions{
  344. Name: "my-clusterrole",
  345. Verbs: []string{"get", "list"},
  346. Resources: []ResourceOptions{
  347. {
  348. Resource: "replicasets",
  349. SubResource: "scale",
  350. },
  351. },
  352. },
  353. },
  354. expectErr: false,
  355. },
  356. "test-valid-case-with-additional-resource": {
  357. clusterRoleOptions: &CreateClusterRoleOptions{
  358. CreateRoleOptions: &CreateRoleOptions{
  359. Name: "my-clusterrole",
  360. Verbs: []string{"impersonate"},
  361. Resources: []ResourceOptions{
  362. {
  363. Resource: "userextras",
  364. SubResource: "scopes",
  365. Group: "authentication.k8s.io",
  366. },
  367. },
  368. },
  369. },
  370. expectErr: false,
  371. },
  372. "test-invalid-empty-non-resource-url": {
  373. clusterRoleOptions: &CreateClusterRoleOptions{
  374. CreateRoleOptions: &CreateRoleOptions{
  375. Name: "my-clusterrole",
  376. Verbs: []string{"create"},
  377. },
  378. NonResourceURLs: []string{""},
  379. },
  380. expectErr: true,
  381. },
  382. "test-invalid-non-resource-url": {
  383. clusterRoleOptions: &CreateClusterRoleOptions{
  384. CreateRoleOptions: &CreateRoleOptions{
  385. Name: "my-clusterrole",
  386. Verbs: []string{"create"},
  387. },
  388. NonResourceURLs: []string{"logs"},
  389. },
  390. expectErr: true,
  391. },
  392. "test-invalid-non-resource-url-with-*": {
  393. clusterRoleOptions: &CreateClusterRoleOptions{
  394. CreateRoleOptions: &CreateRoleOptions{
  395. Name: "my-clusterrole",
  396. Verbs: []string{"create"},
  397. },
  398. NonResourceURLs: []string{"/logs/*/"},
  399. },
  400. expectErr: true,
  401. },
  402. "test-invalid-non-resource-url-with-multiple-*": {
  403. clusterRoleOptions: &CreateClusterRoleOptions{
  404. CreateRoleOptions: &CreateRoleOptions{
  405. Name: "my-clusterrole",
  406. Verbs: []string{"create"},
  407. },
  408. NonResourceURLs: []string{"/logs*/*"},
  409. },
  410. expectErr: true,
  411. },
  412. "test-invalid-verb-for-non-resource-url": {
  413. clusterRoleOptions: &CreateClusterRoleOptions{
  414. CreateRoleOptions: &CreateRoleOptions{
  415. Name: "my-clusterrole",
  416. Verbs: []string{"create"},
  417. },
  418. NonResourceURLs: []string{"/logs/"},
  419. },
  420. expectErr: true,
  421. },
  422. "test-resource-and-non-resource-url-specified-together": {
  423. clusterRoleOptions: &CreateClusterRoleOptions{
  424. CreateRoleOptions: &CreateRoleOptions{
  425. Name: "my-clusterrole",
  426. Verbs: []string{"get"},
  427. Resources: []ResourceOptions{
  428. {
  429. Resource: "replicasets",
  430. SubResource: "scale",
  431. },
  432. },
  433. },
  434. NonResourceURLs: []string{"/logs/", "/logs/*"},
  435. },
  436. expectErr: false,
  437. },
  438. "test-aggregation-rule-with-verb": {
  439. clusterRoleOptions: &CreateClusterRoleOptions{
  440. CreateRoleOptions: &CreateRoleOptions{
  441. Name: "my-clusterrole",
  442. Verbs: []string{"get"},
  443. },
  444. AggregationRule: map[string]string{"foo-key": "foo-vlue"},
  445. },
  446. expectErr: true,
  447. },
  448. "test-aggregation-rule-with-resource": {
  449. clusterRoleOptions: &CreateClusterRoleOptions{
  450. CreateRoleOptions: &CreateRoleOptions{
  451. Name: "my-clusterrole",
  452. Resources: []ResourceOptions{
  453. {
  454. Resource: "replicasets",
  455. SubResource: "scale",
  456. },
  457. },
  458. },
  459. AggregationRule: map[string]string{"foo-key": "foo-vlue"},
  460. },
  461. expectErr: true,
  462. },
  463. "test-aggregation-rule-with-no-resource-url": {
  464. clusterRoleOptions: &CreateClusterRoleOptions{
  465. CreateRoleOptions: &CreateRoleOptions{
  466. Name: "my-clusterrole",
  467. },
  468. NonResourceURLs: []string{"/logs/"},
  469. AggregationRule: map[string]string{"foo-key": "foo-vlue"},
  470. },
  471. expectErr: true,
  472. },
  473. "test-aggregation-rule": {
  474. clusterRoleOptions: &CreateClusterRoleOptions{
  475. CreateRoleOptions: &CreateRoleOptions{
  476. Name: "my-clusterrole",
  477. },
  478. AggregationRule: map[string]string{"foo-key": "foo-vlue"},
  479. },
  480. expectErr: false,
  481. },
  482. }
  483. for name, test := range tests {
  484. t.Run(name, func(t *testing.T) {
  485. var err error
  486. test.clusterRoleOptions.Mapper, err = tf.ToRESTMapper()
  487. if err != nil {
  488. t.Fatal(err)
  489. }
  490. err = test.clusterRoleOptions.Validate()
  491. if test.expectErr && err == nil {
  492. t.Errorf("%s: expect error happens, but validate passes.", name)
  493. }
  494. if !test.expectErr && err != nil {
  495. t.Errorf("%s: unexpected error: %v", name, err)
  496. }
  497. })
  498. }
  499. }