backend_dispatcher/types/
mod.rs

1pub mod bos;
2pub mod cfs;
3pub mod hsm;
4pub mod ims;
5pub mod kafka;
6
7use std::{collections::HashMap, str::FromStr};
8
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use strum_macros::{AsRefStr, Display, EnumIter, EnumString, IntoStaticStr};
12
13use crate::error::Error;
14
15#[derive(Serialize, Deserialize, Debug, Clone)]
16pub enum K8sAuth {
17    #[serde(rename = "native")]
18    Native {
19        certificate_authority_data: String,
20        client_certificate_data: String,
21        client_key_data: String,
22    },
23    #[serde(rename = "vault")]
24    Vault { base_url: String },
25}
26
27#[derive(Serialize, Deserialize, Debug, Clone)]
28pub struct K8sDetails {
29    pub api_url: String,
30    pub authentication: K8sAuth,
31}
32
33// From CSM used by Manta
34#[derive(
35    Debug, EnumIter, EnumString, IntoStaticStr, AsRefStr, Display, Serialize, Deserialize, Clone,
36)]
37pub enum ArtifactType {
38    Memory,
39    Processor,
40    NodeAccel,
41    NodeHsnNic,
42    Drive,
43    CabinetPDU,
44    CabinetPDUPowerConnector,
45    CMMRectifier,
46    NodeAccelRiser,
47    NodeEnclosurePowerSupplie,
48    NodeBMC,
49    RouterBMC,
50}
51
52#[derive(Default, Debug, Serialize, Deserialize, Clone)]
53pub struct NodeSummary {
54    pub xname: String,
55    pub r#type: String,
56    pub processors: Vec<ArtifactSummary>,
57    pub memory: Vec<ArtifactSummary>,
58    pub node_accels: Vec<ArtifactSummary>,
59    pub node_hsn_nics: Vec<ArtifactSummary>,
60}
61
62/* impl From<HWInventoryByLocation> for NodeSummary {
63    fn from(value: HWInventoryByLocation) -> Self {
64        NodeSummary {
65            xname: value.id,
66            r#type: value.r#type.unwrap_or_default(),
67            processors: value
68                .processors
69                .unwrap_or_default()
70                .into_iter()
71                .map(ArtifactSummary::from)
72                .collect(),
73            // FIXME: implement FROM trait from HWInvByLlocProcessor to ArtifactSummary
74            memory: value
75                .memory
76                .unwrap_or_default()
77                .into_iter()
78                .map(ArtifactSummary::from)
79                .collect(),
80            // FIXME: implement FROM trait from HWInvByLlocMemory to ArtifactSummary
81            node_accels: value
82                .node_accels
83                .unwrap_or_default()
84                .into_iter()
85                .map(ArtifactSummary::from)
86                .collect(),
87            // FIXME: implement FROM trait from HWInvByLlocNodeAccel to ArtifactSummary
88            node_hsn_nics: value
89                .node_hsn_nics
90                .unwrap_or_default()
91                .into_iter()
92                .map(ArtifactSummary::from)
93                .collect(),
94            // FIXME: implement FROM trait from HWInvByLlocHSNNIC to ArtifactSummary
95        }
96    }
97}
98
99impl Into<HWInventoryByLocation> for NodeSummary {
100    fn into(self) -> HWInventoryByLocation {
101        let redfish_system_fru_info = RedfishSystemFRUInfo {
102            asset_tag: None,
103            bios_version: None,
104            model: None,
105            manufacturer: None,
106            part_number: None,
107            serial_number: None,
108            sku: None,
109            system_type: None,
110            uuid: None,
111        };
112
113        let hw_inv_by_fr_node = HWInvByFRUNode {
114            fru_id: None,
115            r#type: None,
116            fru_sub_type: None,
117            hw_inventory_by_fru_type: self.r#type.clone(),
118            node_fru_info: redfish_system_fru_info,
119        };
120
121        let processor_summary = ProcessorSummary {
122            count: self.processors.len().try_into().ok(),
123            model: self.processors.first().unwrap().info.clone(),
124        };
125
126        let memory_capacity_vec: Vec<usize> = self
127            .memory
128            .iter()
129            .map(|memory| {
130                let binding = "".to_string();
131                let mem_capacity = memory.info.as_ref().unwrap_or(&binding);
132                /* .strip_suffix(" MiB")
133                .unwrap_or_default(); */
134
135                usize::from_str(mem_capacity.strip_suffix(" MiB").unwrap_or_default())
136                    .unwrap_or_default()
137            })
138            .collect();
139
140        let memory_summary = MemorySummary {
141            total_system_memory_gib: Some(memory_capacity_vec.iter().sum::<usize>() as u32),
142        };
143
144        let node_location_info = NodeLocationInfo {
145            id: self.xname.clone(),
146            name: None,
147            description: None,
148            hostname: None,
149            processor_summary: Some(processor_summary),
150            memory_summary: Some(memory_summary),
151        };
152
153        HWInventoryByLocation {
154            id: self.xname,
155            r#type: Some(self.r#type.clone()),
156            ordinal: None,
157            status: None,
158            node_location_info,
159            hw_inventory_by_location_type: self.r#type,
160            populated_fru: Some(hw_inv_by_fr_node),
161            cabinets: None,
162            chassis: None,
163            compute_modules: None,
164            router_modules: None,
165            node_enclosures: None,
166            hsn_boards: None,        // FIXME: implement!
167            mgmt_switches: None,     // FIXME: implement!
168            mgmt_hl_switches: None,  // FIXME: implement!
169            cdu_mgmt_switches: None, // FIXME: implement!
170            nodes: None,             // FIXME: implement!
171            processors: Some(
172                self.processors
173                    .into_iter()
174                    .map(|processor| processor.into())
175                    .collect(),
176            ), // FIXME: implement!
177            node_accels: Some(
178                self.node_accels
179                    .into_iter()
180                    .map(|node_accel| node_accel.into())
181                    .collect(),
182            ), // FIXME: implement!
183            drives: None,            // FIXME: implement!
184            memory: Some(
185                self.memory
186                    .into_iter()
187                    .map(|memory| memory.into())
188                    .collect(),
189            ), // FIXME: implement!
190            cabinet_pdus: None,      // FIXME: implement!
191            cabinet_pdu_power_connectors: None, // FIXME: implement!
192            cmm_rectifiers: None,    // FIXME: implement!
193            node_accel_risers: None, // FIXME: implement!
194            node_hsn_nics: Some(
195                self.node_hsn_nics
196                    .into_iter()
197                    .map(|node_hsn_nic| node_hsn_nic.into())
198                    .collect(),
199            ), // FIXME: implement!
200            node_enclosure_power_supplies: None, // FIXME: implement!
201            node_bmc: None,
202            router_bmc: None, // FIXME: implement!
203        }
204    }
205} */
206
207impl From<HWInvByLocNode> for NodeSummary {
208    fn from(value: HWInvByLocNode) -> Self {
209        NodeSummary {
210            xname: value.id,
211            r#type: value.r#type.unwrap_or_default(),
212            processors: value
213                .processors
214                .unwrap_or_default()
215                .into_iter()
216                .map(ArtifactSummary::from)
217                .collect(),
218            // FIXME: implement FROM trait from HWInvByLlocProcessor to ArtifactSummary
219            memory: value
220                .memory
221                .unwrap_or_default()
222                .into_iter()
223                .map(ArtifactSummary::from)
224                .collect(),
225            // FIXME: implement FROM trait from HWInvByLlocMemory to ArtifactSummary
226            node_accels: value
227                .node_accels
228                .unwrap_or_default()
229                .into_iter()
230                .map(ArtifactSummary::from)
231                .collect(),
232            // FIXME: implement FROM trait from HWInvByLlocNodeAccel to ArtifactSummary
233            node_hsn_nics: value
234                .node_hsn_nics
235                .unwrap_or_default()
236                .into_iter()
237                .map(ArtifactSummary::from)
238                .collect(),
239            // FIXME: implement FROM trait from HWInvByLlocHSNNIC to ArtifactSummary
240        }
241    }
242}
243
244impl Into<HWInvByLocNode> for NodeSummary {
245    fn into(self) -> HWInvByLocNode {
246        let redfish_system_fru_info = RedfishSystemFRUInfo {
247            asset_tag: None,
248            bios_version: None,
249            model: None,
250            manufacturer: None,
251            part_number: None,
252            serial_number: None,
253            sku: None,
254            system_type: None,
255            uuid: None,
256        };
257
258        let hw_inv_by_fr_node = HWInvByFRUNode {
259            fru_id: None,
260            r#type: None,
261            fru_sub_type: None,
262            hw_inventory_by_fru_type: self.r#type.clone(),
263            node_fru_info: redfish_system_fru_info,
264        };
265
266        HWInvByLocNode {
267            id: self.xname,
268            r#type: Some(self.r#type.clone()),
269            ordinal: None,
270            status: None,
271            hw_inventory_by_location_type: self.r#type,
272            populated_fru: Some(hw_inv_by_fr_node),
273            node_location_info: None,
274            processors: Some(
275                self.processors
276                    .into_iter()
277                    .map(|processor| processor.into())
278                    .collect(),
279            ),
280            node_accels: Some(
281                self.node_accels
282                    .into_iter()
283                    .map(|node_accel| node_accel.into())
284                    .collect(),
285            ),
286            drives: None,
287            memory: Some(
288                self.memory
289                    .into_iter()
290                    .map(|memory| memory.into())
291                    .collect(),
292            ),
293            node_accel_risers: None,
294            node_hsn_nics: Some(
295                self.node_hsn_nics
296                    .into_iter()
297                    .map(|node_hsn_nic| node_hsn_nic.into())
298                    .collect(),
299            ),
300        }
301    }
302}
303
304impl NodeSummary {
305    pub fn from_csm_value(hw_artifact_value: Value) -> Self {
306        let processors = hw_artifact_value["Processors"]
307            .as_array()
308            .unwrap_or(&Vec::new())
309            .iter()
310            .map(|processor_value| ArtifactSummary::from_processor_value(processor_value.clone()))
311            .collect();
312
313        let memory = hw_artifact_value["Memory"]
314            .as_array()
315            .unwrap_or(&Vec::new())
316            .iter()
317            .map(|memory_value| ArtifactSummary::from_memory_value(memory_value.clone()))
318            .collect();
319
320        let node_accels = hw_artifact_value["NodeAccels"]
321            .as_array()
322            .unwrap_or(&Vec::new())
323            .iter()
324            .map(|nodeaccel_value| ArtifactSummary::from_nodeaccel_value(nodeaccel_value.clone()))
325            .collect();
326
327        let node_hsn_nics = hw_artifact_value["NodeHsnNics"]
328            .as_array()
329            .unwrap_or(&Vec::new())
330            .iter()
331            .map(|nodehsnnic_value| {
332                ArtifactSummary::from_nodehsnnics_value(nodehsnnic_value.clone())
333            })
334            .collect();
335
336        Self {
337            xname: hw_artifact_value["ID"].as_str().unwrap().to_string(),
338            r#type: hw_artifact_value["Type"].as_str().unwrap().to_string(),
339            processors,
340            memory,
341            node_accels,
342            node_hsn_nics,
343        }
344    }
345}
346
347#[derive(Debug, Serialize, Deserialize, Clone)]
348pub struct ArtifactSummary {
349    pub xname: String,
350    pub r#type: ArtifactType,
351    pub info: Option<String>,
352}
353
354impl From<HWInvByLocProcessor> for ArtifactSummary {
355    fn from(value: HWInvByLocProcessor) -> Self {
356        ArtifactSummary {
357            xname: value.id,
358            r#type: ArtifactType::from_str(value.r#type.unwrap().as_str()).unwrap(),
359            info: value.populated_fru.and_then(|hw_inv_by_fru_processor| {
360                hw_inv_by_fru_processor.processor_fru_info.model
361            }),
362        }
363    }
364}
365
366impl Into<HWInvByLocProcessor> for ArtifactSummary {
367    fn into(self) -> HWInvByLocProcessor {
368        let redfish_process_fru_info = RedfishProcessorFRUInfo {
369            instruction_set: None,
370            manufacturer: None,
371            max_speed_mhz: None,
372            model: self.info,
373            processor_architecture: None,
374            processor_id: None,
375            processor_type: None,
376            total_cores: None,
377            total_threads: None,
378        };
379
380        let hw_inv_by_fru_processor = HWInvByFRUProcessor {
381            fru_id: None,
382            r#type: Some(self.r#type.to_string()),
383            fru_sub_type: None,
384            hw_inventory_by_fru_type: self.r#type.to_string(),
385            processor_fru_info: redfish_process_fru_info,
386        };
387
388        let processor_location_info = RedfishProcessorLocationInfo {
389            id: None,
390            name: None,
391            description: None,
392            socket: None,
393        };
394
395        HWInvByLocProcessor {
396            id: self.xname,
397            r#type: Some(self.r#type.to_string()),
398            ordinal: None,
399            status: None,
400            hw_inventory_by_location_type: self.r#type.to_string(),
401            populated_fru: Some(hw_inv_by_fru_processor),
402            processor_location_info,
403        }
404    }
405}
406
407impl From<HWInvByLocMemory> for ArtifactSummary {
408    fn from(value: HWInvByLocMemory) -> Self {
409        ArtifactSummary {
410            xname: value.id,
411            r#type: ArtifactType::from_str(value.r#type.unwrap().as_str()).unwrap(),
412            info: value.populated_fru.and_then(|hw_inv_by_fru_memory| {
413                hw_inv_by_fru_memory
414                    .memory_fru_info
415                    .capacity_mib
416                    .map(|capacity_mib| capacity_mib.to_string())
417            }),
418        }
419    }
420}
421
422impl Into<HWInvByLocMemory> for ArtifactSummary {
423    fn into(self) -> HWInvByLocMemory {
424        let redfish_memory_fru_info = RedfishMemoryFRUInfo {
425            base_module_type: None,
426            bus_width_bits: None,
427            capacity_mib: self.info.map(|info| usize::from_str(&info).unwrap_or(0)), // FIXME:
428            // settings memory capacity to 0 if any issue... this does not look ok...
429            data_width_bits: None,
430            error_correction: None,
431            manufacturer: None,
432            memory_type: None,
433            memory_device_type: None,
434            operating_speed_mhz: None,
435            part_number: None,
436            rank_count: None,
437            serial_number: None,
438        };
439
440        let hw_inv_by_fru_memory = HWInvByFRUMemory {
441            fru_id: None,
442            r#type: Some(self.r#type.to_string()),
443            fru_sub_type: None,
444            hw_inventory_by_fru_type: self.r#type.to_string(),
445            memory_fru_info: redfish_memory_fru_info,
446        };
447
448        let memory_location = MemoryLocation {
449            socket: None,
450            memory_controller: None,
451            channel: None,
452            slot: None,
453        };
454
455        let redfish_memory_location_info = RedfishMemoryLocationInfo {
456            id: None,
457            name: None,
458            description: None,
459            memory_location: Some(memory_location),
460        };
461
462        HWInvByLocMemory {
463            id: self.xname,
464            r#type: Some(self.r#type.to_string()),
465            ordinal: None,
466            status: None,
467            hw_inventory_by_location_type: self.r#type.to_string(),
468            populated_fru: Some(hw_inv_by_fru_memory),
469            memory_location_info: redfish_memory_location_info,
470        }
471    }
472}
473
474impl From<HWInvByLocNodeAccel> for ArtifactSummary {
475    fn from(value: HWInvByLocNodeAccel) -> Self {
476        ArtifactSummary {
477            xname: value.id,
478            r#type: ArtifactType::from_str(value.r#type.unwrap().as_str()).unwrap(),
479            info: value.populated_fru.and_then(|hw_inv_by_fru_node_accel| {
480                hw_inv_by_fru_node_accel.node_accel_fru_info.model
481            }),
482        }
483    }
484}
485
486impl Into<HWInvByLocNodeAccel> for ArtifactSummary {
487    fn into(self) -> HWInvByLocNodeAccel {
488        // NOTE: yes, sounds weird FRU for node accelerator uses FRU for processor... but that is
489        // what the API docs says...
490        let redfish_processor_fru_info = RedfishProcessorFRUInfo {
491            instruction_set: None,
492            manufacturer: None,
493            max_speed_mhz: None,
494            model: self.info,
495            processor_architecture: None,
496            processor_id: None,
497            processor_type: None,
498            total_cores: None,
499            total_threads: None,
500        };
501
502        let hw_inv_by_fru_node_accel = HWInvByFRUNodeAccel {
503            fru_id: None,
504            r#type: Some(self.r#type.to_string()),
505            fru_sub_type: None,
506            hw_inventory_by_fru_type: self.r#type.to_string(),
507            node_accel_fru_info: redfish_processor_fru_info,
508        };
509
510        HWInvByLocNodeAccel {
511            id: self.xname,
512            r#type: Some(self.r#type.to_string()),
513            ordinal: None,
514            status: None,
515            hw_inventory_by_location_type: self.r#type.to_string(),
516            populated_fru: Some(hw_inv_by_fru_node_accel),
517            node_accel_location_info: None,
518        }
519    }
520}
521
522impl From<HWInvByLocHSNNIC> for ArtifactSummary {
523    fn from(value: HWInvByLocHSNNIC) -> Self {
524        ArtifactSummary {
525            xname: value.id,
526            r#type: ArtifactType::from_str(value.r#type.unwrap().as_str()).unwrap(),
527            info: value
528                .populated_fru
529                .and_then(|hw_inv_by_fru_hsn_nic| hw_inv_by_fru_hsn_nic.hsn_nic_fru_info.model),
530        }
531    }
532}
533
534impl Into<HWInvByLocHSNNIC> for ArtifactSummary {
535    fn into(self) -> HWInvByLocHSNNIC {
536        // NOTE: yes, sounds weird FRU for node accelerator uses FRU for processor... but that is
537        // what the API docs says...
538        let hsn_nic_fru_info = HSNNICFRUInfo {
539            manufacturer: None,
540            model: self.info,
541            part_number: None,
542            sku: None,
543            serial_number: None,
544        };
545
546        let hw_inv_by_fru_hsn_nic = HWInvByFRUHSNNIC {
547            fru_id: None,
548            r#type: Some(self.r#type.to_string()),
549            fru_sub_type: None,
550            hw_inventory_by_fru_type: self.r#type.to_string(),
551            hsn_nic_fru_info,
552        };
553
554        let hsn_nic_location_info = HSNNICLocationInfo {
555            id: None,
556            name: None,
557            description: None,
558        };
559
560        HWInvByLocHSNNIC {
561            id: self.xname,
562            r#type: Some(self.r#type.to_string()),
563            ordinal: None,
564            status: None,
565            hw_inventory_by_location_type: self.r#type.to_string(),
566            populated_fru: Some(hw_inv_by_fru_hsn_nic),
567            hsn_nic_location_info,
568        }
569    }
570}
571
572impl ArtifactSummary {
573    fn from_processor_value(processor_value: Value) -> Self {
574        Self {
575            xname: processor_value["ID"].as_str().unwrap().to_string(),
576            r#type: ArtifactType::from_str(processor_value["Type"].as_str().unwrap()).unwrap(),
577            info: processor_value
578                .pointer("/PopulatedFRU/ProcessorFRUInfo/Model")
579                .map(|model| model.as_str().unwrap().to_string()),
580        }
581    }
582
583    fn from_memory_value(memory_value: Value) -> Self {
584        Self {
585            xname: memory_value["ID"].as_str().unwrap().to_string(),
586            r#type: ArtifactType::from_str(memory_value["Type"].as_str().unwrap()).unwrap(),
587            info: memory_value
588                .pointer("/PopulatedFRU/MemoryFRUInfo/CapacityMiB")
589                .map(|capacity_mib| capacity_mib.as_number().unwrap().to_string() + " MiB"),
590        }
591    }
592
593    fn from_nodehsnnics_value(nodehsnnic_value: Value) -> Self {
594        Self {
595            xname: nodehsnnic_value["ID"].as_str().unwrap().to_string(),
596            r#type: ArtifactType::from_str(nodehsnnic_value["Type"].as_str().unwrap()).unwrap(),
597            info: nodehsnnic_value
598                .pointer("/NodeHsnNicLocationInfo/Description")
599                .map(|description| description.as_str().unwrap().to_string()),
600        }
601    }
602
603    fn from_nodeaccel_value(nodeaccel_value: Value) -> Self {
604        Self {
605            xname: nodeaccel_value["ID"].as_str().unwrap().to_string(),
606            r#type: ArtifactType::from_str(nodeaccel_value["Type"].as_str().unwrap()).unwrap(),
607            info: nodeaccel_value
608                .pointer("/PopulatedFRU/NodeAccelFRUInfo/Model")
609                .map(|model| model.as_str().unwrap().to_string()),
610        }
611    }
612}
613
614// From OCHAMI API
615#[derive(Debug, Serialize, Deserialize, Clone)]
616pub struct Group {
617    pub label: String,
618    #[serde(skip_serializing_if = "Option::is_none")]
619    pub description: Option<String>,
620    #[serde(skip_serializing_if = "Option::is_none")]
621    pub tags: Option<Vec<String>>,
622    #[serde(skip_serializing_if = "Option::is_none")]
623    pub members: Option<Member>,
624    #[serde(skip_serializing_if = "Option::is_none")]
625    #[serde(rename = "exclusiveGroup")]
626    pub exclusive_group: Option<String>,
627}
628
629#[derive(Debug, Serialize, Deserialize, Default, Clone)]
630pub struct Member {
631    #[serde(skip_serializing_if = "Option::is_none")]
632    pub ids: Option<Vec<String>>,
633}
634#[derive(Debug, Serialize, Deserialize, Default, Clone)]
635pub struct XnameId {
636    #[serde(skip_serializing_if = "Option::is_none")]
637    pub id: Option<String>,
638}
639
640impl Group {
641    /// Constructor
642    pub fn new(
643        label: &str,
644        description: Option<String>,
645        member_vec_opt: Option<Vec<String>>,
646        tag_vec_opt: Option<Vec<String>>,
647        exclusive_opt: Option<String>,
648    ) -> Self {
649        let members_opt = if let Some(member_vec) = member_vec_opt {
650            Some(Member {
651                ids: Some(member_vec),
652            })
653        } else {
654            None
655        };
656
657        let group = Self {
658            label: label.to_string(),
659            description,
660            tags: tag_vec_opt,
661            members: members_opt,
662            exclusive_group: exclusive_opt,
663        };
664
665        group
666    }
667
668    /// Get group members
669    pub fn get_members(&self) -> Vec<String> {
670        self.members
671            .clone()
672            .map(|member| member.ids.unwrap_or_default())
673            .unwrap_or_default()
674    }
675}
676
677#[derive(Debug, Serialize, Deserialize, Clone)]
678pub struct NodeMetadataArray {
679    #[serde(skip_serializing_if = "Option::is_none")]
680    #[serde(rename = "Components")]
681    pub components: Option<Vec<Component>>,
682}
683
684#[derive(Debug, Serialize, Deserialize, Clone)]
685pub struct Component {
686    #[serde(skip_serializing_if = "Option::is_none")]
687    #[serde(rename = "ID")]
688    pub id: Option<String>,
689    #[serde(skip_serializing_if = "Option::is_none")]
690    #[serde(rename = "Type")]
691    pub r#type: Option<String>,
692    #[serde(skip_serializing_if = "Option::is_none")]
693    #[serde(rename = "State")]
694    pub state: Option<String>,
695    #[serde(skip_serializing_if = "Option::is_none")]
696    #[serde(rename = "Flag")]
697    pub flag: Option<String>,
698    #[serde(skip_serializing_if = "Option::is_none")]
699    #[serde(rename = "Enabled")]
700    pub enabled: Option<bool>,
701    #[serde(skip_serializing_if = "Option::is_none")]
702    #[serde(rename = "SoftwareStatus")]
703    pub software_status: Option<String>,
704    #[serde(skip_serializing_if = "Option::is_none")]
705    #[serde(rename = "Role")]
706    pub role: Option<String>,
707    #[serde(skip_serializing_if = "Option::is_none")]
708    #[serde(rename = "SubRole")]
709    pub sub_role: Option<String>,
710    #[serde(skip_serializing_if = "Option::is_none")]
711    #[serde(rename = "NID")]
712    pub nid: Option<usize>,
713    #[serde(skip_serializing_if = "Option::is_none")]
714    #[serde(rename = "Subtype")]
715    pub subtype: Option<String>,
716    #[serde(skip_serializing_if = "Option::is_none")]
717    #[serde(rename = "NetType")]
718    pub net_type: Option<String>,
719    #[serde(skip_serializing_if = "Option::is_none")]
720    #[serde(rename = "Arch")]
721    pub arch: Option<String>,
722    #[serde(skip_serializing_if = "Option::is_none")]
723    #[serde(rename = "Class")]
724    pub class: Option<String>,
725    #[serde(skip_serializing_if = "Option::is_none")]
726    #[serde(rename = "ReservationDisabled")]
727    pub reservation_disabled: Option<bool>,
728    #[serde(skip_serializing_if = "Option::is_none")]
729    #[serde(rename = "Locked")]
730    pub locked: Option<bool>,
731}
732
733#[derive(Debug, Serialize, Deserialize, Clone)]
734pub struct ComponentArrayPostQuery {
735    #[serde(skip_serializing_if = "Option::is_none")]
736    #[serde(rename = "ComponentIDs")]
737    pub component_ids: Option<Vec<String>>,
738    #[serde(skip_serializing_if = "Option::is_none")]
739    pub partition: Option<String>,
740    #[serde(skip_serializing_if = "Option::is_none")]
741    pub group: Option<String>,
742    #[serde(skip_serializing_if = "Option::is_none")]
743    #[serde(rename = "stateonly")]
744    pub state_only: Option<bool>,
745    #[serde(skip_serializing_if = "Option::is_none")]
746    #[serde(rename = "flagonly")]
747    pub falg_only: Option<bool>,
748    #[serde(skip_serializing_if = "Option::is_none")]
749    #[serde(rename = "roleonly")]
750    pub role_only: Option<bool>,
751    #[serde(skip_serializing_if = "Option::is_none")]
752    #[serde(rename = "nidonly")]
753    pub nid_only: Option<bool>,
754    #[serde(skip_serializing_if = "Option::is_none")]
755    pub r#type: Option<String>,
756    #[serde(skip_serializing_if = "Option::is_none")]
757    pub state: Option<String>,
758    #[serde(skip_serializing_if = "Option::is_none")]
759    pub flag: Option<String>,
760    #[serde(skip_serializing_if = "Option::is_none")]
761    pub enabled: Option<String>,
762    #[serde(skip_serializing_if = "Option::is_none")]
763    #[serde(rename = "softwarestatus")]
764    pub software_status: Option<String>,
765    #[serde(skip_serializing_if = "Option::is_none")]
766    pub role: Option<String>,
767    #[serde(skip_serializing_if = "Option::is_none")]
768    pub subrole: Option<String>,
769    #[serde(skip_serializing_if = "Option::is_none")]
770    pub subtype: Option<String>,
771    #[serde(skip_serializing_if = "Option::is_none")]
772    arch: Option<String>,
773    #[serde(skip_serializing_if = "Option::is_none")]
774    pub class: Option<String>,
775    #[serde(skip_serializing_if = "Option::is_none")]
776    pub nid: Option<String>,
777    #[serde(skip_serializing_if = "Option::is_none")]
778    pub nid_start: Option<String>,
779    #[serde(skip_serializing_if = "Option::is_none")]
780    pub nid_end: Option<String>,
781}
782
783#[derive(Debug, Serialize, Deserialize, Clone)]
784pub struct ComponentArrayPostByNidQuery {
785    #[serde(rename = "NIDRanges")]
786    pub nid_ranges: Vec<String>,
787    #[serde(skip_serializing_if = "Option::is_none")]
788    pub partition: Option<String>,
789    #[serde(skip_serializing_if = "Option::is_none")]
790    #[serde(rename = "stateonly")]
791    pub state_only: Option<bool>,
792    #[serde(skip_serializing_if = "Option::is_none")]
793    #[serde(rename = "flagonly")]
794    pub falg_only: Option<bool>,
795    #[serde(skip_serializing_if = "Option::is_none")]
796    #[serde(rename = "roleonly")]
797    pub role_only: Option<bool>,
798    #[serde(skip_serializing_if = "Option::is_none")]
799    #[serde(rename = "nidonly")]
800    pub nid_only: Option<bool>,
801}
802
803#[derive(Debug, Serialize, Deserialize, Clone)]
804pub struct ComponentArrayPostArray {
805    #[serde(rename = "Components")]
806    pub components: Vec<ComponentCreate>,
807    #[serde(skip_serializing_if = "Option::is_none")]
808    #[serde(rename = "Force")]
809    pub force: Option<bool>,
810}
811
812#[derive(Debug, Serialize, Deserialize, Clone)]
813pub struct ComponentCreate {
814    #[serde(rename = "ID")]
815    pub id: String,
816    #[serde(rename = "State")]
817    pub state: String,
818    #[serde(skip_serializing_if = "Option::is_none")]
819    #[serde(rename = "Flag")]
820    pub flag: Option<String>,
821    #[serde(skip_serializing_if = "Option::is_none")]
822    #[serde(rename = "Enabled")]
823    pub enabled: Option<bool>,
824    #[serde(skip_serializing_if = "Option::is_none")]
825    #[serde(rename = "SoftwareStatus")]
826    pub software_status: Option<String>,
827    #[serde(skip_serializing_if = "Option::is_none")]
828    #[serde(rename = "Role")]
829    pub role: Option<String>,
830    #[serde(skip_serializing_if = "Option::is_none")]
831    #[serde(rename = "SubRole")]
832    pub sub_role: Option<String>,
833    #[serde(skip_serializing_if = "Option::is_none")]
834    #[serde(rename = "NID")]
835    pub nid: Option<usize>,
836    #[serde(skip_serializing_if = "Option::is_none")]
837    #[serde(rename = "Subtype")]
838    pub subtype: Option<String>,
839    #[serde(skip_serializing_if = "Option::is_none")]
840    #[serde(rename = "NetType")]
841    pub net_type: Option<String>,
842    #[serde(skip_serializing_if = "Option::is_none")]
843    #[serde(rename = "Arch")]
844    pub arch: Option<String>,
845    #[serde(skip_serializing_if = "Option::is_none")]
846    #[serde(rename = "Class")]
847    pub class: Option<String>,
848}
849
850#[derive(Debug, Serialize, Deserialize, Clone)]
851pub struct ComponentPut {
852    pub component: ComponentCreate,
853    #[serde(skip_serializing_if = "Option::is_none")]
854    #[serde(rename = "Force")]
855    pub force: Option<bool>,
856}
857
858#[derive(Debug, Serialize, Deserialize, Default, Clone)]
859pub struct BootParameters {
860    #[serde(default)]
861    pub hosts: Vec<String>,
862    #[serde(skip_serializing_if = "Option::is_none")]
863    pub macs: Option<Vec<String>>,
864    #[serde(skip_serializing_if = "Option::is_none")]
865    pub nids: Option<Vec<u32>>,
866    #[serde(default)]
867    pub params: String, // FIXME: change type to HashMap<String, String> by using function
868    // bss::utils::convert_kernel_params_to_map AND create new method
869    // bss::BootParameters::num_kernel_params which returns the list of kernel parameters
870    #[serde(default)]
871    pub kernel: String,
872    #[serde(default)]
873    pub initrd: String,
874    #[serde(rename = "cloud-init")]
875    #[serde(skip_serializing_if = "Option::is_none")]
876    pub cloud_init: Option<Value>,
877}
878
879impl BootParameters {
880    // Assumes s3 path looks like:
881    // - s3://boot-images/59e0180a-3fdd-4936-bba7-14ba914ffd34/kernel
882    // - craycps-s3:s3://boot-images/59e0180a-3fdd-4936-bba7-14ba914ffd34/rootfs:3dfae8d1fa3bb2bfb18152b4f9940ad0-667:dvs:api-gw-service-nmn.local:300:nmn0,hsn0:0
883    // - url=s3://boot-images/59e0180a-3fdd-4936-bba7-14ba914ffd34/rootfs,etag=3dfae8d1fa3bb2bfb18152b4f9940ad0-667 bos_update_frequency=4h
884    pub fn get_image_id_from_s3_path(s3_path: &str) -> Option<&str> {
885        s3_path.split("/").skip(3).next()
886    }
887
888    /// Returns the image id. This function may fail since it assumes kernel path has the following
889    // FIXME: Change function signature so it returns a Result<String, Error> instead of String
890    pub fn get_boot_image(&self) -> String {
891        let params: HashMap<&str, &str> = self
892            .params
893            .split_whitespace()
894            .map(|kernel_param| {
895                kernel_param
896                    .split_once('=')
897                    .map(|(key, value)| (key.trim(), value.trim()))
898                    .unwrap_or((kernel_param, ""))
899            })
900            .collect();
901
902        // NOTE: CN nodes have UIID image id in 'root' kernel parameter
903        // Get `root` kernel parameter and split it by '/'
904        let root_kernel_param_opt = params.get("root");
905        // NOTE: CN nodes have UIID image id in 'metal.server' kernel parameter
906        // Get `root` kernel parameter and split it by '/'
907        let metal_server_kernel_param_opt = params.get("metal.server");
908
909        let boot_image_id_opt: Option<&str> = if let Some(root_kernel_param) = root_kernel_param_opt
910        {
911            Self::get_image_id_from_s3_path(root_kernel_param)
912        } else if let Some(metal_server_kernel_param) = metal_server_kernel_param_opt {
913            Self::get_image_id_from_s3_path(metal_server_kernel_param)
914        } else {
915            None
916        };
917
918        boot_image_id_opt.unwrap_or("").to_string()
919
920        /* let mut path_elem_vec = self.kernel.split("/").skip(3);
921
922        let mut image_id: String = path_elem_vec.next().unwrap_or_default().to_string();
923
924        for path_elem in path_elem_vec {
925            if !path_elem.eq("kernel") {
926                image_id = format!("{}/{}", image_id, path_elem);
927            } else {
928                break;
929            }
930        }
931
932        image_id */
933    }
934
935    /// Update boot image in kernel boot parameters and also in kernel and initrd fields if
936    /// exists. Otherwise nothing is changed. This method updates both kernel params related to
937    /// NCN and also CN
938    /// Returns a boolean that indicates if kernel parameters have change:
939    /// - kernel parameter value changed
940    ///  - number of kernel parameters have changed
941    pub fn update_boot_image(&mut self, new_image_id: &str) -> Result<bool, Error> {
942        let mut changed = false;
943        // replace image id in 'root' kernel param
944
945        // convert kernel params to a hashmap
946        let mut params: HashMap<&str, &str> = self
947            .params
948            .split_whitespace()
949            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
950            .collect();
951
952        // NOTE: CN nodes have UIID image id in 'root' kernel parameter
953        // Get `root` kernel parameter and split it by '/'
954        let root_kernel_param_rslt = params.get("root");
955
956        let mut root_kernel_param: Vec<&str> = match root_kernel_param_rslt {
957            Some(root_kernel_param) => root_kernel_param.split("/").collect::<Vec<&str>>(),
958            None => {
959                return Err(Error::Message(
960                    "ERROR - The 'root' kernel param is missing from user input".to_string(),
961                ));
962            }
963        };
964
965        // Replace image id in root kernel param with new image id
966        for current_image_id in &mut root_kernel_param {
967            // Look for any substring between '/' that matches an UUID formant and take it as
968            // the image id
969            if uuid::Uuid::try_parse(current_image_id).is_ok() {
970                if *current_image_id != new_image_id {
971                    changed = true;
972                }
973                // Replace image id in `root` kernel parameter with new value
974                *current_image_id = new_image_id;
975            }
976        }
977
978        // Create new `root` kernel param string
979        let new_root_kernel_param = root_kernel_param.join("/");
980
981        // Create new kernel parameters
982        params
983            .entry("root")
984            .and_modify(|root_param| *root_param = &new_root_kernel_param);
985
986        self.update_kernel_param("root", &new_root_kernel_param);
987
988        // replace image id in 'nmd_data' kernel param
989
990        // convert kernel params to a hashmap
991        let mut params: HashMap<&str, &str> = self
992            .params
993            .split_whitespace()
994            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
995            .map(|(key, value)| (key.trim(), value.trim()))
996            .collect();
997
998        // NOTE: NCN nodes have UUID image id in 'metal.server' kernel parameter
999        let mut metal_server_kernel_param: Vec<&str>;
1000        if let Some(metal_server_data) = params.get("metal.server") {
1001            metal_server_kernel_param = metal_server_data.split("/").collect();
1002
1003            for substring in &mut metal_server_kernel_param {
1004                if uuid::Uuid::try_parse(substring).is_ok() {
1005                    *substring = new_image_id;
1006                    changed = true;
1007                }
1008            }
1009
1010            let new_metal_server_kernel_param = metal_server_kernel_param.join("/");
1011
1012            params
1013                .entry("metal.server")
1014                .and_modify(|metal_server_param| {
1015                    *metal_server_param = &new_metal_server_kernel_param
1016                });
1017
1018            self.update_kernel_param("metal.server", &new_metal_server_kernel_param);
1019
1020            // convert kernel params to a hashmap
1021            params = self
1022                .params
1023                .split_whitespace()
1024                .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1025                .collect();
1026        } else {
1027        };
1028
1029        // NOTE: NCN nodes have UUID image id 'nmd_data' kernel parameter
1030        let mut nmd_kernel_param: Vec<&str>;
1031        if let Some(nmd_data) = params.get("nmd_data") {
1032            nmd_kernel_param = nmd_data.split("/").collect();
1033
1034            for substring in &mut nmd_kernel_param {
1035                if uuid::Uuid::try_parse(substring).is_ok() {
1036                    *substring = new_image_id;
1037                    changed = true;
1038                }
1039            }
1040
1041            let new_nmd_kernel_param = nmd_kernel_param.join("/");
1042
1043            params
1044                .entry("nmd_data")
1045                .and_modify(|nmd_param| *nmd_param = &new_nmd_kernel_param);
1046
1047            self.update_kernel_param("nmd_data", &new_nmd_kernel_param);
1048        } else {
1049        };
1050
1051        self.kernel = format!("s3://boot-images/{}/kernel", new_image_id);
1052
1053        self.initrd = format!("s3://boot-images/{}/initrd", new_image_id);
1054
1055        Ok(changed)
1056    }
1057
1058    /// Set a str of kernel parameters:
1059    ///  - if kernel parameter already exists, then it will be updated
1060    ///  - if kernel parameter does not exists, then it will be added
1061    /// Returns true if kernel params have change
1062    pub fn update_kernel_params(&mut self, new_params: &str) -> bool {
1063        let mut change = false;
1064
1065        let new_params: Vec<(&str, &str)> = new_params
1066            .split_whitespace()
1067            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1068            .map(|(key, value)| (key.trim(), value.trim()))
1069            .collect();
1070
1071        let mut params: HashMap<&str, &str> = self
1072            .params
1073            .split_whitespace()
1074            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1075            .collect();
1076
1077        for (new_key, new_value) in &new_params {
1078            for (key, value) in params.iter_mut() {
1079                if *key == *new_key {
1080                    log::debug!("key '{}' found", key);
1081                    if value != new_value {
1082                        log::info!("changing key {} from {} to {}", key, value, new_value);
1083
1084                        *value = new_value;
1085                        change = true
1086                    } else {
1087                        log::debug!("key '{}' value does not change ({})", key, value);
1088                    }
1089                }
1090            }
1091        }
1092
1093        if change == false {
1094            log::debug!("No value change in kernel params. Checking is either new params have been added or removed");
1095            if new_params.len() != params.len() {
1096                log::info!("num kernel parameters have changed");
1097                change = true;
1098            }
1099        }
1100
1101        self.params = params
1102            .iter()
1103            .map(|(key, value)| {
1104                if !value.is_empty() {
1105                    format!("{key}={value}")
1106                } else {
1107                    key.to_string()
1108                }
1109            })
1110            .collect::<Vec<String>>()
1111            .join(" ");
1112
1113        change
1114    }
1115
1116    /// Update kernel parameter. If kernel parameter exists, then it will be updated with new
1117    /// Note: This function won't make any change to params without values (eg: 'quiet') since
1118    /// they don't have values
1119    /// value. otherwise nothing will change
1120    pub fn update_kernel_param(&mut self, new_key: &str, new_value: &str) -> bool {
1121        let mut changed = false;
1122        // convert kernel params to a hashmap
1123        let mut params: HashMap<&str, &str> = self
1124            .params
1125            .split_whitespace()
1126            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1127            .map(|(key, value)| (key.trim(), value.trim()))
1128            .collect();
1129
1130        // Update kernel param with new value
1131        // params.entry(key).and_modify(|value| *value = new_value);
1132        for (current_key, current_value) in params.iter_mut() {
1133            if *current_key == new_key {
1134                log::debug!("key '{}' found", new_key);
1135                if *current_value != new_value {
1136                    log::info!(
1137                        "changing key {} from {} to {}",
1138                        new_key,
1139                        current_value,
1140                        new_value
1141                    );
1142
1143                    *current_value = new_value;
1144                    changed = true
1145                } else {
1146                    log::debug!(
1147                        "key '{}' value does not change ({})",
1148                        new_key,
1149                        current_value
1150                    );
1151                }
1152            }
1153            /* if *current_key == new_key {
1154                *current_value = new_value;
1155                changed = true;
1156            } */
1157        }
1158
1159        // Create new kernel params as a string
1160        self.params = params
1161            .iter()
1162            .map(|(key, value)| {
1163                if !value.is_empty() {
1164                    format!("{key}={value}")
1165                } else {
1166                    key.to_string()
1167                }
1168            })
1169            .collect::<Vec<String>>()
1170            .join(" ");
1171
1172        changed
1173    }
1174
1175    /// Add a kernel parameter:
1176    ///  - if kernel parameter does not exists, then it will be added,
1177    /// otherwise nothing will change
1178    /// Returns true if kernel params have change
1179    pub fn add_kernel_params(&mut self, new_kernel_params: &str) -> bool {
1180        let mut changed = false;
1181        let mut params: HashMap<&str, &str> = self
1182            .params
1183            .split_whitespace()
1184            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1185            .map(|(key, value)| (key.trim(), value.trim()))
1186            .collect();
1187
1188        let new_kernel_params_tuple: HashMap<&str, &str> = new_kernel_params
1189            .split_whitespace()
1190            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1191            .collect();
1192
1193        for (key, new_value) in new_kernel_params_tuple {
1194            // NOTE: do not use --> `params.entry(key).or_insert(new_value);` otherwise, I don't know
1195            // how do we know if the key already exists or not
1196            if params.contains_key(key) {
1197                log::info!("key '{}' already exists, the new kernel parameter won't be added since it already exists", key);
1198            } else {
1199                log::info!(
1200                    "key '{}' not found, adding new kernel param with value '{}'",
1201                    key,
1202                    new_value
1203                );
1204                params.insert(key, new_value);
1205                changed = true
1206            }
1207        }
1208
1209        self.params = params
1210            .iter()
1211            .map(|(key, value)| {
1212                if !value.is_empty() {
1213                    format!("{key}={value}")
1214                } else {
1215                    key.to_string()
1216                }
1217            })
1218            .collect::<Vec<String>>()
1219            .join(" ");
1220
1221        changed
1222    }
1223
1224    /// Delete kernel parameter. If kernel parameter exists, then it will be removed, otherwise
1225    /// nothing will be changed
1226    /// It accepts kernel params in format 'key=value' or just 'key'
1227    /// Returns true if kernel params have change
1228    pub fn delete_kernel_params(&mut self, kernel_params_to_delete: &str) -> bool {
1229        let mut changed = false;
1230        let mut params: HashMap<&str, &str> = self
1231            .params
1232            .split_whitespace()
1233            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1234            .map(|(key, value)| (key.trim(), value.trim()))
1235            .collect();
1236
1237        let kernel_params_to_delete_tuple: HashMap<&str, &str> = kernel_params_to_delete
1238            .split_whitespace()
1239            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1240            .collect();
1241
1242        for (key, _value) in kernel_params_to_delete_tuple {
1243            log::debug!("key '{}' to be removed", key);
1244
1245            changed = changed | params.remove(key).is_some();
1246
1247            if changed {
1248                log::debug!("key '{}' removed", key);
1249            } else {
1250                log::debug!("key '{}' not found", key);
1251            }
1252        }
1253
1254        self.params = params
1255            .iter()
1256            .map(|(key, value)| {
1257                if !value.is_empty() {
1258                    format!("{key}={value}")
1259                } else {
1260                    key.to_string()
1261                }
1262            })
1263            .collect::<Vec<String>>()
1264            .join(" ");
1265
1266        changed
1267    }
1268
1269    /// Apply a str of kernel parameters:
1270    ///  - current kernel params will be ignored/removed and replaced by the new ones
1271    /// Returns true if kernel params have change
1272    // FIXME: integrate fixed introduced in methods 'add_kernel_param' and 'delete_kernel_param'
1273    pub fn apply_kernel_params(&mut self, new_params: &str) -> bool {
1274        let mut change = false;
1275
1276        let new_params: Vec<(&str, &str)> = new_params
1277            .split_whitespace()
1278            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1279            .map(|(key, value)| (key.trim(), value.trim()))
1280            .collect();
1281
1282        let mut params: HashMap<&str, &str> = HashMap::new();
1283
1284        for (new_key, new_value) in &new_params {
1285            for (key, value) in params.iter_mut() {
1286                if *key == *new_key {
1287                    log::debug!("key '{}' found", key);
1288                    if value != new_value {
1289                        log::info!("changing key {} from {} to {}", key, value, new_value);
1290
1291                        *value = new_value;
1292                        change = true
1293                    } else {
1294                        log::debug!("key '{}' value does not change ({})", key, value);
1295                    }
1296                }
1297            }
1298        }
1299
1300        if change == false {
1301            log::debug!("No value change in kernel params. Checking is either new params have been added or removed");
1302            if new_params.len() != params.len() {
1303                log::info!("num kernel parameters have changed");
1304                change = true;
1305            }
1306        }
1307
1308        self.params = new_params
1309            .iter()
1310            .map(|(key, value)| {
1311                if !value.is_empty() {
1312                    format!("{key}={value}")
1313                } else {
1314                    key.to_string()
1315                }
1316            })
1317            .collect::<Vec<String>>()
1318            .join(" ");
1319
1320        change
1321    }
1322}
1323
1324#[derive(Debug, Serialize, Deserialize)]
1325pub enum ComponentType {
1326    CDU,
1327    CabinetCDU,
1328    CabinetPDU,
1329    CabinetPDUOutlet,
1330    CabinetPDUPowerConnector,
1331    CabinetPDUController,
1332    r#Cabinet,
1333    Chassis,
1334    ChassisBMC,
1335    CMMRectifier,
1336    CMMFpga,
1337    CEC,
1338    ComputeModule,
1339    RouterModule,
1340    NodeBMC,
1341    NodeEnclosure,
1342    NodeEnclosurePowerSupply,
1343    HSNBoard,
1344    Node,
1345    Processor,
1346    Drive,
1347    StorageGroup,
1348    NodeNIC,
1349    Memory,
1350    NodeAccel,
1351    NodeAccelRiser,
1352    NodeFpga,
1353    HSNAsic,
1354    RouterFpga,
1355    RouterBMC,
1356    HSNLink,
1357    HSNConnector,
1358    INVALID,
1359}
1360
1361#[derive(Debug, Serialize, Deserialize, Clone)]
1362pub struct ProcessorId {
1363    #[serde(rename = "EffectiveFamily")]
1364    #[serde(skip_serializing_if = "Option::is_none")]
1365    pub effective_family: Option<String>,
1366    #[serde(rename = "EffectiveModel")]
1367    #[serde(skip_serializing_if = "Option::is_none")]
1368    pub efffective_model: Option<String>,
1369    #[serde(rename = "IdentificationRegisters")]
1370    #[serde(skip_serializing_if = "Option::is_none")]
1371    pub identification_registers: Option<String>,
1372    #[serde(rename = "MicrocodeInfo")]
1373    #[serde(skip_serializing_if = "Option::is_none")]
1374    pub microcode_info: Option<String>,
1375    #[serde(rename = "Step")]
1376    #[serde(skip_serializing_if = "Option::is_none")]
1377    pub step: Option<String>,
1378    #[serde(rename = "VendorId")]
1379    #[serde(skip_serializing_if = "Option::is_none")]
1380    pub vendor_id: Option<String>,
1381}
1382
1383#[derive(Debug, Serialize, Deserialize, Clone)]
1384pub struct HWInvByFRUProcessor {
1385    #[serde(rename = "FRUID")]
1386    #[serde(skip_serializing_if = "Option::is_none")]
1387    pub fru_id: Option<String>,
1388    #[serde(rename = "Type")]
1389    #[serde(skip_serializing_if = "Option::is_none")]
1390    pub r#type: Option<String>,
1391    #[serde(rename = "FRUSubType")]
1392    #[serde(skip_serializing_if = "Option::is_none")]
1393    pub fru_sub_type: Option<String>,
1394    #[serde(rename = "HWInventoryByFRUType")]
1395    pub hw_inventory_by_fru_type: String,
1396    #[serde(rename = "ProcessorFRUInfo")]
1397    pub processor_fru_info: RedfishProcessorFRUInfo,
1398}
1399
1400#[derive(Debug, Serialize, Deserialize, Clone)]
1401pub struct HWInvByFRUMemory {
1402    #[serde(rename = "FRUID")]
1403    #[serde(skip_serializing_if = "Option::is_none")]
1404    pub fru_id: Option<String>,
1405    #[serde(rename = "Type")]
1406    #[serde(skip_serializing_if = "Option::is_none")]
1407    pub r#type: Option<String>,
1408    #[serde(rename = "FRUSubType")]
1409    #[serde(skip_serializing_if = "Option::is_none")]
1410    pub fru_sub_type: Option<String>,
1411    #[serde(rename = "HWInventoryByFRUType")]
1412    pub hw_inventory_by_fru_type: String,
1413    #[serde(rename = "MemoryFRUInfo")]
1414    pub memory_fru_info: RedfishMemoryFRUInfo,
1415}
1416
1417#[derive(Debug, Serialize, Deserialize, Clone)]
1418pub struct HWInvByFRUHSNNIC {
1419    #[serde(rename = "FRUID")]
1420    #[serde(skip_serializing_if = "Option::is_none")]
1421    pub fru_id: Option<String>,
1422    #[serde(rename = "Type")]
1423    #[serde(skip_serializing_if = "Option::is_none")]
1424    pub r#type: Option<String>,
1425    #[serde(rename = "FRUSubType")]
1426    #[serde(skip_serializing_if = "Option::is_none")]
1427    pub fru_sub_type: Option<String>,
1428    #[serde(rename = "HWInventoryByFRUType")]
1429    pub hw_inventory_by_fru_type: String,
1430    #[serde(rename = "HSNNICFRUInfo")]
1431    pub hsn_nic_fru_info: HSNNICFRUInfo,
1432}
1433
1434#[derive(Debug, Serialize, Deserialize, Clone)]
1435pub struct HWInvByFRUNodeAccel {
1436    #[serde(rename = "FRUID")]
1437    #[serde(skip_serializing_if = "Option::is_none")]
1438    pub fru_id: Option<String>,
1439    #[serde(rename = "Type")]
1440    #[serde(skip_serializing_if = "Option::is_none")]
1441    pub r#type: Option<String>,
1442    #[serde(rename = "FRUSubType")]
1443    #[serde(skip_serializing_if = "Option::is_none")]
1444    pub fru_sub_type: Option<String>,
1445    #[serde(rename = "HWInventoryByFRUType")]
1446    pub hw_inventory_by_fru_type: String,
1447    #[serde(rename = "NodeAccelFRUInfo")]
1448    pub node_accel_fru_info: RedfishProcessorFRUInfo, // NOTE: yes, sounds weird FRU for node accelerator uses FRU for processor... but that is
1449                                                      // what the API docs says...
1450}
1451
1452#[derive(Debug, Serialize, Deserialize, Clone)]
1453pub struct RedfishProcessorFRUInfo {
1454    #[serde(rename = "InstructionSet")]
1455    #[serde(skip_serializing_if = "Option::is_none")]
1456    pub instruction_set: Option<String>,
1457    #[serde(rename = "Manufacturer")]
1458    #[serde(skip_serializing_if = "Option::is_none")]
1459    pub manufacturer: Option<String>,
1460    #[serde(rename = "MaxSpeedMHz")]
1461    #[serde(skip_serializing_if = "Option::is_none")]
1462    pub max_speed_mhz: Option<usize>,
1463    #[serde(rename = "Model")]
1464    #[serde(skip_serializing_if = "Option::is_none")]
1465    pub model: Option<String>,
1466    #[serde(rename = "ProcessorArchitecture")]
1467    #[serde(skip_serializing_if = "Option::is_none")]
1468    pub processor_architecture: Option<String>,
1469    #[serde(rename = "ProcessorId")]
1470    #[serde(skip_serializing_if = "Option::is_none")]
1471    pub processor_id: Option<ProcessorId>,
1472    #[serde(rename = "ProcessorType")]
1473    #[serde(skip_serializing_if = "Option::is_none")]
1474    pub processor_type: Option<String>,
1475    #[serde(rename = "TotalCores")]
1476    #[serde(skip_serializing_if = "Option::is_none")]
1477    pub total_cores: Option<usize>,
1478    #[serde(rename = "TotalThreads")]
1479    #[serde(skip_serializing_if = "Option::is_none")]
1480    pub total_threads: Option<usize>,
1481}
1482
1483#[derive(Debug, Serialize, Deserialize, Clone)]
1484pub struct RedfishMemoryFRUInfo {
1485    #[serde(rename = "BaseModuleType")]
1486    #[serde(skip_serializing_if = "Option::is_none")]
1487    pub base_module_type: Option<String>,
1488    #[serde(rename = "BusWidthBits")]
1489    #[serde(skip_serializing_if = "Option::is_none")]
1490    pub bus_width_bits: Option<usize>,
1491    #[serde(rename = "CapacityMiB")]
1492    #[serde(skip_serializing_if = "Option::is_none")]
1493    pub capacity_mib: Option<usize>,
1494    #[serde(rename = "DataWidthBits")]
1495    #[serde(skip_serializing_if = "Option::is_none")]
1496    pub data_width_bits: Option<usize>,
1497    #[serde(rename = "ErrorCorrection")]
1498    #[serde(skip_serializing_if = "Option::is_none")]
1499    pub error_correction: Option<String>,
1500    #[serde(rename = "Manufacturer")]
1501    #[serde(skip_serializing_if = "Option::is_none")]
1502    pub manufacturer: Option<String>,
1503    #[serde(rename = "MemoryType")]
1504    #[serde(skip_serializing_if = "Option::is_none")]
1505    pub memory_type: Option<String>,
1506    #[serde(rename = "MemoryDeviceType")]
1507    #[serde(skip_serializing_if = "Option::is_none")]
1508    pub memory_device_type: Option<String>,
1509    #[serde(rename = "OperatingSpeedMhz")]
1510    #[serde(skip_serializing_if = "Option::is_none")]
1511    pub operating_speed_mhz: Option<usize>,
1512    #[serde(rename = "PartNumber")]
1513    #[serde(skip_serializing_if = "Option::is_none")]
1514    pub part_number: Option<String>,
1515    #[serde(rename = "RankCount")]
1516    #[serde(skip_serializing_if = "Option::is_none")]
1517    pub rank_count: Option<usize>,
1518    #[serde(rename = "SerialNumber")]
1519    #[serde(skip_serializing_if = "Option::is_none")]
1520    pub serial_number: Option<String>,
1521}
1522
1523#[derive(Debug, Serialize, Deserialize, Clone)]
1524pub struct HWInventoryByFRU {
1525    #[serde(rename = "FRUID")]
1526    #[serde(skip_serializing_if = "Option::is_none")]
1527    pub fru_id: Option<String>,
1528    #[serde(rename = "Type")]
1529    #[serde(skip_serializing_if = "Option::is_none")]
1530    pub r#type: Option<String>,
1531    #[serde(rename = "FRUSubType")]
1532    #[serde(skip_serializing_if = "Option::is_none")]
1533    pub fru_sub_type: Option<String>,
1534    #[serde(rename = "HWInventoryByFRUType")]
1535    pub hw_inventory_by_fru_type: String,
1536}
1537
1538#[derive(Debug, Serialize, Deserialize, Clone)]
1539pub struct RedfishChassisLocationInfo {
1540    #[serde(rename = "Id")]
1541    #[serde(skip_serializing_if = "Option::is_none")]
1542    pub id: Option<String>,
1543    #[serde(rename = "Name")]
1544    #[serde(skip_serializing_if = "Option::is_none")]
1545    pub name: Option<String>,
1546    #[serde(rename = "Description")]
1547    #[serde(skip_serializing_if = "Option::is_none")]
1548    pub description: Option<String>,
1549    #[serde(rename = "Hostname")]
1550    #[serde(skip_serializing_if = "Option::is_none")]
1551    pub hostname: Option<String>,
1552}
1553
1554#[derive(Debug, Serialize, Deserialize, Clone)]
1555pub struct HWInvByLocChassis {
1556    #[serde(rename = "ID")]
1557    pub id: String,
1558    #[serde(rename = "Type")]
1559    #[serde(skip_serializing_if = "Option::is_none")]
1560    pub r#type: Option<String>,
1561    #[serde(rename = "Ordinal")]
1562    #[serde(skip_serializing_if = "Option::is_none")]
1563    pub ordinal: Option<u32>,
1564    #[serde(rename = "Status")]
1565    #[serde(skip_serializing_if = "Option::is_none")]
1566    pub status: Option<String>,
1567    #[serde(rename = "HWInventoryByLocationType")]
1568    pub hw_inventory_by_location_type: String,
1569    #[serde(rename = "PopulatedFRU")]
1570    #[serde(skip_serializing_if = "Option::is_none")]
1571    pub populated_fru: Option<HWInventoryByFRU>,
1572    #[serde(rename = "ChassisLocatinInfo")]
1573    #[serde(skip_serializing_if = "Option::is_none")]
1574    pub chassis_location_info: Option<RedfishChassisLocationInfo>,
1575    #[serde(rename = "ComputeModules")]
1576    #[serde(skip_serializing_if = "Option::is_none")]
1577    pub compute_modules: Option<HWInvByLocComputeModule>,
1578    #[serde(rename = "RouterModules")]
1579    #[serde(skip_serializing_if = "Option::is_none")]
1580    pub router_modules: Option<HWInvByLocRouterModule>,
1581}
1582
1583#[derive(Debug, Serialize, Deserialize, Clone)]
1584pub struct HWInvByLocNodeEnclosure {
1585    #[serde(rename = "ID")]
1586    pub id: String,
1587    #[serde(rename = "Type")]
1588    #[serde(skip_serializing_if = "Option::is_none")]
1589    pub r#type: Option<String>,
1590    #[serde(rename = "Ordinal")]
1591    #[serde(skip_serializing_if = "Option::is_none")]
1592    pub ordinal: Option<u32>,
1593    #[serde(rename = "Status")]
1594    #[serde(skip_serializing_if = "Option::is_none")]
1595    pub status: Option<String>,
1596    #[serde(rename = "HWInventoryByLocationType")]
1597    pub hw_inventory_by_location_type: String,
1598    #[serde(rename = "PopulatedFRU")]
1599    #[serde(skip_serializing_if = "Option::is_none")]
1600    pub populated_fru: Option<HWInventoryByFRU>,
1601    #[serde(rename = "NodeEnclosureLocationInfo")]
1602    #[serde(skip_serializing_if = "Option::is_none")]
1603    pub node_enclosure_location_info: Option<RedfishChassisLocationInfo>,
1604}
1605
1606#[derive(Debug, Serialize, Deserialize, Clone)]
1607pub struct HWInvByLocComputeModule {
1608    #[serde(rename = "ID")]
1609    pub id: String,
1610    #[serde(rename = "Type")]
1611    #[serde(skip_serializing_if = "Option::is_none")]
1612    pub r#type: Option<String>,
1613    #[serde(rename = "Ordinal")]
1614    #[serde(skip_serializing_if = "Option::is_none")]
1615    pub ordinal: Option<u32>,
1616    #[serde(rename = "Status")]
1617    #[serde(skip_serializing_if = "Option::is_none")]
1618    pub status: Option<String>,
1619    #[serde(rename = "HWInventoryByLocationType")]
1620    pub hw_inventory_by_location_type: String,
1621    #[serde(rename = "PopulatedFRU")]
1622    #[serde(skip_serializing_if = "Option::is_none")]
1623    pub populated_fru: Option<HWInventoryByFRU>,
1624    #[serde(rename = "ComputeModuleLocationInfo")]
1625    #[serde(skip_serializing_if = "Option::is_none")]
1626    pub compute_module_location_info: Option<RedfishChassisLocationInfo>,
1627    #[serde(rename = "NodeEnclosures")]
1628    #[serde(skip_serializing_if = "Option::is_none")]
1629    pub node_enclosures: Option<HWInvByLocNodeEnclosure>,
1630}
1631
1632#[derive(Debug, Serialize, Deserialize, Clone)]
1633pub struct HWInvByLocHSNBoard {
1634    #[serde(rename = "ID")]
1635    pub id: String,
1636    #[serde(rename = "Type")]
1637    #[serde(skip_serializing_if = "Option::is_none")]
1638    pub r#type: Option<String>,
1639    #[serde(rename = "Ordinal")]
1640    #[serde(skip_serializing_if = "Option::is_none")]
1641    pub ordinal: Option<u32>,
1642    #[serde(rename = "Status")]
1643    #[serde(skip_serializing_if = "Option::is_none")]
1644    pub status: Option<String>,
1645    #[serde(rename = "HWInventoryByLocationType")]
1646    pub hw_inventory_by_location_type: String,
1647    #[serde(rename = "PopulatedFRU")]
1648    #[serde(skip_serializing_if = "Option::is_none")]
1649    pub populated_fru: Option<HWInventoryByFRU>,
1650    #[serde(rename = "HSNBoardLocationInfo")]
1651    #[serde(skip_serializing_if = "Option::is_none")]
1652    pub hsn_board_location_info: Option<RedfishChassisLocationInfo>,
1653}
1654
1655#[derive(Debug, Serialize, Deserialize, Clone)]
1656pub struct HWInvByLocRouterModule {
1657    #[serde(rename = "ID")]
1658    pub id: String,
1659    #[serde(rename = "Type")]
1660    #[serde(skip_serializing_if = "Option::is_none")]
1661    pub r#type: Option<String>,
1662    #[serde(rename = "Ordinal")]
1663    #[serde(skip_serializing_if = "Option::is_none")]
1664    pub ordinal: Option<u32>,
1665    #[serde(rename = "Status")]
1666    #[serde(skip_serializing_if = "Option::is_none")]
1667    pub status: Option<String>,
1668    #[serde(rename = "HWInventoryByLocationType")]
1669    pub hw_inventory_by_location_type: String,
1670    #[serde(rename = "PopulatedFRU")]
1671    #[serde(skip_serializing_if = "Option::is_none")]
1672    pub populated_fru: Option<HWInventoryByFRU>,
1673    #[serde(rename = "RouterModuleLocationInfo")]
1674    #[serde(skip_serializing_if = "Option::is_none")]
1675    pub router_module_location_info: Option<RedfishChassisLocationInfo>,
1676    pub hsn_boards: Option<HWInvByLocHSNBoard>,
1677}
1678
1679#[derive(Debug, Serialize, Deserialize, Clone)]
1680pub struct HWInvByLocCabinet {
1681    #[serde(rename = "ID")]
1682    pub id: String,
1683    #[serde(rename = "Type")]
1684    #[serde(skip_serializing_if = "Option::is_none")]
1685    pub r#type: Option<String>,
1686    #[serde(rename = "Ordinal")]
1687    #[serde(skip_serializing_if = "Option::is_none")]
1688    pub ordinal: Option<u32>,
1689    #[serde(rename = "Status")]
1690    #[serde(skip_serializing_if = "Option::is_none")]
1691    pub status: Option<String>,
1692    #[serde(rename = "HWInventoryByLocationType")]
1693    pub hw_inventory_by_location_type: String,
1694    #[serde(rename = "PopulatedFRU")]
1695    #[serde(skip_serializing_if = "Option::is_none")]
1696    pub populated_fru: Option<HWInventoryByFRU>,
1697    #[serde(rename = "CabinetLocationInfo")]
1698    #[serde(skip_serializing_if = "Option::is_none")]
1699    pub cabinet_location_info: Option<RedfishChassisLocationInfo>,
1700    #[serde(rename = "Chassis")]
1701    #[serde(skip_serializing_if = "Option::is_none")]
1702    pub chassis: Option<HWInvByLocChassis>,
1703}
1704
1705#[derive(Debug, Serialize, Deserialize, Clone)]
1706pub struct HWInvByLocMgmtSwitch {
1707    #[serde(rename = "ID")]
1708    pub id: String,
1709    #[serde(rename = "Type")]
1710    #[serde(skip_serializing_if = "Option::is_none")]
1711    pub r#type: Option<String>,
1712    #[serde(rename = "Ordinal")]
1713    #[serde(skip_serializing_if = "Option::is_none")]
1714    pub ordinal: Option<u32>,
1715    #[serde(rename = "Status")]
1716    #[serde(skip_serializing_if = "Option::is_none")]
1717    pub status: Option<String>,
1718    #[serde(rename = "HWInventoryByLocationType")]
1719    pub hw_inventory_by_location_type: String,
1720    #[serde(rename = "PopulatedFRU")]
1721    #[serde(skip_serializing_if = "Option::is_none")]
1722    pub populated_fru: Option<HWInventoryByFRU>,
1723    #[serde(rename = "MgmtSwitchLocationInfo")]
1724    #[serde(skip_serializing_if = "Option::is_none")]
1725    pub mgmt_switch_location_info: Option<RedfishChassisLocationInfo>,
1726}
1727
1728#[derive(Debug, Serialize, Deserialize, Clone)]
1729pub struct HWInvByLocMgmtHLSwitch {
1730    #[serde(rename = "ID")]
1731    pub id: String,
1732    #[serde(rename = "Type")]
1733    #[serde(skip_serializing_if = "Option::is_none")]
1734    pub r#type: Option<String>,
1735    #[serde(rename = "Ordinal")]
1736    #[serde(skip_serializing_if = "Option::is_none")]
1737    pub ordinal: Option<u32>,
1738    #[serde(rename = "Status")]
1739    #[serde(skip_serializing_if = "Option::is_none")]
1740    pub status: Option<String>,
1741    #[serde(rename = "HWInventoryByLocationType")]
1742    pub hw_inventory_by_location_type: String,
1743    #[serde(rename = "PopulatedFRU")]
1744    #[serde(skip_serializing_if = "Option::is_none")]
1745    pub populated_fru: Option<HWInventoryByFRU>,
1746    #[serde(rename = "MgmtHLSwitchLocationInfo")]
1747    #[serde(skip_serializing_if = "Option::is_none")]
1748    pub mgmt_hl_switch_location_info: Option<RedfishChassisLocationInfo>,
1749}
1750
1751#[derive(Debug, Serialize, Deserialize, Clone)]
1752pub struct HWInvByLocCDUMgmtSwitch {
1753    #[serde(rename = "ID")]
1754    pub id: String,
1755    #[serde(rename = "Type")]
1756    #[serde(skip_serializing_if = "Option::is_none")]
1757    pub r#type: Option<String>,
1758    #[serde(rename = "Ordinal")]
1759    #[serde(skip_serializing_if = "Option::is_none")]
1760    pub ordinal: Option<u32>,
1761    #[serde(rename = "Status")]
1762    #[serde(skip_serializing_if = "Option::is_none")]
1763    pub status: Option<String>,
1764    #[serde(rename = "HWInventoryByLocationType")]
1765    pub hw_inventory_by_location_type: String,
1766    #[serde(rename = "PopulatedFRU")]
1767    #[serde(skip_serializing_if = "Option::is_none")]
1768    pub populated_fru: Option<HWInventoryByFRU>,
1769    #[serde(rename = "CDUMgmtSwitchLocationInfo")]
1770    #[serde(skip_serializing_if = "Option::is_none")]
1771    pub cdu_mgmt_switch_location_info: Option<RedfishChassisLocationInfo>,
1772}
1773
1774#[derive(Debug, Serialize, Deserialize, Clone)]
1775pub struct ProcessorSummary {
1776    #[serde(rename = "Count")]
1777    #[serde(skip_serializing_if = "Option::is_none")]
1778    pub count: Option<u32>,
1779    #[serde(rename = "Model")]
1780    #[serde(skip_serializing_if = "Option::is_none")]
1781    pub model: Option<String>,
1782}
1783
1784#[derive(Debug, Serialize, Deserialize, Clone)]
1785pub struct MemorySummary {
1786    #[serde(rename = "TotalSystemMemoryGiB")]
1787    #[serde(skip_serializing_if = "Option::is_none")]
1788    pub total_system_memory_gib: Option<u32>,
1789}
1790
1791#[derive(Debug, Serialize, Deserialize, Clone)]
1792pub struct RedfishSystemLocationInfo {
1793    #[serde(rename = "Id")]
1794    #[serde(skip_serializing_if = "Option::is_none")]
1795    pub id: Option<String>,
1796    #[serde(rename = "Name")]
1797    #[serde(skip_serializing_if = "Option::is_none")]
1798    pub name: Option<String>,
1799    #[serde(rename = "Description")]
1800    #[serde(skip_serializing_if = "Option::is_none")]
1801    pub description: Option<String>,
1802    #[serde(rename = "Hostname")]
1803    #[serde(skip_serializing_if = "Option::is_none")]
1804    pub hostname: Option<String>,
1805    #[serde(rename = "ProcessorSummary")]
1806    #[serde(skip_serializing_if = "Option::is_none")]
1807    pub processor_summary: Option<ProcessorSummary>,
1808    #[serde(rename = "MemorySummary")]
1809    #[serde(skip_serializing_if = "Option::is_none")]
1810    pub memory_summary: Option<MemorySummary>,
1811}
1812
1813#[derive(Debug, Serialize, Deserialize, Clone)]
1814pub struct RedfishProcessorLocationInfo {
1815    #[serde(rename = "Id")]
1816    #[serde(skip_serializing_if = "Option::is_none")]
1817    pub id: Option<String>,
1818    #[serde(rename = "Name")]
1819    #[serde(skip_serializing_if = "Option::is_none")]
1820    pub name: Option<String>,
1821    #[serde(rename = "Description")]
1822    #[serde(skip_serializing_if = "Option::is_none")]
1823    pub description: Option<String>,
1824    #[serde(rename = "Socket")]
1825    #[serde(skip_serializing_if = "Option::is_none")]
1826    pub socket: Option<String>,
1827}
1828
1829#[derive(Debug, Serialize, Deserialize, Clone)]
1830pub struct HWInvByLocProcessor {
1831    #[serde(rename = "ID")]
1832    pub id: String,
1833    #[serde(rename = "Type")]
1834    #[serde(skip_serializing_if = "Option::is_none")]
1835    pub r#type: Option<String>,
1836    #[serde(rename = "Ordinal")]
1837    #[serde(skip_serializing_if = "Option::is_none")]
1838    pub ordinal: Option<u32>,
1839    #[serde(rename = "Status")]
1840    #[serde(skip_serializing_if = "Option::is_none")]
1841    pub status: Option<String>,
1842    #[serde(rename = "HWInventoryByLocationType")]
1843    pub hw_inventory_by_location_type: String,
1844    #[serde(rename = "PopulatedFRU")]
1845    #[serde(skip_serializing_if = "Option::is_none")]
1846    pub populated_fru: Option<HWInvByFRUProcessor>,
1847    #[serde(rename = "ProcessorLocationInfo")]
1848    pub processor_location_info: RedfishProcessorLocationInfo,
1849}
1850
1851#[derive(Debug, Serialize, Deserialize, Clone)]
1852pub struct HWInvByLocNodeAccel {
1853    #[serde(rename = "ID")]
1854    pub id: String,
1855    #[serde(rename = "Type")]
1856    #[serde(skip_serializing_if = "Option::is_none")]
1857    pub r#type: Option<String>,
1858    #[serde(rename = "Ordinal")]
1859    #[serde(skip_serializing_if = "Option::is_none")]
1860    pub ordinal: Option<u32>,
1861    #[serde(rename = "Status")]
1862    #[serde(skip_serializing_if = "Option::is_none")]
1863    pub status: Option<String>,
1864    #[serde(rename = "HWInventoryByLocationType")]
1865    pub hw_inventory_by_location_type: String,
1866    #[serde(rename = "PopulatedFRU")]
1867    #[serde(skip_serializing_if = "Option::is_none")]
1868    pub populated_fru: Option<HWInvByFRUNodeAccel>,
1869    #[serde(rename = "NodeAccelLocationInfo")]
1870    #[serde(skip_serializing_if = "Option::is_none")]
1871    pub node_accel_location_info: Option<RedfishProcessorLocationInfo>,
1872}
1873
1874#[derive(Debug, Serialize, Deserialize, Clone)]
1875pub struct RedfishDriveLocationInfo {
1876    #[serde(rename = "Id")]
1877    #[serde(skip_serializing_if = "Option::is_none")]
1878    pub id: Option<String>,
1879    #[serde(rename = "Name")]
1880    #[serde(skip_serializing_if = "Option::is_none")]
1881    pub name: Option<String>,
1882    #[serde(rename = "Description")]
1883    #[serde(skip_serializing_if = "Option::is_none")]
1884    pub description: Option<String>,
1885}
1886
1887#[derive(Debug, Serialize, Deserialize, Clone)]
1888pub struct HWInvByLocDrive {
1889    #[serde(rename = "ID")]
1890    pub id: String,
1891    #[serde(rename = "Type")]
1892    #[serde(skip_serializing_if = "Option::is_none")]
1893    pub r#type: Option<String>,
1894    #[serde(rename = "Ordinal")]
1895    #[serde(skip_serializing_if = "Option::is_none")]
1896    pub ordinal: Option<u32>,
1897    #[serde(rename = "Status")]
1898    #[serde(skip_serializing_if = "Option::is_none")]
1899    pub status: Option<String>,
1900    #[serde(rename = "HWInventoryByLocationType")]
1901    pub hw_inventory_by_location_type: String,
1902    #[serde(rename = "PopulatedFRU")]
1903    #[serde(skip_serializing_if = "Option::is_none")]
1904    pub populated_fru: Option<HWInventoryByFRU>,
1905    #[serde(rename = "DriveLocationInfo")]
1906    #[serde(skip_serializing_if = "Option::is_none")]
1907    pub drive_location_info: Option<RedfishDriveLocationInfo>,
1908}
1909
1910#[derive(Debug, Serialize, Deserialize, Clone)]
1911pub struct MemoryLocation {
1912    #[serde(rename = "Socket")]
1913    #[serde(skip_serializing_if = "Option::is_none")]
1914    pub socket: Option<u32>,
1915    #[serde(rename = "MemoryController")]
1916    #[serde(skip_serializing_if = "Option::is_none")]
1917    pub memory_controller: Option<u32>,
1918    #[serde(rename = "Channel")]
1919    #[serde(skip_serializing_if = "Option::is_none")]
1920    pub channel: Option<u32>,
1921    #[serde(rename = "Slot")]
1922    #[serde(skip_serializing_if = "Option::is_none")]
1923    pub slot: Option<u32>,
1924}
1925
1926#[derive(Debug, Serialize, Deserialize, Clone)]
1927pub struct RedfishMemoryLocationInfo {
1928    #[serde(rename = "Id")]
1929    #[serde(skip_serializing_if = "Option::is_none")]
1930    pub id: Option<String>,
1931    #[serde(rename = "Name")]
1932    #[serde(skip_serializing_if = "Option::is_none")]
1933    pub name: Option<String>,
1934    #[serde(rename = "Description")]
1935    #[serde(skip_serializing_if = "Option::is_none")]
1936    pub description: Option<String>,
1937    #[serde(rename = "MemoryLocation")]
1938    #[serde(skip_serializing_if = "Option::is_none")]
1939    pub memory_location: Option<MemoryLocation>,
1940}
1941
1942#[derive(Debug, Serialize, Deserialize, Clone)]
1943pub struct HWInvByLocMemory {
1944    #[serde(rename = "ID")]
1945    pub id: String,
1946    #[serde(rename = "Type")]
1947    #[serde(skip_serializing_if = "Option::is_none")]
1948    pub r#type: Option<String>,
1949    #[serde(rename = "Ordinal")]
1950    #[serde(skip_serializing_if = "Option::is_none")]
1951    pub ordinal: Option<u32>,
1952    #[serde(rename = "Status")]
1953    #[serde(skip_serializing_if = "Option::is_none")]
1954    pub status: Option<String>,
1955    #[serde(rename = "HWInventoryByLocationType")]
1956    pub hw_inventory_by_location_type: String,
1957    #[serde(rename = "PopulatedFRU")]
1958    #[serde(skip_serializing_if = "Option::is_none")]
1959    pub populated_fru: Option<HWInvByFRUMemory>,
1960    #[serde(rename = "MemoryLocationInfo")]
1961    pub memory_location_info: RedfishMemoryLocationInfo,
1962}
1963
1964#[derive(Debug, Serialize, Deserialize, Clone)]
1965pub struct RedfishNodeAccelRiserLocationInfo {
1966    #[serde(rename = "Name")]
1967    #[serde(skip_serializing_if = "Option::is_none")]
1968    pub name: Option<String>,
1969    #[serde(rename = "Description")]
1970    #[serde(skip_serializing_if = "Option::is_none")]
1971    pub description: Option<String>,
1972}
1973
1974#[derive(Debug, Serialize, Deserialize, Clone)]
1975pub struct HWInvByLocNodeAccelRiser {
1976    #[serde(rename = "ID")]
1977    pub id: String,
1978    #[serde(rename = "Type")]
1979    #[serde(skip_serializing_if = "Option::is_none")]
1980    pub r#type: Option<String>,
1981    #[serde(rename = "Ordinal")]
1982    #[serde(skip_serializing_if = "Option::is_none")]
1983    pub ordinal: Option<u32>,
1984    #[serde(rename = "Status")]
1985    #[serde(skip_serializing_if = "Option::is_none")]
1986    pub status: Option<String>,
1987    #[serde(rename = "HWInventoryByLocationType")]
1988    pub hw_inventory_by_location_type: String,
1989    #[serde(rename = "PopulatedFRU")]
1990    #[serde(skip_serializing_if = "Option::is_none")]
1991    pub populated_fru: Option<HWInventoryByFRU>,
1992    #[serde(rename = "NodeAccelRiserLocationInfo")]
1993    #[serde(skip_serializing_if = "Option::is_none")]
1994    pub node_accel_riser_location_info: Option<RedfishNodeAccelRiserLocationInfo>,
1995}
1996
1997#[derive(Debug, Serialize, Deserialize, Clone)]
1998pub struct HSNNICLocationInfo {
1999    #[serde(rename = "Id")]
2000    #[serde(skip_serializing_if = "Option::is_none")]
2001    pub id: Option<String>,
2002    #[serde(rename = "Name")]
2003    #[serde(skip_serializing_if = "Option::is_none")]
2004    pub name: Option<String>,
2005    #[serde(rename = "Description")]
2006    #[serde(skip_serializing_if = "Option::is_none")]
2007    pub description: Option<String>,
2008}
2009
2010#[derive(Debug, Serialize, Deserialize, Clone)]
2011pub struct HWInvByLocHSNNIC {
2012    #[serde(rename = "ID")]
2013    pub id: String,
2014    #[serde(rename = "Type")]
2015    #[serde(skip_serializing_if = "Option::is_none")]
2016    pub r#type: Option<String>,
2017    #[serde(rename = "Ordinal")]
2018    #[serde(skip_serializing_if = "Option::is_none")]
2019    pub ordinal: Option<u32>,
2020    #[serde(rename = "Status")]
2021    #[serde(skip_serializing_if = "Option::is_none")]
2022    pub status: Option<String>,
2023    #[serde(rename = "HWInventoryByLocationType")]
2024    pub hw_inventory_by_location_type: String,
2025    #[serde(rename = "PopulatedFRU")]
2026    #[serde(skip_serializing_if = "Option::is_none")]
2027    pub populated_fru: Option<HWInvByFRUHSNNIC>,
2028    /* #[serde(rename = "NodeHsnNicLocationInfo")]
2029    pub node_hsn_nic_location_info: HSNNICLocationInfo, */
2030    #[serde(rename = "HSNNICLocationInfo")]
2031    pub hsn_nic_location_info: HSNNICLocationInfo,
2032}
2033
2034#[derive(Debug, Serialize, Deserialize, Clone)]
2035pub struct RedfishSystemFRUInfo {
2036    #[serde(rename = "AssetTag")]
2037    #[serde(skip_serializing_if = "Option::is_none")]
2038    pub asset_tag: Option<String>,
2039    #[serde(rename = "BiosVersion")]
2040    #[serde(skip_serializing_if = "Option::is_none")]
2041    pub bios_version: Option<String>,
2042    #[serde(rename = "Model")]
2043    #[serde(skip_serializing_if = "Option::is_none")]
2044    pub model: Option<String>,
2045    #[serde(rename = "Manufacturer")]
2046    #[serde(skip_serializing_if = "Option::is_none")]
2047    pub manufacturer: Option<String>,
2048    #[serde(rename = "PartNumber")]
2049    #[serde(skip_serializing_if = "Option::is_none")]
2050    pub part_number: Option<String>,
2051    #[serde(rename = "SerialNumber")]
2052    #[serde(skip_serializing_if = "Option::is_none")]
2053    pub serial_number: Option<String>,
2054    #[serde(rename = "SKU")]
2055    #[serde(skip_serializing_if = "Option::is_none")]
2056    pub sku: Option<String>,
2057    #[serde(rename = "SystemType")]
2058    #[serde(skip_serializing_if = "Option::is_none")]
2059    pub system_type: Option<String>,
2060    #[serde(rename = "UUID")]
2061    #[serde(skip_serializing_if = "Option::is_none")]
2062    pub uuid: Option<String>,
2063}
2064
2065#[derive(Debug, Serialize, Deserialize, Clone)]
2066pub struct HWInvByFRUNode {
2067    #[serde(rename = "FRUID")]
2068    #[serde(skip_serializing_if = "Option::is_none")]
2069    pub fru_id: Option<String>,
2070    #[serde(rename = "Type")]
2071    #[serde(skip_serializing_if = "Option::is_none")]
2072    pub r#type: Option<String>,
2073    #[serde(rename = "FRUSubType")]
2074    #[serde(skip_serializing_if = "Option::is_none")]
2075    pub fru_sub_type: Option<String>,
2076    #[serde(rename = "HWInventoryByFRUType")]
2077    pub hw_inventory_by_fru_type: String,
2078    #[serde(rename = "NodeFRUInfo")]
2079    pub node_fru_info: RedfishSystemFRUInfo,
2080}
2081
2082#[derive(Debug, Serialize, Deserialize, Clone)]
2083pub struct HSNNICFRUInfo {
2084    #[serde(rename = "Manufacturer")]
2085    #[serde(skip_serializing_if = "Option::is_none")]
2086    pub manufacturer: Option<String>,
2087    #[serde(rename = "Model")]
2088    #[serde(skip_serializing_if = "Option::is_none")]
2089    pub model: Option<String>,
2090    #[serde(rename = "PartNumber")]
2091    #[serde(skip_serializing_if = "Option::is_none")]
2092    pub part_number: Option<String>,
2093    #[serde(rename = "SKU")]
2094    #[serde(skip_serializing_if = "Option::is_none")]
2095    pub sku: Option<String>,
2096    #[serde(rename = "SerialNumber")]
2097    #[serde(skip_serializing_if = "Option::is_none")]
2098    pub serial_number: Option<String>,
2099}
2100
2101#[derive(Debug, Serialize, Deserialize, Clone)]
2102pub struct HWInvByLocNode {
2103    #[serde(rename = "ID")]
2104    pub id: String,
2105    #[serde(rename = "Type")]
2106    #[serde(skip_serializing_if = "Option::is_none")]
2107    pub r#type: Option<String>,
2108    #[serde(rename = "Ordinal")]
2109    #[serde(skip_serializing_if = "Option::is_none")]
2110    pub ordinal: Option<u32>,
2111    #[serde(rename = "Status")]
2112    #[serde(skip_serializing_if = "Option::is_none")]
2113    pub status: Option<String>,
2114    #[serde(rename = "HWInventoryByLocationType")]
2115    pub hw_inventory_by_location_type: String,
2116    #[serde(rename = "PopulatedFRU")]
2117    #[serde(skip_serializing_if = "Option::is_none")]
2118    pub populated_fru: Option<HWInvByFRUNode>,
2119    #[serde(rename = "NodeLocationInfo")]
2120    #[serde(skip_serializing_if = "Option::is_none")]
2121    pub node_location_info: Option<RedfishSystemLocationInfo>,
2122    #[serde(rename = "Processors")]
2123    #[serde(skip_serializing_if = "Option::is_none")]
2124    pub processors: Option<Vec<HWInvByLocProcessor>>,
2125    #[serde(rename = "NodeAccels")]
2126    #[serde(skip_serializing_if = "Option::is_none")]
2127    pub node_accels: Option<Vec<HWInvByLocNodeAccel>>,
2128    #[serde(rename = "Dives")]
2129    #[serde(skip_serializing_if = "Option::is_none")]
2130    pub drives: Option<Vec<HWInvByLocDrive>>,
2131    #[serde(rename = "Memory")]
2132    #[serde(skip_serializing_if = "Option::is_none")]
2133    pub memory: Option<Vec<HWInvByLocMemory>>,
2134    #[serde(rename = "NodeAccelRisers")]
2135    #[serde(skip_serializing_if = "Option::is_none")]
2136    pub node_accel_risers: Option<Vec<HWInvByLocNodeAccelRiser>>,
2137    #[serde(rename = "NodeHsnNICs")]
2138    #[serde(skip_serializing_if = "Option::is_none")]
2139    pub node_hsn_nics: Option<Vec<HWInvByLocHSNNIC>>,
2140}
2141
2142#[derive(Debug, Serialize, Deserialize, Clone)]
2143pub struct RedfishPDULocationInfo {
2144    #[serde(rename = "Id")]
2145    #[serde(skip_serializing_if = "Option::is_none")]
2146    pub id: Option<String>,
2147    #[serde(rename = "Name")]
2148    #[serde(skip_serializing_if = "Option::is_none")]
2149    pub name: Option<String>,
2150    #[serde(rename = "Description")]
2151    #[serde(skip_serializing_if = "Option::is_none")]
2152    pub description: Option<String>,
2153    #[serde(rename = "UUID")]
2154    #[serde(skip_serializing_if = "Option::is_none")]
2155    pub uuid: Option<String>,
2156}
2157
2158#[derive(Debug, Serialize, Deserialize, Clone)]
2159pub struct RedfishOutletLocationInfo {
2160    #[serde(rename = "Id")]
2161    #[serde(skip_serializing_if = "Option::is_none")]
2162    pub id: Option<String>,
2163    #[serde(rename = "Name")]
2164    #[serde(skip_serializing_if = "Option::is_none")]
2165    pub name: Option<String>,
2166    #[serde(rename = "Description")]
2167    #[serde(skip_serializing_if = "Option::is_none")]
2168    pub description: Option<String>,
2169}
2170
2171#[derive(Debug, Serialize, Deserialize, Clone)]
2172pub struct HWInvByLocOutlet {
2173    #[serde(rename = "ID")]
2174    pub id: String,
2175    #[serde(rename = "Type")]
2176    #[serde(skip_serializing_if = "Option::is_none")]
2177    pub r#type: Option<String>,
2178    #[serde(rename = "Ordinal")]
2179    #[serde(skip_serializing_if = "Option::is_none")]
2180    pub ordinal: Option<u32>,
2181    #[serde(rename = "Status")]
2182    #[serde(skip_serializing_if = "Option::is_none")]
2183    pub status: Option<String>,
2184    #[serde(rename = "HWInventoryByLocationType")]
2185    pub hw_inventory_by_location_type: String,
2186    #[serde(rename = "PopulatedFRU")]
2187    #[serde(skip_serializing_if = "Option::is_none")]
2188    pub populated_fru: Option<HWInventoryByFRU>,
2189    #[serde(rename = "OutletLocationInfo")]
2190    #[serde(skip_serializing_if = "Option::is_none")]
2191    pub outlet_location_info: Option<RedfishOutletLocationInfo>,
2192}
2193
2194#[derive(Debug, Serialize, Deserialize, Clone)]
2195pub struct HWInvByLocPDU {
2196    #[serde(rename = "ID")]
2197    pub id: String,
2198    #[serde(rename = "Type")]
2199    #[serde(skip_serializing_if = "Option::is_none")]
2200    pub r#type: Option<String>,
2201    #[serde(rename = "Ordinal")]
2202    #[serde(skip_serializing_if = "Option::is_none")]
2203    pub ordinal: Option<u32>,
2204    #[serde(rename = "Status")]
2205    #[serde(skip_serializing_if = "Option::is_none")]
2206    pub status: Option<String>,
2207    #[serde(rename = "HWInventoryByLocationType")]
2208    pub hw_inventory_by_location_type: String,
2209    #[serde(rename = "PopulatedFRU")]
2210    #[serde(skip_serializing_if = "Option::is_none")]
2211    pub populated_fru: Option<HWInventoryByFRU>,
2212    #[serde(rename = "PDULocationInfo")]
2213    #[serde(skip_serializing_if = "Option::is_none")]
2214    pub pdu_location_info: Option<RedfishPDULocationInfo>,
2215    #[serde(rename = "CabinetPDUPowerConnectors")]
2216    #[serde(skip_serializing_if = "Option::is_none")]
2217    pub cabinet_pdu_power_connectors: Option<Vec<HWInvByLocOutlet>>,
2218}
2219
2220#[derive(Debug, Serialize, Deserialize, Clone)]
2221pub struct RedfishCMMRectifierLocationInfo {
2222    #[serde(rename = "Name")]
2223    #[serde(skip_serializing_if = "Option::is_none")]
2224    pub name: Option<String>,
2225    #[serde(rename = "FirmwareVersion")]
2226    #[serde(skip_serializing_if = "Option::is_none")]
2227    pub firmware_version: Option<String>,
2228}
2229
2230#[derive(Debug, Serialize, Deserialize, Clone)]
2231pub struct HWInvByLocCMMRectifier {
2232    #[serde(rename = "ID")]
2233    pub id: String,
2234    #[serde(rename = "Type")]
2235    #[serde(skip_serializing_if = "Option::is_none")]
2236    pub r#type: Option<String>,
2237    #[serde(rename = "Ordinal")]
2238    #[serde(skip_serializing_if = "Option::is_none")]
2239    pub ordinal: Option<u32>,
2240    #[serde(rename = "Status")]
2241    #[serde(skip_serializing_if = "Option::is_none")]
2242    pub status: Option<String>,
2243    #[serde(rename = "HWInventoryByLocationType")]
2244    pub hw_inventory_by_location_type: String,
2245    #[serde(rename = "PopulatedFRU")]
2246    #[serde(skip_serializing_if = "Option::is_none")]
2247    pub populated_fru: Option<HWInventoryByFRU>,
2248    #[serde(rename = "CMMRectifierLocationInfo")]
2249    #[serde(skip_serializing_if = "Option::is_none")]
2250    pub cmm_rectifier_location_info: Option<RedfishCMMRectifierLocationInfo>,
2251}
2252
2253#[derive(Debug, Serialize, Deserialize, Clone)]
2254pub struct RedfishNodeEnclosurePowerSupplyLocationInfo {
2255    #[serde(rename = "Name")]
2256    #[serde(skip_serializing_if = "Option::is_none")]
2257    pub name: Option<String>,
2258    #[serde(rename = "FirmwareVersion")]
2259    #[serde(skip_serializing_if = "Option::is_none")]
2260    pub firmware_version: Option<String>,
2261}
2262
2263#[derive(Debug, Serialize, Deserialize, Clone)]
2264pub struct HWInvByLocNodePowerSupply {
2265    #[serde(rename = "ID")]
2266    pub id: String,
2267    #[serde(rename = "Type")]
2268    #[serde(skip_serializing_if = "Option::is_none")]
2269    pub r#type: Option<String>,
2270    #[serde(rename = "Ordinal")]
2271    #[serde(skip_serializing_if = "Option::is_none")]
2272    pub ordinal: Option<u32>,
2273    #[serde(rename = "Status")]
2274    #[serde(skip_serializing_if = "Option::is_none")]
2275    pub status: Option<String>,
2276    #[serde(rename = "HWInventoryByLocationType")]
2277    pub hw_inventory_by_location_type: String,
2278    #[serde(rename = "PopulatedFRU")]
2279    #[serde(skip_serializing_if = "Option::is_none")]
2280    pub populated_fru: Option<HWInventoryByFRU>,
2281    #[serde(rename = "NodeEnclosurePowerSupplyLocationInfo")]
2282    #[serde(skip_serializing_if = "Option::is_none")]
2283    pub node_enclosure_power_supply_location_info:
2284        Option<RedfishNodeEnclosurePowerSupplyLocationInfo>,
2285}
2286
2287#[derive(Debug, Serialize, Deserialize, Clone)]
2288pub struct RedfishManagerLocationInfo {
2289    #[serde(rename = "Id")]
2290    #[serde(skip_serializing_if = "Option::is_none")]
2291    pub id: Option<String>,
2292    #[serde(rename = "Name")]
2293    #[serde(skip_serializing_if = "Option::is_none")]
2294    pub name: Option<String>,
2295    #[serde(rename = "Description")]
2296    #[serde(skip_serializing_if = "Option::is_none")]
2297    pub description: Option<String>,
2298    #[serde(rename = "DateTime")]
2299    #[serde(skip_serializing_if = "Option::is_none")]
2300    pub date_time: Option<String>,
2301    #[serde(rename = "DateTimeLocalOffset")]
2302    #[serde(skip_serializing_if = "Option::is_none")]
2303    pub date_time_local_offset: Option<String>,
2304    #[serde(rename = "FirmwareVersion")]
2305    #[serde(skip_serializing_if = "Option::is_none")]
2306    pub firmware_version: Option<String>,
2307}
2308
2309#[derive(Debug, Serialize, Deserialize, Clone)]
2310pub struct HWInvByLocNodeBMC {
2311    #[serde(rename = "ID")]
2312    pub id: String,
2313    #[serde(rename = "Type")]
2314    #[serde(skip_serializing_if = "Option::is_none")]
2315    pub r#type: Option<String>,
2316    #[serde(rename = "Ordinal")]
2317    #[serde(skip_serializing_if = "Option::is_none")]
2318    pub ordinal: Option<u32>,
2319    #[serde(rename = "Status")]
2320    #[serde(skip_serializing_if = "Option::is_none")]
2321    pub status: Option<String>,
2322    #[serde(rename = "HWInventoryByLocationType")]
2323    pub hw_inventory_by_location_type: String,
2324    #[serde(rename = "PopulatedFRU")]
2325    #[serde(skip_serializing_if = "Option::is_none")]
2326    pub populated_fru: Option<HWInventoryByFRU>,
2327    #[serde(rename = "NodeBMCLocationInfo")]
2328    #[serde(skip_serializing_if = "Option::is_none")]
2329    pub node_bmc_location_info: Option<RedfishManagerLocationInfo>,
2330}
2331
2332#[derive(Debug, Serialize, Deserialize, Clone)]
2333pub struct HWInvByLocRouterBMC {
2334    #[serde(rename = "ID")]
2335    pub id: String,
2336    #[serde(rename = "Type")]
2337    #[serde(skip_serializing_if = "Option::is_none")]
2338    pub r#type: Option<String>,
2339    #[serde(rename = "Ordinal")]
2340    #[serde(skip_serializing_if = "Option::is_none")]
2341    pub ordinal: Option<u32>,
2342    #[serde(rename = "Status")]
2343    #[serde(skip_serializing_if = "Option::is_none")]
2344    pub status: Option<String>,
2345    #[serde(rename = "HWInventoryByLocationType")]
2346    pub hw_inventory_by_location_type: String,
2347    #[serde(rename = "PopulatedFRU")]
2348    #[serde(skip_serializing_if = "Option::is_none")]
2349    pub populated_fru: Option<HWInventoryByFRU>,
2350    #[serde(rename = "RouterBMCLocationInfo")]
2351    #[serde(skip_serializing_if = "Option::is_none")]
2352    pub router_bmc_location_info: Option<RedfishManagerLocationInfo>,
2353}
2354
2355/* #[derive(Debug, Serialize, Deserialize, Clone)]
2356pub struct HWInventoryList {
2357    #[serde(rename = "Hardware")]
2358    pub hw_inventory: Vec<HWInventory>,
2359} */
2360
2361#[derive(Debug, Serialize, Deserialize, Clone)]
2362pub struct HWInventory {
2363    #[serde(rename = "XName")]
2364    #[serde(skip_serializing_if = "Option::is_none")]
2365    pub xname: Option<String>,
2366    #[serde(rename = "Format")]
2367    #[serde(skip_serializing_if = "Option::is_none")]
2368    pub format: Option<String>,
2369    #[serde(rename = "Cabinets")]
2370    #[serde(skip_serializing_if = "Option::is_none")]
2371    pub cabinets: Option<Vec<HWInvByLocCabinet>>,
2372    #[serde(rename = "Chassis")]
2373    #[serde(skip_serializing_if = "Option::is_none")]
2374    pub chassis: Option<Vec<HWInvByLocChassis>>,
2375    #[serde(rename = "ComputeModules")]
2376    #[serde(skip_serializing_if = "Option::is_none")]
2377    pub compute_modules: Option<Vec<HWInvByLocComputeModule>>,
2378    #[serde(rename = "RouterModules")]
2379    #[serde(skip_serializing_if = "Option::is_none")]
2380    pub router_modules: Option<Vec<HWInvByLocRouterModule>>,
2381    #[serde(rename = "NodeEnclosures")]
2382    #[serde(skip_serializing_if = "Option::is_none")]
2383    pub node_enclosures: Option<Vec<HWInvByLocNodeEnclosure>>,
2384    #[serde(rename = "HSNBoards")]
2385    #[serde(skip_serializing_if = "Option::is_none")]
2386    pub hsn_boards: Option<Vec<HWInvByLocHSNBoard>>,
2387    #[serde(rename = "MgmtSwitches")]
2388    #[serde(skip_serializing_if = "Option::is_none")]
2389    pub mgmt_switches: Option<Vec<HWInvByLocMgmtSwitch>>,
2390    #[serde(rename = "MgmtHLSwitches")]
2391    #[serde(skip_serializing_if = "Option::is_none")]
2392    pub mgmt_hl_switches: Option<Vec<HWInvByLocMgmtHLSwitch>>,
2393    #[serde(rename = "CDUMgmtSwitches")]
2394    #[serde(skip_serializing_if = "Option::is_none")]
2395    pub cdu_mgmt_switches: Option<Vec<HWInvByLocCDUMgmtSwitch>>,
2396    #[serde(rename = "Nodes")]
2397    #[serde(skip_serializing_if = "Option::is_none")]
2398    pub nodes: Option<Vec<HWInvByLocNode>>,
2399    #[serde(rename = "Processors")]
2400    #[serde(skip_serializing_if = "Option::is_none")]
2401    pub processors: Option<Vec<HWInvByLocProcessor>>,
2402    #[serde(rename = "NodeAccels")]
2403    #[serde(skip_serializing_if = "Option::is_none")]
2404    pub node_accels: Option<Vec<HWInvByLocNodeAccel>>,
2405    #[serde(rename = "Drives")]
2406    #[serde(skip_serializing_if = "Option::is_none")]
2407    pub drives: Option<Vec<HWInvByLocDrive>>,
2408    #[serde(rename = "Memory")]
2409    #[serde(skip_serializing_if = "Option::is_none")]
2410    pub memory: Option<Vec<HWInvByLocMemory>>,
2411    #[serde(rename = "CabinetPDUs")]
2412    #[serde(skip_serializing_if = "Option::is_none")]
2413    pub cabinet_pdus: Option<Vec<HWInvByLocPDU>>,
2414    #[serde(rename = "CabinetPDUPowerConnectors")]
2415    #[serde(skip_serializing_if = "Option::is_none")]
2416    pub cabinet_pdu_power_connectors: Option<Vec<HWInvByLocOutlet>>,
2417    #[serde(rename = "CMMRectifiers")]
2418    #[serde(skip_serializing_if = "Option::is_none")]
2419    pub cmm_rectifiers: Option<Vec<HWInvByLocCMMRectifier>>,
2420    #[serde(rename = "NodeAccelRisers")]
2421    #[serde(skip_serializing_if = "Option::is_none")]
2422    pub node_accel_risers: Option<Vec<HWInvByLocNodeAccelRiser>>,
2423    #[serde(rename = "NodeHsnNICs")]
2424    #[serde(skip_serializing_if = "Option::is_none")]
2425    pub node_hsn_nics: Option<Vec<HWInvByLocHSNNIC>>,
2426    #[serde(rename = "NodeEnclosurePowerSupplies")]
2427    #[serde(skip_serializing_if = "Option::is_none")]
2428    pub node_enclosure_power_supplies: Option<Vec<HWInvByLocNodePowerSupply>>,
2429    #[serde(rename = "NodeBMC")]
2430    #[serde(skip_serializing_if = "Option::is_none")]
2431    pub node_bmc: Option<Vec<HWInvByLocNodeBMC>>,
2432    #[serde(rename = "RouterBMC")]
2433    #[serde(skip_serializing_if = "Option::is_none")]
2434    pub router_bmc: Option<Vec<HWInvByLocRouterBMC>>,
2435}
2436
2437#[derive(Debug, Serialize, Deserialize, Clone)]
2438pub struct Hardware {
2439    #[serde(rename = "Hardware")]
2440    #[serde(skip_serializing_if = "Option::is_none")]
2441    pub hardware: Option<Vec<HWInvByLocNode>>,
2442}
2443
2444#[derive(Debug, Serialize, Deserialize, Clone)]
2445pub struct NodeLocationInfo {
2446    #[serde(rename = "Id")]
2447    pub id: String,
2448    #[serde(rename = "Name")]
2449    #[serde(skip_serializing_if = "Option::is_none")]
2450    pub name: Option<String>,
2451    #[serde(rename = "Description")]
2452    #[serde(skip_serializing_if = "Option::is_none")]
2453    pub description: Option<String>,
2454    #[serde(rename = "Hostname")]
2455    #[serde(skip_serializing_if = "Option::is_none")]
2456    pub hostname: Option<String>,
2457    #[serde(rename = "ProcessorSummary")]
2458    #[serde(skip_serializing_if = "Option::is_none")]
2459    pub processor_summary: Option<ProcessorSummary>,
2460    #[serde(rename = "MemorySummary")]
2461    #[serde(skip_serializing_if = "Option::is_none")]
2462    pub memory_summary: Option<MemorySummary>,
2463}
2464
2465#[derive(Debug, Serialize, Deserialize, Clone)]
2466#[serde(untagged)] // <-- this is important. More info https://serde.rs/enum-representations.html#untagged
2467pub enum HWInventoryByLocation {
2468    /* HWInvByLocCabinet(HWInvByLocCabinet),
2469    HWInvByLocChassis(HWInvByLocChassis),
2470    HWInvByLocComputeModule(HWInvByLocComputeModule),
2471    HWInvByLocRouterModule(HWInvByLocRouterModule),
2472    HWInvByLocNodeEnclosure(HWInvByLocNodeEnclosure),
2473    HWInvByLocHSNBoard(HWInvByLocHSNBoard),
2474    HWInvByLocMgmtSwitch(HWInvByLocMgmtSwitch),
2475    HWInvByLocMgmtHLSwitch(HWInvByLocMgmtHLSwitch),
2476    HWInvByLocCDUMgmtSwitch(HWInvByLocCDUMgmtSwitch), */
2477    HWInvByLocNode(HWInvByLocNode),
2478    HWInvByLocProcessor(HWInvByLocProcessor),
2479    HWInvByLocNodeAccel(HWInvByLocNodeAccel),
2480    /*     HWInvByLocDrive(HWInvByLocDrive), */
2481    HWInvByLocMemory(HWInvByLocMemory),
2482    /* HWInvByLocPDU(HWInvByLocPDU),
2483    HWInvByLocOutlet(HWInvByLocOutlet),
2484    HWInvByLocCMMRectifier(HWInvByLocCMMRectifier),
2485    HWInvByLocNodeAccelRiser(HWInvByLocNodeAccelRiser), */
2486    HWInvByLocHSNNIC(HWInvByLocHSNNIC),
2487    /* HWInvByLocNodePowerSupply(HWInvByLocNodePowerSupply),
2488    HWInvByLocNodeBMC(HWInvByLocNodeBMC),
2489    HWInvByLocRouterBMC(HWInvByLocRouterBMC), */
2490}
2491
2492/// struct used in POST and GET endpoints that manage multiple instances of 'HWInventoryByLocation'
2493#[derive(Debug, Serialize, Deserialize, Clone)]
2494pub struct HWInventoryByLocationList {
2495    #[serde(rename = "Hardware")]
2496    #[serde(skip_serializing_if = "Option::is_none")]
2497    pub hardware: Option<Vec<HWInventoryByLocation>>,
2498}