Documentation
¶
Overview ¶
internal/controld/pgstore/environments.go
internal/controld/pgstore/events.go
internal/controld/pgstore/fleet.go
internal/controld/pgstore/host.go
internal/controld/pgstore/migrate.go
Package pgstore implements controld.Store on Postgres, using pgx/v5's pgxpool. It embeds and runs its own migrations (see migrate.go), so Open alone is enough to bring a fresh database up to schema.
internal/controld/pgstore/sessions.go
internal/controld/pgstore/tx.go
Index ¶
- func Migrate(ctx context.Context, pool *pgxpool.Pool) error
- type Store
- func (s *Store) Close()
- func (s *Store) DeleteAgentCredential(ctx context.Context, userID, provider string) error
- func (s *Store) DeleteSecret(ctx context.Context, name string) error
- func (s *Store) EnsureWorkspace(ctx context.Context, ws control.WorkspaceID) error
- func (s *Store) EnvironmentByName(ctx context.Context, ws control.WorkspaceID, name string) (control.EnvironmentID, error)
- func (s *Store) Environments() control.EnvironmentRepository
- func (s *Store) Fleet() control.FleetRepository
- func (s *Store) GetAgentCredential(ctx context.Context, userID, provider string) (controld.AgentCredential, error)
- func (s *Store) GetCredential(ctx context.Context, userID, provider string) (controld.Credential, error)
- func (s *Store) GetSecret(ctx context.Context, name string) ([]byte, []byte, error)
- func (s *Store) GetUser(ctx context.Context, id string) (controld.User, error)
- func (s *Store) InsertToken(ctx context.Context, userID, tokenHash string) error
- func (s *Store) ListAgentCredentials(ctx context.Context, userID string) ([]controld.AgentCredential, error)
- func (s *Store) ListCredentials(ctx context.Context, userID string) ([]controld.Credential, error)
- func (s *Store) ListSecrets(ctx context.Context) ([]controld.SecretMeta, error)
- func (s *Store) NextRunnerGeneration(ctx context.Context, pool control.PoolID, id control.RunnerID) (uint64, error)
- func (s *Store) PutAgentCredential(ctx context.Context, c controld.AgentCredential) (uint64, error)
- func (s *Store) PutSecret(ctx context.Context, name string, ciphertext, nonce []byte) error
- func (s *Store) Record(ctx context.Context, e control.Event) error
- func (s *Store) Run(ctx context.Context, fn func(context.Context) error) error
- func (s *Store) Sessions() control.SessionRepository
- func (s *Store) SetCredentialStatus(ctx context.Context, userID, provider, status string) error
- func (s *Store) SnapshotHolder(ctx context.Context, ws control.WorkspaceID, ref string) (control.RunnerID, error)
- func (s *Store) SnapshotRunner(ctx context.Context, ws control.WorkspaceID, id control.EnvironmentID) (control.RunnerID, error)
- func (s *Store) TouchCredentialUsed(ctx context.Context, userID, provider string) error
- func (s *Store) UpsertCredential(ctx context.Context, c controld.Credential) error
- func (s *Store) UpsertUser(ctx context.Context, githubID int64, login, role string) (controld.User, error)
- func (s *Store) UserByToken(ctx context.Context, tokenHash string) (controld.User, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Migrate ¶
Migrate applies every embedded migration in migrations/ whose leading version number is greater than the highest version already recorded in schema_migrations, in ascending order. Each migration file runs and its version is recorded in a single transaction, so a failed migration leaves schema_migrations untouched for that version.
Types ¶
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is a Postgres-backed controld.Store.
func Open ¶
Open connects to dsn, runs any pending migrations, and returns a ready Store. The caller should call Close when done with it.
func (*Store) DeleteAgentCredential ¶ added in v0.0.3
func (*Store) EnsureWorkspace ¶
EnsureWorkspace makes ws exist. It is a statement of fact rather than a create: New calls it on every start for the installation workspace, and the repository contract suite for its two, so a second call must be a no-op rather than a conflict.
func (*Store) EnvironmentByName ¶
func (s *Store) EnvironmentByName(ctx context.Context, ws control.WorkspaceID, name string) (control.EnvironmentID, error)
EnvironmentByName resolves a name inside ws to an id. The index is a locator, never authority: a name another workspace holds is simply not here, which is the same answer as a name nobody holds.
func (*Store) Environments ¶
func (s *Store) Environments() control.EnvironmentRepository
func (*Store) Fleet ¶
func (s *Store) Fleet() control.FleetRepository
func (*Store) GetAgentCredential ¶ added in v0.0.3
func (*Store) GetCredential ¶
func (*Store) InsertToken ¶
func (*Store) ListAgentCredentials ¶ added in v0.0.3
func (s *Store) ListAgentCredentials(ctx context.Context, userID string) ([]controld.AgentCredential, error)
ListAgentCredentials does not select ciphertext or nonce at all. Clearing them after the scan would be a promise this code keeps; not reading them is a promise the QUERY keeps, which survives someone editing the loop below.
func (*Store) ListCredentials ¶
func (*Store) ListSecrets ¶
func (*Store) NextRunnerGeneration ¶
func (s *Store) NextRunnerGeneration(ctx context.Context, pool control.PoolID, id control.RunnerID) (uint64, error)
NextRunnerGeneration opens a new generation for id in pool and returns it: 1 for a runner never seen, else one more than stored. One statement, so two controld replicas racing a reconnecting runner cannot mint the same generation twice — the row, not either process, is the authority the fleet repository then fences on.
func (*Store) PutAgentCredential ¶ added in v0.0.3
PutAgentCredential writes the row in ONE statement whose WHERE is the version guard: the update fires only when the stored version is exactly one behind the version the caller sealed for, so two concurrent puts cannot both win and neither can leave a ciphertext sealed against a version the row does not have. A guard that did not fire returns no row, which is control.ErrConflict — the caller re-reads, re-seals, and tries again.
func (*Store) Record ¶
Record writes one control.Event to the events table (migration 0009), on whatever q(ctx) hands back — so an event recorded inside a Run commits with the mutation it describes, and one recorded outside a unit is its own write. That is the whole point of the table: an event is a fact exactly when the change it reports is.
The columns are the event's fixed fields and nothing else. Nothing here takes a terminal byte, a session's content, a secret, a raw error, a price, or a provider resource id, because control.Event has none of them to give.
func (*Store) Run ¶
Run opens one transaction, hands fn a context that carries it, and commits when fn returns nil. A context already carrying a transaction joins it: fn runs inside the enclosing unit and the outer Run commits. A failure to begin or commit is control.ErrUnavailable; fn's own error is returned as is after the rollback.
func (*Store) Sessions ¶
func (s *Store) Sessions() control.SessionRepository
Sessions, Environments, and Fleet are the three control repository ports, each a view over this store's own rows rather than a copy of them: the sessions Sessions() creates are the sessions Fleet() places, which is what makes one Store satisfy the whole repository contract (controlapp/repotest).
func (*Store) SetCredentialStatus ¶
func (*Store) SnapshotHolder ¶
func (s *Store) SnapshotHolder(ctx context.Context, ws control.WorkspaceID, ref string) (control.RunnerID, error)
SnapshotHolder names the runner holding ref's snapshot in ws, "" when no environment's CURRENT cache has it. The staleness test is in the statement (snapshot_hash = setup_hash) rather than in Go: a cache whose environment's setup has moved on is not an answer to "where can this checkpoint boot", and a row this query cannot reach is a row no code path here can decide to use anyway.
func (*Store) SnapshotRunner ¶
func (s *Store) SnapshotRunner(ctx context.Context, ws control.WorkspaceID, id control.EnvironmentID) (control.RunnerID, error)
SnapshotRunner names the runner that built id's cached snapshot, "" when there is none — stale or not, because the wire has always shown the column.