feat: don't use CNS for CNI DEL command in windows multitenancy (#1216)

* feat: don't use CNS for CNI DEL command in windows multitenancy

* go fmt

* go fmt take 2

* fix: don't fallback to CNS for getNetwork or deleteHostNCApipaEndpoint, handle errNetworkNotFound

* test: add test for FindNetworkIDFromNetNs

* fix: getNetworkName needs to fallback to CNS when not found in state file for ADD

* fix: simplify the deleteHostNCApipaEndpoint function

* fix: linter

* fix: cnm should compile

* fix: always return retriable error for endpoint deletion failure

* fix: handle npe in cns/hnsclient by not using that package

* fix: logging

* fix: don't try cns if there is no multitenancy client

* fix: don't call CNS twice during ADD cmd

* fix: use hns wrapper, add some logging, don't return error when endpoint is already deleted
This commit is contained in:
Matthew Long 2022-02-03 19:14:31 -08:00 коммит произвёл GitHub
Родитель 494308df4e
Коммит 580c3e4072
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
25 изменённых файлов: 241 добавлений и 100 удалений

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

@ -1,3 +1,4 @@
//go:build unit || integration
// +build unit integration
package client

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

@ -1,5 +1,5 @@
// +build linux
// +build integration
//go:build linux && integration
// +build linux,integration
package client

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

@ -1,3 +1,4 @@
//go:build unit
// +build unit
package client

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

@ -453,7 +453,7 @@ func (plugin *NetPlugin) Add(args *cniSkel.CmdArgs) error {
}
// Initialize values from network config.
networkID, err := plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, nwCfg)
networkID, err := plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, args.Netns, cnsNetworkConfig, nwCfg)
if err != nil {
log.Printf("[cni-net] Failed to extract network name from network config. error: %v", err)
return err
@ -843,7 +843,7 @@ func (plugin *NetPlugin) Get(args *cniSkel.CmdArgs) error {
}
// Initialize values from network config.
if networkId, err = plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, nwCfg); err != nil {
if networkId, err = plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, args.Netns, nil, nwCfg); err != nil {
// TODO: Ideally we should return from here only.
log.Printf("[cni-net] Failed to extract network name from network config. error: %v", err)
}
@ -962,14 +962,13 @@ func (plugin *NetPlugin) Delete(args *cniSkel.CmdArgs) error {
plugin.ipamInvoker = NewAzureIpamInvoker(plugin, &nwInfo)
}
}
// Initialize values from network config.
networkID, err = plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, nwCfg)
// If error is not found error, then we ignore it, to comply with CNI SPEC.
// Initialize values from network config.
networkID, err = plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, args.Netns, nil, nwCfg)
if err != nil {
log.Printf("[cni-net] Failed to extract network name from network config. error: %v", err)
if !cnscli.IsNotFound(err) {
// If error is not found error, then we ignore it, to comply with CNI SPEC.
if !network.IsNetworkNotFoundError(err) {
err = plugin.Errorf("Failed to extract network name from network config. error: %v", err)
return err
}
@ -1013,19 +1012,15 @@ func (plugin *NetPlugin) Delete(args *cniSkel.CmdArgs) error {
return err
}
cnsclient, err := cnscli.New(nwCfg.CNSUrl, defaultRequestTimeout)
if err != nil {
log.Printf("failed to initialized cns client with URL %s: %v", nwCfg.CNSUrl, err.Error())
return plugin.Errorf(err.Error())
}
// schedule send metric before attempting delete
defer sendMetricFunc()
telemetry.LogAndSendEvent(plugin.tb, fmt.Sprintf("Deleting endpoint:%v", endpointID))
// Delete the endpoint.
if err = plugin.nm.DeleteEndpoint(cnsclient, networkID, endpointID); err != nil {
err = plugin.Errorf("Failed to delete endpoint: %v", err)
return err
if err = plugin.nm.DeleteEndpoint(networkID, endpointID); err != nil {
// return a retriable error so the container runtime will retry this DEL later
// the implementation of this function returns nil if the endpoint doens't exist, so
// we don't have to check that here
return plugin.RetriableError(fmt.Errorf("failed to delete endpoint: %w", err))
}
if !nwCfg.MultiTenancy {

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

@ -135,7 +135,7 @@ func updateSubnetPrefix(cnsNetworkConfig *cns.GetNetworkContainerResponse, subne
return nil
}
func (plugin *NetPlugin) getNetworkName(podName, podNs, ifName string, nwCfg *cni.NetworkConfig) (string, error) {
func (plugin *NetPlugin) getNetworkName(_, _, _, _ string, _ *cns.GetNetworkContainerResponse, nwCfg *cni.NetworkConfig) (string, error) {
return nwCfg.Name, nil
}

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

@ -1,4 +1,5 @@
//+build linux
//go:build linux
// +build linux
package network

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

@ -1060,7 +1060,7 @@ func TestGetNetworkName(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
nwName, _ := plugin.getNetworkName("", "", "", &tt.nwCfg)
nwName, _ := plugin.getNetworkName("", "", "", "", nil, &tt.nwCfg)
require.Equal(t, tt.nwCfg.Name, nwName)
})
}

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

@ -1,7 +1,6 @@
package network
import (
"context"
"encoding/json"
"fmt"
"net"
@ -160,42 +159,45 @@ func updateSubnetPrefix(cnsNwConfig *cns.GetNetworkContainerResponse, subnetPref
return nil
}
func (plugin *NetPlugin) getNetworkName(podName, podNs, ifName string, nwCfg *cni.NetworkConfig) (string, error) {
var (
networkName string
err error
cnsNetworkConfig *cns.GetNetworkContainerResponse
)
networkName = nwCfg.Name
err = nil
if nwCfg.MultiTenancy {
determineWinVer()
if len(strings.TrimSpace(podName)) == 0 || len(strings.TrimSpace(podNs)) == 0 {
err = fmt.Errorf("POD info cannot be empty. PodName: %s, PodNamespace: %s", podName, podNs)
return networkName, err
}
_, cnsNetworkConfig, _, err = plugin.multitenancyClient.GetContainerNetworkConfiguration(context.TODO(), nwCfg, podName, podNs, ifName)
if err != nil {
log.Printf(
"GetContainerNetworkConfiguration failed for podname %v namespace %v with error %v",
podName,
podNs,
err)
} else {
var subnet net.IPNet
if err = updateSubnetPrefix(cnsNetworkConfig, &subnet); err == nil {
// networkName will look like ~ azure-vlan1-172-28-1-0_24
networkName = strings.Replace(subnet.String(), ".", "-", -1)
networkName = strings.Replace(networkName, "/", "_", -1)
networkName = fmt.Sprintf("%s-vlan%v-%v", nwCfg.Name, cnsNetworkConfig.MultiTenancyInfo.ID, networkName)
}
}
func (plugin *NetPlugin) getNetworkName(podName, podNs, ifName, netNs string, cnsResponse *cns.GetNetworkContainerResponse, nwCfg *cni.NetworkConfig) (string, error) {
// For singletenancy, the network name is simply the nwCfg.Name
if !nwCfg.MultiTenancy {
return nwCfg.Name, nil
}
return networkName, err
// in multitenancy case, the network name will be in the state file or can be built from cnsResponse
determineWinVer()
if len(strings.TrimSpace(netNs)) == 0 || len(strings.TrimSpace(podName)) == 0 || len(strings.TrimSpace(podNs)) == 0 {
return "", fmt.Errorf("POD info cannot be empty. PodName: %s, PodNamespace: %s, NetNs: %s", podName, podNs, netNs)
}
// First try to build the network name from the cnsResponse if present
// This will happen during ADD call
if cnsResponse != nil {
var subnet net.IPNet
if err := updateSubnetPrefix(cnsResponse, &subnet); err != nil {
log.Printf("Error updating subnet prefix: %v", err)
return "", err
}
// networkName will look like ~ azure-vlan1-172-28-1-0_24
networkSuffix := strings.Replace(subnet.String(), ".", "-", -1)
networkSuffix = strings.Replace(networkSuffix, "/", "_", -1)
networkName := fmt.Sprintf("%s-vlan%v-%v", nwCfg.Name, cnsResponse.MultiTenancyInfo.ID, networkSuffix)
return networkName, nil
}
// If no cnsResponse was present, try to get the network name from the state file
// This will happen during DEL call
networkName, err := plugin.nm.FindNetworkIDFromNetNs(netNs)
if err != nil {
log.Printf("Error getting network name from state: %v.", err)
return "", fmt.Errorf("error getting network name from state: %w", err)
}
return networkName, nil
}
func setupInfraVnetRoutingForMultitenancy(

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

@ -183,7 +183,7 @@ func TestSetEndpointOptions(t *testing.T) {
ID: 1,
},
CnetAddressSpace: []cns.IPSubnet{
cns.IPSubnet{
{
IPAddress: "192.168.0.4",
PrefixLength: 24,
},
@ -221,7 +221,7 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
nwCfg: cni.NetworkConfig{
RuntimeConfig: cni.RuntimeConfig{
PortMappings: []cni.PortMapping{
cni.PortMapping{
{
Protocol: "tcp",
HostIp: "19.268.0.4",
HostPort: 8000,

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

@ -150,6 +150,13 @@ func (plugin *Plugin) Errorf(format string, args ...interface{}) *cniTypes.Error
return plugin.Error(fmt.Errorf(format, args...))
}
// RetriableError logs and returns a CNI error with the TryAgainLater error code
func (plugin *Plugin) RetriableError(err error) *cniTypes.Error {
tryAgainErr := cniTypes.NewError(cniTypes.ErrTryAgainLater, err.Error(), "")
log.Printf("[%v] %+v.", plugin.Name, tryAgainErr.Error())
return tryAgainErr
}
// Initialize key-value store
func (plugin *Plugin) InitializeKeyValueStore(config *common.PluginConfig) error {
// Create the key value store.

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

@ -271,12 +271,8 @@ func (plugin *netPlugin) deleteEndpoint(w http.ResponseWriter, r *http.Request)
return
}
cnscli, err := cnsclient.New("", defaultCNSTimeout)
if err != nil {
log.Errorf("failed to init CNS client", err)
}
// Process request.
err = plugin.nm.DeleteEndpoint(cnscli, req.NetworkID, req.EndpointID)
err = plugin.nm.DeleteEndpoint(req.NetworkID, req.EndpointID)
if err != nil {
plugin.SendErrorResponse(w, err)
return

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

@ -4,6 +4,7 @@
package network
import (
"errors"
"fmt"
)
@ -12,7 +13,7 @@ var (
errSubnetNotFound = fmt.Errorf("Subnet not found")
errNetworkModeInvalid = fmt.Errorf("Network mode is invalid")
errNetworkExists = fmt.Errorf("Network already exists")
errNetworkNotFound = fmt.Errorf("Network not found")
errNetworkNotFound = &networkNotFoundError{}
errEndpointExists = fmt.Errorf("Endpoint already exists")
errEndpointNotFound = fmt.Errorf("Endpoint not found")
errNamespaceNotFound = fmt.Errorf("Namespace not found")
@ -20,3 +21,13 @@ var (
errEndpointInUse = fmt.Errorf("Endpoint is already joined to a sandbox")
errEndpointNotInUse = fmt.Errorf("Endpoint is not joined to a sandbox")
)
type networkNotFoundError struct{}
func (n *networkNotFoundError) Error() string {
return "Network not found"
}
func IsNetworkNotFoundError(err error) bool {
return errors.Is(err, errNetworkNotFound)
}

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

@ -124,7 +124,7 @@ func (nw *network) newEndpoint(cli apipaClient, nl netlink.NetlinkInterface, plc
}
// DeleteEndpoint deletes an existing endpoint from the network.
func (nw *network) deleteEndpoint(cli apipaClient, nl netlink.NetlinkInterface, plc platform.ExecClient, endpointID string) error {
func (nw *network) deleteEndpoint(nl netlink.NetlinkInterface, plc platform.ExecClient, endpointID string) error {
var err error
log.Printf("[net] Deleting endpoint %v from network %v.", endpointID, nw.Id)
@ -142,7 +142,7 @@ func (nw *network) deleteEndpoint(cli apipaClient, nl netlink.NetlinkInterface,
}
// Call the platform implementation.
err = nw.deleteEndpointImpl(cli, nl, plc, ep)
err = nw.deleteEndpointImpl(nl, plc, ep)
if err != nil {
return err
}

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

@ -231,7 +231,7 @@ func (nw *network) newEndpointImpl(_ apipaClient, nl netlink.NetlinkInterface, p
}
// deleteEndpointImpl deletes an existing endpoint from the network.
func (nw *network) deleteEndpointImpl(_ apipaClient, nl netlink.NetlinkInterface, plc platform.ExecClient, ep *endpoint) error {
func (nw *network) deleteEndpointImpl(nl netlink.NetlinkInterface, plc platform.ExecClient, ep *endpoint) error {
var epClient EndpointClient
// Delete the veth pair by deleting one of the peer interfaces.

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

@ -38,6 +38,10 @@ const (
// Container interface name prefix
containerIfNamePrefix = "vEthernet"
// hostNCApipaEndpointName indicates the prefix for the name of the apipa endpoint used for
// the host container connectivity
hostNCApipaEndpointNamePrefix = "HostNCApipaEndpoint"
)
type AzureHNSEndpointClient interface {
@ -280,11 +284,33 @@ func (nw *network) configureHcnEndpoint(epInfo *EndpointInfo) (*hcn.HostComputeE
return hcnEndpoint, nil
}
func (nw *network) deleteHostNCApipaEndpoint(cli apipaClient, networkContainerID string) error {
log.Printf("[net] Deleting HostNCApipaEndpoint for network container: %s", networkContainerID)
err := cli.DeleteHostNCApipaEndpoint(context.TODO(), networkContainerID)
log.Printf("[net] Completed HostNCApipaEndpoint deletion for network container: %s"+
" with error: %v", networkContainerID, err)
func (nw *network) deleteHostNCApipaEndpoint(networkContainerID string) error {
// TODO: this code is duplicated in cns/hnsclient, but that code has logging messages that require a CNSLogger,
// which makes is hard to use in this package. We should refactor this into a common package with no logging deps
// so it can be called in both places
// HostNCApipaEndpoint name is derived from NC ID
endpointName := fmt.Sprintf("%s-%s", hostNCApipaEndpointNamePrefix, networkContainerID)
log.Printf("[net] Deleting HostNCApipaEndpoint: %s for NC: %s", endpointName, networkContainerID)
// Check if the endpoint exists
endpoint, err := hnsv2.GetEndpointByName(endpointName)
if err != nil {
// If error is anything other than EndpointNotFoundError, return error.
// else log the error but don't return error because endpoint is already deleted.
if _, endpointNotFound := err.(hcn.EndpointNotFoundError); !endpointNotFound {
return fmt.Errorf("[net] deleteEndpointByNameHnsV2 failed due to error with GetEndpointByName: %w", err)
}
log.Printf("[net] Delete called on the Endpoint: %s which doesn't exist. Error: %v", endpointName, err)
return nil
}
if err := hnsv2.DeleteEndpoint(endpoint); err != nil {
return fmt.Errorf("failed to delete HostNCApipa endpoint: %+v: %w", endpoint, err)
}
log.Printf("[net] Successfully deleted HostNCApipa endpoint: %+v", endpoint)
return nil
}
@ -313,7 +339,7 @@ func (nw *network) createHostNCApipaEndpoint(cli apipaClient, epInfo *EndpointIn
defer func() {
if err != nil {
nw.deleteHostNCApipaEndpoint(cli, epInfo.NetworkContainerID)
nw.deleteHostNCApipaEndpoint(epInfo.NetworkContainerID)
}
}()
@ -415,13 +441,13 @@ func (nw *network) newEndpointImplHnsV2(cli apipaClient, epInfo *EndpointInfo) (
}
// deleteEndpointImpl deletes an existing endpoint from the network.
func (nw *network) deleteEndpointImpl(cli apipaClient, _ netlink.NetlinkInterface, _ platform.ExecClient, ep *endpoint) error {
func (nw *network) deleteEndpointImpl(_ netlink.NetlinkInterface, _ platform.ExecClient, ep *endpoint) error {
if useHnsV2, err := UseHnsV2(ep.NetNs); useHnsV2 {
if err != nil {
return err
}
return nw.deleteEndpointImplHnsV2(cli, ep)
return nw.deleteEndpointImplHnsV2(ep)
}
return nw.deleteEndpointImplHnsV1(ep)
@ -447,14 +473,14 @@ func (nw *network) deleteEndpointImplHnsV1(ep *endpoint) error {
}
// deleteEndpointImplHnsV2 deletes an existing endpoint from the network using HNS v2.
func (nw *network) deleteEndpointImplHnsV2(cli apipaClient, ep *endpoint) error {
func (nw *network) deleteEndpointImplHnsV2(ep *endpoint) error {
var (
hcnEndpoint *hcn.HostComputeEndpoint
err error
)
if ep.AllowInboundFromHostToNC || ep.AllowInboundFromNCToHost {
if err = nw.deleteHostNCApipaEndpoint(cli, ep.NetworkContainerID); err != nil {
if err = nw.deleteHostNCApipaEndpoint(ep.NetworkContainerID); err != nil {
log.Errorf("[net] Failed to delete HostNCApipaEndpoint due to error: %v", err)
return err
}
@ -462,8 +488,16 @@ func (nw *network) deleteEndpointImplHnsV2(cli apipaClient, ep *endpoint) error
log.Printf("[net] Deleting hcn endpoint with id: %s", ep.HnsId)
if hcnEndpoint, err = hnsv2.GetEndpointByID(ep.HnsId); err != nil {
return fmt.Errorf("Failed to get hcn endpoint with id: %s due to err: %v", ep.HnsId, err)
hcnEndpoint, err = hnsv2.GetEndpointByID(ep.HnsId)
if err != nil {
// If error is anything other than EndpointNotFoundError, return error.
// else log the error but don't return error because endpoint is already deleted.
if _, endpointNotFound := err.(hcn.EndpointNotFoundError); !endpointNotFound {
return fmt.Errorf("Failed to get hcn endpoint with id: %s due to err: %w", ep.HnsId, err)
}
log.Printf("[net] Delete called on the Endpoint: %s which doesn't exist. Error: %v", ep.HnsId, err)
return nil
}
// Remove this endpoint from the namespace

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

@ -1,18 +1,20 @@
// Copyright 2017 Microsoft. All rights reserved.
// MIT License
//go:build windows
// +build windows
package network
import (
"fmt"
"github.com/Azure/azure-container-networking/network/hnswrapper"
"net"
"testing"
"github.com/Azure/azure-container-networking/network/hnswrapper"
)
func TestNewAndDeleteEndpointImplHnsV2(t *testing.T){
func TestNewAndDeleteEndpointImplHnsV2(t *testing.T) {
nw := &network{
Endpoints: map[string]*endpoint{},
}
@ -22,29 +24,29 @@ func TestNewAndDeleteEndpointImplHnsV2(t *testing.T){
hnsv2 = hnswrapper.Hnsv2wrapperFake{}
epInfo := &EndpointInfo{
Id: "753d3fb6-e9b3-49e2-a109-2acc5dda61f1",
ContainerID: "545055c2-1462-42c8-b222-e75d0b291632",
NetNsPath: "fakeNameSpace",
IfName: "eth0",
Data: make(map[string]interface{}),
DNS: DNSInfo{
Suffix: "10.0.0.0",
Id: "753d3fb6-e9b3-49e2-a109-2acc5dda61f1",
ContainerID: "545055c2-1462-42c8-b222-e75d0b291632",
NetNsPath: "fakeNameSpace",
IfName: "eth0",
Data: make(map[string]interface{}),
DNS: 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)
endpoint, err := nw.newEndpointImplHnsV2(nil, epInfo)
if err != nil {
fmt.Printf("+%v", err)
t.Fatal(err)
}
err = nw.deleteEndpointImplHnsV2(nil, endpoint)
err = nw.deleteEndpointImplHnsV2(endpoint)
if err != nil {
fmt.Printf("+%v", err)
t.Fatal(err)
}
}
}

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

@ -72,3 +72,7 @@ func (f Hnsv2wrapper) ListEndpointsOfNetwork(networkId string) ([]hcn.HostComput
func (f Hnsv2wrapper) ApplyEndpointPolicy(endpoint *hcn.HostComputeEndpoint, requestType hcn.RequestType, endpointPolicy hcn.PolicyEndpointRequest) error {
return endpoint.ApplyPolicy(requestType, endpointPolicy)
}
func (f Hnsv2wrapper) GetEndpointByName(endpointName string) (*hcn.HostComputeEndpoint, error) {
return hcn.GetEndpointByName(endpointName)
}

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

@ -285,6 +285,10 @@ func (f Hnsv2wrapperFake) ApplyEndpointPolicy(endpoint *hcn.HostComputeEndpoint,
return nil
}
func (Hnsv2wrapperFake) GetEndpointByName(endpointName string) (*hcn.HostComputeEndpoint, error) {
return nil, hcn.EndpointNotFoundError{EndpointName: endpointName}
}
type FakeHNSCache struct {
networks map[string]*FakeHostComputeNetwork
endpoints map[string]*FakeHostComputeEndpoint

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

@ -24,4 +24,5 @@ type HnsV2WrapperInterface interface {
GetEndpointByID(endpointId string) (*hcn.HostComputeEndpoint, error)
ListEndpointsOfNetwork(networkId string) ([]hcn.HostComputeEndpoint, error)
ApplyEndpointPolicy(endpoint *hcn.HostComputeEndpoint, requestType hcn.RequestType, endpointPolicy hcn.PolicyEndpointRequest) error
GetEndpointByName(endpointName string) (*hcn.HostComputeEndpoint, error)
}

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

@ -74,9 +74,11 @@ type NetworkManager interface {
CreateNetwork(nwInfo *NetworkInfo) error
DeleteNetwork(networkID string) error
GetNetworkInfo(networkID string) (NetworkInfo, error)
// FindNetworkIDFromNetNs returns the network name that contains an endpoint created for this netNS, errNetworkNotFound if no network is found
FindNetworkIDFromNetNs(netNs string) (string, error)
CreateEndpoint(client apipaClient, networkID string, epInfo *EndpointInfo) error
DeleteEndpoint(cli apipaClient, networkID string, endpointID string) error
DeleteEndpoint(networkID string, endpointID string) error
GetEndpointInfo(networkID string, endpointID string) (*EndpointInfo, error)
GetAllEndpoints(networkID string) (map[string]*EndpointInfo, error)
GetEndpointInfoBasedOnPODDetails(networkID string, podName string, podNameSpace string, doExactMatchForPodName bool) (*EndpointInfo, error)
@ -352,7 +354,7 @@ func (nm *networkManager) CreateEndpoint(cli apipaClient, networkID string, epIn
}
// DeleteEndpoint deletes an existing container endpoint.
func (nm *networkManager) DeleteEndpoint(cli apipaClient, networkID string, endpointID string) error {
func (nm *networkManager) DeleteEndpoint(networkID, endpointID string) error {
nm.Lock()
defer nm.Unlock()
@ -361,7 +363,7 @@ func (nm *networkManager) DeleteEndpoint(cli apipaClient, networkID string, endp
return err
}
err = nw.deleteEndpoint(cli, nm.netlink, nm.plClient, endpointID)
err = nw.deleteEndpoint(nm.netlink, nm.plClient, endpointID)
if err != nil {
return err
}

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

@ -58,7 +58,7 @@ func (nm *MockNetworkManager) CreateEndpoint(_ apipaClient, networkID string, ep
}
// DeleteEndpoint mock
func (nm *MockNetworkManager) DeleteEndpoint(_ apipaClient, networkID string, endpointID string) error {
func (nm *MockNetworkManager) DeleteEndpoint(networkID, endpointID string) error {
delete(nm.TestEndpointInfoMap, endpointID)
return nil
}
@ -104,3 +104,13 @@ func (nm *MockNetworkManager) GetNumberOfEndpoints(ifName string, networkID stri
func (nm *MockNetworkManager) SetupNetworkUsingState(networkMonitor *cnms.NetworkMonitor) error {
return nil
}
func (nm *MockNetworkManager) FindNetworkIDFromNetNs(netNs string) (string, error) {
// based on the GetAllEndpoints func above, it seems that this mock is only intended to be used with
// one network, so just return the network here if it exists
for network := range nm.TestNetworkInfoMap {
return network, nil
}
return "", errNetworkNotFound
}

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

@ -244,3 +244,26 @@ func (nm *networkManager) getNetwork(networkId string) (*network, error) {
return nil, errNetworkNotFound
}
// getNetworkIDForNetNs finds the network that contains the endpoint that was created for this netNs. Returns
// and errNetworkNotFound if the netNs is not found in any network
func (nm *networkManager) FindNetworkIDFromNetNs(netNs string) (string, error) {
log.Printf("Querying state for network for NetNs [%s]", netNs)
// Look through the external interfaces
for _, iface := range nm.ExternalInterfaces {
// Look through the networks
for _, network := range iface.Networks {
// Network may have multiple endpoints, so look through all of them
for _, endpoint := range network.Endpoints {
// If the netNs matches for this endpoint, return the network ID (which is the name)
if endpoint.NetNs == netNs {
log.Printf("Found network [%s] for NetNS [%s]", network.Id, netNs)
return network.Id, nil
}
}
}
}
return "", errNetworkNotFound
}

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

@ -213,4 +213,48 @@ var _ = Describe("Test Network", func() {
})
})
})
Describe("Test FindNetworkIDFromNetNs", func() {
Context("When network exists", func() {
It("Should be returned", func() {
netNs := "989c079b-45a6-485f-8f9e-88b05d6c55c4"
networkID := "byovnetbridge-vlan1-10-128-8-0_23"
nm := &networkManager{
ExternalInterfaces: map[string]*externalInterface{
networkID: {
Name: networkID,
Networks: map[string]*network{
"byovnetbridge-vlan1-10-128-8-0_23": {
Id: "byovnetbridge-vlan1-10-128-8-0_23",
Endpoints: map[string]*endpoint{
"a591be2a-eth0": {
Id: "a591be2a-eth0",
NetNs: netNs,
},
},
NetNs: "aaac079b-45a6-485f-8f9e-88b05d6c55c4",
},
},
},
},
}
got, err := nm.FindNetworkIDFromNetNs(netNs)
Expect(err).NotTo(HaveOccurred())
Expect(got).To(Equal(networkID))
})
})
Context("When network does not exist", func() {
It("Should return an errNetworkNotFound", func() {
nm := &networkManager{
ExternalInterfaces: make(map[string]*externalInterface),
}
_, err := nm.FindNetworkIDFromNetNs("989c079b-45a6-485f-8f9e-88b05d6c55c4")
Expect(err).To(HaveOccurred())
Expect(IsNetworkNotFoundError(err)).To(BeTrue())
})
})
})
})

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

@ -1,17 +1,19 @@
// Copyright 2017 Microsoft. All rights reserved.
// MIT License
//go:build windows
// +build windows
package network
import (
"fmt"
"github.com/Azure/azure-container-networking/network/hnswrapper"
"testing"
"github.com/Azure/azure-container-networking/network/hnswrapper"
)
func TestNewAndDeleteNetworkImplHnsV2(t *testing.T){
func TestNewAndDeleteNetworkImplHnsV2(t *testing.T) {
nm := &networkManager{
ExternalInterfaces: map[string]*externalInterface{},
}
@ -23,7 +25,7 @@ func TestNewAndDeleteNetworkImplHnsV2(t *testing.T){
nwInfo := &NetworkInfo{
Id: "d3e97a83-ba4c-45d5-ba88-dc56757ece28",
MasterIfName: "eth0",
Mode: "bridge",
Mode: "bridge",
}
extInterface := &externalInterface{
@ -31,7 +33,7 @@ func TestNewAndDeleteNetworkImplHnsV2(t *testing.T){
Subnets: []string{"subnet1", "subnet2"},
}
network,err := nm.newNetworkImplHnsV2(nwInfo,extInterface)
network, err := nm.newNetworkImplHnsV2(nwInfo, extInterface)
if err != nil {
fmt.Printf("+%v", err)

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

@ -1,4 +1,5 @@
//+build linux
//go:build linux
// +build linux
package network