Skip to content

Commit 558f89e

Browse files
authored
TQ: omdb support for listing trust quorum configs per rack (#9792)
Tested on a4x2: ``` root@oxz_switch:~# omdb db trust-quorum list-configs --rack-id 18594251-205a-47f1-926f-7c5230ab2735 note: database URL not specified. Will search DNS. note: (override with --db-url or OMDB_DB_URL) note: using DNS from system config (typically /etc/resolv.conf) note: (if this is not right, use --dns-server to specify an alternate DNS server) note: using database URL postgresql://root@[fd00:17:1:d03::3]:32221,[fd00:17:1:d01::3]:32221,[fd00:17:1:d04::4]:32221,[fd00:17:1:d02::3]:32221,[fd00:17:1:d04::3]:32221/omicron?sslmode=disable note: database schema version matches expected (228.0.0) EPOCH LAST_COMMITTED_EPOCH STATE THRESHOLD COMMIT_CRASH_TOLERANCE COORDINATOR TIME_CREATED TIME_COMMITTING TIME_COMMITTED TIME_ABORTED ABORT_REASON 1 n/a Committed 3 1 3ad41e1a-faa0-47dd-9ec3-e75575ec4388 2026-02-03T21:28:15.740Z 2026-02-03T21:28:15.740Z 2026-02-03T21:28:15.740Z ``` This is just the raw data. You can match the coordinator to the actual part and serial with: ``` root@oxz_switch:~# omdb db inventory baseboard-ids note: database URL not specified. Will search DNS. note: (override with --db-url or OMDB_DB_URL) note: using DNS from system config (typically /etc/resolv.conf) note: (if this is not right, use --dns-server to specify an alternate DNS server) note: using database URL postgresql://root@[fd00:17:1:d03::3]:32221,[fd00:17:1:d01::3]:32221,[fd00:17:1:d04::4]:32221,[fd00:17:1:d02::3]:32221,[fd00:17:1:d04::3]:32221/omicron?sslmode=disable note: database schema version matches expected (228.0.0) ID PART_NUMBER SERIAL_NUMBER 3ad41e1a-faa0-47dd-9ec3-e75575ec4388 913-0000019 20000000 4d75005c-6fa3-40df-af8c-c41b3f3fad17 913-0000019 20000001 ca0f623c-7260-4b00-91e6-6d2a2b68f06e 913-0000019 20000002 40b8965d-89ab-4957-86af-68b11533ffb8 913-0000019 20000003 befe71ec-e7ca-4ee3-b750-fcb9ffd6d68c FAKE_SIM_SIDECAR SimSidecar0 ```
1 parent 360801b commit 558f89e

File tree

3 files changed

+121
-0
lines changed

3 files changed

+121
-0
lines changed

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

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ use omicron_uuid_kinds::InstanceUuid;
161161
use omicron_uuid_kinds::ParseError;
162162
use omicron_uuid_kinds::PhysicalDiskUuid;
163163
use omicron_uuid_kinds::PropolisUuid;
164+
use omicron_uuid_kinds::RackUuid;
164165
use omicron_uuid_kinds::SledUuid;
165166
use omicron_uuid_kinds::VolumeUuid;
166167
use omicron_uuid_kinds::ZpoolUuid;
@@ -435,6 +436,8 @@ enum DbCommands {
435436
/// More precisely, `omdb db whatis` reports tables containing a unique UUID
436437
/// column with the specified value.
437438
Whatis(whatis::WhatisArgs),
439+
/// Print information about trust quorum configurations
440+
TrustQuorum(TrustQuorumArgs),
438441
}
439442

440443
#[derive(Debug, Args, Clone)]
@@ -1162,6 +1165,25 @@ struct SetStorageBufferArgs {
11621165
storage_buffer: i64,
11631166
}
11641167

1168+
#[derive(Debug, Args, Clone)]
1169+
struct TrustQuorumArgs {
1170+
#[command(subcommand)]
1171+
command: TrustQuorumCommands,
1172+
}
1173+
1174+
#[derive(Debug, Subcommand, Clone)]
1175+
enum TrustQuorumCommands {
1176+
/// List trust quorum configurations for a rack
1177+
ListConfigs(TrustQuorumListConfigsArgs),
1178+
}
1179+
1180+
#[derive(Debug, Args, Clone)]
1181+
struct TrustQuorumListConfigsArgs {
1182+
/// Rack ID to list configurations for
1183+
#[arg(long)]
1184+
rack_id: RackUuid,
1185+
}
1186+
11651187
impl DbArgs {
11661188
/// Run a `omdb db` subcommand.
11671189
///
@@ -1532,6 +1554,11 @@ impl DbArgs {
15321554
DbCommands::Whatis(args) => {
15331555
whatis::cmd_db_whatis(&datastore, args).await
15341556
}
1557+
DbCommands::TrustQuorum(TrustQuorumArgs {
1558+
command: TrustQuorumCommands::ListConfigs(args),
1559+
}) => {
1560+
cmd_db_trust_quorum_list_configs(&opctx, &datastore, &fetch_opts, &args).await
1561+
}
15351562
}
15361563
}
15371564
}).await
@@ -8108,3 +8135,69 @@ async fn cmd_db_zpool_set_storage_buffer(
81088135

81098136
Ok(())
81108137
}
8138+
8139+
/// Run `omdb db trust-quorum list-configs`.
8140+
async fn cmd_db_trust_quorum_list_configs(
8141+
opctx: &OpContext,
8142+
datastore: &DataStore,
8143+
fetch_opts: &DbFetchOptions,
8144+
args: &TrustQuorumListConfigsArgs,
8145+
) -> Result<(), anyhow::Error> {
8146+
#[derive(Tabled)]
8147+
#[tabled(rename_all = "SCREAMING_SNAKE_CASE")]
8148+
struct TqConfigRow {
8149+
epoch: i64,
8150+
#[tabled(display_with = "option_impl_display")]
8151+
last_committed_epoch: Option<i64>,
8152+
state: String,
8153+
threshold: u8,
8154+
commit_crash_tolerance: u8,
8155+
coordinator_hardware_baseboard_id: Uuid,
8156+
#[tabled(display_with = "datetime_rfc3339_concise")]
8157+
time_created: DateTime<Utc>,
8158+
#[tabled(display_with = "option_datetime_rfc3339_concise")]
8159+
time_committing: Option<DateTime<Utc>>,
8160+
#[tabled(display_with = "option_datetime_rfc3339_concise")]
8161+
time_committed: Option<DateTime<Utc>>,
8162+
#[tabled(display_with = "option_datetime_rfc3339_concise")]
8163+
time_aborted: Option<DateTime<Utc>>,
8164+
#[tabled(display_with = "display_option_blank")]
8165+
abort_reason: Option<String>,
8166+
}
8167+
8168+
let limit = fetch_opts.fetch_limit;
8169+
let configs = datastore
8170+
.tq_list_config(opctx, args.rack_id, &first_page::<i64>(limit))
8171+
.await
8172+
.context("listing trust quorum configurations")?;
8173+
8174+
check_limit(&configs, limit, || {
8175+
String::from("listing trust quorum configurations")
8176+
});
8177+
8178+
let rows: Vec<TqConfigRow> = configs
8179+
.into_iter()
8180+
.map(|config| TqConfigRow {
8181+
epoch: config.epoch,
8182+
last_committed_epoch: config.last_committed_epoch,
8183+
state: format!("{:?}", config.state),
8184+
threshold: config.threshold.into(),
8185+
commit_crash_tolerance: config.commit_crash_tolerance.into(),
8186+
coordinator_hardware_baseboard_id: config.coordinator,
8187+
time_created: config.time_created,
8188+
time_committing: config.time_committing,
8189+
time_committed: config.time_committed,
8190+
time_aborted: config.time_aborted,
8191+
abort_reason: config.abort_reason,
8192+
})
8193+
.collect();
8194+
8195+
let table = tabled::Table::new(rows)
8196+
.with(tabled::settings::Style::empty())
8197+
.with(tabled::settings::Padding::new(0, 1, 0, 0))
8198+
.to_string();
8199+
8200+
println!("{}", table);
8201+
8202+
Ok(())
8203+
}

dev-tools/omdb/tests/usage_errors.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ Commands:
152152
zpool Commands for querying and interacting with pools
153153
user-data-export Commands for querying and interacting with user data export objects
154154
whatis Given a UUID, try to figure out what type of object it refers to
155+
trust-quorum Print information about trust quorum configurations
155156
help Print this message or the help of the given subcommand(s)
156157

157158
Options:
@@ -218,6 +219,7 @@ Commands:
218219
zpool Commands for querying and interacting with pools
219220
user-data-export Commands for querying and interacting with user data export objects
220221
whatis Given a UUID, try to figure out what type of object it refers to
222+
trust-quorum Print information about trust quorum configurations
221223
help Print this message or the help of the given subcommand(s)
222224

223225
Options:

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use super::DataStore;
88
use crate::authz;
99
use crate::context::OpContext;
10+
use crate::db::pagination::paginated;
1011
use async_bb8_diesel::AsyncRunQueryDsl;
1112
use chrono::Utc;
1213
use diesel::prelude::*;
@@ -27,7 +28,9 @@ use nexus_types::trust_quorum::{
2728
TrustQuorumConfig, TrustQuorumConfigState, TrustQuorumMemberData,
2829
TrustQuorumMemberState,
2930
};
31+
use omicron_common::api::external::DataPageParams;
3032
use omicron_common::api::external::Error;
33+
use omicron_common::api::external::ListResultVec;
3134
use omicron_common::api::external::LookupType;
3235
use omicron_common::api::external::OptionalLookupResult;
3336
use omicron_common::bail_unless;
@@ -177,6 +180,29 @@ impl DataStore {
177180
.map_err(|err| err.into_public_ignore_retries())
178181
}
179182

183+
pub async fn tq_list_config(
184+
&self,
185+
opctx: &OpContext,
186+
rack_id: RackUuid,
187+
pagparams: &DataPageParams<'_, i64>,
188+
) -> ListResultVec<DbTrustQuorumConfiguration> {
189+
let authz_rack = authz::Rack::new(
190+
authz::FLEET,
191+
rack_id.into_untyped_uuid(),
192+
LookupType::ById(rack_id.into_untyped_uuid()),
193+
);
194+
opctx.authorize(authz::Action::Read, &authz_rack).await?;
195+
let conn = &*self.pool_connection_authorized(opctx).await?;
196+
197+
use nexus_db_schema::schema::trust_quorum_configuration::dsl;
198+
paginated(dsl::trust_quorum_configuration, dsl::epoch, pagparams)
199+
.filter(dsl::rack_id.eq(DbTypedUuid::<RackKind>::from(rack_id)))
200+
.select(DbTrustQuorumConfiguration::as_select())
201+
.load_async(conn)
202+
.await
203+
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
204+
}
205+
180206
/// Get the trust quorum configuration from the database for the given Epoch
181207
pub async fn tq_get_config(
182208
&self,

0 commit comments

Comments
 (0)