From 6e8f5d0a3d52e11f5e4f8459201b9ebc13724a66 Mon Sep 17 00:00:00 2001 From: Mohamed Mahmoud Date: Tue, 4 Jun 2024 16:21:00 -0400 Subject: [PATCH] add application object controllers Signed-off-by: Mohamed Mahmoud --- cmd/bpfman-agent/main.go | 7 + .../bpfman-agent/application-program.go | 239 ++++++++++++++++++ .../bpfman-agent/application-program_test.go | 91 +++++++ .../application-program_test.go | 221 ++++++++++++++++ .../bpfman-operator/application-programs.go | 59 +---- 5 files changed, 560 insertions(+), 57 deletions(-) create mode 100644 controllers/bpfman-agent/application-program.go create mode 100644 controllers/bpfman-agent/application-program_test.go create mode 100644 controllers/bpfman-operator/application-program_test.go diff --git a/cmd/bpfman-agent/main.go b/cmd/bpfman-agent/main.go index 9d63bac18..c99630adc 100644 --- a/cmd/bpfman-agent/main.go +++ b/cmd/bpfman-agent/main.go @@ -193,6 +193,13 @@ func main() { os.Exit(1) } + if err = (&bpfmanagent.BpfApplicationReconciler{ + ReconcilerCommon: common, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create BpfApplicationProgram controller", "controller", "BpfProgram") + os.Exit(1) + } + //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/controllers/bpfman-agent/application-program.go b/controllers/bpfman-agent/application-program.go new file mode 100644 index 000000000..a4ebc0902 --- /dev/null +++ b/controllers/bpfman-agent/application-program.go @@ -0,0 +1,239 @@ +package bpfmanagent + +import ( + "context" + "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + "github.com/bpfman/bpfman-operator/internal" + + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +type BpfApplicationReconciler struct { + ReconcilerCommon + currentApp *bpfmaniov1alpha1.BpfApplication + ourNode *v1.Node +} + +func (r *BpfApplicationReconciler) getFinalizer() string { + return internal.BpfApplicationControllerFinalizer +} + +func (r *BpfApplicationReconciler) getName() string { + return r.currentApp.Name +} + +func (r *BpfApplicationReconciler) getNode() *v1.Node { + return r.ourNode +} + +func (r *BpfApplicationReconciler) getNodeSelector() *metav1.LabelSelector { + return &r.currentApp.Spec.NodeSelector +} + +func (r *BpfApplicationReconciler) getBpfGlobalData() map[string][]byte { + return r.currentApp.Spec.GlobalData +} + +func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + // Initialize node and current program + r.currentApp = &bpfmaniov1alpha1.BpfApplication{} + r.ourNode = &v1.Node{} + r.Logger = ctrl.Log.WithName("application") + + ctxLogger := log.FromContext(ctx) + ctxLogger.Info("Reconcile Application: Enter", "ReconcileKey", req) + + // Lookup K8s node object for this bpfman-agent This should always succeed + if err := r.Get(ctx, types.NamespacedName{Namespace: v1.NamespaceAll, Name: r.NodeName}, r.ourNode); err != nil { + return ctrl.Result{Requeue: false}, fmt.Errorf("failed getting bpfman-agent node %s : %v", + req.NamespacedName, err) + } + + appPrograms := &bpfmaniov1alpha1.BpfApplicationList{} + + opts := []client.ListOption{} + + if err := r.List(ctx, appPrograms, opts...); err != nil { + return ctrl.Result{Requeue: false}, fmt.Errorf("failed getting BpfApplicationPrograms for full reconcile %s : %v", + req.NamespacedName, err) + } + + if len(appPrograms.Items) == 0 { + r.Logger.Info("BpfApplicationController found no application Programs") + return ctrl.Result{Requeue: false}, nil + } + + var res ctrl.Result + var err error + + for _, a := range appPrograms.Items { + for _, p := range a.Spec.Programs { + switch p.Type { + case bpfmaniov1alpha1.ProgTypeFentry: + fentryProgram := bpfmaniov1alpha1.FentryProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: a.Name + "fentry", + }, + Spec: bpfmaniov1alpha1.FentryProgramSpec{ + FentryProgramInfo: *p.Fentry, + BpfAppCommon: a.Spec.BpfAppCommon, + }, + } + rec := &FentryProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + currentFentryProgram: &fentryProgram, + } + fentryObjects := []client.Object{&fentryProgram} + // Reconcile FentryProgram. + res, err = r.reconcileCommon(ctx, rec, fentryObjects) + + case bpfmaniov1alpha1.ProgTypeFexit: + fexitProgram := bpfmaniov1alpha1.FexitProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: a.Name + "fexit", + }, + Spec: bpfmaniov1alpha1.FexitProgramSpec{ + FexitProgramInfo: *p.Fexit, + BpfAppCommon: a.Spec.BpfAppCommon, + }, + } + rec := &FexitProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + currentFexitProgram: &fexitProgram, + } + fexitObjects := []client.Object{&fexitProgram} + // Reconcile FexitProgram. + res, err = r.reconcileCommon(ctx, rec, fexitObjects) + + case bpfmaniov1alpha1.ProgTypeKprobe, bpfmaniov1alpha1.ProgTypeKretprobe: + kprobeProgram := bpfmaniov1alpha1.KprobeProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: a.Name + "kprobe", + }, + Spec: bpfmaniov1alpha1.KprobeProgramSpec{ + KprobeProgramInfo: *p.Kprobe, + BpfAppCommon: a.Spec.BpfAppCommon, + }, + } + rec := &KprobeProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + currentKprobeProgram: &kprobeProgram, + } + kprobeObjects := []client.Object{&kprobeProgram} + // Reconcile KprobeProgram or KpretprobeProgram. + res, err = r.reconcileCommon(ctx, rec, kprobeObjects) + + case bpfmaniov1alpha1.ProgTypeUprobe, bpfmaniov1alpha1.ProgTypeUretprobe: + uprobeProgram := bpfmaniov1alpha1.UprobeProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: a.Name + "uprobe", + }, + Spec: bpfmaniov1alpha1.UprobeProgramSpec{ + UprobeProgramInfo: *p.Uprobe, + BpfAppCommon: a.Spec.BpfAppCommon, + }, + } + rec := &UprobeProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + currentUprobeProgram: &uprobeProgram, + } + uprobeObjects := []client.Object{&uprobeProgram} + // Reconcile UprobeProgram or UpretprobeProgram. + res, err = r.reconcileCommon(ctx, rec, uprobeObjects) + + case bpfmaniov1alpha1.ProgTypeTracepoint: + tracepointProgram := bpfmaniov1alpha1.TracepointProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: a.Name + "tracepoint", + }, + Spec: bpfmaniov1alpha1.TracepointProgramSpec{ + TracepointProgramInfo: *p.Tracepoint, + BpfAppCommon: a.Spec.BpfAppCommon, + }, + } + rec := &TracepointProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + currentTracepointProgram: &tracepointProgram, + } + tracepointObjects := []client.Object{&tracepointProgram} + // Reconcile TracepointProgram. + res, err = r.reconcileCommon(ctx, rec, tracepointObjects) + + case bpfmaniov1alpha1.ProgTypeTC: + tcProgram := bpfmaniov1alpha1.TcProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: a.Name + "tc", + }, + Spec: bpfmaniov1alpha1.TcProgramSpec{ + TcProgramInfo: *p.TC, + BpfAppCommon: a.Spec.BpfAppCommon, + }, + } + rec := &TcProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + currentTcProgram: &tcProgram, + } + tcObjects := []client.Object{&tcProgram} + // Reconcile TcProgram. + res, err = r.reconcileCommon(ctx, rec, tcObjects) + + case bpfmaniov1alpha1.ProgTypeXDP: + xdpProgram := bpfmaniov1alpha1.XdpProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: a.Name + "xdp", + }, + Spec: bpfmaniov1alpha1.XdpProgramSpec{ + XdpProgramInfo: *p.XDP, + BpfAppCommon: a.Spec.BpfAppCommon, + }, + } + rec := &XdpProgramReconciler{ + ReconcilerCommon: r.ReconcilerCommon, + currentXdpProgram: &xdpProgram, + } + xdpObjects := []client.Object{&xdpProgram} + // Reconcile XdpProgram. + res, err = r.reconcileCommon(ctx, rec, xdpObjects) + + default: + r.Logger.Info("Unsupported Bpf program type", "ProgType", p.Type) + return ctrl.Result{Requeue: false}, nil + } + } + } + + return res, err +} + +// SetupWithManager sets up the controller with the Manager. +// The Bpfman-Agent should reconcile whenever a BpfApplication object is updated, +// load the programs to the node via bpfman, and then create a bpfProgram object +// to reflect per node state information. +func (r *BpfApplicationReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&bpfmaniov1alpha1.BpfApplication{}, builder.WithPredicates(predicate.And(predicate.GenerationChangedPredicate{}, predicate.ResourceVersionChangedPredicate{}))). + Owns(&bpfmaniov1alpha1.BpfProgram{}, + builder.WithPredicates(predicate.And( + internal.BpfProgramNodePredicate(r.NodeName)), + ), + ). + // Only trigger reconciliation if node labels change since that could + // make the BpfApplication no longer select the Node. Additionally only + // care about node events specific to our node + Watches( + &v1.Node{}, + &handler.EnqueueRequestForObject{}, + builder.WithPredicates(predicate.And(predicate.LabelChangedPredicate{}, nodePredicate(r.NodeName))), + ). + Complete(r) +} diff --git a/controllers/bpfman-agent/application-program_test.go b/controllers/bpfman-agent/application-program_test.go new file mode 100644 index 000000000..7f2813408 --- /dev/null +++ b/controllers/bpfman-agent/application-program_test.go @@ -0,0 +1,91 @@ +package bpfmanagent + +import ( + "testing" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + testutils "github.com/bpfman/bpfman-operator/internal/test-utils" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" +) + +func TestBpfApplicationControllerCreate(t *testing.T) { + var ( + name = "fakeAppProgram" + bytecodePath = "/tmp/hello.o" + bpfFentryFunctionName = "fentry_test" + bpfKprobeFunctionName = "kprobe_test" + bpfTracepointFunctionName = "tracepoint-test" + fakeNode = testutils.NewNode("fake-control-plane") + functionFentryName = "do_unlinkat" + functionKprobeName = "try_to_wake_up" + tracepointName = "syscalls/sys_enter_setitimer" + offset = 0 + retprobe = false + ) + + // A AppProgram object with metadata and spec. + App := &bpfmaniov1alpha1.BpfApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: bpfmaniov1alpha1.BpfApplicationSpec{ + BpfAppCommon: bpfmaniov1alpha1.BpfAppCommon{ + NodeSelector: metav1.LabelSelector{}, + }, + Programs: []bpfmaniov1alpha1.BpfApplicationProgram{ + { + Type: bpfmaniov1alpha1.ProgTypeFentry, + Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfFentryFunctionName, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + FunctionName: functionFentryName, + }, + }, + { + Type: bpfmaniov1alpha1.ProgTypeKprobe, + Kprobe: &bpfmaniov1alpha1.KprobeProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfKprobeFunctionName, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + FunctionName: functionKprobeName, + Offset: uint64(offset), + RetProbe: retprobe, + }, + }, + { + Type: bpfmaniov1alpha1.ProgTypeTracepoint, + Tracepoint: &bpfmaniov1alpha1.TracepointProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfTracepointFunctionName, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + Names: []string{tracepointName}, + }, + }, + }, + }, + } + + // Objects to track in the fake client. + _ = []runtime.Object{fakeNode, App} + + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, App) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfApplicationList{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfApplication{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfProgramList{}) + +} diff --git a/controllers/bpfman-operator/application-program_test.go b/controllers/bpfman-operator/application-program_test.go new file mode 100644 index 000000000..c4ed5064b --- /dev/null +++ b/controllers/bpfman-operator/application-program_test.go @@ -0,0 +1,221 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package bpfmanoperator + +import ( + "context" + "fmt" + "testing" + + bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1" + internal "github.com/bpfman/bpfman-operator/internal" + testutils "github.com/bpfman/bpfman-operator/internal/test-utils" + + "github.com/stretchr/testify/require" + meta "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" +) + +// Runs the ApplicationProgramReconcile test. If multiCondition == true, it runs it +// with an error case in which the program object has multiple conditions. +func appProgramReconcile(t *testing.T, multiCondition bool) { + var ( + name = "fakeAppProgram" + bytecodePath = "/tmp/hello.o" + bpfFentryFunctionName = "fentry_test" + bpfKprobeFunctionName = "kprobe_test" + bpfTracepointFunctionName = "tracepoint-test" + fakeNode = testutils.NewNode("fake-control-plane") + functionFentryName = "do_unlinkat" + functionKprobeName = "try_to_wake_up" + tracepointName = "syscalls/sys_enter_setitimer" + offset = 0 + retprobe = false + ctx = context.TODO() + bpfProgName = fmt.Sprintf("%s-%s", name, fakeNode.Name) + ) + // A AppProgram object with metadata and spec. + App := &bpfmaniov1alpha1.BpfApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: bpfmaniov1alpha1.BpfApplicationSpec{ + BpfAppCommon: bpfmaniov1alpha1.BpfAppCommon{ + NodeSelector: metav1.LabelSelector{}, + }, + Programs: []bpfmaniov1alpha1.BpfApplicationProgram{ + { + Type: bpfmaniov1alpha1.ProgTypeFentry, + Fentry: &bpfmaniov1alpha1.FentryProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfFentryFunctionName, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + FunctionName: functionFentryName, + }, + }, + { + Type: bpfmaniov1alpha1.ProgTypeKprobe, + Kprobe: &bpfmaniov1alpha1.KprobeProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfKprobeFunctionName, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + FunctionName: functionKprobeName, + Offset: uint64(offset), + RetProbe: retprobe, + }, + }, + { + Type: bpfmaniov1alpha1.ProgTypeTracepoint, + Tracepoint: &bpfmaniov1alpha1.TracepointProgramInfo{ + BpfProgramCommon: bpfmaniov1alpha1.BpfProgramCommon{ + BpfFunctionName: bpfTracepointFunctionName, + ByteCode: bpfmaniov1alpha1.BytecodeSelector{ + Path: &bytecodePath, + }, + }, + Names: []string{tracepointName}, + }, + }, + }, + }, + } + + // The expected accompanying BpfProgram object + expectedBpfProg := &bpfmaniov1alpha1.BpfProgram{ + ObjectMeta: metav1.ObjectMeta{ + Name: bpfProgName, + OwnerReferences: []metav1.OwnerReference{ + { + Name: App.Name, + Controller: &[]bool{true}[0], + }, + }, + Labels: map[string]string{internal.BpfProgramOwnerLabel: App.Name, internal.K8sHostLabel: fakeNode.Name}, + Finalizers: []string{internal.BpfApplicationControllerFinalizer}, + }, + Spec: bpfmaniov1alpha1.BpfProgramSpec{ + Type: "application", + }, + Status: bpfmaniov1alpha1.BpfProgramStatus{ + Conditions: []metav1.Condition{bpfmaniov1alpha1.BpfProgCondLoaded.Condition()}, + }, + } + + // Objects to track in the fake client. + objs := []runtime.Object{fakeNode, App, expectedBpfProg} + + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, App) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfProgram{}) + s.AddKnownTypes(bpfmaniov1alpha1.SchemeGroupVersion, &bpfmaniov1alpha1.BpfProgramList{}) + + // Create a fake client to mock API calls. + cl := fake.NewClientBuilder().WithStatusSubresource(App).WithRuntimeObjects(objs...).Build() + + rc := ReconcilerCommon{ + Client: cl, + Scheme: s, + } + + // Set development Logger so we can see all logs in tests. + logf.SetLogger(zap.New(zap.UseFlagOptions(&zap.Options{Development: true}))) + + // Create a ApplicationProgram object with the scheme and fake client. + r := &BpfApplicationReconciler{ReconcilerCommon: rc} + + // Mock request to simulate Reconcile() being called on an event for a + // watched resource . + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: name, + }, + } + + // First reconcile should add the finalizer to the applicationProgram object + res, err := r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Require no requeue + require.False(t, res.Requeue) + + // Check the BpfProgram Object was created successfully + err = cl.Get(ctx, types.NamespacedName{Name: App.Name, Namespace: metav1.NamespaceAll}, App) + require.NoError(t, err) + + // Check the bpfman-operator finalizer was successfully added + require.Contains(t, App.GetFinalizers(), internal.BpfmanOperatorFinalizer) + + // NOTE: THIS IS A TEST FOR AN ERROR PATH. THERE SHOULD NEVER BE MORE THAN + // ONE CONDITION. + if multiCondition { + // Add some random conditions and verify that the condition still gets + // updated correctly. + meta.SetStatusCondition(&App.Status.Conditions, bpfmaniov1alpha1.ProgramDeleteError.Condition("bogus condition #1")) + if err := r.Status().Update(ctx, App); err != nil { + r.Logger.V(1).Info("failed to set App Program object status") + } + meta.SetStatusCondition(&App.Status.Conditions, bpfmaniov1alpha1.ProgramReconcileError.Condition("bogus condition #2")) + if err := r.Status().Update(ctx, App); err != nil { + r.Logger.V(1).Info("failed to set App Program object status") + } + // Make sure we have 2 conditions + require.Equal(t, 2, len(App.Status.Conditions)) + } + + // Second reconcile should check bpfProgram Status and write Success condition to tcProgram Status + res, err = r.Reconcile(ctx, req) + if err != nil { + t.Fatalf("reconcile: (%v)", err) + } + + // Require no requeue + require.False(t, res.Requeue) + + // Check the BpfProgram Object was created successfully + err = cl.Get(ctx, types.NamespacedName{Name: App.Name, Namespace: metav1.NamespaceAll}, App) + require.NoError(t, err) + + // Make sure we only have 1 condition now + require.Equal(t, 1, len(App.Status.Conditions)) + // Make sure it's the right one. + require.Equal(t, App.Status.Conditions[0].Type, string(bpfmaniov1alpha1.ProgramReconcileSuccess)) +} + +func TestAppProgramReconcile(t *testing.T) { + appProgramReconcile(t, false) +} + +func TestAppUpdateStatus(t *testing.T) { + appProgramReconcile(t, true) +} diff --git a/controllers/bpfman-operator/application-programs.go b/controllers/bpfman-operator/application-programs.go index 8e9afa2ab..4357b3878 100644 --- a/controllers/bpfman-operator/application-programs.go +++ b/controllers/bpfman-operator/application-programs.go @@ -1,5 +1,5 @@ /* -Copyright 2023 The bpfman Authors. +Copyright 2024 The bpfman Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -86,62 +86,7 @@ func (r *BpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Reque } } - return r.reconcileAppPrograms(ctx, appProgram) -} - -func (r *BpfApplicationReconciler) reconcileAppPrograms(ctx context.Context, application *bpfmaniov1alpha1.BpfApplication) (ctrl.Result, error) { - var result ctrl.Result - var err error - - for _, prog := range application.Spec.Programs { - switch prog.Type { - case bpfmaniov1alpha1.ProgTypeXDP: - r.Logger.Info("Reconciling Application XDP Programs") - result, err = reconcileBpfProgram(ctx, r, prog.XDP) - - case bpfmaniov1alpha1.ProgTypeTC: - r.Logger.Info("Reconciling Application TC Programs") - result, err = reconcileBpfProgram(ctx, r, prog.TC) - - case bpfmaniov1alpha1.ProgTypeFentry: - r.Logger.Info("Reconciling Application Fentry/Fexit Programs") - result, err = reconcileBpfProgram(ctx, r, prog.Fentry) - - case bpfmaniov1alpha1.ProgTypeFexit: - r.Logger.Info("Reconciling Application Fexit Programs") - result, err = reconcileBpfProgram(ctx, r, prog.Fexit) - - case bpfmaniov1alpha1.ProgTypeKprobe: - r.Logger.Info("Reconciling Application Kprobe Programs") - result, err = reconcileBpfProgram(ctx, r, prog.Kprobe) - - case bpfmaniov1alpha1.ProgTypeKretprobe: - r.Logger.Info("Reconciling Application Kretprobe Programs") - result, err = reconcileBpfProgram(ctx, r, prog.Kretprobe) - - case bpfmaniov1alpha1.ProgTypeUprobe: - r.Logger.Info("Reconciling Application Uprobe Programs") - result, err = reconcileBpfProgram(ctx, r, prog.Uprobe) - - case bpfmaniov1alpha1.ProgTypeUretprobe: - r.Logger.Info("Reconciling Application Uretprobe Programs") - result, err = reconcileBpfProgram(ctx, r, prog.Uretprobe) - - case bpfmaniov1alpha1.ProgTypeTracepoint: - r.Logger.Info("Reconciling Application Tracepoint Programs") - result, err = reconcileBpfProgram(ctx, r, prog.Tracepoint) - - default: - err := fmt.Errorf("invalid program type: %s", prog.Type) - r.Logger.Error(err, "invalid program type") - return ctrl.Result{}, err - } - if err != nil { - r.Logger.Error(err, "failed reconciling Application Programs") - return ctrl.Result{}, err - } - } - return result, nil + return reconcileBpfProgram(ctx, r, appProgram) } // SetupWithManager sets up the controller with the Manager.