backend_dispatcher/types/
mod.rs

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