Skip to content

Commit ab2053c

Browse files
kvapsclaude
andcommitted
fix(controller): re-enqueue RD when child Resources change
The tiebreaker logic only fired on RD creation. When the controller saw the RD before its child Resources existed (typical apply order: RD, then Resource_a, then Resource_b), the count was 0 diskful → no witness → done. Subsequent Resource creations didn't enqueue the RD, so the 2-diskful trigger was missed and the witness never landed until the next periodic re-sync. Wire a `Watches(&Resource{}, EnqueueForRD)` so every Resource event fans out to its parent RD's reconcile. Idempotent — running again on an already-witnessed RD is a no-op. Stand-side regression: tests/e2e/tiebreaker.sh failed before this fix, passes after. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
1 parent 621d8b4 commit ab2053c

1 file changed

Lines changed: 24 additions & 0 deletions

File tree

internal/controller/resourcedefinition_controller.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@ import (
2323
"strings"
2424

2525
"k8s.io/apimachinery/pkg/runtime"
26+
"k8s.io/apimachinery/pkg/types"
2627
ctrl "sigs.k8s.io/controller-runtime"
2728
"sigs.k8s.io/controller-runtime/pkg/client"
29+
"sigs.k8s.io/controller-runtime/pkg/handler"
2830
logf "sigs.k8s.io/controller-runtime/pkg/log"
31+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
2932

3033
blockstoriov1alpha1 "github.com/cozystack/blockstor/api/v1alpha1"
3134
apiv1 "github.com/cozystack/blockstor/pkg/api/v1"
@@ -220,9 +223,30 @@ func alreadyExists(err error) bool {
220223
}
221224

222225
// SetupWithManager sets up the controller with the Manager.
226+
//
227+
// We Watch Resources too — the tiebreaker logic needs to fire when
228+
// child Resources land, not just on the RD's own creation. Without
229+
// the watch, an `apply RD + 2 Resources` race never re-runs the RD
230+
// reconciler after the Resources finish, and a 2-replica RD sits
231+
// without its DISKLESS witness until the next periodic re-sync.
223232
func (r *ResourceDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error {
224233
return ctrl.NewControllerManagedBy(mgr).
225234
For(&blockstoriov1alpha1.ResourceDefinition{}).
235+
Watches(&blockstoriov1alpha1.Resource{},
236+
handler.EnqueueRequestsFromMapFunc(r.enqueueRDForResource)).
226237
Named("resourcedefinition").
227238
Complete(r)
228239
}
240+
241+
// enqueueRDForResource maps a Resource event to its parent RD.
242+
// Resource.Spec.ResourceDefinitionName is the canonical link.
243+
func (r *ResourceDefinitionReconciler) enqueueRDForResource(_ context.Context, obj client.Object) []reconcile.Request {
244+
res, ok := obj.(*blockstoriov1alpha1.Resource)
245+
if !ok || res.Spec.ResourceDefinitionName == "" {
246+
return nil
247+
}
248+
249+
return []reconcile.Request{
250+
{NamespacedName: types.NamespacedName{Name: res.Spec.ResourceDefinitionName}},
251+
}
252+
}

0 commit comments

Comments
 (0)