Skip to content

Commit

Permalink
Add unit-tests for Drain controller
Browse files Browse the repository at this point in the history
  • Loading branch information
e0ne committed Jun 27, 2023
1 parent d525d52 commit 6f8e5b2
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 5 deletions.
5 changes: 3 additions & 2 deletions controllers/drain_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package controllers
import (
"context"
"fmt"
"sort"
"strings"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
Expand All @@ -16,8 +19,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
"sort"
"strings"

sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
constants "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
Expand Down
120 changes: 120 additions & 0 deletions controllers/drain_controller_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package controllers

import (
goctx "context"
"time"

v1 "k8s.io/api/core/v1"

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

sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
consts "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
"github.com/k8snetworkplumbingwg/sriov-network-operator/test/util"
)

func createNodeObj(name, anno string) *v1.Node {
node := &v1.Node{}
node.Name = name
node.Annotations = map[string]string{}
node.Annotations[consts.NodeDrainAnnotation] = anno

return node
}

func createNode(node *v1.Node) {
Expect(k8sClient.Create(goctx.TODO(), node)).Should(Succeed())
}

var _ = Describe("Drain Controller", func() {

BeforeEach(func() {
node1 := createNodeObj("node1", "Drain_Required")
node2 := createNodeObj("node2", "Drain_Required")
createNode(node1)
createNode(node2)
})
AfterEach(func() {
node1 := createNodeObj("node1", "Drain_Required")
node2 := createNodeObj("node2", "Drain_Required")
err := k8sClient.Delete(goctx.TODO(), node1)
Expect(err).NotTo(HaveOccurred())
err = k8sClient.Delete(goctx.TODO(), node2)
Expect(err).NotTo(HaveOccurred())
})

Context("Parallel nodes draining", func() {

It("Should drain one node", func() {
config := &sriovnetworkv1.SriovOperatorConfig{}
err := util.WaitForNamespacedObject(config, k8sClient, testNamespace, "default", interval, timeout)
Expect(err).NotTo(HaveOccurred())
config.Spec = sriovnetworkv1.SriovOperatorConfigSpec{
EnableInjector: func() *bool { b := true; return &b }(),
EnableOperatorWebhook: func() *bool { b := true; return &b }(),
MaxParallelNodeConfiguration: 1,
}
updateErr := k8sClient.Update(goctx.TODO(), config)
Expect(updateErr).NotTo(HaveOccurred())
time.Sleep(3 * time.Second)

nodeList := &v1.NodeList{}
listErr := k8sClient.List(ctx, nodeList)
Expect(listErr).NotTo(HaveOccurred())

drainingNodes := 0
for _, node := range nodeList.Items {
if utils.NodeHasAnnotation(node, "sriovnetwork.openshift.io/state", "Draining") {
drainingNodes++
}
}
Expect(drainingNodes).To(Equal(1))
})

It("Should drain two nodes", func() {
config := &sriovnetworkv1.SriovOperatorConfig{}
err := util.WaitForNamespacedObject(config, k8sClient, testNamespace, "default", interval, timeout)
Expect(err).NotTo(HaveOccurred())
config.Spec = sriovnetworkv1.SriovOperatorConfigSpec{
EnableInjector: func() *bool { b := true; return &b }(),
EnableOperatorWebhook: func() *bool { b := true; return &b }(),
MaxParallelNodeConfiguration: 2,
}
updateErr := k8sClient.Update(goctx.TODO(), config)
Expect(updateErr).NotTo(HaveOccurred())
time.Sleep(3 * time.Second)

nodeList := &v1.NodeList{}
listErr := k8sClient.List(ctx, nodeList)
Expect(listErr).NotTo(HaveOccurred())

for _, node := range nodeList.Items {
Expect(utils.NodeHasAnnotation(node, "sriovnetwork.openshift.io/state", "Draining")).To(BeTrue())
}
})

It("Should drain all nodes", func() {
config := &sriovnetworkv1.SriovOperatorConfig{}
err := util.WaitForNamespacedObject(config, k8sClient, testNamespace, "default", interval, timeout)
Expect(err).NotTo(HaveOccurred())
config.Spec = sriovnetworkv1.SriovOperatorConfigSpec{
EnableInjector: func() *bool { b := true; return &b }(),
EnableOperatorWebhook: func() *bool { b := true; return &b }(),
MaxParallelNodeConfiguration: 0,
}
updateErr := k8sClient.Update(goctx.TODO(), config)
Expect(updateErr).NotTo(HaveOccurred())
time.Sleep(3 * time.Second)

nodeList := &v1.NodeList{}
listErr := k8sClient.List(ctx, nodeList)
Expect(listErr).NotTo(HaveOccurred())

for _, node := range nodeList.Items {
Expect(utils.NodeHasAnnotation(node, "sriovnetwork.openshift.io/state", "Draining")).To(BeTrue())
}
})
})
})
6 changes: 6 additions & 0 deletions controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ var _ = BeforeSuite(func(done Done) {
}).SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())

err = (&DrainReconciler{
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
}).SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())

os.Setenv("RESOURCE_PREFIX", "openshift.io")
os.Setenv("NAMESPACE", "openshift-sriov-network-operator")
os.Setenv("ENABLE_ADMISSION_CONTROLLER", "true")
Expand Down
7 changes: 4 additions & 3 deletions pkg/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
snclientset "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/client/clientset/versioned"
sninformer "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/client/informers/externalversions"
consts "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
plugin "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/plugins"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
)
Expand Down Expand Up @@ -562,7 +563,7 @@ func (dn *Daemon) nodeStateSyncHandler() error {
// isNodeDraining: check if the node is draining
// both Draining and MCP paused labels will return true
func (dn *Daemon) isNodeDraining() bool {
anno, ok := dn.node.Annotations[annoKey]
anno, ok := dn.node.Annotations[consts.NodeDrainAnnotation]
if !ok {
return false
}
Expand Down Expand Up @@ -689,8 +690,8 @@ func (dn *Daemon) annotateNode(node, value string) error {
if newNode.Annotations == nil {
newNode.Annotations = map[string]string{}
}
if newNode.Annotations[annoKey] != value {
newNode.Annotations[annoKey] = value
if newNode.Annotations[consts.NodeDrainAnnotation] != value {
newNode.Annotations[consts.NodeDrainAnnotation] = value
newData, err := json.Marshal(newNode)
if err != nil {
return err
Expand Down

0 comments on commit 6f8e5b2

Please sign in to comment.