Skip to content

Commit b29105c

Browse files
adwk67NickLarsenNZ
andauthored
feat: Superset Listener integration (#625)
* add volume, volumeMount for listener * added integration test * changelog and docs * use opaque string for listener_class and persist address for all listener classes * fix tests (use exsting service, avoid name clash) * use test ns-specific listener classes and simplify config use * Update rust/operator-binary/src/crd/mod.rs Co-authored-by: Nick <[email protected]> * Update rust/operator-binary/src/superset_controller.rs Co-authored-by: Nick <[email protected]> * Update rust/operator-binary/src/superset_controller.rs Co-authored-by: Nick <[email protected]> * fixed typo/formatting * fixed inconsistency in docs * changelog entry marked as breaking * Update rust/operator-binary/src/crd/mod.rs Co-authored-by: Nick <[email protected]> * Update rust/operator-binary/src/superset_controller.rs Co-authored-by: Nick <[email protected]> * Update rust/operator-binary/src/superset_controller.rs Co-authored-by: Nick <[email protected]> * use to_owned for showing intention * changes in line with decision 51: metrics exposed separately, no extra suffix for node service --------- Co-authored-by: Nick <[email protected]>
1 parent 1be722b commit b29105c

File tree

22 files changed

+443
-206
lines changed

22 files changed

+443
-206
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Use `--file-log-max-files` (or `FILE_LOG_MAX_FILES`) to limit the number of log files kept.
99
- Use `--file-log-rotation-period` (or `FILE_LOG_ROTATION_PERIOD`) to configure the frequency of rotation.
1010
- Use `--console-log-format` (or `CONSOLE_LOG_FORMAT`) to set the format to `plain` (default) or `json`.
11+
- BREAKING: Added listener support for Superset ([#625]).
1112

1213
### Changed
1314

@@ -31,6 +32,7 @@
3132
[#615]: https://github.com/stackabletech/superset-operator/pull/615
3233
[#617]: https://github.com/stackabletech/superset-operator/pull/617
3334
[#623]: https://github.com/stackabletech/superset-operator/pull/623
35+
[#625]: https://github.com/stackabletech/superset-operator/pull/625
3436
[#628]: https://github.com/stackabletech/superset-operator/pull/628
3537

3638
## [25.3.0] - 2025-03-21

deploy/helm/superset-operator/crds/crds.yaml

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -129,23 +129,6 @@ spec:
129129
credentialsSecret:
130130
description: The name of the Secret object containing the admin user credentials and database connection details. Read the [getting started guide first steps](https://docs.stackable.tech/home/nightly/superset/getting_started/first_steps) to find out more.
131131
type: string
132-
listenerClass:
133-
default: cluster-internal
134-
description: |-
135-
This field controls which type of Service the Operator creates for this SupersetCluster:
136-
137-
* cluster-internal: Use a ClusterIP service
138-
139-
* external-unstable: Use a NodePort service
140-
141-
* external-stable: Use a LoadBalancer service
142-
143-
This is a temporary solution with the goal to keep yaml manifests forward compatible. In the future, this setting will control which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change.
144-
enum:
145-
- cluster-internal
146-
- external-unstable
147-
- external-stable
148-
type: string
149132
mapboxSecret:
150133
description: The name of a Secret object. The Secret should contain a key `connections.mapboxApiKey`. This is the API key required for map charts to work that use mapbox. The token should be in the JWT format.
151134
nullable: true
@@ -251,6 +234,10 @@ spec:
251234
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
252235
nullable: true
253236
type: string
237+
listenerClass:
238+
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose the webserver.
239+
nullable: true
240+
type: string
254241
logging:
255242
default:
256243
containers: {}
@@ -479,6 +466,10 @@ spec:
479466
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
480467
nullable: true
481468
type: string
469+
listenerClass:
470+
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose the webserver.
471+
nullable: true
472+
type: string
482473
logging:
483474
default:
484475
containers: {}

deploy/helm/superset-operator/templates/roles.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,17 @@ rules:
125125
- bind
126126
resourceNames:
127127
- {{ include "operator.name" . }}-clusterrole
128+
- apiGroups:
129+
- listeners.stackable.tech
130+
resources:
131+
- listeners
132+
verbs:
133+
- get
134+
- list
135+
- watch
136+
- patch
137+
- create
138+
- delete
128139
---
129140
apiVersion: rbac.authorization.k8s.io/v1
130141
kind: ClusterRole
Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
= Service exposition with ListenerClasses
2-
:description: Superset service exposition with ListenerClass: configure access via internal, external-unstable, or external-stable services.
2+
:description: Configure the Superset service exposure with listener classes: cluster-internal, external-unstable, or external-stable.
33

44
Apache Superset offers a web UI and an API.
5-
The Operator deploys a service called `<name>-external` (where `<name>` is the name of the SupersetCluster) through which Superset can be reached.
6-
7-
This service can have three different types: `cluster-internal`, `external-unstable` and `external-stable`.
8-
Read more about the types in the xref:concepts:service-exposition.adoc[service exposition] documentation at platform level.
9-
10-
This is how the ListenerClass is configured:
5+
The operator deploys a xref:listener-operator:listener.adoc[Listener] for the Nodes pod.
6+
The listener defaults to only being accessible from within the Kubernetes cluster, but this can be changed by setting `.spec.nodes.config.listenerClass`:
117

128
[source,yaml]
139
----
1410
spec:
15-
clusterConfig:
16-
listenerClass: cluster-internal # <1>
11+
nodes:
12+
config:
13+
listenerClass: external-stable # <1>
1714
----
18-
<1> The default `cluster-internal` setting.
15+
<1> Specify one of `external-stable`, `external-unstable`, `cluster-internal` (the default setting is `cluster-internal`).

rust/operator-binary/src/crd/mod.rs

Lines changed: 26 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ use stackable_operator::{
1616
},
1717
},
1818
config::{
19-
fragment,
20-
fragment::{Fragment, ValidationError},
19+
fragment::{self, Fragment, ValidationError},
2120
merge::Merge,
2221
},
2322
k8s_openapi::apimachinery::pkg::api::resource::Quantity,
@@ -48,6 +47,14 @@ pub const MAX_LOG_FILES_SIZE: MemoryQuantity = MemoryQuantity {
4847
unit: BinaryMultiple::Mebi,
4948
};
5049

50+
pub const LISTENER_VOLUME_NAME: &str = "listener";
51+
pub const LISTENER_VOLUME_DIR: &str = "/stackable/listener";
52+
53+
pub const APP_PORT_NAME: &str = "http";
54+
pub const APP_PORT: u16 = 8088;
55+
pub const METRICS_PORT_NAME: &str = "metrics";
56+
pub const METRICS_PORT: u16 = 9102;
57+
5158
const DEFAULT_NODE_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = Duration::from_minutes_unchecked(2);
5259

5360
#[derive(Debug, Snafu)]
@@ -57,6 +64,12 @@ pub enum Error {
5764

5865
#[snafu(display("fragment validation failure"))]
5966
FragmentValidationFailure { source: ValidationError },
67+
68+
#[snafu(display("Configuration/Executor conflict!"))]
69+
NoRoleForExecutorFailure,
70+
71+
#[snafu(display("object has no associated namespace"))]
72+
NoNamespace,
6073
}
6174

6275
#[derive(Display, EnumIter, EnumString)]
@@ -157,20 +170,6 @@ pub mod versioned {
157170
#[serde(default)]
158171
pub cluster_operation: ClusterOperation,
159172

160-
/// This field controls which type of Service the Operator creates for this SupersetCluster:
161-
///
162-
/// * cluster-internal: Use a ClusterIP service
163-
///
164-
/// * external-unstable: Use a NodePort service
165-
///
166-
/// * external-stable: Use a LoadBalancer service
167-
///
168-
/// This is a temporary solution with the goal to keep yaml manifests forward compatible.
169-
/// In the future, this setting will control which [ListenerClass](DOCS_BASE_URL_PLACEHOLDER/listener-operator/listenerclass.html)
170-
/// will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change.
171-
#[serde(default)]
172-
pub listener_class: v1alpha1::CurrentlySupportedListenerClasses,
173-
174173
/// The name of a Secret object.
175174
/// The Secret should contain a key `connections.mapboxApiKey`.
176175
/// This is the API key required for map charts to work that use mapbox.
@@ -224,21 +223,10 @@ pub mod versioned {
224223
/// Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
225224
#[fragment_attrs(serde(default))]
226225
pub graceful_shutdown_timeout: Option<Duration>,
227-
}
228-
229-
// TODO: Temporary solution until listener-operator is finished
230-
#[derive(Clone, Debug, Default, Display, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
231-
#[serde(rename_all = "PascalCase")]
232-
pub enum CurrentlySupportedListenerClasses {
233-
#[default]
234-
#[serde(rename = "cluster-internal")]
235-
ClusterInternal,
236226

237-
#[serde(rename = "external-unstable")]
238-
ExternalUnstable,
239-
240-
#[serde(rename = "external-stable")]
241-
ExternalStable,
227+
/// This field controls which [ListenerClass](DOCS_BASE_URL_PLACEHOLDER/listener-operator/listenerclass.html) is used to expose the webserver.
228+
#[serde(default)]
229+
pub listener_class: String,
242230
}
243231

244232
#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
@@ -406,18 +394,6 @@ impl FlaskAppConfigOptions for SupersetConfigOptions {
406394
}
407395
}
408396

409-
impl v1alpha1::CurrentlySupportedListenerClasses {
410-
pub fn k8s_service_type(&self) -> String {
411-
match self {
412-
v1alpha1::CurrentlySupportedListenerClasses::ClusterInternal => "ClusterIP".to_string(),
413-
v1alpha1::CurrentlySupportedListenerClasses::ExternalUnstable => "NodePort".to_string(),
414-
v1alpha1::CurrentlySupportedListenerClasses::ExternalStable => {
415-
"LoadBalancer".to_string()
416-
}
417-
}
418-
}
419-
}
420-
421397
impl v1alpha1::SupersetConfig {
422398
pub const CREDENTIALS_SECRET_PROPERTY: &'static str = "credentialsSecret";
423399
pub const MAPBOX_SECRET_PROPERTY: &'static str = "mapboxSecret";
@@ -440,6 +416,7 @@ impl v1alpha1::SupersetConfig {
440416
graceful_shutdown_timeout: Some(DEFAULT_NODE_GRACEFUL_SHUTDOWN_TIMEOUT),
441417
row_limit: None,
442418
webserver_timeout: None,
419+
listener_class: Some("cluster-internal".to_owned()),
443420
}
444421
}
445422
}
@@ -505,17 +482,19 @@ impl HasStatusCondition for v1alpha1::SupersetCluster {
505482
}
506483

507484
impl v1alpha1::SupersetCluster {
485+
/// The name of the group-listener provided for a specific role-group.
486+
/// The UI will use this group listener so that only one load balancer
487+
/// is needed (per role group).
488+
pub fn group_listener_name(&self, rolegroup: &RoleGroupRef<Self>) -> String {
489+
rolegroup.object_name()
490+
}
491+
508492
pub fn get_role(&self, role: &SupersetRole) -> Option<&Role<v1alpha1::SupersetConfigFragment>> {
509493
match role {
510494
SupersetRole::Node => self.spec.nodes.as_ref(),
511495
}
512496
}
513497

514-
/// The name of the role-level load-balanced Kubernetes `Service`
515-
pub fn node_role_service_name(&self) -> Option<String> {
516-
self.metadata.name.clone()
517-
}
518-
519498
/// Metadata about a node rolegroup
520499
pub fn node_rolegroup_ref(
521500
&self,

rust/operator-binary/src/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ mod built_info {
5252
include!(concat!(env!("OUT_DIR"), "/built.rs"));
5353
}
5454

55-
pub const APP_PORT: u16 = 8088;
5655
pub const OPERATOR_NAME: &str = "superset.stackable.tech";
5756

5857
#[derive(Parser)]

0 commit comments

Comments
 (0)