Storage Package Reference¶
pkg/storage/— Volume Manager, Secret Manager, and DebugFS Injection.
Overview¶
The pkg/storage package provides storage abstractions for Firecracker VMs, including volume management (directory and block drivers), secret/config injection, and debugfs operations for ext4 rootfs modification.
Package Structure:
pkg/storage/
├── volume.go # VolumeManager (dispatcher)
├── volume_dir.go # DirectoryDriver (host directory volumes)
├── volume_block.go # BlockDriver (block device volumes)
├── volume_meta.go # MetaStore (volume metadata)
├── volume_quota.go # Quota management
├── credential_store.go # SecretManager (secrets/configs)
├── driver.go # VolumeDriver interface
└───────────────────────┴────────────────────────────────────────────────────
VolumeManager¶
File: volume.go
The VolumeManager dispatches volume operations to appropriate drivers.
Type Definition¶
type VolumeManager struct {
drivers map[VolumeType]VolumeDriver
defaultType VolumeType
mu sync.RWMutex
}
Volume Types¶
type VolumeType string
const (
VolumeTypeDir VolumeType = "dir" // Host directory
VolumeTypeBlock VolumeType = "block" // Block device
)
Volume Struct¶
type Volume struct {
ID string `json:"id"` // Sanitized name
Name string `json:"name"` // Original name
Path string `json:"path"` // Volume path
TaskID string `json:"task_id"` // Associated task
}
Constructor¶
func NewVolumeManager(volumesDir string) (*VolumeManager, error)
Parameters: - volumesDir — Base directory for volumes (default: /var/lib/swarmcracker/volumes)
Example:
vm, err := storage.NewVolumeManager("/var/lib/swarmcracker/volumes")
if err != nil {
log.Fatal(err)
}
Methods¶
CreateVolume (Legacy)¶
func (vm *VolumeManager) CreateVolume(ctx context.Context, name, taskID string, sizeMB int) (*Volume, error)
Purpose: Create volume with default type (dir).
CreateVolumeWithOptions¶
func (vm *VolumeManager) CreateVolumeWithOptions(ctx context.Context, name, taskID string, opts CreateOptions) (*Volume, error)
Purpose: Create volume with full options.
type CreateOptions struct {
Type VolumeType
SizeMB int
Quota QuotaConfig
Labels map[string]string
}
Example:
vol, err := vm.CreateVolumeWithOptions(ctx, "data-vol", "task-123", storage.CreateOptions{
Type: storage.VolumeTypeDir,
SizeMB: 1024,
})
GetVolume¶
func (vm *VolumeManager) GetVolume(name string) (*Volume, error)
Purpose: Retrieve volume handle by name.
GetVolumeInfo¶
func (vm *VolumeManager) GetVolumeInfo(ctx context.Context, name string, volType VolumeType) (*VolumeInfo, error)
Purpose: Get detailed volume info.
type VolumeInfo struct {
Name string
Type VolumeType
SizeMB int
UsedMB int64
CreatedAt time.Time
LastUsedAt time.Time
TaskID string
}
MountVolume¶
func (vm *VolumeManager) MountVolume(ctx context.Context, vol *Volume, rootfsPath, target string) error
Purpose: Copy volume data into rootfs at target path.
Implementation (DirectoryDriver): 1. Copy directory contents to rootfs subdirectory 2. Preserve permissions and ownership
UnmountVolume¶
func (vm *VolumeManager) UnmountVolume(ctx context.Context, vol *Volume, rootfsPath, target string, readOnly bool) error
Purpose: Sync data back from rootfs to volume.
DeleteVolume¶
func (vm *VolumeManager) DeleteVolume(ctx context.Context, name string) error
Purpose: Remove volume and its data.
ListVolumes¶
func (vm *VolumeManager) ListVolumes(ctx context.Context) ([]*Volume, error)
Purpose: List all volumes.
ListVolumeInfos¶
func (vm *VolumeManager) ListVolumeInfos(ctx context.Context) ([]*VolumeInfo, error)
Purpose: List detailed volume info.
SnapshotVolume¶
func (vm *VolumeManager) SnapshotVolume(ctx context.Context, name string) (*Snapshot, error)
Purpose: Create point-in-time snapshot.
RestoreVolume¶
func (vm *VolumeManager) RestoreVolume(ctx context.Context, name string, snap *Snapshot) error
Purpose: Restore from snapshot.
DirectoryDriver¶
File: volume_dir.go
Host directory-backed volumes.
Type Definition¶
type DirectoryDriver struct {
baseDir string
meta *MetaStore
quotaMgr *QuotaManager
}
Constructor¶
func NewDirectoryDriver(baseDir string) (*DirectoryDriver, error)
Methods¶
Create¶
func (d *DirectoryDriver) Create(ctx context.Context, name string, opts CreateOptions) (string, error)
Purpose: Create directory volume.
Implementation:
volPath := filepath.Join(d.baseDir, sanitizeVolumeName(name))
os.MkdirAll(volPath, 0755)
// Apply quota if specified
if opts.Quota.Enabled {
d.quotaMgr.SetQuota(volPath, opts.Quota.MaxBytes)
}
Mount¶
func (d *DirectoryDriver) Mount(ctx context.Context, name, rootfsPath, target string) error
Purpose: Copy volume contents into rootfs using debugfs.
Implementation:
// For each file in volume:
debugfs -w rootfsPath -R "write <src> <target>"
Unmount¶
func (d *DirectoryDriver) Unmount(ctx context.Context, name, rootfsPath, target string, readOnly bool) error
Purpose: Copy rootfs data back to volume.
Delete¶
func (d *DirectoryDriver) Delete(ctx context.Context, name string) error
Stat¶
func (d *DirectoryDriver) Stat(ctx context.Context, name string) (*VolumeInfo, error)
BlockDriver¶
File: volume_block.go
Block device-backed volumes for high-performance I/O.
Type Definition¶
type BlockDriver struct {
baseDir string
meta *MetaStore
}
Constructor¶
func NewBlockDriver(baseDir string) (*BlockDriver, error)
Methods¶
Create¶
func (b *BlockDriver) Create(ctx context.Context, name string, opts CreateOptions) (string, error)
Purpose: Create block device volume.
Implementation: 1. Create qcow2 or raw image file 2. Setup loop device 3. Format with ext4
Mount¶
func (b *BlockDriver) Mount(ctx context.Context, name, rootfsPath, target string) error
Purpose: Mount block volume and copy to rootfs.
Snapshot¶
func (b *BlockDriver) Snapshot(ctx context.Context, name string) (*Snapshot, error)
Purpose: Create qcow2 snapshot.
MetaStore¶
File: volume_meta.go
JSON-based volume metadata storage.
Type Definition¶
type MetaStore struct {
metaDir string
mu sync.RWMutex
}
type VolumeMeta struct {
Name string `json:"name"`
Type VolumeType `json:"type"`
SizeMB int `json:"size_mb"`
CreatedAt time.Time `json:"created_at"`
LastUsedAt time.Time `json:"last_used_at"`
TaskID string `json:"task_id"`
Quota QuotaInfo `json:"quota"`
}
Methods¶
func (m *MetaStore) Save(ctx context.Context, meta *VolumeMeta) error
func (m *MetaStore) Load(ctx context.Context, name string) (*VolumeMeta, error)
func (m *MetaStore) List(ctx context.Context) ([]*VolumeMeta, error)
func (m *MetaStore) Delete(ctx context.Context, name string) error
func (m *MetaStore) UpdateTaskID(ctx context.Context, name, taskID string) error
Quota Management¶
File: volume_quota.go
Type Definition¶
type QuotaManager struct {
enabled bool
}
type QuotaConfig struct {
Enabled bool
MaxBytes int64
}
Methods¶
func (q *QuotaManager) SetQuota(path string, maxBytes int64) error
func (q *QuotaManager) GetUsage(path string) (int64, error)
Implementation (Linux):
# Set project quota
setquota -P <project-id> <soft> <hard> 0 0 <path>
SecretManager¶
File: credential_store.go
Manages secrets and configs injection into VM rootfs.
Type Definition¶
type SecretManager struct {
secretsDir string
configsDir string
}
Constructor¶
func NewSecretManager(secretsDir, configsDir string) *SecretManager
Methods¶
InjectSecret¶
func (sm *SecretManager) InjectSecret(ctx context.Context, rootfsPath, targetPath string, secretData []byte) error
Purpose: Inject secret file into rootfs.
Implementation:
// Use debugfs to write file
debugfs -w rootfsPath -R "write <temp-file> <target-path>"
InjectConfig¶
func (sm *SecretManager) InjectConfig(ctx context.Context, rootfsPath, targetPath string, configData []byte) error
Purpose: Inject config file into rootfs.
ListSecrets¶
func (sm *SecretManager) ListSecrets(ctx context.Context) ([]string, error)
DeleteSecret¶
func (sm *SecretManager) DeleteSecret(ctx context.Context, name string) error
Volume Reference Helpers¶
File: volume.go
IsVolumeReference¶
func IsVolumeReference(source string) bool
Purpose: Check if mount source is a volume reference.
Rules: - volume://name → Volume reference - name (no slashes) → Volume reference - /path/to/dir → Host path (not volume)
ExtractVolumeName¶
func ExtractVolumeName(source string) string
Purpose: Extract volume name from reference.
IsVolumeReference("volume://data") // true → "data"
IsVolumeReference("data") // true → "data"
IsVolumeReference("/var/data") // false → ""
Testing¶
Mock VolumeManager¶
type MockVolumeManager struct {
Volumes map[string]*Volume
}
func (m *MockVolumeManager) CreateVolume(ctx context.Context, name, taskID string, sizeMB int) (*Volume, error) {
vol := &Volume{
ID: name,
Name: name,
Path: "/mock/" + name,
}
m.Volumes[name] = vol
return vol, nil
}
Error Handling¶
Common Errors¶
| Error | Cause | Resolution |
|---|---|---|
"volume name cannot be empty" | Empty name | Provide valid name |
"volume not found" | Invalid name | Check volume exists |
"no driver registered for type" | Unknown type | Use dir or block |
"block driver unavailable" | Not root | Run with privileges |
"quota not supported" | No quota support | Enable project quotas |
Related Documentation¶
| Topic | Document |
|---|---|
| SwarmKit executor | SwarmKit Reference |
| Image preparation | Image Reference |
| Operations guide | Operations Guide |