Merge pull request #62945 from nak3/all-resource-create-role

Automatic merge from submit-queue (batch tested with PRs 67026, 62945, 66917). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

`kubectl create {clusterrole,role}`'s `--resources` flag support asterisk to specify all resources

**What this PR does / why we need it**:

Currently `kubectl create (cluster)role`'s `--resources` flag does not support asterisk to specify all resources.

```
# kubectl create clusterrole superrole --verb=get  --resource=*
the server doesn't have a resource type "*"
```

As an user, we create a role with `--resources=*` sometimes, so this PR supports it.

Fixes https://github.com/kubernetes/kubernetes/issues/62989

**Special notes for your reviewer**:

- This patch does not support `--resource=*` for `SpecialVerbs` - e.g `kubectl create role foo --verb=impersonate  --resource=*`, because current code also does not support `kubectl create role foo --verb=impersonate  --resource=users,pods`

**Release note**:

```release-note
`kubectl create {clusterrole,role}`'s `--resources` flag supports asterisk to specify all resources.
```
This commit is contained in:
Kubernetes Submit Queue 2018-08-08 20:53:02 -07:00 committed by GitHub
commit bd0de223da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 165 additions and 7 deletions

View File

@ -204,6 +204,11 @@ func (o *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
}
resource.Resource = parts[0]
if resource.Resource == "*" && len(parts) == 1 && len(sections) == 1 {
o.Resources = []ResourceOptions{*resource}
break
}
o.Resources = append(o.Resources, *resource)
}
@ -279,6 +284,9 @@ func (o *CreateRoleOptions) validateResource() error {
if len(r.Resource) == 0 {
return fmt.Errorf("resource must be specified if apiGroup/subresource specified")
}
if r.Resource == "*" {
return nil
}
resource := schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}
groupVersionResource, err := o.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group})

View File

@ -360,24 +360,26 @@ func TestComplete(t *testing.T) {
tf.Client = &fake.RESTClient{}
tf.ClientConfigVal = defaultClientConfig()
cmd := NewCmdCreateRole(tf, genericclioptions.NewTestIOStreamsDiscard())
cmd.Flags().Set("resource", "pods,deployments.extensions")
defaultTestResources := "pods,deployments.extensions"
tests := map[string]struct {
params []string
resources string
roleOptions *CreateRoleOptions
expected *CreateRoleOptions
expectErr bool
}{
"test-missing-name": {
params: []string{},
params: []string{},
resources: defaultTestResources,
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
},
expectErr: true,
},
"test-duplicate-verbs": {
params: []string{roleName},
params: []string{roleName},
resources: defaultTestResources,
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
Name: roleName,
@ -410,7 +412,8 @@ func TestComplete(t *testing.T) {
expectErr: false,
},
"test-verball": {
params: []string{roleName},
params: []string{roleName},
resources: defaultTestResources,
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
Name: roleName,
@ -438,8 +441,151 @@ func TestComplete(t *testing.T) {
},
expectErr: false,
},
"test-allresource": {
params: []string{roleName},
resources: "*,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-allresource-subresource": {
params: []string{roleName},
resources: "*/scale,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
SubResource: "scale",
},
{
Resource: "pods",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-allresrouce-allgroup": {
params: []string{roleName},
resources: "*.*,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
Group: "*",
},
{
Resource: "pods",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-allresource-allgroup-subresource": {
params: []string{roleName},
resources: "*.*/scale,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
Group: "*",
SubResource: "scale",
},
{
Resource: "pods",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-allresource-specificgroup": {
params: []string{roleName},
resources: "*.extensions,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
Group: "extensions",
},
{
Resource: "pods",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-allresource-specificgroup-subresource": {
params: []string{roleName},
resources: "*.extensions/scale,pods",
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created"),
Name: roleName,
Verbs: []string{"*"},
},
expected: &CreateRoleOptions{
Name: roleName,
Verbs: []string{"*"},
Resources: []ResourceOptions{
{
Resource: "*",
Group: "extensions",
SubResource: "scale",
},
{
Resource: "pods",
},
},
ResourceNames: []string{},
},
expectErr: false,
},
"test-duplicate-resourcenames": {
params: []string{roleName},
params: []string{roleName},
resources: defaultTestResources,
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
Name: roleName,
@ -464,7 +610,8 @@ func TestComplete(t *testing.T) {
expectErr: false,
},
"test-valid-complete-case": {
params: []string{roleName},
params: []string{roleName},
resources: defaultTestResources,
roleOptions: &CreateRoleOptions{
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
Name: roleName,
@ -491,6 +638,9 @@ func TestComplete(t *testing.T) {
}
for name, test := range tests {
cmd := NewCmdCreateRole(tf, genericclioptions.NewTestIOStreamsDiscard())
cmd.Flags().Set("resource", test.resources)
err := test.roleOptions.Complete(tf, cmd, test.params)
if !test.expectErr && err != nil {
t.Errorf("%s: unexpected error: %v", name, err)