Skip to content

Commit

Permalink
Naive CEL validation example (#1372)
Browse files Browse the repository at this point in the history
* Naive CEL validation example

for #1367 and kube-rs/website#53

Signed-off-by: clux <[email protected]>

* fmt

Signed-off-by: clux <[email protected]>

---------

Signed-off-by: clux <[email protected]>
  • Loading branch information
clux authored Dec 15, 2023
1 parent 3a4f724 commit 9dc932b
Showing 1 changed file with 51 additions and 6 deletions.
57 changes: 51 additions & 6 deletions examples/crd_derive_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,11 @@ pub struct FooSpec {
#[serde(default)]
#[schemars(schema_with = "set_listable_schema")]
set_listable: Vec<u32>,
// Field with CEL validation
#[serde(default)]
#[schemars(schema_with = "cel_validations")]
cel_validated: Option<String>,
}

// https://kubernetes.io/docs/reference/using-api/server-side-apply/#merge-strategy
fn set_listable_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
serde_json::from_value(serde_json::json!({
Expand All @@ -101,6 +104,18 @@ fn set_listable_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::sche
.unwrap()
}

// https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#validation-rules
fn cel_validations(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
serde_json::from_value(serde_json::json!({
"type": "string",
"x-kubernetes-validations": [{
"rule": "self != 'illegal'",
"message": "string cannot be illegal"
}]
}))
.unwrap()
}

fn default_value() -> String {
"default_value".into()
}
Expand Down Expand Up @@ -144,6 +159,7 @@ async fn main() -> Result<()> {
// Empty listables to be patched in later
default_listable: Default::default(),
set_listable: Default::default(),
cel_validated: Default::default(),
});

// Set up dynamic resource to test using raw values.
Expand Down Expand Up @@ -190,10 +206,8 @@ async fn main() -> Result<()> {
assert_eq!(err.code, 422);
assert_eq!(err.reason, "Invalid");
assert_eq!(err.status, "Failure");
assert_eq!(
err.message,
"Foo.clux.dev \"qux\" is invalid: spec.non_nullable: Required value"
);
assert!(err.message.contains("clux.dev \"qux\" is invalid"));
assert!(err.message.contains("spec.non_nullable: Required value"));
}
_ => panic!(),
}
Expand All @@ -213,8 +227,39 @@ async fn main() -> Result<()> {
assert_eq!(pres.spec.set_listable, vec![2, 3]);
println!("{:?}", serde_json::to_value(pres.spec));

delete_crd(client.clone()).await?;
// cel validation triggers:
let cel_patch = serde_json::json!({
"apiVersion": "clux.dev/v1",
"kind": "Foo",
"spec": {
"cel_validated": Some("illegal")
}
});
let cel_res = foos.patch("baz", &ssapply, &Patch::Apply(cel_patch)).await;
assert!(cel_res.is_err());
match cel_res.err() {
Some(kube::Error::Api(err)) => {
assert_eq!(err.code, 422);
assert_eq!(err.reason, "Invalid");
assert_eq!(err.status, "Failure");
assert!(err.message.contains("Foo.clux.dev \"baz\" is invalid"));
assert!(err.message.contains("spec.cel_validated: Invalid value"));
assert!(err.message.contains("string cannot be illegal"));
}
_ => panic!(),
}
// cel validation happy:
let cel_patch_ok = serde_json::json!({
"apiVersion": "clux.dev/v1",
"kind": "Foo",
"spec": {
"cel_validated": Some("legal")
}
});
foos.patch("baz", &ssapply, &Patch::Apply(cel_patch_ok)).await?;

// all done
delete_crd(client.clone()).await?;
Ok(())
}

Expand Down

0 comments on commit 9dc932b

Please sign in to comment.