Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to set ingressClassName for v1 Ingress. #363

Merged
merged 5 commits into from
Nov 2, 2021
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
9 changes: 9 additions & 0 deletions api/v1beta1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,15 @@ 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.
//
// +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"`
}

// ConfigMapOptions defines custom options for configMaps
Expand Down
5 changes: 5 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions config/crd/bases/solr.apache.org_solrclouds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,12 @@ 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.
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:
type: string
Expand Down
1 change: 1 addition & 0 deletions controllers/controller_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -926,4 +926,5 @@ var (
WhenUnsatisfiable: corev1.ScheduleAnyway,
},
}
testIngressClass = "test-ingress-class"
)
71 changes: 55 additions & 16 deletions controllers/solrcloud_controller_ingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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")
Expand All @@ -162,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{
Expand All @@ -175,6 +189,14 @@ var _ = FDescribe("SolrCloud controller - Ingress", func() {
PodPort: 3000,
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")
Expand Down Expand Up @@ -220,11 +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")
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) {
Expand All @@ -248,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")
Expand Down Expand Up @@ -299,6 +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(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")
Expand Down Expand Up @@ -369,6 +396,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")
Expand Down Expand Up @@ -444,6 +473,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")
Expand Down Expand Up @@ -515,6 +546,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")
Expand Down Expand Up @@ -589,6 +622,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")
Expand All @@ -602,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
Expand All @@ -612,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"
Expand All @@ -635,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")
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion controllers/util/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions controllers/util/solr_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
3 changes: 3 additions & 0 deletions docs/solr-cloud/solr-cloud-crd.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,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.
Expand Down
11 changes: 10 additions & 1 deletion docs/upgrade-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`**.
Expand Down Expand Up @@ -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.
Expand Down
7 changes: 7 additions & 0 deletions helm/solr-operator/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,13 @@ annotations:
url: https://github.com/apache/solr-operator/issues/307
- name: Github PR
url: https://github.com/apache/solr-operator/pull/360
- 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
Expand Down
6 changes: 6 additions & 0 deletions helm/solr-operator/crds/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2318,6 +2318,12 @@ 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.
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:
type: string
Expand Down
5 changes: 3 additions & 2 deletions helm/solr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,9 @@ When using the helm chart, omit `customSolrKubeOptions.`
| 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* |
3 changes: 3 additions & 0 deletions helm/solr/templates/_custom_option_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ labels:
annotations:
{{- toYaml .Values.ingressOptions.annotations | nindent 2 }}
{{ end }}
{{- if .Values.ingressOptions.ingressClassName -}}
ingressClassName: {{ .Values.ingressOptions.ingressClassName }}
{{ end }}
{{- end -}}

{{/*
Expand Down
1 change: 1 addition & 0 deletions helm/solr/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ nodeServiceOptions:
ingressOptions:
annotations: {}
labels: {}
ingressClassName: ""

configMapOptions:
annotations: {}
Expand Down