diff --git a/crates/admin-cli/src/component_manager/update_firmware/args.rs b/crates/admin-cli/src/component_manager/update_firmware/args.rs index 70a6482f81..fb1e418813 100644 --- a/crates/admin-cli/src/component_manager/update_firmware/args.rs +++ b/crates/admin-cli/src/component_manager/update_firmware/args.rs @@ -58,6 +58,12 @@ pub struct SwitchArgs { help = "NVLink switch components to update; omit to update all supported components" )] pub components: Vec, + + #[clap( + long = "bypass-state-controller", + help = "Bypass the state controller and dispatch directly to the component backend" + )] + pub bypass_state_controller: bool, } #[derive(ClapArgs, Debug)] @@ -75,6 +81,12 @@ pub struct PowerShelfArgs { help = "Power shelf components to update; omit to update all supported components" )] pub components: Vec, + + #[clap( + long = "bypass-state-controller", + help = "Bypass the state controller and dispatch directly to the component backend" + )] + pub bypass_state_controller: bool, } #[derive(ClapArgs, Debug)] @@ -92,6 +104,12 @@ pub struct ComputeTrayArgs { help = "Compute tray components to update; omit to update all supported components" )] pub components: Vec, + + #[clap( + long = "bypass-state-controller", + help = "Bypass the state controller and dispatch directly to the component backend" + )] + pub bypass_state_controller: bool, } #[derive(ClapArgs, Debug)] @@ -108,6 +126,7 @@ impl From for rpc::forge::UpdateComponentFirmwareRequest { match args.target { Target::Switch(target) => Self { target_version: target.target_version, + bypass_state_controller: target.bypass_state_controller, target: Some( rpc::forge::update_component_firmware_request::Target::Switches( rpc::forge::UpdateSwitchFirmwareTarget { @@ -125,6 +144,7 @@ impl From for rpc::forge::UpdateComponentFirmwareRequest { }, Target::PowerShelf(target) => Self { target_version: target.target_version, + bypass_state_controller: target.bypass_state_controller, target: Some( rpc::forge::update_component_firmware_request::Target::PowerShelves( rpc::forge::UpdatePowerShelfFirmwareTarget { @@ -142,6 +162,7 @@ impl From for rpc::forge::UpdateComponentFirmwareRequest { }, Target::ComputeTray(target) => Self { target_version: target.target_version, + bypass_state_controller: target.bypass_state_controller, target: Some( rpc::forge::update_component_firmware_request::Target::ComputeTrays( rpc::forge::UpdateComputeTrayFirmwareTarget { @@ -159,6 +180,7 @@ impl From for rpc::forge::UpdateComponentFirmwareRequest { }, Target::Rack(target) => Self { target_version: target.target_version, + bypass_state_controller: false, target: Some( rpc::forge::update_component_firmware_request::Target::Racks( rpc::forge::UpdateRackFirmwareTarget { diff --git a/crates/api/src/handlers/component_manager.rs b/crates/api/src/handlers/component_manager.rs index 48cac3ebf4..ee2b0e97f0 100644 --- a/crates/api/src/handlers/component_manager.rs +++ b/crates/api/src/handlers/component_manager.rs @@ -873,6 +873,7 @@ pub(crate) async fn component_power_control( let req = request.into_inner(); let action = map_power_action(req.action)?; + let bypass_state_controller = req.bypass_state_controller; let target = req .target @@ -880,6 +881,12 @@ pub(crate) async fn component_power_control( let (results, exploration_ips) = match target { rpc::component_power_control_request::Target::SwitchIds(list) => { + if cm.nv_switch_use_state_controller && !bypass_state_controller { + // TODO: implement state controller path for switch power control + return Err(Status::unimplemented( + "switch power control through the state controller is not yet supported", + )); + } let endpoints = resolve_switch_endpoints(api, &list.ids).await?; let mut results: Vec<_> = endpoints @@ -918,6 +925,12 @@ pub(crate) async fn component_power_control( (results, ips) } rpc::component_power_control_request::Target::PowerShelfIds(list) => { + if cm.power_shelf_use_state_controller && !bypass_state_controller { + // TODO: implement state controller path for power shelf power control + return Err(Status::unimplemented( + "power shelf power control through the state controller is not yet supported", + )); + } let endpoints = resolve_power_shelf_endpoints(api, &list.ids).await?; let mut results: Vec<_> = endpoints @@ -956,7 +969,7 @@ pub(crate) async fn component_power_control( (results, ips) } rpc::component_power_control_request::Target::MachineIds(list) => { - if cm.compute_tray_use_state_controller { + if cm.compute_tray_use_state_controller && !bypass_state_controller { // TODO: implement state controller path for compute tray power control return Err(Status::unimplemented( "compute tray power control through the state controller is not yet supported", @@ -1280,6 +1293,7 @@ pub(crate) async fn update_component_firmware( ) -> Result, Status> { log_request_data(&request); let req = request.into_inner(); + let bypass_state_controller = req.bypass_state_controller; let target = req .target @@ -1302,7 +1316,7 @@ pub(crate) async fn update_component_firmware( return Err(Status::invalid_argument("switch_ids must not be empty")); } - if cm.nv_switch_use_state_controller { + if cm.nv_switch_use_state_controller && !bypass_state_controller { component_names = map_nv_switch_component_names(&t.components)?; let mut txn = @@ -1367,7 +1381,7 @@ pub(crate) async fn update_component_firmware( return Err(Status::invalid_argument("machine_ids must not be empty")); } - if cm.compute_tray_use_state_controller { + if cm.compute_tray_use_state_controller && !bypass_state_controller { component_names = map_compute_tray_component_names(&t.components)?; let machine = db::machine::find_one( @@ -1422,6 +1436,12 @@ pub(crate) async fn update_component_firmware( } rpc::update_component_firmware_request::Target::PowerShelves(t) => { let cm = require_component_manager(api)?; + if cm.power_shelf_use_state_controller && !bypass_state_controller { + // TODO: implement state controller path for power shelf firmware updates + return Err(Status::unimplemented( + "power shelf firmware updates through the state controller are not yet supported", + )); + } let list = t .power_shelf_ids .ok_or_else(|| Status::invalid_argument("power_shelf_ids is required"))?; @@ -1454,6 +1474,12 @@ pub(crate) async fn update_component_firmware( power_shelf_results = Some(results); } rpc::update_component_firmware_request::Target::Racks(t) => { + if bypass_state_controller { + // TODO: implement RMS backend direct dispatch for a full rack + return Err(Status::invalid_argument( + "bypass_state_controller is not supported for rack-level firmware updates", + )); + } let list = t .rack_ids .ok_or_else(|| Status::invalid_argument("rack_ids is required"))?; diff --git a/crates/rpc/proto/forge.proto b/crates/rpc/proto/forge.proto index acc106a9d7..a9980f044c 100644 --- a/crates/rpc/proto/forge.proto +++ b/crates/rpc/proto/forge.proto @@ -8063,6 +8063,9 @@ message ComponentPowerControlRequest { PowerShelfIdList power_shelf_ids = 3; } common.SystemPowerControl action = 4; + // When true, bypass the state controller and dispatch directly to the + // component backend. + bool bypass_state_controller = 5; } message ComponentPowerControlResponse { @@ -8145,6 +8148,9 @@ message UpdateComponentFirmwareRequest { UpdateRackFirmwareTarget racks = 5; } string target_version = 4; + // When true, bypass the state controller and dispatch directly to the + // component backend. + bool bypass_state_controller = 6; } message UpdateComponentFirmwareResponse {