Closed clux closed 4 years ago
For how to customise the crd, kubebuilder does this type of thing: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html - which might be applicable. But I'm not sure if you want to go that deep with it (or that string typed).
(Yeah, I haven't kept up with CRDs after the initial v1beta1. I should update the test to use v1 too...)
CustomResourceSubresources
is already defined in the crate, so it could be enough to just add the equivalent of #[serde(flatten)] sub_resources: CustomResourceSubresources
to every generated struct Foo
. If you need the status, you can deserialize it manually from the CustomResourceSubresourceStatus
's inner serde_json::Value
using its Deserializer
impl.
// Generated
struct Foo {
spec: Option<FooSpec>,
sub_resources: k8s_openapi::...::CustomResourceSubresources,
}
// Generated
impl Deserialize for Foo {
... // Foo::sub_resources's fields will be set to Some(...) if they're in the JSON
}
// User's own type
struct FooStatus {
...
}
let foo: Foo = ...;
let status: Option<FooStatus> = foo.sub_resources.status.map(|status| serde::Deserialize::deserialize(status)).transpose().unwrap();
I have a WIP implementation in https://github.com/Arnavion/k8s-openapi/compare/fix-62 It still has some work to be done, but let me know if it works for you. See the custom_resource_definition.rs
test for an example.
TODO:
I haven't updated the CRD test to v1
yet. I did add a basic sanity test to verify that the status
field is (de)serialized correctly.
Serialization currently uses unsafe
to transmute a &str
to &'static str
, because serde::ser::SerializeStruct::serialize_field
requires the key name to be a &'static str
even though a serializer shouldn't need that. serde_derive::Serialize
doesn't have this problem with #[serde(flatten)]
because it uses a separate Serializer
that wraps a SerializeStruct
. #[derive(CustomResourceDefinition)]
cannot use that particlar Serializer
because it's not public API. I'll probably have the codegen emit one just for this purpose.
Nice! I was goofing around with your library last night but am not great with proc_macro debugging. Made the following test case for it, not sure if it's meant to work like this:
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate k8s_openapi_derive;
use k8s_openapi::Resource;
#[derive(CustomResourceDefinition, Deserialize, Serialize, Clone, Debug, PartialEq)]
#[custom_resource_definition(group = "clux.dev", version = "v1", plural = "foos", namespaced, has_subresources = "v1beta1")]
pub struct FooSpec {
name: String,
info: String,
}
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct FooStatus {
is_bad: bool,
}
fn main() {
println!("Kind {}", Foo::KIND);
let mut foo = Foo::default();
foo.status = Some(FooStatus { is_bad: true });
}
ultimately fails whenever i set the new arg to anything. posted an error on the commit.
One tangential suggestion; you can omit the plural
arg. You can get the plural value via to_plural(K::KIND.to_ascii_lowercase())
via inflector::string::pluralize
.
We rely on this in kube already because that information is not passed through the k8s_openapi::Resource
trait.
Tested with this diff:
diff --git a/kube/Cargo.toml b/kube/Cargo.toml
index a562f98..6bb3500 100644
--- a/kube/Cargo.toml
+++ b/kube/Cargo.toml
@@ -42,6 +42,8 @@ features = ["json", "gzip", "stream"]
[dependencies.k8s-openapi]
version = "0.7.1"
+git = "https://github.com/Arnavion/k8s-openapi"
+rev = "cf1062a5def77f111179c40a8d73424e66f95aa3"
default-features = false
features = []
@@ -55,9 +57,16 @@ tempfile = "3.1.0"
env_logger = "0.7.1"
tokio = { version = "0.2.11", features = ["full"] }
anyhow = "1.0.26"
-k8s-openapi-derive = "0.7.1"
+k8s-openapi-derive = { git = "https://github.com/Arnavion/k8s-openapi", rev = "cf1062a5def77f111179c40a8d73424e66f95aa3" }
[dev-dependencies.k8s-openapi]
-version = "0.7.1"
+#version = "0.7.1"
+git = "https://github.com/Arnavion/k8s-openapi"
+rev = "cf1062a5def77f111179c40a8d73424e66f95aa3"
default-features = false
features = ["v1_17"]
+
+[dev-dependencies.k8s-openapi-codegen-common]
+#version = "0.7.1"
+git = "https://github.com/Arnavion/k8s-openapi"
+rev = "cf1062a5def77f111179c40a8d73424e66f95aa3"
diff --git a/kube/examples/crd_derive.rs b/kube/examples/crd_derive.rs
new file mode 100644
index 0000000..8883fe4
--- /dev/null
+++ b/kube/examples/crd_derive.rs
@@ -0,0 +1,23 @@
+#[macro_use] extern crate serde_derive;
+#[macro_use] extern crate k8s_openapi_derive;
+use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceSubresourceStatus;
+use k8s_openapi::Resource;
+
+#[derive(CustomResourceDefinition, Deserialize, Serialize, Clone, Debug, PartialEq)]
+#[custom_resource_definition(group = "clux.dev", version = "v1", plural = "foos", namespaced, has_subresources = "v1")]
+pub struct FooSpec {
+ name: String,
+ info: String,
+}
+
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
+pub struct FooStatus {
+ is_bad: bool,
+}
+
+fn main() {
+ println!("Kind {}", Foo::KIND);
+ let mut foo = Foo::default();
+ //foo.subresources.status = Some(CustomResourceSubresourceStatus(serde_json::Value));
+ foo.status = Some(FooStatus { is_bad: true });
+}
So it does something with status now. It constructs the foo.subresources.status field, which appear to be an Option<CustomResourceSubresourceStatus<Value>>
which isn't super helpful.
The raw foo.status
does not exist. I don't think you can use flatten
straight on the hidden root object, that causes the unexpected nesting for users.
Ok, sorry, this works:
let status = serde_json::to_value(FooStatus { is_bad: true }).unwrap();
foo.subresources.status = Some(CustomResourceSubresourceStatus(status));
println!("Foo: {:?}", foo)
which creates this output:
Kind Foo
Foo: Foo { metadata: None, spec: None, subresources: CustomResourceSubresources { scale: None, status: Some(CustomResourceSubresourceStatus(Object({"is_bad": Bool(true)}))) } }
Yes, and then if you serialize foo
to JSON you'll see the fields of subresources
getting flattened into the main object, like they should be.
Hello again! Trying out the very nifty k8s-openapi-derive crate now :-)
Currently the
#[derive(CustomResourceDefinition)]
expects aFooSpec
struct to then attach inside aFoo
struct. But AFAIK, there's no way to attach aFooStatus
struct, so we could accessFoo::status
fields.E.g.
This would also require the subresources (in the crd spec) enabled to work, but can't get far enough for that to matter atm.