-
Notifications
You must be signed in to change notification settings - Fork 99
change: update NICo to use RMS fw object management API #1861
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
anunna0
wants to merge
20
commits into
NVIDIA:main
Choose a base branch
from
anunna0:RMS_fw_object_management
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
d8db201
Updated to use RMS fw object management API
anunna0 fee8068
fixed mock rms
anunna0 1f35d88
fix two failing tests
anunna0 afb6587
renamed rack-firmware to firmware_object
anunna0 b95b7f2
fix lint failure
anunna0 77ed51d
update NVOS update to use switch inventory
anunna0 151f48f
cleaned up reference to rack-firmware
anunna0 bbb4f6e
remove dead code
anunna0 909791f
Merge branch 'main' into RMS_fw_object_management
anunna0 97cc023
Merge branch 'main' into RMS_fw_object_management
anunna0 63254ea
Merge branch 'main' into RMS_fw_object_management
anunna0 fd40e53
remove all firmware object management APIs
anunna0 a817566
updated CM API, handler, state machine, to use new RMS ApplyFirmwareO…
anunna0 9695036
fixed wiring for maintenance
anunna0 a3ce0a8
Merge branch 'main' into RMS_fw_object_management
anunna0 29d2939
error response improvements
anunna0 11b69ba
re-enabled default to prod
anunna0 8d3741a
addressed review comments
anunna0 f2cd488
Merge branch 'main' into RMS_fw_object_management
anunna0 909990a
Merge origin/main into RMS_fw_object_management
anunna0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,12 +15,15 @@ | |
| * limitations under the License. | ||
| */ | ||
|
|
||
| use std::path::PathBuf; | ||
|
|
||
| use clap::{Args as ClapArgs, Parser, Subcommand}; | ||
|
|
||
| use crate::component_manager::common::{ | ||
| ComputeTrayComponentArg, MachineTargetArgs, NvSwitchComponentArg, PowerShelfComponentArg, | ||
| PowerShelfTargetArgs, RackTargetArgs, SwitchTargetArgs, | ||
| }; | ||
| use crate::errors::{CarbideCliError, CarbideCliResult}; | ||
|
|
||
| #[derive(Parser, Debug)] | ||
| pub struct Args { | ||
|
|
@@ -48,8 +51,11 @@ pub struct SwitchArgs { | |
| #[clap(flatten)] | ||
| pub ids: SwitchTargetArgs, | ||
|
|
||
| #[clap(long = "target-version", help = "Firmware target version")] | ||
| pub target_version: String, | ||
| #[clap(flatten)] | ||
| pub firmware_source: FirmwareSourceArgs, | ||
|
|
||
| #[clap(long = "force-update", help = "Force firmware update when supported")] | ||
| pub force_update: bool, | ||
|
|
||
| #[clap( | ||
| long = "component", | ||
|
|
@@ -68,6 +74,9 @@ pub struct PowerShelfArgs { | |
| #[clap(long = "target-version", help = "Firmware target version")] | ||
| pub target_version: String, | ||
|
|
||
| #[clap(long = "force-update", help = "Force firmware update when supported")] | ||
| pub force_update: bool, | ||
|
|
||
| #[clap( | ||
| long = "component", | ||
| value_enum, | ||
|
|
@@ -82,8 +91,11 @@ pub struct ComputeTrayArgs { | |
| #[clap(flatten)] | ||
| pub ids: MachineTargetArgs, | ||
|
|
||
| #[clap(long = "target-version", help = "Firmware target version")] | ||
| pub target_version: String, | ||
| #[clap(flatten)] | ||
| pub firmware_source: FirmwareSourceArgs, | ||
|
|
||
| #[clap(long = "force-update", help = "Force firmware update when supported")] | ||
| pub force_update: bool, | ||
|
|
||
| #[clap( | ||
| long = "component", | ||
|
|
@@ -99,32 +111,114 @@ pub struct RackArgs { | |
| #[clap(flatten)] | ||
| pub ids: RackTargetArgs, | ||
|
|
||
| #[clap(long = "target-version", help = "Firmware target version")] | ||
| pub target_version: String, | ||
| #[clap(flatten)] | ||
| pub firmware_source: FirmwareSourceArgs, | ||
|
|
||
| #[clap(long = "force-update", help = "Force firmware update when supported")] | ||
| pub force_update: bool, | ||
| } | ||
|
|
||
| impl From<Args> for rpc::forge::UpdateComponentFirmwareRequest { | ||
| fn from(args: Args) -> Self { | ||
| #[derive(ClapArgs, Debug)] | ||
| pub struct FirmwareSourceArgs { | ||
| #[clap( | ||
| long = "target-version", | ||
| help = "Firmware target version for legacy direct-update paths" | ||
| )] | ||
| pub target_version: Option<String>, | ||
|
|
||
| #[clap( | ||
| long = "sot-json-file", | ||
| value_name = "PATH", | ||
| help = "SOT JSON file for RMS ApplyFirmwareObjectFromJSON" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for backends supporting SOT JSON |
||
| )] | ||
| pub sot_json_file: Option<PathBuf>, | ||
|
|
||
| #[clap( | ||
| long = "access-token", | ||
| help = "Artifact access token; required with --sot-json-file" | ||
| )] | ||
| pub access_token: Option<String>, | ||
| } | ||
|
|
||
| fn resolve_firmware_source( | ||
| source: FirmwareSourceArgs, | ||
| ) -> CarbideCliResult<(String, Option<String>)> { | ||
| match ( | ||
| source.target_version, | ||
| source.sot_json_file, | ||
| source.access_token, | ||
| ) { | ||
| (Some(_), Some(_), _) => Err(CarbideCliError::ChooseOneError( | ||
| "--target-version", | ||
| "--sot-json-file", | ||
| )), | ||
| (None, None, _) => Err(CarbideCliError::RequireOneError( | ||
| "--target-version", | ||
| "--sot-json-file", | ||
| )), | ||
| (Some(_), None, Some(_)) => Err(CarbideCliError::GenericError( | ||
| "--access-token requires --sot-json-file".to_string(), | ||
| )), | ||
| (Some(target_version), None, None) => { | ||
| if target_version.trim().is_empty() { | ||
| Err(CarbideCliError::GenericError( | ||
| "--target-version must not be empty".to_string(), | ||
| )) | ||
| } else { | ||
| Ok((target_version, None)) | ||
| } | ||
| } | ||
| (None, Some(sot_json_file), access_token) => { | ||
| let token = access_token.ok_or_else(|| { | ||
| CarbideCliError::GenericError( | ||
| "--access-token is required with --sot-json-file".to_string(), | ||
| ) | ||
| })?; | ||
| if token.trim().is_empty() { | ||
| return Err(CarbideCliError::GenericError( | ||
| "--access-token must not be empty".to_string(), | ||
| )); | ||
| } | ||
|
|
||
| let config_json = std::fs::read_to_string(sot_json_file)?; | ||
| serde_json::from_str::<serde_json::Value>(&config_json)?; | ||
| Ok((config_json, Some(token))) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl TryFrom<Args> for rpc::forge::UpdateComponentFirmwareRequest { | ||
| type Error = CarbideCliError; | ||
|
|
||
| fn try_from(args: Args) -> CarbideCliResult<Self> { | ||
| match args.target { | ||
| Target::Switch(target) => Self { | ||
| target_version: target.target_version, | ||
| target: Some( | ||
| rpc::forge::update_component_firmware_request::Target::Switches( | ||
| rpc::forge::UpdateSwitchFirmwareTarget { | ||
| switch_ids: Some(target.ids.into()), | ||
| components: target | ||
| .components | ||
| .into_iter() | ||
| .map(|component| { | ||
| rpc::forge::NvSwitchComponent::from(component) as i32 | ||
| }) | ||
| .collect(), | ||
| }, | ||
| Target::Switch(target) => { | ||
| let (target_version, access_token) = | ||
| resolve_firmware_source(target.firmware_source)?; | ||
| Ok(Self { | ||
| target_version, | ||
| access_token, | ||
| force_update: target.force_update, | ||
| target: Some( | ||
| rpc::forge::update_component_firmware_request::Target::Switches( | ||
| rpc::forge::UpdateSwitchFirmwareTarget { | ||
| switch_ids: Some(target.ids.into()), | ||
| components: target | ||
| .components | ||
| .into_iter() | ||
| .map(|component| { | ||
| rpc::forge::NvSwitchComponent::from(component) as i32 | ||
| }) | ||
| .collect(), | ||
| }, | ||
| ), | ||
| ), | ||
| ), | ||
| }, | ||
| Target::PowerShelf(target) => Self { | ||
| }) | ||
| } | ||
| Target::PowerShelf(target) => Ok(Self { | ||
| target_version: target.target_version, | ||
| access_token: None, | ||
| force_update: target.force_update, | ||
| target: Some( | ||
| rpc::forge::update_component_firmware_request::Target::PowerShelves( | ||
| rpc::forge::UpdatePowerShelfFirmwareTarget { | ||
|
|
@@ -139,34 +233,120 @@ impl From<Args> for rpc::forge::UpdateComponentFirmwareRequest { | |
| }, | ||
| ), | ||
| ), | ||
| }, | ||
| Target::ComputeTray(target) => Self { | ||
| target_version: target.target_version, | ||
| target: Some( | ||
| rpc::forge::update_component_firmware_request::Target::ComputeTrays( | ||
| rpc::forge::UpdateComputeTrayFirmwareTarget { | ||
| machine_ids: Some(target.ids.into()), | ||
| components: target | ||
| .components | ||
| .into_iter() | ||
| .map(|component| { | ||
| rpc::forge::ComputeTrayComponent::from(component) as i32 | ||
| }) | ||
| .collect(), | ||
| }, | ||
| }), | ||
| Target::ComputeTray(target) => { | ||
| let (target_version, access_token) = | ||
| resolve_firmware_source(target.firmware_source)?; | ||
| Ok(Self { | ||
| target_version, | ||
| access_token, | ||
| force_update: target.force_update, | ||
| target: Some( | ||
| rpc::forge::update_component_firmware_request::Target::ComputeTrays( | ||
| rpc::forge::UpdateComputeTrayFirmwareTarget { | ||
| machine_ids: Some(target.ids.into()), | ||
| components: target | ||
| .components | ||
| .into_iter() | ||
| .map(|component| { | ||
| rpc::forge::ComputeTrayComponent::from(component) as i32 | ||
| }) | ||
| .collect(), | ||
| }, | ||
| ), | ||
| ), | ||
| ), | ||
| }, | ||
| Target::Rack(target) => Self { | ||
| target_version: target.target_version, | ||
| target: Some( | ||
| rpc::forge::update_component_firmware_request::Target::Racks( | ||
| rpc::forge::UpdateRackFirmwareTarget { | ||
| rack_ids: Some(target.ids.into()), | ||
| }, | ||
| }) | ||
| } | ||
| Target::Rack(target) => { | ||
| let (target_version, access_token) = | ||
| resolve_firmware_source(target.firmware_source)?; | ||
| Ok(Self { | ||
| target_version, | ||
| access_token, | ||
| force_update: target.force_update, | ||
| target: Some( | ||
| rpc::forge::update_component_firmware_request::Target::Racks( | ||
| rpc::forge::UpdateFirmwareObjectTarget { | ||
| rack_ids: Some(target.ids.into()), | ||
| }, | ||
| ), | ||
| ), | ||
| ), | ||
| }, | ||
| }) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| fn temp_sot_file(contents: &str) -> PathBuf { | ||
| let path = std::env::temp_dir().join(format!( | ||
| "bmm-sot-{}-{}.json", | ||
| std::process::id(), | ||
| std::time::SystemTime::now() | ||
| .duration_since(std::time::UNIX_EPOCH) | ||
| .expect("system time before unix epoch") | ||
| .as_nanos() | ||
| )); | ||
| std::fs::write(&path, contents).expect("write test SOT JSON"); | ||
| path | ||
| } | ||
|
|
||
| #[test] | ||
| fn target_version_source_uses_legacy_version() { | ||
| let (target_version, access_token) = resolve_firmware_source(FirmwareSourceArgs { | ||
| target_version: Some("fw-1.0".to_string()), | ||
| sot_json_file: None, | ||
| access_token: None, | ||
| }) | ||
| .expect("legacy source should resolve"); | ||
|
|
||
| assert_eq!(target_version, "fw-1.0"); | ||
| assert_eq!(access_token, None); | ||
| } | ||
|
|
||
| #[test] | ||
| fn sot_json_source_reads_file_and_sets_access_token() { | ||
| let path = temp_sot_file(r#"{"Id":"fw-object"}"#); | ||
|
|
||
| let (target_version, access_token) = resolve_firmware_source(FirmwareSourceArgs { | ||
| target_version: None, | ||
| sot_json_file: Some(path.clone()), | ||
| access_token: Some("token".to_string()), | ||
| }) | ||
| .expect("SOT source should resolve"); | ||
|
|
||
| assert_eq!(target_version, r#"{"Id":"fw-object"}"#); | ||
| assert_eq!(access_token.as_deref(), Some("token")); | ||
| let _ = std::fs::remove_file(path); | ||
| } | ||
|
|
||
| #[test] | ||
| fn access_token_without_sot_json_file_is_rejected() { | ||
| let err = resolve_firmware_source(FirmwareSourceArgs { | ||
| target_version: Some("fw-1.0".to_string()), | ||
| sot_json_file: None, | ||
| access_token: Some("token".to_string()), | ||
| }) | ||
| .expect_err("access token without SOT JSON should fail"); | ||
|
|
||
| assert!(err.to_string().contains("--access-token requires")); | ||
| } | ||
|
|
||
| #[test] | ||
| fn invalid_sot_json_file_is_rejected() { | ||
| let path = temp_sot_file("not-json"); | ||
|
|
||
| let err = resolve_firmware_source(FirmwareSourceArgs { | ||
| target_version: None, | ||
| sot_json_file: Some(path.clone()), | ||
| access_token: Some("token".to_string()), | ||
| }) | ||
| .expect_err("invalid SOT JSON should fail"); | ||
|
|
||
| assert!(matches!(err, CarbideCliError::JsonError(_))); | ||
| let _ = std::fs::remove_file(path); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for backends do not support SOT JSON.