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.

Potentially problematic release.


This version of dstack might be problematic. Click here for more details.

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
@@ -1,142 +0,0 @@
1
- from typing import List, Tuple
2
-
3
- from fastapi import APIRouter, Depends
4
- from sqlalchemy.ext.asyncio import AsyncSession
5
-
6
- import dstack._internal.core.models.pools as models
7
- import dstack._internal.server.schemas.pools as schemas
8
- import dstack._internal.server.services.pools as pools
9
- from dstack._internal.core.errors import ConfigurationError
10
- from dstack._internal.core.models.pools import Instance
11
- from dstack._internal.server.db import get_session
12
- from dstack._internal.server.models import ProjectModel, UserModel
13
- from dstack._internal.server.schemas.pools import ListPoolsRequest
14
- from dstack._internal.server.schemas.runs import AddRemoteInstanceRequest
15
- from dstack._internal.server.security.permissions import Authenticated, ProjectMember
16
- from dstack._internal.server.utils.routers import get_base_api_additional_responses
17
-
18
- root_router = APIRouter(
19
- prefix="/api/pools",
20
- tags=["pool"],
21
- responses=get_base_api_additional_responses(),
22
- deprecated=True,
23
- )
24
- router = APIRouter(
25
- prefix="/api/project/{project_name}/pool",
26
- tags=["pool"],
27
- responses=get_base_api_additional_responses(),
28
- deprecated=True,
29
- )
30
-
31
-
32
- @root_router.post("/list_instances")
33
- async def list_pool_instances(
34
- body: ListPoolsRequest,
35
- session: AsyncSession = Depends(get_session),
36
- user: UserModel = Depends(Authenticated()),
37
- ) -> List[Instance]:
38
- """
39
- Returns all instances visible to user sorted by descending `created_at`.
40
- `project_name` and `pool_name` can be specified as filters.
41
-
42
- The results are paginated. To get the next page, pass `created_at` and `id` of
43
- the last instance from the previous page as `prev_created_at` and `prev_id`.
44
- """
45
- return await pools.list_user_pool_instances(
46
- session=session,
47
- user=user,
48
- project_names=[body.project_name] if body.project_name is not None else None,
49
- fleet_ids=None,
50
- pool_name=body.pool_name,
51
- only_active=body.only_active,
52
- prev_created_at=body.prev_created_at,
53
- prev_id=body.prev_id,
54
- limit=body.limit,
55
- ascending=body.ascending,
56
- )
57
-
58
-
59
- @router.post("/list")
60
- async def list_pool(
61
- session: AsyncSession = Depends(get_session),
62
- user_project: Tuple[UserModel, ProjectModel] = Depends(ProjectMember()),
63
- ) -> List[models.Pool]:
64
- _, project = user_project
65
- return await pools.list_project_pools(session=session, project=project)
66
-
67
-
68
- @router.post("/create")
69
- async def create_pool(
70
- body: schemas.CreatePoolRequest,
71
- session: AsyncSession = Depends(get_session),
72
- user_project: Tuple[UserModel, ProjectModel] = Depends(ProjectMember()),
73
- ) -> None:
74
- _, project = user_project
75
- await pools.create_pool(session=session, project=project, name=body.name)
76
-
77
-
78
- @router.post("/set_default")
79
- async def set_default_pool(
80
- body: schemas.SetDefaultPoolRequest,
81
- session: AsyncSession = Depends(get_session),
82
- user_project: Tuple[UserModel, ProjectModel] = Depends(ProjectMember()),
83
- ):
84
- _, project_model = user_project
85
- await pools.set_default_pool(session, project_model, body.pool_name)
86
-
87
-
88
- @router.post("/delete")
89
- async def delete_pool(
90
- body: schemas.DeletePoolRequest,
91
- session: AsyncSession = Depends(get_session),
92
- user_project: Tuple[UserModel, ProjectModel] = Depends(ProjectMember()),
93
- ) -> None:
94
- _, project = user_project
95
- await pools.delete_pool(session, project, body.name)
96
-
97
-
98
- @router.post("/show")
99
- async def show_pool(
100
- body: schemas.ShowPoolRequest,
101
- session: AsyncSession = Depends(get_session),
102
- user_project: Tuple[UserModel, ProjectModel] = Depends(ProjectMember()),
103
- ) -> models.PoolInstances:
104
- _, project = user_project
105
- return await pools.show_pool_instances(session, project, pool_name=body.name)
106
-
107
-
108
- @router.post("/remove")
109
- async def remove_instance(
110
- body: schemas.RemoveInstanceRequest,
111
- session: AsyncSession = Depends(get_session),
112
- user_project: Tuple[UserModel, ProjectModel] = Depends(ProjectMember()),
113
- ) -> None:
114
- _, project_model = user_project
115
- await pools.remove_instance(
116
- session, project_model, body.pool_name, body.instance_name, body.force
117
- )
118
-
119
-
120
- @router.post("/add_remote")
121
- async def add_instance(
122
- body: AddRemoteInstanceRequest,
123
- session: AsyncSession = Depends(get_session),
124
- user_project: Tuple[UserModel, ProjectModel] = Depends(ProjectMember()),
125
- ) -> Instance:
126
- if not body.host.strip() or not body.ssh_user.strip() or not body.ssh_keys:
127
- raise ConfigurationError("Host, user or ssh keys are empty")
128
-
129
- _, project = user_project
130
- result = await pools.add_remote(
131
- session,
132
- project=project,
133
- pool_name=body.pool_name,
134
- instance_name=body.instance_name,
135
- instance_network=body.instance_network,
136
- region=body.region,
137
- host=body.host,
138
- port=body.port or 22,
139
- ssh_user=body.ssh_user,
140
- ssh_keys=body.ssh_keys,
141
- )
142
- return result
@@ -1,38 +0,0 @@
1
- from datetime import datetime
2
- from typing import Optional
3
- from uuid import UUID
4
-
5
- from dstack._internal.core.models.common import CoreModel
6
-
7
-
8
- class DeletePoolRequest(CoreModel):
9
- name: str
10
- force: bool
11
-
12
-
13
- class CreatePoolRequest(CoreModel):
14
- name: str
15
-
16
-
17
- class ShowPoolRequest(CoreModel):
18
- name: Optional[str]
19
-
20
-
21
- class RemoveInstanceRequest(CoreModel):
22
- pool_name: str
23
- instance_name: str
24
- force: bool = False
25
-
26
-
27
- class SetDefaultPoolRequest(CoreModel):
28
- pool_name: str
29
-
30
-
31
- class ListPoolsRequest(CoreModel):
32
- project_name: Optional[str]
33
- pool_name: Optional[str]
34
- only_active: bool = False
35
- prev_created_at: Optional[datetime]
36
- prev_id: Optional[UUID]
37
- limit: int = 1000
38
- ascending: bool = False
@@ -1,72 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from typing import Any, List, Optional
3
-
4
- from dstack._internal.core.backends.base import Backend
5
- from dstack._internal.core.errors import BackendInvalidCredentialsError
6
- from dstack._internal.core.models.backends import (
7
- AnyConfigInfo,
8
- AnyConfigInfoWithCreds,
9
- AnyConfigInfoWithCredsPartial,
10
- AnyConfigValues,
11
- )
12
- from dstack._internal.core.models.backends.base import BackendType
13
- from dstack._internal.server.models import BackendModel, ProjectModel
14
-
15
- # Most clouds allow ~ 40-60 tags/labels per resource.
16
- # We'll introduce our own base limit that can be customized per backend if required.
17
- TAGS_MAX_NUM = 25
18
-
19
-
20
- class Configurator(ABC):
21
- TYPE: BackendType
22
-
23
- def get_default_configs(self) -> List[AnyConfigInfoWithCreds]:
24
- """
25
- Tries to detect backend creds on the machine and
26
- automatically construct backend configs from the creds.
27
- """
28
- return []
29
-
30
- @abstractmethod
31
- def get_config_values(self, config: AnyConfigInfoWithCredsPartial) -> AnyConfigValues:
32
- """
33
- Validates backend config and returns possible values for unfilled config parameters.
34
- """
35
- pass
36
-
37
- @abstractmethod
38
- def create_backend(
39
- self, project: ProjectModel, config: AnyConfigInfoWithCreds
40
- ) -> BackendModel:
41
- """
42
- Creates BackendModel given backend config and creds.
43
- It may perform backend initialization, create
44
- cloud resources such as networks and managed identites, and
45
- save additional configuration parameters.
46
- """
47
- pass
48
-
49
- @abstractmethod
50
- def get_config_info(self, model: BackendModel, include_creds: bool) -> AnyConfigInfo:
51
- """
52
- Constructs backend's ConfigInfo to be returned in API responses.
53
- Project admins may need to see backend's creds. In this case `include_creds` will be True.
54
- Otherwise, no sensitive information should be included.
55
- """
56
- pass
57
-
58
- @abstractmethod
59
- def get_backend(self, model: BackendModel) -> Backend:
60
- """
61
- Returns Backend instance from config and creds stored in `model`.
62
- """
63
- pass
64
-
65
-
66
- def raise_invalid_credentials_error(
67
- fields: Optional[List[List[str]]] = None, details: Optional[Any] = None
68
- ):
69
- msg = BackendInvalidCredentialsError.msg
70
- if details:
71
- msg += f": {details}"
72
- raise BackendInvalidCredentialsError(fields=fields, msg=msg)
@@ -1,87 +0,0 @@
1
- import json
2
- from typing import List
3
-
4
- from dstack._internal.core.backends.base import Backend
5
- from dstack._internal.core.backends.cudo import CudoBackend, CudoConfig, api_client
6
- from dstack._internal.core.models.backends.base import (
7
- BackendType,
8
- ConfigElementValue,
9
- ConfigMultiElement,
10
- )
11
- from dstack._internal.core.models.backends.cudo import (
12
- CudoConfigInfo,
13
- CudoConfigInfoWithCreds,
14
- CudoConfigInfoWithCredsPartial,
15
- CudoConfigValues,
16
- CudoCreds,
17
- CudoStoredConfig,
18
- )
19
- from dstack._internal.server.models import BackendModel, DecryptedString, ProjectModel
20
- from dstack._internal.server.services.backends import Configurator
21
- from dstack._internal.server.services.backends.configurators.base import (
22
- raise_invalid_credentials_error,
23
- )
24
-
25
- REGIONS = [
26
- "no-luster-1",
27
- "se-smedjebacken-1",
28
- "gb-london-1",
29
- "se-stockholm-1",
30
- "us-newyork-1",
31
- "us-santaclara-1",
32
- ]
33
-
34
- DEFAULT_REGION = "no-luster-1"
35
-
36
-
37
- class CudoConfigurator(Configurator):
38
- TYPE: BackendType = BackendType.CUDO
39
-
40
- def get_config_values(self, config: CudoConfigInfoWithCredsPartial) -> CudoConfigValues:
41
- config_values = CudoConfigValues()
42
- if config.creds is None:
43
- return config_values
44
- self._validate_cudo_api_key(config.creds.api_key)
45
- config_values.regions = self._get_regions_element(
46
- selected=config.regions or [DEFAULT_REGION]
47
- )
48
- return config_values
49
-
50
- def create_backend(
51
- self, project: ProjectModel, config: CudoConfigInfoWithCreds
52
- ) -> BackendModel:
53
- if config.regions is None:
54
- config.regions = REGIONS
55
- return BackendModel(
56
- project_id=project.id,
57
- type=self.TYPE.value,
58
- config=CudoStoredConfig(**CudoConfigInfo.__response__.parse_obj(config).dict()).json(),
59
- auth=DecryptedString(plaintext=CudoCreds.parse_obj(config.creds).json()),
60
- )
61
-
62
- def get_config_info(self, model: BackendModel, include_creds: bool) -> CudoConfigInfo:
63
- config = self._get_backend_config(model)
64
- if include_creds:
65
- return CudoConfigInfoWithCreds.__response__.parse_obj(config)
66
- return CudoConfigInfo.__response__.parse_obj(config)
67
-
68
- def get_backend(self, model: BackendModel) -> Backend:
69
- config = self._get_backend_config(model)
70
- return CudoBackend(config=config)
71
-
72
- def _get_regions_element(self, selected: List[str]) -> ConfigMultiElement:
73
- element = ConfigMultiElement(selected=selected)
74
- for r in REGIONS:
75
- element.values.append(ConfigElementValue(value=r, label=r))
76
- return element
77
-
78
- def _get_backend_config(self, model: BackendModel) -> CudoConfig:
79
- return CudoConfig.__response__(
80
- **json.loads(model.config),
81
- creds=CudoCreds.parse_raw(model.auth.get_plaintext_or_error()),
82
- )
83
-
84
- def _validate_cudo_api_key(self, api_key: str):
85
- client = api_client.CudoApiClient(api_key=api_key)
86
- if not client.validate_api_key():
87
- raise_invalid_credentials_error(fields=[["creds", "api_key"]])
@@ -1,79 +0,0 @@
1
- import json
2
- from typing import List
3
-
4
- from dstack._internal.core.backends.datacrunch import DataCrunchBackend
5
- from dstack._internal.core.backends.datacrunch.config import DataCrunchConfig
6
- from dstack._internal.core.models.backends.base import (
7
- BackendType,
8
- ConfigElementValue,
9
- ConfigMultiElement,
10
- )
11
- from dstack._internal.core.models.backends.datacrunch import (
12
- AnyDataCrunchConfigInfo,
13
- DataCrunchConfigInfo,
14
- DataCrunchConfigInfoWithCreds,
15
- DataCrunchConfigInfoWithCredsPartial,
16
- DataCrunchConfigValues,
17
- DataCrunchCreds,
18
- DataCrunchStoredConfig,
19
- )
20
- from dstack._internal.server.models import BackendModel, DecryptedString, ProjectModel
21
- from dstack._internal.server.services.backends.configurators.base import Configurator
22
-
23
- REGIONS = [
24
- "FIN-01",
25
- "ICE-01",
26
- ]
27
-
28
- DEFAULT_REGION = "FIN-01"
29
-
30
-
31
- class DataCrunchConfigurator(Configurator):
32
- TYPE: BackendType = BackendType.DATACRUNCH
33
-
34
- def get_config_values(
35
- self, config: DataCrunchConfigInfoWithCredsPartial
36
- ) -> DataCrunchConfigValues:
37
- config_values = DataCrunchConfigValues()
38
- if config.creds is None:
39
- return config_values
40
- config_values.regions = self._get_regions_element(
41
- selected=config.regions or [DEFAULT_REGION]
42
- )
43
- return config_values
44
-
45
- def create_backend(
46
- self, project: ProjectModel, config: DataCrunchConfigInfoWithCreds
47
- ) -> BackendModel:
48
- if config.regions is None:
49
- config.regions = REGIONS
50
- return BackendModel(
51
- project_id=project.id,
52
- type=self.TYPE.value,
53
- config=DataCrunchStoredConfig(
54
- **DataCrunchConfigInfo.__response__.parse_obj(config).dict()
55
- ).json(),
56
- auth=DecryptedString(plaintext=DataCrunchCreds.parse_obj(config.creds).json()),
57
- )
58
-
59
- def get_config_info(self, model: BackendModel, include_creds: bool) -> AnyDataCrunchConfigInfo:
60
- config = self._get_backend_config(model)
61
- if include_creds:
62
- return DataCrunchConfigInfoWithCreds.__response__.parse_obj(config)
63
- return DataCrunchConfigInfo.__response__.parse_obj(config)
64
-
65
- def get_backend(self, model: BackendModel) -> DataCrunchBackend:
66
- config = self._get_backend_config(model)
67
- return DataCrunchBackend(config=config)
68
-
69
- def _get_backend_config(self, model: BackendModel) -> DataCrunchConfig:
70
- return DataCrunchConfig.__response__(
71
- **json.loads(model.config),
72
- creds=DataCrunchCreds.parse_raw(model.auth.get_plaintext_or_error()),
73
- )
74
-
75
- def _get_regions_element(self, selected: List[str]) -> ConfigMultiElement:
76
- element = ConfigMultiElement(selected=selected)
77
- for r in REGIONS:
78
- element.values.append(ConfigElementValue(value=r, label=r))
79
- return element
@@ -1,63 +0,0 @@
1
- from typing import List
2
-
3
- from dstack._internal.core.backends.kubernetes import KubernetesBackend
4
- from dstack._internal.core.backends.kubernetes.config import KubernetesConfig
5
- from dstack._internal.core.backends.kubernetes.utils import get_api_from_config_data
6
- from dstack._internal.core.models.backends.base import BackendType
7
- from dstack._internal.core.models.backends.kubernetes import (
8
- AnyKubernetesConfigInfo,
9
- KubernetesConfigInfo,
10
- KubernetesConfigInfoWithCreds,
11
- KubernetesConfigInfoWithCredsPartial,
12
- KubernetesConfigValues,
13
- KubernetesStoredConfig,
14
- )
15
- from dstack._internal.server.models import BackendModel, DecryptedString, ProjectModel
16
- from dstack._internal.server.services.backends.configurators.base import (
17
- Configurator,
18
- raise_invalid_credentials_error,
19
- )
20
- from dstack._internal.utils.logging import get_logger
21
-
22
- logger = get_logger(__name__)
23
-
24
-
25
- class KubernetesConfigurator(Configurator):
26
- TYPE: BackendType = BackendType.KUBERNETES
27
-
28
- def get_default_configs(self) -> List[KubernetesConfigInfoWithCreds]:
29
- # TODO: automatically pick up kubernetes config
30
- return []
31
-
32
- def get_config_values(
33
- self, config: KubernetesConfigInfoWithCredsPartial
34
- ) -> KubernetesConfigValues:
35
- try:
36
- api = get_api_from_config_data(config.kubeconfig.data)
37
- api.list_node()
38
- except Exception as e:
39
- logger.debug("Invalid kubeconfig: %s", str(e))
40
- raise_invalid_credentials_error(fields=[["kubeconfig"]])
41
- return KubernetesConfigValues()
42
-
43
- def create_backend(
44
- self, project: ProjectModel, config: KubernetesConfigInfoWithCreds
45
- ) -> BackendModel:
46
- return BackendModel(
47
- project_id=project.id,
48
- type=self.TYPE.value,
49
- config=KubernetesStoredConfig.__response__.parse_obj(config).json(),
50
- auth=DecryptedString(plaintext=""),
51
- )
52
-
53
- def get_config_info(self, model: BackendModel, include_creds: bool) -> AnyKubernetesConfigInfo:
54
- config = self._get_backend_config(model)
55
- if include_creds:
56
- return KubernetesConfigInfoWithCreds.__response__.parse_obj(config)
57
- return KubernetesConfigInfo.__response__.parse_obj(config)
58
-
59
- def get_backend(self, model: BackendModel) -> KubernetesBackend:
60
- return KubernetesBackend(self._get_backend_config(model))
61
-
62
- def _get_backend_config(self, model: BackendModel) -> KubernetesConfig:
63
- return KubernetesConfig.__response__.parse_raw(model.config)
@@ -1,98 +0,0 @@
1
- import json
2
- from typing import List
3
-
4
- from dstack._internal.core.backends.lambdalabs import LambdaBackend, api_client
5
- from dstack._internal.core.backends.lambdalabs.config import LambdaConfig
6
- from dstack._internal.core.models.backends.base import (
7
- BackendType,
8
- ConfigElementValue,
9
- ConfigMultiElement,
10
- )
11
- from dstack._internal.core.models.backends.lambdalabs import (
12
- AnyLambdaConfigInfo,
13
- LambdaConfigInfo,
14
- LambdaConfigInfoWithCreds,
15
- LambdaConfigInfoWithCredsPartial,
16
- LambdaConfigValues,
17
- LambdaCreds,
18
- LambdaStoredConfig,
19
- )
20
- from dstack._internal.server.models import BackendModel, DecryptedString, ProjectModel
21
- from dstack._internal.server.services.backends.configurators.base import (
22
- Configurator,
23
- raise_invalid_credentials_error,
24
- )
25
-
26
- REGIONS = [
27
- "us-south-1",
28
- "us-south-2",
29
- "us-south-3",
30
- "us-west-2",
31
- "us-west-1",
32
- "us-midwest-1",
33
- "us-west-3",
34
- "us-east-1",
35
- "us-east-2",
36
- "europe-central-1",
37
- "asia-south-1",
38
- "me-west-1",
39
- "asia-northeast-1",
40
- "asia-northeast-2",
41
- ]
42
-
43
- DEFAULT_REGION = "us-east-1"
44
-
45
-
46
- class LambdaConfigurator(Configurator):
47
- TYPE: BackendType = BackendType.LAMBDA
48
-
49
- def get_config_values(self, config: LambdaConfigInfoWithCredsPartial) -> LambdaConfigValues:
50
- config_values = LambdaConfigValues()
51
- if config.creds is None:
52
- return config_values
53
- self._validate_lambda_api_key(config.creds.api_key)
54
- config_values.regions = self._get_regions_element(
55
- selected=config.regions or [DEFAULT_REGION]
56
- )
57
- return config_values
58
-
59
- def create_backend(
60
- self, project: ProjectModel, config: LambdaConfigInfoWithCreds
61
- ) -> BackendModel:
62
- if config.regions is None:
63
- config.regions = REGIONS
64
- return BackendModel(
65
- project_id=project.id,
66
- type=self.TYPE.value,
67
- config=LambdaStoredConfig(
68
- **LambdaConfigInfo.__response__.parse_obj(config).dict()
69
- ).json(),
70
- auth=DecryptedString(plaintext=LambdaCreds.parse_obj(config.creds).json()),
71
- )
72
-
73
- def get_config_info(self, model: BackendModel, include_creds: bool) -> AnyLambdaConfigInfo:
74
- config = self._get_backend_config(model)
75
- if include_creds:
76
- return LambdaConfigInfoWithCreds.__response__.parse_obj(config)
77
- return LambdaConfigInfo.__response__.parse_obj(config)
78
-
79
- def get_backend(self, model: BackendModel) -> LambdaBackend:
80
- config = self._get_backend_config(model)
81
- return LambdaBackend(config=config)
82
-
83
- def _get_backend_config(self, model: BackendModel) -> LambdaConfig:
84
- return LambdaConfig.__response__(
85
- **json.loads(model.config),
86
- creds=LambdaCreds.parse_raw(model.auth.get_plaintext_or_error()),
87
- )
88
-
89
- def _validate_lambda_api_key(self, api_key: str):
90
- client = api_client.LambdaAPIClient(api_key=api_key)
91
- if not client.validate_api_key():
92
- raise_invalid_credentials_error(fields=[["creds", "api_key"]])
93
-
94
- def _get_regions_element(self, selected: List[str]) -> ConfigMultiElement:
95
- element = ConfigMultiElement(selected=selected)
96
- for r in REGIONS:
97
- element.values.append(ConfigElementValue(value=r, label=r))
98
- return element
@@ -1,85 +0,0 @@
1
- import json
2
- from typing import List
3
-
4
- import requests
5
-
6
- import dstack._internal.core.backends.nebius.api_client as api_client
7
- from dstack._internal.core.backends.base import Backend
8
- from dstack._internal.core.backends.nebius import NebiusBackend
9
- from dstack._internal.core.backends.nebius.config import NebiusConfig
10
- from dstack._internal.core.models.backends.base import (
11
- BackendType,
12
- ConfigElementValue,
13
- ConfigMultiElement,
14
- )
15
- from dstack._internal.core.models.backends.nebius import (
16
- NebiusConfigInfo,
17
- NebiusConfigInfoWithCreds,
18
- NebiusConfigInfoWithCredsPartial,
19
- NebiusConfigValues,
20
- NebiusCreds,
21
- NebiusStoredConfig,
22
- )
23
- from dstack._internal.server.models import BackendModel, DecryptedString, ProjectModel
24
- from dstack._internal.server.services.backends import Configurator
25
- from dstack._internal.server.services.backends.configurators.base import (
26
- raise_invalid_credentials_error,
27
- )
28
-
29
- REGIONS = ["eu-north1-c"]
30
-
31
-
32
- class NebiusConfigurator(Configurator):
33
- TYPE: BackendType = BackendType.NEBIUS
34
-
35
- def get_config_values(self, config: NebiusConfigInfoWithCredsPartial) -> NebiusConfigValues:
36
- config_values = NebiusConfigValues()
37
- if config.creds is None:
38
- return config_values
39
- self._validate_nebius_creds(config.creds)
40
- # TODO(egor-s) cloud_id
41
- # TODO(egor-s) folder_id
42
- # TODO(egor-s) network_id
43
- config_values.regions = self._get_regions_element(selected=config.regions or [])
44
- return config_values
45
-
46
- def create_backend(
47
- self, project: ProjectModel, config: NebiusConfigInfoWithCreds
48
- ) -> BackendModel:
49
- if config.regions is None:
50
- config.regions = REGIONS
51
- self._validate_nebius_creds(config.creds)
52
- return BackendModel(
53
- project_id=project.id,
54
- type=self.TYPE.value,
55
- config=NebiusStoredConfig.__response__.parse_obj(config).json(),
56
- auth=DecryptedString(plaintext=NebiusCreds.parse_obj(config.creds).json()),
57
- )
58
-
59
- def get_config_info(self, model: BackendModel, include_creds: bool) -> NebiusConfigInfo:
60
- config = self._get_backend_config(model)
61
- if include_creds:
62
- return NebiusConfigInfoWithCreds.__response__.parse_obj(config)
63
- return NebiusConfigInfo.__response__.parse_obj(config)
64
-
65
- def get_backend(self, model: BackendModel) -> Backend:
66
- config = self._get_backend_config(model)
67
- return NebiusBackend(config=config)
68
-
69
- def _get_backend_config(self, model: BackendModel) -> NebiusConfig:
70
- return NebiusConfig.__response__(
71
- **json.loads(model.config),
72
- creds=NebiusCreds.parse_raw(model.auth.get_plaintext_or_error()),
73
- )
74
-
75
- def _validate_nebius_creds(self, creds: NebiusCreds):
76
- try:
77
- api_client.NebiusAPIClient(json.loads(creds.data)).get_token()
78
- except requests.HTTPError:
79
- raise_invalid_credentials_error(fields=[["creds", "data"]])
80
-
81
- def _get_regions_element(self, selected: List[str]) -> ConfigMultiElement:
82
- element = ConfigMultiElement(selected=selected)
83
- for r in REGIONS:
84
- element.values.append(ConfigElementValue(value=r, label=r))
85
- return element