nv_redfish/
service_root.rs1use std::sync::Arc;
17
18use nv_redfish_core::{Bmc, NavProperty, ODataId};
19use tagged_types::TaggedType;
20
21#[cfg(feature = "accounts")]
22use crate::account::AccountService;
23#[cfg(feature = "accounts")]
24use crate::account::SlotDefinedConfig as SlotDefinedUserAccountsConfig;
25#[cfg(feature = "chassis")]
26use crate::chassis::ChassisCollection;
27#[cfg(feature = "computer-systems")]
28use crate::computer_system::SystemCollection;
29#[cfg(feature = "event-service")]
30use crate::event_service::EventService;
31#[cfg(feature = "managers")]
32use crate::manager::ManagerCollection;
33use crate::schema::redfish::service_root::ServiceRoot as SchemaServiceRoot;
34#[cfg(feature = "telemetry-service")]
35use crate::telemetry_service::TelemetryService;
36#[cfg(feature = "update-service")]
37use crate::update_service::UpdateService;
38use crate::{Error, NvBmc, ProtocolFeatures, Resource, ResourceSchema};
39
40pub type Vendor<T> = TaggedType<T, VendorTag>;
42#[doc(hidden)]
43#[derive(tagged_types::Tag)]
44#[implement(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
45#[transparent(Debug, Display, Serialize, Deserialize)]
46#[capability(inner_access, cloned)]
47pub enum VendorTag {}
48
49pub type Product<T> = TaggedType<T, ProductTag>;
51#[doc(hidden)]
52#[derive(tagged_types::Tag)]
53#[implement(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
54#[transparent(Debug, Display, Serialize, Deserialize)]
55#[capability(inner_access, cloned)]
56pub enum ProductTag {}
57
58#[derive(Clone)]
60pub struct ServiceRoot<B: Bmc> {
61 pub root: Arc<SchemaServiceRoot>,
63 #[allow(dead_code)] bmc: NvBmc<B>,
65}
66
67impl<B: Bmc> ServiceRoot<B> {
68 pub async fn new(bmc: Arc<B>) -> Result<Self, Error<B>> {
74 let root = NavProperty::<SchemaServiceRoot>::new_reference(ODataId::service_root())
75 .get(bmc.as_ref())
76 .await
77 .map_err(Error::Bmc)?;
78 let mut protocol_features = root
79 .protocol_features_supported
80 .as_ref()
81 .map(ProtocolFeatures::new)
82 .unwrap_or_default();
83
84 if Self::expand_is_not_working_properly(&root) {
85 protocol_features.expand.expand_all = false;
86 protocol_features.expand.no_links = false;
87 }
88
89 let bmc = NvBmc::new(bmc, protocol_features);
90 Ok(Self { root, bmc })
91 }
92
93 pub fn vendor(&self) -> Option<Vendor<&str>> {
95 self.root
96 .vendor
97 .as_ref()
98 .and_then(Option::as_ref)
99 .map(String::as_str)
100 .map(Vendor::new)
101 }
102
103 pub fn product(&self) -> Option<Product<&str>> {
105 self.root
106 .product
107 .as_ref()
108 .and_then(Option::as_ref)
109 .map(String::as_str)
110 .map(Product::new)
111 }
112
113 #[cfg(feature = "accounts")]
121 pub async fn account_service(&self) -> Result<Option<AccountService<B>>, Error<B>> {
122 AccountService::new(&self.bmc, self).await
123 }
124
125 #[cfg(feature = "chassis")]
133 pub async fn chassis(&self) -> Result<Option<ChassisCollection<B>>, Error<B>> {
134 ChassisCollection::new(&self.bmc, self).await
135 }
136
137 #[cfg(feature = "computer-systems")]
145 pub async fn systems(&self) -> Result<Option<SystemCollection<B>>, Error<B>> {
146 SystemCollection::new(&self.bmc, self).await
147 }
148
149 #[cfg(feature = "update-service")]
157 pub async fn update_service(&self) -> Result<Option<UpdateService<B>>, Error<B>> {
158 UpdateService::new(&self.bmc, self).await
159 }
160
161 #[cfg(feature = "event-service")]
169 pub async fn event_service(&self) -> Result<Option<EventService<B>>, Error<B>> {
170 EventService::new(&self.bmc, self).await
171 }
172
173 #[cfg(feature = "telemetry-service")]
181 pub async fn telemetry_service(&self) -> Result<Option<TelemetryService<B>>, Error<B>> {
182 TelemetryService::new(&self.bmc, self).await
183 }
184
185 #[cfg(feature = "managers")]
193 pub async fn managers(&self) -> Result<Option<ManagerCollection<B>>, Error<B>> {
194 ManagerCollection::new(&self.bmc, self).await
195 }
196}
197
198impl<B: Bmc> ServiceRoot<B> {
200 #[cfg(feature = "accounts")]
205 pub(crate) fn bug_no_account_type_in_accounts(&self) -> bool {
206 self.root
207 .vendor
208 .as_ref()
209 .and_then(Option::as_ref)
210 .is_some_and(|v| v == "HPE")
211 }
212
213 #[cfg(feature = "accounts")]
219 pub(crate) fn slot_defined_user_accounts(&self) -> Option<SlotDefinedUserAccountsConfig> {
220 if self
221 .root
222 .vendor
223 .as_ref()
224 .and_then(Option::as_ref)
225 .is_some_and(|v| v == "Dell")
226 {
227 Some(SlotDefinedUserAccountsConfig {
228 min_slot: Some(3),
229 hide_disabled: true,
230 disable_account_on_delete: true,
231 })
232 } else {
233 None
234 }
235 }
236
237 #[cfg(feature = "update-service")]
241 pub(crate) fn fw_inventory_wrong_release_date(&self) -> bool {
242 self.root
243 .vendor
244 .as_ref()
245 .and_then(Option::as_ref)
246 .is_some_and(|v| v == "Dell")
247 }
248
249 #[cfg(feature = "chassis")]
252 pub(crate) fn bug_invalid_contained_by_fields(&self) -> bool {
253 Self::is_ami_viking(&self.root)
254 }
255
256 #[cfg(any(
258 feature = "chassis",
259 feature = "computer-systems",
260 feature = "managers",
261 feature = "update-service",
262 ))]
263 pub(crate) fn bug_missing_root_nav_properties(&self) -> bool {
264 Self::is_ami_viking(&self.root)
265 }
266
267 #[cfg(feature = "chassis")]
271 pub(crate) fn bug_missing_chassis_type_field(&self) -> bool {
272 Self::is_ami_viking(&self.root)
273 }
274
275 #[cfg(feature = "chassis")]
278 pub(crate) fn bug_missing_chassis_name_field(&self) -> bool {
279 Self::is_ami_viking(&self.root)
280 }
281
282 #[cfg(feature = "update-service")]
285 pub(crate) fn bug_missing_update_service_name_field(&self) -> bool {
286 Self::is_ami_viking(&self.root)
287 }
288
289 #[cfg(feature = "computer-systems")]
294 pub(crate) fn computer_systems_wrong_last_reset_time(&self) -> bool {
295 self.root
296 .vendor
297 .as_ref()
298 .and_then(Option::as_ref)
299 .is_some_and(|v| v == "Dell")
300 }
301
302 #[cfg(feature = "event-service")]
305 pub(crate) fn event_service_sse_no_member_id(&self) -> bool {
306 self.root
307 .vendor
308 .as_ref()
309 .and_then(Option::as_ref)
310 .is_some_and(|v| v == "NVIDIA")
311 }
312
313 #[cfg(feature = "event-service")]
316 pub(crate) fn event_service_sse_wrong_timestamp_offset(&self) -> bool {
317 self.root
318 .vendor
319 .as_ref()
320 .and_then(Option::as_ref)
321 .is_some_and(|v| v == "Dell")
322 }
323
324 #[cfg(feature = "event-service")]
327 pub(crate) fn event_service_sse_wrong_event_type(&self) -> bool {
328 self.root
329 .vendor
330 .as_ref()
331 .and_then(Option::as_ref)
332 .is_some_and(|v| v == "NVIDIA")
333 }
334
335 #[cfg(feature = "event-service")]
337 pub(crate) fn event_service_sse_no_odata_id(&self) -> bool {
338 self.root.vendor.as_ref().and_then(Option::as_ref).is_some()
339 }
340
341 fn expand_is_not_working_properly(root: &SchemaServiceRoot) -> bool {
345 Self::is_ami_viking(root)
346 }
347
348 fn is_ami_viking(root: &SchemaServiceRoot) -> bool {
349 root.vendor
350 .as_ref()
351 .and_then(Option::as_ref)
352 .is_some_and(|v| v == "AMI")
353 && root
354 .redfish_version
355 .as_ref()
356 .is_some_and(|version| version == "1.11.0")
357 }
358}
359
360impl<B: Bmc> Resource for ServiceRoot<B> {
361 fn resource_ref(&self) -> &ResourceSchema {
362 &self.root.as_ref().base
363 }
364}