Skip to content

Commit 68f612c

Browse files
authored
[MGS] Add endpoints to get/set host startup options (#2284)
1 parent 542970f commit 68f612c

File tree

4 files changed

+291
-3
lines changed

4 files changed

+291
-3
lines changed

gateway-cli/src/main.rs

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use anyhow::Context;
1010
use anyhow::Result;
1111
use clap::Parser;
1212
use clap::Subcommand;
13+
use gateway_client::types::HostStartupOptions;
1314
use gateway_client::types::IgnitionCommand;
1415
use gateway_client::types::PowerState;
1516
use gateway_client::types::SpComponentFirmwareSlot;
@@ -105,7 +106,27 @@ enum Command {
105106
/// Target SP (e.g., 'sled/7', 'switch/1', 'power/0')
106107
#[clap(value_parser = sp_identifier_from_str, action)]
107108
sp: SpIdentifier,
108-
options: Option<u64>,
109+
/// Set startup options to the bitwise-OR of all further options
110+
#[clap(long)]
111+
set: bool,
112+
#[clap(long, requires = "set")]
113+
phase2_recovery: bool,
114+
#[clap(long, requires = "set")]
115+
kbm: bool,
116+
#[clap(long, requires = "set")]
117+
bootrd: bool,
118+
#[clap(long, requires = "set")]
119+
prom: bool,
120+
#[clap(long, requires = "set")]
121+
kmdb: bool,
122+
#[clap(long, requires = "set")]
123+
kmdb_boot: bool,
124+
#[clap(long, requires = "set")]
125+
boot_ramdisk: bool,
126+
#[clap(long, requires = "set")]
127+
boot_net: bool,
128+
#[clap(long, requires = "set")]
129+
startup_verbose: bool,
109130
},
110131

111132
/// Ask SP for its inventory.
@@ -366,8 +387,41 @@ async fn main() -> Result<()> {
366387
dumper.dump(&info)?;
367388
}
368389
}
369-
Command::StartupOptions { .. } => {
370-
todo!("missing MGS endpoint");
390+
Command::StartupOptions {
391+
sp,
392+
set,
393+
phase2_recovery,
394+
kbm,
395+
bootrd,
396+
prom,
397+
kmdb,
398+
kmdb_boot,
399+
boot_ramdisk,
400+
boot_net,
401+
startup_verbose,
402+
} => {
403+
if set {
404+
let options = HostStartupOptions {
405+
phase2_recovery_mode: phase2_recovery,
406+
kbm,
407+
bootrd,
408+
prom,
409+
kmdb,
410+
kmdb_boot,
411+
boot_ramdisk,
412+
boot_net,
413+
verbose: startup_verbose,
414+
};
415+
client
416+
.sp_startup_options_set(sp.type_, sp.slot, &options)
417+
.await?;
418+
} else {
419+
let info = client
420+
.sp_startup_options_get(sp.type_, sp.slot)
421+
.await?
422+
.into_inner();
423+
dumper.dump(&info)?;
424+
}
371425
}
372426
Command::Inventory { sp } => {
373427
let info =

gateway/src/http_entrypoints.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,21 @@ impl Display for SpIdentifier {
276276
}
277277
}
278278

279+
#[derive(
280+
Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema,
281+
)]
282+
pub struct HostStartupOptions {
283+
pub phase2_recovery_mode: bool,
284+
pub kbm: bool,
285+
pub bootrd: bool,
286+
pub prom: bool,
287+
pub kmdb: bool,
288+
pub kmdb_boot: bool,
289+
pub boot_ramdisk: bool,
290+
pub boot_net: bool,
291+
pub verbose: bool,
292+
}
293+
279294
/// See RFD 81.
280295
///
281296
/// This enum only lists power states the SP is able to control; higher power
@@ -512,6 +527,51 @@ async fn sp_get(
512527
Ok(HttpResponseOk(info))
513528
}
514529

530+
/// Get host startup options for a sled
531+
///
532+
/// This endpoint will currently fail for any `SpType` other than
533+
/// `SpType::Sled`.
534+
#[endpoint {
535+
method = GET,
536+
path = "/sp/{type}/{slot}/startup-options",
537+
}]
538+
async fn sp_startup_options_get(
539+
rqctx: RequestContext<Arc<ServerContext>>,
540+
path: Path<PathSp>,
541+
) -> Result<HttpResponseOk<HostStartupOptions>, HttpError> {
542+
let apictx = rqctx.context();
543+
let mgmt_switch = &apictx.mgmt_switch;
544+
let sp = mgmt_switch.sp(path.into_inner().sp.into())?;
545+
546+
let options = sp.get_startup_options().await.map_err(SpCommsError::from)?;
547+
548+
Ok(HttpResponseOk(options.into()))
549+
}
550+
551+
/// Set host startup options for a sled
552+
///
553+
/// This endpoint will currently fail for any `SpType` other than
554+
/// `SpType::Sled`.
555+
#[endpoint {
556+
method = POST,
557+
path = "/sp/{type}/{slot}/startup-options",
558+
}]
559+
async fn sp_startup_options_set(
560+
rqctx: RequestContext<Arc<ServerContext>>,
561+
path: Path<PathSp>,
562+
body: TypedBody<HostStartupOptions>,
563+
) -> Result<HttpResponseUpdatedNoContent, HttpError> {
564+
let apictx = rqctx.context();
565+
let mgmt_switch = &apictx.mgmt_switch;
566+
let sp = mgmt_switch.sp(path.into_inner().sp.into())?;
567+
568+
sp.set_startup_options(body.into_inner().into())
569+
.await
570+
.map_err(SpCommsError::from)?;
571+
572+
Ok(HttpResponseUpdatedNoContent {})
573+
}
574+
515575
/// List components of an SP
516576
///
517577
/// A component is a distinct entity under an SP's direct control. This lists
@@ -975,6 +1035,8 @@ pub fn api() -> GatewayApiDescription {
9751035
) -> Result<(), String> {
9761036
api.register(sp_list)?;
9771037
api.register(sp_get)?;
1038+
api.register(sp_startup_options_get)?;
1039+
api.register(sp_startup_options_set)?;
9781040
api.register(sp_reset)?;
9791041
api.register(sp_power_state_get)?;
9801042
api.register(sp_power_state_set)?;

gateway/src/http_entrypoints/conversions.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
//! Conversions between externally-defined types and HTTP / JsonSchema types.
88
9+
use super::HostStartupOptions;
910
use super::IgnitionCommand;
1011
use super::PowerState;
1112
use super::SpComponentInfo;
@@ -21,6 +22,7 @@ use super::UpdatePreparationProgress;
2122
use crate::error::SpCommsError;
2223
use dropshot::HttpError;
2324
use gateway_messages::SpComponent;
25+
use gateway_messages::StartupOptions;
2426
use gateway_messages::UpdateStatus;
2527
use gateway_sp_comms::error::CommunicationError;
2628
use std::str;
@@ -270,3 +272,39 @@ impl From<gateway_sp_comms::SpInventory> for SpComponentList {
270272
Self { components: inv.devices.into_iter().map(Into::into).collect() }
271273
}
272274
}
275+
276+
impl From<HostStartupOptions> for StartupOptions {
277+
fn from(mgs_opt: HostStartupOptions) -> Self {
278+
let mut opt = StartupOptions::empty();
279+
opt.set(
280+
StartupOptions::PHASE2_RECOVERY_MODE,
281+
mgs_opt.phase2_recovery_mode,
282+
);
283+
opt.set(StartupOptions::STARTUP_KBM, mgs_opt.kbm);
284+
opt.set(StartupOptions::STARTUP_BOOTRD, mgs_opt.bootrd);
285+
opt.set(StartupOptions::STARTUP_PROM, mgs_opt.prom);
286+
opt.set(StartupOptions::STARTUP_KMDB, mgs_opt.kmdb);
287+
opt.set(StartupOptions::STARTUP_KMDB_BOOT, mgs_opt.kmdb_boot);
288+
opt.set(StartupOptions::STARTUP_BOOT_RAMDISK, mgs_opt.boot_ramdisk);
289+
opt.set(StartupOptions::STARTUP_BOOT_NET, mgs_opt.boot_net);
290+
opt.set(StartupOptions::STARTUP_VERBOSE, mgs_opt.verbose);
291+
opt
292+
}
293+
}
294+
295+
impl From<StartupOptions> for HostStartupOptions {
296+
fn from(opt: StartupOptions) -> Self {
297+
Self {
298+
phase2_recovery_mode: opt
299+
.contains(StartupOptions::PHASE2_RECOVERY_MODE),
300+
kbm: opt.contains(StartupOptions::STARTUP_KBM),
301+
bootrd: opt.contains(StartupOptions::STARTUP_BOOTRD),
302+
prom: opt.contains(StartupOptions::STARTUP_PROM),
303+
kmdb: opt.contains(StartupOptions::STARTUP_KMDB),
304+
kmdb_boot: opt.contains(StartupOptions::STARTUP_KMDB_BOOT),
305+
boot_ramdisk: opt.contains(StartupOptions::STARTUP_BOOT_RAMDISK),
306+
boot_net: opt.contains(StartupOptions::STARTUP_BOOT_NET),
307+
verbose: opt.contains(StartupOptions::STARTUP_VERBOSE),
308+
}
309+
}
310+
}

openapi/gateway.json

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,97 @@
836836
}
837837
}
838838
}
839+
},
840+
"/sp/{type}/{slot}/startup-options": {
841+
"get": {
842+
"summary": "Get host startup options for a sled",
843+
"description": "This endpoint will currently fail for any `SpType` other than `SpType::Sled`.",
844+
"operationId": "sp_startup_options_get",
845+
"parameters": [
846+
{
847+
"in": "path",
848+
"name": "slot",
849+
"required": true,
850+
"schema": {
851+
"type": "integer",
852+
"format": "uint32",
853+
"minimum": 0
854+
}
855+
},
856+
{
857+
"in": "path",
858+
"name": "type",
859+
"required": true,
860+
"schema": {
861+
"$ref": "#/components/schemas/SpType"
862+
}
863+
}
864+
],
865+
"responses": {
866+
"200": {
867+
"description": "successful operation",
868+
"content": {
869+
"application/json": {
870+
"schema": {
871+
"$ref": "#/components/schemas/HostStartupOptions"
872+
}
873+
}
874+
}
875+
},
876+
"4XX": {
877+
"$ref": "#/components/responses/Error"
878+
},
879+
"5XX": {
880+
"$ref": "#/components/responses/Error"
881+
}
882+
}
883+
},
884+
"post": {
885+
"summary": "Set host startup options for a sled",
886+
"description": "This endpoint will currently fail for any `SpType` other than `SpType::Sled`.",
887+
"operationId": "sp_startup_options_set",
888+
"parameters": [
889+
{
890+
"in": "path",
891+
"name": "slot",
892+
"required": true,
893+
"schema": {
894+
"type": "integer",
895+
"format": "uint32",
896+
"minimum": 0
897+
}
898+
},
899+
{
900+
"in": "path",
901+
"name": "type",
902+
"required": true,
903+
"schema": {
904+
"$ref": "#/components/schemas/SpType"
905+
}
906+
}
907+
],
908+
"requestBody": {
909+
"content": {
910+
"application/json": {
911+
"schema": {
912+
"$ref": "#/components/schemas/HostStartupOptions"
913+
}
914+
}
915+
},
916+
"required": true
917+
},
918+
"responses": {
919+
"204": {
920+
"description": "resource updated"
921+
},
922+
"4XX": {
923+
"$ref": "#/components/responses/Error"
924+
},
925+
"5XX": {
926+
"$ref": "#/components/responses/Error"
927+
}
928+
}
929+
}
839930
}
840931
},
841932
"components": {
@@ -883,6 +974,49 @@
883974
"sha256_hash"
884975
]
885976
},
977+
"HostStartupOptions": {
978+
"type": "object",
979+
"properties": {
980+
"boot_net": {
981+
"type": "boolean"
982+
},
983+
"boot_ramdisk": {
984+
"type": "boolean"
985+
},
986+
"bootrd": {
987+
"type": "boolean"
988+
},
989+
"kbm": {
990+
"type": "boolean"
991+
},
992+
"kmdb": {
993+
"type": "boolean"
994+
},
995+
"kmdb_boot": {
996+
"type": "boolean"
997+
},
998+
"phase2_recovery_mode": {
999+
"type": "boolean"
1000+
},
1001+
"prom": {
1002+
"type": "boolean"
1003+
},
1004+
"verbose": {
1005+
"type": "boolean"
1006+
}
1007+
},
1008+
"required": [
1009+
"boot_net",
1010+
"boot_ramdisk",
1011+
"bootrd",
1012+
"kbm",
1013+
"kmdb",
1014+
"kmdb_boot",
1015+
"phase2_recovery_mode",
1016+
"prom",
1017+
"verbose"
1018+
]
1019+
},
8861020
"PowerState": {
8871021
"description": "See RFD 81.\n\nThis enum only lists power states the SP is able to control; higher power states are controlled by ignition.",
8881022
"type": "string",

0 commit comments

Comments
 (0)