Skip to main content

nv_redfish/
service_root.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::bmc_quirks::BmcQuirks;
17use crate::core::Bmc;
18use crate::core::NavProperty;
19use crate::core::ODataId;
20use crate::schema::redfish::service_root::ServiceRoot as SchemaServiceRoot;
21use crate::Error;
22use crate::NvBmc;
23use crate::ProtocolFeatures;
24use crate::Resource;
25use crate::ResourceSchema;
26use std::sync::Arc;
27use tagged_types::TaggedType;
28
29#[cfg(feature = "accounts")]
30use crate::account::AccountService;
31#[cfg(feature = "chassis")]
32use crate::chassis::ChassisCollection;
33#[cfg(feature = "computer-systems")]
34use crate::computer_system::SystemCollection;
35#[cfg(feature = "event-service")]
36use crate::event_service::EventService;
37#[cfg(feature = "managers")]
38use crate::manager::ManagerCollection;
39#[cfg(feature = "oem-hpe")]
40use crate::oem::hpe::HpeiLoServiceExt;
41#[cfg(feature = "telemetry-service")]
42use crate::telemetry_service::TelemetryService;
43#[cfg(feature = "update-service")]
44use crate::update_service::UpdateService;
45
46/// The vendor or manufacturer associated with Redfish service.
47pub type Vendor<T> = TaggedType<T, VendorTag>;
48#[doc(hidden)]
49#[derive(tagged_types::Tag)]
50#[implement(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
51#[transparent(Debug, Display, Serialize, Deserialize)]
52#[capability(inner_access, cloned)]
53pub enum VendorTag {}
54
55/// The product associated with Redfish service..
56pub type Product<T> = TaggedType<T, ProductTag>;
57#[doc(hidden)]
58#[derive(tagged_types::Tag)]
59#[implement(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
60#[transparent(Debug, Display, Serialize, Deserialize)]
61#[capability(inner_access, cloned)]
62pub enum ProductTag {}
63
64/// The version of Redfish schema.
65pub type RedfishVersion<'a> = TaggedType<&'a str, RedfishVersionTag>;
66#[doc(hidden)]
67#[derive(tagged_types::Tag)]
68#[implement(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
69#[transparent(Debug, Display, Serialize, Deserialize)]
70#[capability(inner_access, cloned)]
71pub enum RedfishVersionTag {}
72
73/// Represents `ServiceRoot` in the BMC model.
74#[derive(Clone)]
75pub struct ServiceRoot<B: Bmc> {
76    /// Content of the root.
77    pub root: Arc<SchemaServiceRoot>,
78    #[allow(dead_code)] // feature-enabled field
79    bmc: NvBmc<B>,
80}
81
82impl<B: Bmc> ServiceRoot<B> {
83    /// Create a new service root.
84    ///
85    /// # Errors
86    ///
87    /// Returns error if retrieving the root path via Redfish fails.
88    pub async fn new(bmc: Arc<B>) -> Result<Self, Error<B>> {
89        let root = NavProperty::<SchemaServiceRoot>::new_reference(ODataId::service_root())
90            .get(bmc.as_ref())
91            .await
92            .map_err(Error::Bmc)?;
93        let quirks = BmcQuirks::new(&root);
94        let mut protocol_features = root
95            .protocol_features_supported
96            .as_ref()
97            .map(ProtocolFeatures::new)
98            .unwrap_or_default();
99
100        if quirks.expand_is_not_working_properly() {
101            protocol_features.expand.expand_all = false;
102            protocol_features.expand.no_links = false;
103        }
104
105        let bmc = NvBmc::new(bmc, protocol_features, quirks);
106        Ok(Self { root, bmc })
107    }
108
109    /// Replace BMC in this root.
110    #[must_use]
111    pub fn replace_bmc(self, bmc: Arc<B>) -> Self {
112        let root = self.root;
113        let bmc = self.bmc.replace_bmc(bmc);
114        Self { root, bmc }
115    }
116
117    /// Restrict usage of expand.
118    #[must_use]
119    pub fn restrict_expand(self) -> Self {
120        let root = self.root;
121        let bmc = self.bmc.restrict_expand();
122        Self { root, bmc }
123    }
124
125    /// The vendor or manufacturer associated with this Redfish service.
126    pub fn vendor(&self) -> Option<Vendor<&str>> {
127        self.root
128            .vendor
129            .as_ref()
130            .and_then(Option::as_ref)
131            .map(String::as_str)
132            .map(Vendor::new)
133    }
134
135    /// The product associated with this Redfish service.
136    pub fn product(&self) -> Option<Product<&str>> {
137        self.root
138            .product
139            .as_ref()
140            .and_then(Option::as_ref)
141            .map(String::as_str)
142            .map(Product::new)
143    }
144
145    /// The vendor or manufacturer associated with this Redfish service.
146    pub fn redfish_version(&self) -> Option<RedfishVersion<'_>> {
147        self.root
148            .redfish_version
149            .as_deref()
150            .map(RedfishVersion::new)
151    }
152
153    /// Get the account service belonging to the BMC.
154    ///
155    /// Returns `Ok(None)` when the BMC does not expose AccountService.
156    ///
157    /// # Errors
158    ///
159    /// Returns error if retrieving account service data fails.
160    #[cfg(feature = "accounts")]
161    pub async fn account_service(&self) -> Result<Option<AccountService<B>>, Error<B>> {
162        AccountService::new(&self.bmc, self).await
163    }
164
165    /// Get chassis collection in BMC
166    ///
167    /// Returns `Ok(None)` when the BMC does not expose Chassis.
168    ///
169    /// # Errors
170    ///
171    /// Returns error if retrieving chassis collection data fails.
172    #[cfg(feature = "chassis")]
173    pub async fn chassis(&self) -> Result<Option<ChassisCollection<B>>, Error<B>> {
174        ChassisCollection::new(&self.bmc, self).await
175    }
176
177    /// Get computer system collection in BMC
178    ///
179    /// Returns `Ok(None)` when the BMC does not expose Systems.
180    ///
181    /// # Errors
182    ///
183    /// Returns error if retrieving system collection data fails.
184    #[cfg(feature = "computer-systems")]
185    pub async fn systems(&self) -> Result<Option<SystemCollection<B>>, Error<B>> {
186        SystemCollection::new(&self.bmc, self).await
187    }
188
189    /// Get update service in BMC
190    ///
191    /// Returns `Ok(None)` when the BMC does not expose UpdateService.
192    ///
193    /// # Errors
194    ///
195    /// Returns error if retrieving update service data fails.
196    #[cfg(feature = "update-service")]
197    pub async fn update_service(&self) -> Result<Option<UpdateService<B>>, Error<B>> {
198        UpdateService::new(&self.bmc, self).await
199    }
200
201    /// Get event service in BMC
202    ///
203    /// Returns `Ok(None)` when the BMC does not expose EventService.
204    ///
205    /// # Errors
206    ///
207    /// Returns error if retrieving event service data fails.
208    #[cfg(feature = "event-service")]
209    pub async fn event_service(&self) -> Result<Option<EventService<B>>, Error<B>> {
210        EventService::new(&self.bmc, self).await
211    }
212
213    /// Get telemetry service in BMC
214    ///
215    /// Returns `Ok(None)` when the BMC does not expose TelemetryService.
216    ///
217    /// # Errors
218    ///
219    /// Returns error if retrieving telemetry service data fails.
220    #[cfg(feature = "telemetry-service")]
221    pub async fn telemetry_service(&self) -> Result<Option<TelemetryService<B>>, Error<B>> {
222        TelemetryService::new(&self.bmc, self).await
223    }
224
225    /// Get manager collection in BMC
226    ///
227    /// Returns `Ok(None)` when the BMC does not expose Managers.
228    ///
229    /// # Errors
230    ///
231    /// Returns error if retrieving manager collection data fails.
232    #[cfg(feature = "managers")]
233    pub async fn managers(&self) -> Result<Option<ManagerCollection<B>>, Error<B>> {
234        ManagerCollection::new(&self.bmc, self).await
235    }
236
237    /// Get HPE OEM extension in service root
238    ///
239    /// Returns `Ok(None)` when the BMC does not expose HPE extension.
240    ///
241    /// # Errors
242    ///
243    /// Returns error if retrieving manager collection data fails.
244    #[cfg(feature = "oem-hpe")]
245    pub fn oem_hpe_ilo_service_ext(&self) -> Result<Option<HpeiLoServiceExt<B>>, Error<B>> {
246        HpeiLoServiceExt::new(&self.root)
247    }
248}
249
250impl<B: Bmc> Resource for ServiceRoot<B> {
251    fn resource_ref(&self) -> &ResourceSchema {
252        &self.root.as_ref().base
253    }
254}