driver

package
v0.0.1-dev.137 Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package driver defines the storage driver interface that the Rune VolumeController and node-side agent talk to. Built-in drivers live in subpackages (driver/local, driver/dovolume, ...) and register themselves with the registry from init().

Introduced in RUNE-069.

Package driver — registry for storage drivers.

Drivers register themselves in init() via Register(). The runed binary blank-imports each built-in driver package from cmd/runed/main.go; out-of-tree drivers are added by adding one more blank-import.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnsupported is returned by drivers that lack the requested
	// capability (e.g. local-host calling Snapshot).
	ErrUnsupported = errors.New("storage driver: operation unsupported")

	// ErrNotFound is returned when a handle has no backing store. Delete
	// implementations SHOULD swallow this internally and return nil to
	// preserve idempotency.
	ErrNotFound = errors.New("storage driver: handle not found")

	// ErrInvalidConfig is returned for misconfigured StorageClass /
	// Volume parameters (bad fsType, missing required field, ...).
	ErrInvalidConfig = errors.New("storage driver: invalid configuration")

	// ErrOnlineExpandUnsupported is returned by Expand when the driver
	// requires the volume to be detached first.
	ErrOnlineExpandUnsupported = errors.New("storage driver: online expand unsupported")

	// ErrAccessModeUnsupported is returned by Provision when the requested
	// AccessMode is not in Capabilities.AccessModes.
	ErrAccessModeUnsupported = errors.New("storage driver: access mode unsupported")
)

Sentinel errors. Drivers SHOULD wrap these with %w when returning richer context so callers can use errors.Is.

Functions

func Register

func Register(name string, factory Factory)

Register adds a driver factory under the given name. Panics if name is empty or already registered — driver registration happens at init() time in operator-controlled code, so a duplicate name is a programming bug that must not be papered over at runtime.

func Registered

func Registered() []string

Registered returns the sorted list of currently-registered driver names. Useful for diagnostics and the API-server's StorageClass linter.

Types

type Capabilities

type Capabilities struct {
	// AccessModes is the set of access modes the driver can satisfy.
	AccessModes []types.AccessMode

	// Snapshots indicates Snapshot/RestoreFromSnapshot are implemented.
	Snapshots bool

	// Expand indicates Expand is implemented (some drivers only support
	// offline expand — see Driver.Expand docs).
	Expand bool

	// OnlineExpand is true if Expand may be called while the volume is
	// Bound (without first detaching).
	OnlineExpand bool

	// BlockDevice is true if the driver exposes a raw block device the
	// runner is expected to format/mount itself. Directory-style drivers
	// (local, local-host, NFS) set this to false.
	BlockDevice bool

	// TopologyKeys are the well-known label keys this driver consumes from
	// StorageClass.AllowedTopologies. Used by the API-server linter to
	// reject unknown keys early.
	TopologyKeys []string
}

Capabilities describes the optional features a driver supports.

type DevicePath

type DevicePath string

DevicePath is a node-local block device path returned by Attach (e.g. "/dev/disk/by-id/scsi-0DO_Volume_flo-data"). Empty for directory drivers.

type Driver

type Driver interface {
	// Name returns the registered driver name (e.g. "local", "do-volume").
	// Must match the registry key.
	Name() string

	// Capabilities describes what this driver supports. Returned values are
	// expected to be stable for the lifetime of the process.
	Capabilities() Capabilities

	// Provision creates a new backing store for the volume and returns an
	// opaque handle that subsequent calls (Attach, Snapshot, ...) re-parse.
	// MUST be idempotent on Volume.ID — the controller retries on failure.
	Provision(ctx context.Context, opctx OpContext, req ProvisionRequest) (VolumeHandle, error)

	// Delete destroys the backing store identified by handle. Implementations
	// MUST tolerate missing/already-deleted handles (return nil).
	Delete(ctx context.Context, opctx OpContext, handle VolumeHandle) error

	// Attach makes the volume available to the named node (e.g. attaches a
	// cloud block device, opens an iSCSI session, no-ops for local
	// directories). Returns the device path the node should Mount.
	// For drivers that don't have a separate attach step, return an empty
	// DevicePath and a nil error.
	Attach(ctx context.Context, opctx OpContext, handle VolumeHandle, node NodeID) (DevicePath, error)

	// Detach is the inverse of Attach. Idempotent.
	Detach(ctx context.Context, opctx OpContext, handle VolumeHandle, node NodeID) error

	// Mount makes the volume usable at MountTarget. For block-device drivers
	// this typically formats (if needed) and mounts; for directory-style
	// drivers it bind-mounts or returns the source path the runner should
	// bind-mount itself. The returned MountTarget is what the runner uses —
	// drivers may rewrite it (e.g. local-host returns the host path
	// directly rather than the proposed Target).
	Mount(ctx context.Context, opctx OpContext, opts MountOpts) (MountTarget, error)

	// Unmount is the inverse of Mount. Idempotent.
	Unmount(ctx context.Context, opctx OpContext, target MountTarget) error

	// Snapshot creates a point-in-time snapshot of the volume. Drivers
	// without snapshot support (Capabilities.Snapshots == false) MUST return
	// ErrUnsupported.
	Snapshot(ctx context.Context, opctx OpContext, req SnapshotRequest) (SnapshotHandle, error)

	// RestoreFromSnapshot provisions a NEW volume from a snapshot. The
	// returned handle replaces the volume's existing handle. OpContext
	// here describes the TARGET volume + its class — the source snapshot
	// is carried on RestoreRequest.
	// Drivers without snapshot support MUST return ErrUnsupported.
	RestoreFromSnapshot(ctx context.Context, opctx OpContext, req RestoreRequest) (VolumeHandle, error)

	// DeleteSnapshot destroys the snapshot identified by handle. MUST be
	// idempotent — implementations should swallow ErrNotFound and return
	// nil so the controller can re-drive a Deleting snapshot safely.
	// Drivers without snapshot support MUST return ErrUnsupported.
	DeleteSnapshot(ctx context.Context, opctx OpContext, handle SnapshotHandle) error

	// Expand grows the volume to NewSize. Online expansion vs offline is
	// driver-dependent; drivers that only support offline expand (e.g.
	// do-volume) MUST refuse if the volume is currently Bound and return
	// ErrOnlineExpandUnsupported.
	// Drivers without expand support (Capabilities.Expand == false) MUST
	// return ErrUnsupported.
	Expand(ctx context.Context, opctx OpContext, handle VolumeHandle, newSize string) error
}

Driver is the contract every storage backend implements. The interface is deliberately not CSI: it captures only what Rune needs in v1 and keeps the surface narrow enough for in-process Go drivers. A future CSI shim driver can wrap external CSI plugins behind this same interface.

The leader-side VolumeController calls Provision, Delete, Snapshot, RestoreFromSnapshot and Expand. Node-side agents call Attach, Detach, Mount and Unmount. Capabilities and Name are pure metadata.

Every operation method takes an OpContext as the second argument (after ctx). The controller / agent populates it with the resolved StorageClass, the Volume row, and the merged parameter map. Drivers consult OpContext for any per-class / per-volume configuration they need (region, fsType, auth references, …) — the v0.0.1-dev.46 fix routed Volume.Size into the driver layer the same way; this generalises the pattern to all driver methods so per-class config no longer has to live in the runefile only. See RUNE-200.

All methods MUST be context-aware and idempotent: the controller and agent retry on transient failures.

func New

func New(name string, config map[string]any) (Driver, error)

New is a convenience that looks up name and invokes the factory with config. Returns a wrapped error if either step fails.

type Factory

type Factory func(config map[string]any) (Driver, error)

Factory constructs a Driver from operator-supplied config (parsed from the runefile [storage.<name>] section). Returning an error here is fatal — the controller will refuse to start with an unconfigurable driver.

config is the raw map for the runefile section; drivers decode it themselves to keep this package free of viper/koanf dependencies.

func Lookup

func Lookup(name string) (Factory, bool)

Lookup returns the factory registered under name, or false if none. Used by the controller at boot to instantiate drivers referenced by StorageClass.Driver.

func MustLookup

func MustLookup(name string) Factory

MustLookup is the panic-on-missing variant. Reserved for tests and init-time wiring where a missing driver is unambiguously a bug.

type MountOpts

type MountOpts struct {
	Handle   VolumeHandle
	Node     NodeID
	Device   DevicePath  // device returned by Attach (empty for directory drivers)
	Target   MountTarget // proposed mount target (may be rewritten by driver)
	ReadOnly bool
	// FsType is the filesystem to format with on first mount of a block
	// device. Ignored by directory drivers. Sourced from StorageClass /
	// Volume parameters.
	FsType string
}

MountOpts is the input to Driver.Mount. The Volume lives on the accompanying OpContext.

type MountTarget

type MountTarget string

MountTarget is a node-local filesystem path the runner consumes when it bind-mounts the volume into a container.

type NodeID

type NodeID string

NodeID identifies a node in the Rune cluster (matches types.Node.ID).

type OpContext

type OpContext struct {
	// StorageClass that this operation is acting on. May be nil for
	// orphan deletes (class removed before its volumes). Live operations
	// always carry the resolved class.
	StorageClass *types.StorageClass

	// Volume is the row this operation pertains to. Always non-nil for
	// volume-scoped operations (every method on the interface).
	Volume *types.Volume

	// Parameters is StorageClass.Parameters with Volume.Parameters
	// overlaid on top, pre-merged by the caller. Drivers consult this
	// map for per-class configuration (region, fsType, auth refs, etc.)
	// rather than re-merging themselves.
	Parameters map[string]string

	// NodeHostname is the OS hostname (os.Hostname()) of the agent
	// running this call, populated by the controller / agent at
	// build time. Cloud-backed drivers use it to map Rune's node
	// identity onto the cloud provider's instance identity — DO
	// droplets, for example, are addressable by their hostname-derived
	// name via /v2/droplets?name=... Empty when the caller has no
	// hostname to report (controller-only operations like Provision /
	// Delete that don't run on a specific node, or tests).
	NodeHostname string
}

OpContext is the per-call context every Driver method receives as the second positional argument (after ctx). The controller / agent builds it before each call so drivers can consult per-class / per-volume configuration without holding it as instance state. Drivers MUST treat OpContext fields as read-only.

StorageClass MAY be nil — orphan deletes (the class was deleted before its volumes were reclaimed) carry only Volume + Parameters, where Parameters comes from Volume.Metadata.DriverParameters as a snapshot taken at Provision time (see RUNE-200 PR 2).

Parameters is always populated (may be empty). Drivers MUST consult Parameters rather than re-merging StorageClass.Parameters with Volume.Parameters themselves.

type ProvisionRequest

type ProvisionRequest struct {
	// SizeBytes is Volume.Size already parsed into bytes by the controller.
	// Drivers that need the original string can read OpContext.Volume.Size.
	SizeBytes int64

	// Topology is the topology constraint the controller selected for this
	// provision (the chosen TopologySelector after intersecting
	// StorageClass.AllowedTopologies with node availability). Empty means
	// no constraint.
	Topology *types.TopologySelector

	// Deadline is a soft deadline for the operation. Drivers should respect
	// ctx.Done() but may use this for finer-grained internal timeouts.
	Deadline time.Time
}

ProvisionRequest is the input to Driver.Provision. Volume, StorageClass and merged parameters live on the accompanying OpContext; this struct carries only fields specific to the provision operation itself.

type RestoreRequest

type RestoreRequest struct {
	// Source is the snapshot being restored.
	Source       *types.Snapshot
	SourceHandle SnapshotHandle

	// SizeBytes is the target Volume.Size already parsed into bytes.
	SizeBytes int64
}

RestoreRequest is the input to Driver.RestoreFromSnapshot. The TARGET volume and its storage class live on the accompanying OpContext; this struct carries only the source snapshot reference.

type SnapshotHandle

type SnapshotHandle string

SnapshotHandle is the opaque driver identifier for a snapshot.

type SnapshotRequest

type SnapshotRequest struct {
	Handle   VolumeHandle
	Snapshot *types.Snapshot
}

SnapshotRequest is the input to Driver.Snapshot. The Volume being snapshotted lives on the accompanying OpContext.

type UsageReporter

type UsageReporter interface {
	Usage(ctx context.Context, opctx OpContext, handle VolumeHandle) (usedBytes, capacityBytes uint64, err error)
}

UsageReporter is an OPTIONAL capability: drivers that can measure a volume's live on-disk usage implement it (the local directory drivers do, via a bounded directory walk). The API read path type-asserts for it and leaves usage at zero/unknown for drivers without it — cloud block drivers would need a node-local statfs, which requires agent support and is future work.

usedBytes is the measured usage. capacityBytes MAY be 0 when the driver cannot determine a real capacity (directory-backed volumes have no device boundary); callers should then fall back to the volume's spec size.

type VolumeHandle

type VolumeHandle string

VolumeHandle is the opaque, driver-owned identifier returned by Provision and stored on Volume.Handle. The controller treats it as a black-box string; the owning driver re-parses it.

Directories

Path Synopsis
Package awsebs implements the "aws-ebs" storage driver, backed by Amazon EBS (Elastic Block Store) volumes.
Package awsebs implements the "aws-ebs" storage driver, backed by Amazon EBS (Elastic Block Store) volumes.
Package dovolume implements the "do-volume" storage driver — Rune's reference cloud driver, backed by DigitalOcean Block Storage.
Package dovolume implements the "do-volume" storage driver — Rune's reference cloud driver, backed by DigitalOcean Block Storage.
Package gcepd implements the "gce-pd" storage driver, backed by Google Compute Engine Persistent Disks.
Package gcepd implements the "gce-pd" storage driver, backed by Google Compute Engine Persistent Disks.
Package hcloudvolume implements the "hcloud-volume" storage driver — Rune's Hetzner Cloud Block Storage driver.
Package hcloudvolume implements the "hcloud-volume" storage driver — Rune's Hetzner Cloud Block Storage driver.
Package local implements two storage Driver names that ship with the Rune binary:
Package local implements two storage Driver names that ship with the Rune binary:

Jump to

Keyboard shortcuts

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