backend_dispatcher/types/
mod.rs

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