diff --git a/internal/cmd/base/servers.go b/internal/cmd/base/servers.go index afb944dd26..408f47d40e 100644 --- a/internal/cmd/base/servers.go +++ b/internal/cmd/base/servers.go @@ -349,7 +349,10 @@ func (b *Server) SetupKMSes(ui cli.Ui, config *config.Config) error { kmsLogger := b.Logger.ResetNamed(fmt.Sprintf("kms-%s-%s", purpose, kms.Type)) + origPurpose := kms.Purpose + kms.Purpose = []string{purpose} wrapper, wrapperConfigError := configutil.ConfigureWrapper(kms, &b.InfoKeys, &b.Info, kmsLogger) + kms.Purpose = origPurpose if wrapperConfigError != nil { if !errwrap.ContainsType(wrapperConfigError, new(logical.KeyNotFoundError)) { return fmt.Errorf( diff --git a/internal/cmd/commands/controller/controller.go b/internal/cmd/commands/controller/controller.go index 4e424c0dd5..e2e0ec39d7 100644 --- a/internal/cmd/commands/controller/controller.go +++ b/internal/cmd/commands/controller/controller.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/boundary/internal/auth/password" "github.com/hashicorp/boundary/internal/cmd/base" "github.com/hashicorp/boundary/internal/cmd/config" + "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/servers/controller" "github.com/hashicorp/boundary/sdk/strutil" "github.com/hashicorp/boundary/sdk/wrapper" @@ -304,10 +305,29 @@ func (c *Command) Run(args []string) int { } } if err := c.CreateDevDatabase("postgres", opts...); err != nil { - c.UI.Error(fmt.Errorf("Error creating dev database container: %s", err.Error()).Error()) + c.UI.Error(fmt.Errorf("Error creating dev database container: %w", err).Error()) return 1 } c.ShutdownFuncs = append(c.ShutdownFuncs, c.DestroyDevDatabase) + } else { + if c.Config.Database == nil || c.Config.Database.Url == "" { + c.UI.Error(`"url" not specified in "database" config block"`) + return 1 + } + dbaseUrl, err := config.ParseAddress(c.Config.Database.Url) + if err != nil && err != config.ErrNotAUrl { + c.UI.Error(fmt.Errorf("Error parsing database url: %w", err).Error()) + return 1 + } + c.DatabaseUrl = strings.TrimSpace(dbaseUrl) + if err := db.InitStore("postgres", nil, c.DatabaseUrl); err != nil { + c.UI.Error(fmt.Errorf("Error running database migrations: %w", err).Error()) + return 1 + } + if err := c.ConnectToDatabase("postgres"); err != nil { + c.UI.Error(fmt.Errorf("Error connecting to database: %w", err).Error()) + return 1 + } } defer func() { diff --git a/internal/cmd/config/config.go b/internal/cmd/config/config.go index 21a6f50497..4ecd32c524 100644 --- a/internal/cmd/config/config.go +++ b/internal/cmd/config/config.go @@ -4,9 +4,13 @@ import ( "bytes" "crypto/rand" "encoding/base64" + "errors" "fmt" "io" "io/ioutil" + "net/url" + "os" + "strings" wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/hcl" @@ -91,6 +95,7 @@ type Config struct { PassthroughDirectory string `hcl:"-"` Worker *Worker `hcl:"worker"` Controller *Controller `hcl:"controller"` + Database *Database `hcl:"database"` } type Controller struct { @@ -107,6 +112,10 @@ type Worker struct { Controllers []string `hcl:"controllers"` } +type Database struct { + Url string `hcl:"url"` +} + // DevWorker is a Config that is used for dev mode of Boundary // workers func DevWorker() (*Config, error) { @@ -235,3 +244,37 @@ func (c *Config) Sanitized() map[string]interface{} { return result } + +var ErrNotAUrl = errors.New("not a url") + +// ParseAddress parses a URL with schemes file://, env://, or any other. +// Depending on the scheme it will return specific types of data: +// +// * file:// will return a string with the file's contents * env:// will return +// a string with the env var's contents * anything else will return the string +// as it was +// +// On error, we return the original string along with the error. The caller can +// switch on ErrNotAUrl to understand whether it was the parsing step that +// errored or something else. This is useful to attempt to read a non-URL string +// from some resource, but where the original input may simply be a valid string +// of that type. +func ParseAddress(addr string) (string, error) { + addr = strings.TrimSpace(addr) + parsed, err := url.Parse(addr) + if err != nil { + return addr, ErrNotAUrl + } + switch parsed.Scheme { + case "file": + contents, err := ioutil.ReadFile(strings.TrimPrefix(addr, "file://")) + if err != nil { + return addr, fmt.Errorf("error reading file at %s: %w", addr, err) + } + return string(contents), nil + case "env": + return os.Getenv(strings.TrimPrefix(addr, "env://")), nil + } + + return addr, nil +} diff --git a/internal/db/db.go b/internal/db/db.go index f1bae9b4fc..4f9b92d612 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -139,24 +139,30 @@ func InitStore(dialect string, cleanup func() error, url string) error { source, err := migrations.NewMigrationSource(dialect) if err != nil { mErr = multierror.Append(mErr, fmt.Errorf("error creating migration driver: %w", err)) - if err := cleanup(); err != nil { - mErr = multierror.Append(mErr, fmt.Errorf("error cleaning up from creating driver: %w", err)) + if cleanup != nil { + if err := cleanup(); err != nil { + mErr = multierror.Append(mErr, fmt.Errorf("error cleaning up from creating driver: %w", err)) + } } return mErr.ErrorOrNil() } m, err := migrate.NewWithSourceInstance("httpfs", source, url) if err != nil { mErr = multierror.Append(mErr, fmt.Errorf("error creating migrations: %w", err)) - if err := cleanup(); err != nil { - mErr = multierror.Append(mErr, fmt.Errorf("error cleaning up from creating migrations: %w", err)) + if cleanup != nil { + if err := cleanup(); err != nil { + mErr = multierror.Append(mErr, fmt.Errorf("error cleaning up from creating migrations: %w", err)) + } } return mErr.ErrorOrNil() } if err := m.Up(); err != nil && err != migrate.ErrNoChange { mErr = multierror.Append(mErr, fmt.Errorf("error running migrations: %w", err)) - if err := cleanup(); err != nil { - mErr = multierror.Append(mErr, fmt.Errorf("error cleaning up from running migrations: %w", err)) + if cleanup != nil { + if err := cleanup(); err != nil { + mErr = multierror.Append(mErr, fmt.Errorf("error cleaning up from running migrations: %w", err)) + } } return mErr.ErrorOrNil() } diff --git a/internal/servers/controller/testing.go b/internal/servers/controller/testing.go index 8631c52dc1..3dfd707bca 100644 --- a/internal/servers/controller/testing.go +++ b/internal/servers/controller/testing.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/boundary/api/authtokens" "github.com/hashicorp/boundary/internal/cmd/base" "github.com/hashicorp/boundary/internal/cmd/config" + "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/servers" "github.com/hashicorp/go-hclog" @@ -343,6 +344,9 @@ func NewTestController(t *testing.T, opts *TestControllerOpts) *TestController { if opts.DatabaseUrl != "" { tc.b.DatabaseUrl = opts.DatabaseUrl + if err := db.InitStore("postgres", nil, tc.b.DatabaseUrl); err != nil { + t.Fatal(err) + } if err := tc.b.ConnectToDatabase("postgres"); err != nil { t.Fatal(err) }