Skip to content

Commit c4569f1

Browse files
committed
add linux multitenancy test
1 parent 903b482 commit c4569f1

File tree

3 files changed

+185
-1
lines changed

3 files changed

+185
-1
lines changed

cni/network/network_linux_test.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,18 @@
44
package network
55

66
import (
7+
"fmt"
8+
"log"
9+
"net"
10+
"regexp"
711
"testing"
812

13+
"github.com/Azure/azure-container-networking/cni"
914
"github.com/Azure/azure-container-networking/cns"
1015
"github.com/Azure/azure-container-networking/network"
16+
"github.com/Azure/azure-container-networking/platform"
17+
"github.com/Azure/azure-container-networking/telemetry"
18+
cniSkel "github.com/containernetworking/cni/pkg/skel"
1119
"github.com/stretchr/testify/assert"
1220
"github.com/stretchr/testify/require"
1321
)
@@ -160,3 +168,141 @@ func TestAddSnatForDns(t *testing.T) {
160168
})
161169
}
162170
}
171+
172+
// Happy path scenario for add and delete
173+
func TestPluginLinuxAdd(t *testing.T) {
174+
resources := GetTestResources()
175+
localNwCfg := cni.NetworkConfig{
176+
CNIVersion: "0.3.0",
177+
Name: "mulnet",
178+
MultiTenancy: true,
179+
EnableExactMatchForPodName: true,
180+
Master: "eth0",
181+
}
182+
type endpointEntry struct {
183+
epInfo *network.EndpointInfo
184+
epIDRegex string
185+
}
186+
187+
tests := []struct {
188+
name string
189+
plugin *NetPlugin
190+
args *cniSkel.CmdArgs
191+
want []endpointEntry
192+
match func(*network.EndpointInfo, *network.EndpointInfo) bool
193+
}{
194+
{
195+
// in swiftv1 linux multitenancy, we only get 1 response from cns at a time
196+
name: "Add Happy Path Swiftv1 Multitenancy",
197+
plugin: &NetPlugin{
198+
Plugin: resources.Plugin,
199+
nm: network.NewMockNetworkmanager(network.NewMockEndpointClient(nil)),
200+
tb: &telemetry.TelemetryBuffer{},
201+
report: &telemetry.CNIReport{},
202+
multitenancyClient: NewMockMultitenancy(false, []*cns.GetNetworkContainerResponse{GetTestCNSResponse3()}),
203+
},
204+
args: &cniSkel.CmdArgs{
205+
StdinData: localNwCfg.Serialize(),
206+
ContainerID: "test-container",
207+
Netns: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
208+
Args: fmt.Sprintf("K8S_POD_NAME=%v;K8S_POD_NAMESPACE=%v", "test-pod", "test-pod-ns"),
209+
IfName: eth0IfName,
210+
},
211+
match: func(ei1, ei2 *network.EndpointInfo) bool {
212+
return ei1.NetworkContainerID == ei2.NetworkContainerID
213+
},
214+
want: []endpointEntry{
215+
// should match with GetTestCNSResponse3
216+
{
217+
epInfo: &network.EndpointInfo{
218+
ContainerID: "test-container",
219+
Data: map[string]interface{}{
220+
"VlanID": 1, // Vlan ID used here
221+
"localIP": "168.254.0.4/17",
222+
"snatBridgeIP": "168.254.0.1/17",
223+
"vethname": "mulnettest-containereth0",
224+
},
225+
Routes: []network.RouteInfo{
226+
{
227+
Dst: *parseCIDR("192.168.0.4/24"),
228+
Gw: net.ParseIP("192.168.0.1"),
229+
// interface to use is NOT propagated to ep info
230+
},
231+
},
232+
AllowInboundFromHostToNC: true,
233+
EnableSnatOnHost: true,
234+
EnableMultiTenancy: true,
235+
EnableSnatForDns: true,
236+
PODName: "test-pod",
237+
PODNameSpace: "test-pod-ns",
238+
NICType: cns.InfraNIC,
239+
MasterIfName: eth0IfName,
240+
NetworkContainerID: "Swift_74b34111-6e92-49ee-a82a-8881c850ce0e",
241+
NetworkID: "mulnet",
242+
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
243+
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
244+
HostSubnetPrefix: "20.240.0.0/24",
245+
Options: map[string]interface{}{
246+
dockerNetworkOption: map[string]interface{}{
247+
"VlanID": "1", // doesn't seem to be used in linux
248+
"snatBridgeIP": "168.254.0.1/17",
249+
},
250+
},
251+
// matches with cns ip configuration
252+
IPAddresses: []net.IPNet{
253+
{
254+
IP: net.ParseIP("20.0.0.10"),
255+
Mask: getIPNetWithString("20.0.0.10/24").Mask,
256+
},
257+
},
258+
NATInfo: nil,
259+
// ip config pod ip + mask(s) from cns > interface info > subnet info
260+
Subnets: []network.SubnetInfo{
261+
{
262+
Family: platform.AfINET,
263+
// matches cns ip configuration (20.0.0.1/24 == 20.0.0.0/24)
264+
Prefix: *getIPNetWithString("20.0.0.0/24"),
265+
// matches cns ip configuration gateway ip address
266+
Gateway: net.ParseIP("20.0.0.1"),
267+
},
268+
},
269+
},
270+
epIDRegex: `test-con-eth0`,
271+
},
272+
},
273+
},
274+
}
275+
276+
for _, tt := range tests {
277+
tt := tt
278+
t.Run(tt.name, func(t *testing.T) {
279+
err := tt.plugin.Add(tt.args)
280+
require.NoError(t, err)
281+
allEndpoints, _ := tt.plugin.nm.GetAllEndpoints("")
282+
require.Len(t, allEndpoints, len(tt.want))
283+
for _, wantedEndpointEntry := range tt.want {
284+
epId := "none"
285+
for _, endpointInfo := range allEndpoints {
286+
log.Printf("%v", endpointInfo.NetworkID)
287+
if tt.match(wantedEndpointEntry.epInfo, endpointInfo) {
288+
// save the endpoint id before removing it
289+
epId = endpointInfo.EndpointID
290+
require.Regexp(t, regexp.MustCompile(wantedEndpointEntry.epIDRegex), epId)
291+
292+
// omit endpoint id and ifname fields as they are nondeterministic
293+
endpointInfo.EndpointID = ""
294+
endpointInfo.IfName = ""
295+
296+
require.Equal(t, wantedEndpointEntry.epInfo, endpointInfo)
297+
break
298+
}
299+
}
300+
if epId == "none" {
301+
t.Fail()
302+
}
303+
tt.plugin.nm.DeleteEndpoint("", epId, nil)
304+
}
305+
306+
})
307+
}
308+
}

cni/network/network_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,44 @@ func GetTestCNSResponse2() *cns.GetNetworkContainerResponse {
688688
}
689689
}
690690

691+
// For use with GetAllNetworkContainers in linux multitenancy
692+
func GetTestCNSResponse3() *cns.GetNetworkContainerResponse {
693+
return &cns.GetNetworkContainerResponse{
694+
NetworkContainerID: "Swift_74b34111-6e92-49ee-a82a-8881c850ce0e",
695+
IPConfiguration: cns.IPConfiguration{
696+
IPSubnet: cns.IPSubnet{
697+
IPAddress: "20.0.0.10",
698+
PrefixLength: ipPrefixLen,
699+
},
700+
DNSServers: []string{
701+
"168.63.129.16",
702+
},
703+
GatewayIPAddress: "20.0.0.1",
704+
},
705+
Routes: []cns.Route{
706+
// dummy route
707+
{
708+
IPAddress: "192.168.0.4/24",
709+
GatewayIPAddress: "192.168.0.1",
710+
},
711+
},
712+
MultiTenancyInfo: cns.MultiTenancyInfo{
713+
EncapType: cns.Vlan,
714+
ID: multiTenancyVlan1,
715+
},
716+
PrimaryInterfaceIdentifier: "20.240.0.4/24",
717+
LocalIPConfiguration: cns.IPConfiguration{
718+
IPSubnet: cns.IPSubnet{
719+
IPAddress: "168.254.0.4",
720+
PrefixLength: localIPPrefixLen,
721+
},
722+
GatewayIPAddress: "168.254.0.1",
723+
},
724+
AllowHostToNCCommunication: true,
725+
AllowNCToHostCommunication: false,
726+
}
727+
}
728+
691729
// Test Multitenancy Add
692730
func TestPluginMultitenancyAdd(t *testing.T) {
693731
plugin, _ := cni.NewPlugin("test", "0.3.0")

network/endpoint.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ type EndpointInfo struct {
9393
IPV6Mode string
9494
VnetCidrs string
9595
ServiceCidrs string
96-
NATInfo []policy.NATInfo
96+
NATInfo []policy.NATInfo // windows only
9797
NICType cns.NICType
9898
SkipDefaultRoutes bool
9999
HNSEndpointID string

0 commit comments

Comments
 (0)