Documentation
¶
Overview ¶
Package mongodb holds everything MongoDB-specific: the $jsonSchema validator translation, the repository implementation and the provisioner.
Index ¶
- Constants
- Variables
- func Connect(ctx context.Context, uri string) (*mongo.Client, error)
- func SystemCollectionNames() []string
- func SystemDatabaseName(realm string) string
- type AuthStore
- func (s *AuthStore) APIKeyByHash(ctx context.Context, hash string) (auth.APIKey, error)
- func (s *AuthStore) AddRoles(ctx context.Context, userID string, roles []string, now time.Time) error
- func (s *AuthStore) AppendAudit(ctx context.Context, r auth.AuditRecord) error
- func (s *AuthStore) ClaimIdempotency(ctx context.Context, rec auth.IdempotencyRecord) (auth.IdempotencyRecord, bool, error)
- func (s *AuthStore) ClaimInvitation(ctx context.Context, hash string, now time.Time) (auth.Invitation, error)
- func (s *AuthStore) ClaimJob(ctx context.Context, workerID string, at time.Time, margin time.Duration) (auth.Job, bool, error)
- func (s *AuthStore) ClearLoginAttempts(ctx context.Context, key string) error
- func (s *AuthStore) CompleteIdempotency(ctx context.Context, id string, result *auth.JobResult, jobID string, ...) error
- func (s *AuthStore) CompleteJob(ctx context.Context, id string, result auth.JobResult, ...) error
- func (s *AuthStore) CreateAPIKey(ctx context.Context, k auth.APIKey) error
- func (s *AuthStore) CreateInvitation(ctx context.Context, inv auth.Invitation) error
- func (s *AuthStore) CreateSession(ctx context.Context, x auth.Session) error
- func (s *AuthStore) CreateUser(ctx context.Context, u auth.User) error
- func (s *AuthStore) DeleteAPIKey(ctx context.Context, name string) error
- func (s *AuthStore) DeleteInvitation(ctx context.Context, id string) error
- func (s *AuthStore) DeleteOtherSessions(ctx context.Context, userID, keepID string) error
- func (s *AuthStore) DeleteSecret(ctx context.Context, database, name string) error
- func (s *AuthStore) DeleteSession(ctx context.Context, userID, id string) error
- func (s *AuthStore) DeleteSessions(ctx context.Context, userID string) error
- func (s *AuthStore) DeleteUser(ctx context.Context, id string) error
- func (s *AuthStore) EnqueueJob(ctx context.Context, j auth.Job) error
- func (s *AuthStore) GetJob(ctx context.Context, id string) (auth.Job, bool, error)
- func (s *AuthStore) Identity(ctx context.Context, provider, subject string) (auth.Identity, error)
- func (s *AuthStore) IncrementCounter(ctx context.Context, key string, at, expires time.Time) (int, time.Time, error)
- func (s *AuthStore) ListAPIKeys(ctx context.Context) ([]auth.APIKey, error)
- func (s *AuthStore) ListAudit(ctx context.Context, f auth.AuditFilter) ([]auth.AuditRecord, bool, error)
- func (s *AuthStore) ListInvitations(ctx context.Context) ([]auth.Invitation, error)
- func (s *AuthStore) ListInvocations(ctx context.Context, f auth.InvocationFilter) ([]auth.InvocationRecord, bool, error)
- func (s *AuthStore) ListJobs(ctx context.Context, f auth.JobFilter) ([]auth.Job, bool, error)
- func (s *AuthStore) ListSecrets(ctx context.Context) ([]auth.Secret, error)
- func (s *AuthStore) ListSessions(ctx context.Context, userID string) ([]auth.Session, error)
- func (s *AuthStore) ListUsers(ctx context.Context) ([]auth.User, error)
- func (s *AuthStore) LoginAttempts(ctx context.Context, key string) (auth.Attempts, error)
- func (s *AuthStore) PutIdentity(ctx context.Context, id auth.Identity) error
- func (s *AuthStore) RecordInvocation(ctx context.Context, r auth.InvocationRecord) error
- func (s *AuthStore) RecordLoginFailure(ctx context.Context, key string, at, expires time.Time) error
- func (s *AuthStore) ReleaseIdempotency(ctx context.Context, id string) error
- func (s *AuthStore) RemoveRole(ctx context.Context, userID, role string, now time.Time) error
- func (s *AuthStore) SecretByScope(ctx context.Context, database, name string) (auth.Secret, error)
- func (s *AuthStore) SessionByTokenHash(ctx context.Context, hash string) (auth.Session, auth.User, error)
- func (s *AuthStore) TouchAPIKey(ctx context.Context, hash string, at time.Time) error
- func (s *AuthStore) TouchSession(ctx context.Context, id string, lastUsed, expires time.Time) error
- func (s *AuthStore) UpdateUser(ctx context.Context, id string, upd auth.UserUpdate, now time.Time) error
- func (s *AuthStore) UpsertSecret(ctx context.Context, sec auth.Secret) error
- func (s *AuthStore) UserByEmail(ctx context.Context, email string) (auth.User, error)
- func (s *AuthStore) UserByID(ctx context.Context, id string) (auth.User, error)
- type Omission
- type Provisioner
- type Repository
- func (r *Repository) Create(ctx context.Context, doc storage.Document) error
- func (r *Repository) Delete(ctx context.Context, id string, ifVersion *int64) error
- func (r *Repository) Get(ctx context.Context, id string) (storage.Document, error)
- func (r *Repository) List(ctx context.Context, q storage.Query) (storage.Page, error)
- func (r *Repository) Replace(ctx context.Context, doc storage.Document, ifVersion int64) error
- type Store
Constants ¶
const ( DeploymentDatabase = "backd___deployment" DeploymentCollection = "realms" )
DeploymentDatabase holds what provisioning applied: per realm, the fingerprint of the config it provisioned. Its name can't clash with a realm's databases (<realm>__<database>, where a database name can't start with "_").
const ( UsersCollection = "users" IdentitiesCollection = "identities" SessionsCollection = "sessions" APIKeysCollection = "api_keys" InvitationsCollection = "invitations" LoginAttemptsCollection = "login_attempts" // AuditCollection is append-only: backd inserts and reads, and MongoDB // removes records when they expire. AuditCollection = "audit" // SecretsCollection holds encrypted values for functions (roadmap F5). SecretsCollection = "secrets" // InvocationsCollection is append-only, like AuditCollection: one // record per function call (roadmap F10). InvocationsCollection = "invocations" // JobsCollection holds async function calls (roadmap F11), from // enqueue through a worker's claim to their result, until it's // removed by expiry. JobsCollection = "jobs" // IdempotencyCollection ties an Idempotency-Key to its outcome // (roadmap F12), scoped to the function and the caller. IdempotencyCollection = "idempotency" )
System collections of a realm's system database.
Variables ¶
var ErrConfigMismatch = errors.New("the config differs from the one last provisioned")
ErrConfigMismatch means this instance's config isn't the one last provisioned.
var ErrStandalone = errors.New("mongodb: the server is a standalone instance; backd needs a replica set (a single node is fine): start mongod with --replSet and run rs.initiate(), then add ?replicaSet=<name> to MONGO_URI")
ErrStandalone means MongoDB isn't a replica set member (or a sharded cluster's router), so transactions aren't available.
Functions ¶
func Connect ¶
Connect opens a client and checks the server is reachable and part of a replica set (or a sharded cluster).
func SystemCollectionNames ¶
func SystemCollectionNames() []string
SystemCollectionNames returns the collections of every system database.
func SystemDatabaseName ¶
SystemDatabaseName is the MongoDB database holding a realm's users, sessions and keys. Three underscores can't come from a valid database name, so it never collides with <realm>__<database>.
Types ¶
type AuthStore ¶
type AuthStore struct {
// contains filtered or unexported fields
}
AuthStore implements auth.Store on a realm's system database.
func NewAuthStore ¶
NewAuthStore returns the auth store of realm.
func (*AuthStore) APIKeyByHash ¶
func (*AuthStore) AppendAudit ¶
AppendAudit inserts a record. backd never updates or deletes audit records; MongoDB removes them when they expire.
func (*AuthStore) ClaimIdempotency ¶
func (s *AuthStore) ClaimIdempotency(ctx context.Context, rec auth.IdempotencyRecord) (auth.IdempotencyRecord, bool, error)
ClaimIdempotency inserts rec if its id isn't already used; a duplicate key means someone already claimed it, so the existing record is fetched and returned instead, claimed false.
func (*AuthStore) ClaimInvitation ¶
func (*AuthStore) ClaimJob ¶
func (s *AuthStore) ClaimJob(ctx context.Context, workerID string, at time.Time, margin time.Duration) (auth.Job, bool, error)
ClaimJob atomically claims the oldest claimable job: never claimed (status queued, no lease yet), or whose lease has expired (a dead worker's jobs are picked up again). The lease extends to at plus the job's own timeout_ms plus margin, computed in the same update so a claim never needs a second round trip to look the function's timeout up.
func (*AuthStore) ClearLoginAttempts ¶
func (*AuthStore) CompleteIdempotency ¶
func (s *AuthStore) CompleteIdempotency(ctx context.Context, id string, result *auth.JobResult, jobID string, completedAt, expiresAt time.Time) error
CompleteIdempotency stores a claimed key's outcome: result for a sync call, jobID for async (mutually exclusive). Only the one that applies is set — the collection's validator types "result" as an object, so setting it to an explicit BSON null (rather than leaving it absent) would fail validation.
func (*AuthStore) CompleteJob ¶
func (s *AuthStore) CompleteJob(ctx context.Context, id string, result auth.JobResult, completedAt, expiresAt time.Time) error
CompleteJob records a job's result; expiresAt starts its retention countdown. The update is conditional on the job not already being done, so a worker whose lease expired and was reclaimed can't finish late and overwrite a result another worker already recorded.
func (*AuthStore) CreateAPIKey ¶
func (*AuthStore) CreateInvitation ¶
func (*AuthStore) CreateSession ¶
func (*AuthStore) CreateUser ¶
func (*AuthStore) DeleteAPIKey ¶
func (*AuthStore) DeleteInvitation ¶
func (*AuthStore) DeleteOtherSessions ¶
func (*AuthStore) DeleteSecret ¶
func (*AuthStore) DeleteSession ¶
func (*AuthStore) DeleteSessions ¶
func (*AuthStore) DeleteUser ¶
DeleteUser removes sessions and identities first, so an interrupted delete never leaves credentials without their user.
func (*AuthStore) EnqueueJob ¶
EnqueueJob inserts a new job, queued for a worker to claim.
func (*AuthStore) IncrementCounter ¶
func (s *AuthStore) IncrementCounter(ctx context.Context, key string, at, expires time.Time) (int, time.Time, error)
IncrementCounter reuses the login-throttling collection and pipeline (see RecordLoginFailure) but returns the resulting count and reset time, which a caller that must decide "over the limit or not" needs and login throttling itself doesn't.
func (*AuthStore) ListAPIKeys ¶
func (*AuthStore) ListAudit ¶
func (s *AuthStore) ListAudit(ctx context.Context, f auth.AuditFilter) ([]auth.AuditRecord, bool, error)
func (*AuthStore) ListInvitations ¶
func (*AuthStore) ListInvocations ¶
func (s *AuthStore) ListInvocations(ctx context.Context, f auth.InvocationFilter) ([]auth.InvocationRecord, bool, error)
func (*AuthStore) ListSecrets ¶
func (*AuthStore) ListSessions ¶
func (*AuthStore) LoginAttempts ¶
func (*AuthStore) PutIdentity ¶
func (*AuthStore) RecordInvocation ¶
RecordInvocation inserts a record. backd never updates or deletes invocation records; MongoDB removes them when they expire.
func (*AuthStore) RecordLoginFailure ¶
func (s *AuthStore) RecordLoginFailure(ctx context.Context, key string, at, expires time.Time) error
RecordLoginFailure increments the counter in one atomic update. A counter whose window ended (but that the TTL monitor, which runs about once a minute, hasn't deleted yet) restarts at 1.
func (*AuthStore) ReleaseIdempotency ¶
ReleaseIdempotency removes a claim that shouldn't be remembered.
func (*AuthStore) RemoveRole ¶
func (*AuthStore) SecretByScope ¶
func (*AuthStore) SessionByTokenHash ¶
func (s *AuthStore) SessionByTokenHash(ctx context.Context, hash string) (auth.Session, auth.User, error)
SessionByTokenHash loads the session and its user in one round trip.
func (*AuthStore) TouchAPIKey ¶
func (*AuthStore) TouchSession ¶
func (*AuthStore) UpdateUser ¶
func (*AuthStore) UpsertSecret ¶
UpsertSecret creates or replaces the secret at (s.Database, s.Name), keeping its original created_at on an update.
func (*AuthStore) UserByEmail ¶
type Omission ¶
type Omission struct {
Path string // JSON pointer of the schema containing the keyword
Keyword string
}
Omission records a JSON Schema keyword that has no MongoDB $jsonSchema equivalent and was left out of the database validator.
type Provisioner ¶
type Provisioner struct {
Client *mongo.Client
Registry *registry.Registry
Log *slog.Logger
// Fingerprint of the config (registry.Fingerprint): Apply records it per
// realm, Verify refuses a different one. Empty skips both.
Fingerprint string
Version string // backd's version, recorded with the fingerprint
}
Provisioner makes MongoDB match the registry (Apply) or checks that it does (Verify). It never drops anything: objects in MongoDB that are not in the config are only reported as warnings.
func (*Provisioner) Apply ¶
func (p *Provisioner) Apply(ctx context.Context) error
Apply creates missing collections with their validators, updates validators that differ and creates missing declared indexes. It is idempotent.
func (*Provisioner) Verify ¶
func (p *Provisioner) Verify(ctx context.Context) error
Verify compares collections, validators and indexes with the registry without changing anything and returns an error listing every difference.
func (*Provisioner) VerifySystem ¶
func (p *Provisioner) VerifySystem(ctx context.Context, realm string) error
VerifySystem checks one realm's system database, for commands that write to it without provisioning first.
type Repository ¶
type Repository struct {
// contains filtered or unexported fields
}
Repository implements storage.Repository for one MongoDB collection.
type Store ¶
Store hands out repositories backed by one MongoDB client.
func (*Store) Repository ¶
func (s *Store) Repository(c *registry.Collection) storage.Repository
Repository returns the repository of a configured collection.
func (*Store) Transact ¶
Transact runs fn once inside a MongoDB transaction: every write made through a Repository, using the context fn receives, either all commit or none do (roadmap F7). The driver may retry fn on a transient error (e.g. a write conflict with another transaction), so fn must have no side effects beyond the repositories it's given.