dstack 0.18.44__py3-none-any.whl → 0.19.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. dstack/_internal/cli/commands/gateway.py +15 -3
  2. dstack/_internal/cli/commands/logs.py +0 -22
  3. dstack/_internal/cli/commands/stats.py +8 -17
  4. dstack/_internal/cli/main.py +1 -5
  5. dstack/_internal/cli/services/configurators/fleet.py +4 -39
  6. dstack/_internal/cli/services/configurators/run.py +22 -21
  7. dstack/_internal/cli/services/profile.py +34 -83
  8. dstack/_internal/cli/utils/gateway.py +1 -1
  9. dstack/_internal/core/backends/__init__.py +56 -39
  10. dstack/_internal/core/backends/aws/__init__.py +0 -25
  11. dstack/_internal/core/backends/aws/auth.py +1 -10
  12. dstack/_internal/core/backends/aws/backend.py +26 -0
  13. dstack/_internal/core/backends/aws/compute.py +20 -45
  14. dstack/_internal/{server/services/backends/configurators/aws.py → core/backends/aws/configurator.py} +46 -85
  15. dstack/_internal/core/backends/aws/models.py +135 -0
  16. dstack/_internal/core/backends/aws/resources.py +1 -1
  17. dstack/_internal/core/backends/azure/__init__.py +0 -20
  18. dstack/_internal/core/backends/azure/auth.py +2 -11
  19. dstack/_internal/core/backends/azure/backend.py +21 -0
  20. dstack/_internal/core/backends/azure/compute.py +13 -27
  21. dstack/_internal/{server/services/backends/configurators/azure.py → core/backends/azure/configurator.py} +141 -210
  22. dstack/_internal/core/backends/azure/models.py +89 -0
  23. dstack/_internal/core/backends/base/__init__.py +0 -12
  24. dstack/_internal/core/backends/base/backend.py +18 -0
  25. dstack/_internal/core/backends/base/compute.py +153 -33
  26. dstack/_internal/core/backends/base/configurator.py +105 -0
  27. dstack/_internal/core/backends/base/models.py +14 -0
  28. dstack/_internal/core/backends/configurators.py +138 -0
  29. dstack/_internal/core/backends/cudo/__init__.py +0 -15
  30. dstack/_internal/core/backends/cudo/backend.py +16 -0
  31. dstack/_internal/core/backends/cudo/compute.py +8 -26
  32. dstack/_internal/core/backends/cudo/configurator.py +72 -0
  33. dstack/_internal/core/backends/cudo/models.py +37 -0
  34. dstack/_internal/core/backends/datacrunch/__init__.py +0 -15
  35. dstack/_internal/core/backends/datacrunch/backend.py +16 -0
  36. dstack/_internal/core/backends/datacrunch/compute.py +8 -25
  37. dstack/_internal/core/backends/datacrunch/configurator.py +66 -0
  38. dstack/_internal/core/backends/datacrunch/models.py +38 -0
  39. dstack/_internal/core/{models/backends/dstack.py → backends/dstack/models.py} +7 -7
  40. dstack/_internal/core/backends/gcp/__init__.py +0 -16
  41. dstack/_internal/core/backends/gcp/auth.py +2 -11
  42. dstack/_internal/core/backends/gcp/backend.py +17 -0
  43. dstack/_internal/core/backends/gcp/compute.py +13 -43
  44. dstack/_internal/{server/services/backends/configurators/gcp.py → core/backends/gcp/configurator.py} +46 -103
  45. dstack/_internal/core/backends/gcp/models.py +125 -0
  46. dstack/_internal/core/backends/kubernetes/__init__.py +0 -15
  47. dstack/_internal/core/backends/kubernetes/backend.py +16 -0
  48. dstack/_internal/core/backends/kubernetes/compute.py +16 -5
  49. dstack/_internal/core/backends/kubernetes/configurator.py +55 -0
  50. dstack/_internal/core/backends/kubernetes/models.py +72 -0
  51. dstack/_internal/core/backends/lambdalabs/__init__.py +0 -16
  52. dstack/_internal/core/backends/lambdalabs/backend.py +17 -0
  53. dstack/_internal/core/backends/lambdalabs/compute.py +7 -28
  54. dstack/_internal/core/backends/lambdalabs/configurator.py +82 -0
  55. dstack/_internal/core/backends/lambdalabs/models.py +37 -0
  56. dstack/_internal/core/backends/local/__init__.py +0 -13
  57. dstack/_internal/core/backends/local/backend.py +14 -0
  58. dstack/_internal/core/backends/local/compute.py +16 -2
  59. dstack/_internal/core/backends/models.py +128 -0
  60. dstack/_internal/core/backends/oci/__init__.py +0 -15
  61. dstack/_internal/core/backends/oci/auth.py +1 -5
  62. dstack/_internal/core/backends/oci/backend.py +16 -0
  63. dstack/_internal/core/backends/oci/compute.py +9 -23
  64. dstack/_internal/{server/services/backends/configurators/oci.py → core/backends/oci/configurator.py} +40 -85
  65. dstack/_internal/core/{models/backends/oci.py → backends/oci/models.py} +24 -25
  66. dstack/_internal/core/backends/oci/region.py +1 -1
  67. dstack/_internal/core/backends/runpod/__init__.py +0 -15
  68. dstack/_internal/core/backends/runpod/backend.py +16 -0
  69. dstack/_internal/core/backends/runpod/compute.py +7 -3
  70. dstack/_internal/core/backends/runpod/configurator.py +59 -0
  71. dstack/_internal/core/backends/runpod/models.py +54 -0
  72. dstack/_internal/core/backends/template/__init__.py +0 -0
  73. dstack/_internal/core/backends/tensordock/__init__.py +0 -15
  74. dstack/_internal/core/backends/tensordock/backend.py +16 -0
  75. dstack/_internal/core/backends/tensordock/compute.py +8 -27
  76. dstack/_internal/core/backends/tensordock/configurator.py +68 -0
  77. dstack/_internal/core/backends/tensordock/models.py +38 -0
  78. dstack/_internal/core/backends/vastai/__init__.py +0 -15
  79. dstack/_internal/core/backends/vastai/backend.py +16 -0
  80. dstack/_internal/core/backends/vastai/compute.py +2 -2
  81. dstack/_internal/core/backends/vastai/configurator.py +66 -0
  82. dstack/_internal/core/backends/vastai/models.py +37 -0
  83. dstack/_internal/core/backends/vultr/__init__.py +0 -15
  84. dstack/_internal/core/backends/vultr/backend.py +16 -0
  85. dstack/_internal/core/backends/vultr/compute.py +10 -24
  86. dstack/_internal/core/backends/vultr/configurator.py +64 -0
  87. dstack/_internal/core/backends/vultr/models.py +34 -0
  88. dstack/_internal/core/models/backends/__init__.py +0 -184
  89. dstack/_internal/core/models/backends/base.py +0 -19
  90. dstack/_internal/core/models/configurations.py +20 -15
  91. dstack/_internal/core/models/envs.py +4 -3
  92. dstack/_internal/core/models/fleets.py +17 -22
  93. dstack/_internal/core/models/gateways.py +3 -3
  94. dstack/_internal/core/models/instances.py +24 -0
  95. dstack/_internal/core/models/profiles.py +41 -46
  96. dstack/_internal/core/models/projects.py +1 -1
  97. dstack/_internal/core/models/repos/base.py +0 -5
  98. dstack/_internal/core/models/repos/local.py +3 -3
  99. dstack/_internal/core/models/repos/remote.py +26 -12
  100. dstack/_internal/core/models/repos/virtual.py +1 -1
  101. dstack/_internal/core/models/resources.py +45 -76
  102. dstack/_internal/core/models/runs.py +17 -19
  103. dstack/_internal/core/models/volumes.py +1 -3
  104. dstack/_internal/core/services/profiles.py +7 -16
  105. dstack/_internal/core/services/repos.py +0 -4
  106. dstack/_internal/server/app.py +0 -3
  107. dstack/_internal/server/background/tasks/process_gateways.py +4 -8
  108. dstack/_internal/server/background/tasks/process_instances.py +14 -9
  109. dstack/_internal/server/background/tasks/process_metrics.py +1 -1
  110. dstack/_internal/server/background/tasks/process_placement_groups.py +4 -1
  111. dstack/_internal/server/background/tasks/process_prometheus_metrics.py +1 -1
  112. dstack/_internal/server/background/tasks/process_running_jobs.py +14 -5
  113. dstack/_internal/server/background/tasks/process_submitted_jobs.py +16 -37
  114. dstack/_internal/server/background/tasks/process_volumes.py +5 -2
  115. dstack/_internal/server/migrations/versions/7bc2586e8b9e_make_instancemodel_pool_id_optional.py +36 -0
  116. dstack/_internal/server/migrations/versions/bc8ca4a505c6_store_backendtype_as_string.py +171 -0
  117. dstack/_internal/server/models.py +48 -9
  118. dstack/_internal/server/routers/backends.py +14 -23
  119. dstack/_internal/server/routers/instances.py +3 -4
  120. dstack/_internal/server/routers/metrics.py +10 -8
  121. dstack/_internal/server/routers/prometheus.py +1 -1
  122. dstack/_internal/server/routers/repos.py +1 -2
  123. dstack/_internal/server/routers/runs.py +13 -59
  124. dstack/_internal/server/schemas/gateways.py +14 -23
  125. dstack/_internal/server/schemas/projects.py +7 -2
  126. dstack/_internal/server/schemas/repos.py +2 -38
  127. dstack/_internal/server/schemas/runner.py +1 -0
  128. dstack/_internal/server/schemas/runs.py +1 -24
  129. dstack/_internal/server/services/backends/__init__.py +85 -158
  130. dstack/_internal/server/services/config.py +52 -576
  131. dstack/_internal/server/services/fleets.py +8 -103
  132. dstack/_internal/server/services/gateways/__init__.py +12 -4
  133. dstack/_internal/server/services/{pools.py → instances.py} +22 -329
  134. dstack/_internal/server/services/jobs/__init__.py +9 -6
  135. dstack/_internal/server/services/jobs/configurators/base.py +16 -0
  136. dstack/_internal/server/services/jobs/configurators/dev.py +9 -1
  137. dstack/_internal/server/services/jobs/configurators/extensions/cursor.py +42 -0
  138. dstack/_internal/server/services/metrics.py +39 -13
  139. dstack/_internal/server/services/offers.py +1 -1
  140. dstack/_internal/server/services/projects.py +23 -14
  141. dstack/_internal/server/services/prometheus.py +176 -18
  142. dstack/_internal/server/services/runs.py +24 -16
  143. dstack/_internal/server/services/volumes.py +8 -4
  144. dstack/_internal/server/statics/index.html +1 -1
  145. dstack/_internal/server/statics/{main-4eb116b97819badd1e2c.js → main-4a0fe83e84574654e397.js} +18 -14
  146. dstack/_internal/server/statics/{main-4eb116b97819badd1e2c.js.map → main-4a0fe83e84574654e397.js.map} +1 -1
  147. dstack/_internal/server/testing/common.py +58 -32
  148. dstack/_internal/utils/json_schema.py +6 -0
  149. dstack/_internal/utils/ssh.py +2 -1
  150. dstack/api/__init__.py +4 -0
  151. dstack/api/_public/__init__.py +16 -20
  152. dstack/api/_public/backends.py +1 -1
  153. dstack/api/_public/repos.py +36 -36
  154. dstack/api/_public/runs.py +167 -83
  155. dstack/api/server/__init__.py +11 -13
  156. dstack/api/server/_backends.py +12 -16
  157. dstack/api/server/_fleets.py +15 -57
  158. dstack/api/server/_gateways.py +3 -14
  159. dstack/api/server/_repos.py +1 -4
  160. dstack/api/server/_runs.py +21 -100
  161. dstack/api/server/_volumes.py +10 -5
  162. dstack/version.py +1 -1
  163. {dstack-0.18.44.dist-info → dstack-0.19.0.dist-info}/METADATA +1 -1
  164. {dstack-0.18.44.dist-info → dstack-0.19.0.dist-info}/RECORD +218 -204
  165. tests/_internal/cli/services/configurators/test_profile.py +6 -6
  166. tests/_internal/core/backends/aws/test_configurator.py +35 -0
  167. tests/_internal/core/backends/aws/test_resources.py +1 -1
  168. tests/_internal/core/backends/azure/test_configurator.py +61 -0
  169. tests/_internal/core/backends/cudo/__init__.py +0 -0
  170. tests/_internal/core/backends/cudo/test_configurator.py +37 -0
  171. tests/_internal/core/backends/datacrunch/__init__.py +0 -0
  172. tests/_internal/core/backends/datacrunch/test_configurator.py +17 -0
  173. tests/_internal/core/backends/gcp/test_configurator.py +42 -0
  174. tests/_internal/core/backends/kubernetes/test_configurator.py +43 -0
  175. tests/_internal/core/backends/lambdalabs/__init__.py +0 -0
  176. tests/_internal/core/backends/lambdalabs/test_configurator.py +38 -0
  177. tests/_internal/core/backends/oci/test_configurator.py +55 -0
  178. tests/_internal/core/backends/runpod/__init__.py +0 -0
  179. tests/_internal/core/backends/runpod/test_configurator.py +33 -0
  180. tests/_internal/core/backends/tensordock/__init__.py +0 -0
  181. tests/_internal/core/backends/tensordock/test_configurator.py +38 -0
  182. tests/_internal/core/backends/vastai/__init__.py +0 -0
  183. tests/_internal/core/backends/vastai/test_configurator.py +33 -0
  184. tests/_internal/core/backends/vultr/__init__.py +0 -0
  185. tests/_internal/core/backends/vultr/test_configurator.py +33 -0
  186. tests/_internal/server/background/tasks/test_process_gateways.py +4 -0
  187. tests/_internal/server/background/tasks/test_process_instances.py +49 -48
  188. tests/_internal/server/background/tasks/test_process_metrics.py +0 -3
  189. tests/_internal/server/background/tasks/test_process_placement_groups.py +2 -0
  190. tests/_internal/server/background/tasks/test_process_prometheus_metrics.py +0 -3
  191. tests/_internal/server/background/tasks/test_process_running_jobs.py +0 -21
  192. tests/_internal/server/background/tasks/test_process_runs.py +8 -22
  193. tests/_internal/server/background/tasks/test_process_submitted_jobs.py +3 -40
  194. tests/_internal/server/background/tasks/test_process_submitted_volumes.py +2 -0
  195. tests/_internal/server/background/tasks/test_process_terminating_jobs.py +10 -15
  196. tests/_internal/server/routers/test_backends.py +6 -764
  197. tests/_internal/server/routers/test_fleets.py +0 -26
  198. tests/_internal/server/routers/test_gateways.py +27 -3
  199. tests/_internal/server/routers/test_instances.py +0 -10
  200. tests/_internal/server/routers/test_metrics.py +27 -0
  201. tests/_internal/server/routers/test_projects.py +56 -0
  202. tests/_internal/server/routers/test_prometheus.py +116 -27
  203. tests/_internal/server/routers/test_repos.py +0 -15
  204. tests/_internal/server/routers/test_runs.py +4 -219
  205. tests/_internal/server/routers/test_volumes.py +2 -3
  206. tests/_internal/server/services/backends/__init__.py +0 -0
  207. tests/_internal/server/services/jobs/configurators/test_task.py +35 -0
  208. tests/_internal/server/services/test_config.py +7 -4
  209. tests/_internal/server/services/test_fleets.py +1 -4
  210. tests/_internal/server/services/{test_pools.py → test_instances.py} +11 -49
  211. tests/_internal/server/services/test_metrics.py +9 -5
  212. tests/_internal/server/services/test_repos.py +1 -14
  213. tests/_internal/server/services/test_runs.py +0 -4
  214. dstack/_internal/cli/commands/pool.py +0 -581
  215. dstack/_internal/cli/commands/run.py +0 -75
  216. dstack/_internal/core/backends/aws/config.py +0 -18
  217. dstack/_internal/core/backends/azure/config.py +0 -12
  218. dstack/_internal/core/backends/base/config.py +0 -5
  219. dstack/_internal/core/backends/cudo/config.py +0 -9
  220. dstack/_internal/core/backends/datacrunch/config.py +0 -9
  221. dstack/_internal/core/backends/gcp/config.py +0 -22
  222. dstack/_internal/core/backends/kubernetes/config.py +0 -6
  223. dstack/_internal/core/backends/lambdalabs/config.py +0 -9
  224. dstack/_internal/core/backends/nebius/__init__.py +0 -15
  225. dstack/_internal/core/backends/nebius/api_client.py +0 -319
  226. dstack/_internal/core/backends/nebius/compute.py +0 -220
  227. dstack/_internal/core/backends/nebius/config.py +0 -6
  228. dstack/_internal/core/backends/nebius/types.py +0 -37
  229. dstack/_internal/core/backends/oci/config.py +0 -6
  230. dstack/_internal/core/backends/runpod/config.py +0 -17
  231. dstack/_internal/core/backends/tensordock/config.py +0 -9
  232. dstack/_internal/core/backends/vastai/config.py +0 -6
  233. dstack/_internal/core/backends/vultr/config.py +0 -9
  234. dstack/_internal/core/models/backends/aws.py +0 -86
  235. dstack/_internal/core/models/backends/azure.py +0 -68
  236. dstack/_internal/core/models/backends/cudo.py +0 -43
  237. dstack/_internal/core/models/backends/datacrunch.py +0 -44
  238. dstack/_internal/core/models/backends/gcp.py +0 -67
  239. dstack/_internal/core/models/backends/kubernetes.py +0 -40
  240. dstack/_internal/core/models/backends/lambdalabs.py +0 -43
  241. dstack/_internal/core/models/backends/nebius.py +0 -54
  242. dstack/_internal/core/models/backends/runpod.py +0 -42
  243. dstack/_internal/core/models/backends/tensordock.py +0 -44
  244. dstack/_internal/core/models/backends/vastai.py +0 -43
  245. dstack/_internal/core/models/backends/vultr.py +0 -40
  246. dstack/_internal/core/models/pools.py +0 -43
  247. dstack/_internal/server/routers/pools.py +0 -142
  248. dstack/_internal/server/schemas/pools.py +0 -38
  249. dstack/_internal/server/services/backends/configurators/base.py +0 -72
  250. dstack/_internal/server/services/backends/configurators/cudo.py +0 -87
  251. dstack/_internal/server/services/backends/configurators/datacrunch.py +0 -79
  252. dstack/_internal/server/services/backends/configurators/kubernetes.py +0 -63
  253. dstack/_internal/server/services/backends/configurators/lambdalabs.py +0 -98
  254. dstack/_internal/server/services/backends/configurators/nebius.py +0 -85
  255. dstack/_internal/server/services/backends/configurators/runpod.py +0 -67
  256. dstack/_internal/server/services/backends/configurators/tensordock.py +0 -82
  257. dstack/_internal/server/services/backends/configurators/vastai.py +0 -80
  258. dstack/_internal/server/services/backends/configurators/vultr.py +0 -80
  259. dstack/api/_public/pools.py +0 -41
  260. dstack/api/_public/resources.py +0 -105
  261. dstack/api/server/_pools.py +0 -63
  262. tests/_internal/server/routers/test_pools.py +0 -612
  263. /dstack/_internal/{server/services/backends/configurators → core/backends/dstack}/__init__.py +0 -0
  264. {dstack-0.18.44.dist-info → dstack-0.19.0.dist-info}/LICENSE.md +0 -0
  265. {dstack-0.18.44.dist-info → dstack-0.19.0.dist-info}/WHEEL +0 -0
  266. {dstack-0.18.44.dist-info → dstack-0.19.0.dist-info}/entry_points.txt +0 -0
  267. {dstack-0.18.44.dist-info → dstack-0.19.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,72 @@
1
+ import json
2
+
3
+ from dstack._internal.core.backends.base.configurator import (
4
+ BackendRecord,
5
+ Configurator,
6
+ raise_invalid_credentials_error,
7
+ )
8
+ from dstack._internal.core.backends.cudo import api_client
9
+ from dstack._internal.core.backends.cudo.backend import CudoBackend
10
+ from dstack._internal.core.backends.cudo.models import (
11
+ AnyCudoBackendConfig,
12
+ CudoBackendConfig,
13
+ CudoBackendConfigWithCreds,
14
+ CudoConfig,
15
+ CudoCreds,
16
+ CudoStoredConfig,
17
+ )
18
+ from dstack._internal.core.models.backends.base import BackendType
19
+
20
+ REGIONS = [
21
+ "no-luster-1",
22
+ "se-smedjebacken-1",
23
+ "gb-london-1",
24
+ "se-stockholm-1",
25
+ "us-newyork-1",
26
+ "us-santaclara-1",
27
+ ]
28
+
29
+ DEFAULT_REGION = "no-luster-1"
30
+
31
+
32
+ class CudoConfigurator(Configurator):
33
+ TYPE = BackendType.CUDO
34
+ BACKEND_CLASS = CudoBackend
35
+
36
+ def validate_config(self, config: CudoBackendConfigWithCreds, default_creds_enabled: bool):
37
+ self._validate_cudo_api_key(config.creds.api_key)
38
+
39
+ def create_backend(
40
+ self, project_name: str, config: CudoBackendConfigWithCreds
41
+ ) -> BackendRecord:
42
+ if config.regions is None:
43
+ config.regions = REGIONS
44
+ return BackendRecord(
45
+ config=CudoStoredConfig(
46
+ **CudoBackendConfig.__response__.parse_obj(config).dict()
47
+ ).json(),
48
+ auth=CudoCreds.parse_obj(config.creds).json(),
49
+ )
50
+
51
+ def get_backend_config(
52
+ self, record: BackendRecord, include_creds: bool
53
+ ) -> AnyCudoBackendConfig:
54
+ config = self._get_config(record)
55
+ if include_creds:
56
+ return CudoBackendConfigWithCreds.__response__.parse_obj(config)
57
+ return CudoBackendConfig.__response__.parse_obj(config)
58
+
59
+ def get_backend(self, record: BackendRecord) -> CudoBackend:
60
+ config = self._get_config(record)
61
+ return CudoBackend(config=config)
62
+
63
+ def _get_config(self, record: BackendRecord) -> CudoConfig:
64
+ return CudoConfig.__response__(
65
+ **json.loads(record.config),
66
+ creds=CudoCreds.parse_raw(record.auth),
67
+ )
68
+
69
+ def _validate_cudo_api_key(self, api_key: str):
70
+ client = api_client.CudoApiClient(api_key=api_key)
71
+ if not client.validate_api_key():
72
+ raise_invalid_credentials_error(fields=[["creds", "api_key"]])
@@ -0,0 +1,37 @@
1
+ from typing import Annotated, List, Literal, Optional, Union
2
+
3
+ from pydantic import Field
4
+
5
+ from dstack._internal.core.models.common import CoreModel
6
+
7
+
8
+ class CudoAPIKeyCreds(CoreModel):
9
+ type: Annotated[Literal["api_key"], Field(description="The type of credentials")] = "api_key"
10
+ api_key: Annotated[str, Field(description="The API key")]
11
+
12
+
13
+ AnyCudoCreds = CudoAPIKeyCreds
14
+ CudoCreds = AnyCudoCreds
15
+
16
+
17
+ class CudoBackendConfig(CoreModel):
18
+ type: Annotated[Literal["cudo"], Field(description="The type of backend")] = "cudo"
19
+ regions: Annotated[
20
+ Optional[List[str]], Field(description="The list of Cudo regions. Omit to use all regions")
21
+ ] = None
22
+ project_id: Annotated[str, Field(description="The project ID")]
23
+
24
+
25
+ class CudoBackendConfigWithCreds(CudoBackendConfig):
26
+ creds: Annotated[AnyCudoCreds, Field(description="The credentials")]
27
+
28
+
29
+ AnyCudoBackendConfig = Union[CudoBackendConfig, CudoBackendConfigWithCreds]
30
+
31
+
32
+ class CudoStoredConfig(CudoBackendConfig):
33
+ pass
34
+
35
+
36
+ class CudoConfig(CudoStoredConfig):
37
+ creds: AnyCudoCreds
@@ -1,15 +0,0 @@
1
- from dstack._internal.core.backends.base import Backend
2
- from dstack._internal.core.backends.datacrunch.compute import DataCrunchCompute
3
- from dstack._internal.core.backends.datacrunch.config import DataCrunchConfig
4
- from dstack._internal.core.models.backends.base import BackendType
5
-
6
-
7
- class DataCrunchBackend(Backend):
8
- TYPE: BackendType = BackendType.DATACRUNCH
9
-
10
- def __init__(self, config: DataCrunchConfig):
11
- self.config = config
12
- self._compute = DataCrunchCompute(self.config)
13
-
14
- def compute(self) -> DataCrunchCompute:
15
- return self._compute
@@ -0,0 +1,16 @@
1
+ from dstack._internal.core.backends.base.backend import Backend
2
+ from dstack._internal.core.backends.datacrunch.compute import DataCrunchCompute
3
+ from dstack._internal.core.backends.datacrunch.models import DataCrunchConfig
4
+ from dstack._internal.core.models.backends.base import BackendType
5
+
6
+
7
+ class DataCrunchBackend(Backend):
8
+ TYPE = BackendType.DATACRUNCH
9
+ COMPUTE_CLASS = DataCrunchCompute
10
+
11
+ def __init__(self, config: DataCrunchConfig):
12
+ self.config = config
13
+ self._compute = DataCrunchCompute(self.config)
14
+
15
+ def compute(self) -> DataCrunchCompute:
16
+ return self._compute
@@ -1,24 +1,23 @@
1
1
  from typing import Dict, List, Optional
2
2
 
3
- from dstack._internal.core.backends.base import Compute
3
+ from dstack._internal.core.backends.base.backend import Compute
4
4
  from dstack._internal.core.backends.base.compute import (
5
+ ComputeWithCreateInstanceSupport,
5
6
  generate_unique_instance_name,
6
7
  get_shim_commands,
7
8
  )
8
9
  from dstack._internal.core.backends.base.offers import get_catalog_offers
9
10
  from dstack._internal.core.backends.datacrunch.api_client import DataCrunchAPIClient
10
- from dstack._internal.core.backends.datacrunch.config import DataCrunchConfig
11
+ from dstack._internal.core.backends.datacrunch.models import DataCrunchConfig
11
12
  from dstack._internal.core.models.backends.base import BackendType
12
13
  from dstack._internal.core.models.instances import (
13
14
  InstanceAvailability,
14
15
  InstanceConfiguration,
15
16
  InstanceOffer,
16
17
  InstanceOfferWithAvailability,
17
- SSHKey,
18
18
  )
19
19
  from dstack._internal.core.models.resources import Memory, Range
20
- from dstack._internal.core.models.runs import Job, JobProvisioningData, Requirements, Run
21
- from dstack._internal.core.models.volumes import Volume
20
+ from dstack._internal.core.models.runs import JobProvisioningData, Requirements
22
21
  from dstack._internal.utils.logging import get_logger
23
22
 
24
23
  logger = get_logger("datacrunch.compute")
@@ -33,7 +32,10 @@ IMAGE_SIZE = Memory.parse("50GB")
33
32
  CONFIGURABLE_DISK_SIZE = Range[Memory](min=IMAGE_SIZE, max=None)
34
33
 
35
34
 
36
- class DataCrunchCompute(Compute):
35
+ class DataCrunchCompute(
36
+ ComputeWithCreateInstanceSupport,
37
+ Compute,
38
+ ):
37
39
  def __init__(self, config: DataCrunchConfig):
38
40
  super().__init__()
39
41
  self.config = config
@@ -148,25 +150,6 @@ class DataCrunchCompute(Compute):
148
150
  backend_data=None,
149
151
  )
150
152
 
151
- def run_job(
152
- self,
153
- run: Run,
154
- job: Job,
155
- instance_offer: InstanceOfferWithAvailability,
156
- project_ssh_public_key: str,
157
- project_ssh_private_key: str,
158
- volumes: List[Volume],
159
- ) -> JobProvisioningData:
160
- instance_config = InstanceConfiguration(
161
- project_name=run.project_name,
162
- instance_name=job.job_spec.job_name, # TODO: generate name
163
- ssh_keys=[
164
- SSHKey(public=project_ssh_public_key.strip()),
165
- ],
166
- user=run.user,
167
- )
168
- return self.create_instance(instance_offer, instance_config)
169
-
170
153
  def terminate_instance(
171
154
  self, instance_id: str, region: str, backend_data: Optional[str] = None
172
155
  ) -> None:
@@ -0,0 +1,66 @@
1
+ import json
2
+
3
+ from dstack._internal.core.backends.base.configurator import (
4
+ BackendRecord,
5
+ Configurator,
6
+ )
7
+ from dstack._internal.core.backends.datacrunch.backend import DataCrunchBackend
8
+ from dstack._internal.core.backends.datacrunch.models import (
9
+ AnyDataCrunchBackendConfig,
10
+ DataCrunchBackendConfig,
11
+ DataCrunchBackendConfigWithCreds,
12
+ DataCrunchConfig,
13
+ DataCrunchCreds,
14
+ DataCrunchStoredConfig,
15
+ )
16
+ from dstack._internal.core.models.backends.base import (
17
+ BackendType,
18
+ )
19
+
20
+ REGIONS = [
21
+ "FIN-01",
22
+ "ICE-01",
23
+ ]
24
+
25
+ DEFAULT_REGION = "FIN-01"
26
+
27
+
28
+ class DataCrunchConfigurator(Configurator):
29
+ TYPE = BackendType.DATACRUNCH
30
+ BACKEND_CLASS = DataCrunchBackend
31
+
32
+ def validate_config(
33
+ self, config: DataCrunchBackendConfigWithCreds, default_creds_enabled: bool
34
+ ):
35
+ # FIXME: validate datacrunch creds
36
+ return
37
+
38
+ def create_backend(
39
+ self, project_name: str, config: DataCrunchBackendConfigWithCreds
40
+ ) -> BackendRecord:
41
+ if config.regions is None:
42
+ config.regions = REGIONS
43
+ return BackendRecord(
44
+ config=DataCrunchStoredConfig(
45
+ **DataCrunchBackendConfig.__response__.parse_obj(config).dict()
46
+ ).json(),
47
+ auth=DataCrunchCreds.parse_obj(config.creds).json(),
48
+ )
49
+
50
+ def get_backend_config(
51
+ self, record: BackendRecord, include_creds: bool
52
+ ) -> AnyDataCrunchBackendConfig:
53
+ config = self._get_config(record)
54
+ if include_creds:
55
+ return DataCrunchBackendConfigWithCreds.__response__.parse_obj(config)
56
+ return DataCrunchBackendConfig.__response__.parse_obj(config)
57
+
58
+ def get_backend(self, record: BackendRecord) -> DataCrunchBackend:
59
+ config = self._get_config(record)
60
+ return DataCrunchBackend(config=config)
61
+
62
+ def _get_config(self, record: BackendRecord) -> DataCrunchConfig:
63
+ return DataCrunchConfig.__response__(
64
+ **json.loads(record.config),
65
+ creds=DataCrunchCreds.parse_raw(record.auth),
66
+ )
@@ -0,0 +1,38 @@
1
+ from typing import Annotated, List, Literal, Optional, Union
2
+
3
+ from pydantic import Field
4
+
5
+ from dstack._internal.core.models.common import CoreModel
6
+
7
+
8
+ class DataCrunchAPIKeyCreds(CoreModel):
9
+ type: Annotated[Literal["api_key"], Field(description="The type of credentials")] = "api_key"
10
+ client_id: Annotated[str, Field(description="The client ID")]
11
+ client_secret: Annotated[str, Field(description="The client secret")]
12
+
13
+
14
+ AnyDataCrunchCreds = DataCrunchAPIKeyCreds
15
+ DataCrunchCreds = AnyDataCrunchCreds
16
+
17
+
18
+ class DataCrunchBackendConfig(CoreModel):
19
+ type: Annotated[Literal["datacrunch"], Field(description="The type of backend")] = "datacrunch"
20
+ regions: Annotated[
21
+ Optional[List[str]],
22
+ Field(description="The list of DataCrunch regions. Omit to use all regions"),
23
+ ] = None
24
+
25
+
26
+ class DataCrunchBackendConfigWithCreds(DataCrunchBackendConfig):
27
+ creds: Annotated[AnyDataCrunchCreds, Field(description="The credentials")]
28
+
29
+
30
+ AnyDataCrunchBackendConfig = Union[DataCrunchBackendConfig, DataCrunchBackendConfigWithCreds]
31
+
32
+
33
+ class DataCrunchStoredConfig(DataCrunchBackendConfig):
34
+ pass
35
+
36
+
37
+ class DataCrunchConfig(DataCrunchStoredConfig):
38
+ creds: AnyDataCrunchCreds
@@ -1,15 +1,15 @@
1
- from typing import List
1
+ from typing import Annotated, List, Literal
2
2
 
3
- from typing_extensions import Literal
3
+ from pydantic import Field
4
4
 
5
5
  from dstack._internal.core.models.common import CoreModel
6
6
 
7
- # The OSS is currently aware of some of the DstackBackend internals (DstackConfigInfo) to be able to
7
+ # The OSS is currently aware of some of the DstackBackend internals (DstackBackendConfig) to be able to
8
8
  # show DstackBackend base backends as regular backends.
9
9
  # Consider designing an API that would allow DstackBackend to do the same without exposing its internals.
10
10
 
11
11
 
12
- class DstackConfigInfo(CoreModel):
12
+ class DstackBackendConfig(CoreModel):
13
13
  """
14
14
  This is a config model of DstackBackend stored in BackendModel.config and used by DstackConfigurator.
15
15
  """
@@ -18,9 +18,9 @@ class DstackConfigInfo(CoreModel):
18
18
  base_backends: List[str]
19
19
 
20
20
 
21
- class DstackBaseBackendConfigInfo(CoreModel):
21
+ class DstackBaseBackendConfig(CoreModel):
22
22
  type: str
23
23
 
24
24
 
25
- class DstackConfigValues(CoreModel):
26
- type: Literal["dstack"] = "dstack"
25
+ class DstackConfig(CoreModel):
26
+ type: Annotated[Literal["dstack"], Field(description="The type of backend")] = "dstack"
@@ -1,16 +0,0 @@
1
- from dstack._internal.core.backends.base import Backend
2
- from dstack._internal.core.backends.gcp.compute import GCPCompute
3
- from dstack._internal.core.backends.gcp.config import GCPConfig
4
- from dstack._internal.core.models.backends.base import BackendType
5
-
6
-
7
- class GCPBackend(Backend):
8
- TYPE: BackendType = BackendType.GCP
9
-
10
- def __init__(self, config: GCPConfig):
11
- self.config = config
12
- self._compute = GCPCompute(self.config)
13
- # self._check_credentials()
14
-
15
- def compute(self) -> GCPCompute:
16
- return self._compute
@@ -8,12 +8,11 @@ from google.auth.credentials import Credentials
8
8
  from google.auth.exceptions import DefaultCredentialsError
9
9
  from google.oauth2 import service_account
10
10
 
11
- from dstack._internal.core.errors import BackendAuthError
12
- from dstack._internal.core.models.backends.gcp import (
11
+ from dstack._internal.core.backends.gcp.models import (
13
12
  AnyGCPCreds,
14
- GCPDefaultCreds,
15
13
  GCPServiceAccountCreds,
16
14
  )
15
+ from dstack._internal.core.errors import BackendAuthError
17
16
  from dstack._internal.core.models.common import is_core_model_instance
18
17
 
19
18
 
@@ -57,11 +56,3 @@ def validate_credentials(credentials: Credentials, project_id: str):
57
56
  raise BackendAuthError(f"project_id {project_id} not found")
58
57
  except Exception:
59
58
  raise BackendAuthError("Insufficient permissions")
60
-
61
-
62
- def default_creds_available() -> bool:
63
- try:
64
- authenticate(GCPDefaultCreds())
65
- except BackendAuthError:
66
- return False
67
- return True
@@ -0,0 +1,17 @@
1
+ from dstack._internal.core.backends.base.backend import Backend
2
+ from dstack._internal.core.backends.gcp.compute import GCPCompute
3
+ from dstack._internal.core.backends.gcp.models import GCPConfig
4
+ from dstack._internal.core.models.backends.base import BackendType
5
+
6
+
7
+ class GCPBackend(Backend):
8
+ TYPE = BackendType.GCP
9
+ COMPUTE_CLASS = GCPCompute
10
+
11
+ def __init__(self, config: GCPConfig):
12
+ self.config = config
13
+ self._compute = GCPCompute(self.config)
14
+ # self._check_credentials()
15
+
16
+ def compute(self) -> GCPCompute:
17
+ return self._compute
@@ -12,17 +12,20 @@ import dstack._internal.core.backends.gcp.auth as auth
12
12
  import dstack._internal.core.backends.gcp.resources as gcp_resources
13
13
  from dstack._internal.core.backends.base.compute import (
14
14
  Compute,
15
+ ComputeWithCreateInstanceSupport,
16
+ ComputeWithGatewaySupport,
17
+ ComputeWithMultinodeSupport,
18
+ ComputeWithVolumeSupport,
15
19
  generate_unique_gateway_instance_name,
16
20
  generate_unique_instance_name,
17
21
  generate_unique_volume_name,
18
22
  get_gateway_user_data,
19
- get_job_instance_name,
20
23
  get_shim_commands,
21
24
  get_user_data,
22
25
  merge_tags,
23
26
  )
24
27
  from dstack._internal.core.backends.base.offers import get_catalog_offers
25
- from dstack._internal.core.backends.gcp.config import GCPConfig
28
+ from dstack._internal.core.backends.gcp.models import GCPConfig
26
29
  from dstack._internal.core.errors import (
27
30
  ComputeError,
28
31
  ComputeResourceNotFoundError,
@@ -42,10 +45,9 @@ from dstack._internal.core.models.instances import (
42
45
  InstanceOfferWithAvailability,
43
46
  InstanceType,
44
47
  Resources,
45
- SSHKey,
46
48
  )
47
49
  from dstack._internal.core.models.resources import Memory, Range
48
- from dstack._internal.core.models.runs import Job, JobProvisioningData, Requirements, Run
50
+ from dstack._internal.core.models.runs import JobProvisioningData, Requirements
49
51
  from dstack._internal.core.models.volumes import (
50
52
  Volume,
51
53
  VolumeAttachmentData,
@@ -69,7 +71,13 @@ class GCPVolumeDiskBackendData(CoreModel):
69
71
  disk_type: str
70
72
 
71
73
 
72
- class GCPCompute(Compute):
74
+ class GCPCompute(
75
+ ComputeWithCreateInstanceSupport,
76
+ ComputeWithMultinodeSupport,
77
+ ComputeWithGatewaySupport,
78
+ ComputeWithVolumeSupport,
79
+ Compute,
80
+ ):
73
81
  def __init__(self, config: GCPConfig):
74
82
  super().__init__()
75
83
  self.config = config
@@ -363,44 +371,6 @@ class GCPCompute(Compute):
363
371
  f"Failed to get instance IP address. Instance status: {instance.status}"
364
372
  )
365
373
 
366
- def run_job(
367
- self,
368
- run: Run,
369
- job: Job,
370
- instance_offer: InstanceOfferWithAvailability,
371
- project_ssh_public_key: str,
372
- project_ssh_private_key: str,
373
- volumes: List[Volume],
374
- ) -> JobProvisioningData:
375
- # TODO: run_job is the same for vm-based backends, refactor
376
- instance_config = InstanceConfiguration(
377
- project_name=run.project_name,
378
- instance_name=get_job_instance_name(run, job), # TODO: generate name
379
- ssh_keys=[
380
- SSHKey(public=project_ssh_public_key.strip()),
381
- ],
382
- user=run.user,
383
- volumes=volumes,
384
- reservation=run.run_spec.configuration.reservation,
385
- )
386
- instance_offer = instance_offer.copy()
387
- if len(volumes) > 0:
388
- volume = volumes[0]
389
- if (
390
- volume.provisioning_data is not None
391
- and volume.provisioning_data.availability_zone is not None
392
- ):
393
- if instance_offer.availability_zones is None:
394
- instance_offer.availability_zones = [
395
- volume.provisioning_data.availability_zone
396
- ]
397
- instance_offer.availability_zones = [
398
- z
399
- for z in instance_offer.availability_zones
400
- if z == volume.provisioning_data.availability_zone
401
- ]
402
- return self.create_instance(instance_offer, instance_config)
403
-
404
374
  def create_gateway(
405
375
  self,
406
376
  configuration: GatewayComputeConfiguration,