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.
- dstack/_internal/cli/commands/gateway.py +15 -3
- dstack/_internal/cli/commands/logs.py +0 -22
- dstack/_internal/cli/commands/stats.py +8 -17
- dstack/_internal/cli/main.py +1 -5
- dstack/_internal/cli/services/configurators/fleet.py +4 -39
- dstack/_internal/cli/services/configurators/run.py +22 -20
- dstack/_internal/cli/services/profile.py +34 -83
- dstack/_internal/cli/utils/gateway.py +1 -1
- dstack/_internal/cli/utils/run.py +11 -0
- dstack/_internal/core/backends/__init__.py +56 -39
- dstack/_internal/core/backends/aws/__init__.py +0 -25
- dstack/_internal/core/backends/aws/auth.py +1 -10
- dstack/_internal/core/backends/aws/backend.py +26 -0
- dstack/_internal/core/backends/aws/compute.py +21 -45
- dstack/_internal/{server/services/backends/configurators/aws.py → core/backends/aws/configurator.py} +46 -85
- dstack/_internal/core/backends/aws/models.py +135 -0
- dstack/_internal/core/backends/aws/resources.py +1 -1
- dstack/_internal/core/backends/azure/__init__.py +0 -20
- dstack/_internal/core/backends/azure/auth.py +2 -11
- dstack/_internal/core/backends/azure/backend.py +21 -0
- dstack/_internal/core/backends/azure/compute.py +14 -28
- dstack/_internal/{server/services/backends/configurators/azure.py → core/backends/azure/configurator.py} +141 -210
- dstack/_internal/core/backends/azure/models.py +89 -0
- dstack/_internal/core/backends/base/__init__.py +0 -12
- dstack/_internal/core/backends/base/backend.py +18 -0
- dstack/_internal/core/backends/base/compute.py +153 -33
- dstack/_internal/core/backends/base/configurator.py +105 -0
- dstack/_internal/core/backends/base/models.py +14 -0
- dstack/_internal/core/backends/configurators.py +138 -0
- dstack/_internal/core/backends/cudo/__init__.py +0 -15
- dstack/_internal/core/backends/cudo/backend.py +16 -0
- dstack/_internal/core/backends/cudo/compute.py +8 -26
- dstack/_internal/core/backends/cudo/configurator.py +72 -0
- dstack/_internal/core/backends/cudo/models.py +37 -0
- dstack/_internal/core/backends/datacrunch/__init__.py +0 -15
- dstack/_internal/core/backends/datacrunch/backend.py +16 -0
- dstack/_internal/core/backends/datacrunch/compute.py +8 -25
- dstack/_internal/core/backends/datacrunch/configurator.py +66 -0
- dstack/_internal/core/backends/datacrunch/models.py +38 -0
- dstack/_internal/core/{models/backends/dstack.py → backends/dstack/models.py} +7 -7
- dstack/_internal/core/backends/gcp/__init__.py +0 -16
- dstack/_internal/core/backends/gcp/auth.py +2 -11
- dstack/_internal/core/backends/gcp/backend.py +17 -0
- dstack/_internal/core/backends/gcp/compute.py +14 -44
- dstack/_internal/{server/services/backends/configurators/gcp.py → core/backends/gcp/configurator.py} +46 -103
- dstack/_internal/core/backends/gcp/models.py +125 -0
- dstack/_internal/core/backends/kubernetes/__init__.py +0 -15
- dstack/_internal/core/backends/kubernetes/backend.py +16 -0
- dstack/_internal/core/backends/kubernetes/compute.py +16 -5
- dstack/_internal/core/backends/kubernetes/configurator.py +55 -0
- dstack/_internal/core/backends/kubernetes/models.py +72 -0
- dstack/_internal/core/backends/lambdalabs/__init__.py +0 -16
- dstack/_internal/core/backends/lambdalabs/backend.py +17 -0
- dstack/_internal/core/backends/lambdalabs/compute.py +7 -28
- dstack/_internal/core/backends/lambdalabs/configurator.py +82 -0
- dstack/_internal/core/backends/lambdalabs/models.py +37 -0
- dstack/_internal/core/backends/local/__init__.py +0 -13
- dstack/_internal/core/backends/local/backend.py +14 -0
- dstack/_internal/core/backends/local/compute.py +16 -2
- dstack/_internal/core/backends/models.py +128 -0
- dstack/_internal/core/backends/oci/__init__.py +0 -15
- dstack/_internal/core/backends/oci/auth.py +1 -5
- dstack/_internal/core/backends/oci/backend.py +16 -0
- dstack/_internal/core/backends/oci/compute.py +9 -23
- dstack/_internal/{server/services/backends/configurators/oci.py → core/backends/oci/configurator.py} +40 -85
- dstack/_internal/core/{models/backends/oci.py → backends/oci/models.py} +24 -25
- dstack/_internal/core/backends/oci/region.py +1 -1
- dstack/_internal/core/backends/runpod/__init__.py +0 -15
- dstack/_internal/core/backends/runpod/backend.py +16 -0
- dstack/_internal/core/backends/runpod/compute.py +28 -6
- dstack/_internal/core/backends/runpod/configurator.py +59 -0
- dstack/_internal/core/backends/runpod/models.py +54 -0
- dstack/_internal/core/backends/template/__init__.py +0 -0
- dstack/_internal/core/backends/tensordock/__init__.py +0 -15
- dstack/_internal/core/backends/tensordock/backend.py +16 -0
- dstack/_internal/core/backends/tensordock/compute.py +8 -27
- dstack/_internal/core/backends/tensordock/configurator.py +68 -0
- dstack/_internal/core/backends/tensordock/models.py +38 -0
- dstack/_internal/core/backends/vastai/__init__.py +0 -15
- dstack/_internal/core/backends/vastai/backend.py +16 -0
- dstack/_internal/core/backends/vastai/compute.py +2 -2
- dstack/_internal/core/backends/vastai/configurator.py +66 -0
- dstack/_internal/core/backends/vastai/models.py +37 -0
- dstack/_internal/core/backends/vultr/__init__.py +0 -15
- dstack/_internal/core/backends/vultr/backend.py +16 -0
- dstack/_internal/core/backends/vultr/compute.py +10 -24
- dstack/_internal/core/backends/vultr/configurator.py +64 -0
- dstack/_internal/core/backends/vultr/models.py +34 -0
- dstack/_internal/core/models/backends/__init__.py +0 -184
- dstack/_internal/core/models/backends/base.py +0 -19
- dstack/_internal/core/models/configurations.py +22 -16
- dstack/_internal/core/models/envs.py +4 -3
- dstack/_internal/core/models/fleets.py +17 -22
- dstack/_internal/core/models/gateways.py +3 -3
- dstack/_internal/core/models/instances.py +24 -0
- dstack/_internal/core/models/profiles.py +85 -45
- dstack/_internal/core/models/projects.py +1 -1
- dstack/_internal/core/models/repos/base.py +0 -5
- dstack/_internal/core/models/repos/local.py +3 -3
- dstack/_internal/core/models/repos/remote.py +26 -12
- dstack/_internal/core/models/repos/virtual.py +1 -1
- dstack/_internal/core/models/resources.py +45 -76
- dstack/_internal/core/models/runs.py +21 -19
- dstack/_internal/core/models/volumes.py +1 -3
- dstack/_internal/core/services/profiles.py +7 -16
- dstack/_internal/core/services/repos.py +0 -4
- dstack/_internal/server/app.py +11 -4
- dstack/_internal/server/background/__init__.py +10 -0
- dstack/_internal/server/background/tasks/process_gateways.py +4 -8
- dstack/_internal/server/background/tasks/process_instances.py +14 -9
- dstack/_internal/server/background/tasks/process_metrics.py +1 -1
- dstack/_internal/server/background/tasks/process_placement_groups.py +5 -1
- dstack/_internal/server/background/tasks/process_prometheus_metrics.py +135 -0
- dstack/_internal/server/background/tasks/process_running_jobs.py +80 -24
- dstack/_internal/server/background/tasks/process_runs.py +1 -0
- dstack/_internal/server/background/tasks/process_submitted_jobs.py +20 -38
- dstack/_internal/server/background/tasks/process_volumes.py +5 -2
- dstack/_internal/server/migrations/versions/60e444118b6d_add_jobprometheusmetrics.py +40 -0
- dstack/_internal/server/migrations/versions/7bc2586e8b9e_make_instancemodel_pool_id_optional.py +36 -0
- dstack/_internal/server/migrations/versions/98d1b92988bc_add_jobterminationreason_terminated_due_.py +140 -0
- dstack/_internal/server/migrations/versions/bc8ca4a505c6_store_backendtype_as_string.py +171 -0
- dstack/_internal/server/models.py +59 -9
- dstack/_internal/server/routers/backends.py +14 -23
- dstack/_internal/server/routers/instances.py +3 -4
- dstack/_internal/server/routers/metrics.py +31 -10
- dstack/_internal/server/routers/prometheus.py +36 -0
- dstack/_internal/server/routers/repos.py +1 -2
- dstack/_internal/server/routers/runs.py +13 -59
- dstack/_internal/server/schemas/gateways.py +14 -23
- dstack/_internal/server/schemas/projects.py +7 -2
- dstack/_internal/server/schemas/repos.py +2 -38
- dstack/_internal/server/schemas/runner.py +1 -0
- dstack/_internal/server/schemas/runs.py +1 -24
- dstack/_internal/server/security/permissions.py +1 -1
- dstack/_internal/server/services/backends/__init__.py +85 -158
- dstack/_internal/server/services/config.py +53 -567
- dstack/_internal/server/services/fleets.py +9 -103
- dstack/_internal/server/services/gateways/__init__.py +13 -4
- dstack/_internal/server/services/{pools.py → instances.py} +22 -329
- dstack/_internal/server/services/jobs/__init__.py +9 -6
- dstack/_internal/server/services/jobs/configurators/base.py +25 -1
- dstack/_internal/server/services/jobs/configurators/dev.py +9 -1
- dstack/_internal/server/services/jobs/configurators/extensions/cursor.py +42 -0
- dstack/_internal/server/services/metrics.py +131 -72
- dstack/_internal/server/services/offers.py +1 -1
- dstack/_internal/server/services/projects.py +23 -14
- dstack/_internal/server/services/prometheus.py +245 -0
- dstack/_internal/server/services/runner/client.py +14 -3
- dstack/_internal/server/services/runs.py +67 -31
- dstack/_internal/server/services/volumes.py +9 -4
- dstack/_internal/server/settings.py +3 -0
- dstack/_internal/server/statics/index.html +1 -1
- dstack/_internal/server/statics/{main-fe8fd9db55df8d10e648.js → main-4fd5a4770eff59325ee3.js} +68 -15
- dstack/_internal/server/statics/{main-fe8fd9db55df8d10e648.js.map → main-4fd5a4770eff59325ee3.js.map} +1 -1
- dstack/_internal/server/statics/{main-7510e71dfa9749a4e70e.css → main-da9f8c06a69c20dac23e.css} +1 -1
- dstack/_internal/server/statics/static/media/entraID.d65d1f3e9486a8e56d24fc07b3230885.svg +9 -0
- dstack/_internal/server/testing/common.py +75 -32
- dstack/_internal/utils/json_schema.py +6 -0
- dstack/_internal/utils/ssh.py +2 -1
- dstack/api/__init__.py +4 -0
- dstack/api/_public/__init__.py +16 -20
- dstack/api/_public/backends.py +1 -1
- dstack/api/_public/repos.py +36 -36
- dstack/api/_public/runs.py +170 -83
- dstack/api/server/__init__.py +11 -13
- dstack/api/server/_backends.py +12 -16
- dstack/api/server/_fleets.py +15 -55
- dstack/api/server/_gateways.py +3 -14
- dstack/api/server/_repos.py +1 -4
- dstack/api/server/_runs.py +21 -96
- dstack/api/server/_volumes.py +10 -5
- dstack/api/utils.py +3 -0
- dstack/version.py +1 -1
- {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/METADATA +10 -1
- {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/RECORD +229 -206
- tests/_internal/cli/services/configurators/test_profile.py +6 -6
- tests/_internal/core/backends/aws/test_configurator.py +35 -0
- tests/_internal/core/backends/aws/test_resources.py +1 -1
- tests/_internal/core/backends/azure/test_configurator.py +61 -0
- tests/_internal/core/backends/cudo/__init__.py +0 -0
- tests/_internal/core/backends/cudo/test_configurator.py +37 -0
- tests/_internal/core/backends/datacrunch/__init__.py +0 -0
- tests/_internal/core/backends/datacrunch/test_configurator.py +17 -0
- tests/_internal/core/backends/gcp/test_configurator.py +42 -0
- tests/_internal/core/backends/kubernetes/test_configurator.py +43 -0
- tests/_internal/core/backends/lambdalabs/__init__.py +0 -0
- tests/_internal/core/backends/lambdalabs/test_configurator.py +38 -0
- tests/_internal/core/backends/oci/test_configurator.py +55 -0
- tests/_internal/core/backends/runpod/__init__.py +0 -0
- tests/_internal/core/backends/runpod/test_configurator.py +33 -0
- tests/_internal/core/backends/tensordock/__init__.py +0 -0
- tests/_internal/core/backends/tensordock/test_configurator.py +38 -0
- tests/_internal/core/backends/vastai/__init__.py +0 -0
- tests/_internal/core/backends/vastai/test_configurator.py +33 -0
- tests/_internal/core/backends/vultr/__init__.py +0 -0
- tests/_internal/core/backends/vultr/test_configurator.py +33 -0
- tests/_internal/server/background/tasks/test_process_gateways.py +4 -0
- tests/_internal/server/background/tasks/test_process_instances.py +49 -48
- tests/_internal/server/background/tasks/test_process_metrics.py +0 -3
- tests/_internal/server/background/tasks/test_process_placement_groups.py +2 -0
- tests/_internal/server/background/tasks/test_process_prometheus_metrics.py +186 -0
- tests/_internal/server/background/tasks/test_process_running_jobs.py +123 -19
- tests/_internal/server/background/tasks/test_process_runs.py +8 -22
- tests/_internal/server/background/tasks/test_process_submitted_jobs.py +3 -40
- tests/_internal/server/background/tasks/test_process_submitted_volumes.py +2 -0
- tests/_internal/server/background/tasks/test_process_terminating_jobs.py +10 -15
- tests/_internal/server/routers/test_backends.py +6 -764
- tests/_internal/server/routers/test_fleets.py +2 -26
- tests/_internal/server/routers/test_gateways.py +27 -3
- tests/_internal/server/routers/test_instances.py +0 -10
- tests/_internal/server/routers/test_metrics.py +42 -0
- tests/_internal/server/routers/test_projects.py +56 -0
- tests/_internal/server/routers/test_prometheus.py +333 -0
- tests/_internal/server/routers/test_repos.py +0 -15
- tests/_internal/server/routers/test_runs.py +83 -275
- tests/_internal/server/routers/test_volumes.py +2 -3
- tests/_internal/server/services/backends/__init__.py +0 -0
- tests/_internal/server/services/jobs/configurators/test_task.py +35 -0
- tests/_internal/server/services/test_config.py +7 -4
- tests/_internal/server/services/test_fleets.py +1 -4
- tests/_internal/server/services/{test_pools.py → test_instances.py} +11 -49
- tests/_internal/server/services/test_metrics.py +167 -0
- tests/_internal/server/services/test_repos.py +1 -14
- tests/_internal/server/services/test_runs.py +0 -4
- dstack/_internal/cli/commands/pool.py +0 -581
- dstack/_internal/cli/commands/run.py +0 -75
- dstack/_internal/core/backends/aws/config.py +0 -18
- dstack/_internal/core/backends/azure/config.py +0 -12
- dstack/_internal/core/backends/base/config.py +0 -5
- dstack/_internal/core/backends/cudo/config.py +0 -9
- dstack/_internal/core/backends/datacrunch/config.py +0 -9
- dstack/_internal/core/backends/gcp/config.py +0 -22
- dstack/_internal/core/backends/kubernetes/config.py +0 -6
- dstack/_internal/core/backends/lambdalabs/config.py +0 -9
- dstack/_internal/core/backends/nebius/__init__.py +0 -15
- dstack/_internal/core/backends/nebius/api_client.py +0 -319
- dstack/_internal/core/backends/nebius/compute.py +0 -220
- dstack/_internal/core/backends/nebius/config.py +0 -6
- dstack/_internal/core/backends/nebius/types.py +0 -37
- dstack/_internal/core/backends/oci/config.py +0 -6
- dstack/_internal/core/backends/runpod/config.py +0 -9
- dstack/_internal/core/backends/tensordock/config.py +0 -9
- dstack/_internal/core/backends/vastai/config.py +0 -6
- dstack/_internal/core/backends/vultr/config.py +0 -9
- dstack/_internal/core/models/backends/aws.py +0 -86
- dstack/_internal/core/models/backends/azure.py +0 -68
- dstack/_internal/core/models/backends/cudo.py +0 -43
- dstack/_internal/core/models/backends/datacrunch.py +0 -44
- dstack/_internal/core/models/backends/gcp.py +0 -67
- dstack/_internal/core/models/backends/kubernetes.py +0 -40
- dstack/_internal/core/models/backends/lambdalabs.py +0 -43
- dstack/_internal/core/models/backends/nebius.py +0 -54
- dstack/_internal/core/models/backends/runpod.py +0 -40
- dstack/_internal/core/models/backends/tensordock.py +0 -44
- dstack/_internal/core/models/backends/vastai.py +0 -43
- dstack/_internal/core/models/backends/vultr.py +0 -40
- dstack/_internal/core/models/pools.py +0 -43
- dstack/_internal/server/routers/pools.py +0 -142
- dstack/_internal/server/schemas/pools.py +0 -38
- dstack/_internal/server/services/backends/configurators/base.py +0 -72
- dstack/_internal/server/services/backends/configurators/cudo.py +0 -87
- dstack/_internal/server/services/backends/configurators/datacrunch.py +0 -79
- dstack/_internal/server/services/backends/configurators/kubernetes.py +0 -63
- dstack/_internal/server/services/backends/configurators/lambdalabs.py +0 -98
- dstack/_internal/server/services/backends/configurators/nebius.py +0 -85
- dstack/_internal/server/services/backends/configurators/runpod.py +0 -97
- dstack/_internal/server/services/backends/configurators/tensordock.py +0 -82
- dstack/_internal/server/services/backends/configurators/vastai.py +0 -80
- dstack/_internal/server/services/backends/configurators/vultr.py +0 -80
- dstack/api/_public/pools.py +0 -41
- dstack/api/_public/resources.py +0 -105
- dstack/api/server/_pools.py +0 -63
- tests/_internal/server/routers/test_pools.py +0 -612
- /dstack/_internal/{server/services/backends/configurators → core/backends/dstack}/__init__.py +0 -0
- {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/LICENSE.md +0 -0
- {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/WHEEL +0 -0
- {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/entry_points.txt +0 -0
- {dstack-0.18.43.dist-info → dstack-0.19.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -5,7 +5,7 @@ from dstack._internal.cli.services.profile import (
|
|
|
5
5
|
apply_profile_args,
|
|
6
6
|
register_profile_args,
|
|
7
7
|
)
|
|
8
|
-
from dstack._internal.core.models.profiles import Profile,
|
|
8
|
+
from dstack._internal.core.models.profiles import Profile, ProfileRetry, SpotPolicy
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class TestProfileArgs:
|
|
@@ -51,21 +51,21 @@ class TestProfileArgs:
|
|
|
51
51
|
assert profile.dict() == modified.dict()
|
|
52
52
|
|
|
53
53
|
def test_retry(self):
|
|
54
|
-
profile = Profile(name="test")
|
|
55
|
-
profile.retry_policy = ProfileRetryPolicy(retry=True)
|
|
54
|
+
profile = Profile(name="test", retry=None)
|
|
56
55
|
modified, _ = apply_args(profile, ["--retry"])
|
|
56
|
+
profile.retry = True
|
|
57
57
|
assert profile.dict() == modified.dict()
|
|
58
58
|
|
|
59
59
|
def test_no_retry(self):
|
|
60
|
-
profile = Profile(name="test",
|
|
60
|
+
profile = Profile(name="test", retry=None)
|
|
61
61
|
modified, _ = apply_args(profile, ["--no-retry"])
|
|
62
|
-
profile.
|
|
62
|
+
profile.retry = False
|
|
63
63
|
assert profile.dict() == modified.dict()
|
|
64
64
|
|
|
65
65
|
def test_retry_duration(self):
|
|
66
66
|
profile = Profile(name="test")
|
|
67
67
|
modified, _ = apply_args(profile, ["--retry-duration", "1h"])
|
|
68
|
-
profile.
|
|
68
|
+
profile.retry = ProfileRetry(on_events=None, duration="1h")
|
|
69
69
|
assert profile.dict() == modified.dict()
|
|
70
70
|
|
|
71
71
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.backends.aws.configurator import AWSConfigurator
|
|
6
|
+
from dstack._internal.core.backends.aws.models import AWSAccessKeyCreds, AWSBackendConfigWithCreds
|
|
7
|
+
from dstack._internal.core.errors import (
|
|
8
|
+
BackendAuthError,
|
|
9
|
+
BackendInvalidCredentialsError,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestAWSConfigurator:
|
|
14
|
+
def test_validate_config_valid(self):
|
|
15
|
+
config = AWSBackendConfigWithCreds(
|
|
16
|
+
creds=AWSAccessKeyCreds(access_key="valid", secret_key="valid"), regions=["us-west-1"]
|
|
17
|
+
)
|
|
18
|
+
with (
|
|
19
|
+
patch("dstack._internal.core.backends.aws.auth.authenticate"),
|
|
20
|
+
patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"),
|
|
21
|
+
):
|
|
22
|
+
AWSConfigurator().validate_config(config, default_creds_enabled=True)
|
|
23
|
+
|
|
24
|
+
def test_validate_config_invalid_creds(self):
|
|
25
|
+
config = AWSBackendConfigWithCreds(
|
|
26
|
+
creds=AWSAccessKeyCreds(access_key="invalid", secret_key="invalid"),
|
|
27
|
+
regions=["us-west-1"],
|
|
28
|
+
)
|
|
29
|
+
with (
|
|
30
|
+
patch("dstack._internal.core.backends.aws.auth.authenticate") as authenticate_mock,
|
|
31
|
+
pytest.raises(BackendInvalidCredentialsError) as exc_info,
|
|
32
|
+
):
|
|
33
|
+
authenticate_mock.side_effect = BackendAuthError()
|
|
34
|
+
AWSConfigurator().validate_config(config, default_creds_enabled=True)
|
|
35
|
+
assert exc_info.value.fields == [["creds", "access_key"], ["creds", "secret_key"]]
|
|
@@ -3,6 +3,7 @@ from unittest.mock import Mock
|
|
|
3
3
|
|
|
4
4
|
import pytest
|
|
5
5
|
|
|
6
|
+
from dstack._internal.core.backends.aws.models import AWSOSImage, AWSOSImageConfig
|
|
6
7
|
from dstack._internal.core.backends.aws.resources import (
|
|
7
8
|
_is_valid_tag_key,
|
|
8
9
|
_is_valid_tag_value,
|
|
@@ -10,7 +11,6 @@ from dstack._internal.core.backends.aws.resources import (
|
|
|
10
11
|
validate_tags,
|
|
11
12
|
)
|
|
12
13
|
from dstack._internal.core.errors import BackendError, ComputeResourceNotFoundError
|
|
13
|
-
from dstack._internal.core.models.backends.aws import AWSOSImage, AWSOSImageConfig
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class TestIsValidTagKey:
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from unittest.mock import Mock, patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.backends.azure.configurator import AzureConfigurator
|
|
6
|
+
from dstack._internal.core.backends.azure.models import (
|
|
7
|
+
AzureBackendConfigWithCreds,
|
|
8
|
+
AzureClientCreds,
|
|
9
|
+
)
|
|
10
|
+
from dstack._internal.core.errors import (
|
|
11
|
+
BackendAuthError,
|
|
12
|
+
BackendInvalidCredentialsError,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestAzureConfigurator:
|
|
17
|
+
def test_validate_config_valid(self):
|
|
18
|
+
config = AzureBackendConfigWithCreds(
|
|
19
|
+
creds=AzureClientCreds(
|
|
20
|
+
tenant_id="valid",
|
|
21
|
+
client_id="valid",
|
|
22
|
+
client_secret="valid",
|
|
23
|
+
),
|
|
24
|
+
tenant_id="ten1",
|
|
25
|
+
subscription_id="sub1",
|
|
26
|
+
regions=["eastus"],
|
|
27
|
+
)
|
|
28
|
+
with (
|
|
29
|
+
patch("dstack._internal.core.backends.azure.auth.authenticate") as authenticate_mock,
|
|
30
|
+
patch("azure.mgmt.subscription.SubscriptionClient") as SubscriptionClientMock,
|
|
31
|
+
):
|
|
32
|
+
authenticate_mock.return_value = Mock(), Mock()
|
|
33
|
+
subcription_client_mock = SubscriptionClientMock.return_value
|
|
34
|
+
subcription_client_mock.tenants.list.return_value = [Mock(tenant_id="ten1")]
|
|
35
|
+
subcription_client_mock.subscriptions.list.return_value = [
|
|
36
|
+
Mock(subscription_id="sub1")
|
|
37
|
+
]
|
|
38
|
+
AzureConfigurator().validate_config(config, default_creds_enabled=True)
|
|
39
|
+
|
|
40
|
+
def test_validate_config_invalid_creds(self):
|
|
41
|
+
config = AzureBackendConfigWithCreds(
|
|
42
|
+
creds=AzureClientCreds(
|
|
43
|
+
tenant_id="invalid",
|
|
44
|
+
client_id="invalid",
|
|
45
|
+
client_secret="invalid",
|
|
46
|
+
),
|
|
47
|
+
tenant_id="invalid",
|
|
48
|
+
subscription_id="invalid",
|
|
49
|
+
regions=["eastus"],
|
|
50
|
+
)
|
|
51
|
+
with (
|
|
52
|
+
patch("dstack._internal.core.backends.azure.auth.authenticate") as mock_authenticate,
|
|
53
|
+
pytest.raises(BackendInvalidCredentialsError) as exc_info,
|
|
54
|
+
):
|
|
55
|
+
mock_authenticate.side_effect = BackendAuthError()
|
|
56
|
+
AzureConfigurator().validate_config(config, default_creds_enabled=True)
|
|
57
|
+
assert exc_info.value.fields == [
|
|
58
|
+
["creds", "tenant_id"],
|
|
59
|
+
["creds", "client_id"],
|
|
60
|
+
["creds", "client_secret"],
|
|
61
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.backends.cudo.configurator import CudoConfigurator
|
|
6
|
+
from dstack._internal.core.backends.cudo.models import CudoBackendConfigWithCreds, CudoCreds
|
|
7
|
+
from dstack._internal.core.errors import BackendInvalidCredentialsError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestCudoConfigurator:
|
|
11
|
+
def test_validate_config_valid(self):
|
|
12
|
+
config = CudoBackendConfigWithCreds(
|
|
13
|
+
creds=CudoCreds(api_key="valid"),
|
|
14
|
+
project_id="project1",
|
|
15
|
+
regions=["no-luster-1"],
|
|
16
|
+
)
|
|
17
|
+
with patch(
|
|
18
|
+
"dstack._internal.core.backends.cudo.api_client.CudoApiClient.validate_api_key"
|
|
19
|
+
) as validate_mock:
|
|
20
|
+
validate_mock.return_value = True
|
|
21
|
+
CudoConfigurator().validate_config(config, default_creds_enabled=True)
|
|
22
|
+
|
|
23
|
+
def test_validate_config_invalid_creds(self):
|
|
24
|
+
config = CudoBackendConfigWithCreds(
|
|
25
|
+
creds=CudoCreds(api_key="invalid"),
|
|
26
|
+
project_id="project1",
|
|
27
|
+
regions=["no-luster-1"],
|
|
28
|
+
)
|
|
29
|
+
with (
|
|
30
|
+
patch(
|
|
31
|
+
"dstack._internal.core.backends.cudo.api_client.CudoApiClient.validate_api_key"
|
|
32
|
+
) as validate_mock,
|
|
33
|
+
pytest.raises(BackendInvalidCredentialsError) as exc_info,
|
|
34
|
+
):
|
|
35
|
+
validate_mock.return_value = False
|
|
36
|
+
CudoConfigurator().validate_config(config, default_creds_enabled=True)
|
|
37
|
+
assert exc_info.value.fields == [["creds", "api_key"]]
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from dstack._internal.core.backends.datacrunch.configurator import (
|
|
2
|
+
DataCrunchConfigurator,
|
|
3
|
+
)
|
|
4
|
+
from dstack._internal.core.backends.datacrunch.models import (
|
|
5
|
+
DataCrunchBackendConfigWithCreds,
|
|
6
|
+
DataCrunchCreds,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestDataCrunchConfigurator:
|
|
11
|
+
def test_validate_config_valid(self):
|
|
12
|
+
config = DataCrunchBackendConfigWithCreds(
|
|
13
|
+
creds=DataCrunchCreds(client_id="valid", client_secret="valid"),
|
|
14
|
+
regions=["FIN-01"],
|
|
15
|
+
)
|
|
16
|
+
# Currently no validation is implemented
|
|
17
|
+
DataCrunchConfigurator().validate_config(config, default_creds_enabled=True)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from unittest.mock import Mock, patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.backends.gcp.configurator import GCPConfigurator
|
|
6
|
+
from dstack._internal.core.backends.gcp.models import (
|
|
7
|
+
GCPBackendConfigWithCreds,
|
|
8
|
+
GCPServiceAccountCreds,
|
|
9
|
+
)
|
|
10
|
+
from dstack._internal.core.errors import (
|
|
11
|
+
BackendAuthError,
|
|
12
|
+
BackendInvalidCredentialsError,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestGCPConfigurator:
|
|
17
|
+
def test_validate_config_valid(self):
|
|
18
|
+
config = GCPBackendConfigWithCreds(
|
|
19
|
+
creds=GCPServiceAccountCreds(data="valid", filename="-"),
|
|
20
|
+
project_id="valid-project",
|
|
21
|
+
regions=["us-west1"],
|
|
22
|
+
)
|
|
23
|
+
with (
|
|
24
|
+
patch("dstack._internal.core.backends.gcp.auth.authenticate") as authenticate_mock,
|
|
25
|
+
patch("dstack._internal.core.backends.gcp.resources.check_vpc"),
|
|
26
|
+
):
|
|
27
|
+
authenticate_mock.return_value = Mock(), Mock()
|
|
28
|
+
GCPConfigurator().validate_config(config, default_creds_enabled=True)
|
|
29
|
+
|
|
30
|
+
def test_validate_config_invalid_creds(self):
|
|
31
|
+
config = GCPBackendConfigWithCreds(
|
|
32
|
+
creds=GCPServiceAccountCreds(data="invalid", filename="-"),
|
|
33
|
+
project_id="invalid-project",
|
|
34
|
+
regions=["us-west1"],
|
|
35
|
+
)
|
|
36
|
+
with (
|
|
37
|
+
patch("dstack._internal.core.backends.gcp.auth.authenticate") as authenticate_mock,
|
|
38
|
+
pytest.raises(BackendInvalidCredentialsError) as exc_info,
|
|
39
|
+
):
|
|
40
|
+
authenticate_mock.side_effect = BackendAuthError()
|
|
41
|
+
GCPConfigurator().validate_config(config, default_creds_enabled=True)
|
|
42
|
+
assert exc_info.value.fields == [["creds", "data"]]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from unittest.mock import Mock, patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.backends.kubernetes.configurator import (
|
|
6
|
+
KubernetesConfigurator,
|
|
7
|
+
)
|
|
8
|
+
from dstack._internal.core.backends.kubernetes.models import (
|
|
9
|
+
KubeconfigConfig,
|
|
10
|
+
KubernetesBackendConfigWithCreds,
|
|
11
|
+
KubernetesNetworkingConfig,
|
|
12
|
+
)
|
|
13
|
+
from dstack._internal.core.errors import BackendInvalidCredentialsError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestKubernetesConfigurator:
|
|
17
|
+
def test_validate_config_valid(self):
|
|
18
|
+
config = KubernetesBackendConfigWithCreds(
|
|
19
|
+
kubeconfig=KubeconfigConfig(data="valid", filename="-"),
|
|
20
|
+
networking=KubernetesNetworkingConfig(ssh_host=None, ssh_port=None),
|
|
21
|
+
)
|
|
22
|
+
with patch(
|
|
23
|
+
"dstack._internal.core.backends.kubernetes.utils.get_api_from_config_data"
|
|
24
|
+
) as get_api_mock:
|
|
25
|
+
api_mock = Mock()
|
|
26
|
+
api_mock.list_node.return_value = Mock()
|
|
27
|
+
get_api_mock.return_value = api_mock
|
|
28
|
+
KubernetesConfigurator().validate_config(config, default_creds_enabled=True)
|
|
29
|
+
|
|
30
|
+
def test_validate_config_invalid_config(self):
|
|
31
|
+
config = KubernetesBackendConfigWithCreds(
|
|
32
|
+
kubeconfig=KubeconfigConfig(data="invalid", filename="-"),
|
|
33
|
+
networking=KubernetesNetworkingConfig(ssh_host=None, ssh_port=None),
|
|
34
|
+
)
|
|
35
|
+
with (
|
|
36
|
+
patch(
|
|
37
|
+
"dstack._internal.core.backends.kubernetes.utils.get_api_from_config_data"
|
|
38
|
+
) as get_api_mock,
|
|
39
|
+
pytest.raises(BackendInvalidCredentialsError) as exc_info,
|
|
40
|
+
):
|
|
41
|
+
get_api_mock.side_effect = Exception("Invalid config")
|
|
42
|
+
KubernetesConfigurator().validate_config(config, default_creds_enabled=True)
|
|
43
|
+
assert exc_info.value.fields == [["kubeconfig"]]
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.backends.lambdalabs.configurator import LambdaConfigurator
|
|
6
|
+
from dstack._internal.core.backends.lambdalabs.models import (
|
|
7
|
+
LambdaBackendConfigWithCreds,
|
|
8
|
+
LambdaCreds,
|
|
9
|
+
)
|
|
10
|
+
from dstack._internal.core.errors import BackendInvalidCredentialsError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestLambdaConfigurator:
|
|
14
|
+
def test_validate_config_valid(self):
|
|
15
|
+
config = LambdaBackendConfigWithCreds(
|
|
16
|
+
creds=LambdaCreds(api_key="valid"),
|
|
17
|
+
regions=["us-east-1"],
|
|
18
|
+
)
|
|
19
|
+
with patch(
|
|
20
|
+
"dstack._internal.core.backends.lambdalabs.api_client.LambdaAPIClient.validate_api_key"
|
|
21
|
+
) as validate_mock:
|
|
22
|
+
validate_mock.return_value = True
|
|
23
|
+
LambdaConfigurator().validate_config(config, default_creds_enabled=True)
|
|
24
|
+
|
|
25
|
+
def test_validate_config_invalid_creds(self):
|
|
26
|
+
config = LambdaBackendConfigWithCreds(
|
|
27
|
+
creds=LambdaCreds(api_key="invalid"),
|
|
28
|
+
regions=["us-east-1"],
|
|
29
|
+
)
|
|
30
|
+
with (
|
|
31
|
+
patch(
|
|
32
|
+
"dstack._internal.core.backends.lambdalabs.api_client.LambdaAPIClient.validate_api_key"
|
|
33
|
+
) as validate_mock,
|
|
34
|
+
pytest.raises(BackendInvalidCredentialsError) as exc_info,
|
|
35
|
+
):
|
|
36
|
+
validate_mock.return_value = False
|
|
37
|
+
LambdaConfigurator().validate_config(config, default_creds_enabled=True)
|
|
38
|
+
assert exc_info.value.fields == [["creds", "api_key"]]
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from unittest.mock import Mock, patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from oci.exceptions import ClientError
|
|
5
|
+
|
|
6
|
+
from dstack._internal.core.backends.oci.configurator import OCIConfigurator
|
|
7
|
+
from dstack._internal.core.backends.oci.models import (
|
|
8
|
+
OCIBackendConfigWithCreds,
|
|
9
|
+
OCIClientCreds,
|
|
10
|
+
)
|
|
11
|
+
from dstack._internal.core.errors import BackendInvalidCredentialsError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestOCIConfigurator:
|
|
15
|
+
def test_validate_config_valid(self):
|
|
16
|
+
config = OCIBackendConfigWithCreds(
|
|
17
|
+
creds=OCIClientCreds(
|
|
18
|
+
user="valid_user",
|
|
19
|
+
tenancy="valid_tenancy",
|
|
20
|
+
key_content="valid_key",
|
|
21
|
+
key_file=None,
|
|
22
|
+
pass_phrase=None,
|
|
23
|
+
fingerprint="valid_fingerprint",
|
|
24
|
+
region="us-ashburn-1",
|
|
25
|
+
),
|
|
26
|
+
regions=["us-ashburn-1"],
|
|
27
|
+
)
|
|
28
|
+
with patch(
|
|
29
|
+
"dstack._internal.core.backends.oci.configurator.get_subscribed_regions"
|
|
30
|
+
) as regions_mock:
|
|
31
|
+
regions_mock.return_value = Mock(names=["us-ashburn-1"])
|
|
32
|
+
OCIConfigurator().validate_config(config, default_creds_enabled=True)
|
|
33
|
+
|
|
34
|
+
def test_validate_config_invalid_creds(self):
|
|
35
|
+
config = OCIBackendConfigWithCreds(
|
|
36
|
+
creds=OCIClientCreds(
|
|
37
|
+
user="invalid_user",
|
|
38
|
+
tenancy="invalid_tenancy",
|
|
39
|
+
key_content="invalid_key",
|
|
40
|
+
key_file=None,
|
|
41
|
+
pass_phrase=None,
|
|
42
|
+
fingerprint="invalid_fingerprint",
|
|
43
|
+
region="us-ashburn-1",
|
|
44
|
+
),
|
|
45
|
+
regions=["us-ashburn-1"],
|
|
46
|
+
)
|
|
47
|
+
with (
|
|
48
|
+
patch(
|
|
49
|
+
"dstack._internal.core.backends.oci.configurator.get_subscribed_regions"
|
|
50
|
+
) as regions_mock,
|
|
51
|
+
pytest.raises(BackendInvalidCredentialsError) as exc_info,
|
|
52
|
+
):
|
|
53
|
+
regions_mock.side_effect = ClientError("Invalid credentials")
|
|
54
|
+
OCIConfigurator().validate_config(config, default_creds_enabled=True)
|
|
55
|
+
assert exc_info.value.fields == [["creds"]]
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.backends.runpod.configurator import RunpodConfigurator
|
|
6
|
+
from dstack._internal.core.backends.runpod.models import RunpodBackendConfigWithCreds, RunpodCreds
|
|
7
|
+
from dstack._internal.core.errors import BackendInvalidCredentialsError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestRunpodConfigurator:
|
|
11
|
+
def test_validate_config_valid(self):
|
|
12
|
+
config = RunpodBackendConfigWithCreds(
|
|
13
|
+
creds=RunpodCreds(api_key="valid"),
|
|
14
|
+
)
|
|
15
|
+
with patch(
|
|
16
|
+
"dstack._internal.core.backends.runpod.api_client.RunpodApiClient.validate_api_key"
|
|
17
|
+
) as validate_mock:
|
|
18
|
+
validate_mock.return_value = True
|
|
19
|
+
RunpodConfigurator().validate_config(config, default_creds_enabled=True)
|
|
20
|
+
|
|
21
|
+
def test_validate_config_invalid_creds(self):
|
|
22
|
+
config = RunpodBackendConfigWithCreds(
|
|
23
|
+
creds=RunpodCreds(api_key="invalid"),
|
|
24
|
+
)
|
|
25
|
+
with (
|
|
26
|
+
patch(
|
|
27
|
+
"dstack._internal.core.backends.runpod.api_client.RunpodApiClient.validate_api_key"
|
|
28
|
+
) as validate_mock,
|
|
29
|
+
pytest.raises(BackendInvalidCredentialsError) as exc_info,
|
|
30
|
+
):
|
|
31
|
+
validate_mock.return_value = False
|
|
32
|
+
RunpodConfigurator().validate_config(config, default_creds_enabled=True)
|
|
33
|
+
assert exc_info.value.fields == [["creds", "api_key"]]
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.backends.tensordock.configurator import (
|
|
6
|
+
TensorDockConfigurator,
|
|
7
|
+
)
|
|
8
|
+
from dstack._internal.core.backends.tensordock.models import (
|
|
9
|
+
TensorDockBackendConfigWithCreds,
|
|
10
|
+
TensorDockCreds,
|
|
11
|
+
)
|
|
12
|
+
from dstack._internal.core.errors import BackendInvalidCredentialsError
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestTensorDockConfigurator:
|
|
16
|
+
def test_validate_config_valid(self):
|
|
17
|
+
config = TensorDockBackendConfigWithCreds(
|
|
18
|
+
creds=TensorDockCreds(api_key="valid", api_token="valid"),
|
|
19
|
+
)
|
|
20
|
+
with patch(
|
|
21
|
+
"dstack._internal.core.backends.tensordock.api_client.TensorDockAPIClient.auth_test"
|
|
22
|
+
) as auth_test_mock:
|
|
23
|
+
auth_test_mock.return_value = True
|
|
24
|
+
TensorDockConfigurator().validate_config(config, default_creds_enabled=True)
|
|
25
|
+
|
|
26
|
+
def test_validate_config_invalid_creds(self):
|
|
27
|
+
config = TensorDockBackendConfigWithCreds(
|
|
28
|
+
creds=TensorDockCreds(api_key="invalid", api_token="invalid"),
|
|
29
|
+
)
|
|
30
|
+
with (
|
|
31
|
+
patch(
|
|
32
|
+
"dstack._internal.core.backends.tensordock.api_client.TensorDockAPIClient.auth_test"
|
|
33
|
+
) as auth_test_mock,
|
|
34
|
+
pytest.raises(BackendInvalidCredentialsError) as exc_info,
|
|
35
|
+
):
|
|
36
|
+
auth_test_mock.return_value = False
|
|
37
|
+
TensorDockConfigurator().validate_config(config, default_creds_enabled=True)
|
|
38
|
+
assert exc_info.value.fields == [["creds", "api_key"], ["creds", "api_token"]]
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.backends.vastai.configurator import VastAIConfigurator
|
|
6
|
+
from dstack._internal.core.backends.vastai.models import VastAIBackendConfigWithCreds, VastAICreds
|
|
7
|
+
from dstack._internal.core.errors import BackendInvalidCredentialsError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestVastAIConfigurator:
|
|
11
|
+
def test_validate_config_valid(self):
|
|
12
|
+
config = VastAIBackendConfigWithCreds(
|
|
13
|
+
creds=VastAICreds(api_key="valid"),
|
|
14
|
+
)
|
|
15
|
+
with patch(
|
|
16
|
+
"dstack._internal.core.backends.vastai.api_client.VastAIAPIClient.auth_test"
|
|
17
|
+
) as auth_test_mock:
|
|
18
|
+
auth_test_mock.return_value = True
|
|
19
|
+
VastAIConfigurator().validate_config(config, default_creds_enabled=True)
|
|
20
|
+
|
|
21
|
+
def test_validate_config_invalid_creds(self):
|
|
22
|
+
config = VastAIBackendConfigWithCreds(
|
|
23
|
+
creds=VastAICreds(api_key="invalid"),
|
|
24
|
+
)
|
|
25
|
+
with (
|
|
26
|
+
patch(
|
|
27
|
+
"dstack._internal.core.backends.vastai.api_client.VastAIAPIClient.auth_test"
|
|
28
|
+
) as auth_test_mock,
|
|
29
|
+
pytest.raises(BackendInvalidCredentialsError) as exc_info,
|
|
30
|
+
):
|
|
31
|
+
auth_test_mock.return_value = False
|
|
32
|
+
VastAIConfigurator().validate_config(config, default_creds_enabled=True)
|
|
33
|
+
assert exc_info.value.fields == [["creds", "api_key"]]
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from dstack._internal.core.backends.vultr.configurator import VultrConfigurator
|
|
6
|
+
from dstack._internal.core.backends.vultr.models import VultrBackendConfigWithCreds, VultrCreds
|
|
7
|
+
from dstack._internal.core.errors import BackendInvalidCredentialsError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestVultrConfigurator:
|
|
11
|
+
def test_validate_config_valid(self):
|
|
12
|
+
config = VultrBackendConfigWithCreds(
|
|
13
|
+
creds=VultrCreds(api_key="valid"),
|
|
14
|
+
)
|
|
15
|
+
with patch(
|
|
16
|
+
"dstack._internal.core.backends.vultr.api_client.VultrApiClient.validate_api_key"
|
|
17
|
+
) as validate_mock:
|
|
18
|
+
validate_mock.return_value = True
|
|
19
|
+
VultrConfigurator().validate_config(config, default_creds_enabled=True)
|
|
20
|
+
|
|
21
|
+
def test_validate_config_invalid_creds(self):
|
|
22
|
+
config = VultrBackendConfigWithCreds(
|
|
23
|
+
creds=VultrCreds(api_key="invalid"),
|
|
24
|
+
)
|
|
25
|
+
with (
|
|
26
|
+
patch(
|
|
27
|
+
"dstack._internal.core.backends.vultr.api_client.VultrApiClient.validate_api_key"
|
|
28
|
+
) as validate_mock,
|
|
29
|
+
pytest.raises(BackendInvalidCredentialsError) as exc_info,
|
|
30
|
+
):
|
|
31
|
+
validate_mock.return_value = False
|
|
32
|
+
VultrConfigurator().validate_config(config, default_creds_enabled=True)
|
|
33
|
+
assert exc_info.value.fields == [["creds", "api_key"]]
|
|
@@ -8,6 +8,7 @@ from dstack._internal.core.models.gateways import GatewayProvisioningData, Gatew
|
|
|
8
8
|
from dstack._internal.server.background.tasks.process_gateways import process_submitted_gateways
|
|
9
9
|
from dstack._internal.server.testing.common import (
|
|
10
10
|
AsyncContextManager,
|
|
11
|
+
ComputeMockSpec,
|
|
11
12
|
create_backend,
|
|
12
13
|
create_gateway,
|
|
13
14
|
create_project,
|
|
@@ -37,6 +38,7 @@ class TestProcessSubmittedGateways:
|
|
|
37
38
|
m.return_value = (backend, aws)
|
|
38
39
|
pool_add.return_value = MagicMock()
|
|
39
40
|
pool_add.return_value.client.return_value = MagicMock(AsyncContextManager())
|
|
41
|
+
aws.compute.return_value = Mock(spec=ComputeMockSpec)
|
|
40
42
|
aws.compute.return_value.create_gateway.return_value = GatewayProvisioningData(
|
|
41
43
|
instance_id="i-1234567890",
|
|
42
44
|
ip_address="2.2.2.2",
|
|
@@ -68,6 +70,7 @@ class TestProcessSubmittedGateways:
|
|
|
68
70
|
) as m:
|
|
69
71
|
aws = Mock()
|
|
70
72
|
m.return_value = (backend, aws)
|
|
73
|
+
aws.compute.return_value = Mock(spec=ComputeMockSpec)
|
|
71
74
|
aws.compute.return_value.create_gateway.side_effect = BackendError("Some error")
|
|
72
75
|
await process_submitted_gateways()
|
|
73
76
|
m.assert_called_once()
|
|
@@ -99,6 +102,7 @@ class TestProcessSubmittedGateways:
|
|
|
99
102
|
aws = Mock()
|
|
100
103
|
m.return_value = (backend, aws)
|
|
101
104
|
connect_to_gateway_with_retry_mock.return_value = None
|
|
105
|
+
aws.compute.return_value = Mock(spec=ComputeMockSpec)
|
|
102
106
|
aws.compute.return_value.create_gateway.return_value = GatewayProvisioningData(
|
|
103
107
|
instance_id="i-1234567890",
|
|
104
108
|
ip_address="2.2.2.2",
|