Skip to content

Commit 885521d

Browse files
authored
Display imported fleets with project prefix in CLI (#3630)
1 parent ac875f6 commit 885521d

4 files changed

Lines changed: 55 additions & 20 deletions

File tree

src/dstack/_internal/cli/commands/fleet.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,17 @@ def _command(self, args: argparse.Namespace):
9595
def _list(self, args: argparse.Namespace):
9696
fleets = self.api.client.fleets.list(self.api.project)
9797
if not args.watch:
98-
print_fleets_table(fleets, verbose=args.verbose)
98+
print_fleets_table(fleets, current_project=self.api.project, verbose=args.verbose)
9999
return
100100

101101
try:
102102
with Live(console=console, refresh_per_second=LIVE_TABLE_REFRESH_RATE_PER_SEC) as live:
103103
while True:
104-
live.update(get_fleets_table(fleets, verbose=args.verbose))
104+
live.update(
105+
get_fleets_table(
106+
fleets, current_project=self.api.project, verbose=args.verbose
107+
)
108+
)
105109
time.sleep(LIVE_TABLE_PROVISION_INTERVAL_SECS)
106110
fleets = self.api.client.fleets.list(self.api.project)
107111
except KeyboardInterrupt:

src/dstack/_internal/cli/services/configurators/fleet.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def _apply_plan(self, plan: FleetPlan, command_args: argparse.Namespace):
141141
f"Provisioning [code]{fleet.name}[/]...", console=console
142142
) as live:
143143
while not _finished_provisioning(fleet):
144-
table = get_fleets_table([fleet])
144+
table = get_fleets_table([fleet], current_project=self.api.project)
145145
live.update(table)
146146
time.sleep(LIVE_TABLE_PROVISION_INTERVAL_SECS)
147147
fleet = self.api.client.fleets.get(self.api.project, fleet.name)
@@ -159,6 +159,7 @@ def _apply_plan(self, plan: FleetPlan, command_args: argparse.Namespace):
159159
[fleet],
160160
verbose=_fleet_has_failed_instances(fleet),
161161
format_date=local_time,
162+
current_project=self.api.project,
162163
)
163164
)
164165
if _fleet_has_failed_instances(fleet):
@@ -242,7 +243,7 @@ def _apply_plan_on_old_server(self, plan: FleetPlan, command_args: argparse.Name
242243
f"Provisioning [code]{fleet.name}[/]...", console=console
243244
) as live:
244245
while not _finished_provisioning(fleet):
245-
table = get_fleets_table([fleet])
246+
table = get_fleets_table([fleet], current_project=self.api.project)
246247
live.update(table)
247248
time.sleep(LIVE_TABLE_PROVISION_INTERVAL_SECS)
248249
fleet = self.api.client.fleets.get(self.api.project, fleet.name)
@@ -260,6 +261,7 @@ def _apply_plan_on_old_server(self, plan: FleetPlan, command_args: argparse.Name
260261
[fleet],
261262
verbose=_fleet_has_failed_instances(fleet),
262263
format_date=local_time,
264+
current_project=self.api.project,
263265
)
264266
)
265267
if _fleet_has_failed_instances(fleet):

src/dstack/_internal/cli/utils/fleet.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@
1010
from dstack._internal.utils.common import DateFormatter, pretty_date
1111

1212

13-
def print_fleets_table(fleets: List[Fleet], verbose: bool = False) -> None:
14-
console.print(get_fleets_table(fleets, verbose=verbose))
13+
def print_fleets_table(fleets: List[Fleet], current_project: str, verbose: bool = False) -> None:
14+
console.print(get_fleets_table(fleets, current_project=current_project, verbose=verbose))
1515
console.print()
1616

1717

1818
def get_fleets_table(
19-
fleets: List[Fleet], verbose: bool = False, format_date: DateFormatter = pretty_date
19+
fleets: List[Fleet],
20+
current_project: str,
21+
verbose: bool = False,
22+
format_date: DateFormatter = pretty_date,
2023
) -> Table:
2124
table = Table(box=None)
2225

@@ -40,6 +43,10 @@ def get_fleets_table(
4043
config = fleet.spec.configuration
4144
merged_profile = fleet.spec.merged_profile
4245

46+
name = fleet.name
47+
if fleet.project_name != current_project:
48+
name = f"{fleet.project_name}/{fleet.name}"
49+
4350
# Detect SSH fleet vs backend fleet
4451
if config.ssh_config is not None:
4552
# SSH fleet: fixed number of hosts, no cloud billing
@@ -65,7 +72,7 @@ def get_fleets_table(
6572
nodes = f"{nodes} (cluster)"
6673

6774
fleet_row: Dict[Union[str, int], Any] = {
68-
"NAME": fleet.name,
75+
"NAME": name,
6976
"NODES": nodes,
7077
"BACKEND": backend,
7178
"PRICE": max_price,

src/tests/_internal/cli/utils/test_fleet.py

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ def create_backend_fleet(
126126
gpu_count_max: int = 0,
127127
instances: Optional[List[Instance]] = None,
128128
status: FleetStatus = FleetStatus.ACTIVE,
129+
project_name: str = "test-project",
129130
) -> Fleet:
130131
nodes = FleetNodesSpec(min=nodes_min, target=nodes_min, max=nodes_max)
131132

@@ -154,7 +155,7 @@ def create_backend_fleet(
154155
return Fleet(
155156
id=uuid4(),
156157
name=name,
157-
project_name="test-project",
158+
project_name=project_name,
158159
spec=spec,
159160
created_at=datetime(2023, 1, 2, 3, 4, 5, tzinfo=timezone.utc),
160161
status=status,
@@ -222,7 +223,7 @@ def test_backend_fleet_without_verbose(self):
222223
instances=[instance],
223224
)
224225

225-
table = get_fleets_table([fleet], verbose=False)
226+
table = get_fleets_table([fleet], current_project="test-project", verbose=False)
226227
cells = get_table_cells(table)
227228

228229
assert len(cells) == 2 # 1 fleet row + 1 instance row
@@ -262,7 +263,7 @@ def test_backend_fleet_with_verbose(self):
262263
instances=[instance],
263264
)
264265

265-
table = get_fleets_table([fleet], verbose=True)
266+
table = get_fleets_table([fleet], current_project="test-project", verbose=True)
266267
cells = get_table_cells(table)
267268

268269
assert len(cells) == 2
@@ -310,7 +311,7 @@ def test_ssh_fleet_without_verbose(self):
310311
instances=[instance1, instance2],
311312
)
312313

313-
table = get_fleets_table([fleet], verbose=False)
314+
table = get_fleets_table([fleet], current_project="test-project", verbose=False)
314315
cells = get_table_cells(table)
315316

316317
assert len(cells) == 3 # 1 fleet row + 2 instance rows
@@ -345,7 +346,7 @@ def test_ssh_fleet_with_verbose(self):
345346
instances=[instance],
346347
)
347348

348-
table = get_fleets_table([fleet], verbose=True)
349+
table = get_fleets_table([fleet], current_project="test-project", verbose=True)
349350
cells = get_table_cells(table)
350351

351352
assert len(cells) == 2
@@ -395,7 +396,9 @@ def test_mixed_fleets(self):
395396
instances=[ssh_instance],
396397
)
397398

398-
table = get_fleets_table([backend_fleet, ssh_fleet], verbose=False)
399+
table = get_fleets_table(
400+
[backend_fleet, ssh_fleet], current_project="test-project", verbose=False
401+
)
399402
cells = get_table_cells(table)
400403

401404
assert len(cells) == 4 # 2 fleet rows + 2 instance rows
@@ -433,7 +436,9 @@ def test_fleet_status_colors(self):
433436
name="terminating", status=FleetStatus.TERMINATING, instances=[terminating_instance]
434437
)
435438

436-
table = get_fleets_table([active_fleet, terminating_fleet], verbose=False)
439+
table = get_fleets_table(
440+
[active_fleet, terminating_fleet], current_project="test-project", verbose=False
441+
)
437442

438443
active_style = get_table_cell_style(table, "STATUS", 0)
439444
assert active_style == "bold white"
@@ -451,7 +456,7 @@ def test_instance_status_colors(self):
451456
instances=[idle_instance, busy_instance],
452457
)
453458

454-
table = get_fleets_table([fleet], verbose=False)
459+
table = get_fleets_table([fleet], current_project="test-project", verbose=False)
455460

456461
idle_style = get_table_cell_style(table, "STATUS", 1)
457462
assert idle_style == "bold sea_green3"
@@ -462,7 +467,7 @@ def test_instance_status_colors(self):
462467
def test_empty_fleet(self):
463468
fleet = create_backend_fleet(name="empty-fleet", instances=[])
464469

465-
table = get_fleets_table([fleet], verbose=False)
470+
table = get_fleets_table([fleet], current_project="test-project", verbose=False)
466471
cells = get_table_cells(table)
467472

468473
assert len(cells) == 1
@@ -474,7 +479,7 @@ def test_fleet_with_max_price(self):
474479
max_price=5.0,
475480
)
476481

477-
table = get_fleets_table([fleet], verbose=False)
482+
table = get_fleets_table([fleet], current_project="test-project", verbose=False)
478483
cells = get_table_cells(table)
479484

480485
assert cells[0]["PRICE"] == "$0..$5"
@@ -485,7 +490,7 @@ def test_fleet_with_multiple_backends(self):
485490
backends=[BackendType.AWS, BackendType.GCP, BackendType.AZURE],
486491
)
487492

488-
table = get_fleets_table([fleet], verbose=False)
493+
table = get_fleets_table([fleet], current_project="test-project", verbose=False)
489494
cells = get_table_cells(table)
490495

491496
assert cells[0]["BACKEND"] == "aws, gcp, azure"
@@ -496,7 +501,24 @@ def test_fleet_with_any_backend(self):
496501
backends=None,
497502
)
498503

499-
table = get_fleets_table([fleet], verbose=False)
504+
table = get_fleets_table([fleet], current_project="test-project", verbose=False)
500505
cells = get_table_cells(table)
501506

502507
assert cells[0]["BACKEND"] == "*"
508+
509+
def test_with_imported_fleet(self):
510+
current_project_fleet = create_backend_fleet(
511+
name="current-fleet", project_name="current-project"
512+
)
513+
other_project_fleet = create_backend_fleet(
514+
name="other-fleet", project_name="other-project"
515+
)
516+
table = get_fleets_table(
517+
[current_project_fleet, other_project_fleet],
518+
verbose=False,
519+
current_project="current-project",
520+
)
521+
cells = get_table_cells(table)
522+
assert len(cells) == 2
523+
assert cells[0]["NAME"] == "current-fleet"
524+
assert cells[1]["NAME"] == "other-project/other-fleet"

0 commit comments

Comments
 (0)