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{
|
||||
{
|
||||
Port: 443,
|
||||
TargetGroupName: b.NLBTargetGroupName("tcp"),
|
||||
},
|
||||
}
|
||||
if b.Cluster.UsesNoneDNS() {
|
||||
nlbListeners = append(nlbListeners, &awstasks.NetworkLoadBalancerListener{
|
||||
Port: wellknownports.KopsControllerPort,
|
||||
TargetGroupName: b.NLBTargetGroupName("kops-controller"),
|
||||
})
|
||||
}
|
||||
if lbSpec.SSLCertificate == "" {
|
||||
listener443 := &awstasks.NetworkLoadBalancerListener{
|
||||
Name: fi.PtrTo(b.NLBListenerName("api", 443)),
|
||||
Lifecycle: b.Lifecycle,
|
||||
NetworkLoadBalancer: b.LinkToNLB("api"),
|
||||
Port: 443,
|
||||
TargetGroup: b.LinkToTargetGroup("tcp"),
|
||||
}
|
||||
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{
|
||||
Port: 443,
|
||||
TargetGroupName: b.NLBTargetGroupName("tls"),
|
||||
SSLCertificateID: lbSpec.SSLCertificate,
|
||||
listener443 := &awstasks.NetworkLoadBalancerListener{
|
||||
Name: fi.PtrTo(b.NLBListenerName("api", 443)),
|
||||
Lifecycle: b.Lifecycle,
|
||||
NetworkLoadBalancer: b.LinkToNLB("api"),
|
||||
Port: 443,
|
||||
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{
|
||||
{
|
||||
Port: 22,
|
||||
TargetGroupName: b.NLBTargetGroupName("bastion"),
|
||||
},
|
||||
nlbListener := &awstasks.NetworkLoadBalancerListener{
|
||||
Name: fi.PtrTo(b.NLBListenerName("bastion", 22)),
|
||||
Lifecycle: b.Lifecycle,
|
||||
NetworkLoadBalancer: b.LinkToNLB("bastion"),
|
||||
Port: 22,
|
||||
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