mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 18:28:13 +00:00 
			
		
		
		
	Merge pull request #39852 from xingzhou/kube-39596
Automatic merge from submit-queue Added kubectl create role command Added `kubectl create role` command. Fixed part of #39596 **Release note**: ``` Added one new command `kubectl create role` to help user create a single role from command line. ```
This commit is contained in:
		| @@ -43,6 +43,7 @@ docs/man/man1/kubectl-create-deployment.1 | ||||
| docs/man/man1/kubectl-create-namespace.1 | ||||
| docs/man/man1/kubectl-create-poddisruptionbudget.1 | ||||
| docs/man/man1/kubectl-create-quota.1 | ||||
| docs/man/man1/kubectl-create-role.1 | ||||
| docs/man/man1/kubectl-create-rolebinding.1 | ||||
| docs/man/man1/kubectl-create-secret-docker-registry.1 | ||||
| docs/man/man1/kubectl-create-secret-generic.1 | ||||
| @@ -127,6 +128,7 @@ docs/user-guide/kubectl/kubectl_create_deployment.md | ||||
| docs/user-guide/kubectl/kubectl_create_namespace.md | ||||
| docs/user-guide/kubectl/kubectl_create_poddisruptionbudget.md | ||||
| docs/user-guide/kubectl/kubectl_create_quota.md | ||||
| docs/user-guide/kubectl/kubectl_create_role.md | ||||
| docs/user-guide/kubectl/kubectl_create_rolebinding.md | ||||
| docs/user-guide/kubectl/kubectl_create_secret.md | ||||
| docs/user-guide/kubectl/kubectl_create_secret_docker-registry.md | ||||
|   | ||||
							
								
								
									
										3
									
								
								docs/man/man1/kubectl-create-role.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								docs/man/man1/kubectl-create-role.1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| This file is autogenerated, but we've stopped checking such files into the | ||||
| repository to reduce the need for rebases. Please run hack/generate-docs.sh to | ||||
| populate this file. | ||||
							
								
								
									
										3
									
								
								docs/user-guide/kubectl/kubectl_create_role.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								docs/user-guide/kubectl/kubectl_create_role.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| This file is autogenerated, but we've stopped checking such files into the | ||||
| repository to reduce the need for rebases. Please run hack/generate-docs.sh to | ||||
| populate this file. | ||||
| @@ -57,6 +57,7 @@ pods="pods" | ||||
| podtemplates="podtemplates" | ||||
| replicasets="replicasets" | ||||
| replicationcontrollers="replicationcontrollers" | ||||
| roles="roles" | ||||
| secrets="secrets" | ||||
| serviceaccounts="serviceaccounts" | ||||
| services="services" | ||||
| @@ -2817,6 +2818,22 @@ runTests() { | ||||
|     kube::test::get_object_assert rolebinding/sarole "{{range.subjects}}{{.namespace}}:{{end}}" 'otherns:' | ||||
|     kube::test::get_object_assert rolebinding/sarole "{{range.subjects}}{{.name}}:{{end}}" 'sa-name:' | ||||
|   fi | ||||
|    | ||||
|   if kube::test::if_supports_resource "${roles}" ; then | ||||
|     kubectl create "${kube_flags[@]}" role pod-admin --verb=* --resource=pods | ||||
|     kube::test::get_object_assert role/pod-admin "{{range.rules}}{{range.verbs}}{{.}}:{{end}}{{end}}" '\*:' | ||||
|     kube::test::get_object_assert role/pod-admin "{{range.rules}}{{range.resources}}{{.}}:{{end}}{{end}}" 'pods:' | ||||
|     kube::test::get_object_assert role/pod-admin "{{range.rules}}{{range.apiGroups}}{{.}}:{{end}}{{end}}" ':' | ||||
|     kubectl create "${kube_flags[@]}" role resource-reader --verb=get,list --resource=pods,deployments.extensions | ||||
|     kube::test::get_object_assert role/resource-reader "{{range.rules}}{{range.verbs}}{{.}}:{{end}}{{end}}" 'get:list:get:list:' | ||||
|     kube::test::get_object_assert role/resource-reader "{{range.rules}}{{range.resources}}{{.}}:{{end}}{{end}}" 'pods:deployments:' | ||||
|     kube::test::get_object_assert role/resource-reader "{{range.rules}}{{range.apiGroups}}{{.}}:{{end}}{{end}}" ':extensions:' | ||||
|   	kubectl create "${kube_flags[@]}" role resourcename-reader --verb=get,list --resource=pods --resource-name=foo | ||||
|     kube::test::get_object_assert role/resourcename-reader "{{range.rules}}{{range.verbs}}{{.}}:{{end}}{{end}}" 'get:list:' | ||||
|     kube::test::get_object_assert role/resourcename-reader "{{range.rules}}{{range.resources}}{{.}}:{{end}}{{end}}" 'pods:' | ||||
|     kube::test::get_object_assert role/resourcename-reader "{{range.rules}}{{range.apiGroups}}{{.}}:{{end}}{{end}}" ':' | ||||
|     kube::test::get_object_assert role/resourcename-reader "{{range.rules}}{{range.resourceNames}}{{.}}:{{end}}{{end}}" 'foo:' | ||||
|   fi | ||||
|  | ||||
|   ######################### | ||||
|   # Assert short name     # | ||||
|   | ||||
| @@ -519,7 +519,9 @@ requestheader-username-headers | ||||
| require-kubeconfig | ||||
| required-contexts | ||||
| resolv-conf | ||||
| resource | ||||
| resource-container | ||||
| resource-name | ||||
| resource-quota-sync-period | ||||
| resource-version | ||||
| results-dir | ||||
| @@ -623,6 +625,7 @@ use-service-account-credentials | ||||
| use-kubernetes-cluster-service | ||||
| use-kubernetes-version | ||||
| user-whitelist | ||||
| verb | ||||
| verify-only | ||||
| versioned-clientset-package | ||||
| viper-config | ||||
|   | ||||
| @@ -30,6 +30,7 @@ go_library( | ||||
|         "create_namespace.go", | ||||
|         "create_pdb.go", | ||||
|         "create_quota.go", | ||||
|         "create_role.go", | ||||
|         "create_rolebinding.go", | ||||
|         "create_secret.go", | ||||
|         "create_service.go", | ||||
| @@ -70,6 +71,7 @@ go_library( | ||||
|         "//pkg/apis/certificates:go_default_library", | ||||
|         "//pkg/apis/extensions/v1beta1:go_default_library", | ||||
|         "//pkg/apis/policy:go_default_library", | ||||
|         "//pkg/apis/rbac:go_default_library", | ||||
|         "//pkg/client/clientset_generated/internalclientset:go_default_library", | ||||
|         "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", | ||||
|         "//pkg/client/unversioned:go_default_library", | ||||
| @@ -143,6 +145,7 @@ go_test( | ||||
|         "create_deployment_test.go", | ||||
|         "create_namespace_test.go", | ||||
|         "create_quota_test.go", | ||||
|         "create_role_test.go", | ||||
|         "create_secret_test.go", | ||||
|         "create_service_test.go", | ||||
|         "create_serviceaccount_test.go", | ||||
| @@ -185,6 +188,7 @@ go_test( | ||||
|         "//pkg/apis/batch:go_default_library", | ||||
|         "//pkg/apis/extensions:go_default_library", | ||||
|         "//pkg/apis/policy:go_default_library", | ||||
|         "//pkg/apis/rbac:go_default_library", | ||||
|         "//pkg/kubectl:go_default_library", | ||||
|         "//pkg/kubectl/cmd/testing:go_default_library", | ||||
|         "//pkg/kubectl/cmd/util:go_default_library", | ||||
|   | ||||
| @@ -96,6 +96,7 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { | ||||
| 	cmd.AddCommand(NewCmdCreateService(f, out, errOut)) | ||||
| 	cmd.AddCommand(NewCmdCreateDeployment(f, out)) | ||||
| 	cmd.AddCommand(NewCmdCreateClusterRoleBinding(f, out)) | ||||
| 	cmd.AddCommand(NewCmdCreateRole(f, out)) | ||||
| 	cmd.AddCommand(NewCmdCreateRoleBinding(f, out)) | ||||
| 	cmd.AddCommand(NewCmdCreatePodDisruptionBudget(f, out)) | ||||
| 	return cmd | ||||
|   | ||||
							
								
								
									
										237
									
								
								pkg/kubectl/cmd/create_role.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								pkg/kubectl/cmd/create_role.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,237 @@ | ||||
| /* | ||||
| Copyright 2017 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/spf13/cobra" | ||||
|  | ||||
| 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||
| 	"k8s.io/apimachinery/pkg/util/sets" | ||||
| 	"k8s.io/kubernetes/pkg/apis/rbac" | ||||
| 	"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | ||||
| 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	roleLong = templates.LongDesc(` | ||||
| 		Create a role with single rule.`) | ||||
|  | ||||
| 	roleExample = templates.Examples(` | ||||
| 		# Create a Role named "pod-reader" that allows user to perform "get", "watch" and "list" on pods | ||||
| 		kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods | ||||
|  | ||||
| 		# Create a Role named "pod-reader" with ResourceName specified | ||||
| 		kubectl create role pod-reader --verb=get --verg=list --verb=watch --resource=pods --resource-name=readablepod`) | ||||
|  | ||||
| 	// Valid resource verb list for validation. | ||||
| 	validResourceVerbs = []string{"*", "get", "delete", "list", "create", "update", "patch", "watch", "proxy", "redirect", "deletecollection"} | ||||
|  | ||||
| 	// Valid non-resource verb list for validation. | ||||
| 	validNonResourceVerbs = []string{"get", "post", "put", "delete"} | ||||
| ) | ||||
|  | ||||
| type CreateRoleOptions struct { | ||||
| 	Name          string | ||||
| 	Verbs         []string | ||||
| 	Resources     []schema.GroupVersionResource | ||||
| 	ResourceNames []string | ||||
| } | ||||
|  | ||||
| // Role is a command to ease creating Roles. | ||||
| func NewCmdCreateRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { | ||||
| 	c := &CreateRoleOptions{} | ||||
| 	cmd := &cobra.Command{ | ||||
| 		Use:     "role NAME --verb=verb --resource=resource.group [--resource-name=resourcename] [--dry-run]", | ||||
| 		Short:   roleLong, | ||||
| 		Long:    roleLong, | ||||
| 		Example: roleExample, | ||||
| 		Run: func(cmd *cobra.Command, args []string) { | ||||
| 			cmdutil.CheckErr(c.Complete(cmd, args)) | ||||
| 			cmdutil.CheckErr(c.Validate(f)) | ||||
| 			cmdutil.CheckErr(c.RunCreateRole(f, cmdOut, cmd, args)) | ||||
| 		}, | ||||
| 	} | ||||
| 	cmdutil.AddApplyAnnotationFlags(cmd) | ||||
| 	cmdutil.AddValidateFlags(cmd) | ||||
| 	cmdutil.AddPrinterFlags(cmd) | ||||
| 	cmdutil.AddDryRunFlag(cmd) | ||||
| 	cmd.Flags().StringSliceVar(&c.Verbs, "verb", []string{}, "verb that applies to the resources contained in the rule") | ||||
| 	cmd.Flags().StringSlice("resource", []string{}, "resource that the rule applies to") | ||||
| 	cmd.Flags().StringSliceVar(&c.ResourceNames, "resource-name", []string{}, "resource in the white list that the rule applies to") | ||||
|  | ||||
| 	return cmd | ||||
| } | ||||
|  | ||||
| func (c *CreateRoleOptions) Complete(cmd *cobra.Command, args []string) error { | ||||
| 	name, err := NameFromCommandArgs(cmd, args) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	c.Name = name | ||||
|  | ||||
| 	// Remove duplicate verbs. | ||||
| 	verbs := []string{} | ||||
| 	for _, v := range c.Verbs { | ||||
| 		// VerbAll respresents all kinds of verbs. | ||||
| 		if v == "*" { | ||||
| 			verbs = []string{"*"} | ||||
| 			break | ||||
| 		} | ||||
| 		if !arrayContains(verbs, v) { | ||||
| 			verbs = append(verbs, v) | ||||
| 		} | ||||
| 	} | ||||
| 	c.Verbs = verbs | ||||
|  | ||||
| 	// Support resource.group pattern. If no API Group specified, use "" as core API Group. | ||||
| 	// e.g. --resource=pods,deployments.extensions | ||||
| 	resources := cmdutil.GetFlagStringSlice(cmd, "resource") | ||||
| 	for _, r := range resources { | ||||
| 		sections := strings.Split(r, ".") | ||||
|  | ||||
| 		if len(sections) == 1 { | ||||
| 			c.Resources = append(c.Resources, schema.GroupVersionResource{Resource: r}) | ||||
| 		} else { | ||||
| 			c.Resources = append(c.Resources, schema.GroupVersionResource{Resource: sections[0], Group: strings.Join(sections[1:], ".")}) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Remove duplicate resource names. | ||||
| 	resourceNames := []string{} | ||||
| 	for _, n := range c.ResourceNames { | ||||
| 		if !arrayContains(resourceNames, n) { | ||||
| 			resourceNames = append(resourceNames, n) | ||||
| 		} | ||||
| 	} | ||||
| 	c.ResourceNames = resourceNames | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *CreateRoleOptions) Validate(f cmdutil.Factory) error { | ||||
| 	if c.Name == "" { | ||||
| 		return fmt.Errorf("name must be specified") | ||||
| 	} | ||||
|  | ||||
| 	// validate verbs. | ||||
| 	if len(c.Verbs) == 0 { | ||||
| 		return fmt.Errorf("at least one verb must be specified") | ||||
| 	} | ||||
|  | ||||
| 	for _, v := range c.Verbs { | ||||
| 		if !arrayContains(validResourceVerbs, v) && !arrayContains(validNonResourceVerbs, v) { | ||||
| 			return fmt.Errorf("invalid verb: '%s'", v) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// validate resources. | ||||
| 	mapper, _ := f.Object() | ||||
|  | ||||
| 	if len(c.Resources) == 0 { | ||||
| 		return fmt.Errorf("at least one resource must be specified") | ||||
| 	} | ||||
|  | ||||
| 	for _, r := range c.Resources { | ||||
| 		_, err := mapper.ResourceFor(r) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// validate resource names, can not apply resource names to multiple resources. | ||||
| 	if len(c.ResourceNames) > 0 && len(c.Resources) > 1 { | ||||
| 		return fmt.Errorf("resource name(s) can not be applied to multiple resources") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *CreateRoleOptions) RunCreateRole(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { | ||||
| 	mapper, _ := f.Object() | ||||
| 	dryRun, outputFormat := cmdutil.GetDryRunFlag(cmd), cmdutil.GetFlagString(cmd, "output") | ||||
|  | ||||
| 	// groupResourceMapping is a apigroup-resource map. The key of this map is api group, while the value | ||||
| 	// is a string array of resources under this api group. | ||||
| 	// E.g.  groupResourceMapping = {"extensions": ["replicasets", "deployments"], "batch":["jobs"]} | ||||
| 	groupResourceMapping := map[string][]string{} | ||||
|  | ||||
| 	// This loop does the following work: | ||||
| 	// 1. Constructs groupResourceMapping based on input resources. | ||||
| 	// 2. Prevents pointing to non-existent resources. | ||||
| 	// 3. Transfers resource short name to long name. E.g. rs.extensions is transferred to replicasets.extensions | ||||
| 	for _, r := range c.Resources { | ||||
| 		resource, err := mapper.ResourceFor(r) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if !arrayContains(groupResourceMapping[resource.Group], resource.Resource) { | ||||
| 			groupResourceMapping[resource.Group] = append(groupResourceMapping[resource.Group], resource.Resource) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	role := &rbac.Role{} | ||||
|  | ||||
| 	// Create separate rule for each of the api group. | ||||
| 	rules := []rbac.PolicyRule{} | ||||
| 	for _, g := range sets.StringKeySet(groupResourceMapping).List() { | ||||
| 		rule := rbac.PolicyRule{} | ||||
| 		rule.Verbs = c.Verbs | ||||
| 		rule.Resources = groupResourceMapping[g] | ||||
| 		rule.APIGroups = []string{g} | ||||
| 		rule.ResourceNames = c.ResourceNames | ||||
| 		rules = append(rules, rule) | ||||
| 	} | ||||
| 	role.Name = c.Name | ||||
| 	role.Rules = rules | ||||
|  | ||||
| 	// Create role. | ||||
| 	namespace, _, err := f.DefaultNamespace() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if !dryRun { | ||||
| 		client, err := f.ClientSet() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		_, err = client.Rbac().Roles(namespace).Create(role) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if useShortOutput := outputFormat == "name"; useShortOutput || len(outputFormat) == 0 { | ||||
| 		cmdutil.PrintSuccess(mapper, useShortOutput, cmdOut, "roles", c.Name, dryRun, "created") | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return f.PrintObject(cmd, mapper, role, cmdOut) | ||||
| } | ||||
|  | ||||
| func arrayContains(s []string, e string) bool { | ||||
| 	for _, a := range s { | ||||
| 		if a == e { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
							
								
								
									
										359
									
								
								pkg/kubectl/cmd/create_role_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								pkg/kubectl/cmd/create_role_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,359 @@ | ||||
| /* | ||||
| Copyright 2017 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
|  | ||||
| 	"k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/runtime" | ||||
| 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||
| 	"k8s.io/kubernetes/pkg/apis/rbac" | ||||
| 	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" | ||||
| ) | ||||
|  | ||||
| type testRolePrinter struct { | ||||
| 	CachedRole *rbac.Role | ||||
| } | ||||
|  | ||||
| func (t *testRolePrinter) PrintObj(obj runtime.Object, out io.Writer) error { | ||||
| 	t.CachedRole = obj.(*rbac.Role) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (t *testRolePrinter) AfterPrint(output io.Writer, res string) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (t *testRolePrinter) HandledResources() []string { | ||||
| 	return []string{} | ||||
| } | ||||
|  | ||||
| func TestCreateRole(t *testing.T) { | ||||
| 	roleName := "my-role" | ||||
|  | ||||
| 	f, tf, _, _ := cmdtesting.NewAPIFactory() | ||||
| 	printer := &testRolePrinter{} | ||||
| 	tf.Printer = printer | ||||
| 	tf.Namespace = "test" | ||||
|  | ||||
| 	tests := map[string]struct { | ||||
| 		verbs         string | ||||
| 		resources     string | ||||
| 		resourceNames string | ||||
| 		expectedRole  *rbac.Role | ||||
| 	}{ | ||||
| 		"test-duplicate-resources": { | ||||
| 			verbs:     "get,watch,list", | ||||
| 			resources: "pods,pods", | ||||
| 			expectedRole: &rbac.Role{ | ||||
| 				ObjectMeta: v1.ObjectMeta{ | ||||
| 					Name: roleName, | ||||
| 				}, | ||||
| 				Rules: []rbac.PolicyRule{ | ||||
| 					{ | ||||
| 						Verbs:         []string{"get", "watch", "list"}, | ||||
| 						Resources:     []string{"pods"}, | ||||
| 						APIGroups:     []string{""}, | ||||
| 						ResourceNames: []string{}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		"test-valid-case-with-multiple-apigroups": { | ||||
| 			verbs:     "get,watch,list", | ||||
| 			resources: "pods,deployments.extensions", | ||||
| 			expectedRole: &rbac.Role{ | ||||
| 				ObjectMeta: v1.ObjectMeta{ | ||||
| 					Name: roleName, | ||||
| 				}, | ||||
| 				Rules: []rbac.PolicyRule{ | ||||
| 					{ | ||||
| 						Verbs:         []string{"get", "watch", "list"}, | ||||
| 						Resources:     []string{"pods"}, | ||||
| 						APIGroups:     []string{""}, | ||||
| 						ResourceNames: []string{}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Verbs:         []string{"get", "watch", "list"}, | ||||
| 						Resources:     []string{"deployments"}, | ||||
| 						APIGroups:     []string{"extensions"}, | ||||
| 						ResourceNames: []string{}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for name, test := range tests { | ||||
| 		buf := bytes.NewBuffer([]byte{}) | ||||
| 		cmd := NewCmdCreateRole(f, buf) | ||||
| 		cmd.Flags().Set("dry-run", "true") | ||||
| 		cmd.Flags().Set("output", "object") | ||||
| 		cmd.Flags().Set("verb", test.verbs) | ||||
| 		cmd.Flags().Set("resource", test.resources) | ||||
| 		if test.resourceNames != "" { | ||||
| 			cmd.Flags().Set("resource-name", test.resourceNames) | ||||
| 		} | ||||
| 		cmd.Run(cmd, []string{roleName}) | ||||
| 		if !reflect.DeepEqual(test.expectedRole, printer.CachedRole) { | ||||
| 			t.Errorf("%s:\nexpected:\n%#v\nsaw:\n%#v", name, test.expectedRole, printer.CachedRole) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestValidate(t *testing.T) { | ||||
| 	f, tf, _, _ := cmdtesting.NewAPIFactory() | ||||
| 	tf.Printer = &testPrinter{} | ||||
| 	tf.Namespace = "test" | ||||
|  | ||||
| 	tests := map[string]struct { | ||||
| 		roleOptions *CreateRoleOptions | ||||
| 		expectErr   bool | ||||
| 	}{ | ||||
| 		"test-missing-name": { | ||||
| 			roleOptions: &CreateRoleOptions{}, | ||||
| 			expectErr:   true, | ||||
| 		}, | ||||
| 		"test-missing-verb": { | ||||
| 			roleOptions: &CreateRoleOptions{ | ||||
| 				Name: "my-role", | ||||
| 			}, | ||||
| 			expectErr: true, | ||||
| 		}, | ||||
| 		"test-missing-resource": { | ||||
| 			roleOptions: &CreateRoleOptions{ | ||||
| 				Name:  "my-role", | ||||
| 				Verbs: []string{"get"}, | ||||
| 			}, | ||||
| 			expectErr: true, | ||||
| 		}, | ||||
| 		"test-invalid-verb": { | ||||
| 			roleOptions: &CreateRoleOptions{ | ||||
| 				Name:  "my-role", | ||||
| 				Verbs: []string{"invalid-verb"}, | ||||
| 				Resources: []schema.GroupVersionResource{ | ||||
| 					{ | ||||
| 						Resource: "pods", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectErr: true, | ||||
| 		}, | ||||
| 		"test-invalid-resource": { | ||||
| 			roleOptions: &CreateRoleOptions{ | ||||
| 				Name:  "my-role", | ||||
| 				Verbs: []string{"get"}, | ||||
| 				Resources: []schema.GroupVersionResource{ | ||||
| 					{ | ||||
| 						Resource: "invalid-resource", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			expectErr: true, | ||||
| 		}, | ||||
| 		"test-resource-name-with-multiple-resources": { | ||||
| 			roleOptions: &CreateRoleOptions{ | ||||
| 				Name:  "my-role", | ||||
| 				Verbs: []string{"get"}, | ||||
| 				Resources: []schema.GroupVersionResource{ | ||||
| 					{ | ||||
| 						Resource: "pods", | ||||
| 					}, | ||||
| 					{ | ||||
| 						Resource: "deployments", | ||||
| 						Group:    "extensions", | ||||
| 					}, | ||||
| 				}, | ||||
| 				ResourceNames: []string{"foo"}, | ||||
| 			}, | ||||
| 			expectErr: true, | ||||
| 		}, | ||||
| 		"test-valid-case": { | ||||
| 			roleOptions: &CreateRoleOptions{ | ||||
| 				Name:  "my-role", | ||||
| 				Verbs: []string{"get", "list"}, | ||||
| 				Resources: []schema.GroupVersionResource{ | ||||
| 					{ | ||||
| 						Resource: "pods", | ||||
| 					}, | ||||
| 				}, | ||||
| 				ResourceNames: []string{"foo"}, | ||||
| 			}, | ||||
| 			expectErr: false, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for name, test := range tests { | ||||
| 		err := test.roleOptions.Validate(f) | ||||
| 		if test.expectErr && err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		if !test.expectErr && err != nil { | ||||
| 			t.Errorf("%s: unexpected error: %v", name, err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestComplete(t *testing.T) { | ||||
| 	roleName := "my-role" | ||||
|  | ||||
| 	f, tf, _, _ := cmdtesting.NewAPIFactory() | ||||
| 	tf.Printer = &testPrinter{} | ||||
| 	tf.Namespace = "test" | ||||
|  | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
| 	cmd := NewCmdCreateRole(f, buf) | ||||
| 	cmd.Flags().Set("resource", "pods,deployments.extensions") | ||||
|  | ||||
| 	tests := map[string]struct { | ||||
| 		params      []string | ||||
| 		roleOptions *CreateRoleOptions | ||||
| 		expected    *CreateRoleOptions | ||||
| 		expectErr   bool | ||||
| 	}{ | ||||
| 		"test-missing-name": { | ||||
| 			params:      []string{}, | ||||
| 			roleOptions: &CreateRoleOptions{}, | ||||
| 			expectErr:   true, | ||||
| 		}, | ||||
| 		"test-duplicate-verbs": { | ||||
| 			params: []string{roleName}, | ||||
| 			roleOptions: &CreateRoleOptions{ | ||||
| 				Name: roleName, | ||||
| 				Verbs: []string{ | ||||
| 					"get", | ||||
| 					"watch", | ||||
| 					"list", | ||||
| 					"get", | ||||
| 				}, | ||||
| 			}, | ||||
| 			expected: &CreateRoleOptions{ | ||||
| 				Name: roleName, | ||||
| 				Verbs: []string{ | ||||
| 					"get", | ||||
| 					"watch", | ||||
| 					"list", | ||||
| 				}, | ||||
| 				Resources: []schema.GroupVersionResource{ | ||||
| 					{ | ||||
| 						Resource: "pods", | ||||
| 						Group:    "", | ||||
| 					}, | ||||
| 					{ | ||||
| 						Resource: "deployments", | ||||
| 						Group:    "extensions", | ||||
| 					}, | ||||
| 				}, | ||||
| 				ResourceNames: []string{}, | ||||
| 			}, | ||||
| 			expectErr: false, | ||||
| 		}, | ||||
| 		"test-verball": { | ||||
| 			params: []string{roleName}, | ||||
| 			roleOptions: &CreateRoleOptions{ | ||||
| 				Name: roleName, | ||||
| 				Verbs: []string{ | ||||
| 					"get", | ||||
| 					"watch", | ||||
| 					"list", | ||||
| 					"*", | ||||
| 				}, | ||||
| 			}, | ||||
| 			expected: &CreateRoleOptions{ | ||||
| 				Name:  roleName, | ||||
| 				Verbs: []string{"*"}, | ||||
| 				Resources: []schema.GroupVersionResource{ | ||||
| 					{ | ||||
| 						Resource: "pods", | ||||
| 						Group:    "", | ||||
| 					}, | ||||
| 					{ | ||||
| 						Resource: "deployments", | ||||
| 						Group:    "extensions", | ||||
| 					}, | ||||
| 				}, | ||||
| 				ResourceNames: []string{}, | ||||
| 			}, | ||||
| 			expectErr: false, | ||||
| 		}, | ||||
| 		"test-duplicate-resourcenames": { | ||||
| 			params: []string{roleName}, | ||||
| 			roleOptions: &CreateRoleOptions{ | ||||
| 				Name:          roleName, | ||||
| 				Verbs:         []string{"*"}, | ||||
| 				ResourceNames: []string{"foo", "foo"}, | ||||
| 			}, | ||||
| 			expected: &CreateRoleOptions{ | ||||
| 				Name:  roleName, | ||||
| 				Verbs: []string{"*"}, | ||||
| 				Resources: []schema.GroupVersionResource{ | ||||
| 					{ | ||||
| 						Resource: "pods", | ||||
| 						Group:    "", | ||||
| 					}, | ||||
| 					{ | ||||
| 						Resource: "deployments", | ||||
| 						Group:    "extensions", | ||||
| 					}, | ||||
| 				}, | ||||
| 				ResourceNames: []string{"foo"}, | ||||
| 			}, | ||||
| 			expectErr: false, | ||||
| 		}, | ||||
| 		"test-valid-complete-case": { | ||||
| 			params: []string{roleName}, | ||||
| 			roleOptions: &CreateRoleOptions{ | ||||
| 				Name:          roleName, | ||||
| 				Verbs:         []string{"*"}, | ||||
| 				ResourceNames: []string{"foo"}, | ||||
| 			}, | ||||
| 			expected: &CreateRoleOptions{ | ||||
| 				Name:  roleName, | ||||
| 				Verbs: []string{"*"}, | ||||
| 				Resources: []schema.GroupVersionResource{ | ||||
| 					{ | ||||
| 						Resource: "pods", | ||||
| 						Group:    "", | ||||
| 					}, | ||||
| 					{ | ||||
| 						Resource: "deployments", | ||||
| 						Group:    "extensions", | ||||
| 					}, | ||||
| 				}, | ||||
| 				ResourceNames: []string{"foo"}, | ||||
| 			}, | ||||
| 			expectErr: false, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for name, test := range tests { | ||||
| 		err := test.roleOptions.Complete(cmd, test.params) | ||||
| 		if !test.expectErr && err != nil { | ||||
| 			t.Errorf("%s: unexpected error: %v", name, err) | ||||
| 		} | ||||
| 		if test.expectErr && err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		if !reflect.DeepEqual(test.roleOptions, test.expected) { | ||||
| 			t.Errorf("%s:\nexpected:\n%#v\nsaw:\n%#v", name, test.expected, test.roleOptions) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Kubernetes Submit Queue
					Kubernetes Submit Queue