Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions crates/admin-cli/src/expected_machines/add/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use carbide_utils::has_duplicates;
use carbide_uuid::rack::RackId;
use clap::Parser;
use mac_address::MacAddress;
use rpc::forge::{BmcIpAllocationType, DpuMode, ExpectedHostNic};
use rpc::forge::{BmcIpAllocationType, ExpectedHostNic, HostDpuPolicy};
use serde::{Deserialize, Serialize};

use crate::errors::{CarbideCliError, CarbideCliResult};
Expand Down Expand Up @@ -49,7 +49,7 @@ Pre-allocate a static BMC IP (site-explorer path, like expected switches):
Add a host whose DPU should be treated as a plain NIC:
$ nico-admin-cli expected-machine add --bmc-mac-address 00:11:22:33:44:55 \
--bmc-username admin --bmc-password mypassword --chassis-serial-number sample_serial-1 \
--dpu-mode nic-mode
--dpu-policy use-as-nic

Retain the BMC's auto-allocated DHCP address as a static one (never expires):
$ nico-admin-cli expected-machine add --bmc-mac-address 00:11:22:33:44:55 \
Expand Down Expand Up @@ -165,12 +165,13 @@ pub struct Args {
pub bmc_retain_credentials: Option<bool>,

#[clap(
long = "dpu-mode",
value_name = "DPU_MODE",
long = "dpu-policy",
visible_alias = "dpu-mode",
value_name = "DPU_POLICY",
value_enum,
help = "Per-host DPU operating mode. `dpu-mode` (default): DPUs are managed by NICo; `nic-mode`: DPU hardware present but treated as a plain NIC; `no-dpu`: no DPU hardware at all. Unset defers to the site-wide `[site_explorer] dpu_mode` setting (which itself falls back to `dpu-mode` when not set)."
help = "Per-host DPU policy. `manage` (default): inherit the site policy, which defaults to managing DPUs; `use-as-nic`: configure DPU hardware as plain NICs; `ignore`: do not configure or attach DPU hardware. Unset defers to the site-wide `[site_explorer] dpu_policy` setting. The legacy `--dpu-mode` flag and values remain accepted."
)]
pub dpu_mode: Option<DpuMode>,
pub dpu_policy: Option<HostDpuPolicy>,
Comment thread
coderabbitai[bot] marked this conversation as resolved.

#[clap(
long = "bmc-ip-allocation",
Expand Down Expand Up @@ -229,7 +230,7 @@ impl TryFrom<Args> for rpc::forge::ExpectedMachine {
is_dpf_enabled: value.dpf_enabled,
bmc_ip_address: value.bmc_ip_address.map(|ip| ip.to_string()),
bmc_retain_credentials: value.bmc_retain_credentials,
dpu_mode: value.dpu_mode.map(|m| m as i32),
dpu_mode: value.dpu_policy.map(|policy| policy as i32),
bmc_ip_allocation: value.bmc_ip_allocation.map(|m| m as i32),
host_lifecycle_profile: value.disable_lockdown.map(|dl| {
rpc::forge::HostLifecycleProfile {
Expand Down
56 changes: 51 additions & 5 deletions crates/admin-cli/src/expected_machines/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ pub struct ExpectedMachineJson {
pub bmc_ip_address: Option<String>,
#[serde(default)]
pub bmc_retain_credentials: Option<bool>,
/// Per-host DPU operating mode. None == defer to the site-wide
/// `[site_explorer] dpu_mode` setting (falls back to `DpuMode::DpuMode`
/// if that's also unset).
#[serde(default)]
pub dpu_mode: Option<rpc::forge::DpuMode>,
/// Per-host DPU policy. None == defer to the site-wide
/// `[site_explorer] dpu_policy` setting (falls back to `Manage` if that's
/// also unset). The legacy `dpu_mode` field and values remain accepted.
#[serde(default, alias = "dpu_mode")]
pub dpu_policy: Option<rpc::forge::HostDpuPolicy>,
/// Per-host control over how this BMC's IP is assigned and retained. None ==
/// the server default (`Auto`), which resolves to `fixed` when a
/// `bmc_ip_address` is set and `retained` when it isn't.
Expand All @@ -75,3 +75,49 @@ pub struct _ExpectedMachineMetadata {
pub description: Option<String>,
pub labels: HashMap<String, Option<String>>,
}

#[cfg(test)]
mod tests {
use carbide_test_support::Outcome::*;
use carbide_test_support::scenarios;

use super::*;

#[test]
fn expected_machine_json_deserializes_new_and_legacy_dpu_policy() {
scenarios!(
run = |policy_json| {
let json = format!(
r#"{{
"bmc_mac_address": "AA:BB:CC:DD:EE:FF",
"bmc_username": "root",
"bmc_password": "pass",
"chassis_serial_number": "SN-1"
{policy_json}
}}"#,
);
serde_json::from_str::<ExpectedMachineJson>(&json)
.map(|machine| machine.dpu_policy)
.map_err(drop)
};
"policy omitted" {
"" => Yields(None),
}

"canonical field and value" {
r#", "dpu_policy": "use_as_nic""# =>
Yields(Some(rpc::forge::HostDpuPolicy::UseAsNic)),
}

"legacy field and config value" {
r#", "dpu_mode": "nic_mode""# =>
Yields(Some(rpc::forge::HostDpuPolicy::UseAsNic)),
}

"legacy field and generated Rust value" {
r#", "dpu_mode": "NicMode""# =>
Yields(Some(rpc::forge::HostDpuPolicy::UseAsNic)),
}
);
}
}
21 changes: 11 additions & 10 deletions crates/admin-cli/src/expected_machines/patch/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use carbide_utils::has_duplicates;
use carbide_uuid::rack::RackId;
use clap::{ArgGroup, Parser};
use mac_address::MacAddress;
use rpc::forge::{BmcIpAllocationType, DpuMode};
use rpc::forge::{BmcIpAllocationType, HostDpuPolicy};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

Expand Down Expand Up @@ -47,7 +47,7 @@ use crate::errors::CarbideCliError;
"fallback_dpu_serial_numbers",
"sku_id",
"bmc_ip_address",
"dpu_mode",
"dpu_policy",
"bmc_ip_allocation",
"dpf_enabled",
"host_nics",
Expand All @@ -67,9 +67,9 @@ Rotate the BMC credentials (username and password must be set together):
$ nico-admin-cli expected-machine patch --bmc-mac-address 00:11:22:33:44:55 \
--bmc-username admin --bmc-password mynewpassword

Change the per-host DPU mode:
Change the per-host DPU policy:
$ nico-admin-cli expected-machine patch --bmc-mac-address 00:11:22:33:44:55 \
--dpu-mode no-dpu
--dpu-policy ignore

Retain the BMC's auto-allocated DHCP address as a static one (never expires):
$ nico-admin-cli expected-machine patch --bmc-mac-address 00:11:22:33:44:55 \
Expand Down Expand Up @@ -185,13 +185,14 @@ pub struct Args {
pub bmc_retain_credentials: Option<bool>,

#[clap(
long = "dpu-mode",
value_name = "DPU_MODE",
long = "dpu-policy",
visible_alias = "dpu-mode",
value_name = "DPU_POLICY",
value_enum,
group = "group",
help = "Per-host DPU operating mode. `dpu-mode` (default): DPUs are managed by NICo; `nic-mode`: DPU hardware present but treated as a plain NIC; `no-dpu`: no DPU hardware at all. Unset preserves the existing per-host value."
help = "Per-host DPU policy. `manage`: inherit the site policy, which defaults to managing DPUs; `use-as-nic`: configure DPU hardware as plain NICs; `ignore`: do not configure or attach DPU hardware. Unset preserves the existing per-host value. The legacy `--dpu-mode` flag and values remain accepted."
)]
pub dpu_mode: Option<DpuMode>,
pub dpu_policy: Option<HostDpuPolicy>,

#[clap(
long = "bmc-ip-allocation",
Expand Down Expand Up @@ -241,11 +242,11 @@ impl Args {
&& self.rack_id.is_none()
&& self.dpf_enabled.is_none()
&& self.bmc_ip_address.is_none()
&& self.dpu_mode.is_none()
&& self.dpu_policy.is_none()
&& self.bmc_ip_allocation.is_none()
&& self.host_nics.is_none()
{
return Err(CarbideCliError::GenericError("One of the following options must be specified: bmc-username and bmc-password or chassis-serial-number or fallback-dpu-serial-number or bmc-ip-address or dpu-mode or bmc-ip-allocation or dpf-enabled or host_nics".to_string()));
return Err(CarbideCliError::GenericError("One of the following options must be specified: bmc-username and bmc-password or chassis-serial-number or fallback-dpu-serial-number or bmc-ip-address or dpu-policy or bmc-ip-allocation or dpf-enabled or host_nics".to_string()));
}
if self
.fallback_dpu_serial_numbers
Expand Down
2 changes: 1 addition & 1 deletion crates/admin-cli/src/expected_machines/patch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl Run for Args {
self.dpf_enabled,
self.bmc_ip_address,
self.bmc_retain_credentials,
self.dpu_mode,
self.dpu_policy,
self.bmc_ip_allocation,
self.disable_lockdown
.map(|dl| ::rpc::forge::HostLifecycleProfile {
Expand Down
65 changes: 53 additions & 12 deletions crates/admin-cli/src/expected_machines/show/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ async fn convert_and_print_into_nice_table(
"Pause On Ingestion",
"DPF Enabled",
"Disable Lockdown",
"DPU Mode",
"DPU Policy",
]);

for expected_machine in &expected_machines.expected_machines {
Expand All @@ -157,16 +157,7 @@ async fn convert_and_print_into_nice_table(

let labels = crate::metadata::fmt_labels_as_kv_pairs(expected_machine.metadata.as_ref());

// None on the wire == the DB default (`DpuMode`); fall back to that
// rather than `Unspecified` so `to_possible_value()` produces the
// same kebab-case string the `--dpu-mode` CLI flag accepts.
let dpu_mode_display = expected_machine
.dpu_mode
.and_then(|i| ::rpc::forge::DpuMode::try_from(i).ok())
.unwrap_or(::rpc::forge::DpuMode::DpuMode)
.to_possible_value()
.map(|pv| pv.get_name().to_owned())
.unwrap_or_default();
let dpu_policy_display = dpu_policy_display(expected_machine.dpu_mode);

table.add_row(row![
expected_machine.chassis_serial_number,
Expand Down Expand Up @@ -200,11 +191,61 @@ async fn convert_and_print_into_nice_table(
.and_then(|hlp| hlp.disable_lockdown)
.unwrap_or_default()
.to_string(),
dpu_mode_display,
dpu_policy_display,
]);
}

async_write!(output, "{}", table)?;

Ok(())
}

/// Formats the wire-compatible `DpuMode` field using the canonical host-policy
/// vocabulary. Both an absent value and the protobuf sentinel mean `Manage`.
fn dpu_policy_display(dpu_mode: Option<i32>) -> String {
dpu_mode
.and_then(|value| ::rpc::forge::HostDpuPolicy::try_from(value).ok())
.filter(|policy| *policy != ::rpc::forge::HostDpuPolicy::Unspecified)
.unwrap_or(::rpc::forge::HostDpuPolicy::Manage)
.to_possible_value()
.map(|value| value.get_name().to_owned())
.unwrap_or_default()
}

#[cfg(test)]
mod tests {
use carbide_test_support::value_scenarios;
use rpc::forge::HostDpuPolicy;

use super::dpu_policy_display;

#[test]
fn dpu_policy_display_uses_canonical_policy_vocabulary() {
value_scenarios!(
run = dpu_policy_display;
"missing value defaults to manage" {
None => "manage".to_string(),
}

"protobuf sentinel defaults to manage" {
Some(HostDpuPolicy::Unspecified as i32) => "manage".to_string(),
}

"manage" {
Some(HostDpuPolicy::Manage as i32) => "manage".to_string(),
}

"use as NIC" {
Some(HostDpuPolicy::UseAsNic as i32) => "use-as-nic".to_string(),
}

"ignore" {
Some(HostDpuPolicy::Ignore as i32) => "ignore".to_string(),
}

"unknown value defaults to manage" {
Some(i32::MAX) => "manage".to_string(),
}
);
}
}
Loading
Loading