Skip to content

Commit d300fb8

Browse files
authored
Omdb networking (#4147)
1 parent 6bc5e60 commit d300fb8

File tree

5 files changed

+203
-0
lines changed

5 files changed

+203
-0
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dev-tools/omdb/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ textwrap.workspace = true
3333
tokio = { workspace = true, features = [ "full" ] }
3434
uuid.workspace = true
3535
omicron-workspace-hack = { version = "0.1", path = "../../workspace-hack" }
36+
ipnetwork.workspace = true
3637

3738
[dev-dependencies]
3839
expectorate.workspace = true

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

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
//! would be the only consumer -- and in that case it's okay to query the
1313
//! database directly.
1414
15+
// NOTE: eminates from Tabled macros
16+
#![allow(clippy::useless_vec)]
17+
1518
use crate::Omdb;
1619
use anyhow::anyhow;
1720
use anyhow::bail;
@@ -30,7 +33,9 @@ use nexus_db_model::DnsGroup;
3033
use nexus_db_model::DnsName;
3134
use nexus_db_model::DnsVersion;
3235
use nexus_db_model::DnsZone;
36+
use nexus_db_model::ExternalIp;
3337
use nexus_db_model::Instance;
38+
use nexus_db_model::Project;
3439
use nexus_db_model::Region;
3540
use nexus_db_model::Sled;
3641
use nexus_db_model::Zpool;
@@ -86,6 +91,8 @@ enum DbCommands {
8691
Sleds,
8792
/// Print information about customer instances
8893
Instances,
94+
/// Print information about the network
95+
Network(NetworkArgs),
8996
}
9097

9198
#[derive(Debug, Args)]
@@ -170,6 +177,22 @@ enum ServicesCommands {
170177
ListBySled,
171178
}
172179

180+
#[derive(Debug, Args)]
181+
struct NetworkArgs {
182+
#[command(subcommand)]
183+
command: NetworkCommands,
184+
185+
/// Print out raw data structures from the data store.
186+
#[clap(long)]
187+
verbose: bool,
188+
}
189+
190+
#[derive(Debug, Subcommand)]
191+
enum NetworkCommands {
192+
/// List external IPs
193+
ListEips,
194+
}
195+
173196
impl DbArgs {
174197
/// Run a `omdb db` subcommand.
175198
pub(crate) async fn run_cmd(
@@ -269,6 +292,13 @@ impl DbArgs {
269292
DbCommands::Instances => {
270293
cmd_db_instances(&datastore, self.fetch_limit).await
271294
}
295+
DbCommands::Network(NetworkArgs {
296+
command: NetworkCommands::ListEips,
297+
verbose,
298+
}) => {
299+
cmd_db_eips(&opctx, &datastore, self.fetch_limit, *verbose)
300+
.await
301+
}
272302
}
273303
}
274304
}
@@ -1098,6 +1128,156 @@ async fn cmd_db_dns_names(
10981128
Ok(())
10991129
}
11001130

1131+
async fn cmd_db_eips(
1132+
opctx: &OpContext,
1133+
datastore: &DataStore,
1134+
limit: NonZeroU32,
1135+
verbose: bool,
1136+
) -> Result<(), anyhow::Error> {
1137+
use db::schema::external_ip::dsl;
1138+
let ips: Vec<ExternalIp> = dsl::external_ip
1139+
.filter(dsl::time_deleted.is_null())
1140+
.select(ExternalIp::as_select())
1141+
.get_results_async(&*datastore.pool_connection_for_tests().await?)
1142+
.await?;
1143+
1144+
check_limit(&ips, limit, || String::from("listing external ips"));
1145+
1146+
struct PortRange {
1147+
first: u16,
1148+
last: u16,
1149+
}
1150+
1151+
impl Display for PortRange {
1152+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1153+
write!(f, "{}/{}", self.first, self.last)
1154+
}
1155+
}
1156+
1157+
#[derive(Tabled)]
1158+
enum Owner {
1159+
Instance { project: String, name: String },
1160+
Service { kind: String },
1161+
None,
1162+
}
1163+
1164+
impl Display for Owner {
1165+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1166+
match self {
1167+
Self::Instance { project, name } => {
1168+
write!(f, "Instance {project}/{name}")
1169+
}
1170+
Self::Service { kind } => write!(f, "Service {kind}"),
1171+
Self::None => write!(f, "None"),
1172+
}
1173+
}
1174+
}
1175+
1176+
#[derive(Tabled)]
1177+
struct IpRow {
1178+
ip: ipnetwork::IpNetwork,
1179+
ports: PortRange,
1180+
kind: String,
1181+
owner: Owner,
1182+
}
1183+
1184+
if verbose {
1185+
for ip in &ips {
1186+
if verbose {
1187+
println!("{ip:#?}");
1188+
}
1189+
}
1190+
return Ok(());
1191+
}
1192+
1193+
let mut rows = Vec::new();
1194+
1195+
for ip in &ips {
1196+
let owner = if let Some(owner_id) = ip.parent_id {
1197+
if ip.is_service {
1198+
let service = match LookupPath::new(opctx, datastore)
1199+
.service_id(owner_id)
1200+
.fetch()
1201+
.await
1202+
{
1203+
Ok(instance) => instance,
1204+
Err(e) => {
1205+
eprintln!(
1206+
"error looking up service with id {owner_id}: {e}"
1207+
);
1208+
continue;
1209+
}
1210+
};
1211+
Owner::Service { kind: format!("{:?}", service.1.kind) }
1212+
} else {
1213+
use db::schema::instance::dsl as instance_dsl;
1214+
let instance = match instance_dsl::instance
1215+
.filter(instance_dsl::id.eq(owner_id))
1216+
.limit(1)
1217+
.select(Instance::as_select())
1218+
.load_async(&*datastore.pool_connection_for_tests().await?)
1219+
.await
1220+
.context("loading requested instance")?
1221+
.pop()
1222+
{
1223+
Some(instance) => instance,
1224+
None => {
1225+
eprintln!("instance with id {owner_id} not found");
1226+
continue;
1227+
}
1228+
};
1229+
1230+
use db::schema::project::dsl as project_dsl;
1231+
let project = match project_dsl::project
1232+
.filter(project_dsl::id.eq(instance.project_id))
1233+
.limit(1)
1234+
.select(Project::as_select())
1235+
.load_async(&*datastore.pool_connection_for_tests().await?)
1236+
.await
1237+
.context("loading requested project")?
1238+
.pop()
1239+
{
1240+
Some(instance) => instance,
1241+
None => {
1242+
eprintln!(
1243+
"project with id {} not found",
1244+
instance.project_id
1245+
);
1246+
continue;
1247+
}
1248+
};
1249+
1250+
Owner::Instance {
1251+
project: project.name().to_string(),
1252+
name: instance.name().to_string(),
1253+
}
1254+
}
1255+
} else {
1256+
Owner::None
1257+
};
1258+
1259+
let row = IpRow {
1260+
ip: ip.ip,
1261+
ports: PortRange {
1262+
first: ip.first_port.into(),
1263+
last: ip.last_port.into(),
1264+
},
1265+
kind: format!("{:?}", ip.kind),
1266+
owner,
1267+
};
1268+
rows.push(row);
1269+
}
1270+
1271+
rows.sort_by(|a, b| a.ip.cmp(&b.ip));
1272+
let table = tabled::Table::new(rows)
1273+
.with(tabled::settings::Style::empty())
1274+
.to_string();
1275+
1276+
println!("{}", table);
1277+
1278+
Ok(())
1279+
}
1280+
11011281
fn print_name(
11021282
prefix: &str,
11031283
name: &str,

dev-tools/omdb/tests/test_all_output.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ async fn test_omdb_usage_errors() {
4141
&["db", "dns", "diff"],
4242
&["db", "dns", "names"],
4343
&["db", "services"],
44+
&["db", "network"],
4445
&["nexus"],
4546
&["nexus", "background-tasks"],
4647
&["sled-agent"],

dev-tools/omdb/tests/usage_errors.out

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ Commands:
9191
services Print information about control plane services
9292
sleds Print information about sleds
9393
instances Print information about customer instances
94+
network Print information about the network
9495
help Print this message or the help of the given subcommand(s)
9596

9697
Options:
@@ -112,6 +113,7 @@ Commands:
112113
services Print information about control plane services
113114
sleds Print information about sleds
114115
instances Print information about customer instances
116+
network Print information about the network
115117
help Print this message or the help of the given subcommand(s)
116118

117119
Options:
@@ -186,6 +188,24 @@ Commands:
186188
Options:
187189
-h, --help Print help
188190
=============================================
191+
EXECUTING COMMAND: omdb ["db", "network"]
192+
termination: Exited(2)
193+
---------------------------------------------
194+
stdout:
195+
---------------------------------------------
196+
stderr:
197+
Print information about the network
198+
199+
Usage: omdb db network [OPTIONS] <COMMAND>
200+
201+
Commands:
202+
list-eips List external IPs
203+
help Print this message or the help of the given subcommand(s)
204+
205+
Options:
206+
--verbose Print out raw data structures from the data store
207+
-h, --help Print help
208+
=============================================
189209
EXECUTING COMMAND: omdb ["nexus"]
190210
termination: Exited(2)
191211
---------------------------------------------

0 commit comments

Comments
 (0)