Skip to content
Open
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
4 changes: 4 additions & 0 deletions frontend/src/pages/Offers/List/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ export const OfferList: React.FC<OfferListProps> = ({ withSearchParams, onChange
{
id: 'availability',
content: (gpu: IGpu) => {
// FIXME: array to string comparison never passes.
// Additionally, there are more availability statuses that are worth displaying,
// and several of them may be present at once.

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
if (gpu.availability === 'not_available') {
Expand Down
11 changes: 3 additions & 8 deletions src/dstack/_internal/cli/services/configurators/fleet.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
NO_OFFERS_WARNING,
confirm_ask,
console,
format_instance_availability,
)
from dstack._internal.cli.utils.fleet import get_fleets_table
from dstack._internal.cli.utils.rich import MultiItemStatus
Expand All @@ -32,7 +33,7 @@
FleetSpec,
InstanceGroupPlacement,
)
from dstack._internal.core.models.instances import InstanceAvailability, InstanceStatus, SSHKey
from dstack._internal.core.models.instances import InstanceStatus, SSHKey
from dstack._internal.core.services.diff import diff_models
from dstack._internal.utils.common import local_time
from dstack._internal.utils.logging import get_logger
Expand Down Expand Up @@ -420,12 +421,6 @@ def th(s: str) -> str:
for index, offer in enumerate(print_offers, start=1):
resources = offer.instance.resources

availability = ""
if offer.availability in {
InstanceAvailability.NOT_AVAILABLE,
InstanceAvailability.NO_QUOTA,
}:
availability = offer.availability.value.replace("_", " ").title()
offers_table.add_row(
f"{index}",
offer.backend.replace("remote", "ssh"),
Expand All @@ -434,7 +429,7 @@ def th(s: str) -> str:
resources.pretty_format(),
"yes" if resources.spot else "no",
f"${offer.price:3f}".rstrip("0").rstrip("."),
availability,
format_instance_availability(offer.availability),
style=None if index == 1 else "secondary",
)
if len(plan.offers) > offers_limit:
Expand Down
7 changes: 7 additions & 0 deletions src/dstack/_internal/cli/utils/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from dstack._internal import settings
from dstack._internal.cli.utils.rich import DstackRichHandler
from dstack._internal.core.errors import CLIError, DstackError
from dstack._internal.core.models.instances import InstanceAvailability
from dstack._internal.utils.common import get_dstack_dir, parse_since

_colors = {
Expand Down Expand Up @@ -146,3 +147,9 @@ def resolve_url(url: str, timeout: float = 5.0) -> str:
except requests.exceptions.ConnectionError as e:
raise ValueError(f"Failed to resolve url {url}") from e
return response.url


def format_instance_availability(v: InstanceAvailability) -> str:
if v in (InstanceAvailability.UNKNOWN, InstanceAvailability.AVAILABLE):
return ""
return v.value.replace("_", " ").lower()
13 changes: 5 additions & 8 deletions src/dstack/_internal/cli/utils/gpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from rich.table import Table

from dstack._internal.cli.models.offers import OfferCommandGroupByGpuOutput, OfferRequirements
from dstack._internal.cli.utils.common import console
from dstack._internal.cli.utils.common import console, format_instance_availability
from dstack._internal.core.models.gpus import GpuGroup
from dstack._internal.core.models.profiles import SpotPolicy
from dstack._internal.core.models.runs import Requirements, RunSpec, get_policy_map
Expand Down Expand Up @@ -117,13 +117,10 @@ def print_gpu_table(gpus: List[GpuGroup], run_spec: RunSpec, group_by: List[str]

availability = ""
has_available = any(av.is_available() for av in gpu_group.availability)
has_unavailable = any(not av.is_available() for av in gpu_group.availability)

if has_unavailable and not has_available:
for av in gpu_group.availability:
if av.value in {"not_available", "no_quota", "idle", "busy"}:
availability = av.value.replace("_", " ").lower()
break
if not has_available:
availability = ", ".join(
map(format_instance_availability, set(gpu_group.availability))
)

secondary_style = "grey58"
row_data = [
Expand Down
12 changes: 2 additions & 10 deletions src/dstack/_internal/cli/utils/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
NO_OFFERS_WARNING,
add_row_from_dict,
console,
format_instance_availability,
)
from dstack._internal.core.models.backends.base import BackendType
from dstack._internal.core.models.configurations import DevEnvironmentConfiguration
from dstack._internal.core.models.instances import (
InstanceAvailability,
InstanceOfferWithAvailability,
InstanceType,
)
Expand Down Expand Up @@ -168,14 +168,6 @@ def th(s: str) -> str:
for i, offer in enumerate(job_plan.offers, start=1):
r = offer.instance.resources

availability = ""
if offer.availability in {
InstanceAvailability.NOT_AVAILABLE,
InstanceAvailability.NO_QUOTA,
InstanceAvailability.IDLE,
InstanceAvailability.BUSY,
}:
availability = offer.availability.value.replace("_", " ").lower()
instance = offer.instance.name
if offer.total_blocks > 1:
instance += f" ({offer.blocks}/{offer.total_blocks})"
Expand All @@ -185,7 +177,7 @@ def th(s: str) -> str:
r.pretty_format(include_spot=True),
instance,
f"${offer.price:.4f}".rstrip("0").rstrip("."),
availability,
format_instance_availability(offer.availability),
style=None if i == 1 or not include_run_properties else "secondary",
)
if job_plan.total_offers > len(job_plan.offers):
Expand Down
4 changes: 1 addition & 3 deletions src/dstack/_internal/core/models/instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,7 @@ class InstanceAvailability(Enum):
AVAILABLE = "available"
NOT_AVAILABLE = "not_available"
NO_QUOTA = "no_quota"
NO_BALANCE = (
"no_balance" # Introduced in 0.19.24, may be used after a short compatibility period
)
NO_BALANCE = "no_balance" # For dstack Sky
IDLE = "idle"
BUSY = "busy"

Expand Down