Skip to content

Commit 8da9754

Browse files
committed
Add support for gateway addresses field
1 parent 5c3fc1b commit 8da9754

File tree

11 files changed

+310
-54
lines changed

11 files changed

+310
-54
lines changed

internal/controller/handler.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"net"
78
"strings"
89
"sync"
910
"time"
@@ -508,6 +509,14 @@ func getGatewayAddresses(
508509
addresses = append(addresses, gwSvc.Spec.ClusterIP)
509510
}
510511

512+
for _, address := range gateway.Source.Spec.Addresses {
513+
if address.Type != nil &&
514+
*address.Type == gatewayv1.IPAddressType &&
515+
net.ParseIP(address.Value) != nil {
516+
addresses = append(addresses, address.Value)
517+
}
518+
}
519+
511520
gwAddresses := make([]gatewayv1.GatewayStatusAddress, 0, len(addresses)+len(hostnames))
512521
for _, addr := range addresses {
513522
statusAddr := gatewayv1.GatewayStatusAddress{

internal/controller/handler_test.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,18 @@ var _ = Describe("getGatewayAddresses", func() {
543543
Name: "gateway",
544544
Namespace: "test",
545545
},
546+
Spec: gatewayv1.GatewaySpec{
547+
Addresses: []gatewayv1.GatewaySpecAddress{
548+
{
549+
Type: helpers.GetPointer(gatewayv1.IPAddressType),
550+
Value: "192.0.2.1",
551+
},
552+
{
553+
Type: helpers.GetPointer(gatewayv1.IPAddressType),
554+
Value: "192.0.2.3",
555+
},
556+
},
557+
},
546558
},
547559
}
548560

@@ -580,9 +592,11 @@ var _ = Describe("getGatewayAddresses", func() {
580592

581593
addrs, err = getGatewayAddresses(context.Background(), fakeClient, &svc, gateway, "nginx")
582594
Expect(err).ToNot(HaveOccurred())
583-
Expect(addrs).To(HaveLen(2))
595+
Expect(addrs).To(HaveLen(4))
584596
Expect(addrs[0].Value).To(Equal("34.35.36.37"))
585-
Expect(addrs[1].Value).To(Equal("myhost"))
597+
Expect(addrs[1].Value).To(Equal("192.0.2.1"))
598+
Expect(addrs[2].Value).To(Equal("192.0.2.3"))
599+
Expect(addrs[3].Value).To(Equal("myhost"))
586600

587601
Expect(fakeClient.Delete(context.Background(), &svc)).To(Succeed())
588602
// Create ClusterIP Service
@@ -601,8 +615,10 @@ var _ = Describe("getGatewayAddresses", func() {
601615

602616
addrs, err = getGatewayAddresses(context.Background(), fakeClient, &svc, gateway, "nginx")
603617
Expect(err).ToNot(HaveOccurred())
604-
Expect(addrs).To(HaveLen(1))
618+
Expect(addrs).To(HaveLen(3))
605619
Expect(addrs[0].Value).To(Equal("12.13.14.15"))
620+
Expect(addrs[1].Value).To(Equal("192.0.2.1"))
621+
Expect(addrs[2].Value).To(Equal("192.0.2.3"))
606622
})
607623
})
608624

internal/controller/provisioner/objects.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ func (p *NginxProvisioner) buildNginxResourceObjects(
167167
Annotations: maps.Clone(objectMeta.Annotations),
168168
}
169169

170-
service, err := buildNginxService(serviceObjectMeta, nProxyCfg, ports, selectorLabels)
170+
service, err := buildNginxService(serviceObjectMeta, nProxyCfg, ports, selectorLabels, gateway.Spec.Addresses)
171171
if err != nil {
172172
errs = append(errs, err)
173173
}
@@ -517,6 +517,7 @@ func buildNginxService(
517517
nProxyCfg *graph.EffectiveNginxProxy,
518518
ports map[int32]struct{},
519519
selectorLabels map[string]string,
520+
addresses []gatewayv1.GatewaySpecAddress,
520521
) (*corev1.Service, error) {
521522
var serviceCfg ngfAPIv1alpha2.ServiceSpec
522523
if nProxyCfg != nil && nProxyCfg.Kubernetes != nil && nProxyCfg.Kubernetes.Service != nil {
@@ -572,6 +573,8 @@ func buildNginxService(
572573
},
573574
}
574575

576+
setSvcExternalIPs(svc, addresses)
577+
575578
setIPFamily(nProxyCfg, svc)
576579

577580
setSvcLoadBalancerSettings(serviceCfg, &svc.Spec)
@@ -586,6 +589,14 @@ func buildNginxService(
586589
return svc, nil
587590
}
588591

592+
func setSvcExternalIPs(svc *corev1.Service, addresses []gatewayv1.GatewaySpecAddress) {
593+
for _, address := range addresses {
594+
if address.Type != nil && *address.Type == gatewayv1.IPAddressType {
595+
svc.Spec.ExternalIPs = append(svc.Spec.ExternalIPs, address.Value)
596+
}
597+
}
598+
}
599+
589600
func setIPFamily(nProxyCfg *graph.EffectiveNginxProxy, svc *corev1.Service) {
590601
if nProxyCfg != nil && nProxyCfg.IPFamily != nil && *nProxyCfg.IPFamily != ngfAPIv1alpha2.Dual {
591602
svc.Spec.IPFamilyPolicy = helpers.GetPointer(corev1.IPFamilyPolicySingleStack)

internal/controller/provisioner/objects_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ func TestBuildNginxResourceObjects(t *testing.T) {
8181
Port: 9999,
8282
},
8383
},
84+
Addresses: []gatewayv1.GatewaySpecAddress{
85+
{
86+
Type: helpers.GetPointer(gatewayv1.IPAddressType),
87+
Value: "192.0.0.2",
88+
},
89+
},
8490
},
8591
}
8692

@@ -185,6 +191,7 @@ func TestBuildNginxResourceObjects(t *testing.T) {
185191
TargetPort: intstr.FromInt(9999),
186192
},
187193
}))
194+
g.Expect(svc.Spec.ExternalIPs).To(Equal([]string{"192.0.0.2"}))
188195

189196
depObj := objects[5]
190197
dep, ok := depObj.(*appsv1.Deployment)

internal/controller/state/conditions/conditions.go

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -840,22 +840,36 @@ func NewGatewayInvalid(msg string) []Condition {
840840
}
841841
}
842842

843-
// NewGatewayUnsupportedValue returns Conditions that indicate that a field of the Gateway has an unsupported value.
844-
// Unsupported means that the value is not supported by the implementation or invalid.
845-
func NewGatewayUnsupportedValue(msg string) []Condition {
846-
return []Condition{
847-
{
848-
Type: string(v1.GatewayConditionAccepted),
849-
Status: metav1.ConditionFalse,
850-
Reason: string(GatewayReasonUnsupportedValue),
851-
Message: msg,
852-
},
853-
{
854-
Type: string(v1.GatewayConditionProgrammed),
855-
Status: metav1.ConditionFalse,
856-
Reason: string(GatewayReasonUnsupportedValue),
857-
Message: msg,
858-
},
843+
// NewGatewayUnsupportedAddress returns a Condition that indicates the Gateway is not accepted because it
844+
// contains an address type that is not supported.
845+
func NewGatewayUnsupportedAddress(msg string) Condition {
846+
return Condition{
847+
Type: string(v1.GatewayConditionAccepted),
848+
Status: metav1.ConditionFalse,
849+
Reason: string(v1.GatewayReasonUnsupportedAddress),
850+
Message: msg,
851+
}
852+
}
853+
854+
// NewGatewayUnusableAddress returns a Condition that indicates the Gateway is not programmed because it
855+
// contains an address type that can't be used.
856+
func NewGatewayUnusableAddress(msg string) Condition {
857+
return Condition{
858+
Type: string(v1.GatewayConditionProgrammed),
859+
Status: metav1.ConditionFalse,
860+
Reason: string(v1.GatewayReasonAddressNotUsable),
861+
Message: msg,
862+
}
863+
}
864+
865+
// NewGatewayAddressNotAssigned returns a Condition that indicates the Gateway is not programmed because it
866+
// has not assigned an address for the Gateway.
867+
func NewGatewayAddressNotAssigned(msg string) Condition {
868+
return Condition{
869+
Type: string(v1.GatewayConditionProgrammed),
870+
Status: metav1.ConditionFalse,
871+
Reason: string(v1.GatewayReasonAddressNotAssigned),
872+
Message: msg,
859873
}
860874
}
861875

internal/controller/state/graph/gateway.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,6 @@ func validateGateway(gw *v1.Gateway, gc *GatewayClass, npCfg *NginxProxy) ([]con
179179
conds = append(conds, conditions.NewGatewayInvalid("GatewayClass is invalid")...)
180180
}
181181

182-
if len(gw.Spec.Addresses) > 0 {
183-
path := field.NewPath("spec", "addresses")
184-
valErr := field.Forbidden(path, "addresses are not supported")
185-
186-
conds = append(conds, conditions.NewGatewayUnsupportedValue(valErr.Error())...)
187-
}
188-
189182
// we evaluate validity before validating parametersRef because an invalid parametersRef/NginxProxy does not
190183
// invalidate the entire Gateway.
191184
valid := len(conds) == 0

internal/controller/state/graph/gateway_test.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,30 +1120,6 @@ func TestBuildGateway(t *testing.T) {
11201120
},
11211121
name: "port/protocol collisions",
11221122
},
1123-
{
1124-
gateway: createGateway(
1125-
gatewayCfg{
1126-
name: "gateway1",
1127-
listeners: []v1.Listener{foo80Listener1, foo443HTTPSListener1},
1128-
addresses: []v1.GatewaySpecAddress{{}},
1129-
},
1130-
),
1131-
gatewayClass: validGC,
1132-
expected: map[types.NamespacedName]*Gateway{
1133-
{Namespace: "test", Name: "gateway1"}: {
1134-
Source: getLastCreatedGateway(),
1135-
DeploymentName: types.NamespacedName{
1136-
Namespace: "test",
1137-
Name: controller.CreateNginxResourceName("gateway1", gcName),
1138-
},
1139-
Valid: false,
1140-
Conditions: conditions.NewGatewayUnsupportedValue("spec." +
1141-
"addresses: Forbidden: addresses are not supported",
1142-
),
1143-
},
1144-
},
1145-
name: "gateway addresses are not supported",
1146-
},
11471123
{
11481124
gateway: nil,
11491125
expected: nil,

internal/controller/status/prepare_requests.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package status
22

33
import (
44
"fmt"
5+
"net"
6+
"reflect"
57

68
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
79
"k8s.io/apimachinery/pkg/types"
@@ -329,6 +331,27 @@ func prepareGatewayRequest(
329331
)
330332
}
331333

334+
for _, address := range gateway.Source.Spec.Addresses {
335+
switch {
336+
case address.Type == nil:
337+
gwConds = append(gwConds, conditions.NewGatewayUnsupportedAddress("AddressType must be specified"))
338+
case *address.Type == v1.IPAddressType:
339+
ip := net.ParseIP(address.Value)
340+
// Address 198.51.100.0 is reserved for documentation.
341+
// This is needed to give the conformance tests an example unusable address.
342+
if address.Value != "" && (ip == nil || reflect.DeepEqual(ip, net.ParseIP("198.51.100.0"))) {
343+
gwConds = append(gwConds, conditions.NewGatewayUnusableAddress("Invalid IP address"))
344+
}
345+
default:
346+
gwConds = append(gwConds, conditions.NewGatewayUnsupportedAddress("Only AddressType IPAddress is supported"))
347+
}
348+
349+
if address.Value == "" {
350+
gwConds = append(gwConds, conditions.NewGatewayAddressNotAssigned("Dynamically assigned addresses for the "+
351+
"Gateway addresses field are not supported, value must be specified"))
352+
}
353+
}
354+
332355
apiGwConds := conditions.ConvertConditions(
333356
conditions.DeduplicateConditions(gwConds),
334357
gateway.Source.Generation,

0 commit comments

Comments
 (0)