dstack 0.18.44__py3-none-any.whl → 0.19.0rc1__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-4fd5a4770eff59325ee3.js} +7 -7
  146. dstack/_internal/server/statics/{main-4eb116b97819badd1e2c.js.map → main-4fd5a4770eff59325ee3.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.0rc1.dist-info}/METADATA +1 -1
  164. {dstack-0.18.44.dist-info → dstack-0.19.0rc1.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.0rc1.dist-info}/LICENSE.md +0 -0
  265. {dstack-0.18.44.dist-info → dstack-0.19.0rc1.dist-info}/WHEEL +0 -0
  266. {dstack-0.18.44.dist-info → dstack-0.19.0rc1.dist-info}/entry_points.txt +0 -0
  267. {dstack-0.18.44.dist-info → dstack-0.19.0rc1.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,16 @@ from uuid import UUID
8
8
  import gpuhunt
9
9
  from sqlalchemy.ext.asyncio import AsyncSession
10
10
 
11
+ from dstack._internal.core.backends.base.compute import (
12
+ Compute,
13
+ ComputeWithCreateInstanceSupport,
14
+ ComputeWithGatewaySupport,
15
+ ComputeWithMultinodeSupport,
16
+ ComputeWithPlacementGroupSupport,
17
+ ComputeWithPrivateGatewaySupport,
18
+ ComputeWithReservationSupport,
19
+ ComputeWithVolumeSupport,
20
+ )
11
21
  from dstack._internal.core.models.backends.base import BackendType
12
22
  from dstack._internal.core.models.common import NetworkMode
13
23
  from dstack._internal.core.models.configurations import (
@@ -35,8 +45,7 @@ from dstack._internal.core.models.placement import (
35
45
  PlacementStrategy,
36
46
  )
37
47
  from dstack._internal.core.models.profiles import (
38
- DEFAULT_POOL_NAME,
39
- DEFAULT_POOL_TERMINATION_IDLE_TIME,
48
+ DEFAULT_FLEET_TERMINATION_IDLE_TIME,
40
49
  Profile,
41
50
  TerminationPolicy,
42
51
  )
@@ -71,7 +80,6 @@ from dstack._internal.server.models import (
71
80
  JobModel,
72
81
  JobPrometheusMetrics,
73
82
  PlacementGroupModel,
74
- PoolModel,
75
83
  ProjectModel,
76
84
  RepoCredsModel,
77
85
  RepoModel,
@@ -181,9 +189,6 @@ async def create_repo(
181
189
  if info is None:
182
190
  info = {
183
191
  "repo_type": "remote",
184
- "repo_host_name": "",
185
- "repo_port": None,
186
- "repo_user_name": "",
187
192
  "repo_name": "dstack",
188
193
  }
189
194
  repo = RepoModel(
@@ -206,7 +211,6 @@ async def create_repo_creds(
206
211
  ) -> RepoCredsModel:
207
212
  if creds is None:
208
213
  creds = {
209
- "protocol": "https",
210
214
  "clone_url": "https://github.com/dstackai/dstack.git",
211
215
  "private_key": None,
212
216
  "oauth_token": "test_token",
@@ -325,13 +329,22 @@ def get_job_provisioning_data(
325
329
  backend: BackendType = BackendType.AWS,
326
330
  region: str = "us-east-1",
327
331
  gpu_count: int = 0,
332
+ gpu_memory_gib: float = 16,
333
+ gpu_name: str = "T4",
328
334
  cpu_count: int = 1,
329
335
  memory_gib: float = 0.5,
330
336
  spot: bool = False,
331
337
  hostname: str = "127.0.0.4",
332
338
  internal_ip: Optional[str] = "127.0.0.4",
339
+ price: float = 10.5,
333
340
  ) -> JobProvisioningData:
334
- gpus = [Gpu(name="T4", memory_mib=16384, vendor=gpuhunt.AcceleratorVendor.NVIDIA)] * gpu_count
341
+ gpus = [
342
+ Gpu(
343
+ name=gpu_name,
344
+ memory_mib=int(gpu_memory_gib * 1024),
345
+ vendor=gpuhunt.AcceleratorVendor.NVIDIA,
346
+ )
347
+ ] * gpu_count
335
348
  return JobProvisioningData(
336
349
  backend=backend,
337
350
  instance_type=InstanceType(
@@ -344,7 +357,7 @@ def get_job_provisioning_data(
344
357
  hostname=hostname,
345
358
  internal_ip=internal_ip,
346
359
  region=region,
347
- price=10.5,
360
+ price=price,
348
361
  username="ubuntu",
349
362
  ssh_port=22,
350
363
  dockerized=dockerized,
@@ -439,22 +452,6 @@ def get_gateway_compute_configuration(
439
452
  )
440
453
 
441
454
 
442
- async def create_pool(
443
- session: AsyncSession,
444
- project: ProjectModel,
445
- pool_name: Optional[str] = None,
446
- ) -> PoolModel:
447
- pool_name = pool_name if pool_name is not None else DEFAULT_POOL_NAME
448
- pool = PoolModel(
449
- name=pool_name,
450
- project=project,
451
- project_id=project.id,
452
- )
453
- session.add(pool)
454
- await session.commit()
455
- return pool
456
-
457
-
458
455
  async def create_fleet(
459
456
  session: AsyncSession,
460
457
  project: ProjectModel,
@@ -463,11 +460,14 @@ async def create_fleet(
463
460
  fleet_id: Optional[UUID] = None,
464
461
  status: FleetStatus = FleetStatus.ACTIVE,
465
462
  deleted: bool = False,
463
+ name: Optional[str] = None,
466
464
  ) -> FleetModel:
467
465
  if fleet_id is None:
468
466
  fleet_id = uuid.uuid4()
469
467
  if spec is None:
470
468
  spec = get_fleet_spec()
469
+ if name is not None:
470
+ spec.configuration.name = name
471
471
  fm = FleetModel(
472
472
  id=fleet_id,
473
473
  project=project,
@@ -507,7 +507,6 @@ def get_fleet_configuration(
507
507
  async def create_instance(
508
508
  session: AsyncSession,
509
509
  project: ProjectModel,
510
- pool: PoolModel,
511
510
  fleet: Optional[FleetModel] = None,
512
511
  status: InstanceStatus = InstanceStatus.IDLE,
513
512
  unreachable: bool = False,
@@ -522,7 +521,7 @@ async def create_instance(
522
521
  instance_num: int = 0,
523
522
  backend: BackendType = BackendType.DATACRUNCH,
524
523
  termination_policy: Optional[TerminationPolicy] = None,
525
- termination_idle_time: int = DEFAULT_POOL_TERMINATION_IDLE_TIME,
524
+ termination_idle_time: int = DEFAULT_FLEET_TERMINATION_IDLE_TIME,
526
525
  region: str = "eu-west",
527
526
  remote_connection_info: Optional[RemoteConnectionInfo] = None,
528
527
  offer: Optional[InstanceOfferWithAvailability] = None,
@@ -531,6 +530,7 @@ async def create_instance(
531
530
  busy_blocks: int = 0,
532
531
  name: str = "test_instance",
533
532
  volumes: Optional[List[VolumeModel]] = None,
533
+ price: float = 1.0,
534
534
  ) -> InstanceModel:
535
535
  if instance_id is None:
536
536
  instance_id = uuid.uuid4()
@@ -564,7 +564,6 @@ async def create_instance(
564
564
  id=instance_id,
565
565
  name=name,
566
566
  instance_num=instance_num,
567
- pool=pool,
568
567
  fleet=fleet,
569
568
  project=project,
570
569
  status=status,
@@ -574,7 +573,7 @@ async def create_instance(
574
573
  finished_at=finished_at,
575
574
  job_provisioning_data=job_provisioning_data.json(),
576
575
  offer=offer.json(),
577
- price=1,
576
+ price=price,
578
577
  region=region,
579
578
  backend=backend,
580
579
  termination_policy=termination_policy,
@@ -611,6 +610,8 @@ def get_instance_offer_with_availability(
611
610
  backend: BackendType = BackendType.AWS,
612
611
  region: str = "eu-west",
613
612
  gpu_count: int = 0,
613
+ gpu_name: str = "T4",
614
+ gpu_memory_gib: float = 16,
614
615
  cpu_count: int = 2,
615
616
  memory_gib: float = 12,
616
617
  disk_gib: float = 100.0,
@@ -618,12 +619,20 @@ def get_instance_offer_with_availability(
618
619
  blocks: int = 1,
619
620
  total_blocks: int = 1,
620
621
  availability_zones: Optional[List[str]] = None,
622
+ price: float = 1.0,
623
+ instance_type: str = "instance",
621
624
  ):
622
- gpus = [Gpu(name="T4", memory_mib=16384, vendor=gpuhunt.AcceleratorVendor.NVIDIA)] * gpu_count
625
+ gpus = [
626
+ Gpu(
627
+ name=gpu_name,
628
+ memory_mib=int(gpu_memory_gib * 1024),
629
+ vendor=gpuhunt.AcceleratorVendor.NVIDIA,
630
+ )
631
+ ] * gpu_count
623
632
  return InstanceOfferWithAvailability(
624
633
  backend=backend,
625
634
  instance=InstanceType(
626
- name="instance",
635
+ name=instance_type,
627
636
  resources=Resources(
628
637
  cpus=cpu_count,
629
638
  memory_mib=int(memory_gib * 1024),
@@ -634,7 +643,7 @@ def get_instance_offer_with_availability(
634
643
  ),
635
644
  ),
636
645
  region=region,
637
- price=1,
646
+ price=price,
638
647
  availability=InstanceAvailability.AVAILABLE,
639
648
  availability_zones=availability_zones,
640
649
  blocks=blocks,
@@ -947,3 +956,20 @@ class AsyncContextManager:
947
956
 
948
957
  async def __aexit__(self, exc_type, exc, traceback):
949
958
  pass
959
+
960
+
961
+ class ComputeMockSpec(
962
+ Compute,
963
+ ComputeWithCreateInstanceSupport,
964
+ ComputeWithMultinodeSupport,
965
+ ComputeWithReservationSupport,
966
+ ComputeWithPlacementGroupSupport,
967
+ ComputeWithGatewaySupport,
968
+ ComputeWithPrivateGatewaySupport,
969
+ ComputeWithVolumeSupport,
970
+ ):
971
+ """
972
+ Can be used to create Compute mocks that pass all isinstance asserts.
973
+ """
974
+
975
+ pass
@@ -0,0 +1,6 @@
1
+ def add_extra_schema_types(schema_property: dict, extra_types: list[dict]):
2
+ if "allOf" in schema_property:
3
+ ref = schema_property.pop("allOf")[0]
4
+ else:
5
+ ref = {"type": schema_property.pop("type")}
6
+ schema_property["anyOf"] = [ref, *extra_types]
@@ -128,7 +128,8 @@ def include_ssh_config(path: PathLike, ssh_config_path: PathLike = default_ssh_c
128
128
  except PermissionError:
129
129
  logger.warning(
130
130
  f"Couldn't update `{ssh_config_path}` due to a permissions problem.\n"
131
- f"The `vscode://vscode-remote/ssh-remote+<run name>/workflow` link and "
131
+ f"The `vscode://vscode-remote/ssh-remote+<run name>/workflow` and "
132
+ f"`cursor://vscode-remote/ssh-remote+<run name>/workflow` links and "
132
133
  f"the `ssh <run name>` command won't work.\n"
133
134
  f"To fix this, make sure `{ssh_config_path}` is writable, or add "
134
135
  f"`Include {path}` to the top of `{ssh_config_path}` manually.",
dstack/api/__init__.py CHANGED
@@ -2,6 +2,9 @@
2
2
  from dstack._internal.core.errors import ClientError
3
3
  from dstack._internal.core.models.backends.base import BackendType
4
4
  from dstack._internal.core.models.common import RegistryAuth
5
+ from dstack._internal.core.models.configurations import (
6
+ DevEnvironmentConfiguration as _DevEnvironmentConfiguration,
7
+ )
5
8
  from dstack._internal.core.models.configurations import ScalingSpec as Scaling
6
9
  from dstack._internal.core.models.configurations import (
7
10
  ServiceConfiguration as _ServiceConfiguration,
@@ -22,3 +25,4 @@ from dstack.api._public.runs import Run, RunStatus
22
25
 
23
26
  Service = _ServiceConfiguration
24
27
  Task = _TaskConfiguration
28
+ DevEnvironment = _DevEnvironmentConfiguration
@@ -6,7 +6,6 @@ from dstack._internal.core.services.configs import ConfigManager
6
6
  from dstack._internal.utils.logging import get_logger
7
7
  from dstack._internal.utils.path import PathLike
8
8
  from dstack.api._public.backends import BackendCollection
9
- from dstack.api._public.pools import PoolCollection
10
9
  from dstack.api._public.repos import RepoCollection, get_ssh_keypair
11
10
  from dstack.api._public.runs import RunCollection
12
11
  from dstack.api.server import APIClient
@@ -16,12 +15,14 @@ logger = get_logger(__name__)
16
15
 
17
16
  class Client:
18
17
  """
19
- High-level API client for interacting with dstack server
18
+ High-level API client for interacting with the `dstack` server
20
19
 
21
20
  Attributes:
21
+ project: The project name.
22
22
  runs: Operations with runs.
23
23
  repos: Operations with repositories.
24
24
  backends: Operations with backends.
25
+ client: Low-level API client that supports all API endpoints.
25
26
  """
26
27
 
27
28
  def __init__(
@@ -41,7 +42,6 @@ class Client:
41
42
  self._repos = RepoCollection(api_client, project_name)
42
43
  self._backends = BackendCollection(api_client, project_name)
43
44
  self._runs = RunCollection(api_client, project_name, self)
44
- self._pool = PoolCollection(api_client, project_name)
45
45
  if ssh_identity_file:
46
46
  self.ssh_identity_file = str(ssh_identity_file)
47
47
  else:
@@ -58,13 +58,13 @@ class Client:
58
58
  Creates a Client using the default configuration from `~/.dstack/config.yml` if it exists.
59
59
 
60
60
  Args:
61
- project_name: The name of the project, required if `server_url` and `user_token` are specified
62
- server_url: The dstack server URL (e.g. `http://localhost:3000/` or `https://sky.dstack.ai`)
63
- user_token: The dstack user token
64
- ssh_identity_file: The private SSH key path for SSH tunneling
61
+ project_name: The name of the project. required if `server_url` and `user_token` are specified.
62
+ server_url: The dstack server URL (e.g. `http://localhost:3000/` or `https://sky.dstack.ai`).
63
+ user_token: The dstack user token.
64
+ ssh_identity_file: The private SSH key path for SSH tunneling.
65
65
 
66
66
  Returns:
67
- A client instance
67
+ A client instance.
68
68
  """
69
69
  if server_url is not None and user_token is not None:
70
70
  if project_name is None:
@@ -79,25 +79,21 @@ class Client:
79
79
  )
80
80
 
81
81
  @property
82
- def repos(self) -> RepoCollection:
83
- return self._repos
84
-
85
- @property
86
- def backends(self) -> BackendCollection:
87
- return self._backends
82
+ def project(self) -> str:
83
+ return self._project
88
84
 
89
85
  @property
90
86
  def runs(self) -> RunCollection:
91
87
  return self._runs
92
88
 
93
89
  @property
94
- def client(self) -> APIClient:
95
- return self._client
90
+ def repos(self) -> RepoCollection:
91
+ return self._repos
96
92
 
97
93
  @property
98
- def project(self) -> str:
99
- return self._project
94
+ def backends(self) -> BackendCollection:
95
+ return self._backends
100
96
 
101
97
  @property
102
- def pool(self) -> PoolCollection:
103
- return self._pool
98
+ def client(self) -> APIClient:
99
+ return self._client
@@ -1,6 +1,6 @@
1
1
  from typing import List
2
2
 
3
- from dstack._internal.core.models.backends import BackendInfo
3
+ from dstack._internal.core.backends.models import BackendInfo
4
4
  from dstack.api.server import APIClient
5
5
 
6
6
 
@@ -55,7 +55,7 @@ class RepoCollection:
55
55
  Once the repo is initialized, you can pass the repo object to the run:
56
56
 
57
57
  ```python
58
- run = client.runs.submit(
58
+ run = client.runs.apply_configuration(
59
59
  configuration=...,
60
60
  repo=repo,
61
61
  )
@@ -78,25 +78,6 @@ class RepoCollection:
78
78
  raise ConfigurationError(*e.args)
79
79
  self._api_client.repos.init(self._project, repo.repo_id, repo.get_repo_info(), creds)
80
80
 
81
- def is_initialized(
82
- self,
83
- repo: Repo,
84
- ) -> bool:
85
- # """
86
- # Checks if the remote repo is initialized in the project
87
- #
88
- # Args:
89
- # repo: repo to check
90
- #
91
- # Returns:
92
- # repo is initialized
93
- # """
94
- try:
95
- self._api_client.repos.get(self._project, repo.repo_id, include_creds=False)
96
- return True
97
- except ResourceNotExistsError:
98
- return False
99
-
100
81
  def load(
101
82
  self,
102
83
  repo_dir: PathLike,
@@ -105,22 +86,22 @@ class RepoCollection:
105
86
  git_identity_file: Optional[PathLike] = None,
106
87
  oauth_token: Optional[str] = None,
107
88
  ) -> Union[RemoteRepo, LocalRepo]:
108
- # """
109
- # Loads the repo from the local directory using global config
110
- #
111
- # Args:
112
- # repo_dir: repo root directory
113
- # local: do not try to load `RemoteRepo` first
114
- # init: initialize the repo if it's not initialized
115
- # git_identity_file: path to an SSH private key to access the remote repo
116
- # oauth_token: GitHub OAuth token to access the remote repo
117
- #
118
- # Raises:
119
- # ConfigurationError: if the repo is not initialized and `init` is `False`
120
- #
121
- # Returns:
122
- # repo: initialized repo
123
- # """
89
+ """
90
+ Loads the repo from the local directory using global config
91
+
92
+ Args:
93
+ repo_dir: Repo root directory.
94
+ local: Do not try to load `RemoteRepo` first.
95
+ init: Initialize the repo if it's not initialized.
96
+ git_identity_file: Path to an SSH private key to access the remote repo.
97
+ oauth_token: GitHub OAuth token to access the remote repo.
98
+
99
+ Raises:
100
+ ConfigurationError: If the repo is not initialized and `init` is `False`.
101
+
102
+ Returns:
103
+ repo: Initialized repo.
104
+ """
124
105
  config = ConfigManager()
125
106
  if not init:
126
107
  logger.debug("Loading repo config")
@@ -155,6 +136,25 @@ class RepoCollection:
155
136
  )
156
137
  return repo
157
138
 
139
+ def is_initialized(
140
+ self,
141
+ repo: Repo,
142
+ ) -> bool:
143
+ """
144
+ Checks if the remote repo is initialized in the project
145
+
146
+ Args:
147
+ repo: The repo to check.
148
+
149
+ Returns:
150
+ Whether the repo is initialized or not.
151
+ """
152
+ try:
153
+ self._api_client.repos.get(self._project, repo.repo_id, include_creds=False)
154
+ return True
155
+ except ResourceNotExistsError:
156
+ return False
157
+
158
158
 
159
159
  def get_ssh_keypair(key_path: Optional[PathLike], dstack_key_path: Path) -> str:
160
160
  """Returns a path to the private key"""