-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpredicates.rs
80 lines (67 loc) · 2.27 KB
/
predicates.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use k8s_openapi::api::core::v1 as corev1;
use kube::api::ListParams;
use kube::{
Api,
ResourceExt,
};
use crate::util::{
total_pod_resources,
Context,
PodResources,
};
#[derive(Debug)]
pub enum InvalidNodeReason {
NotEnoughResources,
NodeSelectorMismatch,
}
async fn can_pod_fit(pod: &corev1::Pod, node: &corev1::Node, ctx: &Context) -> bool {
let pod_querier: Api<corev1::Pod> = Api::all(ctx.client.clone());
let list_params = ListParams {
field_selector: Some(format!("spec.nodeName={}", node.name_any())),
..ListParams::default()
};
let mut available_resources = PodResources::new();
if let Some(corev1::NodeStatus { allocatable: Some(allocatable), .. }) = &node.status {
available_resources.cpu = allocatable["cpu"].clone().try_into().expect("invalid node spec: allocatable cpu");
available_resources.memory =
allocatable["memory"].clone().try_into().expect("invalid node spec: allocatable memory");
}
let pods_on_node = pod_querier.list(&list_params).await;
for p in pods_on_node.expect("could not list nodes") {
available_resources -= total_pod_resources(&p)
}
let pod_requests = total_pod_resources(pod);
return pod_requests.cpu <= available_resources.cpu && pod_requests.memory <= available_resources.memory;
}
fn does_node_selector_match(pod: &corev1::Pod, node: &corev1::Node) -> bool {
let mut matches = true;
if let Some(corev1::PodSpec { node_selector: Some(node_selector), .. }) = &pod.spec {
for (pk, pv) in node_selector.iter() {
if let Some(labels) = &node.metadata.labels {
if labels.get(pk) != Some(pv) {
matches = false;
break;
}
} else {
matches = false;
break;
}
}
}
return matches;
}
pub async fn check_node_validity(
pod: &corev1::Pod,
node: &corev1::Node,
ctx: &Context,
) -> Result<(), InvalidNodeReason> {
if !can_pod_fit(pod, node, ctx).await {
return Err(InvalidNodeReason::NotEnoughResources);
}
if !does_node_selector_match(pod, node) {
return Err(InvalidNodeReason::NodeSelectorMismatch);
}
return Ok(());
}
#[cfg(test)]
mod test;