Skip to content

Commit ccc69be

Browse files
committed
use metrics_service_name() and v2::product_logging::framework::VectorContainerLogConfig
1 parent 60e6633 commit ccc69be

4 files changed

Lines changed: 174 additions & 86 deletions

File tree

rust/operator-binary/src/airflow_controller.rs

Lines changed: 62 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Ensures that `Pod`s are configured and running for each [`v1alpha2::AirflowCluster`]
22
use std::{
33
collections::{BTreeMap, BTreeSet, HashMap},
4+
str::FromStr,
45
sync::Arc,
56
};
67

@@ -37,12 +38,12 @@ use stackable_operator::{
3738
},
3839
},
3940
k8s_openapi::{
40-
self, DeepMerge,
41+
DeepMerge,
4142
api::{
4243
apps::v1::{StatefulSet, StatefulSetSpec},
4344
core::v1::{
44-
ConfigMap, EnvVar, PersistentVolumeClaim, PodTemplateSpec, Probe, ServiceAccount,
45-
TCPSocketAction,
45+
ConfigMap, Container as K8sContainer, EnvVar, PersistentVolumeClaim,
46+
PodTemplateSpec, Probe, ServiceAccount, TCPSocketAction,
4647
},
4748
},
4849
apimachinery::pkg::{apis::meta::v1::LabelSelector, util::intstr::IntOrString},
@@ -55,7 +56,6 @@ use stackable_operator::{
5556
},
5657
kvp::{Annotation, Label, LabelError},
5758
logging::controller::ReconcilerError,
58-
product_logging::{self, framework::LoggingError, spec::ContainerLogConfig},
5959
role_utils::RoleGroupRef,
6060
shared::time::Duration,
6161
status::condition::{
@@ -64,14 +64,21 @@ use stackable_operator::{
6464
},
6565
utils::COMMON_BASH_TRAP_FUNCTIONS,
6666
v2::{
67-
builder::meta::ownerreference_from_resource,
68-
types::operator::{RoleGroupName, RoleName},
67+
builder::{meta::ownerreference_from_resource, pod::container::EnvVarSet},
68+
product_logging::framework::{VectorContainerLogConfig, vector_container},
69+
role_group_utils::ResourceNames,
70+
types::{
71+
kubernetes::{ContainerName, VolumeName},
72+
operator::{RoleGroupName, RoleName},
73+
},
6974
},
7075
};
7176
use strum::{EnumDiscriminants, IntoStaticStr};
7277

7378
use crate::{
74-
controller::{AirflowRoleGroupConfig, ValidatedCluster, build::config_map},
79+
controller::{
80+
AirflowRoleGroupConfig, ValidatedCluster, ValidatedLogging, build::config_map, validate,
81+
},
7582
controller_commons::{self, CONFIG_VOLUME_NAME, LOG_CONFIG_VOLUME_NAME, LOG_VOLUME_NAME},
7683
crd::{
7784
self, APP_NAME, AirflowClusterStatus, AirflowConfigOverrides, AirflowExecutor,
@@ -199,9 +206,6 @@ pub enum Error {
199206
source: stackable_operator::cluster_resources::Error,
200207
},
201208

202-
#[snafu(display("vector agent is enabled but vector aggregator ConfigMap is missing"))]
203-
VectorAggregatorConfigMapMissing,
204-
205209
#[snafu(display("failed to update status"))]
206210
ApplyStatus {
207211
source: stackable_operator::client::Error,
@@ -253,9 +257,6 @@ pub enum Error {
253257
source: stackable_operator::builder::meta::Error,
254258
},
255259

256-
#[snafu(display("failed to configure logging"))]
257-
ConfigureLogging { source: LoggingError },
258-
259260
#[snafu(display("failed to add needed volume"))]
260261
AddVolume { source: builder::pod::Error },
261262

@@ -476,7 +477,10 @@ pub async fn reconcile_airflow(
476477
}
477478
}
478479

479-
for (rolegroup_name, validated_rg_config) in role_group_configs {
480+
for (rolegroup_name, validated_rg) in role_group_configs {
481+
let validated_rg_config = &validated_rg.config;
482+
let logging = &validated_rg.logging;
483+
480484
let rolegroup = RoleGroupRef {
481485
cluster: ObjectRef::from_obj(airflow),
482486
role: role_name.clone(),
@@ -540,6 +544,7 @@ pub async fn reconcile_airflow(
540544
airflow_role,
541545
&rolegroup,
542546
validated_rg_config,
547+
logging,
543548
&metadata_database_connection_details,
544549
&celery_database_connection_details,
545550
&rbac_sa,
@@ -707,6 +712,7 @@ fn build_server_rolegroup_statefulset(
707712
airflow_role: &AirflowRole,
708713
rolegroup_ref: &RoleGroupRef<v1alpha2::AirflowCluster>,
709714
validated_rg_config: &AirflowRoleGroupConfig,
715+
logging: &ValidatedLogging,
710716
metadata_database_connection_details: &SqlAlchemyDatabaseConnectionDetails,
711717
celery_database_connection_details: &Option<(
712718
CeleryDatabaseConnectionDetails,
@@ -936,26 +942,12 @@ fn build_server_rolegroup_statefulset(
936942
.context(AddVolumeSnafu)?;
937943
}
938944

939-
if merged_airflow_config.logging.enable_vector_agent {
940-
match &airflow
941-
.spec
942-
.cluster_config
943-
.vector_aggregator_config_map_name
944-
{
945-
Some(vector_aggregator_config_map_name) => {
946-
pb.add_container(build_logging_container(
947-
resolved_product_image,
948-
merged_airflow_config
949-
.logging
950-
.containers
951-
.get(&Container::Vector),
952-
vector_aggregator_config_map_name,
953-
)?);
954-
}
955-
None => {
956-
VectorAggregatorConfigMapMissingSnafu.fail()?;
957-
}
958-
}
945+
if let Some(vector_log_config) = &logging.vector_container {
946+
pb.add_container(build_logging_container(
947+
resolved_product_image,
948+
vector_log_config,
949+
&resource_names,
950+
));
959951
}
960952
let mut pod_template = pb.build_template();
961953
pod_template.merge_from(validated_rg_config.pod_overrides.clone());
@@ -1005,25 +997,30 @@ fn build_server_rolegroup_statefulset(
1005997
})
1006998
}
1007999

1000+
stackable_operator::constant!(VECTOR_CONTAINER_NAME: ContainerName = "vector");
1001+
// Typed volume names required by the v2 `vector_container`. Their values match the `&str`
1002+
// constants in `controller_commons` used elsewhere to build the same volumes.
1003+
stackable_operator::constant!(CONFIG_VOLUME_NAME_TYPED: VolumeName = "config");
1004+
stackable_operator::constant!(LOG_VOLUME_NAME_TYPED: VolumeName = "log");
1005+
1006+
/// Builds the Vector log-collection sidecar container from the up-front-validated logging config.
1007+
///
1008+
/// The vector container's resource limits are set inside the v2 `vector_container` helper (to the
1009+
/// same values previously hard-coded here), so this is behaviour-preserving.
10081010
fn build_logging_container(
10091011
resolved_product_image: &ResolvedProductImage,
1010-
log_config: Option<&ContainerLogConfig>,
1011-
vector_aggregator_config_map_name: &str,
1012-
) -> Result<k8s_openapi::api::core::v1::Container> {
1013-
product_logging::framework::vector_container(
1012+
vector_log_config: &VectorContainerLogConfig,
1013+
resource_names: &ResourceNames,
1014+
) -> K8sContainer {
1015+
vector_container(
1016+
&VECTOR_CONTAINER_NAME,
10141017
resolved_product_image,
1015-
CONFIG_VOLUME_NAME,
1016-
LOG_VOLUME_NAME,
1017-
log_config,
1018-
ResourceRequirementsBuilder::new()
1019-
.with_cpu_request("250m")
1020-
.with_cpu_limit("500m")
1021-
.with_memory_request("128Mi")
1022-
.with_memory_limit("128Mi")
1023-
.build(),
1024-
vector_aggregator_config_map_name,
1018+
vector_log_config,
1019+
resource_names,
1020+
&CONFIG_VOLUME_NAME_TYPED,
1021+
&LOG_VOLUME_NAME_TYPED,
1022+
EnvVarSet::new(),
10251023
)
1026-
.context(ConfigureLoggingSnafu)
10271024
}
10281025

10291026
#[allow(clippy::too_many_arguments)]
@@ -1112,26 +1109,22 @@ fn build_executor_template_config_map(
11121109
))
11131110
.context(AddVolumeSnafu)?;
11141111

1115-
if merged_executor_config.logging.enable_vector_agent {
1116-
match &airflow
1117-
.spec
1118-
.cluster_config
1119-
.vector_aggregator_config_map_name
1120-
{
1121-
Some(vector_aggregator_config_map_name) => {
1122-
pb.add_container(build_logging_container(
1123-
resolved_product_image,
1124-
merged_executor_config
1125-
.logging
1126-
.containers
1127-
.get(&Container::Vector),
1128-
vector_aggregator_config_map_name,
1129-
)?);
1130-
}
1131-
None => {
1132-
VectorAggregatorConfigMapMissingSnafu.fail()?;
1133-
}
1134-
}
1112+
// The Kubernetes executor pod template is not an `AirflowRole` with role groups, so its logging
1113+
// is validated here (at build time) via the shared `validate_logging`, mirroring the role-group
1114+
// path in `validate`.
1115+
let executor_aggregator_config_map_name =
1116+
validate::parse_vector_aggregator_config_map_name(airflow).context(ValidateSnafu)?;
1117+
let executor_logging = validate::validate_logging(
1118+
&merged_executor_config.logging,
1119+
&executor_aggregator_config_map_name,
1120+
)
1121+
.context(ValidateSnafu)?;
1122+
if let Some(vector_log_config) = &executor_logging.vector_container {
1123+
pb.add_container(build_logging_container(
1124+
resolved_product_image,
1125+
vector_log_config,
1126+
&cluster.resource_names(&executor_role_name(), &executor_template_role_group_name()),
1127+
));
11351128
}
11361129

11371130
let mut pod_template = pb.build_template();

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use stackable_operator::{
77
v2::{
88
HasName, HasUid, NameIsValidLabelValue,
99
kvp::label::{recommended_labels, role_group_selector},
10+
product_logging::framework::VectorContainerLogConfig,
1011
role_group_utils::ResourceNames,
1112
types::{
1213
kubernetes::Uid,
@@ -51,6 +52,32 @@ pub type AirflowRoleGroupConfig = stackable_operator::v2::role_utils::RoleGroupC
5152
AirflowConfigOverrides,
5253
>;
5354

55+
/// A validated role group: the merged [`AirflowRoleGroupConfig`] paired with its up-front-validated
56+
/// [`ValidatedLogging`], so the build step reads both from here rather than re-deriving from the raw
57+
/// cluster. (Superset folds logging into a single rolegroup struct; airflow keeps the generic merged
58+
/// config as-is — retaining all its fields without bespoke `#[allow(dead_code)]` — and carries
59+
/// logging alongside it.)
60+
#[derive(Clone, Debug)]
61+
pub struct AirflowRoleGroup {
62+
pub config: AirflowRoleGroupConfig,
63+
pub logging: ValidatedLogging,
64+
}
65+
66+
/// Validated logging configuration for the (optional) Vector container.
67+
///
68+
/// Produced up-front by [`validate::validate_logging`] (mirroring the superset-operator) so that an
69+
/// invalid custom log ConfigMap name or a missing Vector aggregator discovery ConfigMap name fails
70+
/// reconciliation during validation rather than at resource-build time.
71+
///
72+
/// Unlike superset's equivalent this carries no product-container field: superset's is never read,
73+
/// and airflow's `airflow` container log config is consumed leniently in the build, so validating
74+
/// it eagerly here could reject configurations the build currently tolerates.
75+
#[derive(Clone, Debug, PartialEq, Eq)]
76+
pub struct ValidatedLogging {
77+
pub vector_container: Option<VectorContainerLogConfig>,
78+
pub enable_vector_agent: bool,
79+
}
80+
5481
/// Cluster-wide configuration that applies to every role and role group.
5582
///
5683
/// Carries the dereferenced external references, so every downstream build step reads them from
@@ -76,7 +103,7 @@ pub struct ValidatedCluster {
76103
pub product_version: ProductVersion,
77104
pub image: ResolvedProductImage,
78105
pub cluster_config: ValidatedClusterConfig,
79-
pub role_groups: BTreeMap<AirflowRole, BTreeMap<RoleGroupName, AirflowRoleGroupConfig>>,
106+
pub role_groups: BTreeMap<AirflowRole, BTreeMap<RoleGroupName, AirflowRoleGroup>>,
80107
pub role_configs: BTreeMap<AirflowRole, ValidatedRoleConfig>,
81108
}
82109

@@ -86,7 +113,7 @@ impl ValidatedCluster {
86113
name: ClusterName,
87114
image: ResolvedProductImage,
88115
cluster_config: ValidatedClusterConfig,
89-
role_groups: BTreeMap<AirflowRole, BTreeMap<RoleGroupName, AirflowRoleGroupConfig>>,
116+
role_groups: BTreeMap<AirflowRole, BTreeMap<RoleGroupName, AirflowRoleGroup>>,
90117
role_configs: BTreeMap<AirflowRole, ValidatedRoleConfig>,
91118
) -> Self {
92119
// `app_version_label_value` is constructed to be a valid label value, so it is also a valid

0 commit comments

Comments
 (0)