Skip to content

Commit ec5f770

Browse files
committed
[feat aga] Add AGA listener builder without auto-discovery
1 parent 6b4d4fd commit ec5f770

File tree

14 files changed

+1846
-2
lines changed

14 files changed

+1846
-2
lines changed

apis/aga/v1beta1/globalaccelerator_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const (
4848
)
4949

5050
// PortRange defines the port range for Global Accelerator listeners.
51+
// +kubebuilder:validation:XValidation:rule="self.fromPort <= self.toPort",message="FromPort must be less than or equal to ToPort"
5152
type PortRange struct {
5253
// FromPort is the first port in the range of ports, inclusive.
5354
// +kubebuilder:validation:Minimum=1

config/crd/aga/aga-crds.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ spec:
264264
- fromPort
265265
- toPort
266266
type: object
267+
x-kubernetes-validations:
268+
- message: FromPort must be less than or equal to ToPort
269+
rule: self.fromPort <= self.toPort
267270
maxItems: 10
268271
minItems: 1
269272
type: array

config/crd/aga/aga.k8s.aws_globalaccelerators.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ spec:
264264
- fromPort
265265
- toPort
266266
type: object
267+
x-kubernetes-validations:
268+
- message: FromPort must be less than or equal to ToPort
269+
rule: self.fromPort <= self.toPort
267270
maxItems: 10
268271
minItems: 1
269272
type: array
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# This patch adds the GlobalAccelerator validator webhook configuration to the webhook configurations
2+
apiVersion: admissionregistration.k8s.io/v1
3+
kind: ValidatingWebhookConfiguration
4+
metadata:
5+
name: webhook-configuration
6+
webhooks:
7+
- name: vglobalaccelerator.aga.k8s.aws
8+
rules:
9+
- apiGroups:
10+
- "aga.k8s.aws"
11+
apiVersions:
12+
- v1beta1
13+
operations:
14+
- CREATE
15+
- UPDATE
16+
resources:
17+
- globalaccelerators
18+
scope: "Namespaced"

config/webhook/kustomization.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ patchesStrategicMerge:
99
- pod_mutator_patch.yaml
1010
- service_mutator_patch.yaml
1111
- ingressclassparams_validator_patch.yaml
12+
- globalaccelerator_validator_patch.yaml

config/webhook/manifests.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,27 @@ kind: ValidatingWebhookConfiguration
6868
metadata:
6969
name: webhook
7070
webhooks:
71+
- admissionReviewVersions:
72+
- v1beta1
73+
clientConfig:
74+
service:
75+
name: webhook-service
76+
namespace: system
77+
path: /validate-aga-k8s-aws-v1beta1-globalaccelerator
78+
failurePolicy: Fail
79+
matchPolicy: Equivalent
80+
name: vglobalaccelerator.aga.k8s.aws
81+
rules:
82+
- apiGroups:
83+
- aga.k8s.aws
84+
apiVersions:
85+
- v1beta1
86+
operations:
87+
- CREATE
88+
- UPDATE
89+
resources:
90+
- globalaccelerators
91+
sideEffects: None
7192
- admissionReviewVersions:
7293
- v1beta1
7394
clientConfig:

helm/aws-load-balancer-controller/crds/aga-crds.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ spec:
264264
- fromPort
265265
- toPort
266266
type: object
267+
x-kubernetes-validations:
268+
- message: FromPort must be less than or equal to ToPort
269+
rule: self.fromPort <= self.toPort
267270
maxItems: 10
268271
minItems: 1
269272
type: array

main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ import (
6565
"sigs.k8s.io/aws-load-balancer-controller/pkg/runtime"
6666
"sigs.k8s.io/aws-load-balancer-controller/pkg/targetgroupbinding"
6767
"sigs.k8s.io/aws-load-balancer-controller/pkg/version"
68+
agawebhook "sigs.k8s.io/aws-load-balancer-controller/webhooks/aga"
6869
corewebhook "sigs.k8s.io/aws-load-balancer-controller/webhooks/core"
6970
elbv2webhook "sigs.k8s.io/aws-load-balancer-controller/webhooks/elbv2"
7071
networkingwebhook "sigs.k8s.io/aws-load-balancer-controller/webhooks/networking"
@@ -415,6 +416,11 @@ func main() {
415416
elbv2webhook.NewTargetGroupBindingMutator(cloud.ELBV2(), ctrl.Log, lbcMetricsCollector).SetupWithManager(mgr)
416417
elbv2webhook.NewTargetGroupBindingValidator(mgr.GetClient(), cloud.ELBV2(), cloud.VpcID(), ctrl.Log, lbcMetricsCollector).SetupWithManager(mgr)
417418
networkingwebhook.NewIngressValidator(mgr.GetClient(), controllerCFG.IngressConfig, ctrl.Log, lbcMetricsCollector).SetupWithManager(mgr)
419+
420+
// Setup GlobalAccelerator validator only if enabled
421+
if controllerCFG.FeatureGates.Enabled(config.AGAController) {
422+
agawebhook.NewGlobalAcceleratorValidator(ctrl.Log, lbcMetricsCollector).SetupWithManager(mgr)
423+
}
418424
//+kubebuilder:scaffold:builder
419425

420426
go func() {

pkg/aga/model_build_listener.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package aga
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/pkg/errors"
7+
agaapi "sigs.k8s.io/aws-load-balancer-controller/apis/aga/v1beta1"
8+
agamodel "sigs.k8s.io/aws-load-balancer-controller/pkg/model/aga"
9+
"sigs.k8s.io/aws-load-balancer-controller/pkg/model/core"
10+
)
11+
12+
// listenerBuilder builds Listener model resources
13+
type listenerBuilder interface {
14+
Build(ctx context.Context, stack core.Stack, accelerator *agamodel.Accelerator, listeners []agaapi.GlobalAcceleratorListener) ([]*agamodel.Listener, error)
15+
}
16+
17+
// NewListenerBuilder constructs new listenerBuilder
18+
func NewListenerBuilder() listenerBuilder {
19+
return &defaultListenerBuilder{}
20+
}
21+
22+
var _ listenerBuilder = &defaultListenerBuilder{}
23+
24+
type defaultListenerBuilder struct{}
25+
26+
// Build builds Listener model resources
27+
func (b *defaultListenerBuilder) Build(ctx context.Context, stack core.Stack, accelerator *agamodel.Accelerator, listeners []agaapi.GlobalAcceleratorListener) ([]*agamodel.Listener, error) {
28+
if listeners == nil || len(listeners) == 0 {
29+
return nil, nil
30+
}
31+
32+
var result []*agamodel.Listener
33+
for i, listener := range listeners {
34+
listenerModel, err := buildListener(ctx, stack, accelerator, listener, i)
35+
if err != nil {
36+
return nil, err
37+
}
38+
result = append(result, listenerModel)
39+
}
40+
return result, nil
41+
}
42+
43+
// buildListener builds a single Listener model resource
44+
func buildListener(ctx context.Context, stack core.Stack, accelerator *agamodel.Accelerator, listener agaapi.GlobalAcceleratorListener, index int) (*agamodel.Listener, error) {
45+
spec, err := buildListenerSpec(ctx, accelerator, listener)
46+
if err != nil {
47+
return nil, err
48+
}
49+
50+
resourceID := fmt.Sprintf("Listener-%d", index)
51+
listenerModel := agamodel.NewListener(stack, resourceID, spec, accelerator)
52+
return listenerModel, nil
53+
}
54+
55+
// buildListenerSpec builds the ListenerSpec for a single Listener model resource
56+
func buildListenerSpec(ctx context.Context, accelerator *agamodel.Accelerator, listener agaapi.GlobalAcceleratorListener) (agamodel.ListenerSpec, error) {
57+
protocol, err := buildListenerProtocol(ctx, listener)
58+
if err != nil {
59+
return agamodel.ListenerSpec{}, err
60+
}
61+
62+
portRanges, err := buildListenerPortRanges(ctx, listener)
63+
if err != nil {
64+
return agamodel.ListenerSpec{}, err
65+
}
66+
67+
clientAffinity := buildListenerClientAffinity(ctx, listener)
68+
69+
return agamodel.ListenerSpec{
70+
AcceleratorARN: accelerator.AcceleratorARN(),
71+
Protocol: protocol,
72+
PortRanges: portRanges,
73+
ClientAffinity: clientAffinity,
74+
}, nil
75+
}
76+
77+
// buildListenerProtocol determines the protocol for the listener
78+
func buildListenerProtocol(_ context.Context, listener agaapi.GlobalAcceleratorListener) (agamodel.Protocol, error) {
79+
if listener.Protocol == nil {
80+
// TODO: Auto-discovery feature - Auto-determine protocol from endpoints if nil
81+
// For now, default to TCP
82+
return agamodel.ProtocolTCP, nil
83+
}
84+
85+
switch *listener.Protocol {
86+
case agaapi.GlobalAcceleratorProtocolTCP:
87+
return agamodel.ProtocolTCP, nil
88+
case agaapi.GlobalAcceleratorProtocolUDP:
89+
return agamodel.ProtocolUDP, nil
90+
default:
91+
return "", errors.Errorf("unsupported protocol: %s", *listener.Protocol)
92+
}
93+
}
94+
95+
// buildListenerPortRanges determines the port ranges for the listener
96+
func buildListenerPortRanges(_ context.Context, listener agaapi.GlobalAcceleratorListener) ([]agamodel.PortRange, error) {
97+
if listener.PortRanges == nil {
98+
// TODO: Auto-discovery feature - Auto-determine port ranges from endpoints if nil
99+
// For now, default to port 80
100+
return []agamodel.PortRange{{
101+
FromPort: 80,
102+
ToPort: 80,
103+
}}, nil
104+
}
105+
106+
var portRanges []agamodel.PortRange
107+
for _, pr := range *listener.PortRanges {
108+
// Required validations are already done webhooks and CEL
109+
portRanges = append(portRanges, agamodel.PortRange{
110+
FromPort: pr.FromPort,
111+
ToPort: pr.ToPort,
112+
})
113+
}
114+
return portRanges, nil
115+
}
116+
117+
// buildListenerClientAffinity determines the client affinity for the listener
118+
func buildListenerClientAffinity(_ context.Context, listener agaapi.GlobalAcceleratorListener) agamodel.ClientAffinity {
119+
switch listener.ClientAffinity {
120+
case agaapi.ClientAffinitySourceIP:
121+
return agamodel.ClientAffinitySourceIP
122+
case agaapi.ClientAffinityNone:
123+
return agamodel.ClientAffinityNone
124+
default:
125+
// Default to NONE as per AWS Global Accelerator behavior
126+
return agamodel.ClientAffinityNone
127+
}
128+
}

0 commit comments

Comments
 (0)