Files
threshold/internal/servers/controller/controller.go
T

175 lines
5.5 KiB
Go
Raw Normal View History

2020-02-12 13:53:27 -05:00
package controller
import (
"context"
"crypto/rand"
"fmt"
2020-08-12 00:40:39 -04:00
"sync"
2020-02-12 13:53:27 -05:00
2020-08-10 17:15:02 -04:00
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/authtoken"
2020-08-12 00:40:39 -04:00
"github.com/hashicorp/boundary/internal/cmd/config"
2020-08-10 17:15:02 -04:00
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/host/static"
"github.com/hashicorp/boundary/internal/iam"
2020-08-19 16:47:18 -04:00
"github.com/hashicorp/boundary/internal/kms"
2020-08-12 00:40:39 -04:00
"github.com/hashicorp/boundary/internal/servers"
2020-08-10 17:15:02 -04:00
"github.com/hashicorp/boundary/internal/servers/controller/common"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/boundary/internal/target"
2020-02-12 13:53:27 -05:00
"github.com/hashicorp/go-hclog"
2020-08-12 00:40:39 -04:00
"github.com/hashicorp/vault/sdk/helper/base62"
2020-02-12 13:53:27 -05:00
"github.com/hashicorp/vault/sdk/helper/mlock"
2020-08-12 00:40:39 -04:00
"github.com/patrickmn/go-cache"
ua "go.uber.org/atomic"
2020-02-12 13:53:27 -05:00
)
type Controller struct {
2020-03-23 14:50:19 -04:00
conf *Config
logger hclog.Logger
2020-02-12 13:53:27 -05:00
baseContext context.Context
baseCancel context.CancelFunc
2020-08-12 00:40:39 -04:00
started ua.Bool
2020-05-12 17:35:48 -07:00
2020-08-12 00:40:39 -04:00
workerAuthCache *cache.Cache
// Used for testing
workerStatusUpdateTimes *sync.Map
2020-08-12 00:40:39 -04:00
// Repo factory methods
AuthTokenRepoFn common.AuthTokenRepoFactory
IamRepoFn common.IamRepoFactory
PasswordAuthRepoFn common.PasswordAuthRepoFactory
ServersRepoFn common.ServersRepoFactory
SessionRepoFn common.SessionRepoFactory
StaticHostRepoFn common.StaticRepoFactory
TargetRepoFn common.TargetRepoFactory
2020-08-12 00:40:39 -04:00
2020-08-19 16:47:18 -04:00
kms *kms.Kms
2020-02-12 13:53:27 -05:00
}
2020-03-10 15:48:04 -04:00
func New(conf *Config) (*Controller, error) {
2020-03-23 14:50:19 -04:00
c := &Controller{
2020-08-12 00:40:39 -04:00
conf: conf,
logger: conf.Logger.Named("controller"),
workerStatusUpdateTimes: new(sync.Map),
2020-02-12 13:53:27 -05:00
}
2020-08-12 00:40:39 -04:00
c.started.Store(false)
2020-02-12 13:53:27 -05:00
if conf.SecureRandomReader == nil {
conf.SecureRandomReader = rand.Reader
}
2020-08-12 00:40:39 -04:00
var err error
if conf.RawConfig.Controller == nil {
conf.RawConfig.Controller = new(config.Controller)
}
if conf.RawConfig.Controller.Name == "" {
if conf.RawConfig.Controller.Name, err = base62.Random(10); err != nil {
return nil, fmt.Errorf("error auto-generating controller name: %w", err)
}
}
2020-02-12 13:53:27 -05:00
if !conf.RawConfig.DisableMlock {
// Ensure our memory usage is locked into physical RAM
if err := mlock.LockMemory(); err != nil {
return nil, fmt.Errorf(
"Failed to lock memory: %v\n\n"+
"This usually means that the mlock syscall is not available.\n"+
2020-08-10 17:15:02 -04:00
"Boundary uses mlock to prevent memory from being swapped to\n"+
2020-02-12 13:53:27 -05:00
"disk. This requires root privileges as well as a machine\n"+
"that supports mlock. Please enable mlock on your system or\n"+
2020-08-10 17:15:02 -04:00
"disable Boundary from using it. To disable Boundary from using it,\n"+
2020-02-12 13:53:27 -05:00
"set the `disable_mlock` configuration option in your configuration\n"+
"file.",
err)
}
}
2020-05-12 17:35:48 -07:00
// Set up repo stuff
dbase := db.New(c.conf.Database)
2020-08-19 16:47:18 -04:00
kmsRepo, err := kms.NewRepository(dbase, dbase)
if err != nil {
return nil, fmt.Errorf("error creating kms repository: %w", err)
}
c.kms, err = kms.NewKms(kmsRepo, kms.WithLogger(c.logger.Named("kms")))
if err != nil {
return nil, fmt.Errorf("error creating kms cache: %w", err)
}
if err := c.kms.AddExternalWrappers(
kms.WithRootWrapper(c.conf.RootKms),
kms.WithWorkerAuthWrapper(c.conf.WorkerAuthKms),
kms.WithRecoveryWrapper(c.conf.RecoveryKms),
2020-08-19 16:47:18 -04:00
); err != nil {
return nil, fmt.Errorf("error adding config keys to kms: %w", err)
}
2020-06-05 11:52:59 -07:00
c.IamRepoFn = func() (*iam.Repository, error) {
2020-08-19 16:47:18 -04:00
return iam.NewRepository(dbase, dbase, c.kms, iam.WithRandomReader(c.conf.SecureRandomReader))
2020-06-05 11:52:59 -07:00
}
c.StaticHostRepoFn = func() (*static.Repository, error) {
2020-08-19 16:47:18 -04:00
return static.NewRepository(dbase, dbase, c.kms)
2020-05-12 17:35:48 -07:00
}
c.AuthTokenRepoFn = func() (*authtoken.Repository, error) {
return authtoken.NewRepository(dbase, dbase, c.kms,
authtoken.WithTokenTimeToLiveDuration(c.conf.RawConfig.Controller.AuthTokenTimeToLiveDuration),
authtoken.WithTokenTimeToStaleDuration(c.conf.RawConfig.Controller.AuthTokenTimeToStaleDuration))
}
2020-08-12 00:40:39 -04:00
c.ServersRepoFn = func() (*servers.Repository, error) {
return servers.NewRepository(dbase, dbase, c.kms)
2020-08-12 00:40:39 -04:00
}
c.PasswordAuthRepoFn = func() (*password.Repository, error) {
2020-08-19 16:47:18 -04:00
return password.NewRepository(dbase, dbase, c.kms)
}
c.TargetRepoFn = func() (*target.Repository, error) {
return target.NewRepository(dbase, dbase, c.kms)
}
c.SessionRepoFn = func() (*session.Repository, error) {
return session.NewRepository(dbase, dbase, c.kms)
}
2020-05-12 17:35:48 -07:00
2020-08-12 00:40:39 -04:00
c.workerAuthCache = cache.New(0, 0)
2020-02-12 13:53:27 -05:00
return c, nil
}
func (c *Controller) Start() error {
2020-08-12 00:40:39 -04:00
if c.started.Load() {
c.logger.Info("already started, skipping")
return nil
}
c.baseContext, c.baseCancel = context.WithCancel(context.Background())
2020-02-12 13:53:27 -05:00
if err := c.startListeners(); err != nil {
2020-03-23 14:50:19 -04:00
return fmt.Errorf("error starting controller listeners: %w", err)
2020-02-12 13:53:27 -05:00
}
2020-08-12 00:40:39 -04:00
c.startStatusTicking(c.baseContext)
c.startRecoveryNonceCleanupTicking(c.baseContext)
2020-10-01 10:13:57 -04:00
c.startTerminateCompletedSessionsTicking(c.baseContext)
2020-08-12 00:40:39 -04:00
c.started.Store(true)
2020-02-12 13:53:27 -05:00
return nil
}
2020-08-12 00:40:39 -04:00
func (c *Controller) Shutdown(serversOnly bool) error {
if !c.started.Load() {
c.logger.Info("already shut down, skipping")
return nil
}
c.baseCancel()
if err := c.stopListeners(serversOnly); err != nil {
2020-03-23 14:50:19 -04:00
return fmt.Errorf("error stopping controller listeners: %w", err)
2020-02-12 13:53:27 -05:00
}
2020-08-12 00:40:39 -04:00
c.started.Store(false)
2020-02-12 13:53:27 -05:00
return nil
}
2020-08-12 00:40:39 -04:00
// WorkerStatusUpdateTimes returns the map, which specifically is held in _this_
// controller, not the DB. It's used in tests to verify that a given controller
// is receiving updates from an expected set of workers, to test out balancing
// and auto reconnection.
func (c *Controller) WorkerStatusUpdateTimes() *sync.Map {
return c.workerStatusUpdateTimes
}