88
99from dstack ._internal .core .models .common import CoreModel
1010from dstack ._internal .utils .common import pretty_resources
11+ from dstack ._internal .utils .json_schema import add_extra_schema_types
1112from dstack ._internal .utils .logging import get_logger
1213
1314logger = get_logger (__name__ )
@@ -128,6 +129,22 @@ def __str__(self):
128129
129130
130131class GPUSpec (CoreModel ):
132+ class Config :
133+ @staticmethod
134+ def schema_extra (schema : Dict [str , Any ]):
135+ add_extra_schema_types (
136+ schema ["properties" ]["count" ],
137+ extra_types = [{"type" : "integer" }, {"type" : "string" }],
138+ )
139+ add_extra_schema_types (
140+ schema ["properties" ]["memory" ],
141+ extra_types = [{"type" : "integer" }, {"type" : "string" }],
142+ )
143+ add_extra_schema_types (
144+ schema ["properties" ]["total_memory" ],
145+ extra_types = [{"type" : "integer" }, {"type" : "string" }],
146+ )
147+
131148 vendor : Annotated [
132149 Optional [gpuhunt .AcceleratorVendor ],
133150 Field (
@@ -233,6 +250,14 @@ def _vendor_from_string(cls, v: str) -> gpuhunt.AcceleratorVendor:
233250
234251
235252class DiskSpec (CoreModel ):
253+ class Config :
254+ @staticmethod
255+ def schema_extra (schema : Dict [str , Any ]):
256+ add_extra_schema_types (
257+ schema ["properties" ]["size" ],
258+ extra_types = [{"type" : "integer" }, {"type" : "string" }],
259+ )
260+
236261 size : Annotated [Range [Memory ], Field (description = "Disk size" )]
237262
238263 @classmethod
@@ -254,11 +279,26 @@ class ResourcesSpec(CoreModel):
254279 class Config :
255280 @staticmethod
256281 def schema_extra (schema : Dict [str , Any ]):
257- schema .clear ()
258- # replace strict schema with a more permissive one
259- ref_template = "#/definitions/ResourcesSpecRequest/definitions/{model}"
260- for field , value in ResourcesSpecSchema .schema (ref_template = ref_template ).items ():
261- schema [field ] = value
282+ add_extra_schema_types (
283+ schema ["properties" ]["cpu" ],
284+ extra_types = [{"type" : "integer" }, {"type" : "string" }],
285+ )
286+ add_extra_schema_types (
287+ schema ["properties" ]["memory" ],
288+ extra_types = [{"type" : "integer" }, {"type" : "string" }],
289+ )
290+ add_extra_schema_types (
291+ schema ["properties" ]["shm_size" ],
292+ extra_types = [{"type" : "integer" }, {"type" : "string" }],
293+ )
294+ add_extra_schema_types (
295+ schema ["properties" ]["gpu" ],
296+ extra_types = [{"type" : "integer" }, {"type" : "string" }],
297+ )
298+ add_extra_schema_types (
299+ schema ["properties" ]["disk" ],
300+ extra_types = [{"type" : "integer" }, {"type" : "string" }],
301+ )
262302
263303 cpu : Annotated [Range [int ], Field (description = "The number of CPU cores" )] = DEFAULT_CPU_COUNT
264304 memory : Annotated [Range [Memory ], Field (description = "The RAM size (e.g., `8GB`)" )] = (
@@ -290,74 +330,3 @@ def pretty_format(self) -> str:
290330 resources .update (disk_size = self .disk .size )
291331 res = pretty_resources (** resources )
292332 return res
293-
294-
295- IntRangeLike = Union [Range [Union [int , str ]], int , str ]
296- MemoryRangeLike = Union [Range [Union [Memory , float , int , str ]], float , int , str ]
297- MemoryLike = Union [Memory , float , int , str ]
298- GPULike = Union [GPUSpec , "GPUSpecSchema" , int , str ]
299- DiskLike = Union [DiskSpec , "DiskSpecSchema" , float , int , str ]
300- ComputeCapabilityLike = Union [ComputeCapability , float , str ]
301-
302-
303- class GPUSpecSchema (CoreModel ):
304- vendor : Annotated [
305- Optional [gpuhunt .AcceleratorVendor ],
306- Field (
307- description = "The vendor of the GPU/accelerator, one of: `nvidia`, `amd`, `google` (alias: `tpu`), `intel`"
308- ),
309- ] = None
310- name : Annotated [
311- Optional [Union [List [str ], str ]], Field (description = "The GPU name or list of names" )
312- ] = None
313- count : Annotated [IntRangeLike , Field (description = "The number of GPUs" )] = DEFAULT_GPU_COUNT
314- memory : Annotated [
315- Optional [MemoryRangeLike ],
316- Field (
317- description = "The RAM size (e.g., `16GB`). Can be set to a range (e.g. `16GB..`, or `16GB..80GB`)"
318- ),
319- ] = None
320- total_memory : Annotated [
321- Optional [MemoryRangeLike ],
322- Field (
323- description = "The total RAM size (e.g., `32GB`). Can be set to a range (e.g. `16GB..`, or `16GB..80GB`)"
324- ),
325- ] = None
326- compute_capability : Annotated [
327- Optional [ComputeCapabilityLike ],
328- Field (description = "The minimum compute capability of the GPU (e.g., `7.5`)" ),
329- ] = None
330-
331-
332- class DiskSpecSchema (CoreModel ):
333- size : Annotated [
334- MemoryRangeLike ,
335- Field (
336- description = "The disk size. Can be set to a range (e.g., `100GB..` or `100GB..200GB`)"
337- ),
338- ]
339-
340-
341- class ResourcesSpecSchema (CoreModel ):
342- cpu : Annotated [Optional [IntRangeLike ], Field (description = "The number of CPU cores" )] = (
343- DEFAULT_CPU_COUNT
344- )
345- memory : Annotated [
346- Optional [MemoryRangeLike ],
347- Field (description = "The RAM size (e.g., `8GB`)" ),
348- ] = DEFAULT_MEMORY_SIZE
349- shm_size : Annotated [
350- Optional [MemoryLike ],
351- Field (
352- description = "The size of shared memory (e.g., `8GB`). "
353- "If you are using parallel communicating processes (e.g., dataloaders in PyTorch), "
354- "you may need to configure this"
355- ),
356- ] = None
357- gpu : Annotated [
358- Optional [GPULike ],
359- Field (
360- description = "The GPU requirements. Can be set to a number, a string (e.g. `A100`, `80GB:2`, etc.), or an object"
361- ),
362- ] = None
363- disk : Annotated [Optional [DiskLike ], Field (description = "The disk resources" )] = DEFAULT_DISK
0 commit comments