janhoy commented on code in PR #843: URL: https://github.com/apache/solr-operator/pull/843#discussion_r4468575600
########## controllers/util/gateway_util_backendtls.go: ########## @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +import ( + solr "github.com/apache/solr-operator/api/v1beta1" + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" +) + +// GenerateCommonBackendTLSPolicy creates a BackendTLSPolicy for the common Solr service +func GenerateCommonBackendTLSPolicy(solrCloud *solr.SolrCloud) *gatewayv1.BackendTLSPolicy { + if solrCloud.Spec.SolrAddressability.External.Gateway == nil || + solrCloud.Spec.SolrAddressability.External.Gateway.BackendTLSPolicy == nil { + return nil + } + + // Get the full FQDN for hostname validation + domainName := solrCloud.Spec.SolrAddressability.External.DomainName + fqdn := solrCloud.ExternalCommonUrl(domainName, false) Review Comment: Related to Copilot's comment at `tests/e2e/solrcloud_gateway_test.go:196`. Before the assertions are changed to match the code, this needs a decision, because three places in the PR disagree: - **Generators** emit the external hostname — `ExternalCommonUrl(domainName, false)` and `ExternalNodeUrl(nodeName, domainName, false)` at `controllers/util/gateway_util_backendtls.go:36` and `:107`, e.g. `solr-ns-example-solrcloud.solr.example.com`. - **Tests** expect the bare Service name (`tests/e2e/solrcloud_gateway_test.go:183` and `:196`). - **Docs** show the bare Service name (`docs/modules/solr-cloud/pages/gateway-api.adoc:186`). The value matters because the Gateway sends it as SNI and validates the Solr pod's certificate against it. The external hostname therefore only works when the Solr certificate carries the external names as SANs (the `tls.adoc` examples do, via wildcards); a certificate with only in-cluster names will fail the TLS handshake, and that failure shows up only in the Gateway controller's logs. Whichever is intended: align generator, tests and the docs example, and state the resulting certificate-SAN requirement in `gateway-api.adoc`, since it currently appears nowhere. ########## tests/e2e/solrcloud_gateway_test.go: ########## @@ -0,0 +1,282 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package e2e + +import ( + "context" + solrv1beta1 "github.com/apache/solr-operator/api/v1beta1" + "github.com/apache/solr-operator/controllers/util" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" +) + +var _ = Describe("E2E - SolrCloud - Gateway API", func() { Review Comment: All line references in this comment are in `tests/e2e/solrcloud_gateway_test.go`. Flagging this because Copilot's findings at `tests/e2e/solrcloud_gateway_test.go:29`, `:115` and `:153` are static inferences, and I can confirm all three are real. I switched `tests/e2e/solrcloud_gateway_test.go:29` to `FDescribe` locally (nothing else changed) and ran against a fresh KinD cluster — Gateway API v1.6.1 standard channel, k8s v1.33.7, `solr:9.11.0`: ``` Summarizing 3 Failures: [FAIL] ... Can Remove HTTPRoutes and Services when changing addressability [It] Can adapt to changing needs tests/e2e/solrcloud_gateway_test.go:115 [FAIL] ... BackendTLSPolicy Management [It] Creates and manages BackendTLSPolicy resources tests/e2e/solrcloud_gateway_test.go:179 [FAIL] ... BackendTLSPolicy Management [It] Cleans up BackendTLSPolicy when changing from Gateway method tests/e2e/solrcloud_gateway_test.go:256 Ran 3 of 34 Specs in 351.952 seconds FAIL! -- 0 Passed | 3 Failed | 0 Pending | 31 Skipped ``` Before that change, the dry run confirms the specs are excluded entirely, and the suite still reports success: ``` Will run 31 of 34 specs •••••••••••••••••••••••••••••SSS•• SUCCESS! -- 31 Passed | 0 Failed | 0 Pending | 3 Skipped ``` For the TLS-fixture issue, the operator log is unambiguous — the policy is never created, so both specs time out after 180s rather than flaking: ```json {"level":"error","msg":"Reconciler error","SolrCloud":{"name":"foo","namespace":"solr-e2e-2"}, "error":"invalid config: `spec.customSolrKubeOptions.addressability.external.gateway.backendTLSPolicy` requires `spec.solrTLS` to be configured, because BackendTLSPolicy instructs the gateway to use TLS when connecting to Solr backends"} ``` Note this compounds with the e2e job being hard-disabled in CI — `.github/workflows/e2e-tests.yaml:44` is a literal `if: false`, which is why every e2e run shows `skipped` on `main` as well as on PRs, and its matrix has rotted meanwhile (`go-version: '1.26'` against `go.mod`'s 1.27, `kube-version: 'v1.26.6'`). So even a correctly focused suite would not have run here; that is a separate problem from this PR, but it means a green CI tells us nothing about this feature. Worth confirming the specs pass in a real run — today that means locally, or with the workflow re-enabled — before merge. ########## controllers/solr_gateway_util.go: ########## @@ -0,0 +1,339 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package controllers + +import ( + "context" + "fmt" + + solrv1beta1 "github.com/apache/solr-operator/api/v1beta1" + "github.com/apache/solr-operator/controllers/util" + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" +) + +func (r *SolrCloudReconciler) reconcileGatewayResources(ctx context.Context, cloud *solrv1beta1.SolrCloud, solrNodeNames []string, logger logr.Logger) error { + extAddressabilityOpts := cloud.Spec.SolrAddressability.External + + // If not using Gateway method, clean up any existing HTTPRoutes and BackendTLSPolicy resources + if extAddressabilityOpts == nil || extAddressabilityOpts.Method != solrv1beta1.Gateway { + return r.cleanupGatewayResources(ctx, cloud, logger) + } + + // Validate that gateway config is provided + if extAddressabilityOpts.Gateway == nil || len(extAddressabilityOpts.Gateway.ParentRefs) == 0 { + r.Recorder.Event(cloud, corev1.EventTypeWarning, "InvalidConfiguration", "gateway.parentRefs is required when using method=Gateway") + return fmt.Errorf("gateway.parentRefs is required when using method=Gateway") + } + + // Validate that BackendTLSPolicy requires solrTLS to be configured + if extAddressabilityOpts.HasBackendTLSPolicy() && cloud.Spec.SolrTLS == nil { Review Comment: Two things about `controllers/solr_gateway_util.go:50-54`. Returning an `error` from `Reconcile` for a static user misconfiguration puts the controller into controller-runtime's rate-limited requeue (exponential backoff) that can never succeed. The blast radius is much larger than the Gateway resources: the call site at `controllers/solrcloud_controller.go:468-470` returns straight out of `Reconcile`, which is before pod initialization (`:493`), status computation (`:501`), the managed scale-up/scale-down and rolling-update operations (`:525-622`) and unused-Service cleanup (`:708`). Within the Gateway code the `return` at `controllers/solr_gateway_util.go:51-54` also precedes `reconcileGatewayHTTPRoutes` at `:56`. So one wrong field freezes the cloud's reported status, blocks scaling and rolling updates, and stops HTTPRoute reconciliation, until the user happens to notice an Event. A terminal misconfiguration is better surfaced as a status condition alongside the warning Event you already emit, and then skipped, so the remaining Gateway resources keep converging. Same argument for the `parentRefs` validation at `controllers/solr_gateway_util.go:45-48`. Separately, the returned error names a field path that does not exist: ``` spec.customSolrKubeOptions.addressability.external.gateway.backendTLSPolicy ``` The real path is `spec.solrAddressability.external.gateway.backendTLSPolicy`. The Event message on the line above uses the correct short form, so only the `fmt.Errorf` needs fixing. ########## controllers/solr_gateway_util.go: ########## @@ -0,0 +1,339 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package controllers + +import ( + "context" + "fmt" + + solrv1beta1 "github.com/apache/solr-operator/api/v1beta1" + "github.com/apache/solr-operator/controllers/util" + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" +) + +func (r *SolrCloudReconciler) reconcileGatewayResources(ctx context.Context, cloud *solrv1beta1.SolrCloud, solrNodeNames []string, logger logr.Logger) error { Review Comment: Grepping `controllers/*_test.go` and `api/v1beta1/*_test.go` for `HTTPRoute` or `BackendTLSPolicy` returns nothing. Combined with the de-focused e2e specs Copilot flagged, `controllers/solr_gateway_util.go`, `controllers/util/gateway_util.go` and `controllers/util/gateway_util_backendtls.go` currently have no executed coverage from any test. That matters here beyond the usual argument: the envtest-based controller tests would have caught most of what Copilot found by static reading. Nothing in this feature needs real traffic or a Gateway controller — the generated object shape, the `hideCommon`/`hideNodes` transitions, the cleanup-on-method-change path, the `backendTLSPolicy`-requires-`solrTLS` rejection, the hostname question in my comment on `controllers/util/gateway_util_backendtls.go:36`, and the default-normalization churn Copilot raised at `controllers/util/gateway_util.go:198` are all API-server-only assertions. `controllers/solrcloud_controller_ingress_test.go` is a good template, and a round-trip "unchanged route requires no update" test there would be cheaper than the e2e equivalent. ########## docs/modules/solr-cloud/pages/gateway-api.adoc: ########## @@ -0,0 +1,272 @@ += Gateway API +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +== Overview + +The Solr Operator supports using the https://gateway-api.sigs.k8s.io/[Kubernetes Gateway API] for external addressability of SolrClouds. +Gateway API is a vendor-neutral, Kubernetes-native API for managing ingress traffic and is the successor to the Ingress API. Review Comment: This is my main concern, based on having set Gateway API up by hand for a production Solr cluster. `docs/modules/solr-cloud/pages/gateway-api.adoc:22` says "Gateway API is a vendor-neutral, Kubernetes-native API for managing ingress traffic and is the successor to the Ingress API." True upstream, but in this operator the Gateway path is strictly narrower than the Ingress path, and the page never says so. A reader has no way to discover that `method: Ingress` → `method: Gateway` loses capability. Things the page should state plainly and currently doesn't: - `ingressTLSTermination` does not apply to `method: Gateway` (`HasIngressTLSTermination()` at `api/v1beta1/solrcloud_types.go:1601` is gated to `Method == Ingress`). Edge TLS termination must be preconfigured on the Gateway listener; the operator cannot request it or name a Secret for it. See also my comment on `withDefaults` in `api/v1beta1/solrcloud_types.go`. - `backendTLSPolicy` is **upstream** TLS, Gateway → Solr. It is not client/edge mTLS and not a client-authentication mechanism. Worth stating explicitly because the name invites exactly that misreading — client certificate validation is a Gateway-level concern (`gateway.spec.tls.default.frontendValidation`, GEP-91), not something an HTTPRoute or BackendTLSPolicy can express. - There is no `customSolrKubeOptions` equivalent for HTTPRoutes, so the `annotations`/`labels`/`ingressClassName` escape hatch documented at `docs/modules/solr-cloud/pages/addressability.adoc:48` has no Gateway counterpart. See my comment on `SolrGatewayOptions` in `api/v1beta1/solrcloud_types.go` for why that matters in practice. ########## api/v1beta1/solrcloud_types.go: ########## @@ -626,6 +639,107 @@ type SolrIngressTLSTermination struct { TLSSecret string `json:"tlsSecret,omitempty"` } +// SolrGatewayOptions defines how a SolrCloud should be exposed via Kubernetes Gateway API +type SolrGatewayOptions struct { Review Comment: Flagging this as a design question rather than a defect, because it's the thing that blocked a real deployment for me. With a service mesh and authentication delegated to the edge (Keycloak + oauth2-proxy), the HTTPRoute has to reference a preconfigured middleware. On Traefik that is an `ExtensionRef` filter, documented upstream as: ```yaml filters: - type: ExtensionRef extensionRef: group: traefik.io kind: Middleware name: edge-auth-http ``` (https://doc.traefik.io/traefik/reference/routing-configuration/kubernetes/gateway-api/#using-traefik-middleware-as-httproute-filter) On this branch that is not expressible, and there is no per-route workaround: - `SolrGatewayOptions` (`api/v1beta1/solrcloud_types.go:643`) exposes only `parentRefs`, `additionalHostnames`, `annotations`, `labels`, `backendTLSPolicy`. No `filters`, `matches`, `timeouts`, or raw-rule passthrough. - The generated route is hardcoded to one rule with one `backendRef` and no filters (`controllers/util/gateway_util.go:84-95` for the common route, `controllers/util/gateway_util.go:155-169` for node routes). - Editing the live HTTPRoute doesn't survive: `CopyHTTPRouteFields` does `to.Spec.Rules = from.Spec.Rules` on any difference (`controllers/util/gateway_util.go:207-210`). - Pre-creating the HTTPRoute yourself doesn't work either: the reconciler calls `util.OvertakeControllerRef` (`controllers/solr_gateway_util.go:77` and `controllers/solr_gateway_util.go:115`) and then overwrites it, so it adopts and rewrites a route you made rather than leaving it alone. Net effect: anyone doing edge auth, rate limiting, header manipulation or path rewriting — most of what people currently do with Ingress annotations on a Solr cloud — cannot express it on the route. The only remaining option is policy attached at Gateway or listener scope by the platform team, where the implementation supports that; it is coarser than per-route, and not what a team migrating a per-Ingress annotation setup expects to have to rebuild. Useful for scoping: there is no portable standard-channel answer upstream yet either. GEP-1494 ("HTTP Auth in Gateway API", which introduces the `ExternalAuth` HTTPRoute filter) is still **Experimental** and ships only in experimental-channel CRDs — https://gateway-api.sigs.k8s.io/geps/gep-1494/ — so an `ExtensionRef` passthrough is the only thing that helps users today. Two ways forward, either fine by me: 1. Add a passthrough — e.g. `gateway.filters` typed as `[]gatewayv1.HTTPRouteFilter`, or an `httpRouteOptions` member under `customSolrKubeOptions` matching the existing `ingressOptions` precedent. Note this interacts with Copilot's comment at `controllers/util/gateway_util.go:198`: once user-supplied fields exist in the spec, the wholesale `Spec.Rules` replacement has to become a per-field merge like `CopyIngressFields` (`controllers/util/common.go:252-327`), and the default-normalization fix Copilot asks for becomes a prerequisite rather than just an efficiency win. 2. Ship as-is but say so plainly in the docs: Gateway mode supports plain host-based routing only, and anything needing filters or implementation-specific policy should stay on `method: Ingress` for now. What I'd rather avoid is shipping without either, since the "successor to Ingress" framing I commented on at `docs/modules/solr-cloud/pages/gateway-api.adoc:22` will lead people to migrate and then discover this. ########## docs/modules/solr-cloud/pages/gateway-api.adoc: ########## @@ -0,0 +1,272 @@ += Gateway API +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +== Overview + +The Solr Operator supports using the https://gateway-api.sigs.k8s.io/[Kubernetes Gateway API] for external addressability of SolrClouds. +Gateway API is a vendor-neutral, Kubernetes-native API for managing ingress traffic and is the successor to the Ingress API. + +When you configure `spec.solrAddressability.external.method: Gateway`, the Solr Operator creates and manages HTTPRoute resources +that route external traffic to your Solr nodes through an existing Gateway resource in your cluster. + +== What Gets Created + +When Gateway mode is enabled, the Solr Operator automatically creates the following Kubernetes resources: + +=== HTTPRoute Resources + +The operator creates HTTPRoute resources to route traffic to Solr: + +* **Common HTTPRoute**: Routes traffic to the common Solr service (load-balanced across all nodes) +** Named: `<solrcloud-name>-solrcloud-common` +** Hostname: `<namespace>-<solrcloud-name>-solrcloud.<domainName>` +* **Per-Node HTTPRoutes**: Routes traffic directly to individual Solr nodes (when `hideNodes: false`) +** Named: `<solrcloud-name>-solrcloud-<node-index>` +** Hostname: `<namespace>-<solrcloud-name>-solrcloud-<node-index>.<domainName>` + +All HTTPRoutes are owned by the SolrCloud resource and will be automatically cleaned up when the SolrCloud is deleted. + +=== Services + +The same services are created as with other external addressability methods, depending on whether per-node Services are required: + +* Common service (load-balanced) +* Headless service (when not using per-node services) +* Per-node services (when individual node access is enabled) + +== What the Operator Assumes + +The Gateway mode assumes the following resources already exist in your cluster: + +. **Gateway API CRDs**: The Gateway API CRDs must be installed in your cluster +** Minimum version: v1.4.0 (required for `BackendTLSPolicy` support) +** Required CRDs: `Gateway`, `GatewayClass`, `HTTPRoute`, `BackendTLSPolicy` (optional, for TLS backends) +. **Gateway Resource**: A Gateway resource must already exist and be managed by your platform team +** The operator only manages HTTPRoute resources, not the Gateway itself +** The Gateway must be configured with appropriate listeners and TLS termination (if needed) +. **Gateway Controller**: A Gateway controller implementation must be running (e.g., NGINX Gateway Fabric, Istio, Envoy Gateway) + +The Solr Operator does **not** create or manage Gateway or GatewayClass resources - these are infrastructure-level resources +typically managed by platform administrators and are specific to the Gateway implementation deployed in your cluster (e.g., NGINX Gateway Fabric, Istio, Envoy Gateway). + +=== CRD Detection + +Gateway support is enabled automatically; there is no flag to turn it on or off. +At startup, the operator queries the Kubernetes API server to determine whether the Gateway API CRDs are installed. +Gateway support is enabled only when **both** the `HTTPRoute` and `BackendTLSPolicy` types (API group `gateway.networking.k8s.io/v1`) are registered. +If either is missing, the operator logs that Gateway support is disabled, does not watch these types, and ignores `method: Gateway` configurations. + +IMPORTANT: Detection happens only once, when the operator starts. If you install (or remove) the Gateway API CRDs while the operator is running, you must restart the operator pod for the change to take effect. + +== Configuration + +Configure Gateway mode in your SolrCloud spec: + +[source,yaml] +---- +apiVersion: solr.apache.org/v1beta1 +kind: SolrCloud +metadata: + name: example + namespace: solr-ns +spec: + replicas: 3 + solrImage: + tag: "9.7.0" + solrAddressability: + external: + method: Gateway + domainName: solr.example.com + useExternalAddress: true + gateway: + # Reference to existing Gateway resource(s) + parentRefs: + - name: my-gateway + namespace: gateway-ns + sectionName: https # Optional: specific listener name + + # Optional: annotations to add to HTTPRoute resources + annotations: + example.com/custom-annotation: "value" + + # Optional: labels to add to HTTPRoute resources + labels: + app: solr + environment: production +---- + +=== Configuration Options + +* **`parentRefs`** (required): List of Gateway resources to attach HTTPRoutes to +** `name`: Name of the Gateway resource +** `namespace`: Namespace of the Gateway (can be different from SolrCloud namespace) +** `sectionName`: Optional listener name within the Gateway +* **`annotations`**: Optional annotations to add to all created HTTPRoute resources +* **`labels`**: Optional labels to add to all created HTTPRoute resources +* **`domainName`**: Base domain for constructing hostnames +* **`useExternalAddress`**: When true, Solr nodes use external addresses for inter-node communication +* **`hideCommon`**: Set to true to skip creating the common HTTPRoute (default: false) +* **`hideNodes`**: Set to true to skip creating per-node HTTPRoutes (default: false) + +== Backend TLS Policy + +When using TLS-enabled Solr (`spec.solrTLS` is configured), the Solr Operator automatically sets `appProtocol: https` on all Services. +The operator also supports creating `BackendTLSPolicy` resources to configure secure connections between the Gateway and Solr backend services. + +=== Configuring BackendTLSPolicy + +The Solr Operator can automatically create and manage `BackendTLSPolicy` resources (Gateway API v1) when configured in the SolrCloud spec: + +[source,yaml] +---- +apiVersion: solr.apache.org/v1beta1 +kind: SolrCloud +metadata: + name: example + namespace: solr-ns +spec: + replicas: 3 + solrImage: + tag: "9.7.0" + # Enable TLS for Solr + solrTLS: + pkcs12Secret: + name: solr-tls-cert + key: keystore.p12 + solrAddressability: + external: + method: Gateway + domainName: solr.example.com + gateway: + parentRefs: + - name: my-gateway + namespace: gateway-ns + # Configure BackendTLSPolicy for secure backend connections + backendTLSPolicy: + # Option 1: Reference CA certificate from a ConfigMap (default) + caCertificateRefs: + - name: solr-ca-cert + # kind: ConfigMap # Optional, defaults to ConfigMap + # group: "" # Optional, defaults to "" (core API) + + # Option 2: Use well-known CA certificates + # wellKnownCACertificates: "System" +---- + +The generated `BackendTLSPolicy` will look like: + +[source,yaml] +---- +apiVersion: gateway.networking.k8s.io/v1 +kind: BackendTLSPolicy +metadata: + name: example-solrcloud-common + namespace: solr-ns +spec: + targetRefs: + - name: example-solrcloud-common + kind: Service + group: "" + validation: + hostname: example-solrcloud-common + caCertificateRefs: + - group: "" + kind: ConfigMap + name: solr-ca-cert +---- + +=== BackendTLSPolicy Options + +The `backendTLSPolicy` field supports two mutually exclusive options: + +* **`caCertificateRefs`**: References to Kubernetes ConfigMaps or Secrets containing CA certificates +** `name`: Name of the ConfigMap or Secret (required) +** `kind`: Resource kind (optional, defaults to "ConfigMap") +** `group`: API group (optional, defaults to "" for core API) +** Maximum of 8 certificate references +** **Note**: ConfigMaps must contain the CA certificate in a key named `ca.crt` +* **`wellKnownCACertificates`**: Use system CA certificates (e.g., "System") +** Only one of `caCertificateRefs` or `wellKnownCACertificates` can be specified + +When configured, the operator creates: + +* `BackendTLSPolicy` for the common service (if not hidden) +* `BackendTLSPolicy` for each node service (if not hidden) + +These policies configure the Gateway to validate backend TLS certificates and establish secure connections to Solr pods. + +=== Gateway Implementation Support + +NOTE: `BackendTLSPolicy` is part of the Gateway API standard (GA in v1.4.0+), but support varies by implementation. + +[cols="1,1",options="header"] +|=== +| Gateway Implementation | BackendTLSPolicy Support + +| **Standard Gateway API** | ✅ v1 (GA as of v1.4.0) +| **Envoy Gateway** | ✅ Full support +| **kgateway** | ✅ Full support +| **Istio** | ⚠️ Use `DestinationRule` instead +| **NGINX Gateway Fabric** | ✅ Supported +| **GKE Gateway** | ⚠️ Automatic via `appProtocol` +|=== + +**Requirements**: Gateway API v1.4.0 or later is required for `BackendTLSPolicy` support. + +Refer to your Gateway implementation's documentation for specific backend TLS configuration requirements. + +== Complete Example + +[source,yaml] +---- +apiVersion: solr.apache.org/v1beta1 +kind: SolrCloud +metadata: + name: example + namespace: solr-ns +spec: + replicas: 3 + solrImage: + tag: "9.7.0" + solrAddressability: + external: + method: Gateway + domainName: solr.example.com + useExternalAddress: true + gateway: + parentRefs: + - name: my-gateway + namespace: gateway-ns + annotations: + example.com/rate-limit: "1000" Review Comment: The Complete Example at `docs/modules/solr-cloud/pages/gateway-api.adoc:255-256` shows: ```yaml annotations: example.com/rate-limit: "1000" ``` This mirrors the Ingress annotation idiom and reads as working edge configuration, but HTTPRoute annotations are not a portable configuration surface in Gateway API — rate limiting, auth, rewrites and timeouts attach via `filters` or policy objects. I'd drop this example or replace it with something that is honestly just metadata. Same concern more mildly at `docs/modules/solr-cloud/pages/gateway-api.adoc:103-105` and `:119`. Related implementation asymmetry worth fixing in the same pass: `controllers/util/gateway_util.go:191` does `to.Annotations = from.Annotations`, replacing the whole map, so an annotation added out-of-band by a user or another controller is deleted on the next reconcile. The Ingress path merges and never deletes (`controllers/util/common.go:74-80`), and relies on that to let users override `nginx.ingress.kubernetes.io/backend-protocol` (`controllers/util/solr_util.go:1143-1167`). ########## docs/modules/solr-cloud/pages/gateway-api.adoc: ########## @@ -0,0 +1,272 @@ += Gateway API +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +== Overview + +The Solr Operator supports using the https://gateway-api.sigs.k8s.io/[Kubernetes Gateway API] for external addressability of SolrClouds. +Gateway API is a vendor-neutral, Kubernetes-native API for managing ingress traffic and is the successor to the Ingress API. + +When you configure `spec.solrAddressability.external.method: Gateway`, the Solr Operator creates and manages HTTPRoute resources +that route external traffic to your Solr nodes through an existing Gateway resource in your cluster. + +== What Gets Created + +When Gateway mode is enabled, the Solr Operator automatically creates the following Kubernetes resources: + +=== HTTPRoute Resources + +The operator creates HTTPRoute resources to route traffic to Solr: + +* **Common HTTPRoute**: Routes traffic to the common Solr service (load-balanced across all nodes) +** Named: `<solrcloud-name>-solrcloud-common` +** Hostname: `<namespace>-<solrcloud-name>-solrcloud.<domainName>` +* **Per-Node HTTPRoutes**: Routes traffic directly to individual Solr nodes (when `hideNodes: false`) +** Named: `<solrcloud-name>-solrcloud-<node-index>` +** Hostname: `<namespace>-<solrcloud-name>-solrcloud-<node-index>.<domainName>` + +All HTTPRoutes are owned by the SolrCloud resource and will be automatically cleaned up when the SolrCloud is deleted. + +=== Services + +The same services are created as with other external addressability methods, depending on whether per-node Services are required: + +* Common service (load-balanced) +* Headless service (when not using per-node services) +* Per-node services (when individual node access is enabled) + +== What the Operator Assumes + +The Gateway mode assumes the following resources already exist in your cluster: + +. **Gateway API CRDs**: The Gateway API CRDs must be installed in your cluster +** Minimum version: v1.4.0 (required for `BackendTLSPolicy` support) +** Required CRDs: `Gateway`, `GatewayClass`, `HTTPRoute`, `BackendTLSPolicy` (optional, for TLS backends) +. **Gateway Resource**: A Gateway resource must already exist and be managed by your platform team +** The operator only manages HTTPRoute resources, not the Gateway itself +** The Gateway must be configured with appropriate listeners and TLS termination (if needed) +. **Gateway Controller**: A Gateway controller implementation must be running (e.g., NGINX Gateway Fabric, Istio, Envoy Gateway) + +The Solr Operator does **not** create or manage Gateway or GatewayClass resources - these are infrastructure-level resources +typically managed by platform administrators and are specific to the Gateway implementation deployed in your cluster (e.g., NGINX Gateway Fabric, Istio, Envoy Gateway). + +=== CRD Detection + +Gateway support is enabled automatically; there is no flag to turn it on or off. +At startup, the operator queries the Kubernetes API server to determine whether the Gateway API CRDs are installed. +Gateway support is enabled only when **both** the `HTTPRoute` and `BackendTLSPolicy` types (API group `gateway.networking.k8s.io/v1`) are registered. +If either is missing, the operator logs that Gateway support is disabled, does not watch these types, and ignores `method: Gateway` configurations. + +IMPORTANT: Detection happens only once, when the operator starts. If you install (or remove) the Gateway API CRDs while the operator is running, you must restart the operator pod for the change to take effect. + +== Configuration + +Configure Gateway mode in your SolrCloud spec: + +[source,yaml] +---- +apiVersion: solr.apache.org/v1beta1 +kind: SolrCloud +metadata: + name: example + namespace: solr-ns +spec: + replicas: 3 + solrImage: + tag: "9.7.0" + solrAddressability: + external: + method: Gateway + domainName: solr.example.com + useExternalAddress: true + gateway: + # Reference to existing Gateway resource(s) + parentRefs: + - name: my-gateway + namespace: gateway-ns + sectionName: https # Optional: specific listener name + + # Optional: annotations to add to HTTPRoute resources + annotations: + example.com/custom-annotation: "value" + + # Optional: labels to add to HTTPRoute resources + labels: + app: solr + environment: production +---- + +=== Configuration Options + +* **`parentRefs`** (required): List of Gateway resources to attach HTTPRoutes to +** `name`: Name of the Gateway resource +** `namespace`: Namespace of the Gateway (can be different from SolrCloud namespace) +** `sectionName`: Optional listener name within the Gateway +* **`annotations`**: Optional annotations to add to all created HTTPRoute resources +* **`labels`**: Optional labels to add to all created HTTPRoute resources +* **`domainName`**: Base domain for constructing hostnames +* **`useExternalAddress`**: When true, Solr nodes use external addresses for inter-node communication +* **`hideCommon`**: Set to true to skip creating the common HTTPRoute (default: false) +* **`hideNodes`**: Set to true to skip creating per-node HTTPRoutes (default: false) + +== Backend TLS Policy + +When using TLS-enabled Solr (`spec.solrTLS` is configured), the Solr Operator automatically sets `appProtocol: https` on all Services. +The operator also supports creating `BackendTLSPolicy` resources to configure secure connections between the Gateway and Solr backend services. + +=== Configuring BackendTLSPolicy + +The Solr Operator can automatically create and manage `BackendTLSPolicy` resources (Gateway API v1) when configured in the SolrCloud spec: + +[source,yaml] +---- +apiVersion: solr.apache.org/v1beta1 +kind: SolrCloud +metadata: + name: example + namespace: solr-ns +spec: + replicas: 3 + solrImage: + tag: "9.7.0" + # Enable TLS for Solr + solrTLS: + pkcs12Secret: + name: solr-tls-cert + key: keystore.p12 + solrAddressability: + external: + method: Gateway + domainName: solr.example.com + gateway: + parentRefs: + - name: my-gateway + namespace: gateway-ns + # Configure BackendTLSPolicy for secure backend connections + backendTLSPolicy: + # Option 1: Reference CA certificate from a ConfigMap (default) + caCertificateRefs: + - name: solr-ca-cert + # kind: ConfigMap # Optional, defaults to ConfigMap + # group: "" # Optional, defaults to "" (core API) + + # Option 2: Use well-known CA certificates + # wellKnownCACertificates: "System" +---- + +The generated `BackendTLSPolicy` will look like: + +[source,yaml] +---- +apiVersion: gateway.networking.k8s.io/v1 +kind: BackendTLSPolicy +metadata: + name: example-solrcloud-common + namespace: solr-ns +spec: + targetRefs: + - name: example-solrcloud-common + kind: Service + group: "" + validation: + hostname: example-solrcloud-common + caCertificateRefs: + - group: "" + kind: ConfigMap + name: solr-ca-cert +---- + +=== BackendTLSPolicy Options + +The `backendTLSPolicy` field supports two mutually exclusive options: + +* **`caCertificateRefs`**: References to Kubernetes ConfigMaps or Secrets containing CA certificates +** `name`: Name of the ConfigMap or Secret (required) +** `kind`: Resource kind (optional, defaults to "ConfigMap") +** `group`: API group (optional, defaults to "" for core API) +** Maximum of 8 certificate references +** **Note**: ConfigMaps must contain the CA certificate in a key named `ca.crt` +* **`wellKnownCACertificates`**: Use system CA certificates (e.g., "System") +** Only one of `caCertificateRefs` or `wellKnownCACertificates` can be specified + +When configured, the operator creates: + +* `BackendTLSPolicy` for the common service (if not hidden) +* `BackendTLSPolicy` for each node service (if not hidden) + +These policies configure the Gateway to validate backend TLS certificates and establish secure connections to Solr pods. + +=== Gateway Implementation Support + +NOTE: `BackendTLSPolicy` is part of the Gateway API standard (GA in v1.4.0+), but support varies by implementation. + +[cols="1,1",options="header"] Review Comment: The table at `docs/modules/solr-cloud/pages/gateway-api.adoc:217-227` asserts "Full support" for five named implementations. That is a maintenance liability, it omits Traefik (plus Cilium, Kong, HAProxy), and this repo cannot test any of it. I'd replace it with one sentence and a link to the upstream conformance reports, which are maintained for us: https://gateway-api.sigs.k8s.io/implementations/ For balance: the version claim in the same section **is** accurate. `backendtlspolicies.gateway.networking.k8s.io` carries `gateway.networking.k8s.io/channel: standard` on a live v1.6.1 install, and upstream confirms "Standard Channel since v1.4.0". Might be worth linking the canonical API-type page next to the GEP: https://gateway-api.sigs.k8s.io/reference/api-types/policy/backendtlspolicy/ ########## docs/modules/solr-cloud/pages/gateway-api.adoc: ########## @@ -0,0 +1,272 @@ += Gateway API +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +== Overview + +The Solr Operator supports using the https://gateway-api.sigs.k8s.io/[Kubernetes Gateway API] for external addressability of SolrClouds. +Gateway API is a vendor-neutral, Kubernetes-native API for managing ingress traffic and is the successor to the Ingress API. + +When you configure `spec.solrAddressability.external.method: Gateway`, the Solr Operator creates and manages HTTPRoute resources +that route external traffic to your Solr nodes through an existing Gateway resource in your cluster. + +== What Gets Created + +When Gateway mode is enabled, the Solr Operator automatically creates the following Kubernetes resources: + +=== HTTPRoute Resources + +The operator creates HTTPRoute resources to route traffic to Solr: + +* **Common HTTPRoute**: Routes traffic to the common Solr service (load-balanced across all nodes) +** Named: `<solrcloud-name>-solrcloud-common` +** Hostname: `<namespace>-<solrcloud-name>-solrcloud.<domainName>` +* **Per-Node HTTPRoutes**: Routes traffic directly to individual Solr nodes (when `hideNodes: false`) +** Named: `<solrcloud-name>-solrcloud-<node-index>` +** Hostname: `<namespace>-<solrcloud-name>-solrcloud-<node-index>.<domainName>` + +All HTTPRoutes are owned by the SolrCloud resource and will be automatically cleaned up when the SolrCloud is deleted. + +=== Services + +The same services are created as with other external addressability methods, depending on whether per-node Services are required: + +* Common service (load-balanced) +* Headless service (when not using per-node services) +* Per-node services (when individual node access is enabled) + +== What the Operator Assumes + +The Gateway mode assumes the following resources already exist in your cluster: + +. **Gateway API CRDs**: The Gateway API CRDs must be installed in your cluster +** Minimum version: v1.4.0 (required for `BackendTLSPolicy` support) +** Required CRDs: `Gateway`, `GatewayClass`, `HTTPRoute`, `BackendTLSPolicy` (optional, for TLS backends) +. **Gateway Resource**: A Gateway resource must already exist and be managed by your platform team +** The operator only manages HTTPRoute resources, not the Gateway itself +** The Gateway must be configured with appropriate listeners and TLS termination (if needed) +. **Gateway Controller**: A Gateway controller implementation must be running (e.g., NGINX Gateway Fabric, Istio, Envoy Gateway) + +The Solr Operator does **not** create or manage Gateway or GatewayClass resources - these are infrastructure-level resources +typically managed by platform administrators and are specific to the Gateway implementation deployed in your cluster (e.g., NGINX Gateway Fabric, Istio, Envoy Gateway). + +=== CRD Detection + +Gateway support is enabled automatically; there is no flag to turn it on or off. +At startup, the operator queries the Kubernetes API server to determine whether the Gateway API CRDs are installed. +Gateway support is enabled only when **both** the `HTTPRoute` and `BackendTLSPolicy` types (API group `gateway.networking.k8s.io/v1`) are registered. +If either is missing, the operator logs that Gateway support is disabled, does not watch these types, and ignores `method: Gateway` configurations. + +IMPORTANT: Detection happens only once, when the operator starts. If you install (or remove) the Gateway API CRDs while the operator is running, you must restart the operator pod for the change to take effect. + +== Configuration Review Comment: **`solr` chart doesn't document `gateway`.** `helm/solr/values.yaml` documents `addressability.external.method: "Ingress"` and `ingressTLSTermination` but has no `gateway:` key. It passes through via `helm/solr/templates/solrcloud.yaml`, so it works, but it's undiscoverable. *(Anchored here because `helm/solr/values.yaml` is not part of this PR's diff.)* ########## docs/modules/solr-cloud/pages/gateway-api.adoc: ########## @@ -0,0 +1,272 @@ += Gateway API +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +== Overview + +The Solr Operator supports using the https://gateway-api.sigs.k8s.io/[Kubernetes Gateway API] for external addressability of SolrClouds. +Gateway API is a vendor-neutral, Kubernetes-native API for managing ingress traffic and is the successor to the Ingress API. + +When you configure `spec.solrAddressability.external.method: Gateway`, the Solr Operator creates and manages HTTPRoute resources +that route external traffic to your Solr nodes through an existing Gateway resource in your cluster. + +== What Gets Created + +When Gateway mode is enabled, the Solr Operator automatically creates the following Kubernetes resources: + +=== HTTPRoute Resources + +The operator creates HTTPRoute resources to route traffic to Solr: + +* **Common HTTPRoute**: Routes traffic to the common Solr service (load-balanced across all nodes) +** Named: `<solrcloud-name>-solrcloud-common` +** Hostname: `<namespace>-<solrcloud-name>-solrcloud.<domainName>` +* **Per-Node HTTPRoutes**: Routes traffic directly to individual Solr nodes (when `hideNodes: false`) +** Named: `<solrcloud-name>-solrcloud-<node-index>` +** Hostname: `<namespace>-<solrcloud-name>-solrcloud-<node-index>.<domainName>` + +All HTTPRoutes are owned by the SolrCloud resource and will be automatically cleaned up when the SolrCloud is deleted. + +=== Services + +The same services are created as with other external addressability methods, depending on whether per-node Services are required: + +* Common service (load-balanced) +* Headless service (when not using per-node services) +* Per-node services (when individual node access is enabled) + +== What the Operator Assumes + +The Gateway mode assumes the following resources already exist in your cluster: + +. **Gateway API CRDs**: The Gateway API CRDs must be installed in your cluster +** Minimum version: v1.4.0 (required for `BackendTLSPolicy` support) +** Required CRDs: `Gateway`, `GatewayClass`, `HTTPRoute`, `BackendTLSPolicy` (optional, for TLS backends) +. **Gateway Resource**: A Gateway resource must already exist and be managed by your platform team +** The operator only manages HTTPRoute resources, not the Gateway itself +** The Gateway must be configured with appropriate listeners and TLS termination (if needed) +. **Gateway Controller**: A Gateway controller implementation must be running (e.g., NGINX Gateway Fabric, Istio, Envoy Gateway) + +The Solr Operator does **not** create or manage Gateway or GatewayClass resources - these are infrastructure-level resources +typically managed by platform administrators and are specific to the Gateway implementation deployed in your cluster (e.g., NGINX Gateway Fabric, Istio, Envoy Gateway). + +=== CRD Detection + +Gateway support is enabled automatically; there is no flag to turn it on or off. +At startup, the operator queries the Kubernetes API server to determine whether the Gateway API CRDs are installed. +Gateway support is enabled only when **both** the `HTTPRoute` and `BackendTLSPolicy` types (API group `gateway.networking.k8s.io/v1`) are registered. +If either is missing, the operator logs that Gateway support is disabled, does not watch these types, and ignores `method: Gateway` configurations. + +IMPORTANT: Detection happens only once, when the operator starts. If you install (or remove) the Gateway API CRDs while the operator is running, you must restart the operator pod for the change to take effect. + +== Configuration + +Configure Gateway mode in your SolrCloud spec: + +[source,yaml] +---- +apiVersion: solr.apache.org/v1beta1 +kind: SolrCloud +metadata: + name: example + namespace: solr-ns +spec: + replicas: 3 + solrImage: + tag: "9.7.0" + solrAddressability: + external: + method: Gateway + domainName: solr.example.com + useExternalAddress: true + gateway: + # Reference to existing Gateway resource(s) + parentRefs: + - name: my-gateway + namespace: gateway-ns + sectionName: https # Optional: specific listener name + + # Optional: annotations to add to HTTPRoute resources + annotations: + example.com/custom-annotation: "value" + + # Optional: labels to add to HTTPRoute resources + labels: + app: solr + environment: production +---- + +=== Configuration Options + +* **`parentRefs`** (required): List of Gateway resources to attach HTTPRoutes to +** `name`: Name of the Gateway resource +** `namespace`: Namespace of the Gateway (can be different from SolrCloud namespace) +** `sectionName`: Optional listener name within the Gateway +* **`annotations`**: Optional annotations to add to all created HTTPRoute resources +* **`labels`**: Optional labels to add to all created HTTPRoute resources +* **`domainName`**: Base domain for constructing hostnames +* **`useExternalAddress`**: When true, Solr nodes use external addresses for inter-node communication +* **`hideCommon`**: Set to true to skip creating the common HTTPRoute (default: false) +* **`hideNodes`**: Set to true to skip creating per-node HTTPRoutes (default: false) + +== Backend TLS Policy + +When using TLS-enabled Solr (`spec.solrTLS` is configured), the Solr Operator automatically sets `appProtocol: https` on all Services. +The operator also supports creating `BackendTLSPolicy` resources to configure secure connections between the Gateway and Solr backend services. + +=== Configuring BackendTLSPolicy + +The Solr Operator can automatically create and manage `BackendTLSPolicy` resources (Gateway API v1) when configured in the SolrCloud spec: + +[source,yaml] +---- +apiVersion: solr.apache.org/v1beta1 +kind: SolrCloud +metadata: + name: example + namespace: solr-ns +spec: + replicas: 3 + solrImage: + tag: "9.7.0" + # Enable TLS for Solr + solrTLS: + pkcs12Secret: + name: solr-tls-cert + key: keystore.p12 + solrAddressability: + external: + method: Gateway + domainName: solr.example.com + gateway: + parentRefs: + - name: my-gateway + namespace: gateway-ns + # Configure BackendTLSPolicy for secure backend connections + backendTLSPolicy: + # Option 1: Reference CA certificate from a ConfigMap (default) + caCertificateRefs: + - name: solr-ca-cert + # kind: ConfigMap # Optional, defaults to ConfigMap + # group: "" # Optional, defaults to "" (core API) + + # Option 2: Use well-known CA certificates + # wellKnownCACertificates: "System" +---- + +The generated `BackendTLSPolicy` will look like: + +[source,yaml] +---- +apiVersion: gateway.networking.k8s.io/v1 +kind: BackendTLSPolicy +metadata: + name: example-solrcloud-common + namespace: solr-ns +spec: + targetRefs: + - name: example-solrcloud-common + kind: Service + group: "" + validation: + hostname: example-solrcloud-common + caCertificateRefs: + - group: "" + kind: ConfigMap + name: solr-ca-cert +---- + +=== BackendTLSPolicy Options + +The `backendTLSPolicy` field supports two mutually exclusive options: + +* **`caCertificateRefs`**: References to Kubernetes ConfigMaps or Secrets containing CA certificates +** `name`: Name of the ConfigMap or Secret (required) +** `kind`: Resource kind (optional, defaults to "ConfigMap") +** `group`: API group (optional, defaults to "" for core API) +** Maximum of 8 certificate references +** **Note**: ConfigMaps must contain the CA certificate in a key named `ca.crt` +* **`wellKnownCACertificates`**: Use system CA certificates (e.g., "System") +** Only one of `caCertificateRefs` or `wellKnownCACertificates` can be specified + +When configured, the operator creates: + +* `BackendTLSPolicy` for the common service (if not hidden) +* `BackendTLSPolicy` for each node service (if not hidden) + +These policies configure the Gateway to validate backend TLS certificates and establish secure connections to Solr pods. + +=== Gateway Implementation Support + +NOTE: `BackendTLSPolicy` is part of the Gateway API standard (GA in v1.4.0+), but support varies by implementation. + +[cols="1,1",options="header"] +|=== +| Gateway Implementation | BackendTLSPolicy Support + +| **Standard Gateway API** | ✅ v1 (GA as of v1.4.0) +| **Envoy Gateway** | ✅ Full support +| **kgateway** | ✅ Full support +| **Istio** | ⚠️ Use `DestinationRule` instead +| **NGINX Gateway Fabric** | ✅ Supported +| **GKE Gateway** | ⚠️ Automatic via `appProtocol` +|=== + +**Requirements**: Gateway API v1.4.0 or later is required for `BackendTLSPolicy` support. + +Refer to your Gateway implementation's documentation for specific backend TLS configuration requirements. + +== Complete Example + +[source,yaml] +---- +apiVersion: solr.apache.org/v1beta1 +kind: SolrCloud +metadata: + name: example + namespace: solr-ns +spec: + replicas: 3 + solrImage: + tag: "9.7.0" + solrAddressability: + external: + method: Gateway + domainName: solr.example.com + useExternalAddress: true + gateway: + parentRefs: + - name: my-gateway + namespace: gateway-ns + annotations: + example.com/rate-limit: "1000" + labels: + app: solr +---- + +This configuration will create: + +* HTTPRoute: `example-solrcloud-common` → `solr-ns-example-solrcloud.solr.example.com` +* HTTPRoute: `example-solrcloud-0` → `solr-ns-example-solrcloud-0.solr.example.com` +* HTTPRoute: `example-solrcloud-1` → `solr-ns-example-solrcloud-1.solr.example.com` +* HTTPRoute: `example-solrcloud-2` → `solr-ns-example-solrcloud-2.solr.example.com` + +== References Review Comment: On whether this is documentable without covering every implementation: I think yes, provided we document **our** delta and delegate per-implementation detail upstream. Documenting Traefik vs Istio vs Envoy Gateway vs Cilium behaviour in the Solr docs would rot within a release; the upstream conformance reports already do that job. Proposed shape for a short section in `gateway-api.adoc`: **What does not carry over from `method: Ingress`** - `customSolrKubeOptions.ingressOptions.annotations` — no HTTPRoute equivalent, and annotations are not a portable configuration surface in Gateway API. Anything expressed as an ingress-controller annotation (auth, rate limits, rewrites, body size, timeouts) must be re-expressed as a `filters` entry or an implementation-specific policy object attached by your platform team. See my comment on `SolrGatewayOptions` in `api/v1beta1/solrcloud_types.go` — today the operator cannot emit filters at all. - `ingressTLSTermination` — edge TLS is configured on the Gateway listener, not by the operator, and leaving the block in place silently disables `useExternalAddress`. - `nodePortOverride` — Ingress-only (see Copilot's comment on `api/v1beta1/solrcloud_types.go:1478`; worth cross-referencing once that's resolved). - `ingressClassName` — replaced by the `GatewayClass` on the Gateway your `parentRefs` point at. **What to check before switching** - Confirm your Gateway controller is conformant for the features you need: https://gateway-api.sigs.k8s.io/implementations/ and https://gateway-api.sigs.k8s.io/docs/conformance/levels/ — the Core vs Extended vs Implementation-specific distinction is the one that matters. - If you terminate TLS at the edge with client certificates, that is Gateway-level `frontendValidation` (GEP-91, standard channel since Gateway API v1.5.0) and is not implemented everywhere — Traefik lists `GatewayFrontendClientCertificateValidation` under `unsupportedFeatures` in its v1.6 conformance report, so verify before migrating. - If you delegate authentication to the edge, there is no portable standard mechanism yet (GEP-1494 is experimental), so expect an implementation-specific `ExtensionRef`. **Useful links** - Upstream migration guide: https://gateway-api.sigs.k8s.io/guides/getting-started/migrating-from-ingress/ — has a feature-mapping table and is explicit that annotation-driven features are not portable. - For ingress-nginx users specifically: https://gateway-api.sigs.k8s.io/guides/getting-started/migrating-from-ingress-nginx/ - `ingress2gateway` for a mechanical first pass: https://github.com/kubernetes-sigs/ingress2gateway — supports traefik, ingress-nginx, istio, kong, cilium, gce and others. Its own caveat is worth quoting: "Ingress2gateway is not intended to copy annotations from Ingress to Gateway API." It converts the routing, not the behaviour. - TLS configuration guide: https://gateway-api.sigs.k8s.io/guides/user-guides/tls/ Four bullets of delta plus five links, and it commits us to tracking no implementation. ########## docs/modules/solr-cloud/pages/gateway-api.adoc: ########## @@ -0,0 +1,272 @@ += Gateway API +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +== Overview + +The Solr Operator supports using the https://gateway-api.sigs.k8s.io/[Kubernetes Gateway API] for external addressability of SolrClouds. +Gateway API is a vendor-neutral, Kubernetes-native API for managing ingress traffic and is the successor to the Ingress API. + +When you configure `spec.solrAddressability.external.method: Gateway`, the Solr Operator creates and manages HTTPRoute resources +that route external traffic to your Solr nodes through an existing Gateway resource in your cluster. + +== What Gets Created + +When Gateway mode is enabled, the Solr Operator automatically creates the following Kubernetes resources: + +=== HTTPRoute Resources + +The operator creates HTTPRoute resources to route traffic to Solr: + +* **Common HTTPRoute**: Routes traffic to the common Solr service (load-balanced across all nodes) +** Named: `<solrcloud-name>-solrcloud-common` +** Hostname: `<namespace>-<solrcloud-name>-solrcloud.<domainName>` +* **Per-Node HTTPRoutes**: Routes traffic directly to individual Solr nodes (when `hideNodes: false`) +** Named: `<solrcloud-name>-solrcloud-<node-index>` +** Hostname: `<namespace>-<solrcloud-name>-solrcloud-<node-index>.<domainName>` + +All HTTPRoutes are owned by the SolrCloud resource and will be automatically cleaned up when the SolrCloud is deleted. + +=== Services + +The same services are created as with other external addressability methods, depending on whether per-node Services are required: + +* Common service (load-balanced) +* Headless service (when not using per-node services) +* Per-node services (when individual node access is enabled) + +== What the Operator Assumes + +The Gateway mode assumes the following resources already exist in your cluster: + +. **Gateway API CRDs**: The Gateway API CRDs must be installed in your cluster +** Minimum version: v1.4.0 (required for `BackendTLSPolicy` support) +** Required CRDs: `Gateway`, `GatewayClass`, `HTTPRoute`, `BackendTLSPolicy` (optional, for TLS backends) +. **Gateway Resource**: A Gateway resource must already exist and be managed by your platform team +** The operator only manages HTTPRoute resources, not the Gateway itself +** The Gateway must be configured with appropriate listeners and TLS termination (if needed) +. **Gateway Controller**: A Gateway controller implementation must be running (e.g., NGINX Gateway Fabric, Istio, Envoy Gateway) + +The Solr Operator does **not** create or manage Gateway or GatewayClass resources - these are infrastructure-level resources +typically managed by platform administrators and are specific to the Gateway implementation deployed in your cluster (e.g., NGINX Gateway Fabric, Istio, Envoy Gateway). + +=== CRD Detection + +Gateway support is enabled automatically; there is no flag to turn it on or off. +At startup, the operator queries the Kubernetes API server to determine whether the Gateway API CRDs are installed. +Gateway support is enabled only when **both** the `HTTPRoute` and `BackendTLSPolicy` types (API group `gateway.networking.k8s.io/v1`) are registered. +If either is missing, the operator logs that Gateway support is disabled, does not watch these types, and ignores `method: Gateway` configurations. + +IMPORTANT: Detection happens only once, when the operator starts. If you install (or remove) the Gateway API CRDs while the operator is running, you must restart the operator pod for the change to take effect. + +== Configuration + +Configure Gateway mode in your SolrCloud spec: + +[source,yaml] +---- +apiVersion: solr.apache.org/v1beta1 +kind: SolrCloud +metadata: + name: example + namespace: solr-ns +spec: + replicas: 3 + solrImage: + tag: "9.7.0" + solrAddressability: + external: + method: Gateway + domainName: solr.example.com + useExternalAddress: true + gateway: + # Reference to existing Gateway resource(s) + parentRefs: + - name: my-gateway + namespace: gateway-ns + sectionName: https # Optional: specific listener name + + # Optional: annotations to add to HTTPRoute resources + annotations: + example.com/custom-annotation: "value" + + # Optional: labels to add to HTTPRoute resources + labels: + app: solr + environment: production +---- + +=== Configuration Options Review Comment: **`additionalHostnames` restriction isn't documented.** Separate from the count-overflow bug Copilot raised: `GenerateNodeHTTPRoute` ignores the field entirely (`controllers/util/gateway_util.go:113-121`), so it only ever affects the common route. The field's own doc comment says so, but the "Configuration Options" list in `docs/modules/solr-cloud/pages/gateway-api.adoc:113-124` doesn't. ########## api/v1beta1/solrcloud_types.go: ########## @@ -577,6 +587,9 @@ const ( // Use ExternalDNS to make the Solr service(s) externally addressable ExternalDNS ExternalAddressabilityMethod = "ExternalDNS" + // Use Gateway API to make the Solr service(s) externally addressable + Gateway ExternalAddressabilityMethod = "Gateway" + // Make Solr service(s) type:LoadBalancer to make them externally addressable // NOTE: This option is not currently supported. LoadBalancer ExternalAddressabilityMethod = "LoadBalancer" Review Comment: *(The line in question is `api/v1beta1/solrcloud_types.go:600`, five lines below this one — it is outside the PR diff, so this is the closest line GitHub lets me anchor to.)* In `ExternalAddressability.withDefaults` (`api/v1beta1/solrcloud_types.go`): ```go if opts.UseExternalAddress && (opts.HideNodes || opts.IngressTLSTermination != nil) { changed = true opts.UseExternalAddress = false } ``` There is no method guard on `IngressTLSTermination != nil`, while `HasIngressTLSTermination()` at `api/v1beta1/solrcloud_types.go:1601` **is** gated to `Method == Ingress`. So a cloud with `method: Gateway` that still carries an `ingressTLSTermination` block from its Ingress days gets no TLS termination behaviour from it, but does silently get `useExternalAddress` flipped off — which changes the advertised Solr node names. That is an easy state to land in when switching methods, and it fails quietly. Suggest gating that condition on `Method == Ingress`, or rejecting `ingressTLSTermination` together with `method: Gateway` in validation. Either way it deserves a line in the migration notes. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
