Skip to content

Commit b375683

Browse files
Bihanjvstme
andauthored
Add digital ocean and amd dev backend (#3030)
* Add DigitalOcean Backend * Add DigitalOcean base class with DigitalOceanCloud and AMDDevCloud sub classes * Add project_name config * Resolve Review Comments and Update docs * Update src/dstack/_internal/core/backends/digitalocean_base/api_client.py Co-authored-by: jvstme <36324149+jvstme@users.noreply.github.com> * Update src/dstack/_internal/core/backends/digitalocean_base/compute.py Co-authored-by: jvstme <36324149+jvstme@users.noreply.github.com> * Update src/dstack/_internal/core/backends/digitalocean_base/compute.py Co-authored-by: jvstme <36324149+jvstme@users.noreply.github.com> * Update src/dstack/_internal/core/backends/digitalocean_base/models.py Co-authored-by: jvstme <36324149+jvstme@users.noreply.github.com> * Update src/dstack/_internal/core/backends/digitalocean_base/models.py Co-authored-by: jvstme <36324149+jvstme@users.noreply.github.com> * Bump gpuhunt to 0.1.8 --------- Co-authored-by: Bihan Rana Co-authored-by: jvstme <36324149+jvstme@users.noreply.github.com>
1 parent a4ae127 commit b375683

File tree

21 files changed

+669
-46
lines changed

21 files changed

+669
-46
lines changed

docs/docs/concepts/backends.md

Lines changed: 98 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -579,34 +579,6 @@ gcloud projects list --format="json(projectId)"
579579
Using private subnets assumes that both the `dstack` server and users can access the configured VPC's private subnets.
580580
Additionally, [Cloud NAT](https://cloud.google.com/nat/docs/overview) must be configured to provide access to external resources for provisioned instances.
581581

582-
## Hot Aisle
583-
584-
Log in to the SSH TUI as described in the [Hot Aisle Quick Start :material-arrow-top-right-thin:{ .external }](https://hotaisle.xyz/quick-start/).
585-
Create a new team and generate an API key for the member in the team.
586-
587-
Then, go ahead and configure the backend:
588-
589-
<div editor-title="~/.dstack/server/config.yml">
590-
591-
```yaml
592-
projects:
593-
- name: main
594-
backends:
595-
- type: hotaisle
596-
team_handle: hotaisle-team-handle
597-
creds:
598-
type: api_key
599-
api_key: 9c27a4bb7a8e472fae12ab34.3f2e3c1db75b9a0187fd2196c6b3e56d2b912e1c439ba08d89e7b6fcd4ef1d3f
600-
```
601-
602-
</div>
603-
604-
??? info "Required permissions"
605-
The API key must have the following roles assigned:
606-
607-
* **Owner role for the user** - Required for creating and managing SSH keys
608-
* **Operator role for the team** - Required for managing virtual machines within the team
609-
610582
## Lambda
611583

612584
Log into your [Lambda Cloud :material-arrow-top-right-thin:{ .external }](https://lambdalabs.com/service/gpu-cloud) account, click API keys in the sidebar, and then click the `Generate API key`
@@ -937,6 +909,104 @@ projects:
937909

938910
</div>
939911

912+
## AMD Developer Cloud
913+
Log into your [AMD Developer Cloud :material-arrow-top-right-thin:{ .external }](https://amd.digitalocean.com/login) account. Click `API` in the sidebar and click the button `Generate New Token`.
914+
915+
Then, go ahead and configure the backend:
916+
917+
<div editor-title="~/.dstack/server/config.yml">
918+
919+
```yaml
920+
projects:
921+
- name: main
922+
backends:
923+
- type: amddevcloud
924+
project_name: my-amd-project
925+
creds:
926+
type: api_key
927+
api_key: dop_v1_71ea79a0c4bf2ffa70ac9d2a7b2689d2b41768567b22ebabe58a80066dcc5e92
928+
```
929+
930+
</div>
931+
932+
??? info "Project Name"
933+
**project_name** configuration is optional. If it is not provided, the default project is used.
934+
935+
??? info "Required permissions"
936+
The API key must have the following scopes assigned:
937+
938+
* **account** - read
939+
* **droplet** - create,read,update,delete,admin
940+
* **project** - create,read,update,delete
941+
* **regions** - read
942+
* **sizes** - read
943+
* **ssh_key** - create,read,update,delete
944+
945+
946+
947+
## Digital Ocean
948+
Log into your [Digital Ocean :material-arrow-top-right-thin:{ .external }](https://cloud.digitalocean.com/login) account. Click `API` in the sidebar and click the button `Generate New Token`.
949+
950+
Then, go ahead and configure the backend:
951+
952+
<div editor-title="~/.dstack/server/config.yml">
953+
954+
```yaml
955+
projects:
956+
- name: main
957+
backends:
958+
- type: digitalocean
959+
project_name: my-digital-ocean-project
960+
creds:
961+
type: api_key
962+
api_key: dop_v1_71ea79a0c4bf2ffa70ac9d2a7b2689d2b41768567b22ebabe58a80066dcc5e92
963+
```
964+
965+
</div>
966+
967+
??? info "Project Name"
968+
**project_name** configuration is optional. If it is not provided, the default project is used.
969+
970+
??? info "Required permissions"
971+
The API key must have the following scopes assigned:
972+
973+
* **account** - read
974+
* **droplet** - create,read,update,delete,admin
975+
* **project** - create,read,update,delete
976+
* **regions** - read
977+
* **sizes** - read
978+
* **ssh_key** - create,read,update,delete
979+
980+
981+
## Hot Aisle
982+
983+
Log in to the SSH TUI as described in the [Hot Aisle Quick Start :material-arrow-top-right-thin:{ .external }](https://hotaisle.xyz/quick-start/).
984+
Create a new team and generate an API key for the member in the team.
985+
986+
Then, go ahead and configure the backend:
987+
988+
<div editor-title="~/.dstack/server/config.yml">
989+
990+
```yaml
991+
projects:
992+
- name: main
993+
backends:
994+
- type: hotaisle
995+
team_handle: hotaisle-team-handle
996+
creds:
997+
type: api_key
998+
api_key: 9c27a4bb7a8e472fae12ab34.3f2e3c1db75b9a0187fd2196c6b3e56d2b912e1c439ba08d89e7b6fcd4ef1d3f
999+
```
1000+
1001+
</div>
1002+
1003+
??? info "Required permissions"
1004+
The API key must have the following roles assigned:
1005+
1006+
* **Owner role for the user** - Required for creating and managing SSH keys
1007+
* **Operator role for the team** - Required for managing virtual machines within the team
1008+
1009+
9401010
## CloudRift
9411011

9421012
Log into your [CloudRift :material-arrow-top-right-thin:{ .external }](https://console.cloudrift.ai/) console, click `API Keys` in the sidebar and click the button to create a new API key.

docs/docs/reference/server/config.yml.md

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -126,22 +126,6 @@ to configure [backends](../../concepts/backends.md) and other [server-level sett
126126
type:
127127
required: true
128128

129-
##### `projects[n].backends[type=hotaisle]` { #hotaisle data-toc-label="hotaisle" }
130-
131-
#SCHEMA# dstack._internal.core.backends.hotaisle.models.HotAisleBackendConfigWithCreds
132-
overrides:
133-
show_root_heading: false
134-
type:
135-
required: true
136-
item_id_prefix: hotaisle-
137-
138-
###### `projects[n].backends[type=hotaisle].creds` { #hotaisle-creds data-toc-label="creds" }
139-
140-
#SCHEMA# dstack._internal.core.backends.hotaisle.models.HotAisleAPIKeyCreds
141-
overrides:
142-
show_root_heading: false
143-
type:
144-
required: true
145129

146130
##### `projects[n].backends[type=lambda]` { #lambda data-toc-label="lambda" }
147131

@@ -332,6 +316,57 @@ to configure [backends](../../concepts/backends.md) and other [server-level sett
332316
type:
333317
required: true
334318

319+
##### `projects[n].backends[type=amddevcloud]` { #amddevcloud data-toc-label="amddevcloud" }
320+
321+
#SCHEMA# dstack._internal.core.backends.digitalocean_base.models.BaseDigitalOceanBackendConfigWithCreds
322+
overrides:
323+
show_root_heading: false
324+
type:
325+
required: true
326+
item_id_prefix: amddevcloud-
327+
328+
###### `projects[n].backends[type=amddevcloud].creds` { #amddevcloud-creds data-toc-label="creds" }
329+
330+
#SCHEMA# dstack._internal.core.backends.digitalocean_base.models.BaseDigitalOceanAPIKeyCreds
331+
overrides:
332+
show_root_heading: false
333+
type:
334+
required: true
335+
336+
##### `projects[n].backends[type=digitalocean]` { #digitalocean data-toc-label="digitalocean" }
337+
338+
#SCHEMA# dstack._internal.core.backends.digitalocean_base.models.BaseDigitalOceanBackendConfigWithCreds
339+
overrides:
340+
show_root_heading: false
341+
type:
342+
required: true
343+
item_id_prefix: digitalocean-
344+
345+
###### `projects[n].backends[type=digitalocean].creds` { #digitalocean-creds data-toc-label="creds" }
346+
347+
#SCHEMA# dstack._internal.core.backends.digitalocean_base.models.BaseDigitalOceanAPIKeyCreds
348+
overrides:
349+
show_root_heading: false
350+
type:
351+
required: true
352+
353+
##### `projects[n].backends[type=hotaisle]` { #hotaisle data-toc-label="hotaisle" }
354+
355+
#SCHEMA# dstack._internal.core.backends.hotaisle.models.HotAisleBackendConfigWithCreds
356+
overrides:
357+
show_root_heading: false
358+
type:
359+
required: true
360+
item_id_prefix: hotaisle-
361+
362+
###### `projects[n].backends[type=hotaisle].creds` { #hotaisle-creds data-toc-label="creds" }
363+
364+
#SCHEMA# dstack._internal.core.backends.hotaisle.models.HotAisleAPIKeyCreds
365+
overrides:
366+
show_root_heading: false
367+
type:
368+
required: true
369+
335370
##### `projects[n].backends[type=cloudrift]` { #cloudrift data-toc-label="cloudrift" }
336371

337372
#SCHEMA# dstack._internal.core.backends.cloudrift.models.CloudRiftBackendConfigWithCreds

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ dependencies = [
3232
"python-multipart>=0.0.16",
3333
"filelock",
3434
"psutil",
35-
"gpuhunt==0.1.7",
35+
"gpuhunt==0.1.8",
3636
"argcomplete>=3.5.0",
3737
"ignore-python>=0.2.0",
3838
"orjson",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# This package contains the implementation for the AMDDevCloud backend.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from dstack._internal.core.backends.amddevcloud.compute import AMDDevCloudCompute
2+
from dstack._internal.core.backends.digitalocean_base.backend import BaseDigitalOceanBackend
3+
from dstack._internal.core.backends.digitalocean_base.models import BaseDigitalOceanConfig
4+
from dstack._internal.core.models.backends.base import BackendType
5+
6+
7+
class AMDDevCloudBackend(BaseDigitalOceanBackend):
8+
TYPE = BackendType.AMDDEVCLOUD
9+
COMPUTE_CLASS = AMDDevCloudCompute
10+
11+
def __init__(self, config: BaseDigitalOceanConfig, api_url: str):
12+
self.config = config
13+
self._compute = AMDDevCloudCompute(self.config, api_url=api_url, type=self.TYPE)
14+
15+
def compute(self) -> AMDDevCloudCompute:
16+
return self._compute
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from dstack._internal.core.backends.digitalocean_base.compute import BaseDigitalOceanCompute
2+
3+
4+
class AMDDevCloudCompute(BaseDigitalOceanCompute):
5+
pass
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from typing import Optional
2+
3+
from dstack._internal.core.backends.amddevcloud.backend import AMDDevCloudBackend
4+
from dstack._internal.core.backends.digitalocean_base.api_client import DigitalOceanAPIClient
5+
from dstack._internal.core.backends.digitalocean_base.backend import BaseDigitalOceanBackend
6+
from dstack._internal.core.backends.digitalocean_base.configurator import (
7+
BaseDigitalOceanConfigurator,
8+
)
9+
from dstack._internal.core.backends.digitalocean_base.models import AnyBaseDigitalOceanCreds
10+
from dstack._internal.core.models.backends.base import (
11+
BackendType,
12+
)
13+
14+
15+
class AMDDevCloudConfigurator(BaseDigitalOceanConfigurator):
16+
TYPE = BackendType.AMDDEVCLOUD
17+
BACKEND_CLASS = AMDDevCloudBackend
18+
API_URL = "https://api-amd.digitalocean.com"
19+
20+
def get_backend(self, record) -> BaseDigitalOceanBackend:
21+
config = self._get_config(record)
22+
return AMDDevCloudBackend(config=config, api_url=self.API_URL)
23+
24+
def _validate_creds(self, creds: AnyBaseDigitalOceanCreds, project_name: Optional[str] = None):
25+
api_client = DigitalOceanAPIClient(creds.api_key, self.API_URL)
26+
api_client.validate_api_key()
27+
if project_name:
28+
api_client.validate_project_name(project_name)

src/dstack/_internal/core/backends/base/offers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ def get_catalog_offers(
3434
provider = backend.value
3535
if backend == BackendType.LAMBDA:
3636
provider = "lambdalabs"
37+
if backend == BackendType.AMDDEVCLOUD:
38+
provider = "digitalocean"
3739
q = requirements_to_query_filter(requirements)
3840
q.provider = [provider]
3941
offers = []

src/dstack/_internal/core/backends/configurators.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55

66
_CONFIGURATOR_CLASSES: List[Type[Configurator]] = []
77

8+
try:
9+
from dstack._internal.core.backends.amddevcloud.configurator import AMDDevCloudConfigurator
10+
11+
_CONFIGURATOR_CLASSES.append(AMDDevCloudConfigurator)
12+
except ImportError:
13+
pass
814

915
try:
1016
from dstack._internal.core.backends.aws.configurator import AWSConfigurator
@@ -47,6 +53,15 @@
4753
except ImportError:
4854
pass
4955

56+
try:
57+
from dstack._internal.core.backends.digitalocean.configurator import (
58+
DigitalOceanConfigurator,
59+
)
60+
61+
_CONFIGURATOR_CLASSES.append(DigitalOceanConfigurator)
62+
except ImportError:
63+
pass
64+
5065
try:
5166
from dstack._internal.core.backends.gcp.configurator import GCPConfigurator
5267

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# DigitalOcean backend for dstack

0 commit comments

Comments
 (0)