azure-container-networking/network/endpoint_windows_test.go

698 строки
19 KiB
Go

// Copyright 2017 Microsoft. All rights reserved.
// MIT License
//go:build windows
// +build windows
package network
import (
"errors"
"fmt"
"net"
"strings"
"testing"
"time"
"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/network/hnswrapper"
"github.com/Azure/azure-container-networking/platform"
"github.com/Microsoft/hcsshim/hcn"
)
var (
instanceID = "12345-abcde-789"
locationPath = "12345-abcde-789-fea14"
pnpID = "PCI\\VEN_15B3&DEV_101C&SUBSYS_000715B3&REV_00\\5&8c5acce&0&0"
macAddress = "60-45-bd-12-45-65"
networkID = "azure-23:34:56:78:90:ab"
networkName = "l1vh"
l1vhNetworkType = hcn.Transparent
)
func TestNewAndDeleteEndpointImplHnsV2(t *testing.T) {
nw := &network{
Endpoints: map[string]*endpoint{},
}
// this hnsv2 variable overwrites the package level variable in network
// we do this to avoid passing around os specific objects in platform agnostic code
Hnsv2 = hnswrapper.NewHnsv2wrapperFake()
epInfo := &EndpointInfo{
EndpointID: "753d3fb6-e9b3-49e2-a109-2acc5dda61f1",
ContainerID: "545055c2-1462-42c8-b222-e75d0b291632",
NetNsPath: "fakeNameSpace",
IfName: "eth0",
Data: make(map[string]interface{}),
EndpointDNS: DNSInfo{
Suffix: "10.0.0.0",
Servers: []string{"10.0.0.1, 10.0.0.2"},
Options: nil,
},
MacAddress: net.HardwareAddr("00:00:5e:00:53:01"),
NICType: cns.InfraNIC,
HNSNetworkID: "853d3fb6-e9b3-49e2-a109-2acc5dda61f1",
}
ep, err := nw.newEndpointImplHnsV2(nil, epInfo)
if err != nil {
fmt.Printf("+%v", err)
t.Fatal(err)
}
if err = validateEndpoints([]*endpoint{ep}); err != nil {
fmt.Printf("+%v", err)
t.Fatal(err)
}
if epInfo.HNSEndpointID == "" {
t.Fatal("hns endpoint id not populated inside endpoint info during new endpoint impl call")
}
if ep.HnsId == "" {
t.Fatal("hns endpoint id not populated inside endpoint struct during new endpoint impl call")
}
if ep.HNSNetworkID == "" {
t.Fatal("hns network id was not copied to the endpoint struct during new endpoint impl call")
}
err = nw.deleteEndpointImplHnsV2(ep)
if err != nil {
fmt.Printf("+%v", err)
t.Fatal(err)
}
}
func TestDeleteEndpointImplHnsV2ForIB(t *testing.T) {
nw := &network{
Endpoints: map[string]*endpoint{},
}
// this hnsv2 variable overwrites the package level variable in network
// we do this to avoid passing around os specific objects in platform agnostic code
Hnsv2 = hnswrapper.Hnsv2wrapperwithtimeout{
Hnsv2: hnswrapper.NewHnsv2wrapperFake(),
}
ep := endpoint{
HnsId: "753d3fb6-e9b3-49e2-a109-2acc5dda61f1",
IfName: "ib1",
MacAddress: net.HardwareAddr("00:00:5e:00:53:01"),
NICType: cns.BackendNIC,
}
mockCli := NewMockEndpointClient(nil)
err := nw.deleteEndpointImpl(netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false), mockCli,
netio.NewMockNetIO(false, 0), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, &ep)
if err != nil {
t.Fatal("endpoint deletion for IB is executed")
}
}
// Test endpoint deletion when hns id is empty
func TestDeleteEndpointImplHnsV2WithEmptyHNSID(t *testing.T) {
nw := &network{
Endpoints: map[string]*endpoint{},
}
// this hnsv2 variable overwrites the package level variable in network
// we do this to avoid passing around os specific objects in platform agnostic code
Hnsv2 = hnswrapper.Hnsv2wrapperwithtimeout{
Hnsv2: hnswrapper.NewHnsv2wrapperFake(),
}
ep := endpoint{
HnsId: "",
IfName: "eth1",
MacAddress: net.HardwareAddr("00:00:5e:00:53:01"),
NICType: cns.NodeNetworkInterfaceFrontendNIC,
}
// should return nil because HnsID is empty
mockCli := NewMockEndpointClient(nil)
err := nw.deleteEndpointImpl(netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false), mockCli,
netio.NewMockNetIO(false, 0), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, &ep)
if err != nil {
t.Fatal("endpoint deletion gets executed")
}
}
func TestNewEndpointImplHnsv2Timesout(t *testing.T) {
nw := &network{
Endpoints: map[string]*endpoint{},
}
// this hnsv2 variable overwrites the package level variable in network
// we do this to avoid passing around os specific objects in platform agnostic code
hnsFake := hnswrapper.NewHnsv2wrapperFake()
hnsFake.Delay = 10 * time.Second
Hnsv2 = hnswrapper.Hnsv2wrapperwithtimeout{
Hnsv2: hnsFake,
HnsCallTimeout: 5 * time.Second,
}
epInfo := &EndpointInfo{
EndpointID: "753d3fb6-e9b3-49e2-a109-2acc5dda61f1",
ContainerID: "545055c2-1462-42c8-b222-e75d0b291632",
NetNsPath: "fakeNameSpace",
IfName: "eth0",
Data: make(map[string]interface{}),
EndpointDNS: DNSInfo{
Suffix: "10.0.0.0",
Servers: []string{"10.0.0.1, 10.0.0.2"},
Options: nil,
},
MacAddress: net.HardwareAddr("00:00:5e:00:53:01"),
}
_, err := nw.newEndpointImplHnsV2(nil, epInfo)
if err == nil {
t.Fatal("Failed to timeout HNS calls for creating endpoint")
}
}
func TestDeleteEndpointImplHnsv2Timeout(t *testing.T) {
nw := &network{
Endpoints: map[string]*endpoint{},
}
Hnsv2 = hnswrapper.NewHnsv2wrapperFake()
epInfo := &EndpointInfo{
EndpointID: "753d3fb6-e9b3-49e2-a109-2acc5dda61f1",
ContainerID: "545055c2-1462-42c8-b222-e75d0b291632",
NetNsPath: "fakeNameSpace",
IfName: "eth0",
Data: make(map[string]interface{}),
EndpointDNS: DNSInfo{
Suffix: "10.0.0.0",
Servers: []string{"10.0.0.1, 10.0.0.2"},
Options: nil,
},
MacAddress: net.HardwareAddr("00:00:5e:00:53:01"),
}
endpoint, err := nw.newEndpointImplHnsV2(nil, epInfo)
if err != nil {
fmt.Printf("+%v", err)
t.Fatal(err)
}
hnsFake := hnswrapper.NewHnsv2wrapperFake()
hnsFake.Delay = 10 * time.Second
Hnsv2 = hnswrapper.Hnsv2wrapperwithtimeout{
Hnsv2: hnsFake,
HnsCallTimeout: 5 * time.Second,
}
err = nw.deleteEndpointImplHnsV2(endpoint)
if err == nil {
t.Fatal("Failed to timeout HNS calls for deleting endpoint")
}
}
func TestCreateEndpointImplHnsv1Timeout(t *testing.T) {
nw := &network{
Endpoints: map[string]*endpoint{},
}
hnsFake := hnswrapper.NewHnsv1wrapperFake()
hnsFake.Delay = 10 * time.Second
Hnsv1 = hnswrapper.Hnsv1wrapperwithtimeout{
Hnsv1: hnsFake,
HnsCallTimeout: 5 * time.Second,
}
epInfo := &EndpointInfo{
EndpointID: "753d3fb6-e9b3-49e2-a109-2acc5dda61f1",
ContainerID: "545055c2-1462-42c8-b222-e75d0b291632",
NetNsPath: "fakeNameSpace",
IfName: "eth0",
Data: make(map[string]interface{}),
EndpointDNS: DNSInfo{
Suffix: "10.0.0.0",
Servers: []string{"10.0.0.1, 10.0.0.2"},
Options: nil,
},
MacAddress: net.HardwareAddr("00:00:5e:00:53:01"),
}
_, err := nw.newEndpointImplHnsV1(epInfo, nil)
if err == nil {
t.Fatal("Failed to timeout HNS calls for creating endpoint")
}
}
func TestDeleteEndpointImplHnsv1Timeout(t *testing.T) {
nw := &network{
Endpoints: map[string]*endpoint{},
}
Hnsv1 = hnswrapper.NewHnsv1wrapperFake()
epInfo := &EndpointInfo{
EndpointID: "753d3fb6-e9b3-49e2-a109-2acc5dda61f1",
ContainerID: "545055c2-1462-42c8-b222-e75d0b291632",
NetNsPath: "fakeNameSpace",
IfName: "eth0",
Data: make(map[string]interface{}),
EndpointDNS: DNSInfo{
Suffix: "10.0.0.0",
Servers: []string{"10.0.0.1, 10.0.0.2"},
Options: nil,
},
MacAddress: net.HardwareAddr("00:00:5e:00:53:01"),
}
endpoint, err := nw.newEndpointImplHnsV1(epInfo, nil)
if err != nil {
fmt.Printf("+%v", err)
t.Fatal(err)
}
hnsFake := hnswrapper.NewHnsv1wrapperFake()
hnsFake.Delay = 10 * time.Second
Hnsv1 = hnswrapper.Hnsv1wrapperwithtimeout{
Hnsv1: hnsFake,
HnsCallTimeout: 5 * time.Second,
}
err = nw.deleteEndpointImplHnsV1(endpoint)
if err == nil {
t.Fatal("Failed to timeout HNS calls for deleting endpoint")
}
}
func TestDisableVFDeviceHappyPath(t *testing.T) {
mockExecClient := platform.NewMockExecClient(false)
nm := &networkManager{
plClient: mockExecClient,
}
// happy path
mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) {
if strings.Contains(cmd, "Disable-PnpDevice") {
return succededCaseReturn, nil
}
return "", nil
})
err := disableVFDevice(instanceID, nm.plClient)
if err != nil {
t.Fatalf("Failed to test disable VF happy path due to %v", err)
}
}
func TestDisableVFDeviceUnHappyPath(t *testing.T) {
mockExecClient := platform.NewMockExecClient(false)
// set unhappy path
mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) {
return failedCaseReturn, errTestFailure
})
err := disableVFDevice(instanceID, mockExecClient)
if err == nil {
t.Fatalf("Failed to test disable VF unhappy path")
}
}
func TestGetLocationPathHappyPath(t *testing.T) {
mockExecClient := platform.NewMockExecClient(false)
nm := &networkManager{
plClient: mockExecClient,
}
// happy path
mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) {
if strings.Contains(cmd, "Get-PnpDeviceProperty") {
return succededCaseReturn, nil
}
return "", nil
})
_, err := getLocationPath(instanceID, nm.plClient)
if err != nil {
t.Fatalf("Failed to test get locationPath happy path due to %v", err)
}
}
func TestGetLocationPathUnHappyPath(t *testing.T) {
mockExecClient := platform.NewMockExecClient(false)
// set unhappy path
mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) {
return failedCaseReturn, errTestFailure
})
_, err := getLocationPath(instanceID, mockExecClient)
if err == nil {
t.Fatal("Failed to test get location path on unhappy path")
}
}
func TestDismountVFDeviceHappyPath(t *testing.T) {
mockExecClient := platform.NewMockExecClient(false)
nm := &networkManager{
plClient: mockExecClient,
}
// happy path
mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) {
if strings.Contains(cmd, "Dismount-VMHostAssignableDevice") {
return succededCaseReturn, nil
}
return "", nil
})
err := dismountVFDevice(locationPath, nm.plClient)
if err != nil {
t.Fatalf("Failed to test dismount vf device happy path due to %v", err)
}
}
func TestDismountVFDeviceUnHappyPath(t *testing.T) {
mockExecClient := platform.NewMockExecClient(false)
// set unhappy path
mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) {
return failedCaseReturn, errTestFailure
})
err := dismountVFDevice(instanceID, mockExecClient)
if err == nil {
t.Fatal("Failed to test dismount VF unhappy path")
}
}
func TestGetPnPDeviceIDHappyPath(t *testing.T) {
mockExecClient := platform.NewMockExecClient(false)
nm := &networkManager{
plClient: mockExecClient,
}
// happy path
mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) {
if strings.Contains(cmd, "Get-PnpDeviceProperty") || strings.Contains(cmd, "Get-VMHostAssignableDevice") {
return succededCaseReturn, nil
}
return "", nil
})
_, err := getPnPDeviceID(instanceID, nm.plClient)
if err != nil {
t.Fatalf("Failed to test get pnp device id happy path due to %v", err)
}
}
func TestGetPnPDeviceIDUnHappyPath(t *testing.T) {
mockExecClient := platform.NewMockExecClient(false)
// set unhappy path
mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) {
return failedCaseReturn, errTestFailure
})
_, err := getPnPDeviceID(instanceID, mockExecClient)
if err == nil {
t.Fatal("Failed to test get pnp device id unhappy path")
}
}
func TestGetPnPDeviceStateHappyPath(t *testing.T) {
mockExecClient := platform.NewMockExecClient(false)
nm := &networkManager{
plClient: mockExecClient,
}
// happy path
mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) {
if strings.Contains(cmd, "Get-PnpDeviceProperty") {
return succededCaseReturn, nil
}
return "", nil
})
_, _, err := getPnpDeviceState(instanceID, nm.plClient)
if err != nil {
t.Fatalf("Failed to test happy path due to %v", err)
}
}
func TestGetPnPDeviceStateUnHappyPath(t *testing.T) {
mockExecClient := platform.NewMockExecClient(false)
// set unhappy path
mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) {
return failedCaseReturn, errTestFailure
})
_, _, err := getPnpDeviceState(instanceID, mockExecClient)
if err == nil {
t.Fatal("Failed to test get pnp device state unhappy path")
}
}
// endpoint creation is not required for IB
func TestNewEndpointImplHnsv2ForIBHappyPath(t *testing.T) {
nw := &network{
Endpoints: map[string]*endpoint{},
}
// this hnsv2 variable overwrites the package level variable in network
// we do this to avoid passing around os specific objects in platform agnostic code
hnsFake := hnswrapper.NewHnsv2wrapperFake()
Hnsv2 = hnswrapper.Hnsv2wrapperwithtimeout{
Hnsv2: hnsFake,
HnsCallTimeout: 5 * time.Second,
}
epInfo := &EndpointInfo{
EndpointID: "768e8deb-eth1",
Data: make(map[string]interface{}),
IfName: "eth1",
NICType: cns.BackendNIC,
PnPID: pnpID,
}
// Happy Path
endpoint, err := nw.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false),
netio.NewMockNetIO(false, 0), NewMockEndpointClient(nil), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, epInfo)
if endpoint != nil || err != nil {
t.Fatalf("Endpoint is created for IB due to %v", err)
}
}
func TestNewEndpointImplHnsv2ForIBUnHappyPath(t *testing.T) {
nw := &network{
Endpoints: map[string]*endpoint{},
}
// this hnsv2 variable overwrites the package level variable in network
// we do this to avoid passing around os specific objects in platform agnostic code
hnsFake := hnswrapper.NewHnsv2wrapperFake()
Hnsv2 = hnswrapper.Hnsv2wrapperwithtimeout{
Hnsv2: hnsFake,
HnsCallTimeout: 5 * time.Second,
}
epInfo := &EndpointInfo{
EndpointID: "768e8deb-eth1",
Data: make(map[string]interface{}),
IfName: "eth1",
NICType: cns.BackendNIC,
PnPID: pnpID,
}
// Set UnHappy Path
_, err := nw.newEndpointImpl(nil, netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(true),
netio.NewMockNetIO(false, 0), NewMockEndpointClient(nil), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, epInfo)
if err == nil {
t.Fatal("Failed to test Endpoint creation for IB with unhappy path")
}
if !errors.Is(err, platform.ErrMockExec) {
t.Fatalf("Unexpected Error:%v; Error should be %v", err, platform.ErrMockExec)
}
}
func TestCreateAndDeleteEndpointImplHnsv2ForDelegatedHappyPath(t *testing.T) {
nw := &network{
Endpoints: map[string]*endpoint{},
}
// this hnsv2 variable overwrites the package level variable in network
// we do this to avoid passing around os specific objects in platform agnostic code
hnsFake := hnswrapper.NewHnsv2wrapperFake()
Hnsv2 = hnswrapper.Hnsv2wrapperwithtimeout{
Hnsv2: hnsFake,
HnsCallTimeout: 5 * time.Second,
}
epInfo := &EndpointInfo{
EndpointID: "768e8deb-eth1",
Data: make(map[string]interface{}),
IfName: "eth1",
NICType: cns.NodeNetworkInterfaceFrontendNIC,
MacAddress: net.HardwareAddr("00:00:5e:00:53:01"),
}
// Happy Path to create and delete endpoint for delegated NIC
ep, err := nw.newEndpointImplHnsV2(nil, epInfo)
if err != nil {
t.Fatalf("Failed to create endpoint for Delegated NIC due to %v", err)
}
mockCli := NewMockEndpointClient(nil)
err = nw.deleteEndpointImpl(netlink.NewMockNetlink(false, ""), platform.NewMockExecClient(false), mockCli,
netio.NewMockNetIO(false, 0), NewMockNamespaceClient(), iptables.NewClient(), &mockDHCP{}, ep)
if err != nil {
t.Fatalf("Failed to delete endpoint for Delegated NIC due to %v", err)
}
}
// mock to nivoke endpointState deletion with InfraNIC + DelegatedNIC
func TestDeleteEndpointStateForInfraDelegatedNIC(t *testing.T) {
nm := &networkManager{
ExternalInterfaces: map[string]*externalInterface{},
}
// this hnsv2 variable overwrites the package level variable in network
// we do this to avoid passing around os specific objects in platform agnostic code
hnsFake := hnswrapper.NewHnsv2wrapperFake()
Hnsv2 = hnswrapper.Hnsv2wrapperwithtimeout{
Hnsv2: hnsFake,
HnsCallTimeout: 5 * time.Second,
}
// create network for InfraNIC
infraNetworkID := "azure"
infraNetwork := &hcn.HostComputeNetwork{
Name: infraNetworkID,
}
_, err := Hnsv2.CreateNetwork(infraNetwork)
if err != nil {
t.Fatalf("Failed to create network for infraNIC due to %v", err)
}
// create network for DelegatedNIC
delegatedNetwork := &hcn.HostComputeNetwork{
Id: networkID,
Name: networkName,
Type: l1vhNetworkType,
}
_, err = Hnsv2.CreateNetwork(delegatedNetwork)
if err != nil {
t.Fatalf("Failed to create network for delegatedNIC due to %v", err)
}
// make sure two networks are created:
networks := hnsFake.Cache.GetNetworks()
if len(networks) != 2 {
t.Fatal("Failed to create two networks for infraNIC and delegatedNIC")
}
// create endpoint for InfraNIC
infraEndpointID := "infraEndpoint"
infraEndpoint := &hcn.HostComputeEndpoint{
Id: infraEndpointID,
Name: infraEndpointID,
HostComputeNetwork: infraNetworkID,
}
_, err = Hnsv2.CreateEndpoint(infraEndpoint)
if err != nil {
t.Fatalf("Failed to create endpoint for infraNIC due to %v", err)
}
// create endpoint for delegated NIC
deletegatedEndpointID := "delegatedEndpoint"
delegatedEndpoint := &hcn.HostComputeEndpoint{
Id: deletegatedEndpointID,
Name: deletegatedEndpointID,
HostComputeNetwork: deletegatedEndpointID,
MacAddress: macAddress,
}
_, err = Hnsv2.CreateEndpoint(delegatedEndpoint)
if err != nil {
t.Fatalf("Failed to create endpoint for delegatedNIC due to %v", err)
}
// make sure two endpoints are created:
endpoints := hnsFake.Cache.GetEndpoints()
if len(endpoints) != 2 {
t.Fatal("Failed to create two endpoints for infraNIC and delegatedNIC")
}
infraEpInfo := &EndpointInfo{
EndpointID: infraEndpointID,
Data: make(map[string]interface{}),
IfName: "eth0",
NICType: cns.InfraNIC,
HNSEndpointID: infraEndpointID,
HNSNetworkID: infraNetworkID,
}
delegatedEpInfo := &EndpointInfo{
EndpointID: deletegatedEndpointID,
Data: make(map[string]interface{}),
IfName: "eth1",
NICType: cns.NodeNetworkInterfaceFrontendNIC,
MacAddress: net.HardwareAddr(macAddress),
HNSEndpointID: deletegatedEndpointID,
HNSNetworkID: networkID,
}
// mock DeleteEndpointState() to make sure endpoint and network is deleted from cache
// network and endpoint should be deleted from cache for delegatedNIC
err = nm.DeleteEndpointState(networkID, delegatedEpInfo)
if err != nil {
t.Fatalf("Failed to delete endpoint for delegatedNIC state due to %v", err)
}
// endpoint should be deleted from cache for delegatedNIC and network is still there
err = nm.DeleteEndpointState(infraNetworkID, infraEpInfo)
if err != nil {
t.Fatalf("Failed to delete endpoint for delegatedNIC state due to %v", err)
}
// check cache if endpoints are deleted
endpoints = hnsFake.Cache.GetEndpoints()
if len(endpoints) != 0 {
t.Fatalf("Not all endpoints are deleted, the remaining endpoints are %v", endpoints)
}
// check cache if delegated network is deleted and infra network is still there
networks = hnsFake.Cache.GetNetworks()
if len(networks) != 1 {
t.Fatalf("Failed to delete networks")
}
if _, ok := networks[infraNetworkID]; !ok {
t.Fatal("Network for InfraNIC does not exist")
}
}