Skip to content

Commit 4a85800

Browse files
committed
add eviction subresource - for #127
1 parent d450509 commit 4a85800

File tree

4 files changed

+151
-3
lines changed

4 files changed

+151
-3
lines changed

examples/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ path = "pod_attach.rs"
111111
name = "pod_exec"
112112
path = "pod_exec.rs"
113113

114+
[[example]]
115+
name = "pod_evict"
116+
path = "pod_evict.rs"
117+
114118
[[example]]
115119
name = "pod_shell"
116120
path = "pod_shell.rs"

examples/pod_evict.rs

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#[macro_use] extern crate log;
2+
use futures::{StreamExt, TryStreamExt};
3+
use k8s_openapi::api::core::v1::Pod;
4+
use serde_json::json;
5+
6+
use kube::{
7+
api::{Api, Eviction, ListParams, Meta, PostParams, WatchEvent},
8+
Client,
9+
};
10+
11+
#[tokio::main]
12+
async fn main() -> anyhow::Result<()> {
13+
std::env::set_var("RUST_LOG", "info,kube=debug");
14+
env_logger::init();
15+
let client = Client::try_default().await?;
16+
let namespace = std::env::var("NAMESPACE").unwrap_or("default".into());
17+
18+
// Create a Job
19+
let pod_name = "empty-pod";
20+
let empty_pod = serde_json::from_value(json!({
21+
"apiVersion": "v1",
22+
"kind": "Pod",
23+
"metadata": {
24+
"name": pod_name,
25+
},
26+
"spec": {
27+
"containers": [{
28+
"name": "empty",
29+
"image": "alpine:latest",
30+
"command": ["tail", "-f", "/dev/null"]
31+
}],
32+
}
33+
}))?;
34+
35+
let pods: Api<Pod> = Api::namespaced(client, &namespace);
36+
let pp = PostParams::default();
37+
pods.create(&pp, &empty_pod).await?;
38+
39+
// Wait until the pod is running, although it's not necessary
40+
let lp = ListParams::default()
41+
.fields("metadata.name=empty-pod")
42+
.timeout(10);
43+
let mut stream = pods.watch(&lp, "0").await?.boxed();
44+
while let Some(status) = stream.try_next().await? {
45+
match status {
46+
WatchEvent::Added(o) => {
47+
info!("Added {}", Meta::name(&o));
48+
}
49+
WatchEvent::Modified(o) => {
50+
let s = o.status.as_ref().expect("status exists on pod");
51+
if s.phase.clone().unwrap_or_default() == "Running" {
52+
info!("Ready to evict to {}", Meta::name(&o));
53+
break;
54+
}
55+
}
56+
_ => {}
57+
}
58+
}
59+
60+
// Clean up the old job record..
61+
let ev = Eviction::new(pod_name);
62+
let eres = pods.evict(pod_name, &pp, &ev).await?;
63+
println!("{:?}", eres);
64+
Ok(())
65+
}

kube/src/api/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub use dynamic::DynamicResource;
2626
mod subresource;
2727
#[cfg(feature = "ws")]
2828
pub use subresource::{AttachParams, AttachableObject, ExecutingObject};
29-
pub use subresource::{LogParams, LoggingObject, ScaleSpec, ScaleStatus};
29+
pub use subresource::{Eviction, EvictionObject, LogParams, LoggingObject, ScaleSpec, ScaleStatus};
3030

3131
pub(crate) mod object;
3232
pub use self::object::{Object, ObjectList, WatchEvent};

kube/src/api/subresource.rs

+81-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use bytes::Bytes;
22
use futures::Stream;
3-
use serde::de::DeserializeOwned;
3+
use serde::{de::DeserializeOwned, Serialize};
44

55
use crate::{
6-
api::{Api, Patch, PatchParams, PostParams, Resource},
6+
api::{Api, DeleteParams, Patch, PatchParams, PostParams, Resource},
7+
client::Status,
78
Error, Result,
89
};
910

@@ -221,6 +222,84 @@ where
221222
}
222223
}
223224

225+
// ----------------------------------------------------------------------------
226+
// Eviction subresource
227+
// ----------------------------------------------------------------------------
228+
229+
use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta;
230+
/// Eviction body
231+
#[derive(Default, Clone, Serialize)]
232+
pub struct Eviction {
233+
/// How the eviction should occur
234+
pub delete_options: Option<DeleteParams>,
235+
/// Metadata describing the pod being evicted
236+
/// we somehow need this despite providing the name of the pod..
237+
pub metadata: ObjectMeta,
238+
}
239+
240+
impl Eviction {
241+
/// Create an eviction object for a named resource
242+
pub fn new(name: &str) -> Self {
243+
Self {
244+
metadata: ObjectMeta {
245+
name: Some(name.to_string()),
246+
..ObjectMeta::default()
247+
},
248+
delete_options: None,
249+
}
250+
}
251+
252+
/// Attach DeleteParams to the eviction object
253+
pub fn with_options(mut self, dp: DeleteParams) -> Self {
254+
self.delete_options = Some(dp);
255+
self
256+
}
257+
}
258+
259+
impl Resource {
260+
/// Create an eviction
261+
pub fn evict(&self, name: &str, pp: &PostParams, data: Vec<u8>) -> Result<http::Request<Vec<u8>>> {
262+
let base_url = self.make_url() + "/" + name + "/" + "eviction?";
263+
// This is technically identical to Resource::create, but different url
264+
pp.validate()?;
265+
let mut qp = url::form_urlencoded::Serializer::new(base_url);
266+
if pp.dry_run {
267+
qp.append_pair("dryRun", "All");
268+
}
269+
let urlstr = qp.finish();
270+
let req = http::Request::post(urlstr);
271+
req.body(data).map_err(Error::HttpError)
272+
}
273+
}
274+
275+
#[test]
276+
fn evict_path() {
277+
use crate::api::Resource;
278+
use k8s_openapi::api::core::v1 as corev1;
279+
let r = Resource::namespaced::<corev1::Pod>("ns");
280+
let mut pp = PostParams::default();
281+
pp.dry_run = true;
282+
let req = r.evict("foo", &pp, vec![]).unwrap();
283+
assert_eq!(req.uri(), "/api/v1/namespaces/ns/pods/foo/eviction?&dryRun=All");
284+
}
285+
286+
/// Marker trait for objects that can be evicted
287+
pub trait EvictionObject {}
288+
289+
impl EvictionObject for k8s_openapi::api::core::v1::Pod {}
290+
291+
impl<K> Api<K>
292+
where
293+
K: Clone + DeserializeOwned + EvictionObject,
294+
{
295+
/// Create an eviction
296+
pub async fn evict(&self, name: &str, pp: &PostParams, data: &Eviction) -> Result<Status> {
297+
let bytes = serde_json::to_vec(data)?;
298+
let req = self.resource.evict(name, pp, bytes)?;
299+
self.client.request::<Status>(req).await
300+
}
301+
}
302+
224303
// ----------------------------------------------------------------------------
225304
// Attach subresource
226305
// ----------------------------------------------------------------------------

0 commit comments

Comments
 (0)