Skip to content

Commit 48f7670

Browse files
committed
feat: [ami] implement boot_first
Signed-off-by: Krish Dandiwala <kdandiwala@nvidia.com>
1 parent ea1aa92 commit 48f7670

File tree

1 file changed

+65
-31
lines changed

1 file changed

+65
-31
lines changed

src/ami.rs

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,12 @@ impl Redfish for Bmc {
513513
}
514514

515515
async fn boot_first(&self, target: Boot) -> Result<(), RedfishError> {
516-
self.s.boot_first(target).await
516+
let alias = match target {
517+
Boot::Pxe => "Pxe",
518+
Boot::HardDisk => "Hdd",
519+
Boot::UefiHttp => "UefiHttp",
520+
};
521+
self.set_boot_order(alias).await
517522
}
518523

519524
/// AMI BMC requires If-Match header for boot order changes
@@ -738,23 +743,7 @@ impl Redfish for Bmc {
738743
mac_address: &str,
739744
) -> Result<Option<String>, RedfishError> {
740745
let mac = mac_address.to_uppercase();
741-
let system = self.get_system().await?;
742-
743-
let boot_options_id =
744-
system
745-
.boot
746-
.boot_options
747-
.clone()
748-
.ok_or_else(|| RedfishError::MissingKey {
749-
key: "boot.boot_options".to_string(),
750-
url: system.odata.odata_id.clone(),
751-
})?;
752-
753-
let all_boot_options: Vec<BootOption> = self
754-
.get_collection(boot_options_id)
755-
.await
756-
.and_then(|c| c.try_get::<BootOption>())?
757-
.members;
746+
let (system, all_boot_options) = self.get_system_and_boot_options().await?;
758747

759748
let target = all_boot_options.iter().find(|opt| {
760749
let display = opt.display_name.to_uppercase();
@@ -970,19 +959,10 @@ impl Bmc {
970959
self.s.client.patch_with_if_match(&url, data).await
971960
}
972961

973-
/// Get expected and actual first boot option for checking boot order setup.
974-
///
975-
/// AMI boot option format example:
976-
/// DisplayName: "[Slot2]UEFI: HTTP IPv4 Nvidia Network Adapter - B8:E9:24:17:6D:72 P1"
977-
/// BootOptionReference: "Boot0001"
978-
///
979-
async fn get_expected_and_actual_first_boot_option(
962+
async fn get_system_and_boot_options(
980963
&self,
981-
boot_interface_mac: &str,
982-
) -> Result<(Option<String>, Option<String>), RedfishError> {
983-
let mac = boot_interface_mac.to_uppercase();
964+
) -> Result<(ComputerSystem, Vec<BootOption>), RedfishError> {
984965
let system = self.get_system().await?;
985-
986966
let boot_options_id =
987967
system
988968
.boot
@@ -992,14 +972,68 @@ impl Bmc {
992972
key: "boot.boot_options".to_string(),
993973
url: system.odata.odata_id.clone(),
994974
})?;
995-
996975
let all_boot_options: Vec<BootOption> = self
997976
.get_collection(boot_options_id)
998977
.await
999978
.and_then(|c| c.try_get::<BootOption>())?
1000979
.members;
980+
Ok((system, all_boot_options))
981+
}
982+
983+
/// Finds the first boot option matching the given alias and moves it to the front
984+
/// of the boot order.
985+
async fn set_boot_order(&self, alias: &str) -> Result<(), RedfishError> {
986+
let (system, all_boot_options) = self.get_system_and_boot_options().await?;
987+
988+
let target = all_boot_options
989+
.iter()
990+
.find(|opt| opt.alias.as_deref() == Some(alias));
991+
992+
let target_ref = target
993+
.ok_or_else(|| {
994+
let all_names: Vec<_> = all_boot_options
995+
.iter()
996+
.map(|b| {
997+
format!(
998+
"{}: {} (alias={})",
999+
b.boot_option_reference,
1000+
b.display_name,
1001+
b.alias.as_deref().unwrap_or("none")
1002+
)
1003+
})
1004+
.collect();
1005+
RedfishError::MissingBootOption(format!(
1006+
"No boot option with alias {:?} found; available: {:#?}",
1007+
alias, all_names
1008+
))
1009+
})?
1010+
.boot_option_reference
1011+
.clone();
1012+
1013+
let mut boot_order = system.boot.boot_order;
1014+
1015+
if boot_order.first() == Some(&target_ref) {
1016+
return Ok(());
1017+
}
1018+
1019+
boot_order.retain(|id| id != &target_ref);
1020+
boot_order.insert(0, target_ref);
1021+
self.change_boot_order(boot_order).await
1022+
}
1023+
1024+
/// Get expected and actual first boot option for checking boot order setup.
1025+
///
1026+
/// AMI boot option format example:
1027+
/// DisplayName: "[Slot2]UEFI: HTTP IPv4 Nvidia Network Adapter - B8:E9:24:17:6D:72 P1"
1028+
/// BootOptionReference: "Boot0001"
1029+
///
1030+
async fn get_expected_and_actual_first_boot_option(
1031+
&self,
1032+
boot_interface_mac: &str,
1033+
) -> Result<(Option<String>, Option<String>), RedfishError> {
1034+
let mac = boot_interface_mac.to_uppercase();
1035+
let (system, all_boot_options) = self.get_system_and_boot_options().await?;
10011036

1002-
// Find expected boot option display name (HTTP IPv4 with matching MAC)
10031037
let expected_first_boot_option = all_boot_options
10041038
.iter()
10051039
.find(|opt| {

0 commit comments

Comments
 (0)