Skip to content

Commit 4653031

Browse files
committed
[omdb] add initial webhook receiver OMDB commands
This commit adds some quick OMDB commands for listing and displaying webhook receivers. Subsequent commits will also add support for inspecting event deliveries to receivers, but I wanted to get the basic stuff in first.
1 parent d4cc2ec commit 4653031

File tree

2 files changed

+213
-6
lines changed

2 files changed

+213
-6
lines changed

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

+211-6
Original file line numberDiff line numberDiff line change
@@ -6919,7 +6919,7 @@ async fn cmd_db_webhook(
69196919
} => cmd_db_webhook_rx_list(opctx, datastore, fetch_opts, args).await,
69206920
WebhookCommands::Receiver {
69216921
command: WebhookRxCommands::Info(args),
6922-
} => cmd_db_webhook_rx_info(opctx, datastore, fetch_opts, args).await,
6922+
} => cmd_db_webhook_rx_info(datastore, fetch_opts, args).await,
69236923
WebhookCommands::Event => {
69246924
Err(anyhow::anyhow!("not yet implemented, sorry!"))
69256925
}
@@ -6986,12 +6986,217 @@ async fn cmd_db_webhook_rx_list(
69866986
}
69876987

69886988
async fn cmd_db_webhook_rx_info(
6989-
_opctx: &OpContext,
6990-
_datastore: &DataStore,
6991-
_fetch_opts: &DbFetchOptions,
6992-
_args: &WebhookRxInfoArgs,
6989+
datastore: &DataStore,
6990+
fetch_opts: &DbFetchOptions,
6991+
args: &WebhookRxInfoArgs,
69936992
) -> anyhow::Result<()> {
6994-
anyhow::bail!("TODO: eliza, implement this one!")
6993+
use db::model::schema::webhook_receiver::dsl as rx_dsl;
6994+
use db::model::schema::webhook_rx_event_glob::dsl as glob_dsl;
6995+
use db::model::schema::webhook_rx_subscription::dsl as subscription_dsl;
6996+
use db::model::schema::webhook_secret::dsl as secret_dsl;
6997+
6998+
let conn = datastore.pool_connection_for_tests().await?;
6999+
let mut query = match args.receiver {
7000+
NameOrId::Id(id) => {
7001+
rx_dsl::webhook_receiver.filter(rx_dsl::id.eq(id)).into_boxed()
7002+
}
7003+
NameOrId::Name(ref name) => rx_dsl::webhook_receiver
7004+
.filter(rx_dsl::name.eq(name.to_string()))
7005+
.into_boxed(),
7006+
};
7007+
if !fetch_opts.include_deleted {
7008+
query = query.filter(rx_dsl::time_deleted.is_null());
7009+
}
7010+
7011+
let rx = query
7012+
.limit(1)
7013+
.select(db::model::WebhookReceiver::as_select())
7014+
.get_result_async(&*conn)
7015+
.await
7016+
.optional()
7017+
.with_context(|| format!("loading webhook receiver {}", args.receiver))?
7018+
.ok_or_else(|| {
7019+
anyhow::anyhow!("no instance {} exists", args.receiver)
7020+
})?;
7021+
7022+
const ID: &'static str = "ID";
7023+
const NAME: &'static str = "name";
7024+
7025+
const DESCRIPTION: &'static str = "description";
7026+
const CREATED: &'static str = "created at";
7027+
const DELETED: &'static str = "deleted at";
7028+
const MODIFIED: &'static str = "modified at";
7029+
const ENDPOINT: &'static str = "endpoint";
7030+
const GEN: &'static str = "generation";
7031+
const EXACT: &'static str = "exact subscriptions";
7032+
const GLOBS: &'static str = "glob subscriptions";
7033+
const GLOB_REGEX: &'static str = " regex";
7034+
const GLOB_SCHEMA_VERSION: &'static str = " schema version";
7035+
const GLOB_CREATED: &'static str = " created at";
7036+
const GLOB_EXACT: &'static str = " exact subscriptions";
7037+
const WIDTH: usize = const_max_len(&[
7038+
ID,
7039+
NAME,
7040+
DESCRIPTION,
7041+
CREATED,
7042+
DELETED,
7043+
MODIFIED,
7044+
ENDPOINT,
7045+
GEN,
7046+
EXACT,
7047+
GLOBS,
7048+
GLOB_REGEX,
7049+
GLOB_SCHEMA_VERSION,
7050+
GLOB_CREATED,
7051+
GLOB_EXACT,
7052+
]);
7053+
7054+
let db::model::WebhookReceiver {
7055+
identity:
7056+
db::model::WebhookReceiverIdentity {
7057+
id,
7058+
name,
7059+
description,
7060+
time_created,
7061+
time_modified,
7062+
time_deleted,
7063+
},
7064+
endpoint,
7065+
secret_gen,
7066+
subscription_gen,
7067+
} = rx;
7068+
7069+
println!("\n{:=<80}", "== RECEIVER ");
7070+
println!(" {NAME:>WIDTH$}: {name}");
7071+
println!(" {ID:>WIDTH$}: {id}");
7072+
println!(" {DESCRIPTION:>WIDTH$}: {description}");
7073+
println!(" {ENDPOINT:>WIDTH$}: {endpoint}");
7074+
println!();
7075+
println!(" {CREATED:>WIDTH$}: {time_created}");
7076+
println!(" {MODIFIED:>WIDTH$}: {time_modified}");
7077+
if let Some(deleted) = time_deleted {
7078+
println!(" {DELETED:>WIDTH$}: {deleted}");
7079+
}
7080+
7081+
println!("\n{:=<80}", "== SECRETS ");
7082+
println!(" {GEN:>WIDTH$}: {}", secret_gen.0);
7083+
7084+
let query = secret_dsl::webhook_secret
7085+
.filter(secret_dsl::rx_id.eq(id.into_untyped_uuid()))
7086+
.select(db::model::WebhookSecret::as_select());
7087+
let secrets = if fetch_opts.include_deleted {
7088+
query.load_async(&*conn).await
7089+
} else {
7090+
query
7091+
.filter(secret_dsl::time_deleted.is_null())
7092+
.load_async(&*conn)
7093+
.await
7094+
};
7095+
7096+
match secrets {
7097+
Ok(secrets) => {
7098+
#[derive(Tabled)]
7099+
struct SecretRow {
7100+
id: Uuid,
7101+
7102+
#[tabled(display_with = "datetime_rfc3339_concise")]
7103+
created: chrono::DateTime<Utc>,
7104+
7105+
#[tabled(display_with = "datetime_opt_rfc3339_concise")]
7106+
deleted: Option<chrono::DateTime<Utc>>,
7107+
}
7108+
let rows = secrets.into_iter().map(
7109+
|db::model::WebhookSecret {
7110+
identity:
7111+
db::model::WebhookSecretIdentity {
7112+
id,
7113+
time_modified: _,
7114+
time_created,
7115+
},
7116+
webhook_receiver_id: _,
7117+
secret: _,
7118+
time_deleted,
7119+
}| SecretRow {
7120+
id: id.into_untyped_uuid(),
7121+
created: time_created,
7122+
deleted: time_deleted,
7123+
},
7124+
);
7125+
7126+
let table = tabled::Table::new(rows)
7127+
.with(tabled::settings::Style::empty())
7128+
.with(tabled::settings::Padding::new(0, 1, 0, 0))
7129+
.to_string();
7130+
println!("{table}");
7131+
}
7132+
Err(e) => eprintln!("failed to list secrets: {e}"),
7133+
}
7134+
7135+
println!("\n{:=<80}", "== SUBSCRIPTIONS ");
7136+
println!(" {GEN:>WIDTH$}: {}", subscription_gen.0);
7137+
7138+
let exact = subscription_dsl::webhook_rx_subscription
7139+
.filter(subscription_dsl::rx_id.eq(id.into_untyped_uuid()))
7140+
.filter(subscription_dsl::glob.is_null())
7141+
.select(subscription_dsl::event_class)
7142+
.load_async::<db::model::WebhookEventClass>(&*conn)
7143+
.await;
7144+
match exact {
7145+
Ok(exact) => {
7146+
println!(" {EXACT:>WIDTH$}: {}", exact.len());
7147+
for event_class in exact {
7148+
println!(" - {event_class}");
7149+
}
7150+
}
7151+
Err(e) => {
7152+
eprintln!("failed to list exact subscriptions: {e}");
7153+
}
7154+
}
7155+
7156+
let globs = glob_dsl::webhook_rx_event_glob
7157+
.filter(glob_dsl::rx_id.eq(id.into_untyped_uuid()))
7158+
.select(db::model::WebhookRxEventGlob::as_select())
7159+
.load_async::<db::model::WebhookRxEventGlob>(&*conn)
7160+
.await;
7161+
match globs {
7162+
Ok(globs) => {
7163+
println!(" {GLOBS:>WIDTH$}: {}", globs.len());
7164+
for glob in globs {
7165+
let db::model::WebhookRxEventGlob {
7166+
rx_id: _,
7167+
glob: db::model::WebhookGlob { glob, regex },
7168+
time_created,
7169+
schema_version,
7170+
} = glob;
7171+
println!(" - {glob}");
7172+
println!(" {GLOB_CREATED:>WIDTH$}: {time_created}");
7173+
println!(" {GLOB_SCHEMA_VERSION:>WIDTH$}: {schema_version}");
7174+
println!(" {GLOB_REGEX:>WIDTH$}: {regex}");
7175+
let exact = subscription_dsl::webhook_rx_subscription
7176+
.filter(subscription_dsl::rx_id.eq(id.into_untyped_uuid()))
7177+
.filter(subscription_dsl::glob.eq(glob))
7178+
.select(subscription_dsl::event_class)
7179+
.load_async::<db::model::WebhookEventClass>(&*conn)
7180+
.await;
7181+
match exact {
7182+
Ok(exact) => {
7183+
println!(" {GLOB_EXACT:>WIDTH$}: {}", exact.len());
7184+
for event_class in exact {
7185+
println!(" - {event_class}")
7186+
}
7187+
}
7188+
Err(e) => eprintln!(
7189+
"failed to list exact subscriptions for glob: {e}"
7190+
),
7191+
}
7192+
}
7193+
}
7194+
Err(e) => {
7195+
eprintln!("failed to list glob subscriptions: {e}");
7196+
}
7197+
}
7198+
7199+
Ok(())
69957200
}
69967201

69977202
// Format a `chrono::DateTime` in RFC3339 with milliseconds precision and using

dev-tools/omdb/tests/usage_errors.out

+2
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ Commands:
137137
processes
138138
vmms Alias to `omdb db vmm list`
139139
oximeter Print information about the oximeter collector
140+
webhook Print information about webhooks
140141
help Print this message or the help of the given subcommand(s)
141142

142143
Options:
@@ -190,6 +191,7 @@ Commands:
190191
processes
191192
vmms Alias to `omdb db vmm list`
192193
oximeter Print information about the oximeter collector
194+
webhook Print information about webhooks
193195
help Print this message or the help of the given subcommand(s)
194196

195197
Options:

0 commit comments

Comments
 (0)