Skip to content
Merged
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
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions cli/docs/cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -8757,6 +8757,30 @@
}
],
"subcommands": [
{
"name": "recovery-finish",
"about": "Instructs the system that a system recovery operation (\"mupdate\") was",
"long_about": "completed using the software in the specified release\n\nThe system recovery operation is used to bypass the control plane to deploy known-working software when the control plane itself is not functioning or otherwise unable to update itself. When the control plane detects this, it stops making any changes to deployed software to avoid reverting the recovery itself. This operation puts the control plane back in charge of determining what software should be deployed, instructing it that the specified software (which is also what's currently running) is what's supposed to be deployed.\n\nIf the provided version does not match what's currently running, the control plane will continue to avoid changing deployed software until this operation is invoked with the correct version.\n\nThis endpoint should only be called at the direction of Oxide support.",
"args": [
{
"long": "json-body",
"help": "Path to a file that contains the full json body."
},
{
"long": "json-body-template",
"help": "XXX"
},
{
"long": "profile",
"help": "Configuration profile to use for commands",
"global": true
},
{
"long": "system-version",
"help": "Version of the system software to make the target release."
}
]
},
{
"name": "repo",
"args": [
Expand Down
1 change: 1 addition & 0 deletions cli/src/cli_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@ fn xxx<'a>(command: CliCommand) -> Option<&'a str> {
CliCommand::SystemUpdateStatus => Some("system update status"),
CliCommand::SystemUpdateRepositoryList => Some("system update repo list"),
CliCommand::SystemUpdateRepositoryView => Some("system update repo view"),
CliCommand::SystemUpdateRecoveryFinish => Some("system update recovery-finish"),
CliCommand::SystemUpdateRepositoryUpload => None, // Manually implemented

CliCommand::SwitchList => Some("system hardware switch list"),
Expand Down
90 changes: 90 additions & 0 deletions cli/src/generated_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ impl<T: CliConfig> Cli<T> {
}
CliCommand::SystemTimeseriesQuery => Self::cli_system_timeseries_query(),
CliCommand::SystemTimeseriesSchemaList => Self::cli_system_timeseries_schema_list(),
CliCommand::SystemUpdateRecoveryFinish => Self::cli_system_update_recovery_finish(),
CliCommand::SystemUpdateRepositoryList => Self::cli_system_update_repository_list(),
CliCommand::SystemUpdateRepositoryUpload => Self::cli_system_update_repository_upload(),
CliCommand::SystemUpdateRepositoryView => Self::cli_system_update_repository_view(),
Expand Down Expand Up @@ -7973,6 +7974,48 @@ impl<T: CliConfig> Cli<T> {
.about("List timeseries schemas")
}

pub fn cli_system_update_recovery_finish() -> ::clap::Command {
::clap::Command::new("")
.arg(
::clap::Arg::new("system-version")
.long("system-version")
.value_parser(::clap::value_parser!(
types::SetTargetReleaseParamsSystemVersion
))
.required_unless_present("json-body")
.help("Version of the system software to make the target release."),
)
.arg(
::clap::Arg::new("json-body")
.long("json-body")
.value_name("JSON-FILE")
.required(false)
.value_parser(::clap::value_parser!(std::path::PathBuf))
.help("Path to a file that contains the full json body."),
)
.arg(
::clap::Arg::new("json-body-template")
.long("json-body-template")
.action(::clap::ArgAction::SetTrue)
.help("XXX"),
)
.about("Instructs the system that a system recovery operation (\"mupdate\") was")
.long_about(
"completed using the software in the specified release\n\nThe system recovery \
operation is used to bypass the control plane to deploy known-working software \
when the control plane itself is not functioning or otherwise unable to update \
itself. When the control plane detects this, it stops making any changes to \
deployed software to avoid reverting the recovery itself. This operation puts \
the control plane back in charge of determining what software should be \
deployed, instructing it that the specified software (which is also what's \
currently running) is what's supposed to be deployed.\n\nIf the provided version \
does not match what's currently running, the control plane will continue to \
avoid changing deployed software until this operation is invoked with the \
correct version.\n\nThis endpoint should only be called at the direction of \
Oxide support.",
)
}

pub fn cli_system_update_repository_list() -> ::clap::Command {
::clap::Command::new("")
.arg(
Expand Down Expand Up @@ -10078,6 +10121,9 @@ impl<T: CliConfig> Cli<T> {
CliCommand::SystemTimeseriesSchemaList => {
self.execute_system_timeseries_schema_list(matches).await
}
CliCommand::SystemUpdateRecoveryFinish => {
self.execute_system_update_recovery_finish(matches).await
}
CliCommand::SystemUpdateRepositoryList => {
self.execute_system_update_repository_list(matches).await
}
Expand Down Expand Up @@ -19112,6 +19158,40 @@ impl<T: CliConfig> Cli<T> {
}
}

pub async fn execute_system_update_recovery_finish(
&self,
matches: &::clap::ArgMatches,
) -> anyhow::Result<()> {
let mut request = self.client.system_update_recovery_finish();
if let Some(value) =
matches.get_one::<types::SetTargetReleaseParamsSystemVersion>("system-version")
{
request = request.body_map(|body| body.system_version(value.clone()))
}

if let Some(value) = matches.get_one::<std::path::PathBuf>("json-body") {
let body_txt = std::fs::read_to_string(value)
.with_context(|| format!("failed to read {}", value.display()))?;
let body_value = serde_json::from_str::<types::SetTargetReleaseParams>(&body_txt)
.with_context(|| format!("failed to parse {}", value.display()))?;
request = request.body(body_value);
}

self.config
.execute_system_update_recovery_finish(matches, &mut request)?;
let result = request.send().await;
match result {
Ok(r) => {
self.config.success_no_item(&r);
Ok(())
}
Err(r) => {
self.config.error(&r);
Err(anyhow::Error::new(r))
}
}
}

pub async fn execute_system_update_repository_list(
&self,
matches: &::clap::ArgMatches,
Expand Down Expand Up @@ -22992,6 +23072,14 @@ pub trait CliConfig {
Ok(())
}

fn execute_system_update_recovery_finish(
&self,
matches: &::clap::ArgMatches,
request: &mut builder::SystemUpdateRecoveryFinish,
) -> anyhow::Result<()> {
Ok(())
}

fn execute_system_update_repository_list(
&self,
matches: &::clap::ArgMatches,
Expand Down Expand Up @@ -23655,6 +23743,7 @@ pub enum CliCommand {
SystemSubnetPoolUtilizationView,
SystemTimeseriesQuery,
SystemTimeseriesSchemaList,
SystemUpdateRecoveryFinish,
SystemUpdateRepositoryList,
SystemUpdateRepositoryUpload,
SystemUpdateRepositoryView,
Expand Down Expand Up @@ -23970,6 +24059,7 @@ impl CliCommand {
CliCommand::SystemSubnetPoolUtilizationView,
CliCommand::SystemTimeseriesQuery,
CliCommand::SystemTimeseriesSchemaList,
CliCommand::SystemUpdateRecoveryFinish,
CliCommand::SystemUpdateRepositoryList,
CliCommand::SystemUpdateRepositoryUpload,
CliCommand::SystemUpdateRepositoryView,
Expand Down
33 changes: 32 additions & 1 deletion oxide.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://oxide.computer",
"email": "api@oxide.computer"
},
"version": "2026021900.0.0"
"version": "2026022500.0.0"
},
"paths": {
"/device/auth": {
Expand Down Expand Up @@ -12708,6 +12708,37 @@
}
}
},
"/v1/system/update/recovery-finish": {
"put": {
"tags": [
"system/update"
],
"summary": "Instructs the system that a system recovery operation (\"mupdate\") was",
"description": "completed using the software in the specified release\n\nThe system recovery operation is used to bypass the control plane to deploy known-working software when the control plane itself is not functioning or otherwise unable to update itself. When the control plane detects this, it stops making any changes to deployed software to avoid reverting the recovery itself. This operation puts the control plane back in charge of determining what software should be deployed, instructing it that the specified software (which is also what's currently running) is what's supposed to be deployed.\n\nIf the provided version does not match what's currently running, the control plane will continue to avoid changing deployed software until this operation is invoked with the correct version.\n\nThis endpoint should only be called at the direction of Oxide support.",
"operationId": "system_update_recovery_finish",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SetTargetReleaseParams"
}
}
},
"required": true
},
"responses": {
"204": {
"description": "resource updated"
},
"4XX": {
"$ref": "#/components/responses/Error"
},
"5XX": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/v1/system/update/repositories": {
"get": {
"tags": [
Expand Down
75 changes: 75 additions & 0 deletions sdk-httpmock/src/generated_httpmock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19130,6 +19130,60 @@ pub mod operations {
}
}

pub struct SystemUpdateRecoveryFinishWhen(::httpmock::When);
impl SystemUpdateRecoveryFinishWhen {
pub fn new(inner: ::httpmock::When) -> Self {
Self(
inner.method(::httpmock::Method::PUT).path_matches(
regex::Regex::new("^/v1/system/update/recovery-finish$").unwrap(),
),
)
}

pub fn into_inner(self) -> ::httpmock::When {
self.0
}

pub fn body(self, value: &types::SetTargetReleaseParams) -> Self {
Self(self.0.json_body_obj(value))
}
}

pub struct SystemUpdateRecoveryFinishThen(::httpmock::Then);
impl SystemUpdateRecoveryFinishThen {
pub fn new(inner: ::httpmock::Then) -> Self {
Self(inner)
}

pub fn into_inner(self) -> ::httpmock::Then {
self.0
}

pub fn no_content(self) -> Self {
Self(self.0.status(204u16))
}

pub fn client_error(self, status: u16, value: &types::Error) -> Self {
assert_eq!(status / 100u16, 4u16);
Self(
self.0
.status(status)
.header("content-type", "application/json")
.json_body_obj(value),
)
}

pub fn server_error(self, status: u16, value: &types::Error) -> Self {
assert_eq!(status / 100u16, 5u16);
Self(
self.0
.status(status)
.header("content-type", "application/json")
.json_body_obj(value),
)
}
}

pub struct SystemUpdateRepositoryListWhen(::httpmock::When);
impl SystemUpdateRepositoryListWhen {
pub fn new(inner: ::httpmock::When) -> Self {
Expand Down Expand Up @@ -24022,6 +24076,12 @@ pub trait MockServerExt {
operations::SystemTimeseriesSchemaListWhen,
operations::SystemTimeseriesSchemaListThen,
);
fn system_update_recovery_finish<F>(&self, config_fn: F) -> ::httpmock::Mock<'_>
where
F: FnOnce(
operations::SystemUpdateRecoveryFinishWhen,
operations::SystemUpdateRecoveryFinishThen,
);
fn system_update_repository_list<F>(&self, config_fn: F) -> ::httpmock::Mock<'_>
where
F: FnOnce(
Expand Down Expand Up @@ -27559,6 +27619,21 @@ impl MockServerExt for ::httpmock::MockServer {
})
}

fn system_update_recovery_finish<F>(&self, config_fn: F) -> ::httpmock::Mock<'_>
where
F: FnOnce(
operations::SystemUpdateRecoveryFinishWhen,
operations::SystemUpdateRecoveryFinishThen,
),
{
self.mock(|when, then| {
config_fn(
operations::SystemUpdateRecoveryFinishWhen::new(when),
operations::SystemUpdateRecoveryFinishThen::new(then),
)
})
}

fn system_update_repository_list<F>(&self, config_fn: F) -> ::httpmock::Mock<'_>
where
F: FnOnce(
Expand Down
Loading