Skip to content
Draft
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
377 changes: 183 additions & 194 deletions Cargo.lock

Large diffs are not rendered by default.

1,237 changes: 600 additions & 637 deletions Cargo.nix

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ tracing = "0.1"
yaml_serde = "0.10"

[patch."https://github.com/stackabletech/operator-rs.git"]
# stackable-operator = { git = "https://github.com/stackabletech//operator-rs.git", branch = "main"}
stackable-operator = { git = "https://github.com/stackabletech//operator-rs.git", branch = "spike/containerdebug-switch" }
# stackable-operator = { path = "../operator-rs/crates/stackable-operator" }
18 changes: 9 additions & 9 deletions crate-hashes.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 80 additions & 0 deletions extra/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,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 @@ -1621,6 +1641,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 @@ -2329,6 +2369,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 @@ -2930,6 +2990,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,
) -> Vec<String> {
let mut args = vec![
// copy config files to a writable empty folder
Expand Down Expand Up @@ -140,13 +141,17 @@ pub fn container_trino_args(
{COMMON_BASH_TRAP_FUNCTIONS}
{remove_vector_shutdown_file_command}
prepare_signal_handlers
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),
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 @@ -376,7 +376,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 @@ -792,8 +793,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 @@ -888,6 +892,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)]
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 @@ -134,6 +134,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 @@ -144,10 +145,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 @@ -336,8 +343,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 @@ -348,16 +355,22 @@ where
/// [`TrinoRoleGroupConfig`] consumed by the build steps.
fn into_role_group_config(
merged: RoleGroup<v1alpha1::TrinoConfig, JavaCommonConfig, v1alpha1::TrinoConfigOverrides>,
role_group_name: &RoleGroupName,
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
11 changes: 9 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,10 @@ use stackable_operator::{
},
config::{fragment::Fragment, merge::Merge},
constant,
crd::authentication::core,
crd::{
authentication::core,
containerdebug::{default_containerdebug_config, v1alpha1::ContainerdebugConfig},
},
deep_merger::ObjectOverrides,
k8s_openapi::apimachinery::pkg::{api::resource::Quantity, apis::meta::v1::LabelSelector},
kube::{CustomResource, ResourceExt},
Expand Down Expand Up @@ -207,7 +210,7 @@ pub mod versioned {
pub spooling_manager_properties: KeyValueConfigOverrides,
}

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

#[fragment_attrs(serde(default))]
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 @@ -498,6 +504,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