backend_dispatcher/types/
mod.rs

1pub mod cfs;
2pub mod ims;
3
4use std::{collections::HashMap, str::FromStr};
5
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use strum_macros::{AsRefStr, Display, EnumIter, EnumString, IntoStaticStr};
9
10use crate::error::Error;
11
12#[derive(Serialize, Deserialize, Debug)]
13pub enum K8sAuth {
14    Native {
15        certificate_authority_data: String,
16        client_certificate_data: String,
17        client_key_data: String,
18    },
19    Vault {
20        base_url: String,
21        secret_path: String,
22        role_id: 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(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        member_vec_opt: Option<Vec<String>>,
644        tag_vec_opt: Option<Vec<String>>,
645        exclusive_opt: Option<String>,
646    ) -> Self {
647        let members_opt = if let Some(member_vec) = member_vec_opt {
648            Some(Member {
649                ids: Some(member_vec),
650            })
651        } else {
652            None
653        };
654
655        let group = Self {
656            label: label.to_string(),
657            description: None,
658            tags: tag_vec_opt,
659            members: members_opt,
660            exclusive_group: exclusive_opt,
661        };
662
663        group
664    }
665
666    /// Get group members
667    pub fn get_members(&self) -> Vec<String> {
668        self.members
669            .clone()
670            .map(|member| member.ids.unwrap_or_default())
671            .unwrap_or_default()
672    }
673}
674
675#[derive(Debug, Serialize, Deserialize, Clone)]
676pub struct NodeMetadataArray {
677    #[serde(skip_serializing_if = "Option::is_none")]
678    #[serde(rename = "Components")]
679    pub components: Option<Vec<Component>>,
680}
681
682#[derive(Debug, Serialize, Deserialize, Clone)]
683pub struct Component {
684    #[serde(skip_serializing_if = "Option::is_none")]
685    #[serde(rename = "ID")]
686    pub id: Option<String>,
687    #[serde(skip_serializing_if = "Option::is_none")]
688    #[serde(rename = "Type")]
689    pub r#type: Option<String>,
690    #[serde(skip_serializing_if = "Option::is_none")]
691    #[serde(rename = "State")]
692    pub state: Option<String>,
693    #[serde(skip_serializing_if = "Option::is_none")]
694    #[serde(rename = "Flag")]
695    pub flag: Option<String>,
696    #[serde(skip_serializing_if = "Option::is_none")]
697    #[serde(rename = "Enabled")]
698    pub enabled: Option<bool>,
699    #[serde(skip_serializing_if = "Option::is_none")]
700    #[serde(rename = "SoftwareStatus")]
701    pub software_status: Option<String>,
702    #[serde(skip_serializing_if = "Option::is_none")]
703    #[serde(rename = "Role")]
704    pub role: Option<String>,
705    #[serde(skip_serializing_if = "Option::is_none")]
706    #[serde(rename = "SubRole")]
707    pub sub_role: Option<String>,
708    #[serde(skip_serializing_if = "Option::is_none")]
709    #[serde(rename = "NID")]
710    pub nid: Option<usize>,
711    #[serde(skip_serializing_if = "Option::is_none")]
712    #[serde(rename = "Subtype")]
713    pub subtype: Option<String>,
714    #[serde(skip_serializing_if = "Option::is_none")]
715    #[serde(rename = "NetType")]
716    pub net_type: Option<String>,
717    #[serde(skip_serializing_if = "Option::is_none")]
718    #[serde(rename = "Arch")]
719    pub arch: Option<String>,
720    #[serde(skip_serializing_if = "Option::is_none")]
721    #[serde(rename = "Class")]
722    pub class: Option<String>,
723    #[serde(skip_serializing_if = "Option::is_none")]
724    #[serde(rename = "ReservationDisabled")]
725    pub reservation_disabled: Option<bool>,
726    #[serde(skip_serializing_if = "Option::is_none")]
727    #[serde(rename = "Locked")]
728    pub locked: Option<bool>,
729}
730
731#[derive(Debug, Serialize, Deserialize, Clone)]
732pub struct ComponentArrayPostQuery {
733    #[serde(skip_serializing_if = "Option::is_none")]
734    #[serde(rename = "ComponentIDs")]
735    pub component_ids: Option<Vec<String>>,
736    #[serde(skip_serializing_if = "Option::is_none")]
737    pub partition: Option<String>,
738    #[serde(skip_serializing_if = "Option::is_none")]
739    pub group: Option<String>,
740    #[serde(skip_serializing_if = "Option::is_none")]
741    #[serde(rename = "stateonly")]
742    pub state_only: Option<bool>,
743    #[serde(skip_serializing_if = "Option::is_none")]
744    #[serde(rename = "flagonly")]
745    pub falg_only: Option<bool>,
746    #[serde(skip_serializing_if = "Option::is_none")]
747    #[serde(rename = "roleonly")]
748    pub role_only: Option<bool>,
749    #[serde(skip_serializing_if = "Option::is_none")]
750    #[serde(rename = "nidonly")]
751    pub nid_only: Option<bool>,
752    #[serde(skip_serializing_if = "Option::is_none")]
753    pub r#type: Option<String>,
754    #[serde(skip_serializing_if = "Option::is_none")]
755    pub state: Option<String>,
756    #[serde(skip_serializing_if = "Option::is_none")]
757    pub flag: Option<String>,
758    #[serde(skip_serializing_if = "Option::is_none")]
759    pub enabled: Option<String>,
760    #[serde(skip_serializing_if = "Option::is_none")]
761    #[serde(rename = "softwarestatus")]
762    pub software_status: Option<String>,
763    #[serde(skip_serializing_if = "Option::is_none")]
764    pub role: Option<String>,
765    #[serde(skip_serializing_if = "Option::is_none")]
766    pub subrole: Option<String>,
767    #[serde(skip_serializing_if = "Option::is_none")]
768    pub subtype: Option<String>,
769    #[serde(skip_serializing_if = "Option::is_none")]
770    arch: Option<String>,
771    #[serde(skip_serializing_if = "Option::is_none")]
772    pub class: Option<String>,
773    #[serde(skip_serializing_if = "Option::is_none")]
774    pub nid: Option<String>,
775    #[serde(skip_serializing_if = "Option::is_none")]
776    pub nid_start: Option<String>,
777    #[serde(skip_serializing_if = "Option::is_none")]
778    pub nid_end: Option<String>,
779}
780
781#[derive(Debug, Serialize, Deserialize, Clone)]
782pub struct ComponentArrayPostByNidQuery {
783    #[serde(rename = "NIDRanges")]
784    pub nid_ranges: Vec<String>,
785    #[serde(skip_serializing_if = "Option::is_none")]
786    pub partition: Option<String>,
787    #[serde(skip_serializing_if = "Option::is_none")]
788    #[serde(rename = "stateonly")]
789    pub state_only: Option<bool>,
790    #[serde(skip_serializing_if = "Option::is_none")]
791    #[serde(rename = "flagonly")]
792    pub falg_only: Option<bool>,
793    #[serde(skip_serializing_if = "Option::is_none")]
794    #[serde(rename = "roleonly")]
795    pub role_only: Option<bool>,
796    #[serde(skip_serializing_if = "Option::is_none")]
797    #[serde(rename = "nidonly")]
798    pub nid_only: Option<bool>,
799}
800
801#[derive(Debug, Serialize, Deserialize, Clone)]
802pub struct ComponentArrayPostArray {
803    #[serde(rename = "Components")]
804    pub components: Vec<ComponentCreate>,
805    #[serde(skip_serializing_if = "Option::is_none")]
806    #[serde(rename = "Force")]
807    pub force: Option<bool>,
808}
809
810#[derive(Debug, Serialize, Deserialize, Clone)]
811pub struct ComponentCreate {
812    #[serde(rename = "ID")]
813    pub id: String,
814    #[serde(rename = "State")]
815    pub state: String,
816    #[serde(skip_serializing_if = "Option::is_none")]
817    #[serde(rename = "Flag")]
818    pub flag: Option<String>,
819    #[serde(skip_serializing_if = "Option::is_none")]
820    #[serde(rename = "Enabled")]
821    pub enabled: Option<bool>,
822    #[serde(skip_serializing_if = "Option::is_none")]
823    #[serde(rename = "SoftwareStatus")]
824    pub software_status: Option<String>,
825    #[serde(skip_serializing_if = "Option::is_none")]
826    #[serde(rename = "Role")]
827    pub role: Option<String>,
828    #[serde(skip_serializing_if = "Option::is_none")]
829    #[serde(rename = "SubRole")]
830    pub sub_role: Option<String>,
831    #[serde(skip_serializing_if = "Option::is_none")]
832    #[serde(rename = "NID")]
833    pub nid: Option<usize>,
834    #[serde(skip_serializing_if = "Option::is_none")]
835    #[serde(rename = "Subtype")]
836    pub subtype: Option<String>,
837    #[serde(skip_serializing_if = "Option::is_none")]
838    #[serde(rename = "NetType")]
839    pub net_type: Option<String>,
840    #[serde(skip_serializing_if = "Option::is_none")]
841    #[serde(rename = "Arch")]
842    pub arch: Option<String>,
843    #[serde(skip_serializing_if = "Option::is_none")]
844    #[serde(rename = "Class")]
845    pub class: Option<String>,
846}
847
848#[derive(Debug, Serialize, Deserialize, Clone)]
849pub struct ComponentPut {
850    pub component: ComponentCreate,
851    #[serde(skip_serializing_if = "Option::is_none")]
852    #[serde(rename = "Force")]
853    pub force: Option<bool>,
854}
855
856#[derive(Debug, Serialize, Deserialize, Default, Clone)]
857pub struct BootParameters {
858    #[serde(default)]
859    pub hosts: Vec<String>,
860    #[serde(skip_serializing_if = "Option::is_none")]
861    pub macs: Option<Vec<String>>,
862    #[serde(skip_serializing_if = "Option::is_none")]
863    pub nids: Option<Vec<u32>>,
864    #[serde(default)]
865    pub params: String, // FIXME: change type to HashMap<String, String> by using function
866    // bss::utils::convert_kernel_params_to_map AND create new method
867    // bss::BootParameters::num_kernel_params which returns the list of kernel parameters
868    #[serde(default)]
869    pub kernel: String,
870    #[serde(default)]
871    pub initrd: String,
872    #[serde(rename = "cloud-init")]
873    #[serde(skip_serializing_if = "Option::is_none")]
874    pub cloud_init: Option<Value>,
875}
876
877impl BootParameters {
878    // Assumes s3 path looks like:
879    // - s3://boot-images/59e0180a-3fdd-4936-bba7-14ba914ffd34/kernel
880    // - craycps-s3:s3://boot-images/59e0180a-3fdd-4936-bba7-14ba914ffd34/rootfs:3dfae8d1fa3bb2bfb18152b4f9940ad0-667:dvs:api-gw-service-nmn.local:300:nmn0,hsn0:0
881    // - url=s3://boot-images/59e0180a-3fdd-4936-bba7-14ba914ffd34/rootfs,etag=3dfae8d1fa3bb2bfb18152b4f9940ad0-667 bos_update_frequency=4h
882    pub fn get_image_id_from_s3_path(s3_path: &str) -> Option<&str> {
883        s3_path.split("/").skip(3).next()
884    }
885
886    /// Returns the image id. This function may fail since it assumes kernel path has the following
887    // FIXME: Change function signature so it returns a Result<String, Error> instead of String
888    pub fn get_boot_image(&self) -> String {
889        let params: HashMap<&str, &str> = self
890            .params
891            .split_whitespace()
892            .map(|kernel_param| {
893                kernel_param
894                    .split_once('=')
895                    .map(|(key, value)| (key.trim(), value.trim()))
896                    .unwrap_or((kernel_param, ""))
897            })
898            .collect();
899
900        // NOTE: CN nodes have UIID image id in 'root' kernel parameter
901        // Get `root` kernel parameter and split it by '/'
902        let root_kernel_param_opt = params.get("root");
903        // NOTE: CN nodes have UIID image id in 'metal.server' kernel parameter
904        // Get `root` kernel parameter and split it by '/'
905        let metal_server_kernel_param_opt = params.get("metal.server");
906
907        let boot_image_id_opt: Option<&str> = if let Some(root_kernel_param) = root_kernel_param_opt
908        {
909            Self::get_image_id_from_s3_path(root_kernel_param)
910        } else if let Some(metal_server_kernel_param) = metal_server_kernel_param_opt {
911            Self::get_image_id_from_s3_path(metal_server_kernel_param)
912        } else {
913            None
914        };
915
916        boot_image_id_opt.unwrap_or("").to_string()
917
918        /* let mut path_elem_vec = self.kernel.split("/").skip(3);
919
920        let mut image_id: String = path_elem_vec.next().unwrap_or_default().to_string();
921
922        for path_elem in path_elem_vec {
923            if !path_elem.eq("kernel") {
924                image_id = format!("{}/{}", image_id, path_elem);
925            } else {
926                break;
927            }
928        }
929
930        image_id */
931    }
932
933    /// Update boot image in kernel boot parameters and also in kernel and initrd fields if
934    /// exists. Otherwise nothing is changed. This method updates both kernel params related to
935    /// NCN and also CN
936    /// Returns a boolean that indicates if kernel parameters have change:
937    /// - kernel parameter value changed
938    ///  - number of kernel parameters have changed
939    pub fn update_boot_image(&mut self, new_image_id: &str) -> Result<bool, Error> {
940        let mut changed = false;
941        // replace image id in 'root' kernel param
942
943        // convert kernel params to a hashmap
944        let mut params: HashMap<&str, &str> = self
945            .params
946            .split_whitespace()
947            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
948            .collect();
949
950        // NOTE: CN nodes have UIID image id in 'root' kernel parameter
951        // Get `root` kernel parameter and split it by '/'
952        let root_kernel_param_rslt = params.get("root");
953
954        let mut root_kernel_param: Vec<&str> = match root_kernel_param_rslt {
955            Some(root_kernel_param) => root_kernel_param.split("/").collect::<Vec<&str>>(),
956            None => {
957                return Err(Error::Message(
958                    "ERROR - The 'root' kernel param is missing from user input".to_string(),
959                ));
960            }
961        };
962
963        // Replace image id in root kernel param with new image id
964        for current_image_id in &mut root_kernel_param {
965            // Look for any substring between '/' that matches an UUID formant and take it as
966            // the image id
967            if uuid::Uuid::try_parse(current_image_id).is_ok() {
968                if *current_image_id != new_image_id {
969                    changed = true;
970                }
971                // Replace image id in `root` kernel parameter with new value
972                *current_image_id = new_image_id;
973            }
974        }
975
976        // Create new `root` kernel param string
977        let new_root_kernel_param = root_kernel_param.join("/");
978
979        // Create new kernel parameters
980        params
981            .entry("root")
982            .and_modify(|root_param| *root_param = &new_root_kernel_param);
983
984        self.update_kernel_param("root", &new_root_kernel_param);
985
986        // replace image id in 'nmd_data' kernel param
987
988        // convert kernel params to a hashmap
989        let mut params: HashMap<&str, &str> = self
990            .params
991            .split_whitespace()
992            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
993            .map(|(key, value)| (key.trim(), value.trim()))
994            .collect();
995
996        // NOTE: NCN nodes have UUID image id in 'metal.server' kernel parameter
997        let mut metal_server_kernel_param: Vec<&str>;
998        if let Some(metal_server_data) = params.get("metal.server") {
999            metal_server_kernel_param = metal_server_data.split("/").collect();
1000
1001            for substring in &mut metal_server_kernel_param {
1002                if uuid::Uuid::try_parse(substring).is_ok() {
1003                    *substring = new_image_id;
1004                    changed = true;
1005                }
1006            }
1007
1008            let new_metal_server_kernel_param = metal_server_kernel_param.join("/");
1009
1010            params
1011                .entry("metal.server")
1012                .and_modify(|metal_server_param| {
1013                    *metal_server_param = &new_metal_server_kernel_param
1014                });
1015
1016            self.update_kernel_param("metal.server", &new_metal_server_kernel_param);
1017
1018            // convert kernel params to a hashmap
1019            params = self
1020                .params
1021                .split_whitespace()
1022                .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1023                .collect();
1024        } else {
1025        };
1026
1027        // NOTE: NCN nodes have UUID image id 'nmd_data' kernel parameter
1028        let mut nmd_kernel_param: Vec<&str>;
1029        if let Some(nmd_data) = params.get("nmd_data") {
1030            nmd_kernel_param = nmd_data.split("/").collect();
1031
1032            for substring in &mut nmd_kernel_param {
1033                if uuid::Uuid::try_parse(substring).is_ok() {
1034                    *substring = new_image_id;
1035                    changed = true;
1036                }
1037            }
1038
1039            let new_nmd_kernel_param = nmd_kernel_param.join("/");
1040
1041            params
1042                .entry("nmd_data")
1043                .and_modify(|nmd_param| *nmd_param = &new_nmd_kernel_param);
1044
1045            self.update_kernel_param("nmd_data", &new_nmd_kernel_param);
1046        } else {
1047        };
1048
1049        self.kernel = format!("s3://boot-images/{}/kernel", new_image_id);
1050
1051        self.initrd = format!("s3://boot-images/{}/initrd", new_image_id);
1052
1053        Ok(changed)
1054    }
1055
1056    /// Set a str of kernel parameters:
1057    ///  - if kernel parameter already exists, then it will be updated
1058    ///  - if kernel parameter does not exists, then it will be added
1059    /// Returns true if kernel params have change
1060    pub fn update_kernel_params(&mut self, new_params: &str) -> bool {
1061        let mut change = false;
1062
1063        let new_params: Vec<(&str, &str)> = new_params
1064            .split_whitespace()
1065            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1066            .map(|(key, value)| (key.trim(), value.trim()))
1067            .collect();
1068
1069        let mut params: HashMap<&str, &str> = self
1070            .params
1071            .split_whitespace()
1072            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1073            .collect();
1074
1075        for (new_key, new_value) in &new_params {
1076            for (key, value) in params.iter_mut() {
1077                if *key == *new_key {
1078                    log::debug!("key '{}' found", key);
1079                    if value != new_value {
1080                        log::info!("changing key {} from {} to {}", key, value, new_value);
1081
1082                        *value = new_value;
1083                        change = true
1084                    } else {
1085                        log::debug!("key '{}' value does not change ({})", key, value);
1086                    }
1087                }
1088            }
1089        }
1090
1091        if change == false {
1092            log::debug!("No value change in kernel params. Checking is either new params have been added or removed");
1093            if new_params.len() != params.len() {
1094                log::info!("num kernel parameters have changed");
1095                change = true;
1096            }
1097        }
1098
1099        self.params = params
1100            .iter()
1101            .map(|(key, value)| {
1102                if !value.is_empty() {
1103                    format!("{key}={value}")
1104                } else {
1105                    key.to_string()
1106                }
1107            })
1108            .collect::<Vec<String>>()
1109            .join(" ");
1110
1111        change
1112    }
1113
1114    /// Update kernel parameter. If kernel parameter exists, then it will be updated with new
1115    /// Note: This function won't make any change to params without values (eg: 'quiet') since
1116    /// they don't have values
1117    /// value. otherwise nothing will change
1118    pub fn update_kernel_param(&mut self, new_key: &str, new_value: &str) -> bool {
1119        let mut changed = false;
1120        // convert kernel params to a hashmap
1121        let mut params: HashMap<&str, &str> = self
1122            .params
1123            .split_whitespace()
1124            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1125            .map(|(key, value)| (key.trim(), value.trim()))
1126            .collect();
1127
1128        // Update kernel param with new value
1129        // params.entry(key).and_modify(|value| *value = new_value);
1130        for (current_key, current_value) in params.iter_mut() {
1131            if *current_key == new_key {
1132                log::debug!("key '{}' found", new_key);
1133                if *current_value != new_value {
1134                    log::info!(
1135                        "changing key {} from {} to {}",
1136                        new_key,
1137                        current_value,
1138                        new_value
1139                    );
1140
1141                    *current_value = new_value;
1142                    changed = true
1143                } else {
1144                    log::debug!(
1145                        "key '{}' value does not change ({})",
1146                        new_key,
1147                        current_value
1148                    );
1149                }
1150            }
1151            /* if *current_key == new_key {
1152                *current_value = new_value;
1153                changed = true;
1154            } */
1155        }
1156
1157        // Create new kernel params as a string
1158        self.params = params
1159            .iter()
1160            .map(|(key, value)| {
1161                if !value.is_empty() {
1162                    format!("{key}={value}")
1163                } else {
1164                    key.to_string()
1165                }
1166            })
1167            .collect::<Vec<String>>()
1168            .join(" ");
1169
1170        changed
1171    }
1172
1173    /// Add a kernel parameter:
1174    ///  - if kernel parameter does not exists, then it will be added,
1175    /// otherwise nothing will change
1176    /// Returns true if kernel params have change
1177    pub fn add_kernel_params(&mut self, new_kernel_params: &str) -> bool {
1178        let mut changed = false;
1179        let mut params: HashMap<&str, &str> = self
1180            .params
1181            .split_whitespace()
1182            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1183            .map(|(key, value)| (key.trim(), value.trim()))
1184            .collect();
1185
1186        let new_kernel_params_tuple: HashMap<&str, &str> = new_kernel_params
1187            .split_whitespace()
1188            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1189            .collect();
1190
1191        for (key, new_value) in new_kernel_params_tuple {
1192            // NOTE: do not use --> `params.entry(key).or_insert(new_value);` otherwise, I don't know
1193            // how do we know if the key already exists or not
1194            if params.contains_key(key) {
1195                log::info!("key '{}' already exists, the new kernel parameter won't be added since it already exists", key);
1196            } else {
1197                log::info!(
1198                    "key '{}' not found, adding new kernel param with value '{}'",
1199                    key,
1200                    new_value
1201                );
1202                params.insert(key, new_value);
1203                changed = true
1204            }
1205        }
1206
1207        self.params = params
1208            .iter()
1209            .map(|(key, value)| {
1210                if !value.is_empty() {
1211                    format!("{key}={value}")
1212                } else {
1213                    key.to_string()
1214                }
1215            })
1216            .collect::<Vec<String>>()
1217            .join(" ");
1218
1219        changed
1220    }
1221
1222    /// Delete kernel parameter. If kernel parameter exists, then it will be removed, otherwise
1223    /// nothing will be changed
1224    /// It accepts kernel params in format 'key=value' or just 'key'
1225    /// Returns true if kernel params have change
1226    pub fn delete_kernel_params(&mut self, kernel_params_to_delete: &str) -> bool {
1227        let mut changed = false;
1228        let mut params: HashMap<&str, &str> = self
1229            .params
1230            .split_whitespace()
1231            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1232            .map(|(key, value)| (key.trim(), value.trim()))
1233            .collect();
1234
1235        let kernel_params_to_delete_tuple: HashMap<&str, &str> = kernel_params_to_delete
1236            .split_whitespace()
1237            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1238            .collect();
1239
1240        for (key, _value) in kernel_params_to_delete_tuple {
1241            changed = changed | params.remove(key).is_some();
1242        }
1243
1244        self.params = params
1245            .iter()
1246            .map(|(key, value)| {
1247                if !value.is_empty() {
1248                    format!("{key}={value}")
1249                } else {
1250                    key.to_string()
1251                }
1252            })
1253            .collect::<Vec<String>>()
1254            .join(" ");
1255
1256        changed
1257    }
1258
1259    /// Apply a str of kernel parameters:
1260    ///  - current kernel params will be ignored/removed and replaced by the new ones
1261    /// Returns true if kernel params have change
1262    // FIXME: integrate fixed introduced in methods 'add_kernel_param' and 'delete_kernel_param'
1263    pub fn apply_kernel_params(&mut self, new_params: &str) -> bool {
1264        let mut change = false;
1265
1266        let new_params: Vec<(&str, &str)> = new_params
1267            .split_whitespace()
1268            .map(|kernel_param| kernel_param.split_once('=').unwrap_or((kernel_param, "")))
1269            .map(|(key, value)| (key.trim(), value.trim()))
1270            .collect();
1271
1272        let mut params: HashMap<&str, &str> = HashMap::new();
1273
1274        for (new_key, new_value) in &new_params {
1275            for (key, value) in params.iter_mut() {
1276                if *key == *new_key {
1277                    log::debug!("key '{}' found", key);
1278                    if value != new_value {
1279                        log::info!("changing key {} from {} to {}", key, value, new_value);
1280
1281                        *value = new_value;
1282                        change = true
1283                    } else {
1284                        log::debug!("key '{}' value does not change ({})", key, value);
1285                    }
1286                }
1287            }
1288        }
1289
1290        if change == false {
1291            log::debug!("No value change in kernel params. Checking is either new params have been added or removed");
1292            if new_params.len() != params.len() {
1293                log::info!("num kernel parameters have changed");
1294                change = true;
1295            }
1296        }
1297
1298        self.params = new_params
1299            .iter()
1300            .map(|(key, value)| {
1301                if !value.is_empty() {
1302                    format!("{key}={value}")
1303                } else {
1304                    key.to_string()
1305                }
1306            })
1307            .collect::<Vec<String>>()
1308            .join(" ");
1309
1310        change
1311    }
1312}
1313
1314#[derive(Debug, Serialize, Deserialize)]
1315pub enum ComponentType {
1316    CDU,
1317    CabinetCDU,
1318    CabinetPDU,
1319    CabinetPDUOutlet,
1320    CabinetPDUPowerConnector,
1321    CabinetPDUController,
1322    r#Cabinet,
1323    Chassis,
1324    ChassisBMC,
1325    CMMRectifier,
1326    CMMFpga,
1327    CEC,
1328    ComputeModule,
1329    RouterModule,
1330    NodeBMC,
1331    NodeEnclosure,
1332    NodeEnclosurePowerSupply,
1333    HSNBoard,
1334    Node,
1335    Processor,
1336    Drive,
1337    StorageGroup,
1338    NodeNIC,
1339    Memory,
1340    NodeAccel,
1341    NodeAccelRiser,
1342    NodeFpga,
1343    HSNAsic,
1344    RouterFpga,
1345    RouterBMC,
1346    HSNLink,
1347    HSNConnector,
1348    INVALID,
1349}
1350
1351#[derive(Debug, Serialize, Deserialize, Clone)]
1352pub struct ProcessorId {
1353    #[serde(rename = "EffectiveFamily")]
1354    #[serde(skip_serializing_if = "Option::is_none")]
1355    pub effective_family: Option<String>,
1356    #[serde(rename = "EffectiveModel")]
1357    #[serde(skip_serializing_if = "Option::is_none")]
1358    pub efffective_model: Option<String>,
1359    #[serde(rename = "IdentificationRegisters")]
1360    #[serde(skip_serializing_if = "Option::is_none")]
1361    pub identification_registers: Option<String>,
1362    #[serde(rename = "MicrocodeInfo")]
1363    #[serde(skip_serializing_if = "Option::is_none")]
1364    pub microcode_info: Option<String>,
1365    #[serde(rename = "Step")]
1366    #[serde(skip_serializing_if = "Option::is_none")]
1367    pub step: Option<String>,
1368    #[serde(rename = "VendorId")]
1369    #[serde(skip_serializing_if = "Option::is_none")]
1370    pub vendor_id: Option<String>,
1371}
1372
1373#[derive(Debug, Serialize, Deserialize, Clone)]
1374pub struct HWInvByFRUProcessor {
1375    #[serde(rename = "FRUID")]
1376    #[serde(skip_serializing_if = "Option::is_none")]
1377    pub fru_id: Option<String>,
1378    #[serde(rename = "Type")]
1379    #[serde(skip_serializing_if = "Option::is_none")]
1380    pub r#type: Option<String>,
1381    #[serde(rename = "FRUSubType")]
1382    #[serde(skip_serializing_if = "Option::is_none")]
1383    pub fru_sub_type: Option<String>,
1384    #[serde(rename = "HWInventoryByFRUType")]
1385    pub hw_inventory_by_fru_type: String,
1386    #[serde(rename = "ProcessorFRUInfo")]
1387    pub processor_fru_info: RedfishProcessorFRUInfo,
1388}
1389
1390#[derive(Debug, Serialize, Deserialize, Clone)]
1391pub struct HWInvByFRUMemory {
1392    #[serde(rename = "FRUID")]
1393    #[serde(skip_serializing_if = "Option::is_none")]
1394    pub fru_id: Option<String>,
1395    #[serde(rename = "Type")]
1396    #[serde(skip_serializing_if = "Option::is_none")]
1397    pub r#type: Option<String>,
1398    #[serde(rename = "FRUSubType")]
1399    #[serde(skip_serializing_if = "Option::is_none")]
1400    pub fru_sub_type: Option<String>,
1401    #[serde(rename = "HWInventoryByFRUType")]
1402    pub hw_inventory_by_fru_type: String,
1403    #[serde(rename = "MemoryFRUInfo")]
1404    pub memory_fru_info: RedfishMemoryFRUInfo,
1405}
1406
1407#[derive(Debug, Serialize, Deserialize, Clone)]
1408pub struct HWInvByFRUHSNNIC {
1409    #[serde(rename = "FRUID")]
1410    #[serde(skip_serializing_if = "Option::is_none")]
1411    pub fru_id: Option<String>,
1412    #[serde(rename = "Type")]
1413    #[serde(skip_serializing_if = "Option::is_none")]
1414    pub r#type: Option<String>,
1415    #[serde(rename = "FRUSubType")]
1416    #[serde(skip_serializing_if = "Option::is_none")]
1417    pub fru_sub_type: Option<String>,
1418    #[serde(rename = "HWInventoryByFRUType")]
1419    pub hw_inventory_by_fru_type: String,
1420    #[serde(rename = "HSNNICFRUInfo")]
1421    pub hsn_nic_fru_info: HSNNICFRUInfo,
1422}
1423
1424#[derive(Debug, Serialize, Deserialize, Clone)]
1425pub struct HWInvByFRUNodeAccel {
1426    #[serde(rename = "FRUID")]
1427    #[serde(skip_serializing_if = "Option::is_none")]
1428    pub fru_id: Option<String>,
1429    #[serde(rename = "Type")]
1430    #[serde(skip_serializing_if = "Option::is_none")]
1431    pub r#type: Option<String>,
1432    #[serde(rename = "FRUSubType")]
1433    #[serde(skip_serializing_if = "Option::is_none")]
1434    pub fru_sub_type: Option<String>,
1435    #[serde(rename = "HWInventoryByFRUType")]
1436    pub hw_inventory_by_fru_type: String,
1437    #[serde(rename = "NodeAccelFRUInfo")]
1438    pub node_accel_fru_info: RedfishProcessorFRUInfo, // NOTE: yes, sounds weird FRU for node accelerator uses FRU for processor... but that is
1439                                                      // what the API docs says...
1440}
1441
1442#[derive(Debug, Serialize, Deserialize, Clone)]
1443pub struct RedfishProcessorFRUInfo {
1444    #[serde(rename = "InstructionSet")]
1445    #[serde(skip_serializing_if = "Option::is_none")]
1446    pub instruction_set: Option<String>,
1447    #[serde(rename = "Manufacturer")]
1448    #[serde(skip_serializing_if = "Option::is_none")]
1449    pub manufacturer: Option<String>,
1450    #[serde(rename = "MaxSpeedMHz")]
1451    #[serde(skip_serializing_if = "Option::is_none")]
1452    pub max_speed_mhz: Option<usize>,
1453    #[serde(rename = "Model")]
1454    #[serde(skip_serializing_if = "Option::is_none")]
1455    pub model: Option<String>,
1456    #[serde(rename = "ProcessorArchitecture")]
1457    #[serde(skip_serializing_if = "Option::is_none")]
1458    pub processor_architecture: Option<String>,
1459    #[serde(rename = "ProcessorId")]
1460    #[serde(skip_serializing_if = "Option::is_none")]
1461    pub processor_id: Option<ProcessorId>,
1462    #[serde(rename = "ProcessorType")]
1463    #[serde(skip_serializing_if = "Option::is_none")]
1464    pub processor_type: Option<String>,
1465    #[serde(rename = "TotalCores")]
1466    #[serde(skip_serializing_if = "Option::is_none")]
1467    pub total_cores: Option<usize>,
1468    #[serde(rename = "TotalThreads")]
1469    #[serde(skip_serializing_if = "Option::is_none")]
1470    pub total_threads: Option<usize>,
1471}
1472
1473#[derive(Debug, Serialize, Deserialize, Clone)]
1474pub struct RedfishMemoryFRUInfo {
1475    #[serde(rename = "BaseModuleType")]
1476    #[serde(skip_serializing_if = "Option::is_none")]
1477    pub base_module_type: Option<String>,
1478    #[serde(rename = "BusWidthBits")]
1479    #[serde(skip_serializing_if = "Option::is_none")]
1480    pub bus_width_bits: Option<usize>,
1481    #[serde(rename = "CapacityMiB")]
1482    #[serde(skip_serializing_if = "Option::is_none")]
1483    pub capacity_mib: Option<usize>,
1484    #[serde(rename = "DataWidthBits")]
1485    #[serde(skip_serializing_if = "Option::is_none")]
1486    pub data_width_bits: Option<usize>,
1487    #[serde(rename = "ErrorCorrection")]
1488    #[serde(skip_serializing_if = "Option::is_none")]
1489    pub error_correction: Option<String>,
1490    #[serde(rename = "Manufacturer")]
1491    #[serde(skip_serializing_if = "Option::is_none")]
1492    pub manufacturer: Option<String>,
1493    #[serde(rename = "MemoryType")]
1494    #[serde(skip_serializing_if = "Option::is_none")]
1495    pub memory_type: Option<String>,
1496    #[serde(rename = "MemoryDeviceType")]
1497    #[serde(skip_serializing_if = "Option::is_none")]
1498    pub memory_device_type: Option<String>,
1499    #[serde(rename = "OperatingSpeedMhz")]
1500    #[serde(skip_serializing_if = "Option::is_none")]
1501    pub operating_speed_mhz: Option<usize>,
1502    #[serde(rename = "PartNumber")]
1503    #[serde(skip_serializing_if = "Option::is_none")]
1504    pub part_number: Option<String>,
1505    #[serde(rename = "RankCount")]
1506    #[serde(skip_serializing_if = "Option::is_none")]
1507    pub rank_count: Option<usize>,
1508    #[serde(rename = "SerialNumber")]
1509    #[serde(skip_serializing_if = "Option::is_none")]
1510    pub serial_number: Option<String>,
1511}
1512
1513#[derive(Debug, Serialize, Deserialize, Clone)]
1514pub struct HWInventoryByFRU {
1515    #[serde(rename = "FRUID")]
1516    #[serde(skip_serializing_if = "Option::is_none")]
1517    pub fru_id: Option<String>,
1518    #[serde(rename = "Type")]
1519    #[serde(skip_serializing_if = "Option::is_none")]
1520    pub r#type: Option<String>,
1521    #[serde(rename = "FRUSubType")]
1522    #[serde(skip_serializing_if = "Option::is_none")]
1523    pub fru_sub_type: Option<String>,
1524    #[serde(rename = "HWInventoryByFRUType")]
1525    pub hw_inventory_by_fru_type: String,
1526}
1527
1528#[derive(Debug, Serialize, Deserialize, Clone)]
1529pub struct RedfishChassisLocationInfo {
1530    #[serde(rename = "Id")]
1531    #[serde(skip_serializing_if = "Option::is_none")]
1532    pub id: Option<String>,
1533    #[serde(rename = "Name")]
1534    #[serde(skip_serializing_if = "Option::is_none")]
1535    pub name: Option<String>,
1536    #[serde(rename = "Description")]
1537    #[serde(skip_serializing_if = "Option::is_none")]
1538    pub description: Option<String>,
1539    #[serde(rename = "Hostname")]
1540    #[serde(skip_serializing_if = "Option::is_none")]
1541    pub hostname: Option<String>,
1542}
1543
1544#[derive(Debug, Serialize, Deserialize, Clone)]
1545pub struct HWInvByLocChassis {
1546    #[serde(rename = "ID")]
1547    pub id: String,
1548    #[serde(rename = "Type")]
1549    #[serde(skip_serializing_if = "Option::is_none")]
1550    pub r#type: Option<String>,
1551    #[serde(rename = "Ordinal")]
1552    #[serde(skip_serializing_if = "Option::is_none")]
1553    pub ordinal: Option<u32>,
1554    #[serde(rename = "Status")]
1555    #[serde(skip_serializing_if = "Option::is_none")]
1556    pub status: Option<String>,
1557    #[serde(rename = "HWInventoryByLocationType")]
1558    pub hw_inventory_by_location_type: String,
1559    #[serde(rename = "PopulatedFRU")]
1560    #[serde(skip_serializing_if = "Option::is_none")]
1561    pub populated_fru: Option<HWInventoryByFRU>,
1562    #[serde(rename = "ChassisLocatinInfo")]
1563    #[serde(skip_serializing_if = "Option::is_none")]
1564    pub chassis_location_info: Option<RedfishChassisLocationInfo>,
1565    #[serde(rename = "ComputeModules")]
1566    #[serde(skip_serializing_if = "Option::is_none")]
1567    pub compute_modules: Option<HWInvByLocComputeModule>,
1568    #[serde(rename = "RouterModules")]
1569    #[serde(skip_serializing_if = "Option::is_none")]
1570    pub router_modules: Option<HWInvByLocRouterModule>,
1571}
1572
1573#[derive(Debug, Serialize, Deserialize, Clone)]
1574pub struct HWInvByLocNodeEnclosure {
1575    #[serde(rename = "ID")]
1576    pub id: String,
1577    #[serde(rename = "Type")]
1578    #[serde(skip_serializing_if = "Option::is_none")]
1579    pub r#type: Option<String>,
1580    #[serde(rename = "Ordinal")]
1581    #[serde(skip_serializing_if = "Option::is_none")]
1582    pub ordinal: Option<u32>,
1583    #[serde(rename = "Status")]
1584    #[serde(skip_serializing_if = "Option::is_none")]
1585    pub status: Option<String>,
1586    #[serde(rename = "HWInventoryByLocationType")]
1587    pub hw_inventory_by_location_type: String,
1588    #[serde(rename = "PopulatedFRU")]
1589    #[serde(skip_serializing_if = "Option::is_none")]
1590    pub populated_fru: Option<HWInventoryByFRU>,
1591    #[serde(rename = "NodeEnclosureLocationInfo")]
1592    #[serde(skip_serializing_if = "Option::is_none")]
1593    pub node_enclosure_location_info: Option<RedfishChassisLocationInfo>,
1594}
1595
1596#[derive(Debug, Serialize, Deserialize, Clone)]
1597pub struct HWInvByLocComputeModule {
1598    #[serde(rename = "ID")]
1599    pub id: String,
1600    #[serde(rename = "Type")]
1601    #[serde(skip_serializing_if = "Option::is_none")]
1602    pub r#type: Option<String>,
1603    #[serde(rename = "Ordinal")]
1604    #[serde(skip_serializing_if = "Option::is_none")]
1605    pub ordinal: Option<u32>,
1606    #[serde(rename = "Status")]
1607    #[serde(skip_serializing_if = "Option::is_none")]
1608    pub status: Option<String>,
1609    #[serde(rename = "HWInventoryByLocationType")]
1610    pub hw_inventory_by_location_type: String,
1611    #[serde(rename = "PopulatedFRU")]
1612    #[serde(skip_serializing_if = "Option::is_none")]
1613    pub populated_fru: Option<HWInventoryByFRU>,
1614    #[serde(rename = "ComputeModuleLocationInfo")]
1615    #[serde(skip_serializing_if = "Option::is_none")]
1616    pub compute_module_location_info: Option<RedfishChassisLocationInfo>,
1617    #[serde(rename = "NodeEnclosures")]
1618    #[serde(skip_serializing_if = "Option::is_none")]
1619    pub node_enclosures: Option<HWInvByLocNodeEnclosure>,
1620}
1621
1622#[derive(Debug, Serialize, Deserialize, Clone)]
1623pub struct HWInvByLocHSNBoard {
1624    #[serde(rename = "ID")]
1625    pub id: String,
1626    #[serde(rename = "Type")]
1627    #[serde(skip_serializing_if = "Option::is_none")]
1628    pub r#type: Option<String>,
1629    #[serde(rename = "Ordinal")]
1630    #[serde(skip_serializing_if = "Option::is_none")]
1631    pub ordinal: Option<u32>,
1632    #[serde(rename = "Status")]
1633    #[serde(skip_serializing_if = "Option::is_none")]
1634    pub status: Option<String>,
1635    #[serde(rename = "HWInventoryByLocationType")]
1636    pub hw_inventory_by_location_type: String,
1637    #[serde(rename = "PopulatedFRU")]
1638    #[serde(skip_serializing_if = "Option::is_none")]
1639    pub populated_fru: Option<HWInventoryByFRU>,
1640    #[serde(rename = "HSNBoardLocationInfo")]
1641    #[serde(skip_serializing_if = "Option::is_none")]
1642    pub hsn_board_location_info: Option<RedfishChassisLocationInfo>,
1643}
1644
1645#[derive(Debug, Serialize, Deserialize, Clone)]
1646pub struct HWInvByLocRouterModule {
1647    #[serde(rename = "ID")]
1648    pub id: String,
1649    #[serde(rename = "Type")]
1650    #[serde(skip_serializing_if = "Option::is_none")]
1651    pub r#type: Option<String>,
1652    #[serde(rename = "Ordinal")]
1653    #[serde(skip_serializing_if = "Option::is_none")]
1654    pub ordinal: Option<u32>,
1655    #[serde(rename = "Status")]
1656    #[serde(skip_serializing_if = "Option::is_none")]
1657    pub status: Option<String>,
1658    #[serde(rename = "HWInventoryByLocationType")]
1659    pub hw_inventory_by_location_type: String,
1660    #[serde(rename = "PopulatedFRU")]
1661    #[serde(skip_serializing_if = "Option::is_none")]
1662    pub populated_fru: Option<HWInventoryByFRU>,
1663    #[serde(rename = "RouterModuleLocationInfo")]
1664    #[serde(skip_serializing_if = "Option::is_none")]
1665    pub router_module_location_info: Option<RedfishChassisLocationInfo>,
1666    pub hsn_boards: Option<HWInvByLocHSNBoard>,
1667}
1668
1669#[derive(Debug, Serialize, Deserialize, Clone)]
1670pub struct HWInvByLocCabinet {
1671    #[serde(rename = "ID")]
1672    pub id: String,
1673    #[serde(rename = "Type")]
1674    #[serde(skip_serializing_if = "Option::is_none")]
1675    pub r#type: Option<String>,
1676    #[serde(rename = "Ordinal")]
1677    #[serde(skip_serializing_if = "Option::is_none")]
1678    pub ordinal: Option<u32>,
1679    #[serde(rename = "Status")]
1680    #[serde(skip_serializing_if = "Option::is_none")]
1681    pub status: Option<String>,
1682    #[serde(rename = "HWInventoryByLocationType")]
1683    pub hw_inventory_by_location_type: String,
1684    #[serde(rename = "PopulatedFRU")]
1685    #[serde(skip_serializing_if = "Option::is_none")]
1686    pub populated_fru: Option<HWInventoryByFRU>,
1687    #[serde(rename = "CabinetLocationInfo")]
1688    #[serde(skip_serializing_if = "Option::is_none")]
1689    pub cabinet_location_info: Option<RedfishChassisLocationInfo>,
1690    #[serde(rename = "Chassis")]
1691    #[serde(skip_serializing_if = "Option::is_none")]
1692    pub chassis: Option<HWInvByLocChassis>,
1693}
1694
1695#[derive(Debug, Serialize, Deserialize, Clone)]
1696pub struct HWInvByLocMgmtSwitch {
1697    #[serde(rename = "ID")]
1698    pub id: String,
1699    #[serde(rename = "Type")]
1700    #[serde(skip_serializing_if = "Option::is_none")]
1701    pub r#type: Option<String>,
1702    #[serde(rename = "Ordinal")]
1703    #[serde(skip_serializing_if = "Option::is_none")]
1704    pub ordinal: Option<u32>,
1705    #[serde(rename = "Status")]
1706    #[serde(skip_serializing_if = "Option::is_none")]
1707    pub status: Option<String>,
1708    #[serde(rename = "HWInventoryByLocationType")]
1709    pub hw_inventory_by_location_type: String,
1710    #[serde(rename = "PopulatedFRU")]
1711    #[serde(skip_serializing_if = "Option::is_none")]
1712    pub populated_fru: Option<HWInventoryByFRU>,
1713    #[serde(rename = "MgmtSwitchLocationInfo")]
1714    #[serde(skip_serializing_if = "Option::is_none")]
1715    pub mgmt_switch_location_info: Option<RedfishChassisLocationInfo>,
1716}
1717
1718#[derive(Debug, Serialize, Deserialize, Clone)]
1719pub struct HWInvByLocMgmtHLSwitch {
1720    #[serde(rename = "ID")]
1721    pub id: String,
1722    #[serde(rename = "Type")]
1723    #[serde(skip_serializing_if = "Option::is_none")]
1724    pub r#type: Option<String>,
1725    #[serde(rename = "Ordinal")]
1726    #[serde(skip_serializing_if = "Option::is_none")]
1727    pub ordinal: Option<u32>,
1728    #[serde(rename = "Status")]
1729    #[serde(skip_serializing_if = "Option::is_none")]
1730    pub status: Option<String>,
1731    #[serde(rename = "HWInventoryByLocationType")]
1732    pub hw_inventory_by_location_type: String,
1733    #[serde(rename = "PopulatedFRU")]
1734    #[serde(skip_serializing_if = "Option::is_none")]
1735    pub populated_fru: Option<HWInventoryByFRU>,
1736    #[serde(rename = "MgmtHLSwitchLocationInfo")]
1737    #[serde(skip_serializing_if = "Option::is_none")]
1738    pub mgmt_hl_switch_location_info: Option<RedfishChassisLocationInfo>,
1739}
1740
1741#[derive(Debug, Serialize, Deserialize, Clone)]
1742pub struct HWInvByLocCDUMgmtSwitch {
1743    #[serde(rename = "ID")]
1744    pub id: String,
1745    #[serde(rename = "Type")]
1746    #[serde(skip_serializing_if = "Option::is_none")]
1747    pub r#type: Option<String>,
1748    #[serde(rename = "Ordinal")]
1749    #[serde(skip_serializing_if = "Option::is_none")]
1750    pub ordinal: Option<u32>,
1751    #[serde(rename = "Status")]
1752    #[serde(skip_serializing_if = "Option::is_none")]
1753    pub status: Option<String>,
1754    #[serde(rename = "HWInventoryByLocationType")]
1755    pub hw_inventory_by_location_type: String,
1756    #[serde(rename = "PopulatedFRU")]
1757    #[serde(skip_serializing_if = "Option::is_none")]
1758    pub populated_fru: Option<HWInventoryByFRU>,
1759    #[serde(rename = "CDUMgmtSwitchLocationInfo")]
1760    #[serde(skip_serializing_if = "Option::is_none")]
1761    pub cdu_mgmt_switch_location_info: Option<RedfishChassisLocationInfo>,
1762}
1763
1764#[derive(Debug, Serialize, Deserialize, Clone)]
1765pub struct ProcessorSummary {
1766    #[serde(rename = "Count")]
1767    #[serde(skip_serializing_if = "Option::is_none")]
1768    pub count: Option<u32>,
1769    #[serde(rename = "Model")]
1770    #[serde(skip_serializing_if = "Option::is_none")]
1771    pub model: Option<String>,
1772}
1773
1774#[derive(Debug, Serialize, Deserialize, Clone)]
1775pub struct MemorySummary {
1776    #[serde(rename = "TotalSystemMemoryGiB")]
1777    #[serde(skip_serializing_if = "Option::is_none")]
1778    pub total_system_memory_gib: Option<u32>,
1779}
1780
1781#[derive(Debug, Serialize, Deserialize, Clone)]
1782pub struct RedfishSystemLocationInfo {
1783    #[serde(rename = "Id")]
1784    #[serde(skip_serializing_if = "Option::is_none")]
1785    pub id: Option<String>,
1786    #[serde(rename = "Name")]
1787    #[serde(skip_serializing_if = "Option::is_none")]
1788    pub name: Option<String>,
1789    #[serde(rename = "Description")]
1790    #[serde(skip_serializing_if = "Option::is_none")]
1791    pub description: Option<String>,
1792    #[serde(rename = "Hostname")]
1793    #[serde(skip_serializing_if = "Option::is_none")]
1794    pub hostname: Option<String>,
1795    #[serde(rename = "ProcessorSummary")]
1796    #[serde(skip_serializing_if = "Option::is_none")]
1797    pub processor_summary: Option<ProcessorSummary>,
1798    #[serde(rename = "MemorySummary")]
1799    #[serde(skip_serializing_if = "Option::is_none")]
1800    pub memory_summary: Option<MemorySummary>,
1801}
1802
1803#[derive(Debug, Serialize, Deserialize, Clone)]
1804pub struct RedfishProcessorLocationInfo {
1805    #[serde(rename = "Id")]
1806    #[serde(skip_serializing_if = "Option::is_none")]
1807    pub id: Option<String>,
1808    #[serde(rename = "Name")]
1809    #[serde(skip_serializing_if = "Option::is_none")]
1810    pub name: Option<String>,
1811    #[serde(rename = "Description")]
1812    #[serde(skip_serializing_if = "Option::is_none")]
1813    pub description: Option<String>,
1814    #[serde(rename = "Socket")]
1815    #[serde(skip_serializing_if = "Option::is_none")]
1816    pub socket: Option<String>,
1817}
1818
1819#[derive(Debug, Serialize, Deserialize, Clone)]
1820pub struct HWInvByLocProcessor {
1821    #[serde(rename = "ID")]
1822    pub id: String,
1823    #[serde(rename = "Type")]
1824    #[serde(skip_serializing_if = "Option::is_none")]
1825    pub r#type: Option<String>,
1826    #[serde(rename = "Ordinal")]
1827    #[serde(skip_serializing_if = "Option::is_none")]
1828    pub ordinal: Option<u32>,
1829    #[serde(rename = "Status")]
1830    #[serde(skip_serializing_if = "Option::is_none")]
1831    pub status: Option<String>,
1832    #[serde(rename = "HWInventoryByLocationType")]
1833    pub hw_inventory_by_location_type: String,
1834    #[serde(rename = "PopulatedFRU")]
1835    #[serde(skip_serializing_if = "Option::is_none")]
1836    pub populated_fru: Option<HWInvByFRUProcessor>,
1837    #[serde(rename = "ProcessorLocationInfo")]
1838    pub processor_location_info: RedfishProcessorLocationInfo,
1839}
1840
1841#[derive(Debug, Serialize, Deserialize, Clone)]
1842pub struct HWInvByLocNodeAccel {
1843    #[serde(rename = "ID")]
1844    pub id: String,
1845    #[serde(rename = "Type")]
1846    #[serde(skip_serializing_if = "Option::is_none")]
1847    pub r#type: Option<String>,
1848    #[serde(rename = "Ordinal")]
1849    #[serde(skip_serializing_if = "Option::is_none")]
1850    pub ordinal: Option<u32>,
1851    #[serde(rename = "Status")]
1852    #[serde(skip_serializing_if = "Option::is_none")]
1853    pub status: Option<String>,
1854    #[serde(rename = "HWInventoryByLocationType")]
1855    pub hw_inventory_by_location_type: String,
1856    #[serde(rename = "PopulatedFRU")]
1857    #[serde(skip_serializing_if = "Option::is_none")]
1858    pub populated_fru: Option<HWInvByFRUNodeAccel>,
1859    #[serde(rename = "NodeAccelLocationInfo")]
1860    #[serde(skip_serializing_if = "Option::is_none")]
1861    pub node_accel_location_info: Option<RedfishProcessorLocationInfo>,
1862}
1863
1864#[derive(Debug, Serialize, Deserialize, Clone)]
1865pub struct RedfishDriveLocationInfo {
1866    #[serde(rename = "Id")]
1867    #[serde(skip_serializing_if = "Option::is_none")]
1868    pub id: Option<String>,
1869    #[serde(rename = "Name")]
1870    #[serde(skip_serializing_if = "Option::is_none")]
1871    pub name: Option<String>,
1872    #[serde(rename = "Description")]
1873    #[serde(skip_serializing_if = "Option::is_none")]
1874    pub description: Option<String>,
1875}
1876
1877#[derive(Debug, Serialize, Deserialize, Clone)]
1878pub struct HWInvByLocDrive {
1879    #[serde(rename = "ID")]
1880    pub id: String,
1881    #[serde(rename = "Type")]
1882    #[serde(skip_serializing_if = "Option::is_none")]
1883    pub r#type: Option<String>,
1884    #[serde(rename = "Ordinal")]
1885    #[serde(skip_serializing_if = "Option::is_none")]
1886    pub ordinal: Option<u32>,
1887    #[serde(rename = "Status")]
1888    #[serde(skip_serializing_if = "Option::is_none")]
1889    pub status: Option<String>,
1890    #[serde(rename = "HWInventoryByLocationType")]
1891    pub hw_inventory_by_location_type: String,
1892    #[serde(rename = "PopulatedFRU")]
1893    #[serde(skip_serializing_if = "Option::is_none")]
1894    pub populated_fru: Option<HWInventoryByFRU>,
1895    #[serde(rename = "DriveLocationInfo")]
1896    #[serde(skip_serializing_if = "Option::is_none")]
1897    pub drive_location_info: Option<RedfishDriveLocationInfo>,
1898}
1899
1900#[derive(Debug, Serialize, Deserialize, Clone)]
1901pub struct MemoryLocation {
1902    #[serde(rename = "Socket")]
1903    #[serde(skip_serializing_if = "Option::is_none")]
1904    pub socket: Option<u32>,
1905    #[serde(rename = "MemoryController")]
1906    #[serde(skip_serializing_if = "Option::is_none")]
1907    pub memory_controller: Option<u32>,
1908    #[serde(rename = "Channel")]
1909    #[serde(skip_serializing_if = "Option::is_none")]
1910    pub channel: Option<u32>,
1911    #[serde(rename = "Slot")]
1912    #[serde(skip_serializing_if = "Option::is_none")]
1913    pub slot: Option<u32>,
1914}
1915
1916#[derive(Debug, Serialize, Deserialize, Clone)]
1917pub struct RedfishMemoryLocationInfo {
1918    #[serde(rename = "Id")]
1919    #[serde(skip_serializing_if = "Option::is_none")]
1920    pub id: Option<String>,
1921    #[serde(rename = "Name")]
1922    #[serde(skip_serializing_if = "Option::is_none")]
1923    pub name: Option<String>,
1924    #[serde(rename = "Description")]
1925    #[serde(skip_serializing_if = "Option::is_none")]
1926    pub description: Option<String>,
1927    #[serde(rename = "MemoryLocation")]
1928    #[serde(skip_serializing_if = "Option::is_none")]
1929    pub memory_location: Option<MemoryLocation>,
1930}
1931
1932#[derive(Debug, Serialize, Deserialize, Clone)]
1933pub struct HWInvByLocMemory {
1934    #[serde(rename = "ID")]
1935    pub id: String,
1936    #[serde(rename = "Type")]
1937    #[serde(skip_serializing_if = "Option::is_none")]
1938    pub r#type: Option<String>,
1939    #[serde(rename = "Ordinal")]
1940    #[serde(skip_serializing_if = "Option::is_none")]
1941    pub ordinal: Option<u32>,
1942    #[serde(rename = "Status")]
1943    #[serde(skip_serializing_if = "Option::is_none")]
1944    pub status: Option<String>,
1945    #[serde(rename = "HWInventoryByLocationType")]
1946    pub hw_inventory_by_location_type: String,
1947    #[serde(rename = "PopulatedFRU")]
1948    #[serde(skip_serializing_if = "Option::is_none")]
1949    pub populated_fru: Option<HWInvByFRUMemory>,
1950    #[serde(rename = "MemoryLocationInfo")]
1951    pub memory_location_info: RedfishMemoryLocationInfo,
1952}
1953
1954#[derive(Debug, Serialize, Deserialize, Clone)]
1955pub struct RedfishNodeAccelRiserLocationInfo {
1956    #[serde(rename = "Name")]
1957    #[serde(skip_serializing_if = "Option::is_none")]
1958    pub name: Option<String>,
1959    #[serde(rename = "Description")]
1960    #[serde(skip_serializing_if = "Option::is_none")]
1961    pub description: Option<String>,
1962}
1963
1964#[derive(Debug, Serialize, Deserialize, Clone)]
1965pub struct HWInvByLocNodeAccelRiser {
1966    #[serde(rename = "ID")]
1967    pub id: String,
1968    #[serde(rename = "Type")]
1969    #[serde(skip_serializing_if = "Option::is_none")]
1970    pub r#type: Option<String>,
1971    #[serde(rename = "Ordinal")]
1972    #[serde(skip_serializing_if = "Option::is_none")]
1973    pub ordinal: Option<u32>,
1974    #[serde(rename = "Status")]
1975    #[serde(skip_serializing_if = "Option::is_none")]
1976    pub status: Option<String>,
1977    #[serde(rename = "HWInventoryByLocationType")]
1978    pub hw_inventory_by_location_type: String,
1979    #[serde(rename = "PopulatedFRU")]
1980    #[serde(skip_serializing_if = "Option::is_none")]
1981    pub populated_fru: Option<HWInventoryByFRU>,
1982    #[serde(rename = "NodeAccelRiserLocationInfo")]
1983    #[serde(skip_serializing_if = "Option::is_none")]
1984    pub node_accel_riser_location_info: Option<RedfishNodeAccelRiserLocationInfo>,
1985}
1986
1987#[derive(Debug, Serialize, Deserialize, Clone)]
1988pub struct HSNNICLocationInfo {
1989    #[serde(rename = "Id")]
1990    #[serde(skip_serializing_if = "Option::is_none")]
1991    pub id: Option<String>,
1992    #[serde(rename = "Name")]
1993    #[serde(skip_serializing_if = "Option::is_none")]
1994    pub name: Option<String>,
1995    #[serde(rename = "Description")]
1996    #[serde(skip_serializing_if = "Option::is_none")]
1997    pub description: Option<String>,
1998}
1999
2000#[derive(Debug, Serialize, Deserialize, Clone)]
2001pub struct HWInvByLocHSNNIC {
2002    #[serde(rename = "ID")]
2003    pub id: String,
2004    #[serde(rename = "Type")]
2005    #[serde(skip_serializing_if = "Option::is_none")]
2006    pub r#type: Option<String>,
2007    #[serde(rename = "Ordinal")]
2008    #[serde(skip_serializing_if = "Option::is_none")]
2009    pub ordinal: Option<u32>,
2010    #[serde(rename = "Status")]
2011    #[serde(skip_serializing_if = "Option::is_none")]
2012    pub status: Option<String>,
2013    #[serde(rename = "HWInventoryByLocationType")]
2014    pub hw_inventory_by_location_type: String,
2015    #[serde(rename = "PopulatedFRU")]
2016    #[serde(skip_serializing_if = "Option::is_none")]
2017    pub populated_fru: Option<HWInvByFRUHSNNIC>,
2018    /* #[serde(rename = "NodeHsnNicLocationInfo")]
2019    pub node_hsn_nic_location_info: HSNNICLocationInfo, */
2020    #[serde(rename = "HSNNICLocationInfo")]
2021    pub hsn_nic_location_info: HSNNICLocationInfo,
2022}
2023
2024#[derive(Debug, Serialize, Deserialize, Clone)]
2025pub struct RedfishSystemFRUInfo {
2026    #[serde(rename = "AssetTag")]
2027    #[serde(skip_serializing_if = "Option::is_none")]
2028    pub asset_tag: Option<String>,
2029    #[serde(rename = "BiosVersion")]
2030    #[serde(skip_serializing_if = "Option::is_none")]
2031    pub bios_version: Option<String>,
2032    #[serde(rename = "Model")]
2033    #[serde(skip_serializing_if = "Option::is_none")]
2034    pub model: Option<String>,
2035    #[serde(rename = "Manufacturer")]
2036    #[serde(skip_serializing_if = "Option::is_none")]
2037    pub manufacturer: Option<String>,
2038    #[serde(rename = "PartNumber")]
2039    #[serde(skip_serializing_if = "Option::is_none")]
2040    pub part_number: Option<String>,
2041    #[serde(rename = "SerialNumber")]
2042    #[serde(skip_serializing_if = "Option::is_none")]
2043    pub serial_number: Option<String>,
2044    #[serde(rename = "SKU")]
2045    #[serde(skip_serializing_if = "Option::is_none")]
2046    pub sku: Option<String>,
2047    #[serde(rename = "SystemType")]
2048    #[serde(skip_serializing_if = "Option::is_none")]
2049    pub system_type: Option<String>,
2050    #[serde(rename = "UUID")]
2051    #[serde(skip_serializing_if = "Option::is_none")]
2052    pub uuid: Option<String>,
2053}
2054
2055#[derive(Debug, Serialize, Deserialize, Clone)]
2056pub struct HWInvByFRUNode {
2057    #[serde(rename = "FRUID")]
2058    #[serde(skip_serializing_if = "Option::is_none")]
2059    pub fru_id: Option<String>,
2060    #[serde(rename = "Type")]
2061    #[serde(skip_serializing_if = "Option::is_none")]
2062    pub r#type: Option<String>,
2063    #[serde(rename = "FRUSubType")]
2064    #[serde(skip_serializing_if = "Option::is_none")]
2065    pub fru_sub_type: Option<String>,
2066    #[serde(rename = "HWInventoryByFRUType")]
2067    pub hw_inventory_by_fru_type: String,
2068    #[serde(rename = "NodeFRUInfo")]
2069    pub node_fru_info: RedfishSystemFRUInfo,
2070}
2071
2072#[derive(Debug, Serialize, Deserialize, Clone)]
2073pub struct HSNNICFRUInfo {
2074    #[serde(rename = "Manufacturer")]
2075    #[serde(skip_serializing_if = "Option::is_none")]
2076    pub manufacturer: Option<String>,
2077    #[serde(rename = "Model")]
2078    #[serde(skip_serializing_if = "Option::is_none")]
2079    pub model: Option<String>,
2080    #[serde(rename = "PartNumber")]
2081    #[serde(skip_serializing_if = "Option::is_none")]
2082    pub part_number: Option<String>,
2083    #[serde(rename = "SKU")]
2084    #[serde(skip_serializing_if = "Option::is_none")]
2085    pub sku: Option<String>,
2086    #[serde(rename = "SerialNumber")]
2087    #[serde(skip_serializing_if = "Option::is_none")]
2088    pub serial_number: Option<String>,
2089}
2090
2091#[derive(Debug, Serialize, Deserialize, Clone)]
2092pub struct HWInvByLocNode {
2093    #[serde(rename = "ID")]
2094    pub id: String,
2095    #[serde(rename = "Type")]
2096    #[serde(skip_serializing_if = "Option::is_none")]
2097    pub r#type: Option<String>,
2098    #[serde(rename = "Ordinal")]
2099    #[serde(skip_serializing_if = "Option::is_none")]
2100    pub ordinal: Option<u32>,
2101    #[serde(rename = "Status")]
2102    #[serde(skip_serializing_if = "Option::is_none")]
2103    pub status: Option<String>,
2104    #[serde(rename = "HWInventoryByLocationType")]
2105    pub hw_inventory_by_location_type: String,
2106    #[serde(rename = "PopulatedFRU")]
2107    #[serde(skip_serializing_if = "Option::is_none")]
2108    pub populated_fru: Option<HWInvByFRUNode>,
2109    #[serde(rename = "NodeLocationInfo")]
2110    #[serde(skip_serializing_if = "Option::is_none")]
2111    pub node_location_info: Option<RedfishSystemLocationInfo>,
2112    #[serde(rename = "Processors")]
2113    #[serde(skip_serializing_if = "Option::is_none")]
2114    pub processors: Option<Vec<HWInvByLocProcessor>>,
2115    #[serde(rename = "NodeAccels")]
2116    #[serde(skip_serializing_if = "Option::is_none")]
2117    pub node_accels: Option<Vec<HWInvByLocNodeAccel>>,
2118    #[serde(rename = "Dives")]
2119    #[serde(skip_serializing_if = "Option::is_none")]
2120    pub drives: Option<Vec<HWInvByLocDrive>>,
2121    #[serde(rename = "Memory")]
2122    #[serde(skip_serializing_if = "Option::is_none")]
2123    pub memory: Option<Vec<HWInvByLocMemory>>,
2124    #[serde(rename = "NodeAccelRisers")]
2125    #[serde(skip_serializing_if = "Option::is_none")]
2126    pub node_accel_risers: Option<Vec<HWInvByLocNodeAccelRiser>>,
2127    #[serde(rename = "NodeHsnNICs")]
2128    #[serde(skip_serializing_if = "Option::is_none")]
2129    pub node_hsn_nics: Option<Vec<HWInvByLocHSNNIC>>,
2130}
2131
2132#[derive(Debug, Serialize, Deserialize, Clone)]
2133pub struct RedfishPDULocationInfo {
2134    #[serde(rename = "Id")]
2135    #[serde(skip_serializing_if = "Option::is_none")]
2136    pub id: Option<String>,
2137    #[serde(rename = "Name")]
2138    #[serde(skip_serializing_if = "Option::is_none")]
2139    pub name: Option<String>,
2140    #[serde(rename = "Description")]
2141    #[serde(skip_serializing_if = "Option::is_none")]
2142    pub description: Option<String>,
2143    #[serde(rename = "UUID")]
2144    #[serde(skip_serializing_if = "Option::is_none")]
2145    pub uuid: Option<String>,
2146}
2147
2148#[derive(Debug, Serialize, Deserialize, Clone)]
2149pub struct RedfishOutletLocationInfo {
2150    #[serde(rename = "Id")]
2151    #[serde(skip_serializing_if = "Option::is_none")]
2152    pub id: Option<String>,
2153    #[serde(rename = "Name")]
2154    #[serde(skip_serializing_if = "Option::is_none")]
2155    pub name: Option<String>,
2156    #[serde(rename = "Description")]
2157    #[serde(skip_serializing_if = "Option::is_none")]
2158    pub description: Option<String>,
2159}
2160
2161#[derive(Debug, Serialize, Deserialize, Clone)]
2162pub struct HWInvByLocOutlet {
2163    #[serde(rename = "ID")]
2164    pub id: String,
2165    #[serde(rename = "Type")]
2166    #[serde(skip_serializing_if = "Option::is_none")]
2167    pub r#type: Option<String>,
2168    #[serde(rename = "Ordinal")]
2169    #[serde(skip_serializing_if = "Option::is_none")]
2170    pub ordinal: Option<u32>,
2171    #[serde(rename = "Status")]
2172    #[serde(skip_serializing_if = "Option::is_none")]
2173    pub status: Option<String>,
2174    #[serde(rename = "HWInventoryByLocationType")]
2175    pub hw_inventory_by_location_type: String,
2176    #[serde(rename = "PopulatedFRU")]
2177    #[serde(skip_serializing_if = "Option::is_none")]
2178    pub populated_fru: Option<HWInventoryByFRU>,
2179    #[serde(rename = "OutletLocationInfo")]
2180    #[serde(skip_serializing_if = "Option::is_none")]
2181    pub outlet_location_info: Option<RedfishOutletLocationInfo>,
2182}
2183
2184#[derive(Debug, Serialize, Deserialize, Clone)]
2185pub struct HWInvByLocPDU {
2186    #[serde(rename = "ID")]
2187    pub id: String,
2188    #[serde(rename = "Type")]
2189    #[serde(skip_serializing_if = "Option::is_none")]
2190    pub r#type: Option<String>,
2191    #[serde(rename = "Ordinal")]
2192    #[serde(skip_serializing_if = "Option::is_none")]
2193    pub ordinal: Option<u32>,
2194    #[serde(rename = "Status")]
2195    #[serde(skip_serializing_if = "Option::is_none")]
2196    pub status: Option<String>,
2197    #[serde(rename = "HWInventoryByLocationType")]
2198    pub hw_inventory_by_location_type: String,
2199    #[serde(rename = "PopulatedFRU")]
2200    #[serde(skip_serializing_if = "Option::is_none")]
2201    pub populated_fru: Option<HWInventoryByFRU>,
2202    #[serde(rename = "PDULocationInfo")]
2203    #[serde(skip_serializing_if = "Option::is_none")]
2204    pub pdu_location_info: Option<RedfishPDULocationInfo>,
2205    #[serde(rename = "CabinetPDUPowerConnectors")]
2206    #[serde(skip_serializing_if = "Option::is_none")]
2207    pub cabinet_pdu_power_connectors: Option<Vec<HWInvByLocOutlet>>,
2208}
2209
2210#[derive(Debug, Serialize, Deserialize, Clone)]
2211pub struct RedfishCMMRectifierLocationInfo {
2212    #[serde(rename = "Name")]
2213    #[serde(skip_serializing_if = "Option::is_none")]
2214    pub name: Option<String>,
2215    #[serde(rename = "FirmwareVersion")]
2216    #[serde(skip_serializing_if = "Option::is_none")]
2217    pub firmware_version: Option<String>,
2218}
2219
2220#[derive(Debug, Serialize, Deserialize, Clone)]
2221pub struct HWInvByLocCMMRectifier {
2222    #[serde(rename = "ID")]
2223    pub id: String,
2224    #[serde(rename = "Type")]
2225    #[serde(skip_serializing_if = "Option::is_none")]
2226    pub r#type: Option<String>,
2227    #[serde(rename = "Ordinal")]
2228    #[serde(skip_serializing_if = "Option::is_none")]
2229    pub ordinal: Option<u32>,
2230    #[serde(rename = "Status")]
2231    #[serde(skip_serializing_if = "Option::is_none")]
2232    pub status: Option<String>,
2233    #[serde(rename = "HWInventoryByLocationType")]
2234    pub hw_inventory_by_location_type: String,
2235    #[serde(rename = "PopulatedFRU")]
2236    #[serde(skip_serializing_if = "Option::is_none")]
2237    pub populated_fru: Option<HWInventoryByFRU>,
2238    #[serde(rename = "CMMRectifierLocationInfo")]
2239    #[serde(skip_serializing_if = "Option::is_none")]
2240    pub cmm_rectifier_location_info: Option<RedfishCMMRectifierLocationInfo>,
2241}
2242
2243#[derive(Debug, Serialize, Deserialize, Clone)]
2244pub struct RedfishNodeEnclosurePowerSupplyLocationInfo {
2245    #[serde(rename = "Name")]
2246    #[serde(skip_serializing_if = "Option::is_none")]
2247    pub name: Option<String>,
2248    #[serde(rename = "FirmwareVersion")]
2249    #[serde(skip_serializing_if = "Option::is_none")]
2250    pub firmware_version: Option<String>,
2251}
2252
2253#[derive(Debug, Serialize, Deserialize, Clone)]
2254pub struct HWInvByLocNodePowerSupply {
2255    #[serde(rename = "ID")]
2256    pub id: String,
2257    #[serde(rename = "Type")]
2258    #[serde(skip_serializing_if = "Option::is_none")]
2259    pub r#type: Option<String>,
2260    #[serde(rename = "Ordinal")]
2261    #[serde(skip_serializing_if = "Option::is_none")]
2262    pub ordinal: Option<u32>,
2263    #[serde(rename = "Status")]
2264    #[serde(skip_serializing_if = "Option::is_none")]
2265    pub status: Option<String>,
2266    #[serde(rename = "HWInventoryByLocationType")]
2267    pub hw_inventory_by_location_type: String,
2268    #[serde(rename = "PopulatedFRU")]
2269    #[serde(skip_serializing_if = "Option::is_none")]
2270    pub populated_fru: Option<HWInventoryByFRU>,
2271    #[serde(rename = "NodeEnclosurePowerSupplyLocationInfo")]
2272    #[serde(skip_serializing_if = "Option::is_none")]
2273    pub node_enclosure_power_supply_location_info:
2274        Option<RedfishNodeEnclosurePowerSupplyLocationInfo>,
2275}
2276
2277#[derive(Debug, Serialize, Deserialize, Clone)]
2278pub struct RedfishManagerLocationInfo {
2279    #[serde(rename = "Id")]
2280    #[serde(skip_serializing_if = "Option::is_none")]
2281    pub id: Option<String>,
2282    #[serde(rename = "Name")]
2283    #[serde(skip_serializing_if = "Option::is_none")]
2284    pub name: Option<String>,
2285    #[serde(rename = "Description")]
2286    #[serde(skip_serializing_if = "Option::is_none")]
2287    pub description: Option<String>,
2288    #[serde(rename = "DateTime")]
2289    #[serde(skip_serializing_if = "Option::is_none")]
2290    pub date_time: Option<String>,
2291    #[serde(rename = "DateTimeLocalOffset")]
2292    #[serde(skip_serializing_if = "Option::is_none")]
2293    pub date_time_local_offset: Option<String>,
2294    #[serde(rename = "FirmwareVersion")]
2295    #[serde(skip_serializing_if = "Option::is_none")]
2296    pub firmware_version: Option<String>,
2297}
2298
2299#[derive(Debug, Serialize, Deserialize, Clone)]
2300pub struct HWInvByLocNodeBMC {
2301    #[serde(rename = "ID")]
2302    pub id: String,
2303    #[serde(rename = "Type")]
2304    #[serde(skip_serializing_if = "Option::is_none")]
2305    pub r#type: Option<String>,
2306    #[serde(rename = "Ordinal")]
2307    #[serde(skip_serializing_if = "Option::is_none")]
2308    pub ordinal: Option<u32>,
2309    #[serde(rename = "Status")]
2310    #[serde(skip_serializing_if = "Option::is_none")]
2311    pub status: Option<String>,
2312    #[serde(rename = "HWInventoryByLocationType")]
2313    pub hw_inventory_by_location_type: String,
2314    #[serde(rename = "PopulatedFRU")]
2315    #[serde(skip_serializing_if = "Option::is_none")]
2316    pub populated_fru: Option<HWInventoryByFRU>,
2317    #[serde(rename = "NodeBMCLocationInfo")]
2318    #[serde(skip_serializing_if = "Option::is_none")]
2319    pub node_bmc_location_info: Option<RedfishManagerLocationInfo>,
2320}
2321
2322#[derive(Debug, Serialize, Deserialize, Clone)]
2323pub struct HWInvByLocRouterBMC {
2324    #[serde(rename = "ID")]
2325    pub id: String,
2326    #[serde(rename = "Type")]
2327    #[serde(skip_serializing_if = "Option::is_none")]
2328    pub r#type: Option<String>,
2329    #[serde(rename = "Ordinal")]
2330    #[serde(skip_serializing_if = "Option::is_none")]
2331    pub ordinal: Option<u32>,
2332    #[serde(rename = "Status")]
2333    #[serde(skip_serializing_if = "Option::is_none")]
2334    pub status: Option<String>,
2335    #[serde(rename = "HWInventoryByLocationType")]
2336    pub hw_inventory_by_location_type: String,
2337    #[serde(rename = "PopulatedFRU")]
2338    #[serde(skip_serializing_if = "Option::is_none")]
2339    pub populated_fru: Option<HWInventoryByFRU>,
2340    #[serde(rename = "RouterBMCLocationInfo")]
2341    #[serde(skip_serializing_if = "Option::is_none")]
2342    pub router_bmc_location_info: Option<RedfishManagerLocationInfo>,
2343}
2344
2345/* #[derive(Debug, Serialize, Deserialize, Clone)]
2346pub struct HWInventoryList {
2347    #[serde(rename = "Hardware")]
2348    pub hw_inventory: Vec<HWInventory>,
2349} */
2350
2351#[derive(Debug, Serialize, Deserialize, Clone)]
2352pub struct HWInventory {
2353    #[serde(rename = "XName")]
2354    #[serde(skip_serializing_if = "Option::is_none")]
2355    pub xname: Option<String>,
2356    #[serde(rename = "Format")]
2357    #[serde(skip_serializing_if = "Option::is_none")]
2358    pub format: Option<String>,
2359    #[serde(rename = "Cabinets")]
2360    #[serde(skip_serializing_if = "Option::is_none")]
2361    pub cabinets: Option<Vec<HWInvByLocCabinet>>,
2362    #[serde(rename = "Chassis")]
2363    #[serde(skip_serializing_if = "Option::is_none")]
2364    pub chassis: Option<Vec<HWInvByLocChassis>>,
2365    #[serde(rename = "ComputeModules")]
2366    #[serde(skip_serializing_if = "Option::is_none")]
2367    pub compute_modules: Option<Vec<HWInvByLocComputeModule>>,
2368    #[serde(rename = "RouterModules")]
2369    #[serde(skip_serializing_if = "Option::is_none")]
2370    pub router_modules: Option<Vec<HWInvByLocRouterModule>>,
2371    #[serde(rename = "NodeEnclosures")]
2372    #[serde(skip_serializing_if = "Option::is_none")]
2373    pub node_enclosures: Option<Vec<HWInvByLocNodeEnclosure>>,
2374    #[serde(rename = "HSNBoards")]
2375    #[serde(skip_serializing_if = "Option::is_none")]
2376    pub hsn_boards: Option<Vec<HWInvByLocHSNBoard>>,
2377    #[serde(rename = "MgmtSwitches")]
2378    #[serde(skip_serializing_if = "Option::is_none")]
2379    pub mgmt_switches: Option<Vec<HWInvByLocMgmtSwitch>>,
2380    #[serde(rename = "MgmtHLSwitches")]
2381    #[serde(skip_serializing_if = "Option::is_none")]
2382    pub mgmt_hl_switches: Option<Vec<HWInvByLocMgmtHLSwitch>>,
2383    #[serde(rename = "CDUMgmtSwitches")]
2384    #[serde(skip_serializing_if = "Option::is_none")]
2385    pub cdu_mgmt_switches: Option<Vec<HWInvByLocCDUMgmtSwitch>>,
2386    #[serde(rename = "Nodes")]
2387    #[serde(skip_serializing_if = "Option::is_none")]
2388    pub nodes: Option<Vec<HWInvByLocNode>>,
2389    #[serde(rename = "Processors")]
2390    #[serde(skip_serializing_if = "Option::is_none")]
2391    pub processors: Option<Vec<HWInvByLocProcessor>>,
2392    #[serde(rename = "NodeAccels")]
2393    #[serde(skip_serializing_if = "Option::is_none")]
2394    pub node_accels: Option<Vec<HWInvByLocNodeAccel>>,
2395    #[serde(rename = "Drives")]
2396    #[serde(skip_serializing_if = "Option::is_none")]
2397    pub drives: Option<Vec<HWInvByLocDrive>>,
2398    #[serde(rename = "Memory")]
2399    #[serde(skip_serializing_if = "Option::is_none")]
2400    pub memory: Option<Vec<HWInvByLocMemory>>,
2401    #[serde(rename = "CabinetPDUs")]
2402    #[serde(skip_serializing_if = "Option::is_none")]
2403    pub cabinet_pdus: Option<Vec<HWInvByLocPDU>>,
2404    #[serde(rename = "CabinetPDUPowerConnectors")]
2405    #[serde(skip_serializing_if = "Option::is_none")]
2406    pub cabinet_pdu_power_connectors: Option<Vec<HWInvByLocOutlet>>,
2407    #[serde(rename = "CMMRectifiers")]
2408    #[serde(skip_serializing_if = "Option::is_none")]
2409    pub cmm_rectifiers: Option<Vec<HWInvByLocCMMRectifier>>,
2410    #[serde(rename = "NodeAccelRisers")]
2411    #[serde(skip_serializing_if = "Option::is_none")]
2412    pub node_accel_risers: Option<Vec<HWInvByLocNodeAccelRiser>>,
2413    #[serde(rename = "NodeHsnNICs")]
2414    #[serde(skip_serializing_if = "Option::is_none")]
2415    pub node_hsn_nics: Option<Vec<HWInvByLocHSNNIC>>,
2416    #[serde(rename = "NodeEnclosurePowerSupplies")]
2417    #[serde(skip_serializing_if = "Option::is_none")]
2418    pub node_enclosure_power_supplies: Option<Vec<HWInvByLocNodePowerSupply>>,
2419    #[serde(rename = "NodeBMC")]
2420    #[serde(skip_serializing_if = "Option::is_none")]
2421    pub node_bmc: Option<Vec<HWInvByLocNodeBMC>>,
2422    #[serde(rename = "RouterBMC")]
2423    #[serde(skip_serializing_if = "Option::is_none")]
2424    pub router_bmc: Option<Vec<HWInvByLocRouterBMC>>,
2425}
2426
2427#[derive(Debug, Serialize, Deserialize, Clone)]
2428pub struct Hardware {
2429    #[serde(rename = "Hardware")]
2430    #[serde(skip_serializing_if = "Option::is_none")]
2431    pub hardware: Option<Vec<HWInvByLocNode>>,
2432}
2433
2434#[derive(Debug, Serialize, Deserialize, Clone)]
2435pub struct NodeLocationInfo {
2436    #[serde(rename = "Id")]
2437    pub id: String,
2438    #[serde(rename = "Name")]
2439    #[serde(skip_serializing_if = "Option::is_none")]
2440    pub name: Option<String>,
2441    #[serde(rename = "Description")]
2442    #[serde(skip_serializing_if = "Option::is_none")]
2443    pub description: Option<String>,
2444    #[serde(rename = "Hostname")]
2445    #[serde(skip_serializing_if = "Option::is_none")]
2446    pub hostname: Option<String>,
2447    #[serde(rename = "ProcessorSummary")]
2448    #[serde(skip_serializing_if = "Option::is_none")]
2449    pub processor_summary: Option<ProcessorSummary>,
2450    #[serde(rename = "MemorySummary")]
2451    #[serde(skip_serializing_if = "Option::is_none")]
2452    pub memory_summary: Option<MemorySummary>,
2453}
2454
2455#[derive(Debug, Serialize, Deserialize, Clone)]
2456#[serde(untagged)] // <-- this is important. More info https://serde.rs/enum-representations.html#untagged
2457pub enum HWInventoryByLocation {
2458    /* HWInvByLocCabinet(HWInvByLocCabinet),
2459    HWInvByLocChassis(HWInvByLocChassis),
2460    HWInvByLocComputeModule(HWInvByLocComputeModule),
2461    HWInvByLocRouterModule(HWInvByLocRouterModule),
2462    HWInvByLocNodeEnclosure(HWInvByLocNodeEnclosure),
2463    HWInvByLocHSNBoard(HWInvByLocHSNBoard),
2464    HWInvByLocMgmtSwitch(HWInvByLocMgmtSwitch),
2465    HWInvByLocMgmtHLSwitch(HWInvByLocMgmtHLSwitch),
2466    HWInvByLocCDUMgmtSwitch(HWInvByLocCDUMgmtSwitch), */
2467    HWInvByLocNode(HWInvByLocNode),
2468    HWInvByLocProcessor(HWInvByLocProcessor),
2469    HWInvByLocNodeAccel(HWInvByLocNodeAccel),
2470    /*     HWInvByLocDrive(HWInvByLocDrive), */
2471    HWInvByLocMemory(HWInvByLocMemory),
2472    /* HWInvByLocPDU(HWInvByLocPDU),
2473    HWInvByLocOutlet(HWInvByLocOutlet),
2474    HWInvByLocCMMRectifier(HWInvByLocCMMRectifier),
2475    HWInvByLocNodeAccelRiser(HWInvByLocNodeAccelRiser), */
2476    HWInvByLocHSNNIC(HWInvByLocHSNNIC),
2477    /* HWInvByLocNodePowerSupply(HWInvByLocNodePowerSupply),
2478    HWInvByLocNodeBMC(HWInvByLocNodeBMC),
2479    HWInvByLocRouterBMC(HWInvByLocRouterBMC), */
2480}
2481
2482/// struct used in POST and GET endpoints that manage multiple instances of 'HWInventoryByLocation'
2483#[derive(Debug, Serialize, Deserialize, Clone)]
2484pub struct HWInventoryByLocationList {
2485    #[serde(rename = "Hardware")]
2486    #[serde(skip_serializing_if = "Option::is_none")]
2487    pub hardware: Option<Vec<HWInventoryByLocation>>,
2488}
2489
2490#[derive(Debug, Serialize, Deserialize, Clone)]
2491pub struct Link {
2492    #[serde(skip_serializing_if = "Option::is_none")]
2493    pub rel: Option<String>,
2494    #[serde(skip_serializing_if = "Option::is_none")]
2495    pub href: Option<String>,
2496}
2497
2498#[derive(Debug, Serialize, Deserialize, Clone)]
2499pub struct Cfs {
2500    #[serde(skip_serializing_if = "Option::is_none")]
2501    pub configuration: Option<String>,
2502}
2503
2504#[derive(Debug, Serialize, Deserialize, Clone)]
2505pub struct BootSet {
2506    #[serde(skip_serializing_if = "Option::is_none")]
2507    pub name: Option<String>,
2508    #[serde(skip_serializing_if = "Option::is_none")]
2509    pub path: Option<String>,
2510    #[serde(skip_serializing_if = "Option::is_none")]
2511    pub cfs: Option<Cfs>,
2512    #[serde(skip_serializing_if = "Option::is_none")]
2513    pub r#type: Option<String>,
2514    #[serde(skip_serializing_if = "Option::is_none")]
2515    pub etag: Option<String>,
2516    #[serde(skip_serializing_if = "Option::is_none")]
2517    pub kernel_parameters: Option<String>,
2518    #[serde(skip_serializing_if = "Option::is_none")]
2519    pub node_list: Option<Vec<String>>,
2520    #[serde(skip_serializing_if = "Option::is_none")]
2521    pub node_roles_groups: Option<Vec<String>>,
2522    #[serde(skip_serializing_if = "Option::is_none")]
2523    pub node_groups: Option<Vec<String>>,
2524    #[serde(skip_serializing_if = "Option::is_none")]
2525    pub arch: Option<String>, // TODO: use Arch enum instead
2526    #[serde(skip_serializing_if = "Option::is_none")]
2527    pub rootfs_provider: Option<String>,
2528    #[serde(skip_serializing_if = "Option::is_none")]
2529    pub rootfs_provider_passthrough: Option<String>,
2530}
2531
2532#[derive(Debug, Serialize, Deserialize, Clone)]
2533pub struct BosSessionTemplate {
2534    #[serde(skip_serializing_if = "Option::is_none")]
2535    pub name: Option<String>,
2536    #[serde(skip_serializing_if = "Option::is_none")]
2537    pub tenant: Option<String>,
2538    #[serde(skip_serializing_if = "Option::is_none")]
2539    pub description: Option<String>,
2540    #[serde(skip_serializing_if = "Option::is_none")]
2541    pub enable_cfs: Option<bool>,
2542    #[serde(skip_serializing_if = "Option::is_none")]
2543    pub cfs: Option<Cfs>,
2544    #[serde(skip_serializing_if = "Option::is_none")]
2545    pub boot_sets: Option<HashMap<String, BootSet>>,
2546    #[serde(skip_serializing_if = "Option::is_none")]
2547    pub links: Option<Vec<Link>>,
2548}