azure-container-networking/network/endpoint_test.go

455 строки
16 KiB
Go

// Copyright 2019 Microsoft. All rights reserved.
// MIT License
package network
import (
"net"
"testing"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/iptables"
"github.com/Azure/azure-container-networking/netio"
"github.com/Azure/azure-container-networking/netlink"
"github.com/Azure/azure-container-networking/platform"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/stretchr/testify/assert"
)
func TestEndpoint(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Endpoint Suite")
}
var _ = Describe("Test Endpoint", func() {
Describe("Test getEndpoint", func() {
Context("When endpoint not exists", func() {
It("Should raise errEndpointNotFound", func() {
nw := &network{
Endpoints: map[string]*endpoint{},
}
ep, err := nw.getEndpoint("invalid")
Expect(err).To(Equal(errEndpointNotFound))
Expect(ep).To(BeNil())
})
})
Context("When endpoint exists", func() {
It("Should return endpoint with no err", func() {
epId := "epId"
nw := &network{
Endpoints: map[string]*endpoint{},
}
nw.Endpoints[epId] = &endpoint{
Id: epId,
}
ep, err := nw.getEndpoint(epId)
Expect(err).NotTo(HaveOccurred())
Expect(ep.Id).To(Equal(epId))
})
})
})
Describe("Test getEndpointByPOD", func() {
Context("When multiple endpoints found", func() {
It("Should raise errMultipleEndpointsFound", func() {
podName := "test"
podNS := "ns"
nw := &network{
Endpoints: map[string]*endpoint{},
}
nw.Endpoints["pod1"] = &endpoint{
PODName: podName,
PODNameSpace: podNS,
}
nw.Endpoints["pod2"] = &endpoint{
PODName: podName,
PODNameSpace: podNS,
}
ep, err := nw.getEndpointByPOD(podName, podNS, true)
Expect(err).To(Equal(errMultipleEndpointsFound))
Expect(ep).To(BeNil())
})
})
Context("When endpoint not found", func() {
It("Should raise errEndpointNotFound", func() {
nw := &network{
Endpoints: map[string]*endpoint{},
}
ep, err := nw.getEndpointByPOD("invalid", "", false)
Expect(err).To(Equal(errEndpointNotFound))
Expect(ep).To(BeNil())
})
})
Context("When one endpoint found", func() {
It("Should return endpoint", func() {
podName := "test"
podNS := "ns"
nw := &network{
Endpoints: map[string]*endpoint{},
}
nw.Endpoints["pod"] = &endpoint{
PODName: podName,
PODNameSpace: podNS,
}
ep, err := nw.getEndpointByPOD(podName, podNS, true)
Expect(err).NotTo(HaveOccurred())
Expect(ep.PODName).To(Equal(podName))
})
})
})
Describe("Test podNameMatches", func() {
Context("When doExactMatch flag is set", func() {
It("Should exact match", func() {
actual := "nginx"
valid := "nginx"
invalid := "nginx-deployment-5c689d88bb"
Expect(podNameMatches(valid, actual, true)).To(BeTrue())
Expect(podNameMatches(invalid, actual, true)).To(BeFalse())
})
})
Context("When doExactMatch flag is not set", func() {
It("Should not exact match", func() {
actual := "nginx"
valid1 := "nginx"
valid2 := "nginx-deployment-5c689d88bb"
invalid := "nginx-deployment-5c689d88bb-qwq47"
Expect(podNameMatches(valid1, actual, false)).To(BeTrue())
Expect(podNameMatches(valid2, actual, false)).To(BeTrue())
Expect(podNameMatches(invalid, actual, false)).To(BeFalse())
})
})
})
Describe("Test attach", func() {
Context("When SandboxKey in use", func() {
It("Should raise errEndpointInUse", func() {
ep := &endpoint{
SandboxKey: "key",
}
err := ep.attach("")
Expect(err).To(Equal(errEndpointInUse))
})
})
Context("When SandboxKey not in use", func() {
It("Should set SandboxKey", func() {
sandboxKey := "key"
ep := &endpoint{}
err := ep.attach(sandboxKey)
Expect(err).NotTo(HaveOccurred())
Expect(ep.SandboxKey).To(Equal(sandboxKey))
})
})
})
Describe("Test detach", func() {
Context("When SandboxKey not in use", func() {
It("Should raise errEndpointNotInUse", func() {
ep := &endpoint{}
err := ep.detach()
Expect(err).To(Equal(errEndpointNotInUse))
})
})
Context("When SandboxKey in use", func() {
It("Should set SandboxKey empty", func() {
ep := &endpoint{
SandboxKey: "key",
}
err := ep.detach()
Expect(err).NotTo(HaveOccurred())
Expect(ep.SandboxKey).To(BeEmpty())
})
})
})
Describe("Test endpointImpl", func() {
Context("When endpoint add/delete succeed", func() {
nw := &network{
Endpoints: map[string]*endpoint{},
}
epInfo := &EndpointInfo{
EndpointID: "768e8deb-eth1",
Data: make(map[string]interface{}),
IfName: eth0IfName,
NICType: cns.InfraNIC,
ContainerID: "0ea7476f26d192f067abdc8b3df43ce3cdbe324386e1c010cb48de87eefef480",
}
epInfo.Data[VlanIDKey] = 100
It("Should be added", func() {
// Add endpoint with valid id
ep, err := nw.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), NewMockEndpointClient(nil), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, epInfo)
Expect(err).NotTo(HaveOccurred())
Expect(ep).NotTo(BeNil())
Expect(ep.Id).To(Equal(epInfo.EndpointID))
Expect(ep.Gateways).To(BeEmpty())
})
It("should have fields set", func() {
nw2 := &network{
Endpoints: map[string]*endpoint{},
extIf: &externalInterface{IPv4Gateway: net.ParseIP("192.168.0.1")},
}
ep, err := nw2.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), NewMockEndpointClient(nil), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, epInfo)
Expect(err).NotTo(HaveOccurred())
Expect(ep).NotTo(BeNil())
Expect(ep.Id).To(Equal(epInfo.EndpointID))
Expect(ep.Gateways).NotTo(BeNil())
Expect(len(ep.Gateways)).To(Equal(1))
Expect(ep.Gateways[0].String()).To(Equal("192.168.0.1"))
Expect(ep.VlanID).To(Equal(epInfo.Data[VlanIDKey].(int)))
Expect(ep.IfName).To(Equal(epInfo.IfName))
Expect(ep.ContainerID).To(Equal(epInfo.ContainerID))
})
It("Should be not added", func() {
// Adding an endpoint with an id.
mockCli := NewMockEndpointClient(nil)
err := mockCli.AddEndpoints(epInfo)
Expect(err).ToNot(HaveOccurred())
// Adding endpoint with same id should fail and delete should cleanup the state
ep2, err := nw.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), mockCli, NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, epInfo)
Expect(err).To(HaveOccurred())
Expect(ep2).To(BeNil())
assert.Contains(GinkgoT(), err.Error(), "Endpoint already exists")
Expect(len(mockCli.endpoints)).To(Equal(0))
})
It("Should be deleted", func() {
// Adding an endpoint with an id.
mockCli := NewMockEndpointClient(nil)
ep2, err := nw.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), mockCli, NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, epInfo)
Expect(err).ToNot(HaveOccurred())
Expect(ep2).ToNot(BeNil())
Expect(len(mockCli.endpoints)).To(Equal(1))
// Deleting the endpoint
//nolint:errcheck // ignore error
nw.deleteEndpointImpl(netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false), mockCli, netio.NewMockNetIO(false, 0), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, ep2)
Expect(len(mockCli.endpoints)).To(Equal(0))
// Deleting same endpoint with same id should not fail
//nolint:errcheck // ignore error
nw.deleteEndpointImpl(netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false), mockCli, netio.NewMockNetIO(false, 0), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, ep2)
Expect(len(mockCli.endpoints)).To(Equal(0))
})
})
Context("When endpoint added delegated", func() {
epInfo := &EndpointInfo{
EndpointID: "768e8deb-eth1",
Data: make(map[string]interface{}),
IfName: eth0IfName,
MasterIfName: "masterIfName",
NICType: cns.NodeNetworkInterfaceFrontendNIC,
}
epInfo.Data[VlanIDKey] = 100
It("should have fields set", func() {
nw2 := &network{
Endpoints: map[string]*endpoint{},
extIf: &externalInterface{IPv4Gateway: net.ParseIP("192.168.0.1")},
}
ep, err := nw2.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), NewMockEndpointClient(nil), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, epInfo)
Expect(err).NotTo(HaveOccurred())
Expect(ep).NotTo(BeNil())
Expect(ep.Id).To(Equal(epInfo.EndpointID))
Expect(ep.Gateways).NotTo(BeNil())
Expect(len(ep.Gateways)).To(Equal(1))
Expect(ep.Gateways[0].String()).To(Equal("192.168.0.1"))
Expect(ep.VlanID).To(Equal(epInfo.Data[VlanIDKey].(int)))
Expect(ep.IfName).To(Equal("masterIfName"))
})
})
Context("When endpoint add failed", func() {
It("Should not be added to the network", func() {
nw := &network{
Endpoints: map[string]*endpoint{},
}
epInfo := &EndpointInfo{
EndpointID: "768e8deb-eth1",
IfName: eth0IfName,
NICType: cns.InfraNIC,
}
ep, err := nw.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), NewMockEndpointClient(func(ep *EndpointInfo) error {
if ep.NICType == cns.InfraNIC {
return NewErrorMockEndpointClient("AddEndpoints Infra NIC failed")
}
return nil
}), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, epInfo)
Expect(err).To(HaveOccurred())
Expect(ep).To(BeNil())
ep, err = nw.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), NewMockEndpointClient(nil), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, epInfo)
Expect(err).NotTo(HaveOccurred())
Expect(ep).NotTo(BeNil())
Expect(ep.Id).To(Equal(epInfo.EndpointID))
})
})
// TODO: Add secondary endpoint client test coverage in a different way
Context("When secondary endpoint client is used", func() {
_, ipnet, _ := net.ParseCIDR("0.0.0.0/0")
nw := &network{
Endpoints: map[string]*endpoint{},
Mode: opModeTransparent,
extIf: &externalInterface{BridgeName: "testbridge"},
}
epInfo := &EndpointInfo{
EndpointID: "768e8deb-eth1",
IfName: eth0IfName,
NICType: cns.InfraNIC,
}
secondaryEpInfo := &EndpointInfo{
// When we create the secondary endpoint infos while looping over the interface infos, we pass in the same endpoint id
EndpointID: "768e8deb-eth1",
NICType: cns.NodeNetworkInterfaceFrontendNIC,
Routes: []RouteInfo{{Dst: *ipnet}},
}
It("Should not add endpoint to the network when there is an error", func() {
secondaryEpInfo.MacAddress = netio.BadHwAddr // mock netlink will fail to set link state on bad eth
ep, err := nw.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), nil, NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, secondaryEpInfo)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("SecondaryEndpointClient Error: " + netlink.ErrorMockNetlink.Error()))
Expect(ep).To(BeNil())
// should not panic or error when going through the unified endpoint impl flow with only the delegated nic type fields
secondaryEpInfo.MacAddress = netio.HwAddr
ep, err = nw.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), nil, NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, secondaryEpInfo)
Expect(err).ToNot(HaveOccurred())
Expect(ep.Id).To(Equal(epInfo.EndpointID))
})
It("Should add endpoint when there are no errors", func() {
secondaryEpInfo.MacAddress = netio.HwAddr
ep, err := nw.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), nil, NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, secondaryEpInfo)
Expect(err).ToNot(HaveOccurred())
Expect(ep.Id).To(Equal(epInfo.EndpointID))
ep, err = nw.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), nil, NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, epInfo)
Expect(err).ToNot(HaveOccurred())
Expect(ep.Id).To(Equal(epInfo.EndpointID))
})
})
})
Describe("Test updateEndpoint", func() {
Context("When endpoint not found", func() {
It("Should raise errEndpointNotFound", func() {
nm := &networkManager{}
nw := &network{}
existingEpInfo := &EndpointInfo{
EndpointID: "768e8deb-eth1",
IfName: eth0IfName,
}
targetEpInfo := &EndpointInfo{}
err := nm.updateEndpoint(nw, existingEpInfo, targetEpInfo)
Expect(err).To(Equal(errEndpointNotFound))
})
})
})
Describe("Test GetPodNameWithoutSuffix", func() {
Context("When podnames have suffix or not", func() {
It("Should return podname without suffix", func() {
testData := map[string]string{
"nginx-deployment-5c689d88bb": "nginx",
"nginx-deployment-5c689d88bb-qwq47": "nginx-deployment",
"nginx": "nginx",
}
for testValue, expectedPodName := range testData {
podName := GetPodNameWithoutSuffix(testValue)
Expect(podName).To(Equal(expectedPodName))
}
})
})
})
// validation when calling add
Describe("Test validateEndpoints", func() {
Context("When in a single add call we create two endpoint structs", func() {
It("Should have the same container id", func() {
eps := []*endpoint{
{
ContainerID: "0ea7476f26d192f067abdc8b3df43ce3cdbe324386e1c010cb48de87eefef480",
NICType: cns.InfraNIC,
},
{
ContainerID: "0ea7476f26d192f067abdc8b3df43ce3cdbe324386e1c010cb48de87eefef480",
NICType: cns.NodeNetworkInterfaceFrontendNIC,
},
}
Expect(validateEndpoints(eps)).To(BeNil())
})
})
Context("When in a single add call we have different container ids", func() {
It("Should error", func() {
eps := []*endpoint{
{
ContainerID: "0ea7476f26d192f067abdc8b3df43ce3cdbe324386e1c010cb48de87eefef480",
NICType: cns.InfraNIC,
},
{
ContainerID: "0ea7476f26d192f067abdc8b3df43ce3cdbe324386e1c010cb48de87eefef481",
NICType: cns.NodeNetworkInterfaceFrontendNIC,
},
}
Expect(validateEndpoints(eps)).ToNot(BeNil())
})
})
Context("When no container id", func() {
It("Should error", func() {
eps := []*endpoint{
{
ContainerID: "",
NICType: cns.InfraNIC,
},
{
ContainerID: "",
NICType: cns.NodeNetworkInterfaceFrontendNIC,
},
}
Expect(validateEndpoints(eps)).ToNot(BeNil())
})
})
Context("When missing nic type", func() {
It("Should error", func() {
eps := []*endpoint{
{
ContainerID: "0ea7476f26d192f067abdc8b3df43ce3cdbe324386e1c010cb48de87eefef480",
NICType: cns.InfraNIC,
},
{
ContainerID: "0ea7476f26d192f067abdc8b3df43ce3cdbe324386e1c010cb48de87eefef480",
NICType: "",
},
}
Expect(validateEndpoints(eps)).ToNot(BeNil())
})
})
Context("When no container id ib nic", func() {
It("Should error", func() {
eps := []*endpoint{
{
ContainerID: "",
NICType: cns.NodeNetworkInterfaceBackendNIC,
},
}
Expect(validateEndpoints(eps)).ToNot(BeNil())
})
})
})
})