Skip to content

Commit 8b37787

Browse files
authored
Bugfix: Reconcile pointer datasource on reference status update (#3870)
* bugfix: update datasource when datasource reference status updates Previously when a datasource reference status would change pointers to said reference wouldn't reconcile to reflect the latest status. This commit takes care to update them accordingly. Signed-off-by: Adi Aloni <[email protected]> * datasource-controller: include source.datasource in sameSourceSpec Previously only considered PVC and Snpashot sources. Signed-off-by: Adi Aloni <[email protected]> --------- Signed-off-by: Adi Aloni <[email protected]>
1 parent 86f6ec3 commit 8b37787

File tree

2 files changed

+104
-12
lines changed

2 files changed

+104
-12
lines changed

pkg/controller/datasource-controller.go

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -237,20 +237,9 @@ func NewDataSourceController(mgr manager.Manager, log logr.Logger, installerLabe
237237
}
238238

239239
func addDataSourceControllerWatches(mgr manager.Manager, c controller.Controller, log logr.Logger) error {
240-
if err := c.Watch(source.Kind(mgr.GetCache(), &cdiv1.DataSource{}, &handler.TypedEnqueueRequestForObject[*cdiv1.DataSource]{},
241-
predicate.TypedFuncs[*cdiv1.DataSource]{
242-
CreateFunc: func(e event.TypedCreateEvent[*cdiv1.DataSource]) bool { return true },
243-
DeleteFunc: func(e event.TypedDeleteEvent[*cdiv1.DataSource]) bool { return true },
244-
UpdateFunc: func(e event.TypedUpdateEvent[*cdiv1.DataSource]) bool {
245-
return !sameSourceSpec(e.ObjectOld, e.ObjectNew)
246-
},
247-
},
248-
)); err != nil {
249-
return err
250-
}
251-
252240
const dataSourcePvcField = "spec.source.pvc"
253241
const dataSourceSnapshotField = "spec.source.snapshot"
242+
const dataSourceDataSourceField = "spec.source.dataSource"
254243

255244
getKey := func(namespace, name string) string {
256245
return namespace + "/" + name
@@ -269,6 +258,30 @@ func addDataSourceControllerWatches(mgr manager.Manager, c controller.Controller
269258
return reqs
270259
}
271260

261+
if err := c.Watch(source.Kind(mgr.GetCache(), &cdiv1.DataSource{},
262+
handler.TypedEnqueueRequestsFromMapFunc[*cdiv1.DataSource](func(ctx context.Context, obj *cdiv1.DataSource) []reconcile.Request {
263+
reqs := []reconcile.Request{
264+
{
265+
NamespacedName: types.NamespacedName{
266+
Name: obj.Name,
267+
Namespace: obj.Namespace,
268+
},
269+
},
270+
}
271+
return appendMatchingDataSourceRequests(ctx, dataSourceDataSourceField, obj, reqs)
272+
}),
273+
predicate.TypedFuncs[*cdiv1.DataSource]{
274+
CreateFunc: func(e event.TypedCreateEvent[*cdiv1.DataSource]) bool { return true },
275+
DeleteFunc: func(e event.TypedDeleteEvent[*cdiv1.DataSource]) bool { return true },
276+
UpdateFunc: func(e event.TypedUpdateEvent[*cdiv1.DataSource]) bool {
277+
return !sameSourceSpec(e.ObjectOld, e.ObjectNew) ||
278+
!sameConditions(e.ObjectOld, e.ObjectNew)
279+
},
280+
},
281+
)); err != nil {
282+
return err
283+
}
284+
272285
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &cdiv1.DataSource{}, dataSourcePvcField, func(obj client.Object) []string {
273286
if pvc := obj.(*cdiv1.DataSource).Spec.Source.PVC; pvc != nil {
274287
ns := cc.GetNamespace(pvc.Namespace, obj.GetNamespace())
@@ -278,6 +291,7 @@ func addDataSourceControllerWatches(mgr manager.Manager, c controller.Controller
278291
}); err != nil {
279292
return err
280293
}
294+
281295
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &cdiv1.DataSource{}, dataSourceSnapshotField, func(obj client.Object) []string {
282296
if snapshot := obj.(*cdiv1.DataSource).Spec.Source.Snapshot; snapshot != nil {
283297
ns := cc.GetNamespace(snapshot.Namespace, obj.GetNamespace())
@@ -288,6 +302,17 @@ func addDataSourceControllerWatches(mgr manager.Manager, c controller.Controller
288302
return err
289303
}
290304

305+
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &cdiv1.DataSource{}, dataSourceDataSourceField, func(obj client.Object) []string {
306+
ds := obj.(*cdiv1.DataSource)
307+
if sourceDS := ds.Spec.Source.DataSource; sourceDS != nil {
308+
ns := cc.GetNamespace(sourceDS.Namespace, ds.GetNamespace())
309+
return []string{getKey(ns, sourceDS.Name)}
310+
}
311+
return nil
312+
}); err != nil {
313+
return err
314+
}
315+
291316
mapToDataSource := func(ctx context.Context, obj client.Object) []reconcile.Request {
292317
reqs := appendMatchingDataSourceRequests(ctx, dataSourcePvcField, obj, nil)
293318
return appendMatchingDataSourceRequests(ctx, dataSourceSnapshotField, obj, reqs)
@@ -367,6 +392,41 @@ func sameSourceSpec(objOld, objNew client.Object) bool {
367392
if dsOld.Spec.Source.Snapshot != nil {
368393
return reflect.DeepEqual(dsOld.Spec.Source.Snapshot, dsNew.Spec.Source.Snapshot)
369394
}
395+
if dsOld.Spec.Source.DataSource != nil {
396+
return reflect.DeepEqual(dsOld.Spec.Source.DataSource, dsNew.Spec.Source.DataSource)
397+
}
370398

371399
return false
372400
}
401+
402+
func sameConditions(objOld, objNew client.Object) bool {
403+
dsOld, okOld := objOld.(*cdiv1.DataSource)
404+
dsNew, okNew := objNew.(*cdiv1.DataSource)
405+
406+
if !okOld || !okNew {
407+
return false
408+
}
409+
410+
oldConditions := dsOld.Status.Conditions
411+
newConditions := dsNew.Status.Conditions
412+
413+
if len(oldConditions) != len(newConditions) {
414+
return false
415+
}
416+
417+
condMap := make(map[cdiv1.DataSourceConditionType]cdiv1.DataSourceCondition, len(oldConditions))
418+
for _, c := range oldConditions {
419+
condMap[c.Type] = c
420+
}
421+
422+
for _, c := range newConditions {
423+
if oldC, ok := condMap[c.Type]; !ok ||
424+
oldC.Reason != c.Reason ||
425+
oldC.Message != c.Message ||
426+
oldC.Status != c.Status {
427+
return false
428+
}
429+
}
430+
431+
return true
432+
}

tests/datasource_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,38 @@ var _ = Describe("DataSource", func() {
358358
_ = waitForReadyCondition(ds2, corev1.ConditionFalse, "NotFound")
359359
})
360360
})
361+
362+
Context("datasource source", func() {
363+
createDsNoVerify := func(dsName, pvcName string) *cdiv1.DataSource {
364+
By(fmt.Sprintf("creating DataSource %s -> %s", dsName, pvcName))
365+
ds := newDataSource(dsName)
366+
ds.Spec.Source.PVC = &cdiv1.DataVolumeSourcePVC{Namespace: f.Namespace.Name, Name: pvcName}
367+
ds, err := f.CdiClient.CdiV1beta1().DataSources(ds.Namespace).Create(context.TODO(), ds, metav1.CreateOptions{})
368+
Expect(err).ToNot(HaveOccurred())
369+
return ds
370+
}
371+
372+
createDsPointer := func(dsName, dsRefName string) *cdiv1.DataSource {
373+
By(fmt.Sprintf("creating DataSource %s -> DataSource %s", dsName, dsRefName))
374+
ds := newDataSource(dsName)
375+
ds.Spec.Source.DataSource = &cdiv1.DataSourceRefSourceDataSource{Namespace: f.Namespace.Name, Name: dsRefName}
376+
ds, err := f.CdiClient.CdiV1beta1().DataSources(ds.Namespace).Create(context.TODO(), ds, metav1.CreateOptions{})
377+
Expect(err).ToNot(HaveOccurred())
378+
return ds
379+
}
380+
381+
It("should update datasource status when referenced datasource updates", func() {
382+
ds := createDsNoVerify(ds1Name, pvc1Name)
383+
_ = waitForReadyCondition(ds, corev1.ConditionFalse, "NotFound")
384+
385+
dsPointer := createDsPointer(ds2Name, ds.Name)
386+
_ = waitForReadyCondition(dsPointer, corev1.ConditionFalse, "NotFound")
387+
388+
createDv(pvc1Name, testURL(), nil)
389+
_ = waitForReadyCondition(ds, corev1.ConditionTrue, "Ready")
390+
_ = waitForReadyCondition(dsPointer, corev1.ConditionTrue, "Ready")
391+
})
392+
})
361393
})
362394

363395
func deleteDvPvc(f *framework.Framework, pvcName string) {

0 commit comments

Comments
 (0)