Skip to content

Commit 5c9d391

Browse files
committed
refactor: use ConfigMapName, SecretName, ListenerName in CRD
1 parent 31a4dbc commit 5c9d391

13 files changed

Lines changed: 138 additions & 78 deletions

File tree

extra/crds.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,17 @@ spec:
7979
type: object
8080
bootstrapListenerClass:
8181
description: The ListenerClass used for bootstrapping new clients. Should use a stable ListenerClass to avoid unnecessary client restarts (such as `cluster-internal` or `external-stable`).
82+
maxLength: 253
83+
minLength: 1
8284
nullable: true
85+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
8386
type: string
8487
brokerListenerClass:
8588
description: The ListenerClass used for connecting to brokers. Should use a direct connection ListenerClass to minimize cost and minimize performance overhead (such as `cluster-internal` or `external-unstable`).
89+
maxLength: 253
90+
minLength: 1
8691
nullable: true
92+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
8793
type: string
8894
gracefulShutdownTimeout:
8995
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
@@ -608,11 +614,17 @@ spec:
608614
type: object
609615
bootstrapListenerClass:
610616
description: The ListenerClass used for bootstrapping new clients. Should use a stable ListenerClass to avoid unnecessary client restarts (such as `cluster-internal` or `external-stable`).
617+
maxLength: 253
618+
minLength: 1
611619
nullable: true
620+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
612621
type: string
613622
brokerListenerClass:
614623
description: The ListenerClass used for connecting to brokers. Should use a direct connection ListenerClass to minimize cost and minimize performance overhead (such as `cluster-internal` or `external-unstable`).
624+
maxLength: 253
625+
minLength: 1
615626
nullable: true
627+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
616628
type: string
617629
gracefulShutdownTimeout:
618630
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
@@ -1153,7 +1165,10 @@ spec:
11531165
```
11541166
This is necessary when migrating from ZooKeeper to Kraft mode to retain existing broker IDs
11551167
because previously broker ids were generated by Kafka and not the operator.
1168+
maxLength: 253
1169+
minLength: 1
11561170
nullable: true
1171+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
11571172
type: string
11581173
metadataManager:
11591174
description: |-
@@ -1204,6 +1219,11 @@ spec:
12041219
- Which ca.crt to use when validating the other brokers
12051220
12061221
Defaults to `tls`
1222+
Set to `null` to disable internal TLS (resulting in a plaintext cluster).
1223+
maxLength: 253
1224+
minLength: 1
1225+
nullable: true
1226+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
12071227
type: string
12081228
serverSecretClass:
12091229
default: tls
@@ -1214,7 +1234,10 @@ spec:
12141234
- Which cert the servers should use to authenticate themselves against the client
12151235
12161236
Defaults to `tls`.
1237+
maxLength: 253
1238+
minLength: 1
12171239
nullable: true
1240+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
12181241
type: string
12191242
type: object
12201243
vectorAggregatorConfigMapName:
@@ -1223,7 +1246,10 @@ spec:
12231246
It must contain the key `ADDRESS` with the address of the Vector aggregator.
12241247
Follow the [logging tutorial](https://docs.stackable.tech/home/nightly/tutorials/logging-vector-aggregator)
12251248
to learn how to configure log aggregation with Vector.
1249+
maxLength: 253
1250+
minLength: 1
12261251
nullable: true
1252+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
12271253
type: string
12281254
zookeeperConfigMapName:
12291255
description: |-
@@ -1232,7 +1258,10 @@ spec:
12321258
to deploy a ZooKeeper cluster, this will simply be the name of your ZookeeperCluster resource.
12331259
This can only be used up to Kafka version 3.9.x. Since Kafka 4.0.0, ZooKeeper support was dropped.
12341260
Please use the 'controller' role instead.
1261+
maxLength: 253
1262+
minLength: 1
12351263
nullable: true
1264+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
12361265
type: string
12371266
type: object
12381267
clusterOperation:

rust/operator-binary/src/controller.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use stackable_operator::{
4242
kvp::label::{recommended_labels, role_group_selector},
4343
role_group_utils::ResourceNames,
4444
types::{
45-
kubernetes::{NamespaceName, Uid},
45+
kubernetes::{ConfigMapName, NamespaceName, Uid},
4646
operator::{ClusterName, ControllerName, OperatorName, ProductName, ProductVersion},
4747
},
4848
},
@@ -342,11 +342,11 @@ pub struct ValidatedClusterConfig {
342342
/// The discovery `ConfigMap` providing the ZooKeeper connection string, if the cluster
343343
/// is connected to a ZooKeeper ensemble. Resolved from the raw spec during validation so
344344
/// the build steps never have to read it.
345-
pub zookeeper_config_map_name: Option<String>,
345+
pub zookeeper_config_map_name: Option<ConfigMapName>,
346346

347347
/// The `ConfigMap` mapping pods to broker ids, if the user supplied one. Resolved from the
348348
/// raw spec during validation so the build steps never have to read it.
349-
pub broker_id_pod_config_map_name: Option<String>,
349+
pub broker_id_pod_config_map_name: Option<ConfigMapName>,
350350
}
351351

352352
impl ValidatedClusterConfig {

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

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@ mod tests {
231231
),
232232
},
233233
}]),
234-
"internalTls".to_string(),
235-
Some("tls".to_string()),
234+
Some("internal-tls".parse().unwrap()),
235+
Some("tls".parse().unwrap()),
236236
None,
237237
);
238238
let cluster_info = default_cluster_info();
@@ -296,8 +296,8 @@ mod tests {
296296

297297
let kafka_security = KafkaTlsSecurity::new(
298298
ResolvedAuthenticationClasses::new(vec![]),
299-
"tls".to_string(),
300-
Some("tls".to_string()),
299+
Some("tls".parse().unwrap()),
300+
Some("tls".parse().unwrap()),
301301
None,
302302
);
303303
let config = get_kafka_listener_config(
@@ -357,12 +357,8 @@ mod tests {
357357
)
358358
);
359359

360-
let kafka_security = KafkaTlsSecurity::new(
361-
ResolvedAuthenticationClasses::new(vec![]),
362-
"".to_string(),
363-
None,
364-
None,
365-
);
360+
let kafka_security =
361+
KafkaTlsSecurity::new(ResolvedAuthenticationClasses::new(vec![]), None, None, None);
366362

367363
let config = get_kafka_listener_config(
368364
&validated,
@@ -456,8 +452,8 @@ mod tests {
456452
),
457453
},
458454
}]),
459-
"tls".to_string(),
460-
Some("tls".to_string()),
455+
Some("tls".parse().unwrap()),
456+
Some("tls".parse().unwrap()),
461457
None,
462458
);
463459
let cluster_info = default_cluster_info();

rust/operator-binary/src/controller/build/resource/listener.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn build_broker_rolegroup_bootstrap_listener(
3434
.with_labels(validated_cluster.recommended_labels(role, role_group_name))
3535
.build(),
3636
spec: listener::v1alpha1::ListenerSpec {
37-
class_name: Some(merged_config.bootstrap_listener_class.clone()),
37+
class_name: Some(merged_config.bootstrap_listener_class.to_string()),
3838
ports: Some(bootstrap_listener_ports(kafka_security)),
3939
..listener::v1alpha1::ListenerSpec::default()
4040
},

rust/operator-binary/src/controller/build/resource/statefulset.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ pub fn build_broker_rolegroup_statefulset(
335335
pod_builder
336336
.add_listener_volume_by_listener_class(
337337
LISTENER_BROKER_VOLUME_NAME,
338-
listener_class,
338+
listener_class.as_ref(),
339339
&recommended_labels,
340340
)
341341
.context(AddListenerVolumeSnafu)?;

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

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,6 @@ pub enum Error {
105105
"the Vector aggregator discovery ConfigMap name is required when the Vector agent is enabled"
106106
))]
107107
MissingVectorAggregatorConfigMapName,
108-
109-
#[snafu(display("the Vector aggregator discovery ConfigMap name is invalid"))]
110-
ParseVectorAggregatorConfigMapName {
111-
source: stackable_operator::v2::macros::attributed_string_type::Error,
112-
},
113108
}
114109

115110
/// Validated logging configuration for a Kafka role group's Kafka and (optional) Vector
@@ -224,17 +219,14 @@ pub fn validate(
224219

225220
let cluster_id = kafka.cluster_id();
226221

227-
// The Vector aggregator discovery ConfigMap name, validated up-front so an invalid name
228-
// fails reconciliation here rather than at resource-build time. It is only required (per
229-
// role group) when the Vector agent is enabled; see [`validate_logging`].
222+
// The Vector aggregator discovery ConfigMap name. Validity is enforced by the `ConfigMapName`
223+
// type on the CRD field. It is only required (per role group) when the Vector agent is
224+
// enabled; see [`validate_logging`].
230225
let vector_aggregator_config_map_name = kafka
231226
.spec
232227
.cluster_config
233228
.vector_aggregator_config_map_name
234-
.as_deref()
235-
.map(ConfigMapName::from_str)
236-
.transpose()
237-
.context(ParseVectorAggregatorConfigMapNameSnafu)?;
229+
.clone();
238230

239231
let mut role_group_configs: BTreeMap<
240232
KafkaRole,

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
use std::str::FromStr;
2+
13
use serde::{Deserialize, Serialize};
24
use snafu::{OptionExt, ResultExt, Snafu};
35
use stackable_operator::{
46
client::Client,
57
commons::opa::{OpaApiVersion, OpaConfig},
68
k8s_openapi::api::core::v1::ConfigMap,
79
schemars::{self, JsonSchema},
10+
v2::types::kubernetes::SecretClassName,
811
};
912

1013
use crate::crd::v1alpha1;
@@ -23,6 +26,11 @@ pub enum Error {
2326
source: stackable_operator::commons::opa::Error,
2427
},
2528

29+
#[snafu(display("the OPA TLS secret class name (key `OPA_SECRET_CLASS`) is invalid"))]
30+
ParseOpaSecretClass {
31+
source: stackable_operator::v2::macros::attributed_string_type::Error,
32+
},
33+
2634
#[snafu(display("object defines no namespace"))]
2735
ObjectHasNoNamespace,
2836
}
@@ -36,7 +44,7 @@ pub struct KafkaAuthorization {
3644

3745
pub struct KafkaAuthorizationConfig {
3846
pub opa_connect: String,
39-
pub secret_class: Option<String>,
47+
pub secret_class: Option<SecretClassName>,
4048
}
4149

4250
impl KafkaAuthorization {
@@ -60,7 +68,10 @@ impl KafkaAuthorization {
6068
namespace,
6169
})?
6270
.data
63-
.and_then(|mut data| data.remove("OPA_SECRET_CLASS"));
71+
.and_then(|mut data| data.remove("OPA_SECRET_CLASS"))
72+
.map(|secret_class| SecretClassName::from_str(&secret_class))
73+
.transpose()
74+
.context(ParseOpaSecretClassSnafu)?;
6475
let opa_connect = opa
6576
.full_document_url_from_config_map(client, kafka, Some("allow"), &OpaApiVersion::V1)
6677
.await

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

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ use stackable_operator::{
2020
role_utils::{GenericRoleConfig, Role, RoleGroupRef},
2121
schemars::{self, JsonSchema},
2222
status::condition::{ClusterCondition, HasStatusCondition},
23-
v2::{config_overrides::KeyValueConfigOverrides, role_utils::JavaCommonConfig},
23+
v2::{
24+
config_overrides::KeyValueConfigOverrides, role_utils::JavaCommonConfig,
25+
types::kubernetes::ConfigMapName,
26+
},
2427
versioned::versioned,
2528
};
2629
use strum::{Display, EnumIter, EnumString};
@@ -163,14 +166,14 @@ pub mod versioned {
163166
/// Follow the [logging tutorial](DOCS_BASE_URL_PLACEHOLDER/tutorials/logging-vector-aggregator)
164167
/// to learn how to configure log aggregation with Vector.
165168
#[serde(skip_serializing_if = "Option::is_none")]
166-
pub vector_aggregator_config_map_name: Option<String>,
169+
pub vector_aggregator_config_map_name: Option<ConfigMapName>,
167170

168171
/// Provide the name of the ZooKeeper [discovery ConfigMap](DOCS_BASE_URL_PLACEHOLDER/concepts/service_discovery)
169172
/// here. When using the [Stackable operator for Apache ZooKeeper](DOCS_BASE_URL_PLACEHOLDER/zookeeper/)
170173
/// to deploy a ZooKeeper cluster, this will simply be the name of your ZookeeperCluster resource.
171174
/// This can only be used up to Kafka version 3.9.x. Since Kafka 4.0.0, ZooKeeper support was dropped.
172175
/// Please use the 'controller' role instead.
173-
pub zookeeper_config_map_name: Option<String>,
176+
pub zookeeper_config_map_name: Option<ConfigMapName>,
174177

175178
/// Metadata manager to use for the Kafka cluster.
176179
///
@@ -221,7 +224,7 @@ pub mod versioned {
221224
/// because previously broker ids were generated by Kafka and not the operator.
222225
///
223226
#[serde(skip_serializing_if = "Option::is_none")]
224-
pub broker_id_pod_config_map_name: Option<String>,
227+
pub broker_id_pod_config_map_name: Option<ConfigMapName>,
225228
}
226229

227230
#[derive(Clone, Debug, Default, Deserialize, JsonSchema, Merge, PartialEq, Serialize)]
@@ -424,11 +427,13 @@ pub enum MetadataManager {
424427
#[cfg(test)]
425428
mod tests {
426429
use rstest::rstest;
427-
use stackable_operator::versioned::test_utils::RoundtripTestData;
430+
use stackable_operator::{
431+
v2::types::kubernetes::SecretClassName, versioned::test_utils::RoundtripTestData,
432+
};
428433

429434
use super::*;
430435

431-
fn get_server_secret_class(kafka: &v1alpha1::KafkaCluster) -> Option<String> {
436+
fn get_server_secret_class(kafka: &v1alpha1::KafkaCluster) -> Option<SecretClassName> {
432437
kafka
433438
.spec
434439
.cluster_config
@@ -437,7 +442,7 @@ mod tests {
437442
.and_then(|tls| tls.server_secret_class.clone())
438443
}
439444

440-
fn get_internal_secret_class(kafka: &v1alpha1::KafkaCluster) -> String {
445+
fn get_internal_secret_class(kafka: &v1alpha1::KafkaCluster) -> Option<SecretClassName> {
441446
kafka
442447
.spec
443448
.cluster_config
@@ -486,8 +491,8 @@ mod tests {
486491
let kafka: v1alpha1::KafkaCluster =
487492
serde_yaml::from_str(input).expect("illegal test input");
488493
assert_eq!(
489-
get_server_secret_class(&kafka).unwrap(),
490-
"simple-kafka-server-tls".to_string()
494+
get_server_secret_class(&kafka).unwrap().to_string(),
495+
"simple-kafka-server-tls"
491496
);
492497
assert_eq!(
493498
get_internal_secret_class(&kafka),
@@ -533,8 +538,8 @@ mod tests {
533538
serde_yaml::from_str(input).expect("illegal test input");
534539
assert_eq!(get_server_secret_class(&kafka), tls::server_tls_default());
535540
assert_eq!(
536-
get_internal_secret_class(&kafka),
537-
"simple-kafka-internal-tls".to_string()
541+
get_internal_secret_class(&kafka).map(|s| s.to_string()),
542+
Some("simple-kafka-internal-tls".to_string())
538543
);
539544
}
540545

@@ -576,8 +581,8 @@ mod tests {
576581
serde_yaml::from_str(input).expect("illegal test input");
577582
assert_eq!(get_server_secret_class(&kafka), tls::server_tls_default());
578583
assert_eq!(
579-
get_internal_secret_class(&kafka),
580-
"simple-kafka-internal-tls".to_string()
584+
get_internal_secret_class(&kafka).map(|s| s.to_string()),
585+
Some("simple-kafka-internal-tls".to_string())
581586
);
582587

583588
let input = r#"
@@ -596,7 +601,7 @@ mod tests {
596601
let kafka: v1alpha1::KafkaCluster =
597602
serde_yaml::from_str(input).expect("illegal test input");
598603
assert_eq!(
599-
get_server_secret_class(&kafka),
604+
get_server_secret_class(&kafka).map(|s| s.to_string()),
600605
Some("simple-kafka-server-tls".to_string())
601606
);
602607
assert_eq!(

0 commit comments

Comments
 (0)