mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Merge pull request #92109 from kishorj/nlb_udp_support
Allow UDP for AWS NLB
This commit is contained in:
		@@ -3691,9 +3691,10 @@ func (c *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, apiS
 | 
			
		||||
 | 
			
		||||
	sslPorts := getPortSets(annotations[ServiceAnnotationLoadBalancerSSLPorts])
 | 
			
		||||
	for _, port := range apiService.Spec.Ports {
 | 
			
		||||
		if port.Protocol != v1.ProtocolTCP {
 | 
			
		||||
			return nil, fmt.Errorf("Only TCP LoadBalancer is supported for AWS ELB")
 | 
			
		||||
		if err := checkProtocol(port, annotations); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if port.NodePort == 0 {
 | 
			
		||||
			klog.Errorf("Ignoring port without NodePort defined: %v", port)
 | 
			
		||||
			continue
 | 
			
		||||
@@ -3713,7 +3714,7 @@ func (c *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, apiS
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			certificateARN := annotations[ServiceAnnotationLoadBalancerCertificate]
 | 
			
		||||
			if certificateARN != "" && (sslPorts == nil || sslPorts.numbers.Has(int64(port.Port)) || sslPorts.names.Has(port.Name)) {
 | 
			
		||||
			if port.Protocol != v1.ProtocolUDP && certificateARN != "" && (sslPorts == nil || sslPorts.numbers.Has(int64(port.Port)) || sslPorts.names.Has(port.Name)) {
 | 
			
		||||
				portMapping.FrontendProtocol = elbv2.ProtocolEnumTls
 | 
			
		||||
				portMapping.SSLCertificateARN = certificateARN
 | 
			
		||||
				portMapping.SSLPolicy = annotations[ServiceAnnotationLoadBalancerSSLNegotiationPolicy]
 | 
			
		||||
@@ -3724,13 +3725,14 @@ func (c *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, apiS
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			v2Mappings = append(v2Mappings, portMapping)
 | 
			
		||||
		}
 | 
			
		||||
		} else {
 | 
			
		||||
			listener, err := buildListener(port, annotations, sslPorts)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			listeners = append(listeners, listener)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if apiService.Spec.LoadBalancerIP != "" {
 | 
			
		||||
		return nil, fmt.Errorf("LoadBalancerIP cannot be specified for AWS ELB")
 | 
			
		||||
@@ -4762,6 +4764,18 @@ func (c *Cloud) nodeNameToProviderID(nodeName types.NodeName) (InstanceID, error
 | 
			
		||||
	return KubernetesInstanceID(node.Spec.ProviderID).MapToAWSInstanceID()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checkProtocol(port v1.ServicePort, annotations map[string]string) error {
 | 
			
		||||
	// nlb supports tcp, udp
 | 
			
		||||
	if isNLB(annotations) && (port.Protocol == v1.ProtocolTCP || port.Protocol == v1.ProtocolUDP) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	// elb only supports tcp
 | 
			
		||||
	if !isNLB(annotations) && port.Protocol == v1.ProtocolTCP {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Errorf("Protocol %s not supported by LoadBalancer", port.Protocol)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setNodeDisk(
 | 
			
		||||
	nodeDiskMap map[types.NodeName]map[KubernetesVolumeID]bool,
 | 
			
		||||
	volumeID KubernetesVolumeID,
 | 
			
		||||
 
 | 
			
		||||
@@ -185,9 +185,12 @@ func (c *Cloud) ensureLoadBalancerv2(namespacedName types.NamespacedName, loadBa
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// actual maps FrontendPort to an elbv2.Listener
 | 
			
		||||
			actual := map[int64]*elbv2.Listener{}
 | 
			
		||||
			actual := map[int64]map[string]*elbv2.Listener{}
 | 
			
		||||
			for _, listener := range listenerDescriptions.Listeners {
 | 
			
		||||
				actual[*listener.Port] = listener
 | 
			
		||||
				if actual[*listener.Port] == nil {
 | 
			
		||||
					actual[*listener.Port] = map[string]*elbv2.Listener{}
 | 
			
		||||
				}
 | 
			
		||||
				actual[*listener.Port][*listener.Protocol] = listener
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			actualTargetGroups, err := c.elbv2.DescribeTargetGroups(
 | 
			
		||||
@@ -207,10 +210,11 @@ func (c *Cloud) ensureLoadBalancerv2(namespacedName types.NamespacedName, loadBa
 | 
			
		||||
			// Handle additions/modifications
 | 
			
		||||
			for _, mapping := range mappings {
 | 
			
		||||
				frontendPort := mapping.FrontendPort
 | 
			
		||||
				frontendProtocol := mapping.FrontendProtocol
 | 
			
		||||
				nodePort := mapping.TrafficPort
 | 
			
		||||
 | 
			
		||||
				// modifications
 | 
			
		||||
				if listener, ok := actual[frontendPort]; ok {
 | 
			
		||||
				if listener, ok := actual[frontendPort][frontendProtocol]; ok {
 | 
			
		||||
					listenerNeedsModification := false
 | 
			
		||||
 | 
			
		||||
					if aws.StringValue(listener.Protocol) != mapping.FrontendProtocol {
 | 
			
		||||
@@ -315,15 +319,19 @@ func (c *Cloud) ensureLoadBalancerv2(namespacedName types.NamespacedName, loadBa
 | 
			
		||||
				dirty = true
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			frontEndPorts := map[int64]bool{}
 | 
			
		||||
			frontEndPorts := map[int64]map[string]bool{}
 | 
			
		||||
			for i := range mappings {
 | 
			
		||||
				frontEndPorts[mappings[i].FrontendPort] = true
 | 
			
		||||
				if frontEndPorts[mappings[i].FrontendPort] == nil {
 | 
			
		||||
					frontEndPorts[mappings[i].FrontendPort] = map[string]bool{}
 | 
			
		||||
				}
 | 
			
		||||
				frontEndPorts[mappings[i].FrontendPort][mappings[i].FrontendProtocol] = true
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// handle deletions
 | 
			
		||||
			for port, listener := range actual {
 | 
			
		||||
				if _, ok := frontEndPorts[port]; !ok {
 | 
			
		||||
					err := c.deleteListenerV2(listener)
 | 
			
		||||
			for port := range actual {
 | 
			
		||||
				for protocol := range actual[port] {
 | 
			
		||||
					if _, ok := frontEndPorts[port][protocol]; !ok {
 | 
			
		||||
						err := c.deleteListenerV2(actual[port][protocol])
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							return nil, err
 | 
			
		||||
						}
 | 
			
		||||
@@ -331,7 +339,7 @@ func (c *Cloud) ensureLoadBalancerv2(namespacedName types.NamespacedName, loadBa
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		if err := c.reconcileLBAttributes(aws.StringValue(loadBalancer.LoadBalancerArn), annotations); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
@@ -768,10 +776,14 @@ func (c *Cloud) updateInstanceSecurityGroupsForNLB(lbName string, instances map[
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		clientPorts := sets.Int64{}
 | 
			
		||||
		clientProtocol := "tcp"
 | 
			
		||||
		healthCheckPorts := sets.Int64{}
 | 
			
		||||
		for _, port := range portMappings {
 | 
			
		||||
			clientPorts.Insert(port.TrafficPort)
 | 
			
		||||
			healthCheckPorts.Insert(port.HealthCheckPort)
 | 
			
		||||
			if port.TrafficProtocol == string(v1.ProtocolUDP) {
 | 
			
		||||
				clientProtocol = "udp"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		clientRuleAnnotation := fmt.Sprintf("%s=%s", NLBClientRuleDescription, lbName)
 | 
			
		||||
		healthRuleAnnotation := fmt.Sprintf("%s=%s", NLBHealthCheckRuleDescription, lbName)
 | 
			
		||||
@@ -785,14 +797,14 @@ func (c *Cloud) updateInstanceSecurityGroupsForNLB(lbName string, instances map[
 | 
			
		||||
				if err := c.updateInstanceSecurityGroupForNLBTraffic(sgID, sgPerms, healthRuleAnnotation, "tcp", healthCheckPorts, vpcCIDRs); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if err := c.updateInstanceSecurityGroupForNLBTraffic(sgID, sgPerms, clientRuleAnnotation, "tcp", clientPorts, clientCIDRs); err != nil {
 | 
			
		||||
				if err := c.updateInstanceSecurityGroupForNLBTraffic(sgID, sgPerms, clientRuleAnnotation, clientProtocol, clientPorts, clientCIDRs); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				if err := c.updateInstanceSecurityGroupForNLBTraffic(sgID, sgPerms, healthRuleAnnotation, "tcp", nil, nil); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if err := c.updateInstanceSecurityGroupForNLBTraffic(sgID, sgPerms, clientRuleAnnotation, "tcp", nil, nil); err != nil {
 | 
			
		||||
				if err := c.updateInstanceSecurityGroupForNLBTraffic(sgID, sgPerms, clientRuleAnnotation, clientProtocol, nil, nil); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -1371,6 +1371,53 @@ func TestDescribeLoadBalancerOnEnsure(t *testing.T) {
 | 
			
		||||
	c.EnsureLoadBalancer(context.TODO(), TestClusterName, &v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "myservice", UID: "id"}}, []*v1.Node{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCheckProtocol(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name        string
 | 
			
		||||
		annotations map[string]string
 | 
			
		||||
		port        v1.ServicePort
 | 
			
		||||
		wantErr     error
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name:        "TCP with ELB",
 | 
			
		||||
			annotations: make(map[string]string),
 | 
			
		||||
			port:        v1.ServicePort{Protocol: v1.ProtocolTCP, Port: int32(8080)},
 | 
			
		||||
			wantErr:     nil,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "TCP with NLB",
 | 
			
		||||
			annotations: map[string]string{ServiceAnnotationLoadBalancerType: "nlb"},
 | 
			
		||||
			port:        v1.ServicePort{Protocol: v1.ProtocolTCP, Port: int32(8080)},
 | 
			
		||||
			wantErr:     nil,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "UDP with ELB",
 | 
			
		||||
			annotations: make(map[string]string),
 | 
			
		||||
			port:        v1.ServicePort{Protocol: v1.ProtocolUDP, Port: int32(8080)},
 | 
			
		||||
			wantErr:     fmt.Errorf("Protocol UDP not supported by load balancer"),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "UDP with NLB",
 | 
			
		||||
			annotations: map[string]string{ServiceAnnotationLoadBalancerType: "nlb"},
 | 
			
		||||
			port:        v1.ServicePort{Protocol: v1.ProtocolUDP, Port: int32(8080)},
 | 
			
		||||
			wantErr:     nil,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		tt := test
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			t.Parallel()
 | 
			
		||||
			err := checkProtocol(tt.port, tt.annotations)
 | 
			
		||||
			if tt.wantErr != nil && err == nil {
 | 
			
		||||
				t.Errorf("Expected error: want=%s got =%s", tt.wantErr, err)
 | 
			
		||||
			}
 | 
			
		||||
			if tt.wantErr == nil && err != nil {
 | 
			
		||||
				t.Errorf("Unexpected error: want=%s got =%s", tt.wantErr, err)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestBuildListener(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name string
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user