Deriving a schema happens automatically when using
#[derive(CustomResource, JsonSchema)] on a spec struct.
For an example of what is generated look at examples/crd_derive_schema.
Completely overriding can be done with
#[kube(schema = "disabled)] and hooking in a manual schema string on to each
crd.spec.versions.schema. An example of this can be found in examples/crd_derive_no_schema.
Doing this allows eliding the
#[derive(JsonSchema)] instruction, which in some cases is your only choice if you do not own the struct.
If you would like to do it more programmatically, and you have partial
JsonSchema coverage, you could fill in the gaps with
#[kube(schema = "manual")] which avoids having to modify the
CustomResourceDefinition. See examples/crd_derive_custom_schema.
Overriding specific parts of a schema can be done using
#[schemars(schema_with)]. Some specific examples:
It is possible to progress between two structs in a versionend manner.
You can define multiple structs within versioned modules ala https://github.com/kube-rs/kube/blob/main/examples/crd_derive_multi.rs and then use merge_crds to combine them.
Kubernetes >1.25 supports including validation rules in the openapi schema, and there are a couple of ways to include these.
See the Openapi V3 blogpost for more context.
This can be done by following upstream docs, and doing manual #overriding.
This way will grant you entry to the 1.25 Common Expression Language feature. Note however, that there are no recommended ways of doing client-side validation with this approach, but there are new cel parser/interpreter crates that might be useful here.
Deriving via Garde#
Using garde is a nice for the simple case because it allows doing both client-side validation, and server-side validation, with the caveat that it only works on both sides for basic validation rules as schemars can only pick up on some of them.