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
31 changes: 31 additions & 0 deletions mkdocs/docs/concepts/snippets/manage-fleets.ext
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
### Instances

Use `instances` to restrict a run to particular existing fleet instances. You can specify
instance names, hostnames or IP addresses, or a fleet name with an instance number.
For the `fleet` form, use `<project>/<fleet>` when the fleet belongs to another project:

<div editor-title=".dstack.yml">

```yaml
instances:
- name: my-fleet-3
- hostname: 203.0.113.10
- fleet: my-fleet
instance: 3
```

</div>

??? info "Short syntax"

To match by instance name, you can use the string shorthand:

```yaml
instances:
- my-fleet-3
```

When `instances` is set, the run is only placed on a matching existing instance and `dstack`
never provisions new instances. If no matching instance is available, the run fails with a
no-capacity error (use `retry` to wait for a targeted instance to free up).

### Idle duration

If the run is submitted to a fleet with `nodes` set to a range and a new instance is provisioned,
Expand Down
36 changes: 36 additions & 0 deletions mkdocs/docs/guides/protips.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,42 @@ $ dstack apply -R -f examples/.dstack.yml

Or, set [`creation_policy`](../reference/dstack.yml/dev-environment.md#creation_policy) to `reuse` in the run configuration.

### Instances

Use `instances` to restrict a run to particular existing fleet instances. You can specify
instance names, hostnames or IP addresses, or a fleet name with an instance number.
For the `fleet` form, use `<project>/<fleet>` when the fleet belongs to another project:

<div editor-title=".dstack.yml">

```yaml
type: dev-environment
name: vscode
ide: vscode

instances:
- name: my-fleet-3
- hostname: 203.0.113.10
- fleet: my-fleet
instance: 3
```

</div>

??? info "Short syntax"

To match by instance name, you can use the string shorthand:

```yaml
instances:
- my-fleet-3
```

When `instances` is set, the run is only placed on a matching existing instance and
`dstack` never provisions new instances. If no matching instance is available, the run
fails with a no-capacity error (use [`retry`](../reference/dstack.yml/dev-environment.md#retry)
to wait for a targeted instance to free up).

### Idle duration

If the run is submitted to a fleet with `nodes` set to a range and a new instance is provisioned, the shorter of the fleet's and run's `idle_duration` is used.
Expand Down
29 changes: 29 additions & 0 deletions mkdocs/docs/reference/dstack.yml/dev-environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,35 @@ The `dev-environment` configuration type allows running [dev environments](../..
type:
required: true

### `instances[n]` { #_instances data-toc-label="instances" }

=== "Instance name"

#SCHEMA# dstack._internal.core.models.profiles.InstanceNameSelector
overrides:
show_root_heading: false

=== "Hostname"

#SCHEMA# dstack._internal.core.models.profiles.InstanceHostnameSelector
overrides:
show_root_heading: false

=== "Fleet instance"

#SCHEMA# dstack._internal.core.models.profiles.FleetInstanceSelector
overrides:
show_root_heading: false

??? info "Short syntax"

The short syntax for `instances` is a list of instance names:

```yaml
instances:
- my-fleet-0
```

### `resources`

#SCHEMA# dstack._internal.core.models.resources.ResourcesSpec
Expand Down
29 changes: 29 additions & 0 deletions mkdocs/docs/reference/dstack.yml/service.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,35 @@ The `service` configuration type allows running [services](../../concepts/servic
type:
required: true

### `instances[n]` { #_instances data-toc-label="instances" }

=== "Instance name"

#SCHEMA# dstack._internal.core.models.profiles.InstanceNameSelector
overrides:
show_root_heading: false

=== "Hostname"

#SCHEMA# dstack._internal.core.models.profiles.InstanceHostnameSelector
overrides:
show_root_heading: false

=== "Fleet instance"

#SCHEMA# dstack._internal.core.models.profiles.FleetInstanceSelector
overrides:
show_root_heading: false

??? info "Short syntax"

The short syntax for `instances` is a list of instance names:

```yaml
instances:
- my-fleet-0
```

### `resources`

#SCHEMA# dstack._internal.core.models.resources.ResourcesSpec
Expand Down
29 changes: 29 additions & 0 deletions mkdocs/docs/reference/dstack.yml/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,35 @@ The `task` configuration type allows running [tasks](../../concepts/tasks.md).
type:
required: true

### `instances[n]` { #_instances data-toc-label="instances" }

=== "Instance name"

#SCHEMA# dstack._internal.core.models.profiles.InstanceNameSelector
overrides:
show_root_heading: false

=== "Hostname"

#SCHEMA# dstack._internal.core.models.profiles.InstanceHostnameSelector
overrides:
show_root_heading: false

=== "Fleet instance"

#SCHEMA# dstack._internal.core.models.profiles.FleetInstanceSelector
overrides:
show_root_heading: false

??? info "Short syntax"

The short syntax for `instances` is a list of instance names:

```yaml
instances:
- my-fleet-0
```

### `resources`

#SCHEMA# dstack._internal.core.models.resources.ResourcesSpec
Expand Down
2 changes: 2 additions & 0 deletions src/dstack/_internal/core/compatibility/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ def get_profile_excludes(profile: Optional[ProfileParams]) -> IncludeExcludeSetT
return excludes
if profile.backend_options is None:
excludes.add("backend_options")
if profile.instances is None:
excludes.add("instances")
return excludes


Expand Down
2 changes: 2 additions & 0 deletions src/dstack/_internal/core/compatibility/runs.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ def get_run_spec_excludes(run_spec: RunSpec) -> IncludeExcludeDictType:
spec_excludes: IncludeExcludeDictType = {}
configuration_excludes: IncludeExcludeDictType = {}
profile_excludes = get_profile_excludes(run_spec.profile)
for field in get_profile_excludes(run_spec.configuration):
configuration_excludes[field] = True

if run_spec.configuration.backend_options is None:
configuration_excludes["backend_options"] = True
Expand Down
74 changes: 73 additions & 1 deletion src/dstack/_internal/core/models/profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,58 @@ def crons(self) -> List[str]:
return self.cron


class InstanceNameSelector(CoreModel):
name: Annotated[str, Field(description="The fleet instance name", min_length=1)]


class InstanceHostnameSelector(CoreModel):
hostname: Annotated[
str, Field(description="The fleet instance hostname or IP address", min_length=1)
]


def _parse_fleet_instance_selector_fleet(v: Any) -> Any:
if isinstance(v, str):
return EntityReference.parse(v)
return v


class FleetInstanceSelectorConfig(CoreConfig):
@staticmethod
def schema_extra(schema: Dict[str, Any]):
add_extra_schema_types(
schema["properties"]["fleet"],
extra_types=[{"type": "string", "minLength": 1}],
)


class FleetInstanceSelector(generate_dual_core_model(FleetInstanceSelectorConfig)):
fleet: Annotated[
EntityReference,
Field(
description=(
"The fleet reference. For fleets owned by the current project, specify"
" the fleet name. For a fleet from another project, specify"
" `<project name>/<fleet name>` or an object with `project` and `name`"
),
),
]
instance: Annotated[int, Field(description="The fleet instance number", ge=0)]

_validate_fleet = validator("fleet", pre=True, allow_reuse=True)(
_parse_fleet_instance_selector_fleet
)


InstanceSelector = Union[InstanceNameSelector, InstanceHostnameSelector, FleetInstanceSelector]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) Not described in the .dstack.yml references. Consider adding a section similar to volumes

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added instances sections to the dev-environment, task, and service references with tabs per selector type and a short-syntax note.



def parse_instance_selector(v: Union[InstanceSelector, str]) -> InstanceSelector:
if isinstance(v, str):
return InstanceNameSelector(name=v)
return v


class ProfileParamsConfig(CoreConfig):
@staticmethod
def schema_extra(schema: Dict[str, Any]):
Expand All @@ -249,6 +301,10 @@ def schema_extra(schema: Dict[str, Any]):
schema["properties"]["idle_duration"],
extra_types=[{"type": "string"}],
)
add_extra_schema_types(
schema["properties"]["instances"]["items"],
extra_types=[{"type": "string", "minLength": 1}],
)


class ProfileParams(CoreModel):
Expand Down Expand Up @@ -387,10 +443,23 @@ class ProfileParams(CoreModel):
description=(
"The fleets considered for reuse."
" For fleets owned by the current project, specify fleet names."
" For imported fleets, specify `<project name>/<fleet name>`"
" For fleets from another project, specify `<project name>/<fleet name>`"
),
),
] = None
instances: Annotated[
Optional[List[InstanceSelector]],
Field(
description=(
"The specific fleet instances to consider for reuse."
" Each value can be an instance name string (e.g. `my-fleet-0`)"
" or an object with `name`, `hostname`, or `fleet` and `instance`."
" When set, the run is only placed on a matching existing instance"
" and no new instances are provisioned"
),
min_items=1,
),
] = None
tags: Annotated[
Optional[Dict[str, str]],
Field(
Expand All @@ -416,6 +485,9 @@ class ProfileParams(CoreModel):
parse_idle_duration
)
_validate_fleets = validator("fleets", allow_reuse=True, each_item=True)(EntityReference.parse)
_validate_instances = validator("instances", pre=True, allow_reuse=True, each_item=True)(
parse_instance_selector
)
_validate_tags = validator("tags", pre=True, allow_reuse=True)(tags_validator)
_validate_backend_options = validator("backend_options", allow_reuse=True)(
validate_backend_options
Expand Down
Loading
Loading