Skip to content

Commit

Permalink
unit tests, informer caches: generic provisioning
Browse files Browse the repository at this point in the history
This commit automatically provisions the controller informer cache with
the data present on the fake clientset tracker (the "fake" datastore).

This way, users can just create the client with provisioned data, and
that'll trickle down to the informer cache of the pod controller.

Because the `network-attachment-definitions` resources feature dashes,
the heuristic function that guesses - yes, guesses. very deterministic
... - the name of the resource can't be used - [0]. As such, it was
needed to create an alternate `newFakeNetAttachDefClient` where it is
possible to specify the correct resource name.

[0] - https://github.com/k8snetworkplumbingwg/network-attachment-definition-client/blob/2fd7267afcc4d48dfe6a8cd756b5a08bd04c2c97/vendor/k8s.io/client-go/testing/fixture.go#L331

Signed-off-by: Miguel Duarte Barroso <[email protected]>
  • Loading branch information
maiqueb committed Mar 4, 2022
1 parent 1e84f3a commit a9a8e02
Showing 1 changed file with 86 additions and 16 deletions.
102 changes: 86 additions & 16 deletions pkg/reconciler/controlloop/pod_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
v1coreinformerfactory "k8s.io/client-go/informers"
k8sclient "k8s.io/client-go/kubernetes"
fakek8sclient "k8s.io/client-go/kubernetes/fake"
Expand Down Expand Up @@ -46,6 +47,50 @@ type dummyPodController struct {
podCache cache.Store
}

func (dpc *dummyPodController) withSynchedIPPool(ipPoolClient wbclient.Interface) error {
ipPools, err := ipPoolClient.WhereaboutsV1alpha1().IPPools(ipPoolsNamespace()).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return err
}
for _, pool := range ipPools.Items {
if err := dpc.ipPoolCache.Add(&pool); err != nil {
return err
}
}
return nil
}

func (dpc *dummyPodController) withSynchedNetworkAttachments(netAttachDefClient nadclient.Interface) error {
const allNamespaces = ""

networkAttachments, err := netAttachDefClient.K8sCniCncfIoV1().NetworkAttachmentDefinitions(allNamespaces).List(
context.TODO(), metav1.ListOptions{})
if err != nil {
return err
}
for _, network := range networkAttachments.Items {
if err := dpc.networkCache.Add(&network); err != nil {
return err
}
}
return nil
}

func (dpc *dummyPodController) withSynchedPods(k8sClient k8sclient.Interface) error {
const allNamespaces = ""

pods, err := k8sClient.CoreV1().Pods(allNamespaces).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return err
}
for _, pod := range pods.Items {
if err := dpc.podCache.Add(&pod); err != nil {
return err
}
}
return nil
}

var _ = Describe("IPControlLoop", func() {
const (
dummyNetIPRange = "192.168.2.0/24"
Expand All @@ -56,7 +101,6 @@ var _ = Describe("IPControlLoop", func() {
k8sClient k8sclient.Interface
cniConfigDir string
netAttachDefClient nadclient.Interface
networkDefinition *nad.NetworkAttachmentDefinition
pod *v1.Pod
wbClient wbclient.Interface
)
Expand All @@ -81,8 +125,10 @@ var _ = Describe("IPControlLoop", func() {

pod = podSpec(podName, namespace, networkName)
k8sClient = fakek8sclient.NewSimpleClientset(pod)
networkDefinition = netAttachDef(networkName, namespace, dummyNetSpec(networkName, dummyNetIPRange))
netAttachDefClient = fakenadclient.NewSimpleClientset(networkDefinition)

var err error
netAttachDefClient, err = newFakeNetAttachDefClient(namespace, netAttachDef(networkName, namespace, dummyNetSpec(networkName, dummyNetIPRange)))
Expect(err).NotTo(HaveOccurred())
})

AfterEach(func() {
Expand All @@ -101,7 +147,7 @@ var _ = Describe("IPControlLoop", func() {

BeforeEach(func() {
stopChannel = make(chan struct{})
_ = newDummyPodController(k8sClient, wbClient, netAttachDefClient, stopChannel, cniConfigDir)
Expect(newDummyPodController(k8sClient, wbClient, netAttachDefClient, stopChannel, cniConfigDir)).NotTo(BeNil())
})

AfterEach(func() {
Expand All @@ -122,20 +168,15 @@ var _ = Describe("IPControlLoop", func() {
Context("IPPool featuring an allocation for the pod", func() {
var (
dummyNetworkPool *v1alpha1.IPPool
podController *dummyPodController
stopChannel chan struct{}
)

BeforeEach(func() {
stopChannel = make(chan struct{})
dummyNetworkPool = ipPool(dummyNetIPRange, podReference(pod))
wbClient = fakewbclient.NewSimpleClientset(dummyNetworkPool)
podController = newDummyPodController(k8sClient, wbClient, netAttachDefClient, stopChannel, cniConfigDir)

// provision informer cache
Expect(podController.ipPoolCache.Add(dummyNetworkPool)).To(Succeed())
Expect(podController.networkCache.Add(networkDefinition)).To(Succeed())
Expect(podController.podCache.Add(pod)).To(Succeed())
Expect(newDummyPodController(k8sClient, wbClient, netAttachDefClient, stopChannel, cniConfigDir)).NotTo(BeNil())
})

AfterEach(func() {
Expand All @@ -162,6 +203,23 @@ var _ = Describe("IPControlLoop", func() {
})
})

func newFakeNetAttachDefClient(namespace string, networkAttachments ...nad.NetworkAttachmentDefinition) (nadclient.Interface, error) {
var netAttachDefClient nadclient.Interface = fakenadclient.NewSimpleClientset()
gvr := metav1.GroupVersionResource{
Group: "k8s.cni.cncf.io",
Version: "v1",
Resource: "network-attachment-definitions",
}

clientSet := netAttachDefClient.(*fakenadclient.Clientset)
for _, networkAttachment := range networkAttachments {
if err := clientSet.Tracker().Create(schema.GroupVersionResource(gvr), &networkAttachment, namespace); err != nil {
return nil, err
}
}
return netAttachDefClient, nil
}

func dummyNetSpec(networkName string, ipRange string) string {
return fmt.Sprintf(`{
"cniVersion": "0.3.0",
Expand All @@ -186,8 +244,8 @@ func podSpec(name string, namespace string, networks ...string) *v1.Pod {
}
}

func netAttachDef(netName string, namespace string, config string) *nad.NetworkAttachmentDefinition {
return &nad.NetworkAttachmentDefinition{
func netAttachDef(netName string, namespace string, config string) nad.NetworkAttachmentDefinition {
return nad.NetworkAttachmentDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: netName,
Namespace: namespace,
Expand Down Expand Up @@ -251,7 +309,7 @@ func newDummyPodController(
wbClient wbclient.Interface,
nadClient nadclient.Interface,
stopChannel chan struct{},
mountPath string) *dummyPodController {
mountPath string) (*dummyPodController, error) {

const noResyncPeriod = 0
netAttachDefInformerFactory := nadinformers.NewSharedInformerFactory(nadClient, noResyncPeriod)
Expand Down Expand Up @@ -289,14 +347,26 @@ func newDummyPodController(

podController.handler.mountPath = mountPath

go podController.Start(stopChannel)

return &dummyPodController{
controller := &dummyPodController{
PodController: podController,
ipPoolCache: podController.ipPoolInformer.GetStore(),
networkCache: podController.netAttachDefInformer.GetStore(),
podCache: podController.podsInformer.GetStore(),
}

if err := controller.withSynchedIPPool(wbClient); err != nil {
return nil, err
}
if err := controller.withSynchedPods(k8sClient); err != nil {
return nil, err
}
if err := controller.withSynchedNetworkAttachments(nadClient); err != nil {
return nil, err
}

go podController.Start(stopChannel)

return controller, nil
}

func podReference(pod *v1.Pod) string {
Expand Down

0 comments on commit a9a8e02

Please sign in to comment.