From cbedc5b099d3bdea3a08bb8b0c0578e04396d7b2 Mon Sep 17 00:00:00 2001 From: Drew Mudgett Date: Thu, 15 Aug 2024 10:37:20 -0400 Subject: [PATCH] Adding Stickiness option for Target Groups Signed-off-by: drmudgett --- README.md | 1 + aws/cf.go | 11 +++++++++++ aws/cf_template.go | 13 +++++++++++-- kubernetes/adapter.go | 7 +++++++ kubernetes/ingress.go | 1 + worker.go | 1 + 6 files changed, 32 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9badac94..2cf85f92 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ Overview of configuration which can be set via Ingress annotations. |`zalando.org/aws-load-balancer-http2`| `true` \| `false`|`true`| |`zalando.org/aws-waf-web-acl-id` | `string` | N/A | |`kubernetes.io/ingress.class`|`string`|N/A| +|`zalando.org/aws-load-balancer-stickiness`| `true` \| `false`|`false`| The defaults can also be configured globally via a flag on the controller. diff --git a/aws/cf.go b/aws/cf.go index 1a4ab47a..327cb051 100644 --- a/aws/cf.go +++ b/aws/cf.go @@ -35,6 +35,7 @@ type Stack struct { WAFWebACLID string CertificateARNs map[string]time.Time tags map[string]string + Stickiness bool } // IsComplete returns true if the stack status is a complete state. @@ -148,6 +149,7 @@ const ( parameterLoadBalancerTypeParameter = "Type" parameterLoadBalancerWAFWebACLIDParameter = "LoadBalancerWAFWebACLIDParameter" parameterHTTP2Parameter = "HTTP2" + parameterStickinessParameter = "Stickiness" ) type stackSpec struct { @@ -188,6 +190,7 @@ type stackSpec struct { denyInternalDomainsResponse denyResp internalDomains []string tags map[string]string + stickiness bool } type healthCheck struct { @@ -229,6 +232,7 @@ func createStack(svc cloudformationiface.CloudFormationAPI, spec *stackSpec) (st cfParam(parameterIpAddressTypeParameter, spec.ipAddressType), cfParam(parameterLoadBalancerTypeParameter, spec.loadbalancerType), cfParam(parameterHTTP2Parameter, fmt.Sprintf("%t", spec.http2)), + cfParam(parameterStickinessParameter, spec.stickiness), }, Tags: tagMapToCloudformationTags(tags), TemplateBody: aws.String(template), @@ -304,6 +308,7 @@ func updateStack(svc cloudformationiface.CloudFormationAPI, spec *stackSpec) (st cfParam(parameterIpAddressTypeParameter, spec.ipAddressType), cfParam(parameterLoadBalancerTypeParameter, spec.loadbalancerType), cfParam(parameterHTTP2Parameter, fmt.Sprintf("%t", spec.http2)), + cfParam(parameterStickinessParameter, spec.stickiness), }, Tags: tagMapToCloudformationTags(tags), TemplateBody: aws.String(template), @@ -481,6 +486,11 @@ func mapToManagedStack(stack *cloudformation.Stack) *Stack { http2 = false } + stickiness := false + if parameters[parameterStickinessParameter] == "true" { + stickiness = true + } + return &Stack{ Name: aws.StringValue(stack.StackName), DNSName: outputs.dnsName(), @@ -498,6 +508,7 @@ func mapToManagedStack(stack *cloudformation.Stack) *Stack { statusReason: aws.StringValue(stack.StackStatusReason), CWAlarmConfigHash: tags[cwAlarmConfigHashTag], WAFWebACLID: parameters[parameterLoadBalancerWAFWebACLIDParameter], + Stickiness: stickiness, } } diff --git a/aws/cf_template.go b/aws/cf_template.go index 145cb805..7114000f 100644 --- a/aws/cf_template.go +++ b/aws/cf_template.go @@ -103,6 +103,11 @@ func generateTemplate(spec *stackSpec) (string, error) { Description: "H2 Enabled", Default: "true", }, + parameterStickinessParameter: { + Type: "String", + Description: "Enable Target Group Stickiness", + Default: "false", + }, } if spec.wafWebAclId != "" { @@ -168,8 +173,12 @@ func generateTemplate(spec *stackSpec) (string, error) { template.AddResource("HTTPListener", &cloudformation.ElasticLoadBalancingV2Listener{ DefaultActions: &cloudformation.ElasticLoadBalancingV2ListenerActionList{ { - Type: cloudformation.String("forward"), - TargetGroupArn: cloudformation.Ref(httpTargetGroupName).String(), + Type: cloudformation.String("forward"), + TargetGroupArn: cloudformation.Ref(httpTargetGroupName).String(), + TargetGroupStickinessConfig: &cloudformation.ElasticLoadBalancingV2ListenerTargetGroupStickinessConfig{ + Enabled: cloudformation.Ref(parameterStickinessParameter).String(), + DurationSeconds: cloudformation.Integer(3600) + }, }, }, LoadBalancerArn: cloudformation.Ref("LB").String(), diff --git a/kubernetes/adapter.go b/kubernetes/adapter.go index 615cff15..465d6ad7 100644 --- a/kubernetes/adapter.go +++ b/kubernetes/adapter.go @@ -85,6 +85,7 @@ type Ingress struct { LoadBalancerType string WAFWebACLID string Hostnames []string + Stickiness bool } // String returns a string representation of the Ingress instance containing the type, namespace and the resource name. @@ -234,6 +235,11 @@ func (a *Adapter) newIngress(typ IngressType, metadata kubeItemMetadata, host st if getAnnotationsString(annotations, ingressHTTP2Annotation, "") == "false" { http2 = false } + + stickiness := false + if getAnnotationsString(annotations, ingressLoadBalancerStickiness, "") == "true" { + stickiness = true + } return &Ingress{ ResourceType: typ, @@ -251,6 +257,7 @@ func (a *Adapter) newIngress(typ IngressType, metadata kubeItemMetadata, host st LoadBalancerType: loadBalancerType, WAFWebACLID: wafWebAclId, HTTP2: http2, + Stickiness: stickiness, }, nil } diff --git a/kubernetes/ingress.go b/kubernetes/ingress.go index cc61a0a7..d3205537 100644 --- a/kubernetes/ingress.go +++ b/kubernetes/ingress.go @@ -75,6 +75,7 @@ const ( ingressHTTP2Annotation = "zalando.org/aws-load-balancer-http2" ingressWAFWebACLIDAnnotation = "zalando.org/aws-waf-web-acl-id" ingressClassAnnotation = "kubernetes.io/ingress.class" + ingressLoadBalancerStickiness = "zalando.org/aws-load-balancer-stickiness" ) func getAnnotationsString(annotations map[string]string, key string, defaultValue string) string { diff --git a/worker.go b/worker.go index 86e9beea..2e5bfeb4 100644 --- a/worker.go +++ b/worker.go @@ -36,6 +36,7 @@ type loadBalancer struct { certTTL time.Duration cwAlarms aws.CloudWatchAlarmList loadBalancerType string + stickiness bool } const (