Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/guide/service/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
| service.beta.kubernetes.io/aws-load-balancer-type | string | | |
| service.beta.kubernetes.io/aws-load-balancer-internal | boolean | false | |
| [service.beta.kubernetes.io/aws-load-balancer-proxy-protocol](#proxy-protocol-v2) | string | | Set to `"*"` to enable |
| service.beta.kubernetes.io/aws-load-balancer-ip-address-type | string | ipv4 | ipv4 \| dualstack |
| service.beta.kubernetes.io/aws-load-balancer-access-log-enabled | boolean | false | |
| service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name | string | | |
| service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix | string | | |
Expand Down
1 change: 1 addition & 0 deletions pkg/annotations/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const (
SvcLBSuffixSourceRanges = "load-balancer-source-ranges"
SvcLBSuffixLoadBalancerType = "aws-load-balancer-type"
SvcLBSuffixInternal = "aws-load-balancer-internal"
SvcLBSuffixIPAddressType = "aws-load-balancer-ip-address-type"
SvcLBSuffixProxyProtocol = "aws-load-balancer-proxy-protocol"
SvcLBSuffixAccessLogEnabled = "aws-load-balancer-access-log-enabled"
SvcLBSuffixAccessLogS3BucketName = "aws-load-balancer-access-log-s3-bucket-name"
Expand Down
22 changes: 21 additions & 1 deletion pkg/service/model_build_load_balancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ func (t *defaultModelBuildTask) buildLoadBalancer(ctx context.Context, scheme el
}

func (t *defaultModelBuildTask) buildLoadBalancerSpec(ctx context.Context, scheme elbv2model.LoadBalancerScheme) (elbv2model.LoadBalancerSpec, error) {
ipAddressType := elbv2model.IPAddressTypeIPV4
ipAddressType, err := t.buildLoadBalancerIPAddressType(ctx)
if err != nil {
return elbv2model.LoadBalancerSpec{}, err
}
lbAttributes, err := t.buildLoadBalancerAttributes(ctx)
if err != nil {
return elbv2model.LoadBalancerSpec{}, err
Expand All @@ -60,6 +63,23 @@ func (t *defaultModelBuildTask) buildLoadBalancerSpec(ctx context.Context, schem
return spec, nil
}

func (t *defaultModelBuildTask) buildLoadBalancerIPAddressType(_ context.Context) (elbv2model.IPAddressType, error) {
rawIPAddressType := ""
if exists := t.annotationParser.ParseStringAnnotation(annotations.SvcLBSuffixIPAddressType, &rawIPAddressType, t.service.Annotations); !exists{
return t.defaultIPAddressType, nil
}

switch rawIPAddressType {
case string(elbv2model.IPAddressTypeIPV4):
return elbv2model.IPAddressTypeIPV4, nil
case string(elbv2model.IPAddressTypeDualStack):
return elbv2model.IPAddressTypeDualStack, nil
default:
return "", errors.Errorf("unknown IPAddressType: %v", rawIPAddressType)
}
}


func (t *defaultModelBuildTask) buildLoadBalancerScheme(_ context.Context) (elbv2model.LoadBalancerScheme, error) {
internal := false
if _, err := t.annotationParser.ParseBoolAnnotation(annotations.SvcLBSuffixInternal, &internal, t.service.Annotations); err != nil {
Expand Down
69 changes: 69 additions & 0 deletions pkg/service/model_build_load_balancer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,72 @@ func Test_defaultModelBuilderTask_resolveLoadBalancerSubnets(t *testing.T) {
})
}
}

func Test_defaultModelBuildTask_buildLoadBalancerIPAddressType(t *testing.T) {
tests := []struct {
name string
service *corev1.Service
want elbv2.IPAddressType
wantErr bool
}{
{
name: "ipv4_specified_expect_ipv4",
service: &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{"service.beta.kubernetes.io/aws-load-balancer-ip-address-type": "ipv4"},
},
},
want: elbv2.IPAddressTypeIPV4,
wantErr: false,
},
{
name: "dualstack_specified_expect_dualstack",
service: &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{"service.beta.kubernetes.io/aws-load-balancer-ip-address-type": "dualstack"},
},
},
want: elbv2.IPAddressTypeDualStack,
wantErr: false,
},
{
name: "default_value_no_ip_address_type_specified_expect_ipv4",
service: &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{"service.beta.kubernetes.io/aws-load-balancer-other-annotation": "somevalue"},
},
},
want: elbv2.IPAddressTypeIPV4,
wantErr: false,
},
{
name: "invalid_value_expect_error",
service: &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{"service.beta.kubernetes.io/aws-load-balancer-ip-address-type": "DualStack"},
},
},
want: "",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
parser := annotations.NewSuffixAnnotationParser("service.beta.kubernetes.io")
builder := &defaultModelBuildTask{
annotationParser: parser,
service: tt.service,
defaultIPAddressType: elbv2.IPAddressTypeIPV4,
}

got, err := builder.buildLoadBalancerIPAddressType(context.Background())
if (err != nil) != tt.wantErr {
t.Errorf("buildLoadBalancerIPAddressType() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("buildLoadBalancerIPAddressType() got = %v, want %v", got, tt.want)
}
})
}
}
5 changes: 4 additions & 1 deletion pkg/service/model_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package service

import (
"context"

"github.com/aws/aws-sdk-go/service/ec2"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/aws-load-balancer-controller/pkg/annotations"
Expand Down Expand Up @@ -48,6 +49,7 @@ func (b *defaultModelBuilder) Build(ctx context.Context, service *corev1.Service
defaultAccessLogS3Enabled: false,
defaultAccessLogsS3Bucket: "",
defaultAccessLogsS3Prefix: "",
defaultIPAddressType: elbv2model.IPAddressTypeIPV4,
defaultLoadBalancingCrossZoneEnabled: false,
defaultProxyProtocolV2Enabled: false,
defaultHealthCheckProtocol: elbv2model.ProtocolTCP,
Expand Down Expand Up @@ -79,7 +81,8 @@ type defaultModelBuildTask struct {
defaultAccessLogS3Enabled bool
defaultAccessLogsS3Bucket string
defaultAccessLogsS3Prefix string
defaultLoadBalancingCrossZoneEnabled bool
defaultIPAddressType elbv2model.IPAddressType
defaultLoadBalancingCrossZoneEnabled bool
defaultProxyProtocolV2Enabled bool
defaultHealthCheckProtocol elbv2model.Protocol
defaultHealthCheckPort string
Expand Down
166 changes: 163 additions & 3 deletions pkg/service/model_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package service

import (
"context"
"testing"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/golang/mock/gomock"
Expand All @@ -12,8 +15,6 @@ import (
mock_networking "sigs.k8s.io/aws-load-balancer-controller/mocks/networking"
"sigs.k8s.io/aws-load-balancer-controller/pkg/annotations"
"sigs.k8s.io/aws-load-balancer-controller/pkg/deploy"
"testing"
"time"
)

func Test_defaultModelBuilderTask_Build(t *testing.T) {
Expand Down Expand Up @@ -223,7 +224,166 @@ func Test_defaultModelBuilderTask_Build(t *testing.T) {
}
`,
wantNumResources: 4,
},
},
{
testName: "Dualstack service",
svc: &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "nlb-ip-svc-tls",
Namespace: "default",
UID: "bdca2bd0-bfc6-449a-88a3-03451f05f18c",
Annotations: map[string]string{
"service.beta.kubernetes.io/aws-load-balancer-type": "nlb-ip",
"service.beta.kubernetes.io/aws-load-balancer-ip-address-type": "dualstack",
},
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeLoadBalancer,
Selector: map[string]string{"app": "hello"},
Ports: []corev1.ServicePort{
{
Port: 80,
TargetPort: intstr.FromInt(80),
Protocol: corev1.ProtocolTCP,
},
},
},
},
resolveViaDiscoveryCalls: []resolveViaDiscoveryCall{resolveViaDiscoveryCallForOneSubnet},
wantError: false,
wantValue: `
{
"id":"default/nlb-ip-svc-tls",
"resources":{
"AWS::ElasticLoadBalancingV2::Listener":{
"80":{
"spec":{
"loadBalancerARN":{
"$ref":"#/resources/AWS::ElasticLoadBalancingV2::LoadBalancer/LoadBalancer/status/loadBalancerARN"
},
"port":80,
"protocol":"TCP",
"defaultActions":[
{
"type":"forward",
"forwardConfig":{
"targetGroups":[
{
"targetGroupARN":{
"$ref":"#/resources/AWS::ElasticLoadBalancingV2::TargetGroup/default/nlb-ip-svc-tls:80/status/targetGroupARN"
}
}
]
}
}
]
}
}
},
"AWS::ElasticLoadBalancingV2::LoadBalancer":{
"LoadBalancer":{
"spec":{
"name":"k8s-default-nlbipsvc-4d831c6ca6",
"type":"network",
"scheme":"internet-facing",
"ipAddressType":"dualstack",
"subnetMapping":[
{
"subnetID":"subnet-1"
}
],
"loadBalancerAttributes":[
{
"key":"access_logs.s3.enabled",
"value":"false"
},
{
"key":"access_logs.s3.bucket",
"value":""
},
{
"key":"access_logs.s3.prefix",
"value":""
},
{
"key":"load_balancing.cross_zone.enabled",
"value":"false"
}
]
}
}
},
"AWS::ElasticLoadBalancingV2::TargetGroup":{
"default/nlb-ip-svc-tls:80":{
"spec":{
"name":"k8s-default-nlbipsvc-d4818dcd51",
"targetType":"ip",
"port":80,
"protocol":"TCP",
"healthCheckConfig":{
"port":"traffic-port",
"protocol":"TCP",
"intervalSeconds":10,
"timeoutSeconds":10,
"healthyThresholdCount":3,
"unhealthyThresholdCount":3
},
"targetGroupAttributes":[
{
"key":"proxy_protocol_v2.enabled",
"value":"false"
}
]
}
}
},
"K8S::ElasticLoadBalancingV2::TargetGroupBinding":{
"default/nlb-ip-svc-tls:80":{
"spec":{
"template":{
"metadata":{
"name":"k8s-default-nlbipsvc-d4818dcd51",
"namespace":"default",
"creationTimestamp":null
},
"spec":{
"targetGroupARN":{
"$ref":"#/resources/AWS::ElasticLoadBalancingV2::TargetGroup/default/nlb-ip-svc-tls:80/status/targetGroupARN"
},
"targetType":"ip",
"serviceRef":{
"name":"nlb-ip-svc-tls",
"port":80
},
"networking":{
"ingress":[
{
"from":[
{
"ipBlock":{
"cidr":"192.168.0.0/19"
}
}
],
"ports":[
{
"protocol":"TCP",
"port":80
}
]
}
]
}
}
}
}
}
}
}
}
`,
wantNumResources: 4,
},
{
testName: "Multiple listeners, multiple target groups",
svc: &corev1.Service{
Expand Down