From 45042d735f484ede65fa32954c7f227e84ad0d70 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 | 5 +++++ .../core.openstack.org_openstackversions.yaml | 4 ++++ internal/openstack/ovn.go | 9 +++++++++ internal/openstack/version.go | 1 + .../openstackversion_controller_test.go | 19 +++++++++++++++++++ 7 files changed, 43 insertions(+) diff --git a/api/bases/core.openstack.org_openstackversions.yaml b/api/bases/core.openstack.org_openstackversions.yaml index beb521d207..a701ed03c2 100644 --- a/api/bases/core.openstack.org_openstackversions.yaml +++ b/api/bases/core.openstack.org_openstackversions.yaml @@ -258,6 +258,8 @@ spec: type: string manilaSharev1: type: string + ovnHardenedOVSSecurityContext: + type: string rabbitmqVersion: type: string type: object @@ -699,6 +701,8 @@ spec: type: string manilaSharev1: 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 fea75a03f2..070945e667 100644 --- a/api/core/v1beta1/openstackversion_types.go +++ b/api/core/v1beta1/openstackversion_types.go @@ -183,6 +183,7 @@ type ServiceDefaults struct { RabbitmqVersion *string `json:"rabbitmqVersion,omitempty"` GlanceLocationAPI *string `json:"glanceLocationAPI,omitempty"` ManilaSharev1 *string `json:"manilaSharev1,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 94cd7761c6..e9113ec96d 100644 --- a/api/core/v1beta1/zz_generated.deepcopy.go +++ b/api/core/v1beta1/zz_generated.deepcopy.go @@ -1778,6 +1778,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 beb521d207..a701ed03c2 100644 --- a/config/crd/bases/core.openstack.org_openstackversions.yaml +++ b/config/crd/bases/core.openstack.org_openstackversions.yaml @@ -258,6 +258,8 @@ spec: type: string manilaSharev1: type: string + ovnHardenedOVSSecurityContext: + type: string rabbitmqVersion: type: string type: object @@ -699,6 +701,8 @@ spec: type: string manilaSharev1: 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 5fb3e8bb21..558bca1bdc 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 1438506d37..8483cf362a 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("OpenStackOperator 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("OpenStackOperator 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("OpenStackOperator 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("OpenStackOperator 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("OpenStackOperator 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())