diff --git a/kube-core/src/metadata.rs b/kube-core/src/metadata.rs index d087d51b6..67edf6e16 100644 --- a/kube-core/src/metadata.rs +++ b/kube-core/src/metadata.rs @@ -17,6 +17,42 @@ pub struct TypeMeta { pub kind: String, } +impl TypeMeta { + /// Construct a new `TypeMeta` for the object list from the given resource. + /// + /// ``` + /// # use k8s_openapi::api::core::v1::Pod; + /// # use kube_core::TypeMeta; + /// + /// let type_meta = TypeMeta::list::(); + /// assert_eq!(type_meta.kind, "PodList"); + /// assert_eq!(type_meta.api_version, "v1"); + /// ``` + pub fn list>() -> Self { + TypeMeta { + api_version: K::api_version(&()).into(), + kind: K::kind(&()).to_string() + "List", + } + } + + /// Construct a new `TypeMeta` for the object from the given resource. + /// + /// ``` + /// # use k8s_openapi::api::core::v1::Pod; + /// # use kube_core::TypeMeta; + /// + /// let type_meta = TypeMeta::resource::(); + /// assert_eq!(type_meta.kind, "Pod"); + /// assert_eq!(type_meta.api_version, "v1"); + /// ``` + pub fn resource>() -> Self { + TypeMeta { + api_version: K::api_version(&()).into(), + kind: K::kind(&()).into(), + } + } +} + /// A generic representation of any object with `ObjectMeta`. /// /// It allows clients to get access to a particular `ObjectMeta` diff --git a/kube-core/src/object.rs b/kube-core/src/object.rs index c4e962ac6..92ef8838e 100644 --- a/kube-core/src/object.rs +++ b/kube-core/src/object.rs @@ -21,7 +21,10 @@ pub struct ObjectList where T: Clone, { - // NB: kind and apiVersion can be set here, but no need for it atm + /// The type fields, always present + #[serde(flatten, default)] + pub types: TypeMeta, + /// ListMeta - only really used for its `resourceVersion` /// /// See [ListMeta](k8s_openapi::apimachinery::pkg::apis::meta::v1::ListMeta) @@ -50,11 +53,13 @@ impl ObjectList { /// # Example /// /// ``` - /// use kube::api::{ListMeta, ObjectList}; + /// use kube::api::{ListMeta, ObjectList, TypeMeta}; + /// use k8s_openapi::api::core::v1::Pod; /// + /// let types: TypeMeta = TypeMeta::list::(); /// let metadata: ListMeta = Default::default(); /// let items = vec![1, 2, 3]; - /// let objectlist = ObjectList { metadata, items }; + /// # let objectlist = ObjectList { types, metadata, items }; /// /// let first = objectlist.iter().next(); /// println!("First element: {:?}", first); // prints "First element: Some(1)" @@ -68,11 +73,13 @@ impl ObjectList { /// # Example /// /// ``` - /// use kube::api::{ObjectList, ListMeta}; + /// use kube::api::{ListMeta, ObjectList, TypeMeta}; + /// use k8s_openapi::api::core::v1::Pod; /// + /// let types: TypeMeta = TypeMeta::list::(); /// let metadata: ListMeta = Default::default(); /// let items = vec![1, 2, 3]; - /// let mut objectlist = ObjectList { metadata, items }; + /// # let mut objectlist = ObjectList { types, metadata, items }; /// /// let mut first = objectlist.iter_mut().next(); /// @@ -300,7 +307,9 @@ pub struct NotUsed {} #[cfg(test)] mod test { - use super::{ApiResource, HasSpec, HasStatus, NotUsed, Object, Resource}; + use k8s_openapi::apimachinery::pkg::apis::meta::v1::{ObjectMeta, ListMeta}; + + use super::{ApiResource, HasSpec, HasStatus, NotUsed, Object, Resource, ObjectList, TypeMeta}; use crate::resource::ResourceExt; #[test] @@ -337,9 +346,10 @@ mod test { assert_eq!(mypod.namespace().unwrap(), "dev"); assert_eq!(mypod.name_unchecked(), "blog"); assert!(mypod.status().is_none()); - assert_eq!(mypod.spec().containers[0], ContainerSimple { - image: "blog".into() - }); + assert_eq!( + mypod.spec().containers[0], + ContainerSimple { image: "blog".into() } + ); assert_eq!(PodSimple::api_version(&ar), "v1"); assert_eq!(PodSimple::version(&ar), "v1"); @@ -347,4 +357,42 @@ mod test { assert_eq!(PodSimple::kind(&ar), "Pod"); assert_eq!(PodSimple::group(&ar), ""); } + + #[test] + fn k8s_object_list() { + use k8s_openapi::api::core::v1::Pod; + // by grabbing the ApiResource info from the Resource trait + let ar = ApiResource::erase::(&()); + assert_eq!(ar.group, ""); + assert_eq!(ar.kind, "Pod"); + let podlist: ObjectList = ObjectList { + types: TypeMeta{ + api_version: ar.api_version, + kind: ar.kind + "List", + }, + metadata: ListMeta{..Default::default()}, + items: vec![Pod { + metadata: ObjectMeta { + name: Some("test".into()), + namespace: Some("dev".into()), + ..ObjectMeta::default() + }, + spec: None, + status: None, + }], + }; + + assert_eq!(&podlist.types.kind, "PodList"); + assert_eq!(&podlist.types.api_version, "v1"); + + let mypod = &podlist.items[0]; + let meta = mypod.meta(); + assert_eq!(&mypod.metadata, meta); + assert_eq!(meta.namespace.as_ref().unwrap(), "dev"); + assert_eq!(meta.name.as_ref().unwrap(), "test"); + assert_eq!(mypod.namespace().unwrap(), "dev"); + assert_eq!(mypod.name_unchecked(), "test"); + assert!(mypod.status.is_none()); + assert!(mypod.spec.is_none()); + } } diff --git a/kube/src/mock_tests.rs b/kube/src/mock_tests.rs index 8bfbb818a..c8d7c3b0e 100644 --- a/kube/src/mock_tests.rs +++ b/kube/src/mock_tests.rs @@ -96,6 +96,8 @@ impl ApiServerVerifier { assert!(!req_uri.contains("continue=")); // first list has no continue let respdata = json!({ + "kind": "HackList", + "apiVersion": "kube.rs/v1", "metadata": { "continue": "first", }, @@ -111,6 +113,8 @@ impl ApiServerVerifier { let req_uri = request.uri().to_string(); assert!(req_uri.contains("&continue=first")); let respdata = json!({ + "kind": "HackList", + "apiVersion": "kube.rs/v1", "metadata": { "continue": "", "resourceVersion": "2"