Skip to content

Commit 3aa556f

Browse files
Backport: fix(vmip): fix double create VirtualMachineIPLease (#987)
fix(vmip): fix double create VirtualMachineIPLease (#976) Signed-off-by: Dmitry Lopatin <dmitry.lopatin@flant.com> Co-authored-by: Dmitry Lopatin <93423466+LopatinDmitr@users.noreply.github.com>
1 parent ce873a2 commit 3aa556f

5 files changed

Lines changed: 58 additions & 18 deletions

File tree

images/virtualization-artifact/pkg/controller/vmip/vmip_reconciler.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package vmip
1919
import (
2020
"context"
2121
"fmt"
22+
"time"
2223

2324
"k8s.io/apimachinery/pkg/types"
2425
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -33,6 +34,7 @@ import (
3334
"github.com/deckhouse/virtualization-controller/pkg/controller/indexer"
3435
"github.com/deckhouse/virtualization-controller/pkg/controller/reconciler"
3536
"github.com/deckhouse/virtualization-controller/pkg/controller/vmip/internal/state"
37+
"github.com/deckhouse/virtualization-controller/pkg/logger"
3638
virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2"
3739
)
3840

@@ -152,7 +154,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
152154
}
153155

154156
s := state.New(r.client, vmip.Changed())
155-
156157
rec := reconciler.NewBaseReconciler[Handler](r.handlers)
157158
rec.SetHandlerExecutor(func(ctx context.Context, h Handler) (reconcile.Result, error) {
158159
return h.Handle(ctx, s)
@@ -163,7 +164,21 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
163164
return vmip.Update(ctx)
164165
})
165166

166-
return rec.Reconcile(ctx)
167+
// TODO: This code addresses the issue of creating vmipl within the controller.
168+
// The object is saved in etcd but does not get updated in the cache in time.
169+
// As a result, we encounter the creation of multiple vmipl during a single reconcile operation.
170+
// Adding reconcile.Result{RequeueAfter: 2 * time.Second} helps to fix this issue in 90% of cases.
171+
// In the future, this code should be architecturally redesigned to prevent such situations.
172+
result, err := rec.Reconcile(ctx)
173+
if err != nil {
174+
logger.FromContext(ctx).Error("Failed to reconcile VMIP", logger.SlogErr(err))
175+
return reconcile.Result{RequeueAfter: 2 * time.Second}, nil
176+
}
177+
if result.Requeue {
178+
return reconcile.Result{RequeueAfter: 2 * time.Second}, nil
179+
}
180+
181+
return result, nil
167182
}
168183

169184
func (r *Reconciler) factory() *virtv2.VirtualMachineIPAddress {

images/virtualization-artifact/pkg/controller/vmiplease/internal/lifecycle_handler.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2323
"sigs.k8s.io/controller-runtime/pkg/reconcile"
2424

25+
"github.com/deckhouse/virtualization-controller/pkg/common/ip"
2526
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
2627
"github.com/deckhouse/virtualization-controller/pkg/controller/vmiplease/internal/state"
2728
virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2"
@@ -55,7 +56,7 @@ func (h *LifecycleHandler) Handle(ctx context.Context, state state.VMIPLeaseStat
5556
return reconcile.Result{}, err
5657
}
5758

58-
if vmip != nil {
59+
if vmip != nil && vmip.Status.Address == ip.LeaseNameToIP(lease.Name) {
5960
if leaseStatus.Phase != virtv2.VirtualMachineIPAddressLeasePhaseBound {
6061
leaseStatus.Phase = virtv2.VirtualMachineIPAddressLeasePhaseBound
6162
cb.Status(metav1.ConditionTrue).

images/virtualization-artifact/pkg/controller/vmiplease/internal/protection_handler.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2323
"sigs.k8s.io/controller-runtime/pkg/reconcile"
2424

25+
"github.com/deckhouse/virtualization-controller/pkg/common/ip"
2526
"github.com/deckhouse/virtualization-controller/pkg/controller/vmiplease/internal/state"
2627
"github.com/deckhouse/virtualization-controller/pkg/logger"
2728
virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2"
@@ -44,7 +45,7 @@ func (h *ProtectionHandler) Handle(ctx context.Context, state state.VMIPLeaseSta
4445
return reconcile.Result{}, err
4546
}
4647

47-
if vmip != nil {
48+
if vmip != nil && vmip.Status.Address == ip.LeaseNameToIP(lease.Name) {
4849
controllerutil.AddFinalizer(lease, virtv2.FinalizerIPAddressLeaseCleanup)
4950
} else if lease.GetDeletionTimestamp() == nil {
5051
log.Info("Deletion observed: remove cleanup finalizer from VirtualMachineIPAddressLease")

images/virtualization-artifact/pkg/controller/vmiplease/internal/retention_handler.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"sigs.k8s.io/controller-runtime/pkg/reconcile"
2525

26+
"github.com/deckhouse/virtualization-controller/pkg/common/ip"
2627
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
2728
"github.com/deckhouse/virtualization-controller/pkg/controller/vmiplease/internal/state"
2829
"github.com/deckhouse/virtualization-controller/pkg/logger"
@@ -52,7 +53,7 @@ func (h *RetentionHandler) Handle(ctx context.Context, state state.VMIPLeaseStat
5253
return reconcile.Result{}, err
5354
}
5455

55-
if vmip == nil {
56+
if vmip == nil || vmip.Status.Address != ip.LeaseNameToIP(lease.Name) {
5657
if lease.Spec.VirtualMachineIPAddressRef.Name != "" {
5758
log.Info("VirtualMachineIP not found: remove this ref from the spec and retain VMIPLease")
5859
lease.Spec.VirtualMachineIPAddressRef.Name = ""

images/virtualization-artifact/pkg/controller/vmiplease/vmiplease_reconciler.go

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package vmiplease
1919
import (
2020
"context"
2121
"fmt"
22+
"log/slog"
2223
"reflect"
2324

2425
"k8s.io/apimachinery/pkg/types"
@@ -31,7 +32,6 @@ import (
3132
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3233
"sigs.k8s.io/controller-runtime/pkg/source"
3334

34-
"github.com/deckhouse/virtualization-controller/pkg/common/ip"
3535
"github.com/deckhouse/virtualization-controller/pkg/controller/reconciler"
3636
"github.com/deckhouse/virtualization-controller/pkg/controller/vmiplease/internal/state"
3737
virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2"
@@ -70,7 +70,7 @@ func (r *Reconciler) SetupController(_ context.Context, mgr manager.Manager, ctr
7070
return ctr.Watch(source.Kind(mgr.GetCache(), &virtv2.VirtualMachineIPAddressLease{}), &handler.EnqueueRequestForObject{})
7171
}
7272

73-
func (r *Reconciler) enqueueRequestsFromVMIP(_ context.Context, obj client.Object) []reconcile.Request {
73+
func (r *Reconciler) enqueueRequestsFromVMIP(ctx context.Context, obj client.Object) []reconcile.Request {
7474
vmip, ok := obj.(*virtv2.VirtualMachineIPAddress)
7575
if !ok {
7676
return nil
@@ -80,13 +80,30 @@ func (r *Reconciler) enqueueRequestsFromVMIP(_ context.Context, obj client.Objec
8080
return nil
8181
}
8282

83-
return []reconcile.Request{
84-
{
85-
NamespacedName: types.NamespacedName{
86-
Name: ip.IpToLeaseName(vmip.Status.Address),
87-
},
88-
},
83+
var requests []reconcile.Request
84+
85+
var vmiplList virtv2.VirtualMachineIPAddressLeaseList
86+
err := r.client.List(ctx, &vmiplList, &client.ListOptions{})
87+
if err != nil {
88+
slog.Default().Error(fmt.Sprintf("failed to list vmipl: %s", err))
89+
return requests
90+
}
91+
92+
for _, vmipl := range vmiplList.Items {
93+
if vmipl.Spec.VirtualMachineIPAddressRef == nil {
94+
continue
95+
}
96+
97+
if vmipl.Spec.VirtualMachineIPAddressRef.Name == obj.GetName() {
98+
requests = append(requests, reconcile.Request{
99+
NamespacedName: types.NamespacedName{
100+
Name: vmipl.Name,
101+
},
102+
})
103+
}
89104
}
105+
106+
return requests
90107
}
91108

92109
func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
@@ -109,10 +126,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
109126
return h.Handle(ctx, s)
110127
})
111128
rec.SetResourceUpdater(func(ctx context.Context) error {
112-
if s.ShouldDeletion() {
113-
return r.client.Delete(ctx, lease.Changed())
114-
}
115-
116129
if !reflect.DeepEqual(lease.Current().Spec, lease.Changed().Spec) {
117130
leaseStatus := lease.Changed().Status.DeepCopy()
118131
err = r.client.Update(ctx, lease.Changed())
@@ -122,7 +135,16 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
122135
lease.Changed().Status = *leaseStatus
123136
}
124137

125-
return lease.Update(ctx)
138+
err = lease.Update(ctx)
139+
if err != nil {
140+
return err
141+
}
142+
143+
if s.ShouldDeletion() {
144+
return r.client.Delete(ctx, lease.Changed())
145+
}
146+
147+
return nil
126148
})
127149

128150
return rec.Reconcile(ctx)

0 commit comments

Comments
 (0)