2017-02-15 07:38:13 +00:00
/ *
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 .
* /
2018-04-10 14:21:50 +00:00
package create
2017-02-15 07:38:13 +00:00
import (
2017-05-15 06:04:29 +00:00
"fmt"
2017-06-07 06:04:17 +00:00
"strings"
2017-02-15 07:38:13 +00:00
"github.com/spf13/cobra"
2017-10-28 01:31:42 +00:00
rbacv1 "k8s.io/api/rbac/v1"
2018-05-14 16:36:12 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2018-05-15 08:55:44 +00:00
utilflag "k8s.io/apiserver/pkg/util/flag"
2017-02-15 07:38:13 +00:00
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
2018-04-19 21:43:28 +00:00
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
2017-07-07 04:04:11 +00:00
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
2017-02-15 07:38:13 +00:00
)
var (
2017-03-15 03:49:10 +00:00
clusterRoleLong = templates . LongDesc ( i18n . T ( `
Create a ClusterRole . ` ) )
2017-02-15 07:38:13 +00:00
2017-03-15 03:49:10 +00:00
clusterRoleExample = templates . Examples ( i18n . T ( `
2017-02-15 07:38:13 +00:00
# Create a ClusterRole named "pod-reader" that allows user to perform "get" , "watch" and "list" on pods
kubectl create clusterrole pod - reader -- verb = get , list , watch -- resource = pods
# Create a ClusterRole named "pod-reader" with ResourceName specified
2018-03-12 08:29:18 +00:00
kubectl create clusterrole pod - reader -- verb = get -- resource = pods -- resource - name = readablepod -- resource - name = anotherpod
2017-02-14 06:53:42 +00:00
# Create a ClusterRole named "foo" with API Group specified
kubectl create clusterrole foo -- verb = get , list , watch -- resource = rs . extensions
# Create a ClusterRole named "foo" with SubResource specified
2017-05-15 06:04:29 +00:00
kubectl create clusterrole foo -- verb = get , list , watch -- resource = pods , pods / status
# Create a ClusterRole name "foo" with NonResourceURL specified
2018-05-15 08:55:44 +00:00
kubectl create clusterrole "foo" -- verb = get -- non - resource - url = / logs / *
# Create a ClusterRole name "monitoring" with AggregationRule specified
kubectl create clusterrole monitoring -- aggregation - rule = "rbac.example.com/aggregate-to-monitoring=true" ` ) )
2017-05-15 06:04:29 +00:00
// Valid nonResource verb list for validation.
validNonResourceVerbs = [ ] string { "*" , "get" , "post" , "put" , "delete" , "patch" , "head" , "options" }
2017-02-15 07:38:13 +00:00
)
type CreateClusterRoleOptions struct {
* CreateRoleOptions
2017-05-15 06:04:29 +00:00
NonResourceURLs [ ] string
2018-05-15 08:55:44 +00:00
AggregationRule map [ string ] string
2017-02-15 07:38:13 +00:00
}
// ClusterRole is a command to ease creating ClusterRoles.
2018-04-19 21:43:28 +00:00
func NewCmdCreateClusterRole ( f cmdutil . Factory , ioStreams genericclioptions . IOStreams ) * cobra . Command {
2017-02-15 07:38:13 +00:00
c := & CreateClusterRoleOptions {
2018-04-19 21:43:28 +00:00
CreateRoleOptions : NewCreateRoleOptions ( ioStreams ) ,
2018-05-15 08:55:44 +00:00
AggregationRule : map [ string ] string { } ,
2017-02-15 07:38:13 +00:00
}
cmd := & cobra . Command {
2017-10-11 06:26:02 +00:00
Use : "clusterrole NAME --verb=verb --resource=resource.group [--resource-name=resourcename] [--dry-run]" ,
DisableFlagsInUseLine : true ,
2017-02-15 07:38:13 +00:00
Short : clusterRoleLong ,
Long : clusterRoleLong ,
Example : clusterRoleExample ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
cmdutil . CheckErr ( c . Complete ( f , cmd , args ) )
cmdutil . CheckErr ( c . Validate ( ) )
cmdutil . CheckErr ( c . RunCreateRole ( ) )
} ,
}
2018-04-05 22:39:17 +00:00
c . PrintFlags . AddFlags ( cmd )
2017-02-15 07:38:13 +00:00
cmdutil . AddApplyAnnotationFlags ( cmd )
cmdutil . AddValidateFlags ( cmd )
cmdutil . AddDryRunFlag ( cmd )
2018-02-24 09:01:30 +00:00
cmd . Flags ( ) . StringSliceVar ( & c . Verbs , "verb" , c . Verbs , "Verb that applies to the resources contained in the rule" )
cmd . Flags ( ) . StringSliceVar ( & c . NonResourceURLs , "non-resource-url" , c . NonResourceURLs , "A partial url that user should have access to." )
2017-08-02 15:41:19 +00:00
cmd . Flags ( ) . StringSlice ( "resource" , [ ] string { } , "Resource that the rule applies to" )
2018-02-24 09:01:30 +00:00
cmd . Flags ( ) . StringArrayVar ( & c . ResourceNames , "resource-name" , c . ResourceNames , "Resource in the white list that the rule applies to, repeat this flag for multiple items" )
2018-05-15 08:55:44 +00:00
cmd . Flags ( ) . Var ( utilflag . NewMapStringString ( & c . AggregationRule ) , "aggregation-rule" , "An aggregation label selector for combining ClusterRoles." )
2017-02-15 07:38:13 +00:00
return cmd
}
2017-05-15 06:04:29 +00:00
func ( c * CreateClusterRoleOptions ) Complete ( f cmdutil . Factory , cmd * cobra . Command , args [ ] string ) error {
// Remove duplicate nonResourceURLs
nonResourceURLs := [ ] string { }
for _ , n := range c . NonResourceURLs {
if ! arrayContains ( nonResourceURLs , n ) {
nonResourceURLs = append ( nonResourceURLs , n )
}
}
c . NonResourceURLs = nonResourceURLs
return c . CreateRoleOptions . Complete ( f , cmd , args )
}
func ( c * CreateClusterRoleOptions ) Validate ( ) error {
if c . Name == "" {
return fmt . Errorf ( "name must be specified" )
}
2018-05-15 08:55:44 +00:00
if len ( c . AggregationRule ) > 0 {
if len ( c . NonResourceURLs ) > 0 || len ( c . Verbs ) > 0 || len ( c . Resources ) > 0 || len ( c . ResourceNames ) > 0 {
return fmt . Errorf ( "aggregation rule must be specified without nonResourceURLs, verbs, resources or resourceNames" )
}
return nil
}
2017-05-15 06:04:29 +00:00
// validate verbs.
if len ( c . Verbs ) == 0 {
return fmt . Errorf ( "at least one verb must be specified" )
}
if len ( c . Resources ) == 0 && len ( c . NonResourceURLs ) == 0 {
return fmt . Errorf ( "one of resource or nonResourceURL must be specified" )
}
// validate resources
if len ( c . Resources ) > 0 {
for _ , v := range c . Verbs {
if ! arrayContains ( validResourceVerbs , v ) {
return fmt . Errorf ( "invalid verb: '%s'" , v )
}
}
if err := c . validateResource ( ) ; err != nil {
return err
}
}
//validate non-resource-url
if len ( c . NonResourceURLs ) > 0 {
for _ , v := range c . Verbs {
if ! arrayContains ( validNonResourceVerbs , v ) {
return fmt . Errorf ( "invalid verb: '%s' for nonResourceURL" , v )
}
}
2017-06-07 06:04:17 +00:00
for _ , nonResourceURL := range c . NonResourceURLs {
if nonResourceURL == "*" {
continue
}
if nonResourceURL == "" || ! strings . HasPrefix ( nonResourceURL , "/" ) {
return fmt . Errorf ( "nonResourceURL should start with /" )
}
if strings . ContainsRune ( nonResourceURL [ : len ( nonResourceURL ) - 1 ] , '*' ) {
return fmt . Errorf ( "nonResourceURL only supports wildcard matches when '*' is at the end" )
}
}
2017-05-15 06:04:29 +00:00
}
return nil
}
2017-02-15 07:38:13 +00:00
func ( c * CreateClusterRoleOptions ) RunCreateRole ( ) error {
2018-05-14 16:36:12 +00:00
clusterRole := & rbacv1 . ClusterRole {
// this is ok because we know exactly how we want to be serialized
TypeMeta : metav1 . TypeMeta { APIVersion : rbacv1 . SchemeGroupVersion . String ( ) , Kind : "ClusterRole" } ,
}
2017-02-15 07:38:13 +00:00
clusterRole . Name = c . Name
2018-05-15 08:55:44 +00:00
var err error
if len ( c . AggregationRule ) == 0 {
rules , err := generateResourcePolicyRules ( c . Mapper , c . Verbs , c . Resources , c . ResourceNames , c . NonResourceURLs )
if err != nil {
return err
}
clusterRole . Rules = rules
} else {
clusterRole . AggregationRule = & rbacv1 . AggregationRule {
ClusterRoleSelectors : [ ] metav1 . LabelSelector {
{
MatchLabels : c . AggregationRule ,
} ,
} ,
}
2017-02-15 07:38:13 +00:00
}
// Create ClusterRole.
if ! c . DryRun {
2018-03-21 07:34:50 +00:00
clusterRole , err = c . Client . ClusterRoles ( ) . Create ( clusterRole )
2017-02-15 07:38:13 +00:00
if err != nil {
return err
}
}
2018-04-05 22:39:17 +00:00
return c . PrintObj ( clusterRole )
2017-02-15 07:38:13 +00:00
}