storage.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. from typing import TYPE_CHECKING, TypedDict, Literal, NotRequired, Union
  2. if TYPE_CHECKING:
  3. from container import Container
  4. from render import Render
  5. try:
  6. from .error import RenderError
  7. from .validations import valid_fs_path_or_raise
  8. from .volume_mount import VolumeMount
  9. except ImportError:
  10. from error import RenderError
  11. from validations import valid_fs_path_or_raise
  12. from volume_mount import VolumeMount
  13. class IxStorageTmpfsConfig(TypedDict):
  14. size: NotRequired[int]
  15. mode: NotRequired[str]
  16. uid: NotRequired[int]
  17. gid: NotRequired[int]
  18. class AclConfig(TypedDict, total=False):
  19. path: str
  20. class IxStorageHostPathConfig(TypedDict):
  21. path: NotRequired[str] # Either this or acl.path must be set
  22. acl_enable: NotRequired[bool]
  23. acl: NotRequired[AclConfig]
  24. create_host_path: NotRequired[bool]
  25. propagation: NotRequired[Literal["shared", "slave", "private", "rshared", "rslave", "rprivate"]]
  26. auto_permissions: NotRequired[bool] # Only when acl_enable is false
  27. class IxStorageIxVolumeConfig(TypedDict):
  28. dataset_name: str
  29. acl_enable: NotRequired[bool]
  30. acl_entries: NotRequired[AclConfig]
  31. create_host_path: NotRequired[bool]
  32. propagation: NotRequired[Literal["shared", "slave", "private", "rshared", "rslave", "rprivate"]]
  33. auto_permissions: NotRequired[bool] # Only when acl_enable is false
  34. class IxStorageVolumeConfig(TypedDict):
  35. volume_name: NotRequired[str]
  36. nocopy: NotRequired[bool]
  37. auto_permissions: NotRequired[bool]
  38. class IxStorageNfsConfig(TypedDict):
  39. server: str
  40. path: str
  41. options: NotRequired[list[str]]
  42. class IxStorageCifsConfig(TypedDict):
  43. server: str
  44. path: str
  45. username: str
  46. password: str
  47. domain: NotRequired[str]
  48. options: NotRequired[list[str]]
  49. IxStorageVolumeLikeConfigs = Union[IxStorageVolumeConfig, IxStorageNfsConfig, IxStorageCifsConfig, IxStorageTmpfsConfig]
  50. IxStorageBindLikeConfigs = Union[IxStorageHostPathConfig, IxStorageIxVolumeConfig]
  51. IxStorageLikeConfigs = Union[IxStorageBindLikeConfigs, IxStorageVolumeLikeConfigs]
  52. class IxStorage(TypedDict):
  53. type: Literal["ix_volume", "host_path", "tmpfs", "volume", "anonymous", "temporary"]
  54. read_only: NotRequired[bool]
  55. ix_volume_config: NotRequired[IxStorageIxVolumeConfig]
  56. host_path_config: NotRequired[IxStorageHostPathConfig]
  57. tmpfs_config: NotRequired[IxStorageTmpfsConfig]
  58. volume_config: NotRequired[IxStorageVolumeConfig]
  59. nfs_config: NotRequired[IxStorageNfsConfig]
  60. cifs_config: NotRequired[IxStorageCifsConfig]
  61. class Storage:
  62. def __init__(self, render_instance: "Render", container_instance: "Container"):
  63. self._container_instance = container_instance
  64. self._render_instance = render_instance
  65. self._volume_mounts: set[VolumeMount] = set()
  66. def add(self, mount_path: str, config: "IxStorage"):
  67. mount_path = valid_fs_path_or_raise(mount_path)
  68. if self.is_defined(mount_path):
  69. raise RenderError(f"Mount path [{mount_path}] already used for another volume mount")
  70. if self._container_instance._tmpfs.is_defined(mount_path):
  71. raise RenderError(f"Mount path [{mount_path}] already used for another volume mount")
  72. volume_mount = VolumeMount(self._render_instance, mount_path, config)
  73. self._volume_mounts.add(volume_mount)
  74. def is_defined(self, mount_path: str):
  75. return mount_path in [m.mount_path for m in self._volume_mounts]
  76. def _add_docker_socket(self, read_only: bool = True, mount_path: str = ""):
  77. mount_path = valid_fs_path_or_raise(mount_path)
  78. cfg: "IxStorage" = {
  79. "type": "host_path",
  80. "read_only": read_only,
  81. "host_path_config": {"path": "/var/run/docker.sock", "create_host_path": False},
  82. }
  83. self.add(mount_path, cfg)
  84. def _add_udev(self, read_only: bool = True, mount_path: str = ""):
  85. mount_path = valid_fs_path_or_raise(mount_path)
  86. cfg: "IxStorage" = {
  87. "type": "host_path",
  88. "read_only": read_only,
  89. "host_path_config": {"path": "/run/udev", "create_host_path": False},
  90. }
  91. self.add(mount_path, cfg)
  92. def has_mounts(self) -> bool:
  93. return bool(self._volume_mounts)
  94. def render(self):
  95. return [vm.render() for vm in sorted(self._volume_mounts, key=lambda vm: vm.mount_path)]