dstack 0.18.43__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 (278) 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 -20
  7. dstack/_internal/cli/services/profile.py +34 -83
  8. dstack/_internal/cli/utils/gateway.py +1 -1
  9. dstack/_internal/cli/utils/run.py +11 -0
  10. dstack/_internal/core/backends/__init__.py +56 -39
  11. dstack/_internal/core/backends/aws/__init__.py +0 -25
  12. dstack/_internal/core/backends/aws/auth.py +1 -10
  13. dstack/_internal/core/backends/aws/backend.py +26 -0
  14. dstack/_internal/core/backends/aws/compute.py +21 -45
  15. dstack/_internal/{server/services/backends/configurators/aws.py → core/backends/aws/configurator.py} +46 -85
  16. dstack/_internal/core/backends/aws/models.py +135 -0
  17. dstack/_internal/core/backends/aws/resources.py +1 -1
  18. dstack/_internal/core/backends/azure/__init__.py +0 -20
  19. dstack/_internal/core/backends/azure/auth.py +2 -11
  20. dstack/_internal/core/backends/azure/backend.py +21 -0
  21. dstack/_internal/core/backends/azure/compute.py +14 -28
  22. dstack/_internal/{server/services/backends/configurators/azure.py → core/backends/azure/configurator.py} +141 -210
  23. dstack/_internal/core/backends/azure/models.py +89 -0
  24. dstack/_internal/core/backends/base/__init__.py +0 -12
  25. dstack/_internal/core/backends/base/backend.py +18 -0
  26. dstack/_internal/core/backends/base/compute.py +153 -33
  27. dstack/_internal/core/backends/base/configurator.py +105 -0
  28. dstack/_internal/core/backends/base/models.py +14 -0
  29. dstack/_internal/core/backends/configurators.py +138 -0
  30. dstack/_internal/core/backends/cudo/__init__.py +0 -15
  31. dstack/_internal/core/backends/cudo/backend.py +16 -0
  32. dstack/_internal/core/backends/cudo/compute.py +8 -26
  33. dstack/_internal/core/backends/cudo/configurator.py +72 -0
  34. dstack/_internal/core/backends/cudo/models.py +37 -0
  35. dstack/_internal/core/backends/datacrunch/__init__.py +0 -15
  36. dstack/_internal/core/backends/datacrunch/backend.py +16 -0
  37. dstack/_internal/core/backends/datacrunch/compute.py +8 -25
  38. dstack/_internal/core/backends/datacrunch/configurator.py +66 -0
  39. dstack/_internal/core/backends/datacrunch/models.py +38 -0
  40. dstack/_internal/core/{models/backends/dstack.py → backends/dstack/models.py} +7 -7
  41. dstack/_internal/core/backends/gcp/__init__.py +0 -16
  42. dstack/_internal/core/backends/gcp/auth.py +2 -11
  43. dstack/_internal/core/backends/gcp/backend.py +17 -0
  44. dstack/_internal/core/backends/gcp/compute.py +14 -44
  45. dstack/_internal/{server/services/backends/configurators/gcp.py → core/backends/gcp/configurator.py} +46 -103
  46. dstack/_internal/core/backends/gcp/models.py +125 -0
  47. dstack/_internal/core/backends/kubernetes/__init__.py +0 -15
  48. dstack/_internal/core/backends/kubernetes/backend.py +16 -0
  49. dstack/_internal/core/backends/kubernetes/compute.py +16 -5
  50. dstack/_internal/core/backends/kubernetes/configurator.py +55 -0
  51. dstack/_internal/core/backends/kubernetes/models.py +72 -0
  52. dstack/_internal/core/backends/lambdalabs/__init__.py +0 -16
  53. dstack/_internal/core/backends/lambdalabs/backend.py +17 -0
  54. dstack/_internal/core/backends/lambdalabs/compute.py +7 -28
  55. dstack/_internal/core/backends/lambdalabs/configurator.py +82 -0
  56. dstack/_internal/core/backends/lambdalabs/models.py +37 -0
  57. dstack/_internal/core/backends/local/__init__.py +0 -13
  58. dstack/_internal/core/backends/local/backend.py +14 -0
  59. dstack/_internal/core/backends/local/compute.py +16 -2
  60. dstack/_internal/core/backends/models.py +128 -0
  61. dstack/_internal/core/backends/oci/__init__.py +0 -15
  62. dstack/_internal/core/backends/oci/auth.py +1 -5
  63. dstack/_internal/core/backends/oci/backend.py +16 -0
  64. dstack/_internal/core/backends/oci/compute.py +9 -23
  65. dstack/_internal/{server/services/backends/configurators/oci.py → core/backends/oci/configurator.py} +40 -85
  66. dstack/_internal/core/{models/backends/oci.py → backends/oci/models.py} +24 -25
  67. dstack/_internal/core/backends/oci/region.py +1 -1
  68. dstack/_internal/core/backends/runpod/__init__.py +0 -15
  69. dstack/_internal/core/backends/runpod/backend.py +16 -0
  70. dstack/_internal/core/backends/runpod/compute.py +28 -6
  71. dstack/_internal/core/backends/runpod/configurator.py +59 -0
  72. dstack/_internal/core/backends/runpod/models.py +54 -0
  73. dstack/_internal/core/backends/template/__init__.py +0 -0
  74. dstack/_internal/core/backends/tensordock/__init__.py +0 -15
  75. dstack/_internal/core/backends/tensordock/backend.py +16 -0
  76. dstack/_internal/core/backends/tensordock/compute.py +8 -27
  77. dstack/_internal/core/backends/tensordock/configurator.py +68 -0
  78. dstack/_internal/core/backends/tensordock/models.py +38 -0
  79. dstack/_internal/core/backends/vastai/__init__.py +0 -15
  80. dstack/_internal/core/backends/vastai/backend.py +16 -0
  81. dstack/_internal/core/backends/vastai/compute.py +2 -2
  82. dstack/_internal/core/backends/vastai/configurator.py +66 -0
  83. dstack/_internal/core/backends/vastai/models.py +37 -0
  84. dstack/_internal/core/backends/vultr/__init__.py +0 -15
  85. dstack/_internal/core/backends/vultr/backend.py +16 -0
  86. dstack/_internal/core/backends/vultr/compute.py +10 -24
  87. dstack/_internal/core/backends/vultr/configurator.py +64 -0
  88. dstack/_internal/core/backends/vultr/models.py +34 -0
  89. dstack/_internal/core/models/backends/__init__.py +0 -184
  90. dstack/_internal/core/models/backends/base.py +0 -19
  91. dstack/_internal/core/models/configurations.py +22 -16
  92. dstack/_internal/core/models/envs.py +4 -3
  93. dstack/_internal/core/models/fleets.py +17 -22
  94. dstack/_internal/core/models/gateways.py +3 -3
  95. dstack/_internal/core/models/instances.py +24 -0
  96. dstack/_internal/core/models/profiles.py +85 -45
  97. dstack/_internal/core/models/projects.py +1 -1
  98. dstack/_internal/core/models/repos/base.py +0 -5
  99. dstack/_internal/core/models/repos/local.py +3 -3
  100. dstack/_internal/core/models/repos/remote.py +26 -12
  101. dstack/_internal/core/models/repos/virtual.py +1 -1
  102. dstack/_internal/core/models/resources.py +45 -76
  103. dstack/_internal/core/models/runs.py +21 -19
  104. dstack/_internal/core/models/volumes.py +1 -3
  105. dstack/_internal/core/services/profiles.py +7 -16
  106. dstack/_internal/core/services/repos.py +0 -4
  107. dstack/_internal/server/app.py +11 -4
  108. dstack/_internal/server/background/__init__.py +10 -0
  109. dstack/_internal/server/background/tasks/process_gateways.py +4 -8
  110. dstack/_internal/server/background/tasks/process_instances.py +14 -9
  111. dstack/_internal/server/background/tasks/process_metrics.py +1 -1
  112. dstack/_internal/server/background/tasks/process_placement_groups.py +5 -1
  113. dstack/_internal/server/background/tasks/process_prometheus_metrics.py +135 -0
  114. dstack/_internal/server/background/tasks/process_running_jobs.py +80 -24
  115. dstack/_internal/server/background/tasks/process_runs.py +1 -0
  116. dstack/_internal/server/background/tasks/process_submitted_jobs.py +20 -38
  117. dstack/_internal/server/background/tasks/process_volumes.py +5 -2
  118. dstack/_internal/server/migrations/versions/60e444118b6d_add_jobprometheusmetrics.py +40 -0
  119. dstack/_internal/server/migrations/versions/7bc2586e8b9e_make_instancemodel_pool_id_optional.py +36 -0
  120. dstack/_internal/server/migrations/versions/98d1b92988bc_add_jobterminationreason_terminated_due_.py +140 -0
  121. dstack/_internal/server/migrations/versions/bc8ca4a505c6_store_backendtype_as_string.py +171 -0
  122. dstack/_internal/server/models.py +59 -9
  123. dstack/_internal/server/routers/backends.py +14 -23
  124. dstack/_internal/server/routers/instances.py +3 -4
  125. dstack/_internal/server/routers/metrics.py +31 -10
  126. dstack/_internal/server/routers/prometheus.py +36 -0
  127. dstack/_internal/server/routers/repos.py +1 -2
  128. dstack/_internal/server/routers/runs.py +13 -59
  129. dstack/_internal/server/schemas/gateways.py +14 -23
  130. dstack/_internal/server/schemas/projects.py +7 -2
  131. dstack/_internal/server/schemas/repos.py +2 -38
  132. dstack/_internal/server/schemas/runner.py +1 -0
  133. dstack/_internal/server/schemas/runs.py +1 -24
  134. dstack/_internal/server/security/permissions.py +1 -1
  135. dstack/_internal/server/services/backends/__init__.py +85 -158
  136. dstack/_internal/server/services/config.py +53 -567
  137. dstack/_internal/server/services/fleets.py +9 -103
  138. dstack/_internal/server/services/gateways/__init__.py +13 -4
  139. dstack/_internal/server/services/{pools.py → instances.py} +22 -329
  140. dstack/_internal/server/services/jobs/__init__.py +9 -6
  141. dstack/_internal/server/services/jobs/configurators/base.py +25 -1
  142. dstack/_internal/server/services/jobs/configurators/dev.py +9 -1
  143. dstack/_internal/server/services/jobs/configurators/extensions/cursor.py +42 -0
  144. dstack/_internal/server/services/metrics.py +131 -72
  145. dstack/_internal/server/services/offers.py +1 -1
  146. dstack/_internal/server/services/projects.py +23 -14
  147. dstack/_internal/server/services/prometheus.py +245 -0
  148. dstack/_internal/server/services/runner/client.py +14 -3
  149. dstack/_internal/server/services/runs.py +67 -31
  150. dstack/_internal/server/services/volumes.py +9 -4
  151. dstack/_internal/server/settings.py +3 -0
  152. dstack/_internal/server/statics/index.html +1 -1
  153. dstack/_internal/server/statics/{main-fe8fd9db55df8d10e648.js → main-4fd5a4770eff59325ee3.js} +68 -15
  154. dstack/_internal/server/statics/{main-fe8fd9db55df8d10e648.js.map → main-4fd5a4770eff59325ee3.js.map} +1 -1
  155. dstack/_internal/server/statics/{main-7510e71dfa9749a4e70e.css → main-da9f8c06a69c20dac23e.css} +1 -1
  156. dstack/_internal/server/statics/static/media/entraID.d65d1f3e9486a8e56d24fc07b3230885.svg +9 -0
  157. dstack/_internal/server/testing/common.py +75 -32
  158. dstack/_internal/utils/json_schema.py +6 -0
  159. dstack/_internal/utils/ssh.py +2 -1
  160. dstack/api/__init__.py +4 -0
  161. dstack/api/_public/__init__.py +16 -20
  162. dstack/api/_public/backends.py +1 -1
  163. dstack/api/_public/repos.py +36 -36
  164. dstack/api/_public/runs.py +170 -83
  165. dstack/api/server/__init__.py +11 -13
  166. dstack/api/server/_backends.py +12 -16
  167. dstack/api/server/_fleets.py +15 -55
  168. dstack/api/server/_gateways.py +3 -14
  169. dstack/api/server/_repos.py +1 -4
  170. dstack/api/server/_runs.py +21 -96
  171. dstack/api/server/_volumes.py +10 -5
  172. dstack/api/utils.py +3 -0
  173. dstack/version.py +1 -1
  174. {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/METADATA +10 -1
  175. {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/RECORD +229 -206
  176. tests/_internal/cli/services/configurators/test_profile.py +6 -6
  177. tests/_internal/core/backends/aws/test_configurator.py +35 -0
  178. tests/_internal/core/backends/aws/test_resources.py +1 -1
  179. tests/_internal/core/backends/azure/test_configurator.py +61 -0
  180. tests/_internal/core/backends/cudo/__init__.py +0 -0
  181. tests/_internal/core/backends/cudo/test_configurator.py +37 -0
  182. tests/_internal/core/backends/datacrunch/__init__.py +0 -0
  183. tests/_internal/core/backends/datacrunch/test_configurator.py +17 -0
  184. tests/_internal/core/backends/gcp/test_configurator.py +42 -0
  185. tests/_internal/core/backends/kubernetes/test_configurator.py +43 -0
  186. tests/_internal/core/backends/lambdalabs/__init__.py +0 -0
  187. tests/_internal/core/backends/lambdalabs/test_configurator.py +38 -0
  188. tests/_internal/core/backends/oci/test_configurator.py +55 -0
  189. tests/_internal/core/backends/runpod/__init__.py +0 -0
  190. tests/_internal/core/backends/runpod/test_configurator.py +33 -0
  191. tests/_internal/core/backends/tensordock/__init__.py +0 -0
  192. tests/_internal/core/backends/tensordock/test_configurator.py +38 -0
  193. tests/_internal/core/backends/vastai/__init__.py +0 -0
  194. tests/_internal/core/backends/vastai/test_configurator.py +33 -0
  195. tests/_internal/core/backends/vultr/__init__.py +0 -0
  196. tests/_internal/core/backends/vultr/test_configurator.py +33 -0
  197. tests/_internal/server/background/tasks/test_process_gateways.py +4 -0
  198. tests/_internal/server/background/tasks/test_process_instances.py +49 -48
  199. tests/_internal/server/background/tasks/test_process_metrics.py +0 -3
  200. tests/_internal/server/background/tasks/test_process_placement_groups.py +2 -0
  201. tests/_internal/server/background/tasks/test_process_prometheus_metrics.py +186 -0
  202. tests/_internal/server/background/tasks/test_process_running_jobs.py +123 -19
  203. tests/_internal/server/background/tasks/test_process_runs.py +8 -22
  204. tests/_internal/server/background/tasks/test_process_submitted_jobs.py +3 -40
  205. tests/_internal/server/background/tasks/test_process_submitted_volumes.py +2 -0
  206. tests/_internal/server/background/tasks/test_process_terminating_jobs.py +10 -15
  207. tests/_internal/server/routers/test_backends.py +6 -764
  208. tests/_internal/server/routers/test_fleets.py +2 -26
  209. tests/_internal/server/routers/test_gateways.py +27 -3
  210. tests/_internal/server/routers/test_instances.py +0 -10
  211. tests/_internal/server/routers/test_metrics.py +42 -0
  212. tests/_internal/server/routers/test_projects.py +56 -0
  213. tests/_internal/server/routers/test_prometheus.py +333 -0
  214. tests/_internal/server/routers/test_repos.py +0 -15
  215. tests/_internal/server/routers/test_runs.py +83 -275
  216. tests/_internal/server/routers/test_volumes.py +2 -3
  217. tests/_internal/server/services/backends/__init__.py +0 -0
  218. tests/_internal/server/services/jobs/configurators/test_task.py +35 -0
  219. tests/_internal/server/services/test_config.py +7 -4
  220. tests/_internal/server/services/test_fleets.py +1 -4
  221. tests/_internal/server/services/{test_pools.py → test_instances.py} +11 -49
  222. tests/_internal/server/services/test_metrics.py +167 -0
  223. tests/_internal/server/services/test_repos.py +1 -14
  224. tests/_internal/server/services/test_runs.py +0 -4
  225. dstack/_internal/cli/commands/pool.py +0 -581
  226. dstack/_internal/cli/commands/run.py +0 -75
  227. dstack/_internal/core/backends/aws/config.py +0 -18
  228. dstack/_internal/core/backends/azure/config.py +0 -12
  229. dstack/_internal/core/backends/base/config.py +0 -5
  230. dstack/_internal/core/backends/cudo/config.py +0 -9
  231. dstack/_internal/core/backends/datacrunch/config.py +0 -9
  232. dstack/_internal/core/backends/gcp/config.py +0 -22
  233. dstack/_internal/core/backends/kubernetes/config.py +0 -6
  234. dstack/_internal/core/backends/lambdalabs/config.py +0 -9
  235. dstack/_internal/core/backends/nebius/__init__.py +0 -15
  236. dstack/_internal/core/backends/nebius/api_client.py +0 -319
  237. dstack/_internal/core/backends/nebius/compute.py +0 -220
  238. dstack/_internal/core/backends/nebius/config.py +0 -6
  239. dstack/_internal/core/backends/nebius/types.py +0 -37
  240. dstack/_internal/core/backends/oci/config.py +0 -6
  241. dstack/_internal/core/backends/runpod/config.py +0 -9
  242. dstack/_internal/core/backends/tensordock/config.py +0 -9
  243. dstack/_internal/core/backends/vastai/config.py +0 -6
  244. dstack/_internal/core/backends/vultr/config.py +0 -9
  245. dstack/_internal/core/models/backends/aws.py +0 -86
  246. dstack/_internal/core/models/backends/azure.py +0 -68
  247. dstack/_internal/core/models/backends/cudo.py +0 -43
  248. dstack/_internal/core/models/backends/datacrunch.py +0 -44
  249. dstack/_internal/core/models/backends/gcp.py +0 -67
  250. dstack/_internal/core/models/backends/kubernetes.py +0 -40
  251. dstack/_internal/core/models/backends/lambdalabs.py +0 -43
  252. dstack/_internal/core/models/backends/nebius.py +0 -54
  253. dstack/_internal/core/models/backends/runpod.py +0 -40
  254. dstack/_internal/core/models/backends/tensordock.py +0 -44
  255. dstack/_internal/core/models/backends/vastai.py +0 -43
  256. dstack/_internal/core/models/backends/vultr.py +0 -40
  257. dstack/_internal/core/models/pools.py +0 -43
  258. dstack/_internal/server/routers/pools.py +0 -142
  259. dstack/_internal/server/schemas/pools.py +0 -38
  260. dstack/_internal/server/services/backends/configurators/base.py +0 -72
  261. dstack/_internal/server/services/backends/configurators/cudo.py +0 -87
  262. dstack/_internal/server/services/backends/configurators/datacrunch.py +0 -79
  263. dstack/_internal/server/services/backends/configurators/kubernetes.py +0 -63
  264. dstack/_internal/server/services/backends/configurators/lambdalabs.py +0 -98
  265. dstack/_internal/server/services/backends/configurators/nebius.py +0 -85
  266. dstack/_internal/server/services/backends/configurators/runpod.py +0 -97
  267. dstack/_internal/server/services/backends/configurators/tensordock.py +0 -82
  268. dstack/_internal/server/services/backends/configurators/vastai.py +0 -80
  269. dstack/_internal/server/services/backends/configurators/vultr.py +0 -80
  270. dstack/api/_public/pools.py +0 -41
  271. dstack/api/_public/resources.py +0 -105
  272. dstack/api/server/_pools.py +0 -63
  273. tests/_internal/server/routers/test_pools.py +0 -612
  274. /dstack/_internal/{server/services/backends/configurators → core/backends/dstack}/__init__.py +0 -0
  275. {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/LICENSE.md +0 -0
  276. {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/WHEEL +0 -0
  277. {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/entry_points.txt +0 -0
  278. {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/top_level.txt +0 -0
@@ -27,7 +27,6 @@ from dstack._internal.server.testing.common import (
27
27
  create_fleet,
28
28
  create_instance,
29
29
  create_job,
30
- create_pool,
31
30
  create_project,
32
31
  create_repo,
33
32
  create_run,
@@ -346,8 +345,6 @@ class TestCreateFleet:
346
345
  "retry": None,
347
346
  "max_price": None,
348
347
  "idle_duration": None,
349
- "termination_policy": None,
350
- "termination_idle_time": None,
351
348
  "type": "fleet",
352
349
  "name": "test-fleet",
353
350
  "reservation": None,
@@ -360,16 +357,12 @@ class TestCreateFleet:
360
357
  "instance_types": None,
361
358
  "spot_policy": None,
362
359
  "retry": None,
363
- "retry_policy": None,
364
360
  "max_duration": None,
365
361
  "stop_duration": None,
366
362
  "max_price": None,
367
- "pool_name": None,
368
- "instance_name": None,
369
363
  "creation_policy": None,
370
364
  "idle_duration": None,
371
- "termination_policy": None,
372
- "termination_idle_time": None,
365
+ "utilization_policy": None,
373
366
  "name": "",
374
367
  "default": False,
375
368
  "reservation": None,
@@ -393,7 +386,6 @@ class TestCreateFleet:
393
386
  "unreachable": False,
394
387
  "termination_reason": None,
395
388
  "created": "2023-01-02T03:04:00+00:00",
396
- "pool_name": None,
397
389
  "backend": None,
398
390
  "region": None,
399
391
  "availability_zone": None,
@@ -471,8 +463,6 @@ class TestCreateFleet:
471
463
  "retry": None,
472
464
  "max_price": None,
473
465
  "idle_duration": None,
474
- "termination_policy": None,
475
- "termination_idle_time": None,
476
466
  "type": "fleet",
477
467
  "name": spec.configuration.name,
478
468
  "reservation": None,
@@ -485,16 +475,12 @@ class TestCreateFleet:
485
475
  "instance_types": None,
486
476
  "spot_policy": None,
487
477
  "retry": None,
488
- "retry_policy": None,
489
478
  "max_duration": None,
490
479
  "stop_duration": None,
491
480
  "max_price": None,
492
- "pool_name": None,
493
- "instance_name": None,
494
481
  "creation_policy": None,
495
482
  "idle_duration": None,
496
- "termination_policy": None,
497
- "termination_idle_time": None,
483
+ "utilization_policy": None,
498
484
  "name": "",
499
485
  "default": False,
500
486
  "reservation": None,
@@ -524,7 +510,6 @@ class TestCreateFleet:
524
510
  "fleet_id": "1b0e1b45-2f8c-4ab6-8010-a0d1a3e44e0e",
525
511
  "fleet_name": spec.configuration.name,
526
512
  "instance_num": 0,
527
- "pool_name": None,
528
513
  "job_name": None,
529
514
  "hostname": "1.1.1.1",
530
515
  "status": "pending",
@@ -625,12 +610,10 @@ class TestDeleteFleets:
625
610
  await add_project_member(
626
611
  session=session, project=project, user=user, project_role=ProjectRole.USER
627
612
  )
628
- pool = await create_pool(session=session, project=project)
629
613
  fleet = await create_fleet(session=session, project=project)
630
614
  instance = await create_instance(
631
615
  session=session,
632
616
  project=project,
633
- pool=pool,
634
617
  )
635
618
  fleet.instances.append(instance)
636
619
  await session.commit()
@@ -652,7 +635,6 @@ class TestDeleteFleets:
652
635
  ):
653
636
  user = await create_user(session, global_role=GlobalRole.USER)
654
637
  project = await create_project(session)
655
- pool = await create_pool(session=session, project=project)
656
638
  await add_project_member(
657
639
  session=session, project=project, user=user, project_role=ProjectRole.USER
658
640
  )
@@ -674,7 +656,6 @@ class TestDeleteFleets:
674
656
  instance = await create_instance(
675
657
  session=session,
676
658
  project=project,
677
- pool=pool,
678
659
  status=InstanceStatus.BUSY,
679
660
  job=job,
680
661
  )
@@ -742,18 +723,15 @@ class TestDeleteFleetInstances:
742
723
  await add_project_member(
743
724
  session=session, project=project, user=user, project_role=ProjectRole.USER
744
725
  )
745
- pool = await create_pool(session=session, project=project)
746
726
  fleet = await create_fleet(session=session, project=project)
747
727
  instance1 = await create_instance(
748
728
  session=session,
749
729
  project=project,
750
- pool=pool,
751
730
  instance_num=1,
752
731
  )
753
732
  instance2 = await create_instance(
754
733
  session=session,
755
734
  project=project,
756
- pool=pool,
757
735
  instance_num=2,
758
736
  )
759
737
  fleet.instances.append(instance1)
@@ -783,7 +761,6 @@ class TestDeleteFleetInstances:
783
761
  await add_project_member(
784
762
  session=session, project=project, user=user, project_role=ProjectRole.USER
785
763
  )
786
- pool = await create_pool(session=session, project=project)
787
764
  fleet = await create_fleet(session=session, project=project)
788
765
  repo = await create_repo(
789
766
  session=session,
@@ -802,7 +779,6 @@ class TestDeleteFleetInstances:
802
779
  instance = await create_instance(
803
780
  session=session,
804
781
  project=project,
805
- pool=pool,
806
782
  instance_num=1,
807
783
  status=InstanceStatus.BUSY,
808
784
  job=job,
@@ -13,6 +13,7 @@ from dstack._internal.server.services.gateways import (
13
13
  )
14
14
  from dstack._internal.server.services.projects import add_project_member
15
15
  from dstack._internal.server.testing.common import (
16
+ ComputeMockSpec,
16
17
  create_backend,
17
18
  create_gateway,
18
19
  create_gateway_compute,
@@ -174,7 +175,14 @@ class TestCreateGateway:
174
175
  backend = await create_backend(session, project.id, backend_type=BackendType.AWS)
175
176
  response = await client.post(
176
177
  f"/api/project/{project.name}/gateways/create",
177
- json={"name": "test", "backend_type": "aws", "region": "us"},
178
+ json={
179
+ "configuration": {
180
+ "type": "gateway",
181
+ "name": "test",
182
+ "backend": "aws",
183
+ "region": "us",
184
+ },
185
+ },
178
186
  headers=get_auth_headers(user.token),
179
187
  )
180
188
  assert response.status_code == 200
@@ -217,7 +225,14 @@ class TestCreateGateway:
217
225
  g.return_value = "random-name"
218
226
  response = await client.post(
219
227
  f"/api/project/{project.name}/gateways/create",
220
- json={"name": None, "backend_type": "aws", "region": "us"},
228
+ json={
229
+ "configuration": {
230
+ "type": "gateway",
231
+ "name": None,
232
+ "backend": "aws",
233
+ "region": "us",
234
+ },
235
+ },
221
236
  headers=get_auth_headers(user.token),
222
237
  )
223
238
  g.assert_called_once()
@@ -258,7 +273,14 @@ class TestCreateGateway:
258
273
  )
259
274
  response = await client.post(
260
275
  f"/api/project/{project.name}/gateways/create",
261
- json={"name": "test", "backend_type": "aws", "region": "us"},
276
+ json={
277
+ "configuration": {
278
+ "type": "gateway",
279
+ "name": "test",
280
+ "backend": "aws",
281
+ "region": "us",
282
+ },
283
+ },
262
284
  headers=get_auth_headers(user.token),
263
285
  )
264
286
  assert response.status_code == 400
@@ -437,8 +459,10 @@ class TestDeleteGateway:
437
459
  "dstack._internal.server.services.gateways.get_project_backend_by_type_or_error"
438
460
  ) as m:
439
461
  aws = Mock()
462
+ aws.compute.return_value = Mock(spec=ComputeMockSpec)
440
463
  aws.compute.return_value.terminate_gateway.return_value = None # success
441
464
  gcp = Mock()
465
+ gcp.compute.return_value = Mock(spec=ComputeMockSpec)
442
466
  gcp.compute.return_value.terminate_gateway.side_effect = DstackError() # fail
443
467
 
444
468
  def get_backend(project, backend_type):
@@ -15,7 +15,6 @@ from dstack._internal.server.services.projects import add_project_member
15
15
  from dstack._internal.server.testing.common import (
16
16
  create_fleet,
17
17
  create_instance,
18
- create_pool,
19
18
  create_project,
20
19
  create_user,
21
20
  get_auth_headers,
@@ -59,11 +58,6 @@ class TestListInstances:
59
58
  await add_project_member(
60
59
  session, project=projects[2], user=users[1], project_role=ProjectRole.USER
61
60
  )
62
- pools = [
63
- await create_pool(session, projects[0]),
64
- await create_pool(session, projects[1]),
65
- await create_pool(session, projects[2]),
66
- ]
67
61
  fleets = [
68
62
  await create_fleet(
69
63
  session,
@@ -88,7 +82,6 @@ class TestListInstances:
88
82
  await create_instance(
89
83
  session=session,
90
84
  project=projects[0],
91
- pool=pools[0],
92
85
  fleet=fleets[0],
93
86
  created_at=dt.datetime(2024, 1, 1, tzinfo=dt.timezone.utc),
94
87
  name="fleet0-0",
@@ -96,7 +89,6 @@ class TestListInstances:
96
89
  await create_instance(
97
90
  session=session,
98
91
  project=projects[1],
99
- pool=pools[1],
100
92
  fleet=fleets[1],
101
93
  created_at=dt.datetime(2024, 1, 2, tzinfo=dt.timezone.utc),
102
94
  name="fleet1-0",
@@ -104,7 +96,6 @@ class TestListInstances:
104
96
  await create_instance(
105
97
  session=session,
106
98
  project=projects[2],
107
- pool=pools[2],
108
99
  fleet=fleets[2],
109
100
  created_at=dt.datetime(2024, 1, 3, tzinfo=dt.timezone.utc),
110
101
  name="fleet2-0",
@@ -112,7 +103,6 @@ class TestListInstances:
112
103
  await create_instance(
113
104
  session=session,
114
105
  project=projects[2],
115
- pool=pools[2],
116
106
  fleet=fleets[2],
117
107
  created_at=dt.datetime(2024, 1, 4, tzinfo=dt.timezone.utc),
118
108
  instance_num=1,
@@ -14,6 +14,9 @@ from dstack._internal.server.testing.common import (
14
14
  create_run,
15
15
  create_user,
16
16
  get_auth_headers,
17
+ get_instance_offer_with_availability,
18
+ get_job_provisioning_data,
19
+ get_job_runtime_data,
17
20
  )
18
21
 
19
22
  pytestmark = pytest.mark.usefixtures("image_config_mock")
@@ -51,15 +54,38 @@ class TestGetJobMetrics:
51
54
  repo=repo,
52
55
  user=user,
53
56
  )
57
+ jpd = get_job_provisioning_data(
58
+ cpu_count=128, memory_gib=256, gpu_count=2, gpu_memory_gib=32
59
+ )
60
+ offer = get_instance_offer_with_availability(
61
+ cpu_count=64, memory_gib=128, gpu_count=1, gpu_memory_gib=32
62
+ )
63
+ jrd = get_job_runtime_data(offer=offer)
54
64
  job = await create_job(
55
65
  session=session,
56
66
  run=run,
67
+ job_provisioning_data=jpd,
68
+ job_runtime_data=jrd,
69
+ )
70
+ await create_job_metrics_point(
71
+ session=session,
72
+ job_model=job,
73
+ timestamp=datetime(2023, 1, 2, 3, 4, 5, tzinfo=timezone.utc),
74
+ cpu_usage_micro=2 * 1_000_000,
75
+ memory_usage_bytes=256,
76
+ memory_working_set_bytes=128,
77
+ gpus_memory_usage_bytes=[256],
78
+ gpus_util_percent=[2],
57
79
  )
58
80
  await create_job_metrics_point(
59
81
  session=session,
60
82
  job_model=job,
61
83
  timestamp=datetime(2023, 1, 2, 3, 4, 15, tzinfo=timezone.utc),
62
84
  cpu_usage_micro=4 * 1_000_000,
85
+ memory_usage_bytes=512,
86
+ memory_working_set_bytes=256,
87
+ gpus_memory_usage_bytes=[512],
88
+ gpus_util_percent=[6],
63
89
  )
64
90
  await create_job_metrics_point(
65
91
  session=session,
@@ -76,6 +102,7 @@ class TestGetJobMetrics:
76
102
  headers=get_auth_headers(user.token),
77
103
  )
78
104
  assert response.status_code == 200
105
+ # Returns one last sample by default. Filtering is tested in services/test_metrics.py
79
106
  assert response.json() == {
80
107
  "metrics": [
81
108
  {
@@ -93,11 +120,26 @@ class TestGetJobMetrics:
93
120
  "timestamps": ["2023-01-02T03:04:25+00:00"],
94
121
  "values": [512],
95
122
  },
123
+ {
124
+ "name": "cpus_detected_num",
125
+ "timestamps": ["2023-01-02T03:04:25+00:00"],
126
+ "values": [64],
127
+ },
128
+ {
129
+ "name": "memory_total_bytes",
130
+ "timestamps": ["2023-01-02T03:04:25+00:00"],
131
+ "values": [137438953472],
132
+ },
96
133
  {
97
134
  "name": "gpus_detected_num",
98
135
  "timestamps": ["2023-01-02T03:04:25+00:00"],
99
136
  "values": [1],
100
137
  },
138
+ {
139
+ "name": "gpu_memory_total_bytes",
140
+ "timestamps": ["2023-01-02T03:04:25+00:00"],
141
+ "values": [34359738368],
142
+ },
101
143
  {
102
144
  "name": "gpu_memory_usage_bytes_gpu0",
103
145
  "timestamps": ["2023-01-02T03:04:25+00:00"],
@@ -503,6 +503,62 @@ class TestSetProjectMembers:
503
503
  members = res.scalars().all()
504
504
  assert len(members) == 3
505
505
 
506
+ @pytest.mark.asyncio
507
+ @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
508
+ async def test_sets_project_members_by_email(
509
+ self, test_db, session: AsyncSession, client: AsyncClient
510
+ ):
511
+ project = await create_project(
512
+ session=session,
513
+ created_at=datetime(2023, 1, 2, 3, 4, tzinfo=timezone.utc),
514
+ )
515
+ admin = await create_user(
516
+ session=session,
517
+ created_at=datetime(2023, 1, 2, 3, 4, tzinfo=timezone.utc),
518
+ global_role=GlobalRole.ADMIN,
519
+ )
520
+ user1 = await create_user(
521
+ session=session,
522
+ name="user1",
523
+ created_at=datetime(2023, 1, 2, 3, 4, tzinfo=timezone.utc),
524
+ email="testemail@example.com",
525
+ )
526
+ members = [
527
+ {
528
+ "username": user1.email,
529
+ "project_role": ProjectRole.ADMIN,
530
+ },
531
+ ]
532
+ body = {"members": members}
533
+ response = await client.post(
534
+ f"/api/projects/{project.name}/set_members",
535
+ headers=get_auth_headers(admin.token),
536
+ json=body,
537
+ )
538
+ assert response.status_code == 200, response.json()
539
+ assert response.json()["members"] == [
540
+ {
541
+ "user": {
542
+ "id": str(user1.id),
543
+ "username": user1.name,
544
+ "created_at": "2023-01-02T03:04:00+00:00",
545
+ "global_role": user1.global_role,
546
+ "email": user1.email,
547
+ "active": True,
548
+ "permissions": {
549
+ "can_create_projects": True,
550
+ },
551
+ },
552
+ "project_role": ProjectRole.ADMIN,
553
+ "permissions": {
554
+ "can_manage_ssh_fleets": True,
555
+ },
556
+ },
557
+ ]
558
+ res = await session.execute(select(MemberModel))
559
+ members = res.scalars().all()
560
+ assert len(members) == 1
561
+
506
562
  @pytest.mark.asyncio
507
563
  @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
508
564
  async def test_manager_cannot_set_project_admins(