store

package
v1.76.4 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: MIT Imports: 30 Imported by: 0

Documentation

Overview

Package store builds the storage ports once, from configuration, for the apps to be handed: the one place that knows which adapter backs them.

Everything else names the interfaces of internal/port. The adapter is chosen by the `ports.adapter` key of the configuration file: `legacy` (the default, today's ConfigMaps, Secrets and Valkey, unchanged), `memory` or `dynamodb`.

Index

Constants

View Source
const (
	AdapterLegacy = "legacy"
	AdapterMemory = "memory"
	// AdapterDynamoDB keeps State, the session index and the trigger in one
	// DynamoDB table.
	AdapterDynamoDB = "dynamodb"
)

The adapters `ports.adapter` names.

View Source
const BlobS3 = "s3"

BlobS3 is the adapter `ports.blob.adapter` names. It replaces one port and composes with any `ports.adapter`.

Variables

View Source
var ErrLocalLease = errors.New("the tick leases are held in this process only, so a running controller " +
	"would not be kept off the same target and both could act on it (duplicate invites or removals): " +
	"this is safe once a shared State exists (docs/decisions/0029, B3). Scale the controller to 0 and " +
	"pass --unsafe-local-lease to run the tick anyway")

ErrLocalLease is the refusal of a one-shot tick whose lease would not exclude the running controller.

Functions

func RequireSharedLease

func RequireSharedLease(shared, unsafeLocal bool) error

RequireSharedLease refuses a one-shot tick when its lease State is not shared with the controller's, unless the operator opted in.

Types

type Backend added in v1.58.0

type Backend = legacy.Backend

Backend is today's storage as it was opened.

type Config

type Config struct {
	Adapter string
	// Release prefixes the objects' names and the Valkey keys.
	Release string
	Kube    KubeNeed
	// Blob replaces the port of the same name; nil keeps what Adapter brings.
	Blob *config.PortsBlob
	// DynamoDB is the table of the `dynamodb` adapter: Table on layout v4,
	// Tables (one per module) on layout v5.
	DynamoDB dynamoport.Config

	// Module is the module this process runs, and Peers the modules whose
	// tables it may read (ADR 0072). They matter on layout v5 only: the State
	// is then Module's own table, a write of another module's key is refused,
	// and each peer is a read-only view. The composition root of each binary
	// sets them; an empty Module on layout v5 is the whole-estate view of the
	// migration and the backup (the router over every table).
	Module port.Module
	Peers  []port.Module

	// NoTrigger is set by a module that never notifies a controller (the backup
	// and the restore): the plan's `trigger` adapter is not built for it. The
	// aws-serverless preset names `invoke`, which needs the controller functions
	// only the issuer's document names, and would stop such a module at start.
	NoTrigger bool

	// Secrets delivers the secrets the document names (the Valkey password):
	// the composition root sets it after FromServe. Nil delivers none.
	Secrets secrets.Source
	// SecretsRoot is the serve document's `secrets.root` when its source is
	// ssm: the root the `ssm` Secrets adapter takes.
	SecretsRoot string
	// SecretsKMSKey is the serve document's `secrets.kmsKeyId` when its source
	// is ssm: the key the `ssm` Secrets adapter encrypts what it writes with.
	SecretsKMSKey string
	// Secrets layout (ADR 0041): the serve document's `secrets.layout`,
	// `.region`, `.endpoint` and `.grace` when its source is ssm. The layout
	// is v4 (the Secrets port is over it, internal/secretstore) or v5 (ADR
	// 0072, [Stores.V5]); the two do not mix with the other layout's tables.
	SecretsLayout   string
	SecretsSSM      bool
	SecretsRegion   string
	SecretsEndpoint string
	SecretsGrace    time.Duration
	// SecretsReadCache is `secrets.readCache`; nil is not set.
	SecretsReadCache *time.Duration
	// OpenState opens the backend of the v4 stores (storage/state/ssm over the
	// service's retryer, openSSMState).
	// Nil is that backend.
	OpenState secretstore.Opener

	// Cloudflare and Instance are the service document's `cloudflare` section
	// and the instance name; the Blob mints its own R2 credentials from a
	// preset of it (`ports.blob.s3.credentials.preset`). Nil when the blob uses
	// a static document, which needs neither.
	Cloudflare *config.Cloudflare
	Instance   string
	// CloudflareDial opens a Cloudflare account; nil is the real client.
	CloudflareDial minter.Dialer
	// contains filtered or unexported fields
}

Config is what Open needs.

func FromRoster

func FromRoster(f *config.Roster) Config

FromRoster reads what the two controllers share. A controller's reports and links are objects in its namespace, so it requires the cluster.

func FromServe

func FromServe(f *config.Serve) (Config, error)

FromServe reads the configuration of `sluis serve`.

func (Config) As added in v1.75.0

func (c Config) As(own port.Module, peers ...port.Module) Config

As is the Config of a process that runs module own and reads the tables of peers (ADR 0072). It matters on layout v5, where the State is the module's own table; on layout v4 there is one table and it changes nothing.

func (Config) OpenDry added in v1.76.0

func (c Config) OpenDry(ctx context.Context, log *slog.Logger) (*Stores, port.Table, error)

OpenDry builds what Open builds, as a deploy's check does: nothing it reaches mutates. The adapter table is resolved and validated, and State, the blobs, the secrets and the trigger are constructed from their settings, so a setting a function needs and the document lacks is refused here as it is at start. A DynamoDB table is bound and never created, and a blob whose credentials a Cloudflare preset mints is validated and left unopened, because opening it would mint. The Stores are the caller's to Close. An adapter that needs a cluster (the Kubernetes build's own) is planned and not opened, and the Stores are nil.

func (Config) Plan added in v1.75.0

func (c Config) Plan(ctx context.Context, log *slog.Logger) (port.Table, error)

Plan is the adapter table Open would build the ports from, resolved and validated, with nothing opened: a document's adapter choices can be checked without reaching the stores they name.

func (*Config) SetSecrets added in v1.74.0

func (c *Config) SetSecrets(s *config.Secrets)

SetSecrets carries the service document's `secrets` section (the `ssm` source: root, KMS key, layout, region, endpoint, grace) into the config. A controller assembled from the service document calls it too, so it sees the same layout the service does. Any other source sets nothing.

type FlagTable added in v1.75.0

type FlagTable struct {
	// Module names the table's module; empty for the one table of layout v4.
	Module port.Module
	State  port.State
}

FlagTable is one State that holds a maintenance flag: a module's own table on layout v5, or the one table of layout v4 (Module is then empty).

type KubeNeed

type KubeNeed int

KubeNeed says how much a process needs the namespace's objects.

const (
	// KubeNone opens nothing: a hub with `store: memory`.
	KubeNone KubeNeed = iota
	// KubeOptional tries, and goes on without when this is not a cluster: an
	// issuer proving recovery against one it may not be running in.
	KubeOptional
	// KubeRequired stops the start when this is not a cluster.
	KubeRequired
)

How much a process needs the cluster.

type Stores

type Stores struct {
	// Ports is every port, over the chosen adapter.
	Ports port.Set
	// Backend is today's storage as it was opened: what the `legacy` adapter
	// is made of, and, with any adapter, the cluster's own objects that stay the
	// cluster's (the token review, the declared OAuth client). The domain stores
	// (a connected workspace and its credential, an organisation, a person's
	// link, the Slack records) are on Ports for every adapter but `legacy`
	// (internal/portstore), and in the ConfigMaps and Secrets this reaches for
	// `legacy`. It is nil with the memory adapter, which has none.
	Backend *Backend
	// Adapter is the state adapter's name.
	Adapter string
	// Plan is the resolved adapter per concern, for the packages that wire a
	// concern this package does not.
	Plan port.Table
	// SecretsRoot is the root the secrets are kept under when the source is
	// ssm (/sluis/<instance>), and empty for another source.
	SecretsRoot string
	// Secrets delivers the secrets the document names, by name: what the
	// composition root put in Config.Secrets. Nil delivers none.
	Secrets secrets.Source
	// V4 is the installation's secrets on layout v4: Internal and External
	// over one state store. Nil when the secrets are not the ssm source's.
	V4 *secretstore.Stores
	// V5 is the installation's secrets on layout v5: module first (ADR 0072).
	// Nil unless `secrets.layout: v5`; V4 is then nil, and the Secrets port
	// is not set: a caller reads its module's names from V5. The callers move
	// to it module by module.
	V5 *secretstore.StoresV5
	// ClientSecrets is the Secrets port of the generated clients' records
	// (external/oidc/<id>) on layout v5, where Ports.Secrets is not set. Nil on
	// layout v4; [Stores.ClientSecretPort] picks the one in force.
	ClientSecrets port.Secrets
	// Tables is the table of each module on layout v5, nil on layout v4 and
	// with any other adapter. Router, on it, is the one State over all of them
	// that the migration and the backup use.
	Tables *dynamoport.Tables
	// Shared is true when the state is one every replica sees: a Valkey.
	Shared bool
	// Usable is whether the State, Index and snapshot Blob ports work at all:
	// the memory adapter, and the legacy one with a Valkey. Without them a
	// caller keeps its own process-local store, as it always has.
	Usable bool
	// contains filtered or unexported fields
}

Stores is the ports, built once.

func Open

func Open(ctx context.Context, cfg Config, log *slog.Logger) (*Stores, error)

Open builds the ports for the adapter the configuration names.

func (*Stores) ClientSecretPort added in v1.75.0

func (s *Stores) ClientSecretPort() port.Secrets

ClientSecretPort is the Secrets port that holds the generated clients' records: Stores.ClientSecrets on layout v5, the Secrets port otherwise.

func (*Stores) Close

func (s *Stores) Close()

Close releases what Open opened.

func (*Stores) FlagTables added in v1.75.0

func (s *Stores) FlagTables() ([]FlagTable, error)

FlagTables are the States that hold the maintenance flag of this installation: one per module on layout v5, where each module reads the flag of its own table, and one on layout v4. The legacy adapter holds no flag and has none.

func (*Stores) ForModule added in v1.75.0

func (s *Stores) ForModule(own port.Module, peers ...port.Module) (port.Set, error)

ForModule is the ports of module own with read-only views of peers, out of the tables or the memory stores this was opened over. It is how a process that hosts several modules (the issuer's function, until a provider leaves it) gives each its own table: the issuer's State is the oidc table, and a module it hosts writes its own. On layout v4 there is one table and no module to split by, so it is the Ports unchanged. The Blob, Identity and Secrets are the process's, observed once.

func (*Stores) LeaseState

func (s *Stores) LeaseState() (state port.State, shared bool)

LeaseState is the State the controllers take their tick leases from, and whether it is shared by every replica. A lease is only exclusive across processes when the State is: the legacy adapter keeps leases in Valkey, so without one a controller holds its leases in its own memory and a second replica would not be kept off (docs/concepts/sluis/ports.md, "The legacy adapter").

func (*Stores) Maintenance added in v1.75.0

func (s *Stores) Maintenance() *maintenance.Gate

Maintenance is the gate over the maintenance flag in this process's own State: the table of the module it serves, where the restore function sets it. Nil, which never refuses, with no usable shared State, and with the legacy adapter, which holds no such record.

func (*Stores) MaintenanceOf added in v1.75.0

func (s *Stores) MaintenanceOf(m port.Module) *maintenance.Gate

MaintenanceOf is the gate over module m's own table, for a process that hosts several modules (the issuer's function). On layout v4 there is one table, so it is Stores.Maintenance.

func (*Stores) Name

func (s *Stores) Name() string

Name says where state lives, for a log line and the console's page.

func (*Stores) Readiness

func (s *Stores) Readiness() any

Readiness is what readiness should ask: the Valkey, or nothing.

func (*Stores) SecretsPlace added in v1.76.0

func (s *Stores) SecretsPlace() (adapter, root string)

SecretsPlace is the secrets adapter and the root it keeps them under, for a page that tells a person where a secret is: the adapter the plan resolved and the `root` its settings name, or the serve document's `secrets.root`. Both are empty where no secrets adapter was chosen.

Jump to

Keyboard shortcuts

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