manta_server/server/common/
hw_inventory_utils.rs1use serde_json::Value;
5
6pub fn get_list_memory_capacity_from_hw_inventory_value(
9 hw_inventory: &Value,
10) -> Option<Vec<u64>> {
11 hw_inventory
12 .pointer("/Nodes/0/Memory")
13 .and_then(Value::as_array)
14 .map(|memory_list| {
15 memory_list
16 .iter()
17 .map(|memory| {
18 memory
19 .pointer("/PopulatedFRU/MemoryFRUInfo/CapacityMiB")
20 .unwrap_or(&serde_json::json!(0))
21 .as_u64()
22 .unwrap_or(0)
23 })
24 .collect::<Vec<u64>>()
25 })
26}
27
28pub fn get_list_processor_model_from_hw_inventory_value(
31 hw_inventory: &Value,
32) -> Option<Vec<String>> {
33 hw_inventory
34 .pointer("/Nodes/0/Processors")
35 .and_then(Value::as_array)
36 .map(|processor_list| {
37 processor_list
38 .iter()
39 .filter_map(|processor| {
40 processor
41 .pointer("/PopulatedFRU/ProcessorFRUInfo/Model")
42 .and_then(Value::as_str)
43 .map(std::string::ToString::to_string)
44 })
45 .collect::<Vec<String>>()
46 })
47}
48
49pub fn get_list_accelerator_model_from_hw_inventory_value(
52 hw_inventory: &Value,
53) -> Option<Vec<String>> {
54 hw_inventory
55 .pointer("/Nodes/0/NodeAccels")
56 .and_then(Value::as_array)
57 .map(|accelerator_list| {
58 accelerator_list
59 .iter()
60 .filter_map(|accelerator| {
61 accelerator
62 .pointer("/PopulatedFRU/NodeAccelFRUInfo/Model")
63 .and_then(Value::as_str)
64 .map(std::string::ToString::to_string)
65 })
66 .collect::<Vec<String>>()
67 })
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 use serde_json::json;
74
75 #[test]
78 fn memory_capacity_returns_values_for_valid_json() {
79 let hw = json!({
80 "Nodes": [{
81 "Memory": [
82 {"PopulatedFRU": {"MemoryFRUInfo": {"CapacityMiB": 16384}}},
83 {"PopulatedFRU": {"MemoryFRUInfo": {"CapacityMiB": 32768}}}
84 ]
85 }]
86 });
87 let result = get_list_memory_capacity_from_hw_inventory_value(&hw).unwrap();
88 assert_eq!(result, vec![16384, 32768]);
89 }
90
91 #[test]
92 fn memory_capacity_returns_none_when_no_nodes() {
93 let hw = json!({});
94 assert!(get_list_memory_capacity_from_hw_inventory_value(&hw).is_none());
95 }
96
97 #[test]
98 fn memory_capacity_returns_none_when_no_memory_key() {
99 let hw = json!({"Nodes": [{"Processors": []}]});
100 assert!(get_list_memory_capacity_from_hw_inventory_value(&hw).is_none());
101 }
102
103 #[test]
104 fn memory_capacity_returns_empty_vec_for_empty_memory_array() {
105 let hw = json!({"Nodes": [{"Memory": []}]});
106 let result = get_list_memory_capacity_from_hw_inventory_value(&hw).unwrap();
107 assert!(result.is_empty());
108 }
109
110 #[test]
111 fn memory_capacity_defaults_to_zero_when_field_missing() {
112 let hw = json!({
113 "Nodes": [{
114 "Memory": [
115 {"PopulatedFRU": {"MemoryFRUInfo": {}}},
116 {"PopulatedFRU": {"MemoryFRUInfo": {"CapacityMiB": 8192}}}
117 ]
118 }]
119 });
120 let result = get_list_memory_capacity_from_hw_inventory_value(&hw).unwrap();
121 assert_eq!(result, vec![0, 8192]);
122 }
123
124 #[test]
127 fn processor_model_returns_values_for_valid_json() {
128 let hw = json!({
129 "Nodes": [{
130 "Processors": [
131 {"PopulatedFRU": {"ProcessorFRUInfo": {"Model": "AMD EPYC 7742"}}},
132 {"PopulatedFRU": {"ProcessorFRUInfo": {"Model": "Intel Xeon Gold 6248"}}}
133 ]
134 }]
135 });
136 let result = get_list_processor_model_from_hw_inventory_value(&hw).unwrap();
137 assert_eq!(result, vec!["AMD EPYC 7742", "Intel Xeon Gold 6248"]);
138 }
139
140 #[test]
141 fn processor_model_returns_none_when_no_nodes() {
142 let hw = json!({});
143 assert!(get_list_processor_model_from_hw_inventory_value(&hw).is_none());
144 }
145
146 #[test]
147 fn processor_model_skips_entries_without_model_field() {
148 let hw = json!({
149 "Nodes": [{
150 "Processors": [
151 {"PopulatedFRU": {"ProcessorFRUInfo": {"Model": "AMD EPYC 7742"}}},
152 {"PopulatedFRU": {"ProcessorFRUInfo": {}}},
153 {"PopulatedFRU": {}}
154 ]
155 }]
156 });
157 let result = get_list_processor_model_from_hw_inventory_value(&hw).unwrap();
158 assert_eq!(result, vec!["AMD EPYC 7742"]);
159 }
160
161 #[test]
162 fn processor_model_returns_empty_vec_for_empty_array() {
163 let hw = json!({"Nodes": [{"Processors": []}]});
164 let result = get_list_processor_model_from_hw_inventory_value(&hw).unwrap();
165 assert!(result.is_empty());
166 }
167
168 #[test]
171 fn accelerator_model_returns_values_for_valid_json() {
172 let hw = json!({
173 "Nodes": [{
174 "NodeAccels": [
175 {"PopulatedFRU": {"NodeAccelFRUInfo": {"Model": "NVIDIA A100"}}},
176 {"PopulatedFRU": {"NodeAccelFRUInfo": {"Model": "NVIDIA H100"}}}
177 ]
178 }]
179 });
180 let result =
181 get_list_accelerator_model_from_hw_inventory_value(&hw).unwrap();
182 assert_eq!(result, vec!["NVIDIA A100", "NVIDIA H100"]);
183 }
184
185 #[test]
186 fn accelerator_model_returns_none_when_no_nodes() {
187 let hw = json!({});
188 assert!(get_list_accelerator_model_from_hw_inventory_value(&hw).is_none());
189 }
190
191 #[test]
192 fn accelerator_model_skips_entries_without_model_field() {
193 let hw = json!({
194 "Nodes": [{
195 "NodeAccels": [
196 {"PopulatedFRU": {"NodeAccelFRUInfo": {"Model": "NVIDIA A100"}}},
197 {"PopulatedFRU": {"NodeAccelFRUInfo": {}}},
198 {"SomethingElse": {}}
199 ]
200 }]
201 });
202 let result =
203 get_list_accelerator_model_from_hw_inventory_value(&hw).unwrap();
204 assert_eq!(result, vec!["NVIDIA A100"]);
205 }
206
207 #[test]
208 fn accelerator_model_returns_empty_vec_for_empty_array() {
209 let hw = json!({"Nodes": [{"NodeAccels": []}]});
210 let result =
211 get_list_accelerator_model_from_hw_inventory_value(&hw).unwrap();
212 assert!(result.is_empty());
213 }
214}