Repository navigation
Conversation
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01PRUpFQ7R2MdpcGZiH62eUm Signed-off-by: Leechael Yim <[email protected]>
…odes Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01PRUpFQ7R2MdpcGZiH62eUm Signed-off-by: Leechael Yim <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01PRUpFQ7R2MdpcGZiH62eUm Signed-off-by: Leechael Yim <[email protected]>
…oint Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01PRUpFQ7R2MdpcGZiH62eUm Signed-off-by: Leechael Yim <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01PRUpFQ7R2MdpcGZiH62eUm Signed-off-by: Leechael Yim <[email protected]>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Watching a dstack fleet today means opening each node's web console separately (
:9080per VMM) or runningvmm-cli.py lsvmagainst one node at a time. Nothing shows several nodes on one screen, flags which VMs need attention across them, or keeps a record of state changes while you watch.Most VMMs also listen only on a unix socket (
address = "unix:./vmm.sock"by default), each node has its own[auth]token, and every operator polling every node multiplies the load. So "just poll them all from my laptop" doesn't work out of the box.Fix
A new standalone binary,
dstack-vmm-top(dstack/vmm-top/), built with ratatui. It is only ever a client of the VMM's existing API (Status,Version,GetMeta,ListGpus,StartVm/ShutdownVm/StopVm,/logs), sodstack-vmmitself is unchanged.It watches sources of two kinds, in any mix:
-n tdx-01=http://10.0.0.11:9080,unix:/path/vmm.sock, or auto-discovered from the registration files everydstack-vmmwrites (vmm/src/discovery.rs).dstack-vmm-top servepolls many VMMs (including local unix-socket ones), then serves them under one URL and one token. Watch it with--hub https://host:9970.The hub is read-only by construction. It has
GETroutes only, no route that changes a VM, and snapshots exclude encrypted env, user config and the compose file. A token is required on non-loopback addresses unless--insecureis passed. Log requests are accepted only for VM ids the node itself listed. Lifecycle actions are offered only for nodes polled directly with their own VMM token.The dashboard:
/), scope all / live / attention (a), preview pane (v), and mouse support.x). The VMM has no restart call, so restart is stop then start. That sequence is safe becausestart_vmwaits for a VM that was told to stop to finish exiting (vmm/src/app.rs).--once/--json, also used when stdout is not a terminal.Alternatives considered
dstack vmm topsubcommand of the existing CLI: one less binary, but everydstackbuild would then link ratatui and crossterm.dstack-vmm-rpc.Commits
Each commit builds and passes tests and clippy on its own:
build(deps): workspace deps only.feat(vmm-top): read-only dashboard plus--once/--json.feat(vmm-top): VM lifecycle actions. This is the only write path, so it can be reviewed alone.feat(vmm-top): the hub, server and client. This is a new network surface, so it can be reviewed alone.docs(vmm-top): the guide.Verification
cargo test -p dstack-vmm-top: 40 unit tests covering phase folding, tree, sort and scope, selection that stays on the same VM across polls, journal diffing, pause, log follow, layout at 20×5 up to 200×60, column widths at every width from 30 to 220, ANSI and OSC stripping, hub query parsing and token comparison.cargo clippy -p dstack-vmm-top -- -D warnings -D clippy::expect_used -D clippy::unwrap_used(CI's flags) andcargo fmt --check --allare clean at every commit.[auth]enabled.0.0.0.0without a token, answers401without a token and405toPOST, and returnsno VM ../../etcfor an id the node didn't list.StopVmblocked for 10s.dstack-vmm: it would not start in the test container because its host API needs a vsock device. Field names are shared by construction through the generateddstack-vmm-rpctypes, and the start/stop calls are the sameVmmClient<PrpcClient>calls thedstackCLI already makes.Notes for review
unicode-widthalone) makes Cargo movehyper-util,quinn-udpand one other crate fromsocket2 0.5.10to0.6.4, which is already in the lockfile. I checked this against a clean worktree. It is not caused by any specific dependency here.vmm/ui/package-lock.jsonresolves fromregistry.npmmirror.com. Behind proxies that block that host,npm cifails, and with it thedstack-vmmbuild.Generated by Claude Code