use crate::core::Bmc;
use crate::core::EntityTypeRef as _;
use crate::core::ModificationResponse;
use crate::core::NavProperty;
use crate::core::RedfishSettings as _;
use crate::hardware_id::HardwareIdRef;
use crate::hardware_id::Manufacturer as HardwareIdManufacturer;
use crate::hardware_id::Model as HardwareIdModel;
use crate::hardware_id::PartNumber as HardwareIdPartNumber;
use crate::hardware_id::SerialNumber as HardwareIdSerialNumber;
use crate::patch_support::Payload;
use crate::patch_support::ReadPatchFn;
use crate::resource::PowerState;
use crate::schema::computer_system::ComputerSystem as ComputerSystemSchema;
use crate::Error;
use crate::NvBmc;
use crate::Resource;
use crate::ResourceSchema;
use serde::Serialize;
use std::convert::identity;
use std::sync::Arc;
use tagged_types::TaggedType;
#[cfg(feature = "bios")]
use crate::computer_system::Bios;
#[cfg(feature = "boot-options")]
use crate::computer_system::BootOptionCollection;
#[cfg(feature = "memory")]
use crate::computer_system::Memory;
#[cfg(feature = "processors")]
use crate::computer_system::Processor;
#[cfg(feature = "secure-boot")]
use crate::computer_system::SecureBoot;
#[cfg(feature = "storages")]
use crate::computer_system::Storage;
#[cfg(feature = "ethernet-interfaces")]
use crate::ethernet_interface::EthernetInterfaceCollection;
#[cfg(feature = "log-services")]
use crate::log_service::LogService;
#[cfg(feature = "oem-lenovo")]
use crate::oem::lenovo::computer_system::LenovoComputerSystem;
#[cfg(feature = "oem-nvidia-bluefield")]
use crate::oem::nvidia::bluefield::nvidia_computer_system::NvidiaComputerSystem;
#[doc(hidden)]
pub enum ComputerSystemTag {}
pub type Manufacturer<T> = HardwareIdManufacturer<T, ComputerSystemTag>;
pub type Model<T> = HardwareIdModel<T, ComputerSystemTag>;
pub type PartNumber<T> = HardwareIdPartNumber<T, ComputerSystemTag>;
pub type SerialNumber<T> = HardwareIdSerialNumber<T, ComputerSystemTag>;
pub type Sku<T> = TaggedType<T, ComputerSystemSkuTag>;
#[doc(hidden)]
#[derive(tagged_types::Tag)]
#[implement(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[transparent(Debug, Display, FromStr, Serialize, Deserialize)]
#[capability(inner_access, cloned)]
pub enum ComputerSystemSkuTag {}
pub type BootOptionReference<T> = TaggedType<T, BootOptionReferenceTag>;
#[doc(hidden)]
#[derive(tagged_types::Tag)]
#[implement(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[transparent(Debug, Display, FromStr, Serialize, Deserialize)]
#[capability(inner_access, cloned)]
pub enum BootOptionReferenceTag {}
#[derive(Serialize)]
struct BootPatch {
#[serde(rename = "BootOrder")]
boot_order: Vec<BootOptionReference<String>>,
}
#[derive(Serialize)]
struct ComputerSystemBootOrderUpdate {
#[serde(rename = "Boot")]
boot: BootPatch,
}
pub struct ComputerSystem<B: Bmc> {
#[allow(dead_code)] bmc: NvBmc<B>,
data: Arc<ComputerSystemSchema>,
}
impl<B: Bmc> ComputerSystem<B> {
pub(crate) async fn new(
bmc: &NvBmc<B>,
nav: &NavProperty<ComputerSystemSchema>,
read_patch_fn: Option<&ReadPatchFn>,
) -> Result<Self, Error<B>> {
if let Some(read_patch_fn) = read_patch_fn {
Payload::get(bmc.as_ref(), nav, read_patch_fn.as_ref()).await
} else {
nav.get(bmc.as_ref()).await.map_err(Error::Bmc)
}
.map(|data| Self {
bmc: bmc.clone(),
data,
})
}
#[must_use]
pub fn raw(&self) -> Arc<ComputerSystemSchema> {
self.data.clone()
}
#[must_use]
pub fn hardware_id(&self) -> HardwareIdRef<'_, ComputerSystemTag> {
HardwareIdRef {
manufacturer: self
.data
.manufacturer
.as_ref()
.and_then(Option::as_deref)
.map(Manufacturer::new),
model: self
.data
.model
.as_ref()
.and_then(Option::as_deref)
.map(Model::new),
part_number: self
.data
.part_number
.as_ref()
.and_then(Option::as_deref)
.map(PartNumber::new),
serial_number: self
.data
.serial_number
.as_ref()
.and_then(Option::as_deref)
.map(SerialNumber::new),
}
}
#[must_use]
pub fn sku(&self) -> Option<Sku<&str>> {
self.data
.sku
.as_ref()
.and_then(Option::as_ref)
.map(String::as_str)
.map(Sku::new)
}
#[must_use]
pub fn power_state(&self) -> Option<PowerState> {
self.data.power_state.and_then(identity)
}
#[must_use]
pub fn boot_order(&self) -> Option<Vec<BootOptionReference<&str>>> {
self.data
.as_ref()
.boot
.as_ref()
.and_then(|boot| boot.boot_order.as_ref().and_then(Option::as_ref))
.map(|v| {
v.iter()
.map(String::as_str)
.map(BootOptionReference::new)
.collect::<Vec<_>>()
})
}
pub async fn set_boot_order(
&self,
boot_order: Vec<BootOptionReference<String>>,
) -> Result<Option<Self>, Error<B>> {
let update = ComputerSystemBootOrderUpdate {
boot: BootPatch { boot_order },
};
let settings = self.data.settings_object();
let update_odata = settings
.as_ref()
.map_or_else(|| self.data.odata_id(), |settings| settings.odata_id());
match self
.bmc
.as_ref()
.update::<_, NavProperty<ComputerSystemSchema>>(update_odata, None, &update)
.await
.map_err(Error::Bmc)?
{
ModificationResponse::Entity(nav) => {
let data = nav.get(self.bmc.as_ref()).await.map_err(Error::Bmc)?;
Ok(Some(Self {
bmc: self.bmc.clone(),
data,
}))
}
ModificationResponse::Task(_) | ModificationResponse::Empty => Ok(None),
}
}
#[cfg(feature = "bios")]
pub async fn bios(&self) -> Result<Option<Bios<B>>, Error<B>> {
if let Some(bios_ref) = &self.data.bios {
Bios::new(&self.bmc, bios_ref).await.map(Some)
} else {
Ok(None)
}
}
#[cfg(feature = "processors")]
pub async fn processors(&self) -> Result<Option<Vec<Processor<B>>>, Error<B>> {
if let Some(processors_ref) = &self.data.processors {
let processors_collection = self.bmc.expand_property(processors_ref).await?;
let mut processors = Vec::new();
for m in &processors_collection.members {
processors.push(Processor::new(&self.bmc, m).await?);
}
Ok(Some(processors))
} else {
Ok(None)
}
}
#[cfg(feature = "secure-boot")]
pub async fn secure_boot(&self) -> Result<Option<SecureBoot<B>>, Error<B>> {
if let Some(secure_boot_ref) = &self.data.secure_boot {
SecureBoot::new(&self.bmc, secure_boot_ref).await.map(Some)
} else {
Ok(None)
}
}
#[cfg(feature = "storages")]
pub async fn storage_controllers(&self) -> Result<Option<Vec<Storage<B>>>, Error<B>> {
if let Some(storage_ref) = &self.data.storage {
let storage_collection = self.bmc.expand_property(storage_ref).await?;
let mut storage_controllers = Vec::new();
for m in &storage_collection.members {
storage_controllers.push(Storage::new(&self.bmc, m).await?);
}
Ok(Some(storage_controllers))
} else {
Ok(None)
}
}
#[cfg(feature = "memory")]
pub async fn memory_modules(&self) -> Result<Option<Vec<Memory<B>>>, Error<B>> {
if let Some(memory_ref) = &self.data.memory {
let memory_collection = self.bmc.expand_property(memory_ref).await?;
let mut memory_modules = Vec::new();
for m in &memory_collection.members {
memory_modules.push(Memory::new(&self.bmc, m).await?);
}
Ok(Some(memory_modules))
} else {
Ok(None)
}
}
#[cfg(feature = "log-services")]
pub async fn log_services(&self) -> Result<Option<Vec<LogService<B>>>, Error<B>> {
if let Some(log_services_ref) = &self.data.log_services {
let log_services_collection = log_services_ref
.get(self.bmc.as_ref())
.await
.map_err(Error::Bmc)?;
let mut log_services = Vec::new();
for m in &log_services_collection.members {
log_services.push(LogService::new(&self.bmc, m).await?);
}
Ok(Some(log_services))
} else {
Ok(None)
}
}
#[cfg(feature = "ethernet-interfaces")]
pub async fn ethernet_interfaces(
&self,
) -> Result<Option<EthernetInterfaceCollection<B>>, Error<B>> {
if let Some(p) = &self.data.ethernet_interfaces {
EthernetInterfaceCollection::new(&self.bmc, p)
.await
.map(Some)
} else {
Ok(None)
}
}
#[cfg(feature = "boot-options")]
pub async fn boot_options(&self) -> Result<Option<BootOptionCollection<B>>, Error<B>> {
if let Some(p) = &self
.data
.boot
.as_ref()
.and_then(|v| v.boot_options.as_ref())
{
BootOptionCollection::new(&self.bmc, p).await.map(Some)
} else {
Ok(None)
}
}
#[cfg(feature = "oem-nvidia-bluefield")]
pub async fn oem_nvidia_bluefield(&self) -> Result<Option<NvidiaComputerSystem<B>>, Error<B>> {
if let Some(oem) = self.data.base.base.oem.as_ref() {
NvidiaComputerSystem::new(&self.bmc, oem).await
} else {
Ok(None)
}
}
#[cfg(feature = "oem-lenovo")]
pub fn oem_lenovo(&self) -> Result<Option<LenovoComputerSystem<B>>, Error<B>> {
LenovoComputerSystem::new(&self.bmc, &self.data)
}
}
impl<B: Bmc> Resource for ComputerSystem<B> {
fn resource_ref(&self) -> &ResourceSchema {
&self.data.as_ref().base
}
}