Skip to content

Commit 59d34f2

Browse files
fwieselnotandy
authored andcommitted
Decomission: Use Patch + FieldOwner
FieldOwner allows us to identify who maintains a field and detect if there is a conflict between multiple controllers.
1 parent c414867 commit 59d34f2

File tree

1 file changed

+33
-17
lines changed

1 file changed

+33
-17
lines changed

internal/controller/onboarding_controller.go

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"time"
2828

2929
corev1 "k8s.io/api/core/v1"
30+
"k8s.io/apimachinery/pkg/api/equality"
3031
"k8s.io/apimachinery/pkg/api/meta"
3132
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3233
"k8s.io/apimachinery/pkg/runtime"
@@ -107,6 +108,7 @@ func (r *OnboardingController) Reconcile(ctx context.Context, req ctrl.Request)
107108
// check condition reason
108109
status := meta.FindStatusCondition(hv.Status.Conditions, kvmv1.ConditionTypeOnboarding)
109110
if status == nil {
111+
base := hv.DeepCopy()
110112
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
111113
Type: kvmv1.ConditionTypeReady,
112114
Status: metav1.ConditionFalse,
@@ -120,7 +122,7 @@ func (r *OnboardingController) Reconcile(ctx context.Context, req ctrl.Request)
120122
Reason: kvmv1.ConditionReasonInitial,
121123
Message: "Initial onboarding",
122124
})
123-
return ctrl.Result{}, r.Status().Update(ctx, hv)
125+
return ctrl.Result{}, r.patchStatus(ctx, hv, base)
124126
}
125127

126128
switch status.Reason {
@@ -145,7 +147,7 @@ func (r *OnboardingController) abortOnboarding(ctx context.Context, hv *kvmv1.Hy
145147
return nil
146148
}
147149

148-
changed := false
150+
base := hv.DeepCopy()
149151
ready := meta.FindStatusCondition(hv.Status.Conditions, kvmv1.ConditionTypeReady)
150152
if ready != nil {
151153
// Only undo ones own readiness status reporting
@@ -156,23 +158,21 @@ func (r *OnboardingController) abortOnboarding(ctx context.Context, hv *kvmv1.Hy
156158
Reason: kvmv1.ConditionReasonOnboarding,
157159
Message: "Onboarding aborted",
158160
})
159-
changed = true
160161
}
161162
}
162163

163-
if meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
164+
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
164165
Type: kvmv1.ConditionTypeOnboarding,
165166
Status: metav1.ConditionFalse,
166167
Reason: kvmv1.ConditionReasonAborted,
167168
Message: "Aborted due to LifecycleEnabled being false",
168-
}) {
169-
changed = true
170-
}
169+
})
171170

172-
if !changed {
171+
if equality.Semantic.DeepEqual(hv, base) {
173172
// Already aborted
174173
return nil
175174
}
175+
176176
if err := r.deleteTestServers(ctx, computeHost); err != nil {
177177
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
178178
Type: kvmv1.ConditionTypeOnboarding,
@@ -181,9 +181,14 @@ func (r *OnboardingController) abortOnboarding(ctx context.Context, hv *kvmv1.Hy
181181
Message: err.Error(),
182182
})
183183

184-
return errors.Join(err, r.Status().Update(ctx, hv))
184+
if equality.Semantic.DeepEqual(hv, base) {
185+
return err
186+
}
187+
188+
return errors.Join(err, r.patchStatus(ctx, hv, base))
185189
}
186-
return r.Status().Update(ctx, hv)
190+
191+
return r.patchStatus(ctx, hv, base)
187192
}
188193

189194
func (r *OnboardingController) initialOnboarding(ctx context.Context, hv *kvmv1.Hypervisor, host string) error {
@@ -233,13 +238,14 @@ func (r *OnboardingController) initialOnboarding(ctx context.Context, hv *kvmv1.
233238
return result.Err
234239
}
235240

241+
base := hv.DeepCopy()
236242
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
237243
Type: kvmv1.ConditionTypeOnboarding,
238244
Status: metav1.ConditionTrue,
239245
Reason: kvmv1.ConditionReasonTesting,
240246
Message: "Running onboarding tests",
241247
})
242-
return r.Status().Update(ctx, hv)
248+
return r.patchStatus(ctx, hv, base)
243249
}
244250

245251
func (r *OnboardingController) smokeTest(ctx context.Context, hv *kvmv1.Hypervisor, host string) (ctrl.Result, error) {
@@ -261,14 +267,15 @@ func (r *OnboardingController) smokeTest(ctx context.Context, hv *kvmv1.Hypervis
261267
return ctrl.Result{RequeueAfter: defaultWaitTime}, nil
262268
}
263269

270+
base := hv.DeepCopy()
264271
// Set condition back to testing
265272
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
266273
Type: kvmv1.ConditionTypeOnboarding,
267274
Status: metav1.ConditionTrue,
268275
Reason: kvmv1.ConditionReasonTesting,
269276
Message: "Server ended up in error state: " + server.Fault.Message,
270277
})
271-
if err = r.Status().Update(ctx, hv); err != nil {
278+
if err = r.patchStatus(ctx, hv, base); err != nil {
272279
return ctrl.Result{}, err
273280
}
274281

@@ -281,13 +288,14 @@ func (r *OnboardingController) smokeTest(ctx context.Context, hv *kvmv1.Hypervis
281288
case "ACTIVE":
282289
consoleOutput, err := servers.ShowConsoleOutput(ctx, r.testComputeClient, server.ID, servers.ShowConsoleOutputOpts{Length: 11}).Extract()
283290
if err != nil {
291+
base := hv.DeepCopy()
284292
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
285293
Type: kvmv1.ConditionTypeOnboarding,
286294
Status: metav1.ConditionTrue,
287295
Reason: kvmv1.ConditionReasonTesting,
288296
Message: fmt.Sprintf("could not get console output %v", err),
289297
})
290-
if err := r.Status().Update(ctx, hv); err != nil {
298+
if err := r.patchStatus(ctx, hv, base); err != nil {
291299
return ctrl.Result{}, err
292300
}
293301
return ctrl.Result{RequeueAfter: defaultWaitTime}, nil
@@ -298,13 +306,14 @@ func (r *OnboardingController) smokeTest(ctx context.Context, hv *kvmv1.Hypervis
298306
}
299307

300308
if err = servers.Delete(ctx, r.testComputeClient, server.ID).ExtractErr(); err != nil {
309+
base := hv.DeepCopy()
301310
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
302311
Type: kvmv1.ConditionTypeOnboarding,
303312
Status: metav1.ConditionTrue,
304313
Reason: kvmv1.ConditionReasonTesting,
305314
Message: fmt.Sprintf("failed to terminate instance %v", err),
306315
})
307-
if err := r.Status().Update(ctx, hv); err != nil {
316+
if err := r.patchStatus(ctx, hv, base); err != nil {
308317
return ctrl.Result{}, err
309318
}
310319
return ctrl.Result{RequeueAfter: defaultWaitTime}, nil
@@ -321,13 +330,14 @@ func (r *OnboardingController) completeOnboarding(ctx context.Context, host stri
321330

322331
err := r.deleteTestServers(ctx, host)
323332
if err != nil {
333+
base := hv.DeepCopy()
324334
if meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
325335
Type: kvmv1.ConditionTypeOnboarding,
326336
Status: metav1.ConditionTrue, // No cleanup, so we are still "onboarding"
327337
Reason: kvmv1.ConditionReasonAborted,
328338
Message: err.Error(),
329339
}) {
330-
return ctrl.Result{}, errors.Join(err, r.Status().Update(ctx, hv))
340+
return ctrl.Result{}, errors.Join(err, r.patchStatus(ctx, hv, base))
331341
}
332342

333343
return ctrl.Result{}, err
@@ -350,6 +360,7 @@ func (r *OnboardingController) completeOnboarding(ctx context.Context, host stri
350360
return ctrl.Result{}, err
351361
}
352362

363+
base := hv.DeepCopy()
353364
// Set hypervisor ready condition
354365
meta.SetStatusCondition(&hv.Status.Conditions, metav1.Condition{
355366
Type: kvmv1.ConditionTypeReady,
@@ -365,7 +376,7 @@ func (r *OnboardingController) completeOnboarding(ctx context.Context, host stri
365376
Reason: kvmv1.ConditionReasonSucceeded,
366377
Message: "Onboarding completed",
367378
})
368-
return ctrl.Result{}, r.Status().Update(ctx, hv)
379+
return ctrl.Result{}, r.patchStatus(ctx, hv, base)
369380
}
370381

371382
func (r *OnboardingController) deleteTestServers(ctx context.Context, host string) error {
@@ -438,9 +449,10 @@ func (r *OnboardingController) ensureNovaProperties(ctx context.Context, hv *kvm
438449
return fmt.Errorf("could not find exact match for %v", shortHypervisorAddress)
439450
}
440451

452+
base := hv.DeepCopy()
441453
hv.Status.HypervisorID = myHypervisor.ID
442454
hv.Status.ServiceID = myHypervisor.Service.ID
443-
return r.Status().Update(ctx, hv)
455+
return r.patchStatus(ctx, hv, base)
444456
}
445457

446458
func (r *OnboardingController) createOrGetTestServer(ctx context.Context, zone, computeHost string, nodeUid types.UID) (*servers.Server, error) {
@@ -592,6 +604,10 @@ func (r *OnboardingController) findTestFlavor(ctx context.Context) (string, erro
592604
return "", errors.New("couldn't find flavor")
593605
}
594606

607+
func (r *OnboardingController) patchStatus(ctx context.Context, hv, base *kvmv1.Hypervisor) error {
608+
return r.Status().Patch(ctx, hv, k8sclient.MergeFromWithOptions(base, k8sclient.MergeFromWithOptimisticLock{}), k8sclient.FieldOwner(OnboardingControllerName))
609+
}
610+
595611
// SetupWithManager sets up the controller with the Manager.
596612
func (r *OnboardingController) SetupWithManager(mgr ctrl.Manager) error {
597613
ctx := context.Background()

0 commit comments

Comments
 (0)