package network import ( "errors" "net" "sort" "testing" "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/Azure/azure-container-networking/cns" "github.com/Azure/azure-container-networking/cns/restserver" "github.com/Azure/azure-container-networking/store" "github.com/Azure/azure-container-networking/testutils" ) func TestManager(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Manager Suite") } var _ = Describe("Test Manager", func() { Describe("Test deleteExternalInterface", func() { Context("When external interface not found", func() { It("Should return nil", func() { ifName := "eth0" nm := &networkManager{ ExternalInterfaces: map[string]*externalInterface{}, } err := nm.deleteExternalInterface(ifName) Expect(err).NotTo(HaveOccurred()) }) }) Context("When external interface found", func() { It("Should delete external interface", func() { ifName := "eth0" nm := &networkManager{ ExternalInterfaces: map[string]*externalInterface{}, } nm.ExternalInterfaces[ifName] = &externalInterface{} err := nm.deleteExternalInterface(ifName) Expect(err).NotTo(HaveOccurred()) }) }) }) Describe("Test restore", func() { Context("When restore is nil", func() { It("Should return nil", func() { nm := &networkManager{} err := nm.restore(false) Expect(err).NotTo(HaveOccurred()) }) }) Context("When store.Read return ErrKeyNotFound", func() { It("Should return nil", func() { nm := &networkManager{ store: &testutils.KeyValueStoreMock{ ReadError: store.ErrKeyNotFound, }, } err := nm.restore(false) Expect(err).NotTo(HaveOccurred()) }) }) Context("When store.Read return error", func() { It("Should raise error", func() { nm := &networkManager{ store: &testutils.KeyValueStoreMock{ ReadError: errors.New("error for test"), }, } err := nm.restore(false) Expect(err).To(HaveOccurred()) }) }) Context("When GetModificationTime error and not rebooted", func() { It("Should populate pointers", func() { extIfName := "eth0" nwId := "nwId" nm := &networkManager{ store: &testutils.KeyValueStoreMock{ GetModificationTimeError: errors.New("error for test"), }, ExternalInterfaces: map[string]*externalInterface{}, } nm.ExternalInterfaces[extIfName] = &externalInterface{ Name: extIfName, Networks: map[string]*network{}, } nm.ExternalInterfaces[extIfName].Networks[nwId] = &network{} err := nm.restore(false) Expect(err).NotTo(HaveOccurred()) Expect(nm.ExternalInterfaces[extIfName].Networks[nwId].extIf.Name).To(Equal(extIfName)) }) }) }) Describe("Test save", func() { Context("When store is nil", func() { It("Should return nil", func() { nm := &networkManager{} err := nm.save() Expect(err).NotTo(HaveOccurred()) Expect(nm.TimeStamp).To(Equal(time.Time{})) }) }) Context("When store.Write return error", func() { It("Should raise error", func() { nm := &networkManager{ store: &testutils.KeyValueStoreMock{ WriteError: errors.New("error for test"), }, } err := nm.save() Expect(err).To(HaveOccurred()) Expect(nm.TimeStamp).NotTo(Equal(time.Time{})) }) }) }) Describe("Test GetNumberOfEndpoints", func() { Context("When ExternalInterfaces is nil", func() { It("Should return 0", func() { nm := &networkManager{} num := nm.GetNumberOfEndpoints("", "") Expect(num).To(Equal(0)) }) }) Context("When extIf not found", func() { It("Should return 0", func() { nm := &networkManager{ ExternalInterfaces: map[string]*externalInterface{}, } num := nm.GetNumberOfEndpoints("eth0", "") Expect(num).To(Equal(0)) }) }) Context("When Networks is nil", func() { It("Should return 0", func() { ifName := "eth0" nm := &networkManager{ ExternalInterfaces: map[string]*externalInterface{}, } nm.ExternalInterfaces[ifName] = &externalInterface{} num := nm.GetNumberOfEndpoints(ifName, "") Expect(num).To(Equal(0)) }) }) Context("When network not found", func() { It("Should return 0", func() { ifName := "eth0" nm := &networkManager{ ExternalInterfaces: map[string]*externalInterface{}, } nm.ExternalInterfaces[ifName] = &externalInterface{ Networks: map[string]*network{}, } num := nm.GetNumberOfEndpoints(ifName, "nwId") Expect(num).To(Equal(0)) }) }) Context("When endpoints is nil", func() { It("Should return 0", func() { ifName := "eth0" nwId := "nwId" nm := &networkManager{ ExternalInterfaces: map[string]*externalInterface{}, } nm.ExternalInterfaces[ifName] = &externalInterface{ Networks: map[string]*network{}, } nm.ExternalInterfaces[ifName].Networks[nwId] = &network{} num := nm.GetNumberOfEndpoints(ifName, nwId) Expect(num).To(Equal(0)) }) }) Context("When endpoints is found", func() { It("Should return the length of endpoints", func() { ifName := "eth0" nwId := "nwId" nm := &networkManager{ ExternalInterfaces: map[string]*externalInterface{}, } nm.ExternalInterfaces[ifName] = &externalInterface{ Networks: map[string]*network{}, } nm.ExternalInterfaces[ifName].Networks[nwId] = &network{ Endpoints: map[string]*endpoint{ "ep1": {}, "ep2": {}, "ep3": {}, }, } num := nm.GetNumberOfEndpoints(ifName, nwId) Expect(num).To(Equal(3)) }) }) Context("When ifName not specifed in GetNumberofEndpoints", func() { It("Should range the nm.ExternalInterfaces", func() { ifName := "eth0" nwId := "nwId" nm := &networkManager{ ExternalInterfaces: map[string]*externalInterface{}, } nm.ExternalInterfaces[ifName] = &externalInterface{ Networks: map[string]*network{}, } nm.ExternalInterfaces[ifName].Networks[nwId] = &network{ Endpoints: map[string]*endpoint{ "ep1": {}, "ep2": {}, "ep3": {}, }, } num := nm.GetNumberOfEndpoints("", nwId) Expect(num).To(Equal(3)) }) }) Context("When different fields passed to update endpoint state", func() { It("Should error or validate correctly", func() { nm := &networkManager{} err := nm.UpdateEndpointState([]*endpoint{ { IfName: "eth0", ContainerID: "2bfc3b23e078f0bea48612d5d081ace587599cdac026d23e4d57bd03c85d357c", }, { IfName: "", ContainerID: "2bfc3b23e078f0bea48612d5d081ace587599cdac026d23e4d57bd03c85d357c", }, }) Expect(err).To(HaveOccurred()) err = nm.UpdateEndpointState([]*endpoint{ { IfName: "eth1", ContainerID: "", }, { IfName: "eth0", ContainerID: "", }, }) Expect(err).To(HaveOccurred()) err = validateUpdateEndpointState( "2bfc3b23e078f0bea48612d5d081ace587599cdac026d23e4d57bd03c85d357c", map[string]*restserver.IPInfo{ "eth1": {}, "eth2": {}, }) Expect(err).To(BeNil()) }) }) }) Describe("Test EndpointCreate", func() { Context("When no endpoints provided", func() { It("Should return 0", func() { nm := &networkManager{} err := nm.EndpointCreate(nil, []*EndpointInfo{}) Expect(err).NotTo(HaveOccurred()) num := nm.GetNumberOfEndpoints("", "") Expect(num).To(Equal(0)) }) }) }) Describe("Test GetEndpointInfosFromContainerID", func() { Context("When getting containers based on container id regardless of network", func() { It("Should return 0", func() { nm := &networkManager{ ExternalInterfaces: map[string]*externalInterface{ "eth0": { Networks: map[string]*network{ "azure": { Endpoints: map[string]*endpoint{ "12345678-eth0": { Id: "12345678-eth0", ContainerID: "12345678", // potentially empty nictype }, "abcdefgh-eth0": { Id: "abcdefgh-eth0", ContainerID: "abcdefgh", }, }, }, "other": { Endpoints: map[string]*endpoint{ "12345678-1": { Id: "12345678-1", ContainerID: "12345678", NICType: cns.NodeNetworkInterfaceFrontendNIC, }, }, }, }, }, }, } epInfos := nm.GetEndpointInfosFromContainerID("12345678") sort.Slice(epInfos, func(i, j int) bool { return epInfos[i].EndpointID < epInfos[j].EndpointID }) Expect(len(epInfos)).To(Equal(2)) Expect(epInfos[0].EndpointID).To(Equal("12345678-1")) Expect(epInfos[0].NICType).To(Equal(cns.NodeNetworkInterfaceFrontendNIC)) Expect(epInfos[0].NetworkID).To(Equal("other")) Expect(epInfos[1].EndpointID).To(Equal("12345678-eth0")) Expect(string(epInfos[1].NICType)).To(Equal("")) Expect(epInfos[1].NetworkID).To(Equal("azure")) }) }) }) Describe("Test stateless cnsEndpointInfotoCNIEpInfos", func() { endpointID := "" _, dummyIP, _ := net.ParseCIDR("192.0.2.1/24") dummyIPv4Slice := []net.IPNet{ *dummyIP, } Context("When converting from cns to cni unmigrated", func() { It("Should get the right cni endpoint info data", func() { cnsEndpointInfo := restserver.EndpointInfo{ IfnameToIPMap: map[string]*restserver.IPInfo{ "": { IPv4: dummyIPv4Slice, HostVethName: "hostVeth1", HnsEndpointID: "hnsID1", HnsNetworkID: "hnsNetworkID1", MacAddress: "12:34:56:78:9a:bc", }, }, PodName: "test-pod", PodNamespace: "test-pod-ns", } epInfos := cnsEndpointInfotoCNIEpInfos(cnsEndpointInfo, endpointID) Expect(len(epInfos)).To(Equal(1)) Expect(epInfos[0]).To(Equal( &EndpointInfo{ IPAddresses: dummyIPv4Slice, IfName: InfraInterfaceName, HostIfName: "hostVeth1", HNSEndpointID: "hnsID1", NICType: cns.InfraNIC, HNSNetworkID: "hnsNetworkID1", MacAddress: net.HardwareAddr("12:34:56:78:9a:bc"), ContainerID: endpointID, EndpointID: endpointID, NetworkContainerID: endpointID, PODName: "test-pod", PODNameSpace: "test-pod-ns", }, ), "empty infos received from cns should be auto populated and treated as infra") }) }) Context("When converting from cns to cni migrated", func() { _, dummyIP2, _ := net.ParseCIDR("193.0.2.1/24") dummyIPv4Slice2 := []net.IPNet{ *dummyIP2, } It("Should get the right cni endpoint info data if there are multiple ip infos", func() { cnsEndpointInfo := restserver.EndpointInfo{ IfnameToIPMap: map[string]*restserver.IPInfo{ "ifName1": { IPv4: dummyIPv4Slice, HostVethName: "hostVeth1", HnsEndpointID: "hnsID1", HnsNetworkID: "hnsNetworkID1", MacAddress: "12:34:56:78:9a:bc", NICType: cns.InfraNIC, }, "ifName2": { IPv4: dummyIPv4Slice2, HostVethName: "hostVeth2", HnsEndpointID: "hnsID2", HnsNetworkID: "hnsNetworkID2", MacAddress: "22:34:56:78:9a:bc", NICType: cns.NodeNetworkInterfaceFrontendNIC, }, }, PodName: "test-pod", PodNamespace: "test-pod-ns", } epInfos := cnsEndpointInfotoCNIEpInfos(cnsEndpointInfo, endpointID) Expect(len(epInfos)).To(Equal(2)) Expect(epInfos).To(ContainElement( &EndpointInfo{ IPAddresses: dummyIPv4Slice, IfName: "ifName1", HostIfName: "hostVeth1", HNSEndpointID: "hnsID1", NICType: cns.InfraNIC, HNSNetworkID: "hnsNetworkID1", MacAddress: net.HardwareAddr("12:34:56:78:9a:bc"), ContainerID: endpointID, EndpointID: endpointID, NetworkContainerID: endpointID, PODName: "test-pod", PODNameSpace: "test-pod-ns", }, )) Expect(epInfos).To(ContainElement( &EndpointInfo{ IPAddresses: dummyIPv4Slice2, IfName: "ifName2", HostIfName: "hostVeth2", HNSEndpointID: "hnsID2", NICType: cns.NodeNetworkInterfaceFrontendNIC, HNSNetworkID: "hnsNetworkID2", MacAddress: net.HardwareAddr("22:34:56:78:9a:bc"), ContainerID: endpointID, EndpointID: endpointID, NetworkContainerID: endpointID, PODName: "test-pod", PODNameSpace: "test-pod-ns", }, )) }) }) }) Describe("Test stateless generateCNSIPInfoMap", func() { Context("When converting from cni to cns with different combinations", func() { It("Should generate the cns endpoint info data from the endpoint structs for infraNIC+DelegatedVMNIC", func() { mac1, _ := net.ParseMAC("12:34:56:78:9a:bc") mac2, _ := net.ParseMAC("22:34:56:78:9a:bc") endpoints := []*endpoint{ { IfName: "eth0", NICType: cns.InfraNIC, HnsId: "hnsEndpointID1", HNSNetworkID: "hnsNetworkID1", HostIfName: "hostIfName1", MacAddress: mac1, }, { IfName: "eth1", NICType: cns.NodeNetworkInterfaceFrontendNIC, HnsId: "hnsEndpointID2", HNSNetworkID: "hnsNetworkID2", HostIfName: "hostIfName2", MacAddress: mac2, }, } cnsEpInfos := generateCNSIPInfoMap(endpoints) Expect(len(cnsEpInfos)).To(Equal(2)) Expect(cnsEpInfos).To(HaveKey("eth0")) Expect(cnsEpInfos["eth0"]).To(Equal( &restserver.IPInfo{ NICType: cns.InfraNIC, HnsEndpointID: "hnsEndpointID1", HnsNetworkID: "hnsNetworkID1", HostVethName: "hostIfName1", MacAddress: "12:34:56:78:9a:bc", }, )) Expect(cnsEpInfos).To(HaveKey("eth1")) Expect(cnsEpInfos["eth1"]).To(Equal( &restserver.IPInfo{ NICType: cns.NodeNetworkInterfaceFrontendNIC, HnsEndpointID: "hnsEndpointID2", HnsNetworkID: "hnsNetworkID2", HostVethName: "hostIfName2", MacAddress: "22:34:56:78:9a:bc", }, )) }) }) }) })