diff --git a/kube-client/src/api/mod.rs b/kube-client/src/api/mod.rs index 24088e71a..cf814fd98 100644 --- a/kube-client/src/api/mod.rs +++ b/kube-client/src/api/mod.rs @@ -37,7 +37,7 @@ pub use kube_core::{ watch::WatchEvent, Resource, ResourceExt, }; -use kube_core::{DynamicResourceScope, NamespaceResourceScope}; +use kube_core::{resource, DynamicResourceScope, NamespaceResourceScope}; pub use params::{ DeleteParams, GetParams, ListParams, Patch, PatchParams, PostParams, Preconditions, PropagationPolicy, ValidationDirective, VersionMatch, WatchParams, @@ -66,7 +66,7 @@ pub struct Api<K> { /// Api constructors for Resource implementors with custom DynamicTypes /// /// This generally means resources created via [`DynamicObject`](crate::api::DynamicObject). -impl<K: Resource> Api<K> { +impl<K: resource::Typed> Api<K> { /// Cluster level resources, or resources viewed across all namespaces /// /// This function accepts `K::DynamicType` so it can be used with dynamic resources. @@ -131,9 +131,9 @@ impl<K: Resource> Api<K> { /// Api constructors for Resource implementors with Default DynamicTypes /// /// This generally means structs implementing `k8s_openapi::Resource`. -impl<K: Resource> Api<K> +impl<K: resource::Typed> Api<K> where - <K as Resource>::DynamicType: Default, + <K as resource::Typed>::DynamicType: Default, { /// Cluster level resources, or resources viewed across all namespaces /// diff --git a/kube-client/src/client/client_ext.rs b/kube-client/src/client/client_ext.rs index 48704ea07..da1b86bcc 100644 --- a/kube-client/src/client/client_ext.rs +++ b/kube-client/src/client/client_ext.rs @@ -1,10 +1,7 @@ use crate::{Client, Error, Result}; use k8s_openapi::api::core::v1::Namespace as k8sNs; use kube_core::{ - object::ObjectList, - params::{GetParams, ListParams}, - request::Request, - ClusterResourceScope, DynamicResourceScope, NamespaceResourceScope, Resource, + object::ObjectList, params::{GetParams, ListParams}, request::Request, resource, ClusterResourceScope, DynamicResourceScope, NamespaceResourceScope, Resource }; use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; @@ -174,8 +171,8 @@ impl Client { /// ``` pub async fn get<K>(&self, name: &str, scope: &impl ObjectUrl<K>) -> Result<K> where - K: Resource + Serialize + DeserializeOwned + Clone + Debug, - <K as Resource>::DynamicType: Default, + K: resource::Typed + Serialize + DeserializeOwned + Clone + Debug, + <K as resource::Typed>::DynamicType: Default, { let mut req = Request::new(scope.url_path()) .get(name, &GetParams::default()) @@ -184,7 +181,7 @@ impl Client { self.request::<K>(req).await } - /// List instances of a `Resource` implementing type `K` at the specified scope. + /// List instances of a [resource](resource::Typed) implementing type `K` at the specified scope. /// /// ```no_run /// # use k8s_openapi::api::core::v1::Pod; @@ -205,8 +202,8 @@ impl Client { /// ``` pub async fn list<K>(&self, lp: &ListParams, scope: &impl CollectionUrl<K>) -> Result<ObjectList<K>> where - K: Resource + Serialize + DeserializeOwned + Clone + Debug, - <K as Resource>::DynamicType: Default, + K: resource::Typed + Serialize + DeserializeOwned + Clone + Debug, + <K as resource::Typed>::DynamicType: Default, { let mut req = Request::new(scope.url_path()) .list(lp) diff --git a/kube-core/src/dynamic.rs b/kube-core/src/dynamic.rs index ebaa7e3a6..78c14bad7 100644 --- a/kube-core/src/dynamic.rs +++ b/kube-core/src/dynamic.rs @@ -4,7 +4,7 @@ pub use crate::discovery::ApiResource; use crate::{ metadata::TypeMeta, - resource::{DynamicResourceScope, Resource}, + resource::{self, DynamicResourceScope, Resource}, }; use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta; @@ -75,7 +75,7 @@ impl DynamicObject { } } -impl Resource for DynamicObject { +impl resource::Typed for DynamicObject { type DynamicType = ApiResource; type Scope = DynamicResourceScope; @@ -98,7 +98,9 @@ impl Resource for DynamicObject { fn plural(dt: &ApiResource) -> Cow<'_, str> { dt.plural.as_str().into() } +} +impl Resource for DynamicObject { fn meta(&self) -> &ObjectMeta { &self.metadata } diff --git a/kube-core/src/lib.rs b/kube-core/src/lib.rs index 4e87ed752..2a64049b0 100644 --- a/kube-core/src/lib.rs +++ b/kube-core/src/lib.rs @@ -41,7 +41,7 @@ pub mod params; pub mod request; pub use request::Request; -mod resource; +pub mod resource; pub use resource::{ api_version_from_group_version, ClusterResourceScope, DynamicResourceScope, NamespaceResourceScope, Resource, ResourceExt, ResourceScope, SubResourceScope, diff --git a/kube-core/src/metadata.rs b/kube-core/src/metadata.rs index 67edf6e16..79db7896b 100644 --- a/kube-core/src/metadata.rs +++ b/kube-core/src/metadata.rs @@ -4,7 +4,7 @@ use std::{borrow::Cow, marker::PhantomData}; pub use k8s_openapi::apimachinery::pkg::apis::meta::v1::{ListMeta, ObjectMeta}; use serde::{Deserialize, Serialize}; -use crate::{DynamicObject, Resource}; +use crate::{resource, DynamicObject, Resource}; /// Type information that is flattened into every kubernetes object #[derive(Deserialize, Serialize, Clone, Default, Debug, Eq, PartialEq, Hash)] @@ -146,7 +146,7 @@ impl PartialObjectMetaExt for ObjectMeta { } } -impl<K: Resource> Resource for PartialObjectMeta<K> { +impl<K: resource::Typed> resource::Typed for PartialObjectMeta<K> { type DynamicType = K::DynamicType; type Scope = K::Scope; @@ -165,7 +165,9 @@ impl<K: Resource> Resource for PartialObjectMeta<K> { fn plural(dt: &Self::DynamicType) -> Cow<'_, str> { K::plural(dt) } +} +impl<K: Resource> Resource for PartialObjectMeta<K> { fn meta(&self) -> &ObjectMeta { &self.metadata } diff --git a/kube-core/src/object.rs b/kube-core/src/object.rs index 2e51b3f64..847bbe5cd 100644 --- a/kube-core/src/object.rs +++ b/kube-core/src/object.rs @@ -2,7 +2,7 @@ use crate::{ discovery::ApiResource, metadata::{ListMeta, ObjectMeta, TypeMeta}, - resource::{DynamicResourceScope, Resource}, + resource::{self, DynamicResourceScope, Resource}, }; use serde::{Deserialize, Deserializer, Serialize}; use std::borrow::Cow; @@ -241,7 +241,7 @@ where } } -impl<P, U> Resource for Object<P, U> +impl<P, U> resource::Typed for Object<P, U> where P: Clone, U: Clone, @@ -268,7 +268,13 @@ where fn api_version(dt: &ApiResource) -> Cow<'_, str> { dt.api_version.as_str().into() } +} +impl<P, U> Resource for Object<P, U> +where + P: Clone, + U: Clone, +{ fn meta(&self) -> &ObjectMeta { &self.metadata } diff --git a/kube-core/src/resource.rs b/kube-core/src/resource.rs index 3ab1d88df..17b9ac8b6 100644 --- a/kube-core/src/resource.rs +++ b/kube-core/src/resource.rs @@ -1,3 +1,5 @@ +//! Types representing Kubernetes resource objects. + pub use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta; use k8s_openapi::{ api::core::v1::ObjectReference, @@ -12,19 +14,9 @@ pub use k8s_openapi::{ClusterResourceScope, NamespaceResourceScope, ResourceScop pub struct DynamicResourceScope {} impl ResourceScope for DynamicResourceScope {} -/// An accessor trait for a kubernetes Resource. -/// -/// This is for a subset of Kubernetes type that do not end in `List`. -/// These types, using [`ObjectMeta`], SHOULD all have required properties: -/// - `.metadata` -/// - `.metadata.name` -/// -/// And these optional properties: -/// - `.metadata.namespace` -/// - `.metadata.resource_version` -/// -/// This avoids a bunch of the unnecessary unwrap mechanics for apps. -pub trait Resource { +/// Represents a type that can either statically imply a Kubernetes versioned resource type +/// or resolve into one given specific data. +pub trait Typed { /// Type information for types that do not know their resource information at compile time. /// /// Types that know their metadata at compile time should select `DynamicType = ()`. @@ -72,7 +64,21 @@ pub trait Resource { plural = plural ) } +} +/// An accessor trait for a kubernetes Resource. +/// +/// This is for a subset of Kubernetes type that do not end in `List`. +/// These types, using [`ObjectMeta`], SHOULD all have required properties: +/// - `.metadata` +/// - `.metadata.name` +/// +/// And these optional properties: +/// - `.metadata.namespace` +/// - `.metadata.resource_version` +/// +/// This avoids a bunch of the unnecessary unwrap mechanics for apps. +pub trait Resource: Typed { /// Metadata that all persisted resources must have fn meta(&self) -> &ObjectMeta; /// Metadata that all persisted resources must have @@ -166,8 +172,7 @@ pub fn api_version_from_group_version<'a>(group: Cow<'a, str>, version: Cow<'a, output } -/// Implement accessor trait for any ObjectMeta-using Kubernetes Resource -impl<K, S> Resource for K +impl<K, S> Typed for K where K: k8s_openapi::Metadata<Ty = ObjectMeta>, K: k8s_openapi::Resource<Scope = S>, @@ -194,7 +199,14 @@ where fn plural(_: &()) -> Cow<'_, str> { K::URL_PATH_SEGMENT.into() } +} +/// Implement accessor trait for any ObjectMeta-using Kubernetes Resource +impl<K, S> Resource for K +where + K: k8s_openapi::Metadata<Ty = ObjectMeta>, + K: k8s_openapi::Resource<Scope = S>, +{ fn meta(&self) -> &ObjectMeta { self.metadata() } diff --git a/kube-runtime/src/controller/mod.rs b/kube-runtime/src/controller/mod.rs index 5c36b38e7..9dd2d2efe 100644 --- a/kube-runtime/src/controller/mod.rs +++ b/kube-runtime/src/controller/mod.rs @@ -18,7 +18,7 @@ use futures::{ future::{self, BoxFuture}, stream, FutureExt, Stream, StreamExt, TryFuture, TryFutureExt, TryStream, TryStreamExt, }; -use kube_client::api::{Api, DynamicObject, Resource}; +use kube_client::{api::{Api, DynamicObject, Resource}, core::resource}; use pin_project::pin_project; use serde::de::DeserializeOwned; use std::{ @@ -149,13 +149,13 @@ where fn trigger_others<S, K, I>( stream: S, mapper: impl Fn(S::Ok) -> I + Sync + Send + 'static, - dyntype: <S::Ok as Resource>::DynamicType, + dyntype: <S::Ok as resource::Typed>::DynamicType, ) -> impl Stream<Item = Result<ReconcileRequest<K>, S::Error>> where // Input stream has items as some Resource (via Controller::watches) S: TryStream, S::Ok: Resource, - <S::Ok as Resource>::DynamicType: Clone, + <S::Ok as resource::Typed>::DynamicType: Clone, // Output stream is requests for the root type K K: Resource, K::DynamicType: Clone, @@ -212,12 +212,12 @@ where pub fn trigger_owners<KOwner, S>( stream: S, owner_type: KOwner::DynamicType, - child_type: <S::Ok as Resource>::DynamicType, + child_type: <S::Ok as resource::Typed>::DynamicType, ) -> impl Stream<Item = Result<ReconcileRequest<KOwner>, S::Error>> where S: TryStream, S::Ok: Resource, - <S::Ok as Resource>::DynamicType: Clone, + <S::Ok as resource::Typed>::DynamicType: Clone, KOwner: Resource, KOwner::DynamicType: Clone, {