Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
6 changes: 6 additions & 0 deletions dev-tools/omdb/src/bin/omdb/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ mod db_metadata;
mod ereport;
mod saga;
mod sitrep;
mod target_release;
mod user_data_export;
mod whatis;

Expand Down Expand Up @@ -405,6 +406,8 @@ enum DbCommands {
Sleds(SledsArgs),
/// Show instances grouped by the sled they are running on
SledInstances(SledInstancesArgs),
/// Print the current target release and the update date
TargetRelease(target_release::TargetReleaseArgs),
/// Print information about customer instances.
Instance(InstanceArgs),
/// Alias to `omdb instance list`.
Expand Down Expand Up @@ -1453,6 +1456,9 @@ impl DbArgs {
)
.await
}
DbCommands::TargetRelease(args) => {
target_release::cmd_db_target_release(&opctx, &datastore, args).await
}
DbCommands::Instance(InstanceArgs {
command: InstanceCommands::List(args),
}) => {
Expand Down
103 changes: 103 additions & 0 deletions dev-tools/omdb/src/bin/omdb/db/target_release.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// 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 db target-release` subcommand
//!
//! Shows the current target release and date when update was requested.
//! When `--all` option is used, lists all target release records.
Comment on lines +7 to +8
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking a closer look, we may want to change the functionality of the command a bit. Right now we only have two options right? All or one. What if the user wants to see just the latest 5?

In this scenario, it's probably a simpler user experience to have a command that always shows a list of target releases with a limit of records shown. Something like omdb target-release list or omdb target-releases with an optional fetch-limit or --limit flag. This way a user can say I want to see the latest one, or the last 10, or 100 or whatever.

We already have this implemented for several endpoints (DbFetchOptions), see cmd_db_blueprints, cmd_db_physical_disks etc. If DbFetchOptions doesn't make sense for this command, you can also look at how cmd_reconfigurator_config_history implements a --limit flag.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have a --fetch-limit flag on omdb db that applies to any subcommand that respects it (which this one does AFAICT, but it would be good to test / confirm).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I re-added the DbFetchOptions to respect this.

root@oxz_switch0:/tmp# ./omdb-em db --fetch-limit 8 target-release --all
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:1122:3344:109::3]:32221,[fd00:1122:3344:105::3]:32221,[fd00:1122:3344:10b::3]:32221,[fd00:1122:3344:107::3]:32221,[fd00:1122:3344:108::3]:32221/omicron?sslmode=disable
WARN: found schema version 257.0.0, expected 261.0.0
It's possible the database is running a version that's different from what this
tool understands.  This may result in errors or incorrect output.
WARN: listing target releases: found 8 items (the limit).  There may be more items that were ignored.  Consider overriding with --fetch-limit.
 TARGET_RELEASE              TIME_REQUESTED
 19.0.0-0.ci+git42726ecbb1b  2026-04-08T00:25:34.431Z
 19.1.0-0.ci+git073b1306678  2026-04-11T03:25:49.438Z
 19.1.0-0.ci+gitbc696216ef5  2026-04-13T23:24:19.034Z
 19.1.0-0.ci+gitc7312331b08  2026-04-14T21:02:48.258Z
 19.2.0-0.ci+gite4b75dde134  2026-04-21T23:11:22.248Z
 19.3.0-0.ci+gitd4a126e8cc3  2026-05-05T23:45:46.284Z
 19.4.0-0.ci+gitbae719a3bdb  2026-05-13T15:11:13.005Z
 20.0.0-0.ci+git8ca64d81e70  2026-05-15T19:02:14.696Z


use crate::helpers::datetime_rfc3339_concise;
use anyhow::Context;
use async_bb8_diesel::AsyncRunQueryDsl;
use clap::Args;
use diesel::QueryDsl;
use diesel::SelectableHelper;
use nexus_db_model::TargetRelease;
use nexus_db_model::TargetReleaseSource;
use nexus_db_queries::context::OpContext;
use nexus_db_queries::db::DataStore;
use nexus_db_queries::db::datastore::SQL_BATCH_SIZE;
use nexus_db_queries::db::pagination::Paginator;
use nexus_db_queries::db::pagination::paginated;
use nexus_db_schema::schema::target_release::dsl;
use tabled::Tabled;

#[derive(Debug, Args, Clone)]
pub(super) struct TargetReleaseArgs {
/// List of target releases sorted from oldest to newest
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the sample, isn't it the other way around?

#[clap(long)]
all: bool,
}

#[derive(Tabled)]
#[tabled(rename_all = "SCREAMING_SNAKE_CASE")]
struct TargetReleaseRow {
system_version: String,
time_requested: String,
}

pub(super) async fn cmd_db_target_release(
opctx: &OpContext,
datastore: &DataStore,
args: &TargetReleaseArgs,
) -> Result<(), anyhow::Error> {
let releases = if args.all {
let conn = datastore.pool_connection_for_tests().await?;
let mut releases: Vec<TargetRelease> = Vec::new();
let mut paginator = Paginator::new(
SQL_BATCH_SIZE,
dropshot::PaginationOrder::Ascending,
);
while let Some(p) = paginator.next() {
let batch = paginated(
dsl::target_release,
dsl::generation,
&p.current_pagparams(),
)
.select(TargetRelease::as_select())
.load_async(&*conn)
.await
.context("listing target releases")?;
paginator =
p.found_batch(&batch, &|r: &TargetRelease| r.generation);
releases.extend(batch);
}
releases
} else {
vec![
datastore
.target_release_get_current(opctx)
.await
.context("fetching current target release")?,
]
};

let mut rows = Vec::with_capacity(releases.len());
for release in releases {
let system_version = match release
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we are adding unspecified here too, so the variable isn't really system_version, but rather target_release.

.release_source()
.context("interpreting target release source")?
{
TargetReleaseSource::Unspecified => "<unspecified>".to_string(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unspecified means no target release has been set yet, is it useful to have this as part of the list or target releases?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is printing rows from the db - what would you do instead of printing a sentinel like this? Neither skipping nor failing seems great to me.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of skipping, but yeah, it would be useful to know when there have been unspecified target releases

TargetReleaseSource::SystemVersion(tuf_repo_id) => datastore
.tuf_repo_get_version(opctx, &tuf_repo_id)
.await
.with_context(|| format!("fetching TUF repo {tuf_repo_id}"))?
.to_string(),
};
rows.push(TargetReleaseRow {
system_version,
time_requested: datetime_rfc3339_concise(&release.time_requested),
});
}

let table = tabled::Table::new(rows)
.with(tabled::settings::Style::empty())
.with(tabled::settings::Padding::new(1, 1, 0, 0))
.to_string();
Comment thread
karencfv marked this conversation as resolved.

println!("{}", table);

Ok(())
}
2 changes: 2 additions & 0 deletions dev-tools/omdb/tests/usage_errors.out
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ Commands:
sitreps Show the current history of fault management situation reports
sleds Print information about sleds
sled-instances Show instances grouped by the sled they are running on
target-release Print the current target release and the update date
instance Print information about customer instances
instances Alias to `omdb instance list`
network Print information about the network
Expand Down Expand Up @@ -210,6 +211,7 @@ Commands:
sitreps Show the current history of fault management situation reports
sleds Print information about sleds
sled-instances Show instances grouped by the sled they are running on
target-release Print the current target release and the update date
instance Print information about customer instances
instances Alias to `omdb instance list`
network Print information about the network
Expand Down
Loading