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
@@ -1,6 +1,5 @@
1
1
  import json
2
2
  from datetime import datetime, timezone
3
- from operator import itemgetter
4
3
  from unittest.mock import Mock, patch
5
4
 
6
5
  import pytest
@@ -10,7 +9,6 @@ from sqlalchemy import select
10
9
  from sqlalchemy.ext.asyncio import AsyncSession
11
10
 
12
11
  from dstack._internal.core.backends.oci import region as oci_region
13
- from dstack._internal.core.errors import BackendAuthError
14
12
  from dstack._internal.core.models.backends.base import BackendType
15
13
  from dstack._internal.core.models.instances import InstanceStatus
16
14
  from dstack._internal.core.models.users import GlobalRole, ProjectRole
@@ -21,7 +19,6 @@ from dstack._internal.server.testing.common import (
21
19
  create_backend,
22
20
  create_fleet,
23
21
  create_instance,
24
- create_pool,
25
22
  create_project,
26
23
  create_user,
27
24
  create_volume,
@@ -65,7 +62,6 @@ class TestListBackendTypes:
65
62
  "gcp",
66
63
  "kubernetes",
67
64
  "lambda",
68
- "nebius",
69
65
  "oci",
70
66
  "runpod",
71
67
  "tensordock",
@@ -74,717 +70,6 @@ class TestListBackendTypes:
74
70
  ]
75
71
 
76
72
 
77
- class TestGetBackendConfigValuesAWS:
78
- @pytest.mark.asyncio
79
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
80
- async def test_returns_initial_config(
81
- self, test_db, session: AsyncSession, client: AsyncClient
82
- ):
83
- user = await create_user(session=session, global_role=GlobalRole.USER)
84
- body = {"type": "aws"}
85
- with patch(
86
- "dstack._internal.core.backends.aws.auth.default_creds_available"
87
- ) as default_creds_available_mock:
88
- default_creds_available_mock.return_value = False
89
- response = await client.post(
90
- "/api/backends/config_values",
91
- headers=get_auth_headers(user.token),
92
- json=body,
93
- )
94
- default_creds_available_mock.assert_called()
95
- assert response.status_code == 200, response.json()
96
- assert response.json() == {
97
- "type": "aws",
98
- "default_creds": False,
99
- "regions": None,
100
- }
101
-
102
- @pytest.mark.asyncio
103
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
104
- async def test_returns_invalid_credentials(
105
- self, test_db, session: AsyncSession, client: AsyncClient
106
- ):
107
- user = await create_user(session=session, global_role=GlobalRole.USER)
108
- body = {
109
- "type": "aws",
110
- "creds": {
111
- "type": "access_key",
112
- "access_key": "1234",
113
- "secret_key": "1234",
114
- },
115
- }
116
- with (
117
- patch(
118
- "dstack._internal.core.backends.aws.auth.default_creds_available"
119
- ) as default_creds_available_mock,
120
- patch("dstack._internal.core.backends.aws.auth.authenticate") as authenticate_mock,
121
- ):
122
- authenticate_mock.side_effect = BackendAuthError()
123
- response = await client.post(
124
- "/api/backends/config_values",
125
- headers=get_auth_headers(user.token),
126
- json=body,
127
- )
128
- default_creds_available_mock.assert_called()
129
- authenticate_mock.assert_called()
130
- assert response.status_code == 400
131
- assert response.json() == {
132
- "detail": [
133
- {
134
- "code": "invalid_credentials",
135
- "msg": "Invalid credentials",
136
- "fields": ["creds", "access_key"],
137
- },
138
- {
139
- "code": "invalid_credentials",
140
- "msg": "Invalid credentials",
141
- "fields": ["creds", "secret_key"],
142
- },
143
- ]
144
- }
145
-
146
- @pytest.mark.asyncio
147
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
148
- async def test_returns_config_on_valid_creds(
149
- self, test_db, session: AsyncSession, client: AsyncClient
150
- ):
151
- user = await create_user(session=session, global_role=GlobalRole.USER)
152
- body = {
153
- "type": "aws",
154
- "creds": {
155
- "type": "access_key",
156
- "access_key": "1234",
157
- "secret_key": "1234",
158
- },
159
- }
160
- with (
161
- patch(
162
- "dstack._internal.core.backends.aws.auth.default_creds_available"
163
- ) as default_creds_available_mock,
164
- patch("dstack._internal.core.backends.aws.auth.authenticate") as authenticate_mock,
165
- patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"),
166
- ):
167
- default_creds_available_mock.return_value = True
168
- response = await client.post(
169
- "/api/backends/config_values",
170
- headers=get_auth_headers(user.token),
171
- json=body,
172
- )
173
- default_creds_available_mock.assert_called()
174
- authenticate_mock.assert_called()
175
- assert response.status_code == 200, response.json()
176
- assert response.json() == {
177
- "type": "aws",
178
- "default_creds": True,
179
- "regions": {
180
- "selected": [
181
- "us-east-1",
182
- "us-east-2",
183
- "us-west-1",
184
- "us-west-2",
185
- "ap-southeast-1",
186
- "ca-central-1",
187
- "eu-central-1",
188
- "eu-west-1",
189
- "eu-west-2",
190
- "eu-west-3",
191
- "eu-north-1",
192
- ],
193
- "values": [
194
- {"label": "us-east-1", "value": "us-east-1"},
195
- {"label": "us-east-2", "value": "us-east-2"},
196
- {"label": "us-west-1", "value": "us-west-1"},
197
- {"label": "us-west-2", "value": "us-west-2"},
198
- {"label": "ap-southeast-1", "value": "ap-southeast-1"},
199
- {"label": "ca-central-1", "value": "ca-central-1"},
200
- {"label": "eu-central-1", "value": "eu-central-1"},
201
- {"label": "eu-west-1", "value": "eu-west-1"},
202
- {"label": "eu-west-2", "value": "eu-west-2"},
203
- {"label": "eu-west-3", "value": "eu-west-3"},
204
- {"label": "eu-north-1", "value": "eu-north-1"},
205
- ],
206
- },
207
- }
208
-
209
-
210
- class TestGetBackendConfigValuesAzure:
211
- @pytest.mark.asyncio
212
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
213
- async def test_returns_initial_config(
214
- self, test_db, session: AsyncSession, client: AsyncClient
215
- ):
216
- user = await create_user(session=session, global_role=GlobalRole.USER)
217
- body = {"type": "azure"}
218
- with patch(
219
- "dstack._internal.core.backends.azure.auth.default_creds_available"
220
- ) as default_creds_available_mock:
221
- default_creds_available_mock.return_value = False
222
- response = await client.post(
223
- "/api/backends/config_values",
224
- headers=get_auth_headers(user.token),
225
- json=body,
226
- )
227
- default_creds_available_mock.assert_called()
228
- assert response.status_code == 200, response.json()
229
- assert response.json() == {
230
- "type": "azure",
231
- "default_creds": False,
232
- "tenant_id": None,
233
- "subscription_id": None,
234
- "locations": None,
235
- }
236
-
237
- @pytest.mark.asyncio
238
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
239
- async def test_returns_invalid_credentials(
240
- self, test_db, session: AsyncSession, client: AsyncClient
241
- ):
242
- user = await create_user(session=session, global_role=GlobalRole.USER)
243
- body = {
244
- "type": "azure",
245
- "creds": {
246
- "type": "client",
247
- "tenant_id": "1234",
248
- "client_id": "1234",
249
- "client_secret": "1234",
250
- },
251
- }
252
- with (
253
- patch(
254
- "dstack._internal.core.backends.azure.auth.default_creds_available"
255
- ) as default_creds_available_mock,
256
- patch("dstack._internal.core.backends.azure.auth.authenticate") as authenticate_mock,
257
- ):
258
- default_creds_available_mock.return_value = False
259
- authenticate_mock.side_effect = BackendAuthError()
260
- response = await client.post(
261
- "/api/backends/config_values",
262
- headers=get_auth_headers(user.token),
263
- json=body,
264
- )
265
- default_creds_available_mock.assert_called()
266
- authenticate_mock.assert_called()
267
- assert response.status_code == 400
268
- assert response.json() == {
269
- "detail": [
270
- {
271
- "code": "invalid_credentials",
272
- "msg": "Invalid credentials",
273
- "fields": ["creds", "tenant_id"],
274
- },
275
- {
276
- "code": "invalid_credentials",
277
- "msg": "Invalid credentials",
278
- "fields": ["creds", "client_id"],
279
- },
280
- {
281
- "code": "invalid_credentials",
282
- "msg": "Invalid credentials",
283
- "fields": ["creds", "client_secret"],
284
- },
285
- ]
286
- }
287
-
288
- @pytest.mark.asyncio
289
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
290
- @pytest.mark.parametrize(
291
- "body",
292
- [
293
- {
294
- "type": "azure",
295
- "creds": {
296
- "type": "client",
297
- "client_id": "1234",
298
- "client_secret": "1234",
299
- },
300
- "tenant_id": "test_tenant",
301
- },
302
- {
303
- "type": "azure",
304
- "creds": {
305
- "type": "client",
306
- "tenant_id": "test_tenant",
307
- "client_id": "1234",
308
- "client_secret": "1234",
309
- },
310
- },
311
- ],
312
- )
313
- async def test_returns_config_on_valid_creds(
314
- self, test_db, session: AsyncSession, client: AsyncClient, body
315
- ):
316
- user = await create_user(session=session, global_role=GlobalRole.USER)
317
- with (
318
- patch(
319
- "dstack._internal.core.backends.azure.auth.default_creds_available"
320
- ) as default_creds_available_mock,
321
- patch("dstack._internal.core.backends.azure.auth.authenticate") as authenticate_mock,
322
- patch("azure.mgmt.subscription.SubscriptionClient") as SubscriptionClientMock,
323
- patch(
324
- "dstack._internal.core.backends.azure.compute.get_resource_group_network_subnet_or_error"
325
- ),
326
- ):
327
- default_creds_available_mock.return_value = False
328
- authenticate_mock.return_value = None, "test_tenant"
329
- client_mock = SubscriptionClientMock.return_value
330
- tenant_mock = Mock()
331
- tenant_mock.tenant_id = "test_tenant"
332
- client_mock.tenants.list.return_value = [tenant_mock]
333
- subscription_mock = Mock()
334
- subscription_mock.subscription_id = "test_subscription"
335
- subscription_mock.display_name = "Subscription"
336
- client_mock.subscriptions.list.return_value = [subscription_mock]
337
- response = await client.post(
338
- "/api/backends/config_values",
339
- headers=get_auth_headers(user.token),
340
- json=body,
341
- )
342
- assert response.status_code == 200
343
- assert response.json() == {
344
- "type": "azure",
345
- "default_creds": False,
346
- "tenant_id": {
347
- "selected": "test_tenant",
348
- "values": [
349
- {
350
- "value": "test_tenant",
351
- "label": "test_tenant",
352
- }
353
- ],
354
- },
355
- "subscription_id": {
356
- "selected": "test_subscription",
357
- "values": [
358
- {
359
- "value": "test_subscription",
360
- "label": "Subscription (test_subscription)",
361
- }
362
- ],
363
- },
364
- "locations": {
365
- "selected": [
366
- "centralus",
367
- "eastus",
368
- "eastus2",
369
- "southcentralus",
370
- "westus2",
371
- "westus3",
372
- "canadacentral",
373
- "francecentral",
374
- "germanywestcentral",
375
- "northeurope",
376
- "swedencentral",
377
- "uksouth",
378
- "westeurope",
379
- "southeastasia",
380
- "eastasia",
381
- "brazilsouth",
382
- ],
383
- "values": [
384
- {"value": "centralus", "label": "centralus"},
385
- {"value": "eastus", "label": "eastus"},
386
- {"value": "eastus2", "label": "eastus2"},
387
- {"value": "southcentralus", "label": "southcentralus"},
388
- {"value": "westus2", "label": "westus2"},
389
- {"value": "westus3", "label": "westus3"},
390
- {"value": "canadacentral", "label": "canadacentral"},
391
- {"value": "francecentral", "label": "francecentral"},
392
- {"value": "germanywestcentral", "label": "germanywestcentral"},
393
- {"value": "northeurope", "label": "northeurope"},
394
- {"value": "swedencentral", "label": "swedencentral"},
395
- {"value": "uksouth", "label": "uksouth"},
396
- {"value": "westeurope", "label": "westeurope"},
397
- {"value": "southeastasia", "label": "southeastasia"},
398
- {"value": "eastasia", "label": "eastasia"},
399
- {"value": "brazilsouth", "label": "brazilsouth"},
400
- ],
401
- },
402
- }
403
-
404
-
405
- class TestGetBackendConfigValuesGCP:
406
- @pytest.mark.asyncio
407
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
408
- async def test_returns_initial_config(
409
- self, test_db, session: AsyncSession, client: AsyncClient
410
- ):
411
- user = await create_user(session=session, global_role=GlobalRole.USER)
412
- body = {"type": "gcp"}
413
- with patch("dstack._internal.core.backends.gcp.auth.default_creds_available") as m:
414
- m.return_value = True
415
- response = await client.post(
416
- "/api/backends/config_values",
417
- headers=get_auth_headers(user.token),
418
- json=body,
419
- )
420
- assert response.status_code == 200, response.json()
421
- assert response.json() == {
422
- "type": "gcp",
423
- "default_creds": True,
424
- "project_id": None,
425
- "regions": None,
426
- }
427
-
428
- @pytest.mark.asyncio
429
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
430
- async def test_returns_invalid_credentials(
431
- self, test_db, session: AsyncSession, client: AsyncClient
432
- ):
433
- user = await create_user(session=session, global_role=GlobalRole.USER)
434
- body = {
435
- "type": "gcp",
436
- "creds": {
437
- "type": "service_account",
438
- "filename": "1234",
439
- "data": "1234",
440
- },
441
- }
442
- with (
443
- patch(
444
- "dstack._internal.core.backends.gcp.auth.default_creds_available"
445
- ) as default_creds_available_mock,
446
- patch("dstack._internal.core.backends.gcp.auth.authenticate") as authenticate_mock,
447
- ):
448
- default_creds_available_mock.return_value = False
449
- authenticate_mock.side_effect = BackendAuthError()
450
- response = await client.post(
451
- "/api/backends/config_values",
452
- headers=get_auth_headers(user.token),
453
- json=body,
454
- )
455
- authenticate_mock.assert_called()
456
- assert response.status_code == 400
457
- assert response.json() == {
458
- "detail": [
459
- {
460
- "code": "invalid_credentials",
461
- "msg": "Invalid credentials",
462
- "fields": ["creds", "data"],
463
- },
464
- ]
465
- }
466
-
467
- @pytest.mark.asyncio
468
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
469
- async def test_returns_config_on_valid_creds(
470
- self, test_db, session: AsyncSession, client: AsyncClient
471
- ):
472
- user = await create_user(session=session, global_role=GlobalRole.USER)
473
- body = {
474
- "type": "gcp",
475
- "creds": {
476
- "type": "service_account",
477
- "filename": "1234",
478
- "data": "1234",
479
- },
480
- "project_id": "test_project",
481
- }
482
- with (
483
- patch(
484
- "dstack._internal.core.backends.gcp.auth.default_creds_available"
485
- ) as default_creds_available_mock,
486
- patch("dstack._internal.core.backends.gcp.auth.authenticate") as authenticate_mock,
487
- patch("dstack._internal.core.backends.gcp.resources.check_vpc") as check_vpc_mock,
488
- ):
489
- default_creds_available_mock.return_value = False
490
- authenticate_mock.return_value = {}, "test_project"
491
- response = await client.post(
492
- "/api/backends/config_values",
493
- headers=get_auth_headers(user.token),
494
- json=body,
495
- )
496
- authenticate_mock.assert_called()
497
- check_vpc_mock.assert_called()
498
- assert response.status_code == 200, response.json()
499
- assert response.json() == {
500
- "type": "gcp",
501
- "default_creds": False,
502
- "project_id": {
503
- "selected": "test_project",
504
- "values": [
505
- {
506
- "value": "test_project",
507
- "label": "test_project",
508
- }
509
- ],
510
- },
511
- "regions": {
512
- "selected": [
513
- "northamerica-northeast1",
514
- "northamerica-northeast2",
515
- "us-central1",
516
- "us-east1",
517
- "us-east4",
518
- "us-east5",
519
- "us-south1",
520
- "us-west1",
521
- "us-west2",
522
- "us-west3",
523
- "us-west4",
524
- "southamerica-east1",
525
- "southamerica-west1",
526
- "europe-central2",
527
- "europe-north1",
528
- "europe-southwest1",
529
- "europe-west1",
530
- "europe-west2",
531
- "europe-west3",
532
- "europe-west4",
533
- "europe-west6",
534
- "europe-west8",
535
- "europe-west9",
536
- "asia-east1",
537
- "asia-east2",
538
- "asia-northeast1",
539
- "asia-northeast2",
540
- "asia-northeast3",
541
- "asia-south1",
542
- "asia-south2",
543
- "asia-southeast1",
544
- "asia-southeast2",
545
- "me-west1",
546
- "australia-southeast1",
547
- "australia-southeast2",
548
- ],
549
- "values": [
550
- {
551
- "value": "northamerica-northeast1",
552
- "label": "northamerica-northeast1",
553
- },
554
- {
555
- "value": "northamerica-northeast2",
556
- "label": "northamerica-northeast2",
557
- },
558
- {"value": "us-central1", "label": "us-central1"},
559
- {"value": "us-east1", "label": "us-east1"},
560
- {"value": "us-east4", "label": "us-east4"},
561
- {"value": "us-east5", "label": "us-east5"},
562
- {"value": "us-south1", "label": "us-south1"},
563
- {"value": "us-west1", "label": "us-west1"},
564
- {"value": "us-west2", "label": "us-west2"},
565
- {"value": "us-west3", "label": "us-west3"},
566
- {"value": "us-west4", "label": "us-west4"},
567
- {"value": "southamerica-east1", "label": "southamerica-east1"},
568
- {"value": "southamerica-west1", "label": "southamerica-west1"},
569
- {"value": "europe-central2", "label": "europe-central2"},
570
- {"value": "europe-north1", "label": "europe-north1"},
571
- {"value": "europe-southwest1", "label": "europe-southwest1"},
572
- {"value": "europe-west1", "label": "europe-west1"},
573
- {"value": "europe-west2", "label": "europe-west2"},
574
- {"value": "europe-west3", "label": "europe-west3"},
575
- {"value": "europe-west4", "label": "europe-west4"},
576
- {"value": "europe-west6", "label": "europe-west6"},
577
- {"value": "europe-west8", "label": "europe-west8"},
578
- {"value": "europe-west9", "label": "europe-west9"},
579
- {"value": "asia-east1", "label": "asia-east1"},
580
- {"value": "asia-east2", "label": "asia-east2"},
581
- {"value": "asia-northeast1", "label": "asia-northeast1"},
582
- {"value": "asia-northeast2", "label": "asia-northeast2"},
583
- {"value": "asia-northeast3", "label": "asia-northeast3"},
584
- {"value": "asia-south1", "label": "asia-south1"},
585
- {"value": "asia-south2", "label": "asia-south2"},
586
- {"value": "asia-southeast1", "label": "asia-southeast1"},
587
- {"value": "asia-southeast2", "label": "asia-southeast2"},
588
- {"value": "me-west1", "label": "me-west1"},
589
- {"value": "australia-southeast1", "label": "australia-southeast1"},
590
- {"value": "australia-southeast2", "label": "australia-southeast2"},
591
- ],
592
- },
593
- }
594
-
595
-
596
- class TestGetBackendConfigValuesLambda:
597
- @pytest.mark.asyncio
598
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
599
- async def test_returns_initial_config(
600
- self, test_db, session: AsyncSession, client: AsyncClient
601
- ):
602
- user = await create_user(session=session, global_role=GlobalRole.USER)
603
- body = {"type": "lambda"}
604
- response = await client.post(
605
- "/api/backends/config_values",
606
- headers=get_auth_headers(user.token),
607
- json=body,
608
- )
609
- assert response.status_code == 200, response.json()
610
- assert response.json() == {
611
- "type": "lambda",
612
- "regions": None,
613
- }
614
-
615
- @pytest.mark.asyncio
616
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
617
- async def test_returns_invalid_credentials(
618
- self, test_db, session: AsyncSession, client: AsyncClient
619
- ):
620
- user = await create_user(session=session, global_role=GlobalRole.USER)
621
- body = {
622
- "type": "lambda",
623
- "creds": {
624
- "type": "api_key",
625
- "api_key": "1234",
626
- },
627
- }
628
- with patch("dstack._internal.core.backends.lambdalabs.api_client.LambdaAPIClient") as m:
629
- m.return_value.validate_api_key.return_value = False
630
- response = await client.post(
631
- "/api/backends/config_values",
632
- headers=get_auth_headers(user.token),
633
- json=body,
634
- )
635
- m.return_value.validate_api_key.assert_called()
636
- assert response.status_code == 400, response.json()
637
- assert response.json() == {
638
- "detail": [
639
- {
640
- "code": "invalid_credentials",
641
- "msg": "Invalid credentials",
642
- "fields": ["creds", "api_key"],
643
- },
644
- ]
645
- }
646
-
647
- @pytest.mark.asyncio
648
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
649
- async def test_returns_config_on_valid_creds(
650
- self, test_db, session: AsyncSession, client: AsyncClient
651
- ):
652
- user = await create_user(session=session, global_role=GlobalRole.USER)
653
- body = {
654
- "type": "lambda",
655
- "creds": {
656
- "type": "api_key",
657
- "api_key": "1234",
658
- },
659
- }
660
- with patch("dstack._internal.core.backends.lambdalabs.api_client.LambdaAPIClient") as m:
661
- m.return_value.validate_api_key.return_value = True
662
- response = await client.post(
663
- "/api/backends/config_values",
664
- headers=get_auth_headers(user.token),
665
- json=body,
666
- )
667
- m.return_value.validate_api_key.assert_called()
668
- assert response.status_code == 200, response.json()
669
- assert response.json() == {
670
- "type": "lambda",
671
- "regions": {
672
- "selected": ["us-east-1"],
673
- "values": [
674
- {"value": "us-south-1", "label": "us-south-1"},
675
- {"value": "us-south-2", "label": "us-south-2"},
676
- {"value": "us-south-3", "label": "us-south-3"},
677
- {"value": "us-west-2", "label": "us-west-2"},
678
- {"value": "us-west-1", "label": "us-west-1"},
679
- {"value": "us-midwest-1", "label": "us-midwest-1"},
680
- {"value": "us-west-3", "label": "us-west-3"},
681
- {"value": "us-east-1", "label": "us-east-1"},
682
- {"value": "us-east-2", "label": "us-east-2"},
683
- {"value": "europe-central-1", "label": "europe-central-1"},
684
- {"value": "asia-south-1", "label": "asia-south-1"},
685
- {"value": "me-west-1", "label": "me-west-1"},
686
- {"value": "asia-northeast-1", "label": "asia-northeast-1"},
687
- {"value": "asia-northeast-2", "label": "asia-northeast-2"},
688
- ],
689
- },
690
- }
691
-
692
-
693
- class TestGetBackendConfigValuesOCI:
694
- @pytest.mark.asyncio
695
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
696
- async def test_returns_initial_config(
697
- self, test_db, session: AsyncSession, client: AsyncClient
698
- ):
699
- user = await create_user(session=session, global_role=GlobalRole.USER)
700
- body = {"type": "oci"}
701
- with patch(
702
- "dstack._internal.core.backends.oci.auth.default_creds_available"
703
- ) as default_creds_available_mock:
704
- default_creds_available_mock.return_value = False
705
- response = await client.post(
706
- "/api/backends/config_values",
707
- headers=get_auth_headers(user.token),
708
- json=body,
709
- )
710
- default_creds_available_mock.assert_called()
711
- assert response.status_code == 200, response.json()
712
- assert response.json() == {
713
- "type": "oci",
714
- "default_creds": False,
715
- "regions": None,
716
- "compartment_id": None,
717
- }
718
-
719
- @pytest.mark.asyncio
720
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
721
- async def test_returns_invalid_credentials(
722
- self, test_db, session: AsyncSession, client: AsyncClient
723
- ):
724
- user = await create_user(session=session, global_role=GlobalRole.USER)
725
- body = {
726
- "type": "oci",
727
- "creds": FAKE_OCI_CLIENT_CREDS,
728
- }
729
- with patch(
730
- "dstack._internal.core.backends.oci.auth.default_creds_available"
731
- ) as default_creds_available_mock:
732
- response = await client.post(
733
- "/api/backends/config_values",
734
- headers=get_auth_headers(user.token),
735
- json=body,
736
- )
737
- default_creds_available_mock.assert_called()
738
- assert response.status_code == 400
739
- error = response.json()["detail"][0]
740
- assert error["code"] == "invalid_credentials"
741
- assert error["msg"].startswith("Invalid credentials")
742
-
743
- @pytest.mark.asyncio
744
- @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
745
- async def test_returns_config_on_valid_creds(
746
- self, test_db, session: AsyncSession, client: AsyncClient
747
- ):
748
- user = await create_user(session=session, global_role=GlobalRole.USER)
749
- body = {
750
- "type": "oci",
751
- "creds": FAKE_OCI_CLIENT_CREDS,
752
- }
753
- with (
754
- patch(
755
- "dstack._internal.core.backends.oci.auth.default_creds_available"
756
- ) as default_creds_available_mock,
757
- patch(
758
- "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions"
759
- ) as get_regions_mock,
760
- ):
761
- default_creds_available_mock.return_value = True
762
- get_regions_mock.return_value = SAMPLE_OCI_SUBSCRIBED_REGIONS
763
- response = await client.post(
764
- "/api/backends/config_values",
765
- headers=get_auth_headers(user.token),
766
- json=body,
767
- )
768
- default_creds_available_mock.assert_called()
769
- get_regions_mock.assert_called()
770
- body = response.json()
771
- body["regions"]["selected"].sort()
772
- body["regions"]["values"].sort(key=itemgetter("value"))
773
- assert response.status_code == 200, response.json()
774
- assert body == {
775
- "type": "oci",
776
- "default_creds": True,
777
- "regions": {
778
- "selected": ["eu-frankfurt-1", "me-dubai-1"],
779
- "values": [
780
- {"label": "eu-frankfurt-1", "value": "eu-frankfurt-1"},
781
- {"label": "me-dubai-1", "value": "me-dubai-1"},
782
- ],
783
- },
784
- "compartment_id": None,
785
- }
786
-
787
-
788
73
  class TestCreateBackend:
789
74
  @pytest.mark.asyncio
790
75
  @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True)
@@ -821,13 +106,9 @@ class TestCreateBackend:
821
106
  "regions": ["us-west-1"],
822
107
  }
823
108
  with (
824
- patch(
825
- "dstack._internal.core.backends.aws.auth.default_creds_available"
826
- ) as default_creds_available_mock,
827
109
  patch("dstack._internal.core.backends.aws.auth.authenticate"),
828
110
  patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"),
829
111
  ):
830
- default_creds_available_mock.return_value = False
831
112
  response = await client.post(
832
113
  f"/api/project/{project.name}/backends/create",
833
114
  headers=get_auth_headers(user.token),
@@ -856,13 +137,9 @@ class TestCreateBackend:
856
137
  "regions": ["us-east1"],
857
138
  }
858
139
  with (
859
- patch(
860
- "dstack._internal.core.backends.gcp.auth.default_creds_available"
861
- ) as default_creds_available_mock,
862
140
  patch("dstack._internal.core.backends.gcp.auth.authenticate") as authenticate_mock,
863
141
  patch("dstack._internal.core.backends.gcp.resources.check_vpc") as check_vpc_mock,
864
142
  ):
865
- default_creds_available_mock.return_value = False
866
143
  credentials_mock = Mock()
867
144
  authenticate_mock.return_value = credentials_mock, "test_project"
868
145
  response = await client.post(
@@ -919,16 +196,12 @@ class TestCreateBackend:
919
196
  }
920
197
  with (
921
198
  patch(
922
- "dstack._internal.core.backends.oci.auth.default_creds_available"
923
- ) as default_creds_available_mock,
924
- patch(
925
- "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions"
199
+ "dstack._internal.core.backends.oci.configurator.get_subscribed_regions"
926
200
  ) as get_regions_mock,
927
201
  patch(
928
- "dstack._internal.server.services.backends.configurators.oci._create_resources"
202
+ "dstack._internal.core.backends.oci.configurator._create_resources"
929
203
  ) as create_resources_mock,
930
204
  ):
931
- default_creds_available_mock.return_value = False
932
205
  get_regions_mock.return_value = SAMPLE_OCI_SUBSCRIBED_REGIONS
933
206
  create_resources_mock.return_value = SAMPLE_OCI_COMPARTMENT_ID, SAMPLE_OCI_SUBNETS
934
207
  response = await client.post(
@@ -957,13 +230,9 @@ class TestCreateBackend:
957
230
  }
958
231
  with (
959
232
  patch(
960
- "dstack._internal.core.backends.oci.auth.default_creds_available"
961
- ) as default_creds_available_mock,
962
- patch(
963
- "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions"
233
+ "dstack._internal.core.backends.oci.configurator.get_subscribed_regions"
964
234
  ) as get_regions_mock,
965
235
  ):
966
- default_creds_available_mock.return_value = False
967
236
  # us-ashburn-1 not subscribed
968
237
  get_regions_mock.return_value = SAMPLE_OCI_SUBSCRIBED_REGIONS
969
238
  response = await client.post(
@@ -993,7 +262,7 @@ class TestCreateBackend:
993
262
  },
994
263
  "tenant_id": "test_tenant",
995
264
  "subscription_id": "test_subscription",
996
- "locations": ["eastus"],
265
+ "regions": ["eastus"],
997
266
  }
998
267
  with (
999
268
  patch("dstack._internal.core.backends.azure.auth.authenticate") as authenticate_mock,
@@ -1049,13 +318,9 @@ class TestCreateBackend:
1049
318
  "regions": ["us-west-1"],
1050
319
  }
1051
320
  with (
1052
- patch(
1053
- "dstack._internal.core.backends.aws.auth.default_creds_available"
1054
- ) as default_creds_available_mock,
1055
321
  patch("dstack._internal.core.backends.aws.auth.authenticate"),
1056
322
  patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"),
1057
323
  ):
1058
- default_creds_available_mock.return_value = False
1059
324
  response = await client.post(
1060
325
  f"/api/project/{project.name}/backends/create",
1061
326
  headers=get_auth_headers(user.token),
@@ -1065,12 +330,8 @@ class TestCreateBackend:
1065
330
  res = await session.execute(select(BackendModel))
1066
331
  assert len(res.scalars().all()) == 1
1067
332
  with (
1068
- patch(
1069
- "dstack._internal.core.backends.aws.auth.default_creds_available"
1070
- ) as default_creds_available_mock,
1071
333
  patch("dstack._internal.core.backends.aws.auth.authenticate") as authenticate_mock, # noqa: F841
1072
334
  ):
1073
- default_creds_available_mock.return_value = False
1074
335
  response = await client.post(
1075
336
  f"/api/project/{project.name}/backends/create",
1076
337
  headers=get_auth_headers(user.token),
@@ -1120,13 +381,9 @@ class TestUpdateBackend:
1120
381
  "regions": ["us-east-1"],
1121
382
  }
1122
383
  with (
1123
- patch(
1124
- "dstack._internal.core.backends.aws.auth.default_creds_available"
1125
- ) as default_creds_available_mock,
1126
384
  patch("dstack._internal.core.backends.aws.auth.authenticate"),
1127
385
  patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"),
1128
386
  ):
1129
- default_creds_available_mock.return_value = False
1130
387
  response = await client.post(
1131
388
  f"/api/project/{project.name}/backends/update",
1132
389
  headers=get_auth_headers(user.token),
@@ -1209,19 +466,16 @@ class TestDeleteBackends:
1209
466
  session=session, project=project, user=user, project_role=ProjectRole.ADMIN
1210
467
  )
1211
468
  backend = await create_backend(session=session, project_id=project.id)
1212
- pool = await create_pool(session=session, project=project)
1213
469
  fleet = await create_fleet(session=session, project=project)
1214
470
  instance1 = await create_instance(
1215
471
  session=session,
1216
472
  project=project,
1217
- pool=pool,
1218
473
  status=InstanceStatus.TERMINATED,
1219
474
  backend=backend.type,
1220
475
  )
1221
476
  instance2 = await create_instance(
1222
477
  session=session,
1223
478
  project=project,
1224
- pool=pool,
1225
479
  status=InstanceStatus.IDLE,
1226
480
  backend=backend.type,
1227
481
  )
@@ -1379,13 +633,9 @@ class TestCreateBackendYAML:
1379
633
  }
1380
634
  body = {"config_yaml": yaml.dump(config_dict)}
1381
635
  with (
1382
- patch(
1383
- "dstack._internal.core.backends.aws.auth.default_creds_available"
1384
- ) as default_creds_available_mock,
1385
636
  patch("dstack._internal.core.backends.aws.auth.authenticate"),
1386
637
  patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"),
1387
638
  ):
1388
- default_creds_available_mock.return_value = False
1389
639
  response = await client.post(
1390
640
  f"/api/project/{project.name}/backends/create_yaml",
1391
641
  headers=get_auth_headers(user.token),
@@ -1410,16 +660,12 @@ class TestCreateBackendYAML:
1410
660
  body = {"config_yaml": yaml.dump(config_dict)}
1411
661
  with (
1412
662
  patch(
1413
- "dstack._internal.core.backends.oci.auth.default_creds_available"
1414
- ) as default_creds_available_mock,
1415
- patch(
1416
- "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions"
663
+ "dstack._internal.core.backends.oci.configurator.get_subscribed_regions"
1417
664
  ) as get_regions_mock,
1418
665
  patch(
1419
- "dstack._internal.server.services.backends.configurators.oci._create_resources"
666
+ "dstack._internal.core.backends.oci.configurator._create_resources"
1420
667
  ) as create_resources_mock,
1421
668
  ):
1422
- default_creds_available_mock.return_value = False
1423
669
  get_regions_mock.return_value = SAMPLE_OCI_SUBSCRIBED_REGIONS
1424
670
  create_resources_mock.return_value = SAMPLE_OCI_COMPARTMENT_ID, SAMPLE_OCI_SUBNETS
1425
671
  response = await client.post(
@@ -1475,13 +721,9 @@ class TestUpdateBackendYAML:
1475
721
  }
1476
722
  body = {"config_yaml": yaml.dump(config_dict)}
1477
723
  with (
1478
- patch(
1479
- "dstack._internal.core.backends.aws.auth.default_creds_available"
1480
- ) as default_creds_available_mock,
1481
724
  patch("dstack._internal.core.backends.aws.auth.authenticate"),
1482
725
  patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"),
1483
726
  ):
1484
- default_creds_available_mock.return_value = False
1485
727
  response = await client.post(
1486
728
  f"/api/project/{project.name}/backends/update_yaml",
1487
729
  headers=get_auth_headers(user.token),