Skip to content

Commit c7b4936

Browse files
committed
feat: Add conversion webhook
1 parent 886ae7c commit c7b4936

9 files changed

Lines changed: 2253 additions & 100 deletions

File tree

Cargo.lock

Lines changed: 462 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.nix

Lines changed: 1690 additions & 56 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ repository = "https://github.com/stackabletech/zookeeper-operator"
1111

1212
[workspace.dependencies]
1313
product-config = { git = "https://github.com/stackabletech/product-config.git", tag = "0.8.0" }
14-
stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.105.0", features = ["telemetry", "versioned"] }
14+
stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.105.0", features = ["telemetry", "versioned", "webhook"] }
1515

1616
anyhow = "1.0"
1717
built = { version = "0.8", features = ["chrono", "git2"] }

Tiltfile

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ custom_build(
1717
outputs_image_ref_to='result/ref',
1818
)
1919

20-
# Load the latest CRDs from Nix
21-
watch_file('result')
22-
if os.path.exists('result'):
23-
k8s_yaml('result/crds.yaml')
24-
2520
# We need to set the correct image annotation on the operator Deployment to use e.g.
2621
# oci.stackable.tech/sandbox/opa-operator:7y19m3d8clwxlv34v5q2x4p7v536s00g instead of
2722
# oci.stackable.tech/sandbox/opa-operator:0.0.0-dev (which does not exist)
@@ -35,18 +30,12 @@ helm_values = settings.get('helm_values', None)
3530

3631
helm_override_image_repository = 'image.repository=' + registry + '/' + operator_name
3732

38-
# Exclude stale CRDs from Helm chart, and apply the rest
39-
helm_crds, helm_non_crds = filter_yaml(
40-
helm(
41-
'deploy/helm/' + operator_name,
42-
name=operator_name,
43-
namespace="stackable-operators",
44-
set=[
45-
helm_override_image_repository,
46-
],
47-
values=helm_values,
48-
),
49-
api_version = "^apiextensions\\.k8s\\.io/.*$",
50-
kind = "^CustomResourceDefinition$",
51-
)
52-
k8s_yaml(helm_non_crds)
33+
k8s_yaml(helm(
34+
'deploy/helm/' + operator_name,
35+
name=operator_name,
36+
namespace="stackable-operators",
37+
set=[
38+
helm_override_image_repository,
39+
],
40+
values=helm_values,
41+
))

crate-hashes.json

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub mod tls;
4747

4848
pub const APP_NAME: &str = "zookeeper";
4949
pub const OPERATOR_NAME: &str = "zookeeper.stackable.tech";
50+
pub const FIELD_MANAGER: &str = "zookeeper-operator";
5051

5152
pub const ZOOKEEPER_PROPERTIES_FILE: &str = "zoo.cfg";
5253
pub const JVM_SECURITY_PROPERTIES_FILE: &str = "security.properties";

rust/operator-binary/src/main.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
#![allow(clippy::result_large_err)]
44
use std::sync::Arc;
55

6+
use anyhow::anyhow;
67
use clap::Parser;
78
use crd::{
89
APP_NAME, OPERATOR_NAME, ZookeeperCluster, ZookeeperClusterVersion, ZookeeperZnode,
910
ZookeeperZnodeVersion, v1alpha1,
1011
};
11-
use futures::{FutureExt, StreamExt};
12+
use futures::{FutureExt, StreamExt, TryFutureExt};
1213
use stackable_operator::{
1314
YamlSchema,
1415
cli::{Command, RunArguments},
@@ -33,7 +34,10 @@ use stackable_operator::{
3334
utils::signal::SignalWatcher,
3435
};
3536

36-
use crate::{zk_controller::ZK_FULL_CONTROLLER_NAME, znode_controller::ZNODE_FULL_CONTROLLER_NAME};
37+
use crate::{
38+
webhooks::conversion::create_webhook_server, zk_controller::ZK_FULL_CONTROLLER_NAME,
39+
znode_controller::ZNODE_FULL_CONTROLLER_NAME,
40+
};
3741

3842
mod command;
3943
mod config;
@@ -44,6 +48,7 @@ mod operations;
4448
mod product_logging;
4549
mod service;
4650
mod utils;
51+
mod webhooks;
4752
mod zk_controller;
4853
mod znode_controller;
4954

@@ -69,9 +74,9 @@ async fn main() -> anyhow::Result<()> {
6974
.print_yaml_schema(built_info::PKG_VERSION, SerializeOptions::default())?;
7075
}
7176
Command::Run(RunArguments {
72-
product_config,
77+
operator_environment,
7378
watch_namespace,
74-
operator_environment: _,
79+
product_config,
7580
maintenance,
7681
common,
7782
}) => {
@@ -101,17 +106,28 @@ async fn main() -> anyhow::Result<()> {
101106
.run(sigterm_watcher.handle())
102107
.map(anyhow::Ok);
103108

104-
let product_config = product_config.load(&[
105-
"deploy/config-spec/properties.yaml",
106-
"/etc/stackable/zookeeper-operator/config-spec/properties.yaml",
107-
])?;
108-
109109
let client = stackable_operator::client::initialize_operator(
110110
Some(OPERATOR_NAME.to_string()),
111111
&common.cluster_info,
112112
)
113113
.await?;
114114

115+
let webhook_server = create_webhook_server(
116+
&operator_environment,
117+
maintenance.disable_crd_maintenance,
118+
client.as_kube_client(),
119+
)
120+
.await?;
121+
122+
let webhook_server = webhook_server
123+
.run(sigterm_watcher.handle())
124+
.map_err(|err| anyhow!(err).context("failed to run webhook server"));
125+
126+
let product_config = product_config.load(&[
127+
"deploy/config-spec/properties.yaml",
128+
"/etc/stackable/zookeeper-operator/config-spec/properties.yaml",
129+
])?;
130+
115131
let zk_controller = Controller::new(
116132
watch_namespace.get_api::<DeserializeGuard<v1alpha1::ZookeeperCluster>>(&client),
117133
watcher::Config::default(),
@@ -230,7 +246,7 @@ async fn main() -> anyhow::Result<()> {
230246
.map(anyhow::Ok);
231247

232248
// kube-runtime's Controller will tokio::spawn each reconciliation, so this only concerns the internal watch machinery
233-
futures::try_join!(zk_controller, znode_controller, eos_checker)?;
249+
futures::try_join!(zk_controller, znode_controller, eos_checker, webhook_server)?;
234250
}
235251
}
236252

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use snafu::{ResultExt, Snafu};
2+
use stackable_operator::{
3+
cli::OperatorEnvironmentOptions,
4+
kube::{Client, core::crd::MergeError},
5+
webhook::{
6+
WebhookServer, WebhookServerError, WebhookServerOptions,
7+
webhooks::{ConversionWebhook, ConversionWebhookOptions},
8+
},
9+
};
10+
11+
use crate::crd::{
12+
FIELD_MANAGER, ZookeeperCluster, ZookeeperClusterVersion, ZookeeperZnode, ZookeeperZnodeVersion,
13+
};
14+
15+
/// Contains errors which can be encountered when creating the conversion webhook server and the
16+
/// CRD maintainer.
17+
#[derive(Debug, Snafu)]
18+
pub enum Error {
19+
#[snafu(display("failed to merge CRD"))]
20+
MergeCrd { source: MergeError },
21+
22+
#[snafu(display("failed to create conversion webhook server"))]
23+
CreateWebhook { source: WebhookServerError },
24+
}
25+
26+
/// Creates and returns a [`WebhookServer`].
27+
pub async fn create_webhook_server(
28+
operator_environment: &OperatorEnvironmentOptions,
29+
disable_crd_maintenance: bool,
30+
client: Client,
31+
) -> Result<WebhookServer, Error> {
32+
let crds_and_handlers = vec![
33+
(
34+
ZookeeperCluster::merged_crd(ZookeeperClusterVersion::V1Alpha1)
35+
.context(MergeCrdSnafu)?,
36+
ZookeeperCluster::try_convert as fn(_) -> _,
37+
),
38+
(
39+
ZookeeperZnode::merged_crd(ZookeeperZnodeVersion::V1Alpha1).context(MergeCrdSnafu)?,
40+
ZookeeperZnode::try_convert as fn(_) -> _,
41+
),
42+
];
43+
44+
let conversion_webhook_options = ConversionWebhookOptions {
45+
disable_crd_maintenance,
46+
field_manager: FIELD_MANAGER.to_owned(),
47+
};
48+
49+
let (conversion_webhook, _initial_reconcile_rx) =
50+
ConversionWebhook::new(crds_and_handlers, client, conversion_webhook_options);
51+
52+
let webhook_server_options = WebhookServerOptions {
53+
socket_addr: WebhookServer::DEFAULT_SOCKET_ADDRESS,
54+
webhook_namespace: operator_environment.operator_namespace.to_owned(),
55+
webhook_service_name: operator_environment.operator_service_name.to_owned(),
56+
};
57+
58+
WebhookServer::new(vec![Box::new(conversion_webhook)], webhook_server_options)
59+
.await
60+
.context(CreateWebhookSnafu)
61+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod conversion;

0 commit comments

Comments
 (0)