Skip to content

Commit 9c12556

Browse files
Merge pull request #578 from stuggi/OSPRH-29710
[dnsmasq] Default local=/<namespace>.svc/ to resolve queries locally
2 parents ebbeea9 + 0e7f95a commit 9c12556

7 files changed

Lines changed: 137 additions & 29 deletions

File tree

apis/go.mod

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ go 1.24.4
44

55
require (
66
github.com/go-logr/logr v1.4.3
7-
github.com/onsi/gomega v1.39.1
8-
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981
7+
github.com/onsi/gomega v1.40.0
8+
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0
99
k8s.io/api v0.31.14
1010
k8s.io/apiextensions-apiserver v0.33.2
1111
k8s.io/apimachinery v0.31.14
@@ -40,7 +40,6 @@ require (
4040
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
4141
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
4242
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
43-
github.com/onsi/ginkgo/v2 v2.28.2 // indirect
4443
github.com/openshift/api v3.9.0+incompatible // indirect
4544
github.com/pkg/errors v0.9.1 // indirect
4645
github.com/prometheus/client_golang v1.22.0 // indirect

apis/go.sum

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,15 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd
7676
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
7777
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
7878
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
79+
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
7980
github.com/onsi/ginkgo/v2 v2.28.2 h1:DTrMfpqxiNUyQ3Y0zhn1n3cOO2euFgQPYIpkWwxVFps=
8081
github.com/onsi/ginkgo/v2 v2.28.2/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
81-
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
82-
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
82+
github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc=
83+
github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A=
8384
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e h1:E1OdwSpqWuDPCedyUt0GEdoAE+r5TXy7YS21yNEo+2U=
8485
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
85-
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981 h1:v1viH0gmNb+AXMg/0GxDcj8VUTdjVLotfOIGrNyMxHk=
86-
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981/go.mod h1:I/VBXZLdjk8DUGsEbB+Ha72JBFYYntP7Pm2FpEto9K8=
86+
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0 h1:vkFvn06Ns9qW4AbzFjFDu8ioosRmhkEZiDrO3DOQhLg=
87+
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0/go.mod h1:aIuG6lx3aS0vnXweRNdR/Q0SlfOsLIo0OzrqKK7C6xs=
8788
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
8889
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
8990
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -113,8 +114,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
113114
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
114115
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
115116
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
116-
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
117-
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
117+
go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
118+
go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
118119
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
119120
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
120121
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=

apis/network/v1beta1/dnsmasq_webhook.go

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@ limitations under the License.
1717
package v1beta1
1818

1919
import (
20+
"fmt"
21+
22+
annotations "github.com/openstack-k8s-operators/lib-common/modules/common/annotations"
23+
apierrors "k8s.io/apimachinery/pkg/api/errors"
2024
"k8s.io/apimachinery/pkg/runtime"
25+
"k8s.io/apimachinery/pkg/runtime/schema"
26+
"k8s.io/apimachinery/pkg/util/validation/field"
2127
logf "sigs.k8s.io/controller-runtime/pkg/log"
2228
"sigs.k8s.io/controller-runtime/pkg/webhook"
2329
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
24-
apierrors "k8s.io/apimachinery/pkg/api/errors"
25-
"k8s.io/apimachinery/pkg/runtime/schema"
26-
"k8s.io/apimachinery/pkg/util/validation/field"
2730
)
2831

2932
// DNSMasqDefaults -
@@ -48,20 +51,38 @@ var _ webhook.Defaulter = &DNSMasq{}
4851
func (r *DNSMasq) Default() {
4952
dnsmasqlog.Info("default", "name", r.Name)
5053

51-
r.Spec.Default()
54+
r.Spec.Default(r.Namespace)
55+
56+
ann := r.GetAnnotations()
57+
if _, exists := ann[annotations.ReconcileTriggerAnnotation]; exists {
58+
delete(ann, annotations.ReconcileTriggerAnnotation)
59+
r.SetAnnotations(ann)
60+
}
5261
}
5362

5463
// Default - set defaults for this DNSMasq spec
55-
func (spec *DNSMasqSpec) Default() {
64+
func (spec *DNSMasqSpec) Default(namespace string) {
5665
if spec.ContainerImage == "" {
5766
spec.ContainerImage = dnsMasqDefaults.ContainerImageURL
5867
}
59-
spec.DNSMasqSpecCore.Default()
68+
spec.DNSMasqSpecCore.Default(namespace)
6069
}
6170

6271
// Default - common defaults go here (for the OpenStackControlplane which uses this one)
63-
func (spec *DNSMasqSpecCore) Default() {
64-
// nothing here
72+
func (spec *DNSMasqSpecCore) Default(namespace string) {
73+
hasLocal := false
74+
for _, opt := range spec.Options {
75+
if opt.Key == "local" {
76+
hasLocal = true
77+
break
78+
}
79+
}
80+
if !hasLocal {
81+
spec.Options = append(spec.Options, DNSMasqOption{
82+
Key: "local",
83+
Values: []string{fmt.Sprintf("/%s.svc/", namespace)},
84+
})
85+
}
6586
}
6687

6788
var _ webhook.Validator = &DNSMasq{}

go.mod

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ require (
88
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.7.7
99
github.com/metallb/frr-k8s v0.0.15
1010
github.com/onsi/ginkgo/v2 v2.28.2
11-
github.com/onsi/gomega v1.39.1
11+
github.com/onsi/gomega v1.40.0
1212
github.com/openshift/api v3.9.0+incompatible
1313
github.com/openstack-k8s-operators/infra-operator/apis v0.0.0-00010101000000-000000000000
14-
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981
15-
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260417092244-81c71b39e981
16-
go.uber.org/zap v1.27.1
14+
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0
15+
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260506154724-30a976ba8ef0
16+
go.uber.org/zap v1.28.0
1717
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67
1818
k8s.io/api v0.31.14
1919
k8s.io/apiextensions-apiserver v0.33.2

go.sum

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,14 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
114114
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
115115
github.com/onsi/ginkgo/v2 v2.28.2 h1:DTrMfpqxiNUyQ3Y0zhn1n3cOO2euFgQPYIpkWwxVFps=
116116
github.com/onsi/ginkgo/v2 v2.28.2/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
117-
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
118-
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
117+
github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc=
118+
github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A=
119119
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e h1:E1OdwSpqWuDPCedyUt0GEdoAE+r5TXy7YS21yNEo+2U=
120120
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
121-
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981 h1:v1viH0gmNb+AXMg/0GxDcj8VUTdjVLotfOIGrNyMxHk=
122-
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981/go.mod h1:I/VBXZLdjk8DUGsEbB+Ha72JBFYYntP7Pm2FpEto9K8=
123-
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260417092244-81c71b39e981 h1:KAQ8T+Ri3JWgsyK1D6QybScMh6fpkYUUA+0ntnOiAl4=
124-
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260417092244-81c71b39e981/go.mod h1:dEjz8zHRIlP3vnMmWdHytlLeSZ6BHcIiSTPM7xTQxFg=
121+
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0 h1:vkFvn06Ns9qW4AbzFjFDu8ioosRmhkEZiDrO3DOQhLg=
122+
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0/go.mod h1:aIuG6lx3aS0vnXweRNdR/Q0SlfOsLIo0OzrqKK7C6xs=
123+
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260506154724-30a976ba8ef0 h1:mG3QhS/QWv9Y/AkZZ5OzO6hu6+l5oDXnI/Q5ZUbj6Zs=
124+
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260506154724-30a976ba8ef0/go.mod h1:ZYG9CQe7cOePOKQbenEZFA28kPdkUOe9QKbDRwGhEV0=
125125
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
126126
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
127127
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -186,8 +186,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
186186
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
187187
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
188188
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
189-
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
190-
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
189+
go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
190+
go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
191191
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
192192
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
193193
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=

internal/controller/network/dnsmasq_controller.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import (
4949
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
5050
dnsmasq "github.com/openstack-k8s-operators/infra-operator/internal/dnsmasq"
5151
common "github.com/openstack-k8s-operators/lib-common/modules/common"
52+
annotations "github.com/openstack-k8s-operators/lib-common/modules/common/annotations"
5253
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
5354
configmap "github.com/openstack-k8s-operators/lib-common/modules/common/configmap"
5455
deployment "github.com/openstack-k8s-operators/lib-common/modules/common/deployment"
@@ -58,6 +59,7 @@ import (
5859
common_rbac "github.com/openstack-k8s-operators/lib-common/modules/common/rbac"
5960
service "github.com/openstack-k8s-operators/lib-common/modules/common/service"
6061
util "github.com/openstack-k8s-operators/lib-common/modules/common/util"
62+
"github.com/openstack-k8s-operators/lib-common/modules/common/webhook"
6163
)
6264

6365
// DNSMasqReconciler reconciles a DNSMasq object
@@ -375,6 +377,30 @@ func (r *DNSMasqReconciler) reconcileNormal(ctx context.Context, instance *netwo
375377
Log := r.GetLogger(ctx)
376378
Log.Info("Reconciling Service")
377379

380+
// Ensure existing CRs get the default local=/<namespace>.svc/ option on
381+
// upgrade by triggering the webhook via a reconcile-trigger annotation.
382+
hasLocal := false
383+
for _, opt := range instance.Spec.Options {
384+
if opt.Key == "local" {
385+
hasLocal = true
386+
break
387+
}
388+
}
389+
if !hasLocal {
390+
result, err := webhook.EnsureWebhookTrigger(
391+
ctx,
392+
instance,
393+
annotations.ReconcileTriggerAnnotation,
394+
"DNSMasq local option defaulting",
395+
Log,
396+
0, // use default 5 minute timeout
397+
)
398+
if err != nil {
399+
return ctrl.Result{}, err
400+
}
401+
return result, nil
402+
}
403+
378404
serviceLabels := map[string]string{
379405
common.AppSelector: dnsmasq.ServiceName,
380406
}

test/functional/dnsmasq_controller_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
corev1 "k8s.io/api/core/v1"
2626
"k8s.io/apimachinery/pkg/types"
2727

28+
networkv1 "github.com/openstack-k8s-operators/infra-operator/apis/network/v1beta1"
2829
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
2930
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
3031
"github.com/openstack-k8s-operators/lib-common/modules/common/util"
@@ -141,6 +142,8 @@ var _ = Describe("DNSMasq controller", func() {
141142
ContainSubstring("server=1.1.1.1"))
142143
Expect(configData.Data[dnsMasqName.Name]).Should(
143144
ContainSubstring("no-negcache\n"))
145+
Expect(configData.Data[dnsMasqName.Name]).Should(
146+
ContainSubstring(fmt.Sprintf("local=/%s.svc/", namespace)))
144147
Expect(configData.Labels["dnsmasq.openstack.org/name"]).To(Equal(dnsMasqName.Name))
145148
})
146149

@@ -273,6 +276,64 @@ var _ = Describe("DNSMasq controller", func() {
273276
})
274277
})
275278

279+
When("A DNSMasq is created with a custom local option", func() {
280+
BeforeEach(func() {
281+
spec := GetDefaultDNSMasqSpec()
282+
spec["options"] = any([]networkv1.DNSMasqOption{
283+
{
284+
Key: "server",
285+
Values: []string{"1.1.1.1"},
286+
},
287+
{
288+
Key: "no-negcache",
289+
Values: []string{},
290+
},
291+
{
292+
Key: "local",
293+
Values: []string{"/custom.svc/"},
294+
},
295+
})
296+
instance := CreateDNSMasq(namespace, spec)
297+
dnsMasqName = types.NamespacedName{
298+
Name: instance.GetName(),
299+
Namespace: namespace,
300+
}
301+
302+
dnsDataCM = types.NamespacedName{
303+
Namespace: namespace,
304+
Name: "some-dnsdata",
305+
}
306+
307+
th.CreateConfigMap(dnsDataCM, map[string]any{
308+
dnsDataCM.Name: "172.20.0.80 keystone-internal.openstack.svc",
309+
})
310+
cm := th.GetConfigMap(dnsDataCM)
311+
cm.Labels = util.MergeStringMaps(cm.Labels, map[string]string{
312+
"dnsmasqhosts": "dnsdata",
313+
})
314+
Expect(th.K8sClient.Update(ctx, cm)).Should(Succeed())
315+
316+
DeferCleanup(th.DeleteConfigMap, dnsDataCM)
317+
DeferCleanup(th.DeleteInstance, instance)
318+
})
319+
320+
It("uses the custom local value and does not add the default", func() {
321+
th.ExpectCondition(
322+
dnsMasqName,
323+
ConditionGetterFunc(DNSMasqConditionGetter),
324+
condition.ServiceConfigReadyCondition,
325+
corev1.ConditionTrue,
326+
)
327+
328+
configData := th.GetConfigMap(dnsMasqName)
329+
Expect(configData).ShouldNot(BeNil())
330+
Expect(configData.Data[dnsMasqName.Name]).Should(
331+
ContainSubstring("local=/custom.svc/"))
332+
Expect(configData.Data[dnsMasqName.Name]).ShouldNot(
333+
ContainSubstring(fmt.Sprintf("local=/%s.svc/", namespace)))
334+
})
335+
})
336+
276337
When("Deployment rollout is progressing", func() {
277338
BeforeEach(func() {
278339
instance := CreateDNSMasq(namespace, GetDefaultDNSMasqSpec())

0 commit comments

Comments
 (0)