mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 13:37:30 +00:00
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:
commit
bd0de223da
@ -204,6 +204,11 @@ func (o *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
|
|||||||
}
|
}
|
||||||
resource.Resource = parts[0]
|
resource.Resource = parts[0]
|
||||||
|
|
||||||
|
if resource.Resource == "*" && len(parts) == 1 && len(sections) == 1 {
|
||||||
|
o.Resources = []ResourceOptions{*resource}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
o.Resources = append(o.Resources, *resource)
|
o.Resources = append(o.Resources, *resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,6 +284,9 @@ func (o *CreateRoleOptions) validateResource() error {
|
|||||||
if len(r.Resource) == 0 {
|
if len(r.Resource) == 0 {
|
||||||
return fmt.Errorf("resource must be specified if apiGroup/subresource specified")
|
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}
|
resource := schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}
|
||||||
groupVersionResource, err := o.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group})
|
groupVersionResource, err := o.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group})
|
||||||
|
@ -360,17 +360,18 @@ func TestComplete(t *testing.T) {
|
|||||||
tf.Client = &fake.RESTClient{}
|
tf.Client = &fake.RESTClient{}
|
||||||
tf.ClientConfigVal = defaultClientConfig()
|
tf.ClientConfigVal = defaultClientConfig()
|
||||||
|
|
||||||
cmd := NewCmdCreateRole(tf, genericclioptions.NewTestIOStreamsDiscard())
|
defaultTestResources := "pods,deployments.extensions"
|
||||||
cmd.Flags().Set("resource", "pods,deployments.extensions")
|
|
||||||
|
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
params []string
|
params []string
|
||||||
|
resources string
|
||||||
roleOptions *CreateRoleOptions
|
roleOptions *CreateRoleOptions
|
||||||
expected *CreateRoleOptions
|
expected *CreateRoleOptions
|
||||||
expectErr bool
|
expectErr bool
|
||||||
}{
|
}{
|
||||||
"test-missing-name": {
|
"test-missing-name": {
|
||||||
params: []string{},
|
params: []string{},
|
||||||
|
resources: defaultTestResources,
|
||||||
roleOptions: &CreateRoleOptions{
|
roleOptions: &CreateRoleOptions{
|
||||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
||||||
},
|
},
|
||||||
@ -378,6 +379,7 @@ func TestComplete(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"test-duplicate-verbs": {
|
"test-duplicate-verbs": {
|
||||||
params: []string{roleName},
|
params: []string{roleName},
|
||||||
|
resources: defaultTestResources,
|
||||||
roleOptions: &CreateRoleOptions{
|
roleOptions: &CreateRoleOptions{
|
||||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
||||||
Name: roleName,
|
Name: roleName,
|
||||||
@ -411,6 +413,7 @@ func TestComplete(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"test-verball": {
|
"test-verball": {
|
||||||
params: []string{roleName},
|
params: []string{roleName},
|
||||||
|
resources: defaultTestResources,
|
||||||
roleOptions: &CreateRoleOptions{
|
roleOptions: &CreateRoleOptions{
|
||||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
||||||
Name: roleName,
|
Name: roleName,
|
||||||
@ -438,8 +441,151 @@ func TestComplete(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectErr: false,
|
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": {
|
"test-duplicate-resourcenames": {
|
||||||
params: []string{roleName},
|
params: []string{roleName},
|
||||||
|
resources: defaultTestResources,
|
||||||
roleOptions: &CreateRoleOptions{
|
roleOptions: &CreateRoleOptions{
|
||||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
||||||
Name: roleName,
|
Name: roleName,
|
||||||
@ -465,6 +611,7 @@ func TestComplete(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"test-valid-complete-case": {
|
"test-valid-complete-case": {
|
||||||
params: []string{roleName},
|
params: []string{roleName},
|
||||||
|
resources: defaultTestResources,
|
||||||
roleOptions: &CreateRoleOptions{
|
roleOptions: &CreateRoleOptions{
|
||||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
||||||
Name: roleName,
|
Name: roleName,
|
||||||
@ -491,6 +638,9 @@ func TestComplete(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
|
cmd := NewCmdCreateRole(tf, genericclioptions.NewTestIOStreamsDiscard())
|
||||||
|
cmd.Flags().Set("resource", test.resources)
|
||||||
|
|
||||||
err := test.roleOptions.Complete(tf, cmd, test.params)
|
err := test.roleOptions.Complete(tf, cmd, test.params)
|
||||||
if !test.expectErr && err != nil {
|
if !test.expectErr && err != nil {
|
||||||
t.Errorf("%s: unexpected error: %v", name, err)
|
t.Errorf("%s: unexpected error: %v", name, err)
|
||||||
|
Loading…
Reference in New Issue
Block a user