Skip to content

Commit 156ed66

Browse files
committed
chore(quality): apply kubebuilder best practices quality gate
- Fix logging conventions across all controllers (capitalize, past tense) - Move condition type constants to api/v1alpha1/conditions.go - Replace r.Update() with r.Patch() for finalizer add/remove - Default --leader-elect to true in operator - Add AGENTS.md quality gate referencing kubebuilder good-practices guide
1 parent 14a9201 commit 156ed66

17 files changed

Lines changed: 83 additions & 68 deletions

AGENTS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,15 @@ export IMG=<registry>/<project>:<version>
301301
make docker-build docker-push IMG=$IMG
302302
```
303303

304+
## Quality Gate
305+
306+
**All work on this codebase must comply with the kubebuilder good practices guide:**
307+
https://book.kubebuilder.io/reference/good-practices
308+
309+
Before marking any task complete, verify compliance with every applicable practice on that page. This is a hard requirement, not a suggestion.
310+
311+
---
312+
304313
## References
305314

306315
### Essential Reading

api/v1alpha1/conditions.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package v1alpha1
2+
3+
// ImpVM condition type constants.
4+
const (
5+
ConditionScheduled = "Scheduled"
6+
ConditionReady = "Ready"
7+
ConditionNodeHealthy = "NodeHealthy"
8+
)
9+
10+
// ImpNetwork condition type constants.
11+
const (
12+
ConditionNetworkReady = "Ready"
13+
)

cmd/operator/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ func main() {
123123

124124
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metrics endpoint binds to.")
125125
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
126-
flag.BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager.")
126+
flag.BoolVar(&enableLeaderElection, "leader-elect", true, "Enable leader election for controller manager.")
127127
flag.BoolVar(&enableWebhooks, "enable-webhooks", true, "Enable admission webhooks.")
128128

129129
opts := zap.Options{Development: true}

internal/controller/events.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,3 @@ const (
2020
EventReasonCiliumConfigMissing = "CiliumConfigMissing"
2121
EventReasonGroupCIDRError = "GroupCIDRError"
2222
)
23-
24-
// ImpVM condition type constants.
25-
const (
26-
ConditionScheduled = "Scheduled"
27-
ConditionReady = "Ready"
28-
ConditionNodeHealthy = "NodeHealthy"
29-
)
30-
31-
// ImpNetwork condition type constants.
32-
const (
33-
ConditionNetworkReady = "Ready"
34-
)

internal/controller/impnetwork_controller.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,9 @@ func (r *ImpNetworkReconciler) Reconcile(ctx context.Context, req ctrl.Request)
6767
}
6868

6969
if !controllerutil.ContainsFinalizer(net, finalizerImpNetwork) {
70+
patch := client.MergeFrom(net.DeepCopy())
7071
controllerutil.AddFinalizer(net, finalizerImpNetwork)
71-
return ctrl.Result{}, r.Update(ctx, net)
72+
return ctrl.Result{}, r.Patch(ctx, net, patch)
7273
}
7374

7475
return r.sync(ctx, net)
@@ -96,8 +97,9 @@ func (r *ImpNetworkReconciler) handleDeletion(ctx context.Context, net *impdevv1
9697
}
9798
}
9899

100+
patch := client.MergeFrom(net.DeepCopy())
99101
controllerutil.RemoveFinalizer(net, finalizerImpNetwork)
100-
return ctrl.Result{}, r.Update(ctx, net)
102+
return ctrl.Result{}, r.Patch(ctx, net, patch)
101103
}
102104

103105
// reconcileCiliumPool creates or updates the CiliumPodIPPool owned by this ImpNetwork.
@@ -170,7 +172,7 @@ func (r *ImpNetworkReconciler) sync(ctx context.Context, net *impdevv1alpha1.Imp
170172
r.Recorder.Eventf(net, corev1.EventTypeWarning, EventReasonCiliumConfigMissing,
171173
"Cilium ipMasqAgent not configured for subnet %s — see docs/networking/cilium.md",
172174
net.Spec.Subnet)
173-
log.Info("CiliumConfigMissing", "subnet", net.Spec.Subnet)
175+
log.Info("Cilium ipMasqAgent config missing", "subnet", net.Spec.Subnet)
174176
}
175177
}
176178

@@ -249,7 +251,7 @@ func (r *ImpNetworkReconciler) reconcileVTEPTable(ctx context.Context, net *impd
249251
return nil // no change
250252
}
251253

252-
logf.FromContext(ctx).Info("GCing stale VTEP entries",
254+
logf.FromContext(ctx).Info("Removed stale VTEP entries",
253255
"network", net.Name, "before", len(net.Status.VTEPTable), "after", len(filtered))
254256

255257
net.Status.VTEPTable = filtered
@@ -262,7 +264,7 @@ func (r *ImpNetworkReconciler) hasCiliumMasqConfig(ctx context.Context, subnet s
262264
cm := &corev1.ConfigMap{}
263265
if err := r.Get(ctx, client.ObjectKey{Namespace: "kube-system", Name: "ip-masq-agent"}, cm); err != nil {
264266
if !apierrors.IsNotFound(err) {
265-
logf.FromContext(ctx).V(1).Info("ip-masq-agent ConfigMap lookup failed", "err", err)
267+
logf.FromContext(ctx).V(1).Info("IP masq agent ConfigMap lookup failed", "err", err)
266268
}
267269
return false
268270
}
@@ -272,7 +274,7 @@ func (r *ImpNetworkReconciler) hasCiliumMasqConfig(ctx context.Context, subnet s
272274
// setNetworkReady sets the Ready condition to True on an ImpNetwork.
273275
func setNetworkReady(net *impdevv1alpha1.ImpNetwork) {
274276
apimeta.SetStatusCondition(&net.Status.Conditions, metav1.Condition{
275-
Type: ConditionNetworkReady,
277+
Type: impdevv1alpha1.ConditionNetworkReady,
276278
Status: metav1.ConditionTrue,
277279
Reason: "Reconciled",
278280
Message: "ImpNetwork reconciled successfully",
@@ -296,7 +298,7 @@ func (r *ImpNetworkReconciler) ciliumPresent() bool {
296298
func (r *ImpNetworkReconciler) reconcileGroupCIDRs(ctx context.Context, net *impdevv1alpha1.ImpNetwork) error {
297299
desired, err := carveGroupCIDRs(net.Spec.Subnet, net.Spec.Groups)
298300
if err != nil {
299-
logf.FromContext(ctx).Error(err, "group CIDR carving failed", "network", net.Name)
301+
logf.FromContext(ctx).Error(err, "Group CIDR carving failed", "network", net.Name)
300302
r.Recorder.Eventf(net, corev1.EventTypeWarning, EventReasonGroupCIDRError,
301303
"Group CIDR carving failed: %v", err)
302304
return nil // don't block reconcile for this — operator continues without group CIDRs
@@ -379,7 +381,7 @@ func (r *ImpNetworkReconciler) reconcileCiliumEnrollment(ctx context.Context, ne
379381
cew := &cewList.Items[i]
380382
vmKey := cew.GetLabels()["imp.dev/vm-key"] // namespace/name
381383
if _, ok := runningVMs[vmKey]; !ok {
382-
log.Info("deleting stale CiliumExternalWorkload", "cew", cew.GetName(), "vmKey", vmKey)
384+
log.Info("Deleted stale CiliumExternalWorkload", "cew", cew.GetName(), "vmKey", vmKey)
383385
if err := r.Delete(ctx, cew); err != nil && !apierrors.IsNotFound(err) {
384386
return err
385387
}
@@ -411,11 +413,11 @@ func (r *ImpNetworkReconciler) reconcileCiliumEnrollment(ctx context.Context, ne
411413
})
412414
if vm.Status.IP != "" {
413415
if err := unstructured.SetNestedField(cew.Object, vm.Status.IP+"/32", "spec", "ipv4AllocCIDR"); err != nil {
414-
log.Error(err, "failed to set ipv4AllocCIDR", "vm", vm.Name)
416+
log.Error(err, "Failed to set IPv4 alloc CIDR", "vm", vm.Name)
415417
}
416418
}
417419

418-
log.Info("creating CiliumExternalWorkload", "cew", cewName, "vm", vm.Name)
420+
log.Info("Created CiliumExternalWorkload", "cew", cewName, "vm", vm.Name)
419421
if err := r.Create(ctx, cew); err != nil && !apierrors.IsAlreadyExists(err) {
420422
return err
421423
}

internal/controller/impnetwork_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ var _ = Describe("ImpNetwork Controller: core", func() {
8282

8383
updated := &impdevv1alpha1.ImpNetwork{}
8484
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "core-net-2", Namespace: "default"}, updated)).To(Succeed())
85-
c := apimeta.FindStatusCondition(updated.Status.Conditions, ConditionNetworkReady)
85+
c := apimeta.FindStatusCondition(updated.Status.Conditions, impdevv1alpha1.ConditionNetworkReady)
8686
Expect(c).NotTo(BeNil())
8787
Expect(c.Status).To(Equal(metav1.ConditionTrue))
8888
})

internal/controller/impvm_conditions.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,32 +20,32 @@ func setCondition(vm *impdevv1alpha1.ImpVM, condType string, status metav1.Condi
2020
}
2121

2222
func setScheduled(vm *impdevv1alpha1.ImpVM, nodeName string) {
23-
setCondition(vm, ConditionScheduled, metav1.ConditionTrue, "NodeAssigned",
23+
setCondition(vm, impdevv1alpha1.ConditionScheduled, metav1.ConditionTrue, "NodeAssigned",
2424
"VM scheduled to node "+nodeName)
2525
}
2626

2727
func setUnscheduled(vm *impdevv1alpha1.ImpVM) {
28-
setCondition(vm, ConditionScheduled, metav1.ConditionFalse, "NoNodeAvailable",
28+
setCondition(vm, impdevv1alpha1.ConditionScheduled, metav1.ConditionFalse, "NoNodeAvailable",
2929
"No eligible node with available capacity")
3030
}
3131

3232
func setNodeHealthy(vm *impdevv1alpha1.ImpVM) {
33-
setCondition(vm, ConditionNodeHealthy, metav1.ConditionTrue, "NodeReady", "Assigned node is Ready")
33+
setCondition(vm, impdevv1alpha1.ConditionNodeHealthy, metav1.ConditionTrue, "NodeReady", "Assigned node is Ready")
3434
}
3535

3636
func setNodeUnhealthy(vm *impdevv1alpha1.ImpVM, reason string) {
37-
setCondition(vm, ConditionNodeHealthy, metav1.ConditionFalse, "NodeNotReady", reason)
37+
setCondition(vm, impdevv1alpha1.ConditionNodeHealthy, metav1.ConditionFalse, "NodeNotReady", reason)
3838
}
3939

4040
func setReadyFromPhase(vm *impdevv1alpha1.ImpVM) {
4141
switch vm.Status.Phase {
4242
case impdevv1alpha1.VMPhaseRunning:
43-
setCondition(vm, ConditionReady, metav1.ConditionTrue, "Running", "VM is running")
43+
setCondition(vm, impdevv1alpha1.ConditionReady, metav1.ConditionTrue, "Running", "VM is running")
4444
case impdevv1alpha1.VMPhaseSucceeded:
45-
setCondition(vm, ConditionReady, metav1.ConditionFalse, "Completed", "VM completed successfully")
45+
setCondition(vm, impdevv1alpha1.ConditionReady, metav1.ConditionFalse, "Completed", "VM completed successfully")
4646
case impdevv1alpha1.VMPhaseFailed:
47-
setCondition(vm, ConditionReady, metav1.ConditionFalse, "Failed", "VM failed")
47+
setCondition(vm, impdevv1alpha1.ConditionReady, metav1.ConditionFalse, "Failed", "VM failed")
4848
default:
49-
setCondition(vm, ConditionReady, metav1.ConditionUnknown, "Waiting", "Waiting for VM to start")
49+
setCondition(vm, impdevv1alpha1.ConditionReady, metav1.ConditionUnknown, "Waiting", "Waiting for VM to start")
5050
}
5151
}

internal/controller/impvm_controller.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,9 @@ func (r *ImpVMReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resu
8585

8686
// 2. Ensure finalizer
8787
if !controllerutil.ContainsFinalizer(vm, finalizerImp) {
88+
patch := client.MergeFrom(vm.DeepCopy())
8889
controllerutil.AddFinalizer(vm, finalizerImp)
89-
return ctrl.Result{}, r.Update(ctx, vm)
90+
return ctrl.Result{}, r.Patch(ctx, vm, patch)
9091
}
9192

9293
// 3. Handle manual retry reset annotation
@@ -102,8 +103,8 @@ func (r *ImpVMReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resu
102103
if !alreadyMarked {
103104
base := vm.DeepCopy()
104105
vm.Status.Phase = impdevv1alpha1.VMPhaseFailed
105-
setCondition(vm, ConditionScheduled, metav1.ConditionFalse, EventReasonSpecInvalid, msg)
106-
setCondition(vm, ConditionReady, metav1.ConditionFalse, EventReasonSpecInvalid, msg)
106+
setCondition(vm, impdevv1alpha1.ConditionScheduled, metav1.ConditionFalse, EventReasonSpecInvalid, msg)
107+
setCondition(vm, impdevv1alpha1.ConditionReady, metav1.ConditionFalse, EventReasonSpecInvalid, msg)
107108
if err := r.Status().Patch(ctx, vm, client.MergeFrom(base)); err != nil {
108109
return ctrl.Result{}, err
109110
}
@@ -119,7 +120,7 @@ func (r *ImpVMReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resu
119120
return ctrl.Result{}, err
120121
}
121122
if nodeName == "" {
122-
log.Info("no node available", "vm", vm.Name)
123+
log.Info("No node available", "vm", vm.Name)
123124
vmCopy := vm.DeepCopy()
124125
vm.Status.Phase = impdevv1alpha1.VMPhasePending
125126
setUnscheduled(vm)
@@ -240,7 +241,7 @@ func (r *ImpVMReconciler) syncStatus(ctx context.Context, vm *impdevv1alpha1.Imp
240241
if err == nil {
241242
reason = "node is not Ready"
242243
}
243-
log.Info("assigned node unhealthy", "node", vm.Spec.NodeName, "reason", reason)
244+
log.Info("Assigned node unhealthy", "node", vm.Spec.NodeName, "reason", reason)
244245

245246
if vm.Spec.Lifecycle == impdevv1alpha1.VMLifecycleEphemeral {
246247
// Clear assignment — spec patch first.
@@ -345,17 +346,19 @@ func (r *ImpVMReconciler) handleDeletion(ctx context.Context, vm *impdevv1alpha1
345346

346347
// Agent already cleaned up (cleared spec.nodeName + set Succeeded)
347348
if vm.Spec.NodeName == "" {
349+
patch := client.MergeFrom(vm.DeepCopy())
348350
controllerutil.RemoveFinalizer(vm, finalizerImp)
349-
return ctrl.Result{}, r.Update(ctx, vm)
351+
return ctrl.Result{}, r.Patch(ctx, vm, patch)
350352
}
351353

352354
// Check for termination timeout
353355
deadline := vm.DeletionTimestamp.Add(terminationTimeout)
354356
if time.Now().After(deadline) {
355357
r.Recorder.Event(vm, corev1.EventTypeWarning, EventReasonTerminationTimeout,
356358
"Finalizer force-removed after 2min termination timeout")
359+
patch := client.MergeFrom(vm.DeepCopy())
357360
controllerutil.RemoveFinalizer(vm, finalizerImp)
358-
return ctrl.Result{}, r.Update(ctx, vm)
361+
return ctrl.Result{}, r.Patch(ctx, vm, patch)
359362
}
360363

361364
// Signal agent by setting phase=Terminating

internal/controller/impvm_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ var _ = Describe("ImpVM Spec Validation Fallback", func() {
265265
var readyCond *metav1.Condition
266266
for i := range updated.Status.Conditions {
267267
c := &updated.Status.Conditions[i]
268-
if c.Type == ConditionReady {
268+
if c.Type == impdevv1alpha1.ConditionReady {
269269
readyCond = c
270270
break
271271
}

internal/controller/impvm_coverage_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ var _ = Describe("setScheduled / setUnscheduled", func() {
6868
It("sets Scheduled condition to True with correct reason", func() {
6969
vm := &impdevv1alpha1.ImpVM{}
7070
setScheduled(vm, "node-1")
71-
c := apimeta.FindStatusCondition(vm.Status.Conditions, ConditionScheduled)
71+
c := apimeta.FindStatusCondition(vm.Status.Conditions, impdevv1alpha1.ConditionScheduled)
7272
Expect(c).NotTo(BeNil())
7373
Expect(c.Status).To(Equal(metav1.ConditionTrue))
7474
Expect(c.Reason).To(Equal("NodeAssigned"))
@@ -77,7 +77,7 @@ var _ = Describe("setScheduled / setUnscheduled", func() {
7777
It("sets Scheduled condition to False via setUnscheduled", func() {
7878
vm := &impdevv1alpha1.ImpVM{}
7979
setUnscheduled(vm)
80-
c := apimeta.FindStatusCondition(vm.Status.Conditions, ConditionScheduled)
80+
c := apimeta.FindStatusCondition(vm.Status.Conditions, impdevv1alpha1.ConditionScheduled)
8181
Expect(c).NotTo(BeNil())
8282
Expect(c.Status).To(Equal(metav1.ConditionFalse))
8383
})
@@ -87,15 +87,15 @@ var _ = Describe("setNodeHealthy / setNodeUnhealthy", func() {
8787
It("sets NodeHealthy=True", func() {
8888
vm := &impdevv1alpha1.ImpVM{}
8989
setNodeHealthy(vm)
90-
c := apimeta.FindStatusCondition(vm.Status.Conditions, ConditionNodeHealthy)
90+
c := apimeta.FindStatusCondition(vm.Status.Conditions, impdevv1alpha1.ConditionNodeHealthy)
9191
Expect(c).NotTo(BeNil())
9292
Expect(c.Status).To(Equal(metav1.ConditionTrue))
9393
})
9494

9595
It("sets NodeHealthy=False with reason", func() {
9696
vm := &impdevv1alpha1.ImpVM{}
9797
setNodeUnhealthy(vm, "node not found")
98-
c := apimeta.FindStatusCondition(vm.Status.Conditions, ConditionNodeHealthy)
98+
c := apimeta.FindStatusCondition(vm.Status.Conditions, impdevv1alpha1.ConditionNodeHealthy)
9999
Expect(c).NotTo(BeNil())
100100
Expect(c.Status).To(Equal(metav1.ConditionFalse))
101101
Expect(c.Message).To(Equal("node not found"))
@@ -108,7 +108,7 @@ var _ = Describe("setReadyFromPhase", func() {
108108
vm := &impdevv1alpha1.ImpVM{}
109109
vm.Status.Phase = phase
110110
setReadyFromPhase(vm)
111-
c := apimeta.FindStatusCondition(vm.Status.Conditions, ConditionReady)
111+
c := apimeta.FindStatusCondition(vm.Status.Conditions, impdevv1alpha1.ConditionReady)
112112
Expect(c).NotTo(BeNil())
113113
Expect(c.Status).To(Equal(expectedStatus))
114114
},
@@ -122,7 +122,7 @@ var _ = Describe("setReadyFromPhase", func() {
122122
vm := &impdevv1alpha1.ImpVM{}
123123
vm.Status.Phase = impdevv1alpha1.VMPhaseSucceeded
124124
setReadyFromPhase(vm)
125-
c := apimeta.FindStatusCondition(vm.Status.Conditions, ConditionReady)
125+
c := apimeta.FindStatusCondition(vm.Status.Conditions, impdevv1alpha1.ConditionReady)
126126
Expect(c).NotTo(BeNil())
127127
Expect(c.Reason).To(Equal("Completed"))
128128
Expect(c.Message).To(Equal("VM completed successfully"))
@@ -291,7 +291,7 @@ var _ = Describe("applyHTTPCheck", func() {
291291
changed := r.applyHTTPCheck(ctx, vm, spec)
292292
Expect(changed).To(BeTrue())
293293
Expect(vm.Annotations["imp/httpcheck-failures"]).To(Equal("0"))
294-
c := apimeta.FindStatusCondition(vm.Status.Conditions, ConditionReady)
294+
c := apimeta.FindStatusCondition(vm.Status.Conditions, impdevv1alpha1.ConditionReady)
295295
Expect(c).NotTo(BeNil())
296296
Expect(c.Status).To(Equal(metav1.ConditionTrue))
297297
})
@@ -311,7 +311,7 @@ var _ = Describe("applyHTTPCheck", func() {
311311
r.applyHTTPCheck(ctx, vm, spec)
312312
Expect(vm.Annotations["imp/httpcheck-failures"]).To(Equal("1"))
313313
// Not yet at threshold — Ready should not be False.
314-
c := apimeta.FindStatusCondition(vm.Status.Conditions, ConditionReady)
314+
c := apimeta.FindStatusCondition(vm.Status.Conditions, impdevv1alpha1.ConditionReady)
315315
Expect(c).NotTo(BeNil())
316316
Expect(c.Status).NotTo(Equal(metav1.ConditionFalse))
317317
})
@@ -330,7 +330,7 @@ var _ = Describe("applyHTTPCheck", func() {
330330

331331
r.applyHTTPCheck(ctx, vm, spec)
332332
Expect(vm.Annotations["imp/httpcheck-failures"]).To(Equal("1"))
333-
c := apimeta.FindStatusCondition(vm.Status.Conditions, ConditionReady)
333+
c := apimeta.FindStatusCondition(vm.Status.Conditions, impdevv1alpha1.ConditionReady)
334334
Expect(c).NotTo(BeNil())
335335
Expect(c.Status).To(Equal(metav1.ConditionFalse))
336336
Expect(c.Reason).To(Equal("HealthCheckFailed"))
@@ -887,7 +887,7 @@ var _ = Describe("ImpVM syncStatus: node healthy", func() {
887887

888888
updated := &impdevv1alpha1.ImpVM{}
889889
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "sync-healthy-vm", Namespace: "default"}, updated)).To(Succeed())
890-
c := apimeta.FindStatusCondition(updated.Status.Conditions, ConditionNodeHealthy)
890+
c := apimeta.FindStatusCondition(updated.Status.Conditions, impdevv1alpha1.ConditionNodeHealthy)
891891
Expect(c).NotTo(BeNil())
892892
Expect(c.Status).To(Equal(metav1.ConditionTrue))
893893
})

0 commit comments

Comments
 (0)