Skip to content

Commit

Permalink
omdb support for these APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
davepacheco committed Jan 9, 2024
1 parent 155c0be commit cf3aa30
Show file tree
Hide file tree
Showing 7 changed files with 550 additions and 29 deletions.
193 changes: 193 additions & 0 deletions dev-tools/omdb/src/bin/omdb/nexus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use chrono::SecondsFormat;
use chrono::Utc;
use clap::Args;
use clap::Subcommand;
use futures::TryStreamExt;
use nexus_client::types::ActivationReason;
use nexus_client::types::BackgroundTask;
use nexus_client::types::CurrentStatus;
Expand All @@ -36,6 +37,8 @@ pub struct NexusArgs {
enum NexusCommands {
/// print information about background tasks
BackgroundTasks(BackgroundTasksArgs),
/// print information about blueprints
Blueprints(BlueprintsArgs),
}

#[derive(Debug, Args)]
Expand All @@ -54,6 +57,34 @@ enum BackgroundTasksCommands {
Show,
}

#[derive(Debug, Args)]
struct BlueprintsArgs {
#[command(subcommand)]
command: BlueprintsCommands,
}

#[derive(Debug, Subcommand)]
enum BlueprintsCommands {
/// List all blueprints
List,
/// Show a blueprint
Show(BlueprintIdArgs),
/// Delete a blueprint
Delete(BlueprintIdArgs),
/// Set the current target blueprint
SetTarget(BlueprintIdArgs),
/// Generate an initial blueprint from the current state
GenerateCurrent,
/// Generate a new blueprint
Regenerate,
}

#[derive(Debug, Args)]
struct BlueprintIdArgs {
/// id of a blueprint
blueprint_id: Uuid,
}

impl NexusArgs {
/// Run a `omdb nexus` subcommand.
pub(crate) async fn run_cmd(
Expand Down Expand Up @@ -93,6 +124,25 @@ impl NexusArgs {
NexusCommands::BackgroundTasks(BackgroundTasksArgs {
command: BackgroundTasksCommands::Show,
}) => cmd_nexus_background_tasks_show(&client).await,

NexusCommands::Blueprints(BlueprintsArgs {
command: BlueprintsCommands::List,
}) => cmd_nexus_blueprints_list(&client).await,
NexusCommands::Blueprints(BlueprintsArgs {
command: BlueprintsCommands::Show(args),
}) => cmd_nexus_blueprints_show(&client, args).await,
NexusCommands::Blueprints(BlueprintsArgs {
command: BlueprintsCommands::Delete(args),
}) => cmd_nexus_blueprints_delete(&client, args).await,
NexusCommands::Blueprints(BlueprintsArgs {
command: BlueprintsCommands::SetTarget(args),
}) => cmd_nexus_blueprints_set_target(&client, args).await,
NexusCommands::Blueprints(BlueprintsArgs {
command: BlueprintsCommands::Regenerate,
}) => cmd_nexus_blueprints_regenerate(&client).await,
NexusCommands::Blueprints(BlueprintsArgs {
command: BlueprintsCommands::GenerateCurrent,
}) => cmd_nexus_blueprints_generate_current(&client).await,
}
}
}
Expand Down Expand Up @@ -629,3 +679,146 @@ fn reason_code(reason: ActivationReason) -> char {
ActivationReason::Timeout => 'T',
}
}

async fn cmd_nexus_blueprints_list(
client: &nexus_client::Client,
) -> Result<(), anyhow::Error> {
#[derive(Tabled)]
#[tabled(rename_all = "SCREAMING_SNAKE_CASE")]
struct BlueprintRow {
#[tabled(rename = "T")]
is_target: &'static str,
id: String,
parent: String,
reason: String,
time_created: String,
}

let target_id = client
.blueprint_target_view()
.await
.context("fetching current target blueprint")?
.into_inner()
.target_id;
let rows: Vec<BlueprintRow> = client
.blueprint_list_stream(None, None)
.try_collect::<Vec<_>>()
.await
.context("listing blueprints")?
.into_iter()
.map(|blueprint| {
let is_target = match target_id {
Some(target_id) if target_id == blueprint.id => "*",
_ => "",
};

BlueprintRow {
is_target,
id: blueprint.id.to_string(),
parent: blueprint
.parent_blueprint_id
.map(|s| s.to_string())
.unwrap_or_else(|| String::from("<none>")),
reason: blueprint.reason,
time_created: humantime::format_rfc3339_millis(
blueprint.time_created.into(),
)
.to_string(),
}
})
.collect();

let table = tabled::Table::new(rows)
.with(tabled::settings::Style::empty())
.with(tabled::settings::Padding::new(0, 1, 0, 0))
.to_string();

println!("{}", table);
Ok(())
}

async fn cmd_nexus_blueprints_show(
client: &nexus_client::Client,
args: &BlueprintIdArgs,
) -> Result<(), anyhow::Error> {
let blueprint = client
.blueprint_view(&args.blueprint_id)
.await
.with_context(|| format!("fetching blueprint {}", args.blueprint_id))?;
println!("blueprint {}", blueprint.id);
println!(
"parent: {}",
blueprint
.parent_blueprint_id
.map(|u| u.to_string())
.unwrap_or_else(|| String::from("<none>"))
);
println!(
"created by {}{}",
blueprint.creator,
if blueprint.creator.parse::<Uuid>().is_ok() {
" (likely a Nexus instance)"
} else {
""
}
);
println!(
"created at {}",
humantime::format_rfc3339_millis(blueprint.time_created.into(),)
);
println!("created for: {}", blueprint.reason,);

Ok(())
}

async fn cmd_nexus_blueprints_delete(
client: &nexus_client::Client,
args: &BlueprintIdArgs,
) -> Result<(), anyhow::Error> {
let _ = client
.blueprint_delete(&args.blueprint_id)
.await
.with_context(|| format!("deleting blueprint {}", args.blueprint_id))?;
println!("blueprint {} deleted", args.blueprint_id);
Ok(())
}

// XXX-dap add "diff" command?

async fn cmd_nexus_blueprints_set_target(
client: &nexus_client::Client,
args: &BlueprintIdArgs,
) -> Result<(), anyhow::Error> {
client
.blueprint_target_set(&nexus_client::types::BlueprintTargetSet {
target_id: args.blueprint_id,
// XXX-dap ideally keep existing value
enabled: true,
})
.await
.with_context(|| {
format!("setting target to blueprint {}", args.blueprint_id)
})?;
eprintln!("set target blueprint to {}", args.blueprint_id);
Ok(())
}

async fn cmd_nexus_blueprints_generate_current(
client: &nexus_client::Client,
) -> Result<(), anyhow::Error> {
let blueprint = client
.blueprint_create_current()
.await
.context("creating blueprint from current state")?;
eprintln!("created blueprint {} from current state", blueprint.id);
Ok(())
}

async fn cmd_nexus_blueprints_regenerate(
client: &nexus_client::Client,
) -> Result<(), anyhow::Error> {
let blueprint =
client.blueprint_regenerate().await.context("generating blueprint")?;
eprintln!("generated new blueprint {}", blueprint.id);
Ok(())
}
27 changes: 17 additions & 10 deletions nexus/db-queries/src/db/datastore/zpool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,21 @@ use crate::db::identity::Asset;
use crate::db::model::Sled;
use crate::db::model::Zpool;
use crate::db::pagination::paginated;
use crate::db::queries::ALLOW_FULL_TABLE_SCAN_SQL;
use async_bb8_diesel::AsyncConnection;
use async_bb8_diesel::AsyncRunQueryDsl;
use async_bb8_diesel::AsyncSimpleConnection;
use chrono::Utc;
use diesel::prelude::*;
use diesel::upsert::excluded;
use nexus_db_model::PhysicalDiskKind;
use omicron_common::api::external::CreateResult;
use omicron_common::api::external::DataPageParams;
use omicron_common::api::external::Error;
use omicron_common::api::external::ListResultVec;
use omicron_common::api::external::LookupType;
use omicron_common::api::external::ResourceType;
use uuid::Uuid;
use nexus_db_model::PhysicalDiskKind;

impl DataStore {
/// Stores a new zpool in the database.
Expand Down Expand Up @@ -113,17 +116,21 @@ impl DataStore {

use db::schema::physical_disk::dsl as dsl_physical_disk;
use db::schema::zpool::dsl as dsl_zpool;
paginated(dsl_zpool::zpool, dsl_zpool::id, pagparams)
.inner_join(
db::schema::physical_disk::table.on(
// XXX-dap shouldn't need to disable full scan?
let conn = self.pool_connection_authorized(opctx).await?;
conn.transaction_async(|conn| async move {
conn.batch_execute_async(ALLOW_FULL_TABLE_SCAN_SQL).await?;
paginated(dsl_zpool::zpool, dsl_zpool::id, pagparams)
.inner_join(db::schema::physical_disk::table.on(
dsl_zpool::physical_disk_id.eq(dsl_physical_disk::id).and(
dsl_physical_disk::variant.eq(PhysicalDiskKind::U2),
),
),
)
.select(Zpool::as_select())
.load_async(&*self.pool_connection_authorized(opctx).await?)
.await
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
))
.select(Zpool::as_select())
.load_async(&conn)
.await
})
.await
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
}
}
5 changes: 1 addition & 4 deletions nexus/deployment/src/planner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ use crate::blueprint_builder::Error;
use crate::blueprint_builder::SledInfo;
use nexus_types::deployment::Blueprint;
use nexus_types::deployment::OmicronZoneType;
use nexus_types::inventory::Collection;
use slog::{info, Logger};
use std::collections::BTreeMap;
use uuid::Uuid;

pub struct Planner<'a> {
log: Logger,
parent_blueprint: &'a Blueprint,
collection: &'a Collection,
sleds: &'a BTreeMap<Uuid, SledInfo>,
blueprint: BlueprintBuilder<'a>,
}
Expand All @@ -28,7 +26,6 @@ impl<'a> Planner<'a> {
pub fn new_based_on(
log: Logger,
parent_blueprint: &'a Blueprint,
collection: &'a Collection,
sleds: &'a BTreeMap<Uuid, SledInfo>,
creator: &str,
reason: &str,
Expand All @@ -39,7 +36,7 @@ impl<'a> Planner<'a> {
creator,
reason,
);
Planner { log, parent_blueprint, collection, sleds, blueprint }
Planner { log, parent_blueprint, sleds, blueprint }
}

pub fn plan(mut self) -> Result<Blueprint, Error> {
Expand Down
18 changes: 9 additions & 9 deletions nexus/src/app/deployment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,20 @@ impl super::Nexus {
pub async fn blueprint_list(
&self,
_opctx: &OpContext,
_pagparams: &DataPageParams<'_, Uuid>,
pagparams: &DataPageParams<'_, Uuid>,
) -> ListResultVec<Blueprint> {
// XXX-dap authz check
// Since this is just temporary until we have a database impl, ignore
// pagination.
Ok(self
.blueprints
.lock()
.unwrap()
.all_blueprints
.values()
.cloned()
.filter_map(|f| match pagparams.marker {
None => Some(f.clone()),
Some(marker) if f.id > *marker => Some(f.clone()),
_ => None,
})
.collect())
}

Expand Down Expand Up @@ -126,7 +128,7 @@ impl super::Nexus {
pub async fn blueprint_target_set(
&self,
_opctx: &OpContext,
params: params::BlueprintTarget,
params: params::BlueprintTargetSet,
) -> Result<BlueprintTarget, Error> {
// XXX-dap authz check
let new_target_id = params.target_id;
Expand Down Expand Up @@ -175,7 +177,6 @@ impl super::Nexus {
Error::unavail("no recent inventory collection available")
})?;

// XXX-dap working here
let sled_rows = {
let mut all_sleds = Vec::new();
let mut paginator = Paginator::new(limit);
Expand Down Expand Up @@ -235,7 +236,7 @@ impl super::Nexus {

async fn blueprint_add(
&self,
opctx: &OpContext,
_opctx: &OpContext,
blueprint: Blueprint,
) -> Result<(), Error> {
// XXX-dap authz check
Expand Down Expand Up @@ -277,7 +278,7 @@ impl super::Nexus {
let blueprints = self.blueprints.lock().unwrap();
let Some(target_id) = blueprints.target.target_id else {
return Err(Error::conflict(&format!(
"cannot add sled before initial blueprint is created"
"cannot regenerate blueprint without existing target"
)));
};
blueprints
Expand All @@ -290,7 +291,6 @@ impl super::Nexus {
let planner = Planner::new_based_on(
opctx.log.clone(),
&parent_blueprint,
&planning_context.collection,
&planning_context.sleds,
&planning_context.creator,
// XXX-dap this "reason" was intended for the case where we know why
Expand Down
Loading

0 comments on commit cf3aa30

Please sign in to comment.