Skip to content

Commit 7dc2e33

Browse files
committed
add resize subresource for Pods
Implement the resize subresource for Kubernetes Pods as specified in GitHub issue #1793. The resize subresource allows changing resource requirements (CPU/memory limits and requests) for containers in running pods, available in Kubernetes 1.33+. Changes: - Add Request::resize method in kube-core for PATCH requests to /resize endpoint - Add Resize marker trait and Api::resize method in kube-client with k8s_if_ge_1_33 version gating - Include test for resize URL construction - Add pod_resize example demonstrating usage with resource limit modifications Closes #1793 Signed-off-by: Krishna Ketan Rai <[email protected]>
1 parent aaf6bac commit 7dc2e33

File tree

4 files changed

+166
-0
lines changed

4 files changed

+166
-0
lines changed

examples/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,8 @@ path = "secret_syncer.rs"
236236
name = "pod_shell_crossterm"
237237
path = "pod_shell_crossterm.rs"
238238
required-features = ["ws"]
239+
240+
[[example]]
241+
name = "pod_resize"
242+
path = "pod_resize.rs"
243+
required-features = ["latest"]

examples/pod_resize.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use k8s_openapi::api::core::v1::Pod;
2+
use kube::{
3+
api::{Api, PostParams, ResourceExt},
4+
Client, Result,
5+
};
6+
7+
#[tokio::main]
8+
async fn main() -> Result<()> {
9+
unsafe { std::env::set_var("RUST_LOG", "info,kube=debug"); }
10+
tracing_subscriber::fmt::init();
11+
let client = Client::try_default().await?;
12+
13+
let name = std::env::args()
14+
.nth(1)
15+
.expect("Usage: cargo run --bin pod_resize <pod-name>");
16+
17+
let pods: Api<Pod> = Api::default_namespaced(client);
18+
19+
// Resize is only available in Kubernetes 1.33+
20+
k8s_openapi::k8s_if_ge_1_33! {
21+
tracing::info!("Resizing pod {}", name);
22+
23+
// Get the current pod
24+
let mut pod = pods.get(&name).await?;
25+
tracing::info!("Current pod: {}", pod.name_any());
26+
27+
// Modify the pod's resource requirements
28+
if let Some(ref mut spec) = pod.spec {
29+
if let Some(container) = spec.containers.get_mut(0) {
30+
// Example: Update CPU and memory limits
31+
if container.resources.is_none() {
32+
container.resources = Some(Default::default());
33+
}
34+
if let Some(ref mut resources) = container.resources {
35+
use k8s_openapi::apimachinery::pkg::api::resource::Quantity;
36+
use std::collections::BTreeMap;
37+
38+
// Set new resource limits
39+
let mut limits = BTreeMap::new();
40+
limits.insert("cpu".to_string(), Quantity("500m".to_string()));
41+
limits.insert("memory".to_string(), Quantity("256Mi".to_string()));
42+
resources.limits = Some(limits);
43+
44+
// Set new resource requests
45+
let mut requests = BTreeMap::new();
46+
requests.insert("cpu".to_string(), Quantity("250m".to_string()));
47+
requests.insert("memory".to_string(), Quantity("128Mi".to_string()));
48+
resources.requests = Some(requests);
49+
}
50+
}
51+
}
52+
53+
// Apply the resize
54+
let pp = PostParams::default();
55+
let updated_pod = pods.resize(&name, &pp, &pod).await?;
56+
tracing::info!("Pod resized successfully: {}", updated_pod.name_any());
57+
58+
if let Some(ref spec) = updated_pod.spec {
59+
if let Some(container) = spec.containers.get(0) {
60+
if let Some(ref resources) = container.resources {
61+
tracing::info!("New limits: {:?}", resources.limits);
62+
tracing::info!("New requests: {:?}", resources.requests);
63+
}
64+
}
65+
}
66+
}
67+
68+
Ok(())
69+
}

kube-client/src/api/subresource.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,3 +610,78 @@ where
610610
Ok(Portforwarder::new(connection.into_stream(), ports))
611611
}
612612
}
613+
614+
// ----------------------------------------------------------------------------
615+
// Resize subresource
616+
// ----------------------------------------------------------------------------
617+
618+
#[test]
619+
fn resize_path() {
620+
k8s_openapi::k8s_if_ge_1_33! {
621+
use kube_core::{request::Request, Resource, params::PostParams};
622+
use k8s_openapi::api::core::v1 as corev1;
623+
let pp = PostParams::default();
624+
let url = corev1::Pod::url_path(&(), Some("ns"));
625+
let req = Request::new(url).resize("foo", vec![], &pp).unwrap();
626+
assert_eq!(req.uri(), "/api/v1/namespaces/ns/pods/foo/resize?");
627+
}
628+
}
629+
630+
/// Marker trait for objects that can be resized
631+
///
632+
/// See [`Api::resize`] for usage
633+
pub trait Resize {}
634+
635+
k8s_openapi::k8s_if_ge_1_33! {
636+
impl Resize for k8s_openapi::api::core::v1::Pod {}
637+
}
638+
639+
impl<K> Api<K>
640+
where
641+
K: DeserializeOwned + Resize,
642+
{
643+
/// Resize a resource
644+
///
645+
/// This works similarly to [`Api::replace`] but uses the resize subresource.
646+
/// Takes a full Pod object to specify the new resource requirements.
647+
///
648+
/// ```no_run
649+
/// use kube::api::{Api, PostParams};
650+
/// use k8s_openapi::api::core::v1::Pod;
651+
/// # async fn wrapper() -> Result<(), Box<dyn std::error::Error>> {
652+
/// # let client = kube::Client::try_default().await?;
653+
/// let pods: Api<Pod> = Api::namespaced(client, "apps");
654+
/// let mut pod = pods.get("mypod").await?;
655+
///
656+
/// // Modify the pod's resource requirements
657+
/// if let Some(ref mut spec) = pod.spec {
658+
/// if let Some(ref mut containers) = spec.containers.first_mut() {
659+
/// if let Some(ref mut resources) = containers.resources {
660+
/// // Update CPU/memory limits
661+
/// }
662+
/// }
663+
/// }
664+
///
665+
/// let pp = PostParams::default();
666+
/// let resized_pod = pods.resize("mypod", &pp, &pod).await?;
667+
/// # Ok(())
668+
/// # }
669+
/// ```
670+
pub async fn resize(&self, name: &str, pp: &PostParams, data: &K) -> Result<K>
671+
where
672+
K: serde::Serialize,
673+
{
674+
let mut req = self
675+
.request
676+
.resize(
677+
name,
678+
serde_json::to_vec(data).map_err(Error::SerdeError)?,
679+
pp,
680+
)
681+
.map_err(Error::BuildRequest)?;
682+
req.extensions_mut().insert("resize");
683+
self.client.request::<K>(req).await
684+
}
685+
}
686+
687+
// ----------------------------------------------------------------------------

kube-core/src/subresource.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,23 @@ impl Request {
405405
}
406406
}
407407

408+
// ----------------------------------------------------------------------------
409+
// Resize subresource
410+
// ----------------------------------------------------------------------------
411+
412+
impl Request {
413+
/// Resize a pod's resources
414+
pub fn resize(&self, name: &str, data: Vec<u8>, pp: &PostParams) -> Result<http::Request<Vec<u8>>, Error> {
415+
let target = format!("{}/{}/resize?", self.url_path, name);
416+
pp.validate()?;
417+
let mut qp = form_urlencoded::Serializer::new(target);
418+
pp.populate_qp(&mut qp);
419+
let urlstr = qp.finish();
420+
let req = http::Request::patch(urlstr).header(http::header::CONTENT_TYPE, JSON_MIME);
421+
req.body(data).map_err(Error::BuildRequest)
422+
}
423+
}
424+
408425
// ----------------------------------------------------------------------------
409426
// tests
410427
// ----------------------------------------------------------------------------

0 commit comments

Comments
 (0)