Skip to content

Commit 383b63c

Browse files
committed
refactor: move logging & discovery
1 parent 09d457e commit 383b63c

11 files changed

Lines changed: 145 additions & 181 deletions

File tree

rust/operator-binary/src/controller.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,10 @@ use crate::{
5656
authentication::DruidAuthenticationConfig,
5757
crd::{
5858
APP_NAME, CommonRoleGroupConfig, Container, DRUID_CONFIG_DIRECTORY, DeepStorageSpec,
59-
DruidClusterStatus, DruidRole, HDFS_CONFIG_DIRECTORY, LOG_CONFIG_DIRECTORY,
60-
MAX_DRUID_LOG_FILES_SIZE, METRICS_PORT, METRICS_PORT_NAME, OPERATOR_NAME,
61-
RW_CONFIG_DIRECTORY, STACKABLE_LOG_DIR, build_recommended_labels,
62-
security::DruidTlsSecurity, v1alpha1,
59+
DruidClusterStatus, DruidRole, HDFS_CONFIG_DIRECTORY, LOG_CONFIG_DIRECTORY, METRICS_PORT,
60+
METRICS_PORT_NAME, OPERATOR_NAME, RW_CONFIG_DIRECTORY, STACKABLE_LOG_DIR,
61+
build_recommended_labels, security::DruidTlsSecurity, v1alpha1,
6362
},
64-
discovery::{self, build_discovery_configmaps},
6563
internal_secret::create_shared_internal_secret,
6664
listener::{
6765
LISTENER_VOLUME_DIR, LISTENER_VOLUME_NAME, build_group_listener, build_group_listener_pvc,
@@ -75,6 +73,9 @@ mod build;
7573
mod dereference;
7674
mod validate;
7775

76+
use build::discovery::{self, build_discovery_configmaps};
77+
use build::properties::logging::MAX_DRUID_LOG_FILES_SIZE;
78+
7879
use validate::DruidRoleGroupConfig;
7980

8081
pub const DRUID_CONTROLLER_NAME: &str = "druidcluster";
@@ -442,15 +443,10 @@ pub async fn reconcile_druid(
442443

443444
if *druid_role == DruidRole::Router {
444445
// discovery
445-
for discovery_cm in build_discovery_configmaps(
446-
druid,
447-
druid,
448-
&validated_cluster.image,
449-
&validated_cluster.cluster_config.druid_tls_security,
450-
listener,
451-
)
452-
.await
453-
.context(BuildDiscoveryConfigSnafu)?
446+
for discovery_cm in
447+
build_discovery_configmaps(&validated_cluster, druid, listener)
448+
.await
449+
.context(BuildDiscoveryConfigSnafu)?
454450
{
455451
cluster_resources
456452
.add(client, discovery_cm)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Build steps that turn a `ValidatedCluster` into Kubernetes resources.
22
33
pub mod config_map;
4+
pub mod discovery;
45
pub mod properties;

rust/operator-binary/src/controller/build/config_map.rs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,39 @@ use stackable_operator::{
1818
crd::s3,
1919
database_connections::drivers::jdbc::JdbcDatabaseConnection as _,
2020
k8s_openapi::api::core::v1::{ConfigMap, EnvVar},
21+
product_logging::framework::VECTOR_CONFIG_FILE,
2122
role_utils::RoleGroupRef,
2223
};
2324

2425
use crate::{
2526
config::jvm::construct_jvm_args,
2627
controller::{
2728
DRUID_CONTROLLER_NAME,
28-
build::properties::{ConfigFileName, writer::to_java_properties_string},
29+
build::properties::{
30+
ConfigFileName,
31+
logging::{build_log4j2_config, build_vector_config},
32+
writer::to_java_properties_string,
33+
},
2934
validate::{DruidRoleGroupConfig, ValidatedCluster},
3035
},
31-
crd::{
32-
AUTH_AUTHORIZER_OPA_URI, DS_BUCKET, DruidRole, EXTENSIONS_LOADLIST, S3_ACCESS_KEY,
33-
S3_ENDPOINT_URL, S3_PATH_STYLE_ACCESS, S3_SECRET_KEY, ZOOKEEPER_CONNECTION_STRING,
34-
build_recommended_labels, build_string_list, v1alpha1,
35-
},
36+
crd::{DruidRole, build_recommended_labels, build_string_list, v1alpha1},
3637
extensions::get_extension_list,
37-
product_logging::extend_role_group_config_map,
3838
};
3939

4040
// jvm.config is built by `config::jvm`, not a properties builder, so it is not part
4141
// of `ConfigFileName`.
4242
const JVM_CONFIG: &str = "jvm.config";
4343

44+
// Druid `runtime.properties` config-property keys assembled into the rolegroup ConfigMap here.
45+
const EXTENSIONS_LOADLIST: &str = "druid.extensions.loadList";
46+
const ZOOKEEPER_CONNECTION_STRING: &str = "druid.zk.service.host";
47+
const DS_BUCKET: &str = "druid.storage.bucket";
48+
const S3_ENDPOINT_URL: &str = "druid.s3.endpoint.url";
49+
const S3_ACCESS_KEY: &str = "druid.s3.accessKey";
50+
const S3_SECRET_KEY: &str = "druid.s3.secretKey";
51+
const S3_PATH_STYLE_ACCESS: &str = "druid.s3.enablePathStyleAccess";
52+
const AUTH_AUTHORIZER_OPA_URI: &str = "druid.auth.authorizer.OpaAuthorizer.opaUri";
53+
4454
#[derive(Snafu, Debug)]
4555
#[allow(clippy::enum_variant_names)]
4656
pub enum Error {
@@ -90,12 +100,6 @@ pub enum Error {
90100
source: crate::authentication::Error,
91101
},
92102

93-
#[snafu(display("failed to add the logging configuration to the ConfigMap [{cm_name}]"))]
94-
InvalidLoggingConfig {
95-
source: crate::product_logging::Error,
96-
cm_name: String,
97-
},
98-
99103
#[snafu(display("invalid metadata database connection"))]
100104
InvalidMetadataDatabaseConnection {
101105
source: stackable_operator::database_connections::Error,
@@ -314,14 +318,13 @@ pub fn build_rolegroup_config_map(
314318
config_map_builder.add_data(filename, file_content);
315319
}
316320

317-
extend_role_group_config_map(
318-
rolegroup,
319-
&rg.merged_config.logging,
320-
&mut config_map_builder,
321-
)
322-
.context(InvalidLoggingConfigSnafu {
323-
cm_name: rolegroup.object_name(),
324-
})?;
321+
if let Some(log4j2_config) = build_log4j2_config(&rg.merged_config.logging) {
322+
config_map_builder.add_data(ConfigFileName::Log4j2Properties.to_string(), log4j2_config);
323+
}
324+
325+
if let Some(vector_config) = build_vector_config(rolegroup, &rg.merged_config.logging) {
326+
config_map_builder.add_data(VECTOR_CONFIG_FILE, vector_config);
327+
}
325328

326329
config_map_builder
327330
.build()

rust/operator-binary/src/discovery.rs renamed to rust/operator-binary/src/controller/build/discovery.rs

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,23 @@
44
use snafu::{ResultExt, Snafu};
55
use stackable_operator::{
66
builder::{configmap::ConfigMapBuilder, meta::ObjectMetaBuilder},
7-
commons::product_image_selection::ResolvedProductImage,
87
crd::listener::v1alpha1::Listener,
98
k8s_openapi::api::core::v1::ConfigMap,
10-
kube::{Resource, ResourceExt, runtime::reflector::ObjectRef},
9+
kube::{Resource, ResourceExt},
1110
};
1211

1312
use crate::{
1413
DRUID_CONTROLLER_NAME,
15-
crd::{DruidRole, build_recommended_labels, security::DruidTlsSecurity, v1alpha1},
14+
controller::validate::ValidatedCluster,
15+
crd::{DruidRole, build_recommended_labels},
1616
listener::build_listener_connection_string,
1717
};
1818

1919
#[derive(Snafu, Debug)]
2020
pub enum Error {
21-
#[snafu(display("object {} is missing metadata to build owner reference", druid))]
21+
#[snafu(display("object is missing metadata to build owner reference"))]
2222
ObjectMissingMetadataForOwnerRef {
2323
source: stackable_operator::builder::meta::Error,
24-
druid: ObjectRef<v1alpha1::DruidCluster>,
2524
},
2625

2726
#[snafu(display("failed to get service FQDN"))]
@@ -41,37 +40,28 @@ pub enum Error {
4140
ListenerConfiguration { source: crate::listener::Error },
4241
}
4342

44-
/// Builds discovery [`ConfigMap`]s for connecting to a [`v1alpha1::DruidCluster`].
43+
/// Builds discovery [`ConfigMap`]s for connecting to a Druid cluster.
4544
pub async fn build_discovery_configmaps(
46-
druid: &v1alpha1::DruidCluster,
45+
cluster: &ValidatedCluster,
4746
owner: &impl Resource<DynamicType = ()>,
48-
resolved_product_image: &ResolvedProductImage,
49-
druid_tls_security: &DruidTlsSecurity,
5047
listener: Listener,
5148
) -> Result<Vec<ConfigMap>, Error> {
5249
let name = owner.name_unchecked();
5350
Ok(vec![build_discovery_configmap(
54-
druid,
55-
owner,
56-
resolved_product_image,
57-
druid_tls_security,
58-
&name,
59-
listener,
51+
cluster, owner, &name, listener,
6052
)?])
6153
}
6254

63-
/// Build a discovery [`ConfigMap`] containing information about how to connect to a certain [`v1alpha1::DruidCluster`].
55+
/// Build a discovery [`ConfigMap`] containing information about how to connect to a certain Druid cluster.
6456
fn build_discovery_configmap(
65-
druid: &v1alpha1::DruidCluster,
57+
cluster: &ValidatedCluster,
6658
owner: &impl Resource<DynamicType = ()>,
67-
resolved_product_image: &ResolvedProductImage,
68-
druid_tls_security: &DruidTlsSecurity,
6959
name: &str,
7060
listener: Listener,
7161
) -> Result<ConfigMap, Error> {
7262
let router_host = build_listener_connection_string(
7363
listener,
74-
druid_tls_security,
64+
&cluster.cluster_config.druid_tls_security,
7565
&DruidRole::Router.to_string(),
7666
)
7767
.context(ListenerConfigurationSnafu)?;
@@ -84,16 +74,14 @@ fn build_discovery_configmap(
8474
ConfigMapBuilder::new()
8575
.metadata(
8676
ObjectMetaBuilder::new()
87-
.name_and_namespace(druid)
77+
.name_and_namespace(owner)
8878
.name(name)
8979
.ownerreference_from_resource(owner, None, Some(true))
90-
.with_context(|_| ObjectMissingMetadataForOwnerRefSnafu {
91-
druid: ObjectRef::from_obj(druid),
92-
})?
80+
.context(ObjectMissingMetadataForOwnerRefSnafu)?
9381
.with_recommended_labels(&build_recommended_labels(
94-
druid,
82+
owner,
9583
DRUID_CONTROLLER_NAME,
96-
&resolved_product_image.app_version_label_value,
84+
&cluster.image.app_version_label_value,
9785
&DruidRole::Router.to_string(),
9886
"discovery",
9987
))
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//! Builds the log4j2 and Vector logging configuration for the rolegroup `ConfigMap`.
2+
3+
use stackable_operator::{
4+
memory::{BinaryMultiple, MemoryQuantity},
5+
product_logging::{
6+
self,
7+
spec::{ContainerLogConfig, ContainerLogConfigChoice, Logging},
8+
},
9+
role_utils::RoleGroupRef,
10+
};
11+
12+
use crate::crd::{Container, STACKABLE_LOG_DIR, v1alpha1};
13+
14+
const CONSOLE_CONVERSION_PATTERN: &str = "%d{ISO8601} %p [%t] %c - %m%n";
15+
16+
/// File that the Druid log4j2 config writes its rolling log output to.
17+
const DRUID_LOG_FILE: &str = "druid.log4j2.xml";
18+
19+
/// Maximum size of all Druid log files combined, used both for the log4j2 rollover configuration
20+
/// and to size the log volume in the controller.
21+
pub const MAX_DRUID_LOG_FILES_SIZE: MemoryQuantity = MemoryQuantity {
22+
value: 10.0,
23+
unit: BinaryMultiple::Mebi,
24+
};
25+
26+
/// Renders the `log4j2.properties` content for the Druid container.
27+
///
28+
/// Returns `None` when the container uses a custom log ConfigMap rather than the operator's
29+
/// automatic logging configuration.
30+
pub fn build_log4j2_config(logging: &Logging<Container>) -> Option<String> {
31+
if let Some(ContainerLogConfig {
32+
choice: Some(ContainerLogConfigChoice::Automatic(log_config)),
33+
}) = logging.containers.get(&Container::Druid)
34+
{
35+
Some(product_logging::framework::create_log4j2_config(
36+
&format!(
37+
"{STACKABLE_LOG_DIR}/{container}",
38+
container = Container::Druid
39+
),
40+
DRUID_LOG_FILE,
41+
MAX_DRUID_LOG_FILES_SIZE
42+
.scale_to(BinaryMultiple::Mebi)
43+
.floor()
44+
.value as u32,
45+
CONSOLE_CONVERSION_PATTERN,
46+
log_config,
47+
))
48+
} else {
49+
None
50+
}
51+
}
52+
53+
/// Renders the Vector agent config (`vector.yaml`).
54+
///
55+
/// Returns `None` when the Vector agent is disabled for this role group.
56+
pub fn build_vector_config(
57+
rolegroup: &RoleGroupRef<v1alpha1::DruidCluster>,
58+
logging: &Logging<Container>,
59+
) -> Option<String> {
60+
if !logging.enable_vector_agent {
61+
return None;
62+
}
63+
64+
let vector_log_config = if let Some(ContainerLogConfig {
65+
choice: Some(ContainerLogConfigChoice::Automatic(log_config)),
66+
}) = logging.containers.get(&Container::Vector)
67+
{
68+
Some(log_config)
69+
} else {
70+
None
71+
};
72+
73+
Some(product_logging::framework::create_vector_config(
74+
rolegroup,
75+
vector_log_config,
76+
))
77+
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,21 @@
22
33
pub mod writer;
44

5+
pub mod logging;
56
pub mod runtime_properties;
67
pub mod security_properties;
78

89
/// The names of the operator-written Druid config files assembled into the rolegroup ConfigMap.
910
#[derive(Clone, Copy, Debug, strum::Display)]
11+
// The shared `Properties` suffix mirrors the actual on-disk file names; it is not redundant naming.
12+
#[allow(clippy::enum_variant_names)]
1013
pub enum ConfigFileName {
1114
#[strum(serialize = "runtime.properties")]
1215
RuntimeProperties,
1316
#[strum(serialize = "security.properties")]
1417
SecurityProperties,
18+
/// `log4j2.properties` is rendered by the logging framework rather than a properties builder,
19+
/// but it is still an operator-written file assembled into the rolegroup ConfigMap.
20+
#[strum(serialize = "log4j2.properties")]
21+
Log4j2Properties,
1522
}

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ use crate::{
2121
dereference::DereferencedObjects,
2222
},
2323
crd::{
24-
CommonRoleGroupConfig, DruidConfigOverrides, DruidRole, INDEXER_JAVA_OPTS,
25-
STACKABLE_TRUST_STORE, STACKABLE_TRUST_STORE_PASSWORD, build_string_list,
26-
security::DruidTlsSecurity, v1alpha1,
24+
CommonRoleGroupConfig, DruidConfigOverrides, DruidRole, STACKABLE_TRUST_STORE,
25+
STACKABLE_TRUST_STORE_PASSWORD, build_string_list, security::DruidTlsSecurity, v1alpha1,
2726
},
2827
};
2928

@@ -92,6 +91,8 @@ fn key_value_overrides(
9291
let kv = match file {
9392
ConfigFileName::RuntimeProperties => overrides.runtime_properties.as_ref(),
9493
ConfigFileName::SecurityProperties => overrides.security_properties.as_ref(),
94+
// log4j2.properties is rendered by the logging framework and accepts no key/value overrides.
95+
ConfigFileName::Log4j2Properties => None,
9596
};
9697
kv.map(
9798
stackable_operator::config_overrides::KeyValueConfigOverrides::as_product_config_overrides,
@@ -156,6 +157,8 @@ fn build_role_group_config(
156157
}
157158
}
158159

160+
const INDEXER_JAVA_OPTS: &str = "druid.indexer.runner.javaOptsArray";
161+
159162
/// The `druid.indexer.runner.javaOptsArray` entry that `MiddleManagerConfigFragment::compute_files`
160163
/// adds for *every* file (runtime.properties and security.properties).
161164
fn middlemanager_indexer_java_opts() -> (String, Option<String>) {

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ use stackable_operator::{
77
memory::{BinaryMultiple, MemoryQuantity},
88
};
99

10-
use crate::crd::{
11-
PROCESSING_BUFFER_SIZE_BYTES, PROCESSING_NUM_MERGE_BUFFERS, PROCESSING_NUM_THREADS,
12-
storage::HistoricalStorage,
13-
};
10+
use crate::crd::storage::HistoricalStorage;
11+
12+
// Druid historical processing config-property keys, only used for the memory calculations here.
13+
const PROCESSING_BUFFER_SIZE_BYTES: &str = "druid.processing.buffer.sizeBytes";
14+
const PROCESSING_NUM_MERGE_BUFFERS: &str = "druid.processing.numMergeBuffers";
15+
const PROCESSING_NUM_THREADS: &str = "druid.processing.numThreads";
1416

1517
static MIN_HEAP_RATIO: f32 = 0.75;
1618

0 commit comments

Comments
 (0)