154 lines
4.3 KiB
Go
154 lines
4.3 KiB
Go
package servers
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/hashicorp/boundary/globals"
|
|
"github.com/hashicorp/boundary/internal/db"
|
|
"github.com/hashicorp/boundary/internal/kms"
|
|
"github.com/hashicorp/boundary/internal/types/resource"
|
|
)
|
|
|
|
const (
|
|
defaultLiveness = 15 * time.Second
|
|
)
|
|
|
|
type ServerType string
|
|
|
|
const (
|
|
ServerTypeController ServerType = "controller"
|
|
ServerTypeWorker ServerType = "worker"
|
|
)
|
|
|
|
func (s ServerType) String() string {
|
|
return string(s)
|
|
}
|
|
|
|
// Repository is the servers database repository
|
|
type Repository struct {
|
|
reader db.Reader
|
|
writer db.Writer
|
|
kms *kms.Kms
|
|
}
|
|
|
|
// NewRepository creates a new servers Repository. Supports the options: WithLimit
|
|
// which sets a default limit on results returned by repo operations.
|
|
func NewRepository(r db.Reader, w db.Writer, kms *kms.Kms) (*Repository, error) {
|
|
if r == nil {
|
|
return nil, errors.New("error creating server repository with nil reader")
|
|
}
|
|
if w == nil {
|
|
return nil, errors.New("error creating server repository with nil writer")
|
|
}
|
|
if kms == nil {
|
|
return nil, errors.New("error creating server repository with nil kms")
|
|
}
|
|
return &Repository{
|
|
reader: r,
|
|
writer: w,
|
|
kms: kms,
|
|
}, nil
|
|
}
|
|
|
|
// list will return a listing of resources and honor the WithLimit option or the
|
|
// repo defaultLimit
|
|
func (r *Repository) ListServers(ctx context.Context, serverType ServerType, opt ...Option) ([]*Server, error) {
|
|
opts := getOpts(opt...)
|
|
liveness := opts.withLiveness
|
|
if liveness == 0 {
|
|
liveness = defaultLiveness
|
|
}
|
|
updateTime := time.Now().Add(-1 * liveness)
|
|
var servers []*Server
|
|
if err := r.reader.SearchWhere(
|
|
ctx,
|
|
&servers,
|
|
"type = $1 and update_time > $2",
|
|
[]interface{}{serverType, updateTime.Format(time.RFC3339)},
|
|
db.WithLimit(-1),
|
|
); err != nil {
|
|
return nil, fmt.Errorf("error listing servers: %w", err)
|
|
}
|
|
return servers, nil
|
|
}
|
|
|
|
// UpsertServer adds or updates a server in the DB
|
|
func (r *Repository) UpsertServer(ctx context.Context, server *Server, opt ...Option) ([]*Server, int, error) {
|
|
if server == nil {
|
|
return nil, db.NoRowsAffected, errors.New("cannot update server that is nil")
|
|
}
|
|
// Ensure, for now at least, the private ID is always equivalent to the name
|
|
server.PrivateId = server.Name
|
|
// Build query
|
|
q := `
|
|
insert into server
|
|
(private_id, type, name, description, address, update_time)
|
|
values
|
|
($1, $2, $3, $4, $5, $6)
|
|
on conflict on constraint server_pkey
|
|
do update set
|
|
name = $3,
|
|
description = $4,
|
|
address = $5,
|
|
update_time = $6;
|
|
`
|
|
|
|
rowsAffected, err := r.writer.Exec(ctx, q,
|
|
[]interface{}{server.PrivateId,
|
|
server.Type,
|
|
server.Name,
|
|
server.Description,
|
|
server.Address,
|
|
time.Now().Format(time.RFC3339)})
|
|
if err != nil {
|
|
return nil, db.NoRowsAffected, fmt.Errorf("error performing status upsert: %w", err)
|
|
}
|
|
// If updating a controller, done
|
|
if server.Type == resource.Controller.String() {
|
|
return nil, int(rowsAffected), nil
|
|
}
|
|
// Fetch current controllers to feed to the workers
|
|
controllers, err := r.ListServers(ctx, ServerTypeController)
|
|
return controllers, len(controllers), err
|
|
}
|
|
|
|
type RecoveryNonce struct {
|
|
Nonce string
|
|
}
|
|
|
|
// AddRecoveryNonce adds a nonce
|
|
func (r *Repository) AddRecoveryNonce(ctx context.Context, nonce string, opt ...Option) error {
|
|
if nonce == "" {
|
|
return errors.New("empty nonce provided")
|
|
}
|
|
rn := &RecoveryNonce{Nonce: nonce}
|
|
if err := r.writer.Create(ctx, rn); err != nil {
|
|
return fmt.Errorf("error performing nonce insertion: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CleanupNonces removes nonces that no longer need to be stored
|
|
func (r *Repository) CleanupNonces(ctx context.Context, opt ...Option) (int, error) {
|
|
// If something was inserted before 3x the actual validity period, clean it out
|
|
endTime := time.Now().Add(-3 * globals.RecoveryTokenValidityPeriod)
|
|
|
|
rows, err := r.writer.Delete(ctx, &RecoveryNonce{}, db.WithWhere(deleteWhereSql, endTime))
|
|
if err != nil {
|
|
return db.NoRowsAffected, fmt.Errorf("error performing nonce cleanup: %w", err)
|
|
}
|
|
return rows, nil
|
|
}
|
|
|
|
// ListNonces lists nonces. Used only for tests at the moment.
|
|
func (r *Repository) ListNonces(ctx context.Context, opt ...Option) ([]*RecoveryNonce, error) {
|
|
var nonces []*RecoveryNonce
|
|
if err := r.reader.SearchWhere(ctx, &nonces, "", nil, db.WithLimit(-1)); err != nil {
|
|
return nil, fmt.Errorf("error listing nonces: %w", err)
|
|
}
|
|
return nonces, nil
|
|
}
|