Skip to content

Commit 7eebc38

Browse files
committed
fix(vmm): discover VMM instances across all users on the host
- vmm-cli.py scans /run/user/*/dstack-vmm/ to find instances from all users, not just the current user's XDG_RUNTIME_DIR - Rust side falls back to /run/user/<uid>/dstack-vmm when XDG_RUNTIME_DIR is not set, reading uid from /proc/self/status - Remove /run/dstack-vmm fallback (no longer needed)
1 parent 2db8126 commit 7eebc38

2 files changed

Lines changed: 45 additions & 26 deletions

File tree

vmm/src/discovery.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,23 @@ use std::path::{Path, PathBuf};
1313
use tracing::{info, warn};
1414
use uuid::Uuid;
1515

16-
/// Returns the discovery directory path.
17-
/// Uses $XDG_RUNTIME_DIR/dstack-vmm if set, otherwise falls back to /run/dstack-vmm.
16+
/// Returns the discovery directory path under $XDG_RUNTIME_DIR/dstack-vmm.
17+
/// Falls back to /run/user/<uid>/dstack-vmm if XDG_RUNTIME_DIR is not set.
1818
fn discovery_dir() -> PathBuf {
1919
if let Ok(xdg) = std::env::var("XDG_RUNTIME_DIR") {
20-
PathBuf::from(xdg).join("dstack-vmm")
21-
} else {
22-
PathBuf::from("/run/dstack-vmm")
20+
return PathBuf::from(xdg).join("dstack-vmm");
2321
}
22+
// Read real uid from /proc/self/status to avoid adding a libc dependency.
23+
let uid = std::fs::read_to_string("/proc/self/status")
24+
.ok()
25+
.and_then(|s| {
26+
s.lines()
27+
.find(|l| l.starts_with("Uid:"))
28+
.and_then(|l| l.split_whitespace().nth(1))
29+
.and_then(|v| v.parse::<u32>().ok())
30+
})
31+
.expect("failed to determine uid from /proc/self/status");
32+
PathBuf::from(format!("/run/user/{uid}/dstack-vmm"))
2433
}
2534

2635
#[derive(Debug, Clone, Serialize, Deserialize)]

vmm/src/vmm-cli.py

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,22 @@
3434
DEFAULT_CONFIG_PATH = os.path.expanduser("~/.dstack-vmm/config.json")
3535
DEFAULT_KMS_WHITELIST_PATH = os.path.expanduser("~/.dstack-vmm/kms-whitelist.json")
3636

37-
# VMM discovery directory
38-
DISCOVERY_DIR = os.path.join(os.environ.get("XDG_RUNTIME_DIR", "/run"), "dstack-vmm")
37+
# VMM discovery directories
38+
# Each user's instances are in $XDG_RUNTIME_DIR/dstack-vmm (typically /run/user/<uid>/dstack-vmm).
39+
# CLI scans all users' directories so operators can see every instance on the host.
40+
def _get_discovery_dirs() -> List[str]:
41+
dirs = []
42+
# Scan all /run/user/*/dstack-vmm
43+
run_user = "/run/user"
44+
if os.path.isdir(run_user):
45+
try:
46+
for uid_dir in os.listdir(run_user):
47+
candidate = os.path.join(run_user, uid_dir, "dstack-vmm")
48+
if os.path.isdir(candidate):
49+
dirs.append(candidate)
50+
except PermissionError:
51+
pass
52+
return dirs
3953

4054

4155
def load_config() -> Dict[str, Any]:
@@ -56,31 +70,27 @@ def load_config() -> Dict[str, Any]:
5670

5771

5872
def discover_vmm_instances() -> List[Dict[str, Any]]:
59-
"""Discover all running VMM instances from the discovery directory.
73+
"""Discover all running VMM instances across all users on the host.
6074
6175
Returns:
6276
List of VMM instance info dicts, sorted by started_at.
6377
6478
"""
6579
instances = []
66-
if not os.path.isdir(DISCOVERY_DIR):
67-
return instances
68-
69-
for fname in os.listdir(DISCOVERY_DIR):
70-
if not fname.endswith(".json"):
71-
continue
72-
fpath = os.path.join(DISCOVERY_DIR, fname)
73-
try:
74-
with open(fpath, "r") as f:
75-
info = json.load(f)
76-
# Check if process is still alive
77-
pid = info.get("pid")
78-
if pid and not os.path.exists(f"/proc/{pid}"):
79-
# Stale file, skip
80+
for discovery_dir in _get_discovery_dirs():
81+
for fname in os.listdir(discovery_dir):
82+
if not fname.endswith(".json"):
83+
continue
84+
fpath = os.path.join(discovery_dir, fname)
85+
try:
86+
with open(fpath, "r") as f:
87+
info = json.load(f)
88+
pid = info.get("pid")
89+
if pid and not os.path.exists(f"/proc/{pid}"):
90+
continue
91+
instances.append(info)
92+
except (json.JSONDecodeError, FileNotFoundError, PermissionError):
8093
continue
81-
instances.append(info)
82-
except (json.JSONDecodeError, FileNotFoundError, PermissionError):
83-
continue
8494

8595
instances.sort(key=lambda x: x.get("started_at", 0))
8696
return instances
@@ -163,7 +173,7 @@ def cmd_ls_vmm(args):
163173

164174
if not instances:
165175
print("No running VMM instances found.")
166-
print(f" (discovery directory: {DISCOVERY_DIR})")
176+
print(f" (scanned: {', '.join(_get_discovery_dirs()) or '/run/user/*/dstack-vmm'})")
167177
return
168178

169179
if getattr(args, "json", False):

0 commit comments

Comments
 (0)