Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ static_assertions = "1.1.0"
tar = "0.4.37"
tracing.workspace = true
tracing-subscriber.workspace = true
warp = { version = "0.3", default-features = false, features = ["tls"] }
axum = "0.8.7"
axum-server = { version = "0.8.0", features = ["tls-rustls-no-provider"] }
bytes.workspace = true
http.workspace = true
http-body-util.workspace = true
Expand Down
43 changes: 24 additions & 19 deletions examples/admission_controller.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,49 @@
use axum::{Json, Router, response::IntoResponse, routing::post};
use axum_server::tls_rustls::RustlsConfig;
use json_patch::jsonptr::PointerBuf;
use kube::core::{
admission::{AdmissionRequest, AdmissionResponse, AdmissionReview},
DynamicObject, Resource, ResourceExt,
admission::{AdmissionRequest, AdmissionResponse, AdmissionReview},
};
use std::{convert::Infallible, error::Error};
use std::{error::Error, net::SocketAddr};
use tower_http::trace::TraceLayer;
use tracing::*;
use warp::{reply, Filter, Reply};

#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();

let routes = warp::path("mutate")
.and(warp::body::json())
.and_then(mutate_handler)
.with(warp::trace::request());
let app = Router::new().route("/mutate", post(mutate_handler)).layer(
TraceLayer::new_for_http()
.make_span_with(tower_http::trace::DefaultMakeSpan::new().level(Level::INFO)),
);

// You must generate a certificate for the service / url,
// encode the CA in the MutatingWebhookConfiguration, and terminate TLS here.
// See admission_setup.sh + admission_controller.yaml.tpl for how to do this.
let addr = format!("{}:8443", std::env::var("ADMISSION_PRIVATE_IP").unwrap());
warp::serve(warp::post().and(routes))
.tls()
.cert_path("admission-controller-tls.crt")
.key_path("admission-controller-tls.key")
//.run(([0, 0, 0, 0], 8443)) // in-cluster
.run(addr.parse::<std::net::SocketAddr>().unwrap()) // local-dev
.await;
axum_server::bind_rustls(
// SocketAddr::from(([0, 0, 0, 0], 8443)), // in-cluster
addr.parse::<SocketAddr>().unwrap(), // local-dev
RustlsConfig::from_pem_file("admission-controller-tls.crt", "admission-controller-tls.key")
.await
.unwrap(),
)
.serve(app.into_make_service())
.await
.unwrap();
}

// A general /mutate handler, handling errors from the underlying business logic
async fn mutate_handler(body: AdmissionReview<DynamicObject>) -> Result<impl Reply, Infallible> {
async fn mutate_handler(
Json(body): Json<AdmissionReview<DynamicObject>>,
) -> Json<AdmissionReview<DynamicObject>> {
// Parse incoming webhook AdmissionRequest first
let req: AdmissionRequest<_> = match body.try_into() {
Ok(req) => req,
Err(err) => {
error!("invalid request: {}", err.to_string());
return Ok(reply::json(
&AdmissionResponse::invalid(err.to_string()).into_review(),
));
return Json(AdmissionResponse::invalid(err.to_string()).into_review());
}
};

Expand All @@ -60,7 +65,7 @@ async fn mutate_handler(body: AdmissionReview<DynamicObject>) -> Result<impl Rep
};
};
// Wrap the AdmissionResponse wrapped in an AdmissionReview
Ok(reply::json(&res.into_review()))
Json(res.into_review())
}

// The main handler and core business logic, failures here implies rejected applies
Expand Down
Loading