Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions apis/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ go 1.24.4

require (
github.com/go-logr/logr v1.4.3
github.com/onsi/gomega v1.39.1
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981
github.com/onsi/gomega v1.40.0
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0
k8s.io/api v0.31.14
k8s.io/apiextensions-apiserver v0.33.2
k8s.io/apimachinery v0.31.14
Expand Down Expand Up @@ -40,7 +40,6 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/ginkgo/v2 v2.28.2 // indirect
github.com/openshift/api v3.9.0+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect
Expand Down
13 changes: 7 additions & 6 deletions apis/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,15 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo/v2 v2.28.2 h1:DTrMfpqxiNUyQ3Y0zhn1n3cOO2euFgQPYIpkWwxVFps=
github.com/onsi/ginkgo/v2 v2.28.2/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc=
github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A=
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e h1:E1OdwSpqWuDPCedyUt0GEdoAE+r5TXy7YS21yNEo+2U=
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981 h1:v1viH0gmNb+AXMg/0GxDcj8VUTdjVLotfOIGrNyMxHk=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981/go.mod h1:I/VBXZLdjk8DUGsEbB+Ha72JBFYYntP7Pm2FpEto9K8=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0 h1:vkFvn06Ns9qW4AbzFjFDu8ioosRmhkEZiDrO3DOQhLg=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0/go.mod h1:aIuG6lx3aS0vnXweRNdR/Q0SlfOsLIo0OzrqKK7C6xs=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down Expand Up @@ -113,8 +114,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
Expand Down
37 changes: 29 additions & 8 deletions apis/network/v1beta1/dnsmasq_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ limitations under the License.
package v1beta1

import (
"fmt"

annotations "github.com/openstack-k8s-operators/lib-common/modules/common/annotations"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
)

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

r.Spec.Default()
r.Spec.Default(r.Namespace)

ann := r.GetAnnotations()
if _, exists := ann[annotations.ReconcileTriggerAnnotation]; exists {
delete(ann, annotations.ReconcileTriggerAnnotation)
r.SetAnnotations(ann)
}
}

// Default - set defaults for this DNSMasq spec
func (spec *DNSMasqSpec) Default() {
func (spec *DNSMasqSpec) Default(namespace string) {
if spec.ContainerImage == "" {
spec.ContainerImage = dnsMasqDefaults.ContainerImageURL
}
spec.DNSMasqSpecCore.Default()
spec.DNSMasqSpecCore.Default(namespace)
}

// Default - common defaults go here (for the OpenStackControlplane which uses this one)
func (spec *DNSMasqSpecCore) Default() {
// nothing here
func (spec *DNSMasqSpecCore) Default(namespace string) {
hasLocal := false
for _, opt := range spec.Options {
if opt.Key == "local" {
hasLocal = true
break
}
}
if !hasLocal {
spec.Options = append(spec.Options, DNSMasqOption{
Key: "local",
Values: []string{fmt.Sprintf("/%s.svc/", namespace)},
})
}
}

var _ webhook.Validator = &DNSMasq{}
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ require (
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.7.7
github.com/metallb/frr-k8s v0.0.15
github.com/onsi/ginkgo/v2 v2.28.2
github.com/onsi/gomega v1.39.1
github.com/onsi/gomega v1.40.0
github.com/openshift/api v3.9.0+incompatible
github.com/openstack-k8s-operators/infra-operator/apis v0.0.0-00010101000000-000000000000
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260417092244-81c71b39e981
go.uber.org/zap v1.27.1
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260506154724-30a976ba8ef0
go.uber.org/zap v1.28.0
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67
k8s.io/api v0.31.14
k8s.io/apiextensions-apiserver v0.33.2
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.28.2 h1:DTrMfpqxiNUyQ3Y0zhn1n3cOO2euFgQPYIpkWwxVFps=
github.com/onsi/ginkgo/v2 v2.28.2/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc=
github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A=
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e h1:E1OdwSpqWuDPCedyUt0GEdoAE+r5TXy7YS21yNEo+2U=
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981 h1:v1viH0gmNb+AXMg/0GxDcj8VUTdjVLotfOIGrNyMxHk=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260417092244-81c71b39e981/go.mod h1:I/VBXZLdjk8DUGsEbB+Ha72JBFYYntP7Pm2FpEto9K8=
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260417092244-81c71b39e981 h1:KAQ8T+Ri3JWgsyK1D6QybScMh6fpkYUUA+0ntnOiAl4=
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260417092244-81c71b39e981/go.mod h1:dEjz8zHRIlP3vnMmWdHytlLeSZ6BHcIiSTPM7xTQxFg=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0 h1:vkFvn06Ns9qW4AbzFjFDu8ioosRmhkEZiDrO3DOQhLg=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20260506154724-30a976ba8ef0/go.mod h1:aIuG6lx3aS0vnXweRNdR/Q0SlfOsLIo0OzrqKK7C6xs=
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260506154724-30a976ba8ef0 h1:mG3QhS/QWv9Y/AkZZ5OzO6hu6+l5oDXnI/Q5ZUbj6Zs=
github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20260506154724-30a976ba8ef0/go.mod h1:ZYG9CQe7cOePOKQbenEZFA28kPdkUOe9QKbDRwGhEV0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down Expand Up @@ -186,8 +186,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
Expand Down
26 changes: 26 additions & 0 deletions internal/controller/network/dnsmasq_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import (
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
dnsmasq "github.com/openstack-k8s-operators/infra-operator/internal/dnsmasq"
common "github.com/openstack-k8s-operators/lib-common/modules/common"
annotations "github.com/openstack-k8s-operators/lib-common/modules/common/annotations"
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
configmap "github.com/openstack-k8s-operators/lib-common/modules/common/configmap"
deployment "github.com/openstack-k8s-operators/lib-common/modules/common/deployment"
Expand All @@ -58,6 +59,7 @@ import (
common_rbac "github.com/openstack-k8s-operators/lib-common/modules/common/rbac"
service "github.com/openstack-k8s-operators/lib-common/modules/common/service"
util "github.com/openstack-k8s-operators/lib-common/modules/common/util"
"github.com/openstack-k8s-operators/lib-common/modules/common/webhook"
)

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

// Ensure existing CRs get the default local=/<namespace>.svc/ option on
// upgrade by triggering the webhook via a reconcile-trigger annotation.
hasLocal := false
for _, opt := range instance.Spec.Options {
if opt.Key == "local" {
hasLocal = true
break
}
}
if !hasLocal {
result, err := webhook.EnsureWebhookTrigger(
ctx,
instance,
annotations.ReconcileTriggerAnnotation,
"DNSMasq local option defaulting",
Log,
0, // use default 5 minute timeout
)
if err != nil {
return ctrl.Result{}, err
}
return result, nil
}

serviceLabels := map[string]string{
common.AppSelector: dnsmasq.ServiceName,
}
Expand Down
61 changes: 61 additions & 0 deletions test/functional/dnsmasq_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"

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

Expand Down Expand Up @@ -273,6 +276,64 @@ var _ = Describe("DNSMasq controller", func() {
})
})

When("A DNSMasq is created with a custom local option", func() {
BeforeEach(func() {
spec := GetDefaultDNSMasqSpec()
spec["options"] = any([]networkv1.DNSMasqOption{
{
Key: "server",
Values: []string{"1.1.1.1"},
},
{
Key: "no-negcache",
Values: []string{},
},
{
Key: "local",
Values: []string{"/custom.svc/"},
},
})
instance := CreateDNSMasq(namespace, spec)
dnsMasqName = types.NamespacedName{
Name: instance.GetName(),
Namespace: namespace,
}

dnsDataCM = types.NamespacedName{
Namespace: namespace,
Name: "some-dnsdata",
}

th.CreateConfigMap(dnsDataCM, map[string]any{
dnsDataCM.Name: "172.20.0.80 keystone-internal.openstack.svc",
})
cm := th.GetConfigMap(dnsDataCM)
cm.Labels = util.MergeStringMaps(cm.Labels, map[string]string{
"dnsmasqhosts": "dnsdata",
})
Expect(th.K8sClient.Update(ctx, cm)).Should(Succeed())

DeferCleanup(th.DeleteConfigMap, dnsDataCM)
DeferCleanup(th.DeleteInstance, instance)
})

It("uses the custom local value and does not add the default", func() {
th.ExpectCondition(
dnsMasqName,
ConditionGetterFunc(DNSMasqConditionGetter),
condition.ServiceConfigReadyCondition,
corev1.ConditionTrue,
)

configData := th.GetConfigMap(dnsMasqName)
Expect(configData).ShouldNot(BeNil())
Expect(configData.Data[dnsMasqName.Name]).Should(
ContainSubstring("local=/custom.svc/"))
Expect(configData.Data[dnsMasqName.Name]).ShouldNot(
ContainSubstring(fmt.Sprintf("local=/%s.svc/", namespace)))
})
})

When("Deployment rollout is progressing", func() {
BeforeEach(func() {
instance := CreateDNSMasq(namespace, GetDefaultDNSMasqSpec())
Expand Down
Loading