...

Source file src/k8s.io/kubernetes/pkg/proxy/winkernel/proxier_test.go

Documentation: k8s.io/kubernetes/pkg/proxy/winkernel

     1  //go:build windows
     2  // +build windows
     3  
     4  /*
     5  Copyright 2021 The Kubernetes Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package winkernel
    21  
    22  import (
    23  	"encoding/json"
    24  	"fmt"
    25  	"net"
    26  	"strings"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/Microsoft/hcsshim/hcn"
    31  	v1 "k8s.io/api/core/v1"
    32  	discovery "k8s.io/api/discovery/v1"
    33  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    34  	"k8s.io/apimachinery/pkg/types"
    35  	"k8s.io/apimachinery/pkg/util/intstr"
    36  	"k8s.io/kubernetes/pkg/proxy"
    37  	"k8s.io/kubernetes/pkg/proxy/healthcheck"
    38  	fakehcn "k8s.io/kubernetes/pkg/proxy/winkernel/testing"
    39  	netutils "k8s.io/utils/net"
    40  	"k8s.io/utils/ptr"
    41  )
    42  
    43  const (
    44  	testHostName      = "test-hostname"
    45  	testNetwork       = "TestNetwork"
    46  	ipAddress         = "10.0.0.1"
    47  	prefixLen         = 24
    48  	macAddress        = "00-11-22-33-44-55"
    49  	destinationPrefix = "192.168.2.0/24"
    50  	providerAddress   = "10.0.0.3"
    51  	guid              = "123ABC"
    52  	endpointGuid1     = "EPID-1"
    53  	loadbalancerGuid1 = "LBID-1"
    54  	endpointLocal     = "EP-LOCAL"
    55  	endpointGw        = "EP-GW"
    56  	epIpAddressGw     = "192.168.2.1"
    57  	epMacAddressGw    = "00-11-22-33-44-66"
    58  )
    59  
    60  func newHnsNetwork(networkInfo *hnsNetworkInfo) *hcn.HostComputeNetwork {
    61  	var policies []hcn.NetworkPolicy
    62  	for _, remoteSubnet := range networkInfo.remoteSubnets {
    63  		policySettings := hcn.RemoteSubnetRoutePolicySetting{
    64  			DestinationPrefix:           remoteSubnet.destinationPrefix,
    65  			IsolationId:                 remoteSubnet.isolationID,
    66  			ProviderAddress:             remoteSubnet.providerAddress,
    67  			DistributedRouterMacAddress: remoteSubnet.drMacAddress,
    68  		}
    69  		settings, _ := json.Marshal(policySettings)
    70  		policy := hcn.NetworkPolicy{
    71  			Type:     hcn.RemoteSubnetRoute,
    72  			Settings: settings,
    73  		}
    74  		policies = append(policies, policy)
    75  	}
    76  
    77  	network := &hcn.HostComputeNetwork{
    78  		Id:       networkInfo.id,
    79  		Name:     networkInfo.name,
    80  		Type:     hcn.NetworkType(networkInfo.networkType),
    81  		Policies: policies,
    82  	}
    83  	return network
    84  }
    85  
    86  func NewFakeProxier(syncPeriod time.Duration, minSyncPeriod time.Duration, hostname string, nodeIP net.IP, networkType string) *Proxier {
    87  	sourceVip := "192.168.1.2"
    88  	var remoteSubnets []*remoteSubnetInfo
    89  	rs := &remoteSubnetInfo{
    90  		destinationPrefix: destinationPrefix,
    91  		isolationID:       4096,
    92  		providerAddress:   providerAddress,
    93  		drMacAddress:      macAddress,
    94  	}
    95  	remoteSubnets = append(remoteSubnets, rs)
    96  	hnsNetworkInfo := &hnsNetworkInfo{
    97  		id:            strings.ToUpper(guid),
    98  		name:          testNetwork,
    99  		networkType:   networkType,
   100  		remoteSubnets: remoteSubnets,
   101  	}
   102  	hnsNetwork := newHnsNetwork(hnsNetworkInfo)
   103  	hcnMock := fakehcn.NewHcnMock(hnsNetwork)
   104  	proxier := &Proxier{
   105  		svcPortMap:          make(proxy.ServicePortMap),
   106  		endpointsMap:        make(proxy.EndpointsMap),
   107  		hostname:            testHostName,
   108  		nodeIP:              nodeIP,
   109  		serviceHealthServer: healthcheck.NewFakeServiceHealthServer(),
   110  		network:             *hnsNetworkInfo,
   111  		sourceVip:           sourceVip,
   112  		hostMac:             macAddress,
   113  		isDSR:               false,
   114  		hns: &hns{
   115  			hcn: hcnMock,
   116  		},
   117  		hcn:                   hcnMock,
   118  		endPointsRefCount:     make(endPointsReferenceCountMap),
   119  		forwardHealthCheckVip: true,
   120  		mapStaleLoadbalancers: make(map[string]bool),
   121  	}
   122  
   123  	serviceChanges := proxy.NewServiceChangeTracker(proxier.newServiceInfo, v1.IPv4Protocol, nil, proxier.serviceMapChange)
   124  	endpointsChangeTracker := proxy.NewEndpointsChangeTracker(hostname, proxier.newEndpointInfo, v1.IPv4Protocol, nil, proxier.endpointsMapChange)
   125  	proxier.endpointsChanges = endpointsChangeTracker
   126  	proxier.serviceChanges = serviceChanges
   127  
   128  	return proxier
   129  }
   130  
   131  func TestCreateServiceVip(t *testing.T) {
   132  	syncPeriod := 30 * time.Second
   133  	proxier := NewFakeProxier(syncPeriod, syncPeriod, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   134  	if proxier == nil {
   135  		t.Error()
   136  	}
   137  
   138  	svcIP := "10.20.30.41"
   139  	svcPort := 80
   140  	svcNodePort := 3001
   141  	svcExternalIPs := "50.60.70.81"
   142  	svcPortName := proxy.ServicePortName{
   143  		NamespacedName: makeNSN("ns1", "svc1"),
   144  		Port:           "p80",
   145  		Protocol:       v1.ProtocolTCP,
   146  	}
   147  
   148  	makeServiceMap(proxier,
   149  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   150  			svc.Spec.Type = "NodePort"
   151  			svc.Spec.ClusterIP = svcIP
   152  			svc.Spec.ExternalIPs = []string{svcExternalIPs}
   153  			svc.Spec.SessionAffinity = v1.ServiceAffinityClientIP
   154  			svc.Spec.SessionAffinityConfig = &v1.SessionAffinityConfig{
   155  				ClientIP: &v1.ClientIPConfig{
   156  					TimeoutSeconds: ptr.To[int32](v1.DefaultClientIPServiceAffinitySeconds),
   157  				},
   158  			}
   159  			svc.Spec.Ports = []v1.ServicePort{{
   160  				Name:     svcPortName.Port,
   161  				Port:     int32(svcPort),
   162  				Protocol: v1.ProtocolTCP,
   163  				NodePort: int32(svcNodePort),
   164  			}}
   165  		}),
   166  	)
   167  	proxier.setInitialized(true)
   168  	proxier.syncProxyRules()
   169  
   170  	svc := proxier.svcPortMap[svcPortName]
   171  	svcInfo, ok := svc.(*serviceInfo)
   172  	if !ok {
   173  		t.Errorf("Failed to cast serviceInfo %q", svcPortName.String())
   174  
   175  	} else {
   176  		if svcInfo.remoteEndpoint == nil {
   177  			t.Error()
   178  		}
   179  		if svcInfo.remoteEndpoint.ip != svcIP {
   180  			t.Error()
   181  		}
   182  	}
   183  }
   184  
   185  func TestCreateRemoteEndpointOverlay(t *testing.T) {
   186  	syncPeriod := 30 * time.Second
   187  	proxier := NewFakeProxier(syncPeriod, syncPeriod, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   188  	if proxier == nil {
   189  		t.Error()
   190  	}
   191  
   192  	svcIP := "10.20.30.41"
   193  	svcPort := 80
   194  	svcNodePort := 3001
   195  	svcPortName := proxy.ServicePortName{
   196  		NamespacedName: makeNSN("ns1", "svc1"),
   197  		Port:           "p80",
   198  		Protocol:       v1.ProtocolTCP,
   199  	}
   200  
   201  	makeServiceMap(proxier,
   202  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   203  			svc.Spec.Type = "NodePort"
   204  			svc.Spec.ClusterIP = svcIP
   205  			svc.Spec.Ports = []v1.ServicePort{{
   206  				Name:     svcPortName.Port,
   207  				Port:     int32(svcPort),
   208  				Protocol: v1.ProtocolTCP,
   209  				NodePort: int32(svcNodePort),
   210  			}}
   211  		}),
   212  	)
   213  	populateEndpointSlices(proxier,
   214  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
   215  			eps.AddressType = discovery.AddressTypeIPv4
   216  			eps.Endpoints = []discovery.Endpoint{{
   217  				Addresses: []string{epIpAddressRemote},
   218  			}}
   219  			eps.Ports = []discovery.EndpointPort{{
   220  				Name:     ptr.To(svcPortName.Port),
   221  				Port:     ptr.To(int32(svcPort)),
   222  				Protocol: ptr.To(v1.ProtocolTCP),
   223  			}}
   224  		}),
   225  	)
   226  
   227  	proxier.setInitialized(true)
   228  	proxier.syncProxyRules()
   229  
   230  	ep := proxier.endpointsMap[svcPortName][0]
   231  	epInfo, ok := ep.(*endpointInfo)
   232  	if !ok {
   233  		t.Errorf("Failed to cast endpointInfo %q", svcPortName.String())
   234  
   235  	} else {
   236  		if epInfo.hnsID != "EPID-3" {
   237  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   238  		}
   239  	}
   240  
   241  	if *proxier.endPointsRefCount["EPID-3"] <= 0 {
   242  		t.Errorf("RefCount not incremented. Current value: %v", *proxier.endPointsRefCount[endpointGuid1])
   243  	}
   244  
   245  	if *proxier.endPointsRefCount["EPID-3"] != *epInfo.refCount {
   246  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   247  	}
   248  }
   249  
   250  func TestCreateRemoteEndpointL2Bridge(t *testing.T) {
   251  	syncPeriod := 30 * time.Second
   252  	proxier := NewFakeProxier(syncPeriod, syncPeriod, "testhost", netutils.ParseIPSloppy("10.0.0.1"), "L2Bridge")
   253  	if proxier == nil {
   254  		t.Error()
   255  	}
   256  
   257  	svcIP := "10.20.30.41"
   258  	svcPort := 80
   259  	svcNodePort := 3001
   260  	svcPortName := proxy.ServicePortName{
   261  		NamespacedName: makeNSN("ns1", "svc1"),
   262  		Port:           "p80",
   263  		Protocol:       v1.ProtocolTCP,
   264  	}
   265  
   266  	makeServiceMap(proxier,
   267  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   268  			svc.Spec.Type = "NodePort"
   269  			svc.Spec.ClusterIP = svcIP
   270  			svc.Spec.Ports = []v1.ServicePort{{
   271  				Name:     svcPortName.Port,
   272  				Port:     int32(svcPort),
   273  				Protocol: v1.ProtocolTCP,
   274  				NodePort: int32(svcNodePort),
   275  			}}
   276  		}),
   277  	)
   278  	populateEndpointSlices(proxier,
   279  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
   280  			eps.AddressType = discovery.AddressTypeIPv4
   281  			eps.Endpoints = []discovery.Endpoint{{
   282  				Addresses: []string{epIpAddressRemote},
   283  			}}
   284  			eps.Ports = []discovery.EndpointPort{{
   285  				Name:     ptr.To(svcPortName.Port),
   286  				Port:     ptr.To(int32(svcPort)),
   287  				Protocol: ptr.To(v1.ProtocolTCP),
   288  			}}
   289  		}),
   290  	)
   291  	proxier.setInitialized(true)
   292  	proxier.syncProxyRules()
   293  	ep := proxier.endpointsMap[svcPortName][0]
   294  	epInfo, ok := ep.(*endpointInfo)
   295  	if !ok {
   296  		t.Errorf("Failed to cast endpointInfo %q", svcPortName.String())
   297  
   298  	} else {
   299  		if epInfo.hnsID != endpointGuid1 {
   300  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   301  		}
   302  	}
   303  
   304  	if *proxier.endPointsRefCount[endpointGuid1] <= 0 {
   305  		t.Errorf("RefCount not incremented. Current value: %v", *proxier.endPointsRefCount[endpointGuid1])
   306  	}
   307  
   308  	if *proxier.endPointsRefCount[endpointGuid1] != *epInfo.refCount {
   309  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   310  	}
   311  }
   312  func TestSharedRemoteEndpointDelete(t *testing.T) {
   313  	syncPeriod := 30 * time.Second
   314  	proxier := NewFakeProxier(syncPeriod, syncPeriod, "testhost", netutils.ParseIPSloppy("10.0.0.1"), "L2Bridge")
   315  	if proxier == nil {
   316  		t.Error()
   317  	}
   318  
   319  	svcIP1 := "10.20.30.41"
   320  	svcPort1 := 80
   321  	svcNodePort1 := 3001
   322  	svcPortName1 := proxy.ServicePortName{
   323  		NamespacedName: makeNSN("ns1", "svc1"),
   324  		Port:           "p80",
   325  		Protocol:       v1.ProtocolTCP,
   326  	}
   327  
   328  	svcIP2 := "10.20.30.42"
   329  	svcPort2 := 80
   330  	svcNodePort2 := 3002
   331  	svcPortName2 := proxy.ServicePortName{
   332  		NamespacedName: makeNSN("ns1", "svc2"),
   333  		Port:           "p80",
   334  		Protocol:       v1.ProtocolTCP,
   335  	}
   336  
   337  	makeServiceMap(proxier,
   338  		makeTestService(svcPortName1.Namespace, svcPortName1.Name, func(svc *v1.Service) {
   339  			svc.Spec.Type = "NodePort"
   340  			svc.Spec.ClusterIP = svcIP1
   341  			svc.Spec.Ports = []v1.ServicePort{{
   342  				Name:     svcPortName1.Port,
   343  				Port:     int32(svcPort1),
   344  				Protocol: v1.ProtocolTCP,
   345  				NodePort: int32(svcNodePort1),
   346  			}}
   347  		}),
   348  		makeTestService(svcPortName2.Namespace, svcPortName2.Name, func(svc *v1.Service) {
   349  			svc.Spec.Type = "NodePort"
   350  			svc.Spec.ClusterIP = svcIP2
   351  			svc.Spec.Ports = []v1.ServicePort{{
   352  				Name:     svcPortName2.Port,
   353  				Port:     int32(svcPort2),
   354  				Protocol: v1.ProtocolTCP,
   355  				NodePort: int32(svcNodePort2),
   356  			}}
   357  		}),
   358  	)
   359  	populateEndpointSlices(proxier,
   360  		makeTestEndpointSlice(svcPortName1.Namespace, svcPortName1.Name, 1, func(eps *discovery.EndpointSlice) {
   361  			eps.AddressType = discovery.AddressTypeIPv4
   362  			eps.Endpoints = []discovery.Endpoint{{
   363  				Addresses: []string{epIpAddressRemote},
   364  			}}
   365  			eps.Ports = []discovery.EndpointPort{{
   366  				Name:     ptr.To(svcPortName1.Port),
   367  				Port:     ptr.To(int32(svcPort1)),
   368  				Protocol: ptr.To(v1.ProtocolTCP),
   369  			}}
   370  		}),
   371  		makeTestEndpointSlice(svcPortName2.Namespace, svcPortName2.Name, 1, func(eps *discovery.EndpointSlice) {
   372  			eps.AddressType = discovery.AddressTypeIPv4
   373  			eps.Endpoints = []discovery.Endpoint{{
   374  				Addresses: []string{epIpAddressRemote},
   375  			}}
   376  			eps.Ports = []discovery.EndpointPort{{
   377  				Name:     ptr.To(svcPortName2.Port),
   378  				Port:     ptr.To(int32(svcPort2)),
   379  				Protocol: ptr.To(v1.ProtocolTCP),
   380  			}}
   381  		}),
   382  	)
   383  	proxier.setInitialized(true)
   384  	proxier.syncProxyRules()
   385  	ep := proxier.endpointsMap[svcPortName1][0]
   386  	epInfo, ok := ep.(*endpointInfo)
   387  	if !ok {
   388  		t.Errorf("Failed to cast endpointInfo %q", svcPortName1.String())
   389  
   390  	} else {
   391  		if epInfo.hnsID != endpointGuid1 {
   392  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   393  		}
   394  	}
   395  
   396  	if *proxier.endPointsRefCount[endpointGuid1] != 2 {
   397  		t.Errorf("RefCount not incremented. Current value: %v", *proxier.endPointsRefCount[endpointGuid1])
   398  	}
   399  
   400  	if *proxier.endPointsRefCount[endpointGuid1] != *epInfo.refCount {
   401  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   402  	}
   403  
   404  	proxier.setInitialized(false)
   405  	deleteServices(proxier,
   406  		makeTestService(svcPortName2.Namespace, svcPortName2.Name, func(svc *v1.Service) {
   407  			svc.Spec.Type = "NodePort"
   408  			svc.Spec.ClusterIP = svcIP2
   409  			svc.Spec.Ports = []v1.ServicePort{{
   410  				Name:     svcPortName2.Port,
   411  				Port:     int32(svcPort2),
   412  				Protocol: v1.ProtocolTCP,
   413  				NodePort: int32(svcNodePort2),
   414  			}}
   415  		}),
   416  	)
   417  
   418  	deleteEndpointSlices(proxier,
   419  		makeTestEndpointSlice(svcPortName2.Namespace, svcPortName2.Name, 1, func(eps *discovery.EndpointSlice) {
   420  			eps.AddressType = discovery.AddressTypeIPv4
   421  			eps.Endpoints = []discovery.Endpoint{{
   422  				Addresses: []string{epIpAddressRemote},
   423  			}}
   424  			eps.Ports = []discovery.EndpointPort{{
   425  				Name:     ptr.To(svcPortName2.Port),
   426  				Port:     ptr.To(int32(svcPort2)),
   427  				Protocol: ptr.To(v1.ProtocolTCP),
   428  			}}
   429  		}),
   430  	)
   431  
   432  	proxier.setInitialized(true)
   433  	proxier.syncProxyRules()
   434  
   435  	ep = proxier.endpointsMap[svcPortName1][0]
   436  	epInfo, ok = ep.(*endpointInfo)
   437  	if !ok {
   438  		t.Errorf("Failed to cast endpointInfo %q", svcPortName1.String())
   439  
   440  	} else {
   441  		if epInfo.hnsID != endpointGuid1 {
   442  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   443  		}
   444  	}
   445  
   446  	if *epInfo.refCount != 1 {
   447  		t.Errorf("Incorrect Refcount. Current value: %v", *epInfo.refCount)
   448  	}
   449  
   450  	if *proxier.endPointsRefCount[endpointGuid1] != *epInfo.refCount {
   451  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   452  	}
   453  }
   454  func TestSharedRemoteEndpointUpdate(t *testing.T) {
   455  	syncPeriod := 30 * time.Second
   456  	proxier := NewFakeProxier(syncPeriod, syncPeriod, "testhost", netutils.ParseIPSloppy("10.0.0.1"), "L2Bridge")
   457  	if proxier == nil {
   458  		t.Error()
   459  	}
   460  
   461  	svcIP1 := "10.20.30.41"
   462  	svcPort1 := 80
   463  	svcNodePort1 := 3001
   464  	svcPortName1 := proxy.ServicePortName{
   465  		NamespacedName: makeNSN("ns1", "svc1"),
   466  		Port:           "p80",
   467  		Protocol:       v1.ProtocolTCP,
   468  	}
   469  
   470  	svcIP2 := "10.20.30.42"
   471  	svcPort2 := 80
   472  	svcNodePort2 := 3002
   473  	svcPortName2 := proxy.ServicePortName{
   474  		NamespacedName: makeNSN("ns1", "svc2"),
   475  		Port:           "p80",
   476  		Protocol:       v1.ProtocolTCP,
   477  	}
   478  
   479  	makeServiceMap(proxier,
   480  		makeTestService(svcPortName1.Namespace, svcPortName1.Name, func(svc *v1.Service) {
   481  			svc.Spec.Type = "NodePort"
   482  			svc.Spec.ClusterIP = svcIP1
   483  			svc.Spec.Ports = []v1.ServicePort{{
   484  				Name:     svcPortName1.Port,
   485  				Port:     int32(svcPort1),
   486  				Protocol: v1.ProtocolTCP,
   487  				NodePort: int32(svcNodePort1),
   488  			}}
   489  		}),
   490  		makeTestService(svcPortName2.Namespace, svcPortName2.Name, func(svc *v1.Service) {
   491  			svc.Spec.Type = "NodePort"
   492  			svc.Spec.ClusterIP = svcIP2
   493  			svc.Spec.Ports = []v1.ServicePort{{
   494  				Name:     svcPortName2.Port,
   495  				Port:     int32(svcPort2),
   496  				Protocol: v1.ProtocolTCP,
   497  				NodePort: int32(svcNodePort2),
   498  			}}
   499  		}),
   500  	)
   501  
   502  	populateEndpointSlices(proxier,
   503  		makeTestEndpointSlice(svcPortName1.Namespace, svcPortName1.Name, 1, func(eps *discovery.EndpointSlice) {
   504  			eps.AddressType = discovery.AddressTypeIPv4
   505  			eps.Endpoints = []discovery.Endpoint{{
   506  				Addresses: []string{epIpAddressRemote},
   507  			}}
   508  			eps.Ports = []discovery.EndpointPort{{
   509  				Name:     ptr.To(svcPortName1.Port),
   510  				Port:     ptr.To(int32(svcPort1)),
   511  				Protocol: ptr.To(v1.ProtocolTCP),
   512  			}}
   513  		}),
   514  		makeTestEndpointSlice(svcPortName2.Namespace, svcPortName2.Name, 1, func(eps *discovery.EndpointSlice) {
   515  			eps.AddressType = discovery.AddressTypeIPv4
   516  			eps.Endpoints = []discovery.Endpoint{{
   517  				Addresses: []string{epIpAddressRemote},
   518  			}}
   519  			eps.Ports = []discovery.EndpointPort{{
   520  				Name:     ptr.To(svcPortName2.Port),
   521  				Port:     ptr.To(int32(svcPort2)),
   522  				Protocol: ptr.To(v1.ProtocolTCP),
   523  			}}
   524  		}),
   525  	)
   526  
   527  	proxier.setInitialized(true)
   528  	proxier.syncProxyRules()
   529  	ep := proxier.endpointsMap[svcPortName1][0]
   530  	epInfo, ok := ep.(*endpointInfo)
   531  	if !ok {
   532  		t.Errorf("Failed to cast endpointInfo %q", svcPortName1.String())
   533  
   534  	} else {
   535  		if epInfo.hnsID != endpointGuid1 {
   536  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   537  		}
   538  	}
   539  
   540  	if *proxier.endPointsRefCount[endpointGuid1] != 2 {
   541  		t.Errorf("RefCount not incremented. Current value: %v", *proxier.endPointsRefCount[endpointGuid1])
   542  	}
   543  
   544  	if *proxier.endPointsRefCount[endpointGuid1] != *epInfo.refCount {
   545  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   546  	}
   547  
   548  	proxier.setInitialized(false)
   549  
   550  	proxier.OnServiceUpdate(
   551  		makeTestService(svcPortName1.Namespace, svcPortName1.Name, func(svc *v1.Service) {
   552  			svc.Spec.Type = "NodePort"
   553  			svc.Spec.ClusterIP = svcIP1
   554  			svc.Spec.Ports = []v1.ServicePort{{
   555  				Name:     svcPortName1.Port,
   556  				Port:     int32(svcPort1),
   557  				Protocol: v1.ProtocolTCP,
   558  				NodePort: int32(svcNodePort1),
   559  			}}
   560  		}),
   561  		makeTestService(svcPortName1.Namespace, svcPortName1.Name, func(svc *v1.Service) {
   562  			svc.Spec.Type = "NodePort"
   563  			svc.Spec.ClusterIP = svcIP1
   564  			svc.Spec.Ports = []v1.ServicePort{{
   565  				Name:     svcPortName1.Port,
   566  				Port:     int32(svcPort1),
   567  				Protocol: v1.ProtocolTCP,
   568  				NodePort: int32(3003),
   569  			}}
   570  		}))
   571  
   572  	proxier.OnEndpointSliceUpdate(
   573  		makeTestEndpointSlice(svcPortName1.Namespace, svcPortName1.Name, 1, func(eps *discovery.EndpointSlice) {
   574  			eps.AddressType = discovery.AddressTypeIPv4
   575  			eps.Endpoints = []discovery.Endpoint{{
   576  				Addresses: []string{epIpAddressRemote},
   577  			}}
   578  			eps.Ports = []discovery.EndpointPort{{
   579  				Name:     ptr.To(svcPortName1.Port),
   580  				Port:     ptr.To(int32(svcPort1)),
   581  				Protocol: ptr.To(v1.ProtocolTCP),
   582  			}}
   583  		}),
   584  		makeTestEndpointSlice(svcPortName1.Namespace, svcPortName1.Name, 1, func(eps *discovery.EndpointSlice) {
   585  			eps.AddressType = discovery.AddressTypeIPv4
   586  			eps.Endpoints = []discovery.Endpoint{{
   587  				Addresses: []string{epIpAddressRemote},
   588  			}}
   589  			eps.Ports = []discovery.EndpointPort{{
   590  				Name:     ptr.To(svcPortName1.Port),
   591  				Port:     ptr.To(int32(svcPort1)),
   592  				Protocol: ptr.To(v1.ProtocolTCP),
   593  			},
   594  				{
   595  					Name:     ptr.To("p443"),
   596  					Port:     ptr.To[int32](443),
   597  					Protocol: ptr.To(v1.ProtocolTCP),
   598  				}}
   599  		}))
   600  
   601  	proxier.mu.Lock()
   602  	proxier.endpointSlicesSynced = true
   603  	proxier.mu.Unlock()
   604  
   605  	proxier.setInitialized(true)
   606  	proxier.syncProxyRules()
   607  
   608  	ep = proxier.endpointsMap[svcPortName1][0]
   609  	epInfo, ok = ep.(*endpointInfo)
   610  
   611  	if !ok {
   612  		t.Errorf("Failed to cast endpointInfo %q", svcPortName1.String())
   613  
   614  	} else {
   615  		if epInfo.hnsID != endpointGuid1 {
   616  			t.Errorf("%v does not match %v", epInfo.hnsID, endpointGuid1)
   617  		}
   618  	}
   619  
   620  	if *epInfo.refCount != 2 {
   621  		t.Errorf("Incorrect refcount. Current value: %v", *epInfo.refCount)
   622  	}
   623  
   624  	if *proxier.endPointsRefCount[endpointGuid1] != *epInfo.refCount {
   625  		t.Errorf("Global refCount: %v does not match endpoint refCount: %v", *proxier.endPointsRefCount[endpointGuid1], *epInfo.refCount)
   626  	}
   627  }
   628  func TestCreateLoadBalancer(t *testing.T) {
   629  	syncPeriod := 30 * time.Second
   630  	proxier := NewFakeProxier(syncPeriod, syncPeriod, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   631  	if proxier == nil {
   632  		t.Error()
   633  	}
   634  
   635  	svcIP := "10.20.30.41"
   636  	svcPort := 80
   637  	svcNodePort := 3001
   638  	svcPortName := proxy.ServicePortName{
   639  		NamespacedName: makeNSN("ns1", "svc1"),
   640  		Port:           "p80",
   641  		Protocol:       v1.ProtocolTCP,
   642  	}
   643  
   644  	makeServiceMap(proxier,
   645  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   646  			svc.Spec.Type = "NodePort"
   647  			svc.Spec.ClusterIP = svcIP
   648  			svc.Spec.Ports = []v1.ServicePort{{
   649  				Name:     svcPortName.Port,
   650  				Port:     int32(svcPort),
   651  				Protocol: v1.ProtocolTCP,
   652  				NodePort: int32(svcNodePort),
   653  			}}
   654  		}),
   655  	)
   656  	populateEndpointSlices(proxier,
   657  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
   658  			eps.AddressType = discovery.AddressTypeIPv4
   659  			eps.Endpoints = []discovery.Endpoint{{
   660  				Addresses: []string{epIpAddressRemote},
   661  			}}
   662  			eps.Ports = []discovery.EndpointPort{{
   663  				Name:     ptr.To(svcPortName.Port),
   664  				Port:     ptr.To(int32(svcPort)),
   665  				Protocol: ptr.To(v1.ProtocolTCP),
   666  			}}
   667  		}),
   668  	)
   669  
   670  	proxier.setInitialized(true)
   671  	proxier.syncProxyRules()
   672  
   673  	svc := proxier.svcPortMap[svcPortName]
   674  	svcInfo, ok := svc.(*serviceInfo)
   675  	if !ok {
   676  		t.Errorf("Failed to cast serviceInfo %q", svcPortName.String())
   677  
   678  	} else {
   679  		if svcInfo.hnsID != loadbalancerGuid1 {
   680  			t.Errorf("%v does not match %v", svcInfo.hnsID, loadbalancerGuid1)
   681  		}
   682  	}
   683  }
   684  
   685  func TestCreateDsrLoadBalancer(t *testing.T) {
   686  	syncPeriod := 30 * time.Second
   687  	proxier := NewFakeProxier(syncPeriod, syncPeriod, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   688  	if proxier == nil {
   689  		t.Error()
   690  	}
   691  
   692  	svcIP := "10.20.30.41"
   693  	svcPort := 80
   694  	svcNodePort := 3001
   695  	svcPortName := proxy.ServicePortName{
   696  		NamespacedName: makeNSN("ns1", "svc1"),
   697  		Port:           "p80",
   698  		Protocol:       v1.ProtocolTCP,
   699  	}
   700  	lbIP := "11.21.31.41"
   701  
   702  	makeServiceMap(proxier,
   703  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   704  			svc.Spec.Type = "NodePort"
   705  			svc.Spec.ClusterIP = svcIP
   706  			svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
   707  			svc.Spec.Ports = []v1.ServicePort{{
   708  				Name:     svcPortName.Port,
   709  				Port:     int32(svcPort),
   710  				Protocol: v1.ProtocolTCP,
   711  				NodePort: int32(svcNodePort),
   712  			}}
   713  			svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
   714  				IP: lbIP,
   715  			}}
   716  		}),
   717  	)
   718  	populateEndpointSlices(proxier,
   719  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
   720  			eps.AddressType = discovery.AddressTypeIPv4
   721  			eps.Endpoints = []discovery.Endpoint{{
   722  				Addresses: []string{epIpAddressRemote},
   723  				NodeName:  ptr.To("testhost"),
   724  			}}
   725  			eps.Ports = []discovery.EndpointPort{{
   726  				Name:     ptr.To(svcPortName.Port),
   727  				Port:     ptr.To(int32(svcPort)),
   728  				Protocol: ptr.To(v1.ProtocolTCP),
   729  			}}
   730  		}),
   731  	)
   732  
   733  	hcn := (proxier.hcn).(*fakehcn.HcnMock)
   734  	proxier.rootHnsEndpointName = endpointGw
   735  	hcn.PopulateQueriedEndpoints(endpointLocal, guid, epIpAddressRemote, macAddress, prefixLen)
   736  	hcn.PopulateQueriedEndpoints(endpointGw, guid, epIpAddressGw, epMacAddressGw, prefixLen)
   737  	proxier.setInitialized(true)
   738  	proxier.syncProxyRules()
   739  
   740  	svc := proxier.svcPortMap[svcPortName]
   741  	svcInfo, ok := svc.(*serviceInfo)
   742  	if !ok {
   743  		t.Errorf("Failed to cast serviceInfo %q", svcPortName.String())
   744  
   745  	} else {
   746  		if svcInfo.hnsID != loadbalancerGuid1 {
   747  			t.Errorf("%v does not match %v", svcInfo.hnsID, loadbalancerGuid1)
   748  		}
   749  		if svcInfo.localTrafficDSR != true {
   750  			t.Errorf("Failed to create DSR loadbalancer with local traffic policy")
   751  		}
   752  		if len(svcInfo.loadBalancerIngressIPs) == 0 {
   753  			t.Errorf("svcInfo does not have any loadBalancerIngressIPs, %+v", svcInfo)
   754  		} else if svcInfo.loadBalancerIngressIPs[0].healthCheckHnsID != "LBID-4" {
   755  			t.Errorf("The Hns Loadbalancer HealthCheck Id %v does not match %v. ServicePortName %q", svcInfo.loadBalancerIngressIPs[0].healthCheckHnsID, loadbalancerGuid1, svcPortName.String())
   756  		}
   757  	}
   758  }
   759  
   760  // TestClusterIPLBInCreateDsrLoadBalancer tests, if the available endpoints are remote,
   761  // syncproxyrules only creates ClusterIP Loadbalancer and no NodePort, External IP or IngressIP
   762  // loadbalancers will be created.
   763  func TestClusterIPLBInCreateDsrLoadBalancer(t *testing.T) {
   764  	syncPeriod := 30 * time.Second
   765  	proxier := NewFakeProxier(syncPeriod, syncPeriod, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   766  
   767  	if proxier == nil {
   768  		t.Error()
   769  	}
   770  
   771  	svcIP := "10.20.30.41"
   772  	svcPort := 80
   773  	svcNodePort := 3001
   774  	svcPortName := proxy.ServicePortName{
   775  		NamespacedName: makeNSN("ns1", "svc1"),
   776  		Port:           "p80",
   777  		Protocol:       v1.ProtocolTCP,
   778  	}
   779  	lbIP := "11.21.31.41"
   780  
   781  	makeServiceMap(proxier,
   782  		makeTestService(svcPortName.Namespace, svcPortName.Name, func(svc *v1.Service) {
   783  			svc.Spec.Type = "NodePort"
   784  			svc.Spec.ClusterIP = svcIP
   785  			svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
   786  			svc.Spec.Ports = []v1.ServicePort{{
   787  				Name:     svcPortName.Port,
   788  				Port:     int32(svcPort),
   789  				Protocol: v1.ProtocolTCP,
   790  				NodePort: int32(svcNodePort),
   791  			}}
   792  			svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{
   793  				IP: lbIP,
   794  			}}
   795  		}),
   796  	)
   797  	populateEndpointSlices(proxier,
   798  		makeTestEndpointSlice(svcPortName.Namespace, svcPortName.Name, 1, func(eps *discovery.EndpointSlice) {
   799  			eps.AddressType = discovery.AddressTypeIPv4
   800  			eps.Endpoints = []discovery.Endpoint{{
   801  				Addresses: []string{epIpAddressRemote},
   802  				NodeName:  ptr.To("testhost2"), // This will make this endpoint as a remote endpoint
   803  			}}
   804  			eps.Ports = []discovery.EndpointPort{{
   805  				Name:     ptr.To(svcPortName.Port),
   806  				Port:     ptr.To(int32(svcPort)),
   807  				Protocol: ptr.To(v1.ProtocolTCP),
   808  			}}
   809  		}),
   810  	)
   811  
   812  	proxier.setInitialized(true)
   813  	proxier.syncProxyRules()
   814  
   815  	svc := proxier.svcPortMap[svcPortName]
   816  	svcInfo, ok := svc.(*serviceInfo)
   817  	if !ok {
   818  		t.Errorf("Failed to cast serviceInfo %q", svcPortName.String())
   819  
   820  	} else {
   821  		// Checking ClusterIP Loadbalancer is created
   822  		if svcInfo.hnsID != loadbalancerGuid1 {
   823  			t.Errorf("%v does not match %v", svcInfo.hnsID, loadbalancerGuid1)
   824  		}
   825  		// Verifying NodePort Loadbalancer is not created
   826  		if svcInfo.nodePorthnsID != "" {
   827  			t.Errorf("NodePortHnsID %v is not empty.", svcInfo.nodePorthnsID)
   828  		}
   829  		// Verifying ExternalIP Loadbalancer is not created
   830  		for _, externalIP := range svcInfo.externalIPs {
   831  			if externalIP.hnsID != "" {
   832  				t.Errorf("ExternalLBID %v is not empty.", externalIP.hnsID)
   833  			}
   834  		}
   835  		// Verifying IngressIP Loadbalancer is not created
   836  		for _, ingressIP := range svcInfo.loadBalancerIngressIPs {
   837  			if ingressIP.hnsID != "" {
   838  				t.Errorf("IngressLBID %v is not empty.", ingressIP.hnsID)
   839  			}
   840  		}
   841  	}
   842  }
   843  
   844  func TestEndpointSlice(t *testing.T) {
   845  	syncPeriod := 30 * time.Second
   846  	proxier := NewFakeProxier(syncPeriod, syncPeriod, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   847  	if proxier == nil {
   848  		t.Error()
   849  	}
   850  
   851  	proxier.servicesSynced = true
   852  	proxier.endpointSlicesSynced = true
   853  
   854  	svcPortName := proxy.ServicePortName{
   855  		NamespacedName: makeNSN("ns1", "svc1"),
   856  		Port:           "p80",
   857  		Protocol:       v1.ProtocolTCP,
   858  	}
   859  
   860  	proxier.OnServiceAdd(&v1.Service{
   861  		ObjectMeta: metav1.ObjectMeta{Name: svcPortName.Name, Namespace: svcPortName.Namespace},
   862  		Spec: v1.ServiceSpec{
   863  			ClusterIP: "172.20.1.1",
   864  			Selector:  map[string]string{"foo": "bar"},
   865  			Ports:     []v1.ServicePort{{Name: svcPortName.Port, TargetPort: intstr.FromInt32(80), Protocol: v1.ProtocolTCP}},
   866  		},
   867  	})
   868  
   869  	// Add initial endpoint slice
   870  	endpointSlice := &discovery.EndpointSlice{
   871  		ObjectMeta: metav1.ObjectMeta{
   872  			Name:      fmt.Sprintf("%s-1", svcPortName.Name),
   873  			Namespace: svcPortName.Namespace,
   874  			Labels:    map[string]string{discovery.LabelServiceName: svcPortName.Name},
   875  		},
   876  		Ports: []discovery.EndpointPort{{
   877  			Name:     &svcPortName.Port,
   878  			Port:     ptr.To[int32](80),
   879  			Protocol: ptr.To(v1.ProtocolTCP),
   880  		}},
   881  		AddressType: discovery.AddressTypeIPv4,
   882  		Endpoints: []discovery.Endpoint{{
   883  			Addresses:  []string{"192.168.2.3"},
   884  			Conditions: discovery.EndpointConditions{Ready: ptr.To(true)},
   885  			NodeName:   ptr.To("testhost2"),
   886  		}},
   887  	}
   888  
   889  	proxier.OnEndpointSliceAdd(endpointSlice)
   890  	proxier.setInitialized(true)
   891  	proxier.syncProxyRules()
   892  
   893  	svc := proxier.svcPortMap[svcPortName]
   894  	svcInfo, ok := svc.(*serviceInfo)
   895  	if !ok {
   896  		t.Errorf("Failed to cast serviceInfo %q", svcPortName.String())
   897  
   898  	} else {
   899  		if svcInfo.hnsID != loadbalancerGuid1 {
   900  			t.Errorf("The Hns Loadbalancer Id %v does not match %v. ServicePortName %q", svcInfo.hnsID, loadbalancerGuid1, svcPortName.String())
   901  		}
   902  	}
   903  
   904  	ep := proxier.endpointsMap[svcPortName][0]
   905  	epInfo, ok := ep.(*endpointInfo)
   906  	if !ok {
   907  		t.Errorf("Failed to cast endpointInfo %q", svcPortName.String())
   908  
   909  	} else {
   910  		if epInfo.hnsID != "EPID-3" {
   911  			t.Errorf("Hns EndpointId %v does not match %v. ServicePortName %q", epInfo.hnsID, endpointGuid1, svcPortName.String())
   912  		}
   913  	}
   914  }
   915  
   916  func TestNoopEndpointSlice(t *testing.T) {
   917  	p := Proxier{}
   918  	p.OnEndpointSliceAdd(&discovery.EndpointSlice{})
   919  	p.OnEndpointSliceUpdate(&discovery.EndpointSlice{}, &discovery.EndpointSlice{})
   920  	p.OnEndpointSliceDelete(&discovery.EndpointSlice{})
   921  	p.OnEndpointSlicesSynced()
   922  }
   923  
   924  func TestFindRemoteSubnetProviderAddress(t *testing.T) {
   925  	syncPeriod := 30 * time.Second
   926  	proxier := NewFakeProxier(syncPeriod, syncPeriod, "testhost", netutils.ParseIPSloppy("10.0.0.1"), NETWORK_TYPE_OVERLAY)
   927  	if proxier == nil {
   928  		t.Error()
   929  	}
   930  
   931  	networkInfo, _ := proxier.hns.getNetworkByName(testNetwork)
   932  	pa := networkInfo.findRemoteSubnetProviderAddress(providerAddress)
   933  
   934  	if pa != providerAddress {
   935  		t.Errorf("%v does not match %v", pa, providerAddress)
   936  	}
   937  
   938  	pa = networkInfo.findRemoteSubnetProviderAddress(epIpAddressRemote)
   939  
   940  	if pa != providerAddress {
   941  		t.Errorf("%v does not match %v", pa, providerAddress)
   942  	}
   943  
   944  	pa = networkInfo.findRemoteSubnetProviderAddress(serviceVip)
   945  
   946  	if len(pa) != 0 {
   947  		t.Errorf("Provider address is not empty as expected")
   948  	}
   949  }
   950  
   951  func makeNSN(namespace, name string) types.NamespacedName {
   952  	return types.NamespacedName{Namespace: namespace, Name: name}
   953  }
   954  
   955  func makeServiceMap(proxier *Proxier, allServices ...*v1.Service) {
   956  	for i := range allServices {
   957  		proxier.OnServiceAdd(allServices[i])
   958  	}
   959  
   960  	proxier.mu.Lock()
   961  	defer proxier.mu.Unlock()
   962  	proxier.servicesSynced = true
   963  }
   964  func deleteServices(proxier *Proxier, allServices ...*v1.Service) {
   965  	for i := range allServices {
   966  		proxier.OnServiceDelete(allServices[i])
   967  	}
   968  
   969  	proxier.mu.Lock()
   970  	defer proxier.mu.Unlock()
   971  	proxier.servicesSynced = true
   972  }
   973  
   974  func makeTestService(namespace, name string, svcFunc func(*v1.Service)) *v1.Service {
   975  	svc := &v1.Service{
   976  		ObjectMeta: metav1.ObjectMeta{
   977  			Name:        name,
   978  			Namespace:   namespace,
   979  			Annotations: map[string]string{},
   980  		},
   981  		Spec:   v1.ServiceSpec{},
   982  		Status: v1.ServiceStatus{},
   983  	}
   984  	svcFunc(svc)
   985  	return svc
   986  }
   987  
   988  func deleteEndpointSlices(proxier *Proxier, allEndpointSlices ...*discovery.EndpointSlice) {
   989  	for i := range allEndpointSlices {
   990  		proxier.OnEndpointSliceDelete(allEndpointSlices[i])
   991  	}
   992  
   993  	proxier.mu.Lock()
   994  	defer proxier.mu.Unlock()
   995  	proxier.endpointSlicesSynced = true
   996  }
   997  
   998  func populateEndpointSlices(proxier *Proxier, allEndpointSlices ...*discovery.EndpointSlice) {
   999  	for i := range allEndpointSlices {
  1000  		proxier.OnEndpointSliceAdd(allEndpointSlices[i])
  1001  	}
  1002  }
  1003  
  1004  func makeTestEndpointSlice(namespace, name string, sliceNum int, epsFunc func(*discovery.EndpointSlice)) *discovery.EndpointSlice {
  1005  	eps := &discovery.EndpointSlice{
  1006  		ObjectMeta: metav1.ObjectMeta{
  1007  			Name:      fmt.Sprintf("%s-%d", name, sliceNum),
  1008  			Namespace: namespace,
  1009  			Labels:    map[string]string{discovery.LabelServiceName: name},
  1010  		},
  1011  	}
  1012  	epsFunc(eps)
  1013  	return eps
  1014  }
  1015  

View as plain text