package volume
import (
"fmt"
"path/filepath"
"strings"
)
type Manager struct {
maxMounts int
backend Backend
}
func NewManager(cfg Config) (*Manager, error) {
backend := strings.TrimSpace(cfg.Backend)
if backend == "" {
backend = DefaultBackend
}
if backend != DefaultBackend {
return nil, fmt.Errorf("unsupported volume backend %q (only %q)", backend, DefaultBackend)
}
return &Manager{
maxMounts: cfg.MaxMounts,
backend: NewVirtiofsBackend(cfg.Virtiofs),
}, nil
}
func (m *Manager) PrepareSandbox(sandboxID string, mounts []Mount) ([]Device, error) {
if len(mounts) == 0 {
return nil, nil
}
if len(mounts) > m.maxMounts {
return nil, ErrInvalidMount.Wrap(fmt.Errorf("volumeMounts exceeds limit %d: %d", m.maxMounts, len(mounts)))
}
seenTargets := map[string]struct{}{}
for _, mount := range mounts {
target := filepath.Clean(strings.TrimSpace(mount.Path))
if !filepath.IsAbs(target) {
return nil, ErrInvalidMount.Wrap(fmt.Errorf("volume mount path must be absolute: %s", mount.Path))
}
if isBlockedTarget(target) {
return nil, ErrInvalidMount.Wrap(fmt.Errorf("volume mount path is not allowed: %s", target))
}
if _, ok := seenTargets[target]; ok {
return nil, ErrInvalidMount.Wrap(fmt.Errorf("duplicate volume mount path: %s", target))
}
seenTargets[target] = struct{}{}
source := filepath.Clean(strings.TrimSpace(mount.Source))
if source == "" {
return nil, ErrInvalidMount.Wrap(fmt.Errorf("volume mount source must not be empty"))
}
if !filepath.IsAbs(source) {
return nil, ErrInvalidMount.Wrap(fmt.Errorf("volume mount source must be absolute: %s", source))
}
}
return m.backend.Prepare(PrepareRequest{
SandboxID: sandboxID,
Mounts: mounts,
})
}
func (m *Manager) CleanupSandbox(sandboxID string, devices []Device) error {
if m == nil || m.backend == nil {
return nil
}
return m.backend.Cleanup(sandboxID, devices)
}
func (m *Manager) CleanupStaleResources() error {
if m == nil || m.backend == nil {
return nil
}
return m.backend.CleanupStaleResources()
}
func isBlockedTarget(target string) bool {
switch target {
case "/", "/proc", "/sys", "/dev", "/run":
return true
}
return strings.HasPrefix(target, "/proc/") ||
strings.HasPrefix(target, "/sys/") ||
strings.HasPrefix(target, "/dev/") ||
strings.HasPrefix(target, "/run/")
}