From 78bb0ddf5cb3591536a5d410302cf776e9b42857 Mon Sep 17 00:00:00 2001 From: Houston Putman Date: Mon, 1 Nov 2021 15:57:02 -0400 Subject: [PATCH 1/4] Ability to set ingressClassName for v1 Ingress. --- api/v1beta1/common_types.go | 6 ++++++ api/v1beta1/zz_generated.deepcopy.go | 5 +++++ .../crd/bases/solr.apache.org_solrclouds.yaml | 3 +++ controllers/controller_utils_test.go | 1 + .../solrcloud_controller_ingress_test.go | 19 +++++++++++++++++-- controllers/util/solr_util.go | 5 +++++ docs/solr-cloud/solr-cloud-crd.md | 3 +++ helm/solr-operator/Chart.yaml | 7 +++++++ helm/solr-operator/crds/crds.yaml | 3 +++ 9 files changed, 50 insertions(+), 2 deletions(-) diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index 4d69afd6..48df0aa6 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -172,6 +172,12 @@ type IngressOptions struct { // Labels to be added for the Ingress. // +optional Labels map[string]string `json:"labels,omitempty"` + + // IngressClassName is the name of the IngressClass cluster resource. The + // associated IngressClass defines which controller will implement the resource. + // + // +optional + IngressClassName *string `json:"ingressClassName,omitempty"` } // ConfigMapOptions defines custom options for configMaps diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index a581e099..439ca530 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -315,6 +315,11 @@ func (in *IngressOptions) DeepCopyInto(out *IngressOptions) { (*out)[key] = val } } + if in.IngressClassName != nil { + in, out := &in.IngressClassName, &out.IngressClassName + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressOptions. diff --git a/config/crd/bases/solr.apache.org_solrclouds.yaml b/config/crd/bases/solr.apache.org_solrclouds.yaml index 7fff8bdf..500e0b6f 100644 --- a/config/crd/bases/solr.apache.org_solrclouds.yaml +++ b/config/crd/bases/solr.apache.org_solrclouds.yaml @@ -1184,6 +1184,9 @@ spec: type: string description: Annotations to be added for the Ingress. type: object + ingressClassName: + description: IngressClassName is the name of the IngressClass cluster resource. The associated IngressClass defines which controller will implement the resource. + type: string labels: additionalProperties: type: string diff --git a/controllers/controller_utils_test.go b/controllers/controller_utils_test.go index 31fc8f00..72b10d8b 100644 --- a/controllers/controller_utils_test.go +++ b/controllers/controller_utils_test.go @@ -926,4 +926,5 @@ var ( WhenUnsatisfiable: corev1.ScheduleAnyway, }, } + testIngressClass = "test-ingress-class" ) diff --git a/controllers/solrcloud_controller_ingress_test.go b/controllers/solrcloud_controller_ingress_test.go index 125c2b14..c1e8bd92 100644 --- a/controllers/solrcloud_controller_ingress_test.go +++ b/controllers/solrcloud_controller_ingress_test.go @@ -58,8 +58,9 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { Labels: testCommonServiceLabels, }, IngressOptions: &solrv1beta1.IngressOptions{ - Annotations: testIngressAnnotations, - Labels: testIngressLabels, + Annotations: testIngressAnnotations, + Labels: testIngressLabels, + IngressClassName: &testIngressClass, }, NodeServiceOptions: &solrv1beta1.ServiceOptions{ Annotations: testNodeServiceAnnotations, @@ -151,6 +152,8 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { ingress := expectIngress(ctx, solrCloud, solrCloud.CommonIngressName()) Expect(ingress.Labels).To(Equal(util.MergeLabelsOrAnnotations(solrCloud.SharedLabelsWith(solrCloud.Labels), testIngressLabels)), "Incorrect ingress labels") Expect(ingress.Annotations).To(Equal(ingressLabelsWithDefaults(testIngressAnnotations)), "Incorrect ingress annotations") + Expect(ingress.Spec.IngressClassName).To(Not(BeNil()), "Ingress class name should not be nil") + Expect(*ingress.Spec.IngressClassName).To(Equal(testIngressClass), "Incorrect ingress class name") testIngressRules(solrCloud, ingress, true, replicas, 4000, 100, testDomain) By("making sure the node addresses in the Status are correct") @@ -175,6 +178,7 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { PodPort: 3000, CommonServicePort: 4000, } + solrCloud.Spec.CustomSolrKubeOptions.IngressOptions.IngressClassName = nil }) FIt("has the correct resources", func() { By("ensuring the SolrCloud resource is updated with correct specs") @@ -224,6 +228,7 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { ingress := expectIngress(ctx, solrCloud, solrCloud.CommonIngressName()) Expect(ingress.Labels).To(Equal(util.MergeLabelsOrAnnotations(solrCloud.SharedLabelsWith(solrCloud.Labels), testIngressLabels)), "Incorrect ingress labels") Expect(ingress.Annotations).To(Equal(ingressLabelsWithDefaults(testIngressAnnotations)), "Incorrect ingress annotations") + Expect(ingress.Spec.IngressClassName).To(BeNil(), "Ingress class name should be nil when none is provided in custom ingress options") testIngressRules(solrCloud, ingress, true, 0, 4000, 100, testDomain) By("making sure the node addresses in the Status are correct") @@ -299,6 +304,8 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { ingress := expectIngress(ctx, solrCloud, solrCloud.CommonIngressName()) Expect(ingress.Labels).To(Equal(util.MergeLabelsOrAnnotations(solrCloud.SharedLabelsWith(solrCloud.Labels), testIngressLabels)), "Incorrect ingress labels") Expect(ingress.Annotations).To(Equal(ingressLabelsWithDefaults(testIngressAnnotations)), "Incorrect ingress annotations") + Expect(ingress.Spec.IngressClassName).To(Not(BeNil()), "Ingress class name should not be nil") + Expect(*ingress.Spec.IngressClassName).To(Equal(testIngressClass), "Incorrect ingress class name") testIngressRules(solrCloud, ingress, false, replicas, 4000, 100, testDomain) By("making sure the node addresses in the Status are correct") @@ -369,6 +376,8 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { ingress := expectIngress(ctx, solrCloud, solrCloud.CommonIngressName()) Expect(ingress.Labels).To(Equal(util.MergeLabelsOrAnnotations(solrCloud.SharedLabelsWith(solrCloud.Labels), testIngressLabels)), "Incorrect ingress labels") Expect(ingress.Annotations).To(Equal(ingressLabelsWithDefaults(testIngressAnnotations)), "Incorrect ingress annotations") + Expect(ingress.Spec.IngressClassName).To(Not(BeNil()), "Ingress class name should not be nil") + Expect(*ingress.Spec.IngressClassName).To(Equal(testIngressClass), "Incorrect ingress class name") testIngressRules(solrCloud, ingress, true, replicas, 4000, 100, testDomain) By("making sure the node addresses in the Status are correct") @@ -444,6 +453,8 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { ingress := expectIngress(ctx, solrCloud, solrCloud.CommonIngressName()) Expect(ingress.Labels).To(Equal(util.MergeLabelsOrAnnotations(solrCloud.SharedLabelsWith(solrCloud.Labels), testIngressLabels)), "Incorrect ingress labels") Expect(ingress.Annotations).To(Equal(ingressLabelsWithDefaults(testIngressAnnotations)), "Incorrect ingress annotations") + Expect(ingress.Spec.IngressClassName).To(Not(BeNil()), "Ingress class name should not be nil") + Expect(*ingress.Spec.IngressClassName).To(Equal(testIngressClass), "Incorrect ingress class name") testIngressRules(solrCloud, ingress, true, replicas, 4000, 100, append([]string{testDomain}, testAdditionalDomains...)...) By("making sure the node addresses in the Status are correct") @@ -515,6 +526,8 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { ingress := expectIngress(ctx, solrCloud, solrCloud.CommonIngressName()) Expect(ingress.Labels).To(Equal(util.MergeLabelsOrAnnotations(solrCloud.SharedLabelsWith(solrCloud.Labels), testIngressLabels)), "Incorrect ingress labels") Expect(ingress.Annotations).To(Equal(ingressLabelsWithDefaults(testIngressAnnotations)), "Incorrect ingress annotations") + Expect(ingress.Spec.IngressClassName).To(Not(BeNil()), "Ingress class name should not be nil") + Expect(*ingress.Spec.IngressClassName).To(Equal(testIngressClass), "Incorrect ingress class name") testIngressRules(solrCloud, ingress, true, replicas, 80, 100, testDomain) By("making sure the node addresses in the Status are correct") @@ -589,6 +602,8 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { ingress := expectIngress(ctx, solrCloud, solrCloud.CommonIngressName()) Expect(ingress.Labels).To(Equal(util.MergeLabelsOrAnnotations(solrCloud.SharedLabelsWith(solrCloud.Labels), testIngressLabels)), "Incorrect ingress labels") Expect(ingress.Annotations).To(Equal(ingressLabelsWithDefaults(testIngressAnnotations)), "Incorrect ingress annotations") + Expect(ingress.Spec.IngressClassName).To(Not(BeNil()), "Ingress class name should not be nil") + Expect(*ingress.Spec.IngressClassName).To(Equal(testIngressClass), "Incorrect ingress class name") testIngressRules(solrCloud, ingress, true, replicas, 80, 100, testDomain) By("making sure the node addresses in the Status are correct") diff --git a/controllers/util/solr_util.go b/controllers/util/solr_util.go index c3b4a441..5b6b41b3 100644 --- a/controllers/util/solr_util.go +++ b/controllers/util/solr_util.go @@ -910,6 +910,11 @@ func GenerateIngress(solrCloud *solr.SolrCloud, nodeNames []string) (ingress *ne TLS: ingressTLS, }, } + + if nil != customOptions && customOptions.IngressClassName != nil { + ingress.Spec.IngressClassName = customOptions.IngressClassName + } + return ingress } diff --git a/docs/solr-cloud/solr-cloud-crd.md b/docs/solr-cloud/solr-cloud-crd.md index 67c2ba14..b62daec1 100644 --- a/docs/solr-cloud/solr-cloud-crd.md +++ b/docs/solr-cloud/solr-cloud-crd.md @@ -123,6 +123,9 @@ Under `SolrCloud.Spec.solrAddressability`: **Note:** Unless both `external.method=Ingress` and `external.hideNodes=false`, a headless service will be used to make each Solr Node in the statefulSet addressable. If both of those criteria are met, then an individual ClusterIP Service will be created for each Solr Node/Pod. +If you are using an `Ingress` for external addressability, you can customize the created `Ingress` through `SolrCloud.spec.customSolrKubeOptions.ingressOptions`. +Under this property, you can set custom `annotations`, `labels` and an `ingressClassName`. + ## Zookeeper Reference Solr Clouds require an Apache Zookeeper to connect to. diff --git a/helm/solr-operator/Chart.yaml b/helm/solr-operator/Chart.yaml index a2da1676..3a06ef6b 100644 --- a/helm/solr-operator/Chart.yaml +++ b/helm/solr-operator/Chart.yaml @@ -148,6 +148,13 @@ annotations: url: https://github.com/apache/solr-operator/issues/355 - name: Github PR url: https://github.com/apache/solr-operator/pull/356 + - kind: added + description: Ability to set the IngressClassName for v1 Ingress resources. + links: + - name: Github Issue (Ingress v1) + url: https://github.com/apache/solr-operator/issues/277 + - name: Github PR + url: https://github.com/apache/solr-operator/pull/363 artifacthub.io/images: | - name: solr-operator image: apache/solr-operator:v0.5.0-prerelease diff --git a/helm/solr-operator/crds/crds.yaml b/helm/solr-operator/crds/crds.yaml index 68a1e754..97608825 100644 --- a/helm/solr-operator/crds/crds.yaml +++ b/helm/solr-operator/crds/crds.yaml @@ -2318,6 +2318,9 @@ spec: type: string description: Annotations to be added for the Ingress. type: object + ingressClassName: + description: IngressClassName is the name of the IngressClass cluster resource. The associated IngressClass defines which controller will implement the resource. + type: string labels: additionalProperties: type: string From ff507c7ed7b4f142a7867e7fb2e8851d82c39eef Mon Sep 17 00:00:00 2001 From: Houston Putman Date: Mon, 1 Nov 2021 16:07:14 -0400 Subject: [PATCH 2/4] Add option to helm chart. --- helm/solr/README.md | 5 +++-- helm/solr/templates/_custom_option_helpers.tpl | 3 +++ helm/solr/values.yaml | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/helm/solr/README.md b/helm/solr/README.md index 75a22b0c..041b24cb 100644 --- a/helm/solr/README.md +++ b/helm/solr/README.md @@ -273,8 +273,9 @@ Configure Solr to use a separate TLS certificate for client auth. | headlessServiceOptions.labels | map[string]string | | Custom labels to add to the Solr headless service | | nodeServiceOptions.annotations | map[string]string | | Custom annotations to add to the Solr node service(s) | | nodeServiceOptions.labels | map[string]string | | Custom labels to add to the Solr node service(s) | -| ingressOptions.annotations | map[string]string | | Custom annotations to add to the Solr ingress, if it exists | -| ingressOptions.labels | map[string]string | | Custom labels to add to the Solr ingress, if it exists | +| ingressOptions.annotations | map[string]string | | Custom annotations to add to the Solr ingress, if an Ingress is created/used | +| ingressOptions.labels | map[string]string | | Custom labels to add to the Solr ingress, if an Ingress is created/used | +| ingressOptions.ingressClassName | string | | Set the name of the IngressClass to use, if an Ingress is created/used | | configMapOptions.annotations | map[string]string | | Custom annotations to add to the Solr configMap | | configMapOptions.labels | map[string]string | | Custom labels to add to the Solr configMap | | configMapOptions.providedConfigMap | string | | Provide an existing configMap for the Solr XML and/or Solr log4j files. *ADVANCED* | diff --git a/helm/solr/templates/_custom_option_helpers.tpl b/helm/solr/templates/_custom_option_helpers.tpl index 47cb8c85..a1dda9a2 100644 --- a/helm/solr/templates/_custom_option_helpers.tpl +++ b/helm/solr/templates/_custom_option_helpers.tpl @@ -129,6 +129,9 @@ labels: annotations: {{- toYaml .Values.ingressOptions.annotations | nindent 2 }} {{ end }} +{{- if .Values.ingressOptions.ingressClassName -}} +ingressClassName: {{ .Values.ingressOptions.ingressClassName }} +{{ end }} {{- end -}} {{/* diff --git a/helm/solr/values.yaml b/helm/solr/values.yaml index bd6c2cc7..464f47ac 100644 --- a/helm/solr/values.yaml +++ b/helm/solr/values.yaml @@ -325,6 +325,7 @@ nodeServiceOptions: ingressOptions: annotations: {} labels: {} + ingressClassName: "" configMapOptions: annotations: {} From 30f7ff8148233eaf28a65e033fd1afc08b1d474c Mon Sep 17 00:00:00 2001 From: Houston Putman Date: Mon, 1 Nov 2021 16:13:38 -0400 Subject: [PATCH 3/4] Add upgrade notes. --- docs/upgrade-notes.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/upgrade-notes.md b/docs/upgrade-notes.md index d9a8924f..5428a534 100644 --- a/docs/upgrade-notes.md +++ b/docs/upgrade-notes.md @@ -100,6 +100,15 @@ _Note that the Helm chart version does not contain a `v` prefix, which the downl ## Upgrade Warnings and Notes ### v0.5.0 +- Due to the deprecation and removal of `networking.k8s.io/v1beta1` in Kubernetes v1.22, `networking.k8s.io/v1` will be used for Ingresses. + + **This means that Kubernetes support is now limited to 1.19+.** + If you are unable to use a newer version of Kubernetes, please install the `v0.4.0` version of the Solr Operator for use with Kubernetes 1.18 and below. + See the [version compatibility matrix](#kubernetes-versions) for more information. + + This also means that if you specify a custom `ingressClass` via an annotation, you should change to use the `SolrCloud.spec.customSolrKubeOptions.ingressOptions.ingressClassName` instead. + The ability to set the class through annotations is now deprecated in Kubernetes and will be removed in future versions. + - The legacy way of specifying a backupRepository has been **DEPRECATED**. Instead of using `SolrCloud.spec.dataStorage.backupRestoreOptions`, use `SolrCloud.spec.backupRepositories`. The `SolrCloud.spec.dataStorage.backupRestoreOptions` option **will be removed in `v0.6.0`**. @@ -151,7 +160,7 @@ _Note that the Helm chart version does not contain a `v` prefix, which the downl Please refer to the [Zookeeper Operator release notes](https://github.com/pravega/zookeeper-operator/releases) before upgrading. ### v0.2.7 -- Do to the addition of possible sidecar/initContainers for SolrClouds, the version of CRDs used had to be upgraded to `apiextensions.k8s.io/v1`. +- Due to the addition of possible sidecar/initContainers for SolrClouds, the version of CRDs used had to be upgraded to `apiextensions.k8s.io/v1`. **This means that Kubernetes support is now limited to 1.16+.** If you are unable to use a newer version of Kubernetes, please install the `v0.2.6` version of the Solr Operator for use with Kubernetes 1.15 and below. From 2cc47ad836ef88ab6b54a55317b910cdf5b80e1d Mon Sep 17 00:00:00 2001 From: Houston Putman Date: Tue, 2 Nov 2021 13:17:41 -0400 Subject: [PATCH 4/4] Add better validation. Add very comprehensive tests. Don't overwrite default ingress class --- api/v1beta1/common_types.go | 3 + .../crd/bases/solr.apache.org_solrclouds.yaml | 3 + .../solrcloud_controller_ingress_test.go | 58 +++++++++++++------ controllers/util/common.go | 2 +- helm/solr-operator/crds/crds.yaml | 3 + 5 files changed, 51 insertions(+), 18 deletions(-) diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index 48df0aa6..4c29cb61 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -176,6 +176,9 @@ type IngressOptions struct { // IngressClassName is the name of the IngressClass cluster resource. The // associated IngressClass defines which controller will implement the resource. // + // +kubebuilder:validation:Pattern:=[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)* + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=63 // +optional IngressClassName *string `json:"ingressClassName,omitempty"` } diff --git a/config/crd/bases/solr.apache.org_solrclouds.yaml b/config/crd/bases/solr.apache.org_solrclouds.yaml index 500e0b6f..ec403d2b 100644 --- a/config/crd/bases/solr.apache.org_solrclouds.yaml +++ b/config/crd/bases/solr.apache.org_solrclouds.yaml @@ -1186,6 +1186,9 @@ spec: type: object ingressClassName: description: IngressClassName is the name of the IngressClass cluster resource. The associated IngressClass defines which controller will implement the resource. + maxLength: 63 + minLength: 1 + pattern: '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*' type: string labels: additionalProperties: diff --git a/controllers/solrcloud_controller_ingress_test.go b/controllers/solrcloud_controller_ingress_test.go index c1e8bd92..de8f455f 100644 --- a/controllers/solrcloud_controller_ingress_test.go +++ b/controllers/solrcloud_controller_ingress_test.go @@ -165,7 +165,18 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { }) }) - FContext("Hide Nodes from external connections", func() { + FContext("Hide Nodes from external connections - Using default ingress class", func() { + ingressClass := &netv1.IngressClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "example", + Annotations: map[string]string{ + "ingressclass.kubernetes.io/is-default-class": "true", + }, + }, + Spec: netv1.IngressClassSpec{ + Controller: "acme.io/foo", + }, + } BeforeEach(func() { solrCloud.Spec.SolrAddressability = solrv1beta1.SolrAddressabilityOptions{ External: &solrv1beta1.ExternalAddressability{ @@ -179,6 +190,13 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { CommonServicePort: 4000, } solrCloud.Spec.CustomSolrKubeOptions.IngressOptions.IngressClassName = nil + + By("Create a default ingress class, so that the ingress is defaulted with this ingress class name") + Expect(k8sClient.Create(ctx, ingressClass)).To(Succeed(), "Create a default ingress class for the ingress") + }) + AfterEach(func() { + By("Deleting the ingress class, so other tests do not use the default") + Expect(k8sClient.Delete(ctx, ingressClass)).To(Succeed(), "Delete the default ingress class") }) FIt("has the correct resources", func() { By("ensuring the SolrCloud resource is updated with correct specs") @@ -224,12 +242,14 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { By("making sure no individual Solr Node Services exist") expectNoServices(ctx, solrCloud, "Node service shouldn't exist, but it does.", solrCloud.GetAllSolrPodNames()) - By("making sure Ingress was created correctly") - ingress := expectIngress(ctx, solrCloud, solrCloud.CommonIngressName()) - Expect(ingress.Labels).To(Equal(util.MergeLabelsOrAnnotations(solrCloud.SharedLabelsWith(solrCloud.Labels), testIngressLabels)), "Incorrect ingress labels") - Expect(ingress.Annotations).To(Equal(ingressLabelsWithDefaults(testIngressAnnotations)), "Incorrect ingress annotations") - Expect(ingress.Spec.IngressClassName).To(BeNil(), "Ingress class name should be nil when none is provided in custom ingress options") - testIngressRules(solrCloud, ingress, true, 0, 4000, 100, testDomain) + By("making sure Ingress was created correctly with a defaulted ingress class name") + expectIngressWithConsistentChecks(ctx, solrCloud, solrCloud.CommonIngressName(), func(g Gomega, ingress *netv1.Ingress) { + g.Expect(ingress.Labels).To(Equal(util.MergeLabelsOrAnnotations(solrCloud.SharedLabelsWith(solrCloud.Labels), testIngressLabels)), "Incorrect ingress labels") + g.Expect(ingress.Annotations).To(Equal(ingressLabelsWithDefaults(testIngressAnnotations)), "Incorrect ingress annotations") + g.Expect(ingress.Spec.IngressClassName).To(Not(BeNil()), "Ingress class name should not be nil when none is provided in custom ingress options, but a default ingressClass exists") + g.Expect(*ingress.Spec.IngressClassName).To(Equal(ingressClass.Name), "The wrong ingressClass was defaulted") + testIngressRulesWithGomega(g, solrCloud, ingress, true, 0, 4000, 100, testDomain) + }) By("making sure the node addresses in the Status are correct") expectSolrCloudStatusWithChecks(ctx, solrCloud, func(g Gomega, found *solrv1beta1.SolrCloudStatus) { @@ -253,6 +273,7 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { PodPort: 3000, CommonServicePort: 4000, } + solrCloud.Spec.CustomSolrKubeOptions.IngressOptions.IngressClassName = nil }) FIt("has the correct resources", func() { By("testing the Solr StatefulSet") @@ -304,8 +325,7 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { ingress := expectIngress(ctx, solrCloud, solrCloud.CommonIngressName()) Expect(ingress.Labels).To(Equal(util.MergeLabelsOrAnnotations(solrCloud.SharedLabelsWith(solrCloud.Labels), testIngressLabels)), "Incorrect ingress labels") Expect(ingress.Annotations).To(Equal(ingressLabelsWithDefaults(testIngressAnnotations)), "Incorrect ingress annotations") - Expect(ingress.Spec.IngressClassName).To(Not(BeNil()), "Ingress class name should not be nil") - Expect(*ingress.Spec.IngressClassName).To(Equal(testIngressClass), "Incorrect ingress class name") + Expect(ingress.Spec.IngressClassName).To(BeNil(), "Ingress class name should not be nil when none is provided in custom ingress options") testIngressRules(solrCloud, ingress, false, replicas, 4000, 100, testDomain) By("making sure the node addresses in the Status are correct") @@ -617,6 +637,10 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() { }) func testIngressRules(solrCloud *solrv1beta1.SolrCloud, ingress *netv1.Ingress, withCommon bool, withNodes int, commonPort int, nodePort int, domainNames ...string) { + testIngressRulesWithGomega(Default, solrCloud, ingress, withCommon, withNodes, commonPort, nodePort, domainNames...) +} + +func testIngressRulesWithGomega(g Gomega, solrCloud *solrv1beta1.SolrCloud, ingress *netv1.Ingress, withCommon bool, withNodes int, commonPort int, nodePort int, domainNames ...string) { expected := 0 if withCommon { expected += 1 @@ -627,7 +651,7 @@ func testIngressRules(solrCloud *solrv1beta1.SolrCloud, ingress *netv1.Ingress, perDomain := expected numDomains := len(domainNames) expected *= numDomains - Expect(ingress.Spec.Rules).To(HaveLen(expected), "Wrong number of ingress rules.") + g.Expect(ingress.Spec.Rules).To(HaveLen(expected), "Wrong number of ingress rules.") for i := 0; i < perDomain; i++ { // Common Rules ruleName := "common" @@ -650,14 +674,14 @@ func testIngressRules(solrCloud *solrv1beta1.SolrCloud, ingress *netv1.Ingress, ruleIndex := j + i*numDomains rule := ingress.Spec.Rules[ruleIndex] expectedHost := solrCloud.Namespace + "-" + solrCloud.Name + "-solrcloud" + hostAppend + "." + domainName - Expect(rule.Host).To(Equal(expectedHost), "Wrong host for ingress rule: "+ruleName) - Expect(rule.HTTP.Paths).To(HaveLen(1), "Wrong number of path rules in ingress host: "+ruleName) + g.Expect(rule.Host).To(Equal(expectedHost), "Wrong host for ingress rule: "+ruleName) + g.Expect(rule.HTTP.Paths).To(HaveLen(1), "Wrong number of path rules in ingress host: "+ruleName) path := rule.HTTP.Paths[0] - Expect(path.Path).To(Equal(""), "There should be no path value for ingress rule: "+ruleName) - Expect(path.Backend.Service).To(Not(BeNil()), "Backend Service should not be nil") - Expect(path.Backend.Service.Name).To(Equal(solrCloud.Name+"-solrcloud-"+serviceSuffix), "Wrong service name for ingress rule: "+ruleName) - Expect(path.Backend.Service.Port.Number).To(Equal(int32(port)), "Wrong port name for ingress rule: "+ruleName) - Expect(path.Backend.Service.Port.Name).To(BeEmpty(), "Port name should not be used in ingress rules") + g.Expect(path.Path).To(Equal(""), "There should be no path value for ingress rule: "+ruleName) + g.Expect(path.Backend.Service).To(Not(BeNil()), "Backend Service should not be nil") + g.Expect(path.Backend.Service.Name).To(Equal(solrCloud.Name+"-solrcloud-"+serviceSuffix), "Wrong service name for ingress rule: "+ruleName) + g.Expect(path.Backend.Service.Port.Number).To(Equal(int32(port)), "Wrong port name for ingress rule: "+ruleName) + g.Expect(path.Backend.Service.Port.Name).To(BeEmpty(), "Port name should not be used in ingress rules") } } } diff --git a/controllers/util/common.go b/controllers/util/common.go index fd81e301..f5e8efc9 100644 --- a/controllers/util/common.go +++ b/controllers/util/common.go @@ -300,7 +300,7 @@ func CopyIngressFields(from, to *netv1.Ingress, logger logr.Logger) bool { to.Spec.TLS = from.Spec.TLS } - if !DeepEqualWithNils(to.Spec.IngressClassName, from.Spec.IngressClassName) { + if from.Spec.IngressClassName != nil && !DeepEqualWithNils(to.Spec.IngressClassName, from.Spec.IngressClassName) { requireUpdate = true logger.Info("Update required because field changed", "field", "Spec.IngressClassName", "from", to.Spec.IngressClassName, "to", from.Spec.IngressClassName) to.Spec.IngressClassName = from.Spec.IngressClassName diff --git a/helm/solr-operator/crds/crds.yaml b/helm/solr-operator/crds/crds.yaml index 97608825..11a4fa10 100644 --- a/helm/solr-operator/crds/crds.yaml +++ b/helm/solr-operator/crds/crds.yaml @@ -2320,6 +2320,9 @@ spec: type: object ingressClassName: description: IngressClassName is the name of the IngressClass cluster resource. The associated IngressClass defines which controller will implement the resource. + maxLength: 63 + minLength: 1 + pattern: '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*' type: string labels: additionalProperties: