Skip to content

Commit 165b854

Browse files
authored
Add omdb,db,nexus api support for chicken switches (#8449)
This is an initial commit to support chicken switches that allow runtime reconfigurator configuration. There is only one initial chicken switch which can be used to enable the planner background task to run. A follow up PR will be made to add a background task that reads the chicken switch DB table and makes it available to nexus via a watcher. This PR will complete #8253 . Support for listing history was added at the datastore level, but not made available yet in OMDB, because of the way pagination works. This will likely come in a follow up.
1 parent 9694ee4 commit 165b854

File tree

16 files changed

+858
-3
lines changed

16 files changed

+858
-3
lines changed

dev-tools/omdb/src/bin/omdb/nexus.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
//! omdb commands that query or update specific Nexus instances
66
7+
mod chicken_switches;
8+
79
use crate::Omdb;
810
use crate::check_allow_destructive::DestructiveOperationToken;
911
use crate::db::DbUrlOptions;
@@ -15,6 +17,8 @@ use crate::helpers::should_colorize;
1517
use anyhow::Context as _;
1618
use anyhow::bail;
1719
use camino::Utf8PathBuf;
20+
use chicken_switches::ChickenSwitchesArgs;
21+
use chicken_switches::cmd_nexus_chicken_switches;
1822
use chrono::DateTime;
1923
use chrono::SecondsFormat;
2024
use chrono::Utc;
@@ -123,6 +127,8 @@ enum NexusCommands {
123127
BackgroundTasks(BackgroundTasksArgs),
124128
/// interact with blueprints
125129
Blueprints(BlueprintsArgs),
130+
/// interact with reconfigurator chicken switches
131+
ChickenSwitches(ChickenSwitchesArgs),
126132
/// interact with clickhouse policy
127133
ClickhousePolicy(ClickhousePolicyArgs),
128134
/// print information about pending MGS updates
@@ -678,6 +684,10 @@ impl NexusArgs {
678684
cmd_nexus_blueprints_import(&client, token, args).await
679685
}
680686

687+
NexusCommands::ChickenSwitches(args) => {
688+
cmd_nexus_chicken_switches(&omdb, &client, args).await
689+
}
690+
681691
NexusCommands::ClickhousePolicy(ClickhousePolicyArgs {
682692
command,
683693
}) => match command {
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
//! omdb commands for reconfigurator chicken switches
6+
7+
use crate::Omdb;
8+
use crate::check_allow_destructive::DestructiveOperationToken;
9+
use clap::Args;
10+
use clap::Subcommand;
11+
use http::StatusCode;
12+
use nexus_client::types::{
13+
ReconfiguratorChickenSwitches, ReconfiguratorChickenSwitchesParam,
14+
};
15+
use std::num::ParseIntError;
16+
use std::str::FromStr;
17+
18+
#[derive(Debug, Args)]
19+
pub struct ChickenSwitchesArgs {
20+
#[command(subcommand)]
21+
command: ChickenSwitchesCommands,
22+
}
23+
24+
#[derive(Debug, Subcommand)]
25+
pub enum ChickenSwitchesCommands {
26+
/// Show a chicken switch at a given version
27+
Show(ChickenSwitchesShowArgs),
28+
29+
/// Set the value of all chicken switches for the latest version
30+
/// Values carry over from the latest version if unset on the CLI.
31+
Set(ChickenSwitchesSetArgs),
32+
}
33+
34+
#[derive(Debug, Clone, Args)]
35+
pub struct ChickenSwitchesSetArgs {
36+
planner_enabled: bool,
37+
}
38+
39+
#[derive(Debug, Clone, Copy, Args)]
40+
pub struct ChickenSwitchesShowArgs {
41+
version: ChickenSwitchesVersionOrCurrent,
42+
}
43+
44+
#[derive(Debug, Clone, Copy)]
45+
pub enum ChickenSwitchesVersionOrCurrent {
46+
Current,
47+
Version(u32),
48+
}
49+
50+
impl FromStr for ChickenSwitchesVersionOrCurrent {
51+
type Err = ParseIntError;
52+
53+
fn from_str(s: &str) -> Result<Self, Self::Err> {
54+
if matches!(s, "current" | "latest") {
55+
Ok(Self::Current)
56+
} else {
57+
let version = s.parse()?;
58+
Ok(Self::Version(version))
59+
}
60+
}
61+
}
62+
63+
pub async fn cmd_nexus_chicken_switches(
64+
omdb: &Omdb,
65+
client: &nexus_client::Client,
66+
args: &ChickenSwitchesArgs,
67+
) -> Result<(), anyhow::Error> {
68+
match &args.command {
69+
ChickenSwitchesCommands::Show(version) => {
70+
chicken_switches_show(&client, version).await
71+
}
72+
ChickenSwitchesCommands::Set(args) => {
73+
let token = omdb.check_allow_destructive()?;
74+
chicken_switches_set(&client, args, token).await
75+
}
76+
}
77+
}
78+
async fn chicken_switches_show(
79+
client: &nexus_client::Client,
80+
args: &ChickenSwitchesShowArgs,
81+
) -> Result<(), anyhow::Error> {
82+
let res = match args.version {
83+
ChickenSwitchesVersionOrCurrent::Current => {
84+
client.reconfigurator_chicken_switches_show_current().await
85+
}
86+
ChickenSwitchesVersionOrCurrent::Version(version) => {
87+
client.reconfigurator_chicken_switches_show(version).await
88+
}
89+
};
90+
91+
match res {
92+
Ok(switches) => {
93+
let ReconfiguratorChickenSwitches {
94+
version,
95+
planner_enabled,
96+
time_modified,
97+
} = switches.into_inner();
98+
println!("Reconfigurator Chicken Switches: ");
99+
println!(" version: {version}");
100+
println!(" modified time: {time_modified}");
101+
println!(" planner enabled: {planner_enabled}");
102+
}
103+
Err(err) => eprintln!("error: {:#}", err),
104+
}
105+
106+
Ok(())
107+
}
108+
109+
async fn chicken_switches_set(
110+
client: &nexus_client::Client,
111+
args: &ChickenSwitchesSetArgs,
112+
_destruction_token: DestructiveOperationToken,
113+
) -> Result<(), anyhow::Error> {
114+
let switches = match client
115+
.reconfigurator_chicken_switches_show_current()
116+
.await
117+
{
118+
Ok(switches) => {
119+
let Some(version) = switches.version.checked_add(1) else {
120+
eprintln!(
121+
"ERROR: Failed to update chicken switches. Max version reached."
122+
);
123+
return Ok(());
124+
};
125+
let switches = switches.into_inner();
126+
// Future switches should use the following pattern, and only update
127+
// the current switch values if a setting changed.
128+
//
129+
// We may want to use `Options` in `args` to allow defaulting to
130+
// the current setting rather than forcing the user to update all
131+
// settings if the number of switches grows significantly. However,
132+
// this will not play nice with the `NOT_FOUND` case below.
133+
let mut modified = false;
134+
if args.planner_enabled != switches.planner_enabled {
135+
modified = true;
136+
}
137+
if modified {
138+
ReconfiguratorChickenSwitchesParam {
139+
version,
140+
planner_enabled: args.planner_enabled,
141+
}
142+
} else {
143+
println!("No modifications made to current switch values");
144+
return Ok(());
145+
}
146+
}
147+
Err(err) => {
148+
if err.status() == Some(StatusCode::NOT_FOUND) {
149+
ReconfiguratorChickenSwitchesParam {
150+
version: 1,
151+
planner_enabled: args.planner_enabled,
152+
}
153+
} else {
154+
eprintln!("error: {:#}", err);
155+
return Ok(());
156+
}
157+
}
158+
};
159+
160+
client.reconfigurator_chicken_switches_set(&switches).await?;
161+
println!("Chicken switches updated at version {}", switches.version);
162+
163+
Ok(())
164+
}

dev-tools/omdb/tests/usage_errors.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,7 @@ Usage: omdb nexus [OPTIONS] <COMMAND>
841841
Commands:
842842
background-tasks print information about background tasks
843843
blueprints interact with blueprints
844+
chicken-switches interact with reconfigurator chicken switches
844845
clickhouse-policy interact with clickhouse policy
845846
mgs-updates print information about pending MGS updates
846847
oximeter-read-policy interact with oximeter read policy

nexus/db-model/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ mod physical_disk_state;
6666
mod probe;
6767
mod producer_endpoint;
6868
mod project;
69+
mod reconfigurator_chicken_switches;
6970
mod rendezvous_debug_dataset;
7071
mod semver_version;
7172
mod serde_time_delta;
@@ -203,6 +204,7 @@ pub use producer_endpoint::*;
203204
pub use project::*;
204205
pub use quota::*;
205206
pub use rack::*;
207+
pub use reconfigurator_chicken_switches::*;
206208
pub use region::*;
207209
pub use region_replacement::*;
208210
pub use region_replacement_step::*;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
//! Types representing runtime configuration for reconfigurator
6+
7+
use crate::SqlU32;
8+
use chrono::{DateTime, Utc};
9+
use nexus_db_schema::schema::reconfigurator_chicken_switches;
10+
use nexus_types::deployment;
11+
12+
#[derive(Queryable, Clone, Debug, Selectable, Insertable)]
13+
#[diesel(table_name = reconfigurator_chicken_switches)]
14+
pub struct ReconfiguratorChickenSwitches {
15+
pub version: SqlU32,
16+
pub planner_enabled: bool,
17+
pub time_modified: DateTime<Utc>,
18+
}
19+
20+
impl ReconfiguratorChickenSwitches {
21+
pub fn new(version: u32, planner_enabled: bool) -> Self {
22+
Self {
23+
version: version.into(),
24+
planner_enabled,
25+
time_modified: Utc::now(),
26+
}
27+
}
28+
}
29+
30+
impl From<deployment::ReconfiguratorChickenSwitches>
31+
for ReconfiguratorChickenSwitches
32+
{
33+
fn from(value: deployment::ReconfiguratorChickenSwitches) -> Self {
34+
Self {
35+
version: value.version.into(),
36+
planner_enabled: value.planner_enabled,
37+
time_modified: value.time_modified,
38+
}
39+
}
40+
}
41+
42+
impl From<ReconfiguratorChickenSwitches>
43+
for deployment::ReconfiguratorChickenSwitches
44+
{
45+
fn from(value: ReconfiguratorChickenSwitches) -> Self {
46+
Self {
47+
version: value.version.into(),
48+
planner_enabled: value.planner_enabled,
49+
time_modified: value.time_modified,
50+
}
51+
}
52+
}

nexus/db-model/src/schema_versions.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use std::{collections::BTreeMap, sync::LazyLock};
1616
///
1717
/// This must be updated when you change the database schema. Refer to
1818
/// schema/crdb/README.adoc in the root of this repository for details.
19-
pub const SCHEMA_VERSION: Version = Version::new(152, 0, 0);
19+
pub const SCHEMA_VERSION: Version = Version::new(153, 0, 0);
2020

2121
/// List of all past database schema versions, in *reverse* order
2222
///
@@ -28,6 +28,7 @@ static KNOWN_VERSIONS: LazyLock<Vec<KnownVersion>> = LazyLock::new(|| {
2828
// | leaving the first copy as an example for the next person.
2929
// v
3030
// KnownVersion::new(next_int, "unique-dirname-with-the-sql-files"),
31+
KnownVersion::new(153, "chicken-switches"),
3132
KnownVersion::new(152, "ereports"),
3233
KnownVersion::new(151, "zone-image-resolver-inventory"),
3334
KnownVersion::new(150, "add-last-reconciliation-orphaned-datasets"),

nexus/db-queries/src/db/datastore/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ mod probe;
8383
mod project;
8484
mod quota;
8585
mod rack;
86+
mod reconfigurator_chicken_switches;
8687
mod region;
8788
mod region_replacement;
8889
mod region_snapshot;

0 commit comments

Comments
 (0)