Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swap validator for garde #1212

Merged
merged 8 commits into from
Apr 29, 2023
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
2 changes: 1 addition & 1 deletion examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ latest = ["k8s-openapi/v1_26"]
[dev-dependencies]
tokio-util = "0.7.0"
assert-json-diff = "2.0.1"
validator = { version = "0.16.0", features = ["derive"] }
garde = { version = "0.11.2", default-features = false, features = ["derive"] }
anyhow = "1.0.44"
futures = "0.3.17"
jsonpath_lib = "0.3.0"
Expand Down
9 changes: 6 additions & 3 deletions examples/crd_api.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use anyhow::{bail, Result};
use either::Either::{Left, Right};
use garde::Validate;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::time::Duration;
use tokio::time::sleep;
use tracing::*;
use validator::Validate;

use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceDefinition;
use kube::{
Expand All @@ -22,9 +22,12 @@ use kube::{
#[kube(scale = r#"{"specReplicasPath":".spec.replicas", "statusReplicasPath":".status.replicas"}"#)]
#[kube(printcolumn = r#"{"name":"Team", "jsonPath": ".spec.metadata.team", "type": "string"}"#)]
pub struct FooSpec {
#[validate(length(min = 3))]
#[schemars(length(min = 3))]
#[garde(length(min = 3))]
name: String,
#[garde(skip)]
info: String,
#[garde(skip)]
replicas: i32,
}

Expand Down Expand Up @@ -201,7 +204,7 @@ async fn main() -> Result<()> {
replicas: 1,
});
// using derived Validate rules locally:
assert!(fx.spec.validate().is_err());
assert!(fx.spec.validate(&()).is_err());
// check rejection from apiserver (validation rules embedded in JsonSchema)
match foos.create(&pp, &fx).await {
Err(kube::Error::Api(ae)) => {
Expand Down
1 change: 0 additions & 1 deletion kube-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ serde_yaml = "0.9.19"
kube = { path = "../kube", version = "<1.0.0, >=0.61.0", features = ["derive", "client"] }
k8s-openapi = { version = "0.18.0", default-features = false, features = ["v1_26"] }
schemars = { version = "0.8.6", features = ["chrono"] }
validator = { version = "0.16.0", features = ["derive"] }
chrono = { version = "0.4.19", default-features = false }
trybuild = "1.0.48"
assert-json-diff = "2.0.2"
25 changes: 16 additions & 9 deletions kube-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,8 @@ mod custom_resource;
/// use serde::{Serialize, Deserialize};
/// use kube_derive::CustomResource;
/// use schemars::JsonSchema;
/// use validator::Validate;
///
/// #[derive(CustomResource, Serialize, Deserialize, Debug, PartialEq, Clone, Validate, JsonSchema)]
/// #[derive(CustomResource, Serialize, Deserialize, Debug, PartialEq, Clone, JsonSchema)]
/// #[kube(
/// group = "clux.dev",
/// version = "v1",
Expand All @@ -166,7 +165,7 @@ mod custom_resource;
/// )]
/// #[serde(rename_all = "camelCase")]
/// struct FooSpec {
/// #[validate(length(min = 3))]
/// #[schemars(length(min = 3))]
/// data: String,
/// replicas_count: i32
/// }
Expand Down Expand Up @@ -213,7 +212,8 @@ mod custom_resource;
/// - [Serde/Schemars Attributes](https://graham.cool/schemars/examples/3-schemars_attrs/) (no need to duplicate serde renames)
/// - [`#[schemars(schema_with = "func")]`](https://graham.cool/schemars/examples/7-custom_serialization/) (e.g. like in the [`crd_derive` example](/~https://github.com/kube-rs/kube/blob/main/examples/crd_derive.rs))
/// - `impl JsonSchema` on a type / newtype around external type. See [#129](/~https://github.com/kube-rs/kube/issues/129#issuecomment-750852916)
/// - [`#[validate(...)]` field attributes with validator](/~https://github.com/Keats/validator) for kubebuilder style validation rules (see [`crd_api` example](/~https://github.com/kube-rs/kube/blob/main/examples/crd_api.rs)))
/// - [`#[garde(...)]` field attributes for client-side validation](/~https://github.com/jprochazk/garde) (see [`crd_api`
/// example](/~https://github.com/kube-rs/kube/blob/main/examples/crd_api.rs))
///
/// You might need to override parts of the schemas (for fields in question) when you are:
/// - **using complex enums**: enums do not currently generate [structural schemas](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema), so kubernetes won't support them by default
Expand All @@ -229,15 +229,22 @@ mod custom_resource;
/// - **adding validation** via [validator crate](/~https://github.com/Keats/validator) is supported from `schemars` >= [`0.8.5`](/~https://github.com/GREsau/schemars/blob/master/CHANGELOG.md#085---2021-09-20)
/// - **generating rust code from schemas** can be done via [kopium](/~https://github.com/kube-rs/kopium) and is supported on stable crds (> 1.16 kubernetes)
///
/// ## Validation Caveats
/// The supported **`#[validate]` attrs also exist as `#[schemars]` attrs** so you can use those directly if you do not require the validation to run client-side (in your code).
/// Otherwise, you should `#[derive(Validate)]` on your struct to have both server-side (kubernetes) and client-side validation.
/// ## Schema Validation
/// There are two main ways of doing validation; **server-side** (embedding validation attributes into the schema for the apiserver to respect), and **client-side** (provides `validate()` methods in your code).
///
/// When using `validator` directly, you must add it to your dependencies (with the `derive` feature).
/// Client side validation of structs can be achieved by hooking up `#[garde]` attributes in your struct and is a replacement of the now unmaintained [`validator`](/~https://github.com/Keats/validator/issues/201) crate.
/// Server-side validation require mutation of your generated schema, and can in the basic cases be achieved through the use of `schemars`'s [validation attributes](https://graham.cool/schemars/deriving/attributes/#supported-validator-attributes).
/// For complete control, [parts of the schema can be overridden](/~https://github.com/kube-rs/kube/blob/e01187e13ba364ccecec452e023316a62fb13e04/examples/crd_derive.rs#L37-L38) to support more advanced [Kubernetes specific validation rules](https://kubernetes.io/blog/2022/09/23/crd-validation-rules-beta/).
///
/// When using `garde` directly, you must add it to your dependencies (with the `derive` feature).
///
/// ### Validation Caveats
/// Make sure your validation rules are static and handled by `schemars`:
/// - validations from `#[validate(custom = "some_fn")]` will not show up in the schema.
/// - validations from `#[garde(custom(my_func))]` will not show up in the schema.
/// - similarly; [nested / must_match / credit_card were unhandled by schemars at time of writing](/~https://github.com/GREsau/schemars/pull/78)
/// - encoding validations specified through garde (i.e. #[garde(ascii)]), are currently not supported by schemars
/// - to validate required attributes client-side, garde requires a custom validation function (`#[garde(custom(my_required_check))]`)
/// - when using garde, fields that should not be validated need to be explictly skipped through the `#[garde(skip)]` attr
///
/// For sanity, you should review the generated schema before sending it to kubernetes.
///
Expand Down
1 change: 0 additions & 1 deletion kube/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ default-features = false
tokio = { version = "1.14.0", features = ["full"] }
futures = "0.3.17"
serde_json = "1.0.68"
validator = { version = "0.16.0", features = ["derive"] }
serde = { version = "1.0.130", features = ["derive"] }
schemars = "0.8.6"

Expand Down
5 changes: 2 additions & 3 deletions kube/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
//! use schemars::JsonSchema;
//! use serde::{Deserialize, Serialize};
//! use serde_json::json;
//! use validator::Validate;
//! use futures::{StreamExt, TryStreamExt};
//! use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceDefinition;
//! use kube::{
Expand All @@ -59,11 +58,11 @@
//! };
//!
//! // Our custom resource
//! #[derive(CustomResource, Deserialize, Serialize, Clone, Debug, Validate, JsonSchema)]
//! #[derive(CustomResource, Deserialize, Serialize, Clone, Debug, JsonSchema)]
//! #[kube(group = "clux.dev", version = "v1", kind = "Foo", namespaced)]
//! pub struct FooSpec {
//! info: String,
//! #[validate(length(min = 3))]
//! #[schemars(length(min = 3))]
//! name: String,
//! replicas: i32,
//! }
Expand Down