From ab9b86328a4cea304af27597e6c1b7c12897be99 Mon Sep 17 00:00:00 2001 From: Slawek Kaplonski Date: Mon, 31 Aug 2026 15:02:07 +0200 Subject: [PATCH] Add versioned OVS security context defaults Propagate the OVN hardened OVS security context annotation from OpenStackVersion service defaults to OVNController. This defers the security context transition until the normal minor update workflow. Depends-On: https://github.com/openstack-k8s-operators/ovn-operator/pull/616 Related: OSPRH-34172 Assisted-By: GPT-5.6 Terra Signed-off-by: Slawek Kaplonski --- .../core.openstack.org_openstackversions.yaml | 4 ++++ api/core/v1beta1/openstackversion_types.go | 1 + api/core/v1beta1/zz_generated.deepcopy.go | 7 ++++++- .../core.openstack.org_openstackversions.yaml | 4 ++++ internal/openstack/ovn.go | 9 +++++++++ internal/openstack/version.go | 1 + .../openstackversion_controller_test.go | 19 +++++++++++++++++++ 7 files changed, 44 insertions(+), 1 deletion(-) diff --git a/api/bases/core.openstack.org_openstackversions.yaml b/api/bases/core.openstack.org_openstackversions.yaml index 1e060066c8..ca5c7dc3d8 100644 --- a/api/bases/core.openstack.org_openstackversions.yaml +++ b/api/bases/core.openstack.org_openstackversions.yaml @@ -260,6 +260,8 @@ spec: type: string neutronWsgi: type: string + ovnHardenedOVSSecurityContext: + type: string rabbitmqVersion: type: string type: object @@ -703,6 +705,8 @@ spec: type: string neutronWsgi: type: string + ovnHardenedOVSSecurityContext: + type: string rabbitmqVersion: type: string type: object diff --git a/api/core/v1beta1/openstackversion_types.go b/api/core/v1beta1/openstackversion_types.go index c3918f16bb..d80dc06b25 100644 --- a/api/core/v1beta1/openstackversion_types.go +++ b/api/core/v1beta1/openstackversion_types.go @@ -304,6 +304,7 @@ type ServiceDefaults struct { GlanceLocationAPI *string `json:"glanceLocationAPI,omitempty"` ManilaSharev1 *string `json:"manilaSharev1,omitempty"` NeutronWsgi *string `json:"neutronWsgi,omitempty"` + OVNHardenedOVSSecurityContext *string `json:"ovnHardenedOVSSecurityContext,omitempty"` } // OpenStackVersionStatus defines the observed state of OpenStackVersion diff --git a/api/core/v1beta1/zz_generated.deepcopy.go b/api/core/v1beta1/zz_generated.deepcopy.go index 2c57bdb2f9..bd599b6717 100644 --- a/api/core/v1beta1/zz_generated.deepcopy.go +++ b/api/core/v1beta1/zz_generated.deepcopy.go @@ -47,7 +47,7 @@ import ( swift_operatorapiv1beta1 "github.com/openstack-k8s-operators/swift-operator/api/v1beta1" telemetry_operatorapiv1beta1 "github.com/openstack-k8s-operators/telemetry-operator/api/v1beta1" watcher_operatorapiv1beta1 "github.com/openstack-k8s-operators/watcher-operator/api/v1beta1" - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "github.com/rhobs/obo-prometheus-operator/pkg/apis/monitoring/v1" "k8s.io/apimachinery/pkg/runtime" ) @@ -1783,6 +1783,11 @@ func (in *ServiceDefaults) DeepCopyInto(out *ServiceDefaults) { *out = new(string) **out = **in } + if in.OVNHardenedOVSSecurityContext != nil { + in, out := &in.OVNHardenedOVSSecurityContext, &out.OVNHardenedOVSSecurityContext + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceDefaults. diff --git a/config/crd/bases/core.openstack.org_openstackversions.yaml b/config/crd/bases/core.openstack.org_openstackversions.yaml index 1e060066c8..ca5c7dc3d8 100644 --- a/config/crd/bases/core.openstack.org_openstackversions.yaml +++ b/config/crd/bases/core.openstack.org_openstackversions.yaml @@ -260,6 +260,8 @@ spec: type: string neutronWsgi: type: string + ovnHardenedOVSSecurityContext: + type: string rabbitmqVersion: type: string type: object @@ -703,6 +705,8 @@ spec: type: string neutronWsgi: type: string + ovnHardenedOVSSecurityContext: + type: string rabbitmqVersion: type: string type: object diff --git a/internal/openstack/ovn.go b/internal/openstack/ovn.go index e18f8c6f6c..1f66559b5b 100644 --- a/internal/openstack/ovn.go +++ b/internal/openstack/ovn.go @@ -514,6 +514,15 @@ func ReconcileOVNController(ctx context.Context, instance *corev1beta1.OpenStack OVNController.Spec.OvsContainerImage = *version.Status.ContainerImages.OvnControllerOvsImage OVNController.Spec.ExporterImage = *getImg(version.Status.ContainerImages.OpenstackNetworkExporterImage, &missingImageDefault) + if OVNController.GetAnnotations() == nil { + OVNController.SetAnnotations(make(map[string]string)) + } + if version.Status.ServiceDefaults.OVNHardenedOVSSecurityContext != nil && *version.Status.ServiceDefaults.OVNHardenedOVSSecurityContext == "true" { + OVNController.GetAnnotations()[ovnv1.OVNHardenedOVSSecurityContextLabel] = "true" + } else { + OVNController.GetAnnotations()[ovnv1.OVNHardenedOVSSecurityContextLabel] = "false" + } + err := controllerutil.SetControllerReference(helper.GetBeforeObject(), OVNController, helper.GetScheme()) if err != nil { return err diff --git a/internal/openstack/version.go b/internal/openstack/version.go index 2eb585f9e2..b60eddddcc 100644 --- a/internal/openstack/version.go +++ b/internal/openstack/version.go @@ -237,6 +237,7 @@ func InitializeOpenStackVersionServiceDefaults(ctx context.Context) *corev1beta1 // NOTE: In 18 Manila creates sharev1 service and endpoints. From 19 do not create sharev1 anymore // https://review.opendev.org/q/topic:%22remove-v1%22+and+project:openstack/manila defaults.ManilaSharev1 = &trueString // all Manila deployments create sharev1 endpoints by default + defaults.OVNHardenedOVSSecurityContext = &trueString versionString := "4.2" defaults.RabbitmqVersion = &versionString // all new rabbitmq deployments will have rabbitmq-server 4.2 (FR5) diff --git a/test/functional/ctlplane/openstackversion_controller_test.go b/test/functional/ctlplane/openstackversion_controller_test.go index 931b21de32..64e56b7dcf 100644 --- a/test/functional/ctlplane/openstackversion_controller_test.go +++ b/test/functional/ctlplane/openstackversion_controller_test.go @@ -30,6 +30,7 @@ import ( corev1 "github.com/openstack-k8s-operators/openstack-operator/api/core/v1beta1" dataplanev1 "github.com/openstack-k8s-operators/openstack-operator/api/dataplane/v1beta1" + ovnv1 "github.com/openstack-k8s-operators/ovn-operator/api/v1beta1" k8s_corev1 "k8s.io/api/core/v1" k8s_errors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" @@ -212,6 +213,7 @@ var _ = Describe("OpenStackVersion controller", func() { testMariaDBImage := "foo/maria:0.0.2" testMemcachedImage := "foo/memcached:0.0.2" testKeystoneAPIImage := "foo/keystone:0.0.2" + legacyOVSHardenedSecurityContext := "false" // a lightweight controlplane spec we'll use for minor update testing // we are missing some test helpers to simulate ready state so once we have @@ -330,6 +332,9 @@ var _ = Describe("OpenStackVersion controller", func() { version.Status.ContainerImageVersionDefaults[initialVersion].MariadbImage = &testMariaDBImage version.Status.ContainerImageVersionDefaults[initialVersion].InfraMemcachedImage = &testMemcachedImage version.Status.ContainerImageVersionDefaults[initialVersion].KeystoneAPIImage = &testKeystoneAPIImage + version.Status.AvailableServiceDefaults[initialVersion] = &corev1.ServiceDefaults{ + OVNHardenedOVSSecurityContext: &legacyOVSHardenedSecurityContext, + } g.Expect(th.K8sClient.Status().Update(th.Ctx, version)).To(Succeed()) th.Logger.Info("Version injected", "on", names.OpenStackVersionName) @@ -363,6 +368,7 @@ var _ = Describe("OpenStackVersion controller", func() { g.Expect(*osversion.Status.ContainerImages.MariadbImage).Should(Equal(testMariaDBImage)) g.Expect(*osversion.Status.ContainerImages.InfraMemcachedImage).Should(Equal(testMemcachedImage)) g.Expect(*osversion.Status.ContainerImages.KeystoneAPIImage).Should(Equal(testKeystoneAPIImage)) + g.Expect(*osversion.Status.ServiceDefaults.OVNHardenedOVSSecurityContext).Should(Equal("false")) }, timeout, interval).Should(Succeed()) @@ -389,6 +395,13 @@ var _ = Describe("OpenStackVersion controller", func() { SimulateControlplaneReady() + Eventually(func(g Gomega) { + ovnController := &ovnv1.OVNController{} + g.Expect(k8sClient.Get(ctx, names.OVNControllerName, ovnController)).To(Succeed()) + g.Expect(ovnController.GetAnnotations()).To(HaveKeyWithValue( + ovnv1.OVNHardenedOVSSecurityContextLabel, "false")) + }, timeout, interval).Should(Succeed()) + // verify that DeployedVersion is set on the OpenStackControlplane to the initialversion Eventually(func(g Gomega) { th.ExpectCondition( @@ -468,6 +481,12 @@ var _ = Describe("OpenStackVersion controller", func() { g.Expect(*osversion.Status.ContainerImages.MariadbImage).Should(Equal(targetMariaDBVersion)) g.Expect(*osversion.Status.ContainerImages.InfraMemcachedImage).Should(Equal(targetMemcachedVersion)) g.Expect(*osversion.Status.ContainerImages.KeystoneAPIImage).Should(Equal(targetKeystoneAPIVersion)) + g.Expect(*osversion.Status.ServiceDefaults.OVNHardenedOVSSecurityContext).Should(Equal("true")) + + ovnController := &ovnv1.OVNController{} + g.Expect(k8sClient.Get(ctx, names.OVNControllerName, ovnController)).To(Succeed()) + g.Expect(ovnController.GetAnnotations()).To(HaveKeyWithValue( + ovnv1.OVNHardenedOVSSecurityContextLabel, "true")) }, timeout, interval).Should(Succeed())