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,29 +1,22 @@
1
- from pathlib import Path
2
- from typing import Dict, List, Literal, Optional, Union
1
+ from typing import List, Optional
3
2
 
4
3
  import yaml
5
- from pydantic import BaseModel, Field, ValidationError, root_validator
4
+ from pydantic import Field, ValidationError
6
5
  from sqlalchemy.ext.asyncio import AsyncSession
7
6
  from typing_extensions import Annotated
8
7
 
8
+ import dstack._internal.core.backends.configurators
9
+ from dstack._internal.core.backends.models import (
10
+ AnyBackendConfigWithCreds,
11
+ AnyBackendFileConfigWithCreds,
12
+ BackendInfoYAML,
13
+ )
9
14
  from dstack._internal.core.errors import (
10
15
  BackendNotAvailable,
11
16
  ResourceNotExistsError,
12
17
  ServerClientError,
13
18
  )
14
- from dstack._internal.core.models.backends import AnyConfigInfoWithCreds, BackendInfoYAML
15
- from dstack._internal.core.models.backends.aws import AnyAWSCreds, AWSOSImageConfig
16
- from dstack._internal.core.models.backends.azure import AnyAzureCreds
17
19
  from dstack._internal.core.models.backends.base import BackendType
18
- from dstack._internal.core.models.backends.cudo import AnyCudoCreds
19
- from dstack._internal.core.models.backends.datacrunch import AnyDataCrunchCreds
20
- from dstack._internal.core.models.backends.kubernetes import KubernetesNetworkingConfig
21
- from dstack._internal.core.models.backends.lambdalabs import AnyLambdaCreds
22
- from dstack._internal.core.models.backends.oci import AnyOCICreds
23
- from dstack._internal.core.models.backends.runpod import AnyRunpodCreds
24
- from dstack._internal.core.models.backends.tensordock import AnyTensorDockCreds
25
- from dstack._internal.core.models.backends.vastai import AnyVastAICreds
26
- from dstack._internal.core.models.backends.vultr import AnyVultrCreds
27
20
  from dstack._internal.core.models.common import CoreModel
28
21
  from dstack._internal.server import settings
29
22
  from dstack._internal.server.models import ProjectModel, UserModel
@@ -36,7 +29,6 @@ from dstack._internal.server.services.permissions import (
36
29
  DefaultPermissions,
37
30
  set_default_permissions,
38
31
  )
39
- from dstack._internal.utils.common import run_async
40
32
  from dstack._internal.utils.logging import get_logger
41
33
 
42
34
  logger = get_logger(__name__)
@@ -45,7 +37,7 @@ logger = get_logger(__name__)
45
37
  # By default, PyYAML chooses the style of a collection depending on whether it has nested collections.
46
38
  # If a collection has nested collections, it will be assigned the block style. Otherwise it will have the flow style.
47
39
  #
48
- # We want mapping to always be display in block-style but lists without nested objects in flow-style.
40
+ # We want mapping to always be displayed in block-style but lists without nested objects in flow-style.
49
41
  # So we define a custom representeter
50
42
 
51
43
 
@@ -57,464 +49,15 @@ def seq_representer(dumper, sequence):
57
49
  yaml.add_representer(list, seq_representer)
58
50
 
59
51
 
60
- # Below we define pydantic models for configs allowed in server/config.yml and YAML-based API.
61
- # There are some differences between the two, e.g. server/config.yml fills file-based
62
- # credentials by looking for a file, while YAML-based API doesn't do this.
63
- # So for some backends there are two sets of config models.
64
-
65
-
66
- class AWSConfig(CoreModel):
67
- type: Annotated[Literal["aws"], Field(description="The type of the backend")] = "aws"
68
- regions: Annotated[
69
- Optional[List[str]], Field(description="The list of AWS regions. Omit to use all regions")
70
- ] = None
71
- vpc_name: Annotated[
72
- Optional[str],
73
- Field(
74
- description=(
75
- "The name of custom VPCs. All configured regions must have a VPC with this name."
76
- " If your custom VPCs don't have names or have different names in different regions, use `vpc_ids` instead."
77
- )
78
- ),
79
- ] = None
80
- vpc_ids: Annotated[
81
- Optional[Dict[str, str]],
82
- Field(
83
- description=(
84
- "The mapping from AWS regions to VPC IDs."
85
- " If `default_vpcs: true`, omitted regions will use default VPCs"
86
- )
87
- ),
88
- ] = None
89
- default_vpcs: Annotated[
90
- Optional[bool],
91
- Field(
92
- description=(
93
- "A flag to enable/disable using default VPCs in regions not configured by `vpc_ids`."
94
- " Set to `false` if default VPCs should never be used."
95
- " Defaults to `true`"
96
- )
97
- ),
98
- ] = None
99
- public_ips: Annotated[
100
- Optional[bool],
101
- Field(
102
- description=(
103
- "A flag to enable/disable public IP assigning on instances."
104
- " `public_ips: false` requires at least one private subnet with outbound internet connectivity"
105
- " provided by a NAT Gateway or a Transit Gateway."
106
- " Defaults to `true`"
107
- )
108
- ),
109
- ] = None
110
- iam_instance_profile: Annotated[
111
- Optional[str],
112
- Field(
113
- description=(
114
- "The name of the IAM instance profile to associate with EC2 instances."
115
- " You can also specify the IAM role name for roles created via the AWS console."
116
- " AWS automatically creates an instance profile and gives it the same name as the role"
117
- )
118
- ),
119
- ] = None
120
- tags: Annotated[
121
- Optional[Dict[str, str]],
122
- Field(description="The tags that will be assigned to resources created by `dstack`"),
123
- ] = None
124
- os_images: Annotated[
125
- Optional[AWSOSImageConfig],
126
- Field(
127
- description="The mapping of instance categories (CPU, NVIDIA GPU) to AMI configurations"
128
- ),
129
- ] = None
130
- creds: AnyAWSCreds = Field(..., description="The credentials", discriminator="type")
131
-
132
-
133
- class AzureConfig(CoreModel):
134
- type: Annotated[Literal["azure"], Field(description="The type of the backend")] = "azure"
135
- tenant_id: Annotated[str, Field(description="The tenant ID")]
136
- subscription_id: Annotated[str, Field(description="The subscription ID")]
137
- resource_group: Annotated[
138
- Optional[str],
139
- Field(
140
- description=(
141
- "The resource group for resources created by `dstack`."
142
- " If not specified, `dstack` will create a new resource group"
143
- )
144
- ),
145
- ] = None
146
- regions: Annotated[
147
- Optional[List[str]],
148
- Field(description="The list of Azure regions (locations). Omit to use all regions"),
149
- ] = None
150
- vpc_ids: Annotated[
151
- Optional[Dict[str, str]],
152
- Field(
153
- description=(
154
- "The mapping from configured Azure locations to network IDs."
155
- " A network ID must have a format `networkResourceGroup/networkName`"
156
- " If not specified, `dstack` will create a new network for every configured region"
157
- )
158
- ),
159
- ] = None
160
- public_ips: Annotated[
161
- Optional[bool],
162
- Field(
163
- description=(
164
- "A flag to enable/disable public IP assigning on instances."
165
- " `public_ips: false` requires `vpc_ids` that specifies custom networks with outbound internet connectivity"
166
- " provided by NAT Gateway or other mechanism."
167
- " Defaults to `true`"
168
- )
169
- ),
170
- ] = None
171
- tags: Annotated[
172
- Optional[Dict[str, str]],
173
- Field(description="The tags that will be assigned to resources created by `dstack`"),
174
- ] = None
175
- creds: AnyAzureCreds = Field(..., description="The credentials", discriminator="type")
176
-
177
-
178
- class CudoConfig(CoreModel):
179
- type: Annotated[Literal["cudo"], Field(description="The type of backend")] = "cudo"
180
- regions: Annotated[
181
- Optional[List[str]], Field(description="The list of Cudo regions. Omit to use all regions")
182
- ] = None
183
- project_id: Annotated[str, Field(description="The project ID")]
184
- creds: Annotated[AnyCudoCreds, Field(description="The credentials")]
185
-
186
-
187
- class DataCrunchConfig(CoreModel):
188
- type: Annotated[Literal["datacrunch"], Field(description="The type of backend")] = "datacrunch"
189
- regions: Annotated[
190
- Optional[List[str]],
191
- Field(description="The list of DataCrunch regions. Omit to use all regions"),
192
- ] = None
193
- creds: Annotated[AnyDataCrunchCreds, Field(description="The credentials")]
194
-
195
-
196
- class GCPServiceAccountCreds(CoreModel):
197
- type: Annotated[Literal["service_account"], Field(description="The type of credentials")] = (
198
- "service_account"
199
- )
200
- filename: Annotated[str, Field(description="The path to the service account file")]
201
- data: Annotated[
202
- Optional[str],
203
- Field(
204
- description=(
205
- "The contents of the service account file."
206
- " When configuring via `server/config.yml`, it's automatically filled from `filename`."
207
- " When configuring via UI, it has to be specified explicitly"
208
- )
209
- ),
210
- ] = None
211
-
212
- @root_validator
213
- def fill_data(cls, values):
214
- return _fill_data(values)
215
-
216
-
217
- class GCPServiceAccountAPICreds(CoreModel):
218
- type: Annotated[Literal["service_account"], Field(description="The type of credentials")] = (
219
- "service_account"
220
- )
221
- filename: Annotated[
222
- Optional[str], Field(description="The path to the service account file")
223
- ] = ""
224
- data: Annotated[str, Field(description="The contents of the service account file")]
225
-
226
-
227
- class GCPDefaultCreds(CoreModel):
228
- type: Annotated[Literal["default"], Field(description="The type of credentials")] = "default"
229
-
230
-
231
- AnyGCPCreds = Union[GCPServiceAccountCreds, GCPDefaultCreds]
232
- AnyGCPAPICreds = Union[GCPServiceAccountAPICreds, GCPDefaultCreds]
233
-
234
-
235
- class GCPConfig(CoreModel):
236
- type: Annotated[Literal["gcp"], Field(description="The type of backend")] = "gcp"
237
- project_id: Annotated[str, Field(description="The project ID")]
238
- regions: Annotated[
239
- Optional[List[str]], Field(description="The list of GCP regions. Omit to use all regions")
240
- ] = None
241
- vpc_name: Annotated[Optional[str], Field(description="The name of a custom VPC")] = None
242
- vpc_project_id: Annotated[
243
- Optional[str],
244
- Field(description="The shared VPC hosted project ID. Required for shared VPC only"),
245
- ] = None
246
- public_ips: Annotated[
247
- Optional[bool],
248
- Field(
249
- description="A flag to enable/disable public IP assigning on instances. Defaults to `true`"
250
- ),
251
- ] = None
252
- nat_check: Annotated[
253
- Optional[bool],
254
- Field(
255
- description=(
256
- "A flag to enable/disable a check that Cloud NAT is configured for the VPC."
257
- " This should be set to `false` when `public_ips: false` and outbound internet connectivity"
258
- " is provided by a mechanism other than Cloud NAT such as a third-party NAT appliance."
259
- " Defaults to `true`"
260
- )
261
- ),
262
- ] = None
263
- vm_service_account: Annotated[
264
- Optional[str], Field(description="The service account to associate with provisioned VMs")
265
- ] = None
266
- tags: Annotated[
267
- Optional[Dict[str, str]],
268
- Field(
269
- description="The tags (labels) that will be assigned to resources created by `dstack`"
270
- ),
271
- ] = None
272
- creds: AnyGCPCreds = Field(..., description="The credentials", discriminator="type")
273
-
274
-
275
- class GCPAPIConfig(CoreModel):
276
- type: Annotated[Literal["gcp"], Field(description="The type of backend")] = "gcp"
277
- project_id: Annotated[str, Field(description="The project ID")]
278
- regions: Annotated[
279
- Optional[List[str]], Field(description="The list of GCP regions. Omit to use all regions")
280
- ] = None
281
- vpc_name: Annotated[Optional[str], Field(description="The name of a custom VPC")] = None
282
- vpc_project_id: Annotated[
283
- Optional[str],
284
- Field(description="The shared VPC hosted project ID. Required for shared VPC only"),
285
- ] = None
286
- public_ips: Annotated[
287
- Optional[bool],
288
- Field(
289
- description="A flag to enable/disable public IP assigning on instances. Defaults to `true`"
290
- ),
291
- ] = None
292
- nat_check: Annotated[
293
- Optional[bool],
294
- Field(
295
- description=(
296
- "A flag to enable/disable a check that Cloud NAT is configured for the VPC."
297
- " This should be set to `false` when `public_ips: false` and outbound internet connectivity"
298
- " is provided by a mechanism other than Cloud NAT such as a third-party NAT appliance."
299
- " Defaults to `true`"
300
- )
301
- ),
302
- ] = None
303
- vm_service_account: Annotated[
304
- Optional[str], Field(description="The service account associated with provisioned VMs")
305
- ] = None
306
- tags: Annotated[
307
- Optional[Dict[str, str]],
308
- Field(
309
- description="The tags (labels) that will be assigned to resources created by `dstack`"
310
- ),
311
- ] = None
312
- creds: AnyGCPAPICreds = Field(..., description="The credentials", discriminator="type")
313
-
314
-
315
- class KubeconfigConfig(CoreModel):
316
- filename: Annotated[str, Field(description="The path to the kubeconfig file")]
317
- data: Annotated[
318
- Optional[str],
319
- Field(
320
- description=(
321
- "The contents of the kubeconfig file."
322
- " When configuring via `server/config.yml`, it's automatically filled from `filename`."
323
- " When configuring via UI, it has to be specified explicitly"
324
- )
325
- ),
326
- ] = None
327
-
328
- @root_validator
329
- def fill_data(cls, values):
330
- return _fill_data(values)
331
-
332
-
333
- class KubeconfigAPIConfig(CoreModel):
334
- filename: Annotated[str, Field(description="The path to the kubeconfig file")] = ""
335
- data: Annotated[str, Field(description="The contents of the kubeconfig file")]
336
-
337
-
338
- class KubernetesConfig(CoreModel):
339
- type: Annotated[Literal["kubernetes"], Field(description="The type of backend")] = "kubernetes"
340
- kubeconfig: Annotated[KubeconfigConfig, Field(description="The kubeconfig configuration")]
341
- networking: Annotated[
342
- Optional[KubernetesNetworkingConfig], Field(description="The networking configuration")
343
- ]
344
-
345
-
346
- class KubernetesAPIConfig(CoreModel):
347
- type: Annotated[Literal["kubernetes"], Field(description="The type of backend")] = "kubernetes"
348
- kubeconfig: Annotated[KubeconfigAPIConfig, Field(description="The kubeconfig configuration")]
349
- networking: Annotated[
350
- Optional[KubernetesNetworkingConfig], Field(description="The networking configuration")
351
- ]
352
-
353
-
354
- class LambdaConfig(CoreModel):
355
- type: Annotated[Literal["lambda"], Field(description="The type of backend")] = "lambda"
356
- regions: Annotated[
357
- Optional[List[str]],
358
- Field(description="The list of Lambda regions. Omit to use all regions"),
359
- ] = None
360
- creds: Annotated[AnyLambdaCreds, Field(description="The credentials")]
361
-
362
-
363
- class NebiusServiceAccountCreds(CoreModel):
364
- type: Annotated[Literal["service_account"], Field(description="The type of credentials")] = (
365
- "service_account"
366
- )
367
- filename: Annotated[str, Field(description="The path to the service account file")]
368
- data: Annotated[
369
- Optional[str], Field(description="The contents of the service account file")
370
- ] = None
371
-
372
- @root_validator
373
- def fill_data(cls, values):
374
- return _fill_data(values)
375
-
376
-
377
- class NebiusServiceAccountAPICreds(CoreModel):
378
- type: Annotated[Literal["service_account"], Field(description="The type of credentials")] = (
379
- "service_account"
380
- )
381
- filename: Annotated[str, Field(description="The path to the service account file")]
382
- data: Annotated[str, Field(description="The contents of the service account file")]
383
-
384
-
385
- AnyNebiusCreds = NebiusServiceAccountCreds
386
- AnyNebiusAPICreds = NebiusServiceAccountAPICreds
387
-
388
-
389
- class NebiusConfig(CoreModel):
390
- type: Literal["nebius"] = "nebius"
391
- cloud_id: str
392
- folder_id: str
393
- network_id: str
394
- regions: Optional[List[str]] = None
395
- creds: AnyNebiusCreds
396
-
397
-
398
- class NebiusAPIConfig(CoreModel):
399
- type: Literal["nebius"] = "nebius"
400
- cloud_id: str
401
- folder_id: str
402
- network_id: str
403
- regions: Optional[List[str]] = None
404
- creds: AnyNebiusAPICreds
405
-
406
-
407
- class OCIConfig(CoreModel):
408
- type: Annotated[Literal["oci"], Field(description="The type of backend")] = "oci"
409
- creds: Annotated[AnyOCICreds, Field(description="The credentials", discriminator="type")]
410
- regions: Annotated[
411
- Optional[List[str]],
412
- Field(description="The list of OCI regions. Omit to use all regions"),
413
- ] = None
414
- compartment_id: Annotated[
415
- Optional[str],
416
- Field(
417
- description=(
418
- "Compartment where `dstack` will create all resources."
419
- " Omit to instruct `dstack` to create a new compartment"
420
- )
421
- ),
422
- ] = None
423
-
424
-
425
- class RunpodConfig(CoreModel):
426
- type: Literal["runpod"] = "runpod"
427
- regions: Annotated[
428
- Optional[List[str]],
429
- Field(description="The list of RunPod regions. Omit to use all regions"),
430
- ] = None
431
- creds: Annotated[AnyRunpodCreds, Field(description="The credentials")]
432
-
433
-
434
- class TensorDockConfig(CoreModel):
435
- type: Annotated[Literal["tensordock"], Field(description="The type of backend")] = "tensordock"
436
- regions: Annotated[
437
- Optional[List[str]],
438
- Field(description="The list of TensorDock regions. Omit to use all regions"),
439
- ] = None
440
- creds: Annotated[AnyTensorDockCreds, Field(description="The credentials")]
441
-
442
-
443
- class VastAIConfig(CoreModel):
444
- type: Annotated[Literal["vastai"], Field(description="The type of backend")] = "vastai"
445
- regions: Annotated[
446
- Optional[List[str]],
447
- Field(description="The list of VastAI regions. Omit to use all regions"),
448
- ] = None
449
- creds: Annotated[AnyVastAICreds, Field(description="The credentials")]
450
-
451
-
452
- class VultrConfig(CoreModel):
453
- type: Annotated[Literal["vultr"], Field(description="The type of backend")] = "vultr"
454
- regions: Annotated[
455
- Optional[List[str]],
456
- Field(description="The list of Vultr regions. Omit to use all regions"),
457
- ] = None
458
- creds: Annotated[AnyVultrCreds, Field(description="The credentials")]
459
-
460
-
461
- class DstackConfig(CoreModel):
462
- type: Annotated[Literal["dstack"], Field(description="The type of backend")] = "dstack"
463
-
464
-
465
- AnyBackendConfig = Union[
466
- AWSConfig,
467
- AzureConfig,
468
- CudoConfig,
469
- DataCrunchConfig,
470
- GCPConfig,
471
- KubernetesConfig,
472
- LambdaConfig,
473
- NebiusConfig,
474
- OCIConfig,
475
- RunpodConfig,
476
- TensorDockConfig,
477
- VastAIConfig,
478
- VultrConfig,
479
- DstackConfig,
52
+ BackendFileConfigWithCreds = Annotated[
53
+ AnyBackendFileConfigWithCreds, Field(..., discriminator="type")
480
54
  ]
481
55
 
482
- BackendConfig = Annotated[AnyBackendConfig, Field(..., discriminator="type")]
483
-
484
-
485
- class _BackendConfig(BaseModel):
486
- __root__: BackendConfig
487
-
488
-
489
- AnyBackendAPIConfig = Union[
490
- AWSConfig,
491
- AzureConfig,
492
- CudoConfig,
493
- DataCrunchConfig,
494
- GCPAPIConfig,
495
- KubernetesAPIConfig,
496
- LambdaConfig,
497
- NebiusAPIConfig,
498
- OCIConfig,
499
- RunpodConfig,
500
- TensorDockConfig,
501
- VastAIConfig,
502
- VultrConfig,
503
- DstackConfig,
504
- ]
505
-
506
-
507
- BackendAPIConfig = Annotated[AnyBackendAPIConfig, Field(..., discriminator="type")]
508
-
509
-
510
- class _BackendAPIConfig(CoreModel):
511
- __root__: BackendAPIConfig
512
-
513
56
 
514
57
  class ProjectConfig(CoreModel):
515
58
  name: Annotated[str, Field(description="The name of the project")]
516
59
  backends: Annotated[
517
- Optional[List[BackendConfig]], Field(description="The list of backends")
60
+ Optional[List[BackendFileConfigWithCreds]], Field(description="The list of backends")
518
61
  ] = None
519
62
 
520
63
 
@@ -545,19 +88,13 @@ class ServerConfigManager:
545
88
  Initializes the default server/config.yml.
546
89
  The default config is empty or contains an existing `main` project config.
547
90
  """
548
- # The backends auto init feature via default creds is currently disabled
549
- # so that the backend configuration is always explicit.
550
- # Details: https://github.com/dstackai/dstack/issues/1384
551
- self.config = await self._init_config(session=session, init_backends=False)
91
+ self.config = await self._init_config(session)
552
92
  if self.config is not None:
553
93
  self._save_config(self.config)
554
94
 
555
95
  async def sync_config(self, session: AsyncSession):
556
96
  # Disable config.yml sync for https://github.com/dstackai/dstack/issues/815.
557
97
  return
558
- # self.config = await self._init_config(session=session, init_backends=False)
559
- # if self.config is not None:
560
- # self._save_config(self.config)
561
98
 
562
99
  async def apply_encryption(self):
563
100
  if self.config is None:
@@ -593,13 +130,15 @@ class ServerConfigManager:
593
130
  project = await projects_services.get_project_model_by_name_or_error(
594
131
  session=session, project_name=project_config.name
595
132
  )
596
- backends_to_delete = set(backends_services.list_available_backend_types())
597
- for backend_config in project_config.backends or []:
598
- config_info = config_to_internal_config(backend_config)
599
- backend_type = BackendType(config_info.type)
133
+ backends_to_delete = set(
134
+ dstack._internal.core.backends.configurators.list_available_backend_types()
135
+ )
136
+ for backend_file_config in project_config.backends or []:
137
+ backend_config = file_config_to_config(backend_file_config)
138
+ backend_type = BackendType(backend_config.type)
600
139
  backends_to_delete.difference_update([backend_type])
601
140
  try:
602
- current_config_info = await backends_services.get_config_info(
141
+ current_backend_config = await backends_services.get_backend_config(
603
142
  project=project,
604
143
  backend_type=backend_type,
605
144
  )
@@ -610,23 +149,23 @@ class ServerConfigManager:
610
149
  backend_type.value,
611
150
  )
612
151
  continue
613
- if config_info == current_config_info:
152
+ if backend_config == current_backend_config:
614
153
  continue
615
154
  backend_exists = any(backend_type == b.type for b in project.backends)
616
155
  try:
617
- # current_config_info may be None if backend exists
156
+ # current_backend_config may be None if backend exists
618
157
  # but it's config is invalid (e.g. cannot be decrypted).
619
158
  # Update backend in this case.
620
- if current_config_info is None and not backend_exists:
159
+ if current_backend_config is None and not backend_exists:
621
160
  await backends_services.create_backend(
622
- session=session, project=project, config=config_info
161
+ session=session, project=project, config=backend_config
623
162
  )
624
163
  else:
625
164
  await backends_services.update_backend(
626
- session=session, project=project, config=config_info
165
+ session=session, project=project, config=backend_config
627
166
  )
628
167
  except Exception as e:
629
- logger.warning("Failed to configure backend %s: %s", config_info.type, e)
168
+ logger.warning("Failed to configure backend %s: %s", backend_config.type, e)
630
169
  await delete_backends_safe(
631
170
  session=session,
632
171
  project=project,
@@ -634,9 +173,7 @@ class ServerConfigManager:
634
173
  error=False,
635
174
  )
636
175
 
637
- async def _init_config(
638
- self, session: AsyncSession, init_backends: bool
639
- ) -> Optional[ServerConfig]:
176
+ async def _init_config(self, session: AsyncSession) -> Optional[ServerConfig]:
640
177
  project = await projects_services.get_project_model_by_name(
641
178
  session=session,
642
179
  project_name=settings.DEFAULT_PROJECT_NAME,
@@ -646,40 +183,20 @@ class ServerConfigManager:
646
183
  # Force project reload to reflect updates when syncing
647
184
  await session.refresh(project)
648
185
  backends = []
649
- for backend_type in backends_services.list_available_backend_types():
650
- config_info = await backends_services.get_config_info(
186
+ for (
187
+ backend_type
188
+ ) in dstack._internal.core.backends.configurators.list_available_backend_types():
189
+ backend_config = await backends_services.get_backend_config(
651
190
  project=project, backend_type=backend_type
652
191
  )
653
- if config_info is not None:
654
- backends.append(internal_config_to_config(config_info))
655
- if init_backends and len(backends) == 0:
656
- backends = await self._init_backends(session=session, project=project)
192
+ if backend_config is not None:
193
+ backends.append(backend_config)
657
194
  return ServerConfig(
658
195
  projects=[ProjectConfig(name=settings.DEFAULT_PROJECT_NAME, backends=backends)],
659
196
  encryption=EncryptionConfig(keys=[]),
660
197
  default_permissions=None,
661
198
  )
662
199
 
663
- async def _init_backends(
664
- self, session: AsyncSession, project: ProjectModel
665
- ) -> List[BackendConfig]:
666
- backends = []
667
- for backend_type in backends_services.list_available_backend_types():
668
- configurator = backends_services.get_configurator(backend_type)
669
- if configurator is None:
670
- continue
671
- config_infos = await run_async(configurator.get_default_configs)
672
- for config_info in config_infos:
673
- try:
674
- await backends_services.create_backend(
675
- session=session, project=project, config=config_info
676
- )
677
- backends.append(internal_config_to_config(config_info))
678
- break
679
- except Exception as e:
680
- logger.debug("Failed to configure backend %s: %s", config_info.type, e)
681
- return backends
682
-
683
200
  def _load_config(self) -> Optional[ServerConfig]:
684
201
  try:
685
202
  with open(settings.SERVER_CONFIG_FILE_PATH) as f:
@@ -697,13 +214,12 @@ class ServerConfigManager:
697
214
  async def get_backend_config_yaml(
698
215
  project: ProjectModel, backend_type: BackendType
699
216
  ) -> BackendInfoYAML:
700
- config_info = await backends_services.get_config_info(
217
+ backend_config = await backends_services.get_backend_config(
701
218
  project=project, backend_type=backend_type
702
219
  )
703
- if config_info is None:
220
+ if backend_config is None:
704
221
  raise ResourceNotExistsError()
705
- config = internal_config_to_config(config_info)
706
- config_yaml = config_to_yaml(config)
222
+ config_yaml = config_to_yaml(backend_config)
707
223
  return BackendInfoYAML(
708
224
  name=backend_type,
709
225
  config_yaml=config_yaml,
@@ -715,9 +231,8 @@ async def create_backend_config_yaml(
715
231
  project: ProjectModel,
716
232
  config_yaml: str,
717
233
  ):
718
- backend_config = config_yaml_to_backend_config(config_yaml)
719
- config_info = config_to_internal_config(backend_config)
720
- await backends_services.create_backend(session=session, project=project, config=config_info)
234
+ config = config_yaml_to_backend_config(config_yaml)
235
+ await backends_services.create_backend(session=session, project=project, config=config)
721
236
 
722
237
 
723
238
  async def update_backend_config_yaml(
@@ -725,64 +240,35 @@ async def update_backend_config_yaml(
725
240
  project: ProjectModel,
726
241
  config_yaml: str,
727
242
  ):
728
- backend_config = config_yaml_to_backend_config(config_yaml)
729
- config_info = config_to_internal_config(backend_config)
730
- await backends_services.update_backend(session=session, project=project, config=config_info)
731
-
732
-
733
- server_config_manager = ServerConfigManager()
734
-
735
-
736
- def internal_config_to_config(config_info: AnyConfigInfoWithCreds) -> BackendConfig:
737
- backend_config = _BackendConfig.parse_obj(config_info.dict(exclude={"locations"}))
738
- if config_info.type == "azure":
739
- backend_config.__root__.regions = config_info.locations
740
- return backend_config.__root__
741
-
243
+ config = config_yaml_to_backend_config(config_yaml)
244
+ await backends_services.update_backend(session=session, project=project, config=config)
742
245
 
743
- class _ConfigInfoWithCreds(CoreModel):
744
- __root__: Annotated[AnyConfigInfoWithCreds, Field(..., discriminator="type")]
745
246
 
247
+ class _BackendConfigWithCreds(CoreModel):
248
+ """
249
+ Model for parsing API and file YAML configs.
250
+ """
746
251
 
747
- def config_to_internal_config(
748
- backend_config: Union[BackendConfig, BackendAPIConfig],
749
- ) -> AnyConfigInfoWithCreds:
750
- backend_config_dict = backend_config.dict()
751
- # Allow to not specify networking
752
- if backend_config.type == "kubernetes":
753
- if backend_config.networking is None:
754
- backend_config_dict["networking"] = {}
755
- if backend_config.type == "azure":
756
- backend_config_dict["locations"] = backend_config_dict["regions"]
757
- del backend_config_dict["regions"]
758
- config_info = _ConfigInfoWithCreds.parse_obj(backend_config_dict)
759
- return config_info.__root__
252
+ __root__: Annotated[AnyBackendConfigWithCreds, Field(..., discriminator="type")]
760
253
 
761
254
 
762
- def config_yaml_to_backend_config(config_yaml: str) -> BackendAPIConfig:
255
+ def config_yaml_to_backend_config(config_yaml: str) -> AnyBackendConfigWithCreds:
763
256
  try:
764
257
  config_dict = yaml.load(config_yaml, yaml.FullLoader)
765
258
  except yaml.YAMLError:
766
259
  raise ServerClientError("Error parsing YAML")
767
260
  try:
768
- backend_config = _BackendAPIConfig.parse_obj(config_dict).__root__
261
+ backend_config = _BackendConfigWithCreds.parse_obj(config_dict).__root__
769
262
  except ValidationError as e:
770
263
  raise ServerClientError(str(e))
771
264
  return backend_config
772
265
 
773
266
 
774
- def config_to_yaml(config: CoreModel) -> str:
775
- return yaml.dump(config.dict(exclude_none=True), sort_keys=False)
267
+ def file_config_to_config(file_config: AnyBackendFileConfigWithCreds) -> AnyBackendConfigWithCreds:
268
+ backend_config_dict = file_config.dict()
269
+ backend_config = _BackendConfigWithCreds.parse_obj(backend_config_dict)
270
+ return backend_config.__root__
776
271
 
777
272
 
778
- def _fill_data(values: dict):
779
- if values.get("data") is not None:
780
- return values
781
- if "filename" not in values:
782
- raise ValueError()
783
- try:
784
- with open(Path(values["filename"]).expanduser()) as f:
785
- values["data"] = f.read()
786
- except OSError:
787
- raise ValueError(f"No such file {values['filename']}")
788
- return values
273
+ def config_to_yaml(config: CoreModel) -> str:
274
+ return yaml.dump(config.dict(exclude_none=True), sort_keys=False)