Skip to content

Commit 2627692

Browse files
committed
chore: move server properties from the command line to the configuration file
1 parent 1f8fe96 commit 2627692

9 files changed

Lines changed: 250 additions & 142 deletions

File tree

rust/operator-binary/src/config/command.rs

Lines changed: 17 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,8 @@ use crate::{
1010
crd::{
1111
KafkaPodDescriptor, STACKABLE_CONFIG_DIR, STACKABLE_KERBEROS_KRB5_PATH,
1212
STACKABLE_LISTENER_BOOTSTRAP_DIR, STACKABLE_LISTENER_BROKER_DIR,
13-
listener::{KafkaListenerConfig, KafkaListenerName, node_address_cmd},
14-
role::{
15-
KAFKA_ADVERTISED_LISTENERS, KAFKA_CONTROLLER_QUORUM_BOOTSTRAP_SERVERS,
16-
KAFKA_CONTROLLER_QUORUM_VOTERS, KAFKA_LISTENER_SECURITY_PROTOCOL_MAP, KAFKA_LISTENERS,
17-
KAFKA_NODE_ID, KAFKA_NODE_ID_OFFSET, KafkaRole, broker::BROKER_PROPERTIES_FILE,
18-
controller::CONTROLLER_PROPERTIES_FILE,
19-
},
13+
listener::{KafkaListenerName, node_address_cmd},
14+
role::{KafkaRole, broker::BROKER_PROPERTIES_FILE, controller::CONTROLLER_PROPERTIES_FILE},
2015
security::KafkaTlsSecurity,
2116
v1alpha1,
2217
},
@@ -28,8 +23,6 @@ pub fn broker_kafka_container_commands(
2823
kafka: &v1alpha1::KafkaCluster,
2924
cluster_id: &str,
3025
controller_descriptors: Vec<KafkaPodDescriptor>,
31-
kafka_listeners: &KafkaListenerConfig,
32-
opa_connect_string: Option<&str>,
3326
kafka_security: &KafkaTlsSecurity,
3427
product_version: &str,
3528
) -> String {
@@ -51,26 +44,17 @@ pub fn broker_kafka_container_commands(
5144
true => format!("export KERBEROS_REALM=$(grep -oP 'default_realm = \\K.*' {STACKABLE_KERBEROS_KRB5_PATH})"),
5245
false => "".to_string(),
5346
},
54-
broker_start_command = broker_start_command(kafka, cluster_id, controller_descriptors, kafka_listeners, opa_connect_string, kafka_security, product_version),
47+
broker_start_command = broker_start_command(kafka, cluster_id, controller_descriptors, kafka_security, product_version),
5548
}
5649
}
5750

5851
fn broker_start_command(
5952
kafka: &v1alpha1::KafkaCluster,
6053
cluster_id: &str,
6154
controller_descriptors: Vec<KafkaPodDescriptor>,
62-
kafka_listeners: &KafkaListenerConfig,
63-
opa_connect_string: Option<&str>,
6455
kafka_security: &KafkaTlsSecurity,
6556
product_version: &str,
6657
) -> String {
67-
let opa_config = match opa_connect_string {
68-
None => "".to_string(),
69-
Some(opa_connect_string) => {
70-
format!(" --override \"opa.authorizer.url={opa_connect_string}\"")
71-
}
72-
};
73-
7458
let jaas_config = match kafka_security.has_kerberos_enabled() {
7559
true => {
7660
formatdoc! {"
@@ -89,50 +73,35 @@ fn broker_start_command(
8973

9074
let client_port = kafka_security.client_port();
9175

92-
// TODO: The properties file from the configmap is copied to the /tmp folder and appended with dynamic properties
9376
// This should be improved:
9477
// - mount emptyDir as readWriteConfig
95-
// - use config-utils for proper replacements?
96-
// - should we print the adapted properties file at startup?
9778
if kafka.is_controller_configured() {
9879
formatdoc! {"
99-
export REPLICA_ID=$(echo \"$POD_NAME\" | grep -oE '[0-9]+$')
80+
POD_INDEX=$(echo \"$POD_NAME\" | grep -oE '[0-9]+$')
81+
export REPLICA_ID=$((POD_INDEX+NODE_ID_OFFSET))
82+
10083
cp {config_dir}/{properties_file} /tmp/{properties_file}
10184
102-
echo \"{KAFKA_NODE_ID}=$((REPLICA_ID + ${KAFKA_NODE_ID_OFFSET}))\" >> /tmp/{properties_file}
103-
echo \"{KAFKA_CONTROLLER_QUORUM_BOOTSTRAP_SERVERS}={bootstrap_servers}\" >> /tmp/{properties_file}
104-
echo \"{KAFKA_LISTENERS}={listeners}\" >> /tmp/{properties_file}
105-
echo \"{KAFKA_ADVERTISED_LISTENERS}={advertised_listeners}\" >> /tmp/{properties_file}
106-
echo \"{KAFKA_LISTENER_SECURITY_PROTOCOL_MAP}={listener_security_protocol_map}\" >> /tmp/{properties_file}
107-
echo \"{KAFKA_CONTROLLER_QUORUM_VOTERS}={controller_quorum_voters}\" >> /tmp/{properties_file}
85+
config-utils template /tmp/{properties_file}
10886
10987
bin/kafka-storage.sh format --cluster-id {cluster_id} --config /tmp/{properties_file} --ignore-formatted {initial_controller_command}
110-
bin/kafka-server-start.sh /tmp/{properties_file} {opa_config}{jaas_config} &
88+
bin/kafka-server-start.sh /tmp/{properties_file} {jaas_config} &
11189
",
11290
config_dir = STACKABLE_CONFIG_DIR,
11391
properties_file = BROKER_PROPERTIES_FILE,
114-
bootstrap_servers = to_bootstrap_servers(&controller_descriptors, client_port),
115-
listeners = kafka_listeners.listeners(),
116-
advertised_listeners = kafka_listeners.advertised_listeners(),
117-
listener_security_protocol_map = kafka_listeners.listener_security_protocol_map(),
118-
controller_quorum_voters = to_quorum_voters(&controller_descriptors, client_port),
11992
initial_controller_command = initial_controllers_command(&controller_descriptors, product_version, client_port),
12093
}
12194
} else {
12295
formatdoc! {"
123-
bin/kafka-server-start.sh {config_dir}/{properties_file} \
124-
--override \"zookeeper.connect=$ZOOKEEPER\" \
125-
--override \"{KAFKA_LISTENERS}={listeners}\" \
126-
--override \"{KAFKA_ADVERTISED_LISTENERS}={advertised_listeners}\" \
127-
--override \"{KAFKA_LISTENER_SECURITY_PROTOCOL_MAP}={listener_security_protocol_map}\" \
128-
{opa_config} \
96+
cp {config_dir}/{properties_file} /tmp/{properties_file}
97+
98+
config-utils template /tmp/{properties_file}
99+
100+
bin/kafka-server-start.sh /tmp/{properties_file} \
129101
{jaas_config} \
130102
&",
131103
config_dir = STACKABLE_CONFIG_DIR,
132104
properties_file = BROKER_PROPERTIES_FILE,
133-
listeners = kafka_listeners.listeners(),
134-
advertised_listeners = kafka_listeners.advertised_listeners(),
135-
listener_security_protocol_map = kafka_listeners.listener_security_protocol_map(),
136105
}
137106
}
138107
}
@@ -182,7 +151,6 @@ wait_for_termination()
182151
pub fn controller_kafka_container_command(
183152
cluster_id: &str,
184153
controller_descriptors: Vec<KafkaPodDescriptor>,
185-
kafka_listeners: &KafkaListenerConfig,
186154
kafka_security: &KafkaTlsSecurity,
187155
product_version: &str,
188156
) -> String {
@@ -199,14 +167,12 @@ pub fn controller_kafka_container_command(
199167
prepare_signal_handlers
200168
containerdebug --output={STACKABLE_LOG_DIR}/containerdebug-state.json --loop &
201169
202-
export REPLICA_ID=$(echo \"$POD_NAME\" | grep -oE '[0-9]+$')
170+
POD_INDEX=$(echo \"$POD_NAME\" | grep -oE '[0-9]+$')
171+
export REPLICA_ID=$((POD_INDEX+NODE_ID_OFFSET))
172+
203173
cp {config_dir}/{properties_file} /tmp/{properties_file}
204174
205-
echo \"{KAFKA_NODE_ID}=$((REPLICA_ID + ${KAFKA_NODE_ID_OFFSET}))\" >> /tmp/{properties_file}
206-
echo \"{KAFKA_CONTROLLER_QUORUM_BOOTSTRAP_SERVERS}={bootstrap_servers}\" >> /tmp/{properties_file}
207-
echo \"{KAFKA_LISTENERS}={listeners}\" >> /tmp/{properties_file}
208-
echo \"{KAFKA_LISTENER_SECURITY_PROTOCOL_MAP}={listener_security_protocol_map}\" >> /tmp/{properties_file}
209-
echo \"{KAFKA_CONTROLLER_QUORUM_VOTERS}={controller_quorum_voters}\" >> /tmp/{properties_file}
175+
config-utils template /tmp/{properties_file}
210176
211177
bin/kafka-storage.sh format --cluster-id {cluster_id} --config /tmp/{properties_file} --ignore-formatted {initial_controller_command}
212178
bin/kafka-server-start.sh /tmp/{properties_file} &
@@ -217,29 +183,11 @@ pub fn controller_kafka_container_command(
217183
remove_vector_shutdown_file_command = remove_vector_shutdown_file_command(STACKABLE_LOG_DIR),
218184
config_dir = STACKABLE_CONFIG_DIR,
219185
properties_file = CONTROLLER_PROPERTIES_FILE,
220-
bootstrap_servers = to_bootstrap_servers(&controller_descriptors, client_port),
221-
listeners = to_listeners(client_port),
222-
listener_security_protocol_map = to_listener_security_protocol_map(kafka_listeners),
223186
initial_controller_command = initial_controllers_command(&controller_descriptors, product_version, client_port),
224-
controller_quorum_voters = to_quorum_voters(&controller_descriptors, client_port),
225187
create_vector_shutdown_file_command = create_vector_shutdown_file_command(STACKABLE_LOG_DIR)
226188
}
227189
}
228190

229-
fn to_listeners(port: u16) -> String {
230-
// The environment variables are set in the statefulset of the controller
231-
format!(
232-
"{listener_name}://$POD_NAME.$ROLEGROUP_HEADLESS_SERVICE_NAME.$NAMESPACE.svc.$CLUSTER_DOMAIN:{port}",
233-
listener_name = KafkaListenerName::Controller
234-
)
235-
}
236-
237-
fn to_listener_security_protocol_map(kafka_listeners: &KafkaListenerConfig) -> String {
238-
kafka_listeners
239-
.listener_security_protocol_map_for_listener(&KafkaListenerName::Controller)
240-
.unwrap_or("".to_string())
241-
}
242-
243191
fn to_initial_controllers(controller_descriptors: &[KafkaPodDescriptor], port: u16) -> String {
244192
controller_descriptors
245193
.iter()
@@ -248,23 +196,6 @@ fn to_initial_controllers(controller_descriptors: &[KafkaPodDescriptor], port: u
248196
.join(",")
249197
}
250198

251-
// TODO: This can be removed once 3.7.2 is removed. Used in command.rs.
252-
fn to_quorum_voters(controller_descriptors: &[KafkaPodDescriptor], port: u16) -> String {
253-
controller_descriptors
254-
.iter()
255-
.map(|desc| desc.as_quorum_voter(port))
256-
.collect::<Vec<String>>()
257-
.join(",")
258-
}
259-
260-
fn to_bootstrap_servers(controller_descriptors: &[KafkaPodDescriptor], port: u16) -> String {
261-
controller_descriptors
262-
.iter()
263-
.map(|desc| format!("{fqdn}:{port}", fqdn = desc.fqdn()))
264-
.collect::<Vec<String>>()
265-
.join(",")
266-
}
267-
268199
fn initial_controllers_command(
269200
controller_descriptors: &[KafkaPodDescriptor],
270201
product_version: &str,

rust/operator-binary/src/config/node_id_hasher.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ use stackable_operator::role_utils::RoleGroupRef;
22

33
use crate::crd::v1alpha1::KafkaCluster;
44

5+
/// The Kafka node.id needs to be unique across the Kafka cluster.
6+
/// This function generates an integer that is stable for a given role group
7+
/// regardless if broker or controllers.
8+
/// This integer is then added to the pod index to compute the final node.id
9+
/// TODO: this is dangerous. How high are the chances of these ranges overlapping?
510
pub fn node_id_hash32_offset(rolegroup_ref: &RoleGroupRef<KafkaCluster>) -> u32 {
611
let hash = fnv_hash32(&format!(
712
"{role}-{rolegroup}",

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,11 +331,11 @@ pub fn get_kafka_listener_config(
331331
}
332332

333333
pub fn node_address_cmd(directory: &str) -> String {
334-
format!("$(cat {directory}/default-address/address)")
334+
format!("${{file:UTF-8:{directory}/default-address/address}}")
335335
}
336336

337337
pub fn node_port_cmd(directory: &str, port_name: &str) -> String {
338-
format!("$(cat {directory}/default-address/ports/{port_name})")
338+
format!("${{file:UTF-8:{directory}/default-address/ports/{port_name}}}")
339339
}
340340

341341
pub fn pod_fqdn(
@@ -344,7 +344,7 @@ pub fn pod_fqdn(
344344
cluster_info: &KubernetesClusterInfo,
345345
) -> Result<String, KafkaListenerError> {
346346
Ok(format!(
347-
"$POD_NAME.{sts_service_name}.{namespace}.svc.{cluster_domain}",
347+
"${{env:POD_NAME}}.{sts_service_name}.{namespace}.svc.{cluster_domain}",
348348
namespace = kafka.namespace().context(ObjectHasNoNamespaceSnafu)?,
349349
cluster_domain = cluster_info.cluster_domain
350350
))

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,13 +254,14 @@ impl v1alpha1::KafkaCluster {
254254
})
255255
}
256256

257-
/// List all pod descriptors of a provided role expected to form the cluster.
257+
/// List pod descriptors for a given role.
258+
/// If no role is provided, pod descriptors for all roles are listed.
258259
///
259260
/// We try to predict the pods here rather than looking at the current cluster state in order to
260261
/// avoid instance churn.
261262
pub fn pod_descriptors(
262263
&self,
263-
requested_kafka_role: &KafkaRole,
264+
requested_kafka_role: Option<&KafkaRole>,
264265
cluster_info: &KubernetesClusterInfo,
265266
) -> Result<Vec<KafkaPodDescriptor>, Error> {
266267
let namespace = self.metadata.namespace.clone().context(NoNamespaceSnafu)?;
@@ -290,10 +291,12 @@ impl v1alpha1::KafkaCluster {
290291
};
291292

292293
// only return descriptors for selected role
293-
if current_role == *requested_kafka_role {
294+
if requested_kafka_role.is_none() || &current_role == requested_kafka_role.unwrap()
295+
{
294296
for replica in 0..replicas {
295297
pod_descriptors.push(KafkaPodDescriptor {
296298
namespace: namespace.clone(),
299+
role: current_role.to_string(),
297300
role_group_service_name: rolegroup_ref
298301
.rolegroup_headless_service_name(),
299302
role_group_statefulset_name: rolegroup_ref.object_name(),
@@ -348,6 +351,7 @@ pub struct KafkaPodDescriptor {
348351
replica: u16,
349352
cluster_domain: DomainName,
350353
node_id: u32,
354+
pub role: String,
351355
}
352356

353357
impl KafkaPodDescriptor {

rust/operator-binary/src/crd/role/controller.rs

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@ use stackable_operator::{
1515
use strum::{Display, EnumIter};
1616

1717
use crate::crd::{
18-
listener::KafkaListenerName,
19-
role::{
20-
KAFKA_LOG_DIRS, KAFKA_PROCESS_ROLES, KafkaRole,
21-
commons::{CommonConfig, Storage, StorageFragment},
22-
},
18+
role::commons::{CommonConfig, Storage, StorageFragment},
2319
v1alpha1,
2420
};
2521

@@ -121,29 +117,9 @@ impl Configuration for ControllerConfigFragment {
121117
&self,
122118
_resource: &Self::Configurable,
123119
_role_name: &str,
124-
file: &str,
120+
_file: &str,
125121
) -> Result<BTreeMap<String, Option<String>>, stackable_operator::product_config_utils::Error>
126122
{
127-
let mut config = BTreeMap::new();
128-
129-
if file == CONTROLLER_PROPERTIES_FILE {
130-
config.insert(
131-
KAFKA_LOG_DIRS.to_string(),
132-
Some("/stackable/data/kraft".to_string()),
133-
);
134-
135-
// KRAFT
136-
config.insert(
137-
KAFKA_PROCESS_ROLES.to_string(),
138-
Some(KafkaRole::Controller.to_string()),
139-
);
140-
141-
config.insert(
142-
"controller.listener.names".to_string(),
143-
Some(KafkaListenerName::Controller.to_string()),
144-
);
145-
}
146-
147-
Ok(config)
123+
Ok(BTreeMap::new())
148124
}
149125
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ pub const KAFKA_CONTROLLER_QUORUM_BOOTSTRAP_SERVERS: &str = "controller.quorum.b
6868

6969
/// Map of id/endpoint information for the set of voters in a comma-separated list of {id}@{host}:{port} entries.
7070
/// For example: 1@localhost:9092,2@localhost:9093,3@localhost:9094
71-
pub const KAFKA_CONTROLLER_QUORUM_VOTERS: &str = "controller.quorum.voters";
71+
/// TODO: maybe re-enable
72+
// pub const KAFKA_CONTROLLER_QUORUM_VOTERS: &str = "controller.quorum.voters";
7273

7374
#[derive(Snafu, Debug)]
7475
pub enum Error {

rust/operator-binary/src/kafka_controller.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use crate::{
3737
crd::{
3838
self, APP_NAME, DOCKER_IMAGE_BASE_NAME, JVM_SECURITY_PROPERTIES_FILE, KafkaClusterStatus,
3939
OPERATOR_NAME,
40+
listener::get_kafka_listener_config,
4041
role::{
4142
AnyConfig, KafkaRole, broker::BROKER_PROPERTIES_FILE,
4243
controller::CONTROLLER_PROPERTIES_FILE,
@@ -66,6 +67,14 @@ pub struct Ctx {
6667
#[strum_discriminants(derive(IntoStaticStr))]
6768
#[allow(clippy::enum_variant_names)]
6869
pub enum Error {
70+
#[snafu(display("failed to build pod descriptors"))]
71+
BuildPodDescriptors { source: crate::crd::Error },
72+
73+
#[snafu(display("invalid kafka listeners"))]
74+
InvalidKafkaListeners {
75+
source: crate::crd::listener::KafkaListenerError,
76+
},
77+
6978
#[snafu(display("cluster object defines no '{role}' role"))]
7079
MissingKafkaRole {
7180
source: crate::crd::Error,
@@ -242,6 +251,8 @@ impl ReconcilerError for Error {
242251
Error::BuildConfigMap { .. } => None,
243252
Error::BuildService { .. } => None,
244253
Error::BuildListener { .. } => None,
254+
Error::InvalidKafkaListeners { .. } => None,
255+
Error::BuildPodDescriptors { .. } => None,
245256
}
246257
}
247258
}
@@ -359,13 +370,28 @@ pub async fn reconcile_kafka(
359370
build_rolegroup_metrics_service(kafka, &resolved_product_image, &rolegroup_ref)
360371
.context(BuildServiceSnafu)?;
361372

373+
let kafka_listeners = get_kafka_listener_config(
374+
kafka,
375+
&kafka_security,
376+
&rolegroup_ref,
377+
&client.kubernetes_cluster_info,
378+
)
379+
.context(InvalidKafkaListenersSnafu)?;
380+
381+
let pod_descriptors = kafka
382+
.pod_descriptors(None, &client.kubernetes_cluster_info)
383+
.context(BuildPodDescriptorsSnafu)?;
384+
362385
let rg_configmap = build_rolegroup_config_map(
363386
kafka,
364387
&resolved_product_image,
365388
&kafka_security,
366389
&rolegroup_ref,
367390
rolegroup_config,
368391
&merged_config,
392+
&kafka_listeners,
393+
&pod_descriptors,
394+
opa_connect.as_deref(),
369395
)
370396
.context(BuildConfigMapSnafu)?;
371397

@@ -376,7 +402,6 @@ pub async fn reconcile_kafka(
376402
&resolved_product_image,
377403
&rolegroup_ref,
378404
rolegroup_config,
379-
opa_connect.as_deref(),
380405
&kafka_security,
381406
&merged_config,
382407
&rbac_sa,

0 commit comments

Comments
 (0)