Skip to main content

nv_redfish/computer_system/
item.rs

1// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::hardware_id::HardwareIdRef;
17use crate::hardware_id::Manufacturer as HardwareIdManufacturer;
18use crate::hardware_id::Model as HardwareIdModel;
19use crate::hardware_id::PartNumber as HardwareIdPartNumber;
20use crate::hardware_id::SerialNumber as HardwareIdSerialNumber;
21use crate::patch_support::Payload;
22use crate::patch_support::ReadPatchFn;
23use crate::resource::PowerState;
24use crate::schema::redfish::computer_system::ComputerSystem as ComputerSystemSchema;
25use crate::Error;
26use crate::NvBmc;
27use crate::Resource;
28use crate::ResourceSchema;
29use nv_redfish_core::Bmc;
30use nv_redfish_core::NavProperty;
31use std::convert::identity;
32use std::sync::Arc;
33use tagged_types::TaggedType;
34
35#[cfg(feature = "bios")]
36use crate::computer_system::Bios;
37#[cfg(feature = "boot-options")]
38use crate::computer_system::BootOptionCollection;
39#[cfg(feature = "memory")]
40use crate::computer_system::Memory;
41#[cfg(feature = "processors")]
42use crate::computer_system::Processor;
43#[cfg(feature = "secure-boot")]
44use crate::computer_system::SecureBoot;
45#[cfg(feature = "storages")]
46use crate::computer_system::Storage;
47#[cfg(feature = "ethernet-interfaces")]
48use crate::ethernet_interface::EthernetInterfaceCollection;
49#[cfg(feature = "log-services")]
50use crate::log_service::LogService;
51#[cfg(feature = "oem-nvidia-bluefield")]
52use crate::oem::nvidia::bluefield::nvidia_computer_system::NvidiaComputerSystem;
53
54#[doc(hidden)]
55pub enum ComputerSystemTag {}
56
57/// Computer system manufacturer.
58pub type Manufacturer<T> = HardwareIdManufacturer<T, ComputerSystemTag>;
59
60/// Computer system model.
61pub type Model<T> = HardwareIdModel<T, ComputerSystemTag>;
62
63/// Computer system part number.
64pub type PartNumber<T> = HardwareIdPartNumber<T, ComputerSystemTag>;
65
66/// Computer system serial number.
67pub type SerialNumber<T> = HardwareIdSerialNumber<T, ComputerSystemTag>;
68
69/// Computer system SKU.
70pub type Sku<T> = TaggedType<T, ComputerSystemSkuTag>;
71#[doc(hidden)]
72#[derive(tagged_types::Tag)]
73#[implement(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
74#[transparent(Debug, Display, FromStr, Serialize, Deserialize)]
75#[capability(inner_access, cloned)]
76pub enum ComputerSystemSkuTag {}
77
78/// `BootOptionReference` type represent boot order of the `ComputerSystem`.
79pub type BootOptionReference<T> = TaggedType<T, BootOptionReferenceTag>;
80#[doc(hidden)]
81#[derive(tagged_types::Tag)]
82#[implement(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
83#[transparent(Debug, Display, FromStr, Serialize, Deserialize)]
84#[capability(inner_access, cloned)]
85pub enum BootOptionReferenceTag {}
86
87/// Represents a computer system in the BMC.
88///
89/// Provides access to system information and sub-resources such as processors.
90pub struct ComputerSystem<B: Bmc> {
91    #[allow(dead_code)] // feature-enabled...
92    bmc: NvBmc<B>,
93    data: Arc<ComputerSystemSchema>,
94}
95
96impl<B: Bmc> ComputerSystem<B> {
97    /// Create a new computer system handle.
98    pub(crate) async fn new(
99        bmc: &NvBmc<B>,
100        nav: &NavProperty<ComputerSystemSchema>,
101        read_patch_fn: Option<&ReadPatchFn>,
102    ) -> Result<Self, Error<B>> {
103        if let Some(read_patch_fn) = read_patch_fn {
104            Payload::get(bmc.as_ref(), nav, read_patch_fn.as_ref()).await
105        } else {
106            nav.get(bmc.as_ref()).await.map_err(Error::Bmc)
107        }
108        .map(|data| Self {
109            bmc: bmc.clone(),
110            data,
111        })
112    }
113
114    /// Get the raw schema data for this computer system.
115    ///
116    /// Returns an `Arc` to the underlying schema, allowing cheap cloning
117    /// and sharing of the data.
118    #[must_use]
119    pub fn raw(&self) -> Arc<ComputerSystemSchema> {
120        self.data.clone()
121    }
122
123    /// Get hardware identifier of the network adpater.
124    #[must_use]
125    pub fn hardware_id(&self) -> HardwareIdRef<'_, ComputerSystemTag> {
126        HardwareIdRef {
127            manufacturer: self
128                .data
129                .manufacturer
130                .as_ref()
131                .and_then(Option::as_ref)
132                .map(Manufacturer::new),
133            model: self
134                .data
135                .model
136                .as_ref()
137                .and_then(Option::as_ref)
138                .map(Model::new),
139            part_number: self
140                .data
141                .part_number
142                .as_ref()
143                .and_then(Option::as_ref)
144                .map(PartNumber::new),
145            serial_number: self
146                .data
147                .serial_number
148                .as_ref()
149                .and_then(Option::as_ref)
150                .map(SerialNumber::new),
151        }
152    }
153
154    /// The manufacturer SKU for this system.
155    #[must_use]
156    pub fn sku(&self) -> Option<Sku<&String>> {
157        self.data
158            .sku
159            .as_ref()
160            .and_then(Option::as_ref)
161            .map(Sku::new)
162    }
163
164    /// Power state of this system.
165    #[must_use]
166    pub fn power_state(&self) -> Option<PowerState> {
167        self.data.power_state.and_then(identity)
168    }
169
170    /// An array of `BootOptionReference` strings that represent the persistent boot order for with this
171    /// computer system.
172    #[must_use]
173    pub fn boot_order(&self) -> Option<Vec<BootOptionReference<&String>>> {
174        self.data
175            .as_ref()
176            .boot
177            .as_ref()
178            .and_then(|boot| boot.boot_order.as_ref().and_then(Option::as_ref))
179            .map(|v| v.iter().map(BootOptionReference::new).collect::<Vec<_>>())
180    }
181
182    /// Bios associated with this system.
183    ///
184    /// Fetches the BIOS settings.
185    ///
186    /// # Errors
187    ///
188    /// Returns an error if:
189    /// - The system does not provide bios settings
190    /// - Fetching bios data fails
191    #[cfg(feature = "bios")]
192    pub async fn bios(&self) -> Result<Bios<B>, Error<B>> {
193        let bios_ref = self.data.bios.as_ref().ok_or(Error::BiosNotAvailable)?;
194        Bios::new(&self.bmc, bios_ref).await
195    }
196
197    /// Get processors associated with this system.
198    ///
199    /// Fetches the processor collection and returns a list of [`Processor`] handles.
200    ///
201    /// # Errors
202    ///
203    /// Returns an error if:
204    /// - The system does not have a processors collection
205    /// - Fetching processor data fails
206    #[cfg(feature = "processors")]
207    pub async fn processors(&self) -> Result<Vec<Processor<B>>, Error<B>> {
208        let processors_ref = self
209            .data
210            .processors
211            .as_ref()
212            .ok_or(Error::ProcessorsNotAvailable)?;
213
214        let processors_collection = self.bmc.expand_property(processors_ref).await?;
215
216        let mut processors = Vec::new();
217        for m in &processors_collection.members {
218            processors.push(Processor::new(&self.bmc, m).await?);
219        }
220
221        Ok(processors)
222    }
223
224    /// Get secure boot resource associated with this system.
225    ///
226    /// # Errors
227    ///
228    /// Returns an error if:
229    /// - The system does not have a secure boot resource
230    /// - Fetching of secure boot data fails
231    #[cfg(feature = "secure-boot")]
232    pub async fn secure_boot(&self) -> Result<SecureBoot<B>, Error<B>> {
233        let secure_boot_ref = self
234            .data
235            .secure_boot
236            .as_ref()
237            .ok_or(Error::SecureBootNotAvailable)?;
238        SecureBoot::new(&self.bmc, secure_boot_ref).await
239    }
240
241    /// Get storage controllers associated with this system.
242    ///
243    /// Fetches the storage collection and returns a list of [`Storage`] handles.
244    ///
245    /// # Errors
246    ///
247    /// Returns an error if:
248    /// - The system does not have a storage collection
249    /// - Fetching storage data fails
250    #[cfg(feature = "storages")]
251    pub async fn storage_controllers(&self) -> Result<Vec<Storage<B>>, Error<B>> {
252        let storage_ref = self
253            .data
254            .storage
255            .as_ref()
256            .ok_or(Error::StorageNotAvailable)?;
257
258        let storage_collection = self.bmc.expand_property(storage_ref).await?;
259
260        let mut storage_controllers = Vec::new();
261        for m in &storage_collection.members {
262            storage_controllers.push(Storage::new(&self.bmc, m).await?);
263        }
264
265        Ok(storage_controllers)
266    }
267
268    /// Get memory modules associated with this system.
269    ///
270    /// Fetches the memory collection and returns a list of [`Memory`] handles.
271    ///
272    /// # Errors
273    ///
274    /// Returns an error if:
275    /// - The system does not have a memory collection
276    /// - Fetching memory data fails
277    #[cfg(feature = "memory")]
278    pub async fn memory_modules(&self) -> Result<Vec<Memory<B>>, Error<B>> {
279        let memory_ref = self.data.memory.as_ref().ok_or(Error::MemoryNotAvailable)?;
280
281        let memory_collection = self.bmc.expand_property(memory_ref).await?;
282
283        let mut memory_modules = Vec::new();
284        for m in &memory_collection.members {
285            memory_modules.push(Memory::new(&self.bmc, m).await?);
286        }
287
288        Ok(memory_modules)
289    }
290
291    /// Get log services for this computer system.
292    ///
293    /// # Errors
294    ///
295    /// Returns an error if:
296    /// - The computer system does not have log services
297    /// - Fetching log service data fails
298    #[cfg(feature = "log-services")]
299    pub async fn log_services(&self) -> Result<Vec<LogService<B>>, Error<B>> {
300        let log_services_ref = self
301            .data
302            .log_services
303            .as_ref()
304            .ok_or(Error::LogServiceNotAvailable)?;
305
306        let log_services_collection = log_services_ref
307            .get(self.bmc.as_ref())
308            .await
309            .map_err(Error::Bmc)?;
310
311        let mut log_services = Vec::new();
312        for m in &log_services_collection.members {
313            log_services.push(LogService::new(&self.bmc, m).await?);
314        }
315
316        Ok(log_services)
317    }
318
319    /// Get ethernet interfaces for this computer system.
320    ///
321    /// # Errors
322    ///
323    /// Returns an error if:
324    /// - The systems does not have / provide ethernet interfaces
325    /// - Fetching ethernet internet data fails
326    #[cfg(feature = "ethernet-interfaces")]
327    pub async fn ethernet_interfaces(&self) -> Result<EthernetInterfaceCollection<B>, Error<B>> {
328        let p = self
329            .data
330            .ethernet_interfaces
331            .as_ref()
332            .ok_or(Error::EthernetInterfacesNotAvailable)?;
333        EthernetInterfaceCollection::new(&self.bmc, p).await
334    }
335
336    /// Get collection of the UEFI boot options associated with this computer system.
337    ///
338    /// # Errors
339    ///
340    /// Returns an error if:
341    /// - The systems does not have / provide boot options
342    /// - Fetching boot options data fails
343    #[cfg(feature = "boot-options")]
344    pub async fn boot_options(&self) -> Result<BootOptionCollection<B>, Error<B>> {
345        let p = self
346            .data
347            .boot
348            .as_ref()
349            .ok_or(Error::BootOptionsNotAvailable)?
350            .boot_options
351            .as_ref()
352            .ok_or(Error::BootOptionsNotAvailable)?;
353        BootOptionCollection::new(&self.bmc, p).await
354    }
355
356    /// NVIDIA Bluefield OEM extension
357    ///
358    /// # Errors
359    ///
360    /// Returns an error if:
361    /// - `Error::NvidiaComputerSystemNotAvailable` if the systems does not have / provide NVIDIA OEM extension
362    /// - Fetching data fails
363    #[cfg(feature = "oem-nvidia-bluefield")]
364    pub async fn oem_nvidia_bluefield(&self) -> Result<NvidiaComputerSystem<B>, Error<B>> {
365        let oem = self
366            .data
367            .base
368            .base
369            .oem
370            .as_ref()
371            .ok_or(Error::NvidiaComputerSystemNotAvailable)?;
372        NvidiaComputerSystem::new(&self.bmc, oem).await
373    }
374}
375
376impl<B: Bmc> Resource for ComputerSystem<B> {
377    fn resource_ref(&self) -> &ResourceSchema {
378        &self.data.as_ref().base
379    }
380}