volumes

package
v0.7.21 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package volumes translates a named, tenant-scoped platform volume into a concrete mount the existing pkg/mounts pipeline already knows how to realize.

A platform volume is NOT a new storage primitive. The operator configures one shared backend (S3 or NFS); a volume named "data" for tenant T becomes a synthesized models.MountSpec pointing at a deterministic, per-tenant path:

s3   →  s3://<bucket>/<prefix>/<tenant>/<name>/      (operator creds)
nfs  →  <server>:/<export>/<tenant>/<name>           (no creds, kernel mount)

Because the path is keyed by an operator-derived tenant segment plus a sanitized name, the *backing store* is the single source of truth: any node (cluster or not) that mounts the same coordinates sees the same data. That is what makes platform volumes correct under cluster placement, where a sandbox can land on a different host than the one that first created the volume.

This package is deliberately free of dependencies on internal/config and the auth layer so it stays pure and offline-testable. The daemon maps its config into Backend; the service extracts the caller identity into Caller.

Index

Constants

View Source
const (
	BackendS3  = "s3"
	BackendNFS = "nfs"
)
View Source
const MaxVolumeNameLen = 64

MaxVolumeNameLen bounds a volume name so it can never blow up a storage path.

Variables

This section is empty.

Functions

func BuildMountSpec

func BuildMountSpec(b Backend, tenant, name, target string, readOnly bool) (models.MountSpec, error)

BuildMountSpec synthesizes the MountSpec for one volume reference. tenant must already be a TenantScope result; name is sanitized here. The returned spec is fed straight into the existing seal + MountAll path; full target-path policy (blocked dirs, dup targets, count cap) is enforced by MountSpec.Validate in the service, not duplicated here.

func BuildMountSpecForSource

func BuildMountSpecForSource(b Backend, source, target string, readOnly bool) (models.MountSpec, error)

BuildMountSpecForSource synthesizes a MountSpec for an explicit, already-known backend coordinate. This is the path callers use for an existing volume whose source was frozen at creation (volumes.source): the data must mount exactly where it was created even if the operator later reconfigured the bucket/prefix or export, so the stored source — not a recompute from current config — is authoritative. BuildMountSpec is the create-time wrapper that derives source from (tenant, name) and delegates here.

func CheckQuota

func CheckQuota(currentCount, maxPerTenant int) error

CheckQuota enforces the per-tenant volume-count cap at create/attach time. maxPerTenant <= 0 means unlimited. currentCount is the tenant's existing distinct volume count; creating one more must not exceed the cap.

func ExecRunner

func ExecRunner(ctx context.Context, extraEnv []string, name string, args ...string) error

ExecRunner is the production Runner: it executes the command (with extraEnv appended to the process environment) and folds any stderr/stdout into the returned error for operator logs. Reclaim commands produce little output, so capturing combined output is cheap.

func MountSource

func MountSource(b Backend, tenant, sanitizedName string) (string, error)

MountSource computes the deterministic backend coordinate for a volume. name must already be sanitized. It is the single source of truth shared by BuildMountSpec (to mount) and the attacher check (to recognize an existing mount of a given volume), so the two can never drift.

func SanitizeVolumeName

func SanitizeVolumeName(name string) (string, error)

SanitizeVolumeName normalizes a user-supplied volume name to a single, safe path segment. It lowercases, permits only [a-z0-9._-], and rejects anything that could escape its path component (separators, traversal, over-length, or the reserved "." / ".." names). The returned name is guaranteed to round-trip to exactly one path segment.

func TenantScope

func TenantScope(c Caller) (string, error)

TenantScope returns the path segment that isolates one tenant's volumes from another's. This is the load-bearing security boundary: two tenants using the name "data" MUST map to disjoint paths. It is derived entirely server-side and is stable across restarts.

Types

type Backend

type Backend struct {
	Kind string // "s3" or "nfs"

	// S3 backend.
	S3Bucket          string
	S3Prefix          string
	S3Region          string
	S3Endpoint        string
	S3AccessKeyID     string
	S3SecretAccessKey string

	// NFS backend.
	NFSServer  string
	NFSExport  string
	NFSOptions string
}

Backend is the operator-configured storage that platform volumes live on. It mirrors the relevant fields of config.PlatformVolumesConfig without importing it (which would couple this pure package to the env loader).

type Caller

type Caller struct {
	OwnerRef  string // stable per-tenant account key (managed build)
	Operator  bool   // true for the operator PAT path (no per-tenant identity)
	HasAccess bool   // false for background/internal calls with no auth edge
	PATToken  string // operator token, hashed as the fallback scope segment
}

Caller carries the authenticated identity the tenant scope is derived from. The service builds this from controlplane.AccessFromContext; we take primitives so this package never imports the auth layer.

  • Operator/no-access (the open-source PAT path) has no per-tenant identity, so we fall back to a stable hash of the operator token. That collapses to a single self-host tenant, which is correct for single-tenant deploys.
  • A validated user token carries a stable OwnerRef = the tenant key.

type Reclaimer

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

Reclaimer deletes the backing bytes of a deleted platform volume. It is the missing consumer of the pending_volume_deletions ledger: DeletePlatformVolume only removes the metadata row and records coordinates; this is what actually reclaims the S3 prefix / NFS directory.

The repo deliberately carries no AWS SDK — sandbox mounts are realized by the mount-s3 binary — so backend deletion shells out to the same CLI tooling the host already needs (the AWS CLI for S3, mount(8) + the kernel NFS client for NFS). Commands run through an injected Runner so the command construction is unit-testable offline; make test never executes a real delete.

func NewReclaimer

func NewReclaimer(backend Backend, mountRoot string, run Runner) *Reclaimer

NewReclaimer builds a Reclaimer for the operator's configured backend. region / endpoint live on the Backend so S3 deletes hit the same store the mounts do.

func (*Reclaimer) Reclaim

func (r *Reclaimer) Reclaim(ctx context.Context, backendKind, source string) error

Reclaim deletes the data at source for the given backend kind. It is idempotent: deleting an already-empty or already-gone prefix/dir is success, so a ledger row can be retried until the row is removed. backendKind is the volume's stored backend (authoritative over the operator's current default, so a volume created under s3 still reclaims from s3 after a reconfigure).

type Runner

type Runner func(ctx context.Context, extraEnv []string, name string, args ...string) error

Runner executes one external command with extraEnv appended to its environment. The default wires exec.CommandContext; tests inject a recorder. extraEnv carries S3 static credentials so the AWS CLI deletes with the same keys the mount path uses rather than relying on the host's ambient chain.

Jump to

Keyboard shortcuts

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