backend_dispatcher/types/
mod.rs

1pub mod cfs;
2pub mod ims;
3pub mod kafka;
4
5use std::{collections::HashMap, str::FromStr};
6
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9use strum_macros::{AsRefStr, Display, EnumIter, EnumString, IntoStaticStr};
10
11use crate::error::Error;
12
13#[derive(Serialize, Deserialize, Debug)]
14pub enum K8sAuth {
15    Native {
16        certificate_authority_data: String,
17        client_certificate_data: String,
18        client_key_data: String,
19    },
20    Vault {
21        base_url: String,
22        secret_path: String,
23        role_id: String,
24    },
25}
26
27#[derive(Serialize, Deserialize, Debug)]
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(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            changed = changed | params.remove(key).is_some();
1244        }
1245
1246        self.params = params
1247            .iter()
1248            .map(|(key, value)| {
1249                if !value.is_empty() {
1250                    format!("{key}={value}")
1251                } else {
1252                    key.to_string()
1253                }
1254            })
1255            .collect::<Vec<String>>()
1256            .join(" ");
1257
1258        changed
1259    }
1260
1261    /// Apply a str of kernel parameters:
1262    ///  - current kernel params will be ignored/removed and replaced by the new ones
1263    /// Returns true if kernel params have change
1264    // FIXME: integrate fixed introduced in methods 'add_kernel_param' and 'delete_kernel_param'
1265    pub fn apply_kernel_params(&mut self, new_params: &str) -> bool {
1266        let mut change = false;
1267
1268        let new_params: Vec<(&str, &str)> = new_params
1269            .split_whitespace()
1270            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1271            .map(|(key, value)| (key.trim(), value.trim()))
1272            .collect();
1273
1274        let mut params: HashMap<&str, &str> = HashMap::new();
1275
1276        for (new_key, new_value) in &new_params {
1277            for (key, value) in params.iter_mut() {
1278                if *key == *new_key {
1279                    log::debug!("key '{}' found", key);
1280                    if value != new_value {
1281                        log::info!("changing key {} from {} to {}", key, value, new_value);
1282
1283                        *value = new_value;
1284                        change = true
1285                    } else {
1286                        log::debug!("key '{}' value does not change ({})", key, value);
1287                    }
1288                }
1289            }
1290        }
1291
1292        if change == false {
1293            log::debug!("No value change in kernel params. Checking is either new params have been added or removed");
1294            if new_params.len() != params.len() {
1295                log::info!("num kernel parameters have changed");
1296                change = true;
1297            }
1298        }
1299
1300        self.params = new_params
1301            .iter()
1302            .map(|(key, value)| {
1303                if !value.is_empty() {
1304                    format!("{key}={value}")
1305                } else {
1306                    key.to_string()
1307                }
1308            })
1309            .collect::<Vec<String>>()
1310            .join(" ");
1311
1312        change
1313    }
1314}
1315
1316#[derive(Debug, Serialize, Deserialize)]
1317pub enum ComponentType {
1318    CDU,
1319    CabinetCDU,
1320    CabinetPDU,
1321    CabinetPDUOutlet,
1322    CabinetPDUPowerConnector,
1323    CabinetPDUController,
1324    r#Cabinet,
1325    Chassis,
1326    ChassisBMC,
1327    CMMRectifier,
1328    CMMFpga,
1329    CEC,
1330    ComputeModule,
1331    RouterModule,
1332    NodeBMC,
1333    NodeEnclosure,
1334    NodeEnclosurePowerSupply,
1335    HSNBoard,
1336    Node,
1337    Processor,
1338    Drive,
1339    StorageGroup,
1340    NodeNIC,
1341    Memory,
1342    NodeAccel,
1343    NodeAccelRiser,
1344    NodeFpga,
1345    HSNAsic,
1346    RouterFpga,
1347    RouterBMC,
1348    HSNLink,
1349    HSNConnector,
1350    INVALID,
1351}
1352
1353#[derive(Debug, Serialize, Deserialize, Clone)]
1354pub struct ProcessorId {
1355    #[serde(rename = "EffectiveFamily")]
1356    #[serde(skip_serializing_if = "Option::is_none")]
1357    pub effective_family: Option<String>,
1358    #[serde(rename = "EffectiveModel")]
1359    #[serde(skip_serializing_if = "Option::is_none")]
1360    pub efffective_model: Option<String>,
1361    #[serde(rename = "IdentificationRegisters")]
1362    #[serde(skip_serializing_if = "Option::is_none")]
1363    pub identification_registers: Option<String>,
1364    #[serde(rename = "MicrocodeInfo")]
1365    #[serde(skip_serializing_if = "Option::is_none")]
1366    pub microcode_info: Option<String>,
1367    #[serde(rename = "Step")]
1368    #[serde(skip_serializing_if = "Option::is_none")]
1369    pub step: Option<String>,
1370    #[serde(rename = "VendorId")]
1371    #[serde(skip_serializing_if = "Option::is_none")]
1372    pub vendor_id: Option<String>,
1373}
1374
1375#[derive(Debug, Serialize, Deserialize, Clone)]
1376pub struct HWInvByFRUProcessor {
1377    #[serde(rename = "FRUID")]
1378    #[serde(skip_serializing_if = "Option::is_none")]
1379    pub fru_id: Option<String>,
1380    #[serde(rename = "Type")]
1381    #[serde(skip_serializing_if = "Option::is_none")]
1382    pub r#type: Option<String>,
1383    #[serde(rename = "FRUSubType")]
1384    #[serde(skip_serializing_if = "Option::is_none")]
1385    pub fru_sub_type: Option<String>,
1386    #[serde(rename = "HWInventoryByFRUType")]
1387    pub hw_inventory_by_fru_type: String,
1388    #[serde(rename = "ProcessorFRUInfo")]
1389    pub processor_fru_info: RedfishProcessorFRUInfo,
1390}
1391
1392#[derive(Debug, Serialize, Deserialize, Clone)]
1393pub struct HWInvByFRUMemory {
1394    #[serde(rename = "FRUID")]
1395    #[serde(skip_serializing_if = "Option::is_none")]
1396    pub fru_id: Option<String>,
1397    #[serde(rename = "Type")]
1398    #[serde(skip_serializing_if = "Option::is_none")]
1399    pub r#type: Option<String>,
1400    #[serde(rename = "FRUSubType")]
1401    #[serde(skip_serializing_if = "Option::is_none")]
1402    pub fru_sub_type: Option<String>,
1403    #[serde(rename = "HWInventoryByFRUType")]
1404    pub hw_inventory_by_fru_type: String,
1405    #[serde(rename = "MemoryFRUInfo")]
1406    pub memory_fru_info: RedfishMemoryFRUInfo,
1407}
1408
1409#[derive(Debug, Serialize, Deserialize, Clone)]
1410pub struct HWInvByFRUHSNNIC {
1411    #[serde(rename = "FRUID")]
1412    #[serde(skip_serializing_if = "Option::is_none")]
1413    pub fru_id: Option<String>,
1414    #[serde(rename = "Type")]
1415    #[serde(skip_serializing_if = "Option::is_none")]
1416    pub r#type: Option<String>,
1417    #[serde(rename = "FRUSubType")]
1418    #[serde(skip_serializing_if = "Option::is_none")]
1419    pub fru_sub_type: Option<String>,
1420    #[serde(rename = "HWInventoryByFRUType")]
1421    pub hw_inventory_by_fru_type: String,
1422    #[serde(rename = "HSNNICFRUInfo")]
1423    pub hsn_nic_fru_info: HSNNICFRUInfo,
1424}
1425
1426#[derive(Debug, Serialize, Deserialize, Clone)]
1427pub struct HWInvByFRUNodeAccel {
1428    #[serde(rename = "FRUID")]
1429    #[serde(skip_serializing_if = "Option::is_none")]
1430    pub fru_id: Option<String>,
1431    #[serde(rename = "Type")]
1432    #[serde(skip_serializing_if = "Option::is_none")]
1433    pub r#type: Option<String>,
1434    #[serde(rename = "FRUSubType")]
1435    #[serde(skip_serializing_if = "Option::is_none")]
1436    pub fru_sub_type: Option<String>,
1437    #[serde(rename = "HWInventoryByFRUType")]
1438    pub hw_inventory_by_fru_type: String,
1439    #[serde(rename = "NodeAccelFRUInfo")]
1440    pub node_accel_fru_info: RedfishProcessorFRUInfo, // NOTE: yes, sounds weird FRU for node accelerator uses FRU for processor... but that is
1441                                                      // what the API docs says...
1442}
1443
1444#[derive(Debug, Serialize, Deserialize, Clone)]
1445pub struct RedfishProcessorFRUInfo {
1446    #[serde(rename = "InstructionSet")]
1447    #[serde(skip_serializing_if = "Option::is_none")]
1448    pub instruction_set: Option<String>,
1449    #[serde(rename = "Manufacturer")]
1450    #[serde(skip_serializing_if = "Option::is_none")]
1451    pub manufacturer: Option<String>,
1452    #[serde(rename = "MaxSpeedMHz")]
1453    #[serde(skip_serializing_if = "Option::is_none")]
1454    pub max_speed_mhz: Option<usize>,
1455    #[serde(rename = "Model")]
1456    #[serde(skip_serializing_if = "Option::is_none")]
1457    pub model: Option<String>,
1458    #[serde(rename = "ProcessorArchitecture")]
1459    #[serde(skip_serializing_if = "Option::is_none")]
1460    pub processor_architecture: Option<String>,
1461    #[serde(rename = "ProcessorId")]
1462    #[serde(skip_serializing_if = "Option::is_none")]
1463    pub processor_id: Option<ProcessorId>,
1464    #[serde(rename = "ProcessorType")]
1465    #[serde(skip_serializing_if = "Option::is_none")]
1466    pub processor_type: Option<String>,
1467    #[serde(rename = "TotalCores")]
1468    #[serde(skip_serializing_if = "Option::is_none")]
1469    pub total_cores: Option<usize>,
1470    #[serde(rename = "TotalThreads")]
1471    #[serde(skip_serializing_if = "Option::is_none")]
1472    pub total_threads: Option<usize>,
1473}
1474
1475#[derive(Debug, Serialize, Deserialize, Clone)]
1476pub struct RedfishMemoryFRUInfo {
1477    #[serde(rename = "BaseModuleType")]
1478    #[serde(skip_serializing_if = "Option::is_none")]
1479    pub base_module_type: Option<String>,
1480    #[serde(rename = "BusWidthBits")]
1481    #[serde(skip_serializing_if = "Option::is_none")]
1482    pub bus_width_bits: Option<usize>,
1483    #[serde(rename = "CapacityMiB")]
1484    #[serde(skip_serializing_if = "Option::is_none")]
1485    pub capacity_mib: Option<usize>,
1486    #[serde(rename = "DataWidthBits")]
1487    #[serde(skip_serializing_if = "Option::is_none")]
1488    pub data_width_bits: Option<usize>,
1489    #[serde(rename = "ErrorCorrection")]
1490    #[serde(skip_serializing_if = "Option::is_none")]
1491    pub error_correction: Option<String>,
1492    #[serde(rename = "Manufacturer")]
1493    #[serde(skip_serializing_if = "Option::is_none")]
1494    pub manufacturer: Option<String>,
1495    #[serde(rename = "MemoryType")]
1496    #[serde(skip_serializing_if = "Option::is_none")]
1497    pub memory_type: Option<String>,
1498    #[serde(rename = "MemoryDeviceType")]
1499    #[serde(skip_serializing_if = "Option::is_none")]
1500    pub memory_device_type: Option<String>,
1501    #[serde(rename = "OperatingSpeedMhz")]
1502    #[serde(skip_serializing_if = "Option::is_none")]
1503    pub operating_speed_mhz: Option<usize>,
1504    #[serde(rename = "PartNumber")]
1505    #[serde(skip_serializing_if = "Option::is_none")]
1506    pub part_number: Option<String>,
1507    #[serde(rename = "RankCount")]
1508    #[serde(skip_serializing_if = "Option::is_none")]
1509    pub rank_count: Option<usize>,
1510    #[serde(rename = "SerialNumber")]
1511    #[serde(skip_serializing_if = "Option::is_none")]
1512    pub serial_number: Option<String>,
1513}
1514
1515#[derive(Debug, Serialize, Deserialize, Clone)]
1516pub struct HWInventoryByFRU {
1517    #[serde(rename = "FRUID")]
1518    #[serde(skip_serializing_if = "Option::is_none")]
1519    pub fru_id: Option<String>,
1520    #[serde(rename = "Type")]
1521    #[serde(skip_serializing_if = "Option::is_none")]
1522    pub r#type: Option<String>,
1523    #[serde(rename = "FRUSubType")]
1524    #[serde(skip_serializing_if = "Option::is_none")]
1525    pub fru_sub_type: Option<String>,
1526    #[serde(rename = "HWInventoryByFRUType")]
1527    pub hw_inventory_by_fru_type: String,
1528}
1529
1530#[derive(Debug, Serialize, Deserialize, Clone)]
1531pub struct RedfishChassisLocationInfo {
1532    #[serde(rename = "Id")]
1533    #[serde(skip_serializing_if = "Option::is_none")]
1534    pub id: Option<String>,
1535    #[serde(rename = "Name")]
1536    #[serde(skip_serializing_if = "Option::is_none")]
1537    pub name: Option<String>,
1538    #[serde(rename = "Description")]
1539    #[serde(skip_serializing_if = "Option::is_none")]
1540    pub description: Option<String>,
1541    #[serde(rename = "Hostname")]
1542    #[serde(skip_serializing_if = "Option::is_none")]
1543    pub hostname: Option<String>,
1544}
1545
1546#[derive(Debug, Serialize, Deserialize, Clone)]
1547pub struct HWInvByLocChassis {
1548    #[serde(rename = "ID")]
1549    pub id: String,
1550    #[serde(rename = "Type")]
1551    #[serde(skip_serializing_if = "Option::is_none")]
1552    pub r#type: Option<String>,
1553    #[serde(rename = "Ordinal")]
1554    #[serde(skip_serializing_if = "Option::is_none")]
1555    pub ordinal: Option<u32>,
1556    #[serde(rename = "Status")]
1557    #[serde(skip_serializing_if = "Option::is_none")]
1558    pub status: Option<String>,
1559    #[serde(rename = "HWInventoryByLocationType")]
1560    pub hw_inventory_by_location_type: String,
1561    #[serde(rename = "PopulatedFRU")]
1562    #[serde(skip_serializing_if = "Option::is_none")]
1563    pub populated_fru: Option<HWInventoryByFRU>,
1564    #[serde(rename = "ChassisLocatinInfo")]
1565    #[serde(skip_serializing_if = "Option::is_none")]
1566    pub chassis_location_info: Option<RedfishChassisLocationInfo>,
1567    #[serde(rename = "ComputeModules")]
1568    #[serde(skip_serializing_if = "Option::is_none")]
1569    pub compute_modules: Option<HWInvByLocComputeModule>,
1570    #[serde(rename = "RouterModules")]
1571    #[serde(skip_serializing_if = "Option::is_none")]
1572    pub router_modules: Option<HWInvByLocRouterModule>,
1573}
1574
1575#[derive(Debug, Serialize, Deserialize, Clone)]
1576pub struct HWInvByLocNodeEnclosure {
1577    #[serde(rename = "ID")]
1578    pub id: String,
1579    #[serde(rename = "Type")]
1580    #[serde(skip_serializing_if = "Option::is_none")]
1581    pub r#type: Option<String>,
1582    #[serde(rename = "Ordinal")]
1583    #[serde(skip_serializing_if = "Option::is_none")]
1584    pub ordinal: Option<u32>,
1585    #[serde(rename = "Status")]
1586    #[serde(skip_serializing_if = "Option::is_none")]
1587    pub status: Option<String>,
1588    #[serde(rename = "HWInventoryByLocationType")]
1589    pub hw_inventory_by_location_type: String,
1590    #[serde(rename = "PopulatedFRU")]
1591    #[serde(skip_serializing_if = "Option::is_none")]
1592    pub populated_fru: Option<HWInventoryByFRU>,
1593    #[serde(rename = "NodeEnclosureLocationInfo")]
1594    #[serde(skip_serializing_if = "Option::is_none")]
1595    pub node_enclosure_location_info: Option<RedfishChassisLocationInfo>,
1596}
1597
1598#[derive(Debug, Serialize, Deserialize, Clone)]
1599pub struct HWInvByLocComputeModule {
1600    #[serde(rename = "ID")]
1601    pub id: String,
1602    #[serde(rename = "Type")]
1603    #[serde(skip_serializing_if = "Option::is_none")]
1604    pub r#type: Option<String>,
1605    #[serde(rename = "Ordinal")]
1606    #[serde(skip_serializing_if = "Option::is_none")]
1607    pub ordinal: Option<u32>,
1608    #[serde(rename = "Status")]
1609    #[serde(skip_serializing_if = "Option::is_none")]
1610    pub status: Option<String>,
1611    #[serde(rename = "HWInventoryByLocationType")]
1612    pub hw_inventory_by_location_type: String,
1613    #[serde(rename = "PopulatedFRU")]
1614    #[serde(skip_serializing_if = "Option::is_none")]
1615    pub populated_fru: Option<HWInventoryByFRU>,
1616    #[serde(rename = "ComputeModuleLocationInfo")]
1617    #[serde(skip_serializing_if = "Option::is_none")]
1618    pub compute_module_location_info: Option<RedfishChassisLocationInfo>,
1619    #[serde(rename = "NodeEnclosures")]
1620    #[serde(skip_serializing_if = "Option::is_none")]
1621    pub node_enclosures: Option<HWInvByLocNodeEnclosure>,
1622}
1623
1624#[derive(Debug, Serialize, Deserialize, Clone)]
1625pub struct HWInvByLocHSNBoard {
1626    #[serde(rename = "ID")]
1627    pub id: String,
1628    #[serde(rename = "Type")]
1629    #[serde(skip_serializing_if = "Option::is_none")]
1630    pub r#type: Option<String>,
1631    #[serde(rename = "Ordinal")]
1632    #[serde(skip_serializing_if = "Option::is_none")]
1633    pub ordinal: Option<u32>,
1634    #[serde(rename = "Status")]
1635    #[serde(skip_serializing_if = "Option::is_none")]
1636    pub status: Option<String>,
1637    #[serde(rename = "HWInventoryByLocationType")]
1638    pub hw_inventory_by_location_type: String,
1639    #[serde(rename = "PopulatedFRU")]
1640    #[serde(skip_serializing_if = "Option::is_none")]
1641    pub populated_fru: Option<HWInventoryByFRU>,
1642    #[serde(rename = "HSNBoardLocationInfo")]
1643    #[serde(skip_serializing_if = "Option::is_none")]
1644    pub hsn_board_location_info: Option<RedfishChassisLocationInfo>,
1645}
1646
1647#[derive(Debug, Serialize, Deserialize, Clone)]
1648pub struct HWInvByLocRouterModule {
1649    #[serde(rename = "ID")]
1650    pub id: String,
1651    #[serde(rename = "Type")]
1652    #[serde(skip_serializing_if = "Option::is_none")]
1653    pub r#type: Option<String>,
1654    #[serde(rename = "Ordinal")]
1655    #[serde(skip_serializing_if = "Option::is_none")]
1656    pub ordinal: Option<u32>,
1657    #[serde(rename = "Status")]
1658    #[serde(skip_serializing_if = "Option::is_none")]
1659    pub status: Option<String>,
1660    #[serde(rename = "HWInventoryByLocationType")]
1661    pub hw_inventory_by_location_type: String,
1662    #[serde(rename = "PopulatedFRU")]
1663    #[serde(skip_serializing_if = "Option::is_none")]
1664    pub populated_fru: Option<HWInventoryByFRU>,
1665    #[serde(rename = "RouterModuleLocationInfo")]
1666    #[serde(skip_serializing_if = "Option::is_none")]
1667    pub router_module_location_info: Option<RedfishChassisLocationInfo>,
1668    pub hsn_boards: Option<HWInvByLocHSNBoard>,
1669}
1670
1671#[derive(Debug, Serialize, Deserialize, Clone)]
1672pub struct HWInvByLocCabinet {
1673    #[serde(rename = "ID")]
1674    pub id: String,
1675    #[serde(rename = "Type")]
1676    #[serde(skip_serializing_if = "Option::is_none")]
1677    pub r#type: Option<String>,
1678    #[serde(rename = "Ordinal")]
1679    #[serde(skip_serializing_if = "Option::is_none")]
1680    pub ordinal: Option<u32>,
1681    #[serde(rename = "Status")]
1682    #[serde(skip_serializing_if = "Option::is_none")]
1683    pub status: Option<String>,
1684    #[serde(rename = "HWInventoryByLocationType")]
1685    pub hw_inventory_by_location_type: String,
1686    #[serde(rename = "PopulatedFRU")]
1687    #[serde(skip_serializing_if = "Option::is_none")]
1688    pub populated_fru: Option<HWInventoryByFRU>,
1689    #[serde(rename = "CabinetLocationInfo")]
1690    #[serde(skip_serializing_if = "Option::is_none")]
1691    pub cabinet_location_info: Option<RedfishChassisLocationInfo>,
1692    #[serde(rename = "Chassis")]
1693    #[serde(skip_serializing_if = "Option::is_none")]
1694    pub chassis: Option<HWInvByLocChassis>,
1695}
1696
1697#[derive(Debug, Serialize, Deserialize, Clone)]
1698pub struct HWInvByLocMgmtSwitch {
1699    #[serde(rename = "ID")]
1700    pub id: String,
1701    #[serde(rename = "Type")]
1702    #[serde(skip_serializing_if = "Option::is_none")]
1703    pub r#type: Option<String>,
1704    #[serde(rename = "Ordinal")]
1705    #[serde(skip_serializing_if = "Option::is_none")]
1706    pub ordinal: Option<u32>,
1707    #[serde(rename = "Status")]
1708    #[serde(skip_serializing_if = "Option::is_none")]
1709    pub status: Option<String>,
1710    #[serde(rename = "HWInventoryByLocationType")]
1711    pub hw_inventory_by_location_type: String,
1712    #[serde(rename = "PopulatedFRU")]
1713    #[serde(skip_serializing_if = "Option::is_none")]
1714    pub populated_fru: Option<HWInventoryByFRU>,
1715    #[serde(rename = "MgmtSwitchLocationInfo")]
1716    #[serde(skip_serializing_if = "Option::is_none")]
1717    pub mgmt_switch_location_info: Option<RedfishChassisLocationInfo>,
1718}
1719
1720#[derive(Debug, Serialize, Deserialize, Clone)]
1721pub struct HWInvByLocMgmtHLSwitch {
1722    #[serde(rename = "ID")]
1723    pub id: String,
1724    #[serde(rename = "Type")]
1725    #[serde(skip_serializing_if = "Option::is_none")]
1726    pub r#type: Option<String>,
1727    #[serde(rename = "Ordinal")]
1728    #[serde(skip_serializing_if = "Option::is_none")]
1729    pub ordinal: Option<u32>,
1730    #[serde(rename = "Status")]
1731    #[serde(skip_serializing_if = "Option::is_none")]
1732    pub status: Option<String>,
1733    #[serde(rename = "HWInventoryByLocationType")]
1734    pub hw_inventory_by_location_type: String,
1735    #[serde(rename = "PopulatedFRU")]
1736    #[serde(skip_serializing_if = "Option::is_none")]
1737    pub populated_fru: Option<HWInventoryByFRU>,
1738    #[serde(rename = "MgmtHLSwitchLocationInfo")]
1739    #[serde(skip_serializing_if = "Option::is_none")]
1740    pub mgmt_hl_switch_location_info: Option<RedfishChassisLocationInfo>,
1741}
1742
1743#[derive(Debug, Serialize, Deserialize, Clone)]
1744pub struct HWInvByLocCDUMgmtSwitch {
1745    #[serde(rename = "ID")]
1746    pub id: String,
1747    #[serde(rename = "Type")]
1748    #[serde(skip_serializing_if = "Option::is_none")]
1749    pub r#type: Option<String>,
1750    #[serde(rename = "Ordinal")]
1751    #[serde(skip_serializing_if = "Option::is_none")]
1752    pub ordinal: Option<u32>,
1753    #[serde(rename = "Status")]
1754    #[serde(skip_serializing_if = "Option::is_none")]
1755    pub status: Option<String>,
1756    #[serde(rename = "HWInventoryByLocationType")]
1757    pub hw_inventory_by_location_type: String,
1758    #[serde(rename = "PopulatedFRU")]
1759    #[serde(skip_serializing_if = "Option::is_none")]
1760    pub populated_fru: Option<HWInventoryByFRU>,
1761    #[serde(rename = "CDUMgmtSwitchLocationInfo")]
1762    #[serde(skip_serializing_if = "Option::is_none")]
1763    pub cdu_mgmt_switch_location_info: Option<RedfishChassisLocationInfo>,
1764}
1765
1766#[derive(Debug, Serialize, Deserialize, Clone)]
1767pub struct ProcessorSummary {
1768    #[serde(rename = "Count")]
1769    #[serde(skip_serializing_if = "Option::is_none")]
1770    pub count: Option<u32>,
1771    #[serde(rename = "Model")]
1772    #[serde(skip_serializing_if = "Option::is_none")]
1773    pub model: Option<String>,
1774}
1775
1776#[derive(Debug, Serialize, Deserialize, Clone)]
1777pub struct MemorySummary {
1778    #[serde(rename = "TotalSystemMemoryGiB")]
1779    #[serde(skip_serializing_if = "Option::is_none")]
1780    pub total_system_memory_gib: Option<u32>,
1781}
1782
1783#[derive(Debug, Serialize, Deserialize, Clone)]
1784pub struct RedfishSystemLocationInfo {
1785    #[serde(rename = "Id")]
1786    #[serde(skip_serializing_if = "Option::is_none")]
1787    pub id: Option<String>,
1788    #[serde(rename = "Name")]
1789    #[serde(skip_serializing_if = "Option::is_none")]
1790    pub name: Option<String>,
1791    #[serde(rename = "Description")]
1792    #[serde(skip_serializing_if = "Option::is_none")]
1793    pub description: Option<String>,
1794    #[serde(rename = "Hostname")]
1795    #[serde(skip_serializing_if = "Option::is_none")]
1796    pub hostname: Option<String>,
1797    #[serde(rename = "ProcessorSummary")]
1798    #[serde(skip_serializing_if = "Option::is_none")]
1799    pub processor_summary: Option<ProcessorSummary>,
1800    #[serde(rename = "MemorySummary")]
1801    #[serde(skip_serializing_if = "Option::is_none")]
1802    pub memory_summary: Option<MemorySummary>,
1803}
1804
1805#[derive(Debug, Serialize, Deserialize, Clone)]
1806pub struct RedfishProcessorLocationInfo {
1807    #[serde(rename = "Id")]
1808    #[serde(skip_serializing_if = "Option::is_none")]
1809    pub id: Option<String>,
1810    #[serde(rename = "Name")]
1811    #[serde(skip_serializing_if = "Option::is_none")]
1812    pub name: Option<String>,
1813    #[serde(rename = "Description")]
1814    #[serde(skip_serializing_if = "Option::is_none")]
1815    pub description: Option<String>,
1816    #[serde(rename = "Socket")]
1817    #[serde(skip_serializing_if = "Option::is_none")]
1818    pub socket: Option<String>,
1819}
1820
1821#[derive(Debug, Serialize, Deserialize, Clone)]
1822pub struct HWInvByLocProcessor {
1823    #[serde(rename = "ID")]
1824    pub id: String,
1825    #[serde(rename = "Type")]
1826    #[serde(skip_serializing_if = "Option::is_none")]
1827    pub r#type: Option<String>,
1828    #[serde(rename = "Ordinal")]
1829    #[serde(skip_serializing_if = "Option::is_none")]
1830    pub ordinal: Option<u32>,
1831    #[serde(rename = "Status")]
1832    #[serde(skip_serializing_if = "Option::is_none")]
1833    pub status: Option<String>,
1834    #[serde(rename = "HWInventoryByLocationType")]
1835    pub hw_inventory_by_location_type: String,
1836    #[serde(rename = "PopulatedFRU")]
1837    #[serde(skip_serializing_if = "Option::is_none")]
1838    pub populated_fru: Option<HWInvByFRUProcessor>,
1839    #[serde(rename = "ProcessorLocationInfo")]
1840    pub processor_location_info: RedfishProcessorLocationInfo,
1841}
1842
1843#[derive(Debug, Serialize, Deserialize, Clone)]
1844pub struct HWInvByLocNodeAccel {
1845    #[serde(rename = "ID")]
1846    pub id: String,
1847    #[serde(rename = "Type")]
1848    #[serde(skip_serializing_if = "Option::is_none")]
1849    pub r#type: Option<String>,
1850    #[serde(rename = "Ordinal")]
1851    #[serde(skip_serializing_if = "Option::is_none")]
1852    pub ordinal: Option<u32>,
1853    #[serde(rename = "Status")]
1854    #[serde(skip_serializing_if = "Option::is_none")]
1855    pub status: Option<String>,
1856    #[serde(rename = "HWInventoryByLocationType")]
1857    pub hw_inventory_by_location_type: String,
1858    #[serde(rename = "PopulatedFRU")]
1859    #[serde(skip_serializing_if = "Option::is_none")]
1860    pub populated_fru: Option<HWInvByFRUNodeAccel>,
1861    #[serde(rename = "NodeAccelLocationInfo")]
1862    #[serde(skip_serializing_if = "Option::is_none")]
1863    pub node_accel_location_info: Option<RedfishProcessorLocationInfo>,
1864}
1865
1866#[derive(Debug, Serialize, Deserialize, Clone)]
1867pub struct RedfishDriveLocationInfo {
1868    #[serde(rename = "Id")]
1869    #[serde(skip_serializing_if = "Option::is_none")]
1870    pub id: Option<String>,
1871    #[serde(rename = "Name")]
1872    #[serde(skip_serializing_if = "Option::is_none")]
1873    pub name: Option<String>,
1874    #[serde(rename = "Description")]
1875    #[serde(skip_serializing_if = "Option::is_none")]
1876    pub description: Option<String>,
1877}
1878
1879#[derive(Debug, Serialize, Deserialize, Clone)]
1880pub struct HWInvByLocDrive {
1881    #[serde(rename = "ID")]
1882    pub id: String,
1883    #[serde(rename = "Type")]
1884    #[serde(skip_serializing_if = "Option::is_none")]
1885    pub r#type: Option<String>,
1886    #[serde(rename = "Ordinal")]
1887    #[serde(skip_serializing_if = "Option::is_none")]
1888    pub ordinal: Option<u32>,
1889    #[serde(rename = "Status")]
1890    #[serde(skip_serializing_if = "Option::is_none")]
1891    pub status: Option<String>,
1892    #[serde(rename = "HWInventoryByLocationType")]
1893    pub hw_inventory_by_location_type: String,
1894    #[serde(rename = "PopulatedFRU")]
1895    #[serde(skip_serializing_if = "Option::is_none")]
1896    pub populated_fru: Option<HWInventoryByFRU>,
1897    #[serde(rename = "DriveLocationInfo")]
1898    #[serde(skip_serializing_if = "Option::is_none")]
1899    pub drive_location_info: Option<RedfishDriveLocationInfo>,
1900}
1901
1902#[derive(Debug, Serialize, Deserialize, Clone)]
1903pub struct MemoryLocation {
1904    #[serde(rename = "Socket")]
1905    #[serde(skip_serializing_if = "Option::is_none")]
1906    pub socket: Option<u32>,
1907    #[serde(rename = "MemoryController")]
1908    #[serde(skip_serializing_if = "Option::is_none")]
1909    pub memory_controller: Option<u32>,
1910    #[serde(rename = "Channel")]
1911    #[serde(skip_serializing_if = "Option::is_none")]
1912    pub channel: Option<u32>,
1913    #[serde(rename = "Slot")]
1914    #[serde(skip_serializing_if = "Option::is_none")]
1915    pub slot: Option<u32>,
1916}
1917
1918#[derive(Debug, Serialize, Deserialize, Clone)]
1919pub struct RedfishMemoryLocationInfo {
1920    #[serde(rename = "Id")]
1921    #[serde(skip_serializing_if = "Option::is_none")]
1922    pub id: Option<String>,
1923    #[serde(rename = "Name")]
1924    #[serde(skip_serializing_if = "Option::is_none")]
1925    pub name: Option<String>,
1926    #[serde(rename = "Description")]
1927    #[serde(skip_serializing_if = "Option::is_none")]
1928    pub description: Option<String>,
1929    #[serde(rename = "MemoryLocation")]
1930    #[serde(skip_serializing_if = "Option::is_none")]
1931    pub memory_location: Option<MemoryLocation>,
1932}
1933
1934#[derive(Debug, Serialize, Deserialize, Clone)]
1935pub struct HWInvByLocMemory {
1936    #[serde(rename = "ID")]
1937    pub id: String,
1938    #[serde(rename = "Type")]
1939    #[serde(skip_serializing_if = "Option::is_none")]
1940    pub r#type: Option<String>,
1941    #[serde(rename = "Ordinal")]
1942    #[serde(skip_serializing_if = "Option::is_none")]
1943    pub ordinal: Option<u32>,
1944    #[serde(rename = "Status")]
1945    #[serde(skip_serializing_if = "Option::is_none")]
1946    pub status: Option<String>,
1947    #[serde(rename = "HWInventoryByLocationType")]
1948    pub hw_inventory_by_location_type: String,
1949    #[serde(rename = "PopulatedFRU")]
1950    #[serde(skip_serializing_if = "Option::is_none")]
1951    pub populated_fru: Option<HWInvByFRUMemory>,
1952    #[serde(rename = "MemoryLocationInfo")]
1953    pub memory_location_info: RedfishMemoryLocationInfo,
1954}
1955
1956#[derive(Debug, Serialize, Deserialize, Clone)]
1957pub struct RedfishNodeAccelRiserLocationInfo {
1958    #[serde(rename = "Name")]
1959    #[serde(skip_serializing_if = "Option::is_none")]
1960    pub name: Option<String>,
1961    #[serde(rename = "Description")]
1962    #[serde(skip_serializing_if = "Option::is_none")]
1963    pub description: Option<String>,
1964}
1965
1966#[derive(Debug, Serialize, Deserialize, Clone)]
1967pub struct HWInvByLocNodeAccelRiser {
1968    #[serde(rename = "ID")]
1969    pub id: String,
1970    #[serde(rename = "Type")]
1971    #[serde(skip_serializing_if = "Option::is_none")]
1972    pub r#type: Option<String>,
1973    #[serde(rename = "Ordinal")]
1974    #[serde(skip_serializing_if = "Option::is_none")]
1975    pub ordinal: Option<u32>,
1976    #[serde(rename = "Status")]
1977    #[serde(skip_serializing_if = "Option::is_none")]
1978    pub status: Option<String>,
1979    #[serde(rename = "HWInventoryByLocationType")]
1980    pub hw_inventory_by_location_type: String,
1981    #[serde(rename = "PopulatedFRU")]
1982    #[serde(skip_serializing_if = "Option::is_none")]
1983    pub populated_fru: Option<HWInventoryByFRU>,
1984    #[serde(rename = "NodeAccelRiserLocationInfo")]
1985    #[serde(skip_serializing_if = "Option::is_none")]
1986    pub node_accel_riser_location_info: Option<RedfishNodeAccelRiserLocationInfo>,
1987}
1988
1989#[derive(Debug, Serialize, Deserialize, Clone)]
1990pub struct HSNNICLocationInfo {
1991    #[serde(rename = "Id")]
1992    #[serde(skip_serializing_if = "Option::is_none")]
1993    pub id: Option<String>,
1994    #[serde(rename = "Name")]
1995    #[serde(skip_serializing_if = "Option::is_none")]
1996    pub name: Option<String>,
1997    #[serde(rename = "Description")]
1998    #[serde(skip_serializing_if = "Option::is_none")]
1999    pub description: Option<String>,
2000}
2001
2002#[derive(Debug, Serialize, Deserialize, Clone)]
2003pub struct HWInvByLocHSNNIC {
2004    #[serde(rename = "ID")]
2005    pub id: String,
2006    #[serde(rename = "Type")]
2007    #[serde(skip_serializing_if = "Option::is_none")]
2008    pub r#type: Option<String>,
2009    #[serde(rename = "Ordinal")]
2010    #[serde(skip_serializing_if = "Option::is_none")]
2011    pub ordinal: Option<u32>,
2012    #[serde(rename = "Status")]
2013    #[serde(skip_serializing_if = "Option::is_none")]
2014    pub status: Option<String>,
2015    #[serde(rename = "HWInventoryByLocationType")]
2016    pub hw_inventory_by_location_type: String,
2017    #[serde(rename = "PopulatedFRU")]
2018    #[serde(skip_serializing_if = "Option::is_none")]
2019    pub populated_fru: Option<HWInvByFRUHSNNIC>,
2020    /* #[serde(rename = "NodeHsnNicLocationInfo")]
2021    pub node_hsn_nic_location_info: HSNNICLocationInfo, */
2022    #[serde(rename = "HSNNICLocationInfo")]
2023    pub hsn_nic_location_info: HSNNICLocationInfo,
2024}
2025
2026#[derive(Debug, Serialize, Deserialize, Clone)]
2027pub struct RedfishSystemFRUInfo {
2028    #[serde(rename = "AssetTag")]
2029    #[serde(skip_serializing_if = "Option::is_none")]
2030    pub asset_tag: Option<String>,
2031    #[serde(rename = "BiosVersion")]
2032    #[serde(skip_serializing_if = "Option::is_none")]
2033    pub bios_version: Option<String>,
2034    #[serde(rename = "Model")]
2035    #[serde(skip_serializing_if = "Option::is_none")]
2036    pub model: Option<String>,
2037    #[serde(rename = "Manufacturer")]
2038    #[serde(skip_serializing_if = "Option::is_none")]
2039    pub manufacturer: Option<String>,
2040    #[serde(rename = "PartNumber")]
2041    #[serde(skip_serializing_if = "Option::is_none")]
2042    pub part_number: Option<String>,
2043    #[serde(rename = "SerialNumber")]
2044    #[serde(skip_serializing_if = "Option::is_none")]
2045    pub serial_number: Option<String>,
2046    #[serde(rename = "SKU")]
2047    #[serde(skip_serializing_if = "Option::is_none")]
2048    pub sku: Option<String>,
2049    #[serde(rename = "SystemType")]
2050    #[serde(skip_serializing_if = "Option::is_none")]
2051    pub system_type: Option<String>,
2052    #[serde(rename = "UUID")]
2053    #[serde(skip_serializing_if = "Option::is_none")]
2054    pub uuid: Option<String>,
2055}
2056
2057#[derive(Debug, Serialize, Deserialize, Clone)]
2058pub struct HWInvByFRUNode {
2059    #[serde(rename = "FRUID")]
2060    #[serde(skip_serializing_if = "Option::is_none")]
2061    pub fru_id: Option<String>,
2062    #[serde(rename = "Type")]
2063    #[serde(skip_serializing_if = "Option::is_none")]
2064    pub r#type: Option<String>,
2065    #[serde(rename = "FRUSubType")]
2066    #[serde(skip_serializing_if = "Option::is_none")]
2067    pub fru_sub_type: Option<String>,
2068    #[serde(rename = "HWInventoryByFRUType")]
2069    pub hw_inventory_by_fru_type: String,
2070    #[serde(rename = "NodeFRUInfo")]
2071    pub node_fru_info: RedfishSystemFRUInfo,
2072}
2073
2074#[derive(Debug, Serialize, Deserialize, Clone)]
2075pub struct HSNNICFRUInfo {
2076    #[serde(rename = "Manufacturer")]
2077    #[serde(skip_serializing_if = "Option::is_none")]
2078    pub manufacturer: Option<String>,
2079    #[serde(rename = "Model")]
2080    #[serde(skip_serializing_if = "Option::is_none")]
2081    pub model: Option<String>,
2082    #[serde(rename = "PartNumber")]
2083    #[serde(skip_serializing_if = "Option::is_none")]
2084    pub part_number: Option<String>,
2085    #[serde(rename = "SKU")]
2086    #[serde(skip_serializing_if = "Option::is_none")]
2087    pub sku: Option<String>,
2088    #[serde(rename = "SerialNumber")]
2089    #[serde(skip_serializing_if = "Option::is_none")]
2090    pub serial_number: Option<String>,
2091}
2092
2093#[derive(Debug, Serialize, Deserialize, Clone)]
2094pub struct HWInvByLocNode {
2095    #[serde(rename = "ID")]
2096    pub id: String,
2097    #[serde(rename = "Type")]
2098    #[serde(skip_serializing_if = "Option::is_none")]
2099    pub r#type: Option<String>,
2100    #[serde(rename = "Ordinal")]
2101    #[serde(skip_serializing_if = "Option::is_none")]
2102    pub ordinal: Option<u32>,
2103    #[serde(rename = "Status")]
2104    #[serde(skip_serializing_if = "Option::is_none")]
2105    pub status: Option<String>,
2106    #[serde(rename = "HWInventoryByLocationType")]
2107    pub hw_inventory_by_location_type: String,
2108    #[serde(rename = "PopulatedFRU")]
2109    #[serde(skip_serializing_if = "Option::is_none")]
2110    pub populated_fru: Option<HWInvByFRUNode>,
2111    #[serde(rename = "NodeLocationInfo")]
2112    #[serde(skip_serializing_if = "Option::is_none")]
2113    pub node_location_info: Option<RedfishSystemLocationInfo>,
2114    #[serde(rename = "Processors")]
2115    #[serde(skip_serializing_if = "Option::is_none")]
2116    pub processors: Option<Vec<HWInvByLocProcessor>>,
2117    #[serde(rename = "NodeAccels")]
2118    #[serde(skip_serializing_if = "Option::is_none")]
2119    pub node_accels: Option<Vec<HWInvByLocNodeAccel>>,
2120    #[serde(rename = "Dives")]
2121    #[serde(skip_serializing_if = "Option::is_none")]
2122    pub drives: Option<Vec<HWInvByLocDrive>>,
2123    #[serde(rename = "Memory")]
2124    #[serde(skip_serializing_if = "Option::is_none")]
2125    pub memory: Option<Vec<HWInvByLocMemory>>,
2126    #[serde(rename = "NodeAccelRisers")]
2127    #[serde(skip_serializing_if = "Option::is_none")]
2128    pub node_accel_risers: Option<Vec<HWInvByLocNodeAccelRiser>>,
2129    #[serde(rename = "NodeHsnNICs")]
2130    #[serde(skip_serializing_if = "Option::is_none")]
2131    pub node_hsn_nics: Option<Vec<HWInvByLocHSNNIC>>,
2132}
2133
2134#[derive(Debug, Serialize, Deserialize, Clone)]
2135pub struct RedfishPDULocationInfo {
2136    #[serde(rename = "Id")]
2137    #[serde(skip_serializing_if = "Option::is_none")]
2138    pub id: Option<String>,
2139    #[serde(rename = "Name")]
2140    #[serde(skip_serializing_if = "Option::is_none")]
2141    pub name: Option<String>,
2142    #[serde(rename = "Description")]
2143    #[serde(skip_serializing_if = "Option::is_none")]
2144    pub description: Option<String>,
2145    #[serde(rename = "UUID")]
2146    #[serde(skip_serializing_if = "Option::is_none")]
2147    pub uuid: Option<String>,
2148}
2149
2150#[derive(Debug, Serialize, Deserialize, Clone)]
2151pub struct RedfishOutletLocationInfo {
2152    #[serde(rename = "Id")]
2153    #[serde(skip_serializing_if = "Option::is_none")]
2154    pub id: Option<String>,
2155    #[serde(rename = "Name")]
2156    #[serde(skip_serializing_if = "Option::is_none")]
2157    pub name: Option<String>,
2158    #[serde(rename = "Description")]
2159    #[serde(skip_serializing_if = "Option::is_none")]
2160    pub description: Option<String>,
2161}
2162
2163#[derive(Debug, Serialize, Deserialize, Clone)]
2164pub struct HWInvByLocOutlet {
2165    #[serde(rename = "ID")]
2166    pub id: String,
2167    #[serde(rename = "Type")]
2168    #[serde(skip_serializing_if = "Option::is_none")]
2169    pub r#type: Option<String>,
2170    #[serde(rename = "Ordinal")]
2171    #[serde(skip_serializing_if = "Option::is_none")]
2172    pub ordinal: Option<u32>,
2173    #[serde(rename = "Status")]
2174    #[serde(skip_serializing_if = "Option::is_none")]
2175    pub status: Option<String>,
2176    #[serde(rename = "HWInventoryByLocationType")]
2177    pub hw_inventory_by_location_type: String,
2178    #[serde(rename = "PopulatedFRU")]
2179    #[serde(skip_serializing_if = "Option::is_none")]
2180    pub populated_fru: Option<HWInventoryByFRU>,
2181    #[serde(rename = "OutletLocationInfo")]
2182    #[serde(skip_serializing_if = "Option::is_none")]
2183    pub outlet_location_info: Option<RedfishOutletLocationInfo>,
2184}
2185
2186#[derive(Debug, Serialize, Deserialize, Clone)]
2187pub struct HWInvByLocPDU {
2188    #[serde(rename = "ID")]
2189    pub id: String,
2190    #[serde(rename = "Type")]
2191    #[serde(skip_serializing_if = "Option::is_none")]
2192    pub r#type: Option<String>,
2193    #[serde(rename = "Ordinal")]
2194    #[serde(skip_serializing_if = "Option::is_none")]
2195    pub ordinal: Option<u32>,
2196    #[serde(rename = "Status")]
2197    #[serde(skip_serializing_if = "Option::is_none")]
2198    pub status: Option<String>,
2199    #[serde(rename = "HWInventoryByLocationType")]
2200    pub hw_inventory_by_location_type: String,
2201    #[serde(rename = "PopulatedFRU")]
2202    #[serde(skip_serializing_if = "Option::is_none")]
2203    pub populated_fru: Option<HWInventoryByFRU>,
2204    #[serde(rename = "PDULocationInfo")]
2205    #[serde(skip_serializing_if = "Option::is_none")]
2206    pub pdu_location_info: Option<RedfishPDULocationInfo>,
2207    #[serde(rename = "CabinetPDUPowerConnectors")]
2208    #[serde(skip_serializing_if = "Option::is_none")]
2209    pub cabinet_pdu_power_connectors: Option<Vec<HWInvByLocOutlet>>,
2210}
2211
2212#[derive(Debug, Serialize, Deserialize, Clone)]
2213pub struct RedfishCMMRectifierLocationInfo {
2214    #[serde(rename = "Name")]
2215    #[serde(skip_serializing_if = "Option::is_none")]
2216    pub name: Option<String>,
2217    #[serde(rename = "FirmwareVersion")]
2218    #[serde(skip_serializing_if = "Option::is_none")]
2219    pub firmware_version: Option<String>,
2220}
2221
2222#[derive(Debug, Serialize, Deserialize, Clone)]
2223pub struct HWInvByLocCMMRectifier {
2224    #[serde(rename = "ID")]
2225    pub id: String,
2226    #[serde(rename = "Type")]
2227    #[serde(skip_serializing_if = "Option::is_none")]
2228    pub r#type: Option<String>,
2229    #[serde(rename = "Ordinal")]
2230    #[serde(skip_serializing_if = "Option::is_none")]
2231    pub ordinal: Option<u32>,
2232    #[serde(rename = "Status")]
2233    #[serde(skip_serializing_if = "Option::is_none")]
2234    pub status: Option<String>,
2235    #[serde(rename = "HWInventoryByLocationType")]
2236    pub hw_inventory_by_location_type: String,
2237    #[serde(rename = "PopulatedFRU")]
2238    #[serde(skip_serializing_if = "Option::is_none")]
2239    pub populated_fru: Option<HWInventoryByFRU>,
2240    #[serde(rename = "CMMRectifierLocationInfo")]
2241    #[serde(skip_serializing_if = "Option::is_none")]
2242    pub cmm_rectifier_location_info: Option<RedfishCMMRectifierLocationInfo>,
2243}
2244
2245#[derive(Debug, Serialize, Deserialize, Clone)]
2246pub struct RedfishNodeEnclosurePowerSupplyLocationInfo {
2247    #[serde(rename = "Name")]
2248    #[serde(skip_serializing_if = "Option::is_none")]
2249    pub name: Option<String>,
2250    #[serde(rename = "FirmwareVersion")]
2251    #[serde(skip_serializing_if = "Option::is_none")]
2252    pub firmware_version: Option<String>,
2253}
2254
2255#[derive(Debug, Serialize, Deserialize, Clone)]
2256pub struct HWInvByLocNodePowerSupply {
2257    #[serde(rename = "ID")]
2258    pub id: String,
2259    #[serde(rename = "Type")]
2260    #[serde(skip_serializing_if = "Option::is_none")]
2261    pub r#type: Option<String>,
2262    #[serde(rename = "Ordinal")]
2263    #[serde(skip_serializing_if = "Option::is_none")]
2264    pub ordinal: Option<u32>,
2265    #[serde(rename = "Status")]
2266    #[serde(skip_serializing_if = "Option::is_none")]
2267    pub status: Option<String>,
2268    #[serde(rename = "HWInventoryByLocationType")]
2269    pub hw_inventory_by_location_type: String,
2270    #[serde(rename = "PopulatedFRU")]
2271    #[serde(skip_serializing_if = "Option::is_none")]
2272    pub populated_fru: Option<HWInventoryByFRU>,
2273    #[serde(rename = "NodeEnclosurePowerSupplyLocationInfo")]
2274    #[serde(skip_serializing_if = "Option::is_none")]
2275    pub node_enclosure_power_supply_location_info:
2276        Option<RedfishNodeEnclosurePowerSupplyLocationInfo>,
2277}
2278
2279#[derive(Debug, Serialize, Deserialize, Clone)]
2280pub struct RedfishManagerLocationInfo {
2281    #[serde(rename = "Id")]
2282    #[serde(skip_serializing_if = "Option::is_none")]
2283    pub id: Option<String>,
2284    #[serde(rename = "Name")]
2285    #[serde(skip_serializing_if = "Option::is_none")]
2286    pub name: Option<String>,
2287    #[serde(rename = "Description")]
2288    #[serde(skip_serializing_if = "Option::is_none")]
2289    pub description: Option<String>,
2290    #[serde(rename = "DateTime")]
2291    #[serde(skip_serializing_if = "Option::is_none")]
2292    pub date_time: Option<String>,
2293    #[serde(rename = "DateTimeLocalOffset")]
2294    #[serde(skip_serializing_if = "Option::is_none")]
2295    pub date_time_local_offset: Option<String>,
2296    #[serde(rename = "FirmwareVersion")]
2297    #[serde(skip_serializing_if = "Option::is_none")]
2298    pub firmware_version: Option<String>,
2299}
2300
2301#[derive(Debug, Serialize, Deserialize, Clone)]
2302pub struct HWInvByLocNodeBMC {
2303    #[serde(rename = "ID")]
2304    pub id: String,
2305    #[serde(rename = "Type")]
2306    #[serde(skip_serializing_if = "Option::is_none")]
2307    pub r#type: Option<String>,
2308    #[serde(rename = "Ordinal")]
2309    #[serde(skip_serializing_if = "Option::is_none")]
2310    pub ordinal: Option<u32>,
2311    #[serde(rename = "Status")]
2312    #[serde(skip_serializing_if = "Option::is_none")]
2313    pub status: Option<String>,
2314    #[serde(rename = "HWInventoryByLocationType")]
2315    pub hw_inventory_by_location_type: String,
2316    #[serde(rename = "PopulatedFRU")]
2317    #[serde(skip_serializing_if = "Option::is_none")]
2318    pub populated_fru: Option<HWInventoryByFRU>,
2319    #[serde(rename = "NodeBMCLocationInfo")]
2320    #[serde(skip_serializing_if = "Option::is_none")]
2321    pub node_bmc_location_info: Option<RedfishManagerLocationInfo>,
2322}
2323
2324#[derive(Debug, Serialize, Deserialize, Clone)]
2325pub struct HWInvByLocRouterBMC {
2326    #[serde(rename = "ID")]
2327    pub id: String,
2328    #[serde(rename = "Type")]
2329    #[serde(skip_serializing_if = "Option::is_none")]
2330    pub r#type: Option<String>,
2331    #[serde(rename = "Ordinal")]
2332    #[serde(skip_serializing_if = "Option::is_none")]
2333    pub ordinal: Option<u32>,
2334    #[serde(rename = "Status")]
2335    #[serde(skip_serializing_if = "Option::is_none")]
2336    pub status: Option<String>,
2337    #[serde(rename = "HWInventoryByLocationType")]
2338    pub hw_inventory_by_location_type: String,
2339    #[serde(rename = "PopulatedFRU")]
2340    #[serde(skip_serializing_if = "Option::is_none")]
2341    pub populated_fru: Option<HWInventoryByFRU>,
2342    #[serde(rename = "RouterBMCLocationInfo")]
2343    #[serde(skip_serializing_if = "Option::is_none")]
2344    pub router_bmc_location_info: Option<RedfishManagerLocationInfo>,
2345}
2346
2347/* #[derive(Debug, Serialize, Deserialize, Clone)]
2348pub struct HWInventoryList {
2349    #[serde(rename = "Hardware")]
2350    pub hw_inventory: Vec<HWInventory>,
2351} */
2352
2353#[derive(Debug, Serialize, Deserialize, Clone)]
2354pub struct HWInventory {
2355    #[serde(rename = "XName")]
2356    #[serde(skip_serializing_if = "Option::is_none")]
2357    pub xname: Option<String>,
2358    #[serde(rename = "Format")]
2359    #[serde(skip_serializing_if = "Option::is_none")]
2360    pub format: Option<String>,
2361    #[serde(rename = "Cabinets")]
2362    #[serde(skip_serializing_if = "Option::is_none")]
2363    pub cabinets: Option<Vec<HWInvByLocCabinet>>,
2364    #[serde(rename = "Chassis")]
2365    #[serde(skip_serializing_if = "Option::is_none")]
2366    pub chassis: Option<Vec<HWInvByLocChassis>>,
2367    #[serde(rename = "ComputeModules")]
2368    #[serde(skip_serializing_if = "Option::is_none")]
2369    pub compute_modules: Option<Vec<HWInvByLocComputeModule>>,
2370    #[serde(rename = "RouterModules")]
2371    #[serde(skip_serializing_if = "Option::is_none")]
2372    pub router_modules: Option<Vec<HWInvByLocRouterModule>>,
2373    #[serde(rename = "NodeEnclosures")]
2374    #[serde(skip_serializing_if = "Option::is_none")]
2375    pub node_enclosures: Option<Vec<HWInvByLocNodeEnclosure>>,
2376    #[serde(rename = "HSNBoards")]
2377    #[serde(skip_serializing_if = "Option::is_none")]
2378    pub hsn_boards: Option<Vec<HWInvByLocHSNBoard>>,
2379    #[serde(rename = "MgmtSwitches")]
2380    #[serde(skip_serializing_if = "Option::is_none")]
2381    pub mgmt_switches: Option<Vec<HWInvByLocMgmtSwitch>>,
2382    #[serde(rename = "MgmtHLSwitches")]
2383    #[serde(skip_serializing_if = "Option::is_none")]
2384    pub mgmt_hl_switches: Option<Vec<HWInvByLocMgmtHLSwitch>>,
2385    #[serde(rename = "CDUMgmtSwitches")]
2386    #[serde(skip_serializing_if = "Option::is_none")]
2387    pub cdu_mgmt_switches: Option<Vec<HWInvByLocCDUMgmtSwitch>>,
2388    #[serde(rename = "Nodes")]
2389    #[serde(skip_serializing_if = "Option::is_none")]
2390    pub nodes: Option<Vec<HWInvByLocNode>>,
2391    #[serde(rename = "Processors")]
2392    #[serde(skip_serializing_if = "Option::is_none")]
2393    pub processors: Option<Vec<HWInvByLocProcessor>>,
2394    #[serde(rename = "NodeAccels")]
2395    #[serde(skip_serializing_if = "Option::is_none")]
2396    pub node_accels: Option<Vec<HWInvByLocNodeAccel>>,
2397    #[serde(rename = "Drives")]
2398    #[serde(skip_serializing_if = "Option::is_none")]
2399    pub drives: Option<Vec<HWInvByLocDrive>>,
2400    #[serde(rename = "Memory")]
2401    #[serde(skip_serializing_if = "Option::is_none")]
2402    pub memory: Option<Vec<HWInvByLocMemory>>,
2403    #[serde(rename = "CabinetPDUs")]
2404    #[serde(skip_serializing_if = "Option::is_none")]
2405    pub cabinet_pdus: Option<Vec<HWInvByLocPDU>>,
2406    #[serde(rename = "CabinetPDUPowerConnectors")]
2407    #[serde(skip_serializing_if = "Option::is_none")]
2408    pub cabinet_pdu_power_connectors: Option<Vec<HWInvByLocOutlet>>,
2409    #[serde(rename = "CMMRectifiers")]
2410    #[serde(skip_serializing_if = "Option::is_none")]
2411    pub cmm_rectifiers: Option<Vec<HWInvByLocCMMRectifier>>,
2412    #[serde(rename = "NodeAccelRisers")]
2413    #[serde(skip_serializing_if = "Option::is_none")]
2414    pub node_accel_risers: Option<Vec<HWInvByLocNodeAccelRiser>>,
2415    #[serde(rename = "NodeHsnNICs")]
2416    #[serde(skip_serializing_if = "Option::is_none")]
2417    pub node_hsn_nics: Option<Vec<HWInvByLocHSNNIC>>,
2418    #[serde(rename = "NodeEnclosurePowerSupplies")]
2419    #[serde(skip_serializing_if = "Option::is_none")]
2420    pub node_enclosure_power_supplies: Option<Vec<HWInvByLocNodePowerSupply>>,
2421    #[serde(rename = "NodeBMC")]
2422    #[serde(skip_serializing_if = "Option::is_none")]
2423    pub node_bmc: Option<Vec<HWInvByLocNodeBMC>>,
2424    #[serde(rename = "RouterBMC")]
2425    #[serde(skip_serializing_if = "Option::is_none")]
2426    pub router_bmc: Option<Vec<HWInvByLocRouterBMC>>,
2427}
2428
2429#[derive(Debug, Serialize, Deserialize, Clone)]
2430pub struct Hardware {
2431    #[serde(rename = "Hardware")]
2432    #[serde(skip_serializing_if = "Option::is_none")]
2433    pub hardware: Option<Vec<HWInvByLocNode>>,
2434}
2435
2436#[derive(Debug, Serialize, Deserialize, Clone)]
2437pub struct NodeLocationInfo {
2438    #[serde(rename = "Id")]
2439    pub id: String,
2440    #[serde(rename = "Name")]
2441    #[serde(skip_serializing_if = "Option::is_none")]
2442    pub name: Option<String>,
2443    #[serde(rename = "Description")]
2444    #[serde(skip_serializing_if = "Option::is_none")]
2445    pub description: Option<String>,
2446    #[serde(rename = "Hostname")]
2447    #[serde(skip_serializing_if = "Option::is_none")]
2448    pub hostname: Option<String>,
2449    #[serde(rename = "ProcessorSummary")]
2450    #[serde(skip_serializing_if = "Option::is_none")]
2451    pub processor_summary: Option<ProcessorSummary>,
2452    #[serde(rename = "MemorySummary")]
2453    #[serde(skip_serializing_if = "Option::is_none")]
2454    pub memory_summary: Option<MemorySummary>,
2455}
2456
2457#[derive(Debug, Serialize, Deserialize, Clone)]
2458#[serde(untagged)] // <-- this is important. More info https://serde.rs/enum-representations.html#untagged
2459pub enum HWInventoryByLocation {
2460    /* HWInvByLocCabinet(HWInvByLocCabinet),
2461    HWInvByLocChassis(HWInvByLocChassis),
2462    HWInvByLocComputeModule(HWInvByLocComputeModule),
2463    HWInvByLocRouterModule(HWInvByLocRouterModule),
2464    HWInvByLocNodeEnclosure(HWInvByLocNodeEnclosure),
2465    HWInvByLocHSNBoard(HWInvByLocHSNBoard),
2466    HWInvByLocMgmtSwitch(HWInvByLocMgmtSwitch),
2467    HWInvByLocMgmtHLSwitch(HWInvByLocMgmtHLSwitch),
2468    HWInvByLocCDUMgmtSwitch(HWInvByLocCDUMgmtSwitch), */
2469    HWInvByLocNode(HWInvByLocNode),
2470    HWInvByLocProcessor(HWInvByLocProcessor),
2471    HWInvByLocNodeAccel(HWInvByLocNodeAccel),
2472    /*     HWInvByLocDrive(HWInvByLocDrive), */
2473    HWInvByLocMemory(HWInvByLocMemory),
2474    /* HWInvByLocPDU(HWInvByLocPDU),
2475    HWInvByLocOutlet(HWInvByLocOutlet),
2476    HWInvByLocCMMRectifier(HWInvByLocCMMRectifier),
2477    HWInvByLocNodeAccelRiser(HWInvByLocNodeAccelRiser), */
2478    HWInvByLocHSNNIC(HWInvByLocHSNNIC),
2479    /* HWInvByLocNodePowerSupply(HWInvByLocNodePowerSupply),
2480    HWInvByLocNodeBMC(HWInvByLocNodeBMC),
2481    HWInvByLocRouterBMC(HWInvByLocRouterBMC), */
2482}
2483
2484/// struct used in POST and GET endpoints that manage multiple instances of 'HWInventoryByLocation'
2485#[derive(Debug, Serialize, Deserialize, Clone)]
2486pub struct HWInventoryByLocationList {
2487    #[serde(rename = "Hardware")]
2488    #[serde(skip_serializing_if = "Option::is_none")]
2489    pub hardware: Option<Vec<HWInventoryByLocation>>,
2490}
2491
2492#[derive(Debug, Serialize, Deserialize, Clone)]
2493pub struct Link {
2494    #[serde(skip_serializing_if = "Option::is_none")]
2495    pub rel: Option<String>,
2496    #[serde(skip_serializing_if = "Option::is_none")]
2497    pub href: Option<String>,
2498}
2499
2500#[derive(Debug, Serialize, Deserialize, Clone)]
2501pub struct Cfs {
2502    #[serde(skip_serializing_if = "Option::is_none")]
2503    pub configuration: Option<String>,
2504}
2505
2506#[derive(Debug, Serialize, Deserialize, Clone)]
2507pub struct BootSet {
2508    #[serde(skip_serializing_if = "Option::is_none")]
2509    pub name: Option<String>,
2510    #[serde(skip_serializing_if = "Option::is_none")]
2511    pub path: Option<String>,
2512    #[serde(skip_serializing_if = "Option::is_none")]
2513    pub cfs: Option<Cfs>,
2514    #[serde(skip_serializing_if = "Option::is_none")]
2515    pub r#type: Option<String>,
2516    #[serde(skip_serializing_if = "Option::is_none")]
2517    pub etag: Option<String>,
2518    #[serde(skip_serializing_if = "Option::is_none")]
2519    pub kernel_parameters: Option<String>,
2520    #[serde(skip_serializing_if = "Option::is_none")]
2521    pub node_list: Option<Vec<String>>,
2522    #[serde(skip_serializing_if = "Option::is_none")]
2523    pub node_roles_groups: Option<Vec<String>>,
2524    #[serde(skip_serializing_if = "Option::is_none")]
2525    pub node_groups: Option<Vec<String>>,
2526    #[serde(skip_serializing_if = "Option::is_none")]
2527    pub arch: Option<String>, // TODO: use Arch enum instead
2528    #[serde(skip_serializing_if = "Option::is_none")]
2529    pub rootfs_provider: Option<String>,
2530    #[serde(skip_serializing_if = "Option::is_none")]
2531    pub rootfs_provider_passthrough: Option<String>,
2532}
2533
2534#[derive(Debug, Serialize, Deserialize, Clone)]
2535pub struct BosSessionTemplate {
2536    #[serde(skip_serializing_if = "Option::is_none")]
2537    pub name: Option<String>,
2538    #[serde(skip_serializing_if = "Option::is_none")]
2539    pub tenant: Option<String>,
2540    #[serde(skip_serializing_if = "Option::is_none")]
2541    pub description: Option<String>,
2542    #[serde(skip_serializing_if = "Option::is_none")]
2543    pub enable_cfs: Option<bool>,
2544    #[serde(skip_serializing_if = "Option::is_none")]
2545    pub cfs: Option<Cfs>,
2546    #[serde(skip_serializing_if = "Option::is_none")]
2547    pub boot_sets: Option<HashMap<String, BootSet>>,
2548    #[serde(skip_serializing_if = "Option::is_none")]
2549    pub links: Option<Vec<Link>>,
2550}