Add database URL. (#365)

* Add database URL.

This allows specification of either a file://, env://, or other string.
If it starts with file:// or env:// the actual value will be read from
those resources.

* Tidy up the KMS output

* Also run migrations in test mode when specifying the URL
pull/366/head
Jeff Mitchell 6 years ago committed by GitHub
parent c2b49dbc7d
commit c4e2b88022
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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(

@ -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() {

@ -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
}

@ -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()
}

@ -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)
}

Loading…
Cancel
Save