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 @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file.
using OAuth2 client credentials or a bearer token ([#950], [#972]).
- The logs of the `containerdebug` process are now collected by the Vector agent and forwarded to
the Vector aggregator ([#970]).
- Add `containerdebug` config CRD ([#967]).

@adwk67 adwk67 Nov 13, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather refer to the addition of the config.containerdebug field on roles and role groups. Also, the default interval has (silently) changed from 1m to 30m so this should be mentioned. (ignore that bit: my op-rs branch was out of date)


### Changed

Expand Down Expand Up @@ -105,6 +106,7 @@ All notable changes to this project will be documented in this file.
[#961]: https://github.com/stackabletech/trino-operator/pull/961
[#963]: https://github.com/stackabletech/trino-operator/pull/963
[#966]: https://github.com/stackabletech/trino-operator/pull/966
[#967]: https://github.com/stackabletech/trino-operator/pull/967
[#970]: https://github.com/stackabletech/trino-operator/pull/970
[#972]: https://github.com/stackabletech/trino-operator/pull/972

Expand Down
80 changes: 80 additions & 0 deletions extra/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,26 @@ spec:
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
containerdebug:
default:
enabled: null
interval: null
description: |-
Configures the `containerdebug` tool, which periodically logs information about the container
environment (such as network interfaces, DNS lookups and disk usage) in the background of the
product container.
properties:
enabled:
description: Whether `containerdebug` runs in the background of the product container. Defaults to `true`.
nullable: true
type: boolean
interval:
description: |-
Time between two runs of `containerdebug`, e.g. `30m`, `1h` or `2d`. Must not be zero.
Defaults to `30m`.
nullable: true
type: string
type: object
gracefulShutdownTimeout:
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
nullable: true
Expand Down Expand Up @@ -1750,6 +1770,26 @@ spec:
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
containerdebug:
default:
enabled: null
interval: null
description: |-
Configures the `containerdebug` tool, which periodically logs information about the container
environment (such as network interfaces, DNS lookups and disk usage) in the background of the
product container.
properties:
enabled:
description: Whether `containerdebug` runs in the background of the product container. Defaults to `true`.
nullable: true
type: boolean
interval:
description: |-
Time between two runs of `containerdebug`, e.g. `30m`, `1h` or `2d`. Must not be zero.
Defaults to `30m`.
nullable: true
type: string
type: object
gracefulShutdownTimeout:
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
nullable: true
Expand Down Expand Up @@ -2464,6 +2504,26 @@ spec:
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
containerdebug:
default:
enabled: null
interval: null
description: |-
Configures the `containerdebug` tool, which periodically logs information about the container
environment (such as network interfaces, DNS lookups and disk usage) in the background of the
product container.
properties:
enabled:
description: Whether `containerdebug` runs in the background of the product container. Defaults to `true`.
nullable: true
type: boolean
interval:
description: |-
Time between two runs of `containerdebug`, e.g. `30m`, `1h` or `2d`. Must not be zero.
Defaults to `30m`.
nullable: true
type: string
type: object
gracefulShutdownTimeout:
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
nullable: true
Expand Down Expand Up @@ -3071,6 +3131,26 @@ spec:
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
containerdebug:
default:
enabled: null
interval: null
description: |-
Configures the `containerdebug` tool, which periodically logs information about the container
environment (such as network interfaces, DNS lookups and disk usage) in the background of the
product container.
properties:
enabled:
description: Whether `containerdebug` runs in the background of the product container. Defaults to `true`.
nullable: true
type: boolean
interval:
description: |-
Time between two runs of `containerdebug`, e.g. `30m`, `1h` or `2d`. Must not be zero.
Defaults to `30m`.
nullable: true
type: string
type: object
gracefulShutdownTimeout:
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
nullable: true
Expand Down
7 changes: 6 additions & 1 deletion rust/operator-binary/src/controller/build/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ pub fn container_prepare_args(
pub fn container_trino_args(
authentication_config: &TrinoAuthenticationConfig,
catalogs: &BTreeMap<TrinoCatalogName, CatalogConfig>,
merged_config: &ValidatedTrinoConfig,

@adwk67 adwk67 Nov 13, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We pass this only to use containerdebug. Passing just that field makes the dependency explicit and probably simplifies the tests.

) -> Vec<String> {
let mut args = vec![
// copy config files to a writable empty folder
Expand Down Expand Up @@ -152,14 +153,18 @@ pub fn container_trino_args(
{remove_vector_shutdown_file_command}
prepare_signal_handlers
mkdir --parents \"${file_log_directory}\" || true
containerdebug --output={STACKABLE_LOG_DIR}/containerdebug-state.json --loop &
{containerdebug_command}
bin/launcher run --etc-dir={RW_CONFIG_DIR_NAME} &
wait_for_termination $!
{create_vector_shutdown_file_command}
",
remove_vector_shutdown_file_command =
remove_vector_shutdown_file_command(STACKABLE_LOG_DIR),
file_log_directory = FILE_LOG_DIRECTORY.as_ref(),
containerdebug_command = merged_config
.containerdebug
.background_command(STACKABLE_LOG_DIR)
.unwrap_or_default(),
create_vector_shutdown_file_command =
create_vector_shutdown_file_command(STACKABLE_LOG_DIR),
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,8 @@ pub fn build_rolegroup_statefulset(
"-c".to_string(),
])
.args(vec![
command::container_trino_args(trino_authentication_config, catalogs).join("\n"),
command::container_trino_args(trino_authentication_config, catalogs, merged_config)
.join("\n"),
])
.add_env_vars(env.merge(env_overrides.clone()))
.add_container_ports(container_ports(cluster))
Expand Down Expand Up @@ -835,8 +836,11 @@ fn add_derived_volumes_and_mounts(

#[cfg(test)]
mod tests {
use rstest::rstest;
use stackable_operator::{
crd::containerdebug::ValidatedContainerdebugConfig,
k8s_openapi::api::core::v1::{Container as K8sContainer, PodSpec, VolumeMount},
shared::time::Duration,
v2::builder::pod::container::EnvVarName,
};

Expand Down Expand Up @@ -933,6 +937,47 @@ mod tests {
assert_eq!(containerdebug[0].value.as_deref(), Some("/custom/log/dir"));
}

/// The trino container starts `containerdebug` from the role group's validated config. The
/// command itself is owned (and tested) by operator-rs, so only the wiring is checked here.
#[rstest]
#[case::enabled(ValidatedContainerdebugConfig::Enabled {
interval: Duration::from_minutes_unchecked(10)
})]
#[case::disabled(ValidatedContainerdebugConfig::Disabled)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should mention in the docs that containerdebug can be turned off.

fn trino_container_starts_containerdebug_from_config(
#[case] containerdebug: ValidatedContainerdebugConfig,
) {
let expected = containerdebug.background_command(STACKABLE_LOG_DIR);
let cluster = validated_cluster();
let role_group_name = RoleGroupName::from_str("default").expect("valid role group name");
let mut role_group_config =
cluster.coordinator_role_group_configs[&role_group_name].clone();
role_group_config.config.containerdebug = containerdebug;

let stateful_set = build_rolegroup_statefulset(
&cluster,
&TrinoRole::Coordinator,
&role_group_name,
&role_group_config,
)
.expect("the StatefulSet builds");

let args = pod_spec(stateful_set)
.containers
.into_iter()
.find(|container| container.name == "trino")
.expect("the trino container exists")
.args
.expect("the trino container has args")
.join("\n");
assert_eq!(
args.lines()
.find(|line| line.starts_with("containerdebug ")),
expected.as_deref(),
"args: {args}"
);
}

/// The operator's own volume mounts are added with `expect`, which relies on every add whose
/// name derives from user input coming afterwards. A catalog volume that reuses an operator
/// volume name must therefore surface as an error, never as a panic.
Expand Down
12 changes: 9 additions & 3 deletions rust/operator-binary/src/controller/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use stackable_operator::{
product_image_selection::ResolvedProductImage,
resources::{NoRuntimeLimits, Resources},
},
crd::listener::v1alpha1::Listener,
crd::{containerdebug::ValidatedContainerdebugConfig, listener::v1alpha1::Listener},
k8s_openapi::api::{
apps::v1::StatefulSet,
core::v1::{ConfigMap, Service, ServiceAccount},
Expand Down Expand Up @@ -136,6 +136,7 @@ impl ValidatedClusterConfig {
#[derive(Clone, Debug)]
pub struct ValidatedTrinoConfig {
pub affinity: StackableAffinity,
pub containerdebug: ValidatedContainerdebugConfig,
pub graceful_shutdown_timeout: Option<Duration>,
pub logging: validate::ValidatedLogging,
pub query_max_memory: Option<String>,
Expand All @@ -146,10 +147,15 @@ pub struct ValidatedTrinoConfig {

impl ValidatedTrinoConfig {
/// Builds the validated config from the merged [`v1alpha1::TrinoConfig`], swapping in the
/// already-validated logging.
fn from_merged(merged: v1alpha1::TrinoConfig, logging: validate::ValidatedLogging) -> Self {
/// already-validated `containerdebug` and logging configuration.
fn from_merged(
merged: v1alpha1::TrinoConfig,
containerdebug: ValidatedContainerdebugConfig,
logging: validate::ValidatedLogging,
) -> Self {
Self {
affinity: merged.affinity,
containerdebug,
graceful_shutdown_timeout: merged.graceful_shutdown_timeout,
logging,
query_max_memory: merged.query_max_memory,
Expand Down
19 changes: 16 additions & 3 deletions rust/operator-binary/src/controller/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use stackable_operator::{
cli::OperatorEnvironmentOptions,
commons::product_image_selection,
config::fragment,
crd::containerdebug,
kube::ResourceExt as _,
product_logging::spec::Logging,
v2::{
Expand Down Expand Up @@ -87,6 +88,12 @@ pub enum Error {
role_group: RoleGroupName,
},

#[snafu(display("invalid containerdebug configuration for role group {role_group}"))]
InvalidContainerdebugConfig {
source: containerdebug::Error,
role_group: RoleGroupName,
},

#[snafu(display("failed to validate logging configuration"))]
ValidateLoggingConfig {
source: stackable_operator::v2::product_logging::framework::Error,
Expand Down Expand Up @@ -375,8 +382,8 @@ where
role_group: role_group_name.clone(),
})?;
role_groups.insert(
role_group_name,
into_role_group_config(merged, vector_aggregator_config_map_name)?,
role_group_name.clone(),
into_role_group_config(merged, &role_group_name, vector_aggregator_config_map_name)?,
);
}

Expand All @@ -387,16 +394,22 @@ where
/// [`TrinoRoleGroupConfig`] consumed by the build steps.
fn into_role_group_config(
merged: RoleGroup<v1alpha1::TrinoConfig, JavaCommonConfig, v1alpha1::TrinoConfigOverrides>,
role_group_name: &RoleGroupName,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are passing the role_group_name just for the error, which does not indicate the role. It would be better to catch the error at the call site in validate_role_groups so that both role and role_group can be reported with the error.

vector_aggregator_config_map_name: &Option<ConfigMapName>,
) -> Result<TrinoRoleGroupConfig> {
let replicas = merged.replicas;
let common = merged.config;

let containerdebug = common.config.containerdebug.validate().with_context(|_| {
InvalidContainerdebugConfigSnafu {
role_group: role_group_name.clone(),
}
})?;
let logging = validate_logging(&common.config.logging, vector_aggregator_config_map_name)?;

Ok(RoleGroupConfig {
replicas,
config: ValidatedTrinoConfig::from_merged(common.config, logging),
config: ValidatedTrinoConfig::from_merged(common.config, containerdebug, logging),
config_overrides: common.config_overrides,
env_overrides: common.env_overrides.into(),
cli_overrides: common.cli_overrides,
Expand Down
12 changes: 10 additions & 2 deletions rust/operator-binary/src/crd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ use stackable_operator::{
},
config::{fragment::Fragment, merge::Merge},
constant,
crd::{authentication::core, openlineage},
crd::{
authentication::core,
containerdebug::{default_containerdebug_config, v1alpha1::ContainerdebugConfig},
openlineage,
},
deep_merger::ObjectOverrides,
k8s_openapi::apimachinery::pkg::{api::resource::Quantity, apis::meta::v1::LabelSelector},
kube::{CustomResource, ResourceExt},
Expand Down Expand Up @@ -215,7 +219,7 @@ pub mod versioned {
pub event_listener_properties: KeyValueConfigOverrides,
}

#[derive(Clone, Debug, Default, Fragment, JsonSchema, PartialEq)]
#[derive(Clone, Debug, Fragment, JsonSchema, PartialEq)]
#[fragment_attrs(
derive(
Clone,
Expand All @@ -233,6 +237,9 @@ pub mod versioned {
#[fragment_attrs(serde(default))]
pub affinity: StackableAffinity,

#[fragment_attrs(serde(default))]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this attribute was dropped for some reason, no test would catch it. We also don't test that e.g. interval: 0s produces an error.

pub containerdebug: ContainerdebugConfig,

/// 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>,
Expand Down Expand Up @@ -542,6 +549,7 @@ impl v1alpha1::TrinoConfig {
v1alpha1::TrinoConfigFragment {
logging: product_logging::spec::default_logging(),
affinity: get_affinity(cluster_name, role, trino_catalogs, opa_config),
containerdebug: default_containerdebug_config(),
resources: ResourcesFragment {
cpu: CpuLimitsFragment {
min: Some(Quantity(cpu_min.to_string())),
Expand Down
Loading