mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 19:13:34 +00:00
chore: new specs for defining service volumes
This commit is contained in:
+26
-1
@@ -46,6 +46,8 @@ type ServiceSpec struct {
|
|||||||
Ports []PortSpec
|
Ports []PortSpec
|
||||||
// Replicas is the number of containers to run for the service. Only valid for a replicated service.
|
// Replicas is the number of containers to run for the service. Only valid for a replicated service.
|
||||||
Replicas uint `json:",omitempty"`
|
Replicas uint `json:",omitempty"`
|
||||||
|
// Volumes is list of data volumes that can be mounted into the container.
|
||||||
|
Volumes []VolumeSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceSpec) SetDefaults() ServiceSpec {
|
func (s *ServiceSpec) SetDefaults() ServiceSpec {
|
||||||
@@ -85,6 +87,20 @@ func (s *ServiceSpec) Validate() error {
|
|||||||
|
|
||||||
// TODO: validate there is no conflict between ports.
|
// TODO: validate there is no conflict between ports.
|
||||||
|
|
||||||
|
for _, v := range s.Volumes {
|
||||||
|
if err := v.Validate(); err != nil {
|
||||||
|
return fmt.Errorf("invalid volume: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, m := range s.Container.VolumeMounts {
|
||||||
|
if !slices.ContainsFunc(s.Volumes, func(v VolumeSpec) bool {
|
||||||
|
return v.Name == m.VolumeName
|
||||||
|
}) {
|
||||||
|
return fmt.Errorf("volume mount references a volume that doesn't exist in the service spec: '%s'",
|
||||||
|
m.VolumeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,8 +131,11 @@ type ContainerSpec struct {
|
|||||||
// PullPolicy determines when to pull the image from the registry or use the image already available in the cluster.
|
// PullPolicy determines when to pull the image from the registry or use the image already available in the cluster.
|
||||||
// Default is PullPolicyMissing if empty.
|
// Default is PullPolicyMissing if empty.
|
||||||
PullPolicy string
|
PullPolicy string
|
||||||
|
// VolumeMounts specifies how volumes are mounted into the container filesystem.
|
||||||
|
// Each mount references a volume defined in ServiceSpec.Volumes.
|
||||||
|
VolumeMounts []VolumeMount
|
||||||
// Volumes is list of data volumes to mount into the container.
|
// Volumes is list of data volumes to mount into the container.
|
||||||
// TODO: replace with []VolumeSpec
|
// TODO: replace with []VolumeMounts
|
||||||
Volumes []string
|
Volumes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +154,12 @@ func (s *ContainerSpec) Validate() error {
|
|||||||
return fmt.Errorf("invalid image: %w", err)
|
return fmt.Errorf("invalid image: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, m := range s.VolumeMounts {
|
||||||
|
if err := m.Validate(); err != nil {
|
||||||
|
return fmt.Errorf("invalid volume mount: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+63
-16
@@ -21,30 +21,77 @@ const (
|
|||||||
SELinuxUnshared = "Z"
|
SELinuxUnshared = "Z"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// VolumeSpec defines a volume mount specification.
|
||||||
type VolumeSpec struct {
|
type VolumeSpec struct {
|
||||||
Type string
|
// Name is the volume name used to reference this volume in container mounts.
|
||||||
Source string
|
Name string
|
||||||
Target string
|
Type string
|
||||||
ReadOnly bool
|
BindOptions *BindOptions `json:",omitempty"`
|
||||||
Bind *VolumeBind
|
TmpfsOptions *mount.TmpfsOptions `json:",omitempty"`
|
||||||
// TODO: add options for tmpfs.
|
VolumeOptions *VolumeOptions `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type VolumeBind struct {
|
// BindOptions represents options for a bind volume.
|
||||||
CreateHostPath bool
|
type BindOptions struct {
|
||||||
Propagation mount.Propagation
|
// HostPath is the absolute path on the host filesystem.
|
||||||
SELinux string
|
HostPath string
|
||||||
|
// AutoCreate indicates whether the host path should be created if it doesn't exist.
|
||||||
|
// If false, deployment will fail if the path doesn't exist.
|
||||||
|
AutoCreate bool `json:",omitempty"`
|
||||||
|
Propagation mount.Propagation `json:",omitempty"`
|
||||||
|
SELinux string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VolumeOptions represents options for a managed volume.
|
||||||
|
type VolumeOptions struct {
|
||||||
|
// AutoCreate indicates whether the volume should be created if it doesn't exist.
|
||||||
|
// If false, deployment will fail if the volume doesn't exist.
|
||||||
|
AutoCreate bool `json:",omitempty"`
|
||||||
|
// Driver specifies the volume driver and its options for volume creation (AutoCreate is true).
|
||||||
|
Driver *mount.Driver `json:",omitempty"`
|
||||||
|
// Labels are key-value metadata to apply to the volume if creating a new volume.
|
||||||
|
Labels map[string]string `json:",omitempty"`
|
||||||
|
// Name of the managed volume to use. If not specified, defaults to the VolumeSpec.Name.
|
||||||
|
Name string `json:",omitempty"`
|
||||||
|
// NoCopy prevents automatic copying of data from the container mount path to the volume.
|
||||||
|
NoCopy bool `json:",omitempty"`
|
||||||
|
// SubPath is the path within the volume to mount instead of its root.
|
||||||
|
SubPath string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VolumeSpec) Validate() error {
|
func (v *VolumeSpec) Validate() error {
|
||||||
switch v.Type {
|
if v.Name == "" {
|
||||||
case VolumeTypeBind, VolumeTypeVolume:
|
return fmt.Errorf("volume name must not be empty")
|
||||||
default:
|
|
||||||
return fmt.Errorf("invalid volume type: '%s'", v.Type)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(v.Target, "/") {
|
switch v.Type {
|
||||||
return fmt.Errorf("invalid volume target: '%s', must be an absolute path in the container", v.Target)
|
case VolumeTypeBind, VolumeTypeVolume, VolumeTypeTmpfs:
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid volume type: '%s', must be one of '%s', '%s', '%s')",
|
||||||
|
v.Type, VolumeTypeBind, VolumeTypeVolume, VolumeTypeTmpfs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VolumeMount defines how a volume is mounted into a container.
|
||||||
|
type VolumeMount struct {
|
||||||
|
// VolumeName references a volume defined in ServiceSpec.Volumes by its Name field.
|
||||||
|
VolumeName string
|
||||||
|
// ContainerPath is the absolute path where the volume is mounted in the container.
|
||||||
|
ContainerPath string
|
||||||
|
// ReadOnly indicates whether the volume should be mounted read-only.
|
||||||
|
// If false (default), the volume is mounted read-write.
|
||||||
|
ReadOnly bool `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *VolumeMount) Validate() error {
|
||||||
|
if m.VolumeName == "" {
|
||||||
|
return fmt.Errorf("volume name must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(m.ContainerPath, "/") {
|
||||||
|
return fmt.Errorf("invalid container path: '%s', must be an absolute path in the container", m.ContainerPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user