nv_redfish/chassis/
item.rs1use crate::hardware_id::HardwareIdRef;
17use crate::hardware_id::Manufacturer as HardwareIdManufacturer;
18use crate::hardware_id::Model as HardwareIdModel;
19use crate::hardware_id::PartNumber as HardwareIdPartNumber;
20use crate::hardware_id::SerialNumber as HardwareIdSerialNumber;
21use crate::patch_support::JsonValue;
22use crate::patch_support::Payload;
23use crate::patch_support::ReadPatchFn;
24use crate::schema::redfish::chassis::Chassis as ChassisSchema;
25use crate::Error;
26use crate::NvBmc;
27use crate::Resource;
28use crate::ResourceSchema;
29use crate::ServiceRoot;
30use nv_redfish_core::bmc::Bmc;
31use nv_redfish_core::NavProperty;
32use std::sync::Arc;
33
34#[cfg(feature = "assembly")]
35use crate::assembly::Assembly;
36#[cfg(feature = "network-adapters")]
37use crate::chassis::NetworkAdapter;
38#[cfg(feature = "network-adapters")]
39use crate::chassis::NetworkAdapterCollection;
40#[cfg(feature = "power")]
41use crate::chassis::Power;
42#[cfg(feature = "power-supplies")]
43use crate::chassis::PowerSupply;
44#[cfg(feature = "thermal")]
45use crate::chassis::Thermal;
46#[cfg(feature = "log-services")]
47use crate::log_service::LogService;
48#[cfg(feature = "oem-nvidia-baseboard")]
49use crate::oem::nvidia::baseboard::NvidiaCbcChassis;
50#[cfg(feature = "pcie-devices")]
51use crate::pcie_device::PcieDeviceCollection;
52#[cfg(feature = "sensors")]
53use crate::schema::redfish::sensor::Sensor as SchemaSensor;
54#[cfg(feature = "sensors")]
55use crate::sensor::extract_environment_sensors;
56#[cfg(feature = "sensors")]
57use crate::sensor::SensorRef;
58
59#[doc(hidden)]
60pub enum ChassisTag {}
61
62pub type Manufacturer<T> = HardwareIdManufacturer<T, ChassisTag>;
64
65pub type Model<T> = HardwareIdModel<T, ChassisTag>;
67
68pub type PartNumber<T> = HardwareIdPartNumber<T, ChassisTag>;
70
71pub type SerialNumber<T> = HardwareIdSerialNumber<T, ChassisTag>;
73
74pub struct Config {
75 read_patch_fn: Option<ReadPatchFn>,
76}
77
78impl Config {
79 pub fn new<B: Bmc>(root: &ServiceRoot<B>) -> Self {
80 let mut patches = Vec::new();
81 if root.bug_invalid_contained_by_fields() {
82 patches.push(remove_invalid_contained_by_fields);
83 }
84 let read_patch_fn = if patches.is_empty() {
85 None
86 } else {
87 let read_patch_fn: ReadPatchFn =
88 Arc::new(move |v| patches.iter().fold(v, |acc, f| f(acc)));
89 Some(read_patch_fn)
90 };
91 Self { read_patch_fn }
92 }
93}
94
95pub struct Chassis<B: Bmc> {
99 #[allow(dead_code)] bmc: NvBmc<B>,
101 data: Arc<ChassisSchema>,
102 #[allow(dead_code)] config: Arc<Config>,
104}
105
106impl<B: Bmc> Chassis<B> {
107 pub(crate) async fn new(
109 bmc: &NvBmc<B>,
110 nav: &NavProperty<ChassisSchema>,
111 config: Arc<Config>,
112 ) -> Result<Self, Error<B>> {
113 if let Some(read_patch_fn) = &config.read_patch_fn {
114 Payload::get(bmc.as_ref(), nav, read_patch_fn.as_ref()).await
115 } else {
116 nav.get(bmc.as_ref()).await.map_err(Error::Bmc)
117 }
118 .map(|data| Self {
119 bmc: bmc.clone(),
120 data,
121 config,
122 })
123 }
124
125 #[must_use]
130 pub fn raw(&self) -> Arc<ChassisSchema> {
131 self.data.clone()
132 }
133
134 #[must_use]
136 pub fn hardware_id(&self) -> HardwareIdRef<'_, ChassisTag> {
137 HardwareIdRef {
138 manufacturer: self
139 .data
140 .manufacturer
141 .as_ref()
142 .and_then(Option::as_ref)
143 .map(Manufacturer::new),
144 model: self
145 .data
146 .model
147 .as_ref()
148 .and_then(Option::as_ref)
149 .map(Model::new),
150 part_number: self
151 .data
152 .part_number
153 .as_ref()
154 .and_then(Option::as_ref)
155 .map(PartNumber::new),
156 serial_number: self
157 .data
158 .serial_number
159 .as_ref()
160 .and_then(Option::as_ref)
161 .map(SerialNumber::new),
162 }
163 }
164
165 #[cfg(feature = "assembly")]
171 pub async fn assembly(&self) -> Result<Assembly<B>, Error<B>> {
172 let assembly_ref = self
173 .data
174 .assembly
175 .as_ref()
176 .ok_or(Error::AssemblyNotAvailable)?;
177 Assembly::new(&self.bmc, assembly_ref).await
178 }
179
180 #[cfg(feature = "power-supplies")]
189 pub async fn power_supplies(&self) -> Result<Vec<PowerSupply<B>>, Error<B>> {
190 if let Some(ps) = &self.data.power_subsystem {
191 let ps = ps.get(self.bmc.as_ref()).await.map_err(Error::Bmc)?;
192 if let Some(supplies) = &ps.power_supplies {
193 let supplies = &self.bmc.expand_property(supplies).await?.members;
194 let mut power_supplies = Vec::with_capacity(supplies.len());
195 for power_supply in supplies {
196 power_supplies.push(PowerSupply::new(&self.bmc, power_supply).await?);
197 }
198 return Ok(power_supplies);
199 }
200 }
201
202 Ok(Vec::new())
203 }
204
205 #[cfg(feature = "power")]
215 pub async fn power(&self) -> Result<Option<Power<B>>, Error<B>> {
216 if let Some(power_ref) = &self.data.power {
217 Ok(Some(Power::new(&self.bmc, power_ref).await?))
218 } else {
219 Ok(None)
220 }
221 }
222
223 #[cfg(feature = "thermal")]
233 pub async fn thermal(&self) -> Result<Option<Thermal<B>>, Error<B>> {
234 if let Some(thermal_ref) = &self.data.thermal {
235 Thermal::new(&self.bmc, thermal_ref).await.map(Some)
236 } else {
237 Ok(None)
238 }
239 }
240
241 #[cfg(feature = "network-adapters")]
249 pub async fn network_adapters(&self) -> Result<Vec<NetworkAdapter<B>>, Error<B>> {
250 let network_adapters_collection_ref = &self
251 .data
252 .network_adapters
253 .as_ref()
254 .ok_or(Error::NetworkAdaptersNotAvailable)?;
255 NetworkAdapterCollection::new(&self.bmc, network_adapters_collection_ref)
256 .await?
257 .members()
258 .await
259 }
260
261 #[cfg(feature = "log-services")]
269 pub async fn log_services(&self) -> Result<Vec<LogService<B>>, Error<B>> {
270 let log_services_ref = self
271 .data
272 .log_services
273 .as_ref()
274 .ok_or(Error::LogServiceNotAvailable)?;
275
276 let log_services_collection = log_services_ref
277 .get(self.bmc.as_ref())
278 .await
279 .map_err(Error::Bmc)?;
280
281 let mut log_services = Vec::new();
282 for m in &log_services_collection.members {
283 log_services.push(LogService::new(&self.bmc, m).await?);
284 }
285
286 Ok(log_services)
287 }
288
289 #[cfg(feature = "sensors")]
297 pub async fn environment_sensors(&self) -> Result<Vec<SensorRef<B>>, Error<B>> {
298 let sensor_refs = if let Some(env_ref) = &self.data.environment_metrics {
299 extract_environment_sensors(env_ref, self.bmc.as_ref()).await?
300 } else {
301 Vec::new()
302 };
303
304 Ok(sensor_refs
305 .into_iter()
306 .map(|r| SensorRef::new(self.bmc.clone(), r))
307 .collect())
308 }
309
310 #[cfg(feature = "sensors")]
320 pub async fn sensors(&self) -> Result<Vec<SensorRef<B>>, Error<B>> {
321 if let Some(sensors_collection) = &self.data.sensors {
322 let sc = sensors_collection
323 .get(self.bmc.as_ref())
324 .await
325 .map_err(Error::Bmc)?;
326 let mut sensor_data = Vec::with_capacity(sc.members.len());
327 for sensor in &sc.members {
328 sensor_data.push(SensorRef::new(
329 self.bmc.clone(),
330 NavProperty::<SchemaSensor>::new_reference(sensor.id().clone()),
331 ));
332 }
333 Ok(sensor_data)
334 } else {
335 Err(Error::SensorsNotAvailable)
336 }
337 }
338
339 #[cfg(feature = "pcie-devices")]
347 pub async fn pcie_devices(&self) -> Result<PcieDeviceCollection<B>, crate::Error<B>> {
348 let p = self
349 .data
350 .pcie_devices
351 .as_ref()
352 .ok_or(crate::Error::PcieDevicesNotAvailable)?;
353 PcieDeviceCollection::new(&self.bmc, p).await
354 }
355
356 #[cfg(feature = "oem-nvidia-baseboard")]
364 pub fn oem_nvidia_baseboard_cbc(&self) -> Result<NvidiaCbcChassis<B>, Error<B>> {
365 self.data
366 .base
367 .base
368 .oem
369 .as_ref()
370 .ok_or(Error::NvidiaCbcChassisNotAvailable)
371 .and_then(NvidiaCbcChassis::new)
372 }
373}
374
375impl<B: Bmc> Resource for Chassis<B> {
376 fn resource_ref(&self) -> &ResourceSchema {
377 &self.data.as_ref().base
378 }
379}
380
381fn remove_invalid_contained_by_fields(mut v: JsonValue) -> JsonValue {
382 if let JsonValue::Object(ref mut obj) = v {
383 if let Some(JsonValue::Object(ref mut links_obj)) = obj.get_mut("Links") {
384 if let Some(JsonValue::Object(ref mut contained_by_obj)) =
385 links_obj.get_mut("ContainedBy")
386 {
387 contained_by_obj.retain(|k, _| k == "@odata.id");
388 }
389 }
390 }
391 v
392}