...

Source file src/k8s.io/kubectl/pkg/cmd/create/create_clusterrole_test.go

Documentation: k8s.io/kubectl/pkg/cmd/create

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

View as plain text