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 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
38 changes: 21 additions & 17 deletions controlplane/doublezero-admin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,31 +156,35 @@ async fn main() -> eyre::Result<()> {
}
},
Command::Device(command) => match command.command {
DeviceCommands::Create(args) => args.execute(&client, &mut handle),
DeviceCommands::Update(args) => args.execute(&client, &mut handle),
DeviceCommands::List(args) => args.execute(&client, &mut handle),
DeviceCommands::Get(args) => args.execute(&client, &mut handle),
DeviceCommands::Delete(args) => args.execute(&client, &mut handle),
DeviceCommands::Create(args) => args.execute(&ctx, &client, &mut handle).await,
DeviceCommands::Update(args) => args.execute(&ctx, &client, &mut handle).await,
DeviceCommands::List(args) => args.execute(&ctx, &client, &mut handle).await,
DeviceCommands::Get(args) => args.execute(&ctx, &client, &mut handle).await,
DeviceCommands::Delete(args) => args.execute(&ctx, &client, &mut handle).await,
DeviceCommands::MigrateMulticastCounts(args) => args.execute(&client, &mut handle),
DeviceCommands::MigrateUnicastCounts(args) => args.execute(&client, &mut handle),
DeviceCommands::Interface(command) => match command.command {
InterfaceCommands::Create(args) => args.execute(&client, &mut handle),
InterfaceCommands::Update(args) => args.execute(&client, &mut handle),
InterfaceCommands::List(args) => args.execute(&client, &mut handle),
InterfaceCommands::Get(args) => args.execute(&client, &mut handle),
InterfaceCommands::Delete(args) => args.execute(&client, &mut handle),
InterfaceCommands::Create(args) => args.execute(&ctx, &client, &mut handle).await,
InterfaceCommands::Update(args) => args.execute(&ctx, &client, &mut handle).await,
InterfaceCommands::List(args) => args.execute(&ctx, &client, &mut handle).await,
InterfaceCommands::Get(args) => args.execute(&ctx, &client, &mut handle).await,
InterfaceCommands::Delete(args) => args.execute(&ctx, &client, &mut handle).await,
},
},
Command::Link(command) => match command.command {
LinkCommands::Create(args) => match args.command {
cli::link::CreateLinkCommands::Wan(args) => args.execute(&client, &mut handle),
cli::link::CreateLinkCommands::Dzx(args) => args.execute(&client, &mut handle),
cli::link::CreateLinkCommands::Wan(args) => {
args.execute(&ctx, &client, &mut handle).await
}
cli::link::CreateLinkCommands::Dzx(args) => {
args.execute(&ctx, &client, &mut handle).await
}
},
LinkCommands::Accept(args) => args.execute(&client, &mut handle),
LinkCommands::Update(args) => args.execute(&client, &mut handle),
LinkCommands::List(args) => args.execute(&client, &mut handle),
LinkCommands::Get(args) => args.execute(&client, &mut handle),
LinkCommands::Delete(args) => args.execute(&client, &mut handle),
LinkCommands::Accept(args) => args.execute(&ctx, &client, &mut handle).await,
LinkCommands::Update(args) => args.execute(&ctx, &client, &mut handle).await,
LinkCommands::List(args) => args.execute(&ctx, &client, &mut handle).await,
LinkCommands::Get(args) => args.execute(&ctx, &client, &mut handle).await,
LinkCommands::Delete(args) => args.execute(&ctx, &client, &mut handle).await,
},
Command::AccessPass(command) => match command.command {
cli::accesspass::AccessPassCommands::Set(args) => {
Expand Down
52 changes: 27 additions & 25 deletions smartcontract/cli/src/cli/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,38 +175,40 @@ impl ServiceabilityCommand {
},
},
Self::Device(cmd) => match cmd.command {
DeviceCommands::Create(args) => args.execute(client, out),
DeviceCommands::Update(args) => args.execute(client, out),
DeviceCommands::List(args) => args.execute(client, out),
DeviceCommands::Get(args) => args.execute(client, out),
DeviceCommands::Delete(args) => args.execute(client, out),
DeviceCommands::Create(args) => args.execute(ctx, client, out).await,
DeviceCommands::Update(args) => args.execute(ctx, client, out).await,
DeviceCommands::List(args) => args.execute(ctx, client, out).await,
DeviceCommands::Get(args) => args.execute(ctx, client, out).await,
DeviceCommands::Delete(args) => args.execute(ctx, client, out).await,
DeviceCommands::Interface(c) => match c.command {
InterfaceCommands::Create(args) => args.execute(client, out),
InterfaceCommands::Update(args) => args.execute(client, out),
InterfaceCommands::List(args) => args.execute(client, out),
InterfaceCommands::Get(args) => args.execute(client, out),
InterfaceCommands::Delete(args) => args.execute(client, out),
InterfaceCommands::Create(args) => args.execute(ctx, client, out).await,
InterfaceCommands::Update(args) => args.execute(ctx, client, out).await,
InterfaceCommands::List(args) => args.execute(ctx, client, out).await,
InterfaceCommands::Get(args) => args.execute(ctx, client, out).await,
InterfaceCommands::Delete(args) => args.execute(ctx, client, out).await,
},
DeviceCommands::SetHealth(args) => args.execute(client, out),
DeviceCommands::SetHealth(args) => args.execute(ctx, client, out).await,
},
Self::Link(cmd) => match cmd.command {
LinkCommands::Create(args) => match args.command {
CreateLinkCommands::Wan(args) => args.execute(client, out),
CreateLinkCommands::Dzx(args) => args.execute(client, out),
CreateLinkCommands::Wan(args) => args.execute(ctx, client, out).await,
CreateLinkCommands::Dzx(args) => args.execute(ctx, client, out).await,
},
LinkCommands::Accept(args) => args.execute(client, out),
LinkCommands::Update(args) => args.execute(client, out),
LinkCommands::List(args) => args.execute(client, out),
LinkCommands::Get(args) => args.execute(client, out),
LinkCommands::Latency(args) => args.execute(client, out),
LinkCommands::Delete(args) => args.execute(client, out),
LinkCommands::SetHealth(args) => args.execute(client, out),
LinkCommands::Accept(args) => args.execute(ctx, client, out).await,
LinkCommands::Update(args) => args.execute(ctx, client, out).await,
LinkCommands::List(args) => args.execute(ctx, client, out).await,
LinkCommands::Get(args) => args.execute(ctx, client, out).await,
LinkCommands::Latency(args) => args.execute(ctx, client, out).await,
LinkCommands::Delete(args) => args.execute(ctx, client, out).await,
LinkCommands::SetHealth(args) => args.execute(ctx, client, out).await,
LinkCommands::Topology(t) => match t.command {
TopologyCommands::Create(args) => args.execute(client, out),
TopologyCommands::Delete(args) => args.execute(client, out),
TopologyCommands::Clear(args) => args.execute(client, out),
TopologyCommands::AssignNodeSegments(args) => args.execute(client, out),
TopologyCommands::List(args) => args.execute(client, out),
TopologyCommands::Create(args) => args.execute(ctx, client, out).await,
TopologyCommands::Delete(args) => args.execute(ctx, client, out).await,
TopologyCommands::Clear(args) => args.execute(ctx, client, out).await,
TopologyCommands::AssignNodeSegments(args) => {
args.execute(ctx, client, out).await
}
TopologyCommands::List(args) => args.execute(ctx, client, out).await,
},
},
Self::AccessPass(cmd) => match cmd.command {
Expand Down
Loading
Loading