Documentation
¶
Overview ¶
Package clusterconfig keeps the settings and identity material that the nodes of an Ether cluster share in the owner's PostgreSQL database:
- the shared settings document (Shared, a config.SharedBackend),
- sealed identity files such as the plex.direct certificate (Secrets),
- one-time join tokens (jointoken.go),
and the bootstrap steps that turn a standalone server into the first cluster node (Init) and add further nodes (Join). Everything stored is sealed with the cluster's credential key, which travels only inside join tokens and never sits in the database in the clear.
The tables exist on SQLite too (migrations are dialect-neutral) but a standalone server never uses them.
Index ¶
- Constants
- Variables
- func Attach(ctx context.Context, cfg *config.Store, db *sql.DB, o config.SharedOptions) error
- func CheckSetup(ctx context.Context, s SetupRequest) error
- func ConsumeJoinToken(ctx context.Context, db *sql.DB, t JoinToken, usedBy string, now time.Time) error
- func CreateJoinToken(ctx context.Context, db *sql.DB, databaseURL string, key []byte, ...) (JoinToken, TokenInfo, error)
- func Handler(o HandlerOptions) http.Handler
- func Init(ctx context.Context, o InitOptions) error
- func NewToken(ctx context.Context, db *sql.DB, cfg *config.Store, databaseURL string, ...) (JoinToken, TokenInfo, error)
- func RevokeJoinToken(ctx context.Context, db *sql.DB, id string) (bool, error)
- func SetupError(err error) string
- type HandlerOptions
- type InitOptions
- type JoinOptions
- type JoinResult
- type JoinToken
- type Sealer
- type Secrets
- type SetupRequest
- type Shared
- type TokenInfo
Constants ¶
const DefaultJoinTokenTTL = time.Hour
DefaultJoinTokenTTL is how long a join token stays valid.
const JoinTokenPrefix = "ether-join-v1:"
JoinTokenPrefix starts every join token.
const TokenWarning = "" /* 374-byte string literal not displayed */
TokenWarning is shown with every new token.
Variables ¶
var ( // ErrTokenInvalid: the token is malformed or unknown to the cluster. ErrTokenInvalid = errors.New("clusterconfig: join token is not valid for this cluster") // ErrTokenUsed: the token was already used to join a node. ErrTokenUsed = errors.New("clusterconfig: join token has already been used") // ErrTokenExpired: the token's validity window has passed. ErrTokenExpired = errors.New("clusterconfig: join token has expired") )
Functions ¶
func Attach ¶
Attach switches cfg to the cluster's shared settings in db, seeding them from cfg when the database holds none (the first node of a cluster). It is the boot step between opening the database and building components; see config.Store.AttachShared for the options.
func CheckSetup ¶ added in v0.2.4
func CheckSetup(ctx context.Context, s SetupRequest) error
CheckSetup checks connectivity and eligibility without migrations, writes or consuming a join token. Apply repeats the authoritative checks after shutdown.
func ConsumeJoinToken ¶
func ConsumeJoinToken(ctx context.Context, db *sql.DB, t JoinToken, usedBy string, now time.Time) error
ConsumeJoinToken marks the token used by usedBy, atomically: of any number of concurrent attempts exactly one succeeds. A used, expired or unknown token fails with ErrTokenUsed, ErrTokenExpired or ErrTokenInvalid.
func CreateJoinToken ¶
func CreateJoinToken(ctx context.Context, db *sql.DB, databaseURL string, key []byte, ttl time.Duration, now time.Time) (JoinToken, TokenInfo, error)
CreateJoinToken stores a new one-time token (only its hash) valid for ttl and returns it. databaseURL is the URL the joining node will use and key the cluster credential key; both travel only inside the token.
func Handler ¶
func Handler(o HandlerOptions) http.Handler
Handler is the owner API mounted at /ether/api/cluster:
GET /settings shared-settings status and join tokens
POST /join-tokens create a one-time join token {ttlMinutes?, databaseUrl?}
DELETE /join-tokens/{id} revoke an unused token
The admin package authenticates the owner; token creation additionally requires setup to be complete, so the unauthenticated LAN access the wizard allows before then can never mint a token.
func Init ¶
func Init(ctx context.Context, o InitOptions) error
Init turns a stopped standalone server into the first node of a cluster: it copies every table of the local SQLite database into the empty PostgreSQL database (a logical export/import, as backups use), seeds the shared settings from config.json and points config.json at PostgreSQL. It refuses a database that already holds data.
func NewToken ¶
func NewToken(ctx context.Context, db *sql.DB, cfg *config.Store, databaseURL string, ttl time.Duration) (JoinToken, TokenInfo, error)
NewToken creates a join token for the cluster whose database is db, embedding databaseURL and cfg's credential key.
func RevokeJoinToken ¶
RevokeJoinToken deletes an unused token; it reports whether one existed.
func SetupError ¶ added in v0.2.4
SetupError never includes connection strings or join-token material.
Types ¶
type HandlerOptions ¶
type HandlerOptions struct {
// DB is the cluster database; nil or SQLite means clustering is off.
DB *sql.DB
// Clustered reports whether this node runs against PostgreSQL.
Clustered bool
Config *config.Store
// DatabaseURL is the URL placed in new tokens (the node's own).
DatabaseURL func() string
}
HandlerOptions configure the owner API.
type InitOptions ¶
type InitOptions struct {
// DataDir is the standalone server's data directory (config.json,
// .credentials-key and ether.db).
DataDir string
// DatabaseURL is the empty PostgreSQL database the cluster will use.
DatabaseURL string
Logger *slog.Logger
}
InitOptions configure Init.
type JoinOptions ¶
type JoinOptions struct {
// DataDir is the new node's data directory.
DataDir string
// Token is the join token string from an existing node.
Token string
// DatabaseURL overrides the URL in the token (e.g. the database is
// reached under another name from this node).
DatabaseURL string
// Force moves an already configured server's settings aside.
Force bool
// NodeName is recorded as the token's user (default: host name).
NodeName string
Logger *slog.Logger
Now func() time.Time
}
JoinOptions configure Join.
type JoinResult ¶
type JoinResult struct {
// MovedAside lists files renamed out of the way.
MovedAside []string
// MachineIdentifier is the cluster's server identity.
MachineIdentifier string
}
JoinResult reports what Join did.
func Join ¶
func Join(ctx context.Context, o JoinOptions) (JoinResult, error)
Join makes DataDir a node of the cluster the token belongs to: it checks the token's credential key against the cluster, consumes the token, then installs the key and writes a config.json holding node-local defaults (or this server's existing node-local settings) and the database URL. The node then boots with the cluster's shared settings.
type JoinToken ¶
type JoinToken struct {
DatabaseURL string `json:"d"`
ID string `json:"i"`
Secret string `json:"s"`
Key []byte `json:"k"`
}
JoinToken is what a join token string carries. It is a secret: it holds the database URL (with its password) and the cluster credential key.
func ParseJoinToken ¶
ParseJoinToken decodes a token string.
type Sealer ¶
type Sealer interface {
Seal(name string, plain []byte) (string, error)
Unseal(name, sealed string) ([]byte, error)
}
Sealer encrypts values with the cluster credential key (*config.Store).
type Secrets ¶
type Secrets struct {
// contains filtered or unexported fields
}
Secrets stores named, sealed blobs (identity files) shared by all nodes. Each name has a version that increases on every write.
func NewSecrets ¶
NewSecrets returns a blob store sealing values with sealer.
func (*Secrets) Get ¶
Get returns the blob stored under name and its version; version 0 means nothing is stored.
type SetupRequest ¶ added in v0.2.4
type SetupRequest struct {
Mode string `json:"mode"`
DatabaseURL string `json:"databaseUrl"`
Token string `json:"token"`
Replace bool `json:"replace"`
}
SetupRequest carries secrets only in memory until the stopped server applies it.
func (SetupRequest) URL ¶ added in v0.2.4
func (s SetupRequest) URL() string
func (SetupRequest) Validate ¶ added in v0.2.4
func (s SetupRequest) Validate() error
type Shared ¶
type Shared struct {
// contains filtered or unexported fields
}
Shared stores the shared settings document in clusterconfig_shared (one row, versioned for optimistic concurrency).
func (*Shared) LoadShared ¶
LoadShared implements config.SharedBackend.
func (*Shared) SaveShared ¶
SaveShared implements config.SharedBackend.