Skip to main content

nv_redfish/computer_system/
mod.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
16//! Computer System entities and collections.
17//!
18//! This module provides types for working with Redfish ComputerSystem resources
19//! and their sub-resources like processors, storage, memory, and drives.
20
21mod item;
22
23#[cfg(feature = "bios")]
24pub mod bios;
25#[cfg(feature = "boot-options")]
26pub mod boot_option;
27#[cfg(feature = "storages")]
28pub mod drive;
29#[cfg(feature = "memory")]
30pub mod memory;
31#[cfg(feature = "processors")]
32pub mod processor;
33#[cfg(feature = "secure-boot")]
34pub mod secure_boot;
35#[cfg(feature = "storages")]
36pub mod storage;
37
38use crate::patch_support::CollectionWithPatch;
39use crate::patch_support::FilterFn;
40use crate::patch_support::JsonValue;
41use crate::patch_support::ReadPatchFn;
42use crate::resource::Resource as _;
43use crate::schema::redfish::computer_system::ComputerSystem as ComputerSystemSchema;
44use crate::schema::redfish::computer_system_collection::ComputerSystemCollection as ComputerSystemCollectionSchema;
45use crate::schema::redfish::resource::ResourceCollection;
46use crate::Error;
47use crate::NvBmc;
48use crate::ServiceRoot;
49use nv_redfish_core::Bmc;
50use nv_redfish_core::NavProperty;
51use std::convert::identity;
52use std::sync::Arc;
53
54#[doc(inline)]
55pub use item::BootOptionReference;
56#[doc(inline)]
57pub use item::ComputerSystem;
58
59#[doc(inline)]
60#[cfg(feature = "bios")]
61pub use bios::Bios;
62#[doc(inline)]
63#[cfg(feature = "boot-options")]
64pub use boot_option::BootOption;
65#[doc(inline)]
66#[cfg(feature = "boot-options")]
67pub use boot_option::BootOptionCollection;
68#[doc(inline)]
69#[cfg(feature = "storages")]
70pub use drive::Drive;
71#[doc(inline)]
72#[cfg(feature = "memory")]
73pub use memory::Memory;
74#[doc(inline)]
75#[cfg(feature = "processors")]
76pub use processor::Processor;
77#[doc(inline)]
78#[cfg(feature = "secure-boot")]
79pub use secure_boot::SecureBoot;
80#[doc(inline)]
81#[cfg(feature = "secure-boot")]
82pub use secure_boot::SecureBootCurrentBootType;
83#[doc(inline)]
84#[cfg(feature = "storages")]
85pub use storage::Storage;
86
87/// Computer system collection.
88///
89/// Provides functions to access collection members.
90pub struct SystemCollection<B: Bmc> {
91    bmc: NvBmc<B>,
92    collection: Arc<ComputerSystemCollectionSchema>,
93    read_patch_fn: Option<ReadPatchFn>,
94}
95
96impl<B: Bmc> SystemCollection<B> {
97    pub(crate) async fn new(
98        bmc: &NvBmc<B>,
99        root: &ServiceRoot<B>,
100    ) -> Result<Option<Self>, Error<B>> {
101        let mut patches = Vec::new();
102        let mut filters = Vec::new();
103        if let Some(odata_id_filter) = bmc.quirks.filter_computer_system_odata_ids() {
104            filters.push(Box::new(move |js: &JsonValue| {
105                js.get("@odata.id")
106                    .and_then(|v| v.as_str())
107                    .map(odata_id_filter)
108                    .is_some_and(identity)
109            }));
110        }
111        if bmc.quirks.computer_systems_wrong_last_reset_time() {
112            patches.push(computer_systems_wrong_last_reset_time);
113        }
114        let read_patch_fn = (!patches.is_empty())
115            .then(|| Arc::new(move |v| patches.iter().fold(v, |acc, f| f(acc))) as ReadPatchFn);
116        let filters_fn = (!filters.is_empty())
117            .then(move || Arc::new(move |v: &JsonValue| filters.iter().any(|f| f(v))) as FilterFn);
118
119        if let Some(collection_ref) = &root.root.systems {
120            Self::expand_collection(
121                bmc,
122                collection_ref,
123                read_patch_fn.as_ref(),
124                filters_fn.as_ref(),
125            )
126            .await
127            .map(Some)
128        } else if bmc.quirks.bug_missing_root_nav_properties() {
129            bmc.expand_property(&NavProperty::new_reference(
130                format!("{}/Systems", root.odata_id()).into(),
131            ))
132            .await
133            .map(Some)
134        } else {
135            Ok(None)
136        }
137        .map(|c| {
138            c.map(|collection| Self {
139                bmc: bmc.clone(),
140                collection,
141                read_patch_fn,
142            })
143        })
144    }
145
146    /// List all computer systems available in this BMC.
147    ///
148    /// # Errors
149    ///
150    /// Returns an error if fetching system data fails.
151    pub async fn members(&self) -> Result<Vec<ComputerSystem<B>>, Error<B>> {
152        let mut members = Vec::new();
153        for m in &self.collection.members {
154            members.push(ComputerSystem::new(&self.bmc, m, self.read_patch_fn.as_ref()).await?);
155        }
156        Ok(members)
157    }
158}
159
160impl<B: Bmc> CollectionWithPatch<ComputerSystemCollectionSchema, ComputerSystemSchema, B>
161    for SystemCollection<B>
162{
163    fn convert_patched(
164        base: ResourceCollection,
165        members: Vec<NavProperty<ComputerSystemSchema>>,
166    ) -> ComputerSystemCollectionSchema {
167        ComputerSystemCollectionSchema { base, members }
168    }
169}
170
171// `LastResetTime` is marked as `edm.DateTimeOffset`, but some systems
172// puts "0000-00-00T00:00:00+00:00" as LastResetTime that is not
173// conform to ABNF of the DateTimeOffset. We delete such fields...
174fn computer_systems_wrong_last_reset_time(v: JsonValue) -> JsonValue {
175    if let JsonValue::Object(mut obj) = v {
176        if let Some(JsonValue::String(date)) = obj.get("LastResetTime") {
177            if date.starts_with("0000-00-00") {
178                obj.remove("LastResetTime");
179            }
180        }
181        JsonValue::Object(obj)
182    } else {
183        v
184    }
185}