Skip to content

Commit 95105f7

Browse files
committed
feat!: Implement server role listener
BREAKING: CRD changes .spec.clusterConfig.listenerClass to .spec.servers.roleConfig.listenerClass
1 parent bd1e084 commit 95105f7

8 files changed

Lines changed: 376 additions & 330 deletions

File tree

deploy/helm/zookeeper-operator/crds/crds.yaml

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ spec:
2828
clusterConfig:
2929
default:
3030
authentication: []
31-
listenerClass: cluster-internal
3231
tls:
3332
quorumSecretClass: tls
3433
serverSecretClass: tls
@@ -53,20 +52,6 @@ spec:
5352
- authenticationClass
5453
type: object
5554
type: array
56-
listenerClass:
57-
default: cluster-internal
58-
description: |-
59-
This field controls which type of Service the Operator creates for this ZookeeperCluster:
60-
61-
* cluster-internal: Use a ClusterIP service
62-
63-
* external-unstable: Use a NodePort service
64-
65-
This is a temporary solution with the goal to keep yaml manifests forward compatible. In the future, this setting will control which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change.
66-
enum:
67-
- cluster-internal
68-
- external-unstable
69-
type: string
7055
tls:
7156
default:
7257
quorumSecretClass: tls
@@ -444,11 +429,16 @@ spec:
444429
x-kubernetes-preserve-unknown-fields: true
445430
roleConfig:
446431
default:
432+
listenerClass: cluster-internal
447433
podDisruptionBudget:
448434
enabled: true
449435
maxUnavailable: null
450436
description: This is a product-agnostic RoleConfig, which is sufficient for most of the products.
451437
properties:
438+
listenerClass:
439+
default: cluster-internal
440+
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose the ZooKeeper nodes.
441+
type: string
452442
podDisruptionBudget:
453443
default:
454444
enabled: true

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use snafu::{OptionExt, ResultExt, Snafu};
22
use stackable_operator::{
33
memory::{BinaryMultiple, MemoryQuantity},
4-
role_utils::{self, GenericRoleConfig, JavaCommonConfig, JvmArgumentOverrides, Role},
4+
role_utils::{self, JavaCommonConfig, JvmArgumentOverrides, Role},
55
};
66

77
use crate::crd::{
88
JVM_SECURITY_PROPERTIES_FILE, LOG4J_CONFIG_FILE, LOGBACK_CONFIG_FILE, LoggingFramework,
99
METRICS_PORT, STACKABLE_CONFIG_DIR, STACKABLE_LOG_CONFIG_DIR,
10-
v1alpha1::{ZookeeperCluster, ZookeeperConfig, ZookeeperConfigFragment},
10+
v1alpha1::{
11+
ZookeeperCluster, ZookeeperConfig, ZookeeperConfigFragment, ZookeeperServerRoleConfig,
12+
},
1113
};
1214

1315
const JAVA_HEAP_FACTOR: f32 = 0.8;
@@ -29,7 +31,7 @@ pub enum Error {
2931
/// All JVM arguments.
3032
fn construct_jvm_args(
3133
zk: &ZookeeperCluster,
32-
role: &Role<ZookeeperConfigFragment, GenericRoleConfig, JavaCommonConfig>,
34+
role: &Role<ZookeeperConfigFragment, ZookeeperServerRoleConfig, JavaCommonConfig>,
3335
role_group: &str,
3436
) -> Result<Vec<String>, Error> {
3537
let logging_framework = zk.logging_framework();
@@ -63,7 +65,7 @@ fn construct_jvm_args(
6365
/// [`construct_zk_server_heap_env`]).
6466
pub fn construct_non_heap_jvm_args(
6567
zk: &ZookeeperCluster,
66-
role: &Role<ZookeeperConfigFragment, GenericRoleConfig, JavaCommonConfig>,
68+
role: &Role<ZookeeperConfigFragment, ZookeeperServerRoleConfig, JavaCommonConfig>,
6769
role_group: &str,
6870
) -> Result<String, Error> {
6971
let mut jvm_args = construct_jvm_args(zk, role, role_group)?;
@@ -99,7 +101,10 @@ fn is_heap_jvm_argument(jvm_argument: &str) -> bool {
99101
#[cfg(test)]
100102
mod tests {
101103
use super::*;
102-
use crate::crd::{ZookeeperRole, v1alpha1::ZookeeperConfig};
104+
use crate::crd::{
105+
ZookeeperRole,
106+
v1alpha1::{ZookeeperConfig, ZookeeperServerRoleConfig},
107+
};
103108

104109
#[test]
105110
fn test_construct_jvm_arguments_defaults() {
@@ -182,7 +187,7 @@ mod tests {
182187
) -> (
183188
ZookeeperCluster,
184189
ZookeeperConfig,
185-
Role<ZookeeperConfigFragment, GenericRoleConfig, JavaCommonConfig>,
190+
Role<ZookeeperConfigFragment, ZookeeperServerRoleConfig, JavaCommonConfig>,
186191
String,
187192
) {
188193
let zookeeper: ZookeeperCluster =

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

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use stackable_operator::{
3434
};
3535
use strum::{Display, EnumIter, EnumString, IntoEnumIterator};
3636

37-
use crate::crd::affinity::get_affinity;
37+
use crate::crd::{affinity::get_affinity, v1alpha1::ZookeeperServerRoleConfig};
3838

3939
pub mod affinity;
4040
pub mod authentication;
@@ -47,6 +47,7 @@ pub const OPERATOR_NAME: &str = "zookeeper.stackable.tech";
4747
pub const ZOOKEEPER_PROPERTIES_FILE: &str = "zoo.cfg";
4848
pub const JVM_SECURITY_PROPERTIES_FILE: &str = "security.properties";
4949

50+
pub const METRICS_PORT_NAME: &str = "metrics";
5051
pub const METRICS_PORT: u16 = 9505;
5152

5253
pub const STACKABLE_DATA_DIR: &str = "/stackable/data";
@@ -72,6 +73,7 @@ pub const MAX_PREPARE_LOG_FILE_SIZE: MemoryQuantity = MemoryQuantity {
7273
pub const DOCKER_IMAGE_BASE_NAME: &str = "zookeeper";
7374

7475
const DEFAULT_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = Duration::from_minutes_unchecked(2);
76+
pub const DEFAULT_LISTENER_CLASS: &str = "cluster-internal";
7577

7678
mod built_info {
7779
pub const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -139,7 +141,19 @@ pub mod versioned {
139141

140142
// no doc - it's in the struct.
141143
#[serde(skip_serializing_if = "Option::is_none")]
142-
pub servers: Option<Role<ZookeeperConfigFragment, GenericRoleConfig, JavaCommonConfig>>,
144+
pub servers:
145+
Option<Role<ZookeeperConfigFragment, ZookeeperServerRoleConfig, JavaCommonConfig>>,
146+
}
147+
148+
#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
149+
#[serde(rename_all = "camelCase")]
150+
pub struct ZookeeperServerRoleConfig {
151+
#[serde(flatten)]
152+
pub common: GenericRoleConfig,
153+
154+
/// This field controls which [ListenerClass](DOCS_BASE_URL_PLACEHOLDER/listener-operator/listenerclass.html) is used to expose the ZooKeeper nodes.
155+
#[serde(default = "default_listener_class")]
156+
pub listener_class: String,
143157
}
144158

145159
#[derive(Clone, Deserialize, Debug, Eq, JsonSchema, PartialEq, Serialize)]
@@ -164,29 +178,6 @@ pub mod versioned {
164178
skip_serializing_if = "Option::is_none"
165179
)]
166180
pub tls: Option<tls::v1alpha1::ZookeeperTls>,
167-
168-
/// This field controls which type of Service the Operator creates for this ZookeeperCluster:
169-
///
170-
/// * cluster-internal: Use a ClusterIP service
171-
///
172-
/// * external-unstable: Use a NodePort service
173-
///
174-
/// This is a temporary solution with the goal to keep yaml manifests forward compatible.
175-
/// In the future, this setting will control which [ListenerClass](DOCS_BASE_URL_PLACEHOLDER/listener-operator/listenerclass.html)
176-
/// will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change.
177-
#[serde(default)]
178-
pub listener_class: CurrentlySupportedListenerClasses,
179-
}
180-
181-
// TODO: Temporary solution until listener-operator is finished
182-
#[derive(Clone, Debug, Default, Display, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
183-
#[serde(rename_all = "PascalCase")]
184-
pub enum CurrentlySupportedListenerClasses {
185-
#[default]
186-
#[serde(rename = "cluster-internal")]
187-
ClusterInternal,
188-
#[serde(rename = "external-unstable")]
189-
ExternalUnstable,
190181
}
191182

192183
#[derive(Clone, Debug, Default, Fragment, JsonSchema, PartialEq)]
@@ -354,15 +345,18 @@ fn cluster_config_default() -> v1alpha1::ZookeeperClusterConfig {
354345
authentication: vec![],
355346
vector_aggregator_config_map_name: None,
356347
tls: tls::default_zookeeper_tls(),
357-
listener_class: v1alpha1::CurrentlySupportedListenerClasses::default(),
358348
}
359349
}
360350

361-
impl v1alpha1::CurrentlySupportedListenerClasses {
362-
pub fn k8s_service_type(&self) -> String {
363-
match self {
364-
v1alpha1::CurrentlySupportedListenerClasses::ClusterInternal => "ClusterIP".to_string(),
365-
v1alpha1::CurrentlySupportedListenerClasses::ExternalUnstable => "NodePort".to_string(),
351+
fn default_listener_class() -> String {
352+
DEFAULT_LISTENER_CLASS.to_owned()
353+
}
354+
355+
impl Default for ZookeeperServerRoleConfig {
356+
fn default() -> Self {
357+
Self {
358+
listener_class: default_listener_class(),
359+
common: Default::default(),
366360
}
367361
}
368362
}
@@ -494,6 +488,7 @@ impl HasStatusCondition for v1alpha1::ZookeeperCluster {
494488
}
495489

496490
impl ZookeeperPodRef {
491+
// TODO (@NickLarsenNZ): What to do here?
497492
pub fn fqdn(&self, cluster_info: &KubernetesClusterInfo) -> String {
498493
format!(
499494
"{pod_name}.{service_name}.{namespace}.svc.{cluster_domain}",
@@ -529,16 +524,23 @@ impl v1alpha1::ZookeeperCluster {
529524
}
530525
}
531526

532-
/// The name of the role-level load-balanced Kubernetes `Service`
533-
pub fn server_role_service_name(&self) -> Option<String> {
527+
/// The name of the role-level [Listener]
528+
///
529+
/// [Listener]: stackable_operator::crd::listener::v1alpha1::Listener
530+
pub fn server_role_listener_name(&self) -> Option<String> {
534531
self.metadata.name.clone()
535532
}
536533

537-
/// The fully-qualified domain name of the role-level load-balanced Kubernetes `Service`
538-
pub fn server_role_service_fqdn(&self, cluster_info: &KubernetesClusterInfo) -> Option<String> {
534+
/// The fully-qualified domain name of the role-level [Listener]
535+
///
536+
/// [Listener]: stackable_operator::crd::listener::v1alpha1::Listener
537+
pub fn server_role_listener_fqdn(
538+
&self,
539+
cluster_info: &KubernetesClusterInfo,
540+
) -> Option<String> {
539541
Some(format!(
540-
"{role_service_name}.{namespace}.svc.{cluster_domain}",
541-
role_service_name = self.server_role_service_name()?,
542+
"{role_listener_name}.{namespace}.svc.{cluster_domain}",
543+
role_listener_name = self.server_role_listener_name()?,
542544
namespace = self.metadata.namespace.as_ref()?,
543545
cluster_domain = cluster_info.cluster_domain
544546
))
@@ -548,8 +550,10 @@ impl v1alpha1::ZookeeperCluster {
548550
pub fn role(
549551
&self,
550552
role_variant: &ZookeeperRole,
551-
) -> Result<&Role<v1alpha1::ZookeeperConfigFragment, GenericRoleConfig, JavaCommonConfig>, Error>
552-
{
553+
) -> Result<
554+
&Role<v1alpha1::ZookeeperConfigFragment, ZookeeperServerRoleConfig, JavaCommonConfig>,
555+
Error,
556+
> {
553557
match role_variant {
554558
ZookeeperRole::Server => self.spec.servers.as_ref(),
555559
}
@@ -590,7 +594,7 @@ impl v1alpha1::ZookeeperCluster {
590594
}
591595
}
592596

593-
pub fn role_config(&self, role: &ZookeeperRole) -> Option<&GenericRoleConfig> {
597+
pub fn role_config(&self, role: &ZookeeperRole) -> Option<&ZookeeperServerRoleConfig> {
594598
match role {
595599
ZookeeperRole::Server => self.spec.servers.as_ref().map(|s| &s.role_config),
596600
}

0 commit comments

Comments
 (0)