From 9085c8467204ca146a85e488d30abdc3215acc87 Mon Sep 17 00:00:00 2001 From: nicklesimba Date: Mon, 5 Aug 2019 15:04:35 -0400 Subject: [PATCH] Unit tests and update to quickstart guide (#354) * Added a test for GetLoggingLevel * Added up to 96% coverage for checkpoint.go * Improved coverage of checkpoint.go to 96.4% * Improved coverage of checkpoint.go to 96.4% * Adding changes so i will have them saved for my remote fork thingy * Fixed unit tests in checkpoint_test.go and conf_test.go * Removed unnecessary comments * improved conf code coverage by an amount that is greater than 0! * improved coverage, but line 144 of conf.go needs a look * Added unit tests to multus and types, also fixed a bug in conf.go * added label to import types/020 in types.go * hopefully resolved merge conflicts * increased code coverage in multus.go and conf.go, also added bug fixes and formatting * addressed all comments in review * Updated testing.go with better comments * changed 'thejohn' to '_not_type' for readability * added additional unit tests * added tests to kubeletclient.go * added more unit tests to k8sclient.go and kubeletclient.go * Added network status annotations section to quickstart and added more unit tests * made changes to tests based on code review --- doc/quickstart.md | 29 ++- k8sclient/k8sclient_test.go | 185 +++++++++++++++ kubeletclient/kubeletclient_test.go | 41 ++++ logging/logging_test.go | 6 + multus/multus_test.go | 344 +++++++++++++++++++++++++++- types/conf_test.go | 44 ++++ 6 files changed, 647 insertions(+), 2 deletions(-) diff --git a/doc/quickstart.md b/doc/quickstart.md index f22987769..16abfedf5 100644 --- a/doc/quickstart.md +++ b/doc/quickstart.md @@ -176,6 +176,33 @@ You should note that there's 3 interfaces: * `eth0` our default network * `net1` the new interface we created with the macvlan configuration. +### Network Status Annotations + +For additional confirmation, use `kubectl describe pod samplepod` and there will be an annotations section, similar to the following: + +``` +Annotations: k8s.v1.cni.cncf.io/networks: macvlan-conf + k8s.v1.cni.cncf.io/networks-status: + [{ + "name": "cbr0", + "ips": [ + "10.244.1.73" + ], + "default": true, + "dns": {} + },{ + "name": "macvlan-conf", + "interface": "net1", + "ips": [ + "192.168.1.205" + ], + "mac": "86:1d:96:ff:55:0d", + "dns": {} + }] +``` + +This metadata tells us that we have two CNI plugins running successfully. + ### What if I want more interfaces? You can add more interfaces to a pod by creating more custom resources and then referring to them in pod's annotation. You can also reuse configurations, so for example, to attach two macvlan interfaces to a pod, you could create a pod like so: @@ -198,4 +225,4 @@ EOF Note that the annotation now reads `k8s.v1.cni.cncf.io/networks: macvlan-conf,macvlan-conf`. Where we have the same configuration used twice, separated by a comma. -If you were to create another custom resource with the name `foo` you could use that such as: `k8s.v1.cni.cncf.io/networks: foo,macvlan-conf`, and use any number of attachments. +If you were to create another custom resource with the name `foo` you could use that such as: `k8s.v1.cni.cncf.io/networks: foo,macvlan-conf`, and use any number of attachments. \ No newline at end of file diff --git a/k8sclient/k8sclient_test.go b/k8sclient/k8sclient_test.go index 58dbdd619..f58348284 100644 --- a/k8sclient/k8sclient_test.go +++ b/k8sclient/k8sclient_test.go @@ -22,6 +22,8 @@ import ( "path/filepath" "testing" + types020 "github.com/containernetworking/cni/pkg/types/020" + testhelpers "github.com/intel/multus-cni/testing" testutils "github.com/intel/multus-cni/testing" "github.com/containernetworking/cni/pkg/skel" @@ -611,4 +613,187 @@ var _ = Describe("k8sclient operations", func() { Expect(err).To(MatchError("GetPodNetwork: namespace isolation violation: podnamespace: test / target namespace: kube-system")) }) + + It("Returns proper error message", func() { + // getPodNetwork will give us the error, then this test will use that error on the top func boi + err := &NoK8sNetworkError{"no kubernetes network found"} + Expect(err.Error()).To(Equal("no kubernetes network found")) + }) + + It("Sets pod network annotations without error", func() { + fakePod := testutils.NewFakePod("testpod", "kube-system/net1", "") + + net1 := `{ + "name": "net1", + "type": "mynet", + "cniVersion": "0.2.0" +}` + + args := &skel.CmdArgs{ + Args: fmt.Sprintf("K8S_POD_NAME=%s;K8S_POD_NAMESPACE=%s", fakePod.ObjectMeta.Name, fakePod.ObjectMeta.Namespace), + } + + fKubeClient := testutils.NewFakeKubeClient() + fKubeClient.AddPod(fakePod) + fKubeClient.AddNetConfig("kube-system", "net1", net1) + + kubeClient, err := GetK8sClient("", fKubeClient) + Expect(err).NotTo(HaveOccurred()) + k8sArgs, err := GetK8sArgs(args) + Expect(err).NotTo(HaveOccurred()) + + pod, err := kubeClient.GetPod(string(k8sArgs.K8S_POD_NAMESPACE), string(k8sArgs.K8S_POD_NAME)) + Expect(err).NotTo(HaveOccurred()) + + networkstatus := "test status" + _, err = setPodNetworkAnnotation(kubeClient, "test", pod, networkstatus) + Expect(err).NotTo(HaveOccurred()) + }) + + // Still figuring this one out. need to make "setPodNetworkAnnotation throw an error + // It("Fails to set pod network annotations without error", func() { + // fakePod := testutils.NewFakePod("testpod", "kube-system/net1", "") + + // net1 := `{ + // "name": "net1", + // "type": "mynet", + // "cniVersion": "0.2.0" + // }` + + // args := &skel.CmdArgs{ + // Args: fmt.Sprintf("K8S_POD_NAME=%s;K8S_POD_NAMESPACE=%s", fakePod.ObjectMeta.Name, fakePod.ObjectMeta.Namespace), + // } + + // fKubeClient := testutils.NewFakeKubeClient() + // fKubeClient.AddPod(fakePod) + // fKubeClient.AddNetConfig("kube-system", "net1", net1) + + // kubeClient, err := GetK8sClient("", fKubeClient) + // Expect(err).NotTo(HaveOccurred()) + // k8sArgs, err := GetK8sArgs(args) + // Expect(err).NotTo(HaveOccurred()) + + // pod, err := kubeClient.GetPod(string(k8sArgs.K8S_POD_NAMESPACE), string(k8sArgs.K8S_POD_NAME)) + // Expect(err).NotTo(HaveOccurred()) + + // networkstatus := "test status" + // _, err = setPodNetworkAnnotation(kubeClient, "test", pod, networkstatus) + // Expect(err).NotTo(HaveOccurred()) + // }) + + It("Sets network status without error", func() { + result := &types020.Result{ + CNIVersion: "0.2.0", + IP4: &types020.IPConfig{ + IP: *testhelpers.EnsureCIDR("1.1.1.2/24"), + }, + } + + conf := `{ + "name": "node-cni-network", + "type": "multus", + "kubeconfig": "/etc/kubernetes/node-kubeconfig.yaml", + "delegates": [{ + "type": "weave-net" + }], + "runtimeConfig": { + "portMappings": [ + {"hostPort": 8080, "containerPort": 80, "protocol": "tcp"} + ] + } + }` + + delegate, err := types.LoadDelegateNetConf([]byte(conf), nil, "0000:00:00.0") + Expect(err).NotTo(HaveOccurred()) + + delegateNetStatus, err := types.LoadNetworkStatus(result, delegate.Conf.Name, delegate.MasterPlugin) + GinkgoT().Logf("delegateNetStatus %+v\n", delegateNetStatus) + Expect(err).NotTo(HaveOccurred()) + + netstatus := []*types.NetworkStatus{delegateNetStatus} + + fakePod := testutils.NewFakePod("testpod", "kube-system/net1", "") + + netConf, err := types.LoadNetConf([]byte(conf)) + Expect(err).NotTo(HaveOccurred()) + + net1 := `{ + "name": "net1", + "type": "mynet", + "cniVersion": "0.2.0" + }` + + args := &skel.CmdArgs{ + Args: fmt.Sprintf("K8S_POD_NAME=%s;K8S_POD_NAMESPACE=%s", fakePod.ObjectMeta.Name, fakePod.ObjectMeta.Namespace), + } + + fKubeClient := testutils.NewFakeKubeClient() + fKubeClient.AddPod(fakePod) + fKubeClient.AddNetConfig("kube-system", "net1", net1) + + kubeClient, err := GetK8sClient("", fKubeClient) + Expect(err).NotTo(HaveOccurred()) + k8sArgs, err := GetK8sArgs(args) + Expect(err).NotTo(HaveOccurred()) + + err = SetNetworkStatus(kubeClient, k8sArgs, netstatus, netConf) + Expect(err).NotTo(HaveOccurred()) + }) + + It("Fails to set network status without error", func() { + result := &types020.Result{ + CNIVersion: "0.2.0", + IP4: &types020.IPConfig{ + IP: *testhelpers.EnsureCIDR("1.1.1.2/24"), + }, + } + + conf := `{ + "name": "node-cni-network", + "type": "multus", + "kubeconfig": "/etc/kubernetes/node-kubeconfig.yaml", + "delegates": [{ + "type": "weave-net" + }], + "runtimeConfig": { + "portMappings": [ + {"hostPort": 8080, "containerPort": 80, "protocol": "tcp"} + ] + } + }` + + delegate, err := types.LoadDelegateNetConf([]byte(conf), nil, "") + Expect(err).NotTo(HaveOccurred()) + + delegateNetStatus, err := types.LoadNetworkStatus(result, delegate.Conf.Name, delegate.MasterPlugin) + GinkgoT().Logf("delegateNetStatus %+v\n", delegateNetStatus) + Expect(err).NotTo(HaveOccurred()) + + netstatus := []*types.NetworkStatus{delegateNetStatus} + + fakePod := testutils.NewFakePod("testpod", "kube-system/net1", "") + + netConf, err := types.LoadNetConf([]byte(conf)) + Expect(err).NotTo(HaveOccurred()) + + net1 := `{ + "name": "net1", + "type": "mynet", + "cniVersion": "0.2.0" + }` + + args := &skel.CmdArgs{ + Args: fmt.Sprintf("K8S_POD_NAME=%s;K8S_POD_NAMESPACE=%s", fakePod.ObjectMeta.Name, fakePod.ObjectMeta.Namespace), + } + + fKubeClient := testutils.NewFakeKubeClient() + fKubeClient.AddPod(fakePod) + fKubeClient.AddNetConfig("kube-system", "net1", net1) + + k8sArgs, err := GetK8sArgs(args) + Expect(err).NotTo(HaveOccurred()) + + err = SetNetworkStatus(nil, k8sArgs, netstatus, netConf) + Expect(err).To(HaveOccurred()) + }) }) diff --git a/kubeletclient/kubeletclient_test.go b/kubeletclient/kubeletclient_test.go index 2802e57a1..e3815c739 100644 --- a/kubeletclient/kubeletclient_test.go +++ b/kubeletclient/kubeletclient_test.go @@ -115,6 +115,12 @@ var _ = Describe("Kubelet resource endpoint data read operations", func() { _, err := GetResourceClient() Expect(err).NotTo(HaveOccurred()) }) + + It("should fail with missing file", func() { + kubeletSocket = "sampleSocketString" + _, err := GetResourceClient() + Expect(err).To(HaveOccurred()) + }) }) Context("GetPodResourceMap() with valid pod name and namespace", func() { @@ -146,6 +152,41 @@ var _ = Describe("Kubelet resource endpoint data read operations", func() { Expect(resourceMap).ShouldNot(BeNil()) Expect(resourceMap).To(Equal(outputRMap)) }) + + It("should return no error with empty socket", func() { + podUID := k8sTypes.UID("970a395d-bb3b-11e8-89df-408d5c537d23") + fakePod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod-name", + Namespace: "pod-namespace", + UID: podUID, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "container-name", + }, + }, + }, + } + kubeletSocket = "" + client, err := getKubeletClient() + Expect(err).NotTo(HaveOccurred()) + + outputRMap := map[string]*mtypes.ResourceInfo{ + "resource": &mtypes.ResourceInfo{DeviceIDs: []string{"dev0", "dev1"}}, + } + resourceMap, err := client.GetPodResourceMap(fakePod) + Expect(err).NotTo(HaveOccurred()) + Expect(resourceMap).ShouldNot(BeNil()) + Expect(resourceMap).To(Equal(outputRMap)) + }) + + It("should return an error with garbage socket value", func() { + kubeletSocket = "/badfilepath!?//" + _, err := getKubeletClient() + Expect(err).To(HaveOccurred()) + }) }) Context("GetPodResourceMap() with empty podname", func() { diff --git a/logging/logging_test.go b/logging/logging_test.go index 1813d21e3..ee42dd545 100644 --- a/logging/logging_test.go +++ b/logging/logging_test.go @@ -45,6 +45,12 @@ var _ = Describe("logging operations", func() { // check file existance }) + It("Check file setter with bad filepath", func() { + SetLogFile("/invalid/filepath") + Expect(loggingFp).NotTo(Equal(nil)) + // check file existance + }) + It("Check loglevel setter", func() { SetLogLevel("debug") Expect(loggingLevel).To(Equal(DebugLevel)) diff --git a/multus/multus_test.go b/multus/multus_test.go index 6cdca10b5..2e45267b5 100644 --- a/multus/multus_test.go +++ b/multus/multus_test.go @@ -32,9 +32,10 @@ import ( cniversion "github.com/containernetworking/cni/pkg/version" "github.com/containernetworking/plugins/pkg/ns" "github.com/containernetworking/plugins/pkg/testutils" - + "github.com/intel/multus-cni/k8sclient" "github.com/intel/multus-cni/logging" testhelpers "github.com/intel/multus-cni/testing" + "github.com/intel/multus-cni/types" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -324,6 +325,162 @@ var _ = Describe("multus operations", func() { } }) + It("returns the previous result using cmdGet", func() { + args := &skel.CmdArgs{ + ContainerID: "123456789", + Netns: testNS.Path(), + IfName: "eth0", + StdinData: []byte(`{ + "name": "node-cni-network", + "type": "multus", + "defaultnetworkfile": "/tmp/foo.multus.conf", + "defaultnetworkwaitseconds": 3, + "delegates": [{ + "name": "weave1", + "cniVersion": "0.2.0", + "type": "weave-net" + },{ + "name": "other1", + "cniVersion": "0.2.0", + "type": "other-plugin" + }] + }`), + } + + logging.SetLogLevel("verbose") + + // Touch the default network file. + configPath := "/tmp/foo.multus.conf" + os.OpenFile(configPath, os.O_RDONLY|os.O_CREATE, 0755) + + fExec := &fakeExec{} + expectedResult1 := &types020.Result{ + CNIVersion: "0.2.0", + IP4: &types020.IPConfig{ + IP: *testhelpers.EnsureCIDR("1.1.1.2/24"), + }, + } + expectedConf1 := `{ + "name": "weave1", + "cniVersion": "0.2.0", + "type": "weave-net" + }` + fExec.addPlugin(nil, "eth0", expectedConf1, expectedResult1, nil) + + expectedResult2 := &types020.Result{ + CNIVersion: "0.2.0", + IP4: &types020.IPConfig{ + IP: *testhelpers.EnsureCIDR("1.1.1.5/24"), + }, + } + expectedConf2 := `{ + "name": "other1", + "cniVersion": "0.2.0", + "type": "other-plugin" + }` + fExec.addPlugin(nil, "net1", expectedConf2, expectedResult2, nil) + + os.Setenv("CNI_COMMAND", "ADD") + os.Setenv("CNI_IFNAME", "eth0") + result, err := cmdAdd(args, fExec, nil) + Expect(err).NotTo(HaveOccurred()) + Expect(fExec.addIndex).To(Equal(len(fExec.plugins))) + r := result.(*types020.Result) + // plugin 1 is the masterplugin + Expect(reflect.DeepEqual(r, expectedResult1)).To(BeTrue()) + + result, err = cmdGet(args, fExec, nil) + Expect(err).NotTo(HaveOccurred()) + + os.Setenv("CNI_COMMAND", "DEL") + os.Setenv("CNI_IFNAME", "eth0") + err = cmdDel(args, fExec, nil) + Expect(err).NotTo(HaveOccurred()) + Expect(fExec.delIndex).To(Equal(len(fExec.plugins))) + + // Cleanup default network file. + if _, errStat := os.Stat(configPath); errStat == nil { + errRemove := os.Remove(configPath) + Expect(errRemove).NotTo(HaveOccurred()) + } + }) + + It("executes delegates given faulty namespace", func() { + args := &skel.CmdArgs{ + ContainerID: "123456789", + Netns: "fsdadfad", + IfName: "eth0", + StdinData: []byte(`{ + "name": "node-cni-network", + "type": "multus", + "defaultnetworkfile": "/tmp/foo.multus.conf", + "defaultnetworkwaitseconds": 3, + "delegates": [{ + "name": "weave1", + "cniVersion": "0.2.0", + "type": "weave-net" + },{ + "name": "other1", + "cniVersion": "0.2.0", + "type": "other-plugin" + }] + }`), + } + // Netns is given garbage value + + // Touch the default network file. + configPath := "/tmp/foo.multus.conf" + os.OpenFile(configPath, os.O_RDONLY|os.O_CREATE, 0755) + + fExec := &fakeExec{} + expectedResult1 := &types020.Result{ + CNIVersion: "0.2.0", + IP4: &types020.IPConfig{ + IP: *testhelpers.EnsureCIDR("1.1.1.2/24"), + }, + } + expectedConf1 := `{ + "name": "weave1", + "cniVersion": "0.2.0", + "type": "weave-net" + }` + fExec.addPlugin(nil, "eth0", expectedConf1, expectedResult1, nil) + + expectedResult2 := &types020.Result{ + CNIVersion: "0.2.0", + IP4: &types020.IPConfig{ + IP: *testhelpers.EnsureCIDR("1.1.1.5/24"), + }, + } + expectedConf2 := `{ + "name": "other1", + "cniVersion": "0.2.0", + "type": "other-plugin" + }` + fExec.addPlugin(nil, "net1", expectedConf2, expectedResult2, nil) + + os.Setenv("CNI_COMMAND", "ADD") + os.Setenv("CNI_IFNAME", "eth0") + result, err := cmdAdd(args, fExec, nil) + Expect(err).NotTo(HaveOccurred()) + Expect(fExec.addIndex).To(Equal(len(fExec.plugins))) + r := result.(*types020.Result) + // plugin 1 is the masterplugin + Expect(reflect.DeepEqual(r, expectedResult1)).To(BeTrue()) + + os.Setenv("CNI_COMMAND", "DEL") + os.Setenv("CNI_IFNAME", "eth0") + err = cmdDel(args, fExec, nil) + Expect(err).NotTo(HaveOccurred()) + Expect(fExec.delIndex).To(Equal(len(fExec.plugins))) + + // Cleanup default network file. + if _, errStat := os.Stat(configPath); errStat == nil { + errRemove := os.Remove(configPath) + Expect(errRemove).NotTo(HaveOccurred()) + } + }) + It("returns the previous result using cmdGet", func() { args := &skel.CmdArgs{ ContainerID: "123456789", @@ -893,6 +1050,74 @@ var _ = Describe("multus operations", func() { Expect(fExec.delIndex).To(Equal(len(fExec.plugins))) }) + It("executes kubernetes networks and delete it after pod removal", func() { + fakePod := testhelpers.NewFakePod("testpod", "net1", "") + net1 := `{ + "name": "net1", + "type": "mynet", + "cniVersion": "0.2.0" + }` + args := &skel.CmdArgs{ + ContainerID: "123456789", + Netns: testNS.Path(), + IfName: "eth0", + Args: fmt.Sprintf("K8S_POD_NAME=%s;K8S_POD_NAMESPACE=%s", fakePod.ObjectMeta.Name, fakePod.ObjectMeta.Namespace), + StdinData: []byte(`{ + "name": "node-cni-network", + "type": "multus", + "kubeconfig": "/etc/kubernetes/node-kubeconfig.yaml", + "delegates": [{ + "name": "weave1", + "cniVersion": "0.2.0", + "type": "weave-net" + }] + }`), + } + + fExec := &fakeExec{} + expectedResult1 := &types020.Result{ + CNIVersion: "0.2.0", + IP4: &types020.IPConfig{ + IP: *testhelpers.EnsureCIDR("1.1.1.2/24"), + }, + } + expectedConf1 := `{ + "name": "weave1", + "cniVersion": "0.2.0", + "type": "weave-net" + }` + fExec.addPlugin(nil, "eth0", expectedConf1, expectedResult1, nil) + fExec.addPlugin(nil, "net1", net1, &types020.Result{ + CNIVersion: "0.2.0", + IP4: &types020.IPConfig{ + IP: *testhelpers.EnsureCIDR("1.1.1.3/24"), + }, + }, nil) + + fKubeClient := testhelpers.NewFakeKubeClient() + fKubeClient.AddPod(fakePod) + fKubeClient.AddNetConfig(fakePod.ObjectMeta.Namespace, "net1", net1) + + os.Setenv("CNI_COMMAND", "ADD") + os.Setenv("CNI_IFNAME", "eth0") + result, err := cmdAdd(args, fExec, fKubeClient) + Expect(err).NotTo(HaveOccurred()) + Expect(fExec.addIndex).To(Equal(len(fExec.plugins))) + Expect(fKubeClient.PodCount).To(Equal(2)) + Expect(fKubeClient.NetCount).To(Equal(1)) + r := result.(*types020.Result) + // plugin 1 is the masterplugin + Expect(reflect.DeepEqual(r, expectedResult1)).To(BeTrue()) + + os.Setenv("CNI_COMMAND", "DEL") + os.Setenv("CNI_IFNAME", "eth0") + // set fKubeClient to nil to emulate no pod info + fKubeClient.DeletePod(fakePod) + err = cmdDel(args, fExec, fKubeClient) + Expect(err).NotTo(HaveOccurred()) + Expect(fExec.delIndex).To(Equal(len(fExec.plugins))) + }) + It("ensure delegates get portmap runtime config", func() { args := &skel.CmdArgs{ ContainerID: "123456789", @@ -1148,4 +1373,121 @@ var _ = Describe("multus operations", func() { Expect(fKubeClient.PodCount).To(Equal(4)) Expect(fKubeClient.NetCount).To(Equal(2)) }) + + It("fails to execute confListDel given no 'plugins' key", func() { + args := &skel.CmdArgs{ + ContainerID: "123456789", + Netns: testNS.Path(), + IfName: "eth0", + StdinData: []byte(`{ + "name": "node-cni-network", + "type": "multus", + "defaultnetworkfile": "/tmp/foo.multus.conf", + "defaultnetworkwaitseconds": 3, + "delegates": [{ + "name": "weave1", + "cniVersion": "0.2.0", + "type": "weave-net" + },{ + "name": "other1", + "cniVersion": "0.2.0", + "type": "other-plugin" + }] + }`), + } + + // Touch the default network file. + configPath := "/tmp/foo.multus.conf" + os.OpenFile(configPath, os.O_RDONLY|os.O_CREATE, 0755) + + fExec := &fakeExec{} + expectedResult1 := &types020.Result{ + CNIVersion: "0.2.0", + IP4: &types020.IPConfig{ + IP: *testhelpers.EnsureCIDR("1.1.1.2/24"), + }, + } + expectedConf1 := `{ + "name": "weave1", + "cniVersion": "0.2.0", + "type": "weave-net" + }` + fExec.addPlugin(nil, "eth0", expectedConf1, expectedResult1, nil) + + expectedResult2 := &types020.Result{ + CNIVersion: "0.2.0", + IP4: &types020.IPConfig{ + IP: *testhelpers.EnsureCIDR("1.1.1.5/24"), + }, + } + expectedConf2 := `{ + "name": "other1", + "cniVersion": "0.2.0", + "type": "other-plugin" + }` + fExec.addPlugin(nil, "net1", expectedConf2, expectedResult2, nil) + + os.Setenv("CNI_COMMAND", "ADD") + os.Setenv("CNI_IFNAME", "eth0") + + binDir := "/opt/cni/bin" + // use fExec for the exec param + rawnetconflist := []byte(`{"cniVersion":"0.2.0","name":"weave1","type":"weave-net"}`) + k8sargs, err := k8sclient.GetK8sArgs(args) + n, err := types.LoadNetConf(args.StdinData) + rt := types.CreateCNIRuntimeConf(args, k8sargs, args.IfName, n.RuntimeConfig) + + err = conflistDel(rt, rawnetconflist, binDir, fExec) + Expect(err).To(HaveOccurred()) + }) + + It("executes confListDel without error", func() { + args := &skel.CmdArgs{ + ContainerID: "123456789", + Netns: testNS.Path(), + IfName: "eth0", + StdinData: []byte(`{ + "name": "node-cni-network", + "type": "multus", + "delegates": [{ + "cniVersion": "0.3.1", + "name": "mynet-confList", + "plugins": [ + { + "type": "firstPlugin", + "capabilities": {"portMappings": true} + } + ] + }], + "runtimeConfig": { + "portMappings": [ + {"hostPort": 8080, "containerPort": 80, "protocol": "tcp"} + ] + } + }`), + } + + // Touch the default network file. + configPath := "/tmp/foo.multus.conf" + os.OpenFile(configPath, os.O_RDONLY|os.O_CREATE, 0755) + + fExec := &fakeExec{} + expectedConf1 := `{ + "capabilities": {"portMappings": true}, + "name": "mynet-confList", + "cniVersion": "0.3.1", + "type": "firstPlugin", + "runtimeConfig": { + "portMappings": [ + {"hostPort": 8080, "containerPort": 80, "protocol": "tcp"} + ] + } + }` + fExec.addPlugin(nil, "eth0", expectedConf1, nil, nil) + os.Setenv("CNI_COMMAND", "ADD") + os.Setenv("CNI_IFNAME", "eth0") + + err := cmdDel(args, fExec, nil) + Expect(err).NotTo(HaveOccurred()) + }) }) diff --git a/types/conf_test.go b/types/conf_test.go index 26193301b..0a6e67db9 100644 --- a/types/conf_test.go +++ b/types/conf_test.go @@ -468,4 +468,48 @@ var _ = Describe("config operations", func() { Expect(err).To(HaveOccurred()) }) + Context("using UnmarshalJSON", func() { + It("succeeds with valid json", func() { + networkselectionelement := &NetworkSelectionElement{ + Name: "kube-system", + Namespace: "net1", + InterfaceRequest: "", + } + conf := `{ + "name": "kube-system", + "namespace": "net1", + "interfaceRequest": "", + "ips": "10.18.89.129", + "mac": "CB-32-97-FF-D6-79", + "interface": "" +}` + err := networkselectionelement.UnmarshalJSON([]byte(conf)) + Expect(err).NotTo(HaveOccurred()) + }) + + It("fails to parse invalid json", func() { + networkselectionelement := &NetworkSelectionElement{ + Name: "kube-system", + Namespace: "net1", + InterfaceRequest: "", + } + err := networkselectionelement.UnmarshalJSON([]byte("invalidjson~")) + Expect(err).To(HaveOccurred()) + }) + + It("fails with missing name parameter", func() { + networkselectionelement := &NetworkSelectionElement{ + Name: "kube-system", + Namespace: "net1", + InterfaceRequest: "", + } + // conf json does not include "name" + conf := `{ + "namespace": "net1", + "interfaceRequest": "" +}` + err := networkselectionelement.UnmarshalJSON([]byte(conf)) + Expect(err).To(HaveOccurred()) + }) + }) })