Skip to content

Commit cea635c

Browse files
kvapsclaude
andcommitted
fix(controller): re-enqueue siblings on Resource events
When a tiebreaker witness lands on N3, R1 and R2's .res files keep the pre-witness peer list (they only have each other). N3 then can't connect because R1 doesn't know it exists. Symptoms: e2e-auto-diskful times out at wait_uptodate even though R1 + R2 are individually disk:UpToDate — they're missing the third peer. Wire Watches(&Resource{}, EnqueueSiblings) so any Resource event fans out to every other Resource of the same RD. Excludes the originator (its own reconcile fires via For(), so a fan-out to self would just be a redundant requeue). Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
1 parent 6147b26 commit cea635c

1 file changed

Lines changed: 34 additions & 7 deletions

File tree

internal/controller/resource_controller.go

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -675,17 +675,21 @@ func (r *ResourceReconciler) EnsureDRBDIDsForTest(ctx context.Context, target *b
675675

676676
// SetupWithManager sets up the controller with the Manager.
677677
//
678-
// We Watch ResourceDefinitions too — every replica's dispatch reads
679-
// the parent RD's VolumeDefinitions for the satellite render, so an
680-
// RD-side change (volume size, prop bag, encryption passphrase) must
681-
// re-fire every replica's reconcile. Without this watch, `linstor
682-
// volume-definition modify --size` updates Spec.VolumeDefinitions but
683-
// the satellite never gets the new size.
678+
// We Watch ResourceDefinitions and sibling Resources too:
679+
// - RD changes (volume size, prop bag, encryption passphrase, quorum
680+
// toggle) must re-fire every replica's reconcile so the satellite
681+
// gets the updated VolumeDefinitions / DRBD options bag.
682+
// - Sibling-Resource changes (a witness gets created or removed)
683+
// must re-fire the OTHER replicas so their rendered .res reflects
684+
// the new peer set. Without this, R1's .res keeps the pre-witness
685+
// peer list and R3 can't connect (R1 doesn't know it exists).
684686
func (r *ResourceReconciler) SetupWithManager(mgr ctrl.Manager) error {
685687
return ctrl.NewControllerManagedBy(mgr).
686688
For(&blockstoriov1alpha1.Resource{}).
687689
Watches(&blockstoriov1alpha1.ResourceDefinition{},
688690
handler.EnqueueRequestsFromMapFunc(r.enqueueResourcesForRD)).
691+
Watches(&blockstoriov1alpha1.Resource{},
692+
handler.EnqueueRequestsFromMapFunc(r.enqueueSiblings)).
689693
Named("resource").
690694
Complete(r)
691695
}
@@ -698,6 +702,25 @@ func (r *ResourceReconciler) enqueueResourcesForRD(ctx context.Context, obj clie
698702
return nil
699703
}
700704

705+
return r.requestsForRD(ctx, rd.Name, "")
706+
}
707+
708+
// enqueueSiblings maps a Resource event to every OTHER Resource of
709+
// the same RD. The originator's own reconcile fires through For(),
710+
// so we exclude it from the fan-out to avoid the redundant requeue.
711+
func (r *ResourceReconciler) enqueueSiblings(ctx context.Context, obj client.Object) []reconcile.Request {
712+
res, ok := obj.(*blockstoriov1alpha1.Resource)
713+
if !ok || res.Spec.ResourceDefinitionName == "" {
714+
return nil
715+
}
716+
717+
return r.requestsForRD(ctx, res.Spec.ResourceDefinitionName, res.Name)
718+
}
719+
720+
// requestsForRD returns reconcile.Request entries for every Resource
721+
// of the named RD, optionally excluding `excludeName` (used when the
722+
// originating Resource is already getting its own reconcile via For).
723+
func (r *ResourceReconciler) requestsForRD(ctx context.Context, rdName, excludeName string) []reconcile.Request {
701724
var resList blockstoriov1alpha1.ResourceList
702725

703726
if err := r.List(ctx, &resList); err != nil {
@@ -707,7 +730,11 @@ func (r *ResourceReconciler) enqueueResourcesForRD(ctx context.Context, obj clie
707730
out := make([]reconcile.Request, 0, len(resList.Items))
708731

709732
for i := range resList.Items {
710-
if resList.Items[i].Spec.ResourceDefinitionName != rd.Name {
733+
if resList.Items[i].Spec.ResourceDefinitionName != rdName {
734+
continue
735+
}
736+
737+
if resList.Items[i].Name == excludeName {
711738
continue
712739
}
713740

0 commit comments

Comments
 (0)