Skip to content

Commit 2f46832

Browse files
authored
Merge branch 'main' into fix/remove-pvcs
2 parents 265d33c + 06cb1ff commit 2f46832

11 files changed

Lines changed: 227 additions & 83 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file.
1212
- Use `--console-log-format` (or `CONSOLE_LOG_FORMAT`) to set the format to `plain` (default) or `json`.
1313
- Add Listener integration for Trino ([#753]).
1414
- Add support for Trino 476 ([#755]).
15+
- Add internal headless service in addition to the metrics service ([#766]).
1516

1617
### Changed
1718

@@ -66,6 +67,7 @@ All notable changes to this project will be documented in this file.
6667
[#753]: https://github.com/stackabletech/trino-operator/pull/753
6768
[#755]: https://github.com/stackabletech/trino-operator/pull/755
6869
[#760]: https://github.com/stackabletech/trino-operator/pull/760
70+
[#766]: https://github.com/stackabletech/trino-operator/pull/766
6971
[#769]: https://github.com/stackabletech/trino-operator/pull/769
7072

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

rust/operator-binary/src/controller.rs

Lines changed: 67 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ use stackable_operator::{
3636
apps::v1::{StatefulSet, StatefulSetSpec},
3737
core::v1::{
3838
ConfigMap, ConfigMapVolumeSource, ContainerPort, EnvVar, EnvVarSource, ExecAction,
39-
HTTPGetAction, Probe, Secret, SecretKeySelector, Service, ServicePort, ServiceSpec,
40-
Volume,
39+
HTTPGetAction, Probe, Secret, SecretKeySelector, Volume,
4140
},
4241
},
4342
apimachinery::pkg::{apis::meta::v1::LabelSelector, util::intstr::IntOrString},
@@ -47,7 +46,7 @@ use stackable_operator::{
4746
core::{DeserializeGuard, error_boundary},
4847
runtime::{controller::Action, reflector::ObjectRef},
4948
},
50-
kvp::{Annotation, Label, Labels, ObjectLabels},
49+
kvp::{Annotation, Labels, ObjectLabels},
5150
logging::controller::ReconcilerError,
5251
memory::{BinaryMultiple, MemoryQuantity},
5352
product_config_utils::{
@@ -87,16 +86,17 @@ use crate::{
8786
authentication::resolve_authentication_classes,
8887
catalog,
8988
discovery::{TrinoDiscovery, TrinoDiscoveryProtocol, TrinoPodRef},
90-
rolegroup_metrics_service_name, v1alpha1,
89+
rolegroup_headless_service_name, v1alpha1,
9190
},
9291
listener::{
9392
LISTENER_VOLUME_DIR, LISTENER_VOLUME_NAME, build_group_listener, build_group_listener_pvc,
94-
group_listener_name,
93+
group_listener_name, secret_volume_listener_scope,
9594
},
9695
operations::{
9796
add_graceful_shutdown_config, graceful_shutdown_config_properties, pdb::add_pdbs,
9897
},
9998
product_logging::{get_log_properties, get_vector_toml},
99+
service::{build_rolegroup_headless_service, build_rolegroup_metrics_service},
100100
};
101101

102102
pub struct Ctx {
@@ -356,6 +356,9 @@ pub enum Error {
356356

357357
#[snafu(display("failed to configure listener"))]
358358
ListenerConfiguration { source: crate::listener::Error },
359+
360+
#[snafu(display("failed to configure service"))]
361+
ServiceConfiguration { source: crate::service::Error },
359362
}
360363

361364
type Result<T, E = Error> = std::result::Result<T, E>;
@@ -481,8 +484,37 @@ pub async fn reconcile_trino(
481484
.merged_config(&trino_role, &role_group_ref, &catalog_definitions)
482485
.context(FailedToResolveConfigSnafu)?;
483486

484-
let rg_service =
485-
build_rolegroup_service(trino, &resolved_product_image, &role_group_ref)?;
487+
let role_group_service_recommended_labels = build_recommended_labels(
488+
trino,
489+
&resolved_product_image.app_version_label,
490+
&role_group_ref.role,
491+
&role_group_ref.role_group,
492+
);
493+
494+
let role_group_service_selector = Labels::role_group_selector(
495+
trino,
496+
APP_NAME,
497+
&role_group_ref.role,
498+
&role_group_ref.role_group,
499+
)
500+
.context(LabelBuildSnafu)?;
501+
502+
let rg_headless_service = build_rolegroup_headless_service(
503+
trino,
504+
&role_group_ref,
505+
role_group_service_recommended_labels.clone(),
506+
role_group_service_selector.clone().into(),
507+
)
508+
.context(ServiceConfigurationSnafu)?;
509+
510+
let rg_metrics_service = build_rolegroup_metrics_service(
511+
trino,
512+
&role_group_ref,
513+
role_group_service_recommended_labels,
514+
role_group_service_selector.into(),
515+
)
516+
.context(ServiceConfigurationSnafu)?;
517+
486518
let rg_configmap = build_rolegroup_config_map(
487519
trino,
488520
&resolved_product_image,
@@ -514,7 +546,14 @@ pub async fn reconcile_trino(
514546
)?;
515547

516548
cluster_resources
517-
.add(client, rg_service)
549+
.add(client, rg_headless_service)
550+
.await
551+
.with_context(|_| ApplyRoleGroupServiceSnafu {
552+
rolegroup: role_group_ref.clone(),
553+
})?;
554+
555+
cluster_resources
556+
.add(client, rg_metrics_service)
518557
.await
519558
.with_context(|_| ApplyRoleGroupServiceSnafu {
520559
rolegroup: role_group_ref.clone(),
@@ -833,7 +872,7 @@ fn build_rolegroup_catalog_config_map(
833872
/// The rolegroup [`StatefulSet`] runs the rolegroup, as configured by the administrator.
834873
///
835874
/// The [`Pod`](`stackable_operator::k8s_openapi::api::core::v1::Pod`)s are accessible through the
836-
/// corresponding [`Service`] (from [`build_rolegroup_service`]).
875+
/// corresponding [`stackable_operator::k8s_openapi::api::core::v1::Service`] (from [`build_rolegroup_headless_service`]).
837876
#[allow(clippy::too_many_arguments)]
838877
fn build_rolegroup_statefulset(
839878
trino: &v1alpha1::TrinoCluster,
@@ -929,6 +968,7 @@ fn build_rolegroup_statefulset(
929968
// add volume mounts depending on the client tls, internal tls, catalogs and authentication
930969
tls_volume_mounts(
931970
trino,
971+
trino_role,
932972
&mut pod_builder,
933973
&mut cb_prepare,
934974
&mut cb_trino,
@@ -1181,7 +1221,7 @@ fn build_rolegroup_statefulset(
11811221
),
11821222
..LabelSelector::default()
11831223
},
1184-
service_name: Some(rolegroup_metrics_service_name(
1224+
service_name: Some(rolegroup_headless_service_name(
11851225
&role_group_ref.object_name(),
11861226
)),
11871227
template: pod_template,
@@ -1192,53 +1232,6 @@ fn build_rolegroup_statefulset(
11921232
})
11931233
}
11941234

1195-
/// The rolegroup [`Service`] is a headless service that allows direct access to the instances of a certain rolegroup
1196-
///
1197-
/// This is mostly useful for internal communication between peers, or for clients that perform client-side load balancing.
1198-
fn build_rolegroup_service(
1199-
trino: &v1alpha1::TrinoCluster,
1200-
resolved_product_image: &ResolvedProductImage,
1201-
role_group_ref: &RoleGroupRef<v1alpha1::TrinoCluster>,
1202-
) -> Result<Service> {
1203-
Ok(Service {
1204-
metadata: ObjectMetaBuilder::new()
1205-
.name_and_namespace(trino)
1206-
.name(rolegroup_metrics_service_name(
1207-
&role_group_ref.object_name(),
1208-
))
1209-
.ownerreference_from_resource(trino, None, Some(true))
1210-
.context(ObjectMissingMetadataForOwnerRefSnafu)?
1211-
.with_recommended_labels(build_recommended_labels(
1212-
trino,
1213-
&resolved_product_image.app_version_label,
1214-
&role_group_ref.role,
1215-
&role_group_ref.role_group,
1216-
))
1217-
.context(MetadataBuildSnafu)?
1218-
.with_label(Label::try_from(("prometheus.io/scrape", "true")).context(LabelBuildSnafu)?)
1219-
.build(),
1220-
spec: Some(ServiceSpec {
1221-
// Internal communication does not need to be exposed
1222-
type_: Some("ClusterIP".to_string()),
1223-
cluster_ip: Some("None".to_string()),
1224-
ports: Some(service_ports()),
1225-
selector: Some(
1226-
Labels::role_group_selector(
1227-
trino,
1228-
APP_NAME,
1229-
&role_group_ref.role,
1230-
&role_group_ref.role_group,
1231-
)
1232-
.context(LabelBuildSnafu)?
1233-
.into(),
1234-
),
1235-
publish_not_ready_addresses: Some(true),
1236-
..ServiceSpec::default()
1237-
}),
1238-
status: None,
1239-
})
1240-
}
1241-
12421235
pub fn error_policy(
12431236
_obj: Arc<DeserializeGuard<v1alpha1::TrinoCluster>>,
12441237
error: &Error,
@@ -1397,15 +1390,6 @@ fn get_random_base64() -> String {
13971390
openssl::base64::encode_block(&buf)
13981391
}
13991392

1400-
fn service_ports() -> Vec<ServicePort> {
1401-
vec![ServicePort {
1402-
name: Some(METRICS_PORT_NAME.to_string()),
1403-
port: METRICS_PORT.into(),
1404-
protocol: Some("TCP".to_string()),
1405-
..ServicePort::default()
1406-
}]
1407-
}
1408-
14091393
fn container_ports(trino: &v1alpha1::TrinoCluster) -> Vec<ContainerPort> {
14101394
let mut ports = vec![ContainerPort {
14111395
name: Some(METRICS_PORT_NAME.to_string()),
@@ -1518,14 +1502,22 @@ fn create_tls_volume(
15181502
volume_name: &str,
15191503
tls_secret_class: &str,
15201504
requested_secret_lifetime: &Duration,
1505+
listener_scope: Option<String>,
15211506
) -> Result<Volume> {
1507+
let mut secret_volume_source_builder = SecretOperatorVolumeSourceBuilder::new(tls_secret_class);
1508+
1509+
secret_volume_source_builder
1510+
.with_pod_scope()
1511+
.with_format(SecretFormat::TlsPkcs12)
1512+
.with_auto_tls_cert_lifetime(*requested_secret_lifetime);
1513+
1514+
if let Some(listener_scope) = &listener_scope {
1515+
secret_volume_source_builder.with_listener_volume_scope(listener_scope);
1516+
}
1517+
15221518
Ok(VolumeBuilder::new(volume_name)
15231519
.ephemeral(
1524-
SecretOperatorVolumeSourceBuilder::new(tls_secret_class)
1525-
.with_pod_scope()
1526-
.with_node_scope()
1527-
.with_format(SecretFormat::TlsPkcs12)
1528-
.with_auto_tls_cert_lifetime(*requested_secret_lifetime)
1520+
secret_volume_source_builder
15291521
.build()
15301522
.context(TlsCertSecretClassVolumeBuildSnafu)?,
15311523
)
@@ -1534,6 +1526,7 @@ fn create_tls_volume(
15341526

15351527
fn tls_volume_mounts(
15361528
trino: &v1alpha1::TrinoCluster,
1529+
trino_role: &TrinoRole,
15371530
pod_builder: &mut PodBuilder,
15381531
cb_prepare: &mut ContainerBuilder,
15391532
cb_trino: &mut ContainerBuilder,
@@ -1552,6 +1545,8 @@ fn tls_volume_mounts(
15521545
"server-tls-mount",
15531546
server_tls,
15541547
requested_secret_lifetime,
1548+
// add listener
1549+
secret_volume_listener_scope(trino_role),
15551550
)?)
15561551
.context(AddVolumeSnafu)?;
15571552
}
@@ -1588,6 +1583,7 @@ fn tls_volume_mounts(
15881583
"internal-tls-mount",
15891584
internal_tls,
15901585
requested_secret_lifetime,
1586+
None,
15911587
)?)
15921588
.context(AddVolumeSnafu)?;
15931589

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ pub const MAX_TRINO_LOG_FILES_SIZE: MemoryQuantity = MemoryQuantity {
118118
};
119119

120120
pub const METRICS_SERVICE_SUFFIX: &str = "metrics";
121+
pub const HEADLESS_SERVICE_SUFFIX: &str = "headless";
121122

122123
pub const JVM_HEAP_FACTOR: f32 = 0.8;
123124

@@ -833,7 +834,7 @@ impl v1alpha1::TrinoCluster {
833834
let ns = ns.clone();
834835
(0..rolegroup.replicas.unwrap_or(0)).map(move |i| TrinoPodRef {
835836
namespace: ns.clone(),
836-
role_group_service_name: rolegroup_metrics_service_name(
837+
role_group_service_name: rolegroup_headless_service_name(
837838
&role_group_ref.object_name(),
838839
),
839840
pod_name: format!(
@@ -941,6 +942,11 @@ pub fn rolegroup_metrics_service_name(role_group_ref_object_name: &str) -> Strin
941942
format!("{role_group_ref_object_name}-{METRICS_SERVICE_SUFFIX}")
942943
}
943944

945+
/// Returns the headless rolegroup service name `<cluster>-<role>-<rolegroup>-<HEADLESS_SERVICE_SUFFIX>`.
946+
pub fn rolegroup_headless_service_name(role_group_ref_object_name: &str) -> String {
947+
format!("{role_group_ref_object_name}-{HEADLESS_SERVICE_SUFFIX}")
948+
}
949+
944950
fn extract_role_from_coordinator_config(
945951
fragment: Role<TrinoConfigFragment, TrinoCoordinatorRoleConfig, JavaCommonConfig>,
946952
) -> Role<TrinoConfigFragment, GenericRoleConfig, JavaCommonConfig> {

rust/operator-binary/src/listener.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ pub fn group_listener_name(trino: &v1alpha1::TrinoCluster, role: &TrinoRole) ->
8383
}
8484
}
8585

86+
/// The listener volume name depending on the role
87+
pub fn secret_volume_listener_scope(role: &TrinoRole) -> Option<String> {
88+
match role {
89+
TrinoRole::Coordinator => Some(LISTENER_VOLUME_NAME.to_string()),
90+
TrinoRole::Worker => None,
91+
}
92+
}
93+
8694
/// We only use the http/https port here and intentionally omit the metrics one.
8795
fn listener_ports(trino: &v1alpha1::TrinoCluster) -> Vec<ListenerPort> {
8896
let name = trino.exposed_protocol().to_string();

rust/operator-binary/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod crd;
88
mod listener;
99
mod operations;
1010
mod product_logging;
11+
mod service;
1112

1213
use std::sync::Arc;
1314

0 commit comments

Comments
 (0)