@@ -2,18 +2,22 @@ use std::{fmt::Debug, net::SocketAddr};
2
2
3
3
use axum:: { Json , Router , routing:: post} ;
4
4
use k8s_openapi:: apiextensions_apiserver:: pkg:: apis:: apiextensions:: v1:: CustomResourceDefinition ;
5
- use kube:: ResourceExt ;
6
5
// Re-export this type because users of the conversion webhook server require
7
6
// this type to write the handler function. Instead of importing this type from
8
7
// kube directly, consumers can use this type instead. This also eliminates
9
8
// keeping the kube dependency version in sync between here and the operator.
10
9
pub use kube:: core:: conversion:: ConversionReview ;
10
+ use kube:: { Client , ResourceExt } ;
11
11
use snafu:: { ResultExt , Snafu } ;
12
- use tokio:: sync:: mpsc;
12
+ use tokio:: sync:: { mpsc, oneshot } ;
13
13
use tracing:: instrument;
14
14
use x509_cert:: Certificate ;
15
15
16
- use crate :: { WebhookError , WebhookHandler , WebhookServer , options:: WebhookOptions } ;
16
+ use crate :: {
17
+ WebhookError , WebhookHandler , WebhookServer ,
18
+ maintainer:: { CustomResourceDefinitionMaintainer , CustomResourceDefinitionMaintainerOptions } ,
19
+ options:: WebhookOptions ,
20
+ } ;
17
21
18
22
#[ derive( Debug , Snafu ) ]
19
23
pub enum ConversionWebhookError {
@@ -53,15 +57,15 @@ where
53
57
54
58
// TODO: Add a builder, maybe with `bon`.
55
59
#[ derive( Debug ) ]
56
- pub struct ConversionWebhookOptions {
60
+ pub struct ConversionWebhookOptions < ' a > {
57
61
/// The bind address to bind the HTTPS server to.
58
62
pub socket_addr : SocketAddr ,
59
63
60
64
/// The namespace the operator/webhook is running in.
61
- pub namespace : String ,
65
+ pub namespace : & ' a str ,
62
66
63
67
/// The name of the Kubernetes service which points to the operator/webhook.
64
- pub service_name : String ,
68
+ pub service_name : & ' a str ,
65
69
}
66
70
67
71
/// A ready-to-use CRD conversion webhook server.
@@ -77,6 +81,8 @@ impl ConversionWebhookServer {
77
81
/// Creates and returns a new [`ConversionWebhookServer`], which expects POST requests being
78
82
/// made to the `/convert/{CRD_NAME}` endpoint.
79
83
///
84
+ /// The TLS certificate is automatically generated and rotated.
85
+ ///
80
86
/// ## Parameters
81
87
///
82
88
/// This function expects the following parameters:
@@ -134,25 +140,25 @@ impl ConversionWebhookServer {
134
140
#[ instrument( name = "create_conversion_webhook_server" , skip( crds_and_handlers) ) ]
135
141
pub async fn new < H > (
136
142
crds_and_handlers : impl IntoIterator < Item = ( CustomResourceDefinition , H ) > ,
137
- options : ConversionWebhookOptions ,
143
+ options : ConversionWebhookOptions < ' _ > ,
138
144
) -> Result < ( Self , mpsc:: Receiver < Certificate > ) , ConversionWebhookError >
139
145
where
140
146
H : WebhookHandler < ConversionReview , ConversionReview > + Clone + Send + Sync + ' static ,
141
147
{
142
148
tracing:: debug!( "create new conversion webhook server" ) ;
143
149
144
150
let mut router = Router :: new ( ) ;
145
- let mut crds = Vec :: new ( ) ;
151
+
146
152
for ( crd, handler) in crds_and_handlers {
147
153
let crd_name = crd. name_any ( ) ;
148
154
let handler_fn = |Json ( review) : Json < ConversionReview > | async {
149
155
let review = handler. call ( review) ;
150
156
Json ( review)
151
157
} ;
152
158
159
+ // TODO (@Techassi): Make this part of the trait mentioned above
153
160
let route = format ! ( "/convert/{crd_name}" ) ;
154
161
router = router. route ( & route, post ( handler_fn) ) ;
155
- crds. push ( crd) ;
156
162
}
157
163
158
164
let ConversionWebhookOptions {
@@ -180,6 +186,61 @@ impl ConversionWebhookServer {
180
186
Ok ( ( Self ( server) , certificate_rx) )
181
187
}
182
188
189
+ /// Creates and returns a tuple consisting of a [`ConversionWebhookServer`], a [`CustomResourceDefinitionMaintainer`],
190
+ /// and a [`oneshot::Receiver`].
191
+ ///
192
+ /// See the referenced items for more details on usage.
193
+ pub async fn with_maintainer < ' a , H > (
194
+ // TODO (@Techassi): Use a trait type here which can be used to build all part of the
195
+ // conversion webhook server and a CRD maintainer.
196
+ crds_and_handlers : impl IntoIterator < Item = ( CustomResourceDefinition , H ) > + Clone ,
197
+ operator_name : & ' a str ,
198
+ operator_namespace : & ' a str ,
199
+ disable_maintainer : bool ,
200
+ client : Client ,
201
+ ) -> Result <
202
+ (
203
+ Self ,
204
+ CustomResourceDefinitionMaintainer < ' a > ,
205
+ oneshot:: Receiver < ( ) > ,
206
+ ) ,
207
+ ConversionWebhookError ,
208
+ >
209
+ where
210
+ H : WebhookHandler < ConversionReview , ConversionReview > + Clone + Send + Sync + ' static ,
211
+ {
212
+ let socket_addr = ConversionWebhookServer :: DEFAULT_SOCKET_ADDRESS ;
213
+
214
+ // TODO (@Techassi): These should be moved into a builder
215
+ let webhook_options = ConversionWebhookOptions {
216
+ namespace : operator_namespace,
217
+ service_name : operator_name,
218
+ socket_addr,
219
+ } ;
220
+
221
+ let ( conversion_webhook_server, certificate_rx) =
222
+ Self :: new ( crds_and_handlers. clone ( ) , webhook_options) . await ?;
223
+
224
+ let definitions = crds_and_handlers. into_iter ( ) . map ( |( crd, _) | crd) ;
225
+
226
+ // TODO (@Techassi): These should be moved into a builder
227
+ let maintainer_options = CustomResourceDefinitionMaintainerOptions {
228
+ webhook_https_port : socket_addr. port ( ) ,
229
+ disabled : disable_maintainer,
230
+ operator_namespace,
231
+ operator_name,
232
+ } ;
233
+
234
+ let ( maintainer, initial_reconcile_rx) = CustomResourceDefinitionMaintainer :: new (
235
+ client,
236
+ certificate_rx,
237
+ definitions,
238
+ maintainer_options,
239
+ ) ;
240
+
241
+ Ok ( ( conversion_webhook_server, maintainer, initial_reconcile_rx) )
242
+ }
243
+
183
244
/// Runs the [`ConversionWebhookServer`] asynchronously.
184
245
pub async fn run ( self ) -> Result < ( ) , ConversionWebhookError > {
185
246
tracing:: info!( "run conversion webhook server" ) ;
0 commit comments