diff --git a/CHANGELOG.md b/CHANGELOG.md index f72c54b3..f7fdd054 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 @@ -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 diff --git a/rust/operator-binary/src/service.rs b/rust/operator-binary/src/service.rs index c89296cd..36dc33d2 100644 --- a/rust/operator-binary/src/service.rs +++ b/rust/operator-binary/src/service.rs @@ -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, }; @@ -34,20 +34,20 @@ pub enum Error { pub fn build_node_rolegroup_headless_service( superset: &v1alpha1::SupersetCluster, resolved_product_image: &ResolvedProductImage, - rolegroup: &RoleGroupRef, + rolegroup_ref: &RoleGroupRef, ) -> Result { 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(), @@ -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(), @@ -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, + rolegroup_ref: &RoleGroupRef, ) -> Result { 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 @@ -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(), @@ -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, -) -> 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, -) -> String { - format!("{name}-metrics", name = rolegroup.object_name()) -} - fn metrics_ports() -> Vec { vec![ServicePort { name: Some(METRICS_PORT_NAME.to_string()), @@ -153,3 +138,22 @@ fn service_ports() -> Vec { ..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 +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") +} diff --git a/rust/operator-binary/src/superset_controller.rs b/rust/operator-binary/src/superset_controller.rs index 09eef6a2..8f12e3ca 100644 --- a/rust/operator-binary/src/superset_controller.rs +++ b/rust/operator-binary/src/superset_controller.rs @@ -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, }; @@ -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, @@ -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, @@ -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()