k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/apis/rbac/v1/helpers.go (about) 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 v1 18 19 import ( 20 "fmt" 21 22 rbacv1 "k8s.io/api/rbac/v1" 23 24 "sort" 25 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 ) 28 29 // +k8s:deepcopy-gen=false 30 31 // PolicyRuleBuilder let's us attach methods. A no-no for API types. 32 // We use it to construct rules in code. It's more compact than trying to write them 33 // out in a literal and allows us to perform some basic checking during construction 34 type PolicyRuleBuilder struct { 35 PolicyRule rbacv1.PolicyRule `protobuf:"bytes,1,opt,name=policyRule"` 36 } 37 38 func NewRule(verbs ...string) *PolicyRuleBuilder { 39 return &PolicyRuleBuilder{ 40 PolicyRule: rbacv1.PolicyRule{Verbs: verbs}, 41 } 42 } 43 44 func (r *PolicyRuleBuilder) Groups(groups ...string) *PolicyRuleBuilder { 45 r.PolicyRule.APIGroups = append(r.PolicyRule.APIGroups, groups...) 46 return r 47 } 48 49 func (r *PolicyRuleBuilder) Resources(resources ...string) *PolicyRuleBuilder { 50 r.PolicyRule.Resources = append(r.PolicyRule.Resources, resources...) 51 return r 52 } 53 54 func (r *PolicyRuleBuilder) Names(names ...string) *PolicyRuleBuilder { 55 r.PolicyRule.ResourceNames = append(r.PolicyRule.ResourceNames, names...) 56 return r 57 } 58 59 func (r *PolicyRuleBuilder) URLs(urls ...string) *PolicyRuleBuilder { 60 r.PolicyRule.NonResourceURLs = append(r.PolicyRule.NonResourceURLs, urls...) 61 return r 62 } 63 64 func (r *PolicyRuleBuilder) RuleOrDie() rbacv1.PolicyRule { 65 ret, err := r.Rule() 66 if err != nil { 67 panic(err) 68 } 69 return ret 70 } 71 72 func (r *PolicyRuleBuilder) Rule() (rbacv1.PolicyRule, error) { 73 if len(r.PolicyRule.Verbs) == 0 { 74 return rbacv1.PolicyRule{}, fmt.Errorf("verbs are required: %#v", r.PolicyRule) 75 } 76 77 switch { 78 case len(r.PolicyRule.NonResourceURLs) > 0: 79 if len(r.PolicyRule.APIGroups) != 0 || len(r.PolicyRule.Resources) != 0 || len(r.PolicyRule.ResourceNames) != 0 { 80 return rbacv1.PolicyRule{}, fmt.Errorf("non-resource rule may not have apiGroups, resources, or resourceNames: %#v", r.PolicyRule) 81 } 82 case len(r.PolicyRule.Resources) > 0: 83 if len(r.PolicyRule.NonResourceURLs) != 0 { 84 return rbacv1.PolicyRule{}, fmt.Errorf("resource rule may not have nonResourceURLs: %#v", r.PolicyRule) 85 } 86 if len(r.PolicyRule.APIGroups) == 0 { 87 // this a common bug 88 return rbacv1.PolicyRule{}, fmt.Errorf("resource rule must have apiGroups: %#v", r.PolicyRule) 89 } 90 default: 91 return rbacv1.PolicyRule{}, fmt.Errorf("a rule must have either nonResourceURLs or resources: %#v", r.PolicyRule) 92 } 93 94 sort.Strings(r.PolicyRule.Resources) 95 sort.Strings(r.PolicyRule.ResourceNames) 96 sort.Strings(r.PolicyRule.APIGroups) 97 sort.Strings(r.PolicyRule.NonResourceURLs) 98 sort.Strings(r.PolicyRule.Verbs) 99 return r.PolicyRule, nil 100 } 101 102 // +k8s:deepcopy-gen=false 103 104 // ClusterRoleBindingBuilder let's us attach methods. A no-no for API types. 105 // We use it to construct bindings in code. It's more compact than trying to write them 106 // out in a literal. 107 type ClusterRoleBindingBuilder struct { 108 ClusterRoleBinding rbacv1.ClusterRoleBinding `protobuf:"bytes,1,opt,name=clusterRoleBinding"` 109 } 110 111 func NewClusterBinding(clusterRoleName string) *ClusterRoleBindingBuilder { 112 return &ClusterRoleBindingBuilder{ 113 ClusterRoleBinding: rbacv1.ClusterRoleBinding{ 114 ObjectMeta: metav1.ObjectMeta{Name: clusterRoleName}, 115 RoleRef: rbacv1.RoleRef{ 116 APIGroup: GroupName, 117 Kind: "ClusterRole", 118 Name: clusterRoleName, 119 }, 120 }, 121 } 122 } 123 124 func (r *ClusterRoleBindingBuilder) Groups(groups ...string) *ClusterRoleBindingBuilder { 125 for _, group := range groups { 126 r.ClusterRoleBinding.Subjects = append(r.ClusterRoleBinding.Subjects, rbacv1.Subject{APIGroup: rbacv1.GroupName, Kind: rbacv1.GroupKind, Name: group}) 127 } 128 return r 129 } 130 131 func (r *ClusterRoleBindingBuilder) Users(users ...string) *ClusterRoleBindingBuilder { 132 for _, user := range users { 133 r.ClusterRoleBinding.Subjects = append(r.ClusterRoleBinding.Subjects, rbacv1.Subject{APIGroup: rbacv1.GroupName, Kind: rbacv1.UserKind, Name: user}) 134 } 135 return r 136 } 137 138 func (r *ClusterRoleBindingBuilder) SAs(namespace string, serviceAccountNames ...string) *ClusterRoleBindingBuilder { 139 for _, saName := range serviceAccountNames { 140 r.ClusterRoleBinding.Subjects = append(r.ClusterRoleBinding.Subjects, rbacv1.Subject{Kind: rbacv1.ServiceAccountKind, Namespace: namespace, Name: saName}) 141 } 142 return r 143 } 144 145 func (r *ClusterRoleBindingBuilder) BindingOrDie() rbacv1.ClusterRoleBinding { 146 ret, err := r.Binding() 147 if err != nil { 148 panic(err) 149 } 150 return ret 151 } 152 153 func (r *ClusterRoleBindingBuilder) Binding() (rbacv1.ClusterRoleBinding, error) { 154 if len(r.ClusterRoleBinding.Subjects) == 0 { 155 return rbacv1.ClusterRoleBinding{}, fmt.Errorf("subjects are required: %#v", r.ClusterRoleBinding) 156 } 157 158 return r.ClusterRoleBinding, nil 159 } 160 161 // +k8s:deepcopy-gen=false 162 163 // RoleBindingBuilder let's us attach methods. It is similar to 164 // ClusterRoleBindingBuilder above. 165 type RoleBindingBuilder struct { 166 RoleBinding rbacv1.RoleBinding 167 } 168 169 // NewRoleBinding creates a RoleBinding builder that can be used 170 // to define the subjects of a role binding. At least one of 171 // the `Groups`, `Users` or `SAs` method must be called before 172 // calling the `Binding*` methods. 173 func NewRoleBinding(roleName, namespace string) *RoleBindingBuilder { 174 return &RoleBindingBuilder{ 175 RoleBinding: rbacv1.RoleBinding{ 176 ObjectMeta: metav1.ObjectMeta{ 177 Name: roleName, 178 Namespace: namespace, 179 }, 180 RoleRef: rbacv1.RoleRef{ 181 APIGroup: GroupName, 182 Kind: "Role", 183 Name: roleName, 184 }, 185 }, 186 } 187 } 188 189 // Groups adds the specified groups as the subjects of the RoleBinding. 190 func (r *RoleBindingBuilder) Groups(groups ...string) *RoleBindingBuilder { 191 for _, group := range groups { 192 r.RoleBinding.Subjects = append(r.RoleBinding.Subjects, rbacv1.Subject{Kind: rbacv1.GroupKind, APIGroup: GroupName, Name: group}) 193 } 194 return r 195 } 196 197 // Users adds the specified users as the subjects of the RoleBinding. 198 func (r *RoleBindingBuilder) Users(users ...string) *RoleBindingBuilder { 199 for _, user := range users { 200 r.RoleBinding.Subjects = append(r.RoleBinding.Subjects, rbacv1.Subject{Kind: rbacv1.UserKind, APIGroup: GroupName, Name: user}) 201 } 202 return r 203 } 204 205 // SAs adds the specified service accounts as the subjects of the 206 // RoleBinding. 207 func (r *RoleBindingBuilder) SAs(namespace string, serviceAccountNames ...string) *RoleBindingBuilder { 208 for _, saName := range serviceAccountNames { 209 r.RoleBinding.Subjects = append(r.RoleBinding.Subjects, rbacv1.Subject{Kind: rbacv1.ServiceAccountKind, Namespace: namespace, Name: saName}) 210 } 211 return r 212 } 213 214 // BindingOrDie calls the binding method and panics if there is an error. 215 func (r *RoleBindingBuilder) BindingOrDie() rbacv1.RoleBinding { 216 ret, err := r.Binding() 217 if err != nil { 218 panic(err) 219 } 220 return ret 221 } 222 223 // Binding builds and returns the RoleBinding API object from the builder 224 // object. 225 func (r *RoleBindingBuilder) Binding() (rbacv1.RoleBinding, error) { 226 if len(r.RoleBinding.Subjects) == 0 { 227 return rbacv1.RoleBinding{}, fmt.Errorf("subjects are required: %#v", r.RoleBinding) 228 } 229 230 return r.RoleBinding, nil 231 }