1
0
Fork 0
mirror of https://github.com/imjasonh/client-go2 synced 2026-07-07 00:33:49 +00:00

Fix controller example to implement correct interface method (#6)

* Fix controller example to implement correct interface method

- Change ReconcileKind to Reconcile to match the Reconciler interface
- Add nil check for secretLister to handle initialization timing
- Fix OnError handler in e2e test to not fail immediately on expected errors

This allows the controller-owned-lister example to compile and run correctly.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Update examples/controller-owned-lister/main.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Jason Hall 2025-07-28 15:57:12 -04:00 committed by GitHub
parent da1a422278
commit 6c7409049e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 25 additions and 19 deletions

View file

@ -5,7 +5,7 @@ The `controller` package provides a generic Kubernetes controller framework insp
## Features
- **Type-safe generic controllers** - Build controllers for any Kubernetes resource type
- **Simple reconciler interface** - Just implement one method: `ReconcileKind` or pass a function.
- **Simple reconciler interface** - Just implement one method: `Reconcile` or pass a function.
- **Automatic update detection** - The framework detects and persists changes to your objects
- **Built-in conflict resolution** - Automatic retry with exponential backoff
- **Owner reference support** - Automatically reconcile owners when owned resources change
@ -42,7 +42,7 @@ The core interface has just one method:
```go
type Reconciler[T runtime.Object] interface {
ReconcileKind(ctx context.Context, obj T) error
Reconcile(ctx context.Context, obj T) error
}
```
@ -59,7 +59,7 @@ The controller automatically detects and persists changes made during reconcilia
Example:
```go
func (r *MyReconciler) ReconcileKind(ctx context.Context, pod *corev1.Pod) error {
func (r *MyReconciler) Reconcile(ctx context.Context, pod *corev1.Pod) error {
// These changes will be automatically persisted
pod.Labels["processed"] = "true"
pod.Status.Phase = corev1.PodRunning
@ -125,7 +125,7 @@ The controller can watch owned resources and reconcile owners when owned resourc
```go
// In your reconciler, set owner references
func (r *MyReconciler) ReconcileKind(ctx context.Context, pod *corev1.Pod) error {
func (r *MyReconciler) Reconcile(ctx context.Context, pod *corev1.Pod) error {
// Create a owned secret
secret := &corev1.Secret{...}

View file

@ -194,7 +194,7 @@ func (c *Controller[T]) processItem(ctx context.Context, key string) error {
original := c.deepCopy(current)
// Call user's reconciler - they modify 'current' in place
if err := c.reconciler.ReconcileKind(ctx, current); err != nil {
if err := c.reconciler.Reconcile(ctx, current); err != nil {
// Don't update if reconciler returned error
return err
}
@ -228,7 +228,7 @@ func (c *Controller[T]) updateIfNeeded(ctx context.Context, original, current T)
// Warn if spec changed (not allowed)
if specChanged {
clog.WarnContext(ctx, "spec changes ignored in ReconcileKind",
clog.WarnContext(ctx, "spec changes ignored in Reconcile",
"namespace", origMeta.Namespace,
"name", origMeta.Name)
}

View file

@ -31,7 +31,7 @@
// // dependencies
// }
//
// func (r *MyReconciler) ReconcileKind(ctx context.Context, pod *corev1.Pod) error {
// func (r *MyReconciler) Reconcile(ctx context.Context, pod *corev1.Pod) error {
// // Complex reconciliation logic
// return nil
// }

View file

@ -36,8 +36,8 @@ type PodReconciler struct {
// Add dependencies here
}
// ReconcileKind implements the Reconciler interface.
func (r *PodReconciler) ReconcileKind(ctx context.Context, pod *corev1.Pod) error {
// Reconcile implements the Reconciler interface.
func (r *PodReconciler) Reconcile(ctx context.Context, pod *corev1.Pod) error {
// Complex reconciliation logic
if pod.DeletionTimestamp != nil {
// Handle deletion

View file

@ -9,7 +9,7 @@ import (
// Reconciler is the interface for reconciling objects of type T.
// Implementations should mutate the object in-place. The controller will
// automatically persist any changes to the object's status and finalizers
// after ReconcileKind returns successfully.
// after Reconcile returns successfully.
//
// Important rules:
// - DO modify obj.Status to update status (will be persisted)
@ -17,7 +17,7 @@ import (
// - DO NOT modify obj.Spec (changes will be ignored and logged)
// - DO NOT modify obj.Metadata except for finalizers (changes will be ignored)
type Reconciler[T runtime.Object] interface {
ReconcileKind(ctx context.Context, obj T) error
Reconcile(ctx context.Context, obj T) error
}
// ReconcilerFunc is an adapter to allow ordinary functions to be used as Reconcilers.
@ -25,7 +25,7 @@ type Reconciler[T runtime.Object] interface {
// Reconciler[T] that calls f.
type ReconcilerFunc[T runtime.Object] func(ctx context.Context, obj T) error
// ReconcileKind calls f(ctx, obj).
func (f ReconcilerFunc[T]) ReconcileKind(ctx context.Context, obj T) error {
// Reconcile calls f(ctx, obj).
func (f ReconcilerFunc[T]) Reconcile(ctx context.Context, obj T) error {
return f(ctx, obj)
}

View file

@ -28,7 +28,7 @@ func TestReconcilerFunc(t *testing.T) {
},
}
err := fn.ReconcileKind(context.Background(), pod)
err := fn.Reconcile(context.Background(), pod)
if !called {
t.Error("reconciler function was not called")
}
@ -43,7 +43,7 @@ type testReconciler struct {
err error
}
func (r *testReconciler) ReconcileKind(ctx context.Context, pod *corev1.Pod) error {
func (r *testReconciler) Reconcile(ctx context.Context, pod *corev1.Pod) error {
r.called = true
// Modify the pod to test automatic updates
if pod.Status.Phase == "" {
@ -63,7 +63,7 @@ func TestReconcilerInterface(t *testing.T) {
},
}
err := r.ReconcileKind(context.Background(), pod)
err := r.Reconcile(context.Background(), pod)
if !r.called {
t.Error("reconciler was not called")
}

View file

@ -18,9 +18,15 @@ type ConfigMapReconciler struct {
secretLister *generic.Lister[*corev1.Secret]
}
func (r *ConfigMapReconciler) ReconcileKind(ctx context.Context, cm *corev1.ConfigMap) error {
func (r *ConfigMapReconciler) Reconcile(ctx context.Context, cm *corev1.ConfigMap) error {
log := clog.FromContext(ctx)
// Check if secretLister is available
if r.secretLister == nil {
log.Info("Secret lister not available yet")
return fmt.Errorf("secret lister not available")
}
// List secrets in the same namespace
secrets, err := r.secretLister.ByNamespace(cm.Namespace).List(labels.Everything())
if err != nil {

View file

@ -23,8 +23,8 @@ type ConfigMapReconciler struct {
logger *slog.Logger
}
// ReconcileKind implements the reconciliation logic for ConfigMaps.
func (r *ConfigMapReconciler) ReconcileKind(ctx context.Context, cm *corev1.ConfigMap) error {
// Reconcile implements the reconciliation logic for ConfigMaps.
func (r *ConfigMapReconciler) Reconcile(ctx context.Context, cm *corev1.ConfigMap) error {
r.logger.Info("reconciling configmap",
"namespace", cm.Namespace,
"name", cm.Name,