Skip to content

Commit 580c3e4

Browse files
authored
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
1 parent 494308d commit 580c3e4

25 files changed

+239
-98
lines changed

cni/client/client_common_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//go:build unit || integration
12
// +build unit integration
23

34
package client

cni/client/client_integration_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// +build linux
2-
// +build integration
1+
//go:build linux && integration
2+
// +build linux,integration
33

44
package client
55

cni/client/client_unit_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//go:build unit
12
// +build unit
23

34
package client

cni/network/network.go

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ func (plugin *NetPlugin) Add(args *cniSkel.CmdArgs) error {
453453
}
454454

455455
// Initialize values from network config.
456-
networkID, err := plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, nwCfg)
456+
networkID, err := plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, args.Netns, cnsNetworkConfig, nwCfg)
457457
if err != nil {
458458
log.Printf("[cni-net] Failed to extract network name from network config. error: %v", err)
459459
return err
@@ -843,7 +843,7 @@ func (plugin *NetPlugin) Get(args *cniSkel.CmdArgs) error {
843843
}
844844

845845
// Initialize values from network config.
846-
if networkId, err = plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, nwCfg); err != nil {
846+
if networkId, err = plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, args.Netns, nil, nwCfg); err != nil {
847847
// TODO: Ideally we should return from here only.
848848
log.Printf("[cni-net] Failed to extract network name from network config. error: %v", err)
849849
}
@@ -962,14 +962,13 @@ func (plugin *NetPlugin) Delete(args *cniSkel.CmdArgs) error {
962962
plugin.ipamInvoker = NewAzureIpamInvoker(plugin, &nwInfo)
963963
}
964964
}
965-
// Initialize values from network config.
966-
networkID, err = plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, nwCfg)
967965

968-
// If error is not found error, then we ignore it, to comply with CNI SPEC.
966+
// Initialize values from network config.
967+
networkID, err = plugin.getNetworkName(k8sPodName, k8sNamespace, args.IfName, args.Netns, nil, nwCfg)
969968
if err != nil {
970969
log.Printf("[cni-net] Failed to extract network name from network config. error: %v", err)
971-
972-
if !cnscli.IsNotFound(err) {
970+
// If error is not found error, then we ignore it, to comply with CNI SPEC.
971+
if !network.IsNetworkNotFoundError(err) {
973972
err = plugin.Errorf("Failed to extract network name from network config. error: %v", err)
974973
return err
975974
}
@@ -1013,19 +1012,15 @@ func (plugin *NetPlugin) Delete(args *cniSkel.CmdArgs) error {
10131012
return err
10141013
}
10151014

1016-
cnsclient, err := cnscli.New(nwCfg.CNSUrl, defaultRequestTimeout)
1017-
if err != nil {
1018-
log.Printf("failed to initialized cns client with URL %s: %v", nwCfg.CNSUrl, err.Error())
1019-
return plugin.Errorf(err.Error())
1020-
}
1021-
10221015
// schedule send metric before attempting delete
10231016
defer sendMetricFunc()
10241017
telemetry.LogAndSendEvent(plugin.tb, fmt.Sprintf("Deleting endpoint:%v", endpointID))
10251018
// Delete the endpoint.
1026-
if err = plugin.nm.DeleteEndpoint(cnsclient, networkID, endpointID); err != nil {
1027-
err = plugin.Errorf("Failed to delete endpoint: %v", err)
1028-
return err
1019+
if err = plugin.nm.DeleteEndpoint(networkID, endpointID); err != nil {
1020+
// return a retriable error so the container runtime will retry this DEL later
1021+
// the implementation of this function returns nil if the endpoint doens't exist, so
1022+
// we don't have to check that here
1023+
return plugin.RetriableError(fmt.Errorf("failed to delete endpoint: %w", err))
10291024
}
10301025

10311026
if !nwCfg.MultiTenancy {

cni/network/network_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ func updateSubnetPrefix(cnsNetworkConfig *cns.GetNetworkContainerResponse, subne
135135
return nil
136136
}
137137

138-
func (plugin *NetPlugin) getNetworkName(podName, podNs, ifName string, nwCfg *cni.NetworkConfig) (string, error) {
138+
func (plugin *NetPlugin) getNetworkName(_, _, _, _ string, _ *cns.GetNetworkContainerResponse, nwCfg *cni.NetworkConfig) (string, error) {
139139
return nwCfg.Name, nil
140140
}
141141

cni/network/network_linux_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
//+build linux
1+
//go:build linux
2+
// +build linux
23

34
package network
45

cni/network/network_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,7 @@ func TestGetNetworkName(t *testing.T) {
10601060
for _, tt := range tests {
10611061
tt := tt
10621062
t.Run(tt.name, func(t *testing.T) {
1063-
nwName, _ := plugin.getNetworkName("", "", "", &tt.nwCfg)
1063+
nwName, _ := plugin.getNetworkName("", "", "", "", nil, &tt.nwCfg)
10641064
require.Equal(t, tt.nwCfg.Name, nwName)
10651065
})
10661066
}

cni/network/network_windows.go

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package network
22

33
import (
4-
"context"
54
"encoding/json"
65
"fmt"
76
"net"
@@ -160,42 +159,45 @@ func updateSubnetPrefix(cnsNwConfig *cns.GetNetworkContainerResponse, subnetPref
160159
return nil
161160
}
162161

163-
func (plugin *NetPlugin) getNetworkName(podName, podNs, ifName string, nwCfg *cni.NetworkConfig) (string, error) {
164-
var (
165-
networkName string
166-
err error
167-
cnsNetworkConfig *cns.GetNetworkContainerResponse
168-
)
169-
170-
networkName = nwCfg.Name
171-
err = nil
172-
173-
if nwCfg.MultiTenancy {
174-
determineWinVer()
175-
if len(strings.TrimSpace(podName)) == 0 || len(strings.TrimSpace(podNs)) == 0 {
176-
err = fmt.Errorf("POD info cannot be empty. PodName: %s, PodNamespace: %s", podName, podNs)
177-
return networkName, err
178-
}
162+
func (plugin *NetPlugin) getNetworkName(podName, podNs, ifName, netNs string, cnsResponse *cns.GetNetworkContainerResponse, nwCfg *cni.NetworkConfig) (string, error) {
163+
// For singletenancy, the network name is simply the nwCfg.Name
164+
if !nwCfg.MultiTenancy {
165+
return nwCfg.Name, nil
166+
}
179167

180-
_, cnsNetworkConfig, _, err = plugin.multitenancyClient.GetContainerNetworkConfiguration(context.TODO(), nwCfg, podName, podNs, ifName)
181-
if err != nil {
182-
log.Printf(
183-
"GetContainerNetworkConfiguration failed for podname %v namespace %v with error %v",
184-
podName,
185-
podNs,
186-
err)
187-
} else {
188-
var subnet net.IPNet
189-
if err = updateSubnetPrefix(cnsNetworkConfig, &subnet); err == nil {
190-
// networkName will look like ~ azure-vlan1-172-28-1-0_24
191-
networkName = strings.Replace(subnet.String(), ".", "-", -1)
192-
networkName = strings.Replace(networkName, "/", "_", -1)
193-
networkName = fmt.Sprintf("%s-vlan%v-%v", nwCfg.Name, cnsNetworkConfig.MultiTenancyInfo.ID, networkName)
194-
}
168+
// in multitenancy case, the network name will be in the state file or can be built from cnsResponse
169+
determineWinVer()
170+
if len(strings.TrimSpace(netNs)) == 0 || len(strings.TrimSpace(podName)) == 0 || len(strings.TrimSpace(podNs)) == 0 {
171+
return "", fmt.Errorf("POD info cannot be empty. PodName: %s, PodNamespace: %s, NetNs: %s", podName, podNs, netNs)
172+
}
173+
174+
// First try to build the network name from the cnsResponse if present
175+
// This will happen during ADD call
176+
if cnsResponse != nil {
177+
var subnet net.IPNet
178+
if err := updateSubnetPrefix(cnsResponse, &subnet); err != nil {
179+
log.Printf("Error updating subnet prefix: %v", err)
180+
return "", err
195181
}
182+
183+
// networkName will look like ~ azure-vlan1-172-28-1-0_24
184+
networkSuffix := strings.Replace(subnet.String(), ".", "-", -1)
185+
networkSuffix = strings.Replace(networkSuffix, "/", "_", -1)
186+
networkName := fmt.Sprintf("%s-vlan%v-%v", nwCfg.Name, cnsResponse.MultiTenancyInfo.ID, networkSuffix)
187+
188+
return networkName, nil
189+
}
190+
191+
// If no cnsResponse was present, try to get the network name from the state file
192+
// This will happen during DEL call
193+
networkName, err := plugin.nm.FindNetworkIDFromNetNs(netNs)
194+
if err != nil {
195+
log.Printf("Error getting network name from state: %v.", err)
196+
return "", fmt.Errorf("error getting network name from state: %w", err)
197+
196198
}
197199

198-
return networkName, err
200+
return networkName, nil
199201
}
200202

201203
func setupInfraVnetRoutingForMultitenancy(

cni/network/network_windows_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ func TestSetEndpointOptions(t *testing.T) {
183183
ID: 1,
184184
},
185185
CnetAddressSpace: []cns.IPSubnet{
186-
cns.IPSubnet{
186+
{
187187
IPAddress: "192.168.0.4",
188188
PrefixLength: 24,
189189
},
@@ -221,7 +221,7 @@ func TestSetPoliciesFromNwCfg(t *testing.T) {
221221
nwCfg: cni.NetworkConfig{
222222
RuntimeConfig: cni.RuntimeConfig{
223223
PortMappings: []cni.PortMapping{
224-
cni.PortMapping{
224+
{
225225
Protocol: "tcp",
226226
HostIp: "19.268.0.4",
227227
HostPort: 8000,

cni/plugin.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,13 @@ func (plugin *Plugin) Errorf(format string, args ...interface{}) *cniTypes.Error
150150
return plugin.Error(fmt.Errorf(format, args...))
151151
}
152152

153+
// RetriableError logs and returns a CNI error with the TryAgainLater error code
154+
func (plugin *Plugin) RetriableError(err error) *cniTypes.Error {
155+
tryAgainErr := cniTypes.NewError(cniTypes.ErrTryAgainLater, err.Error(), "")
156+
log.Printf("[%v] %+v.", plugin.Name, tryAgainErr.Error())
157+
return tryAgainErr
158+
}
159+
153160
// Initialize key-value store
154161
func (plugin *Plugin) InitializeKeyValueStore(config *common.PluginConfig) error {
155162
// Create the key value store.

0 commit comments

Comments
 (0)