Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions scripts/docs/gen_schema_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import importlib
import inspect
import json
import logging
import re
from enum import Enum
Expand Down Expand Up @@ -233,15 +234,26 @@ def generate_schema_reference(
schema_props = {}
for name, field in cls.__fields__.items():
default = field.default
if isinstance(default, Enum):
default = default.value
default_repr: Optional[str]
if default is None:
default_repr = None
elif isinstance(default, (list, tuple, dict)) and len(default) == 0:
default_repr = None
elif isinstance(default, str):
default_repr = default
elif isinstance(default, BaseModel):
default_repr = str(default)
elif isinstance(default, Enum):
default_repr = str(default.value)
else:
default_repr = json.dumps(default)
friendly_type = get_friendly_type(field.annotation)
friendly_type = _enrich_type_from_schema(friendly_type, schema_props.get(name, {}))
values = dict(
name=name,
description=field.field_info.description,
type=friendly_type,
default=default,
default=default_repr,
required=field.required,
)
# TODO: If the field doesn't have description (e.g. BaseConfiguration.type), we could fallback to docstring
Expand Down
4 changes: 3 additions & 1 deletion src/dstack/_internal/core/backends/kubernetes/compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ def run_job(
else:
assert False, f"unexpected mount point: {mount_point!r}"
for volume in volumes:
assert isinstance(volume.configuration, KubernetesVolumeConfiguration)
pvc_name = volume.volume_id
assert pvc_name is not None, f"missing PVC name: {volume!r}"
mount_path = volume_name_path_map.get(volume.name)
Expand All @@ -265,14 +266,15 @@ def run_job(
name=volume_name,
persistent_volume_claim=client.V1PersistentVolumeClaimVolumeSource(
claim_name=pvc_name,
read_only=False,
),
),
)
volume_mounts.append(
client.V1VolumeMount(
name=volume_name,
mount_path=mount_path,
read_only=volume.configuration.read_only,
recursive_read_only="IfPossible" if volume.configuration.read_only else None,
)
)

Expand Down
12 changes: 7 additions & 5 deletions src/dstack/_internal/core/compatibility/volumes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from dstack._internal.core.models.common import IncludeExcludeDictType
from dstack._internal.core.models.volumes import AnyVolumeConfiguration, VolumeSpec
from dstack._internal.core.models.volumes import (
AnyVolumeConfiguration,
KubernetesVolumeConfiguration,
VolumeSpec,
)


def get_volume_spec_excludes(volume_spec: VolumeSpec) -> IncludeExcludeDictType:
Expand Down Expand Up @@ -29,9 +33,7 @@ def _get_volume_configuration_excludes(
) -> IncludeExcludeDictType:
configuration_excludes: IncludeExcludeDictType = {}

# Add excludes like this:
#
# if configuration.tags is None:
# configuration_excludes["tags"] = True
if isinstance(configuration, KubernetesVolumeConfiguration) and not configuration.read_only:
configuration_excludes["read_only"] = True

return configuration_excludes
3 changes: 3 additions & 0 deletions src/dstack/_internal/core/models/volumes.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ class KubernetesVolumeConfiguration(BaseVolumeConfiguration):
list[str],
Field(description="A list of accepted access modes. Ignored if `claim_name` is set"),
] = ["ReadWriteOnce"]
read_only: Annotated[
bool, Field(description="If `true`, enforces the volume to be mounted as read-only")
] = False

@property
def external_volume_id(self) -> Optional[str]:
Expand Down
Loading