Documentation
¶
Overview ¶
Package shared provides backend-agnostic components that can be reused across different backend implementations (Docker, Kubernetes, Nomad, etc.).
What lives here ¶
- SKUProfile, ResourceStats, ResourceAllocator (resources.go) — the resource pool primitives used by every backend that tracks CPU/memory/disk
- Registry helpers (registry.go) — image-registry parsing + allowlist validation (ParseRegistry, IsImageAllowed, ValidateImage) used by substrate adapters to enforce per-tenant image policy
- CallbackSender (callback_sender.go) — HMAC-signed callback delivery with bbolt-backed persistence so failure callbacks survive restarts
- BoltStore (bolt_store.go) — small wrapper around bbolt used by the callback, diagnostics, and release stores
- Diagnostics (diagnostics.go) — persisted failure diagnostics with fallback for "lease no longer in memory" reads
- Releases (releases.go) — release/deployment history with TTL cleanup
- Types (types.go) — shared SKU and resource types
All of these are consumed by the docker backend and are usable by any future in-process backend (Kubernetes, Nomad, etc.). HTTP-only backends running in a separate process should reuse callback_sender and the HMAC types but typically maintain their own registry.
Index ¶
- Constants
- Variables
- func IsImageAllowed(image string, allowedRegistries []string) bool
- func ParseRegistry(image string) (string, error)
- func ValidateImage(image string, allowedRegistries []string) error
- type CallbackEntry
- type CallbackSender
- type CallbackSenderConfig
- type CallbackStore
- func (s CallbackStore) Close() error
- func (s CallbackStore) Healthy() error
- func (s *CallbackStore) ListPending() ([]CallbackEntry, error)
- func (s *CallbackStore) Remove(leaseUUID string) error
- func (s *CallbackStore) RemoveOlderThan(maxAge time.Duration) (int, error)
- func (s *CallbackStore) Store(entry CallbackEntry) error
- type CallbackStoreConfig
- type DiagnosticEntry
- type DiagnosticsStore
- func (s DiagnosticsStore) Close() error
- func (s *DiagnosticsStore) Delete(leaseUUID string) error
- func (s *DiagnosticsStore) Get(leaseUUID string) (*DiagnosticEntry, error)
- func (s DiagnosticsStore) Healthy() error
- func (s *DiagnosticsStore) RemoveOlderThan(maxAge time.Duration) (int, error)
- func (s *DiagnosticsStore) Store(entry DiagnosticEntry) error
- type DiagnosticsStoreConfig
- type Release
- type ReleaseStore
- func (s *ReleaseStore) ActivateLatest(leaseUUID string) error
- func (s *ReleaseStore) Append(leaseUUID string, r Release) error
- func (s ReleaseStore) Close() error
- func (s *ReleaseStore) Delete(leaseUUID string) error
- func (s ReleaseStore) Healthy() error
- func (s *ReleaseStore) Latest(leaseUUID string) (*Release, error)
- func (s *ReleaseStore) LatestActive(leaseUUID string) (*Release, error)
- func (s *ReleaseStore) List(leaseUUID string) ([]Release, error)
- func (s *ReleaseStore) RecordMigration(leaseUUID string, manifest []byte) error
- func (s *ReleaseStore) RemoveOlderThan(maxAge time.Duration) (int, error)
- func (s *ReleaseStore) UpdateLatestStatus(leaseUUID, status, errMsg string) error
- type ReleaseStoreConfig
- type ResourceAllocation
- type ResourcePool
- func (p *ResourcePool) GetAllocation(leaseUUID string) *ResourceAllocation
- func (p *ResourcePool) ListAllocations() []ResourceAllocation
- func (p *ResourcePool) Release(leaseUUID string)
- func (p *ResourcePool) Reset(allocations []ResourceAllocation)
- func (p *ResourcePool) SetRetainedDisk(mb int64)
- func (p *ResourcePool) Stats() ResourceStats
- func (p *ResourcePool) TenantStats(tenant string) ResourceStats
- func (p *ResourcePool) TryAllocate(leaseUUID, sku, tenant string) error
- func (p *ResourcePool) TryAllocateAdopt(leaseUUID, sku, tenant string) error
- type ResourceStats
- type RetentionEntry
- type RetentionStore
- func (s *RetentionStore) ClaimForRestore(orig, newLease string, maxAge time.Duration) (*RetentionEntry, error)
- func (s RetentionStore) Close() error
- func (s *RetentionStore) Delete(orig string) error
- func (s *RetentionStore) DeleteIfActive(orig string) ([]string, bool, error)
- func (s *RetentionStore) Get(orig string) (*RetentionEntry, error)
- func (s RetentionStore) Healthy() error
- func (s *RetentionStore) Keys() ([]string, error)
- func (s *RetentionStore) KeysPage(after string, limit int) (keys []string, next string, err error)
- func (s *RetentionStore) List() ([]RetentionEntry, error)
- func (s *RetentionStore) ListByTenant(tenant string) ([]RetentionEntry, error)
- func (s *RetentionStore) ListExpired(maxAge time.Duration) ([]RetentionEntry, error)
- func (s *RetentionStore) ListReaping() ([]RetentionEntry, error)
- func (s *RetentionStore) ListRestoring() ([]RetentionEntry, error)
- func (s *RetentionStore) MarkReapingIfActive(orig string) ([]string, bool, error)
- func (s *RetentionStore) MarkReapingIfExpired(orig string, maxAge time.Duration) ([]string, bool, error)
- func (s *RetentionStore) Put(e RetentionEntry) error
- func (s *RetentionStore) PutActiveMerged(base RetentionEntry) (bool, error)
- func (s *RetentionStore) PutReaping(base RetentionEntry) (bool, error)
- func (s *RetentionStore) ReIndex() error
- func (s *RetentionStore) RevertToActive(orig string, expectGen int) (bool, error)
- type RetentionStoreConfig
- type SKUProfile
- type SKUResolver
- type TenantQuotaConfig
Constants ¶
const ( // CallbackMaxAttempts is the number of times to attempt callback delivery. CallbackMaxAttempts = 3 // CallbackTimeout is the per-attempt timeout for callback HTTP requests. CallbackTimeout = 10 * time.Second )
const RetentionStatusActive = "active"
RetentionStatusActive is the status of an active (held) retention entry.
const RetentionStatusReaping = "reaping"
RetentionStatusReaping marks a record whose volumes are pending physical destruction: the bytes are still on disk (so the footprint must keep counting in the admission projection) but the record is NOT restore-claimable. It is a finalizer tombstone — kept until every volume is confirmed destroyed, then Delete()d. See ENG-376.
const RetentionStatusRestoring = "restoring"
RetentionStatusRestoring is the status of an entry currently being restored.
Variables ¶
var ( // ErrNoRetention is returned when no retained data exists for a given lease UUID. ErrNoRetention = errors.New("no retained data for lease") // ErrNotRestorable is returned when a retained lease is not in a restorable state. ErrNotRestorable = errors.New("retained lease not in a restorable state") )
Functions ¶
func IsImageAllowed ¶
IsImageAllowed checks if an image is from an allowed registry.
func ParseRegistry ¶
ParseRegistry extracts the registry domain from a container image reference. Uses the distribution/reference library for robust parsing with Docker Hub normalization (e.g., "nginx" -> "docker.io").
func ValidateImage ¶
ValidateImage checks if an image reference is valid and allowed.
Types ¶
type CallbackEntry ¶
type CallbackEntry struct {
LeaseUUID string `json:"lease_uuid"`
CallbackURL string `json:"callback_url"`
Success bool `json:"success"`
Status backend.CallbackStatus `json:"status,omitempty"`
Backend string `json:"backend,omitempty"`
Error string `json:"error,omitempty"`
// Retained persists the best-effort deprovision retain-success flag so a
// restart-replayed callback keeps it. Legacy entries default to false.
Retained bool `json:"retained,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
CallbackEntry represents a pending callback to be delivered.
Success is retained for backwards compatibility with entries persisted by binaries that predate the Status field. New writers populate Success AND Status (and Backend). Readers prefer Status when non-empty and fall back to Success otherwise; see callback_sender.ReplayPendingCallbacks.
type CallbackSender ¶
type CallbackSender struct {
// contains filtered or unexported fields
}
CallbackSender handles HMAC-signed callback delivery with retry and persistence.
func NewCallbackSender ¶
func NewCallbackSender(cfg CallbackSenderConfig) *CallbackSender
NewCallbackSender creates a new CallbackSender. Panics if HTTPClient, Logger, or StopCtx is nil (programming error). Store may be nil to disable callback persistence (callbacks will not survive restarts).
func (*CallbackSender) DeliverCallback ¶
func (s *CallbackSender) DeliverCallback(leaseUUID, callbackURL string, body []byte) bool
DeliverCallback attempts to deliver a callback with retries. Returns true if delivery succeeded.
func (*CallbackSender) ReplayPendingCallbacks ¶
func (s *CallbackSender) ReplayPendingCallbacks()
ReplayPendingCallbacks replays any callbacks that were persisted but not successfully delivered before the previous shutdown.
func (*CallbackSender) SendCallback ¶
func (s *CallbackSender) SendCallback(leaseUUID, callbackURL, backendName string, status backend.CallbackStatus, errMsg string, retained bool)
TODO(ENG-134): no per-lease ctx seam — see k3s.Deprovision doc for the residual deprovision-vs-callback TOCTOU this enables.
SendCallback sends a provision result callback with HMAC signature. It persists the callback before delivery and removes it on success. The caller must provide the callbackURL (resolved from its own state) and the backendName (so Fred can label metrics per-backend without a placement lookup, which is often already deleted for intentional deprovisions). retained is the best-effort ground-truth deprovision retain-success flag (false for all non-deprovision callbacks); it is threaded into the payload and persisted so a restart-replayed callback keeps it.
type CallbackSenderConfig ¶
type CallbackSenderConfig struct {
Store *CallbackStore
HTTPClient *http.Client
Secret string
Logger *slog.Logger
StopCtx context.Context
OnDelivery func(outcome string) // optional metrics callback
OnStoreError func() // optional; called when bbolt persistence fails
Backoff *[CallbackMaxAttempts]time.Duration // retry delays; nil uses default {0, 1s, 5s}
}
CallbackSenderConfig configures a CallbackSender.
type CallbackStore ¶
type CallbackStore struct {
// contains filtered or unexported fields
}
CallbackStore persists pending callbacks in bbolt so they survive restarts.
func NewCallbackStore ¶
func NewCallbackStore(cfg CallbackStoreConfig) (*CallbackStore, error)
NewCallbackStore opens or creates a bbolt database for callback persistence. If MaxAge > 0, a background cleanup loop removes expired entries periodically and an initial cleanup runs immediately to clear stale entries from previous runs.
func (CallbackStore) Close ¶
func (s CallbackStore) Close() error
Close shuts down the store gracefully. It is idempotent: the first call closes the database and captures any error; subsequent calls return the same error.
func (CallbackStore) Healthy ¶
func (s CallbackStore) Healthy() error
Healthy checks that the bbolt database is accessible and the bucket exists.
func (*CallbackStore) ListPending ¶
func (s *CallbackStore) ListPending() ([]CallbackEntry, error)
ListPending returns all pending callback entries for replay on startup.
func (*CallbackStore) Remove ¶
func (s *CallbackStore) Remove(leaseUUID string) error
Remove deletes a callback entry after successful delivery.
func (*CallbackStore) RemoveOlderThan ¶
func (s *CallbackStore) RemoveOlderThan(maxAge time.Duration) (int, error)
RemoveOlderThan deletes callback entries older than maxAge and returns the number of entries removed.
func (*CallbackStore) Store ¶
func (s *CallbackStore) Store(entry CallbackEntry) error
Store persists a callback entry before attempting delivery.
type CallbackStoreConfig ¶
type CallbackStoreConfig struct {
DBPath string // Path to bbolt database file
MaxAge time.Duration // Max age before entries are cleaned up (0 = no expiry)
CleanupInterval time.Duration // How often to run cleanup (defaults to MaxAge)
OnCleanupPanic util.PanicHandler // Optional: invoked on cleanup-loop panic (e.g., bump a metric)
}
CallbackStoreConfig configures the callback store.
type DiagnosticEntry ¶
type DiagnosticEntry struct {
LeaseUUID string `json:"lease_uuid"`
ProviderUUID string `json:"provider_uuid"`
Tenant string `json:"tenant"`
Error string `json:"error"`
Logs map[string]string `json:"logs,omitempty"`
FailCount int `json:"fail_count"`
CreatedAt time.Time `json:"created_at"`
}
DiagnosticEntry represents a persisted failure diagnostic record.
type DiagnosticsStore ¶
type DiagnosticsStore struct {
// contains filtered or unexported fields
}
DiagnosticsStore persists failure diagnostics in bbolt so they survive container removal and backend restarts.
func NewDiagnosticsStore ¶
func NewDiagnosticsStore(cfg DiagnosticsStoreConfig) (*DiagnosticsStore, error)
NewDiagnosticsStore opens or creates a bbolt database for diagnostics persistence. If MaxAge > 0, a background cleanup loop removes expired entries periodically and an initial cleanup runs immediately to clear stale entries from previous runs.
func (DiagnosticsStore) Close ¶
func (s DiagnosticsStore) Close() error
Close shuts down the store gracefully. It is idempotent: the first call closes the database and captures any error; subsequent calls return the same error.
func (*DiagnosticsStore) Delete ¶
func (s *DiagnosticsStore) Delete(leaseUUID string) error
Delete removes a diagnostic entry by lease UUID. It is a no-op if the entry does not exist.
func (*DiagnosticsStore) Get ¶
func (s *DiagnosticsStore) Get(leaseUUID string) (*DiagnosticEntry, error)
Get retrieves a diagnostic entry by lease UUID. Returns nil, nil when not found.
func (DiagnosticsStore) Healthy ¶
func (s DiagnosticsStore) Healthy() error
Healthy checks that the bbolt database is accessible and the bucket exists.
func (*DiagnosticsStore) RemoveOlderThan ¶
func (s *DiagnosticsStore) RemoveOlderThan(maxAge time.Duration) (int, error)
RemoveOlderThan deletes diagnostic entries older than maxAge and returns the number of entries removed.
func (*DiagnosticsStore) Store ¶
func (s *DiagnosticsStore) Store(entry DiagnosticEntry) error
Store persists a diagnostic entry, upserting by LeaseUUID.
type DiagnosticsStoreConfig ¶
type DiagnosticsStoreConfig struct {
DBPath string // Path to bbolt database file
MaxAge time.Duration // Max age before entries are cleaned up (0 = no expiry)
CleanupInterval time.Duration // How often to run cleanup (defaults to MaxAge)
OnCleanupPanic util.PanicHandler // Optional: invoked on cleanup-loop panic.
}
DiagnosticsStoreConfig configures the diagnostics store.
type Release ¶
type Release struct {
Version int `json:"version"`
Manifest []byte `json:"manifest"`
Image string `json:"image"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
Error string `json:"error,omitempty"`
}
Release represents a single release (deployment) of a lease.
type ReleaseStore ¶
type ReleaseStore struct {
// contains filtered or unexported fields
}
ReleaseStore persists release history in bbolt so it survives backend restarts.
func NewReleaseStore ¶
func NewReleaseStore(cfg ReleaseStoreConfig) (*ReleaseStore, error)
NewReleaseStore opens or creates a bbolt database for release persistence.
func (*ReleaseStore) ActivateLatest ¶
func (s *ReleaseStore) ActivateLatest(leaseUUID string) error
ActivateLatest marks the most recent release as "active" and all previous "active" releases as "superseded" in a single transaction.
func (*ReleaseStore) Append ¶
func (s *ReleaseStore) Append(leaseUUID string, r Release) error
Append adds a new release for a lease, auto-assigning Version.
func (ReleaseStore) Close ¶
func (s ReleaseStore) Close() error
Close shuts down the store gracefully. It is idempotent: the first call closes the database and captures any error; subsequent calls return the same error.
func (*ReleaseStore) Delete ¶
func (s *ReleaseStore) Delete(leaseUUID string) error
Delete removes all releases for a lease. No-op if not found.
func (ReleaseStore) Healthy ¶
func (s ReleaseStore) Healthy() error
Healthy checks that the bbolt database is accessible and the bucket exists.
func (*ReleaseStore) Latest ¶
func (s *ReleaseStore) Latest(leaseUUID string) (*Release, error)
Latest returns the most recent release for a lease. Returns nil, nil when not found.
func (*ReleaseStore) LatestActive ¶
func (s *ReleaseStore) LatestActive(leaseUUID string) (*Release, error)
LatestActive returns the most recent release with "active" status for a lease. Returns nil, nil when no active release is found.
func (*ReleaseStore) List ¶
func (s *ReleaseStore) List(leaseUUID string) ([]Release, error)
List returns all releases for a lease. Returns nil, nil when not found.
func (*ReleaseStore) RecordMigration ¶
func (s *ReleaseStore) RecordMigration(leaseUUID string, manifest []byte) error
RecordMigration appends an "active" release entry for a recover-time migration so the lease's release history captures the wrap-and-rename step. Idempotent: if the most-recent active entry already carries the same wrapped manifest bytes (byte-equal), the call is a no-op. This lets the migration pipeline re-run on the next startup if it was interrupted between rename and recover-loop completion without inflating release history.
Used exclusively by the docker backend's migrate.go (Task 9).
func (*ReleaseStore) RemoveOlderThan ¶
func (s *ReleaseStore) RemoveOlderThan(maxAge time.Duration) (int, error)
RemoveOlderThan prunes release history older than maxAge while preserving each lease's load-bearing records. For every lease it ALWAYS retains its index-latest entry — the entry the runtime mutators append to / activate, and (because Append assigns the next version to the tail) the holder of the lease's maximum version, which keeps Append's max+1 derivation collision-free — AND, when a distinct one exists, the most-recent "active" release that recoverState rehydrates the StackManifest from (see LatestActive). So it protects one entry when the newest entry is itself the active release or no active release exists, two otherwise. Only entries that are BOTH older than the cutoff AND not protected are pruned, so a lease's record is never emptied and its live manifest is never removed (ENG-440). Corrupt or empty values are removed whole-key. Returns the number of release ENTRIES removed (corrupt/empty keys count as one).
func (*ReleaseStore) UpdateLatestStatus ¶
func (s *ReleaseStore) UpdateLatestStatus(leaseUUID, status, errMsg string) error
UpdateLatestStatus updates the status (and optionally error) of the most recent release.
type ReleaseStoreConfig ¶
type ReleaseStoreConfig struct {
DBPath string
MaxAge time.Duration
CleanupInterval time.Duration
OnCleanupPanic util.PanicHandler // Optional: invoked on cleanup-loop panic.
}
ReleaseStoreConfig configures the release store.
type ResourceAllocation ¶
type ResourceAllocation struct {
LeaseUUID string
Tenant string
SKU string
CPUCores float64
MemoryMB int64
DiskMB int64
}
ResourceAllocation tracks resources allocated to a single lease.
type ResourcePool ¶
type ResourcePool struct {
// contains filtered or unexported fields
}
ResourcePool manages the backend's resource capacity. It provides atomic allocation and release of resources based on SKU profiles.
func NewResourcePool ¶
func NewResourcePool(totalCPU float64, totalMemoryMB, totalDiskMB int64, resolver SKUResolver, tenantQuota *TenantQuotaConfig) *ResourcePool
NewResourcePool creates a new resource pool with the given capacity. Panics if resolver is nil (programming error).
func (*ResourcePool) GetAllocation ¶
func (p *ResourcePool) GetAllocation(leaseUUID string) *ResourceAllocation
GetAllocation returns the allocation for a lease, or nil if not allocated.
func (*ResourcePool) ListAllocations ¶
func (p *ResourcePool) ListAllocations() []ResourceAllocation
ListAllocations returns a copy of all current allocations.
func (*ResourcePool) Release ¶
func (p *ResourcePool) Release(leaseUUID string)
Release returns resources for a lease back to the pool. It is safe to call Release for a lease that has no allocation.
func (*ResourcePool) Reset ¶
func (p *ResourcePool) Reset(allocations []ResourceAllocation)
Reset clears all allocations and rebuilds from a list of allocations.
func (*ResourcePool) SetRetainedDisk ¶ added in v0.5.0
func (p *ResourcePool) SetRetainedDisk(mb int64)
SetRetainedDisk records the aggregate disk (MB) reserved by retained (soft-deleted) volumes. The owner derives this from the retention store and pushes it here; TryAllocate subtracts it from available disk so retained volumes keep counting against the pool until reaped. Idempotent.
func (*ResourcePool) Stats ¶
func (p *ResourcePool) Stats() ResourceStats
Stats returns current resource usage statistics.
func (*ResourcePool) TenantStats ¶
func (p *ResourcePool) TenantStats(tenant string) ResourceStats
TenantStats returns resource usage statistics for a specific tenant. RetainedDiskMB is intentionally left 0: retained disk is a provider-level term (not attributed per tenant), so AvailableDiskMB() on a tenant snapshot intentionally excludes it.
func (*ResourcePool) TryAllocate ¶
func (p *ResourcePool) TryAllocate(leaseUUID, sku, tenant string) error
TryAllocate attempts to reserve resources for a new provision (gates all of CPU, memory, disk, and tenant quota).
func (*ResourcePool) TryAllocateAdopt ¶ added in v0.5.0
func (p *ResourcePool) TryAllocateAdopt(leaseUUID, sku, tenant string) error
TryAllocateAdopt reserves resources for a lease being RESTORED by adopting an existing retained volume (rename, not new disk). It gates CPU, memory, and tenant quota normally but SKIPS the global disk capacity check: the adopted bytes are already committed on disk and counted in the retained projection, so re-gating them would double-count the lease's own footprint and spuriously deny a restore that physically fits. DiskMB is still added to allocatedDisk for correct live accounting; the retained projection drops it when the record flips to restoring.
type ResourceStats ¶
type ResourceStats struct {
TotalCPU float64
TotalMemoryMB int64
TotalDiskMB int64
AllocatedCPU float64
AllocatedMemoryMB int64
AllocatedDiskMB int64
RetainedDiskMB int64
AllocationCount int
}
ResourceStats contains resource usage statistics.
func (ResourceStats) AvailableCPU ¶
func (s ResourceStats) AvailableCPU() float64
AvailableCPU returns available CPU cores.
func (ResourceStats) AvailableDiskMB ¶
func (s ResourceStats) AvailableDiskMB() int64
AvailableDiskMB returns disk available for new allocations: total minus live allocations minus retained (soft-deleted) reservations, clamped to >= 0 (a total_disk_mb shrink or stale retained projection must not surface a negative "available" via the /stats endpoints).
func (ResourceStats) AvailableMemoryMB ¶
func (s ResourceStats) AvailableMemoryMB() int64
AvailableMemoryMB returns available memory in MB.
type RetentionEntry ¶ added in v0.5.0
type RetentionEntry struct {
OriginalLeaseUUID string `json:"original_lease_uuid"`
Tenant string `json:"tenant"`
ProviderUUID string `json:"provider_uuid"`
Items []backend.LeaseItem `json:"items"`
StackManifest *manifest.StackManifest `json:"stack_manifest"`
CallbackURL string `json:"callback_url"`
RetainedVolumeNames []string `json:"retained_volume_names"`
Status string `json:"status"`
NewLeaseUUID string `json:"new_lease_uuid,omitempty"`
Generation int `json:"generation"`
CreatedAt time.Time `json:"created_at"`
RestoringSince time.Time `json:"restoring_since,omitempty"`
ReapingSince time.Time `json:"reaping_since,omitempty"`
}
RetentionEntry records the data needed to restore a soft-deleted lease.
type RetentionStore ¶ added in v0.5.0
type RetentionStore struct {
// contains filtered or unexported fields
}
RetentionStore persists soft-deleted lease data in bbolt. The `retention` bucket is the single source of truth; byTenant/byStatus are a DERIVED in-memory index rebuilt from the bucket on open (never persisted, cannot drift across a restart). The bucket is INDEX-COUPLED: it may be mutated ONLY through this type's wrapped methods (each maintains the index under s.mu). Never wire boltStore.startCleanup / removeOlderThan to this store — they cursor.Delete directly on the bucket and would bypass the index.
func NewRetentionStore ¶ added in v0.5.0
func NewRetentionStore(cfg RetentionStoreConfig) (*RetentionStore, error)
NewRetentionStore opens or creates a bbolt database for retention persistence. No background cleanup loop is started; the docker backend drives reaping and eviction explicitly via the MarkReaping* / ListReaping / ListExpired methods (reapExpiredRetentions, evictRetentionsToCap, and the retryReapingRecords sweep in restore.go), plus PutReaping for deprovision give-up tombstones.
func (*RetentionStore) ClaimForRestore ¶ added in v0.5.0
func (s *RetentionStore) ClaimForRestore(orig, newLease string, maxAge time.Duration) (*RetentionEntry, error)
ClaimForRestore atomically transitions an ACTIVE, non-expired record to restoring. Returns ErrNoRetention when absent or expired, ErrNotRestorable when not in active state.
func (RetentionStore) Close ¶ added in v0.5.0
func (s RetentionStore) Close() error
Close shuts down the store gracefully. It is idempotent: the first call closes the database and captures any error; subsequent calls return the same error.
func (*RetentionStore) Delete ¶ added in v0.5.0
func (s *RetentionStore) Delete(orig string) error
Delete removes a RetentionEntry by original lease UUID. It is idempotent: no error is returned when the entry is absent. It reads the pre-image in-txn so the index can drop the deleted record's partition membership.
func (*RetentionStore) DeleteIfActive ¶ added in v0.5.0
func (s *RetentionStore) DeleteIfActive(orig string) ([]string, bool, error)
DeleteIfActive atomically removes a record ONLY if it is still ACTIVE. Returns (names, deleted, err); deleted=false (nil names) when absent or not active (e.g. concurrently claimed for restore). Used by reconcileOrphanedRetentions (ENG-370) to prune an orphaned active record whose backing volumes have already vanished out-of-band — the ACTIVE-only CAS guarantees a concurrent restore (active→restoring) is never clobbered. The returned names are unused there: the volumes are already gone, so there is nothing to destroy.
func (*RetentionStore) Get ¶ added in v0.5.0
func (s *RetentionStore) Get(orig string) (*RetentionEntry, error)
Get retrieves a RetentionEntry by original lease UUID. Returns nil, nil when absent.
func (RetentionStore) Healthy ¶ added in v0.5.0
func (s RetentionStore) Healthy() error
Healthy checks that the bbolt database is accessible and the bucket exists.
func (*RetentionStore) Keys ¶ added in v0.5.0
func (s *RetentionStore) Keys() ([]string, error)
Keys returns every retained lease UUID (the bbolt key) without unmarshalling the heavy record value (skips the dominant per-record json.Unmarshal). string(k) copies, so no cursor bytes escape the transaction.
func (*RetentionStore) KeysPage ¶ added in v0.7.0
KeysPage returns one keyset page of retained lease UUIDs (the bbolt keys) in ascending key order, containing the keys strictly greater than `after`. It uses a bbolt cursor Seek so the read is O(limit), not a full-bucket scan, and (like Keys) skips the heavy per-record value unmarshal.
- limit <= 0 -> returns ALL keys, next "" — the unpaginated passthrough. The cursor is ignored in this mode, matching PaginateRetentions/keysetPage.
- limit > 0 -> returns up to limit keys strictly greater than `after`; next is the last returned key iff a full page was returned AND more keys remain, otherwise "".
The returned slice is always non-nil so callers serialize it as [] not null. Precondition: keys are canonical lease UUIDs — bbolt stores keys byte-sorted, which matches the client's keyset cursor order (canonical-lowercase UUID).
func (*RetentionStore) List ¶ added in v0.5.0
func (s *RetentionStore) List() ([]RetentionEntry, error)
List returns all RetentionEntry records in the store.
func (*RetentionStore) ListByTenant ¶ added in v0.5.0
func (s *RetentionStore) ListByTenant(tenant string) ([]RetentionEntry, error)
ListByTenant returns all entries for the given tenant (eventually-consistent; callers must re-validate via CAS before mutating — see type doc). Served from the index.
func (*RetentionStore) ListExpired ¶ added in v0.5.0
func (s *RetentionStore) ListExpired(maxAge time.Duration) ([]RetentionEntry, error)
ListExpired returns active entries whose CreatedAt is older than maxAge.
func (*RetentionStore) ListReaping ¶ added in v0.5.0
func (s *RetentionStore) ListReaping() ([]RetentionEntry, error)
ListReaping returns all entries currently in the reaping (pending-destroy) state.
func (*RetentionStore) ListRestoring ¶ added in v0.5.0
func (s *RetentionStore) ListRestoring() ([]RetentionEntry, error)
ListRestoring returns all entries currently restoring (eventually-consistent). Served from the index.
func (*RetentionStore) MarkReapingIfActive ¶ added in v0.5.0
func (s *RetentionStore) MarkReapingIfActive(orig string) ([]string, bool, error)
MarkReapingIfActive atomically transitions an ACTIVE record to reaping and returns its volume names for the caller to destroy AFTER the txn commits. ok=false (nil names) when absent or not active (e.g. concurrently claimed for restore). The record is NOT deleted — it is the finalizer tombstone that keeps the footprint counted until the volumes are confirmed gone. (ENG-376)
func (*RetentionStore) MarkReapingIfExpired ¶ added in v0.5.0
func (s *RetentionStore) MarkReapingIfExpired(orig string, maxAge time.Duration) ([]string, bool, error)
MarkReapingIfExpired atomically transitions an ACTIVE, expired record to reaping and returns its volume names for the caller to destroy AFTER the txn commits. The record is NOT deleted — it stays a counted tombstone until the volumes are confirmed gone. Returns ok=false when absent, not active, or not yet expired, and a no-op when maxAge<=0. (ENG-376)
func (*RetentionStore) Put ¶ added in v0.5.0
func (s *RetentionStore) Put(e RetentionEntry) error
Put persists a RetentionEntry, upserting by OriginalLeaseUUID. It reads the pre-image in-txn so the index can drop the stale partition membership of any record being overwritten (a status/tenant change must not leave a phantom).
func (*RetentionStore) PutActiveMerged ¶ added in v0.5.0
func (s *RetentionStore) PutActiveMerged(base RetentionEntry) (bool, error)
PutActiveMerged atomically upserts the soft-delete record for a closing lease, merging mergeVolumes into any existing record's RetainedVolumeNames. Single txn, so it is safe against a concurrent ClaimForRestore (no Get→Put TOCTOU):
- absent: writes `base` fresh (caller sets CreatedAt=now, Generation=0, Status=active).
- existing ACTIVE: PRESERVES the stored CreatedAt and Generation, writes the UNION of stored RetainedVolumeNames and base.RetainedVolumeNames (dedup), and KEEPS the stored StackManifest when base's is nil (a close retry must never clobber a restorable manifest with a nil one); other fields come from `base`.
- existing NON-active (restoring): writes NOTHING, returns ok=false — a restore owns the record; a blind write would corrupt the CAS. Caller defers (keeps lease Failed).
Returns (ok bool, err error): ok=false + nil err means "deferred, record is restoring".
func (*RetentionStore) PutReaping ¶ added in v0.5.0
func (s *RetentionStore) PutReaping(base RetentionEntry) (bool, error)
PutReaping writes a reaping tombstone for an ABANDONED on-disk footprint (a deprovision give-up). It is idempotent and never clobbers a still-counted record:
- absent: writes a fresh reaping record (stamps ReapingSince=now).
- existing reaping: unions RetainedVolumeNames and PRESERVES ReapingSince (aging).
- existing active/restoring: writes NOTHING, returns ok=false — that record already counts the footprint (or owns it for restore); a blind reaping write would corrupt accounting/CAS. Caller treats ok=false as "already tracked".
Single txn, so it is safe against a concurrent ClaimForRestore. (ENG-376)
func (*RetentionStore) ReIndex ¶ added in v0.5.0
func (s *RetentionStore) ReIndex() error
ReIndex rebuilds the in-memory index from the primary bucket and swaps it in. Safe on a live store: it holds s.mu across the WHOLE scan+swap, which serializes it with mutators (each holds s.mu across its {db.Update + indexApply}). Holding the lock only for the swap would be unsafe — a mutator could commit a write and update the live index between the scan returning and the swap, and the swap would then overwrite that write with a pre-scan snapshot (lost update → drift until the next rebuild). fireReindex runs outside the lock. The self-heal/recovery seam (the index is never the source of truth).
func (*RetentionStore) RevertToActive ¶ added in v0.5.0
func (s *RetentionStore) RevertToActive(orig string, expectGen int) (bool, error)
RevertToActive transitions a restoring record back to active, using a compare-and-swap on Generation. Returns (true, nil) on success, (false, nil) when the record is absent, not in restoring state, or the generation does not match. On success the Generation is bumped and NewLeaseUUID/RestoringSince are cleared.
type RetentionStoreConfig ¶ added in v0.5.0
type RetentionStoreConfig struct {
DBPath string
// OnReindex (nil-safe) fires after each index build with record count, duration, and
// trigger ("open"|"manual"). A callback (not a metrics import) so this package stays
// free of internal/metrics — mirrors boltStore.startCleanup's onPanic seam.
OnReindex func(count int, dur time.Duration, trigger string)
}
RetentionStoreConfig configures the retention store.
type SKUProfile ¶
type SKUProfile struct {
CPUCores float64 `yaml:"cpu_cores"`
MemoryMB int64 `yaml:"memory_mb"`
DiskMB int64 `yaml:"disk_mb"`
}
SKUProfile defines resource limits for a SKU.
func (SKUProfile) Validate ¶
func (p SKUProfile) Validate() error
Validate checks that the profile's resource values are valid.
type SKUResolver ¶
type SKUResolver func(sku string) (SKUProfile, error)
SKUResolver resolves a SKU identifier to its resource profile. This abstracts the SKU mapping logic so it can be shared between components.
type TenantQuotaConfig ¶
type TenantQuotaConfig struct {
MaxCPUCores float64 `yaml:"max_cpu_cores"`
MaxMemoryMB int64 `yaml:"max_memory_mb"`
MaxDiskMB int64 `yaml:"max_disk_mb"`
}
TenantQuotaConfig configures per-tenant resource limits. When set, each tenant's aggregate resource usage is capped.
func (TenantQuotaConfig) Validate ¶
func (q TenantQuotaConfig) Validate() error
Validate checks that all quota values are positive.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package leasesm owns the per-lease state machine and actor, plus the substrate-agnostic seams they consume.
|
Package leasesm owns the per-lease state machine and actor, plus the substrate-agnostic seams they consume. |
|
Package manifest defines the tenant-facing container manifest schema (StackManifest, holding a map of named per-service Manifest entries), JSON parsing, and validation.
|
Package manifest defines the tenant-facing container manifest schema (StackManifest, holding a map of named per-service Manifest entries), JSON parsing, and validation. |
|
Package workbarrier provides a reference-counted barrier whose zero signal is exposed as a real channel, so callers can wait-with-timeout using a plain select without spawning helper goroutines that would leak when the count never drops to zero.
|
Package workbarrier provides a reference-counted barrier whose zero signal is exposed as a real channel, so callers can wait-with-timeout using a plain select without spawning helper goroutines that would leak when the count never drops to zero. |