From 347c91e085263cfeae6b61e86f811d1ecb89883a Mon Sep 17 00:00:00 2001 From: Rain Date: Thu, 25 Apr 2024 01:46:26 -0700 Subject: [PATCH 1/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?= =?UTF-8?q?itial=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.6-beta.1 --- dev-tools/omdb/src/bin/omdb/nexus.rs | 30 +++++++++++++++ dev-tools/omdb/tests/successes.out | 9 +++++ dev-tools/omdb/tests/test_all_output.rs | 2 + dev-tools/omdb/tests/usage_errors.out | 21 +++++++++-- nexus/src/app/background/status.rs | 35 +++++++++++++++++ nexus/src/internal_api/http_entrypoints.rs | 31 +++++++++++++++ openapi/nexus-internal.json | 44 ++++++++++++++++++++++ 7 files changed, 168 insertions(+), 4 deletions(-) diff --git a/dev-tools/omdb/src/bin/omdb/nexus.rs b/dev-tools/omdb/src/bin/omdb/nexus.rs index 67b91e0280..520f28b48e 100644 --- a/dev-tools/omdb/src/bin/omdb/nexus.rs +++ b/dev-tools/omdb/src/bin/omdb/nexus.rs @@ -20,6 +20,7 @@ use futures::future::try_join; use futures::TryStreamExt; use nexus_client::types::ActivationReason; use nexus_client::types::BackgroundTask; +use nexus_client::types::BackgroundTasksActivateRequest; use nexus_client::types::CurrentStatus; use nexus_client::types::LastResult; use nexus_client::types::SledSelector; @@ -77,6 +78,15 @@ enum BackgroundTasksCommands { List, /// Print human-readable summary of the status of each background task Show, + /// Activate one or more background tasks + Activate(BackgroundTasksActivateArgs), +} + +#[derive(Debug, Args)] +struct BackgroundTasksActivateArgs { + /// Name of the background tasks to activate + #[clap(value_name = "TASK_NAME", required = true)] + tasks: Vec, } #[derive(Debug, Args)] @@ -298,6 +308,9 @@ impl NexusArgs { NexusCommands::BackgroundTasks(BackgroundTasksArgs { command: BackgroundTasksCommands::Show, }) => cmd_nexus_background_tasks_show(&client).await, + NexusCommands::BackgroundTasks(BackgroundTasksArgs { + command: BackgroundTasksCommands::Activate(args), + }) => cmd_nexus_background_tasks_activate(&client, args).await, NexusCommands::Blueprints(BlueprintsArgs { command: BlueprintsCommands::List, @@ -465,6 +478,23 @@ async fn cmd_nexus_background_tasks_show( Ok(()) } +/// Runs `omdb nexus background-tasks activate` +async fn cmd_nexus_background_tasks_activate( + client: &nexus_client::Client, + args: &BackgroundTasksActivateArgs, +) -> Result<(), anyhow::Error> { + let body = BackgroundTasksActivateRequest { + bgtask_names: args.tasks.iter().cloned().collect(), + }; + client + .bgtask_activate(&body) + .await + .context("error activating background tasks")?; + + eprintln!("activated background tasks: {}", args.tasks.join(", ")); + Ok(()) +} + fn print_task(bgtask: &BackgroundTask) { println!("task: {:?}", bgtask.name); println!( diff --git a/dev-tools/omdb/tests/successes.out b/dev-tools/omdb/tests/successes.out index 17668d002f..a6d956029e 100644 --- a/dev-tools/omdb/tests/successes.out +++ b/dev-tools/omdb/tests/successes.out @@ -436,6 +436,15 @@ warning: unknown background task: "switch_port_config_manager" (don't know how t stderr: note: using Nexus URL http://127.0.0.1:REDACTED_PORT/ ============================================= +EXECUTING COMMAND: omdb ["nexus", "background-tasks", "activate", "inventory_collection"] +termination: Exited(0) +--------------------------------------------- +stdout: +--------------------------------------------- +stderr: +note: using Nexus URL http://127.0.0.1:REDACTED_PORT/ +activated background tasks: inventory_collection +============================================= EXECUTING COMMAND: omdb ["nexus", "blueprints", "list"] termination: Exited(0) --------------------------------------------- diff --git a/dev-tools/omdb/tests/test_all_output.rs b/dev-tools/omdb/tests/test_all_output.rs index ef4792df62..f2450cf37b 100644 --- a/dev-tools/omdb/tests/test_all_output.rs +++ b/dev-tools/omdb/tests/test_all_output.rs @@ -51,6 +51,7 @@ async fn test_omdb_usage_errors() { &["mgs"], &["nexus"], &["nexus", "background-tasks"], + &["nexus", "collections"], &["sled-agent"], &["sled-agent", "zones"], &["sled-agent", "zpools"], @@ -93,6 +94,7 @@ async fn test_omdb_success_cases(cptestctx: &ControlPlaneTestContext) { &["mgs", "inventory"], &["nexus", "background-tasks", "doc"], &["nexus", "background-tasks", "show"], + &["nexus", "background-tasks", "activate", "inventory_collection"], &["nexus", "blueprints", "list"], &["nexus", "blueprints", "show", &initial_blueprint_id], &["nexus", "blueprints", "show", "current-target"], diff --git a/dev-tools/omdb/tests/usage_errors.out b/dev-tools/omdb/tests/usage_errors.out index e8967c859a..8d18641c01 100644 --- a/dev-tools/omdb/tests/usage_errors.out +++ b/dev-tools/omdb/tests/usage_errors.out @@ -302,14 +302,27 @@ print information about background tasks Usage: omdb nexus background-tasks Commands: - doc Show documentation about background tasks - list Print a summary of the status of all background tasks - show Print human-readable summary of the status of each background task - help Print this message or the help of the given subcommand(s) + doc Show documentation about background tasks + list Print a summary of the status of all background tasks + show Print human-readable summary of the status of each background task + activate Activate one or more background tasks + help Print this message or the help of the given subcommand(s) Options: -h, --help Print help ============================================= +EXECUTING COMMAND: omdb ["nexus", "collections"] +termination: Exited(2) +--------------------------------------------- +stdout: +--------------------------------------------- +stderr: +error: unrecognized subcommand 'collections' + +Usage: omdb nexus [OPTIONS] + +For more information, try '--help'. +============================================= EXECUTING COMMAND: omdb ["sled-agent"] termination: Exited(2) --------------------------------------------- diff --git a/nexus/src/app/background/status.rs b/nexus/src/app/background/status.rs index 120401c439..f4fb9e56e5 100644 --- a/nexus/src/app/background/status.rs +++ b/nexus/src/app/background/status.rs @@ -13,6 +13,7 @@ use omicron_common::api::external::LookupResult; use omicron_common::api::external::LookupType; use omicron_common::api::external::ResourceType; use std::collections::BTreeMap; +use std::collections::BTreeSet; impl Nexus { pub(crate) async fn bgtasks_list( @@ -53,4 +54,38 @@ impl Nexus { let period = driver.task_period(task); Ok(BackgroundTask::new(task.name(), description, period, status)) } + + pub(crate) async fn bgtask_activate( + &self, + opctx: &OpContext, + mut names: BTreeSet, + ) -> Result<(), Error> { + opctx.authorize(authz::Action::Modify, &authz::FLEET).await?; + let driver = &self.background_tasks.driver; + + // Ensure all task names are valid by removing them from the set of + // names as we find them. + let tasks_to_activate: Vec<_> = + driver.tasks().filter(|t| names.remove(t.name())).collect(); + + // If any names weren't recognized, return an error. + if !names.is_empty() { + let mut names_str = "background tasks: ".to_owned(); + for (i, name) in names.iter().enumerate() { + names_str.push_str(name); + if i < names.len() - 1 { + names_str.push_str(", "); + } + } + + return Err(LookupType::ByOther(names_str) + .into_not_found(ResourceType::BackgroundTask)); + } + + for task in tasks_to_activate { + driver.activate(task); + } + + Ok(()) + } } diff --git a/nexus/src/internal_api/http_entrypoints.rs b/nexus/src/internal_api/http_entrypoints.rs index c2582daaf4..5e5113dc7b 100644 --- a/nexus/src/internal_api/http_entrypoints.rs +++ b/nexus/src/internal_api/http_entrypoints.rs @@ -58,6 +58,7 @@ use oximeter_producer::{collect, ProducerIdPathParams}; use schemars::JsonSchema; use serde::Deserialize; use std::collections::BTreeMap; +use std::collections::BTreeSet; use std::sync::Arc; use uuid::Uuid; @@ -94,6 +95,7 @@ pub(crate) fn internal_api() -> NexusApiDescription { api.register(bgtask_list)?; api.register(bgtask_view)?; + api.register(bgtask_activate)?; api.register(blueprint_list)?; api.register(blueprint_view)?; @@ -749,6 +751,12 @@ struct BackgroundTaskPathParam { bgtask_name: String, } +/// Query parameters for multiple background task requests. +#[derive(Deserialize, JsonSchema)] +struct BackgroundTasksActivateRequest { + bgtask_names: BTreeSet, +} + /// Fetch status of one background task /// /// This is exposed for support and debugging. @@ -771,6 +779,29 @@ async fn bgtask_view( apictx.internal_latencies.instrument_dropshot_handler(&rqctx, handler).await } +/// Activates one or more background tasks, causing them to be run immediately +/// if idle, or scheduled to run again as soon as possible if already running. +#[endpoint { + method = POST, + // Can't be "bgtasks/activate" because it conflicts with the GET endpoint + // for bgtask_view. + path = "/bgtasks-activate", +}] +async fn bgtask_activate( + rqctx: RequestContext>, + body: TypedBody, +) -> Result { + let apictx = rqctx.context(); + let handler = async { + let opctx = crate::context::op_context_for_internal_api(&rqctx).await; + let nexus = &apictx.nexus; + let body = body.into_inner(); + nexus.bgtask_activate(&opctx, body.bgtask_names).await?; + Ok(HttpResponseUpdatedNoContent()) + }; + apictx.internal_latencies.instrument_dropshot_handler(&rqctx, handler).await +} + // NAT RPW internal APIs /// Path parameters for NAT ChangeSet diff --git a/openapi/nexus-internal.json b/openapi/nexus-internal.json index 091c43c820..f95dcc21d9 100644 --- a/openapi/nexus-internal.json +++ b/openapi/nexus-internal.json @@ -125,6 +125,34 @@ } } }, + "/bgtasks-activate": { + "post": { + "summary": "Activates one or more background tasks, causing them to be run immediately", + "description": "if idle, or scheduled to run again as soon as possible if already running.", + "operationId": "bgtask_activate", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackgroundTasksActivateRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "resource updated" + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + } + } + }, "/crucible/0/upstairs/{upstairs_id}/downstairs/{downstairs_id}/stop-request": { "post": { "summary": "An Upstairs will update this endpoint if a Downstairs client task is", @@ -1428,6 +1456,22 @@ "period" ] }, + "BackgroundTasksActivateRequest": { + "description": "Query parameters for multiple background task requests.", + "type": "object", + "properties": { + "bgtask_names": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } + }, + "required": [ + "bgtask_names" + ] + }, "Baseboard": { "description": "Properties that uniquely identify an Oxide hardware component", "type": "object", From c389177426cc8ca2052540966431517ed751d177 Mon Sep 17 00:00:00 2001 From: Rain Date: Thu, 25 Apr 2024 01:53:04 -0700 Subject: [PATCH 2/3] add nexus blueprints and nexus sleds Created using spr 1.3.6-beta.1 --- dev-tools/omdb/tests/test_all_output.rs | 3 +- dev-tools/omdb/tests/usage_errors.out | 38 ++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/dev-tools/omdb/tests/test_all_output.rs b/dev-tools/omdb/tests/test_all_output.rs index f2450cf37b..eeea949573 100644 --- a/dev-tools/omdb/tests/test_all_output.rs +++ b/dev-tools/omdb/tests/test_all_output.rs @@ -51,7 +51,8 @@ async fn test_omdb_usage_errors() { &["mgs"], &["nexus"], &["nexus", "background-tasks"], - &["nexus", "collections"], + &["nexus", "blueprints"], + &["nexus", "sleds"], &["sled-agent"], &["sled-agent", "zones"], &["sled-agent", "zpools"], diff --git a/dev-tools/omdb/tests/usage_errors.out b/dev-tools/omdb/tests/usage_errors.out index 8d18641c01..31fd51d9ad 100644 --- a/dev-tools/omdb/tests/usage_errors.out +++ b/dev-tools/omdb/tests/usage_errors.out @@ -311,17 +311,47 @@ Commands: Options: -h, --help Print help ============================================= -EXECUTING COMMAND: omdb ["nexus", "collections"] +EXECUTING COMMAND: omdb ["nexus", "blueprints"] termination: Exited(2) --------------------------------------------- stdout: --------------------------------------------- stderr: -error: unrecognized subcommand 'collections' +interact with blueprints -Usage: omdb nexus [OPTIONS] +Usage: omdb nexus blueprints -For more information, try '--help'. +Commands: + list List all blueprints + show Show a blueprint + diff Diff two blueprints + delete Delete a blueprint + target Interact with the current target blueprint + regenerate Generate a new blueprint + import Import a blueprint + help Print this message or the help of the given subcommand(s) + +Options: + -h, --help Print help +============================================= +EXECUTING COMMAND: omdb ["nexus", "sleds"] +termination: Exited(2) +--------------------------------------------- +stdout: +--------------------------------------------- +stderr: +interact with sleds + +Usage: omdb nexus sleds + +Commands: + list-uninitialized List all uninitialized sleds + add Add an uninitialized sled + expunge Expunge a sled (DANGEROUS) + help Print this message or the help of the given subcommand(s) + +Options: + -h, --help Print help ============================================= EXECUTING COMMAND: omdb ["sled-agent"] termination: Exited(2) From 237061ab8157daf7f9e582543eff8d09a05e635d Mon Sep 17 00:00:00 2001 From: Rain Date: Thu, 25 Apr 2024 02:17:38 -0700 Subject: [PATCH 3/3] clippy Created using spr 1.3.6-beta.1 --- dev-tools/omdb/src/bin/omdb/nexus.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dev-tools/omdb/src/bin/omdb/nexus.rs b/dev-tools/omdb/src/bin/omdb/nexus.rs index 520f28b48e..9ca5800583 100644 --- a/dev-tools/omdb/src/bin/omdb/nexus.rs +++ b/dev-tools/omdb/src/bin/omdb/nexus.rs @@ -483,9 +483,8 @@ async fn cmd_nexus_background_tasks_activate( client: &nexus_client::Client, args: &BackgroundTasksActivateArgs, ) -> Result<(), anyhow::Error> { - let body = BackgroundTasksActivateRequest { - bgtask_names: args.tasks.iter().cloned().collect(), - }; + let body = + BackgroundTasksActivateRequest { bgtask_names: args.tasks.clone() }; client .bgtask_activate(&body) .await