volumes

package
v0.0.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 3, 2026 License: MIT Imports: 19 Imported by: 0

README

Volumes

Volumes are persistent block storage that exist independently of instances. They allow data to survive instance deletion and be reattached to new instances.

Lifecycle

  1. Create - POST /volumes creates an ext4-formatted sparse disk file of the specified size
  2. Create from Archive - POST /volumes/from-archive creates a volume pre-populated with content from a tar.gz file
  3. Attach - Specify volumes in CreateInstanceRequest.volumes with a mount path
  4. Use - Volume appears as a block device inside the guest, mounted at the specified path
  5. Detach - Volumes are automatically detached when an instance is deleted
  6. Delete - DELETE /volumes/{id} removes the volume (fails if still attached)

Cloud Hypervisor Integration

When an instance with volumes is created, each volume's raw disk file is passed to Cloud Hypervisor as an additional DiskConfig entry in the VM configuration. The disks appear in order as /dev/vdX devices:

  • /dev/vda - rootfs (read-only image)
  • /dev/vdb - overlay (writable instance storage)
  • /dev/vdc - config disk (read-only)
  • /dev/vdd, /dev/vde, ... - attached volumes

The init process inside the guest reads the requested mount paths from the config disk and mounts each volume at its specified path.

Multi-Attach (Read-Only Sharing)

A single volume can be attached to multiple instances simultaneously if all attachments are read-only. This enables sharing static content (libraries, datasets, config files) across many VMs without duplication.

Rules:

  • First attachment can be read-write or read-only
  • If any attachment is read-write, no other attachments are allowed
  • If all existing attachments are read-only, additional read-only attachments are allowed
  • Cannot add read-write attachment to a volume with existing attachments

Overlay Mode

When attaching a volume with overlay: true, the instance gets copy-on-write semantics:

  • Base volume is mounted read-only (shared)
  • A per-instance overlay disk captures all writes
  • Instance sees combined view: base data + its local changes
  • Other instances don't see each other's overlay writes (isolated)

This allows multiple instances to share a common base (e.g., dataset, model weights) while each can make local modifications without affecting others. Requires readonly: true and overlay_size specifying the max size of per-instance writes.

Creating Volumes from Archives

Volumes can be created with initial content by uploading a tar.gz archive via POST /volumes/from-archive. This is useful for pre-populating volumes with datasets, configuration files, or application data.

Request: Multipart form with fields:

  • name - Volume name (required)
  • size_gb - Maximum size in GB (required, extraction fails if content exceeds this)
  • id - Optional custom volume ID
  • content - tar.gz file (required)

Safety: The extraction process protects against adversarial archives:

  • Tracks cumulative extracted size and aborts if limit exceeded
  • Validates paths to prevent directory traversal attacks
  • Rejects absolute paths and symlinks that escape the destination

The resulting volume size is automatically calculated from the extracted content (with filesystem overhead), not the specified size_gb which serves as an upper limit.

Constraints

  • Volumes can only be attached at instance creation time (no hot-attach)
  • Deleting an instance detaches its volumes but does not delete them
  • Cannot delete a volume while it has any attachments

Storage

Volumes are stored as sparse raw disk files at {dataDir}/volumes/{id}/data.raw, pre-formatted as ext4. Sparse files only consume actual disk space for written data.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrArchiveTooLarge is returned when extracted content exceeds the size limit
	ErrArchiveTooLarge = errors.New("archive content exceeds size limit")
	// ErrInvalidArchivePath is returned when a tar entry has a malicious path
	ErrInvalidArchivePath = errors.New("invalid archive path")
)
View Source
var (
	ErrNotFound      = errors.New("volume not found")
	ErrInUse         = errors.New("volume is in use")
	ErrAlreadyExists = errors.New("volume already exists")
	ErrAmbiguousName = errors.New("multiple volumes with the same name")
)

Functions

func ExtractTarGz

func ExtractTarGz(r io.Reader, destDir string, maxBytes int64) (int64, error)

ExtractTarGz extracts a tar.gz archive to destDir, aborting if the extracted content exceeds maxBytes. Returns the total extracted bytes on success.

Security considerations (runs with elevated privileges): This function implements multiple layers of defense against malicious archives: 1. Path validation - rejects absolute paths and path traversal attempts upfront 2. securejoin - safe path joining that resolves symlinks within the root 3. O_NOFOLLOW - prevents following symlinks when creating files (defense in depth) 4. Size limiting - tracks cumulative size and aborts if limit exceeded 5. io.LimitReader - secondary protection when copying file contents

The destination directory should be a freshly created temp directory to minimize TOCTOU attack surface. The same approach is used by umoci and containerd.

Types

type AttachVolumeRequest

type AttachVolumeRequest struct {
	InstanceID string
	MountPath  string
	Readonly   bool
}

AttachVolumeRequest is the domain request for attaching a volume to an instance

type Attachment

type Attachment struct {
	InstanceID string
	MountPath  string
	Readonly   bool
}

Attachment represents a volume attached to an instance

type CreateVolumeFromArchiveRequest

type CreateVolumeFromArchiveRequest struct {
	Name   string
	SizeGb int     // Maximum size in GB (extraction fails if content exceeds this)
	Id     *string // Optional custom ID
}

CreateVolumeFromArchiveRequest is the domain request for creating a volume pre-populated with content from a tar.gz archive

type CreateVolumeRequest

type CreateVolumeRequest struct {
	Name   string
	SizeGb int
	Id     *string // Optional custom ID
}

CreateVolumeRequest is the domain request for creating a volume

type Manager

type Manager interface {
	ListVolumes(ctx context.Context) ([]Volume, error)
	CreateVolume(ctx context.Context, req CreateVolumeRequest) (*Volume, error)
	CreateVolumeFromArchive(ctx context.Context, req CreateVolumeFromArchiveRequest, archive io.Reader) (*Volume, error)
	GetVolume(ctx context.Context, id string) (*Volume, error)
	GetVolumeByName(ctx context.Context, name string) (*Volume, error)
	DeleteVolume(ctx context.Context, id string) error

	// Attachment operations (called by instance manager)
	// Multi-attach rules:
	// - If no attachments: allow any mode (rw or ro)
	// - If existing attachment is rw: reject all new attachments
	// - If existing attachments are ro: only allow new ro attachments
	AttachVolume(ctx context.Context, id string, req AttachVolumeRequest) error
	DetachVolume(ctx context.Context, volumeID string, instanceID string) error

	// GetVolumePath returns the path to the volume data file
	GetVolumePath(id string) string

	// TotalVolumeBytes returns the total size of all volumes.
	// Used by the resource manager for disk capacity tracking.
	TotalVolumeBytes(ctx context.Context) (int64, error)
}

Manager provides volume lifecycle operations

func NewManager

func NewManager(p *paths.Paths, maxTotalVolumeStorage int64, meter metric.Meter) Manager

NewManager creates a new volumes manager. maxTotalVolumeStorage is the maximum total volume storage in bytes (0 = unlimited). If meter is nil, metrics are disabled.

type Metrics

type Metrics struct {
	// contains filtered or unexported fields
}

Metrics holds the metrics instruments for volume operations.

type Volume

type Volume struct {
	Id          string
	Name        string
	SizeGb      int
	CreatedAt   time.Time
	Attachments []Attachment // List of current attachments (empty if not attached)
}

Volume represents a persistent block storage volume

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL