Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ All notable changes to this project will be documented in this file.
- Ship shell-completion scripts in the client installer and recommend `bash-completion` so apt/dnf pull it in when available. `build/` is added to `.gitignore`.
- Migrate all six `exchange` verbs (`create`, `update`, `list`, `get`, `delete`, `set-device`) to the RFC-20 conforming shape on top of the shared CLI helpers. Every verb is now `pub async fn execute(self, ctx: &CliContext, client: &C, out: &mut W) -> eyre::Result<()>`, consumes the helpers (`require!`, `render_collection`, `render_record`, `print_signature`), and the update/delete/set-device paths route their pubkey-or-code argument through a new `resolve_exchange_pk` helper in `smartcontract/cli/src/helpers.rs`. The pre-existing BGP community range check in `exchange update` is preserved. `exchange set-device` retains its legacy `Option<String>::and_then` semantics for `--device1` / `--device2` (an unknown device silently resolves to `None`, which clears the slot) under an explanatory comment. `controlplane/doublezero-admin`, the unified `doublezero` binary, and the serviceability dispatcher all forward `&ctx` and await every exchange arm. Behavior is byte-identical: table layout, JSON schema, `Signature: <sig>` line, and `--json` / `--json-compact` semantics match pre-refactor output exactly; all 7 exchange unit tests pass without assertion changes.
- Migrate all five `contributor` verbs (`create`, `update`, `list`, `get`, `delete`) to the RFC-20 conforming shape on top of the shared CLI helpers. Every verb is now `pub async fn execute(self, ctx: &CliContext, client: &C, out: &mut W) -> eyre::Result<()>`, consumes the helpers (`require!`, `render_collection`, `render_record`, `print_signature`), and `update` / `delete` route their pubkey-or-code argument through a new `resolve_contributor_pk` helper in `smartcontract/cli/src/helpers.rs`. The duplicate-code precondition in `create` and `update` is preserved, as is the `owner = "me"` short-circuit in `create` that resolves to the payer. `update`'s pubkey resolution now goes through the shared helper rather than an in-line `Pubkey::from_str` (the old code-by-pubkey path was a code-or-pubkey path despite the variable name; the resolver accepts both). `controlplane/doublezero-admin`, the unified `doublezero` binary, and the serviceability dispatcher all forward `&ctx` and await every contributor arm. Behavior is byte-identical: table layout, JSON schema, `Signature: <sig>` line, and `--json` / `--json-compact` semantics match pre-refactor output exactly; all 5 contributor unit tests pass without assertion changes.
- Migrate the 5 `multicastgroup` CRUD verbs (`create`, `update`, `list`, `get`, `delete`), the 6 `multicastgroup allowlist` verbs (publisher + subscriber `add`/`list`/`remove`), the 6 standalone foundation/QA `allowlist` verbs (`foundation add`/`list`/`remove`, `qa add`/`list`/`remove`), the 8 `user` verbs (`create`, `create-subscribe`, `subscribe`, `request-ban`, `update`, `list`, `get`, `delete`), and the 9 `globalconfig` verbs and sub-tree verbs (`get`, `set`, `set-version`, `airdrop get`/`set`, `authority get`/`set`, `feature-flags get`/`set`) to the RFC-20 `pub async fn execute(self, ctx: &CliContext, client, out)` signature. Signature-only sweep: verb bodies (including the post-write `--wait` polling in `user create-subscribe`/`subscribe` and the bespoke `multicastgroup update` re-fetch flow) are unchanged. `MulticastGroupCommands::execute` itself flips from sync to async and propagates `ctx` through its nested allowlist arms; the binary's `Multicast` arm becomes `args.command.execute(&ctx, &client, &mut handle).await` (single line). Test files gain the per-file `block_on` shim and `cli_context_default_for_tests()` import. `controlplane/doublezero-admin`, the unified `doublezero` binary, and the serviceability dispatcher all forward `&ctx` and await every multicastgroup, allowlist, user, and globalconfig arm. All 345 unit tests pass byte-identically. Helper adoption (`require!`, `print_signature`, `render_collection`, `render_record`) lands opportunistically in follow-up PRs.
- Migrate the 11 `device` and `device interface` verbs (device `create`, `update`, `list`, `get`, `delete`, `set-health` plus interface `create`, `update`, `list`, `get`, `delete`) and the 14 `link` and `topology` verbs (link `accept`, `delete`, `wan create`, `dzx create`, `get`, `latency`, `list`, `set-health`, `update` plus topology `assign-node-segments`, `clear`, `create`, `delete`, `list`) to the RFC-20 `pub async fn execute(self, ctx: &CliContext, client, out)` signature. Signature-only sweep: verb bodies (including `--wait` polling via `poll_for_*_activated`, the per-verb requirement checks, and the `Signature:` writes) are unchanged. Test files gain a per-file `block_on` shim and `cli_context_default_for_tests()` import so the existing sync `#[test]` bodies can drive the now-async `execute`. `controlplane/doublezero-admin`, the unified `doublezero` binary, and the serviceability dispatcher all forward `&ctx` and await every device, interface, link, and topology arm. All 345 unit tests pass byte-identically (92 in the migrated modules: device 46, link 29, topology 17). Helper adoption (`require!`, `print_signature`, `render_collection`, `render_record`) lands opportunistically in follow-up PRs; the `--wait` polling flow on `device create/update`, `device interface create/update`, `link wan-create`/`dzx-create`/`accept`/`update` needs special handling there since the post-signature poll has to be preserved.
- Migrate all six `accesspass` verbs (`set`, `close`, `list`, `get`, `user-balances`, `fund`) and all six `resource` verbs (`allocate`, `create`, `deallocate`, `get`, `close`, `verify`), plus the eight leaf single-file verbs (`address`, `balance`, `init`, `migrate`, `keygen`, `export`, `config get`, `config set`), to the RFC-20 `pub async fn execute(self, ctx: &CliContext, client, out) -> eyre::Result<()>` signature. The five small leaf verbs (`address`, `balance`, `init`, `migrate`, `keygen`) also adopt the `require!` macro and (where applicable) the `print_signature` helper since their bodies were one-line readiness checks paired with a single `Signature:` write. The larger and more idiosyncratic verbs (`config get`/`set` which manipulate the persisted YAML, `export` which serializes the whole graph, the accesspass and resource verbs which contain bespoke output and progress-spinner logic) keep their existing bodies for now and only get the signature flip; helper adoption for those lands opportunistically in follow-up PRs. `controlplane/doublezero-admin`, the unified `doublezero` binary, and the serviceability dispatcher all forward `&ctx` and await every accesspass, resource, and leaf-verb arm. `config get`/`set` tests gain a per-file `block_on` shim and a `cli_context_default_for_tests()` import so the existing sync `#[test]` bodies can still drive the now-async `execute`. The bespoke `accesspass fund` signature (`R: BufRead` for stdin) is preserved — only the `_ctx` parameter is inserted after `self`. Behavior is byte-identical: table layouts, JSON schemas, `Signature:` lines, the `fund` interactive flow, and the `config` text output all match the pre-refactor strings exactly; all 345 unit tests pass without assertion changes.
- Migrate all eight `tenant` verbs (`create`, `update`, `list`, `get`, `delete`, `administrator add`, `administrator remove`, `update-payment-status`) and all six `permission` verbs (`set`, `suspend`, `resume`, `delete`, `get`, `list`) to the RFC-20 conforming shape on top of the shared CLI helpers. Every verb is now `pub async fn execute(self, ctx: &CliContext, client: &C, out: &mut W) -> eyre::Result<()>`, consumes the helpers (`require!`, `render_collection`, `render_record`, `print_signature`), and tenant verbs that accept a pubkey-or-code identifier (`update`, `delete`, `add-administrator`, `remove-administrator`, `update-payment-status`) route through a new `resolve_tenant_pk` helper in `smartcontract/cli/src/helpers.rs`. The duplicate-code precondition in `tenant create` is preserved, as is the `administrator = "me"` short-circuit. `tenant delete`'s bespoke two-line output ("✓ Tenant 'X' deleted successfully\n Signature: ..."), its cascade-delete progress spinners, and its reference-count polling loop are preserved with manual `writeln!` calls and an explanatory comment. `permission set`'s bespoke two-line aligned output ("Signature: ..." + "Permissions: ...") is preserved the same way. Permission verbs derive the on-chain PDA from `user_payer` rather than going through a pubkey-or-code resolver. `controlplane/doublezero-admin`, the unified `doublezero` binary, and the serviceability dispatcher all forward `&ctx` and await every tenant and permission arm. Behavior is byte-identical: table layout, JSON schema, `Signature:` line shape, and `--json` / `--json-compact` semantics match pre-refactor output exactly; all 18 tenant and 18 permission unit tests pass without assertion changes.
Expand Down
4 changes: 3 additions & 1 deletion client/doublezero/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,9 @@ async fn main() -> eyre::Result<()> {
// (Subscribe/Unsubscribe/Publish/Unpublish) stay binary-local because
// they depend on `ServiceControllerImpl` and `resolve_client_ip`.
Command::Multicast(args) => match args.command {
MulticastCommands::Group(args) => args.command.execute(&client, &mut handle),
MulticastCommands::Group(args) => {
args.command.execute(&ctx, &client, &mut handle).await
}
MulticastCommands::Subscribe(args) => args.execute(&client).await,
MulticastCommands::Unsubscribe(args) => args.execute(&client).await,
MulticastCommands::Publish(args) => args.execute(&client).await,
Expand Down
66 changes: 37 additions & 29 deletions controlplane/doublezero-admin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,22 +91,30 @@ async fn main() -> eyre::Result<()> {
ConfigCommands::Set(args) => args.execute(&ctx, &client, &mut handle).await,
},
Command::GlobalConfig(command) => match command.command {
GlobalConfigCommands::Set(args) => args.execute(&client, &mut handle),
GlobalConfigCommands::Get(args) => args.execute(&client, &mut handle),
GlobalConfigCommands::Set(args) => args.execute(&ctx, &client, &mut handle).await,
GlobalConfigCommands::Get(args) => args.execute(&ctx, &client, &mut handle).await,
GlobalConfigCommands::Airdrop(command) => match command.command {
AirdropCommands::Set(args) => args.execute(&client, &mut handle),
AirdropCommands::Get(args) => args.execute(&client, &mut handle),
AirdropCommands::Set(args) => args.execute(&ctx, &client, &mut handle).await,
AirdropCommands::Get(args) => args.execute(&ctx, &client, &mut handle).await,
},
GlobalConfigCommands::Authority(command) => match command.command {
AuthorityCommands::Set(args) => args.execute(&client, &mut handle),
AuthorityCommands::Get(args) => args.execute(&client, &mut handle),
AuthorityCommands::Set(args) => args.execute(&ctx, &client, &mut handle).await,
AuthorityCommands::Get(args) => args.execute(&ctx, &client, &mut handle).await,
},
GlobalConfigCommands::Allowlist(command) => match command.command {
FoundationAllowlistCommands::List(args) => args.execute(&client, &mut handle),
FoundationAllowlistCommands::Add(args) => args.execute(&client, &mut handle),
FoundationAllowlistCommands::Remove(args) => args.execute(&client, &mut handle),
FoundationAllowlistCommands::List(args) => {
args.execute(&ctx, &client, &mut handle).await
}
FoundationAllowlistCommands::Add(args) => {
args.execute(&ctx, &client, &mut handle).await
}
FoundationAllowlistCommands::Remove(args) => {
args.execute(&ctx, &client, &mut handle).await
}
},
GlobalConfigCommands::SetVersion(args) => args.execute(&client, &mut handle),
GlobalConfigCommands::SetVersion(args) => {
args.execute(&ctx, &client, &mut handle).await
}
},
Command::Account(args) => args.execute(&dzclient, &mut handle),
Command::Accounts(args) => args.execute(&dzclient, &mut handle),
Expand Down Expand Up @@ -216,14 +224,14 @@ async fn main() -> eyre::Result<()> {
PermissionCommands::List(args) => args.execute(&ctx, &client, &mut handle).await,
},
Command::User(command) => match command.command {
UserCommands::Create(args) => args.execute(&client, &mut handle),
UserCommands::CreateSubscribe(args) => args.execute(&client, &mut handle),
UserCommands::Subscribe(args) => args.execute(&client, &mut handle),
UserCommands::Update(args) => args.execute(&client, &mut handle),
UserCommands::List(args) => args.execute(&client, &mut handle),
UserCommands::Get(args) => args.execute(&client, &mut handle),
UserCommands::Delete(args) => args.execute(&client, &mut handle),
UserCommands::RequestBan(args) => args.execute(&client, &mut handle),
UserCommands::Create(args) => args.execute(&ctx, &client, &mut handle).await,
UserCommands::CreateSubscribe(args) => args.execute(&ctx, &client, &mut handle).await,
UserCommands::Subscribe(args) => args.execute(&ctx, &client, &mut handle).await,
UserCommands::Update(args) => args.execute(&ctx, &client, &mut handle).await,
UserCommands::List(args) => args.execute(&ctx, &client, &mut handle).await,
UserCommands::Get(args) => args.execute(&ctx, &client, &mut handle).await,
UserCommands::Delete(args) => args.execute(&ctx, &client, &mut handle).await,
UserCommands::RequestBan(args) => args.execute(&ctx, &client, &mut handle).await,
},
Command::Multicast(args) => match args.command {
cli::multicast::MulticastCommands::Group(args) => match args.command {
Expand All @@ -233,44 +241,44 @@ async fn main() -> eyre::Result<()> {
match args.command {
cli::multicastgroup::MulticastGroupPubAllowlistCommands::List(
args,
) => args.execute(&client, &mut handle),
) => args.execute(&ctx, &client, &mut handle).await,
cli::multicastgroup::MulticastGroupPubAllowlistCommands::Add(
args,
) => args.execute(&client, &mut handle),
) => args.execute(&ctx, &client, &mut handle).await,
cli::multicastgroup::MulticastGroupPubAllowlistCommands::Remove(
args,
) => args.execute(&client, &mut handle),
) => args.execute(&ctx, &client, &mut handle).await,
}
}
cli::multicastgroup::MulticastGroupAllowlistCommands::Subscriber(args) => {
match args.command {
cli::multicastgroup::MulticastGroupSubAllowlistCommands::List(
args,
) => args.execute(&client, &mut handle),
) => args.execute(&ctx, &client, &mut handle).await,
cli::multicastgroup::MulticastGroupSubAllowlistCommands::Add(
args,
) => args.execute(&client, &mut handle),
) => args.execute(&ctx, &client, &mut handle).await,
cli::multicastgroup::MulticastGroupSubAllowlistCommands::Remove(
args,
) => args.execute(&client, &mut handle),
) => args.execute(&ctx, &client, &mut handle).await,
}
}
}
}
cli::multicastgroup::MulticastGroupCommands::Create(args) => {
args.execute(&client, &mut handle)
args.execute(&ctx, &client, &mut handle).await
}
cli::multicastgroup::MulticastGroupCommands::Update(args) => {
args.execute(&client, &mut handle)
args.execute(&ctx, &client, &mut handle).await
}
cli::multicastgroup::MulticastGroupCommands::List(args) => {
args.execute(&client, &mut handle)
args.execute(&ctx, &client, &mut handle).await
}
cli::multicastgroup::MulticastGroupCommands::Get(args) => {
args.execute(&client, &mut handle)
args.execute(&ctx, &client, &mut handle).await
}
cli::multicastgroup::MulticastGroupCommands::Delete(args) => {
args.execute(&client, &mut handle)
args.execute(&ctx, &client, &mut handle).await
}
},
},
Expand Down
21 changes: 16 additions & 5 deletions smartcontract/cli/src/allowlist/foundation/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{
requirements::{CHECK_BALANCE, CHECK_ID_JSON},
};
use clap::Args;
use doublezero_cli_core::CliContext;
use doublezero_sdk::commands::allowlist::foundation::add::AddFoundationAllowlistCommand;
use solana_sdk::pubkey::Pubkey;
use std::{io::Write, str::FromStr};
Expand All @@ -15,7 +16,12 @@ pub struct AddFoundationAllowlistCliCommand {
}

impl AddFoundationAllowlistCliCommand {
pub fn execute<C: CliCommand, W: Write>(self, client: &C, out: &mut W) -> eyre::Result<()> {
pub async fn execute<C: CliCommand, W: Write>(
self,
_ctx: &CliContext,
client: &C,
out: &mut W,
) -> eyre::Result<()> {
// Check requirements
client.check_requirements(CHECK_ID_JSON | CHECK_BALANCE)?;

Expand All @@ -37,6 +43,8 @@ impl AddFoundationAllowlistCliCommand {

#[cfg(test)]
mod tests {
use doublezero_cli_core::testing::{block_on, cli_context_default_for_tests};

use crate::{
allowlist::foundation::add::{
AddFoundationAllowlistCliCommand, AddFoundationAllowlistCommand,
Expand Down Expand Up @@ -70,10 +78,13 @@ mod tests {

/*****************************************************************************************************/
let mut output = Vec::new();
let res = AddFoundationAllowlistCliCommand {
pubkey: pubkey.to_string(),
}
.execute(&client, &mut output);
let ctx = cli_context_default_for_tests();
let res = block_on(
AddFoundationAllowlistCliCommand {
pubkey: pubkey.to_string(),
}
.execute(&ctx, &client, &mut output),
);
assert!(res.is_ok());
let output_str = String::from_utf8(output).unwrap();
assert_eq!(
Expand Down
Loading
Loading