test: add uts for cni add function (#3069)

* add dualnic windows multitenancy test

* add linux multitenancy test

* add linux swiftv2 multi nic ep info test

* add windows swiftv2 infra with delegated ep info test

* add check to ensure epInfo.ifName is overwritten in add endpoint for linux swiftv2

* test options set in invoker propagate to all endpoint infos

* test dns in nwCfg propagates to all endpoint infos

* test options and data are created for each endpoint info

* address linter issues
This commit is contained in:
Alexander 2024-10-16 13:21:17 -07:00 коммит произвёл GitHub
Родитель b5046a001f
Коммит 2e8881348e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
7 изменённых файлов: 803 добавлений и 8 удалений

Просмотреть файл

@ -31,7 +31,7 @@ type MockIpamInvoker struct {
delegatedVMNIC bool
delegatedVMNICFail bool
ipMap map[string]bool
customReturn map[string]network.InterfaceInfo
add func(opt IPAMAddConfig) (ipamAddResult IPAMAddResult, err error)
}
func NewMockIpamInvoker(ipv6, v4Fail, v6Fail, delegatedVMNIC, delegatedVMNICFail bool) *MockIpamInvoker {
@ -47,8 +47,11 @@ func NewMockIpamInvoker(ipv6, v4Fail, v6Fail, delegatedVMNIC, delegatedVMNICFail
func NewCustomMockIpamInvoker(customReturn map[string]network.InterfaceInfo) *MockIpamInvoker {
return &MockIpamInvoker{
customReturn: customReturn,
add: func(_ IPAMAddConfig) (ipamAddResult IPAMAddResult, err error) {
ipamAddResult = IPAMAddResult{interfaceInfo: make(map[string]network.InterfaceInfo)}
ipamAddResult.interfaceInfo = customReturn
return ipamAddResult, nil
},
ipMap: make(map[string]bool),
}
}
@ -112,9 +115,8 @@ func (invoker *MockIpamInvoker) Add(opt IPAMAddConfig) (ipamAddResult IPAMAddRes
}
}
if invoker.customReturn != nil {
ipamAddResult.interfaceInfo = invoker.customReturn
return ipamAddResult, nil
if invoker.add != nil {
return invoker.add(opt)
}
return ipamAddResult, nil

Просмотреть файл

@ -46,6 +46,7 @@ func setNetworkOptions(cnsNwConfig *cns.GetNetworkContainerResponse, nwInfo *net
}
}
// update epInfo data field, allow host to nc, allow nc to host, and network container id
func setEndpointOptions(cnsNwConfig *cns.GetNetworkContainerResponse, epInfo *network.EndpointInfo, vethName string) {
if cnsNwConfig != nil && cnsNwConfig.MultiTenancyInfo.ID != 0 {
logger.Info("Setting Endpoint Options")

Просмотреть файл

@ -4,10 +4,18 @@
package network
import (
"fmt"
"net"
"regexp"
"testing"
"github.com/Azure/azure-container-networking/cni"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/network"
"github.com/Azure/azure-container-networking/platform"
"github.com/Azure/azure-container-networking/telemetry"
cniSkel "github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -160,3 +168,387 @@ func TestAddSnatForDns(t *testing.T) {
})
}
}
// linux swiftv2 example
func GetTestCNSResponseSecondaryLinux(macAddress string) map[string]network.InterfaceInfo {
parsedMAC, _ := net.ParseMAC(macAddress)
return map[string]network.InterfaceInfo{
string(cns.InfraNIC): {
IPConfigs: []*network.IPConfig{
{
Address: *getCIDRNotationForAddress("20.241.0.35/16"),
Gateway: net.ParseIP("20.241.0.35"), // actual scenario doesn't have a gateway
},
},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("169.254.2.1/16"),
Gw: net.ParseIP("10.244.2.1"),
},
{
Dst: *getCIDRNotationForAddress("0.0.0.0/32"),
Gw: net.ParseIP("169.254.2.1"),
},
},
NICType: cns.InfraNIC,
SkipDefaultRoutes: true,
HostSubnetPrefix: *getCIDRNotationForAddress("10.224.0.0/16"),
},
macAddress: {
MacAddress: parsedMAC,
IPConfigs: []*network.IPConfig{
{
Address: *getCIDRNotationForAddress("10.241.0.35/32"),
Gateway: net.ParseIP("10.241.0.35"), // actual scenario doesn't have a gateway
},
},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("169.254.2.1/32"),
Gw: net.ParseIP("10.244.2.1"),
},
{
Dst: *getCIDRNotationForAddress("0.0.0.0/0"),
Gw: net.ParseIP("169.254.2.1"),
},
},
NICType: cns.NodeNetworkInterfaceFrontendNIC,
SkipDefaultRoutes: false,
},
}
}
// Happy path scenario for add and delete
func TestPluginLinuxAdd(t *testing.T) {
resources := GetTestResources()
mulNwCfg := cni.NetworkConfig{
CNIVersion: "0.3.0",
Name: "mulnet",
MultiTenancy: true,
EnableExactMatchForPodName: true,
Master: "eth0",
}
nwCfg := cni.NetworkConfig{
CNIVersion: "0.3.0",
Name: "net",
MultiTenancy: false,
EnableExactMatchForPodName: true,
// test auto finding master interface
DNS: types.DNS{
Nameservers: []string{
"ns1", "ns2",
},
Domain: "myDomain",
},
}
macAddress := "60:45:bd76:f6:44"
parsedMACAddress, _ := net.ParseMAC(macAddress)
type endpointEntry struct {
epInfo *network.EndpointInfo
epIDRegex string
}
tests := []struct {
name string
plugin *NetPlugin
args *cniSkel.CmdArgs
want []endpointEntry
match func(*network.EndpointInfo, *network.EndpointInfo) bool
}{
{
// in swiftv1 linux multitenancy, we only get 1 response from cns at a time
name: "Add Happy Path Swiftv1 Multitenancy",
plugin: &NetPlugin{
Plugin: resources.Plugin,
nm: network.NewMockNetworkmanager(network.NewMockEndpointClient(nil)),
tb: &telemetry.TelemetryBuffer{},
report: &telemetry.CNIReport{},
multitenancyClient: NewMockMultitenancy(false, []*cns.GetNetworkContainerResponse{GetTestCNSResponse3()}),
},
args: &cniSkel.CmdArgs{
StdinData: mulNwCfg.Serialize(),
ContainerID: "test-container",
Netns: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
Args: fmt.Sprintf("K8S_POD_NAME=%v;K8S_POD_NAMESPACE=%v", "test-pod", "test-pod-ns"),
IfName: eth0IfName,
},
match: func(ei1, ei2 *network.EndpointInfo) bool {
return ei1.NetworkContainerID == ei2.NetworkContainerID
},
want: []endpointEntry{
// should match with GetTestCNSResponse3
{
epInfo: &network.EndpointInfo{
ContainerID: "test-container",
Data: map[string]interface{}{
"VlanID": 1, // Vlan ID used here
"localIP": "168.254.0.4/17",
"snatBridgeIP": "168.254.0.1/17",
"vethname": "mulnettest-containereth0",
},
Routes: []network.RouteInfo{
{
Dst: *parseCIDR("192.168.0.4/24"),
Gw: net.ParseIP("192.168.0.1"),
// interface to use is NOT propagated to ep info
},
},
AllowInboundFromHostToNC: true,
EnableSnatOnHost: true,
EnableMultiTenancy: true,
EnableSnatForDns: true,
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.InfraNIC,
MasterIfName: eth0IfName,
NetworkContainerID: "Swift_74b34111-6e92-49ee-a82a-8881c850ce0e",
NetworkID: "mulnet",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "20.240.0.0/24",
Options: map[string]interface{}{
dockerNetworkOption: map[string]interface{}{
"VlanID": "1", // doesn't seem to be used in linux
"snatBridgeIP": "168.254.0.1/17",
},
},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("20.0.0.10"),
Mask: getIPNetWithString("20.0.0.10/24").Mask,
},
},
NATInfo: nil,
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
// matches cns ip configuration (20.0.0.1/24 == 20.0.0.0/24)
Prefix: *getIPNetWithString("20.0.0.0/24"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("20.0.0.1"),
},
},
},
epIDRegex: `test-con-eth0`,
},
},
},
{
// Based on a live swiftv2 linux cluster's cns invoker response
name: "Add Happy Path Swiftv2",
plugin: &NetPlugin{
Plugin: resources.Plugin,
nm: network.NewMockNetworkmanager(network.NewMockEndpointClient(nil)),
tb: &telemetry.TelemetryBuffer{},
report: &telemetry.CNIReport{},
ipamInvoker: &MockIpamInvoker{
add: func(opt IPAMAddConfig) (ipamAddResult IPAMAddResult, err error) {
ipamAddResult = IPAMAddResult{interfaceInfo: make(map[string]network.InterfaceInfo)}
ipamAddResult.interfaceInfo = GetTestCNSResponseSecondaryLinux(macAddress)
opt.options["testflag"] = "copy"
return ipamAddResult, nil
},
ipMap: make(map[string]bool),
},
netClient: &InterfaceGetterMock{
// used in secondary find master interface
interfaces: []net.Interface{
{
Name: "secondary",
HardwareAddr: parsedMACAddress,
},
{
Name: "primary",
HardwareAddr: net.HardwareAddr{},
},
},
// used in primary find master interface
interfaceAddrs: map[string][]net.Addr{
"primary": {
// match with the host subnet prefix to know that this ip belongs to the host
getCIDRNotationForAddress("10.224.0.0/16"),
},
},
},
},
args: &cniSkel.CmdArgs{
StdinData: nwCfg.Serialize(),
ContainerID: "test-container",
Netns: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
Args: fmt.Sprintf("K8S_POD_NAME=%v;K8S_POD_NAMESPACE=%v", "test-pod", "test-pod-ns"),
IfName: eth0IfName,
},
match: func(ei1, ei2 *network.EndpointInfo) bool {
return ei1.NICType == ei2.NICType
},
want: []endpointEntry{
// should match infra
{
epInfo: &network.EndpointInfo{
ContainerID: "test-container",
Data: map[string]interface{}{
"vethname": "nettest-containereth0",
},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("169.254.2.1/16"),
Gw: net.ParseIP("10.244.2.1"),
},
{
Dst: *getCIDRNotationForAddress("0.0.0.0/32"),
Gw: net.ParseIP("169.254.2.1"),
},
},
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.InfraNIC,
SkipDefaultRoutes: true,
MasterIfName: "primary",
NetworkID: "net",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "10.224.0.0/16",
EndpointDNS: network.DNSInfo{
Servers: []string{
"ns1", "ns2",
},
Suffix: "myDomain",
},
Options: map[string]interface{}{
"testflag": "copy",
},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("20.241.0.35"),
Mask: getIPNetWithString("20.241.0.35/16").Mask,
},
},
NATInfo: nil,
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
// matches cns ip configuration (20.241.0.0/16 == 20.241.0.35/16)
Prefix: *getIPNetWithString("20.241.0.0/16"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("20.241.0.35"),
},
},
},
epIDRegex: `.*`,
},
// should match secondary
{
epInfo: &network.EndpointInfo{
MacAddress: parsedMACAddress,
ContainerID: "test-container",
Data: map[string]interface{}{
"vethname": "nettest-containereth0",
},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("169.254.2.1/32"),
Gw: net.ParseIP("10.244.2.1"),
},
{
Dst: *getCIDRNotationForAddress("0.0.0.0/0"),
Gw: net.ParseIP("169.254.2.1"),
},
},
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.NodeNetworkInterfaceFrontendNIC,
SkipDefaultRoutes: false,
MasterIfName: "secondary",
NetworkID: "net",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "<nil>",
EndpointDNS: network.DNSInfo{
Servers: []string{
"ns1", "ns2",
},
Suffix: "myDomain",
},
Options: map[string]interface{}{
"testflag": "copy",
},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("10.241.0.35"),
Mask: getIPNetWithString("10.241.0.35/32").Mask,
},
},
NATInfo: nil,
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
Prefix: *getIPNetWithString("10.241.0.35/32"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("10.241.0.35"),
},
},
},
epIDRegex: `.*`,
},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
err := tt.plugin.Add(tt.args)
require.NoError(t, err)
allEndpoints, _ := tt.plugin.nm.GetAllEndpoints("")
require.Len(t, allEndpoints, len(tt.want))
// compare contents
for _, wantedEndpointEntry := range tt.want {
epID := "none"
for _, endpointInfo := range allEndpoints {
if !tt.match(wantedEndpointEntry.epInfo, endpointInfo) {
continue
}
// save the endpoint id before removing it
epID = endpointInfo.EndpointID
require.Regexp(t, regexp.MustCompile(wantedEndpointEntry.epIDRegex), epID)
// omit endpoint id and ifname fields as they are nondeterministic
endpointInfo.EndpointID = ""
endpointInfo.IfName = ""
require.Equal(t, wantedEndpointEntry.epInfo, endpointInfo)
}
if epID == "none" {
t.Fail()
}
err = tt.plugin.nm.DeleteEndpoint("", epID, nil)
require.NoError(t, err)
}
// confirm separate entities
// that is, if one is modified, the other should not be modified
epInfos := []*network.EndpointInfo{}
for _, val := range allEndpoints {
epInfos = append(epInfos, val)
}
if len(epInfos) > 1 {
epInfo1 := epInfos[0]
epInfo2 := epInfos[1]
epInfo1.Data["dummy"] = "dummy value"
epInfo1.Options["dummy"] = "another dummy value"
require.NotEqual(t, epInfo1.Data, epInfo2.Data)
require.NotEqual(t, epInfo1.Options, epInfo2.Options)
}
// ensure deleted
require.Empty(t, allEndpoints)
})
}
}

Просмотреть файл

@ -688,6 +688,44 @@ func GetTestCNSResponse2() *cns.GetNetworkContainerResponse {
}
}
// For use with GetAllNetworkContainers in linux multitenancy
func GetTestCNSResponse3() *cns.GetNetworkContainerResponse {
return &cns.GetNetworkContainerResponse{
NetworkContainerID: "Swift_74b34111-6e92-49ee-a82a-8881c850ce0e",
IPConfiguration: cns.IPConfiguration{
IPSubnet: cns.IPSubnet{
IPAddress: "20.0.0.10",
PrefixLength: ipPrefixLen,
},
DNSServers: []string{
"168.63.129.16",
},
GatewayIPAddress: "20.0.0.1",
},
Routes: []cns.Route{
// dummy route
{
IPAddress: "192.168.0.4/24",
GatewayIPAddress: "192.168.0.1",
},
},
MultiTenancyInfo: cns.MultiTenancyInfo{
EncapType: cns.Vlan,
ID: multiTenancyVlan1,
},
PrimaryInterfaceIdentifier: "20.240.0.4/24",
LocalIPConfiguration: cns.IPConfiguration{
IPSubnet: cns.IPSubnet{
IPAddress: "168.254.0.4",
PrefixLength: localIPPrefixLen,
},
GatewayIPAddress: "168.254.0.1",
},
AllowHostToNCCommunication: true,
AllowNCToHostCommunication: false,
}
}
// Test Multitenancy Add
func TestPluginMultitenancyAdd(t *testing.T) {
plugin, _ := cni.NewPlugin("test", "0.3.0")

Просмотреть файл

@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"net"
"regexp"
"testing"
"github.com/Azure/azure-container-networking/cni"
@ -14,6 +15,7 @@ import (
"github.com/Azure/azure-container-networking/network"
"github.com/Azure/azure-container-networking/network/hnswrapper"
"github.com/Azure/azure-container-networking/network/policy"
"github.com/Azure/azure-container-networking/platform"
"github.com/Azure/azure-container-networking/telemetry"
hnsv2 "github.com/Microsoft/hcsshim/hcn"
cniSkel "github.com/containernetworking/cni/pkg/skel"
@ -855,3 +857,362 @@ func TestPluginMultitenancyWindowsDelete(t *testing.T) {
})
}
}
// windows swiftv2 example
func GetTestCNSResponseSecondaryWindows(macAddress string) map[string]network.InterfaceInfo {
parsedMAC, _ := net.ParseMAC(macAddress)
return map[string]network.InterfaceInfo{
string(cns.InfraNIC): {
IPConfigs: []*network.IPConfig{
{
Address: *getCIDRNotationForAddress("10.244.2.107/16"),
Gateway: net.ParseIP("10.244.2.1"),
},
},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("1.1.1.1/24"),
Gw: net.ParseIP("10.244.2.1"),
},
},
SkipDefaultRoutes: true,
NICType: cns.InfraNIC,
HostSubnetPrefix: *getCIDRNotationForAddress("20.224.0.0/16"),
},
macAddress: {
MacAddress: parsedMAC,
IPConfigs: []*network.IPConfig{
{
Address: *getCIDRNotationForAddress("10.241.0.21/16"),
Gateway: net.ParseIP("10.241.0.1"),
},
},
Routes: []network.RouteInfo{
{
// just to ensure we don't overwrite if we had more routes
Dst: *getCIDRNotationForAddress("2.2.2.2/24"),
Gw: net.ParseIP("99.244.2.1"),
},
},
NICType: cns.NodeNetworkInterfaceFrontendNIC,
},
}
}
// Happy path scenario for add and delete
func TestPluginWindowsAdd(t *testing.T) {
resources := GetTestResources()
localNwCfg := cni.NetworkConfig{
CNIVersion: "0.3.0",
Name: "mulnet",
MultiTenancy: true,
EnableExactMatchForPodName: true,
Master: "eth0",
}
nwCfg := cni.NetworkConfig{
CNIVersion: "0.3.0",
Name: "net",
MultiTenancy: false,
EnableExactMatchForPodName: true,
}
macAddress := "60:45:bd:76:f6:44"
parsedMACAddress, _ := net.ParseMAC(macAddress)
type endpointEntry struct {
epInfo *network.EndpointInfo
epIDRegex string
}
tests := []struct {
name string
plugin *NetPlugin
args *cniSkel.CmdArgs
want []endpointEntry
match func(*network.EndpointInfo, *network.EndpointInfo) bool
}{
{
name: "Add Happy Path Dual NIC",
plugin: &NetPlugin{
Plugin: resources.Plugin,
nm: network.NewMockNetworkmanager(network.NewMockEndpointClient(nil)),
tb: &telemetry.TelemetryBuffer{},
report: &telemetry.CNIReport{},
multitenancyClient: NewMockMultitenancy(false, []*cns.GetNetworkContainerResponse{GetTestCNSResponse1(), GetTestCNSResponse2()}),
},
args: &cniSkel.CmdArgs{
StdinData: localNwCfg.Serialize(),
ContainerID: "test-container",
Netns: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
Args: fmt.Sprintf("K8S_POD_NAME=%v;K8S_POD_NAMESPACE=%v", "test-pod", "test-pod-ns"),
IfName: eth0IfName,
},
match: func(ei1, ei2 *network.EndpointInfo) bool {
return ei1.NetworkID == ei2.NetworkID
},
want: []endpointEntry{
// should match with GetTestCNSResponse1
{
epInfo: &network.EndpointInfo{
ContainerID: "test-container",
Data: map[string]interface{}{
"cnetAddressSpace": []string(nil),
},
Routes: []network.RouteInfo{},
EnableSnatOnHost: true,
EnableMultiTenancy: true,
EnableSnatForDns: true,
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.InfraNIC,
MasterIfName: eth0IfName,
NetworkID: "mulnet-vlan1-20-0-0-0_24",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "20.240.0.0/24",
Options: map[string]interface{}{
dockerNetworkOption: map[string]interface{}{
"VlanID": "1",
},
},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("20.0.0.10"),
Mask: getIPNetWithString("20.0.0.10/24").Mask,
},
},
// LocalIPConfiguration doesn't seem used in windows
// Constant, in windows, NAT Info comes from
// options > ipamAddConfig >
// cns invoker may populate network.SNATIPKey with the default response received >
// getNATInfo (with nwCfg) > adds nat info based on condition
// typically adds azure dns (168.63.129.16)
NATInfo: []policy.NATInfo{
{
Destinations: []string{"168.63.129.16"},
},
},
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
// matches cns ip configuration (20.0.0.1/24 == 20.0.0.0/24)
Prefix: *getIPNetWithString("20.0.0.0/24"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("20.0.0.1"),
},
},
},
epIDRegex: `.*`,
},
// should match with GetTestCNSResponse2
{
epInfo: &network.EndpointInfo{
ContainerID: "test-container",
Data: map[string]interface{}{
"cnetAddressSpace": []string(nil),
},
Routes: []network.RouteInfo{},
EnableSnatOnHost: true,
EnableMultiTenancy: true,
EnableSnatForDns: true,
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.InfraNIC,
MasterIfName: eth0IfName,
NetworkID: "mulnet-vlan2-10-0-0-0_24",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "10.240.0.0/24",
Options: map[string]interface{}{
dockerNetworkOption: map[string]interface{}{
"VlanID": "2",
},
},
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("10.0.0.10"),
Mask: getIPNetWithString("10.0.0.10/24").Mask,
},
},
NATInfo: []policy.NATInfo{
{
Destinations: []string{"168.63.129.16"},
},
},
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
Prefix: *getIPNetWithString("10.0.0.0/24"),
Gateway: net.ParseIP("10.0.0.1"),
},
},
},
epIDRegex: `.*`,
},
},
},
{
// Based on a live swiftv2 windows cluster's (infra + delegated) cns invoker response
name: "Add Happy Path Swiftv2",
plugin: &NetPlugin{
Plugin: resources.Plugin,
nm: network.NewMockNetworkmanager(network.NewMockEndpointClient(nil)),
tb: &telemetry.TelemetryBuffer{},
report: &telemetry.CNIReport{},
ipamInvoker: NewCustomMockIpamInvoker(GetTestCNSResponseSecondaryWindows(macAddress)),
netClient: &InterfaceGetterMock{
// used in secondary find master interface
interfaces: []net.Interface{
{
Name: "secondary",
HardwareAddr: parsedMACAddress,
},
{
Name: "primary",
HardwareAddr: net.HardwareAddr{},
},
},
// used in primary find master interface
interfaceAddrs: map[string][]net.Addr{
"primary": {
// match with the host subnet prefix to know that this ip belongs to the host
getCIDRNotationForAddress("20.224.0.0/16"),
},
},
},
},
args: &cniSkel.CmdArgs{
StdinData: nwCfg.Serialize(),
ContainerID: "test-container",
Netns: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
Args: fmt.Sprintf("K8S_POD_NAME=%v;K8S_POD_NAMESPACE=%v", "test-pod", "test-pod-ns"),
IfName: eth0IfName,
},
match: func(ei1, ei2 *network.EndpointInfo) bool {
return ei1.NICType == ei2.NICType
},
want: []endpointEntry{
// should match infra
{
epInfo: &network.EndpointInfo{
ContainerID: "test-container",
Data: map[string]interface{}{},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("1.1.1.1/24"),
Gw: net.ParseIP("10.244.2.1"),
},
},
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.InfraNIC,
SkipDefaultRoutes: true,
MasterIfName: "primary",
NetworkID: "net",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "20.224.0.0/16",
Options: map[string]interface{}{},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("10.244.2.107"),
Mask: getIPNetWithString("10.244.2.107/16").Mask,
},
},
NATInfo: nil,
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
Prefix: *getIPNetWithString("10.244.0.0/16"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("10.244.2.1"),
},
},
},
epIDRegex: `.*`,
},
// should match secondary
{
epInfo: &network.EndpointInfo{
MacAddress: parsedMACAddress,
ContainerID: "test-container",
Data: map[string]interface{}{},
Routes: []network.RouteInfo{
{
// just to ensure we don't overwrite if we had more routes
Dst: *getCIDRNotationForAddress("2.2.2.2/24"),
Gw: net.ParseIP("99.244.2.1"),
},
},
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.NodeNetworkInterfaceFrontendNIC,
SkipDefaultRoutes: false,
MasterIfName: "secondary",
NetworkID: "azure-" + macAddress,
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "<nil>",
Options: map[string]interface{}{},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("10.241.0.21"),
Mask: getIPNetWithString("10.241.0.21/16").Mask,
},
},
NATInfo: nil,
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
Prefix: *getIPNetWithString("10.241.0.21/16"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("10.241.0.1"),
},
},
},
epIDRegex: `.*`,
},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
err := tt.plugin.Add(tt.args)
require.NoError(t, err)
allEndpoints, _ := tt.plugin.nm.GetAllEndpoints("")
require.Len(t, allEndpoints, len(tt.want))
for _, wantedEndpointEntry := range tt.want {
epID := "none"
for _, endpointInfo := range allEndpoints {
if !tt.match(wantedEndpointEntry.epInfo, endpointInfo) {
continue
}
// save the endpoint id before removing it
epID = endpointInfo.EndpointID
require.Regexp(t, regexp.MustCompile(wantedEndpointEntry.epIDRegex), epID)
// omit endpoint id and ifname fields as they are nondeterministic
endpointInfo.EndpointID = ""
endpointInfo.IfName = ""
require.Equal(t, wantedEndpointEntry.epInfo, endpointInfo)
}
if epID == "none" {
t.Fail()
}
err = tt.plugin.nm.DeleteEndpoint("", epID, nil)
require.NoError(t, err)
}
// ensure deleted
require.Empty(t, allEndpoints)
})
}
}

Просмотреть файл

@ -66,7 +66,7 @@ type EndpointInfo struct {
EndpointID string
ContainerID string
NetNsPath string
IfName string // value differs during creation vs. deletion flow
IfName string // value differs during creation vs. deletion flow; used in statefile, not necessarily the nic name
SandboxKey string
IfIndex int
MacAddress net.HardwareAddr
@ -93,7 +93,7 @@ type EndpointInfo struct {
IPV6Mode string
VnetCidrs string
ServiceCidrs string
NATInfo []policy.NATInfo
NATInfo []policy.NATInfo // windows only
NICType cns.NICType
SkipDefaultRoutes bool
HNSEndpointID string

Просмотреть файл

@ -79,6 +79,7 @@ func TestSecondaryAddEndpoints(t *testing.T) {
} 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")
}
})
}