Derive Macro kube::CustomResource [−][src]
#[derive(CustomResource)]
{
// Attributes available to this derive:
#[kube]
}
derive
only.Expand description
Re-exports from kube-derive
A custom derive for kubernetes custom resource definitions.
This will generate a root object containing your spec and metadata.
This root object will implement the kube::Resource
trait
so it can be used with kube::Api
.
The generated type will also implement kube’s kube::CustomResourceExt
trait to generate the crd
and generate kube::core::ApiResource
information for use with the dynamic api.
Example
use serde::{Serialize, Deserialize};
use kube::core::{Resource, CustomResourceExt};
use kube_derive::CustomResource;
use schemars::JsonSchema;
#[derive(CustomResource, Clone, Debug, Deserialize, Serialize, JsonSchema)]
#[kube(group = "clux.dev", version = "v1", kind = "Foo", namespaced)]
struct FooSpec {
info: String,
}
println!("kind = {}", Foo::kind(&())); // impl kube::Resource
let f = Foo::new("foo-1", FooSpec {
info: "informative info".into(),
});
println!("foo: {:?}", f); // debug print on generated type
println!("crd: {}", serde_yaml::to_string(&Foo::crd()).unwrap()); // crd yaml
This example creates a struct Foo
containing metadata, the spec,
and optionally status. The generated type Foo
can be used with the kube
crate
as an Api<Foo>
object (FooSpec
can not be used with Api
).
let client = Client::try_default().await?;
let foos: Api<Foo> = Api::namespaced(client.clone(), "default");
let crds: Api<CustomResourceDefinition> = Api::all(client.clone());
crds.patch("foos.clux.dev", &ssapply, serde_yaml::to_vec(&Foo::crd())?).await
This example posts the generated ::crd
to the CustomResourceDefinition
API.
After this has been accepted (few secs max), you can start using foos
as a normal
kube Api
object. See the crd_
prefixed examples
for details on this.
Required properties
#[kube(group = "mygroup.tld")]
Your cr api group. The part before the slash in the top level apiVersion
key.
#[kube(version = "v1")]
Your cr api version. The part after the slash in the top level apiVersion
key.
#[kube(kind = "Kind")]
Name of your kind and your generated root type.
Optional #[kube]
attributes
#[kube(apiextensions = "v1beta1")]
The version for CustomResourceDefinition
desired in the apiextensions.k8s.io
group.
Default is v1
(for clusters >= 1.17). If using kubernetes <= 1.16 please use v1beta1
.
- NOTE: Support for
v1
requires deriving the openapi v3JsonSchema
via theschemars
dependency. - NOTE: When using
v1beta
the associatedCustomResourceExt
trait lives inkube::core::crd::v1beta
#[kube(singular = "nonstandard-singular")]
To specify the singular name. Defaults to lowercased kind
.
#[kube(plural = "nonstandard-plural")]
To specify the plural name. Defaults to inferring from singular.
#[kube(namespaced)]
To specify that this is a namespaced resource rather than cluster level.
#[kube(struct = "StructName")]
Customize the name of the generated root struct (defaults to kind
).
#[kube(kube_core = "::kube_core")]
Customize the crate name the generated code will reach into (defaults to kube::core
).
Should be one of kube::core
, kube_client::core
or kube_core
.
#[kube(status = "StatusStructName")]
Adds a status struct to the top level generated type and enables the status subresource in your crd.
#[kube(derive = "Trait")]
Adding #[kube(derive = "PartialEq")]
is required if you want your generated
top level type to be able to #[derive(PartialEq)]
#[kube(scale = r#"json"#)]
Allow customizing the scale struct for the scale subresource.
#[kube(printcolumn = r#"json"#)]
Allows adding straight json to printcolumns.
#[kube(shortname = "sn")]
Add a single shortname to the generated crd.
Example with all properties
use serde::{Serialize, Deserialize};
use kube_derive::CustomResource;
use schemars::JsonSchema;
use validator::Validate;
#[derive(CustomResource, Serialize, Deserialize, Debug, PartialEq, Clone, Validate, JsonSchema)]
#[kube(
group = "clux.dev",
version = "v1",
kind = "Foo",
struct = "FooCrd",
namespaced,
status = "FooStatus",
derive = "PartialEq",
singular = "foot",
plural = "feetz",
shortname = "f",
scale = r#"{"specReplicasPath":".spec.replicas", "statusReplicasPath":".status.replicas"}"#,
printcolumn = r#"{"name":"Spec", "type":"string", "description":"name of foo", "jsonPath":".spec.name"}"#
)]
#[serde(rename_all = "camelCase")]
struct FooSpec {
#[validate(length(min = 3))]
data: String,
replicas_count: i32
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, JsonSchema)]
struct FooStatus {
replicas: i32
}
Generated code
The example above will roughly generate:
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct FooCrd {
api_version: String,
kind: String,
metadata: ObjectMeta,
spec: FooSpec,
status: Option<FooStatus>,
}
impl kube::Resource for FooCrd {...}
impl FooCrd {
pub fn new(name: &str, spec: FooSpec) -> Self { ... }
pub fn crd() -> k8s_openapi::...::CustomResourceDefinition { ... }
}
Customizing Schemas
Should you need to customize the schemas, you can use:
- Serde/Schemars Attributes (no need to duplicate serde renames)
#[schemars(schema_with = "func")]
(e.g. like in thecrd_derive
example)impl JsonSchema
on a type / newtype around external type. See #129#[validate(...)]
field attributes with validator for kubebuilder style validation rules (seecrd_api
example))
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, so kubernetes won’t support them by default
- customizing merge-strategies (e.g. like in the
crd_derive_schema
example)
See kubernetes openapi validation for the format of the OpenAPI v3 schemas.
If you have to override a lot, you can opt-out of schema-generation entirely
Advanced Features
- embedding k8s-openapi types can be done by enabling the
schemars
feature ofk8s-openapi
from0.13.0
- adding validation via validator crate is supported from
schemars
>=0.8.5
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.
When using validator
directly, you must add it to your dependencies (with the derive
feature).
Make sure your validation rules are static and handled by schemars
:
- validations from
#[validate(custom = "some_fn")]
will not show up in the schema. - similarly; nested / must_match / credit_card were unhandled by schemars at time of writing
For sanity, you should review the generated schema before sending it to kubernetes.
Versioning
Note that any changes to your struct / validation rules / serialization attributes will require you to re-apply the generated schema to kubernetes, so that the apiserver can validate against the right version of your structs.
How to best deal with version changes has not been fully sketched out. See #569.
Debugging
Try cargo-expand
to see your own macro expansion.
Installation
Enable the derive
feature on the kube
crate:
kube = { version = "...", features = ["derive"] }
Runtime dependencies
Due to rust-lang/rust#54363, we cannot be resilient against crate renames within our generated code. It’s therefore required that you have the following crates in scope, not renamed:
serde_json
k8s_openapi
schemars
(by default, unlessschema
feature disabled)
You are ultimately responsible for maintaining the versions and feature flags of these libraries.