From a60b6befc6e95b3da0a83206cfe9668fd69ffc45 Mon Sep 17 00:00:00 2001 From: Martin Schuppert Date: Thu, 18 Jul 2024 14:20:34 +0200 Subject: [PATCH] [validation] check galera instance names are valid The galera controller creates StatefulSet for the db to run. This adds a StatefulSet pod's label "controller-revision-hash": "-" to the pod. The kubernetes label is restricted under 63 char and the revision hash is an int32, 10 chars + the hyphen. The galera controller also adds a suffix '-galera' to the statefulset name. With this the max name must not exceed 46 chars. Also the name of the created galera instance must match a lowercase RFC 1123. Depends-On: https://github.com/openstack-k8s-operators/lib-common/pull/532 Depends-On: https://github.com/openstack-k8s-operators/mariadb-operator/pull/246 Jira: https://issues.redhat.com/browse/OSPRH-8063 Signed-off-by: Martin Schuppert --- .../v1beta1/openstackcontrolplane_webhook.go | 20 +++++ .../openstackoperator_controller_test.go | 74 +++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/apis/core/v1beta1/openstackcontrolplane_webhook.go b/apis/core/v1beta1/openstackcontrolplane_webhook.go index e93930548..2d0c4a5c0 100644 --- a/apis/core/v1beta1/openstackcontrolplane_webhook.go +++ b/apis/core/v1beta1/openstackcontrolplane_webhook.go @@ -334,6 +334,16 @@ func (r *OpenStackControlPlane) ValidateCreateServices(basePath *field.Path) (ad } } + if r.Spec.Galera.Enabled { + if r.Spec.Galera.Templates != nil { + err := common_webhook.ValidateDNS1123Label( + basePath.Child("galera").Child("templates"), + maps.Keys(*r.Spec.Galera.Templates), + mariadbv1.CrMaxLengthCorrection) // omit issue with statefulset pod label "controller-revision-hash": "-" + errors = append(errors, err...) + } + } + return warnings, errors } @@ -455,6 +465,16 @@ func (r *OpenStackControlPlane) ValidateUpdateServices(old OpenStackControlPlane } } + if r.Spec.Galera.Enabled { + if r.Spec.Galera.Templates != nil { + err := common_webhook.ValidateDNS1123Label( + basePath.Child("galera").Child("templates"), + maps.Keys(*r.Spec.Galera.Templates), + mariadbv1.CrMaxLengthCorrection) // omit issue with statefulset pod label "controller-revision-hash": "-" + errors = append(errors, err...) + } + } + return errors } diff --git a/tests/functional/ctlplane/openstackoperator_controller_test.go b/tests/functional/ctlplane/openstackoperator_controller_test.go index 5af882b9e..d4d1d0050 100644 --- a/tests/functional/ctlplane/openstackoperator_controller_test.go +++ b/tests/functional/ctlplane/openstackoperator_controller_test.go @@ -2011,4 +2011,78 @@ var _ = Describe("OpenStackOperator Webhook", func() { "Invalid value: \"foo_bar\": a lowercase RFC 1123 label must consist"), ) }) + + It("Blocks creating ctlplane CRs with to long galera keys/names", func() { + spec := GetDefaultOpenStackControlPlaneSpec() + + galeraTemplate := map[string]interface{}{ + "foo-1234567890-1234567890-1234567890-1234567890-1234567890": map[string]interface{}{ + "storageRequest": "500M", + }, + } + + spec["galera"] = map[string]interface{}{ + "enabled": true, + "templates": galeraTemplate, + } + + raw := map[string]interface{}{ + "apiVersion": "core.openstack.org/v1beta1", + "kind": "OpenStackControlPlane", + "metadata": map[string]interface{}{ + "name": "foo", + "namespace": namespace, + }, + "spec": spec, + } + + unstructuredObj := &unstructured.Unstructured{Object: raw} + _, err := controllerutil.CreateOrPatch( + th.Ctx, th.K8sClient, unstructuredObj, func() error { return nil }) + Expect(err).Should(HaveOccurred()) + var statusError *k8s_errors.StatusError + Expect(errors.As(err, &statusError)).To(BeTrue()) + Expect(statusError.ErrStatus.Details.Kind).To(Equal("OpenStackControlPlane")) + Expect(statusError.ErrStatus.Message).To( + ContainSubstring( + "Invalid value: \"foo-1234567890-1234567890-1234567890-1234567890-1234567890\": must be no more than 46 characters"), + ) + }) + + It("Blocks creating ctlplane CRs with wrong galera keys/names", func() { + spec := GetDefaultOpenStackControlPlaneSpec() + + galeraTemplate := map[string]interface{}{ + "foo_bar": map[string]interface{}{ + "storageRequest": "500M", + }, + } + + spec["galera"] = map[string]interface{}{ + "enabled": true, + "templates": galeraTemplate, + } + + raw := map[string]interface{}{ + "apiVersion": "core.openstack.org/v1beta1", + "kind": "OpenStackControlPlane", + "metadata": map[string]interface{}{ + "name": "foo", + "namespace": namespace, + }, + "spec": spec, + } + + unstructuredObj := &unstructured.Unstructured{Object: raw} + _, err := controllerutil.CreateOrPatch( + th.Ctx, th.K8sClient, unstructuredObj, func() error { return nil }) + Expect(err).Should(HaveOccurred()) + var statusError *k8s_errors.StatusError + Expect(errors.As(err, &statusError)).To(BeTrue()) + Expect(statusError.ErrStatus.Details.Kind).To(Equal("OpenStackControlPlane")) + Expect(statusError.ErrStatus.Message).To( + ContainSubstring( + "Invalid value: \"foo_bar\": a lowercase RFC 1123 label must consist"), + ) + }) })