Skip to main content

nv_redfish/manager/
item.rs

1// SPDX-FileCopyrightText: Copyright (c) 2025-2026 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::resource::ResetType;
17use crate::schema::manager::Manager as ManagerSchema;
18use crate::schema::manager::ResetToDefaultsType as ManagerResetToDefaultsType;
19use crate::Error;
20use crate::NvBmc;
21use crate::Resource;
22use crate::ResourceSchema;
23use nv_redfish_core::Bmc;
24use nv_redfish_core::ModificationResponse;
25use nv_redfish_core::NavProperty;
26use std::sync::Arc;
27
28#[cfg(feature = "manager-network-protocol")]
29use super::network_protocol::ManagerNetworkProtocol;
30#[cfg(feature = "ethernet-interfaces")]
31use crate::ethernet_interface::EthernetInterfaceCollection;
32#[cfg(feature = "host-interfaces")]
33use crate::host_interface::HostInterfaceCollection;
34#[cfg(feature = "log-services")]
35use crate::log_service::LogService;
36#[cfg(feature = "oem-ami")]
37use crate::oem::ami::config_bmc::ConfigBmc as AmiConfigBmc;
38#[cfg(feature = "oem-dell-attributes")]
39use crate::oem::dell::attributes::DellAttributes;
40#[cfg(feature = "oem-hpe")]
41use crate::oem::hpe::manager::HpeManager;
42#[cfg(feature = "oem-lenovo")]
43use crate::oem::lenovo::manager::LenovoManager;
44#[cfg(feature = "oem-supermicro")]
45use crate::oem::supermicro::manager::SupermicroManager;
46
47/// Represents a manager (BMC) in the system.
48///
49/// Provides access to manager information and associated services.
50pub struct Manager<B: Bmc> {
51    #[allow(dead_code)] // enabled by features
52    bmc: NvBmc<B>,
53    data: Arc<ManagerSchema>,
54}
55
56impl<B: Bmc> Manager<B> {
57    /// Create a new manager handle.
58    pub(crate) async fn new(
59        bmc: &NvBmc<B>,
60        nav: &NavProperty<ManagerSchema>,
61    ) -> Result<Self, Error<B>> {
62        nav.get(bmc.as_ref())
63            .await
64            .map_err(Error::Bmc)
65            .map(|data| Self {
66                bmc: bmc.clone(),
67                data,
68            })
69    }
70
71    /// Get the raw schema data for this manager.
72    ///
73    /// Returns an `Arc` to the underlying schema, allowing cheap cloning
74    /// and sharing of the data.
75    #[must_use]
76    pub fn raw(&self) -> Arc<ManagerSchema> {
77        self.data.clone()
78    }
79
80    /// Get the network protocol resource associated with this manager.
81    ///
82    /// Returns `Ok(None)` when the network protocol link is absent.
83    ///
84    /// # Errors
85    ///
86    /// Returns an error if fetching the network protocol resource fails.
87    #[cfg(feature = "manager-network-protocol")]
88    pub async fn network_protocol(&self) -> Result<Option<ManagerNetworkProtocol<B>>, Error<B>> {
89        if let Some(network_protocol_ref) = &self.data.network_protocol {
90            ManagerNetworkProtocol::new(&self.bmc, network_protocol_ref)
91                .await
92                .map(Some)
93        } else {
94            Ok(None)
95        }
96    }
97
98    /// Reset this manager.
99    ///
100    /// # Errors
101    ///
102    /// Returns an error if the manager does not support the `Reset` action or
103    /// if invoking the action fails.
104    pub async fn reset(
105        &self,
106        reset_type: Option<ResetType>,
107    ) -> Result<ModificationResponse<()>, Error<B>>
108    where
109        B::Error: nv_redfish_core::ActionError,
110    {
111        let actions = self
112            .data
113            .actions
114            .as_ref()
115            .ok_or(Error::ActionNotAvailable)?;
116
117        if actions.reset.is_none() {
118            return Err(Error::ActionNotAvailable);
119        }
120
121        actions
122            .reset(self.bmc.as_ref(), reset_type)
123            .await
124            .map_err(Error::Bmc)
125    }
126
127    /// Reset this manager's settings to defaults.
128    ///
129    /// # Errors
130    ///
131    /// Returns an error if the manager does not support the `ResetToDefaults`
132    /// action or if invoking the action fails.
133    pub async fn reset_to_defaults(
134        &self,
135        reset_type: ManagerResetToDefaultsType,
136    ) -> Result<ModificationResponse<()>, Error<B>>
137    where
138        B::Error: nv_redfish_core::ActionError,
139    {
140        let actions = self
141            .data
142            .actions
143            .as_ref()
144            .ok_or(Error::ActionNotAvailable)?;
145
146        if actions.reset_to_defaults.is_none() {
147            return Err(Error::ActionNotAvailable);
148        }
149
150        actions
151            .reset_to_defaults(self.bmc.as_ref(), Some(reset_type))
152            .await
153            .map_err(Error::Bmc)
154    }
155
156    /// Get ethernet interfaces for this manager.
157    ///
158    /// Returns `Ok(None)` when the ethernet interfaces link is absent.
159    ///
160    /// # Errors
161    ///
162    /// Returns an error if fetching ethernet interfaces data fails.
163    #[cfg(feature = "ethernet-interfaces")]
164    pub async fn ethernet_interfaces(
165        &self,
166    ) -> Result<Option<EthernetInterfaceCollection<B>>, crate::Error<B>> {
167        if let Some(p) = &self.data.ethernet_interfaces {
168            EthernetInterfaceCollection::new(&self.bmc, p)
169                .await
170                .map(Some)
171        } else {
172            Ok(None)
173        }
174    }
175
176    /// Get host interfaces for this manager.
177    ///
178    /// Returns `Ok(None)` when the host interfaces link is absent.
179    ///
180    /// # Errors
181    ///
182    /// Returns an error if fetching host interfaces data fails.
183    #[cfg(feature = "host-interfaces")]
184    pub async fn host_interfaces(
185        &self,
186    ) -> Result<Option<HostInterfaceCollection<B>>, crate::Error<B>> {
187        if let Some(p) = &self.data.host_interfaces {
188            HostInterfaceCollection::new(&self.bmc, p).await.map(Some)
189        } else {
190            Ok(None)
191        }
192    }
193
194    /// Get log services for this manager.
195    ///
196    /// Returns `Ok(None)` when the log services link is absent.
197    ///
198    /// # Errors
199    ///
200    /// Returns an error if fetching log service data fails.
201    #[cfg(feature = "log-services")]
202    pub async fn log_services(&self) -> Result<Option<Vec<LogService<B>>>, crate::Error<B>> {
203        if let Some(log_services_ref) = &self.data.log_services {
204            let log_services_collection = log_services_ref
205                .get(self.bmc.as_ref())
206                .await
207                .map_err(crate::Error::Bmc)?;
208
209            let mut log_services = Vec::new();
210            for m in &log_services_collection.members {
211                log_services.push(LogService::new(&self.bmc, m).await?);
212            }
213
214            Ok(Some(log_services))
215        } else {
216            Ok(None)
217        }
218    }
219
220    /// Get Dell Manager attributes for this manager.
221    ///
222    /// Returns `Ok(None)` when the manager does not include `Oem.Dell`.
223    ///
224    /// # Errors
225    ///
226    /// Returns an error if fetching manager attributes data fails.
227    #[cfg(feature = "oem-dell-attributes")]
228    pub async fn oem_dell_attributes(&self) -> Result<Option<DellAttributes<B>>, Error<B>> {
229        DellAttributes::manager_attributes(&self.bmc, &self.data).await
230    }
231
232    /// Get Lenovo Manager OEM.
233    ///
234    /// Returns `Ok(None)` when the manager does not include `Oem.Lenovo`.
235    ///
236    /// # Errors
237    ///
238    /// Returns an error if parsing Lenovo manager OEM data fails.
239    #[cfg(feature = "oem-lenovo")]
240    pub fn oem_lenovo(&self) -> Result<Option<LenovoManager<B>>, Error<B>> {
241        LenovoManager::new(&self.bmc, &self.data)
242    }
243
244    /// Get HPE Manager OEM.
245    ///
246    /// Returns `Ok(None)` when the manager does not include `Oem.Hpe`.
247    ///
248    /// # Errors
249    ///
250    /// Returns an error if parsing HPE manager OEM data fails.
251    #[cfg(feature = "oem-hpe")]
252    pub fn oem_hpe(&self) -> Result<Option<HpeManager<B>>, Error<B>> {
253        HpeManager::new(&self.bmc, &self.data)
254    }
255
256    /// Get Supermicro Manager OEM.
257    ///
258    /// Returns `Ok(None)` when the manager does not include `Oem.Supermicro`.
259    ///
260    /// # Errors
261    ///
262    /// Returns an error if parsing Supermicro manager OEM data fails.
263    #[cfg(feature = "oem-supermicro")]
264    pub fn oem_supermicro(&self) -> Result<Option<SupermicroManager<B>>, Error<B>> {
265        SupermicroManager::new(&self.bmc, &self.data)
266    }
267
268    /// Get AMI Manager ConfigBMC OEM extension.
269    ///
270    /// Returns `Ok(None)` when the manager does not include `Oem.Ami` or `Oem.ConfigBMC`.
271    ///
272    /// # Errors
273    ///
274    /// Returns an error if retrieving BMC config data fails.
275    #[cfg(feature = "oem-ami")]
276    pub async fn oem_ami_config_bmc(&self) -> Result<Option<AmiConfigBmc<B>>, Error<B>> {
277        AmiConfigBmc::new(&self.bmc, &self.data).await
278    }
279}
280
281impl<B: Bmc> Resource for Manager<B> {
282    fn resource_ref(&self) -> &ResourceSchema {
283        &self.data.as_ref().base
284    }
285}