Skip to content

Commit c40ee7f

Browse files
committed
feat: Support TargetGroupBinding on targets outside the cluster's VPC
1 parent b63a294 commit c40ee7f

File tree

5 files changed

+70
-3
lines changed

5 files changed

+70
-3
lines changed

apis/elbv2/v1beta1/targetgroupbinding_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ type TargetGroupBindingSpec struct {
145145
// ipAddressType specifies whether the target group is of type IPv4 or IPv6. If unspecified, it will be automatically inferred.
146146
// +optional
147147
IPAddressType *TargetGroupIPAddressType `json:"ipAddressType,omitempty"`
148+
149+
// VpcId is the VPC of the TargetGroup. If unspecified, it will be automatically inferred.
150+
// +optional
151+
VpcId string `json:"vpcId,omitempty"`
148152
}
149153

150154
// TargetGroupBindingStatus defines the observed state of TargetGroupBinding

config/crd/bases/elbv2.k8s.aws_targetgroupbindings.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,10 @@ spec:
386386
- instance
387387
- ip
388388
type: string
389+
vpcId:
390+
description: VpcId is the VPC of the TargetGroup. If unspecified,
391+
it will be automatically inferred.
392+
type: string
389393
required:
390394
- serviceRef
391395
- targetGroupARN

pkg/targetgroupbinding/resource_manager.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ func (m *defaultResourceManager) reconcileWithIPTargetType(ctx context.Context,
127127
}
128128

129129
tgARN := tgb.Spec.TargetGroupARN
130+
vpcId := tgb.Spec.VpcId
130131
targets, err := m.targetsManager.ListTargets(ctx, tgARN)
131132
if err != nil {
132133
return err
@@ -145,7 +146,7 @@ func (m *defaultResourceManager) reconcileWithIPTargetType(ctx context.Context,
145146
}
146147
}
147148
if len(unmatchedEndpoints) > 0 {
148-
if err := m.registerPodEndpoints(ctx, tgARN, unmatchedEndpoints); err != nil {
149+
if err := m.registerPodEndpoints(ctx, tgARN, vpcId, unmatchedEndpoints); err != nil {
149150
return err
150151
}
151152
}
@@ -382,8 +383,13 @@ func (m *defaultResourceManager) deregisterTargets(ctx context.Context, tgARN st
382383
return m.targetsManager.DeregisterTargets(ctx, tgARN, sdkTargets)
383384
}
384385

385-
func (m *defaultResourceManager) registerPodEndpoints(ctx context.Context, tgARN string, endpoints []backend.PodEndpoint) error {
386-
vpcInfo, err := m.vpcInfoProvider.FetchVPCInfo(ctx, m.vpcID)
386+
func (m *defaultResourceManager) registerPodEndpoints(ctx context.Context, tgARN, tgVpcId string, endpoints []backend.PodEndpoint) error {
387+
vpcId := m.vpcID
388+
// Target group is in a different VPC from the cluster's VPC
389+
if tgVpcId != m.vpcID {
390+
vpcId = tgVpcId
391+
}
392+
vpcInfo, err := m.vpcInfoProvider.FetchVPCInfo(ctx, vpcId)
387393
if err != nil {
388394
return err
389395
}

webhooks/elbv2/targetgroupbinding_mutator.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ func (m *targetGroupBindingMutator) MutateCreate(ctx context.Context, obj runtim
4343
if err := m.defaultingIPAddressType(ctx, tgb); err != nil {
4444
return nil, err
4545
}
46+
if err := m.defaultingVpcId(ctx, tgb); err != nil {
47+
return nil, err
48+
}
4649
return tgb, nil
4750
}
4851

@@ -85,6 +88,18 @@ func (m *targetGroupBindingMutator) defaultingIPAddressType(ctx context.Context,
8588
return nil
8689
}
8790

91+
func (m *targetGroupBindingMutator) defaultingVpcId(ctx context.Context, tgb *elbv2api.TargetGroupBinding) error {
92+
if tgb.Spec.VpcId != "" {
93+
return nil
94+
}
95+
vpcId, err := m.getVpcIdFromAWS(ctx, tgb.Spec.TargetGroupARN)
96+
if err != nil {
97+
return errors.Wrap(err, "unable to get target group VpcId")
98+
}
99+
tgb.Spec.VpcId = vpcId
100+
return nil
101+
}
102+
88103
func (m *targetGroupBindingMutator) obtainSDKTargetTypeFromAWS(ctx context.Context, tgARN string) (string, error) {
89104
targetGroup, err := m.getTargetGroupFromAWS(ctx, tgARN)
90105
if err != nil {
@@ -125,6 +140,14 @@ func (m *targetGroupBindingMutator) getTargetGroupFromAWS(ctx context.Context, t
125140
return tgList[0], nil
126141
}
127142

143+
func (m *targetGroupBindingMutator) getVpcIdFromAWS(ctx context.Context, tgARN string) (string, error) {
144+
targetGroup, err := m.getTargetGroupFromAWS(ctx, tgARN)
145+
if err != nil {
146+
return "", err
147+
}
148+
return awssdk.StringValue(targetGroup.VpcId), nil
149+
}
150+
128151
// +kubebuilder:webhook:path=/mutate-elbv2-k8s-aws-v1beta1-targetgroupbinding,mutating=true,failurePolicy=fail,groups=elbv2.k8s.aws,resources=targetgroupbindings,verbs=create;update,versions=v1beta1,name=mtargetgroupbinding.elbv2.k8s.aws,sideEffects=None,webhookVersions=v1,admissionReviewVersions=v1beta1
129152

130153
func (m *targetGroupBindingMutator) SetupWithManager(mgr ctrl.Manager) {

webhooks/elbv2/targetgroupbinding_validator.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ func (v *targetGroupBindingValidator) ValidateCreate(ctx context.Context, obj ru
5555
if err := v.checkTargetGroupIPAddressType(ctx, tgb); err != nil {
5656
return err
5757
}
58+
if err := v.checkTargetGroupVpcId(ctx, tgb); err != nil {
59+
return err
60+
}
5861
return nil
5962
}
6063

@@ -83,6 +86,9 @@ func (v *targetGroupBindingValidator) checkRequiredFields(tgb *elbv2api.TargetGr
8386
if tgb.Spec.TargetType == nil {
8487
absentRequiredFields = append(absentRequiredFields, "spec.targetType")
8588
}
89+
if tgb.Spec.VpcId == "" {
90+
absentRequiredFields = append(absentRequiredFields, "spec.vpcId")
91+
}
8692
if len(absentRequiredFields) != 0 {
8793
return errors.Errorf("%s must specify these fields: %s", "TargetGroupBinding", strings.Join(absentRequiredFields, ","))
8894
}
@@ -108,6 +114,10 @@ func (v *targetGroupBindingValidator) checkImmutableFields(tgb *elbv2api.TargetG
108114
if oldTGB.Spec.IPAddressType != nil && tgb.Spec.IPAddressType != nil && (*oldTGB.Spec.IPAddressType) != (*tgb.Spec.IPAddressType) {
109115
changedImmutableFields = append(changedImmutableFields, "spec.ipAddressType")
110116
}
117+
if (tgb.Spec.VpcId != "" && oldTGB.Spec.VpcId != "" && (tgb.Spec.VpcId) != (oldTGB.Spec.VpcId)) ||
118+
(tgb.Spec.VpcId == "") != (oldTGB.Spec.VpcId == "") {
119+
changedImmutableFields = append(changedImmutableFields, "spec.vpcId")
120+
}
111121
if len(changedImmutableFields) != 0 {
112122
return errors.Errorf("%s update may not change these fields: %s", "TargetGroupBinding", strings.Join(changedImmutableFields, ","))
113123
}
@@ -150,6 +160,18 @@ func (v *targetGroupBindingValidator) checkTargetGroupIPAddressType(ctx context.
150160
return nil
151161
}
152162

163+
// checkTargetGroupVpcId ensures VpcId matches with that on the AWS target group
164+
func (v *targetGroupBindingValidator) checkTargetGroupVpcId(ctx context.Context, tgb *elbv2api.TargetGroupBinding) error {
165+
vpcId, err := v.getVpcIdFromAWS(ctx, tgb.Spec.TargetGroupARN)
166+
if err != nil {
167+
return errors.Wrap(err, "unable to get target group VpcId")
168+
}
169+
if vpcId != tgb.Spec.VpcId {
170+
return errors.Errorf("invalid vpc Id %v doesnt match VpcId from TargetGroup %v", tgb.Spec.VpcId, tgb.Spec.TargetGroupARN)
171+
}
172+
return nil
173+
}
174+
153175
// getTargetGroupIPAddressTypeFromAWS returns the target group IP address type of AWS target group
154176
func (v *targetGroupBindingValidator) getTargetGroupIPAddressTypeFromAWS(ctx context.Context, tgARN string) (elbv2api.TargetGroupIPAddressType, error) {
155177
targetGroup, err := v.getTargetGroupFromAWS(ctx, tgARN)
@@ -183,6 +205,14 @@ func (v *targetGroupBindingValidator) getTargetGroupFromAWS(ctx context.Context,
183205
return tgList[0], nil
184206
}
185207

208+
func (v *targetGroupBindingValidator) getVpcIdFromAWS(ctx context.Context, tgARN string) (string, error) {
209+
targetGroup, err := v.getTargetGroupFromAWS(ctx, tgARN)
210+
if err != nil {
211+
return "", err
212+
}
213+
return awssdk.StringValue(targetGroup.VpcId), nil
214+
}
215+
186216
// +kubebuilder:webhook:path=/validate-elbv2-k8s-aws-v1beta1-targetgroupbinding,mutating=false,failurePolicy=fail,groups=elbv2.k8s.aws,resources=targetgroupbindings,verbs=create;update,versions=v1beta1,name=vtargetgroupbinding.elbv2.k8s.aws,sideEffects=None,webhookVersions=v1,admissionReviewVersions=v1beta1
187217

188218
func (v *targetGroupBindingValidator) SetupWithManager(mgr ctrl.Manager) {

0 commit comments

Comments
 (0)