@@ -7,13 +7,15 @@ import (
77 "encoding/json"
88 "fmt"
99 "net"
10+ "regexp"
1011 "testing"
1112
1213 "github.com/Azure/azure-container-networking/cni"
1314 "github.com/Azure/azure-container-networking/cns"
1415 "github.com/Azure/azure-container-networking/network"
1516 "github.com/Azure/azure-container-networking/network/hnswrapper"
1617 "github.com/Azure/azure-container-networking/network/policy"
18+ "github.com/Azure/azure-container-networking/platform"
1719 "github.com/Azure/azure-container-networking/telemetry"
1820 hnsv2 "github.com/Microsoft/hcsshim/hcn"
1921 cniSkel "github.com/containernetworking/cni/pkg/skel"
@@ -855,3 +857,182 @@ func TestPluginMultitenancyWindowsDelete(t *testing.T) {
855857 })
856858 }
857859}
860+
861+ // Happy path scenario for add and delete
862+ func TestPluginWindowsAdd (t * testing.T ) {
863+ resources := GetTestResources ()
864+ localNwCfg := cni.NetworkConfig {
865+ CNIVersion : "0.3.0" ,
866+ Name : "mulnet" ,
867+ MultiTenancy : true ,
868+ EnableExactMatchForPodName : true ,
869+ Master : "eth0" ,
870+ }
871+ type endpointEntry struct {
872+ epInfo * network.EndpointInfo
873+ epIDRegex string
874+ }
875+
876+ tests := []struct {
877+ name string
878+ plugin * NetPlugin
879+ args * cniSkel.CmdArgs
880+ want []endpointEntry
881+ match func (* network.EndpointInfo , * network.EndpointInfo ) bool
882+ }{
883+ {
884+ name : "Add Happy Path Dual NIC" ,
885+ plugin : & NetPlugin {
886+ Plugin : resources .Plugin ,
887+ nm : network .NewMockNetworkmanager (network .NewMockEndpointClient (nil )),
888+ tb : & telemetry.TelemetryBuffer {},
889+ report : & telemetry.CNIReport {},
890+ multitenancyClient : NewMockMultitenancy (false , []* cns.GetNetworkContainerResponse {GetTestCNSResponse1 (), GetTestCNSResponse2 ()}),
891+ },
892+ args : & cniSkel.CmdArgs {
893+ StdinData : localNwCfg .Serialize (),
894+ ContainerID : "test-container" ,
895+ Netns : "bc526fae-4ba0-4e80-bc90-ad721e5850bf" ,
896+ Args : fmt .Sprintf ("K8S_POD_NAME=%v;K8S_POD_NAMESPACE=%v" , "test-pod" , "test-pod-ns" ),
897+ IfName : eth0IfName ,
898+ },
899+ match : func (ei1 , ei2 * network.EndpointInfo ) bool {
900+ return ei1 .NetworkID == ei2 .NetworkID
901+ },
902+ want : []endpointEntry {
903+ // should match with GetTestCNSResponse1
904+ {
905+ epInfo : & network.EndpointInfo {
906+ ContainerID : "test-container" ,
907+ Data : map [string ]interface {}{
908+ "cnetAddressSpace" : ([]string )(nil ),
909+ },
910+ Routes : []network.RouteInfo {},
911+ EnableSnatOnHost : true ,
912+ EnableMultiTenancy : true ,
913+ EnableSnatForDns : true ,
914+ PODName : "test-pod" ,
915+ PODNameSpace : "test-pod-ns" ,
916+ NICType : cns .InfraNIC ,
917+ MasterIfName : eth0IfName ,
918+ NetworkID : "mulnet-vlan1-20-0-0-0_24" ,
919+ NetNsPath : "bc526fae-4ba0-4e80-bc90-ad721e5850bf" ,
920+ NetNs : "bc526fae-4ba0-4e80-bc90-ad721e5850bf" ,
921+ HostSubnetPrefix : "20.240.0.0/24" ,
922+ Options : map [string ]interface {}{
923+ dockerNetworkOption : map [string ]interface {}{
924+ "VlanID" : "1" ,
925+ },
926+ },
927+ // matches with cns ip configuration
928+ IPAddresses : []net.IPNet {
929+ {
930+ IP : net .ParseIP ("20.0.0.10" ),
931+ Mask : getIPNetWithString ("20.0.0.10/24" ).Mask ,
932+ },
933+ },
934+ // LocalIPConfiguration doesn't seem used in windows
935+ // Constant, in windows, NAT Info comes from
936+ // options > ipamAddConfig >
937+ // cns invoker may populate network.SNATIPKey with the default response received >
938+ // getNATInfo (with nwCfg) > adds nat info based on condition
939+ // typically adds azure dns (168.63.129.16)
940+ NATInfo : []policy.NATInfo {
941+ {
942+ Destinations : []string {"168.63.129.16" },
943+ },
944+ },
945+ // ip config pod ip + mask(s) from cns > interface info > subnet info
946+ Subnets : []network.SubnetInfo {
947+ {
948+ Family : platform .AfINET ,
949+ // matches cns ip configuration (20.0.0.1/24 == 20.0.0.0/24)
950+ Prefix : * getIPNetWithString ("20.0.0.0/24" ),
951+ // matches cns ip configuration gateway ip address
952+ Gateway : net .ParseIP ("20.0.0.1" ),
953+ },
954+ },
955+ },
956+ epIDRegex : `.*` ,
957+ },
958+ // should match with GetTestCNSResponse2
959+ {
960+ epInfo : & network.EndpointInfo {
961+ ContainerID : "test-container" ,
962+ Data : map [string ]interface {}{
963+ "cnetAddressSpace" : ([]string )(nil ),
964+ },
965+ Routes : []network.RouteInfo {},
966+ EnableSnatOnHost : true ,
967+ EnableMultiTenancy : true ,
968+ EnableSnatForDns : true ,
969+ PODName : "test-pod" ,
970+ PODNameSpace : "test-pod-ns" ,
971+ NICType : cns .InfraNIC ,
972+ MasterIfName : eth0IfName ,
973+ NetworkID : "mulnet-vlan2-10-0-0-0_24" ,
974+ NetNsPath : "bc526fae-4ba0-4e80-bc90-ad721e5850bf" ,
975+ NetNs : "bc526fae-4ba0-4e80-bc90-ad721e5850bf" ,
976+ HostSubnetPrefix : "10.240.0.0/24" ,
977+ Options : map [string ]interface {}{
978+ dockerNetworkOption : map [string ]interface {}{
979+ "VlanID" : "2" ,
980+ },
981+ },
982+ IPAddresses : []net.IPNet {
983+ {
984+ IP : net .ParseIP ("10.0.0.10" ),
985+ Mask : getIPNetWithString ("10.0.0.10/24" ).Mask ,
986+ },
987+ },
988+ NATInfo : []policy.NATInfo {
989+ {
990+ Destinations : []string {"168.63.129.16" },
991+ },
992+ },
993+ Subnets : []network.SubnetInfo {
994+ {
995+ Family : platform .AfINET ,
996+ Prefix : * getIPNetWithString ("10.0.0.0/24" ),
997+ Gateway : net .ParseIP ("10.0.0.1" ),
998+ },
999+ },
1000+ },
1001+ epIDRegex : `.*` ,
1002+ },
1003+ },
1004+ },
1005+ }
1006+
1007+ for _ , tt := range tests {
1008+ tt := tt
1009+ t .Run (tt .name , func (t * testing.T ) {
1010+ err := tt .plugin .Add (tt .args )
1011+ require .NoError (t , err )
1012+ allEndpoints , _ := tt .plugin .nm .GetAllEndpoints ("" )
1013+ require .Len (t , allEndpoints , len (tt .want ))
1014+ for _ , wantedEndpointEntry := range tt .want {
1015+ epId := "none"
1016+ for _ , endpointInfo := range allEndpoints {
1017+ if tt .match (wantedEndpointEntry .epInfo , endpointInfo ) {
1018+ // save the endpoint id before removing it
1019+ epId = endpointInfo .EndpointID
1020+ require .Regexp (t , regexp .MustCompile (wantedEndpointEntry .epIDRegex ), epId )
1021+
1022+ // omit endpoint id and ifname fields as they are nondeterministic
1023+ endpointInfo .EndpointID = ""
1024+ endpointInfo .IfName = ""
1025+
1026+ require .Equal (t , wantedEndpointEntry .epInfo , endpointInfo )
1027+ break
1028+ }
1029+ }
1030+ if epId == "none" {
1031+ t .Fail ()
1032+ }
1033+ tt .plugin .nm .DeleteEndpoint ("" , epId , nil )
1034+ }
1035+
1036+ })
1037+ }
1038+ }
0 commit comments