azure-container-networking/network/secondary_endpoint_linux_te...

381 строка
12 KiB
Go

//go:build linux
// +build linux
package network
import (
"net"
"testing"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/netio"
"github.com/Azure/azure-container-networking/netlink"
"github.com/Azure/azure-container-networking/network/networkutils"
"github.com/Azure/azure-container-networking/platform"
"github.com/stretchr/testify/require"
)
func TestSecondaryAddEndpoints(t *testing.T) {
nl := netlink.NewMockNetlink(false, "")
plc := platform.NewMockExecClient(false)
mac, _ := net.ParseMAC("ab:cd:ef:12:34:56")
invalidMac, _ := net.ParseMAC("12:34:56:ab:cd:ef")
tests := []struct {
name string
client *SecondaryEndpointClient
epInfo *EndpointInfo
wantErr bool
wantErrMsg string
}{
{
name: "Add endpoints",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
ep: &endpoint{SecondaryInterfaces: make(map[string]*InterfaceInfo)},
dhcpClient: &mockDHCP{},
},
epInfo: &EndpointInfo{MacAddress: mac},
wantErr: false,
},
{
name: "Add endpoints invalid mac",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
ep: &endpoint{SecondaryInterfaces: make(map[string]*InterfaceInfo)},
},
epInfo: &EndpointInfo{MacAddress: invalidMac},
wantErr: true,
wantErrMsg: "SecondaryEndpointClient Error: " + netio.ErrMockNetIOFail.Error() + ": " + invalidMac.String(),
},
{
name: "Add endpoints interface already added",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
ep: &endpoint{SecondaryInterfaces: map[string]*InterfaceInfo{"eth1": {Name: "eth1"}}},
},
epInfo: &EndpointInfo{MacAddress: mac},
wantErr: true,
wantErrMsg: "SecondaryEndpointClient Error: eth1 already exists",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
err := tt.client.AddEndpoints(tt.epInfo)
if tt.wantErr {
require.Error(t, err)
require.Contains(t, tt.wantErrMsg, err.Error(), "Expected:%v actual:%v", tt.wantErrMsg, err.Error())
} else {
require.NoError(t, err)
require.Equal(t, tt.client.ep.SecondaryInterfaces["eth1"].MacAddress, tt.epInfo.MacAddress)
require.Equal(t, "eth1", tt.epInfo.IfName, "interface name should update based on mac address here before being referenced later")
}
})
}
}
func TestSecondaryDeleteEndpoints(t *testing.T) {
nl := netlink.NewMockNetlink(false, "")
plc := platform.NewMockExecClient(false)
tests := []struct {
name string
client *SecondaryEndpointClient
ep *endpoint
wantErr bool
}{
{
name: "Delete endpoint happy path",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
nsClient: NewMockNamespaceClient(),
},
ep: &endpoint{
NetworkNameSpace: "testns",
SecondaryInterfaces: map[string]*InterfaceInfo{
"eth1": {
Name: "eth1",
Routes: []RouteInfo{
{
Dst: net.IPNet{IP: net.ParseIP("192.168.0.4"), Mask: net.CIDRMask(ipv4FullMask, ipv4Bits)},
},
},
},
},
},
},
{
name: "Delete endpoint happy path namespace not found",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
nsClient: NewMockNamespaceClient(),
},
ep: &endpoint{
SecondaryInterfaces: map[string]*InterfaceInfo{
"eth1": {
Name: "eth1",
Routes: []RouteInfo{
{
Dst: net.IPNet{IP: net.ParseIP("192.168.0.4"), Mask: net.CIDRMask(ipv4FullMask, ipv4Bits)},
},
},
},
},
},
},
{
name: "Delete endpoint enter namespace failure",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
nsClient: NewMockNamespaceClient(),
},
ep: &endpoint{
NetworkNameSpace: failToEnterNamespaceName,
SecondaryInterfaces: map[string]*InterfaceInfo{
"eth1": {
Name: "eth1",
Routes: []RouteInfo{
{
Dst: net.IPNet{IP: net.ParseIP("192.168.0.4"), Mask: net.CIDRMask(ipv4FullMask, ipv4Bits)},
},
},
},
},
},
wantErr: true,
},
{
name: "Delete endpoint netlink failure",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(true, "netlink failure"),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
nsClient: NewMockNamespaceClient(),
},
ep: &endpoint{
NetworkNameSpace: failToEnterNamespaceName,
SecondaryInterfaces: map[string]*InterfaceInfo{
"eth1": {
Name: "eth1",
Routes: []RouteInfo{
{
Dst: net.IPNet{IP: net.ParseIP("192.168.0.4"), Mask: net.CIDRMask(ipv4FullMask, ipv4Bits)},
},
},
},
},
},
wantErr: true,
},
{
// new way to handle delegated nics
// if the nictype is delegated, the data is on the endpoint itself, not the secondary interfaces field
name: "Delete endpoint with nic type delegated",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
nsClient: NewMockNamespaceClient(),
},
// revisit in future, but currently the struct looks like this (with duplicated fields)
ep: &endpoint{
NetworkNameSpace: "testns",
IfName: "eth1",
Routes: []RouteInfo{
{
Dst: net.IPNet{IP: net.ParseIP("192.168.0.4"), Mask: net.CIDRMask(ipv4FullMask, ipv4Bits)},
},
},
NICType: cns.NodeNetworkInterfaceFrontendNIC,
SecondaryInterfaces: map[string]*InterfaceInfo{
"eth1": {
Name: "eth1",
Routes: []RouteInfo{
{
Dst: net.IPNet{IP: net.ParseIP("192.168.0.4"), Mask: net.CIDRMask(ipv4FullMask, ipv4Bits)},
},
},
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
require.Len(t, tt.ep.SecondaryInterfaces, 1)
if tt.wantErr {
require.Error(t, tt.client.DeleteEndpoints(tt.ep))
require.Len(t, tt.ep.SecondaryInterfaces, 1)
} else {
require.Nil(t, tt.client.DeleteEndpoints(tt.ep))
require.Len(t, tt.ep.SecondaryInterfaces, 0)
}
})
}
}
func TestSecondaryConfigureContainerInterfacesAndRoutes(t *testing.T) {
nl := netlink.NewMockNetlink(false, "")
plc := platform.NewMockExecClient(false)
tests := []struct {
name string
client *SecondaryEndpointClient
epInfo *EndpointInfo
wantErr bool
wantErrMsg string
}{
{
name: "Configure Interface and routes happy path",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
dhcpClient: &mockDHCP{},
ep: &endpoint{SecondaryInterfaces: map[string]*InterfaceInfo{"eth1": {Name: "eth1"}}},
},
epInfo: &EndpointInfo{
IfName: "eth1",
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("192.168.0.4"),
Mask: net.CIDRMask(subnetv4Mask, ipv4Bits),
},
},
Routes: []RouteInfo{
{
Dst: net.IPNet{IP: net.ParseIP("192.168.0.4"), Mask: net.CIDRMask(ipv4FullMask, ipv4Bits)},
},
},
},
wantErr: false,
},
{
name: "Configure Interface and routes assign ip fail",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(netlink.NewMockNetlink(true, ""), plc),
netioshim: netio.NewMockNetIO(false, 0),
dhcpClient: &mockDHCP{},
ep: &endpoint{SecondaryInterfaces: map[string]*InterfaceInfo{"eth1": {Name: "eth1"}}},
},
epInfo: &EndpointInfo{
IfName: "eth1",
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("192.168.0.4"),
Mask: net.CIDRMask(subnetv4Mask, ipv4Bits),
},
},
},
wantErr: true,
wantErrMsg: "",
},
{
name: "Configure Interface and routes add routes fail",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(true, 1),
dhcpClient: &mockDHCP{},
ep: &endpoint{SecondaryInterfaces: map[string]*InterfaceInfo{"eth1": {Name: "eth1"}}},
},
epInfo: &EndpointInfo{
IfName: "eth1",
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("192.168.0.4"),
Mask: net.CIDRMask(subnetv4Mask, ipv4Bits),
},
},
Routes: []RouteInfo{
{
Dst: net.IPNet{IP: net.ParseIP("192.168.0.4"), Mask: net.CIDRMask(ipv4FullMask, ipv4Bits)},
},
},
},
wantErr: true,
wantErrMsg: netio.ErrMockNetIOFail.Error(),
},
{
name: "Configure Interface and routes add routes invalid interface name",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
dhcpClient: &mockDHCP{},
ep: &endpoint{SecondaryInterfaces: map[string]*InterfaceInfo{"eth1": {Name: "eth1"}}},
},
epInfo: &EndpointInfo{
IfName: "eth2",
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("192.168.0.4"),
Mask: net.CIDRMask(subnetv4Mask, ipv4Bits),
},
},
},
wantErr: true,
wantErrMsg: "SecondaryEndpointClient Error: eth2 does not exist",
},
{
name: "Configure Interface and routes add routes fail when no routes are provided",
client: &SecondaryEndpointClient{
netlink: netlink.NewMockNetlink(false, ""),
plClient: platform.NewMockExecClient(false),
netUtilsClient: networkutils.NewNetworkUtils(nl, plc),
netioshim: netio.NewMockNetIO(false, 0),
dhcpClient: &mockDHCP{},
ep: &endpoint{SecondaryInterfaces: map[string]*InterfaceInfo{"eth1": {Name: "eth1"}}},
},
epInfo: &EndpointInfo{
IfName: "eth1",
},
wantErr: true,
wantErrMsg: "SecondaryEndpointClient Error: routes expected for eth1",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
err := tt.client.ConfigureContainerInterfacesAndRoutes(tt.epInfo)
if tt.wantErr {
require.Error(t, err)
require.Contains(t, err.Error(), tt.wantErrMsg, "Expected:%v actual:%v", tt.wantErrMsg, err.Error())
} else {
require.NoError(t, err)
}
})
}
}