Skip to content

Commit 37d0f99

Browse files
committed
Don't allow gateway DNS records to be created if they clash with existing ingress controllers.
1 parent db0e811 commit 37d0f99

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

pkg/operator/controller/gateway-service-dns/controller.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
corev1 "k8s.io/api/core/v1"
1818

1919
configv1 "github.com/openshift/api/config/v1"
20+
operatorv1 "github.com/openshift/api/operator/v1"
2021
iov1 "github.com/openshift/api/operatoringress/v1"
2122

2223
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -241,8 +242,18 @@ func (r *reconciler) ensureDNSRecordsForGateway(ctx context.Context, gateway *ga
241242
Name: service.Name,
242243
UID: service.UID,
243244
}
245+
ics := operatorv1.IngressControllerList{}
246+
if err := r.cache.List(ctx, &ics); err != nil {
247+
log.Error(err, "failed to list Ingress Controllers")
248+
return []error{err}
249+
}
244250
var errs []error
245251
for _, domain := range domains {
252+
// Check if the domain matches one from an existing ingress controller. If so, log an error and ignore the invalid domain.
253+
if err := domainClashes(domain, ics); err != nil {
254+
log.Error(fmt.Errorf("error creating DNS record for gateway %s: %w", gateway.Name, err), "ignoring invalid gateway domain")
255+
continue
256+
}
246257
name := operatorcontroller.GatewayDNSRecordName(gateway, domain)
247258
dnsPolicy := iov1.UnmanagedDNS
248259
if dnsrecord.ManageDNSForDomain(domain, infraConfig.Status.PlatformStatus, dnsConfig) {
@@ -254,6 +265,20 @@ func (r *reconciler) ensureDNSRecordsForGateway(ctx context.Context, gateway *ga
254265
return errs
255266
}
256267

268+
// domainClashes checks if domain clashes with any of the wildcard records of the ingress controllers in icList. If
269+
// there is a clash, an error is returned describing which ingress controller already uses the specified domain name.
270+
func domainClashes(domain string, icList operatorv1.IngressControllerList) error {
271+
for _, ic := range icList.Items {
272+
if len(ic.Status.Domain) == 0 {
273+
continue
274+
}
275+
if strings.Compare(domain, "*."+ic.Status.Domain+".") == 0 {
276+
return fmt.Errorf("listener hostname %q conflicts with the domain from ingress controller %s.", domain, ic.Name)
277+
}
278+
}
279+
return nil
280+
}
281+
257282
// deleteStaleDNSRecordsForGateway deletes any DNSRecord CRs that are associated
258283
// with the given gateway but specify a DNS name that is not in the given set of
259284
// domains. Such DNSRecord CRs may exist if a hostname was modified or deleted

pkg/operator/controller/gateway-service-dns/controller_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
gatewayapiv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
1212

1313
configv1 "github.com/openshift/api/config/v1"
14+
operatorv1 "github.com/openshift/api/operator/v1"
1415
iov1 "github.com/openshift/api/operatoringress/v1"
1516

1617
corev1 "k8s.io/api/core/v1"
@@ -41,6 +42,17 @@ func Test_Reconcile(t *testing.T) {
4142
},
4243
},
4344
}
45+
ic := func(name, domain string) *operatorv1.IngressController {
46+
return &operatorv1.IngressController{
47+
ObjectMeta: metav1.ObjectMeta{
48+
Namespace: "openshift-ingress-operator",
49+
Name: name,
50+
},
51+
Status: operatorv1.IngressControllerStatus{
52+
Domain: domain,
53+
},
54+
}
55+
}
4456
gw := func(name string, listeners ...gatewayapiv1beta1.Listener) *gatewayapiv1beta1.Gateway {
4557
return &gatewayapiv1beta1.Gateway{
4658
ObjectMeta: metav1.ObjectMeta{
@@ -127,6 +139,7 @@ func Test_Reconcile(t *testing.T) {
127139
infraConfig,
128140
gw("example-gateway", l("stage-http", "*.stage.example.com", 80)),
129141
svc("example-gateway", gatewayManagedLabel, exampleGatewayLabel, ingHost("lb.example.com")),
142+
ic("default", "apps.example.com"),
130143
},
131144
reconcileRequest: req("openshift-ingress", "example-gateway"),
132145
expectCreate: []client.Object{},
@@ -140,6 +153,7 @@ func Test_Reconcile(t *testing.T) {
140153
dnsConfig,
141154
gw("example-gateway", l("stage-http", "*.stage.example.com", 80)),
142155
svc("example-gateway", gatewayManagedLabel, exampleGatewayLabel, ingHost("lb.example.com")),
156+
ic("default", "apps.example.com"),
143157
},
144158
reconcileRequest: req("openshift-ingress", "example-gateway"),
145159
expectCreate: []client.Object{},
@@ -153,6 +167,7 @@ func Test_Reconcile(t *testing.T) {
153167
dnsConfig, infraConfig,
154168
gw("example-gateway"),
155169
svc("example-gateway", gatewayManagedLabel, exampleGatewayLabel, ingHost("lb.example.com")),
170+
ic("default", "apps.example.com"),
156171
},
157172
reconcileRequest: req("openshift-ingress", "example-gateway"),
158173
expectCreate: []client.Object{},
@@ -170,6 +185,7 @@ func Test_Reconcile(t *testing.T) {
170185
l("prod-https", "*.prod.example.com", 443),
171186
),
172187
svc("example-gateway", gatewayManagedLabel, exampleGatewayLabel, ingHost("lb.example.com")),
188+
ic("default", "apps.example.com"),
173189
},
174190
reconcileRequest: req("openshift-ingress", "example-gateway"),
175191
expectCreate: []client.Object{
@@ -190,6 +206,7 @@ func Test_Reconcile(t *testing.T) {
190206
),
191207
svc("example-gateway", gatewayManagedLabel, exampleGatewayLabel, ingHost("newlb.example.com")),
192208
dnsrecord("example-gateway-7bdcfc8f68-wildcard", "*.example.com.", iov1.ManagedDNS, exampleGatewayLabel, "oldlb.example.com"),
209+
ic("default", "apps.example.com"),
193210
},
194211
reconcileRequest: req("openshift-ingress", "example-gateway"),
195212
expectCreate: []client.Object{},
@@ -208,6 +225,7 @@ func Test_Reconcile(t *testing.T) {
208225
),
209226
svc("example-gateway", gatewayManagedLabel, exampleGatewayLabel, ingHost("lb.example.com")),
210227
dnsrecord("example-gateway-64754456b8-wildcard", "*.old.example.com.", iov1.ManagedDNS, exampleGatewayLabel, "lb.example.com"),
228+
ic("default", "apps.example.com"),
211229
},
212230
reconcileRequest: req("openshift-ingress", "example-gateway"),
213231
expectCreate: []client.Object{
@@ -224,6 +242,7 @@ func Test_Reconcile(t *testing.T) {
224242
dnsConfig, infraConfig,
225243
gw("example-gateway", l("stage-http", "*.stage.example.com", 80), l("stage-https", "*.stage.example.com", 443)),
226244
svc("example-gateway", gatewayManagedLabel, exampleGatewayLabel, ingHost("lb.example.com")),
245+
ic("default", "apps.example.com"),
227246
},
228247
reconcileRequest: req("openshift-ingress", "example-gateway"),
229248
expectCreate: []client.Object{
@@ -238,6 +257,7 @@ func Test_Reconcile(t *testing.T) {
238257
dnsConfig, infraConfig,
239258
gw("example-gateway", l("http", "*.foo.com", 80)),
240259
svc("example-gateway", gatewayManagedLabel, exampleGatewayLabel, ingHost("lb.example.com")),
260+
ic("default", "apps.example.com"),
241261
},
242262
reconcileRequest: req("openshift-ingress", "example-gateway"),
243263
expectCreate: []client.Object{
@@ -246,12 +266,54 @@ func Test_Reconcile(t *testing.T) {
246266
expectUpdate: []client.Object{},
247267
expectDelete: []client.Object{},
248268
},
269+
{
270+
name: "gateway with two unique host names, one of which clashes with an existing ingress controller",
271+
existingObjects: []runtime.Object{
272+
dnsConfig, infraConfig,
273+
gw(
274+
"example-gateway",
275+
l("stage-https", "*.stage.apps.example.com", 443),
276+
l("apps-https", "*.apps.example.com", 443),
277+
),
278+
svc("example-gateway", gatewayManagedLabel, exampleGatewayLabel, ingHost("lb.example.com")),
279+
ic("default", "apps.example.com"),
280+
},
281+
reconcileRequest: req("openshift-ingress", "example-gateway"),
282+
expectCreate: []client.Object{
283+
dnsrecord("example-gateway-644bf77744-wildcard", "*.stage.apps.example.com.", iov1.ManagedDNS, exampleGatewayLabel, "lb.example.com"),
284+
},
285+
expectUpdate: []client.Object{},
286+
expectDelete: []client.Object{},
287+
},
288+
{
289+
name: "gateway with two unique host names, neither of which clashes with an existing ingress controller",
290+
existingObjects: []runtime.Object{
291+
dnsConfig, infraConfig,
292+
gw(
293+
"example-gateway",
294+
l("stage-https", "*.stage.apps.example.com", 443),
295+
// apps.example.com looks like it'll clash with the default ic below, but the ic creates a record
296+
// for *.apps.example.com, which doesn't actually clash with apps.example.com
297+
l("apps-https", "apps.example.com", 443),
298+
),
299+
svc("example-gateway", gatewayManagedLabel, exampleGatewayLabel, ingHost("lb.example.com")),
300+
ic("default", "apps.example.com"),
301+
},
302+
reconcileRequest: req("openshift-ingress", "example-gateway"),
303+
expectCreate: []client.Object{
304+
dnsrecord("example-gateway-644bf77744-wildcard", "*.stage.apps.example.com.", iov1.ManagedDNS, exampleGatewayLabel, "lb.example.com"),
305+
dnsrecord("example-gateway-54b5446744-wildcard", "apps.example.com.", iov1.ManagedDNS, exampleGatewayLabel, "lb.example.com"),
306+
},
307+
expectUpdate: []client.Object{},
308+
expectDelete: []client.Object{},
309+
},
249310
}
250311

251312
scheme := runtime.NewScheme()
252313
iov1.AddToScheme(scheme)
253314
corev1.AddToScheme(scheme)
254315
gatewayapiv1beta1.AddToScheme(scheme)
316+
operatorv1.AddToScheme(scheme)
255317

256318
for _, tc := range tests {
257319
t.Run(tc.name, func(t *testing.T) {

0 commit comments

Comments
 (0)