@@ -18,63 +18,25 @@ package clusterbinding
1818
1919import (
2020 "context"
21- "fmt"
22- "maps"
23- "reflect"
24- "slices"
2521 "time"
2622
27- corev1 "k8s.io/api/core/v1"
28- rbacv1 "k8s.io/api/rbac/v1"
29- "k8s.io/apimachinery/pkg/api/errors"
30- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3123 utilerrors "k8s.io/apimachinery/pkg/util/errors"
32- "k8s.io/utils/ptr"
3324 "sigs.k8s.io/controller-runtime/pkg/cache"
3425 "sigs.k8s.io/controller-runtime/pkg/client"
3526
36- kuberesources "github.com/kube-bind/kube-bind/backend/kubernetes/resources"
3727 kubebindv1alpha2 "github.com/kube-bind/kube-bind/sdk/apis/kubebind/v1alpha2"
3828 conditionsapi "github.com/kube-bind/kube-bind/sdk/apis/third_party/conditions/apis/conditions/v1alpha1"
3929 "github.com/kube-bind/kube-bind/sdk/apis/third_party/conditions/util/conditions"
4030)
4131
42- type reconciler struct {
43- scope kubebindv1alpha2.InformerScope
44-
45- listServiceExports func (ctx context.Context , cache cache.Cache , ns string ) ([]* kubebindv1alpha2.APIServiceExport , error )
46- getBoundSchema func (ctx context.Context , cache cache.Cache , namespace , name string ) (* kubebindv1alpha2.BoundSchema , error )
47- getClusterRole func (ctx context.Context , cache cache.Cache , name string ) (* rbacv1.ClusterRole , error )
48- createClusterRole func (ctx context.Context , client client.Client , binding * rbacv1.ClusterRole ) error
49- updateClusterRole func (ctx context.Context , client client.Client , binding * rbacv1.ClusterRole ) error
50-
51- getClusterRoleBinding func (ctx context.Context , cache cache.Cache , name string ) (* rbacv1.ClusterRoleBinding , error )
52- createClusterRoleBinding func (ctx context.Context , client client.Client , binding * rbacv1.ClusterRoleBinding ) error
53- updateClusterRoleBinding func (ctx context.Context , client client.Client , binding * rbacv1.ClusterRoleBinding ) error
54- deleteClusterRoleBinding func (ctx context.Context , client client.Client , name string ) error
55-
56- getRoleBinding func (ctx context.Context , cache cache.Cache , ns , name string ) (* rbacv1.RoleBinding , error )
57- createRoleBinding func (ctx context.Context , client client.Client , binding * rbacv1.RoleBinding ) error
58- updateRoleBinding func (ctx context.Context , client client.Client , binding * rbacv1.RoleBinding ) error
59-
60- getNamespace func (ctx context.Context , cache cache.Cache , name string ) (* corev1.Namespace , error )
61- }
32+ type reconciler struct {}
6233
6334func (r * reconciler ) reconcile (ctx context.Context , client client.Client , cache cache.Cache , clusterBinding * kubebindv1alpha2.ClusterBinding ) error {
6435 var errs []error
6536
6637 if err := r .ensureClusterBindingConditions (ctx , clusterBinding ); err != nil {
6738 errs = append (errs , err )
6839 }
69- if err := r .ensureRBACRoleBinding (ctx , client , cache , clusterBinding ); err != nil {
70- errs = append (errs , err )
71- }
72- if err := r .ensureRBACClusterRole (ctx , client , cache , clusterBinding ); err != nil {
73- errs = append (errs , err )
74- }
75- if err := r .ensureRBACClusterRoleBinding (ctx , client , cache , clusterBinding ); err != nil {
76- errs = append (errs , err )
77- }
7840
7941 conditions .SetSummary (clusterBinding )
8042
@@ -120,187 +82,3 @@ func (r *reconciler) ensureClusterBindingConditions(_ context.Context, clusterBi
12082
12183 return nil
12284}
123-
124- func (r * reconciler ) ensureRBACClusterRole (ctx context.Context , client client.Client , cache cache.Cache , clusterBinding * kubebindv1alpha2.ClusterBinding ) error {
125- name := "kube-binder-" + clusterBinding .Namespace
126- role , err := r .getClusterRole (ctx , cache , name )
127- if err != nil && ! errors .IsNotFound (err ) {
128- return fmt .Errorf ("failed to get ClusterRole %s: %w" , name , err )
129- }
130-
131- ns , err := r .getNamespace (ctx , cache , clusterBinding .Namespace )
132- if err != nil {
133- return fmt .Errorf ("failed to get Namespace %s: %w" , clusterBinding .Namespace , err )
134- }
135-
136- exports , err := r .listServiceExports (ctx , cache , clusterBinding .Namespace )
137- if err != nil {
138- return fmt .Errorf ("failed to list APIServiceExports: %w" , err )
139- }
140- expected := & rbacv1.ClusterRole {
141- ObjectMeta : metav1.ObjectMeta {
142- Name : name ,
143- OwnerReferences : []metav1.OwnerReference {
144- {
145- APIVersion : "v1" ,
146- Kind : "Namespace" ,
147- Name : clusterBinding .Namespace ,
148- Controller : ptr .To (true ),
149- UID : ns .UID ,
150- },
151- },
152- },
153- Rules : []rbacv1.PolicyRule {
154- // Always need to be able to get/list/watch the BoundSchemas
155- // to be able to figure out what to bind.
156- {
157- APIGroups : []string {kubebindv1alpha2 .GroupName },
158- Resources : []string {"boundschemas" },
159- Verbs : []string {"get" , "list" , "watch" },
160- },
161- {
162- APIGroups : []string {kubebindv1alpha2 .GroupName },
163- Resources : []string {"boundschemas/status" },
164- Verbs : []string {"get" , "update" , "patch" },
165- },
166- }}
167- for _ , export := range exports {
168- // Collect unique GroupResources and sort for stable rule ordering.
169- grSet := map [string ]kubebindv1alpha2.GroupResource {}
170- for _ , res := range export .Spec .Resources {
171- key := res .ResourceGroupName ()
172- grSet [key ] = kubebindv1alpha2.GroupResource {Group : res .Group , Resource : res .Resource }
173- }
174- keys := slices .Collect (maps .Keys (grSet ))
175- slices .Sort (keys )
176- for _ , k := range keys {
177- // k is already normalized (e.g., "pods.core" for empty group).
178- schema , err := r .getBoundSchema (ctx , cache , clusterBinding .Namespace , k )
179- if err != nil {
180- return fmt .Errorf ("failed to get BoundSchema %q: %w" , k , err )
181- }
182- expected .Rules = append (expected .Rules ,
183- rbacv1.PolicyRule {
184- APIGroups : []string {schema .Spec .Group },
185- Resources : []string {schema .Spec .Names .Plural },
186- Verbs : []string {"get" , "list" , "watch" , "create" , "update" , "patch" , "delete" },
187- },
188- )
189- }
190- }
191-
192- if role == nil {
193- if err := r .createClusterRole (ctx , client , expected ); err != nil {
194- return fmt .Errorf ("failed to create ClusterRole %s: %w" , expected .Name , err )
195- }
196- } else if ! reflect .DeepEqual (role .Rules , expected .Rules ) {
197- role = role .DeepCopy ()
198- role .Rules = expected .Rules
199- if err := r .updateClusterRole (ctx , client , role ); err != nil {
200- return fmt .Errorf ("failed to create ClusterRole %s: %w" , role .Name , err )
201- }
202- }
203-
204- return nil
205- }
206-
207- func (r * reconciler ) ensureRBACClusterRoleBinding (ctx context.Context , client client.Client , cache cache.Cache , clusterBinding * kubebindv1alpha2.ClusterBinding ) error {
208- name := "kube-binder-" + clusterBinding .Namespace
209- binding , err := r .getClusterRoleBinding (ctx , cache , name )
210- if err != nil && ! errors .IsNotFound (err ) {
211- return fmt .Errorf ("failed to get ClusterRoleBinding %s: %w" , name , err )
212- }
213- if r .scope != kubebindv1alpha2 .ClusterScope {
214- if err := r .deleteClusterRoleBinding (ctx , client , name ); err != nil && ! errors .IsNotFound (err ) {
215- return fmt .Errorf ("failed to delete ClusterRoleBinding %s: %w" , name , err )
216- }
217- }
218-
219- ns , err := r .getNamespace (ctx , cache , clusterBinding .Namespace )
220- if err != nil {
221- return fmt .Errorf ("failed to get Namespace %s: %w" , clusterBinding .Namespace , err )
222- }
223-
224- expected := & rbacv1.ClusterRoleBinding {
225- ObjectMeta : metav1.ObjectMeta {
226- Name : name ,
227- OwnerReferences : []metav1.OwnerReference {
228- {
229- APIVersion : "v1" ,
230- Kind : "Namespace" ,
231- Name : clusterBinding .Namespace ,
232- Controller : ptr .To (true ),
233- UID : ns .UID ,
234- },
235- },
236- },
237- Subjects : []rbacv1.Subject {
238- {
239- Kind : "ServiceAccount" ,
240- Namespace : clusterBinding .Namespace ,
241- Name : kuberesources .ServiceAccountName ,
242- },
243- },
244- RoleRef : rbacv1.RoleRef {
245- Kind : "ClusterRole" ,
246- Name : name ,
247- APIGroup : "rbac.authorization.k8s.io" ,
248- },
249- }
250-
251- if binding == nil {
252- if err := r .createClusterRoleBinding (ctx , client , expected ); err != nil {
253- return fmt .Errorf ("failed to create ClusterRoleBinding %s: %w" , expected .Name , err )
254- }
255- } else if ! reflect .DeepEqual (binding .Subjects , expected .Subjects ) {
256- binding = binding .DeepCopy ()
257- binding .Subjects = expected .Subjects
258- // roleRef is immutable
259- if err := r .updateClusterRoleBinding (ctx , client , binding ); err != nil {
260- return fmt .Errorf ("failed to create ClusterRoleBinding %s: %w" , expected .Namespace , err )
261- }
262- }
263-
264- return nil
265- }
266-
267- func (r * reconciler ) ensureRBACRoleBinding (ctx context.Context , client client.Client , cache cache.Cache , clusterBinding * kubebindv1alpha2.ClusterBinding ) error {
268- binding , err := r .getRoleBinding (ctx , cache , clusterBinding .Namespace , "kube-binder" )
269- if err != nil && ! errors .IsNotFound (err ) {
270- return fmt .Errorf ("failed to get RoleBinding \" kube-binder\" : %w" , err )
271- }
272-
273- expected := & rbacv1.RoleBinding {
274- ObjectMeta : metav1.ObjectMeta {
275- Name : kuberesources .ServiceAccountName ,
276- },
277- Subjects : []rbacv1.Subject {
278- {
279- Kind : "ServiceAccount" ,
280- Name : kuberesources .ServiceAccountName ,
281- Namespace : clusterBinding .Namespace ,
282- },
283- },
284- RoleRef : rbacv1.RoleRef {
285- APIGroup : "rbac.authorization.k8s.io" ,
286- Kind : "ClusterRole" ,
287- Name : "kube-binder" ,
288- },
289- }
290-
291- if binding == nil {
292- expected .Namespace = clusterBinding .Namespace
293- if err := r .createRoleBinding (ctx , client , expected ); err != nil {
294- return fmt .Errorf ("failed to create RoleBinding %s: %w" , expected .Name , err )
295- }
296- } else if ! reflect .DeepEqual (binding .Subjects , expected .Subjects ) {
297- binding = binding .DeepCopy ()
298- binding .Subjects = expected .Subjects
299- // roleRef is immutable
300- if err := r .updateRoleBinding (ctx , client , binding ); err != nil {
301- return fmt .Errorf ("failed to create RoleBinding %s: %w" , expected .Namespace , err )
302- }
303- }
304-
305- return nil
306- }
0 commit comments