From 52e4392617dc1a0d88b0f33278343bea19d9f39e Mon Sep 17 00:00:00 2001 From: Eirik A Date: Mon, 9 Sep 2024 09:32:16 +0100 Subject: [PATCH] Doc tweaks and 2 missing impls pre release (#1573) * Doc tweaks and 2 missing impls pre release Mostly doc stuff that was inconsistent or looked unprofessional. In particular, the lib re-export ones now seem to concatenate the docstrings, so have made these cleaner on both end. Cleaned up the cert check example a little bit to more showcase the problem. Missing impls: - Derive + Clone on marker `Namespace` and `Cluster` for unstable client_ext Signed-off-by: clux * redundant word Signed-off-by: clux * more missing links Signed-off-by: clux --------- Signed-off-by: clux --- examples/README.md | 5 +- examples/cert_check.rs | 70 +++++++++------------------- kube-client/src/client/client_ext.rs | 2 + kube-client/src/client/mod.rs | 2 +- kube-client/src/config/mod.rs | 5 +- kube-core/src/lib.rs | 2 +- kube-derive/src/lib.rs | 13 ++++-- kube/src/lib.rs | 10 ++-- 8 files changed, 45 insertions(+), 64 deletions(-) diff --git a/examples/README.md b/examples/README.md index e672bd203..21fe1ef5c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -69,11 +69,10 @@ cargo run --example crd_api cargo run --example crd_derive cargo run --example crd_derive_schema cargo run --example crd_derive_no_schema --no-default-features --features=openssl-tls,latest -# collect kube-root configmaps from each namespace, with strictly typed serialization on ca.crt key -cargo run --example cert_check +cargo run --example cert_check # showcases partial typing with Resource derive ``` -The last one opts out from the default `schema` feature from `kube-derive` (and thus the need for you to derive/impl `JsonSchema`). +The `no_schema` one opts out from the default `schema` feature from `kube-derive` (and thus the need for you to derive/impl `JsonSchema`). **However**: without the `schema` feature, it's left **up to you to fill in a valid openapi v3 schema**, as schemas are **required** for [v1::CustomResourceDefinitions](https://docs.rs/k8s-openapi/0.10.0/k8s_openapi/apiextensions_apiserver/pkg/apis/apiextensions/v1/struct.CustomResourceDefinition.html), and the generated crd will be rejected by the apiserver if it's missing. As the last example shows, you can do this directly without `schemars`. diff --git a/examples/cert_check.rs b/examples/cert_check.rs index 0df692293..99295d225 100644 --- a/examples/cert_check.rs +++ b/examples/cert_check.rs @@ -7,41 +7,20 @@ use k8s_openapi::{ use kube::{ api::ObjectMeta, client::scope::{Cluster, Namespace}, - Client, Resource, ResourceExt, + Client, Resource, }; use serde::{Deserialize, Serialize}; use tracing::*; -use thiserror::Error; - -#[derive(Debug, Error)] -enum Error { - #[error("Failed to open client: {0}")] - ClientSetup(#[source] kube::Error), - #[error("Failed to list namespaces: {0}")] - NamespaceList(#[source] kube::Error), - #[error("Failed to get ConfigMap: {0}")] - FetchFailed(#[from] kube::Error), - #[error("Expected certificate key in ConfigMap: {0}")] - MissingKey(#[from] serde_json::Error), -} - -// Variant of ConfigMap that only accepts ConfigMaps with a CA certificate -// to demonstrate manual implementation -#[derive(Serialize, Deserialize, Debug, Clone)] -struct CaConfigMapManual { - metadata: ObjectMeta, - data: CaConfigMapData, -} - +// Our own way of representing data - partially typed in 2 ways +// For a ConfigMap variant that only accepts CA certificates #[derive(Serialize, Deserialize, Debug, Clone)] struct CaConfigMapData { #[serde(rename = "ca.crt")] ca_crt: String, } -// Variant of ConfigMap that only accepts ConfigMaps with a CA certificate -// with inherited resource implementation +// Method 1 :: inherit resource implementation from k8s_openapi's ConfigMap #[derive(Resource, Serialize, Deserialize, Debug, Clone)] #[resource(inherit = ConfigMap)] struct CaConfigMap { @@ -49,7 +28,13 @@ struct CaConfigMap { data: CaConfigMapData, } -// Display of a manual implementation +// Method 2 :: manual Resource implementation +#[derive(Serialize, Deserialize, Debug, Clone)] +struct CaConfigMapManual { + metadata: ObjectMeta, + data: CaConfigMapData, +} +// Method 2 :: manual Resource implementation impl Resource for CaConfigMapManual { type DynamicType = (); type Scope = NamespaceResourceScope; @@ -79,33 +64,24 @@ impl Resource for CaConfigMapManual { } } - #[tokio::main] -async fn main() -> Result<(), Error> { +async fn main() -> anyhow::Result<()> { tracing_subscriber::fmt::init(); - let client = Client::try_default().await.map_err(Error::ClientSetup)?; - let namespaces = client - .list::(&Default::default(), &Cluster) - .await - .map_err(Error::NamespaceList)?; + let client = Client::try_default().await?; + let namespaces = client.list::(&Default::default(), &Cluster).await?; + let kube_root = "kube-root-ca.crt"; for ns in namespaces { + let ns = Namespace::try_from(&ns)?; // Equivalent ways to GET using different structs and different Resource impls, with added field validation on top. - let _ca: ConfigMap = client - .get("kube-root-ca.crt", &Namespace::from(ns.name_any())) - .await?; - let _ca: CaConfigMapManual = client - .get("kube-root-ca.crt", &Namespace::from(ns.name_any())) - .await?; - let ca: CaConfigMap = client - .get("kube-root-ca.crt", &Namespace::from(ns.name_any())) - .await?; - info!( - "Found correct root ca config map in {}: {}", - ns.name_any(), - ca.name_any() - ); + let ca1: ConfigMap = client.get(kube_root, &ns).await?; + let ca2: CaConfigMapManual = client.get(kube_root, &ns).await?; + let ca3: CaConfigMap = client.get(kube_root, &ns).await?; + info!("Found {kube_root} in {ns:?} with all 3 methods"); + debug!("ca1: {ca1:?}"); + debug!("ca2: {ca2:?}"); + debug!("ca3: {ca3:?}"); } Ok(()) diff --git a/kube-client/src/client/client_ext.rs b/kube-client/src/client/client_ext.rs index 74ff5fd0d..f0de2f5b2 100644 --- a/kube-client/src/client/client_ext.rs +++ b/kube-client/src/client/client_ext.rs @@ -39,10 +39,12 @@ pub trait ObjectUrl { } /// Marker type for cluster level queries +#[derive(Debug, Clone)] pub struct Cluster; /// Namespace newtype for namespace level queries /// /// You can create this directly, or convert `From` a `String` / `&str`, or `TryFrom` an `k8s_openapi::api::core::v1::Namespace` +#[derive(Debug, Clone)] pub struct Namespace(String); /// Referenced object name resolution diff --git a/kube-client/src/client/mod.rs b/kube-client/src/client/mod.rs index 6b65e0941..768a06100 100644 --- a/kube-client/src/client/mod.rs +++ b/kube-client/src/client/mod.rs @@ -1,4 +1,4 @@ -//! A basic API client for interacting with the Kubernetes API +//! API client for interacting with the Kubernetes API //! //! The [`Client`] uses standard kube error handling. //! diff --git a/kube-client/src/config/mod.rs b/kube-client/src/config/mod.rs index d7c891a23..a55c3e03f 100644 --- a/kube-client/src/config/mod.rs +++ b/kube-client/src/config/mod.rs @@ -118,7 +118,10 @@ pub enum LoadDataError { NoBase64DataOrFile, } -/// Configuration object detailing things like cluster URL, default namespace, root certificates, and timeouts. +/// Configuration object for accessing a Kuernetes cluster +/// +/// The configurable parameters for connecting like cluster URL, default namespace, root certificates, and timeouts. +/// Normally created implicitly through [`Config::infer`] or [`Client::try_default`](crate::Client::try_default). /// /// # Usage /// Construct a [`Config`] instance by using one of the many constructors. diff --git a/kube-core/src/lib.rs b/kube-core/src/lib.rs index 5a5492b48..969d10e0a 100644 --- a/kube-core/src/lib.rs +++ b/kube-core/src/lib.rs @@ -1,4 +1,4 @@ -//! Crate with types and traits necessary for interacting with the Kubernetes API +//! Types and traits necessary for interacting with the Kubernetes API //! //! This crate provides the minimal apimachinery necessary to make requests to the kubernetes API. //! diff --git a/kube-derive/src/lib.rs b/kube-derive/src/lib.rs index 0c59066cc..c24b4a92e 100644 --- a/kube-derive/src/lib.rs +++ b/kube-derive/src/lib.rs @@ -312,13 +312,13 @@ pub fn derive_custom_resource(input: proc_macro::TokenStream) -> proc_macro::Tok /// A custom derive for inheriting Resource impl for the type. /// -/// This will generate a [`kube::Resource`] trait implementation, which inherits the specified -/// resources trait implementation. +/// This will generate a [`kube::Resource`] trait implementation, +/// inheriting from a specified resource trait implementation. /// -/// Such implementation allows to add strict typing to some typical resources like `Secret` or `ConfigMap`, +/// This allows strict typing to some typical resources like `Secret` or `ConfigMap`, /// in cases when implementing CRD is not desirable or it does not fit the use-case. /// -/// This object can be used with [`kube::Api`]. +/// Once derived, the type can be used with [`kube::Api`]. /// /// # Example /// @@ -351,6 +351,11 @@ pub fn derive_custom_resource(input: proc_macro::TokenStream) -> proc_macro::Tok /// ``` /// // impl kube::Resource for FooMap { .. } /// ``` +/// [`kube`]: https://docs.rs/kube +/// [`kube::Api`]: https://docs.rs/kube/*/kube/struct.Api.html +/// [`kube::Resource`]: https://docs.rs/kube/*/kube/trait.Resource.html +/// [`kube::core::ApiResource`]: https://docs.rs/kube/*/kube/core/struct.ApiResource.html +/// [`kube::CustomResourceExt`]: https://docs.rs/kube/*/kube/trait.CustomResourceExt.html #[proc_macro_derive(Resource, attributes(resource))] pub fn derive_resource(input: proc_macro::TokenStream) -> proc_macro::TokenStream { resource::derive(proc_macro2::TokenStream::from(input)).into() diff --git a/kube/src/lib.rs b/kube/src/lib.rs index 73c3fd47e..e7be35690 100644 --- a/kube/src/lib.rs +++ b/kube/src/lib.rs @@ -10,7 +10,7 @@ //! - [`client`] with the Kubernetes [`Client`] and its layers //! - [`config`] for cluster [`Config`] //! - [`api`] with the generic Kubernetes [`Api`] -//! - [`derive`](kube_derive) with the [`CustomResource`] derive for building controllers types +//! - [`derive`](kube_derive) with the [`CustomResource`] / [`Resource`](kube_derive::Resource) derive for building controllers types //! - [`runtime`] with a [`Controller`](crate::runtime::Controller) / [`watcher`](crate::runtime::watcher()) / [`reflector`](crate::runtime::reflector::reflector) / [`Store`](crate::runtime::reflector::Store) //! - [`core`] with generics from `apimachinery` //! @@ -160,7 +160,6 @@ cfg_error! { pub type Result = std::result::Result; } -/// Re-exports from [`kube-derive`](kube_derive) #[cfg(feature = "derive")] #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub use kube_derive::CustomResource; @@ -169,16 +168,13 @@ pub use kube_derive::CustomResource; #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub use kube_derive::Resource; -/// Re-exports from `kube-runtime` #[cfg(feature = "runtime")] #[cfg_attr(docsrs, doc(cfg(feature = "runtime")))] #[doc(inline)] pub use kube_runtime as runtime; pub use crate::core::{CustomResourceExt, Resource, ResourceExt}; -/// Re-exports from `kube_core` -#[doc(inline)] -pub use kube_core as core; +#[doc(inline)] pub use kube_core as core; // Mock tests for the runtime #[cfg(test)] @@ -186,7 +182,7 @@ pub use kube_core as core; mod mock_tests; pub mod prelude { - //! A "prelude" for kube client crate. Reduces the number of duplicated imports. + //! A prelude for kube. Reduces the number of duplicated imports. //! //! This prelude is similar to the standard library's prelude in that you'll //! almost always want to import its entire contents, but unlike the