Skip to content

Commit 4b7f32b

Browse files
committed
feat: wiring in RackHarwareType with rack-firmware management
This wires in the new `RackHardwareType` and `RackHardwareClass` in with the `rack-firmware` management flows, such that the flow is now: ``` admin-cli rack-firmware create <rack-hardware-type> ... ``` ...to associate a given rack firmware bundle with an expected rack type. And then, when you: ``` admin-cli rack-firmare apply <rack-id> .... ``` ...the backend will now check to make sure the: - The `RackFirmwareType` of the given `RackId` (based on its configured `RackCapabilitiesSet`) matches the configured `RackFirmwareType` for the firmware. - The `RackHardwareClass` of the given `RackId` (based on its configured `RackCapabilitesSet`) matches the configured `firmware_type` (`<dev|prod>`) for the firmware. I also introduced a `RackHardwareType::Any` in here, as if to say "I don't care what the hardware is, just apply the firmware", e.g. ``` admin-cli rack-firmware create any .... ``` ...which will associate that firmware with `RackFirmwareType::Any`, so when you go to `rack-firmware apply`, it will apply to `::Any` hardware. Improved the `rack-firmware list` API call as well with a filtering. Tests included! Signed-off-by: Chet Nichols III <chetn@nvidia.com>
1 parent b210840 commit 4b7f32b

16 files changed

Lines changed: 309 additions & 60 deletions

File tree

crates/admin-cli/src/rack_firmware/create/args.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@
1818
use std::path::PathBuf;
1919

2020
use ::rpc::admin_cli::CarbideCliError;
21+
use ::rpc::forge::RackHardwareType;
2122
use clap::Parser;
2223

2324
#[derive(Parser, Debug)]
2425
pub struct Args {
25-
#[clap(help = "Path to JSON configuration file")]
26+
#[clap(help = "Rack hardware type for this firmware configuration.")]
27+
pub rack_hardware_type: RackHardwareType,
28+
#[clap(help = "Path to JSON configuration file.")]
2629
pub json_file: PathBuf,
27-
#[clap(help = "Artifactory token for downloading firmware files")]
30+
#[clap(help = "Artifactory token for downloading firmware files.")]
2831
pub artifactory_token: String,
2932
}
3033

@@ -40,11 +43,12 @@ impl TryFrom<Args> for rpc::forge::RackFirmwareCreateRequest {
4043
))
4144
})?;
4245

43-
// Check that the JSON is valid
46+
// Check that the JSON is valid.
4447
serde_json::from_str::<serde_json::Value>(&config_json)
4548
.map_err(|e| CarbideCliError::GenericError(format!("Invalid JSON in file: {}", e)))?;
4649

4750
Ok(Self {
51+
rack_hardware_type: args.rack_hardware_type as i32,
4852
config_json,
4953
artifactory_token: args.artifactory_token,
5054
})

crates/admin-cli/src/rack_firmware/create/cmd.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
*/
1717

1818
use ::rpc::admin_cli::{CarbideCliError, OutputFormat};
19+
use ::rpc::forge::RackHardwareType;
20+
use prettytable::{Table, row};
1921

2022
use super::args::Args;
2123
use crate::rpc::ApiClient;
@@ -31,10 +33,15 @@ pub async fn create(
3133
if format == OutputFormat::Json {
3234
println!("{}", serde_json::to_string_pretty(&result)?);
3335
} else {
34-
println!("Created Rack firmware configuration:");
35-
println!(" ID: {}", result.id);
36-
println!(" Available: {}", result.available);
37-
println!(" Created: {}", result.created);
36+
let hw_type = RackHardwareType::try_from(result.rack_hardware_type)
37+
.unwrap_or_default()
38+
.as_str_name();
39+
let mut table = Table::new();
40+
table.add_row(row!["ID", result.id]);
41+
table.add_row(row!["Hardware Type", hw_type]);
42+
table.add_row(row!["Available", result.available]);
43+
table.add_row(row!["Created", result.created]);
44+
table.printstd();
3845
}
3946

4047
Ok(())

crates/admin-cli/src/rack_firmware/get/cmd.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
*/
1717

1818
use ::rpc::admin_cli::{CarbideCliError, OutputFormat};
19-
use prettytable::{Cell, Row, Table};
19+
use ::rpc::forge::RackHardwareType;
20+
use prettytable::{Cell, Row, Table, row};
2021

2122
use super::args::Args;
2223
use crate::rpc::ApiClient;
@@ -42,13 +43,18 @@ pub async fn get(
4243
if format == OutputFormat::Json {
4344
println!("{}", serde_json::to_string_pretty(&result)?);
4445
} else {
45-
println!("Rack Firmware Configuration:");
46-
println!(" ID: {}", result.id);
47-
println!(" Available: {}", result.available);
48-
println!(" Created: {}", result.created);
49-
println!(" Updated: {}", result.updated);
50-
51-
// Display parsed firmware components
46+
let hw_type = RackHardwareType::try_from(result.rack_hardware_type)
47+
.unwrap_or_default()
48+
.as_str_name();
49+
let mut table = Table::new();
50+
table.add_row(row!["ID", result.id]);
51+
table.add_row(row!["Hardware Type", hw_type]);
52+
table.add_row(row!["Available", result.available]);
53+
table.add_row(row!["Created", result.created]);
54+
table.add_row(row!["Updated", result.updated]);
55+
table.printstd();
56+
57+
// Display parsed firmware components.
5258
if !result.parsed_components.is_empty() && result.parsed_components != "{}" {
5359
if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(&result.parsed_components)
5460
&& let Some(devices) = parsed.get("devices").and_then(|d| d.as_object())

crates/admin-cli/src/rack_firmware/history/cmd.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
use ::rpc::admin_cli::{CarbideCliError, OutputFormat};
19+
use ::rpc::forge::RackHardwareType;
1920
use prettytable::{Cell, Row, Table};
2021

2122
use super::args::Args;
@@ -46,16 +47,21 @@ pub async fn history(
4647
table.set_titles(Row::new(vec![
4748
Cell::new("Rack ID"),
4849
Cell::new("Firmware ID"),
50+
Cell::new("Hardware Type"),
4951
Cell::new("Firmware Type"),
5052
Cell::new("Applied At"),
5153
Cell::new("Available"),
5254
]));
5355

5456
for (rack_id, records) in &result.histories {
5557
for record in &records.records {
58+
let hw_type = RackHardwareType::try_from(record.rack_hardware_type)
59+
.unwrap_or_default()
60+
.as_str_name();
5661
table.add_row(Row::new(vec![
5762
Cell::new(rack_id),
5863
Cell::new(&record.firmware_id),
64+
Cell::new(hw_type),
5965
Cell::new(&record.firmware_type),
6066
Cell::new(&record.applied_at),
6167
Cell::new(&record.firmware_available.to_string()),

crates/admin-cli/src/rack_firmware/list/args.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,25 @@
1515
* limitations under the License.
1616
*/
1717

18+
use ::rpc::forge::RackHardwareType;
1819
use clap::Parser;
1920

2021
#[derive(Parser, Debug)]
2122
pub struct Args {
22-
#[clap(long, help = "Show only available configurations")]
23+
#[clap(long, help = "Show only available configurations.")]
2324
pub only_available: bool,
25+
#[clap(help = "Filter by rack hardware type.")]
26+
pub rack_hardware_type: Option<RackHardwareType>,
2427
}
2528

26-
impl From<Args> for rpc::forge::RackFirmwareListRequest {
29+
impl From<Args> for rpc::forge::RackFirmwareSearchFilter {
2730
fn from(args: Args) -> Self {
2831
Self {
2932
only_available: args.only_available,
33+
rack_hardware_type: args
34+
.rack_hardware_type
35+
.map(|t| t as i32)
36+
.unwrap_or(RackHardwareType::Unspecified as i32),
3037
}
3138
}
3239
}

crates/admin-cli/src/rack_firmware/list/cmd.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
use ::rpc::admin_cli::{CarbideCliError, OutputFormat};
19+
use ::rpc::forge::RackHardwareType;
1920
use prettytable::{Cell, Row, Table};
2021

2122
use super::args::Args;
@@ -36,14 +37,19 @@ pub async fn list(
3637
let mut table = Table::new();
3738
table.set_titles(Row::new(vec![
3839
Cell::new("ID"),
40+
Cell::new("Hardware Type"),
3941
Cell::new("Available"),
4042
Cell::new("Created"),
4143
Cell::new("Updated"),
4244
]));
4345

4446
for config in result.configs {
47+
let hw_type = RackHardwareType::try_from(config.rack_hardware_type)
48+
.unwrap_or_default()
49+
.as_str_name();
4550
table.add_row(Row::new(vec![
4651
Cell::new(&config.id),
52+
Cell::new(hw_type),
4753
Cell::new(&config.available.to_string()),
4854
Cell::new(&config.created),
4955
Cell::new(&config.updated),

crates/admin-cli/src/rack_firmware/tests.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
// Argument Parsing - Ensure required/optional arg combinations parse correctly.
2525

2626
use clap::{CommandFactory, Parser};
27+
use rpc::forge::RackHardwareType;
2728

2829
use super::*;
2930

@@ -71,6 +72,43 @@ fn parse_list_only_available() {
7172
}
7273
}
7374

75+
// parse_list_with_hardware_type_filter ensures list parses with a
76+
// hardware type filter.
77+
#[test]
78+
fn parse_list_with_hardware_type_filter() {
79+
let cmd = Cmd::try_parse_from(["rack-firmware", "list", "any"])
80+
.expect("should parse list with hardware type filter");
81+
82+
match cmd {
83+
Cmd::List(args) => {
84+
assert!(!args.only_available);
85+
assert_eq!(args.rack_hardware_type, Some(RackHardwareType::Any));
86+
}
87+
_ => panic!("expected List variant"),
88+
}
89+
}
90+
91+
// parse_create_with_hardware_type ensures create parses with
92+
// hardware type as first argument.
93+
#[test]
94+
fn parse_create_with_hardware_type() {
95+
let cmd = Cmd::try_parse_from([
96+
"rack-firmware",
97+
"create",
98+
"any",
99+
"/tmp/test.json",
100+
"test-token",
101+
])
102+
.expect("should parse create with hardware type");
103+
104+
match cmd {
105+
Cmd::Create(args) => {
106+
assert_eq!(args.rack_hardware_type, RackHardwareType::Any);
107+
}
108+
_ => panic!("expected Create variant"),
109+
}
110+
}
111+
74112
// parse_create_missing_args_fails ensures create fails without required args.
75113
#[test]
76114
fn parse_create_missing_args_fails() {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- Add rack_hardware_type to rack_firmware table.
2+
-- Defaults existing rows to 'any' (matches any rack hardware type).
3+
ALTER TABLE rack_firmware ADD COLUMN rack_hardware_type VARCHAR(128) NOT NULL DEFAULT 'any';
4+
CREATE INDEX idx_rack_firmware_rack_hardware_type ON rack_firmware(rack_hardware_type);
5+
6+
-- Add rack_hardware_type to rack_firmware_apply_history table.
7+
ALTER TABLE rack_firmware_apply_history ADD COLUMN rack_hardware_type VARCHAR(128) NOT NULL DEFAULT 'any';

0 commit comments

Comments
 (0)