Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- `EOS_DISABLED` (`--eos-disabled`) to disable the EoS checker completely.
- Helm: Allow Pod `priorityClassName` to be configured ([#664]).
- Add version `4.1.4` ([#669]).
- Add `prometheus.io/path|port|scheme` annotations to metrics service ([#671]).

### Changed

Expand All @@ -26,6 +27,7 @@
[#666]: https://github.com/stackabletech/superset-operator/pull/666
[#669]: https://github.com/stackabletech/superset-operator/pull/669
[#670]: https://github.com/stackabletech/superset-operator/pull/670
[#671]: https://github.com/stackabletech/superset-operator/pull/671

## [25.7.0] - 2025-07-23

Expand Down
64 changes: 34 additions & 30 deletions rust/operator-binary/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use stackable_operator::{
builder::meta::ObjectMetaBuilder,
commons::product_image_selection::ResolvedProductImage,
k8s_openapi::api::core::v1::{Service, ServicePort, ServiceSpec},
kvp::{Label, Labels},
kvp::{Annotations, Labels},
role_utils::RoleGroupRef,
};

Expand Down Expand Up @@ -34,20 +34,20 @@ pub enum Error {
pub fn build_node_rolegroup_headless_service(
superset: &v1alpha1::SupersetCluster,
resolved_product_image: &ResolvedProductImage,
rolegroup: &RoleGroupRef<v1alpha1::SupersetCluster>,
rolegroup_ref: &RoleGroupRef<v1alpha1::SupersetCluster>,
) -> Result<Service, Error> {
let headless_service = Service {
metadata: ObjectMetaBuilder::new()
.name_and_namespace(superset)
.name(rolegroup_headless_service_name(rolegroup))
.name(rolegroup_ref.rolegroup_headless_service_name())
.ownerreference_from_resource(superset, None, Some(true))
.context(ObjectMissingMetadataForOwnerRefSnafu)?
.with_recommended_labels(build_recommended_labels(
superset,
SUPERSET_CONTROLLER_NAME,
&resolved_product_image.app_version_label_value,
&rolegroup.role,
&rolegroup.role_group,
&rolegroup_ref.role,
&rolegroup_ref.role_group,
))
.context(MetadataBuildSnafu)?
.build(),
Expand All @@ -60,8 +60,8 @@ pub fn build_node_rolegroup_headless_service(
Labels::role_group_selector(
superset,
APP_NAME,
&rolegroup.role,
&rolegroup.role_group,
&rolegroup_ref.role,
&rolegroup_ref.role_group,
)
.context(LabelBuildSnafu)?
.into(),
Expand All @@ -78,23 +78,24 @@ pub fn build_node_rolegroup_headless_service(
pub fn build_node_rolegroup_metrics_service(
superset: &v1alpha1::SupersetCluster,
resolved_product_image: &ResolvedProductImage,
rolegroup: &RoleGroupRef<v1alpha1::SupersetCluster>,
rolegroup_ref: &RoleGroupRef<v1alpha1::SupersetCluster>,
) -> Result<Service, Error> {
let metrics_service = Service {
metadata: ObjectMetaBuilder::new()
.name_and_namespace(superset)
.name(rolegroup_metrics_service_name(rolegroup))
.name(rolegroup_ref.rolegroup_metrics_service_name())
.ownerreference_from_resource(superset, None, Some(true))
.context(ObjectMissingMetadataForOwnerRefSnafu)?
.with_recommended_labels(build_recommended_labels(
superset,
SUPERSET_CONTROLLER_NAME,
&resolved_product_image.app_version_label_value,
&rolegroup.role,
&rolegroup.role_group,
&rolegroup_ref.role,
&rolegroup_ref.role_group,
))
.context(MetadataBuildSnafu)?
.with_label(Label::try_from(("prometheus.io/scrape", "true")).context(LabelBuildSnafu)?)
.with_labels(prometheus_labels())
.with_annotations(prometheus_annotations())
.build(),
spec: Some(ServiceSpec {
// Internal communication does not need to be exposed
Expand All @@ -105,8 +106,8 @@ pub fn build_node_rolegroup_metrics_service(
Labels::role_group_selector(
superset,
APP_NAME,
&rolegroup.role,
&rolegroup.role_group,
&rolegroup_ref.role,
&rolegroup_ref.role_group,
)
.context(LabelBuildSnafu)?
.into(),
Expand All @@ -120,22 +121,6 @@ pub fn build_node_rolegroup_metrics_service(
Ok(metrics_service)
}

/// Headless service for cluster internal purposes only.
// TODO: Move to operator-rs
pub fn rolegroup_headless_service_name(
rolegroup: &RoleGroupRef<v1alpha1::SupersetCluster>,
) -> String {
format!("{name}-headless", name = rolegroup.object_name())
}

/// Headless metrics service exposes Prometheus endpoint only
// TODO: Move to operator-rs
pub fn rolegroup_metrics_service_name(
rolegroup: &RoleGroupRef<v1alpha1::SupersetCluster>,
) -> String {
format!("{name}-metrics", name = rolegroup.object_name())
}

fn metrics_ports() -> Vec<ServicePort> {
vec![ServicePort {
name: Some(METRICS_PORT_NAME.to_string()),
Expand All @@ -153,3 +138,22 @@ fn service_ports() -> Vec<ServicePort> {
..ServicePort::default()
}]
}
/// Common labels for Prometheus
fn prometheus_labels() -> Labels {
Labels::try_from([("prometheus.io/scrape", "true")]).expect("should be a valid label")
}

/// Common annotations for Prometheus
///
/// These annotations can be used in a ServiceMonitor.
///
/// see also <https://github.com/prometheus-community/helm-charts/blob/prometheus-27.32.0/charts/prometheus/values.yaml#L983-L1036>
fn prometheus_annotations() -> Annotations {
Annotations::try_from([
("prometheus.io/path".to_owned(), "/metrics".to_owned()),
("prometheus.io/port".to_owned(), METRICS_PORT.to_string()),
("prometheus.io/scheme".to_owned(), "http".to_owned()),
("prometheus.io/scrape".to_owned(), "true".to_owned()),
])
.expect("should be valid annotations")
}
15 changes: 2 additions & 13 deletions rust/operator-binary/src/superset_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,7 @@ use crate::{
listener::{LISTENER_VOLUME_DIR, LISTENER_VOLUME_NAME, build_group_listener},
operations::{graceful_shutdown::add_graceful_shutdown_config, pdb::add_pdbs},
product_logging::{LOG_CONFIG_FILE, extend_config_map_with_log_config},
service::{
build_node_rolegroup_headless_service, build_node_rolegroup_metrics_service,
rolegroup_headless_service_name,
},
service::{build_node_rolegroup_headless_service, build_node_rolegroup_metrics_service},
util::build_recommended_labels,
};

Expand All @@ -112,9 +109,6 @@ pub struct Ctx {
#[strum_discriminants(derive(IntoStaticStr))]
#[allow(clippy::enum_variant_names)]
pub enum Error {
#[snafu(display("object has no namespace"))]
ObjectHasNoNamespace,

#[snafu(display("object defines no node role"))]
NoNodeRole,

Expand All @@ -136,11 +130,6 @@ pub enum Error {
source: stackable_operator::cluster_resources::Error,
},

#[snafu(display("failed to apply global Service"))]
ApplyRoleService {
source: stackable_operator::cluster_resources::Error,
},

#[snafu(display("failed to apply Service for {rolegroup}"))]
ApplyRoleGroupService {
source: stackable_operator::cluster_resources::Error,
Expand Down Expand Up @@ -921,7 +910,7 @@ fn build_server_rolegroup_statefulset(
),
..LabelSelector::default()
},
service_name: Some(rolegroup_headless_service_name(rolegroup_ref)),
service_name: Some(rolegroup_ref.rolegroup_headless_service_name()),
template: pod_template,
volume_claim_templates: pvcs,
..StatefulSetSpec::default()
Expand Down
Loading