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
10 changes: 10 additions & 0 deletions dev-tools/omdb/src/bin/omdb/nexus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

//! omdb commands that query or update specific Nexus instances

mod chicken_switches;

use crate::Omdb;
use crate::check_allow_destructive::DestructiveOperationToken;
use crate::db::DbUrlOptions;
Expand All @@ -15,6 +17,8 @@ use crate::helpers::should_colorize;
use anyhow::Context as _;
use anyhow::bail;
use camino::Utf8PathBuf;
use chicken_switches::ChickenSwitchesArgs;
use chicken_switches::cmd_nexus_chicken_switches;
use chrono::DateTime;
use chrono::SecondsFormat;
use chrono::Utc;
Expand Down Expand Up @@ -123,6 +127,8 @@ enum NexusCommands {
BackgroundTasks(BackgroundTasksArgs),
/// interact with blueprints
Blueprints(BlueprintsArgs),
/// interact with reconfigurator chicken switches
ChickenSwitches(ChickenSwitchesArgs),
/// interact with clickhouse policy
ClickhousePolicy(ClickhousePolicyArgs),
/// print information about pending MGS updates
Expand Down Expand Up @@ -678,6 +684,10 @@ impl NexusArgs {
cmd_nexus_blueprints_import(&client, token, args).await
}

NexusCommands::ChickenSwitches(args) => {
cmd_nexus_chicken_switches(&omdb, &client, args).await
}

NexusCommands::ClickhousePolicy(ClickhousePolicyArgs {
command,
}) => match command {
Expand Down
164 changes: 164 additions & 0 deletions dev-tools/omdb/src/bin/omdb/nexus/chicken_switches.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! omdb commands for reconfigurator chicken switches

use crate::Omdb;
use crate::check_allow_destructive::DestructiveOperationToken;
use clap::Args;
use clap::Subcommand;
use http::StatusCode;
use nexus_client::types::{
ReconfiguratorChickenSwitches, ReconfiguratorChickenSwitchesParam,
};
use std::num::ParseIntError;
use std::str::FromStr;

#[derive(Debug, Args)]
pub struct ChickenSwitchesArgs {
#[command(subcommand)]
command: ChickenSwitchesCommands,
}

#[derive(Debug, Subcommand)]
pub enum ChickenSwitchesCommands {
/// Show a chicken switch at a given version
Show(ChickenSwitchesShowArgs),

/// Set the value of all chicken switches for the latest version
/// Values carry over from the latest version if unset on the CLI.
Set(ChickenSwitchesSetArgs),
}

#[derive(Debug, Clone, Args)]
pub struct ChickenSwitchesSetArgs {
planner_enabled: bool,
}

#[derive(Debug, Clone, Copy, Args)]
pub struct ChickenSwitchesShowArgs {
version: ChickenSwitchesVersionOrCurrent,
}

#[derive(Debug, Clone, Copy)]
pub enum ChickenSwitchesVersionOrCurrent {
Current,
Version(u32),
}

impl FromStr for ChickenSwitchesVersionOrCurrent {
type Err = ParseIntError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if matches!(s, "current" | "latest") {
Ok(Self::Current)
} else {
let version = s.parse()?;
Ok(Self::Version(version))
}
}
}

pub async fn cmd_nexus_chicken_switches(
omdb: &Omdb,
client: &nexus_client::Client,
args: &ChickenSwitchesArgs,
) -> Result<(), anyhow::Error> {
match &args.command {
ChickenSwitchesCommands::Show(version) => {
chicken_switches_show(&client, version).await
}
ChickenSwitchesCommands::Set(args) => {
let token = omdb.check_allow_destructive()?;
chicken_switches_set(&client, args, token).await
}
}
}
async fn chicken_switches_show(
client: &nexus_client::Client,
args: &ChickenSwitchesShowArgs,
) -> Result<(), anyhow::Error> {
let res = match args.version {
ChickenSwitchesVersionOrCurrent::Current => {
client.reconfigurator_chicken_switches_show_current().await
}
ChickenSwitchesVersionOrCurrent::Version(version) => {
client.reconfigurator_chicken_switches_show(version).await
}
};

match res {
Ok(switches) => {
let ReconfiguratorChickenSwitches {
version,
planner_enabled,
time_modified,
} = switches.into_inner();
println!("Reconfigurator Chicken Switches: ");
println!(" version: {version}");
println!(" modified time: {time_modified}");
println!(" planner enabled: {planner_enabled}");
}
Err(err) => eprintln!("error: {:#}", err),
}

Ok(())
}

async fn chicken_switches_set(
client: &nexus_client::Client,
args: &ChickenSwitchesSetArgs,
_destruction_token: DestructiveOperationToken,
) -> Result<(), anyhow::Error> {
let switches = match client
.reconfigurator_chicken_switches_show_current()
.await
{
Ok(switches) => {
let Some(version) = switches.version.checked_add(1) else {
eprintln!(
"ERROR: Failed to update chicken switches. Max version reached."
);
return Ok(());
};
let switches = switches.into_inner();
// Future switches should use the following pattern, and only update
// the current switch values if a setting changed.
//
// We may want to use `Options` in `args` to allow defaulting to
// the current setting rather than forcing the user to update all
// settings if the number of switches grows significantly. However,
// this will not play nice with the `NOT_FOUND` case below.
let mut modified = false;
if args.planner_enabled != switches.planner_enabled {
modified = true;
}
if modified {
ReconfiguratorChickenSwitchesParam {
version,
planner_enabled: args.planner_enabled,
}
} else {
println!("No modifications made to current switch values");
return Ok(());
}
}
Err(err) => {
if err.status() == Some(StatusCode::NOT_FOUND) {
ReconfiguratorChickenSwitchesParam {
version: 1,
planner_enabled: args.planner_enabled,
}
} else {
eprintln!("error: {:#}", err);
return Ok(());
}
}
};

client.reconfigurator_chicken_switches_set(&switches).await?;
println!("Chicken switches updated at version {}", switches.version);

Ok(())
}
1 change: 1 addition & 0 deletions dev-tools/omdb/tests/usage_errors.out
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,7 @@ Usage: omdb nexus [OPTIONS] <COMMAND>
Commands:
background-tasks print information about background tasks
blueprints interact with blueprints
chicken-switches interact with reconfigurator chicken switches
clickhouse-policy interact with clickhouse policy
mgs-updates print information about pending MGS updates
oximeter-read-policy interact with oximeter read policy
Expand Down
2 changes: 2 additions & 0 deletions nexus/db-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ mod physical_disk_state;
mod probe;
mod producer_endpoint;
mod project;
mod reconfigurator_chicken_switches;
mod rendezvous_debug_dataset;
mod semver_version;
mod serde_time_delta;
Expand Down Expand Up @@ -203,6 +204,7 @@ pub use producer_endpoint::*;
pub use project::*;
pub use quota::*;
pub use rack::*;
pub use reconfigurator_chicken_switches::*;
pub use region::*;
pub use region_replacement::*;
pub use region_replacement_step::*;
Expand Down
52 changes: 52 additions & 0 deletions nexus/db-model/src/reconfigurator_chicken_switches.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! Types representing runtime configuration for reconfigurator

use crate::SqlU32;
use chrono::{DateTime, Utc};
use nexus_db_schema::schema::reconfigurator_chicken_switches;
use nexus_types::deployment;

#[derive(Queryable, Clone, Debug, Selectable, Insertable)]
#[diesel(table_name = reconfigurator_chicken_switches)]
pub struct ReconfiguratorChickenSwitches {
pub version: SqlU32,
pub planner_enabled: bool,
pub time_modified: DateTime<Utc>,
}

impl ReconfiguratorChickenSwitches {
pub fn new(version: u32, planner_enabled: bool) -> Self {
Self {
version: version.into(),
planner_enabled,
time_modified: Utc::now(),
}
}
}

impl From<deployment::ReconfiguratorChickenSwitches>
for ReconfiguratorChickenSwitches
{
fn from(value: deployment::ReconfiguratorChickenSwitches) -> Self {
Self {
version: value.version.into(),
planner_enabled: value.planner_enabled,
time_modified: value.time_modified,
}
}
}

impl From<ReconfiguratorChickenSwitches>
for deployment::ReconfiguratorChickenSwitches
{
fn from(value: ReconfiguratorChickenSwitches) -> Self {
Self {
version: value.version.into(),
planner_enabled: value.planner_enabled,
time_modified: value.time_modified,
}
}
}
3 changes: 2 additions & 1 deletion nexus/db-model/src/schema_versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::{collections::BTreeMap, sync::LazyLock};
///
/// This must be updated when you change the database schema. Refer to
/// schema/crdb/README.adoc in the root of this repository for details.
pub const SCHEMA_VERSION: Version = Version::new(152, 0, 0);
pub const SCHEMA_VERSION: Version = Version::new(153, 0, 0);

/// List of all past database schema versions, in *reverse* order
///
Expand All @@ -28,6 +28,7 @@ static KNOWN_VERSIONS: LazyLock<Vec<KnownVersion>> = LazyLock::new(|| {
// | leaving the first copy as an example for the next person.
// v
// KnownVersion::new(next_int, "unique-dirname-with-the-sql-files"),
KnownVersion::new(153, "chicken-switches"),
KnownVersion::new(152, "ereports"),
KnownVersion::new(151, "zone-image-resolver-inventory"),
KnownVersion::new(150, "add-last-reconciliation-orphaned-datasets"),
Expand Down
1 change: 1 addition & 0 deletions nexus/db-queries/src/db/datastore/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ mod probe;
mod project;
mod quota;
mod rack;
mod reconfigurator_chicken_switches;
mod region;
mod region_replacement;
mod region_snapshot;
Expand Down
Loading
Loading