From b0c67947c368eaee3e4ba2d32d693327d5748de3 Mon Sep 17 00:00:00 2001 From: Eirik A Date: Thu, 20 Jul 2023 20:36:34 +0100 Subject: [PATCH] dynamic_watcher example: show how to use dynamic type information at loop level (#1258) dynamic_watcher example: show how to grab type information common question Signed-off-by: clux --- examples/dynamic_watcher.rs | 15 ++++++++------ kube-core/src/params.rs | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/examples/dynamic_watcher.rs b/examples/dynamic_watcher.rs index ec2ff5944..9ab6753c6 100644 --- a/examples/dynamic_watcher.rs +++ b/examples/dynamic_watcher.rs @@ -1,6 +1,6 @@ use futures::{Stream, StreamExt, TryStreamExt}; use kube::{ - api::{Api, DynamicObject, GroupVersionKind, Resource, ResourceExt}, + api::{Api, ApiResource, DynamicObject, GroupVersionKind, Resource, ResourceExt}, runtime::{metadata_watcher, watcher, watcher::Event, WatchStreamExt}, }; use serde::de::DeserializeOwned; @@ -32,21 +32,24 @@ async fn main() -> anyhow::Result<()> { // Start a metadata or a full resource watch if watch_metadata { - handle_events(metadata_watcher(api, wc)).await + handle_events(metadata_watcher(api, wc), &ar).await } else { - handle_events(watcher(api, wc)).await + handle_events(watcher(api, wc), &ar).await } } -async fn handle_events( +async fn handle_events< + K: Resource + Clone + Debug + Send + DeserializeOwned + 'static, +>( stream: impl Stream>> + Send + 'static, + ar: &ApiResource, ) -> anyhow::Result<()> { let mut items = stream.applied_objects().boxed(); while let Some(p) = items.try_next().await? { if let Some(ns) = p.namespace() { - info!("saw {} in {ns}", p.name_any()); + info!("saw {} {} in {ns}", K::kind(ar), p.name_any()); } else { - info!("saw {}", p.name_any()); + info!("saw {} {}", K::kind(ar), p.name_any()); } trace!("full obj: {p:?}"); } diff --git a/kube-core/src/params.rs b/kube-core/src/params.rs index 93d333f19..7cd93c2b2 100644 --- a/kube-core/src/params.rs +++ b/kube-core/src/params.rs @@ -444,6 +444,8 @@ impl PostParams { /// /// See [kubernetes patch docs](https://kubernetes.io/docs/tasks/run-application/update-api-object-kubectl-patch/#use-a-json-merge-patch-to-update-a-deployment) for the older patch types. /// +/// Note that applying an invalid patch will **not** always return an error. See an example of such a case below. +/// /// Note that patches have different effects on different fields depending on their merge strategies. /// These strategies are configurable when deriving your [`CustomResource`](https://docs.rs/kube-derive/*/kube_derive/derive.CustomResource.html#customizing-schemas). /// @@ -473,6 +475,44 @@ impl PostParams { /// }; /// let patch = Patch::Apply(&r); /// ``` +/// # Invalid Patches +/// +/// In this example patch contains a `PodSpec` and **not** a complete or partial `Pod`. +/// This patch is invalid as the full structure of a resource is required. +/// The invalid patch will be accepted by the cluster, but no changes will be made. +/// +/// Using serve-side style [`Apply`](Patch::Apply) patches mitigates this issue. +/// +/// ```no_run +/// use k8s_openapi::api::core::v1::{Pod, PodSpec}; +/// use kube::{Api, api::{PatchParams, Patch}}; +/// +/// # async fn wrapper() -> Result<(), Box> { +/// # let client = kube::Client::try_default().await?; +/// let pods: Api = Api::namespaced(client, "apps"); +/// let pp = PatchParams::default(); +/// +/// let invalid_patch: PodSpec = serde_json::from_value(serde_json::json!({ +/// "activeDeadlineSeconds": 5 +/// }))?; +/// +/// // This will have no effect on mypod. +/// pods.patch("mypod", &pp, &Patch::Strategic(invalid_patch)).await?; +/// +/// let valid_patch: Pod = serde_json::from_value(serde_json::json!({ +/// "spec": { +/// "activeDeadlineSeconds": 5 +/// } +/// }))?; +/// +/// // This will set activeDeadlineSeconds to 5. +/// pods.patch("mypod", &pp, &Patch::Strategic(valid_patch)).await?; +/// +/// # Ok(()) +/// # } +/// ``` +/// +/// #[non_exhaustive] #[derive(Debug, PartialEq, Clone)] pub enum Patch {