Skip to content

Commit fb99485

Browse files
Add validation for external volumes with auto_cleanup_duration
1 parent 4e1b56c commit fb99485

2 files changed

Lines changed: 86 additions & 2 deletions

File tree

src/dstack/_internal/server/services/volumes.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,23 @@ def _validate_volume_configuration(configuration: VolumeConfiguration):
400400
)
401401
if configuration.name is not None:
402402
validate_dstack_resource_name(configuration.name)
403+
# External volumes (with volume_id) cannot have auto_cleanup_duration
404+
if configuration.volume_id is not None and configuration.auto_cleanup_duration is not None:
405+
if (
406+
isinstance(configuration.auto_cleanup_duration, int)
407+
and configuration.auto_cleanup_duration >= 0
408+
):
409+
raise ServerClientError(
410+
"External volumes (with volume_id) do not support auto_cleanup_duration. "
411+
"Auto-cleanup only works for volumes created and managed by dstack."
412+
)
413+
elif isinstance(
414+
configuration.auto_cleanup_duration, str
415+
) and configuration.auto_cleanup_duration not in ("off", "-1"):
416+
raise ServerClientError(
417+
"External volumes (with volume_id) do not support auto_cleanup_duration. "
418+
"Auto-cleanup only works for volumes created and managed by dstack."
419+
)
403420

404421

405422
async def _delete_volume(session: AsyncSession, project: ProjectModel, volume_model: VolumeModel):

src/tests/_internal/server/services/test_volumes.py

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,78 @@
33
import pytest
44
from freezegun import freeze_time
55

6-
from dstack._internal.core.models.volumes import VolumeStatus
7-
from dstack._internal.server.services.volumes import _get_volume_cost
6+
from dstack._internal.core.errors import ServerClientError
7+
from dstack._internal.core.models.backends.base import BackendType
8+
from dstack._internal.core.models.volumes import VolumeConfiguration, VolumeStatus
9+
from dstack._internal.server.services.volumes import (
10+
_get_volume_cost,
11+
_validate_volume_configuration,
12+
)
813
from dstack._internal.server.testing.common import get_volume, get_volume_provisioning_data
914

1015

16+
class TestValidateVolumeConfiguration:
17+
def test_external_volume_with_auto_cleanup_duration_raises_error(self):
18+
"""External volumes (with volume_id) should not allow auto_cleanup_duration"""
19+
config = VolumeConfiguration(
20+
backend=BackendType.AWS,
21+
region="us-east-1",
22+
volume_id="vol-123456",
23+
auto_cleanup_duration="1h",
24+
)
25+
with pytest.raises(
26+
ServerClientError, match="External volumes.*do not support auto_cleanup_duration"
27+
):
28+
_validate_volume_configuration(config)
29+
30+
def test_external_volume_with_auto_cleanup_duration_int_raises_error(self):
31+
"""External volumes with integer auto_cleanup_duration should also raise error"""
32+
config = VolumeConfiguration(
33+
backend=BackendType.AWS,
34+
region="us-east-1",
35+
volume_id="vol-123456",
36+
auto_cleanup_duration=3600,
37+
)
38+
with pytest.raises(
39+
ServerClientError, match="External volumes.*do not support auto_cleanup_duration"
40+
):
41+
_validate_volume_configuration(config)
42+
43+
def test_external_volume_with_auto_cleanup_disabled_succeeds(self):
44+
"""External volumes with auto_cleanup_duration='off' or -1 should be allowed"""
45+
config1 = VolumeConfiguration(
46+
backend=BackendType.AWS,
47+
region="us-east-1",
48+
volume_id="vol-123456",
49+
auto_cleanup_duration="off",
50+
)
51+
config2 = VolumeConfiguration(
52+
backend=BackendType.AWS,
53+
region="us-east-1",
54+
volume_id="vol-123456",
55+
auto_cleanup_duration=-1,
56+
)
57+
# Should not raise any errors
58+
_validate_volume_configuration(config1)
59+
_validate_volume_configuration(config2)
60+
61+
def test_external_volume_without_auto_cleanup_succeeds(self):
62+
"""External volumes without auto_cleanup_duration should be allowed"""
63+
config = VolumeConfiguration(
64+
backend=BackendType.AWS, region="us-east-1", volume_id="vol-123456"
65+
)
66+
# Should not raise any errors
67+
_validate_volume_configuration(config)
68+
69+
def test_new_volume_with_auto_cleanup_duration_succeeds(self):
70+
"""New volumes (without volume_id) with auto_cleanup_duration should be allowed"""
71+
config = VolumeConfiguration(
72+
backend=BackendType.AWS, region="us-east-1", size=100, auto_cleanup_duration="1h"
73+
)
74+
# Should not raise any errors
75+
_validate_volume_configuration(config)
76+
77+
1178
class TestGetVolumeCost:
1279
def test_returns_0_when_no_provisioning_data(self):
1380
volume = get_volume(provisioning_data=None)

0 commit comments

Comments
 (0)