use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Local};
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub struct Node {
#[serde(rename = "apiVersion")]
pub api_version: String,
pub kind: String,
pub metadata: NodeMetadata,
pub spec: NodeSpec,
pub status: NodeStatus,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub struct NodeSpec {
#[serde(rename = "podCIDR")]
pub pod_cidr: String,
pub taints: Option<Vec<Taint>>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub struct Taint {
pub key: String,
pub value: String,
pub effect: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub struct NodeMetadata {
pub name: String,
pub role: String,
pub labels: Option<HashMap<String, String>>,
pub annotations: Option<HashMap<String, String>>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub struct NodeStatus {
pub capacity: Capacity,
pub allocatable: Allocatable,
pub condition: Option<Vec<Condition>>,
pub addresses: Option<Vec<Address>>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub struct Capacity {
pub cpu: Option<String>,
pub memory: Option<String>,
pub disk: Option<String>,
pub pods: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub struct Allocatable {
pub cpu: Option<String>,
pub memory: Option<String>,
pub disk: Option<String>,
pub pods: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub struct Condition {
#[serde(rename = "type")]
pub node_type: Option<String>,
pub status: Option<String>,
#[serde(rename = "lastHeartbeatTime")]
pub last_heartbeat_time: Option<DateTime<Local>>,
pub reasion: Option<String>,
pub message: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub struct Address {
#[serde(rename = "type")]
pub address_type: String,
pub address: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_node_deserialization() {
let node_yaml = r#"
{
"apiVersion": "v1",
"kind": "Node",
"metadata": {
"name": "node-name",
"role": "master",
"labels": {
"kubernetes.io/hostname": "node-name",
"beta.kubernetes.io/os": "linux",
"beta.kubernetes.io/arch": "amd64"
},
"annotations": {
"kubeadm.alpha.kubernetes.io/cri-socket": "/var/run/dockershim.sock"
}
},
"spec": {
"podCIDR": "10.244.0.0/24",
"taints": [
{
"key": "key1",
"value": "value1",
"effect": "NoSchedule"
}
]
},
"status": {
"capacity": {
"cpu": "4",
"memory": "16384Mi",
"ephemeral-storage": "1024Gi",
"pods": "110"
},
"allocatable": {
"cpu": "3",
"memory": "12288Mi",
"ephemeral-storage": "800Gi",
"pods": "100"
},
"conditions": [
{
"type": "Ready",
"status": "True",
"lastHeartbeatTime": "2024-12-10T12:34:56Z",
"lastTransitionTime": "2024-12-10T12:34:56Z",
"reason": "KubeletReady",
"message": "kubelet is posting ready status"
}
],
"addresses": [
{
"type": "InternalIP",
"address": "192.168.1.1"
},
{
"type": "Hostname",
"address": "node-name"
}
]
}
}
"#;
let node: Node = serde_yaml::from_str(node_yaml).expect("Failed to parse YAML");
assert_eq!(node.api_version, "v1");
assert_eq!(node.kind, "Node");
assert_eq!(node.metadata.name, "node-name");
assert_eq!(node.metadata.labels.clone().unwrap().len(), 3);
assert_eq!(node.spec.pod_cidr, "10.244.0.0/24");
assert_eq!(node.spec.taints.clone().unwrap().len(), 1);
assert_eq!(node.status.capacity.cpu.clone().unwrap(), "4");
let addresses = node.status.addresses.clone().unwrap(); assert_eq!(addresses[0].address, "192.168.1.1");
println!("{:#?}", node);
}
}