mirror of https://github.com/kubernetes/kops.git
				
				
				
			Merge pull request #16299 from justinsb/split_out_loadbalancerlistener
Refactor: Split out NLB Listener into its own task
This commit is contained in:
		
						commit
						61842d1e45
					
				|  | @ -21,39 +21,41 @@ import ( | |||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws" | ||||
| 	"github.com/aws/aws-sdk-go/aws/request" | ||||
| 	"github.com/aws/aws-sdk-go/service/elbv2" | ||||
| 	"k8s.io/klog/v2" | ||||
| ) | ||||
| 
 | ||||
| func (m *MockELBV2) DescribeListeners(request *elbv2.DescribeListenersInput) (*elbv2.DescribeListenersOutput, error) { | ||||
| func (m *MockELBV2) DescribeListenersPagesWithContext(ctx aws.Context, request *elbv2.DescribeListenersInput, callback func(*elbv2.DescribeListenersOutput, bool) bool, options ...request.Option) error { | ||||
| 	m.mutex.Lock() | ||||
| 	defer m.mutex.Unlock() | ||||
| 
 | ||||
| 	klog.Infof("DescribeListeners v2 %v", request) | ||||
| 	klog.Infof("DescribeListenersPagesWithContext v2 %v", request) | ||||
| 
 | ||||
| 	resp := &elbv2.DescribeListenersOutput{ | ||||
| 	page := &elbv2.DescribeListenersOutput{ | ||||
| 		Listeners: make([]*elbv2.Listener, 0), | ||||
| 	} | ||||
| 	for _, l := range m.Listeners { | ||||
| 		listener := l.description | ||||
| 		if aws.StringValue(request.LoadBalancerArn) == aws.StringValue(listener.LoadBalancerArn) { | ||||
| 			resp.Listeners = append(resp.Listeners, &listener) | ||||
| 			page.Listeners = append(page.Listeners, &listener) | ||||
| 		} else { | ||||
| 			for _, reqARN := range request.ListenerArns { | ||||
| 				if aws.StringValue(reqARN) == aws.StringValue(listener.ListenerArn) { | ||||
| 					resp.Listeners = append(resp.Listeners, &listener) | ||||
| 					page.Listeners = append(page.Listeners, &listener) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return resp, nil | ||||
| 	callback(page, true) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (m *MockELBV2) CreateListener(request *elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) { | ||||
| func (m *MockELBV2) CreateListenerWithContext(ctx aws.Context, request *elbv2.CreateListenerInput, opts ...request.Option) (*elbv2.CreateListenerOutput, error) { | ||||
| 	m.mutex.Lock() | ||||
| 	defer m.mutex.Unlock() | ||||
| 
 | ||||
| 	klog.Infof("CreateListener v2 %v", request) | ||||
| 	klog.Infof("CreateListenerWithContext v2 %v", request) | ||||
| 
 | ||||
| 	l := elbv2.Listener{ | ||||
| 		DefaultActions:  request.DefaultActions, | ||||
|  | @ -96,11 +98,11 @@ func (m *MockELBV2) CreateListener(request *elbv2.CreateListenerInput) (*elbv2.C | |||
| 	return &elbv2.CreateListenerOutput{Listeners: []*elbv2.Listener{&l}}, nil | ||||
| } | ||||
| 
 | ||||
| func (m *MockELBV2) DeleteListener(request *elbv2.DeleteListenerInput) (*elbv2.DeleteListenerOutput, error) { | ||||
| func (m *MockELBV2) DeleteListenerWithContext(ctx aws.Context, request *elbv2.DeleteListenerInput, opts ...request.Option) (*elbv2.DeleteListenerOutput, error) { | ||||
| 	m.mutex.Lock() | ||||
| 	defer m.mutex.Unlock() | ||||
| 
 | ||||
| 	klog.Infof("DeleteListener v2 %v", request) | ||||
| 	klog.Infof("DeleteListenerWithContext v2 %v", request) | ||||
| 
 | ||||
| 	lARN := aws.StringValue(request.ListenerArn) | ||||
| 	if _, ok := m.Listeners[lARN]; !ok { | ||||
|  |  | |||
|  | @ -134,31 +134,49 @@ func (b *APILoadBalancerBuilder) Build(c *fi.CloudupModelBuilderContext) error { | |||
| 		listeners := map[string]*awstasks.ClassicLoadBalancerListener{ | ||||
| 			"443": {InstancePort: 443}, | ||||
| 		} | ||||
| 		var nlbListeners []*awstasks.NetworkLoadBalancerListener | ||||
| 
 | ||||
| 		nlbListeners := []*awstasks.NetworkLoadBalancerListener{ | ||||
| 			{ | ||||
| 		if lbSpec.SSLCertificate == "" { | ||||
| 			listener443 := &awstasks.NetworkLoadBalancerListener{ | ||||
| 				Name:                fi.PtrTo(b.NLBListenerName("api", 443)), | ||||
| 				Lifecycle:           b.Lifecycle, | ||||
| 				NetworkLoadBalancer: b.LinkToNLB("api"), | ||||
| 				Port:                443, | ||||
| 				TargetGroupName: b.NLBTargetGroupName("tcp"), | ||||
| 			}, | ||||
| 				TargetGroup:         b.LinkToTargetGroup("tcp"), | ||||
| 			} | ||||
| 		if b.Cluster.UsesNoneDNS() { | ||||
| 			nlbListeners = append(nlbListeners, &awstasks.NetworkLoadBalancerListener{ | ||||
| 				Port:            wellknownports.KopsControllerPort, | ||||
| 				TargetGroupName: b.NLBTargetGroupName("kops-controller"), | ||||
| 			}) | ||||
| 			nlbListeners = append(nlbListeners, listener443) | ||||
| 		} else { | ||||
| 			listener8443 := &awstasks.NetworkLoadBalancerListener{ | ||||
| 				Name:                fi.PtrTo(b.NLBListenerName("api", 8443)), | ||||
| 				Lifecycle:           b.Lifecycle, | ||||
| 				NetworkLoadBalancer: b.LinkToNLB("api"), | ||||
| 				Port:                8443, | ||||
| 				TargetGroup:         b.LinkToTargetGroup("tcp"), | ||||
| 			} | ||||
| 			nlbListeners = append(nlbListeners, listener8443) | ||||
| 
 | ||||
| 		if lbSpec.SSLCertificate != "" { | ||||
| 			listeners["443"].SSLCertificateID = lbSpec.SSLCertificate | ||||
| 			nlbListeners[0].Port = 8443 | ||||
| 
 | ||||
| 			nlbListener := &awstasks.NetworkLoadBalancerListener{ | ||||
| 			listener443 := &awstasks.NetworkLoadBalancerListener{ | ||||
| 				Name:                fi.PtrTo(b.NLBListenerName("api", 443)), | ||||
| 				Lifecycle:           b.Lifecycle, | ||||
| 				NetworkLoadBalancer: b.LinkToNLB("api"), | ||||
| 				Port:                443, | ||||
| 				TargetGroupName:  b.NLBTargetGroupName("tls"), | ||||
| 				TargetGroup:         b.LinkToTargetGroup("tls"), | ||||
| 				SSLCertificateID:    lbSpec.SSLCertificate, | ||||
| 			} | ||||
| 			if lbSpec.SSLPolicy != nil { | ||||
| 				nlbListener.SSLPolicy = *lbSpec.SSLPolicy | ||||
| 				listener443.SSLPolicy = *lbSpec.SSLPolicy | ||||
| 			} | ||||
| 			nlbListeners = append(nlbListeners, listener443) | ||||
| 		} | ||||
| 
 | ||||
| 		if b.Cluster.UsesNoneDNS() { | ||||
| 			nlbListener := &awstasks.NetworkLoadBalancerListener{ | ||||
| 				Name:                fi.PtrTo(b.NLBListenerName("api", wellknownports.KopsControllerPort)), | ||||
| 				Lifecycle:           b.Lifecycle, | ||||
| 				NetworkLoadBalancer: b.LinkToNLB("api"), | ||||
| 				Port:                wellknownports.KopsControllerPort, | ||||
| 				TargetGroup:         b.LinkToTargetGroup("kops-controller"), | ||||
| 			} | ||||
| 			nlbListeners = append(nlbListeners, nlbListener) | ||||
| 		} | ||||
|  | @ -184,7 +202,6 @@ func (b *APILoadBalancerBuilder) Build(c *fi.CloudupModelBuilderContext) error { | |||
| 				b.LinkToELBSecurityGroup("api"), | ||||
| 			}, | ||||
| 			SubnetMappings: nlbSubnetMappings, | ||||
| 			Listeners:      nlbListeners, | ||||
| 			TargetGroups:   make([]*awstasks.TargetGroup, 0), | ||||
| 
 | ||||
| 			Tags:              tags, | ||||
|  | @ -359,6 +376,9 @@ func (b *APILoadBalancerBuilder) Build(c *fi.CloudupModelBuilderContext) error { | |||
| 				nlb.TargetGroups = append(nlb.TargetGroups, secondaryTG) | ||||
| 			} | ||||
| 			sort.Stable(awstasks.OrderTargetGroupsByName(nlb.TargetGroups)) | ||||
| 			for _, nlbListener := range nlbListeners { | ||||
| 				c.AddTask(nlbListener) | ||||
| 			} | ||||
| 			c.AddTask(nlb) | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -328,12 +328,15 @@ func (b *BastionModelBuilder) Build(c *fi.CloudupModelBuilderContext) error { | |||
| 		// Override the returned name to be the expected ELB name
 | ||||
| 		tags["Name"] = "bastion." + b.ClusterName() | ||||
| 
 | ||||
| 		nlbListeners := []*awstasks.NetworkLoadBalancerListener{ | ||||
| 			{ | ||||
| 		nlbListener := &awstasks.NetworkLoadBalancerListener{ | ||||
| 			Name:                fi.PtrTo(b.NLBListenerName("bastion", 22)), | ||||
| 			Lifecycle:           b.Lifecycle, | ||||
| 			NetworkLoadBalancer: b.LinkToNLB("bastion"), | ||||
| 			Port:                22, | ||||
| 				TargetGroupName: b.NLBTargetGroupName("bastion"), | ||||
| 			}, | ||||
| 			TargetGroup:         b.LinkToTargetGroup("bastion"), | ||||
| 		} | ||||
| 		c.AddTask(nlbListener) | ||||
| 
 | ||||
| 		nlb = &awstasks.NetworkLoadBalancer{ | ||||
| 			Name:      fi.PtrTo(b.NLBName("bastion")), | ||||
| 			Lifecycle: b.Lifecycle, | ||||
|  | @ -344,7 +347,6 @@ func (b *BastionModelBuilder) Build(c *fi.CloudupModelBuilderContext) error { | |||
| 			SecurityGroups: []*awstasks.SecurityGroup{ | ||||
| 				b.LinkToELBSecurityGroup("bastion"), | ||||
| 			}, | ||||
| 			Listeners:    nlbListeners, | ||||
| 			TargetGroups: make([]*awstasks.TargetGroup, 0), | ||||
| 
 | ||||
| 			Tags:          tags, | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ package model | |||
| import ( | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"k8s.io/klog/v2" | ||||
|  | @ -115,6 +116,11 @@ func (b *KopsModelContext) LinkToNLB(prefix string) *awstasks.NetworkLoadBalance | |||
| 	return &awstasks.NetworkLoadBalancer{Name: &name} | ||||
| } | ||||
| 
 | ||||
| func (b *KopsModelContext) NLBListenerName(loadBalancerPrefix string, port int) string { | ||||
| 	name := b.NLBName(loadBalancerPrefix) | ||||
| 	return name + "-" + strconv.Itoa(port) | ||||
| } | ||||
| 
 | ||||
| func (b *KopsModelContext) LinkToTargetGroup(prefix string) *awstasks.TargetGroup { | ||||
| 	name := b.NLBTargetGroupName(prefix) | ||||
| 	return &awstasks.TargetGroup{Name: &name} | ||||
|  |  | |||
|  | @ -58,8 +58,6 @@ type NetworkLoadBalancer struct { | |||
| 	SubnetMappings []*SubnetMapping | ||||
| 	SecurityGroups []*SecurityGroup | ||||
| 
 | ||||
| 	Listeners []*NetworkLoadBalancerListener | ||||
| 
 | ||||
| 	Scheme *string | ||||
| 
 | ||||
| 	CrossZoneLoadBalancing *bool | ||||
|  | @ -80,6 +78,9 @@ type NetworkLoadBalancer struct { | |||
| 
 | ||||
| 	// waitForLoadBalancerReady controls whether we wait for the load balancer to be ready before completing the "Render" operation.
 | ||||
| 	waitForLoadBalancerReady bool | ||||
| 
 | ||||
| 	// After this is found/created, we store the ARN
 | ||||
| 	loadBalancerArn string | ||||
| } | ||||
| 
 | ||||
| func (e *NetworkLoadBalancer) SetWaitForLoadBalancerReady(v bool) { | ||||
|  | @ -94,66 +95,6 @@ func (e *NetworkLoadBalancer) CompareWithID() *string { | |||
| 	return e.Name | ||||
| } | ||||
| 
 | ||||
| type NetworkLoadBalancerListener struct { | ||||
| 	Port             int | ||||
| 	TargetGroupName  string | ||||
| 	SSLCertificateID string | ||||
| 	SSLPolicy        string | ||||
| } | ||||
| 
 | ||||
| func (e *NetworkLoadBalancerListener) mapToAWS(targetGroups []*TargetGroup, loadBalancerArn string) (*elbv2.CreateListenerInput, error) { | ||||
| 	var tgARN string | ||||
| 	for _, tg := range targetGroups { | ||||
| 		if fi.ValueOf(tg.Name) == e.TargetGroupName { | ||||
| 			tgARN = fi.ValueOf(tg.ARN) | ||||
| 		} | ||||
| 	} | ||||
| 	if tgARN == "" { | ||||
| 		return nil, fmt.Errorf("target group not found for NLB listener %+v", e) | ||||
| 	} | ||||
| 
 | ||||
| 	l := &elbv2.CreateListenerInput{ | ||||
| 		DefaultActions: []*elbv2.Action{ | ||||
| 			{ | ||||
| 				TargetGroupArn: aws.String(tgARN), | ||||
| 				Type:           aws.String(elbv2.ActionTypeEnumForward), | ||||
| 			}, | ||||
| 		}, | ||||
| 		LoadBalancerArn: aws.String(loadBalancerArn), | ||||
| 		Port:            aws.Int64(int64(e.Port)), | ||||
| 	} | ||||
| 
 | ||||
| 	if e.SSLCertificateID != "" { | ||||
| 		l.Certificates = []*elbv2.Certificate{} | ||||
| 		l.Certificates = append(l.Certificates, &elbv2.Certificate{ | ||||
| 			CertificateArn: aws.String(e.SSLCertificateID), | ||||
| 		}) | ||||
| 		l.Protocol = aws.String(elbv2.ProtocolEnumTls) | ||||
| 		if e.SSLPolicy != "" { | ||||
| 			l.SslPolicy = aws.String(e.SSLPolicy) | ||||
| 		} | ||||
| 	} else { | ||||
| 		l.Protocol = aws.String(elbv2.ProtocolEnumTcp) | ||||
| 	} | ||||
| 
 | ||||
| 	return l, nil | ||||
| } | ||||
| 
 | ||||
| var _ fi.CloudupHasDependencies = &NetworkLoadBalancerListener{} | ||||
| 
 | ||||
| func (e *NetworkLoadBalancerListener) GetDependencies(tasks map[string]fi.CloudupTask) []fi.CloudupTask { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // OrderListenersByPort implements sort.Interface for []OrderListenersByPort, based on port number
 | ||||
| type OrderListenersByPort []*NetworkLoadBalancerListener | ||||
| 
 | ||||
| func (a OrderListenersByPort) Len() int      { return len(a) } | ||||
| func (a OrderListenersByPort) Swap(i, j int) { a[i], a[j] = a[j], a[i] } | ||||
| func (a OrderListenersByPort) Less(i, j int) bool { | ||||
| 	return a[i].Port < a[j].Port | ||||
| } | ||||
| 
 | ||||
| // The load balancer name 'api.renamenlbcluster.k8s.local' can only contain characters that are alphanumeric characters and hyphens(-)\n\tstatus code: 400,
 | ||||
| func findNetworkLoadBalancerByLoadBalancerName(cloud awsup.AWSCloud, loadBalancerName string) (*elbv2.LoadBalancer, error) { | ||||
| 	request := &elbv2.DescribeLoadBalancersInput{ | ||||
|  | @ -255,6 +196,7 @@ func (e *NetworkLoadBalancer) getHostedZoneId() *string { | |||
| } | ||||
| 
 | ||||
| func (e *NetworkLoadBalancer) Find(c *fi.CloudupContext) (*NetworkLoadBalancer, error) { | ||||
| 	ctx := c.Context() | ||||
| 	cloud := c.T.Cloud.(awsup.AWSCloud) | ||||
| 
 | ||||
| 	lb, err := cloud.FindELBV2ByNameTag(e.Tags["Name"]) | ||||
|  | @ -319,23 +261,16 @@ func (e *NetworkLoadBalancer) Find(c *fi.CloudupContext) (*NetworkLoadBalancer, | |||
| 		request := &elbv2.DescribeListenersInput{ | ||||
| 			LoadBalancerArn: loadBalancerArn, | ||||
| 		} | ||||
| 		response, err := cloud.ELBV2().DescribeListeners(request) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("error querying for NLB listeners :%v", err) | ||||
| 		var listeners []*elbv2.Listener | ||||
| 		if err := cloud.ELBV2().DescribeListenersPagesWithContext(ctx, request, func(page *elbv2.DescribeListenersOutput, lastPage bool) bool { | ||||
| 			listeners = append(listeners, page.Listeners...) | ||||
| 			return true | ||||
| 		}); err != nil { | ||||
| 			return nil, fmt.Errorf("listing NLB listeners: %w", err) | ||||
| 		} | ||||
| 
 | ||||
| 		actual.Listeners = []*NetworkLoadBalancerListener{} | ||||
| 		actual.TargetGroups = []*TargetGroup{} | ||||
| 		for _, l := range response.Listeners { | ||||
| 			actualListener := &NetworkLoadBalancerListener{} | ||||
| 			actualListener.Port = int(aws.Int64Value(l.Port)) | ||||
| 			if len(l.Certificates) != 0 { | ||||
| 				actualListener.SSLCertificateID = aws.StringValue(l.Certificates[0].CertificateArn) // What if there is more then one certificate, can we just grab the default certificate? we don't set it as default, we only set the one.
 | ||||
| 				if l.SslPolicy != nil { | ||||
| 					actualListener.SSLPolicy = aws.StringValue(l.SslPolicy) | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 		for _, l := range listeners { | ||||
| 			// This will need to be rearranged when we recognized multiple listeners and target groups per NLB
 | ||||
| 			if len(l.DefaultActions) > 0 { | ||||
| 				targetGroupARN := l.DefaultActions[0].TargetGroupArn | ||||
|  | @ -356,11 +291,8 @@ func (e *NetworkLoadBalancer) Find(c *fi.CloudupContext) (*NetworkLoadBalancer, | |||
| 					if len(descResp.TargetGroups) != 1 { | ||||
| 						return nil, fmt.Errorf("unexpected DescribeTargetGroups response: %v", descResp) | ||||
| 					} | ||||
| 
 | ||||
| 					actualListener.TargetGroupName = aws.StringValue(descResp.TargetGroups[0].TargetGroupName) | ||||
| 				} | ||||
| 			} | ||||
| 			actual.Listeners = append(actual.Listeners, actualListener) | ||||
| 		} | ||||
| 		sort.Stable(OrderTargetGroupsByName(actual.TargetGroups)) | ||||
| 
 | ||||
|  | @ -443,6 +375,9 @@ func (e *NetworkLoadBalancer) Find(c *fi.CloudupContext) (*NetworkLoadBalancer, | |||
| 	actual.WellKnownServices = e.WellKnownServices | ||||
| 	actual.Lifecycle = e.Lifecycle | ||||
| 
 | ||||
| 	// Store for other tasks
 | ||||
| 	e.loadBalancerArn = aws.StringValue(lb.LoadBalancerArn) | ||||
| 
 | ||||
| 	klog.V(4).Infof("Found NLB %+v", actual) | ||||
| 
 | ||||
| 	return actual, nil | ||||
|  | @ -496,7 +431,6 @@ func (e *NetworkLoadBalancer) Run(c *fi.CloudupContext) error { | |||
| func (e *NetworkLoadBalancer) Normalize(c *fi.CloudupContext) error { | ||||
| 	// We need to sort our arrays consistently, so we don't get spurious changes
 | ||||
| 	sort.Stable(OrderSubnetMappingsByName(e.SubnetMappings)) | ||||
| 	sort.Stable(OrderListenersByPort(e.Listeners)) | ||||
| 	sort.Stable(OrderTargetGroupsByName(e.TargetGroups)) | ||||
| 
 | ||||
| 	e.IpAddressType = fi.PtrTo("dualstack") | ||||
|  | @ -569,10 +503,6 @@ func (_ *NetworkLoadBalancer) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Ne | |||
| 	var loadBalancerName string | ||||
| 	var loadBalancerArn string | ||||
| 
 | ||||
| 	if len(e.Listeners) != len(e.TargetGroups) { | ||||
| 		return fmt.Errorf("nlb listeners and target groups do not match: %v listeners vs %v target groups", len(e.Listeners), len(e.TargetGroups)) | ||||
| 	} | ||||
| 
 | ||||
| 	if a == nil { | ||||
| 		if e.LoadBalancerName == nil { | ||||
| 			return fi.RequiredField("LoadBalancerName") | ||||
|  | @ -619,7 +549,8 @@ func (_ *NetworkLoadBalancer) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Ne | |||
| 			e.DNSName = lb.DNSName | ||||
| 			e.HostedZoneId = lb.CanonicalHostedZoneId | ||||
| 			e.VPC = &VPC{ID: lb.VpcId} | ||||
| 			loadBalancerArn = fi.ValueOf(lb.LoadBalancerArn) | ||||
| 			loadBalancerArn = aws.StringValue(lb.LoadBalancerArn) | ||||
| 			e.loadBalancerArn = loadBalancerArn | ||||
| 		} | ||||
| 
 | ||||
| 		if e.waitForLoadBalancerReady { | ||||
|  | @ -634,20 +565,6 @@ func (_ *NetworkLoadBalancer) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Ne | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			for _, listener := range e.Listeners { | ||||
| 				createListenerInput, err := listener.mapToAWS(e.TargetGroups, loadBalancerArn) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 
 | ||||
| 				klog.V(2).Infof("Creating Listener for NLB with port %v", listener.Port) | ||||
| 				_, err = t.Cloud.ELBV2().CreateListener(createListenerInput) | ||||
| 				if err != nil { | ||||
| 					return fmt.Errorf("error creating listener for NLB: %v", err) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		loadBalancerName = fi.ValueOf(a.LoadBalancerName) | ||||
| 
 | ||||
|  | @ -720,43 +637,6 @@ func (_ *NetworkLoadBalancer) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Ne | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if changes.Listeners != nil { | ||||
| 
 | ||||
| 			if lb != nil { | ||||
| 
 | ||||
| 				request := &elbv2.DescribeListenersInput{ | ||||
| 					LoadBalancerArn: lb.LoadBalancerArn, | ||||
| 				} | ||||
| 				response, err := t.Cloud.ELBV2().DescribeListeners(request) | ||||
| 				if err != nil { | ||||
| 					return fmt.Errorf("error querying for NLB listeners :%v", err) | ||||
| 				} | ||||
| 
 | ||||
| 				for _, l := range response.Listeners { | ||||
| 					// delete the listener before recreating it
 | ||||
| 					_, err := t.Cloud.ELBV2().DeleteListener(&elbv2.DeleteListenerInput{ | ||||
| 						ListenerArn: l.ListenerArn, | ||||
| 					}) | ||||
| 					if err != nil { | ||||
| 						return fmt.Errorf("error deleting load balancer listener with arn = : %v : %v", l.ListenerArn, err) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			for _, listener := range changes.Listeners { | ||||
| 
 | ||||
| 				awsListener, err := listener.mapToAWS(e.TargetGroups, loadBalancerArn) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 
 | ||||
| 				klog.V(2).Infof("Creating Listener for NLB with port %v", listener.Port) | ||||
| 				_, err = t.Cloud.ELBV2().CreateListener(awsListener) | ||||
| 				if err != nil { | ||||
| 					return fmt.Errorf("error creating NLB listener: %v", err) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if err := t.AddELBV2Tags(loadBalancerArn, e.Tags); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | @ -792,20 +672,6 @@ type terraformNetworkLoadBalancerSubnetMapping struct { | |||
| 	PrivateIPv4Address *string                  `cty:"private_ipv4_address"` | ||||
| } | ||||
| 
 | ||||
| type terraformNetworkLoadBalancerListener struct { | ||||
| 	LoadBalancer   *terraformWriter.Literal                     `cty:"load_balancer_arn"` | ||||
| 	Port           int64                                        `cty:"port"` | ||||
| 	Protocol       string                                       `cty:"protocol"` | ||||
| 	CertificateARN *string                                      `cty:"certificate_arn"` | ||||
| 	SSLPolicy      *string                                      `cty:"ssl_policy"` | ||||
| 	DefaultAction  []terraformNetworkLoadBalancerListenerAction `cty:"default_action"` | ||||
| } | ||||
| 
 | ||||
| type terraformNetworkLoadBalancerListenerAction struct { | ||||
| 	Type           string                   `cty:"type"` | ||||
| 	TargetGroupARN *terraformWriter.Literal `cty:"target_group_arn"` | ||||
| } | ||||
| 
 | ||||
| func (_ *NetworkLoadBalancer) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *NetworkLoadBalancer) error { | ||||
| 	nlbTF := &terraformNetworkLoadBalancer{ | ||||
| 		Name:                   *e.LoadBalancerName, | ||||
|  | @ -839,48 +705,11 @@ func (_ *NetworkLoadBalancer) RenderTerraform(t *terraform.TerraformTarget, a, e | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	err := t.RenderResource("aws_lb", *e.Name, nlbTF) | ||||
| 	err := t.RenderResource("aws_lb", e.TerraformName(), nlbTF) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, listener := range e.Listeners { | ||||
| 		var listenerTG *TargetGroup | ||||
| 		for _, tg := range e.TargetGroups { | ||||
| 			if aws.StringValue(tg.Name) == listener.TargetGroupName { | ||||
| 				listenerTG = tg | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		if listenerTG == nil { | ||||
| 			return fmt.Errorf("target group not found for NLB listener %+v", e) | ||||
| 		} | ||||
| 		listenerTF := &terraformNetworkLoadBalancerListener{ | ||||
| 			LoadBalancer: e.TerraformLink(), | ||||
| 			Port:         int64(listener.Port), | ||||
| 			DefaultAction: []terraformNetworkLoadBalancerListenerAction{ | ||||
| 				{ | ||||
| 					Type:           elbv2.ActionTypeEnumForward, | ||||
| 					TargetGroupARN: listenerTG.TerraformLink(), | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		if listener.SSLCertificateID != "" { | ||||
| 			listenerTF.CertificateARN = &listener.SSLCertificateID | ||||
| 			listenerTF.Protocol = elbv2.ProtocolEnumTls | ||||
| 			if listener.SSLPolicy != "" { | ||||
| 				listenerTF.SSLPolicy = &listener.SSLPolicy | ||||
| 			} | ||||
| 		} else { | ||||
| 			listenerTF.Protocol = elbv2.ProtocolEnumTcp | ||||
| 		} | ||||
| 
 | ||||
| 		err = t.RenderResource("aws_lb_listener", fmt.Sprintf("%v-%v", e.TerraformName(), listener.Port), listenerTF) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  | @ -894,7 +723,7 @@ func (e *NetworkLoadBalancer) TerraformLink(params ...string) *terraformWriter.L | |||
| 	if len(params) > 0 { | ||||
| 		prop = params[0] | ||||
| 	} | ||||
| 	return terraformWriter.LiteralProperty("aws_lb", *e.Name, prop) | ||||
| 	return terraformWriter.LiteralProperty("aws_lb", e.TerraformName(), prop) | ||||
| } | ||||
| 
 | ||||
| // FindDeletions schedules deletion of the corresponding legacy classic load balancer when it no longer has targets.
 | ||||
|  |  | |||
|  | @ -0,0 +1,261 @@ | |||
| /* | ||||
| Copyright 2019 The Kubernetes Authors. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package awstasks | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/aws/aws-sdk-go/aws" | ||||
| 	"github.com/aws/aws-sdk-go/service/elbv2" | ||||
| 	"k8s.io/klog/v2" | ||||
| 	"k8s.io/kops/upup/pkg/fi" | ||||
| 	"k8s.io/kops/upup/pkg/fi/cloudup/awsup" | ||||
| 	"k8s.io/kops/upup/pkg/fi/cloudup/terraform" | ||||
| 	"k8s.io/kops/upup/pkg/fi/cloudup/terraformWriter" | ||||
| ) | ||||
| 
 | ||||
| // +kops:fitask
 | ||||
| type NetworkLoadBalancerListener struct { | ||||
| 	Name      *string | ||||
| 	Lifecycle fi.Lifecycle | ||||
| 
 | ||||
| 	NetworkLoadBalancer *NetworkLoadBalancer | ||||
| 
 | ||||
| 	Port             int | ||||
| 	TargetGroup      *TargetGroup | ||||
| 	SSLCertificateID string | ||||
| 	SSLPolicy        string | ||||
| 
 | ||||
| 	listenerArn string | ||||
| } | ||||
| 
 | ||||
| var _ fi.CompareWithID = &NetworkLoadBalancerListener{} | ||||
| var _ fi.CloudupTaskNormalize = &NetworkLoadBalancerListener{} | ||||
| 
 | ||||
| func (e *NetworkLoadBalancerListener) CompareWithID() *string { | ||||
| 	return e.Name | ||||
| } | ||||
| 
 | ||||
| func (e *NetworkLoadBalancerListener) Find(c *fi.CloudupContext) (*NetworkLoadBalancerListener, error) { | ||||
| 	ctx := c.Context() | ||||
| 
 | ||||
| 	cloud := c.T.Cloud.(awsup.AWSCloud) | ||||
| 
 | ||||
| 	if e.NetworkLoadBalancer == nil { | ||||
| 		return nil, fi.RequiredField("NetworkLoadBalancer") | ||||
| 	} | ||||
| 
 | ||||
| 	loadBalancerArn := e.NetworkLoadBalancer.loadBalancerArn | ||||
| 	if loadBalancerArn == "" { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 
 | ||||
| 	var l *elbv2.Listener | ||||
| 	{ | ||||
| 		request := &elbv2.DescribeListenersInput{ | ||||
| 			LoadBalancerArn: &loadBalancerArn, | ||||
| 		} | ||||
| 		// TODO: Move to lbInfo?
 | ||||
| 		var allListeners []*elbv2.Listener | ||||
| 		if err := cloud.ELBV2().DescribeListenersPagesWithContext(ctx, request, func(page *elbv2.DescribeListenersOutput, lastPage bool) bool { | ||||
| 			allListeners = append(allListeners, page.Listeners...) | ||||
| 			return true | ||||
| 		}); err != nil { | ||||
| 			return nil, fmt.Errorf("error querying for NLB listeners :%v", err) | ||||
| 		} | ||||
| 
 | ||||
| 		var matches []*elbv2.Listener | ||||
| 		for _, listener := range allListeners { | ||||
| 			if aws.Int64Value(listener.Port) == int64(e.Port) { | ||||
| 				matches = append(matches, listener) | ||||
| 			} | ||||
| 		} | ||||
| 		if len(matches) == 0 { | ||||
| 			return nil, nil | ||||
| 		} | ||||
| 		if len(matches) > 1 { | ||||
| 			return nil, fmt.Errorf("found multiple listeners matching %+v", e) | ||||
| 		} | ||||
| 		l = matches[0] | ||||
| 	} | ||||
| 
 | ||||
| 	actual := &NetworkLoadBalancerListener{} | ||||
| 	actual.listenerArn = aws.StringValue(l.ListenerArn) | ||||
| 
 | ||||
| 	actual.Port = int(aws.Int64Value(l.Port)) | ||||
| 	if len(l.Certificates) != 0 { | ||||
| 		actual.SSLCertificateID = aws.StringValue(l.Certificates[0].CertificateArn) // What if there is more then one certificate, can we just grab the default certificate? we don't set it as default, we only set the one.
 | ||||
| 		if l.SslPolicy != nil { | ||||
| 			actual.SSLPolicy = aws.StringValue(l.SslPolicy) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// This will need to be rearranged when we recognized multiple listeners and target groups per NLB
 | ||||
| 	if len(l.DefaultActions) > 0 { | ||||
| 		targetGroupARN := l.DefaultActions[0].TargetGroupArn | ||||
| 		if targetGroupARN != nil { | ||||
| 			actual.TargetGroup = &TargetGroup{ | ||||
| 				ARN: targetGroupARN, | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	_ = actual.Normalize(c) | ||||
| 	actual.Lifecycle = e.Lifecycle | ||||
| 
 | ||||
| 	// Avoid spurious changes
 | ||||
| 	actual.Name = e.Name | ||||
| 	actual.NetworkLoadBalancer = e.NetworkLoadBalancer | ||||
| 
 | ||||
| 	klog.V(4).Infof("Found NLB listener %+v", actual) | ||||
| 
 | ||||
| 	return actual, nil | ||||
| } | ||||
| 
 | ||||
| func (e *NetworkLoadBalancerListener) Run(c *fi.CloudupContext) error { | ||||
| 	return fi.CloudupDefaultDeltaRunMethod(e, c) | ||||
| } | ||||
| 
 | ||||
| func (e *NetworkLoadBalancerListener) Normalize(c *fi.CloudupContext) error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (*NetworkLoadBalancerListener) CheckChanges(a, e, changes *NetworkLoadBalancerListener) error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (*NetworkLoadBalancerListener) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *NetworkLoadBalancerListener) error { | ||||
| 	ctx := context.TODO() | ||||
| 
 | ||||
| 	if e.NetworkLoadBalancer == nil { | ||||
| 		return fi.RequiredField("NetworkLoadBalancer") | ||||
| 	} | ||||
| 	loadBalancerArn := e.NetworkLoadBalancer.loadBalancerArn | ||||
| 	if loadBalancerArn == "" { | ||||
| 		return fmt.Errorf("load balancer not yet created (arn not set)") | ||||
| 	} | ||||
| 
 | ||||
| 	if a != nil { | ||||
| 		// TODO: Can we do better here?
 | ||||
| 		klog.Warningf("deleting ELB listener %q for required changes (%+v)", a.listenerArn, changes) | ||||
| 
 | ||||
| 		// delete the listener before recreating it
 | ||||
| 		_, err := t.Cloud.ELBV2().DeleteListenerWithContext(ctx, &elbv2.DeleteListenerInput{ | ||||
| 			ListenerArn: &a.listenerArn, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("error deleting load balancer listener with arn=%q: %w", e.listenerArn, err) | ||||
| 		} | ||||
| 		a = nil | ||||
| 	} | ||||
| 
 | ||||
| 	if a == nil { | ||||
| 		if e.TargetGroup == nil { | ||||
| 			return fi.RequiredField("TargetGroup") | ||||
| 		} | ||||
| 		targetGroupARN := fi.ValueOf(e.TargetGroup.ARN) | ||||
| 		if targetGroupARN == "" { | ||||
| 			return fmt.Errorf("target group not yet created (arn not set)") | ||||
| 		} | ||||
| 		request := &elbv2.CreateListenerInput{ | ||||
| 			DefaultActions: []*elbv2.Action{ | ||||
| 				{ | ||||
| 					TargetGroupArn: aws.String(targetGroupARN), | ||||
| 					Type:           aws.String(elbv2.ActionTypeEnumForward), | ||||
| 				}, | ||||
| 			}, | ||||
| 			LoadBalancerArn: aws.String(loadBalancerArn), | ||||
| 			Port:            aws.Int64(int64(e.Port)), | ||||
| 		} | ||||
| 
 | ||||
| 		if e.SSLCertificateID != "" { | ||||
| 			request.Certificates = []*elbv2.Certificate{} | ||||
| 			request.Certificates = append(request.Certificates, &elbv2.Certificate{ | ||||
| 				CertificateArn: aws.String(e.SSLCertificateID), | ||||
| 			}) | ||||
| 			request.Protocol = aws.String(elbv2.ProtocolEnumTls) | ||||
| 			if e.SSLPolicy != "" { | ||||
| 				request.SslPolicy = aws.String(e.SSLPolicy) | ||||
| 			} | ||||
| 		} else { | ||||
| 			request.Protocol = aws.String(elbv2.ProtocolEnumTcp) | ||||
| 		} | ||||
| 
 | ||||
| 		klog.V(2).Infof("Creating Listener for NLB with port %v", e.Port) | ||||
| 		_, err := t.Cloud.ELBV2().CreateListenerWithContext(ctx, request) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("creating listener for NLB on port %v: %w", e.Port, err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: Tags on the listener?
 | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| type terraformNetworkLoadBalancerListener struct { | ||||
| 	LoadBalancer   *terraformWriter.Literal                     `cty:"load_balancer_arn"` | ||||
| 	Port           int64                                        `cty:"port"` | ||||
| 	Protocol       string                                       `cty:"protocol"` | ||||
| 	CertificateARN *string                                      `cty:"certificate_arn"` | ||||
| 	SSLPolicy      *string                                      `cty:"ssl_policy"` | ||||
| 	DefaultAction  []terraformNetworkLoadBalancerListenerAction `cty:"default_action"` | ||||
| } | ||||
| 
 | ||||
| type terraformNetworkLoadBalancerListenerAction struct { | ||||
| 	Type           string                   `cty:"type"` | ||||
| 	TargetGroupARN *terraformWriter.Literal `cty:"target_group_arn"` | ||||
| } | ||||
| 
 | ||||
| func (_ *NetworkLoadBalancerListener) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *NetworkLoadBalancerListener) error { | ||||
| 	if e.TargetGroup == nil { | ||||
| 		return fi.RequiredField("TargetGroup") | ||||
| 	} | ||||
| 
 | ||||
| 	listenerTF := &terraformNetworkLoadBalancerListener{ | ||||
| 		LoadBalancer: e.NetworkLoadBalancer.TerraformLink(), | ||||
| 		Port:         int64(e.Port), | ||||
| 		DefaultAction: []terraformNetworkLoadBalancerListenerAction{ | ||||
| 			{ | ||||
| 				Type:           elbv2.ActionTypeEnumForward, | ||||
| 				TargetGroupARN: e.TargetGroup.TerraformLink(), | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	if e.SSLCertificateID != "" { | ||||
| 		listenerTF.CertificateARN = &e.SSLCertificateID | ||||
| 		listenerTF.Protocol = elbv2.ProtocolEnumTls | ||||
| 		if e.SSLPolicy != "" { | ||||
| 			listenerTF.SSLPolicy = &e.SSLPolicy | ||||
| 		} | ||||
| 	} else { | ||||
| 		listenerTF.Protocol = elbv2.ProtocolEnumTcp | ||||
| 	} | ||||
| 
 | ||||
| 	err := t.RenderResource("aws_lb_listener", e.TerraformName(), listenerTF) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (e *NetworkLoadBalancerListener) TerraformName() string { | ||||
| 	tfName := fmt.Sprintf("%v-%v", e.NetworkLoadBalancer.TerraformName(), e.Port) | ||||
| 	return tfName | ||||
| } | ||||
|  | @ -0,0 +1,52 @@ | |||
| //go:build !ignore_autogenerated
 | ||||
| // +build !ignore_autogenerated
 | ||||
| 
 | ||||
| /* | ||||
| Copyright The Kubernetes Authors. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| // Code generated by fitask. DO NOT EDIT.
 | ||||
| 
 | ||||
| package awstasks | ||||
| 
 | ||||
| import ( | ||||
| 	"k8s.io/kops/upup/pkg/fi" | ||||
| ) | ||||
| 
 | ||||
| // NetworkLoadBalancerListener
 | ||||
| 
 | ||||
| var _ fi.HasLifecycle = &NetworkLoadBalancerListener{} | ||||
| 
 | ||||
| // GetLifecycle returns the Lifecycle of the object, implementing fi.HasLifecycle
 | ||||
| func (o *NetworkLoadBalancerListener) GetLifecycle() fi.Lifecycle { | ||||
| 	return o.Lifecycle | ||||
| } | ||||
| 
 | ||||
| // SetLifecycle sets the Lifecycle of the object, implementing fi.SetLifecycle
 | ||||
| func (o *NetworkLoadBalancerListener) SetLifecycle(lifecycle fi.Lifecycle) { | ||||
| 	o.Lifecycle = lifecycle | ||||
| } | ||||
| 
 | ||||
| var _ fi.HasName = &NetworkLoadBalancerListener{} | ||||
| 
 | ||||
| // GetName returns the Name of the object, implementing fi.HasName
 | ||||
| func (o *NetworkLoadBalancerListener) GetName() *string { | ||||
| 	return o.Name | ||||
| } | ||||
| 
 | ||||
| // String is the stringer function for the task, producing readable output using fi.TaskAsString
 | ||||
| func (o *NetworkLoadBalancerListener) String() string { | ||||
| 	return fi.CloudupTaskAsString(o) | ||||
| } | ||||
		Loading…
	
		Reference in New Issue