Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c523b61
add volume, volumeMount for listener
adwk67 Apr 24, 2025
cc197fc
Merge branch 'main' into feat/integrate-listener-operator
adwk67 Apr 24, 2025
9cb8f70
added integration test
adwk67 Apr 25, 2025
9952329
changelog and docs
adwk67 Apr 25, 2025
7fde2db
use opaque string for listener_class and persist address for all list…
adwk67 Apr 28, 2025
999e40a
Merge branch 'main' into feat/integrate-listener-operator
adwk67 Apr 28, 2025
7ee1e8e
fix tests (use exsting service, avoid name clash)
adwk67 Apr 28, 2025
05f330e
use test ns-specific listener classes and simplify config use
adwk67 Apr 30, 2025
df0773a
Update rust/operator-binary/src/crd/mod.rs
adwk67 May 5, 2025
a967ae7
Update rust/operator-binary/src/superset_controller.rs
adwk67 May 5, 2025
37743a9
Update rust/operator-binary/src/superset_controller.rs
adwk67 May 5, 2025
cf2b664
fixed typo/formatting
adwk67 May 5, 2025
f9b3f5c
fixed inconsistency in docs
adwk67 May 5, 2025
0de25d4
changelog entry marked as breaking
adwk67 May 5, 2025
7301589
Update rust/operator-binary/src/crd/mod.rs
adwk67 May 5, 2025
7bce0dd
Update rust/operator-binary/src/superset_controller.rs
adwk67 May 5, 2025
ed1a1c7
Update rust/operator-binary/src/superset_controller.rs
adwk67 May 5, 2025
80a5fcf
use to_owned for showing intention
adwk67 May 5, 2025
61613f1
changes in line with decision 51: metrics exposed separately, no extr…
adwk67 May 6, 2025
5f82289
Merge branch 'main' into feat/integrate-listener-operator
adwk67 May 6, 2025
4a9cf78
Merge branch 'main' into feat/integrate-listener-operator
adwk67 May 6, 2025
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Use `--file-log-max-files` (or `FILE_LOG_MAX_FILES`) to limit the number of log files kept.
- Use `--file-log-rotation-period` (or `FILE_LOG_ROTATION_PERIOD`) to configure the frequency of rotation.
- Use `--console-log-format` (or `CONSOLE_LOG_FORMAT`) to set the format to `plain` (default) or `json`.
- BREAKING: Added listener support for Superset ([#625]).

### Changed

Expand All @@ -31,6 +32,7 @@
[#615]: https://github.com/stackabletech/superset-operator/pull/615
[#617]: https://github.com/stackabletech/superset-operator/pull/617
[#623]: https://github.com/stackabletech/superset-operator/pull/623
[#625]: https://github.com/stackabletech/superset-operator/pull/625
[#628]: https://github.com/stackabletech/superset-operator/pull/628

## [25.3.0] - 2025-03-21
Expand Down
25 changes: 8 additions & 17 deletions deploy/helm/superset-operator/crds/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -129,23 +129,6 @@ spec:
credentialsSecret:
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.
type: string
listenerClass:
default: cluster-internal
description: |-
This field controls which type of Service the Operator creates for this SupersetCluster:

* cluster-internal: Use a ClusterIP service

* external-unstable: Use a NodePort service

* external-stable: Use a LoadBalancer service

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.
enum:
- cluster-internal
- external-unstable
- external-stable
type: string
mapboxSecret:
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.
nullable: true
Expand Down Expand Up @@ -251,6 +234,10 @@ spec:
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
nullable: true
type: string
listenerClass:
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose the webserver.
nullable: true
type: string
logging:
default:
containers: {}
Expand Down Expand Up @@ -479,6 +466,10 @@ spec:
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
nullable: true
type: string
listenerClass:
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose the webserver.
nullable: true
type: string
logging:
default:
containers: {}
Expand Down
11 changes: 11 additions & 0 deletions deploy/helm/superset-operator/templates/roles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,17 @@ rules:
- bind
resourceNames:
- {{ include "operator.name" . }}-clusterrole
- apiGroups:
- listeners.stackable.tech
resources:
- listeners
verbs:
- get
- list
- watch
- patch
- create
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
Expand Down
17 changes: 7 additions & 10 deletions docs/modules/superset/pages/usage-guide/listenerclass.adoc
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
= Service exposition with ListenerClasses
:description: Superset service exposition with ListenerClass: configure access via internal, external-unstable, or external-stable services.
:description: Configure the Superset service exposure with listener classes: cluster-internal, external-unstable, or external-stable.

Apache Superset offers a web UI and an API.
The Operator deploys a service called `<name>-external` (where `<name>` is the name of the SupersetCluster) through which Superset can be reached.

This service can have three different types: `cluster-internal`, `external-unstable` and `external-stable`.
Read more about the types in the xref:concepts:service-exposition.adoc[service exposition] documentation at platform level.

This is how the ListenerClass is configured:
The operator deploys a xref:listener-operator:listener.adoc[Listener] for the Nodes pod.
The listener defaults to only being accessible from within the Kubernetes cluster, but this can be changed by setting `.spec.nodes.config.listenerClass`:

[source,yaml]
----
spec:
clusterConfig:
listenerClass: cluster-internal # <1>
nodes:
config:
listenerClass: external-stable # <1>
----
<1> The default `cluster-internal` setting.
<1> Specify one of `external-stable`, `external-unstable`, `cluster-internal` (the default setting is `cluster-internal`).
73 changes: 26 additions & 47 deletions rust/operator-binary/src/crd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ use stackable_operator::{
},
},
config::{
fragment,
fragment::{Fragment, ValidationError},
fragment::{self, Fragment, ValidationError},
merge::Merge,
},
k8s_openapi::apimachinery::pkg::api::resource::Quantity,
Expand Down Expand Up @@ -48,6 +47,14 @@ pub const MAX_LOG_FILES_SIZE: MemoryQuantity = MemoryQuantity {
unit: BinaryMultiple::Mebi,
};

pub const LISTENER_VOLUME_NAME: &str = "listener";
pub const LISTENER_VOLUME_DIR: &str = "/stackable/listener";

pub const APP_PORT_NAME: &str = "http";
pub const APP_PORT: u16 = 8088;
pub const METRICS_PORT_NAME: &str = "metrics";
pub const METRICS_PORT: u16 = 9102;

const DEFAULT_NODE_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = Duration::from_minutes_unchecked(2);

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

#[snafu(display("fragment validation failure"))]
FragmentValidationFailure { source: ValidationError },

#[snafu(display("Configuration/Executor conflict!"))]
NoRoleForExecutorFailure,

#[snafu(display("object has no associated namespace"))]
NoNamespace,
}

#[derive(Display, EnumIter, EnumString)]
Expand Down Expand Up @@ -157,20 +170,6 @@ pub mod versioned {
#[serde(default)]
pub cluster_operation: ClusterOperation,

/// This field controls which type of Service the Operator creates for this SupersetCluster:
///
/// * cluster-internal: Use a ClusterIP service
///
/// * external-unstable: Use a NodePort service
///
/// * external-stable: Use a LoadBalancer service
///
/// This is a temporary solution with the goal to keep yaml manifests forward compatible.
/// In the future, this setting will control which [ListenerClass](DOCS_BASE_URL_PLACEHOLDER/listener-operator/listenerclass.html)
/// will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change.
#[serde(default)]
pub listener_class: v1alpha1::CurrentlySupportedListenerClasses,

/// 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.
Expand Down Expand Up @@ -224,21 +223,10 @@ pub mod versioned {
/// Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
#[fragment_attrs(serde(default))]
pub graceful_shutdown_timeout: Option<Duration>,
}

// TODO: Temporary solution until listener-operator is finished
#[derive(Clone, Debug, Default, Display, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub enum CurrentlySupportedListenerClasses {
#[default]
#[serde(rename = "cluster-internal")]
ClusterInternal,

#[serde(rename = "external-unstable")]
ExternalUnstable,

#[serde(rename = "external-stable")]
ExternalStable,
/// This field controls which [ListenerClass](DOCS_BASE_URL_PLACEHOLDER/listener-operator/listenerclass.html) is used to expose the webserver.
#[serde(default)]
pub listener_class: String,
}

#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
Expand Down Expand Up @@ -406,18 +394,6 @@ impl FlaskAppConfigOptions for SupersetConfigOptions {
}
}

impl v1alpha1::CurrentlySupportedListenerClasses {
pub fn k8s_service_type(&self) -> String {
match self {
v1alpha1::CurrentlySupportedListenerClasses::ClusterInternal => "ClusterIP".to_string(),
v1alpha1::CurrentlySupportedListenerClasses::ExternalUnstable => "NodePort".to_string(),
v1alpha1::CurrentlySupportedListenerClasses::ExternalStable => {
"LoadBalancer".to_string()
}
}
}
}

impl v1alpha1::SupersetConfig {
pub const CREDENTIALS_SECRET_PROPERTY: &'static str = "credentialsSecret";
pub const MAPBOX_SECRET_PROPERTY: &'static str = "mapboxSecret";
Expand All @@ -440,6 +416,7 @@ impl v1alpha1::SupersetConfig {
graceful_shutdown_timeout: Some(DEFAULT_NODE_GRACEFUL_SHUTDOWN_TIMEOUT),
row_limit: None,
webserver_timeout: None,
listener_class: Some("cluster-internal".to_owned()),
}
}
}
Expand Down Expand Up @@ -505,17 +482,19 @@ impl HasStatusCondition for v1alpha1::SupersetCluster {
}

impl v1alpha1::SupersetCluster {
/// The name of the group-listener provided for a specific role-group.
/// The UI will use this group listener so that only one load balancer
/// is needed (per role group).
pub fn group_listener_name(&self, rolegroup: &RoleGroupRef<Self>) -> String {
rolegroup.object_name()
}

pub fn get_role(&self, role: &SupersetRole) -> Option<&Role<v1alpha1::SupersetConfigFragment>> {
match role {
SupersetRole::Node => self.spec.nodes.as_ref(),
}
}

/// The name of the role-level load-balanced Kubernetes `Service`
pub fn node_role_service_name(&self) -> Option<String> {
self.metadata.name.clone()
}

/// Metadata about a node rolegroup
pub fn node_rolegroup_ref(
&self,
Expand Down
1 change: 0 additions & 1 deletion rust/operator-binary/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ mod built_info {
include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

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

#[derive(Parser)]
Expand Down
Loading