Skip to content

Commit

Permalink
create operatorConfig controller for config-daemon
Browse files Browse the repository at this point in the history
Signed-off-by: Sebastian Sch <[email protected]>
  • Loading branch information
SchSeba committed Dec 26, 2024
1 parent 53adb45 commit ab31c0c
Show file tree
Hide file tree
Showing 2 changed files with 231 additions and 0 deletions.
61 changes: 61 additions & 0 deletions pkg/daemon/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package daemon

import (
"context"
"reflect"

"k8s.io/apimachinery/pkg/api/errors"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"

sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
snolog "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/log"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
)

type OperatorConfigReconcile struct {
client client.Client
latestFeatureGates map[string]bool
}

func NewOperatorConfigReconcile(client client.Client) *OperatorConfigReconcile {
return &OperatorConfigReconcile{client: client, latestFeatureGates: make(map[string]bool)}
}

func (oc *OperatorConfigReconcile) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
reqLogger := log.FromContext(ctx).WithName("Reconcile")
operatorConfig := &sriovnetworkv1.SriovOperatorConfig{}
err := oc.client.Get(ctx, client.ObjectKey{Namespace: req.Namespace, Name: req.Name}, operatorConfig)
if err != nil {
if errors.IsNotFound(err) {
reqLogger.Info("OperatorConfig doesn't exist", "name", req.Name, "namespace", req.Namespace)
return ctrl.Result{}, nil
}
reqLogger.Error(err, "Failed to operatorConfig", "name", req.Name, "namespace", req.Namespace)
return ctrl.Result{}, err
}

// update log level
snolog.SetLogLevel(operatorConfig.Spec.LogLevel)

newDisableDrain := operatorConfig.Spec.DisableDrain
if vars.DisableDrain != newDisableDrain {
vars.DisableDrain = newDisableDrain
log.Log.Info("Set Disable Drain", "value", vars.DisableDrain)
}

if !reflect.DeepEqual(oc.latestFeatureGates, operatorConfig.Spec.FeatureGates) {
vars.FeatureGate.Init(operatorConfig.Spec.FeatureGates)
oc.latestFeatureGates = operatorConfig.Spec.FeatureGates
log.Log.Info("Updated featureGates", "featureGates", vars.FeatureGate.String())
}

return ctrl.Result{}, nil
}

func (oc *OperatorConfigReconcile) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&sriovnetworkv1.SriovOperatorConfig{}).
Complete(oc)
}
170 changes: 170 additions & 0 deletions pkg/daemon/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package daemon_test

import (
"context"
"sync"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/daemon"
snolog "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/log"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
)

var _ = Describe("Daemon OperatorConfig Controller", Ordered, func() {
var cancel context.CancelFunc
var ctx context.Context

BeforeAll(func() {
By("Setup controller manager")
k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme.Scheme,
})
Expect(err).ToNot(HaveOccurred())

configController := daemon.NewOperatorConfigReconcile(k8sClient)
err = configController.SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())

ctx, cancel = context.WithCancel(context.Background())

wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
defer GinkgoRecover()
By("Start controller manager")
err := k8sManager.Start(ctx)
Expect(err).ToNot(HaveOccurred())
}()

DeferCleanup(func() {
By("Shutdown controller manager")
cancel()
wg.Wait()
})

err = k8sClient.Create(ctx, &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "default"}})
Expect(err).ToNot(HaveOccurred())
})

BeforeEach(func() {
Expect(k8sClient.DeleteAllOf(context.Background(), &sriovnetworkv1.SriovOperatorConfig{}, client.InNamespace(testNamespace))).ToNot(HaveOccurred())
})

Context("LogLevel", func() {
It("should configure the log level base on sriovOperatorConfig", func() {
soc := &sriovnetworkv1.SriovOperatorConfig{ObjectMeta: metav1.ObjectMeta{
Name: consts.DefaultConfigName,
Namespace: testNamespace,
},
Spec: sriovnetworkv1.SriovOperatorConfigSpec{
LogLevel: 1,
},
}

err := k8sClient.Create(ctx, soc)
Expect(err).ToNot(HaveOccurred())
validateExpectedLogLevel(1)

})

It("should update the log level in runtime", func() {
soc := &sriovnetworkv1.SriovOperatorConfig{ObjectMeta: metav1.ObjectMeta{
Name: consts.DefaultConfigName,
Namespace: testNamespace,
},
Spec: sriovnetworkv1.SriovOperatorConfigSpec{
LogLevel: 1,
},
}

err := k8sClient.Create(ctx, soc)
Expect(err).ToNot(HaveOccurred())
validateExpectedLogLevel(1)

soc.Spec.LogLevel = 2
err = k8sClient.Update(ctx, soc)
Expect(err).ToNot(HaveOccurred())
validateExpectedLogLevel(2)
})
})

Context("Disable Drain", func() {
It("should update the skip drain flag", func() {
soc := &sriovnetworkv1.SriovOperatorConfig{ObjectMeta: metav1.ObjectMeta{
Name: consts.DefaultConfigName,
Namespace: testNamespace,
},
Spec: sriovnetworkv1.SriovOperatorConfigSpec{
DisableDrain: true,
},
}

err := k8sClient.Create(ctx, soc)
Expect(err).ToNot(HaveOccurred())
validateExpectedDrain(true)

soc.Spec.DisableDrain = false
err = k8sClient.Update(ctx, soc)
Expect(err).ToNot(HaveOccurred())
validateExpectedDrain(false)
})
})

Context("Feature gates", func() {
It("should update the feature gates struct", func() {
soc := &sriovnetworkv1.SriovOperatorConfig{ObjectMeta: metav1.ObjectMeta{
Name: consts.DefaultConfigName,
Namespace: testNamespace,
},
Spec: sriovnetworkv1.SriovOperatorConfigSpec{
FeatureGates: map[string]bool{
"test": true,
"bla": true,
},
},
}

err := k8sClient.Create(ctx, soc)
Expect(err).ToNot(HaveOccurred())
EventuallyWithOffset(1, func(g Gomega) {
g.Expect(vars.FeatureGate.IsEnabled("test")).To(BeTrue())
}, "15s", "3s").Should(Succeed())
EventuallyWithOffset(1, func(g Gomega) {
g.Expect(vars.FeatureGate.IsEnabled("bla")).To(BeTrue())
}, "15s", "3s").Should(Succeed())

soc.Spec.FeatureGates["test"] = false
err = k8sClient.Update(ctx, soc)
Expect(err).ToNot(HaveOccurred())
EventuallyWithOffset(1, func(g Gomega) {
g.Expect(vars.FeatureGate.IsEnabled("test")).To(BeFalse())
}, "15s", "3s").Should(Succeed())
EventuallyWithOffset(1, func(g Gomega) {
g.Expect(vars.FeatureGate.IsEnabled("bla")).To(BeTrue())
}, "15s", "3s").Should(Succeed())
})
})
})

func validateExpectedLogLevel(level int) {
EventuallyWithOffset(1, func(g Gomega) {
g.Expect(snolog.GetLogLevel()).To(Equal(level))
}, "15s", "3s").Should(Succeed())
}

func validateExpectedDrain(disableDrain bool) {
EventuallyWithOffset(1, func(g Gomega) {
g.Expect(vars.DisableDrain).To(Equal(disableDrain))
}, "15s", "3s").Should(Succeed())
}

0 comments on commit ab31c0c

Please sign in to comment.