Skip to content

Commit e9691e2

Browse files
authored
feat: add support to set ProtocolVersion based on annotation values (#1589)
* feat: add support to set ProtocolVersion based on annotation values * Add comment to mock method * address review comments * Fix typo
1 parent 842b95e commit e9691e2

File tree

12 files changed

+188
-3
lines changed

12 files changed

+188
-3
lines changed

docs/guide/ingress/annotations.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ You can add annotations to kubernetes Ingress and Service objects to customize t
3333
|[alb.ingress.kubernetes.io/ssl-policy](#ssl-policy)|string|ELBSecurityPolicy-2016-08|Ingress|Exclusive|
3434
|[alb.ingress.kubernetes.io/target-type](#target-type)|instance \| ip|instance|Ingress,Service|N/A|
3535
|[alb.ingress.kubernetes.io/backend-protocol](#backend-protocol)|HTTP \| HTTPS|HTTP|Ingress,Service|N/A|
36+
|[alb.ingress.kubernetes.io/backend-protocol-version](#backend-protocol-version)|string | HTTP1 |Ingress,Service|N/A|
3637
|[alb.ingress.kubernetes.io/target-group-attributes](#target-group-attributes)|stringMap|N/A|Ingress,Service|N/A|
3738
|[alb.ingress.kubernetes.io/healthcheck-port](#healthcheck-port)|integer \| traffic-port|traffic-port|Ingress,Service|N/A|
3839
|[alb.ingress.kubernetes.io/healthcheck-protocol](#healthcheck-protocol)|HTTP \| HTTPS|HTTP|Ingress,Service|N/A|
@@ -155,6 +156,13 @@ Traffic Routing can be controlled with following annotations:
155156
alb.ingress.kubernetes.io/backend-protocol: HTTPS
156157
```
157158

159+
- <a name="backend-protocol-version">`alb.ingress.kubernetes.io/backend-protocol-version`</a> specifies the application protocol used to route traffic to pods. Only valid when HTTP or HTTPS is used as the backend protocol.
160+
161+
!!!example
162+
```
163+
alb.ingress.kubernetes.io/backend-protocol-version: HTTP2
164+
```
165+
158166
- <a name="subnets">`alb.ingress.kubernetes.io/subnets`</a> specifies the [Availability Zone](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html) that ALB will route traffic to. See [Load Balancer subnets](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-subnets.html) for more details.
159167

160168
!!!note ""

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module sigs.k8s.io/aws-load-balancer-controller
33
go 1.13
44

55
require (
6-
github.com/aws/aws-sdk-go v1.35.4
6+
github.com/aws/aws-sdk-go v1.35.18
77
github.com/go-logr/logr v0.1.0
88
github.com/golang/mock v1.2.0
99
github.com/google/go-cmp v0.4.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ github.com/aws/aws-sdk-go v1.33.14 h1:ucjyVEvtIdtn4acf+RKsgk6ybAYeMLXpGZeqoVvi7K
2828
github.com/aws/aws-sdk-go v1.33.14/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
2929
github.com/aws/aws-sdk-go v1.35.4 h1:GG0sdhmzQSe4/UcF9iuQP9i+58bPRyU4OpujyzMlVjo=
3030
github.com/aws/aws-sdk-go v1.35.4/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
31+
github.com/aws/aws-sdk-go v1.35.18 h1:Gka1bopihF2e9XFhuVZPrgafmOFpCsRtAPMYLp/0AfA=
32+
github.com/aws/aws-sdk-go v1.35.18/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
3133
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
3234
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
3335
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=

mocks/aws/services/mock_ec2.go

Lines changed: 92 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/annotations/constants.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const (
2323
IngressSuffixSSLPolicy = "ssl-policy"
2424
IngressSuffixTargetType = "target-type"
2525
IngressSuffixBackendProtocol = "backend-protocol"
26+
IngressSuffixBackendProtocolVersion = "backend-protocol-version"
2627
IngressSuffixTargetGroupAttributes = "target-group-attributes"
2728
IngressSuffixHealthCheckPort = "healthcheck-port"
2829
IngressSuffixHealthCheckProtocol = "healthcheck-protocol"

pkg/deploy/elbv2/target_group_manager.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ func buildSDKCreateTargetGroupInput(tgSpec elbv2model.TargetGroupSpec) *elbv2sdk
189189
sdkObj.TargetType = awssdk.String(string(tgSpec.TargetType))
190190
sdkObj.Port = awssdk.Int64(tgSpec.Port)
191191
sdkObj.Protocol = awssdk.String(string(tgSpec.Protocol))
192+
if tgSpec.ProtocolVersion != nil {
193+
sdkObj.ProtocolVersion = (*string)(tgSpec.ProtocolVersion)
194+
}
192195
if tgSpec.HealthCheckConfig != nil {
193196
hcConfig := *tgSpec.HealthCheckConfig
194197
sdkObj.HealthCheckEnabled = awssdk.Bool(true)

pkg/deploy/elbv2/target_group_manager_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ func Test_isSDKTargetGroupHealthCheckDrifted(t *testing.T) {
350350
func Test_buildSDKCreateTargetGroupInput(t *testing.T) {
351351
port9090 := intstr.FromInt(9090)
352352
protocolHTTP := elbv2model.ProtocolHTTP
353+
protocolVersionHTTP2 := elbv2model.ProtocolVersionHTTP2
353354
type args struct {
354355
tgSpec elbv2model.TargetGroupSpec
355356
}
@@ -394,6 +395,44 @@ func Test_buildSDKCreateTargetGroupInput(t *testing.T) {
394395
TargetType: awssdk.String("ip"),
395396
},
396397
},
398+
{
399+
name: "standard case with protocol version",
400+
args: args{
401+
tgSpec: elbv2model.TargetGroupSpec{
402+
Name: "my-tg",
403+
TargetType: elbv2model.TargetTypeIP,
404+
Port: 8080,
405+
Protocol: elbv2model.ProtocolHTTP,
406+
ProtocolVersion: &protocolVersionHTTP2,
407+
HealthCheckConfig: &elbv2model.TargetGroupHealthCheckConfig{
408+
Port: &port9090,
409+
Protocol: &protocolHTTP,
410+
Path: awssdk.String("/healthcheck"),
411+
Matcher: &elbv2model.HealthCheckMatcher{HTTPCode: "200"},
412+
IntervalSeconds: awssdk.Int64(10),
413+
TimeoutSeconds: awssdk.Int64(5),
414+
HealthyThresholdCount: awssdk.Int64(3),
415+
UnhealthyThresholdCount: awssdk.Int64(2),
416+
},
417+
},
418+
},
419+
want: &elbv2sdk.CreateTargetGroupInput{
420+
HealthCheckEnabled: awssdk.Bool(true),
421+
HealthCheckIntervalSeconds: awssdk.Int64(10),
422+
HealthCheckPath: awssdk.String("/healthcheck"),
423+
HealthCheckPort: awssdk.String("9090"),
424+
HealthCheckProtocol: awssdk.String("HTTP"),
425+
HealthCheckTimeoutSeconds: awssdk.Int64(5),
426+
HealthyThresholdCount: awssdk.Int64(3),
427+
Matcher: &elbv2sdk.Matcher{HttpCode: awssdk.String("200")},
428+
UnhealthyThresholdCount: awssdk.Int64(2),
429+
Name: awssdk.String("my-tg"),
430+
Port: awssdk.Int64(8080),
431+
Protocol: awssdk.String("HTTP"),
432+
ProtocolVersion: awssdk.String("HTTP2"),
433+
TargetType: awssdk.String("ip"),
434+
},
435+
},
397436
}
398437
for _, tt := range tests {
399438
t.Run(tt.name, func(t *testing.T) {

pkg/deploy/elbv2/target_group_synthesizer.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@ func isSDKTargetGroupRequiresReplacement(sdkTG TargetGroupWithTags, resTG *elbv2
165165
if string(resTG.Spec.Protocol) != awssdk.StringValue(sdkTG.TargetGroup.Protocol) {
166166
return true
167167
}
168+
if resTG.Spec.ProtocolVersion != nil {
169+
if string(*resTG.Spec.ProtocolVersion) != awssdk.StringValue(sdkTG.TargetGroup.ProtocolVersion) {
170+
return true
171+
}
172+
}
168173

169174
return isSDKTargetGroupRequiresReplacementDueToNLBHealthCheck(sdkTG, resTG)
170175
}

pkg/ingress/model_build_target_group.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ func (t *defaultModelBuildTask) buildTargetGroupSpec(ctx context.Context,
106106
if err != nil {
107107
return elbv2model.TargetGroupSpec{}, err
108108
}
109+
tgProtocolVersion, err := t.buildTargetGroupProtocolVersion(ctx, svcAndIngAnnotations)
110+
if err != nil {
111+
return elbv2model.TargetGroupSpec{}, err
112+
}
109113
healthCheckConfig, err := t.buildTargetGroupHealthCheckConfig(ctx, svc, svcAndIngAnnotations, targetType, tgProtocol)
110114
if err != nil {
111115
return elbv2model.TargetGroupSpec{}, err
@@ -124,12 +128,13 @@ func (t *defaultModelBuildTask) buildTargetGroupSpec(ctx context.Context,
124128
}
125129

126130
tgPort := t.buildTargetGroupPort(ctx, targetType, svcPort)
127-
name := t.buildTargetGroupName(ctx, k8s.NamespacedName(ing), svc, port, tgPort, targetType, tgProtocol)
131+
name := t.buildTargetGroupName(ctx, k8s.NamespacedName(ing), svc, port, tgPort, targetType, tgProtocol, tgProtocolVersion)
128132
return elbv2model.TargetGroupSpec{
129133
Name: name,
130134
TargetType: targetType,
131135
Port: tgPort,
132136
Protocol: tgProtocol,
137+
ProtocolVersion: &tgProtocolVersion,
133138
HealthCheckConfig: &healthCheckConfig,
134139
TargetGroupAttributes: tgAttributes,
135140
Tags: tags,
@@ -141,7 +146,7 @@ var invalidTargetGroupNamePattern = regexp.MustCompile("[[:^alnum:]]")
141146
// buildTargetGroupName will calculate the targetGroup's name.
142147
func (t *defaultModelBuildTask) buildTargetGroupName(_ context.Context,
143148
ingKey types.NamespacedName, svc *corev1.Service, port intstr.IntOrString, tgPort int64,
144-
targetType elbv2model.TargetType, tgProtocol elbv2model.Protocol) string {
149+
targetType elbv2model.TargetType, tgProtocol elbv2model.Protocol, tgProtocolVersion elbv2model.ProtocolVersion) string {
145150
uuidHash := sha256.New()
146151
_, _ = uuidHash.Write([]byte(t.clusterName))
147152
_, _ = uuidHash.Write([]byte(t.ingGroup.ID.String()))
@@ -152,6 +157,7 @@ func (t *defaultModelBuildTask) buildTargetGroupName(_ context.Context,
152157
_, _ = uuidHash.Write([]byte(strconv.Itoa(int(tgPort))))
153158
_, _ = uuidHash.Write([]byte(targetType))
154159
_, _ = uuidHash.Write([]byte(tgProtocol))
160+
_, _ = uuidHash.Write([]byte(tgProtocolVersion))
155161
uuid := hex.EncodeToString(uuidHash.Sum(nil))
156162

157163
sanitizedNamespace := invalidTargetGroupNamePattern.ReplaceAllString(svc.Namespace, "")
@@ -201,6 +207,21 @@ func (t *defaultModelBuildTask) buildTargetGroupProtocol(_ context.Context, svcA
201207
}
202208
}
203209

210+
func (t *defaultModelBuildTask) buildTargetGroupProtocolVersion(_ context.Context, svcAndIngAnnotations map[string]string) (elbv2model.ProtocolVersion, error) {
211+
rawBackendProtocolVersion := string(t.defaultBackendProtocolVersion)
212+
_ = t.annotationParser.ParseStringAnnotation(annotations.IngressSuffixBackendProtocolVersion, &rawBackendProtocolVersion, svcAndIngAnnotations)
213+
switch rawBackendProtocolVersion {
214+
case string(elbv2model.ProtocolVersionHTTP1):
215+
return elbv2model.ProtocolVersionHTTP1, nil
216+
case string(elbv2model.ProtocolVersionHTTP2):
217+
return elbv2model.ProtocolVersionHTTP2, nil
218+
case string(elbv2model.ProtocolVersionGRPC):
219+
return elbv2model.ProtocolVersionGRPC, nil
220+
default:
221+
return "", errors.Errorf("backend protocol version must be within [%v, %v, %v]: %v", elbv2model.ProtocolVersionHTTP1, elbv2model.ProtocolVersionHTTP2, elbv2model.ProtocolVersionGRPC, rawBackendProtocolVersion)
222+
}
223+
}
224+
204225
func (t *defaultModelBuildTask) buildTargetGroupHealthCheckConfig(ctx context.Context, svc *corev1.Service, svcAndIngAnnotations map[string]string, targetType elbv2model.TargetType, tgProtocol elbv2model.Protocol) (elbv2model.TargetGroupHealthCheckConfig, error) {
205226
healthCheckPort, err := t.buildTargetGroupHealthCheckPort(ctx, svc, svcAndIngAnnotations, targetType)
206227
if err != nil {

pkg/ingress/model_builder.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ func (b *defaultModelBuilder) Build(ctx context.Context, ingGroup Group) (core.S
9999
defaultSSLPolicy: "ELBSecurityPolicy-2016-08",
100100
defaultTargetType: elbv2model.TargetTypeInstance,
101101
defaultBackendProtocol: elbv2model.ProtocolHTTP,
102+
defaultBackendProtocolVersion: elbv2model.ProtocolVersionHTTP1,
102103
defaultHealthCheckPath: "/",
103104
defaultHealthCheckIntervalSeconds: 15,
104105
defaultHealthCheckTimeoutSeconds: 5,
@@ -138,6 +139,7 @@ type defaultModelBuildTask struct {
138139
defaultSSLPolicy string
139140
defaultTargetType elbv2model.TargetType
140141
defaultBackendProtocol elbv2model.Protocol
142+
defaultBackendProtocolVersion elbv2model.ProtocolVersion
141143
defaultHealthCheckPath string
142144
defaultHealthCheckTimeoutSeconds int64
143145
defaultHealthCheckIntervalSeconds int64

pkg/model/elbv2/listener.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ const (
6969
ProtocolTCP_UDP Protocol = "TCP_UDP"
7070
)
7171

72+
type ProtocolVersion string
73+
74+
const (
75+
ProtocolVersionHTTP1 ProtocolVersion = "HTTP1"
76+
ProtocolVersionHTTP2 ProtocolVersion = "HTTP2"
77+
ProtocolVersionGRPC ProtocolVersion = "GRPC"
78+
)
79+
7280
// The type of action.
7381
type ActionType string
7482

pkg/model/elbv2/target_group.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ type TargetGroupSpec struct {
121121
// The protocol to use for routing traffic to the targets.
122122
Protocol Protocol `json:"protocol"`
123123

124+
// The target group protocol version.
125+
// +optional
126+
ProtocolVersion *ProtocolVersion `json:"protocolVersion,omitempty"`
127+
124128
// Configuration for TargetGroup's HealthCheck.
125129
// +optional
126130
HealthCheckConfig *TargetGroupHealthCheckConfig `json:"healthCheckConfig,omitempty"`

0 commit comments

Comments
 (0)