@@ -2,18 +2,22 @@ use std::{fmt::Debug, net::SocketAddr};
22
33use axum:: { Json , Router , routing:: post} ;
44use k8s_openapi:: apiextensions_apiserver:: pkg:: apis:: apiextensions:: v1:: CustomResourceDefinition ;
5- use kube:: ResourceExt ;
65// Re-export this type because users of the conversion webhook server require
76// this type to write the handler function. Instead of importing this type from
87// kube directly, consumers can use this type instead. This also eliminates
98// keeping the kube dependency version in sync between here and the operator.
109pub use kube:: core:: conversion:: ConversionReview ;
10+ use kube:: { Client , ResourceExt } ;
1111use snafu:: { ResultExt , Snafu } ;
12- use tokio:: sync:: mpsc;
12+ use tokio:: sync:: { mpsc, oneshot } ;
1313use tracing:: instrument;
1414use x509_cert:: Certificate ;
1515
16- use crate :: { WebhookError , WebhookHandler , WebhookServer , options:: WebhookOptions } ;
16+ use crate :: {
17+ WebhookError , WebhookHandler , WebhookServer ,
18+ maintainer:: { CustomResourceDefinitionMaintainer , CustomResourceDefinitionMaintainerOptions } ,
19+ options:: WebhookOptions ,
20+ } ;
1721
1822#[ derive( Debug , Snafu ) ]
1923pub enum ConversionWebhookError {
@@ -53,15 +57,15 @@ where
5357
5458// TODO: Add a builder, maybe with `bon`.
5559#[ derive( Debug ) ]
56- pub struct ConversionWebhookOptions {
60+ pub struct ConversionWebhookOptions < ' a > {
5761 /// The bind address to bind the HTTPS server to.
5862 pub socket_addr : SocketAddr ,
5963
6064 /// The namespace the operator/webhook is running in.
61- pub namespace : String ,
65+ pub namespace : & ' a str ,
6266
6367 /// The name of the Kubernetes service which points to the operator/webhook.
64- pub service_name : String ,
68+ pub service_name : & ' a str ,
6569}
6670
6771/// A ready-to-use CRD conversion webhook server.
@@ -77,6 +81,8 @@ impl ConversionWebhookServer {
7781 /// Creates and returns a new [`ConversionWebhookServer`], which expects POST requests being
7882 /// made to the `/convert/{CRD_NAME}` endpoint.
7983 ///
84+ /// The TLS certificate is automatically generated and rotated.
85+ ///
8086 /// ## Parameters
8187 ///
8288 /// This function expects the following parameters:
@@ -134,25 +140,25 @@ impl ConversionWebhookServer {
134140 #[ instrument( name = "create_conversion_webhook_server" , skip( crds_and_handlers) ) ]
135141 pub async fn new < H > (
136142 crds_and_handlers : impl IntoIterator < Item = ( CustomResourceDefinition , H ) > ,
137- options : ConversionWebhookOptions ,
143+ options : ConversionWebhookOptions < ' _ > ,
138144 ) -> Result < ( Self , mpsc:: Receiver < Certificate > ) , ConversionWebhookError >
139145 where
140146 H : WebhookHandler < ConversionReview , ConversionReview > + Clone + Send + Sync + ' static ,
141147 {
142148 tracing:: debug!( "create new conversion webhook server" ) ;
143149
144150 let mut router = Router :: new ( ) ;
145- let mut crds = Vec :: new ( ) ;
151+
146152 for ( crd, handler) in crds_and_handlers {
147153 let crd_name = crd. name_any ( ) ;
148154 let handler_fn = |Json ( review) : Json < ConversionReview > | async {
149155 let review = handler. call ( review) ;
150156 Json ( review)
151157 } ;
152158
159+ // TODO (@Techassi): Make this part of the trait mentioned above
153160 let route = format ! ( "/convert/{crd_name}" ) ;
154161 router = router. route ( & route, post ( handler_fn) ) ;
155- crds. push ( crd) ;
156162 }
157163
158164 let ConversionWebhookOptions {
@@ -180,6 +186,61 @@ impl ConversionWebhookServer {
180186 Ok ( ( Self ( server) , certificate_rx) )
181187 }
182188
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+
183244 /// Runs the [`ConversionWebhookServer`] asynchronously.
184245 pub async fn run ( self ) -> Result < ( ) , ConversionWebhookError > {
185246 tracing:: info!( "run conversion webhook server" ) ;
0 commit comments