Skip to content

Commit 8e03664

Browse files
committed
DynamicRESTMapper now reconciles version changes in bound resources and CRDs
On-behalf-of: @SAP [email protected] Signed-off-by: Robert Vasek <[email protected]>
1 parent acd61ea commit 8e03664

File tree

3 files changed

+452
-21
lines changed

3 files changed

+452
-21
lines changed

pkg/reconciler/dynamicrestmapper/dynamicrestmapper_controller.go

Lines changed: 140 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"fmt"
2323
"time"
2424

25+
apiextensionshelpers "k8s.io/apiextensions-apiserver/pkg/apihelpers"
2526
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2627
apierrors "k8s.io/apimachinery/pkg/api/errors"
2728
"k8s.io/apimachinery/pkg/api/meta"
@@ -39,6 +40,7 @@ import (
3940
"github.com/kcp-dev/kcp/pkg/informer"
4041
"github.com/kcp-dev/kcp/pkg/logging"
4142
"github.com/kcp-dev/kcp/pkg/reconciler/apis/apibinding"
43+
"github.com/kcp-dev/kcp/pkg/tombstone"
4244
builtinschemas "github.com/kcp-dev/kcp/pkg/virtual/apiexport/schemas/builtin"
4345
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
4446
apisv1alpha2 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2"
@@ -135,23 +137,28 @@ func NewController(
135137
},
136138
}
137139

138-
objOrTombstone := func(obj any) any {
139-
if tombstone, ok := obj.(cache.DeletedFinalStateUnknown); ok {
140-
obj = tombstone.Obj
141-
}
142-
return obj
143-
}
144-
145140
_, _ = logicalClusterInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
146141
AddFunc: func(obj interface{}) {
147-
c.enqueueLogicalCluster(nil, objOrTombstone(obj).(*corev1alpha1.LogicalCluster), opCreate)
142+
c.enqueueLogicalCluster(nil, tombstone.Obj[*corev1alpha1.LogicalCluster](obj), opCreate)
148143
},
149144
UpdateFunc: func(oldObj, newObj interface{}) {
150-
c.enqueueLogicalCluster(objOrTombstone(oldObj).(*corev1alpha1.LogicalCluster),
151-
objOrTombstone(newObj).(*corev1alpha1.LogicalCluster), opUpdate)
145+
c.enqueueLogicalCluster(tombstone.Obj[*corev1alpha1.LogicalCluster](oldObj),
146+
tombstone.Obj[*corev1alpha1.LogicalCluster](newObj), opUpdate)
152147
},
153148
DeleteFunc: func(obj interface{}) {
154-
c.enqueueLogicalCluster(objOrTombstone(obj).(*corev1alpha1.LogicalCluster), nil, opDelete)
149+
c.enqueueLogicalCluster(tombstone.Obj[*corev1alpha1.LogicalCluster](obj), nil, opDelete)
150+
},
151+
})
152+
153+
_, _ = apiBindingInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
154+
UpdateFunc: func(oldObj, newObj interface{}) {
155+
c.enqueueAPIBindingUpdate(tombstone.Obj[*apisv1alpha2.APIBinding](newObj))
156+
},
157+
})
158+
159+
_, _ = crdInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
160+
UpdateFunc: func(oldObj, newObj interface{}) {
161+
c.enqueueCRDUpdate(tombstone.Obj[*apiextensionsv1.CustomResourceDefinition](newObj))
155162
},
156163
})
157164

@@ -204,6 +211,115 @@ func diffResourceBindingsAnn(oldAnn, newAnn apibinding.ResourceBindingsAnnotatio
204211
return
205212
}
206213

214+
func (c *Controller) enqueueCRDUpdate(crd *apiextensionsv1.CustomResourceDefinition) {
215+
if !apiextensionshelpers.IsCRDConditionTrue(crd, apiextensionsv1.Established) {
216+
// The CRD is not ready yet. Nothing to do, we'll get notified on the next update event.
217+
return
218+
}
219+
220+
gr := schema.GroupResource{
221+
Group: crd.Spec.Group,
222+
Resource: crd.Status.AcceptedNames.Plural,
223+
}
224+
225+
lc, err := c.getLogicalCluster(logicalcluster.From(crd), corev1alpha1.LogicalClusterName)
226+
if err != nil {
227+
utilruntime.HandleError(err)
228+
return
229+
}
230+
231+
boundResourcesAnn, err := apibinding.GetResourceBindings(lc)
232+
if err != nil {
233+
utilruntime.HandleError(err)
234+
return
235+
}
236+
237+
if _, hasCRD := boundResourcesAnn[gr.String()]; !hasCRD {
238+
// The CRD is not listed in the resources lock yet.
239+
return
240+
}
241+
242+
// Update the GR by removing and adding it back again.
243+
resourceLock := apibinding.ResourceBindingsAnnotation{
244+
gr.String(): apibinding.ExpirableLock{
245+
Lock: apibinding.Lock{
246+
CRD: true,
247+
},
248+
},
249+
}
250+
it := queueItem{
251+
ClusterName: logicalcluster.From(crd),
252+
ClusterResourceName: corev1alpha1.LogicalClusterName,
253+
Op: opUpdate,
254+
255+
ToRemove: resourceLock,
256+
ToAdd: resourceLock,
257+
}
258+
259+
keyBytes, err := json.Marshal(&it)
260+
if err != nil {
261+
utilruntime.HandleError(err)
262+
return
263+
}
264+
key := string(keyBytes)
265+
266+
logging.WithQueueKey(logging.WithReconciler(klog.Background(), ControllerName), key).WithName(crd.Name).
267+
V(4).Info("queueing ResourceBindingsAnnotation patch because of CRD")
268+
c.queue.Add(key)
269+
}
270+
271+
func (c *Controller) enqueueAPIBindingUpdate(apiBinding *apisv1alpha2.APIBinding) {
272+
lc, err := c.getLogicalCluster(logicalcluster.From(apiBinding), corev1alpha1.LogicalClusterName)
273+
if err != nil {
274+
utilruntime.HandleError(err)
275+
return
276+
}
277+
boundResourcesAnn, err := apibinding.GetResourceBindings(lc)
278+
if err != nil {
279+
utilruntime.HandleError(err)
280+
return
281+
}
282+
283+
it := queueItem{
284+
ClusterName: logicalcluster.From(apiBinding),
285+
ClusterResourceName: corev1alpha1.LogicalClusterName,
286+
Op: opUpdate,
287+
ToAdd: make(apibinding.ResourceBindingsAnnotation),
288+
ToRemove: make(apibinding.ResourceBindingsAnnotation),
289+
}
290+
291+
for _, boundRes := range apiBinding.Status.BoundResources {
292+
gr := schema.GroupResource{
293+
Group: boundRes.Group,
294+
Resource: boundRes.Resource,
295+
}
296+
key := gr.String()
297+
if _, hasBinding := boundResourcesAnn[key]; !hasBinding {
298+
continue
299+
}
300+
301+
// Update the GR by removing and adding it back again.
302+
resourceLock := apibinding.ExpirableLock{
303+
Lock: apibinding.Lock{
304+
Name: apiBinding.Name,
305+
},
306+
}
307+
it.ToRemove[key] = resourceLock
308+
it.ToAdd[key] = resourceLock
309+
}
310+
311+
keyBytes, err := json.Marshal(&it)
312+
if err != nil {
313+
utilruntime.HandleError(err)
314+
return
315+
}
316+
key := string(keyBytes)
317+
318+
logging.WithQueueKey(logging.WithReconciler(klog.Background(), ControllerName), key).WithName(apiBinding.Name).
319+
V(4).Info("queueing ResourceBindingsAnnotation patch because of APIBinding")
320+
c.queue.Add(key)
321+
}
322+
207323
func (c *Controller) enqueueLogicalCluster(oldObj *corev1alpha1.LogicalCluster, newObj *corev1alpha1.LogicalCluster, op ctrlOp) {
208324
oldBoundResourcesAnnStr := getResourceBindingsAnnJSON(oldObj)
209325
newBoundResourcesAnnStr := getResourceBindingsAnnJSON(newObj)
@@ -307,16 +423,20 @@ func (c *Controller) gatherGVKRsForCRD(crd *apiextensionsv1.CustomResourceDefini
307423
if crd == nil {
308424
return nil
309425
}
310-
gvkrs := make([]typeMeta, len(crd.Status.StoredVersions))
311-
for i, crdVersion := range crd.Status.StoredVersions {
312-
gvkrs[i] = newTypeMeta(
426+
gvkrs := make([]typeMeta, 0, len(crd.Spec.Versions))
427+
for _, version := range crd.Spec.Versions {
428+
if !version.Served {
429+
continue
430+
}
431+
432+
gvkrs = append(gvkrs, newTypeMeta(
313433
crd.Spec.Group,
314-
crdVersion,
434+
version.Name,
315435
crd.Status.AcceptedNames.Kind,
316436
crd.Status.AcceptedNames.Singular,
317437
crd.Status.AcceptedNames.Plural,
318438
resourceScopeToRESTScope(crd.Spec.Scope),
319-
)
439+
))
320440
}
321441
return gvkrs
322442
}
@@ -341,6 +461,10 @@ func (c *Controller) gatherGVKRsForAPIBinding(apiBinding *apisv1alpha2.APIBindin
341461
}
342462

343463
for _, schVersion := range sch.Spec.Versions {
464+
if !schVersion.Served {
465+
continue
466+
}
467+
344468
gvkrs = append(gvkrs, newTypeMeta(
345469
sch.Spec.Group,
346470
schVersion.Name,

0 commit comments

Comments
 (0)