Allow not destroying dev databases (#366)

This also shifts some logic around to better prepare for non-dev-mode
workloads, although it does not actually call the KMS creation functions
and initial auth method creation from non-dev commands yet.
pull/366/merge
Jeff Mitchell 6 years ago committed by GitHub
parent c4e2b88022
commit 37e9fed2e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -461,6 +461,28 @@ func (b *Server) CreateDevDatabase(dialect string, opt ...Option) error {
b.Database.LogMode(true)
if err := b.CreateGlobalKmsKeys(); err != nil {
return err
}
if opts.withSkipAuthMethodCreation {
// now that we have passed all the error cases, reset c to be a noop so the
// defer doesn't do anything.
c = func() error { return nil }
return nil
}
if err := b.CreateInitialAuthMethod(); err != nil {
return err
}
// now that we have passed all the error cases, reset c to be a noop so the
// defer doesn't do anything.
c = func() error { return nil }
return nil
}
func (b *Server) CreateGlobalKmsKeys() error {
rw := db.New(b.Database)
kmsRepo, err := kms.NewRepository(rw, rw)
@ -488,11 +510,24 @@ func (b *Server) CreateDevDatabase(dialect string, opt ...Option) error {
return fmt.Errorf("error creating global scope kms keys: %w", err)
}
if opts.withSkipAuthMethodCreation {
// now that we have passed all the error cases, reset c to be a noop so the
// defer doesn't do anything.
c = func() error { return nil }
return nil
return nil
}
func (b *Server) CreateInitialAuthMethod() error {
rw := db.New(b.Database)
kmsRepo, err := kms.NewRepository(rw, rw)
if err != nil {
return fmt.Errorf("error creating kms repository: %w", err)
}
kmsCache, err := kms.NewKms(kmsRepo)
if err != nil {
return fmt.Errorf("error creating kms cache: %w", err)
}
if err := kmsCache.AddExternalWrappers(
kms.WithRootWrapper(b.RootKms),
); err != nil {
return fmt.Errorf("error adding config keys to kms: %w", err)
}
// Create the dev auth method
@ -504,46 +539,53 @@ func (b *Server) CreateDevDatabase(dialect string, opt ...Option) error {
if err != nil {
return fmt.Errorf("error creating new in memory auth method: %w", err)
}
amId := b.DevAuthMethodId
if amId == "" {
amId = "ampw_1234567890"
if b.DevAuthMethodId == "" {
b.DevAuthMethodId, err = db.NewPublicId(password.AuthMethodPrefix)
if err != nil {
return fmt.Errorf("error generating dev auth method id: %w", err)
}
}
_, err = pwRepo.CreateAuthMethod(ctx, authMethod, password.WithPublicId(amId))
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-b.ShutdownCh
cancel()
}()
_, err = pwRepo.CreateAuthMethod(ctx, authMethod, password.WithPublicId(b.DevAuthMethodId))
if err != nil {
return fmt.Errorf("error saving auth method to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "dev auth method id")
b.Info["dev auth method id"] = amId
b.InfoKeys = append(b.InfoKeys, "generated auth method id")
b.Info["generated auth method id"] = b.DevAuthMethodId
// Create the dev user
acctLoginName := b.DevLoginName
if acctLoginName == "" {
acctLoginName, err = base62.Random(10)
if b.DevLoginName == "" {
b.DevLoginName, err = base62.Random(10)
if err != nil {
return fmt.Errorf("unable to generate dev login name: %w", err)
return fmt.Errorf("unable to generate login name: %w", err)
}
acctLoginName = strings.ToLower(acctLoginName)
b.DevLoginName = strings.ToLower(b.DevLoginName)
}
pw := b.DevPassword
if pw == "" {
pw, err = base62.Random(20)
if b.DevPassword == "" {
b.DevPassword, err = base62.Random(20)
if err != nil {
return fmt.Errorf("unable to generate dev password: %w", err)
return fmt.Errorf("unable to generate password: %w", err)
}
}
b.InfoKeys = append(b.InfoKeys, "dev password")
b.Info["dev password"] = pw
b.InfoKeys = append(b.InfoKeys, "generated password")
b.Info["generated password"] = b.DevPassword
acct, err := password.NewAccount(amId, password.WithLoginName(acctLoginName))
acct, err := password.NewAccount(b.DevAuthMethodId, password.WithLoginName(b.DevLoginName))
if err != nil {
return fmt.Errorf("error creating new in memory auth account: %w", err)
}
acct, err = pwRepo.CreateAccount(ctx, scope.Global.String(), acct, password.WithPassword(pw))
acct, err = pwRepo.CreateAccount(ctx, scope.Global.String(), acct, password.WithPassword(b.DevPassword))
if err != nil {
return fmt.Errorf("error saving auth account to the db: %w", err)
}
b.InfoKeys = append(b.InfoKeys, "dev login name")
b.Info["dev login name"] = acct.GetLoginName()
b.InfoKeys = append(b.InfoKeys, "generated login name")
b.Info["generated login name"] = acct.GetLoginName()
// Create a role tying them together
iamRepo, err := iam.NewRepository(rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader))
@ -552,24 +594,21 @@ func (b *Server) CreateDevDatabase(dialect string, opt ...Option) error {
}
pr, err := iam.NewRole(scope.Global.String())
if err != nil {
return fmt.Errorf("error creating in memory role for default dev grants: %w", err)
return fmt.Errorf("error creating in memory role for generated grants: %w", err)
}
pr.Name = "Dev Mode Global Scope Admin Role"
pr.Name = "Generated Global Scope Admin Role"
pr.Description = `Provides admin grants to all authenticated users within the "global" scope`
defPermsRole, err := iamRepo.CreateRole(ctx, pr)
if err != nil {
return fmt.Errorf("error creating role for default dev grants: %w", err)
return fmt.Errorf("error creating role for default generated grants: %w", err)
}
if _, err := iamRepo.AddRoleGrants(ctx, defPermsRole.PublicId, defPermsRole.Version, []string{"id=*;actions=*"}); err != nil {
return fmt.Errorf("error creating grant for default dev grants: %w", err)
return fmt.Errorf("error creating grant for default generated grants: %w", err)
}
if _, err := iamRepo.AddPrincipalRoles(ctx, defPermsRole.PublicId, defPermsRole.Version+1, []string{"u_auth"}, nil); err != nil {
return fmt.Errorf("error adding principal to role for default dev grants: %w", err)
return fmt.Errorf("error adding principal to role for default generated grants: %w", err)
}
// now that we have passed all the error cases, reset c to be a noop so the
// defer doesn't do anything.
c = func() error { return nil }
return nil
}

@ -35,6 +35,7 @@ type Command struct {
flagDevControllerAPIListenAddr string
flagDevControllerClusterListenAddr string
flagDevSkipAuthMethodCreation bool
flagDevDisableDatabaseDestruction bool
}
func (c *Command) Synopsis() string {
@ -124,6 +125,12 @@ func (c *Command) Flags() *base.FlagSets {
Usage: "If set, an auth method will not be created as part of the dev instance. The recovery KMS will be needed to perform any actions.",
})
f.BoolVar(&base.BoolVar{
Name: "dev-disable-database-destruction",
Target: &c.flagDevDisableDatabaseDestruction,
Usage: "If set, if a database is created automatically in Docker, it will not be removed when the dev server is shut down.",
})
f.BoolVar(&base.BoolVar{
Name: "combine-logs",
Target: &c.flagCombineLogs,
@ -266,7 +273,9 @@ func (c *Command) Run(args []string) int {
c.UI.Error(fmt.Errorf("Error creating dev database container: %w", err).Error())
return 1
}
c.ShutdownFuncs = append(c.ShutdownFuncs, c.DestroyDevDatabase)
if !c.flagDevDisableDatabaseDestruction {
c.ShutdownFuncs = append(c.ShutdownFuncs, c.DestroyDevDatabase)
}
c.PrintInfo(c.UI, "dev mode")
c.ReleaseLogGate()

@ -17,6 +17,7 @@ import (
func TestAuthenticationHandler(t *testing.T) {
c := NewTestController(t, &TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: "ampw_1234567890",
DefaultLoginName: "admin",
DefaultPassword: "password123",
})

@ -194,9 +194,11 @@ func (tc *TestController) Shutdown() {
if err := tc.b.RunShutdownFuncs(); err != nil {
tc.t.Error(err)
}
if tc.b.DestroyDevDatabase() != nil {
if err := tc.b.DestroyDevDatabase(); err != nil {
tc.t.Error(err)
if !tc.opts.DisableDatabaseDestruction {
if tc.b.DestroyDevDatabase() != nil {
if err := tc.b.DestroyDevDatabase(); err != nil {
tc.t.Error(err)
}
}
}
}
@ -223,6 +225,10 @@ type TestControllerOpts struct {
// database
DisableDatabaseCreation bool
// DisableDatabaseDestruction can be set true to allow a database to be
// created but examined after-the-fact
DisableDatabaseDestruction bool
// If set, instead of creating a dev database, it will connect to an
// existing database given the url
DatabaseUrl string
@ -350,6 +356,14 @@ func NewTestController(t *testing.T, opts *TestControllerOpts) *TestController {
if err := tc.b.ConnectToDatabase("postgres"); err != nil {
t.Fatal(err)
}
if err := tc.b.CreateGlobalKmsKeys(); err != nil {
t.Fatal(err)
}
if !opts.DisableAuthMethodCreation {
if err := tc.b.CreateInitialAuthMethod(); err != nil {
t.Fatal(err)
}
}
} else if !opts.DisableDatabaseCreation {
var createOpts []base.Option
if opts.DisableAuthMethodCreation {

@ -39,18 +39,19 @@ func getOpts(opt ...Option) (*controller.TestControllerOpts, error) {
}
type option struct {
tcOptions *controller.TestControllerOpts
setWithConfigFile bool
setWithConfigText bool
setDisableAuthMethodCreation bool
setDisableDatabaseCreation bool
setDefaultAuthMethodId bool
setDefaultLoginName bool
setDefaultPassword bool
setRootKms bool
setWorkerAuthKms bool
setRecoveryKms bool
setDatabaseUrl bool
tcOptions *controller.TestControllerOpts
setWithConfigFile bool
setWithConfigText bool
setDisableAuthMethodCreation bool
setDisableDatabaseCreation bool
setDisableDatabaseDesctruction bool
setDefaultAuthMethodId bool
setDefaultLoginName bool
setDefaultPassword bool
setRootKms bool
setWorkerAuthKms bool
setRecoveryKms bool
setDatabaseUrl bool
}
type Option func(*option) error
@ -108,6 +109,16 @@ func DisableDatabaseCreation() Option {
}
}
// DisableDatabaseCreation skips creating a database in docker and allows one to
// be provided through a tcOptions.
func DisableDatabaseDestruction() Option {
return func(c *option) error {
c.setDisableDatabaseDestruction = true
c.tcOptions.DisableDatabaseDestruction = true
return nil
}
}
func WithDefaultAuthMethodId(id string) Option {
return func(c *option) error {
c.setDefaultAuthMethodId = true

Loading…
Cancel
Save