Skip to content

Commit e863fd5

Browse files
authored
Merge pull request #650 from kubernetes-sigs/AttributesController
Created a controller to manage ALB attributes
2 parents d93862a + 8779ae3 commit e863fd5

File tree

22 files changed

+746
-363
lines changed

22 files changed

+746
-363
lines changed

go.mod

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,45 @@ module github.com/kubernetes-sigs/aws-alb-ingress-controller
22

33
require (
44
github.com/aws/aws-sdk-go v1.15.39
5-
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973
65
github.com/blang/semver v3.5.1+incompatible
76
github.com/cenkalti/backoff v2.0.0+incompatible
8-
github.com/davecgh/go-spew v1.1.1
97
github.com/eapache/channels v1.1.0
10-
github.com/eapache/queue v1.1.0
11-
github.com/ghodss/yaml v1.0.0
12-
github.com/go-ini/ini v1.38.1
13-
github.com/gogo/protobuf v1.1.1
8+
github.com/eapache/queue v1.1.0 // indirect
9+
github.com/ghodss/yaml v1.0.0 // indirect
10+
github.com/go-ini/ini v1.38.1 // indirect
11+
github.com/gogo/protobuf v1.1.1 // indirect
1412
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
15-
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7
16-
github.com/golang/protobuf v1.2.0
17-
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a
18-
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf
19-
github.com/googleapis/gnostic v0.2.0
20-
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7
21-
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47
13+
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7 // indirect
14+
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a // indirect
15+
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
16+
github.com/googleapis/gnostic v0.2.0 // indirect
17+
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
18+
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47 // indirect
2219
github.com/imdario/mergo v0.0.0-20171009183408-7fe0c75c13ab
23-
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8
24-
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be
25-
github.com/karlseguin/ccache v2.0.2+incompatible
26-
github.com/matttproud/golang_protobuf_extensions v1.0.1
27-
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
28-
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742
29-
github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c
30-
github.com/peterbourgon/diskv v2.0.1+incompatible
20+
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be // indirect
21+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
22+
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
23+
github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c // indirect
24+
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
3125
github.com/pkg/errors v0.8.0
32-
github.com/pmezard/go-difflib v1.0.0
3326
github.com/prometheus/client_golang v0.9.0-pre1.0.20180919114304-73edb9af667d
3427
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910
3528
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e
36-
github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7
3729
github.com/spf13/pflag v1.0.1
38-
github.com/stretchr/objx v0.1.1
30+
github.com/stretchr/objx v0.1.1 // indirect
3931
github.com/stretchr/testify v1.2.2
4032
github.com/ticketmaster/aws-sdk-go-cache v0.0.0-20180926195306-58922816129c
41-
golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb
42-
golang.org/x/net v0.0.0-20180724234803-3673e40ba225
43-
golang.org/x/sys v0.0.0-20180724212812-e072cadbbdc8
44-
golang.org/x/text v0.3.0
45-
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2
33+
golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb // indirect
34+
golang.org/x/net v0.0.0-20180724234803-3673e40ba225 // indirect
35+
golang.org/x/sys v0.0.0-20180724212812-e072cadbbdc8 // indirect
36+
golang.org/x/text v0.3.0 // indirect
37+
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 // indirect
4638
gopkg.in/go-playground/pool.v3 v3.1.1
47-
gopkg.in/inf.v0 v0.9.1
48-
gopkg.in/yaml.v2 v2.2.1
39+
gopkg.in/inf.v0 v0.9.1 // indirect
40+
gopkg.in/yaml.v2 v2.2.1 // indirect
4941
k8s.io/api v0.0.0-20180628040859-072894a440bd
5042
k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d
5143
k8s.io/apiserver v0.0.0-20180628044425-01459b68eb5f
5244
k8s.io/client-go v8.0.0+incompatible
53-
k8s.io/kube-openapi v0.0.0-20180719232738-d8ea2fe547a4
45+
k8s.io/kube-openapi v0.0.0-20180719232738-d8ea2fe547a4 // indirect
5446
)

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v
5555
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
5656
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
5757
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
58+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
5859
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5960
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
6061
github.com/prometheus/client_golang v0.9.0-pre1.0.20180919114304-73edb9af667d h1:DYicbQQTRiJXT51TQULZYt3cNfpC+5y0TeG/vqwsGH4=
@@ -67,7 +68,9 @@ github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7 h1:NgR6WN8nQ4SmF
6768
github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
6869
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
6970
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
71+
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
7072
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
73+
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
7174
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
7275
github.com/ticketmaster/aws-sdk-go-cache v0.0.0-20180926195306-58922816129c h1:3cRzuTKE8C2VkXUQNHOU7FWOOMN1Ddklypzs4ZyQSBw=
7376
github.com/ticketmaster/aws-sdk-go-cache v0.0.0-20180926195306-58922816129c/go.mod h1:H9sbOivuFYIUAS9No3MxP7K6WXz8i8Xg4qRJ/nu3zM4=

internal/alb/lb/attributes.go

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
package lb
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strconv"
7+
8+
"github.com/aws/aws-sdk-go/aws"
9+
"github.com/aws/aws-sdk-go/service/elbv2"
10+
"github.com/aws/aws-sdk-go/service/elbv2/elbv2iface"
11+
"github.com/kubernetes-sigs/aws-alb-ingress-controller/internal/albctx"
12+
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/util/log"
13+
api "k8s.io/api/core/v1"
14+
)
15+
16+
const (
17+
DeletionProtectionEnabledKey = "deletion_protection.enabled"
18+
AccessLogsS3EnabledKey = "access_logs.s3.enabled"
19+
AccessLogsS3BucketKey = "access_logs.s3.bucket"
20+
AccessLogsS3PrefixKey = "access_logs.s3.prefix"
21+
IdleTimeoutTimeoutSecondsKey = "idle_timeout.timeout_seconds"
22+
RoutingHTTP2EnabledKey = "routing.http2.enabled"
23+
24+
DeletionProtectionEnabled = false
25+
AccessLogsS3Enabled = false
26+
AccessLogsS3Bucket = ""
27+
AccessLogsS3Prefix = ""
28+
IdleTimeoutTimeoutSeconds = 60
29+
RoutingHTTP2Enabled = true
30+
)
31+
32+
// Attributes represents the desired state of attributes for a load balancer.
33+
type Attributes struct {
34+
// LbArn is the ARN of the load balancer
35+
LbArn string
36+
37+
// DeletionProtectionEnabled: deletion_protection.enabled - Indicates whether deletion protection
38+
// is enabled. The value is true or false. The default is false.
39+
DeletionProtectionEnabled bool
40+
41+
// AccessLogsS3Enabled: access_logs.s3.enabled - Indicates whether access logs are enabled.
42+
// The value is true or false. The default is false.
43+
AccessLogsS3Enabled bool
44+
45+
// AccessLogsS3Bucket: access_logs.s3.bucket - The name of the S3 bucket for the access logs.
46+
// This attribute is required if access logs are enabled. The bucket must
47+
// exist in the same region as the load balancer and have a bucket policy
48+
// that grants Elastic Load Balancing permissions to write to the bucket.
49+
AccessLogsS3Bucket string
50+
51+
// AccessLogsS3Prefix: access_logs.s3.prefix - The prefix for the location in the S3 bucket
52+
// for the access logs.
53+
AccessLogsS3Prefix string
54+
55+
// IdleTimeoutTimeoutSeconds: idle_timeout.timeout_seconds - The idle timeout value, in seconds. The
56+
// valid range is 1-4000 seconds. The default is 60 seconds.
57+
IdleTimeoutTimeoutSeconds int64
58+
59+
// RoutingHTTP2Enabled: routing.http2.enabled - Indicates whether HTTP/2 is enabled. The value
60+
// is true or false. The default is true.
61+
RoutingHTTP2Enabled bool
62+
}
63+
64+
func NewAttributes(attrs []*elbv2.LoadBalancerAttribute) (a *Attributes, err error) {
65+
a = &Attributes{
66+
DeletionProtectionEnabled: DeletionProtectionEnabled,
67+
AccessLogsS3Enabled: AccessLogsS3Enabled,
68+
AccessLogsS3Bucket: AccessLogsS3Bucket,
69+
AccessLogsS3Prefix: AccessLogsS3Prefix,
70+
IdleTimeoutTimeoutSeconds: IdleTimeoutTimeoutSeconds,
71+
RoutingHTTP2Enabled: RoutingHTTP2Enabled,
72+
}
73+
var e error
74+
for _, attr := range attrs {
75+
attrValue := aws.StringValue(attr.Value)
76+
switch attrKey := aws.StringValue(attr.Key); attrKey {
77+
case DeletionProtectionEnabledKey:
78+
a.DeletionProtectionEnabled, err = strconv.ParseBool(attrValue)
79+
if err != nil {
80+
return a, fmt.Errorf("invalid load balancer attribute value %s=%s", attrKey, attrValue)
81+
}
82+
case AccessLogsS3EnabledKey:
83+
a.AccessLogsS3Enabled, err = strconv.ParseBool(attrValue)
84+
if err != nil {
85+
return a, fmt.Errorf("invalid load balancer attribute value %s=%s", attrKey, attrValue)
86+
}
87+
case AccessLogsS3BucketKey:
88+
a.AccessLogsS3Bucket = attrValue
89+
case AccessLogsS3PrefixKey:
90+
a.AccessLogsS3Prefix = attrValue
91+
case IdleTimeoutTimeoutSecondsKey:
92+
a.IdleTimeoutTimeoutSeconds, err = strconv.ParseInt(attrValue, 10, 64)
93+
if err != nil {
94+
return a, fmt.Errorf("invalid load balancer attribute value %s=%s", attrKey, attrValue)
95+
}
96+
if a.IdleTimeoutTimeoutSeconds < 1 || a.IdleTimeoutTimeoutSeconds > 4000 {
97+
return a, fmt.Errorf("%s must be within 1-4000 seconds", attrKey)
98+
}
99+
case RoutingHTTP2EnabledKey:
100+
a.RoutingHTTP2Enabled, err = strconv.ParseBool(attrValue)
101+
if err != nil {
102+
return a, fmt.Errorf("invalid load balancer attribute value %s=%s", attrKey, attrValue)
103+
}
104+
default:
105+
e = NewInvalidAttribute(attrKey)
106+
}
107+
}
108+
return a, e
109+
}
110+
111+
// AttributesController provides functionality to manage Attributes
112+
type AttributesController interface {
113+
// Reconcile ensures the load balancer attributes in AWS matches the state specified by the ingress configuration.
114+
Reconcile(context.Context, *Attributes) error
115+
}
116+
117+
// NewAttributesController constructs a new attributes controller
118+
func NewAttributesController(elbv2 elbv2iface.ELBV2API) AttributesController {
119+
return &attributesController{
120+
elbv2: elbv2,
121+
}
122+
}
123+
124+
type attributesController struct {
125+
elbv2 elbv2iface.ELBV2API
126+
}
127+
128+
func (c *attributesController) Reconcile(ctx context.Context, desired *Attributes) error {
129+
raw, err := c.elbv2.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{
130+
LoadBalancerArn: aws.String(desired.LbArn),
131+
})
132+
133+
if err != nil {
134+
return fmt.Errorf("failed to retrieve attributes from ELBV2 in AWS: %s", err.Error())
135+
}
136+
137+
current, err := NewAttributes(raw.Attributes)
138+
if err != nil && !IsInvalidAttribute(err) {
139+
return fmt.Errorf("failed parsing attributes: %v", err)
140+
}
141+
142+
changeSet := attributesChangeSet(current, desired)
143+
if len(changeSet) > 0 {
144+
albctx.GetLogger(ctx).Infof("Modifying ELBV2 attributes to %v.", log.Prettify(changeSet))
145+
_, err = c.elbv2.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{
146+
LoadBalancerArn: aws.String(desired.LbArn),
147+
Attributes: changeSet,
148+
})
149+
if err != nil {
150+
eventf, ok := albctx.GetEventf(ctx)
151+
if ok {
152+
eventf(api.EventTypeWarning, "ERROR", "%s attributes modification failed: %s", desired.LbArn, err.Error())
153+
}
154+
return fmt.Errorf("failed modifying attributes: %s", err)
155+
}
156+
157+
}
158+
return nil
159+
}
160+
161+
// attributesChangeSet returns a list of elbv2.LoadBalancerAttribute required to change a into b
162+
func attributesChangeSet(a, b *Attributes) (changeSet []*elbv2.LoadBalancerAttribute) {
163+
if a.DeletionProtectionEnabled != b.DeletionProtectionEnabled {
164+
changeSet = append(changeSet, lbAttribute(DeletionProtectionEnabledKey, fmt.Sprintf("%v", b.DeletionProtectionEnabled)))
165+
}
166+
167+
if a.AccessLogsS3Enabled != b.AccessLogsS3Enabled {
168+
changeSet = append(changeSet, lbAttribute(AccessLogsS3EnabledKey, fmt.Sprintf("%v", b.AccessLogsS3Enabled)))
169+
}
170+
171+
if a.AccessLogsS3Bucket != b.AccessLogsS3Bucket {
172+
changeSet = append(changeSet, lbAttribute(AccessLogsS3BucketKey, b.AccessLogsS3Bucket))
173+
}
174+
175+
if a.AccessLogsS3Prefix != b.AccessLogsS3Prefix {
176+
changeSet = append(changeSet, lbAttribute(AccessLogsS3PrefixKey, b.AccessLogsS3Prefix))
177+
}
178+
179+
if a.IdleTimeoutTimeoutSeconds != b.IdleTimeoutTimeoutSeconds {
180+
changeSet = append(changeSet, lbAttribute(IdleTimeoutTimeoutSecondsKey, fmt.Sprintf("%v", b.IdleTimeoutTimeoutSeconds)))
181+
}
182+
183+
if a.RoutingHTTP2Enabled != b.RoutingHTTP2Enabled {
184+
changeSet = append(changeSet, lbAttribute(RoutingHTTP2EnabledKey, fmt.Sprintf("%v", b.RoutingHTTP2Enabled)))
185+
}
186+
187+
return
188+
}
189+
190+
func lbAttribute(k, v string) *elbv2.LoadBalancerAttribute {
191+
return &elbv2.LoadBalancerAttribute{Key: aws.String(k), Value: aws.String(v)}
192+
}
193+
194+
// NewInvalidAttribute returns a new InvalidAttribute error
195+
func NewInvalidAttribute(name string) error {
196+
return InvalidAttribute{
197+
Name: fmt.Sprintf("the load balancer attribute %v is not valid", name),
198+
}
199+
}
200+
201+
// InvalidAttribute error
202+
type InvalidAttribute struct {
203+
Name string
204+
}
205+
206+
func (e InvalidAttribute) Error() string {
207+
return e.Name
208+
}
209+
210+
// IsInvalidAttribute checks if the err is from an invalid attribute
211+
func IsInvalidAttribute(e error) bool {
212+
_, ok := e.(InvalidAttribute)
213+
return ok
214+
}

0 commit comments

Comments
 (0)