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: 0 additions & 1 deletion frontend/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ export const API = {
RUN_GET_PLAN: (projectName: IProject['project_name']) => `${API.PROJECTS.RUNS(projectName)}/get_plan`,
RUNS_DELETE: (projectName: IProject['project_name']) => `${API.PROJECTS.RUNS(projectName)}/delete`,
RUNS_STOP: (projectName: IProject['project_name']) => `${API.PROJECTS.RUNS(projectName)}/stop`,
RUNS_SUBMIT: (projectName: IProject['project_name']) => `${API.PROJECTS.RUNS(projectName)}/submit`,
RUNS_APPLY: (projectName: IProject['project_name']) => `${API.PROJECTS.RUNS(projectName)}/apply`,

// Logs
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/types/gateway.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ declare interface IGatewayReplica {
}

declare interface IGateway {
backend: string,
name: string,
project_name?: string,
ip_address: string,
instance_id: string,
region:string
hostname?: string,
wildcard_domain?: string
default: boolean
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/types/run.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,6 @@ declare interface IResources {

disk?: IDisk;
cpu_arch?: string | null;

/** @deprecated Use formatResources() from libs/resources instead. Remove in 0.21. */
description?: string;
}

declare interface InstanceType {
Expand Down
7 changes: 0 additions & 7 deletions src/dstack/_internal/cli/commands/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from dstack._internal.cli.utils.common import (
get_start_time,
)
from dstack._internal.core.errors import CLIError
from dstack._internal.core.models.common import EntityReference
from dstack._internal.core.models.events import EventTargetType
from dstack._internal.server.schemas.events import LIST_EVENTS_DEFAULT_LIMIT
Expand Down Expand Up @@ -159,12 +158,6 @@ def _build_filters(args: argparse.Namespace, api: Client) -> EventListFilters:
filters.target_gateways = []
for name in args.target_gateways:
id = api.client.gateways.get(api.project, name).id
if id is None:
# TODO(0.21): Remove this check once `Gateway.id` is required.
raise CLIError(
"Cannot determine gateway ID, most likely due to an outdated dstack server."
" Update the server to 0.20.7 or higher or remove --target-gateway."
)
filters.target_gateways.append(id)
elif args.target_secrets:
filters.target_secrets = [
Expand Down
51 changes: 8 additions & 43 deletions src/dstack/_internal/cli/services/configurators/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from dstack._internal.cli.utils.gateway import get_gateways_table
from dstack._internal.cli.utils.rich import MultiItemStatus
from dstack._internal.core.errors import (
MethodNotAllowedError,
ResourceNotExistsError,
)
from dstack._internal.core.models.common import ApplyAction
Expand All @@ -29,7 +28,6 @@
from dstack._internal.utils.common import local_time
from dstack._internal.utils.logging import get_logger
from dstack._internal.utils.nested_list import NestedList, NestedListItem
from dstack.api._public import Client

logger = get_logger(__name__)

Expand All @@ -50,13 +48,7 @@ def apply_configuration(
configuration_path=configuration_path,
)
with console.status("Getting apply plan..."):
try:
plan = self.api.client.gateways.get_plan(project_name=self.api.project, spec=spec)
use_legacy_api = False
except MethodNotAllowedError:
# pre-0.20.27 server
plan = _get_plan_legacy(self.api, spec)
use_legacy_api = True
plan = self.api.client.gateways.get_plan(project_name=self.api.project, spec=spec)
_print_plan_header(plan)

action_message = ""
Expand Down Expand Up @@ -123,19 +115,13 @@ def apply_configuration(
time.sleep(1)

with console.status("Applying plan..."):
if use_legacy_api:
gateway = self.api.client.gateways.create(
project_name=self.api.project,
configuration=conf,
)
else:
gateway = self.api.client.gateways.apply_plan(
project_name=self.api.project,
plan=ApplyGatewayPlanInput(
spec=spec,
current_resource=plan.current_resource,
),
)
gateway = self.api.client.gateways.apply_plan(
project_name=self.api.project,
plan=ApplyGatewayPlanInput(
spec=spec,
current_resource=plan.current_resource,
),
)

if plan.action == ApplyAction.UPDATE and delete_gateway_name is None:
console.print(get_gateways_table([gateway], current_project=self.api.project))
Expand Down Expand Up @@ -222,27 +208,6 @@ def apply_args(self, conf: GatewayConfiguration, args: argparse.Namespace):
conf.name = args.name


def _get_plan_legacy(api: Client, spec: GatewaySpec) -> GatewayPlan:
user = api.client.users.get_my_user()
current_resource = None
if spec.configuration.name is not None:
try:
current_resource = api.client.gateways.get(
project_name=api.project,
gateway_name=spec.configuration.name,
)
except ResourceNotExistsError:
pass
return GatewayPlan(
project_name=api.project,
user=user.username,
spec=spec,
effective_spec=spec,
current_resource=current_resource,
action=ApplyAction.CREATE,
)


def _print_plan_header(plan: GatewayPlan):
def th(s: str) -> str:
return f"[bold]{s}[/bold]"
Expand Down
17 changes: 3 additions & 14 deletions src/dstack/_internal/cli/utils/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,7 @@ def get_gateway_relative_to_project(
# `get` would resolve `Gateway.default` relative to the gateway's host project
gateways = client.list(project, include_imported=True)
for gateway in gateways:
if gateway.name == gateway_name and (
gateway_project == gateway.project_name
# Compatibility with pre-0.20.20 servers:
# gateway.project_name is None means the gateway is in the current `project`
or (gateway.project_name is None and gateway_project == project)
):
if gateway.name == gateway_name and gateway_project == gateway.project_name:
return gateway
ref = EntityReference(name=gateway_name, project=gateway_project)
raise ResourceNotExistsError(msg=f"Gateway {ref.format()!r} not found in project {project!r}")
Expand Down Expand Up @@ -78,17 +73,11 @@ def get_gateways_table(
for gateway in gateways:
name = format_entity_reference(
gateway.name,
# project_name == None means pre-0.20.20 server, which means no gateway exports support,
# which means the gateway is from the current project
gateway.project_name if gateway.project_name is not None else current_project,
gateway.project_name,
current_project,
)
domain = gateway.wildcard_domain
if (
gateway.project_name is not None
and gateway.project_name != current_project
and domain is not None
):
if gateway.project_name != current_project and domain is not None:
domain = interpolate_gateway_domain(
domain=domain,
run_project_name=current_project,
Expand Down
20 changes: 1 addition & 19 deletions src/dstack/_internal/core/compatibility/common.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,9 @@
from typing import Optional

from dstack._internal.core.models.common import EntityReference, IncludeExcludeSetType
from dstack._internal.core.models.common import IncludeExcludeSetType
from dstack._internal.core.models.profiles import ProfileParams


def get_profile_excludes(profile: Optional[ProfileParams]) -> IncludeExcludeSetType:
excludes: IncludeExcludeSetType = set()
if profile is None:
return excludes
if profile.backend_options is None:
excludes.add("backend_options")
if profile.instances is None:
excludes.add("instances")
return excludes


def patch_profile_params(params: ProfileParams) -> None:
# If there are no project-prefixed fleets, replace all EntityReference with str
# for compatibility with pre-0.20.14 servers that don't support EntityReference.
if params.fleets is not None and all(
EntityReference.parse(f).project is None for f in params.fleets
):
params.fleets = [
fleet_ref.format() if isinstance(fleet_ref, EntityReference) else fleet_ref
for fleet_ref in params.fleets
]
6 changes: 0 additions & 6 deletions src/dstack/_internal/core/compatibility/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,4 @@

def get_list_events_excludes(request: ListEventsRequest) -> IncludeExcludeDictType:
list_gpus_excludes: IncludeExcludeDictType = {}
if request.target_volumes is None:
list_gpus_excludes["target_volumes"] = True
if request.target_gateways is None:
list_gpus_excludes["target_gateways"] = True
if request.target_secrets is None:
list_gpus_excludes["target_secrets"] = True
return list_gpus_excludes
12 changes: 0 additions & 12 deletions src/dstack/_internal/core/compatibility/exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,9 @@

def get_create_export_excludes(request: CreateExportRequest) -> IncludeExcludeDictType:
excludes: IncludeExcludeDictType = {}
if not request.is_global:
excludes["is_global"] = True
if not request.exported_gateways:
excludes["exported_gateways"] = True
return excludes


def get_update_export_excludes(request: UpdateExportRequest) -> IncludeExcludeDictType:
excludes: IncludeExcludeDictType = {}
if not request.set_global:
excludes["set_global"] = True
if not request.unset_global:
excludes["unset_global"] = True
if not request.add_exported_gateways:
excludes["add_exported_gateways"] = True
if not request.remove_exported_gateways:
excludes["remove_exported_gateways"] = True
return excludes
27 changes: 7 additions & 20 deletions src/dstack/_internal/core/compatibility/fleets.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional

from dstack._internal.core.compatibility.common import get_profile_excludes, patch_profile_params
from dstack._internal.core.compatibility.common import get_profile_excludes
from dstack._internal.core.models.common import IncludeExcludeDictType
from dstack._internal.core.models.fleets import ApplyFleetPlanInput, FleetSpec

Expand All @@ -20,44 +20,31 @@ def get_apply_plan_excludes(plan_input: ApplyFleetPlanInput) -> IncludeExcludeDi
apply_plan_excludes["spec"] = spec_excludes
current_resource = plan_input.current_resource
if current_resource is not None:
current_resource_excludes = {}
current_resource_excludes: IncludeExcludeDictType = {}
current_resource_spec_excludes = get_fleet_spec_excludes(current_resource.spec)
if current_resource_spec_excludes:
current_resource_excludes["spec"] = current_resource_spec_excludes
# `Resources.description` is deprecated and never set since 0.21. Not sending it lets 0.22
# drop the field without breaking 0.21 clients.
current_resource_excludes["instances"] = {
"__all__": {"instance_type": {"resources": {"description": True}}}
}
apply_plan_excludes["current_resource"] = current_resource_excludes
return {"plan": apply_plan_excludes}


def get_create_fleet_excludes(fleet_spec: FleetSpec) -> IncludeExcludeDictType:
create_fleet_excludes: IncludeExcludeDictType = {}
spec_excludes = get_fleet_spec_excludes(fleet_spec)
if spec_excludes:
create_fleet_excludes["spec"] = spec_excludes
return create_fleet_excludes


def get_fleet_spec_excludes(fleet_spec: FleetSpec) -> Optional[IncludeExcludeDictType]:
"""
Returns `fleet_spec` exclude mapping to exclude certain fields from the request.
Use this method to exclude new fields when they are not set to keep
clients backward-compatibility with older servers.
"""
spec_excludes: IncludeExcludeDictType = {}
configuration_excludes: IncludeExcludeDictType = {}
profile_excludes = get_profile_excludes(fleet_spec.profile)

spec_excludes["autocreated"] = True
if fleet_spec.configuration.backend_options is None:
configuration_excludes["backend_options"] = True

if configuration_excludes:
spec_excludes["configuration"] = configuration_excludes
if profile_excludes:
spec_excludes["profile"] = profile_excludes
if spec_excludes:
return spec_excludes
return None


def patch_fleet_spec(spec: FleetSpec) -> None:
patch_profile_params(spec.profile)
21 changes: 14 additions & 7 deletions src/dstack/_internal/core/compatibility/gateways.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
from dstack._internal.core.models.common import IncludeExcludeDictType
from dstack._internal.core.models.gateways import GatewayConfiguration, GatewaySpec
from dstack._internal.core.models.gateways import (
ApplyGatewayPlanInput,
GatewayConfiguration,
GatewaySpec,
)
from dstack._internal.server.schemas.gateways import SetDefaultGatewayRequest


def get_apply_plan_excludes(plan_input: ApplyGatewayPlanInput) -> IncludeExcludeDictType:
apply_plan_excludes: IncludeExcludeDictType = {}
if plan_input.current_resource is not None:
# `Gateway.backend` and `Gateway.region` are deprecated and never set since 0.21.
# Not sending them lets 0.22 drop the fields without breaking 0.21 clients.
apply_plan_excludes["current_resource"] = {"backend": True, "region": True}
return {"plan": apply_plan_excludes}


def get_gateway_spec_excludes(gateway_spec: GatewaySpec) -> IncludeExcludeDictType:
"""
Returns `gateway_spec` exclude mapping to exclude certain fields from the request.
Expand All @@ -29,17 +42,11 @@ def get_create_gateway_excludes(configuration: GatewayConfiguration) -> IncludeE

def get_set_default_gateway_excludes(request: SetDefaultGatewayRequest) -> IncludeExcludeDictType:
excludes: IncludeExcludeDictType = {}
if request.gateway_project is None:
excludes["gateway_project"] = True
return excludes


def _get_gateway_configuration_excludes(
configuration: GatewayConfiguration,
) -> IncludeExcludeDictType:
configuration_excludes: IncludeExcludeDictType = {}

if configuration.replicas is None:
configuration_excludes["replicas"] = True

return configuration_excludes
4 changes: 0 additions & 4 deletions src/dstack/_internal/core/compatibility/gpus.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@

def get_list_gpus_excludes(request: ListGpusRequest) -> Optional[IncludeExcludeDictType]:
list_gpus_excludes: IncludeExcludeDictType = {}
if not request.full_offers:
list_gpus_excludes["full_offers"] = True
if not request.unallocated_resources:
list_gpus_excludes["unallocated_resources"] = True
run_spec_excludes = get_run_spec_excludes(request.run_spec)
if run_spec_excludes is not None:
list_gpus_excludes["run_spec"] = run_spec_excludes
Expand Down
Loading
Loading