Skip to content

Commit

Permalink
fix(admission): fix admission reject request when serde failed (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
zen-xu committed Nov 2, 2022
1 parent 3df34d3 commit fae3fd9
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 18 deletions.
2 changes: 2 additions & 0 deletions crates/habitat-admission/Cargo.toml
Expand Up @@ -18,3 +18,5 @@ serde_json = "1"
tracing = "0.1"
tracing-subscriber = "0.3"
warp = { version = "0.3", default-features = false, features = ["tls"] }
regex = "1"
lazy_static = "1"
2 changes: 2 additions & 0 deletions crates/habitat-admission/src/lib.rs
@@ -1,2 +1,4 @@
pub mod mutate;
pub mod validate;

mod util;
27 changes: 18 additions & 9 deletions crates/habitat-admission/src/mutate.rs
@@ -1,14 +1,16 @@
use habitat_api::Job;
use kube::core::{
admission::{AdmissionRequest, AdmissionResponse, AdmissionReview},
ResourceExt,
DynamicObject, ResourceExt,
};
use std::{convert::Infallible, error::Error};
use tracing::*;
use warp::{reply, Reply};

use crate::util::try_cast_dynamic_obj_into_job;

pub async fn handler(body: AdmissionReview<Job>) -> Result<impl Reply, Infallible> {

pub async fn handler(body: AdmissionReview<DynamicObject>) -> Result<impl Reply, Infallible> {
// Parse incoming webhook AdmissionRequest first
let req: AdmissionRequest<_> = match body.try_into() {
Ok(req) => req,
Expand All @@ -25,14 +27,21 @@ pub async fn handler(body: AdmissionReview<Job>) -> Result<impl Reply, Infallibl
// req.Object always exists for us, but could be None if extending to DELETE events
if let Some(obj) = req.object {
let name = obj.name_any(); // apiserver may not have generated a name yet
res = match mutate(res.clone(), &obj) {
Ok(res) => {
info!("accepted: {:?} on Job {}", req.operation, name);
res
}

res = match try_cast_dynamic_obj_into_job(&obj) {
Ok(job) => match mutate(res.clone(), &job) {
Ok(res) => {
info!("accepted: {:?} on Job {}", req.operation, name);
res
}
Err(err) => {
warn!("denied: {:?} on {} ({})", req.operation, name, err);
res.deny(err.to_string())
}
},
Err(err) => {
warn!("denied: {:?} on {} ({})", req.operation, name, err);
res.deny(err.to_string())
warn!("invalid job: {:?} on {} ({})", req.operation, name, err);
res.deny(err)
}
};
};
Expand Down
13 changes: 13 additions & 0 deletions crates/habitat-admission/src/util.rs
@@ -0,0 +1,13 @@
use habitat_api::Job;
use kube::core::DynamicObject;
use lazy_static::lazy_static;
use regex::Regex;

pub fn try_cast_dynamic_obj_into_job(obj: &DynamicObject) -> Result<Job, String> {
lazy_static! {
static ref RE: Regex = Regex::new(r" at line \d+ column \d+").unwrap();
}

let obj_json = serde_json::to_string(obj).unwrap();
serde_json::from_str(&obj_json).map_err(|e| RE.replace(&e.to_string(), "").to_string())
}
26 changes: 17 additions & 9 deletions crates/habitat-admission/src/validate.rs
@@ -1,14 +1,16 @@
use habitat_api::Job;
use kube::core::{
admission::{AdmissionRequest, AdmissionResponse, AdmissionReview},
ResourceExt,
DynamicObject, ResourceExt,
};
use std::{convert::Infallible, error::Error};
use tracing::*;
use warp::{reply, Reply};

use crate::util::try_cast_dynamic_obj_into_job;

pub async fn handler(body: AdmissionReview<Job>) -> Result<impl Reply, Infallible> {

pub async fn handler(body: AdmissionReview<DynamicObject>) -> Result<impl Reply, Infallible> {
// Parse incoming webhook AdmissionRequest first
let req: AdmissionRequest<_> = match body.try_into() {
Ok(req) => req,
Expand All @@ -25,14 +27,20 @@ pub async fn handler(body: AdmissionReview<Job>) -> Result<impl Reply, Infallibl
// req.Object always exists for us, but could be None if extending to DELETE events
if let Some(obj) = req.object {
let name = obj.name_any(); // apiserver may not have generated a name yet
res = match validate(res.clone(), &obj) {
Ok(res) => {
info!("accepted: {:?} on Job {}", req.operation, name);
res
}
res = match try_cast_dynamic_obj_into_job(&obj) {
Ok(job) => match validate(res.clone(), &job) {
Ok(res) => {
info!("accepted: {:?} on Job {}", req.operation, name);
res
}
Err(err) => {
warn!("denied: {:?} on {} ({})", req.operation, name, err);
res.deny(err.to_string())
}
},
Err(err) => {
warn!("denied: {:?} on {} ({})", req.operation, name, err);
res.deny(err.to_string())
warn!("invalid job: {:?} on {} ({})", req.operation, name, err);
res.deny(err)
}
};
};
Expand Down

0 comments on commit fae3fd9

Please sign in to comment.