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::bmc_quirks::BmcQuirks;
17use crate::patch_support::Payload;
18use crate::patch_support::ReadPatchFn;
19use crate::patches::remove_invalid_resource_state;
20use crate::schema::redfish::manager::Manager as ManagerSchema;
21use crate::Error;
22use crate::NvBmc;
23use crate::Resource;
24use crate::ResourceSchema;
25use nv_redfish_core::Bmc;
26use nv_redfish_core::NavProperty;
27use std::sync::Arc;
28
29#[cfg(feature = "ethernet-interfaces")]
30use crate::ethernet_interface::EthernetInterfaceCollection;
31#[cfg(feature = "host-interfaces")]
32use crate::host_interface::HostInterfaceCollection;
33#[cfg(feature = "log-services")]
34use crate::log_service::LogService;
35#[cfg(feature = "oem-ami")]
36use crate::oem::ami::config_bmc::ConfigBmc as AmiConfigBmc;
37#[cfg(feature = "oem-dell-attributes")]
38use crate::oem::dell::attributes::DellAttributes;
39#[cfg(feature = "oem-hpe")]
40use crate::oem::hpe::manager::HpeManager;
41#[cfg(feature = "oem-lenovo")]
42use crate::oem::lenovo::manager::LenovoManager;
43#[cfg(feature = "oem-supermicro")]
44use crate::oem::supermicro::manager::SupermicroManager;
45
46pub struct Config {
47    pub(crate) read_patch_fn: Option<ReadPatchFn>,
48}
49
50impl Config {
51    pub fn new(quirks: &BmcQuirks) -> Self {
52        let mut patches = Vec::new();
53        if quirks.wrong_resource_status_state() {
54            patches.push(remove_invalid_resource_state);
55        }
56        let read_patch_fn = (!patches.is_empty())
57            .then(|| Arc::new(move |v| patches.iter().fold(v, |acc, f| f(acc))) as ReadPatchFn);
58        Self { read_patch_fn }
59    }
60}
61
62/// Represents a manager (BMC) in the system.
63///
64/// Provides access to manager information and associated services.
65pub struct Manager<B: Bmc> {
66    #[allow(dead_code)] // enabled by features
67    bmc: NvBmc<B>,
68    data: Arc<ManagerSchema>,
69}
70
71impl<B: Bmc> Manager<B> {
72    /// Create a new manager handle.
73    pub(crate) async fn new(
74        bmc: &NvBmc<B>,
75        nav: &NavProperty<ManagerSchema>,
76    ) -> Result<Self, Error<B>> {
77        let config = Config::new(&bmc.quirks);
78        if let Some(read_patch_fn) = &config.read_patch_fn {
79            Payload::get(bmc.as_ref(), nav, read_patch_fn.as_ref()).await
80        } else {
81            nav.get(bmc.as_ref()).await.map_err(Error::Bmc)
82        }
83        .map(|data| Self {
84            bmc: bmc.clone(),
85            data,
86        })
87    }
88
89    /// Get the raw schema data for this manager.
90    ///
91    /// Returns an `Arc` to the underlying schema, allowing cheap cloning
92    /// and sharing of the data.
93    #[must_use]
94    pub fn raw(&self) -> Arc<ManagerSchema> {
95        self.data.clone()
96    }
97
98    /// Get ethernet interfaces for this manager.
99    ///
100    /// Returns `Ok(None)` when the ethernet interfaces link is absent.
101    ///
102    /// # Errors
103    ///
104    /// Returns an error if fetching ethernet interfaces data fails.
105    #[cfg(feature = "ethernet-interfaces")]
106    pub async fn ethernet_interfaces(
107        &self,
108    ) -> Result<Option<EthernetInterfaceCollection<B>>, crate::Error<B>> {
109        if let Some(p) = &self.data.ethernet_interfaces {
110            EthernetInterfaceCollection::new(&self.bmc, p)
111                .await
112                .map(Some)
113        } else {
114            Ok(None)
115        }
116    }
117
118    /// Get host interfaces for this manager.
119    ///
120    /// Returns `Ok(None)` when the host interfaces link is absent.
121    ///
122    /// # Errors
123    ///
124    /// Returns an error if fetching host interfaces data fails.
125    #[cfg(feature = "host-interfaces")]
126    pub async fn host_interfaces(
127        &self,
128    ) -> Result<Option<HostInterfaceCollection<B>>, crate::Error<B>> {
129        if let Some(p) = &self.data.host_interfaces {
130            HostInterfaceCollection::new(&self.bmc, p).await.map(Some)
131        } else {
132            Ok(None)
133        }
134    }
135
136    /// Get log services for this manager.
137    ///
138    /// Returns `Ok(None)` when the log services link is absent.
139    ///
140    /// # Errors
141    ///
142    /// Returns an error if fetching log service data fails.
143    #[cfg(feature = "log-services")]
144    pub async fn log_services(&self) -> Result<Option<Vec<LogService<B>>>, crate::Error<B>> {
145        if let Some(log_services_ref) = &self.data.log_services {
146            let log_services_collection = log_services_ref
147                .get(self.bmc.as_ref())
148                .await
149                .map_err(crate::Error::Bmc)?;
150
151            let mut log_services = Vec::new();
152            for m in &log_services_collection.members {
153                log_services.push(LogService::new(&self.bmc, m).await?);
154            }
155
156            Ok(Some(log_services))
157        } else {
158            Ok(None)
159        }
160    }
161
162    /// Get Dell Manager attributes for this manager.
163    ///
164    /// Returns `Ok(None)` when the manager does not include `Oem.Dell`.
165    ///
166    /// # Errors
167    ///
168    /// Returns an error if fetching manager attributes data fails.
169    #[cfg(feature = "oem-dell-attributes")]
170    pub async fn oem_dell_attributes(&self) -> Result<Option<DellAttributes<B>>, Error<B>> {
171        DellAttributes::manager_attributes(&self.bmc, &self.data).await
172    }
173
174    /// Get Lenovo Manager OEM.
175    ///
176    /// Returns `Ok(None)` when the manager does not include `Oem.Lenovo`.
177    ///
178    /// # Errors
179    ///
180    /// Returns an error if parsing Lenovo manager OEM data fails.
181    #[cfg(feature = "oem-lenovo")]
182    pub fn oem_lenovo(&self) -> Result<Option<LenovoManager<B>>, Error<B>> {
183        LenovoManager::new(&self.bmc, &self.data)
184    }
185
186    /// Get HPE Manager OEM.
187    ///
188    /// Returns `Ok(None)` when the manager does not include `Oem.Hpe`.
189    ///
190    /// # Errors
191    ///
192    /// Returns an error if parsing HPE manager OEM data fails.
193    #[cfg(feature = "oem-hpe")]
194    pub fn oem_hpe(&self) -> Result<Option<HpeManager<B>>, Error<B>> {
195        HpeManager::new(&self.bmc, &self.data)
196    }
197
198    /// Get Supermicro Manager OEM.
199    ///
200    /// Returns `Ok(None)` when the manager does not include `Oem.Supermicro`.
201    ///
202    /// # Errors
203    ///
204    /// Returns an error if parsing Supermicro manager OEM data fails.
205    #[cfg(feature = "oem-supermicro")]
206    pub fn oem_supermicro(&self) -> Result<Option<SupermicroManager<B>>, Error<B>> {
207        SupermicroManager::new(&self.bmc, &self.data)
208    }
209
210    /// Get AMI Manager ConfigBMC OEM extension.
211    ///
212    /// Returns `Ok(None)` when the manager does not include `Oem.Ami` or `Oem.ConfigBMC`.
213    ///
214    /// # Errors
215    ///
216    /// Returns an error if retrieving BMC config data fails.
217    #[cfg(feature = "oem-ami")]
218    pub async fn oem_ami_config_bmc(&self) -> Result<Option<AmiConfigBmc<B>>, Error<B>> {
219        AmiConfigBmc::new(&self.bmc, &self.data).await
220    }
221}
222
223impl<B: Bmc> Resource for Manager<B> {
224    fn resource_ref(&self) -> &ResourceSchema {
225        &self.data.as_ref().base
226    }
227}