Skip to content

Refactor ClusterBpfApplication reconciler to follow standard Kubernetes controller patterns #454

@frobware

Description

@frobware

The ClusterBpfApplication reconciler currently processes all objects in each reconcile call rather than following the standard Kubernetes controller pattern of processing one object per call.

Current Behaviour

The reconciler:

  1. Lists ALL ClusterBpfApplication objects
  2. Loops through each one, reconciling them all in a single reconcile call
  3. Returns early on various conditions, potentially leaving objects unprocessed

Issues This Causes

  1. "Object not found" log noise: When objects are deleted but still in the work queue, the controller tries to reconcile non-existent objects, generating excessive error logs
  2. Performance impact: O(n) complexity on every reconcile call instead of O(1)
  3. Error propagation: One failing object can block reconciliation of all others
  4. Concurrency concerns: Multiple reconcile calls can process the same objects simultaneously
  5. Unpredictable behavior: Early returns may leave objects unprocessed
  6. Framework integration: Doesn't align with controller-runtime's work queue management and retry logic

Observations

  • High volume of "ClusterBpfApplication" errors & messages in logs
  • Unnecessary API server load from listing all objects repeatedly
  • Potential delays in object reconciliation due to early returns
  • Severely impacts cluster operations: When make -C bpfman/examples deploy is run without Security Profiles operator (e.g., OpenShift), load failures combined with the N-times processing per reconcile generates thousands of log messages, making the cluster difficult to operate and debug

Solution

Update the reconciler to follow the standard Kubernetes controller pattern where each reconcile call processes exactly one object:

func (r *ClBpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
      // Get the specific object that triggered this reconcile
      r.currentApp = &bpfmaniov1alpha1.ClusterBpfApplication{}
      if err := r.Get(ctx, req.NamespacedName, r.currentApp); err != nil {
          if errors.IsNotFound(err) {
              // Object was deleted, nothing to do
              return ctrl.Result{}, nil
          }
          return ctrl.Result{}, err
      }

      // Reconcile this specific object
      return r.reconcileObject(ctx)
  }

Benefits of This Approach

  • Each reconcile call processes exactly one object (better isolation)
  • Deleted objects are handled gracefully (eliminates log noise)
  • More efficient API usage
  • Better alignment with controller-runtime patterns
  • Improved error handling and recovery

Files affected:

  • controllers/bpfman-agent/cl_application_program.go
  • controllers/bpfman-agent/ns_application_program.go

References:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    🆕 New

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions