From 1f0edbf060da1ba212cddeb137356eb00db9ca7d Mon Sep 17 00:00:00 2001 From: Marc-Merino <35137847+Marc-Merino@users.noreply.github.com> Date: Thu, 1 Oct 2026 03:45:27 -0500 Subject: [PATCH] feat: Add OpenShift Route support for Listeners --- crates/stackable-operator/CHANGELOG.md | 5 +++ .../crds/ListenerClass.yaml | 23 +++++++++++ .../src/crd/listener/class/mod.rs | 39 +++++++++++++++++++ .../src/crd/listener/core/mod.rs | 5 +++ 4 files changed, 72 insertions(+) diff --git a/crates/stackable-operator/CHANGELOG.md b/crates/stackable-operator/CHANGELOG.md index ee60b2114..2415e4cc9 100644 --- a/crates/stackable-operator/CHANGELOG.md +++ b/crates/stackable-operator/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added + +- BREAKING: Add the `OpenShiftRoute` Listener service type, configured by `ListenerClass.spec.openshiftRoute`. + Exhaustive matches on `ServiceType` must handle the new variant. + ## [0.119.0] - 2026-09-23 ### Removed diff --git a/crates/stackable-operator/crds/ListenerClass.yaml b/crates/stackable-operator/crds/ListenerClass.yaml index afa4c00a8..094fd4c24 100644 --- a/crates/stackable-operator/crds/ListenerClass.yaml +++ b/crates/stackable-operator/crds/ListenerClass.yaml @@ -38,6 +38,28 @@ spec: Ignored unless serviceType is LoadBalancer. nullable: true type: string + openshiftRoute: + description: |- + Configures the OpenShift Route when `serviceType` is `OpenShiftRoute`. + + Ignored for other service types. + nullable: true + properties: + port: + description: |- + Name of the Listener port to expose. + + A Route can only expose a single port. May be omitted if the Listener only has one port. + nullable: true + type: string + tls: + default: Passthrough + description: How the Route handles TLS. Defaults to `Passthrough`. + enum: + - Passthrough + - None + type: string + type: object pinnedNodePorts: default: false description: |- @@ -106,6 +128,7 @@ spec: - NodePort - LoadBalancer - ClusterIP + - OpenShiftRoute type: string required: - serviceType diff --git a/crates/stackable-operator/src/crd/listener/class/mod.rs b/crates/stackable-operator/src/crd/listener/class/mod.rs index f212a2163..98e2832ae 100644 --- a/crates/stackable-operator/src/crd/listener/class/mod.rs +++ b/crates/stackable-operator/src/crd/listener/class/mod.rs @@ -34,6 +34,12 @@ pub mod versioned { pub struct ListenerClassSpec { pub service_type: core_v1alpha1::ServiceType, + /// Configures the OpenShift Route when `serviceType` is `OpenShiftRoute`. + /// + /// Ignored for other service types. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub openshift_route: Option, + /// Configures whether a LoadBalancer service should also allocate node ports (like NodePort). /// /// Ignored unless serviceType is LoadBalancer. @@ -121,6 +127,32 @@ pub mod versioned { #[schemars(schema_with = "raw_object_schema")] pub service_overrides: Service, } + + /// Configures how a Listener is exposed through an OpenShift Route. + #[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] + #[serde(rename_all = "camelCase")] + pub struct OpenShiftRouteConfig { + /// Name of the Listener port to expose. + /// + /// A Route can only expose a single port. May be omitted if the Listener only has one port. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub port: Option, + + /// How the Route handles TLS. Defaults to `Passthrough`. + #[serde(default)] + pub tls: OpenShiftRouteTls, + } + + #[derive(Clone, Copy, Debug, Default, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] + pub enum OpenShiftRouteTls { + /// Forward TLS traffic to the application, which must terminate TLS itself. + /// Exposed on port 443. + #[default] + Passthrough, + + /// Forward plain HTTP traffic. Exposed on port 80. + None, + } } #[cfg(test)] @@ -130,6 +162,13 @@ impl stackable_versioned::test_utils::RoundtripTestData for v1alpha1::ListenerCl - serviceType: ClusterIP - serviceType: NodePort - serviceType: LoadBalancer + - serviceType: OpenShiftRoute + - serviceType: OpenShiftRoute + openshiftRoute: + port: https + - serviceType: OpenShiftRoute + openshiftRoute: + tls: None - serviceType: ClusterIP loadBalancerAllocateNodePorts: false loadBalancerClass: foo diff --git a/crates/stackable-operator/src/crd/listener/core/mod.rs b/crates/stackable-operator/src/crd/listener/core/mod.rs index 545b19afd..b8d83e7c3 100644 --- a/crates/stackable-operator/src/crd/listener/core/mod.rs +++ b/crates/stackable-operator/src/crd/listener/core/mod.rs @@ -26,6 +26,11 @@ pub mod versioned { /// Assigns an IP address from a pool of IP addresses that your cluster has reserved for /// that purpose. ClusterIP, + + /// Expose a single port through an OpenShift Route, using a hostname assigned by OpenShift. + /// + /// Only available on OpenShift. Configured by `ListenerClass.spec.openshiftRoute`. + OpenShiftRoute, } /// Service Internal Traffic Policy enables internal traffic restrictions to only route internal