Skip to content

Commit 71082b5

Browse files
committed
Refactor backend to be less schema bound
1 parent 878858c commit 71082b5

69 files changed

Lines changed: 1162 additions & 2939 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/controllers/clusterbinding/clusterbinding_controller.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,11 @@ func NewClusterBindingReconciler(
7777
}
7878
return exports, nil
7979
},
80-
getAPIResourceSchema: func(ctx context.Context, cache cache.Cache, name string) (*kubebindv1alpha2.APIResourceSchema, error) {
81-
result := &kubebindv1alpha2.APIResourceSchema{}
82-
err := cache.Get(ctx, types.NamespacedName{Name: name}, result)
80+
getBoundSchema: func(ctx context.Context, cache cache.Cache, namespace, name string) (*kubebindv1alpha2.BoundSchema, error) {
81+
result := &kubebindv1alpha2.BoundSchema{}
82+
err := cache.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, result)
8383
if err != nil {
84-
return nil, fmt.Errorf("failed to get APIResourceSchema %q: %w", name, err)
84+
return nil, fmt.Errorf("failed to get BoundSchema %q: %w", name, err)
8585
}
8686
return result, nil
8787
},

backend/controllers/clusterbinding/clusterbinding_reconcile.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ import (
4040
type reconciler struct {
4141
scope kubebindv1alpha2.InformerScope
4242

43-
listServiceExports func(ctx context.Context, cache cache.Cache, ns string) ([]*kubebindv1alpha2.APIServiceExport, error)
44-
getAPIResourceSchema func(ctx context.Context, cache cache.Cache, name string) (*kubebindv1alpha2.APIResourceSchema, error)
45-
getClusterRole func(ctx context.Context, cache cache.Cache, name string) (*rbacv1.ClusterRole, error)
46-
createClusterRole func(ctx context.Context, client client.Client, binding *rbacv1.ClusterRole) error
47-
updateClusterRole func(ctx context.Context, client client.Client, binding *rbacv1.ClusterRole) error
43+
listServiceExports func(ctx context.Context, cache cache.Cache, ns string) ([]*kubebindv1alpha2.APIServiceExport, error)
44+
getBoundSchema func(ctx context.Context, cache cache.Cache, namespace, name string) (*kubebindv1alpha2.BoundSchema, error)
45+
getClusterRole func(ctx context.Context, cache cache.Cache, name string) (*rbacv1.ClusterRole, error)
46+
createClusterRole func(ctx context.Context, client client.Client, binding *rbacv1.ClusterRole) error
47+
updateClusterRole func(ctx context.Context, client client.Client, binding *rbacv1.ClusterRole) error
4848

4949
getClusterRoleBinding func(ctx context.Context, cache cache.Cache, name string) (*rbacv1.ClusterRoleBinding, error)
5050
createClusterRoleBinding func(ctx context.Context, client client.Client, binding *rbacv1.ClusterRoleBinding) error
@@ -151,21 +151,22 @@ func (r *reconciler) ensureRBACClusterRole(ctx context.Context, client client.Cl
151151
}
152152
for _, export := range exports {
153153
for _, res := range export.Spec.Resources {
154-
schema, err := r.getAPIResourceSchema(ctx, cache, res.Name)
154+
name := res.Resource + "." + res.Group
155+
schema, err := r.getBoundSchema(ctx, cache, clusterBinding.Namespace, name)
155156
if err != nil {
156-
return fmt.Errorf("failed to get APIResourceSchema %w", err)
157+
return fmt.Errorf("failed to get BoundSchema %w", err)
157158
}
158159

159160
expected.Rules = append(expected.Rules,
160161
rbacv1.PolicyRule{
161-
APIGroups: []string{schema.Spec.APIResourceSchemaCRDSpec.Group},
162-
Resources: []string{schema.Spec.APIResourceSchemaCRDSpec.Names.Plural},
162+
APIGroups: []string{schema.Spec.Group},
163+
Resources: []string{schema.Spec.Names.Plural},
163164
Verbs: []string{"get", "list", "watch", "update", "patch", "delete", "create"},
164165
},
165166
rbacv1.PolicyRule{
166167
APIGroups: []string{kubebindv1alpha2.GroupName},
167-
Resources: []string{"apiresourceschemas"},
168-
Verbs: []string{"get", "list", "watch"},
168+
Resources: []string{"boundschemas"},
169+
Verbs: []string{"get", "list", "watch", "update", "patch"},
169170
},
170171
)
171172
}

backend/controllers/serviceexport/serviceexport_controller.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,17 @@ func NewAPIServiceExportReconciler(
5858
mgr mcmanager.Manager,
5959
opts controller.TypedOptions[mcreconcile.Request],
6060
) (*APIServiceExportReconciler, error) {
61-
if err := mgr.GetFieldIndexer().IndexField(ctx, &kubebindv1alpha2.APIServiceExport{}, indexers.ServiceExportByAPIResourceSchema,
62-
indexers.IndexServiceExportByAPIResourceSchema); err != nil {
63-
return nil, fmt.Errorf("failed to setup ServiceExportByAPIResourceSchema indexer: %w", err)
61+
if err := mgr.GetFieldIndexer().IndexField(ctx, &kubebindv1alpha2.APIServiceExport{}, indexers.ServiceExportByBoundSchema,
62+
indexers.IndexServiceExportByBoundSchema); err != nil {
63+
return nil, fmt.Errorf("failed to setup ServiceExportByBoundSchema indexer: %w", err)
6464
}
6565

6666
r := &APIServiceExportReconciler{
6767
manager: mgr,
6868
opts: opts,
6969
reconciler: reconciler{
70-
getAPIResourceSchema: func(ctx context.Context, cache cache.Cache, name string) (*kubebindv1alpha2.APIResourceSchema, error) {
71-
var schema kubebindv1alpha2.APIResourceSchema
70+
getBoundSchema: func(ctx context.Context, cache cache.Cache, name string) (*kubebindv1alpha2.BoundSchema, error) {
71+
var schema kubebindv1alpha2.BoundSchema
7272
key := types.NamespacedName{Name: name}
7373
if err := cache.Get(ctx, key, &schema); err != nil {
7474
return nil, err
@@ -141,14 +141,14 @@ func (r *APIServiceExportReconciler) Reconcile(ctx context.Context, req mcreconc
141141
}
142142

143143
// getAPIResourceSchemaMapper returns a mapper function that uses the manager to find related APIServiceExports.
144-
func getAPIResourceSchemaMapper(clusterName string, cl cluster.Cluster) handler.TypedEventHandler[client.Object, mcreconcile.Request] {
144+
func getBoundSchemaMapper(clusterName string, cl cluster.Cluster) handler.TypedEventHandler[client.Object, mcreconcile.Request] {
145145
return handler.TypedEnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []mcreconcile.Request {
146-
apiResourceSchema := obj.(*kubebindv1alpha2.APIResourceSchema)
147-
apiResourceSchemaKey := apiResourceSchema.Name
146+
boundSchema := obj.(*kubebindv1alpha2.BoundSchema)
147+
boundSchemaKey := boundSchema.Name
148148
c := cl.GetClient()
149149

150150
var exports kubebindv1alpha2.APIServiceExportList
151-
if err := c.List(ctx, &exports, client.MatchingFields{indexers.ServiceExportByAPIResourceSchema: apiResourceSchemaKey}); err != nil {
151+
if err := c.List(ctx, &exports, client.MatchingFields{indexers.ServiceExportByBoundSchema: boundSchemaKey}); err != nil {
152152
return []mcreconcile.Request{}
153153
}
154154

@@ -171,8 +171,8 @@ func (r *APIServiceExportReconciler) SetupWithManager(mgr mcmanager.Manager) err
171171
return mcbuilder.ControllerManagedBy(mgr).
172172
For(&kubebindv1alpha2.APIServiceExport{}).
173173
Watches(
174-
&kubebindv1alpha2.APIResourceSchema{},
175-
getAPIResourceSchemaMapper,
174+
&kubebindv1alpha2.BoundSchema{},
175+
getBoundSchemaMapper,
176176
).
177177
WithOptions(r.opts).
178178
Named(controllerName).

backend/controllers/serviceexport/serviceexport_reconcile.go

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ package serviceexport
1818

1919
import (
2020
"context"
21-
"crypto/sha256"
22-
"encoding/hex"
23-
"slices"
24-
"sort"
2521

2622
"k8s.io/apimachinery/pkg/api/errors"
2723
utilerrors "k8s.io/apimachinery/pkg/util/errors"
@@ -30,13 +26,13 @@ import (
3026
"sigs.k8s.io/controller-runtime/pkg/client"
3127

3228
kubebindv1alpha2 "github.com/kube-bind/kube-bind/sdk/apis/kubebind/v1alpha2"
33-
kubebindhelpers "github.com/kube-bind/kube-bind/sdk/apis/kubebind/v1alpha2/helpers"
29+
"github.com/kube-bind/kube-bind/sdk/apis/kubebind/v1alpha2/helpers"
3430
"github.com/kube-bind/kube-bind/sdk/apis/third_party/conditions/util/conditions"
3531
)
3632

3733
type reconciler struct {
38-
getAPIResourceSchema func(ctx context.Context, cache cache.Cache, name string) (*kubebindv1alpha2.APIResourceSchema, error)
39-
deleteServiceExport func(ctx context.Context, client client.Client, namespace, name string) error
34+
getBoundSchema func(ctx context.Context, cache cache.Cache, name string) (*kubebindv1alpha2.BoundSchema, error)
35+
deleteServiceExport func(ctx context.Context, client client.Client, namespace, name string) error
4036
}
4137

4238
func (r *reconciler) reconcile(ctx context.Context, cache cache.Cache, export *kubebindv1alpha2.APIServiceExport) error {
@@ -56,49 +52,34 @@ func (r *reconciler) reconcile(ctx context.Context, cache cache.Cache, export *k
5652

5753
func (r *reconciler) ensureSchema(ctx context.Context, cache cache.Cache, export *kubebindv1alpha2.APIServiceExport) (specChanged bool, err error) {
5854
logger := klog.FromContext(ctx)
59-
leafHashes := make([]string, 0, len(export.Spec.Resources))
60-
for _, resourceRef := range export.Spec.Resources {
61-
if resourceRef.Type != "APIResourceSchema" {
62-
logger.V(1).Info("Skipping unsupported resource type", "type", resourceRef.Type)
63-
continue
64-
}
55+
schemas := make([]*kubebindv1alpha2.BoundSchema, 0, len(export.Spec.Resources))
6556

66-
schema, err := r.getAPIResourceSchema(ctx, cache, resourceRef.Name)
57+
for _, res := range export.Spec.Resources {
58+
name := res.Resource + "." + res.Group
59+
schema, err := r.getBoundSchema(ctx, cache, name)
6760
if err != nil {
6861
if errors.IsNotFound(err) {
6962
continue
7063
}
7164
return false, err
7265
}
7366

74-
hash := kubebindhelpers.APIResourceSchemaCRDSpecHash(&schema.Spec.APIResourceSchemaCRDSpec)
75-
leafHashes = append(leafHashes, hash)
67+
schemas = append(schemas, schema)
7668
}
7769

78-
hashOfHashes := hashOfHashes(leafHashes)
70+
hash := helpers.BoundSchemasSpecHash(schemas)
7971

80-
if export.Annotations[kubebindv1alpha2.SourceSpecHashAnnotationKey] != hashOfHashes {
72+
if export.Annotations[kubebindv1alpha2.SourceSpecHashAnnotationKey] != hash {
8173
// both exist, update APIServiceExport
82-
logger.V(1).Info("Updating APIServiceExport. Hash mismatch", "hash", hashOfHashes, "expected", export.Annotations[kubebindv1alpha2.SourceSpecHashAnnotationKey])
74+
logger.V(1).Info("Updating APIServiceExport. Hash mismatch", "hash", hash, "expected", export.Annotations[kubebindv1alpha2.SourceSpecHashAnnotationKey])
8375
if export.Annotations == nil {
8476
export.Annotations = map[string]string{}
8577
}
86-
export.Annotations[kubebindv1alpha2.SourceSpecHashAnnotationKey] = hashOfHashes
78+
export.Annotations[kubebindv1alpha2.SourceSpecHashAnnotationKey] = hash
8779
return true, nil
8880
}
8981

9082
conditions.MarkTrue(export, kubebindv1alpha2.APIServiceExportConditionProviderInSync)
9183

9284
return false, nil
9385
}
94-
95-
func hashOfHashes(hashes []string) string {
96-
hexHashes := slices.Clone(hashes)
97-
sort.Strings(hexHashes)
98-
99-
rootHasher := sha256.New()
100-
for _, h := range hexHashes {
101-
rootHasher.Write([]byte(h))
102-
}
103-
return hex.EncodeToString(rootHasher.Sum(nil))
104-
}

backend/controllers/serviceexportrequest/serviceexportrequest_controller.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ func NewAPIServiceExportRequestReconciler(
6161
opts controller.TypedOptions[mcreconcile.Request],
6262
scope kubebindv1alpha2.InformerScope,
6363
isolation kubebindv1alpha2.Isolation,
64+
schemaSource string,
6465
) (*APIServiceExportRequestReconciler, error) {
6566
// Set up field indexers for APIServiceExportRequests
6667
if err := mgr.GetFieldIndexer().IndexField(ctx, &kubebindv1alpha2.APIServiceExportRequest{}, indexers.ServiceExportRequestByServiceExport,
@@ -81,9 +82,10 @@ func NewAPIServiceExportRequestReconciler(
8182
reconciler: reconciler{
8283
informerScope: scope,
8384
clusterScopedIsolation: isolation,
84-
getAPIResourceSchema: func(ctx context.Context, cache cache.Cache, name string) (*kubebindv1alpha2.APIResourceSchema, error) {
85-
var schema kubebindv1alpha2.APIResourceSchema
86-
key := types.NamespacedName{Name: name}
85+
schemaSource: schemaSource,
86+
getBoundSchema: func(ctx context.Context, cache cache.Cache, namespace, name string) (*kubebindv1alpha2.BoundSchema, error) {
87+
var schema kubebindv1alpha2.BoundSchema
88+
key := types.NamespacedName{Namespace: namespace, Name: name}
8789
if err := cache.Get(ctx, key, &schema); err != nil {
8890
return nil, err
8991
}
@@ -100,11 +102,8 @@ func NewAPIServiceExportRequestReconciler(
100102
createServiceExport: func(ctx context.Context, cl client.Client, resource *kubebindv1alpha2.APIServiceExport) error {
101103
return cl.Create(ctx, resource)
102104
},
103-
createAPIResourceSchema: func(ctx context.Context, cl client.Client, schema *kubebindv1alpha2.APIResourceSchema) (*kubebindv1alpha2.APIResourceSchema, error) {
104-
if err := cl.Create(ctx, schema); err != nil {
105-
return nil, err
106-
}
107-
return schema, nil
105+
createBoundSchema: func(ctx context.Context, cl client.Client, schema *kubebindv1alpha2.BoundSchema) error {
106+
return cl.Create(ctx, schema)
108107
},
109108
deleteServiceExportRequest: func(ctx context.Context, cl client.Client, ns, name string) error {
110109
return cl.Delete(ctx, &kubebindv1alpha2.APIServiceExportRequest{
@@ -150,15 +149,15 @@ func getServiceExportRequestMapper(clusterName string, cl cluster.Cluster) handl
150149
})
151150
}
152151

153-
// getAPIResourceSchemaMapper creates a mapping function for APIResourceSchema changes.
154-
func getAPIResourceSchemaMapper(clusterName string, cl cluster.Cluster) handler.TypedEventHandler[client.Object, mcreconcile.Request] {
152+
// getBoundSchemaMapper creates a mapping function for BoundSchema changes.
153+
func getBoundSchemaMapper(clusterName string, cl cluster.Cluster) handler.TypedEventHandler[client.Object, mcreconcile.Request] {
155154
return handler.TypedEnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []mcreconcile.Request {
156-
apiResourceSchema := obj.(*kubebindv1alpha2.APIResourceSchema)
157-
apiResourceSchemaKey := apiResourceSchema.Name
155+
boundSchema := obj.(*kubebindv1alpha2.BoundSchema)
156+
boundSchemaKey := boundSchema.Name
158157
c := cl.GetClient()
159158

160159
var requests kubebindv1alpha2.APIServiceExportRequestList
161-
if err := c.List(ctx, &requests, client.MatchingFields{indexers.ServiceExportRequestByGroupResource: apiResourceSchemaKey}); err != nil {
160+
if err := c.List(ctx, &requests, client.MatchingFields{indexers.ServiceExportRequestByGroupResource: boundSchemaKey}); err != nil {
162161
return []mcreconcile.Request{}
163162
}
164163

@@ -197,6 +196,7 @@ func (r *APIServiceExportRequestReconciler) Reconcile(ctx context.Context, req m
197196

198197
client := cl.GetClient()
199198
cache := cl.GetCache()
199+
mapper := cl.GetRESTMapper()
200200

201201
// Fetch the APIServiceExportRequest instance
202202
apiServiceExportRequest := &kubebindv1alpha2.APIServiceExportRequest{}
@@ -214,7 +214,7 @@ func (r *APIServiceExportRequestReconciler) Reconcile(ctx context.Context, req m
214214
original := apiServiceExportRequest.DeepCopy()
215215

216216
// Run the reconciliation logic
217-
if err := r.reconciler.reconcile(ctx, client, cache, apiServiceExportRequest); err != nil {
217+
if err := r.reconciler.reconcile(ctx, mapper, client, cache, apiServiceExportRequest); err != nil {
218218
logger.Error(err, "Failed to reconcile APIServiceExportRequest")
219219
return ctrl.Result{}, err
220220
}
@@ -241,8 +241,8 @@ func (r *APIServiceExportRequestReconciler) SetupWithManager(mgr mcmanager.Manag
241241
getServiceExportRequestMapper,
242242
).
243243
Watches(
244-
&kubebindv1alpha2.APIResourceSchema{},
245-
getAPIResourceSchemaMapper,
244+
&kubebindv1alpha2.BoundSchema{},
245+
getBoundSchemaMapper,
246246
).
247247
WithOptions(r.opts).
248248
Named(controllerName).

0 commit comments

Comments
 (0)