Skip to content

Commit

Permalink
Generalize common functions to support other program types
Browse files Browse the repository at this point in the history
Also, rename application-common.go to common.go.

Signed-off-by: Andre Fredette <[email protected]>
  • Loading branch information
anfredette committed Jan 23, 2025
1 parent d68ab2a commit 83561f6
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 315 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ metadata:
capabilities: Basic Install
categories: OpenShift Optional
containerImage: quay.io/bpfman/bpfman-operator:latest
createdAt: "2025-01-22T17:15:06Z"
createdAt: "2025-01-22T23:05:42Z"
features.operators.openshift.io/cnf: "false"
features.operators.openshift.io/cni: "false"
features.operators.openshift.io/csi: "true"
Expand Down
23 changes: 21 additions & 2 deletions controllers/app-agent/application-program.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/bpfman/bpfman-operator/internal"

v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -53,8 +54,12 @@ type BpfApplicationReconciler struct {
ourNode *v1.Node
}

func (r *BpfApplicationReconciler) getRecType() string {
return internal.ApplicationString
// func (r *BpfApplicationReconciler) getRecType() string {
// return internal.ApplicationString
// }

func (r *BpfApplicationReconciler) getAppNodeName() string {
return r.currentAppNode.Name
}

func (r *BpfApplicationReconciler) getNode() *v1.Node {
Expand All @@ -69,6 +74,20 @@ func (r *BpfApplicationReconciler) GetStatus() *bpfmaniov1alpha1.BpfAppStatus {
return &r.currentAppNode.Status
}

func (r *BpfApplicationReconciler) isBeingDeleted() bool {
return !r.currentApp.GetDeletionTimestamp().IsZero()
}

func (r *BpfApplicationReconciler) updateBpfAppStatus(ctx context.Context, condition metav1.Condition) error {
r.currentAppNode.Status.Conditions = nil
meta.SetStatusCondition(&r.currentAppNode.Status.Conditions, condition)
return r.Status().Update(ctx, r.currentAppNode)
}

func (r *BpfApplicationReconciler) updateLoadStatus(newCondition bpfmaniov1alpha1.BpfProgramConditionType) {
r.currentAppNode.Spec.AppLoadStatus = newCondition
}

// 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
Expand Down
217 changes: 28 additions & 189 deletions controllers/app-agent/application-program_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package appagent

import (
"context"
"reflect"
"testing"

bpfmaniov1alpha1 "github.com/bpfman/bpfman-operator/apis/v1alpha1"
Expand Down Expand Up @@ -154,10 +155,7 @@ func TestBpfApplicationControllerCreate(t *testing.T) {

// ANF-TODO: Check more fields?

//////////////////////////////////////////////////////////
// Do another reconcile and make sure there are no changes
//////////////////////////////////////////////////////////

// Do a second reconcile and check that Status was updated
r.Logger.Info("Second reconcile")
res, err = r.Reconcile(ctx, req)
require.NoError(t, err)
Expand All @@ -179,12 +177,31 @@ func TestBpfApplicationControllerCreate(t *testing.T) {
require.Equal(t, 1, len(bpfAppNode2.Status.Conditions))
require.Equal(t, string(bpfmaniov1alpha1.ProgramReconcileSuccess), bpfAppNode2.Status.Conditions[0].Type)

// ANF-TODO: This needs to be checked after the 3rd reconcile
// // Check that the bpfAppNode was not updated
// require.True(t, reflect.DeepEqual(bpfAppNode, bpfAppNode2))
// Do a 3rd reconcile and make sure it doesn't change
r.Logger.Info("Third reconcile")
res, err = r.Reconcile(ctx, req)
require.NoError(t, err)

// Require no requeue
require.False(t, res.Requeue)

r.Logger.Info("Third reconcile", "res:", res, "err:", err)

// Check the BpfProgram Object was created successfully
bpfAppNode3, bpfAppNodeNew, err := r.getBpfAppNode(ctx, false)
require.NoError(t, err)

// Make sure we got bpfAppNode from the api server and didn't create a new
// one.
require.Equal(t, false, bpfAppNodeNew)

// Check that the bpfAppNode was not updated
require.True(t, reflect.DeepEqual(bpfAppNode2, bpfAppNode3))

currentProgram := programMap[xdpBpfFunctionName]

attachPoint := bpfAppNode.Spec.Programs[xdpBpfFunctionName].XDP.AttachPoints[0]

xdpReconciler := &XdpProgramReconciler{
ReconcilerCommon: rc,
appCommon: bpfmaniov1alpha1.BpfAppCommon{
Expand All @@ -195,190 +212,12 @@ func TestBpfApplicationControllerCreate(t *testing.T) {
},
currentProgram: &currentProgram,
currentProgramNode: &bpfmaniov1alpha1.BpfApplicationProgramNode{},
ourNode: fakeNode,
currentAttachPoint: &attachPoint,
}

attachPoint := bpfAppNode.Spec.Programs[xdpBpfFunctionName].XDP.AttachPoints[0]

loadRequest, err := xdpReconciler.getLoadRequest(xdpBpfFunctionName, &attachPoint, nil)
loadRequest, err := xdpReconciler.getLoadRequest(nil)
require.NoError(t, err)

r.Logger.Info("LoadRequest", "loadRequest:", loadRequest)
// {"loadRequest:": "bytecode:{file:\"/tmp/hello.o\"} name:\"XdpTest\"
// program_type:6 attach:{xdp_attach_info:{priority:50 iface:\"eth0\"
// proceed_on:2 proceed_on:31 netns:\"/host/proc/0/ns/net\"}}
// metadata:{key:\"bpfman.io/ProgramName\" value:\"BpfApplication\"}
// metadata:{key:\"bpfman.io/uuid\"
// value:\"1b464e84-c7b3-4dbf-beab-6de3447673c2\"}"}

// rfentry := &FentryProgramReconciler{ClusterProgramReconciler: rc, ourNode: fakeNode}
// err = r.getBpfProgram(ctx, rfentry, name, fentryAppProgramId, fentryAttachPoint, fentryBpfProg)
// require.NoError(t, err)

// require.NotEmpty(t, fentryBpfProg)
// // Finalizer is written
// require.Equal(t, internal.BpfApplicationControllerFinalizer, fentryBpfProg.Finalizers[0])
// // owningConfig Label was correctly set
// require.Equal(t, name, fentryBpfProg.Labels[internal.BpfProgramOwner])
// // node Label was correctly set
// require.Equal(t, fakeNode.Name, fentryBpfProg.Labels[internal.K8sHostLabel])
// // fentry function Annotation was correctly set
// require.Equal(t, fentryFunctionName, fentryBpfProg.Annotations[internal.FentryProgramFunction])
// // Type is set
// require.Equal(t, r.getRecType(), fentryBpfProg.Spec.Type)
// // Require no requeue
// require.False(t, res.Requeue)

// // Update UID of bpfProgram with Fake UID since the fake API server won't
// fentryBpfProg.UID = types.UID(fentryFakeUID)
// err = cl.Update(ctx, fentryBpfProg)
// require.NoError(t, err)

// // Second reconcile should create the bpfman Load Request and update the
// // BpfProgram object's maps field and id annotation.
// res, err = r.Reconcile(ctx, req)
// if err != nil {
// t.Fatalf("reconcile: (%v)", err)
// }

// // Require no requeue
// require.False(t, res.Requeue)

// // do Fentry Program
// expectedLoadReq := &gobpfman.LoadRequest{
// Bytecode: &gobpfman.BytecodeLocation{
// Location: &gobpfman.BytecodeLocation_File{File: bytecodePath},
// },
// Name: bpfFentryFunctionName,
// ProgramType: *internal.Tracing.Uint32(),
// Metadata: map[string]string{internal.UuidMetadataKey: string(fentryBpfProg.UID), internal.ProgramNameKey: name},
// MapOwnerId: nil,
// Attach: &gobpfman.AttachInfo{
// Info: &gobpfman.AttachInfo_FentryAttachInfo{
// FentryAttachInfo: &gobpfman.FentryAttachInfo{
// FnName: fentryFunctionName,
// },
// },
// },
// }

// // Check that the bpfProgram's programs was correctly updated
// err = r.getBpfProgram(ctx, rfentry, name, fentryAppProgramId, fentryAttachPoint, fentryBpfProg)
// require.NoError(t, err)

// // prog ID should already have been set
// id, err := GetID(fentryBpfProg)
// require.NoError(t, err)

// // Check the bpfLoadRequest was correctly Built
// if !cmp.Equal(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform()) {
// cmp.Diff(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform())
// t.Logf("Diff %v", cmp.Diff(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform()))
// t.Fatal("Built bpfman LoadRequest does not match expected")
// }

// // Third reconcile should set the status to loaded
// res, err = r.Reconcile(ctx, req)
// if err != nil {
// t.Fatalf("reconcile: (%v)", err)
// }

// // Require no requeue
// require.False(t, res.Requeue)

// // Check that the bpfProgram's status was correctly updated
// err = r.getBpfProgram(ctx, rfentry, name, fentryAppProgramId, fentryAttachPoint, fentryBpfProg)
// require.NoError(t, err)

// require.Equal(t, string(bpfmaniov1alpha1.BpfProgCondLoaded), fentryBpfProg.Status.Conditions[0].Type)

// // do kprobe program
// // First reconcile should create the bpf program object
// res, err = r.Reconcile(ctx, req)
// if err != nil {
// t.Fatalf("reconcile: (%v)", err)
// }

// rkprobe := &KprobeProgramReconciler{ClusterProgramReconciler: rc, ourNode: fakeNode}
// err = r.getBpfProgram(ctx, rkprobe, name, kprobeAppProgramId, kprobeAttachPoint, kprobeBpfProg)
// require.NoError(t, err)

// require.NotEmpty(t, kprobeBpfProg)
// // Finalizer is written
// require.Equal(t, internal.BpfApplicationControllerFinalizer, kprobeBpfProg.Finalizers[0])
// // owningConfig Label was correctly set
// require.Equal(t, name, kprobeBpfProg.Labels[internal.BpfProgramOwner])
// // node Label was correctly set
// require.Equal(t, fakeNode.Name, kprobeBpfProg.Labels[internal.K8sHostLabel])
// // fentry function Annotation was correctly set
// require.Equal(t, kprobeFunctionName, kprobeBpfProg.Annotations[internal.KprobeProgramFunction])
// // Type is set
// require.Equal(t, r.getRecType(), kprobeBpfProg.Spec.Type)
// // Require no requeue
// require.False(t, res.Requeue)

// // Update UID of bpfProgram with Fake UID since the fake API server won't
// kprobeBpfProg.UID = types.UID(kprobeFakeUID)
// err = cl.Update(ctx, kprobeBpfProg)
// require.NoError(t, err)

// // Second reconcile should create the bpfman Load Request and update the
// // BpfProgram object's maps field and id annotation.
// res, err = r.Reconcile(ctx, req)
// if err != nil {
// t.Fatalf("reconcile: (%v)", err)
// }

// // Require no requeue
// require.False(t, res.Requeue)

// expectedLoadReq = &gobpfman.LoadRequest{
// Bytecode: &gobpfman.BytecodeLocation{
// Location: &gobpfman.BytecodeLocation_File{File: bytecodePath},
// },
// Name: bpfKprobeFunctionName,
// ProgramType: *internal.Kprobe.Uint32(),
// Metadata: map[string]string{internal.UuidMetadataKey: string(kprobeBpfProg.UID), internal.ProgramNameKey: name},
// MapOwnerId: nil,
// Attach: &gobpfman.AttachInfo{
// Info: &gobpfman.AttachInfo_KprobeAttachInfo{
// KprobeAttachInfo: &gobpfman.KprobeAttachInfo{
// FnName: kprobeFunctionName,
// Offset: uint64(kprobeOffset),
// Retprobe: kprobeRetprobe,
// ContainerPid: &kprobecontainerpid,
// },
// },
// },
// }

// // Check that the bpfProgram's programs was correctly updated
// err = r.getBpfProgram(ctx, rkprobe, name, kprobeAppProgramId, kprobeAttachPoint, kprobeBpfProg)
// require.NoError(t, err)

// // prog ID should already have been set
// id, err = GetID(kprobeBpfProg)
// require.NoError(t, err)

// // Check the bpfLoadRequest was correctly Built
// if !cmp.Equal(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform()) {
// cmp.Diff(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform())
// t.Logf("Diff %v", cmp.Diff(expectedLoadReq, cli.LoadRequests[int(*id)], protocmp.Transform()))
// t.Fatal("Built bpfman LoadRequest does not match expected")
// }

// // Third reconcile should set the status to loaded
// res, err = r.Reconcile(ctx, req)
// if err != nil {
// t.Fatalf("reconcile: (%v)", err)
// }

// // Require no requeue
// require.False(t, res.Requeue)

// // Check that the bpfProgram's status was correctly updated
// err = r.getBpfProgram(ctx, rkprobe, name, kprobeAppProgramId, kprobeAttachPoint, kprobeBpfProg)
// require.NoError(t, err)

// require.Equal(t, string(bpfmaniov1alpha1.BpfProgCondLoaded), kprobeBpfProg.Status.Conditions[0].Type)
require.Equal(t, xdpBpfFunctionName, loadRequest.Name)
require.Equal(t, uint32(6), loadRequest.ProgramType)
}
Loading

0 comments on commit 83561f6

Please sign in to comment.