1use k8s_openapi::api::core::v1::Pod;
2use kube::api::Api;
3use prettytable::{color, Attr, Cell, Row, Table};
4
5use crate::list_vault_pods;
6
7#[tracing::instrument(skip_all)]
8pub async fn construct_table(api: &Api<Pod>) -> anyhow::Result<Table> {
9 let mut table = Table::new();
10 table.set_titles(row![
11 "NAME",
12 "STATUS",
13 "IMAGE",
14 "INITIALIZED",
15 "SEALED",
16 "ACTIVE",
17 "READY",
18 ]);
19
20 let pods = api.list(&list_vault_pods()).await?;
21
22 let get_vault_label = |pod: &Pod, label: &str| match pod.metadata.labels {
23 Some(ref labels) => labels
24 .get(label)
25 .unwrap_or(&String::from("unknown"))
26 .to_string(),
27 None => String::from("unknown"),
28 };
29
30 for p in pods.iter() {
31 let name = p
32 .metadata
33 .name
34 .clone()
35 .ok_or(anyhow::anyhow!("pod does not have a name"))?;
36 let status = p
37 .status
38 .as_ref()
39 .ok_or(anyhow::anyhow!("pod does not have a status"))?
40 .phase
41 .clone()
42 .ok_or(anyhow::anyhow!("pod does not have a phase"))?;
43 let image = p
44 .spec
45 .as_ref()
46 .ok_or(anyhow::anyhow!("pod does not have a spec"))?
47 .containers
48 .first()
49 .ok_or(anyhow::anyhow!("pod does not have a container"))?
50 .image
51 .clone()
52 .ok_or(anyhow::anyhow!("container does not have an image"))?;
53
54 let initialized = get_vault_label(p, "vault-initialized");
55 let initialized =
56 Cell::new(&initialized).with_style(Attr::ForegroundColor(match initialized.as_str() {
57 "true" => color::GREEN,
58 "false" => color::RED,
59 _ => color::YELLOW,
60 }));
61
62 let sealed = get_vault_label(p, "vault-sealed");
63 let sealed = Cell::new(&sealed).with_style(Attr::ForegroundColor(match sealed.as_str() {
64 "true" => color::RED,
65 "false" => color::GREEN,
66 _ => color::YELLOW,
67 }));
68
69 let active = get_vault_label(p, "vault-active");
70 let active = Cell::new(&active).with_style(Attr::ForegroundColor(match active.as_str() {
71 "true" => color::GREEN,
72 "false" => color::WHITE,
73 _ => color::YELLOW,
74 }));
75
76 let ready = {
77 let mut ready = "unknown".to_string();
78
79 for c in p
80 .status
81 .as_ref()
82 .ok_or(anyhow::anyhow!("pod does not have a status"))?
83 .conditions
84 .as_ref()
85 .ok_or(anyhow::anyhow!("pod does not have status conditions"))?
86 {
87 if c.type_ == "Ready" {
88 ready = match c.status.as_str() {
89 "True" => "true".to_string(),
90 "False" => "false".to_string(),
91 _ => "unknown".to_string(),
92 };
93
94 break;
95 }
96 }
97
98 ready
99 };
100 let ready = Cell::new(&ready).with_style(Attr::ForegroundColor(match ready.as_str() {
101 "true" => color::GREEN,
102 "false" => color::WHITE,
103 _ => color::YELLOW,
104 }));
105
106 table.add_row(Row::new(vec![
107 Cell::new(&name),
108 Cell::new(&status),
109 Cell::new(&image),
110 initialized,
111 sealed,
112 active,
113 ready,
114 ]));
115 }
116
117 Ok(table)
118}