Alegal/add timeout to hns calls (#1369)

* initial implemenation with timeout

* initial implemenation with timeout hns

* modify test

* modify code slightly

* updating to read in timeout flag and settings

* updating to read in timeout settings

* remove extra space

* correct a typo

* timeout value greater than zero for detection

* add couple ut's and remove needless code

* including timeout in hnsv1

* wip

* address comments

* address comments

* supress linter errors and update conflist

* fix linter and ensure we don't regress our tests

* updating with p.r feedback

* addressing comments

* updating linter warning

* update to address TM's comments

* fix lint error

* correct a linter spacing complaint

* remove fmt.sprintf
This commit is contained in:
aegal 2022-05-25 14:18:46 -07:00 коммит произвёл GitHub
Родитель b1ae762c89
Коммит 251edbfd04
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
22 изменённых файлов: 1227 добавлений и 118 удалений

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

@ -43,7 +43,10 @@
"NeedEncap": true
}
}
]
],
"windowsSettings": {
"hnsTimeoutDurationInSeconds" : 120
}
}
]
}

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

@ -43,7 +43,10 @@
"NeedEncap": true
}
}
]
],
"windowsSettings": {
"hnsTimeoutDurationInSeconds" : 120
}
}
]
}

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

@ -80,7 +80,8 @@ type NetworkConfig struct {
}
type WindowsSettings struct {
EnableLoopbackDSR bool `json:"enableLoopbackDSR,omitempty"`
EnableLoopbackDSR bool `json:"enableLoopbackDSR,omitempty"`
HnsTimeoutDurationInSeconds int `json:"hnsTimeoutDurationInSeconds,omitempty"`
}
type K8SPodEnvArgs struct {

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

@ -72,7 +72,6 @@ type NetPlugin struct {
report *telemetry.CNIReport
tb *telemetry.TelemetryBuffer
nnsClient NnsClient
hnsEndpointClient network.AzureHNSEndpointClient
multitenancyClient MultitenancyClient
}
@ -106,7 +105,6 @@ func NewPlugin(name string,
config *common.PluginConfig,
client NnsClient,
multitenancyClient MultitenancyClient,
azHnsClient network.AzureHNSEndpointClient,
) (*NetPlugin, error) {
// Setup base plugin.
plugin, err := cni.NewPlugin(name, config.Version)
@ -128,7 +126,6 @@ func NewPlugin(name string,
nm: nm,
nnsClient: client,
multitenancyClient: multitenancyClient,
hnsEndpointClient: azHnsClient,
}, nil
}
@ -399,6 +396,7 @@ func (plugin *NetPlugin) Add(args *cniSkel.CmdArgs) error {
return plugin.Errorf(errMsg)
}
platformInit(nwCfg)
if nwCfg.ExecutionMode == string(util.Baremetal) {
var res *nnscontracts.ConfigureContainerNetworkingResponse
log.Printf("Baremetal mode. Calling vnet agent for ADD")
@ -898,6 +896,8 @@ func (plugin *NetPlugin) Delete(args *cniSkel.CmdArgs) error {
telemetry.SendCNIMetric(&cniMetric, plugin.tb)
}
platformInit(nwCfg)
log.Printf("Execution mode :%s", nwCfg.ExecutionMode)
if nwCfg.ExecutionMode == string(util.Baremetal) {

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

@ -138,3 +138,5 @@ func (plugin *NetPlugin) getNetworkName(_ string, _ *IPAMAddResult, nwCfg *cni.N
func getNATInfo(_ string, _ interface{}, _, _ bool) (natInfo []policy.NATInfo) {
return natInfo
}
func platformInit(cniConfig *cni.NetworkConfig) {}

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

@ -69,7 +69,7 @@ func GetTestResources() *NetPlugin {
pluginName := "testplugin"
config := &common.PluginConfig{}
grpcClient := &nns.MockGrpcClient{}
plugin, _ := NewPlugin(pluginName, config, grpcClient, &Multitenancy{}, nil)
plugin, _ := NewPlugin(pluginName, config, grpcClient, &Multitenancy{})
plugin.report = &telemetry.CNIReport{}
mockNetworkManager := acnnetwork.NewMockNetworkmanager()
plugin.nm = mockNetworkManager
@ -957,7 +957,7 @@ func TestNewPlugin(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
plugin, err := NewPlugin("test", &tt.config, nil, nil, nil)
plugin, err := NewPlugin("test", &tt.config, nil, nil)
if tt.wantErr {
require.NoError(t, err)
require.NotNil(t, plugin)

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

@ -49,15 +49,15 @@ func (plugin *NetPlugin) handleConsecutiveAdd(args *cniSkel.CmdArgs, endpointId
return nil, err
}
hnsEndpoint, err := plugin.hnsEndpointClient.GetHNSEndpointByName(endpointId)
hnsEndpoint, err := network.Hnsv1.GetHNSEndpointByName(endpointId)
if hnsEndpoint != nil {
log.Printf("[net] Found existing endpoint through hcsshim: %+v", hnsEndpoint)
endpoint, _ := plugin.hnsEndpointClient.GetHNSEndpointByID(hnsEndpoint.Id)
isAttached, _ := plugin.hnsEndpointClient.IsAttached(endpoint, args.ContainerID)
endpoint, _ := network.Hnsv1.GetHNSEndpointByID(hnsEndpoint.Id)
isAttached, _ := network.Hnsv1.IsAttached(endpoint, args.ContainerID)
// Attach endpoint if it's not attached yet.
if !isAttached {
log.Printf("[net] Attaching ep %v to container %v", hnsEndpoint.Id, args.ContainerID)
err := plugin.hnsEndpointClient.HotAttachEndpoint(args.ContainerID, hnsEndpoint.Id)
err := network.Hnsv1.HotAttachEndpoint(args.ContainerID, hnsEndpoint.Id)
if err != nil {
log.Printf("[cni-net] Failed to hot attach shared endpoint[%v] to container [%v], err:%v.", hnsEndpoint.Id, args.ContainerID, err)
return nil, err
@ -388,3 +388,11 @@ func getNATInfo(executionMode string, ncPrimaryIPIface interface{}, multitenancy
return natInfo
}
func platformInit(cniConfig *cni.NetworkConfig) {
if cniConfig.WindowsSettings.HnsTimeoutDurationInSeconds > 0 {
log.Printf("Enabling timeout for Hns calls with a timeout value of : %v", cniConfig.WindowsSettings.HnsTimeoutDurationInSeconds)
network.EnableHnsV1Timeout(cniConfig.WindowsSettings.HnsTimeoutDurationInSeconds)
network.EnableHnsV2Timeout(cniConfig.WindowsSettings.HnsTimeoutDurationInSeconds)
}
}

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

@ -5,6 +5,7 @@ package network
import (
"fmt"
"github.com/Azure/azure-container-networking/network/hnswrapper"
"net"
"testing"
@ -19,6 +20,10 @@ import (
"github.com/stretchr/testify/require"
)
func init() {
network.Hnsv2 = hnswrapper.NewHnsv2wrapperFake()
network.Hnsv1 = hnswrapper.NewHnsv1wrapperFake()
}
// Test windows network policies is set
func TestAddWithRunTimeNetPolicies(t *testing.T) {
_, ipnetv4, _ := net.ParseCIDR("10.240.0.0/12")
@ -87,7 +92,6 @@ func TestPluginSecondAddSamePodWindows(t *testing.T) {
Plugin: plugin,
nm: network.NewMockNetworkmanager(),
ipamInvoker: NewMockIpamInvoker(false, false, false),
hnsEndpointClient: network.NewMockHNSEndpoint(true, false),
report: &telemetry.CNIReport{},
tb: &telemetry.TelemetryBuffer{},
},
@ -107,7 +111,6 @@ func TestPluginSecondAddSamePodWindows(t *testing.T) {
Plugin: plugin,
nm: network.NewMockNetworkmanager(),
ipamInvoker: NewMockIpamInvoker(false, false, false),
hnsEndpointClient: network.NewMockHNSEndpoint(false, false),
report: &telemetry.CNIReport{},
tb: &telemetry.TelemetryBuffer{},
},

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

@ -17,7 +17,6 @@ import (
"github.com/Azure/azure-container-networking/cni/network"
"github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/log"
acnnetwork "github.com/Azure/azure-container-networking/network"
"github.com/Azure/azure-container-networking/nns"
"github.com/Azure/azure-container-networking/platform"
"github.com/Azure/azure-container-networking/store"
@ -163,7 +162,6 @@ func rootExecute() error {
&config,
&nns.GrpcClient{},
&network.Multitenancy{},
&acnnetwork.AzureHNSEndpoint{},
)
if err != nil {
printCNIError(fmt.Sprintf("Failed to create network plugin, err:%v.\n", err))

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

@ -197,11 +197,11 @@ func (nw *network) getEndpointByPOD(podName string, podNameSpace string, doExact
func podNameMatches(source string, actualValue string, doExactMatch bool) bool {
if doExactMatch {
return (source == actualValue)
return source == actualValue
} else {
// If exact match flag is disabled we just check if the existing podname field for an endpoint
// starts with passed podname string.
return (actualValue == GetPodNameWithoutSuffix(source))
return actualValue == GetPodNameWithoutSuffix(source)
}
}

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

@ -5,24 +5,18 @@ package network
import (
"context"
"encoding/json"
"fmt"
"net"
"strings"
"github.com/Azure/azure-container-networking/log"
"github.com/Azure/azure-container-networking/netlink"
"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/Microsoft/hcsshim"
"github.com/Microsoft/hcsshim/hcn"
)
// this hnsv2 variable is package level variable in network
// we do this to avoid passing around os specific objects in platform agnostic code
var hnsv2 hnswrapper.HnsV2WrapperInterface = hnswrapper.Hnsv2wrapper{}
const (
// hcnSchemaVersionMajor indicates major version number for hcn schema
hcnSchemaVersionMajor = 2
@ -44,34 +38,6 @@ const (
hostNCApipaEndpointNamePrefix = "HostNCApipaEndpoint"
)
type AzureHNSEndpointClient interface {
GetHNSEndpointByName(endpointName string) (*hcsshim.HNSEndpoint, error)
GetHNSEndpointByID(endpointID string) (*hcsshim.HNSEndpoint, error)
HotAttachEndpoint(containerID string, endpointID string) error
IsAttached(hnsep *hcsshim.HNSEndpoint, containerID string) (bool, error)
}
func (az AzureHNSEndpoint) GetHNSEndpointByName(endpointName string) (*hcsshim.HNSEndpoint, error) {
return hcsshim.GetHNSEndpointByName(endpointName)
}
func (az AzureHNSEndpoint) GetHNSEndpointByID(id string) (*hcsshim.HNSEndpoint, error) {
return hcsshim.GetHNSEndpointByID(id)
}
func (az AzureHNSEndpoint) HotAttachEndpoint(containerID, endpointID string) error {
return hcsshim.HotAttachEndpoint(containerID, endpointID)
}
func (az AzureHNSEndpoint) IsAttached(hnsep *hcsshim.HNSEndpoint, containerID string) (bool, error) {
return hnsep.IsAttached(containerID)
}
// HotAttachEndpoint is a wrapper of hcsshim's HotAttachEndpoint.
func (endpoint *EndpointInfo) HotAttachEndpoint(containerID string) error {
return hcsshim.HotAttachEndpoint(containerID, endpoint.Id)
}
// ConstructEndpointID constructs endpoint name from netNsPath.
func ConstructEndpointID(containerID string, netNsPath string, ifName string) (string, string) {
if len(containerID) > 8 {
@ -98,6 +64,7 @@ func ConstructEndpointID(containerID string, netNsPath string, ifName string) (s
// newEndpointImpl creates a new endpoint in the network.
func (nw *network) newEndpointImpl(cli apipaClient, _ netlink.NetlinkInterface, _ platform.ExecClient, epInfo *EndpointInfo) (*endpoint, error) {
if useHnsV2, err := UseHnsV2(epInfo.NetNsPath); useHnsV2 {
if err != nil {
return nil, err
@ -147,17 +114,8 @@ func (nw *network) newEndpointImplHnsV1(epInfo *EndpointInfo) (*endpoint, error)
}
}
// Marshal the request.
buffer, err := json.Marshal(hnsEndpoint)
if err != nil {
return nil, err
}
hnsRequest := string(buffer)
hnsResponse, err := Hnsv1.CreateEndpoint(hnsEndpoint, "")
// Create the HNS endpoint.
log.Printf("[net] HNSEndpointRequest POST request:%+v", hnsRequest)
hnsResponse, err := hcsshim.HNSEndpointRequest("POST", "", hnsRequest)
log.Printf("[net] HNSEndpointRequest POST response:%+v err:%v.", hnsResponse, err)
if err != nil {
return nil, err
}
@ -165,7 +123,7 @@ func (nw *network) newEndpointImplHnsV1(epInfo *EndpointInfo) (*endpoint, error)
defer func() {
if err != nil {
log.Printf("[net] HNSEndpointRequest DELETE id:%v", hnsResponse.Id)
hnsResponse, err := hcsshim.HNSEndpointRequest("DELETE", hnsResponse.Id, "")
hnsResponse, err := Hnsv1.DeleteEndpoint(hnsResponse.Id)
log.Printf("[net] HNSEndpointRequest DELETE response:%+v err:%v.", hnsResponse, err)
}
}()
@ -176,7 +134,7 @@ func (nw *network) newEndpointImplHnsV1(epInfo *EndpointInfo) (*endpoint, error)
} else {
// Attach the endpoint.
log.Printf("[net] Attaching endpoint %v to container %v.", hnsResponse.Id, epInfo.ContainerID)
err = hcsshim.HotAttachEndpoint(epInfo.ContainerID, hnsResponse.Id)
err = Hnsv1.HotAttachEndpoint(epInfo.ContainerID, hnsResponse.Id)
if err != nil {
log.Printf("[net] Failed to attach endpoint: %v.", err)
return nil, err
@ -294,7 +252,7 @@ func (nw *network) deleteHostNCApipaEndpoint(networkContainerID string) error {
log.Printf("[net] Deleting HostNCApipaEndpoint: %s for NC: %s", endpointName, networkContainerID)
// Check if the endpoint exists
endpoint, err := hnsv2.GetEndpointByName(endpointName)
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.
@ -306,7 +264,7 @@ func (nw *network) deleteHostNCApipaEndpoint(networkContainerID string) error {
return nil
}
if err := hnsv2.DeleteEndpoint(endpoint); err != nil {
if err := Hnsv2.DeleteEndpoint(endpoint); err != nil {
return fmt.Errorf("failed to delete HostNCApipa endpoint: %+v: %w", endpoint, err)
}
@ -351,7 +309,7 @@ func (nw *network) createHostNCApipaEndpoint(cli apipaClient, epInfo *EndpointIn
return nil
}
// newEndpointImplHnsV2 creates a new endpoint in the network using HnsV2
// newEndpointImplHnsV2 creates a new endpoint in the network using Hnsv2
func (nw *network) newEndpointImplHnsV2(cli apipaClient, epInfo *EndpointInfo) (*endpoint, error) {
hcnEndpoint, err := nw.configureHcnEndpoint(epInfo)
if err != nil {
@ -361,7 +319,7 @@ func (nw *network) newEndpointImplHnsV2(cli apipaClient, epInfo *EndpointInfo) (
// Create the HCN endpoint.
log.Printf("[net] Creating hcn endpoint: %+v", hcnEndpoint)
hnsResponse, err := hnsv2.CreateEndpoint(hcnEndpoint)
hnsResponse, err := Hnsv2.CreateEndpoint(hcnEndpoint)
if err != nil {
return nil, fmt.Errorf("Failed to create endpoint: %s due to error: %v", hcnEndpoint.Name, err)
}
@ -371,24 +329,24 @@ func (nw *network) newEndpointImplHnsV2(cli apipaClient, epInfo *EndpointInfo) (
defer func() {
if err != nil {
log.Printf("[net] Deleting hcn endpoint with id: %s", hnsResponse.Id)
err = hnsv2.DeleteEndpoint(hnsResponse)
err = Hnsv2.DeleteEndpoint(hnsResponse)
log.Printf("[net] Completed hcn endpoint deletion for id: %s with error: %v", hnsResponse.Id, err)
}
}()
var namespace *hcn.HostComputeNamespace
if namespace, err = hnsv2.GetNamespaceByID(epInfo.NetNsPath); err != nil {
if namespace, err = Hnsv2.GetNamespaceByID(epInfo.NetNsPath); err != nil {
return nil, fmt.Errorf("Failed to get hcn namespace: %s due to error: %v", epInfo.NetNsPath, err)
}
if err = hnsv2.AddNamespaceEndpoint(namespace.Id, hnsResponse.Id); err != nil {
if err = Hnsv2.AddNamespaceEndpoint(namespace.Id, hnsResponse.Id); err != nil {
return nil, fmt.Errorf("[net] Failed to add endpoint: %s to hcn namespace: %s due to error: %v",
hnsResponse.Id, namespace.Id, err)
}
defer func() {
if err != nil {
if errRemoveNsEp := hnsv2.RemoveNamespaceEndpoint(namespace.Id, hnsResponse.Id); errRemoveNsEp != nil {
if errRemoveNsEp := Hnsv2.RemoveNamespaceEndpoint(namespace.Id, hnsResponse.Id); errRemoveNsEp != nil {
log.Printf("[net] Failed to remove endpoint: %s from namespace: %s due to error: %v",
hnsResponse.Id, hnsResponse.Id, errRemoveNsEp)
}
@ -456,7 +414,7 @@ func (nw *network) deleteEndpointImpl(_ netlink.NetlinkInterface, _ platform.Exe
// deleteEndpointImplHnsV1 deletes an existing endpoint from the network using HNS v1.
func (nw *network) deleteEndpointImplHnsV1(ep *endpoint) error {
log.Printf("[net] HNSEndpointRequest DELETE id:%v", ep.HnsId)
hnsResponse, err := hcsshim.HNSEndpointRequest("DELETE", ep.HnsId, "")
hnsResponse, err := Hnsv1.DeleteEndpoint(ep.HnsId)
log.Printf("[net] HNSEndpointRequest DELETE response:%+v err:%v.", hnsResponse, err)
// todo: may need to improve error handling if hns or hcsshim change their error bubbling.
@ -488,7 +446,7 @@ func (nw *network) deleteEndpointImplHnsV2(ep *endpoint) error {
log.Printf("[net] Deleting hcn endpoint with id: %s", ep.HnsId)
hcnEndpoint, err = hnsv2.GetEndpointByID(ep.HnsId)
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.
@ -501,12 +459,12 @@ func (nw *network) deleteEndpointImplHnsV2(ep *endpoint) error {
}
// Remove this endpoint from the namespace
if err = hnsv2.RemoveNamespaceEndpoint(hcnEndpoint.HostComputeNamespace, hcnEndpoint.Id); err != nil {
if err = Hnsv2.RemoveNamespaceEndpoint(hcnEndpoint.HostComputeNamespace, hcnEndpoint.Id); err != nil {
log.Errorf("Failed to remove hcn endpoint: %s from namespace: %s due to error: %v", ep.HnsId,
hcnEndpoint.HostComputeNamespace, err)
}
if err = hnsv2.DeleteEndpoint(hcnEndpoint); err != nil {
if err = Hnsv2.DeleteEndpoint(hcnEndpoint); err != nil {
return fmt.Errorf("Failed to delete hcn endpoint: %s due to error: %v", ep.HnsId, err)
}

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

@ -10,6 +10,7 @@ import (
"fmt"
"net"
"testing"
"time"
"github.com/Azure/azure-container-networking/network/hnswrapper"
)
@ -21,7 +22,9 @@ func TestNewAndDeleteEndpointImplHnsV2(t *testing.T) {
// 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.Hnsv2wrapperFake{}
Hnsv2 = hnswrapper.Hnsv2wrapperwithtimeout{
Hnsv2: hnswrapper.NewHnsv2wrapperFake(),
}
epInfo := &EndpointInfo{
Id: "753d3fb6-e9b3-49e2-a109-2acc5dda61f1",
@ -50,3 +53,162 @@ func TestNewAndDeleteEndpointImplHnsV2(t *testing.T) {
t.Fatal(err)
}
}
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{
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"),
}
_, 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{
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)
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{
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"),
}
_, err := nw.newEndpointImplHnsV1(epInfo)
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{
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.newEndpointImplHnsV1(epInfo)
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")
}
}

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

@ -0,0 +1,95 @@
//go:build windows
//+build windows
package hnswrapper
import (
"encoding/json"
"github.com/Azure/azure-container-networking/log"
"github.com/Microsoft/hcsshim"
)
type Hnsv1wrapper struct {
}
func (Hnsv1wrapper) CreateEndpoint(endpoint *hcsshim.HNSEndpoint, path string) (*hcsshim.HNSEndpoint, error) {
// Marshal the request.
buffer, err := json.Marshal(endpoint)
if err != nil {
return nil, err
}
hnsRequest := string(buffer)
// Create the HNS endpoint.
log.Printf("[net] HNSEndpointRequest POST request:%+v", hnsRequest)
hnsResponse, err := hcsshim.HNSEndpointRequest("POST", path, hnsRequest)
log.Printf("[net] HNSEndpointRequest POST response:%+v err:%v.", hnsResponse, err)
if err != nil {
return nil, err
}
return hnsResponse, err
}
func (Hnsv1wrapper) DeleteEndpoint(endpointId string) (*hcsshim.HNSEndpoint, error) {
hnsResponse, err := hcsshim.HNSEndpointRequest("DELETE", endpointId, "")
if err != nil {
return nil, err
}
return hnsResponse, err
}
func (Hnsv1wrapper) CreateNetwork(network *hcsshim.HNSNetwork, path string) (*hcsshim.HNSNetwork, error) {
// Marshal the request.
buffer, err := json.Marshal(network)
if err != nil {
return nil, err
}
hnsRequest := string(buffer)
// Create the HNS network.
log.Printf("[net] HNSNetworkRequest POST request:%+v", hnsRequest)
hnsResponse, err := hcsshim.HNSNetworkRequest("POST", path, hnsRequest)
log.Printf("[net] HNSNetworkRequest POST response:%+v err:%v.", hnsResponse, err)
if err != nil {
return nil, err
}
return hnsResponse, nil
}
func (Hnsv1wrapper) DeleteNetwork(networkId string) (*hcsshim.HNSNetwork, error) {
hnsResponse, err := hcsshim.HNSNetworkRequest("DELETE", networkId, "")
if err != nil {
return nil, err
}
return hnsResponse, err
}
func (Hnsv1wrapper) GetHNSEndpointByName(endpointName string) (*hcsshim.HNSEndpoint, error) {
return hcsshim.GetHNSEndpointByName(endpointName)
}
func (Hnsv1wrapper) GetHNSEndpointByID(id string) (*hcsshim.HNSEndpoint, error) {
return hcsshim.GetHNSEndpointByID(id)
}
func (Hnsv1wrapper) HotAttachEndpoint(containerID, endpointID string) error {
return hcsshim.HotAttachEndpoint(containerID, endpointID)
}
func (Hnsv1wrapper) IsAttached(endpoint *hcsshim.HNSEndpoint, containerID string) (bool, error) {
return endpoint.IsAttached(containerID)
}
func (w Hnsv1wrapper) GetHNSGlobals() (*hcsshim.HNSGlobals, error) {
return hcsshim.GetHNSGlobals()
}

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

@ -0,0 +1,63 @@
//go:build windows
// +build windows
package hnswrapper
import (
"time"
"github.com/Microsoft/hcsshim"
)
type Hnsv1wrapperfake struct {
Delay time.Duration
}
func NewHnsv1wrapperFake() *Hnsv1wrapperfake {
return &Hnsv1wrapperfake{}
}
func (h Hnsv1wrapperfake) CreateEndpoint(endpoint *hcsshim.HNSEndpoint, path string) (*hcsshim.HNSEndpoint, error) {
delayHnsCall(h.Delay)
return &hcsshim.HNSEndpoint{}, nil
}
func (h Hnsv1wrapperfake) DeleteEndpoint(endpointId string) (*hcsshim.HNSEndpoint, error) {
delayHnsCall(h.Delay)
return &hcsshim.HNSEndpoint{}, nil
}
func (h Hnsv1wrapperfake) CreateNetwork(network *hcsshim.HNSNetwork, path string) (*hcsshim.HNSNetwork, error) {
delayHnsCall(h.Delay)
return &hcsshim.HNSNetwork{}, nil
}
func (h Hnsv1wrapperfake) DeleteNetwork(networkId string) (*hcsshim.HNSNetwork, error) {
delayHnsCall(h.Delay)
return &hcsshim.HNSNetwork{}, nil
}
func (h Hnsv1wrapperfake) GetHNSEndpointByName(endpointName string) (*hcsshim.HNSEndpoint, error) {
delayHnsCall(h.Delay)
return &hcsshim.HNSEndpoint{}, nil
}
func (h Hnsv1wrapperfake) GetHNSEndpointByID(endpointID string) (*hcsshim.HNSEndpoint, error) {
delayHnsCall(h.Delay)
return &hcsshim.HNSEndpoint{}, nil
}
func (h Hnsv1wrapperfake) HotAttachEndpoint(containerID string, endpointID string) error {
delayHnsCall(h.Delay)
return nil
}
func (h Hnsv1wrapperfake) IsAttached(hnsep *hcsshim.HNSEndpoint, containerID string) (bool, error) {
delayHnsCall(h.Delay)
return true, nil
}
func (h Hnsv1wrapperfake) GetHNSGlobals() (*hcsshim.HNSGlobals, error) {
delayHnsCall(h.Delay)
return &hcsshim.HNSGlobals{}, nil
}

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

@ -0,0 +1,23 @@
// Copyright 2017 Microsoft. All rights reserved.
// MIT License
//go:build windows
// +build windows
package hnswrapper
import (
"github.com/Microsoft/hcsshim"
)
type HnsV1WrapperInterface interface {
CreateEndpoint(endpoint *hcsshim.HNSEndpoint, path string) (*hcsshim.HNSEndpoint, error)
DeleteEndpoint(endpointId string) (*hcsshim.HNSEndpoint, error)
CreateNetwork(network *hcsshim.HNSNetwork, path string) (*hcsshim.HNSNetwork, error)
DeleteNetwork(networkId string) (*hcsshim.HNSNetwork, error)
GetHNSEndpointByName(endpointName string) (*hcsshim.HNSEndpoint, error)
GetHNSEndpointByID(endpointID string) (*hcsshim.HNSEndpoint, error)
HotAttachEndpoint(containerID string, endpointID string) error
IsAttached(hnsep *hcsshim.HNSEndpoint, containerID string) (bool, error)
GetHNSGlobals() (*hcsshim.HNSGlobals, error)
}

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

@ -0,0 +1,230 @@
//go:build windows
// +build windows
package hnswrapper
import (
"context"
"github.com/Microsoft/hcsshim"
"github.com/pkg/errors"
"time"
)
type Hnsv1wrapperwithtimeout struct {
Hnsv1 HnsV1WrapperInterface
// hnsCallTimeout indicates the time to wait for hns calls before timing out
HnsCallTimeout time.Duration
}
type EndpointFuncResult struct {
endpoint *hcsshim.HNSEndpoint
Err error
}
type NetworkFuncResult struct {
network *hcsshim.HNSNetwork
Err error
}
type EndpointAttachedFuncResult struct {
isAttached bool
Err error
}
type HnsGlobalFuncResult struct {
HnsGlobals *hcsshim.HNSGlobals
Err error
}
func (h Hnsv1wrapperwithtimeout) CreateEndpoint(endpoint *hcsshim.HNSEndpoint, path string) (*hcsshim.HNSEndpoint, error) {
r := make(chan EndpointFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
endpoint, err := h.Hnsv1.CreateEndpoint(endpoint, path)
r <- EndpointFuncResult{
endpoint: endpoint,
Err: err,
}
}()
select {
case res := <-r:
return res.endpoint, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "CreateEndpoint timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv1wrapperwithtimeout) DeleteEndpoint(endpointId string) (*hcsshim.HNSEndpoint, error) {
r := make(chan EndpointFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
endpoint, err := h.Hnsv1.DeleteEndpoint(endpointId)
r <- EndpointFuncResult{
endpoint: endpoint,
Err: err,
}
}()
select {
case res := <-r:
return res.endpoint, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "DeleteEndpoint timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv1wrapperwithtimeout) CreateNetwork(network *hcsshim.HNSNetwork, path string) (*hcsshim.HNSNetwork, error) {
r := make(chan NetworkFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
network, err := h.Hnsv1.CreateNetwork(network, path)
r <- NetworkFuncResult{
network: network,
Err: err,
}
}()
select {
case res := <-r:
return res.network, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "CreateNetwork timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv1wrapperwithtimeout) DeleteNetwork(networkId string) (*hcsshim.HNSNetwork, error) {
r := make(chan NetworkFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
network, err := h.Hnsv1.DeleteNetwork(networkId)
r <- NetworkFuncResult{
network: network,
Err: err,
}
}()
select {
case res := <-r:
return res.network, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "DeleteNetwork timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv1wrapperwithtimeout) GetHNSEndpointByName(endpointName string) (*hcsshim.HNSEndpoint, error) {
r := make(chan EndpointFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
endpoint, err := h.Hnsv1.GetHNSEndpointByName(endpointName)
r <- EndpointFuncResult{
endpoint: endpoint,
Err: err,
}
}()
select {
case res := <-r:
return res.endpoint, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "GetHNSEndpointByName timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv1wrapperwithtimeout) GetHNSEndpointByID(endpointID string) (*hcsshim.HNSEndpoint, error) {
r := make(chan EndpointFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
endpoint, err := h.Hnsv1.GetHNSEndpointByName(endpointID)
r <- EndpointFuncResult{
endpoint: endpoint,
Err: err,
}
}()
select {
case res := <-r:
return res.endpoint, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "GetHNSEndpointByID timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv1wrapperwithtimeout) HotAttachEndpoint(containerID string, endpointID string) error {
r := make(chan error)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
r <- h.Hnsv1.HotAttachEndpoint(containerID, endpointID)
}()
select {
case res := <-r:
return res
case <-ctx.Done():
return errors.Wrapf(ErrHNSCallTimeout, "HotAttachEndpoint timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv1wrapperwithtimeout) IsAttached(hnsep *hcsshim.HNSEndpoint, containerID string) (bool, error) {
r := make(chan EndpointAttachedFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
isAttached, err := h.Hnsv1.IsAttached(hnsep, containerID)
r <- EndpointAttachedFuncResult{
isAttached: isAttached,
Err: err,
}
}()
select {
case res := <-r:
return res.isAttached, res.Err
case <-ctx.Done():
return false, errors.Wrapf(ErrHNSCallTimeout, "IsHnsEndpointAttached timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv1wrapperwithtimeout) GetHNSGlobals() (*hcsshim.HNSGlobals, error) {
r := make(chan HnsGlobalFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
hnsGlobals, err := h.Hnsv1.GetHNSGlobals()
r <- HnsGlobalFuncResult{
HnsGlobals: hnsGlobals,
Err: err,
}
}()
select {
case res := <-r:
return res.HnsGlobals, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "GetHNSGlobals timeout value is %v ", h.HnsCallTimeout.String())
}
}

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

@ -13,6 +13,7 @@ import (
"reflect"
"strings"
"sync"
"time"
"github.com/Microsoft/hcsshim/hcn"
)
@ -28,6 +29,7 @@ func newErrorFakeHNS(errStr string) error {
type Hnsv2wrapperFake struct {
Cache FakeHNSCache
*sync.Mutex
Delay time.Duration
}
func NewHnsv2wrapperFake() *Hnsv2wrapperFake {
@ -40,21 +42,30 @@ func NewHnsv2wrapperFake() *Hnsv2wrapperFake {
}
}
func delayHnsCall(delay time.Duration){
time.Sleep(delay)
}
func (f Hnsv2wrapperFake) CreateNetwork(network *hcn.HostComputeNetwork) (*hcn.HostComputeNetwork, error) {
f.Lock()
defer f.Unlock()
delayHnsCall(f.Delay)
f.Cache.networks[network.Name] = NewFakeHostComputeNetwork(network)
return network, nil
}
func (f Hnsv2wrapperFake) DeleteNetwork(network *hcn.HostComputeNetwork) error {
delayHnsCall(f.Delay)
return nil
}
func (f Hnsv2wrapperFake) ModifyNetworkSettings(network *hcn.HostComputeNetwork, request *hcn.ModifyNetworkSettingRequest) error {
f.Lock()
defer f.Unlock()
delayHnsCall(f.Delay)
networkCache, ok := f.Cache.networks[network.Name]
if !ok {
return nil
@ -153,17 +164,20 @@ func (f Hnsv2wrapperFake) ModifyNetworkSettings(network *hcn.HostComputeNetwork,
return nil
}
func (Hnsv2wrapperFake) AddNetworkPolicy(network *hcn.HostComputeNetwork, networkPolicy hcn.PolicyNetworkRequest) error {
func (f Hnsv2wrapperFake) AddNetworkPolicy(network *hcn.HostComputeNetwork, networkPolicy hcn.PolicyNetworkRequest) error {
delayHnsCall(f.Delay)
return nil
}
func (Hnsv2wrapperFake) RemoveNetworkPolicy(network *hcn.HostComputeNetwork, networkPolicy hcn.PolicyNetworkRequest) error {
func (f Hnsv2wrapperFake) RemoveNetworkPolicy(network *hcn.HostComputeNetwork, networkPolicy hcn.PolicyNetworkRequest) error {
delayHnsCall(f.Delay)
return nil
}
func (f Hnsv2wrapperFake) GetNetworkByName(networkName string) (*hcn.HostComputeNetwork, error) {
f.Lock()
defer f.Unlock()
delayHnsCall(f.Delay)
if network, ok := f.Cache.networks[networkName]; ok {
return network.GetHCNObj(), nil
}
@ -173,6 +187,7 @@ func (f Hnsv2wrapperFake) GetNetworkByName(networkName string) (*hcn.HostCompute
func (f Hnsv2wrapperFake) GetNetworkByID(networkID string) (*hcn.HostComputeNetwork, error) {
f.Lock()
defer f.Unlock()
delayHnsCall(f.Delay)
for _, network := range f.Cache.networks {
if network.ID == networkID {
return network.GetHCNObj(), nil
@ -184,6 +199,7 @@ func (f Hnsv2wrapperFake) GetNetworkByID(networkID string) (*hcn.HostComputeNetw
func (f Hnsv2wrapperFake) GetEndpointByID(endpointID string) (*hcn.HostComputeEndpoint, error) {
f.Lock()
defer f.Unlock()
delayHnsCall(f.Delay)
if ep, ok := f.Cache.endpoints[endpointID]; ok {
return ep.GetHCNObj(), nil
}
@ -193,6 +209,7 @@ func (f Hnsv2wrapperFake) GetEndpointByID(endpointID string) (*hcn.HostComputeEn
func (f Hnsv2wrapperFake) CreateEndpoint(endpoint *hcn.HostComputeEndpoint) (*hcn.HostComputeEndpoint, error) {
f.Lock()
defer f.Unlock()
delayHnsCall(f.Delay)
f.Cache.endpoints[endpoint.Id] = NewFakeHostComputeEndpoint(endpoint)
return endpoint, nil
}
@ -200,26 +217,31 @@ func (f Hnsv2wrapperFake) CreateEndpoint(endpoint *hcn.HostComputeEndpoint) (*hc
func (f Hnsv2wrapperFake) DeleteEndpoint(endpoint *hcn.HostComputeEndpoint) error {
f.Lock()
defer f.Unlock()
delayHnsCall(f.Delay)
delete(f.Cache.endpoints, endpoint.Id)
return nil
}
func (Hnsv2wrapperFake) GetNamespaceByID(netNamespacePath string) (*hcn.HostComputeNamespace, error) {
func (f Hnsv2wrapperFake) GetNamespaceByID(netNamespacePath string) (*hcn.HostComputeNamespace, error) {
delayHnsCall(f.Delay)
nameSpace := &hcn.HostComputeNamespace{Id: "ea37ac15-119e-477b-863b-cc23d6eeaa4d", NamespaceId: 1000}
return nameSpace, nil
}
func (Hnsv2wrapperFake) AddNamespaceEndpoint(namespaceId string, endpointId string) error {
func (f Hnsv2wrapperFake) AddNamespaceEndpoint(namespaceId string, endpointId string) error {
delayHnsCall(f.Delay)
return nil
}
func (Hnsv2wrapperFake) RemoveNamespaceEndpoint(namespaceId string, endpointId string) error {
func (f Hnsv2wrapperFake) RemoveNamespaceEndpoint(namespaceId string, endpointId string) error {
delayHnsCall(f.Delay)
return nil
}
func (f Hnsv2wrapperFake) ListEndpointsOfNetwork(networkId string) ([]hcn.HostComputeEndpoint, error) {
f.Lock()
defer f.Unlock()
delayHnsCall(f.Delay)
endpoints := make([]hcn.HostComputeEndpoint, 0)
for _, endpoint := range f.Cache.endpoints {
if endpoint.HostComputeNetwork == networkId {
@ -232,7 +254,7 @@ func (f Hnsv2wrapperFake) ListEndpointsOfNetwork(networkId string) ([]hcn.HostCo
func (f Hnsv2wrapperFake) ApplyEndpointPolicy(endpoint *hcn.HostComputeEndpoint, requestType hcn.RequestType, endpointPolicy hcn.PolicyEndpointRequest) error {
f.Lock()
defer f.Unlock()
delayHnsCall(f.Delay)
epCache, ok := f.Cache.endpoints[endpoint.Id]
if !ok {
return newErrorFakeHNS(fmt.Sprintf("[FakeHNS] could not find endpoint %s", endpoint.Id))
@ -285,7 +307,8 @@ func (f Hnsv2wrapperFake) ApplyEndpointPolicy(endpoint *hcn.HostComputeEndpoint,
return nil
}
func (Hnsv2wrapperFake) GetEndpointByName(endpointName string) (*hcn.HostComputeEndpoint, error) {
func (f Hnsv2wrapperFake) GetEndpointByName(endpointName string) (*hcn.HostComputeEndpoint, error) {
delayHnsCall(f.Delay)
return nil, hcn.EndpointNotFoundError{EndpointName: endpointName}
}

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

@ -0,0 +1,382 @@
//go:build windows
// +build windows
package hnswrapper
import (
"context"
"fmt"
"time"
"github.com/pkg/errors"
"github.com/Microsoft/hcsshim/hcn"
)
// ErrHNSCallTimeout - hns call timeout
var ErrHNSCallTimeout = errors.New("timed out calling hns")
type Hnsv2wrapperwithtimeout struct {
Hnsv2 HnsV2WrapperInterface
// hnsCallTimeout indicates the time to wait for hns calls before timing out
HnsCallTimeout time.Duration
}
type CreateEndpointFuncResult struct {
endpoint *hcn.HostComputeEndpoint
Err error
}
type GetEndpointByIDFuncResult struct {
endpoint *hcn.HostComputeEndpoint
Err error
}
type ListEndpointsFuncResult struct {
endpoints []hcn.HostComputeEndpoint
Err error
}
type CreateNetworkFuncResult struct {
network *hcn.HostComputeNetwork
Err error
}
type GetNamespaceByIDFuncResult struct {
namespace *hcn.HostComputeNamespace
Err error
}
type GetNetworkByNameFuncResult struct {
network *hcn.HostComputeNetwork
Err error
}
type GetNetworkByIDFuncResult struct {
network *hcn.HostComputeNetwork
Err error
}
func (h Hnsv2wrapperwithtimeout) CreateEndpoint(endpoint *hcn.HostComputeEndpoint) (*hcn.HostComputeEndpoint, error) {
r := make(chan CreateEndpointFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
endpoint, err := h.Hnsv2.CreateEndpoint(endpoint)
r <- CreateEndpointFuncResult{
endpoint: endpoint,
Err: err,
}
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res.endpoint, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "CreateEndpoint timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) DeleteEndpoint(endpoint *hcn.HostComputeEndpoint) error {
r := make(chan error)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
r <- h.Hnsv2.DeleteEndpoint(endpoint)
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res
case <-ctx.Done():
return errors.Wrapf(ErrHNSCallTimeout, "DeleteEndpoint timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) CreateNetwork(network *hcn.HostComputeNetwork) (*hcn.HostComputeNetwork, error) {
r := make(chan CreateNetworkFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
network, err := h.Hnsv2.CreateNetwork(network)
r <- CreateNetworkFuncResult{
network: network,
Err: err,
}
}()
select {
case res := <-r:
return res.network, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "CreateNetwork timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) DeleteNetwork(network *hcn.HostComputeNetwork) error {
r := make(chan error)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
r <- h.Hnsv2.DeleteNetwork(network)
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res
case <-ctx.Done():
return errors.Wrapf(ErrHNSCallTimeout, "DeleteNetwork timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) ModifyNetworkSettings(network *hcn.HostComputeNetwork, request *hcn.ModifyNetworkSettingRequest) error {
r := make(chan error)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
r <- h.Hnsv2.ModifyNetworkSettings(network, request)
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res
case <-ctx.Done():
return errors.Wrapf(ErrHNSCallTimeout, "ModifyNetworkSettings timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) AddNetworkPolicy(network *hcn.HostComputeNetwork, networkPolicy hcn.PolicyNetworkRequest) error {
r := make(chan error)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
r <- h.Hnsv2.AddNetworkPolicy(network, networkPolicy)
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res
case <-ctx.Done():
return errors.Wrapf(ErrHNSCallTimeout, "AddNetworkPolicy timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) RemoveNetworkPolicy(network *hcn.HostComputeNetwork, networkPolicy hcn.PolicyNetworkRequest) error {
r := make(chan error)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
r <- h.Hnsv2.RemoveNetworkPolicy(network, networkPolicy)
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res
case <-ctx.Done():
return errors.Wrapf(ErrHNSCallTimeout, "RemoveNetworkPolicy timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) GetNamespaceByID(netNamespacePath string) (*hcn.HostComputeNamespace, error) {
r := make(chan GetNamespaceByIDFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
namespace, err := h.Hnsv2.GetNamespaceByID(netNamespacePath)
r <- GetNamespaceByIDFuncResult{
namespace: namespace,
Err: err,
}
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res.namespace, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "GetNamespaceByID timeout value is %v ", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) AddNamespaceEndpoint(namespaceId string, endpointId string) error {
r := make(chan error)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
r <- h.Hnsv2.AddNamespaceEndpoint(namespaceId, endpointId)
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res
case <-ctx.Done():
return fmt.Errorf("AddNamespaceEndpoint %w , timeout value is %s seconds", ErrHNSCallTimeout, h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) RemoveNamespaceEndpoint(namespaceId string, endpointId string) error {
r := make(chan error)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
r <- h.Hnsv2.RemoveNamespaceEndpoint(namespaceId, endpointId)
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res
case <-ctx.Done():
return errors.Wrapf(ErrHNSCallTimeout, "RemoveNamespaceEndpoint %w , timeout value is %s seconds", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) GetNetworkByName(networkName string) (*hcn.HostComputeNetwork, error) {
r := make(chan GetNetworkByNameFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
network, err := h.Hnsv2.GetNetworkByName(networkName)
r <- GetNetworkByNameFuncResult{
network: network,
Err: err,
}
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res.network, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "GetNetworkByName %w , timeout value is %s seconds", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) GetNetworkByID(networkId string) (*hcn.HostComputeNetwork, error) {
r := make(chan GetNetworkByIDFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
network, err := h.Hnsv2.GetNetworkByID(networkId)
r <- GetNetworkByIDFuncResult{
network: network,
Err: err,
}
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res.network, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "GetNetworkByID %w , timeout value is %s seconds", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) GetEndpointByID(endpointId string) (*hcn.HostComputeEndpoint, error) {
r := make(chan GetEndpointByIDFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
endpoint, err := h.Hnsv2.GetEndpointByID(endpointId)
r <- GetEndpointByIDFuncResult{
endpoint: endpoint,
Err: err,
}
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res.endpoint, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "GetEndpointByID %w , timeout value is %s seconds", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) ListEndpointsOfNetwork(networkId string) ([]hcn.HostComputeEndpoint, error) {
r := make(chan ListEndpointsFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
endpoints, err := h.Hnsv2.ListEndpointsOfNetwork(networkId)
r <- ListEndpointsFuncResult{
endpoints: endpoints,
Err: err,
}
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res.endpoints, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "ListEndpointsOfNetwork %w , timeout value is %s seconds", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) ApplyEndpointPolicy(endpoint *hcn.HostComputeEndpoint, requestType hcn.RequestType, endpointPolicy hcn.PolicyEndpointRequest) error {
r := make(chan error)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
r <- h.Hnsv2.ApplyEndpointPolicy(endpoint, requestType, endpointPolicy)
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res
case <-ctx.Done():
return errors.Wrapf(ErrHNSCallTimeout, "ApplyEndpointPolicy %w , timeout value is %s seconds", h.HnsCallTimeout.String())
}
}
func (h Hnsv2wrapperwithtimeout) GetEndpointByName(endpointName string) (*hcn.HostComputeEndpoint, error) {
r := make(chan GetEndpointByIDFuncResult)
ctx, cancel := context.WithTimeout(context.TODO(), h.HnsCallTimeout)
defer cancel()
go func() {
endpoint, err := h.Hnsv2.GetEndpointByName(endpointName)
r <- GetEndpointByIDFuncResult{
endpoint: endpoint,
Err: err,
}
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-r:
return res.endpoint, res.Err
case <-ctx.Done():
return nil, errors.Wrapf(ErrHNSCallTimeout, "GetEndpointByName %w , timeout value is %s seconds", h.HnsCallTimeout.String())
}
}

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

@ -161,7 +161,7 @@ func (nm *networkManager) restore(isRehydrationRequired bool) error {
for _, extIf := range nm.ExternalInterfaces {
for _, nw := range extIf.Networks {
log.Printf("[net] Deleting the network %s on reboot\n", nw.Id)
nm.deleteNetwork(nw.Id)
_ = nm.deleteNetwork(nw.Id)
}
}
@ -278,11 +278,11 @@ func (nm *networkManager) CreateNetwork(nwInfo *NetworkInfo) error {
}
// DeleteNetwork deletes an existing container network.
func (nm *networkManager) DeleteNetwork(networkId string) error {
func (nm *networkManager) DeleteNetwork(networkID string) error {
nm.Lock()
defer nm.Unlock()
err := nm.deleteNetwork(networkId)
err := nm.deleteNetwork(networkID)
if err != nil {
return err
}

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

@ -208,18 +208,18 @@ func (nm *networkManager) newNetwork(nwInfo *NetworkInfo) (*network, error) {
}
// DeleteNetwork deletes an existing container network.
func (nm *networkManager) deleteNetwork(networkId string) error {
func (nm *networkManager) deleteNetwork(networkID string) error {
var err error
log.Printf("[net] Deleting network %v.", networkId)
log.Printf("[net] Deleting network %v.", networkID)
defer func() {
if err != nil {
log.Printf("[net] Failed to delete network %v, err:%v.", networkId, err)
log.Printf("[net] Failed to delete network %v, err:%v.", networkID, err)
}
}()
// Find the network.
nw, err := nm.getNetwork(networkId)
nw, err := nm.getNetwork(networkID)
if err != nil {
return err
}
@ -232,7 +232,7 @@ func (nm *networkManager) deleteNetwork(networkId string) error {
// Remove the network object.
if nw.extIf != nil {
delete(nw.extIf.Networks, networkId)
delete(nw.extIf.Networks, networkID)
}
log.Printf("[net] Deleted network %+v.", nw)

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

@ -11,6 +11,8 @@ import (
"strings"
"time"
"github.com/Azure/azure-container-networking/network/hnswrapper"
"github.com/Azure/azure-container-networking/log"
"github.com/Azure/azure-container-networking/network/policy"
"github.com/Microsoft/hcsshim"
@ -55,6 +57,26 @@ func UseHnsV2(netNs string) (bool, error) {
return useHnsV2, err
}
// Regarding this Hnsv2 and Hnv1 variable
// this pattern is to avoid passing around os specific objects in platform agnostic code
var Hnsv2 hnswrapper.HnsV2WrapperInterface = hnswrapper.Hnsv2wrapper{}
var Hnsv1 hnswrapper.HnsV1WrapperInterface = hnswrapper.Hnsv1wrapper{}
func EnableHnsV2Timeout(timeoutValue int) {
if _, ok := Hnsv2.(hnswrapper.Hnsv2wrapperwithtimeout); !ok {
var timeoutDuration = time.Duration(timeoutValue) * time.Second
Hnsv2 = hnswrapper.Hnsv2wrapperwithtimeout{Hnsv2: hnswrapper.Hnsv2wrapper{}, HnsCallTimeout: timeoutDuration}
}
}
func EnableHnsV1Timeout(timeoutValue int) {
if _, ok := Hnsv1.(hnswrapper.Hnsv1wrapperwithtimeout); !ok {
var timeoutDuration = time.Duration(timeoutValue) * time.Second
Hnsv1 = hnswrapper.Hnsv1wrapperwithtimeout{Hnsv1: hnswrapper.Hnsv1wrapper{}, HnsCallTimeout: timeoutDuration}
}
}
// newNetworkImplHnsV1 creates a new container network for HNSv1.
func (nm *networkManager) newNetworkImplHnsV1(nwInfo *NetworkInfo, extIf *externalInterface) (*network, error) {
var (
@ -122,17 +144,7 @@ func (nm *networkManager) newNetworkImplHnsV1(nwInfo *NetworkInfo, extIf *extern
hnsNetwork.Subnets = append(hnsNetwork.Subnets, hnsSubnet)
}
// Marshal the request.
buffer, err := json.Marshal(hnsNetwork)
if err != nil {
return nil, err
}
hnsRequest := string(buffer)
// Create the HNS network.
log.Printf("[net] HNSNetworkRequest POST request:%+v", hnsRequest)
hnsResponse, err := hcsshim.HNSNetworkRequest("POST", "", hnsRequest)
log.Printf("[net] HNSNetworkRequest POST response:%+v err:%v.", hnsResponse, err)
hnsResponse, err := Hnsv1.CreateNetwork(hnsNetwork, "")
if err != nil {
return nil, err
}
@ -140,7 +152,7 @@ func (nm *networkManager) newNetworkImplHnsV1(nwInfo *NetworkInfo, extIf *extern
defer func() {
if err != nil {
log.Printf("[net] HNSNetworkRequest DELETE id:%v", hnsResponse.Id)
hnsResponse, err := hcsshim.HNSNetworkRequest("DELETE", hnsResponse.Id, "")
hnsResponse, err := Hnsv1.DeleteNetwork(hnsResponse.Id)
log.Printf("[net] HNSNetworkRequest DELETE response:%+v err:%v.", hnsResponse, err)
}
}()
@ -162,7 +174,7 @@ func (nm *networkManager) newNetworkImplHnsV1(nwInfo *NetworkInfo, extIf *extern
NetNs: nwInfo.NetNs,
}
globals, err := hcsshim.GetHNSGlobals()
globals, err := Hnsv1.GetHNSGlobals()
if err != nil || globals.Version.Major <= hcsshim.HNSVersion1803.Major {
// err would be not nil for windows 1709 & below
// Sleep for 10 seconds as a workaround for windows 1803 & below
@ -312,13 +324,13 @@ func (nm *networkManager) newNetworkImplHnsV2(nwInfo *NetworkInfo, extIf *extern
}
// check if network exists, only create the network does not exist
hnsResponse, err := hnsv2.GetNetworkByName(hcnNetwork.Name)
hnsResponse, err := Hnsv2.GetNetworkByName(hcnNetwork.Name)
if err != nil {
// if network not found, create the HNS network.
if errors.As(err, &hcn.NetworkNotFoundError{}) {
log.Printf("[net] Creating hcn network: %+v", hcnNetwork)
hnsResponse, err = hnsv2.CreateNetwork(hcnNetwork)
hnsResponse, err = Hnsv2.CreateNetwork(hcnNetwork)
if err != nil {
return nil, fmt.Errorf("Failed to create hcn network: %s due to error: %v", hcnNetwork.Name, err)
@ -361,10 +373,8 @@ func (nm *networkManager) newNetworkImpl(nwInfo *NetworkInfo, extIf *externalInt
if err != nil {
return nil, err
}
return nm.newNetworkImplHnsV2(nwInfo, extIf)
}
return nm.newNetworkImplHnsV1(nwInfo, extIf)
}
@ -374,33 +384,31 @@ func (nm *networkManager) deleteNetworkImpl(nw *network) error {
if err != nil {
return err
}
return nm.deleteNetworkImplHnsV2(nw)
}
return nm.deleteNetworkImplHnsV1(nw)
}
// DeleteNetworkImplHnsV1 deletes an existing container network using HnsV1.
func (nm *networkManager) deleteNetworkImplHnsV1(nw *network) error {
log.Printf("[net] HNSNetworkRequest DELETE id:%v", nw.HnsId)
hnsResponse, err := hcsshim.HNSNetworkRequest("DELETE", nw.HnsId, "")
hnsResponse, err := Hnsv1.DeleteNetwork(nw.HnsId)
log.Printf("[net] HNSNetworkRequest DELETE response:%+v err:%v.", hnsResponse, err)
return err
}
// DeleteNetworkImplHnsV2 deletes an existing container network using HnsV2.
// DeleteNetworkImplHnsV2 deletes an existing container network using Hnsv2.
func (nm *networkManager) deleteNetworkImplHnsV2(nw *network) error {
var hcnNetwork *hcn.HostComputeNetwork
var err error
log.Printf("[net] Deleting hcn network with id: %s", nw.HnsId)
if hcnNetwork, err = hnsv2.GetNetworkByID(nw.HnsId); err != nil {
if hcnNetwork, err = Hnsv2.GetNetworkByID(nw.HnsId); err != nil {
return fmt.Errorf("Failed to get hcn network with id: %s due to err: %v", nw.HnsId, err)
}
if err = hnsv2.DeleteNetwork(hcnNetwork); err != nil {
if err = Hnsv2.DeleteNetwork(hcnNetwork); err != nil {
return fmt.Errorf("Failed to delete hcn network: %s due to error: %v", nw.HnsId, err)
}

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

@ -9,6 +9,7 @@ package network
import (
"fmt"
"testing"
"time"
"github.com/Azure/azure-container-networking/network/hnswrapper"
@ -22,7 +23,7 @@ func TestNewAndDeleteNetworkImplHnsV2(t *testing.T) {
// 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()
Hnsv2 = hnswrapper.NewHnsv2wrapperFake()
nwInfo := &NetworkInfo{
Id: "d3e97a83-ba4c-45d5-ba88-dc56757ece28",
@ -57,13 +58,13 @@ func TestSuccesfulNetworkCreationWhenAlreadyExists(t *testing.T) {
// 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()
Hnsv2 = hnswrapper.NewHnsv2wrapperFake()
network := &hcn.HostComputeNetwork{
Name: "azure-vlan1-172-28-1-0_24",
}
_, err := hnsv2.CreateNetwork(network)
_, err := Hnsv2.CreateNetwork(network)
// network name is derived from network info id
nwInfo := &NetworkInfo{
@ -84,3 +85,149 @@ func TestSuccesfulNetworkCreationWhenAlreadyExists(t *testing.T) {
t.Fatal(err)
}
}
func TestNewNetworkImplHnsV2WithTimeout(t *testing.T) {
nm := &networkManager{
ExternalInterfaces: map[string]*externalInterface{},
}
hnsFake := hnswrapper.NewHnsv2wrapperFake()
hnsFake.Delay = 15 * time.Second
Hnsv2 = hnswrapper.Hnsv2wrapperwithtimeout{
Hnsv2: hnsFake,
HnsCallTimeout: 10 * time.Second,
}
nwInfo := &NetworkInfo{
Id: "d3e97a83-ba4c-45d5-ba88-dc56757ece28",
MasterIfName: "eth0",
Mode: "bridge",
}
extInterface := &externalInterface{
Name: "eth0",
Subnets: []string{"subnet1", "subnet2"},
}
_, err := nm.newNetworkImplHnsV2(nwInfo, extInterface)
if err == nil {
t.Fatal("Failed to timeout HNS calls for creating network")
}
}
func TestDeleteNetworkImplHnsV2WithTimeout(t *testing.T) {
nm := &networkManager{
ExternalInterfaces: map[string]*externalInterface{},
}
nwInfo := &NetworkInfo{
Id: "d3e97a83-ba4c-45d5-ba88-dc56757ece28",
MasterIfName: "eth0",
Mode: "bridge",
}
extInterface := &externalInterface{
Name: "eth0",
Subnets: []string{"subnet1", "subnet2"},
}
Hnsv2 = hnswrapper.NewHnsv2wrapperFake()
network, err := nm.newNetworkImplHnsV2(nwInfo, extInterface)
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 = nm.deleteNetworkImplHnsV2(network)
if err == nil {
t.Fatal("Failed to timeout HNS calls for deleting network")
}
}
func TestNewNetworkImplHnsV1WithTimeout(t *testing.T) {
nm := &networkManager{
ExternalInterfaces: map[string]*externalInterface{},
}
hnsFake := hnswrapper.NewHnsv1wrapperFake()
hnsFake.Delay = 10 * time.Second
Hnsv1 = hnswrapper.Hnsv1wrapperwithtimeout{
Hnsv1: hnsFake,
HnsCallTimeout: 5 * time.Second,
}
nwInfo := &NetworkInfo{
Id: "d3e97a83-ba4c-45d5-ba88-dc56757ece28",
MasterIfName: "eth0",
Mode: "bridge",
}
extInterface := &externalInterface{
Name: "eth0",
Subnets: []string{"subnet1", "subnet2"},
}
_, err := nm.newNetworkImplHnsV1(nwInfo, extInterface)
if err == nil {
t.Fatal("Failed to timeout HNS calls for creating network")
}
}
func TestDeleteNetworkImplHnsV1WithTimeout(t *testing.T) {
nm := &networkManager{
ExternalInterfaces: map[string]*externalInterface{},
}
nwInfo := &NetworkInfo{
Id: "d3e97a83-ba4c-45d5-ba88-dc56757ece28",
MasterIfName: "eth0",
Mode: "bridge",
}
extInterface := &externalInterface{
Name: "eth0",
Subnets: []string{"subnet1", "subnet2"},
}
Hnsv1 = hnswrapper.NewHnsv1wrapperFake()
network, err := nm.newNetworkImplHnsV1(nwInfo, extInterface)
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 = nm.deleteNetworkImplHnsV1(network)
if err == nil {
t.Fatal("Failed to timeout HNS calls for deleting network")
}
}