Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[omdb] add basic support for activating background tasks #5615

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
2 changes: 1 addition & 1 deletion dev-tools/omdb/src/bin/omdb/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ struct Omdb {
#[arg(env = "OMDB_DNS_SERVER", long)]
dns_server: Option<SocketAddr>,

/// allow potentially-destructive subcommands
/// Allow potentially-destructive subcommands.
#[arg(short = 'w', long = "destructive")]
allow_destructive: bool,

Expand Down
36 changes: 36 additions & 0 deletions dev-tools/omdb/src/bin/omdb/nexus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String>,
}

#[derive(Debug, Args)]
Expand Down Expand Up @@ -294,6 +304,12 @@ impl NexusArgs {
NexusCommands::BackgroundTasks(BackgroundTasksArgs {
command: BackgroundTasksCommands::Show,
}) => cmd_nexus_background_tasks_show(&client).await,
NexusCommands::BackgroundTasks(BackgroundTasksArgs {
command: BackgroundTasksCommands::Activate(args),
}) => {
let token = omdb.check_allow_destructive()?;
cmd_nexus_background_tasks_activate(&client, args, token).await
}

NexusCommands::Blueprints(BlueprintsArgs {
command: BlueprintsCommands::List,
Expand Down Expand Up @@ -461,6 +477,26 @@ 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,
sunshowers marked this conversation as resolved.
Show resolved Hide resolved
// This isn't quite "destructive" in the sense that of it being potentially
// dangerous, but it does modify the system rather than being a read-only
// view on it.
_destruction_token: DestructiveOperationToken,
) -> Result<(), anyhow::Error> {
let body =
BackgroundTasksActivateRequest { bgtask_names: args.tasks.clone() };
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!(
Expand Down
9 changes: 9 additions & 0 deletions dev-tools/omdb/tests/successes.out
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,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 ["--destructive", "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)
---------------------------------------------
Expand Down
9 changes: 9 additions & 0 deletions dev-tools/omdb/tests/test_all_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ async fn test_omdb_usage_errors() {
&["mgs"],
&["nexus"],
&["nexus", "background-tasks"],
&["nexus", "blueprints"],
&["nexus", "sleds"],
&["sled-agent"],
&["sled-agent", "zones"],
&["sled-agent", "zpools"],
Expand Down Expand Up @@ -95,6 +97,13 @@ async fn test_omdb_success_cases(cptestctx: &ControlPlaneTestContext) {
&["mgs", "inventory"],
&["nexus", "background-tasks", "doc"],
&["nexus", "background-tasks", "show"],
&[
"--destructive",
"nexus",
"background-tasks",
"activate",
"inventory_collection",
],
&["nexus", "blueprints", "list"],
&["nexus", "blueprints", "show", &initial_blueprint_id],
&["nexus", "blueprints", "show", "current-target"],
Expand Down
55 changes: 49 additions & 6 deletions dev-tools/omdb/tests/usage_errors.out
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Commands:
Options:
--log-level <LOG_LEVEL> log level filter [env: LOG_LEVEL=] [default: warn]
--dns-server <DNS_SERVER> [env: OMDB_DNS_SERVER=]
-w, --destructive allow potentially-destructive subcommands
-w, --destructive Allow potentially-destructive subcommands
-h, --help Print help (see more with '--help')
=============================================
EXECUTING COMMAND: omdb ["--help"]
Expand Down Expand Up @@ -54,7 +54,7 @@ Options:
[env: OMDB_DNS_SERVER=]

-w, --destructive
allow potentially-destructive subcommands
Allow potentially-destructive subcommands

-h, --help
Print help (see a summary with '-h')
Expand Down Expand Up @@ -328,10 +328,53 @@ print information about background tasks
Usage: omdb nexus background-tasks <COMMAND>

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", "blueprints"]
termination: Exited(2)
---------------------------------------------
stdout:
---------------------------------------------
stderr:
interact with blueprints

Usage: omdb nexus blueprints <COMMAND>

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 <COMMAND>

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
Expand Down
35 changes: 35 additions & 0 deletions nexus/src/app/background/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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<String>,
) -> 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(())
}
}
31 changes: 30 additions & 1 deletion nexus/src/internal_api/http_entrypoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ use omicron_uuid_kinds::UpstairsRepairKind;
use schemars::JsonSchema;
use serde::Deserialize;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::sync::Arc;
use uuid::Uuid;

Expand Down Expand Up @@ -93,6 +94,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)?;
Expand Down Expand Up @@ -737,12 +739,18 @@ struct BackgroundTaskPathParam {
bgtask_name: String,
}

/// Query parameters for Background Task activation requests.
#[derive(Deserialize, JsonSchema)]
struct BackgroundTasksActivateRequest {
bgtask_names: BTreeSet<String>,
}

/// Fetch status of one background task
///
/// This is exposed for support and debugging.
#[endpoint {
method = GET,
path = "/bgtasks/{bgtask_name}",
path = "/bgtasks/view/{bgtask_name}",
}]
async fn bgtask_view(
rqctx: RequestContext<Arc<ServerContext>>,
Expand All @@ -759,6 +767,27 @@ 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,
path = "/bgtasks/activate",
}]
async fn bgtask_activate(
rqctx: RequestContext<Arc<ServerContext>>,
body: TypedBody<BackgroundTasksActivateRequest>,
) -> Result<HttpResponseUpdatedNoContent, HttpError> {
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
Expand Down
46 changes: 45 additions & 1 deletion openapi/nexus-internal.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,35 @@
}
}
},
"/bgtasks/{bgtask_name}": {
"/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"
}
}
}
},
"/bgtasks/view/{bgtask_name}": {
"get": {
"summary": "Fetch status of one background task",
"description": "This is exposed for support and debugging.",
Expand Down Expand Up @@ -1396,6 +1424,22 @@
"period"
]
},
"BackgroundTasksActivateRequest": {
"description": "Query parameters for Background Task activation 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",
Expand Down
Loading