diff --git a/depowners.md b/depowners.md index de75af9e1..089092798 100644 --- a/depowners.md +++ b/depowners.md @@ -86,6 +86,9 @@ the first place. * github.com/kr/pretty * Jeff * github.com/lib/pq + * Jim + * Mike +* github.com/jackc/pgx * Jim * Mike * github.com/mattn/go-colorable diff --git a/go.mod b/go.mod index e62f65e4f..c89dffc48 100644 --- a/go.mod +++ b/go.mod @@ -52,12 +52,11 @@ require ( github.com/hashicorp/vault/sdk v0.2.1 github.com/iancoleman/strcase v0.2.0 github.com/jackc/pgconn v1.10.0 + github.com/jackc/pgx/v4 v4.11.0 github.com/jefferai/keyring v1.1.7-0.20210105022822-8749b3d9ce79 - github.com/jinzhu/gorm v1.9.12 github.com/json-iterator/go v1.1.10 // indirect github.com/kr/pretty v0.3.0 github.com/kr/text v0.2.0 - github.com/lib/pq v1.10.3 github.com/mattn/go-colorable v0.1.8 github.com/mattn/go-isatty v0.0.13 // indirect github.com/mitchellh/cli v1.1.2 diff --git a/go.sum b/go.sum index 625890ad7..d1e9edf79 100644 --- a/go.sum +++ b/go.sum @@ -708,9 +708,8 @@ github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.6.0/go.mod h1:4vXEAYvW1fRQ2/FhZ78H73A60MHw1geSm145z2mdY1g= +github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg= -github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= diff --git a/internal/auth/oidc/repository_account_test.go b/internal/auth/oidc/repository_account_test.go index 11a22ac64..62dc111da 100644 --- a/internal/auth/oidc/repository_account_test.go +++ b/internal/auth/oidc/repository_account_test.go @@ -1160,7 +1160,7 @@ func TestRepository_UpdateAccount(t *testing.T) { assert.Equal(tt.wantCount, gotCount, "row count") assert.NotSame(tt.orig, got) assert.Equal(tt.orig.AuthMethodId, got.AuthMethodId) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if tt.want.Name == "" { diff --git a/internal/auth/oidc/repository_managed_group_test.go b/internal/auth/oidc/repository_managed_group_test.go index e7600db3a..12cbc8db9 100644 --- a/internal/auth/oidc/repository_managed_group_test.go +++ b/internal/auth/oidc/repository_managed_group_test.go @@ -952,7 +952,7 @@ func TestRepository_UpdateManagedGroup(t *testing.T) { assert.Equal(tt.wantCount, gotCount, "row count") assert.NotSame(tt.orig, got) assert.Equal(tt.orig.AuthMethodId, got.AuthMethodId) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if tt.want.Name == "" { diff --git a/internal/auth/oidc/testing.go b/internal/auth/oidc/testing.go index 4fc07d8fb..d46ff8c6d 100644 --- a/internal/auth/oidc/testing.go +++ b/internal/auth/oidc/testing.go @@ -31,7 +31,6 @@ import ( wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/timestamppb" - "gorm.io/gorm" ) const TestFakeManagedGroupFilter = `"/foo" == "bar"` @@ -41,7 +40,7 @@ const TestFakeManagedGroupFilter = `"/foo" == "bar"` // WithSigningAlgs options are supported. func TestAuthMethod( t *testing.T, - conn *gorm.DB, + conn *db.DB, databaseWrapper wrapping.Wrapper, scopeId string, state AuthMethodState, @@ -158,7 +157,7 @@ func TestSortAuthMethods(t *testing.T, methods []*AuthMethod) { } // TestAccount creates a test oidc auth account. -func TestAccount(t *testing.T, conn *gorm.DB, am *AuthMethod, subject string, opt ...Option) *Account { +func TestAccount(t *testing.T, conn *db.DB, am *AuthMethod, subject string, opt ...Option) *Account { t.Helper() require := require.New(t) rw := db.New(conn) @@ -179,7 +178,7 @@ func TestAccount(t *testing.T, conn *gorm.DB, am *AuthMethod, subject string, op } // TestManagedGroup creates a test oidc managed group. -func TestManagedGroup(t *testing.T, conn *gorm.DB, am *AuthMethod, filter string, opt ...Option) *ManagedGroup { +func TestManagedGroup(t *testing.T, conn *db.DB, am *AuthMethod, filter string, opt ...Option) *ManagedGroup { t.Helper() require := require.New(t) rw := db.New(conn) @@ -197,7 +196,7 @@ func TestManagedGroup(t *testing.T, conn *gorm.DB, am *AuthMethod, filter string } // TestManagedGroupMember adds given account IDs to a managed group -func TestManagedGroupMember(t *testing.T, conn *gorm.DB, managedGroupId, memberId string, opt ...Option) *ManagedGroupMemberAccount { +func TestManagedGroupMember(t *testing.T, conn *db.DB, managedGroupId, memberId string, opt ...Option) *ManagedGroupMemberAccount { t.Helper() require := require.New(t) rw := db.New(conn) diff --git a/internal/auth/password/argon2_test.go b/internal/auth/password/argon2_test.go index 0a81f2bc5..f53fb4534 100644 --- a/internal/auth/password/argon2_test.go +++ b/internal/auth/password/argon2_test.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/boundary/internal/iam" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) func TestArgon2Configuration_New(t *testing.T) { @@ -289,7 +288,7 @@ func TestArgon2Configuration_Validate(t *testing.T) { } } -func testArgon2Confs(t *testing.T, conn *gorm.DB, authMethodId string, count int) []*Argon2Configuration { +func testArgon2Confs(t *testing.T, conn *db.DB, authMethodId string, count int) []*Argon2Configuration { t.Helper() assert, require := assert.New(t), require.New(t) rw := db.New(conn) diff --git a/internal/auth/password/repository_account_test.go b/internal/auth/password/repository_account_test.go index 031d5efb3..13ee140a7 100644 --- a/internal/auth/password/repository_account_test.go +++ b/internal/auth/password/repository_account_test.go @@ -589,6 +589,7 @@ func TestRepository_UpdateAccount(t *testing.T) { wrapper := db.TestWrapper(t) kms := kms.TestKms(t, conn, wrapper) iamRepo := iam.TestRepo(t, conn, wrapper) + ctx := context.Background() changeLoginName := func(s string) func(*Account) *Account { return func(a *Account) *Account { @@ -949,7 +950,7 @@ func TestRepository_UpdateAccount(t *testing.T) { assert.Equal(tt.wantCount, gotCount, "row count") assert.NotSame(tt.orig, got) assert.Equal(tt.orig.AuthMethodId, got.AuthMethodId) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if tt.want.Name == "" { diff --git a/internal/auth/password/repository_authmethod_test.go b/internal/auth/password/repository_authmethod_test.go index 33783b0e6..1c5a073a6 100644 --- a/internal/auth/password/repository_authmethod_test.go +++ b/internal/auth/password/repository_authmethod_test.go @@ -769,7 +769,7 @@ func TestRepository_UpdateAuthMethod(t *testing.T) { require.NoError(err) assert.Empty(cmp.Diff(updatedAM, foundAuthMethod, protocmp.Transform())) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if amToUpdate.Name == "" && contains(tt.args.fieldMaskPaths, "name") { diff --git a/internal/auth/password/testing.go b/internal/auth/password/testing.go index 1f6995403..975ed4cb9 100644 --- a/internal/auth/password/testing.go +++ b/internal/auth/password/testing.go @@ -8,13 +8,12 @@ import ( "github.com/hashicorp/boundary/internal/db" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) // TestAuthMethod creates a password auth methods to the provided DB with the // provided scope id. If any errors are encountered during the creation of the // auth methods, the test will fail. -func TestAuthMethod(t *testing.T, conn *gorm.DB, scopeId string, opt ...Option) *AuthMethod { +func TestAuthMethod(t *testing.T, conn *db.DB, scopeId string, opt ...Option) *AuthMethod { t.Helper() assert, require := assert.New(t), require.New(t) w := db.New(conn) @@ -48,7 +47,7 @@ func TestAuthMethod(t *testing.T, conn *gorm.DB, scopeId string, opt ...Option) // TestAuthMethods creates count number of password auth methods to the provided DB // with the provided scope id. If any errors are encountered during the creation of // the auth methods, the test will fail. -func TestAuthMethods(t *testing.T, conn *gorm.DB, scopeId string, count int) []*AuthMethod { +func TestAuthMethods(t *testing.T, conn *db.DB, scopeId string, count int) []*AuthMethod { t.Helper() var auts []*AuthMethod for i := 0; i < count; i++ { @@ -60,7 +59,7 @@ func TestAuthMethods(t *testing.T, conn *gorm.DB, scopeId string, count int) []* // TestMultipleAccounts creates count number of password account to the provided DB // with the provided auth method id. The auth method must have been created previously. // If any errors are encountered during the creation of the account, the test will fail. -func TestMultipleAccounts(t *testing.T, conn *gorm.DB, authMethodId string, count int) []*Account { +func TestMultipleAccounts(t *testing.T, conn *db.DB, authMethodId string, count int) []*Account { t.Helper() var auts []*Account for i := 0; i < count; i++ { @@ -73,7 +72,7 @@ func TestMultipleAccounts(t *testing.T, conn *gorm.DB, authMethodId string, coun // auth method id and loginName. The auth method must have been created // previously. See password.NewAccount(...) for a list of supported options. // If any errors are encountered during the creation of the account, the test will fail. -func TestAccount(t *testing.T, conn *gorm.DB, authMethodId, loginName string, opt ...Option) *Account { +func TestAccount(t *testing.T, conn *db.DB, authMethodId, loginName string, opt ...Option) *Account { t.Helper() assert, require := assert.New(t), require.New(t) require.NotEmpty(loginName) diff --git a/internal/authtoken/testing.go b/internal/authtoken/testing.go index 2b95e00c4..b34cded2f 100644 --- a/internal/authtoken/testing.go +++ b/internal/authtoken/testing.go @@ -9,10 +9,9 @@ import ( "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/kms" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) -func TestAuthToken(t *testing.T, conn *gorm.DB, kms *kms.Kms, scopeId string, opt ...Option) *AuthToken { +func TestAuthToken(t *testing.T, conn *db.DB, kms *kms.Kms, scopeId string, opt ...Option) *AuthToken { t.Helper() authMethod := password.TestAuthMethods(t, conn, scopeId, 1)[0] // auth account is only used to join auth method to user. diff --git a/internal/cmd/base/dev.go b/internal/cmd/base/dev.go index 5db90e915..58185f21e 100644 --- a/internal/cmd/base/dev.go +++ b/internal/cmd/base/dev.go @@ -94,7 +94,7 @@ func (b *Server) CreateDevDatabase(ctx context.Context, opt ...Option) error { b.Info["dev database container"] = strings.TrimPrefix(container, "/") } - if err := b.ConnectToDatabase(dialect); err != nil { + if err := b.ConnectToDatabase(ctx, dialect); err != nil { if c != nil { err = multierror.Append(err, c()) } diff --git a/internal/cmd/base/internal/docker/supported.go b/internal/cmd/base/internal/docker/supported.go index 55867a8e2..50460fc18 100644 --- a/internal/cmd/base/internal/docker/supported.go +++ b/internal/cmd/base/internal/docker/supported.go @@ -4,11 +4,12 @@ package docker import ( - "database/sql" "fmt" "os" "strings" + "github.com/hashicorp/boundary/internal/db/common" + _ "github.com/jackc/pgx/v4/stdlib" "github.com/ory/dockertest/v3" ) @@ -37,7 +38,7 @@ func startDbInDockerSupported(dialect string, opt ...Option) (cleanup func() err } switch dialect { - case "postgres": + case "postgres", "pgx": switch { case os.Getenv("BOUNDARY_TESTING_PG_URL") != "": url = os.Getenv("BOUNDARY_TESTING_PG_URL") @@ -68,7 +69,7 @@ func startDbInDockerSupported(dialect string, opt ...Option) (cleanup func() err } if err := pool.Retry(func() error { - db, err := sql.Open(dialect, url) + db, err := common.SqlOpen(dialect, url) if err != nil { return fmt.Errorf("error opening %s dev container: %w", dialect, err) } diff --git a/internal/cmd/base/servers.go b/internal/cmd/base/servers.go index e9edaf369..90d7671b3 100644 --- a/internal/cmd/base/servers.go +++ b/internal/cmd/base/servers.go @@ -39,8 +39,6 @@ import ( "github.com/hashicorp/go-secure-stdlib/strutil" "github.com/mitchellh/cli" "google.golang.org/grpc/grpclog" - "gorm.io/gorm" - "gorm.io/gorm/logger" ) const ( @@ -120,7 +118,7 @@ type Server struct { DatabaseMaxOpenConnections int DevDatabaseCleanupFunc func() error - Database *gorm.DB + Database *db.DB // StatusGracePeriodDuration represents the period of time (as a // duration) that the controller will wait before marking @@ -548,38 +546,22 @@ func (b *Server) RunShutdownFuncs() error { return mErr.ErrorOrNil() } -func (b *Server) ConnectToDatabase(dialect string) error { +func (b *Server) ConnectToDatabase(ctx context.Context, dialect string) error { dbType, err := db.StringToDbType(dialect) if err != nil { return fmt.Errorf("unable to create db object with dialect %s: %w", dialect, err) } - dbase, err := db.Open(dbType, b.DatabaseUrl) + opts := []db.Option{ + db.WithMaxOpenConnections(b.DatabaseMaxOpenConnections), + } + if os.Getenv("BOUNDARY_DISABLE_GORM_FORMATTER") == "" { + opts = append(opts, db.WithGormFormatter(b.Logger)) + } + dbase, err := db.Open(dbType, b.DatabaseUrl, opts...) if err != nil { return fmt.Errorf("unable to create db object with dialect %s: %w", dialect, err) } - if b.DatabaseMaxOpenConnections == 1 { - return fmt.Errorf("unable to create db object with dialect %s: %s", dialect, "max_open_connections must be unlimited by setting 0 or at least 2") - } else { - underlyingDB, err := dbase.DB() - if err != nil { - return fmt.Errorf("unable retreive db: %w", err) - } - underlyingDB.SetMaxOpenConns(b.DatabaseMaxOpenConnections) - } b.Database = dbase - if os.Getenv("BOUNDARY_DISABLE_GORM_FORMATTER") == "" { - newLogger := logger.New( - db.GetGormLogger(b.Logger), - logger.Config{ - LogLevel: logger.Error, // Log level - Colorful: false, // Disable color - }, - ) - dbase = dbase.Session(&gorm.Session{Logger: newLogger}) - } - - b.Database = dbase - return nil } @@ -618,13 +600,11 @@ func (b *Server) CreateGlobalKmsKeys(ctx context.Context) error { return nil } -func (b *Server) DestroyDevDatabase() error { +func (b *Server) DestroyDevDatabase(ctx context.Context) error { if b.Database != nil { - underlyingDB, err := b.Database.DB() - if err != nil { + if err := b.Database.Close(ctx); err != nil { return err } - underlyingDB.Close() } if b.DevDatabaseCleanupFunc != nil { return b.DevDatabaseCleanupFunc() diff --git a/internal/cmd/commands/database/funcs.go b/internal/cmd/commands/database/funcs.go index f1ea8d486..9438b8725 100644 --- a/internal/cmd/commands/database/funcs.go +++ b/internal/cmd/commands/database/funcs.go @@ -2,10 +2,10 @@ package database import ( "context" - "database/sql" "fmt" "github.com/hashicorp/boundary/internal/cmd/base" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/internal/db/schema" "github.com/hashicorp/boundary/internal/errors" "github.com/mitchellh/cli" @@ -20,7 +20,7 @@ func migrateDatabase(ctx context.Context, ui cli.Ui, dialect, u string, initiali noop := func() {} // This database is used to keep an exclusive lock on the database for the // remainder of the command - dBase, err := sql.Open(dialect, u) + dBase, err := common.SqlOpen(dialect, u) if err != nil { ui.Error(fmt.Errorf("Error establishing db connection: %w", err).Error()) return noop, 2 diff --git a/internal/cmd/commands/database/funcs_test.go b/internal/cmd/commands/database/funcs_test.go index fe41b4656..6ad2dd1b5 100644 --- a/internal/cmd/commands/database/funcs_test.go +++ b/internal/cmd/commands/database/funcs_test.go @@ -2,10 +2,10 @@ package database import ( "context" - "database/sql" "testing" "github.com/hashicorp/boundary/internal/cmd/base" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/internal/db/schema" "github.com/hashicorp/boundary/testing/dbtest" "github.com/mitchellh/cli" @@ -49,7 +49,7 @@ func TestMigrateDatabase(t *testing.T) { require.NoError(t, c()) }) - dBase, err := sql.Open(dialect, u) + dBase, err := common.SqlOpen(dialect, u) require.NoError(t, err) earlyMigrationVersion := 2000 @@ -75,7 +75,7 @@ func TestMigrateDatabase(t *testing.T) { require.NoError(t, c()) }) - dBase, err := sql.Open(dialect, u) + dBase, err := common.SqlOpen(dialect, u) require.NoError(t, err) earlyMigrationVersion := 2000 @@ -100,7 +100,7 @@ func TestMigrateDatabase(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - dBase, err := sql.Open(dialect, u) + dBase, err := common.SqlOpen(dialect, u) require.NoError(t, err) createStmt := `create table if not exists schema_migrations (version bigint primary key, dirty boolean not null)` @@ -120,7 +120,7 @@ func TestMigrateDatabase(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - dBase, err := sql.Open(dialect, u) + dBase, err := common.SqlOpen(dialect, u) require.NoError(t, err) createStmt := `create table if not exists schema_migrations (version bigint primary key, dirty boolean not null)` @@ -154,7 +154,7 @@ func TestMigrateDatabase(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - dBase, err := sql.Open(dialect, u) + dBase, err := common.SqlOpen(dialect, u) require.NoError(t, err) man, err := schema.NewManager(ctx, dialect, dBase) @@ -177,7 +177,7 @@ func TestMigrateDatabase(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - dBase, err := sql.Open(dialect, u) + dBase, err := common.SqlOpen(dialect, u) require.NoError(t, err) man, err := schema.NewManager(ctx, dialect, dBase) @@ -217,7 +217,7 @@ func TestVerifyOplogIsEmpty(t *testing.T) { }) _ = c - dBase, err := sql.Open(dialect, u) + dBase, err := common.SqlOpen(dialect, u) require.NoError(t, err) man, err := schema.NewManager(ctx, dialect, dBase) @@ -228,7 +228,7 @@ func TestVerifyOplogIsEmpty(t *testing.T) { cmd.srv = base.NewServer(&base.Command{UI: cmd.UI}) cmd.srv.DatabaseUrl = u - require.NoError(t, cmd.srv.ConnectToDatabase(dialect)) + require.NoError(t, cmd.srv.ConnectToDatabase(ctx, dialect)) - assert.NoError(t, cmd.verifyOplogIsEmpty()) + assert.NoError(t, cmd.verifyOplogIsEmpty(ctx)) } diff --git a/internal/cmd/commands/database/init.go b/internal/cmd/commands/database/init.go index 47c40cd48..6c8a81abf 100644 --- a/internal/cmd/commands/database/init.go +++ b/internal/cmd/commands/database/init.go @@ -1,6 +1,7 @@ package database import ( + "context" "fmt" "github.com/hashicorp/boundary/internal/cmd/base" @@ -164,6 +165,7 @@ func (c *InitCommand) AutocompleteFlags() complete.Flags { } func (c *InitCommand) Run(args []string) (retCode int) { + ctx := context.Background() if result := c.ParseFlagsAndConfig(args); result > 0 { return result } @@ -277,11 +279,11 @@ func (c *InitCommand) Run(args []string) (retCode int) { return base.CommandUserError } // Everything after is done with normal database URL and is affecting actual data - if err := c.srv.ConnectToDatabase(dialect); err != nil { + if err := c.srv.ConnectToDatabase(ctx, dialect); err != nil { c.UI.Error(fmt.Errorf("Error connecting to database after migrations: %w", err).Error()) return base.CommandCliError } - if err := c.verifyOplogIsEmpty(); err != nil { + if err := c.verifyOplogIsEmpty(ctx); err != nil { c.UI.Error(fmt.Sprintf("The database appears to have already been initialized: %v", err)) return base.CommandCliError } @@ -491,9 +493,9 @@ func (c *InitCommand) ParseFlagsAndConfig(args []string) int { return base.CommandSuccess } -func (c *InitCommand) verifyOplogIsEmpty() error { +func (c *InitCommand) verifyOplogIsEmpty(ctx context.Context) error { const op = "database.(InitCommand).verifyOplogIsEmpty" - underlyingDB, err := c.srv.Database.DB() + underlyingDB, err := c.srv.Database.SqlDB(ctx) if err != nil { return errors.NewDeprecated(errors.Internal, op, "unable to retreive db", errors.WithWrap(err)) } diff --git a/internal/cmd/commands/dev/dev.go b/internal/cmd/commands/dev/dev.go index 6cb3934f6..8df71fd6c 100644 --- a/internal/cmd/commands/dev/dev.go +++ b/internal/cmd/commands/dev/dev.go @@ -556,7 +556,7 @@ func (c *Command) Run(args []string) int { } if !c.flagDisableDatabaseDestruction { - c.ShutdownFuncs = append(c.ShutdownFuncs, c.DestroyDevDatabase) + c.ShutdownFuncs = append(c.ShutdownFuncs, func() error { return c.DestroyDevDatabase(ctx) }) } default: c.DatabaseUrl, err = parseutil.ParsePath(c.flagDatabaseUrl) diff --git a/internal/cmd/commands/server/server.go b/internal/cmd/commands/server/server.go index 1139573a9..a2851a79d 100644 --- a/internal/cmd/commands/server/server.go +++ b/internal/cmd/commands/server/server.go @@ -389,12 +389,12 @@ func (c *Command) Run(args []string) int { } c.DatabaseMaxOpenConnections = c.Config.Controller.Database.MaxOpenConnections - if err := c.ConnectToDatabase("postgres"); err != nil { + if err := c.ConnectToDatabase(ctx, "postgres"); err != nil { c.UI.Error(fmt.Errorf("Error connecting to database: %w", err).Error()) return base.CommandCliError } - underlyingDB, err := c.Database.DB() + underlyingDB, err := c.Database.SqlDB(ctx) if err != nil { c.UI.Error(fmt.Errorf("Can't get db: %w.", err).Error()) return base.CommandCliError diff --git a/internal/credential/vault/jobs_test.go b/internal/credential/vault/jobs_test.go index 35f963c98..3ceeaadf2 100644 --- a/internal/credential/vault/jobs_test.go +++ b/internal/credential/vault/jobs_test.go @@ -21,7 +21,6 @@ import ( vault "github.com/hashicorp/vault/api" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) const testUpdateTokenStatusExpirationQuery = ` @@ -33,7 +32,7 @@ update credential_vault_token ` func testVaultToken(t *testing.T, - conn *gorm.DB, + conn *db.DB, wrapper wrapping.Wrapper, v *TestVaultServer, cs *CredentialStore, @@ -87,7 +86,7 @@ func testVaultToken(t *testing.T, } func testVaultCred(t *testing.T, - conn *gorm.DB, + conn *db.DB, v *TestVaultServer, cl *CredentialLibrary, sess *session.Session, diff --git a/internal/credential/vault/repository_credential_library_test.go b/internal/credential/vault/repository_credential_library_test.go index 6a1e9320f..039675242 100644 --- a/internal/credential/vault/repository_credential_library_test.go +++ b/internal/credential/vault/repository_credential_library_test.go @@ -795,7 +795,7 @@ func TestRepository_UpdateCredentialLibrary(t *testing.T) { assert.Equal(tt.wantCount, gotCount, "row count") assert.NotSame(tt.orig, got) assert.Equal(tt.orig.StoreId, got.StoreId) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if tt.want.Name == "" { diff --git a/internal/credential/vault/repository_credential_store_test.go b/internal/credential/vault/repository_credential_store_test.go index e44b0bde7..2b7f72484 100644 --- a/internal/credential/vault/repository_credential_store_test.go +++ b/internal/credential/vault/repository_credential_store_test.go @@ -23,7 +23,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/testing/protocmp" - "gorm.io/gorm" ) func TestRepository_CreateCredentialStoreResource(t *testing.T) { @@ -756,7 +755,7 @@ func TestRepository_UpdateCredentialStore_Attributes(t *testing.T) { assert.Equal(tt.wantCount, gotCount, "row count") assert.NotSame(tt.orig, got) assert.Equal(tt.orig.ScopeId, got.ScopeId) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if tt.want.Name == "" { @@ -887,7 +886,7 @@ func TestRepository_UpdateCredentialStore_Attributes(t *testing.T) { assert.Equal(1, gotCount2, "count of updated records") require.NotNil(got2) assert.Nil(got2.CaCert) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) dbassert.IsNull(got2, "CaCert") @@ -1270,9 +1269,9 @@ func TestRepository_DeleteCredentialStore(t *testing.T) { type tokenMap map[string]*tokenCount - type setupFn func(t *testing.T, conn *gorm.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) + type setupFn func(t *testing.T, conn *db.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) - baseSetup := func(t *testing.T, conn *gorm.DB) (wrapper wrapping.Wrapper, repo *Repository, scopeId string) { + baseSetup := func(t *testing.T, conn *db.DB) (wrapper wrapping.Wrapper, repo *Repository, scopeId string) { wrapper = db.TestWrapper(t) kms := kms.TestKms(t, conn, wrapper) sche := scheduler.TestScheduler(t, conn, wrapper) @@ -1286,7 +1285,7 @@ func TestRepository_DeleteCredentialStore(t *testing.T) { return } - testStores := func(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, tokens tokenMap, scopeId string, count int) ([]*CredentialStore, tokenMap) { + testStores := func(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, tokens tokenMap, scopeId string, count int) ([]*CredentialStore, tokenMap) { if tokens == nil { tokens = make(tokenMap) } @@ -1299,13 +1298,13 @@ func TestRepository_DeleteCredentialStore(t *testing.T) { return css, tokens } - makeMaintainingTokens := func(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, tokens tokenMap, scopeId, storeId string, count int) tokenMap { + makeMaintainingTokens := func(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, tokens tokenMap, scopeId, storeId string, count int) tokenMap { testTokens(t, conn, wrapper, scopeId, storeId, count) tokens[storeId].maintaining = count return tokens } - makeRevokedTokens := func(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, tokens tokenMap, scopeId, storeId string, count int) tokenMap { + makeRevokedTokens := func(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, tokens tokenMap, scopeId, storeId string, count int) tokenMap { require.NotNil(t, tokens) const query = ` update credential_vault_token @@ -1327,7 +1326,7 @@ update credential_vault_token return tokens } - makeExpiredTokens := func(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, tokens tokenMap, scopeId, storeId string, count int) tokenMap { + makeExpiredTokens := func(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, tokens tokenMap, scopeId, storeId string, count int) tokenMap { require.NotNil(t, tokens) const query = ` update credential_vault_token @@ -1349,7 +1348,7 @@ update credential_vault_token return tokens } - assertTokens := func(t *testing.T, conn *gorm.DB, want tokenMap) { + assertTokens := func(t *testing.T, conn *db.DB, want tokenMap) { const query = ` select store_id, status, count(token_hmac) from credential_vault_token @@ -1399,7 +1398,7 @@ group by store_id, status; }{ { name: "simple", - setup: func(t *testing.T, conn *gorm.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { + setup: func(t *testing.T, conn *db.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { wrapper, repo, scopeId := baseSetup(t, conn) css, tokens := testStores(t, conn, wrapper, nil, scopeId, 1) cs := css[0] @@ -1409,7 +1408,7 @@ group by store_id, status; }, { name: "with-libraries", - setup: func(t *testing.T, conn *gorm.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { + setup: func(t *testing.T, conn *db.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { wrapper, repo, scopeId := baseSetup(t, conn) css, tokens := testStores(t, conn, wrapper, nil, scopeId, 1) cs := css[0] @@ -1421,7 +1420,7 @@ group by store_id, status; }, { name: "with-maintaining-tokens", - setup: func(t *testing.T, conn *gorm.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { + setup: func(t *testing.T, conn *db.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { wrapper, repo, scopeId := baseSetup(t, conn) css, tokens := testStores(t, conn, wrapper, nil, scopeId, 1) cs := css[0] @@ -1434,7 +1433,7 @@ group by store_id, status; }, { name: "with-revoked-tokens", - setup: func(t *testing.T, conn *gorm.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { + setup: func(t *testing.T, conn *db.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { wrapper, repo, scopeId := baseSetup(t, conn) css, tokens := testStores(t, conn, wrapper, nil, scopeId, 1) cs := css[0] @@ -1447,7 +1446,7 @@ group by store_id, status; }, { name: "with-expired-tokens", - setup: func(t *testing.T, conn *gorm.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { + setup: func(t *testing.T, conn *db.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { wrapper, repo, scopeId := baseSetup(t, conn) css, tokens := testStores(t, conn, wrapper, nil, scopeId, 1) cs := css[0] @@ -1460,7 +1459,7 @@ group by store_id, status; }, { name: "with-all-token-statuses", - setup: func(t *testing.T, conn *gorm.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { + setup: func(t *testing.T, conn *db.DB) (storeId string, libs []*CredentialLibrary, tokens tokenMap, repo *Repository) { wrapper, repo, scopeId := baseSetup(t, conn) css, tokens := testStores(t, conn, wrapper, nil, scopeId, 1) cs := css[0] diff --git a/internal/credential/vault/supported.go b/internal/credential/vault/supported.go index 206bee5f9..1cfcf95ac 100644 --- a/internal/credential/vault/supported.go +++ b/internal/credential/vault/supported.go @@ -5,7 +5,6 @@ package vault import ( "crypto/tls" - "database/sql" "fmt" "io/ioutil" "net/http" @@ -16,8 +15,10 @@ import ( "testing" "time" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/go-rootcerts" vault "github.com/hashicorp/vault/api" + _ "github.com/jackc/pgx/v4/stdlib" "github.com/ory/dockertest/v3" "github.com/stretchr/testify/require" ) @@ -224,7 +225,7 @@ func gotMountDatabase(t *testing.T, v *TestVaultServer, opt ...TestOption) *Test dburl := fmt.Sprintf(dbUrlTemplate, "postgres", "password") err = pool.Retry(func() error { var err error - db, err := sql.Open("postgres", dburl) + db, err := common.SqlOpen("postgres", dburl) if err != nil { return err } @@ -244,7 +245,7 @@ func gotMountDatabase(t *testing.T, v *TestVaultServer, opt ...TestOption) *Test grantClosedRole = `grant select, insert, update, delete on boundary_closed to closed_role` ) - db, err := sql.Open("postgres", dburl) + db, err := common.SqlOpen("postgres", dburl) require.NoError(err) defer db.Close() diff --git a/internal/credential/vault/testing.go b/internal/credential/vault/testing.go index bc9bb2741..53042d626 100644 --- a/internal/credential/vault/testing.go +++ b/internal/credential/vault/testing.go @@ -7,7 +7,6 @@ import ( "crypto/rand" "crypto/x509" "crypto/x509/pkix" - "database/sql" "encoding/pem" "fmt" "math/big" @@ -19,6 +18,7 @@ import ( "testing" "time" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/db" @@ -28,14 +28,13 @@ import ( vault "github.com/hashicorp/vault/api" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) // TestCredentialStore creates a vault credential store in the provided DB with // the provided scope, vault address, token, and accessor and any values passed // in through the Options vargs. If any errors are encountered during the // creation of the store, the test will fail. -func TestCredentialStore(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, scopeId, vaultAddr, vaultToken, accessor string, opts ...Option) *CredentialStore { +func TestCredentialStore(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, scopeId, vaultAddr, vaultToken, accessor string, opts ...Option) *CredentialStore { t.Helper() ctx := context.Background() kmsCache := kms.TestKms(t, conn, wrapper) @@ -76,7 +75,7 @@ func TestCredentialStore(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, // the provided DB with the provided scope id. If any errors are // encountered during the creation of the credential stores, the test will // fail. -func TestCredentialStores(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, scopeId string, count int) []*CredentialStore { +func TestCredentialStores(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, scopeId string, count int) []*CredentialStore { t.Helper() ctx := context.Background() kmsCache := kms.TestKms(t, conn, wrapper) @@ -114,7 +113,7 @@ func TestCredentialStores(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, // libraries in the provided DB with the provided store id. If any errors // are encountered during the creation of the credential libraries, the // test will fail. -func TestCredentialLibraries(t *testing.T, conn *gorm.DB, _ wrapping.Wrapper, storeId string, count int) []*CredentialLibrary { +func TestCredentialLibraries(t *testing.T, conn *db.DB, _ wrapping.Wrapper, storeId string, count int) []*CredentialLibrary { t.Helper() assert, require := assert.New(t), require.New(t) w := db.New(conn) @@ -145,7 +144,7 @@ func TestCredentialLibraries(t *testing.T, conn *gorm.DB, _ wrapping.Wrapper, st // TestCredentials creates count number of vault credentials in the provided DB with // the provided library id and session id. If any errors are encountered // during the creation of the credentials, the test will fail. -func TestCredentials(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, libraryId, sessionId string, count int) []*Credential { +func TestCredentials(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, libraryId, sessionId string, count int) []*Credential { t.Helper() assert, require := assert.New(t), require.New(t) rw := db.New(conn) @@ -189,7 +188,7 @@ func TestCredentials(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, libr return credentials } -func createTestToken(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, scopeId, storeId, token, accessor string) *Token { +func createTestToken(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, scopeId, storeId, token, accessor string) *Token { t.Helper() w := db.New(conn) ctx := context.Background() @@ -211,7 +210,7 @@ func createTestToken(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, scop return inToken } -func testTokens(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, scopeId, storeId string, count int) []*Token { +func testTokens(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, scopeId, storeId string, count int) []*Token { t.Helper() assert, require := assert.New(t), require.New(t) w := db.New(conn) @@ -871,7 +870,7 @@ func (d *TestDatabase) ValidateCredential(t *testing.T, s *vault.Secret) error { require := require.New(t) require.NotNil(s) dburl := d.URL.Encode(t, s) - db, err := sql.Open("postgres", dburl) + db, err := common.SqlOpen("postgres", dburl) if err != nil { return err } diff --git a/internal/db/assert/asserts_test.go b/internal/db/assert/asserts_test.go index fff28927f..e19c2ca0a 100644 --- a/internal/db/assert/asserts_test.go +++ b/internal/db/assert/asserts_test.go @@ -1,6 +1,7 @@ package dbassert import ( + "context" "testing" "github.com/hashicorp/boundary/internal/db" @@ -10,7 +11,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) func Test_FieldDomain(t *testing.T) { @@ -59,11 +59,12 @@ func Test_FieldNullable(t *testing.T) { func Test_FieldIsNull(t *testing.T) { t.Parallel() + ctx := context.Background() assert := assert.New(t) conn, _ := db.TestSetup(t, "postgres") initStore(t, conn) require := require.New(t) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) assert.NoError(err) mockery := new(dbassert.MockTesting) @@ -82,10 +83,11 @@ func Test_FieldIsNull(t *testing.T) { func Test_FieldNotNull(t *testing.T) { t.Parallel() + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") initStore(t, conn) require := require.New(t) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) mockery := new(dbassert.MockTesting) dbassert := New(mockery, underlyingDB) @@ -113,7 +115,7 @@ type testModel struct { func (*testModel) TableName() string { return "test_table_dbasserts" } // CreateTestModel is a helper that creates a testModel in the DB. -func createTestModel(t dbassert.TestingT, db *gorm.DB, nullable *string, typeInt *int) *testModel { +func createTestModel(t dbassert.TestingT, db *db.DB, nullable *string, typeInt *int) *testModel { publicId, err := base62.Random(12) assert.NoError(t, err) m := testModel{ @@ -126,7 +128,7 @@ func createTestModel(t dbassert.TestingT, db *gorm.DB, nullable *string, typeInt return &m } -func initStore(t *testing.T, db *gorm.DB) { +func initStore(t *testing.T, db *db.DB) { t.Helper() const ( createDomainType = ` diff --git a/internal/db/common/db.go b/internal/db/common/db.go new file mode 100644 index 000000000..0a166f632 --- /dev/null +++ b/internal/db/common/db.go @@ -0,0 +1,15 @@ +package common + +import ( + "database/sql" + + _ "github.com/jackc/pgx/v4" +) + +func SqlOpen(driverName, dataSourceName string) (*sql.DB, error) { + switch driverName { + case "postgres", "pgx": + driverName = "pgx" + } + return sql.Open(driverName, dataSourceName) +} diff --git a/internal/db/db.go b/internal/db/db.go index 6331a08dd..2f5ff3d6d 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -2,14 +2,18 @@ package db import ( "context" + "database/sql" stderrors "errors" "fmt" + "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/observability/event" "github.com/hashicorp/go-hclog" "github.com/jackc/pgconn" + _ "github.com/jackc/pgx/v4" "gorm.io/driver/postgres" "gorm.io/gorm" + "gorm.io/gorm/logger" ) type DbType int @@ -34,9 +38,44 @@ func StringToDbType(dialect string) (DbType, error) { } } -// Open a database connection which is long-lived. -// You need to call Close() on the returned gorm.DB -func Open(dbType DbType, connectionUrl string) (*gorm.DB, error) { +// DB is a wrapper around the ORM +type DB struct { + *gorm.DB +} + +// SqlDB returns the underlying sql.DB +// +// Note: This func is not named DB(), because our choice of ORM (gorm) which is +// embedded for various reasons, already exports a DB() func and it's base type +// is also an export DB type +func (d *DB) SqlDB(ctx context.Context) (*sql.DB, error) { + const op = "db.(DB).SqlDB" + if d.DB == nil { + return nil, errors.New(ctx, errors.Internal, op, "missing underlying database") + } + return d.DB.DB() +} + +// Close the underlying sql.DB +func (d *DB) Close(ctx context.Context) error { + const op = "db.(DB).Close" + if d.DB == nil { + return errors.New(ctx, errors.Internal, op, "missing underlying database") + } + underlying, err := d.DB.DB() + if err != nil { + return errors.Wrap(ctx, err, op) + } + return underlying.Close() +} + +// Open a database connection which is long-lived. The options of +// WithGormFormatter and WithMaxOpenConnections are supported. +// +// Note: Consider if you need to call Close() on the returned DB. Typically the +// answer is no, but there are occasions when it's necessary. See the sql.DB +// docs for more information. +func Open(dbType DbType, connectionUrl string, opt ...Option) (*DB, error) { var dialect gorm.Dialector switch dbType { case Postgres: @@ -52,7 +91,28 @@ func Open(dbType DbType, connectionUrl string) (*gorm.DB, error) { if err != nil { return nil, fmt.Errorf("unable to open database: %w", err) } - return db, nil + opts := GetOpts(opt...) + if opts.withGormFormatter != nil { + newLogger := logger.New( + getGormLogger(opts.withGormFormatter), + logger.Config{ + LogLevel: logger.Error, // Log level + Colorful: false, // Disable color + }, + ) + db = db.Session(&gorm.Session{Logger: newLogger}) + } + if opts.withMaxOpenConnections > 0 { + if dialect.Name() == "postgres" && opts.withMaxOpenConnections == 1 { + return nil, fmt.Errorf("unable to create db object with dialect %s: %s", dialect, "max_open_connections must be unlimited by setting 0 or at least 2") + } + underlyingDB, err := db.DB() + if err != nil { + return nil, fmt.Errorf("unable retreive db: %w", err) + } + underlyingDB.SetMaxOpenConns(opts.withMaxOpenConnections) + } + return &DB{db}, nil } func GetGormLogFormatter(log hclog.Logger) func(values ...interface{}) (messages []interface{}) { @@ -85,6 +145,6 @@ func (g gormLogger) Printf(msg string, values ...interface{}) { } } -func GetGormLogger(log hclog.Logger) gormLogger { +func getGormLogger(log hclog.Logger) gormLogger { return gormLogger{logger: log} } diff --git a/internal/db/db_test.go b/internal/db/db_test.go index 915da9e26..d0730c790 100644 --- a/internal/db/db_test.go +++ b/internal/db/db_test.go @@ -1,6 +1,7 @@ package db import ( + "context" "testing" "github.com/hashicorp/boundary/testing/dbtest" @@ -8,6 +9,7 @@ import ( ) func TestOpen(t *testing.T) { + ctx := context.Background() cleanup, url, _, err := dbtest.StartUsingTemplate(dbtest.Postgres) if err != nil { t.Fatal(err) @@ -48,7 +50,7 @@ func TestOpen(t *testing.T) { got, err := Open(tt.args.dbType, tt.args.connectionUrl) defer func() { if err == nil { - sqlDB, err := got.DB() + sqlDB, err := got.SqlDB(ctx) require.NoError(t, err) err = sqlDB.Close() require.NoError(t, err) diff --git a/internal/db/domains_test.go b/internal/db/domains_test.go index bd99618da..bf6adc467 100644 --- a/internal/db/domains_test.go +++ b/internal/db/domains_test.go @@ -1,6 +1,7 @@ package db import ( + "context" "strings" "testing" "time" @@ -25,8 +26,10 @@ returning id; ` ) + ctx := context.Background() + conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) for _, typ := range []string{"public", "private", "role", "scope"} { @@ -107,9 +110,9 @@ insert into test_table values ($1); ` ) - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) if _, err := db.Exec(createTable); err != nil { @@ -179,9 +182,9 @@ insert into test_table values ($1); ` ) - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) if _, err := db.Exec(createTable); err != nil { @@ -256,8 +259,9 @@ returning id; ` ) + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) if _, err := db.Exec(createTable); err != nil { t.Fatalf("query: \n%s\n error: %s", createTable, err) @@ -322,9 +326,9 @@ update test_update_time_column set update_time = null; ` ) - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) _, err = db.Exec(createTable) assert.NoError(err) @@ -396,8 +400,8 @@ returning public_id; ) conn, _ := TestSetup(t, "postgres") assert, require := assert.New(t), require.New(t) - - db, err := conn.DB() + ctx := context.Background() + db, err := conn.SqlDB(ctx) require.NoError(err) _, err = db.Exec(createTable) @@ -457,8 +461,8 @@ returning private_id; ) conn, _ := TestSetup(t, "postgres") assert, require := assert.New(t), require.New(t) - - db, err := conn.DB() + ctx := context.Background() + db, err := conn.SqlDB(ctx) require.NoError(err) _, err = db.Exec(createTable) @@ -491,8 +495,9 @@ returning private_id; } func TestDomain_DefaultUsersExist(t *testing.T) { + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) for _, val := range []string{"u_anon", "u_auth"} { rows, err := db.Query(`select from iam_user where public_id = $1`, val) @@ -579,9 +584,9 @@ set id = null; Name string Updatable string } - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) _, err = db.Exec(createTable) assert.NoError(t, err) @@ -693,9 +698,9 @@ values ($1) returning id; ` ) - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) if _, err := db.Exec(createTable); err != nil { @@ -741,9 +746,9 @@ values ($1) returning id; ` ) - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) if _, err := db.Exec(createTable); err != nil { @@ -788,9 +793,9 @@ values ($1) returning id; ` ) - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) if _, err := db.Exec(createTable); err != nil { @@ -835,9 +840,9 @@ values ($1) returning id; ` ) - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) if _, err := db.Exec(createTable); err != nil { @@ -882,9 +887,9 @@ values ($1) returning id; ` ) - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) if _, err := db.Exec(createTable); err != nil { @@ -929,9 +934,9 @@ values ($1) returning id; ` ) - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) if _, err := db.Exec(createTable); err != nil { @@ -980,9 +985,9 @@ func TestDomain_wt_is_sentinel(t *testing.T) { select wt_is_sentinel($1); ` ) - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) tests := []struct { @@ -1043,9 +1048,9 @@ insert on test_not_null_columns ` dropTriggers = `drop trigger test_insert_not_null_columns on test_not_null_columns` ) - + ctx := context.Background() conn, _ := TestSetup(t, "postgres") - db, err := conn.DB() + db, err := conn.SqlDB(ctx) assert.NoError(t, err) _, err = db.Exec(createTable) diff --git a/internal/db/option.go b/internal/db/option.go index 1547bab9a..32b50dcc4 100644 --- a/internal/db/option.go +++ b/internal/db/option.go @@ -2,6 +2,7 @@ package db import ( "github.com/hashicorp/boundary/internal/oplog" + "github.com/hashicorp/go-hclog" wrapping "github.com/hashicorp/go-kms-wrapping" ) @@ -43,6 +44,9 @@ type Options struct { // withPrngValues is used to switch the ID generation to a pseudo-random mode withPrngValues []string + + withGormFormatter hclog.Logger + withMaxOpenConnections int } type oplogOpts struct { @@ -165,3 +169,19 @@ func WithPrngValues(withPrngValues []string) Option { o.withPrngValues = withPrngValues } } + +// WithGormFormatter specifies an optional hclog to use for gorm's log +// formmater +func WithGormFormatter(l hclog.Logger) Option { + return func(o *Options) { + o.withGormFormatter = l + } +} + +// WithMaxOpenConnections specifices and optional max open connections for the +// database +func WithMaxOpenConnections(max int) Option { + return func(o *Options) { + o.withMaxOpenConnections = max + } +} diff --git a/internal/db/option_test.go b/internal/db/option_test.go index 8a1abda47..963b9d008 100644 --- a/internal/db/option_test.go +++ b/internal/db/option_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/hashicorp/boundary/internal/oplog" + "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" ) @@ -175,4 +176,30 @@ func Test_getOpts(t *testing.T) { testOpts.withOrder = "version desc" assert.Equal(opts, testOpts) }) + t.Run("WithGormFormatter", func(t *testing.T) { + assert := assert.New(t) + // test default of false + opts := GetOpts() + testOpts := getDefaultOptions() + assert.Equal(opts, testOpts) + + testLogger := hclog.New(&hclog.LoggerOptions{}) + + // try setting to false + opts = GetOpts(WithGormFormatter(testLogger)) + testOpts.withGormFormatter = testLogger + assert.Equal(opts, testOpts) + }) + t.Run("WithMaxOpenConnections", func(t *testing.T) { + assert := assert.New(t) + // test default of false + opts := GetOpts() + testOpts := getDefaultOptions() + assert.Equal(opts, testOpts) + + // try setting to false + opts = GetOpts(WithMaxOpenConnections(22)) + testOpts.withMaxOpenConnections = 22 + assert.Equal(opts, testOpts) + }) } diff --git a/internal/db/read_writer.go b/internal/db/read_writer.go index f6946017b..119bb8f42 100644 --- a/internal/db/read_writer.go +++ b/internal/db/read_writer.go @@ -190,7 +190,7 @@ type VetForWriter interface { // Db uses a gorm DB connection for read/write type Db struct { - underlying *gorm.DB + underlying *DB } // ensure that Db implements the interfaces of: Reader and Writer @@ -199,7 +199,7 @@ var ( _ Writer = (*Db)(nil) ) -func New(underlying *gorm.DB) *Db { +func New(underlying *DB) *Db { return &Db{underlying: underlying} } @@ -597,7 +597,7 @@ func (rw *Db) Delete(ctx context.Context, i interface{}, opt ...Option) (int, er return NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get ticket")) } } - db := rw.underlying + db := rw.underlying.DB if opts.withWhereClause != "" { db = db.Where(opts.withWhereClause, opts.withWhereClauseArgs...) } @@ -713,7 +713,7 @@ func (rw *Db) getTicketFor(aggregateName string) (*store.Ticket, error) { if rw.underlying == nil { return nil, errors.NewDeprecated(errors.InvalidParameter, op, fmt.Sprintf("%s: underlying db missing", aggregateName), errors.WithoutEvent()) } - ticketer, err := oplog.NewGormTicketer(rw.underlying, oplog.WithAggregateNames(true)) + ticketer, err := oplog.NewGormTicketer(rw.underlying.DB, oplog.WithAggregateNames(true)) if err != nil { return nil, errors.WrapDeprecated(err, op, errors.WithMsg(fmt.Sprintf("%s: unable to get Ticketer", aggregateName)), errors.WithoutEvent()) } @@ -793,7 +793,7 @@ func (rw *Db) addOplogForItems(ctx context.Context, opType OpType, opts Options, if err != nil { return errors.Wrap(ctx, err, op, errors.WithMsg("oplog validation failed"), errors.WithoutEvent()) } - ticketer, err := oplog.NewGormTicketer(rw.underlying, oplog.WithAggregateNames(true)) + ticketer, err := oplog.NewGormTicketer(rw.underlying.DB, oplog.WithAggregateNames(true)) if err != nil { return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get Ticketer"), errors.WithoutEvent()) } @@ -808,7 +808,7 @@ func (rw *Db) addOplogForItems(ctx context.Context, opType OpType, opts Options, } if err := entry.WriteEntryWith( ctx, - &oplog.GormWriter{Tx: rw.underlying}, + &oplog.GormWriter{Tx: rw.underlying.DB}, ticket, oplogMsgs..., ); err != nil { @@ -827,7 +827,7 @@ func (rw *Db) addOplog(ctx context.Context, opType OpType, opts Options, ticket if ticket == nil { return errors.New(ctx, errors.InvalidParameter, op, "missing ticket", errors.WithoutEvent()) } - ticketer, err := oplog.NewGormTicketer(rw.underlying, oplog.WithAggregateNames(true)) + ticketer, err := oplog.NewGormTicketer(rw.underlying.DB, oplog.WithAggregateNames(true)) if err != nil { return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get Ticketer"), errors.WithoutEvent()) } @@ -846,7 +846,7 @@ func (rw *Db) addOplog(ctx context.Context, opType OpType, opts Options, ticket } err = entry.WriteEntryWith( ctx, - &oplog.GormWriter{Tx: rw.underlying}, + &oplog.GormWriter{Tx: rw.underlying.DB}, ticket, msg, ) @@ -876,7 +876,7 @@ func (rw *Db) WriteOplogEntryWith(ctx context.Context, wrapper wrapping.Wrapper, return errors.New(ctx, errors.InvalidParameter, op, "missing metadata") } - ticketer, err := oplog.NewGormTicketer(rw.underlying, oplog.WithAggregateNames(true)) + ticketer, err := oplog.NewGormTicketer(rw.underlying.DB, oplog.WithAggregateNames(true)) if err != nil { return errors.Wrap(ctx, err, op, errors.WithMsg("unable to get Ticketer")) } @@ -892,7 +892,7 @@ func (rw *Db) WriteOplogEntryWith(ctx context.Context, wrapper wrapping.Wrapper, } err = entry.WriteEntryWith( ctx, - &oplog.GormWriter{Tx: rw.underlying}, + &oplog.GormWriter{Tx: rw.underlying.DB}, ticket, msgs..., ) @@ -947,7 +947,7 @@ func (w *Db) DoTx(ctx context.Context, retries uint, backOff Backoff, Handler Tx newTx := w.underlying.WithContext(ctx) newTx = newTx.Begin() - rw := &Db{newTx} + rw := &Db{underlying: &DB{newTx}} if err := Handler(rw, rw); err != nil { if err := newTx.Rollback().Error; err != nil { return info, errors.Wrap(ctx, err, op, errors.WithoutEvent()) diff --git a/internal/db/read_writer_test.go b/internal/db/read_writer_test.go index 9efedb326..14404793c 100644 --- a/internal/db/read_writer_test.go +++ b/internal/db/read_writer_test.go @@ -22,7 +22,6 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" - "gorm.io/gorm" ) func TestDb_UpdateUnsetField(t *testing.T) { @@ -1270,7 +1269,7 @@ func TestDb_Delete(t *testing.T) { } tests := []struct { name string - underlying *gorm.DB + underlying *DB wrapper wrapping.Wrapper args args want int @@ -1540,7 +1539,7 @@ func TestDb_CreateItems(t *testing.T) { } tests := []struct { name string - underlying *gorm.DB + underlying *DB args args wantOplogId string wantOplogMsgs bool @@ -1741,7 +1740,7 @@ func TestDb_DeleteItems(t *testing.T) { } tests := []struct { name string - underlying *gorm.DB + underlying *DB args args wantRowsDeleted int wantOplogId string @@ -1914,7 +1913,7 @@ func TestDb_DeleteItems(t *testing.T) { } } -func testUser(t *testing.T, conn *gorm.DB, name, email, phoneNumber string) *db_test.TestUser { +func testUser(t *testing.T, conn *DB, name, email, phoneNumber string) *db_test.TestUser { t.Helper() require := require.New(t) @@ -1935,7 +1934,7 @@ func testUser(t *testing.T, conn *gorm.DB, name, email, phoneNumber string) *db_ return u } -func testCar(t *testing.T, conn *gorm.DB, name, model string, mpg int32) *db_test.TestCar { +func testCar(t *testing.T, conn *DB, name, model string, mpg int32) *db_test.TestCar { t.Helper() require := require.New(t) @@ -1964,7 +1963,7 @@ func testId(t *testing.T) string { return id } -func testScooter(t *testing.T, conn *gorm.DB, model string, mpg int32) *db_test.TestScooter { +func testScooter(t *testing.T, conn *DB, model string, mpg int32) *db_test.TestScooter { t.Helper() require := require.New(t) @@ -1995,7 +1994,7 @@ func TestDb_LookupById(t *testing.T) { } tests := []struct { name string - underlying *gorm.DB + underlying *DB args args wantErr bool want proto.Message @@ -2095,7 +2094,7 @@ func TestDb_GetTicket(t *testing.T) { type notReplayable struct{} tests := []struct { name string - underlying *gorm.DB + underlying *DB aggregateType interface{} wantErr bool wantErrIs errors.Code @@ -2181,7 +2180,7 @@ func TestDb_WriteOplogEntryWith(t *testing.T) { } tests := []struct { name string - underlying *gorm.DB + underlying *DB args args wantErr bool wantErrIs errors.Code @@ -2889,7 +2888,7 @@ func TestDb_lookupAfterWrite(t *testing.T) { } tests := []struct { name string - underlying *gorm.DB + underlying *DB args args wantErr bool want proto.Message diff --git a/internal/db/schema/manager_test.go b/internal/db/schema/manager_test.go index 84b522d56..ea58b0fb1 100644 --- a/internal/db/schema/manager_test.go +++ b/internal/db/schema/manager_test.go @@ -7,6 +7,7 @@ import ( "strings" "testing" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/internal/db/schema/postgres" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/testing/dbtest" @@ -22,7 +23,7 @@ func TestNewManager(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - d, err := sql.Open(dialect, u) + d, err := common.SqlOpen(dialect, u) require.NoError(t, err) ctx := context.Background() @@ -47,7 +48,7 @@ func TestCurrentState(t *testing.T) { }) require.NoError(t, err) ctx := context.Background() - d, err := sql.Open(dialect, u) + d, err := common.SqlOpen(dialect, u) require.NoError(t, err) m, err := NewManager(ctx, dialect, d) @@ -83,7 +84,7 @@ func TestRollForward(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - d, err := sql.Open(dialect, u) + d, err := common.SqlOpen(dialect, u) require.NoError(t, err) ctx := context.Background() @@ -112,7 +113,7 @@ func TestRollForward_NotFromFresh(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - d, err := sql.Open(dialect, u) + d, err := common.SqlOpen(dialect, u) require.NoError(t, err) // Initialize the DB with only a portion of the current sql scripts. @@ -146,7 +147,7 @@ func TestRunMigration_canceledContext(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - d, err := sql.Open(dialect, u) + d, err := common.SqlOpen(dialect, u) require.NoError(t, err) ctx := context.Background() @@ -174,7 +175,7 @@ func TestRollForward_BadSQL(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - d, err := sql.Open(dialect, u) + d, err := common.SqlOpen(dialect, u) require.NoError(t, err) // Initialize the DB with only a portion of the current sql scripts. @@ -198,12 +199,12 @@ func TestManager_ExclusiveLock(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - d1, err := sql.Open(dialect, u) + d1, err := common.SqlOpen(dialect, u) require.NoError(t, err) m1, err := NewManager(ctx, dialect, d1) require.NoError(t, err) - d2, err := sql.Open(dialect, u) + d2, err := common.SqlOpen(dialect, u) require.NoError(t, err) m2, err := NewManager(ctx, dialect, d2) require.NoError(t, err) @@ -223,12 +224,12 @@ func TestManager_SharedLock(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - d1, err := sql.Open("postgres", u) + d1, err := common.SqlOpen("postgres", u) require.NoError(t, err) m1, err := NewManager(ctx, "postgres", d1) require.NoError(t, err) - d2, err := sql.Open("postgres", u) + d2, err := common.SqlOpen("postgres", u) require.NoError(t, err) m2, err := NewManager(ctx, "postgres", d2) require.NoError(t, err) @@ -252,7 +253,7 @@ func Test_GetMigrationLog(t *testing.T) { t.Cleanup(func() { require.NoError(t, c()) }) - d, err := sql.Open("postgres", u) + d, err := common.SqlOpen("postgres", u) require.NoError(t, err) m, err := NewManager(ctx, "postgres", d) require.NoError(t, err) diff --git a/internal/db/schema/migrations/postgres/11/01_server_type_enum_test.go b/internal/db/schema/migrations/postgres/11/01_server_type_enum_test.go index 6d8779519..4f3c675b2 100644 --- a/internal/db/schema/migrations/postgres/11/01_server_type_enum_test.go +++ b/internal/db/schema/migrations/postgres/11/01_server_type_enum_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/internal/db/schema" "github.com/hashicorp/boundary/testing/dbtest" "github.com/stretchr/testify/require" @@ -14,8 +15,8 @@ import ( const ( insertServerQuery = "insert into server (private_id, type, address) values ($1, $2, $3)" selectServerQuery = "select * from server where private_id = $1" - expectEnumConstraintErr = `pq: new row for relation "server_type_enm" violates check constraint "only_predefined_server_types_allowed"` - expectServerConstraintErr = `pq: insert or update on table "server" violates foreign key constraint "server_type_enm_fkey"` + expectEnumConstraintErr = `ERROR: new row for relation "server_type_enm" violates check constraint "only_predefined_server_types_allowed" (SQLSTATE 23514)` + expectServerConstraintErr = `ERROR: insert or update on table "server" violates foreign key constraint "server_type_enm_fkey" (SQLSTATE 23503)` ) type testServer struct { @@ -48,7 +49,7 @@ func Test_ServerEnumChanges(t *testing.T) { t.Cleanup(func() { require.NoError(c()) }) - d, err := sql.Open(dialect, u) + d, err := common.SqlOpen(dialect, u) require.NoError(err) // migration to the prior migration (before the one we want to test) diff --git a/internal/db/schema/migrations/postgres/12/01_timestamp_sub_funcs_test.go b/internal/db/schema/migrations/postgres/12/01_timestamp_sub_funcs_test.go index eb9fac8d7..7519b73ab 100644 --- a/internal/db/schema/migrations/postgres/12/01_timestamp_sub_funcs_test.go +++ b/internal/db/schema/migrations/postgres/12/01_timestamp_sub_funcs_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/internal/db/schema" "github.com/hashicorp/boundary/testing/dbtest" "github.com/stretchr/testify/require" @@ -41,7 +42,7 @@ func testSetupDb(ctx context.Context, t *testing.T) *sql.DB { t.Cleanup(func() { require.NoError(c()) }) - d, err := sql.Open(dialect, u) + d, err := common.SqlOpen(dialect, u) require.NoError(err) oState := schema.TestCloneMigrationStates(t) diff --git a/internal/db/schema/migrations/postgres/14/warehouse_user_dim_test.go b/internal/db/schema/migrations/postgres/14/warehouse_user_dim_test.go index 9b82f9eb8..749190bbe 100644 --- a/internal/db/schema/migrations/postgres/14/warehouse_user_dim_test.go +++ b/internal/db/schema/migrations/postgres/14/warehouse_user_dim_test.go @@ -2,12 +2,12 @@ package migration import ( "context" - "database/sql" "testing" "github.com/hashicorp/boundary/internal/auth/oidc" "github.com/hashicorp/boundary/internal/authtoken" "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/internal/db/schema" "github.com/hashicorp/boundary/internal/host/static" "github.com/hashicorp/boundary/internal/iam" @@ -18,7 +18,6 @@ import ( wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) func TestMigrations_UserDimension(t *testing.T) { @@ -37,7 +36,7 @@ func TestMigrations_UserDimension(t *testing.T) { t.Cleanup(func() { require.NoError(c()) }) - d, err := sql.Open(dialect, u) + d, err := common.SqlOpen(dialect, u) require.NoError(err) // migration to the prior migration (before the one we want to test) @@ -139,7 +138,7 @@ func TestMigrations_UserDimension(t *testing.T) { assert.False(state.Dirty) } -func testOidcAuthToken(t *testing.T, conn *gorm.DB, kms *kms.Kms, wrapper wrapping.Wrapper, scopeId string) *authtoken.AuthToken { +func testOidcAuthToken(t *testing.T, conn *db.DB, kms *kms.Kms, wrapper wrapping.Wrapper, scopeId string) *authtoken.AuthToken { t.Helper() authMethod := oidc.TestAuthMethod( diff --git a/internal/db/schema/migrations/postgres/16/warehouse_credential_dim_test.go b/internal/db/schema/migrations/postgres/16/warehouse_credential_dim_test.go index cb51f4856..2f82503f0 100644 --- a/internal/db/schema/migrations/postgres/16/warehouse_credential_dim_test.go +++ b/internal/db/schema/migrations/postgres/16/warehouse_credential_dim_test.go @@ -20,7 +20,6 @@ import ( wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) func TestMigrations_CredentialDimension(t *testing.T) { @@ -144,7 +143,7 @@ func TestMigrations_CredentialDimension(t *testing.T) { assert.False(state.Dirty) } -func testOidcAuthToken(t *testing.T, conn *gorm.DB, kms *kms.Kms, wrapper wrapping.Wrapper, scopeId string) *authtoken.AuthToken { +func testOidcAuthToken(t *testing.T, conn *db.DB, kms *kms.Kms, wrapper wrapping.Wrapper, scopeId string) *authtoken.AuthToken { t.Helper() authMethod := oidc.TestAuthMethod( @@ -171,7 +170,7 @@ func testOidcAuthToken(t *testing.T, conn *gorm.DB, kms *kms.Kms, wrapper wrappi return at } -func testSessionCredentialParams(t *testing.T, conn *gorm.DB, kms *kms.Kms, wrapper wrapping.Wrapper, tar *target.TcpTarget) []*session.DynamicCredential { +func testSessionCredentialParams(t *testing.T, conn *db.DB, kms *kms.Kms, wrapper wrapping.Wrapper, tar *target.TcpTarget) []*session.DynamicCredential { t.Helper() rw := db.New(conn) diff --git a/internal/db/schema/migrations/postgres/2/07_iam_test.go b/internal/db/schema/migrations/postgres/2/07_iam_test.go index c52be8e2a..04e76927b 100644 --- a/internal/db/schema/migrations/postgres/2/07_iam_test.go +++ b/internal/db/schema/migrations/postgres/2/07_iam_test.go @@ -2,11 +2,11 @@ package migration import ( "context" - "database/sql" "testing" "github.com/hashicorp/boundary/internal/auth/password" "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/internal/db/schema" "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/testing/dbtest" @@ -38,7 +38,7 @@ func Test_PrimaryAuthMethodChanges(t *testing.T) { t.Cleanup(func() { require.NoError(c()) }) - d, err := sql.Open(dialect, u) + d, err := common.SqlOpen(dialect, u) require.NoError(err) // migration to the prior migration (before the one we want to test) diff --git a/internal/db/schema/migrations/postgres/8/08_connection_test.go b/internal/db/schema/migrations/postgres/8/08_connection_test.go index 0556c8de5..9de3eb8d3 100644 --- a/internal/db/schema/migrations/postgres/8/08_connection_test.go +++ b/internal/db/schema/migrations/postgres/8/08_connection_test.go @@ -1,6 +1,7 @@ package migration import ( + "context" "database/sql" "testing" @@ -37,9 +38,9 @@ func TestMigration(t *testing.T) { ` selectQuery = `select session_id, server_id from session_connection_testing order by session_id` ) - + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres", db.WithTemplate("template1")) - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(err) _, err = db.Exec(createTables) require.NoError(err) diff --git a/internal/db/schema/postgres/postgres.go b/internal/db/schema/postgres/postgres.go index 1c30af45e..8a038abca 100644 --- a/internal/db/schema/postgres/postgres.go +++ b/internal/db/schema/postgres/postgres.go @@ -34,12 +34,11 @@ import ( "fmt" "io" "io/ioutil" - "strconv" "strings" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/go-multierror" - "github.com/lib/pq" + "github.com/jackc/pgconn" ) // schemaAccessLockId is a Lock key used to ensure a single boundary binary is operating @@ -232,14 +231,12 @@ func (p *Postgres) Run(ctx context.Context, migration io.Reader, version int) er if rollbackErr := rollback(); rollbackErr != nil { err = multierror.Append(err, rollbackErr) } - if pgErr, ok := err.(*pq.Error); ok { + if pgErr, ok := err.(*pgconn.PgError); ok { var line uint var col uint var lineColOK bool - if pgErr.Position != "" { - if pos, err := strconv.ParseUint(pgErr.Position, 10, 64); err == nil { - line, col, lineColOK = computeLineFromPos(query, int(pos)) - } + if pgErr.Position != 0 { + line, col, lineColOK = computeLineFromPos(query, int(pgErr.Position)) } message := "migration failed" if lineColOK { @@ -308,8 +305,7 @@ func (p *Postgres) setVersion(ctx context.Context, version int, dirty bool) erro defer func() { p.tx = nil }() return tx.Rollback() } - - query := `truncate ` + pq.QuoteIdentifier(defaultMigrationsTable) + query := `truncate ` + quoteIdentifier(defaultMigrationsTable) if _, err := tx.ExecContext(ctx, query); err != nil { if errRollback := rollback(); errRollback != nil { err = multierror.Append(err, errRollback) @@ -321,7 +317,7 @@ func (p *Postgres) setVersion(ctx context.Context, version int, dirty bool) erro // empty schema Version for failed down migration on the first migration // See: https://github.com/golang-migrate/migrate/issues/330 if version >= 0 || (version == nilVersion && dirty) { - query = `insert into ` + pq.QuoteIdentifier(defaultMigrationsTable) + + query = `insert into ` + quoteIdentifier(defaultMigrationsTable) + ` (version, dirty) values ($1, $2)` if _, err := tx.ExecContext(ctx, query, version, dirty); err != nil { if errRollback := rollback(); errRollback != nil { @@ -368,7 +364,7 @@ func (p *Postgres) CurrentState(ctx context.Context) (version int, previouslyRan return nilVersion, previouslyRan, dirty, errors.New(ctx, errors.MigrationIntegrity, op, "both old and new migration tables exist") } - query := `select version, dirty from ` + pq.QuoteIdentifier(tableName) + query := `select version, dirty from ` + quoteIdentifier(tableName) results, err := p.conn.QueryContext(ctx, query) if err != nil { return nilVersion, previouslyRan, dirty, errors.Wrap(ctx, err, op) @@ -420,7 +416,7 @@ func (p *Postgres) drop(ctx context.Context) (err error) { if len(tableNames) > 0 { // delete one by one ... for _, t := range tableNames { - query = `drop table if exists ` + pq.QuoteIdentifier(t) + ` cascade` + query = `drop table if exists ` + quoteIdentifier(t) + ` cascade` if _, err := p.conn.ExecContext(ctx, query); err != nil { return errors.Wrap(ctx, err, op) } @@ -464,7 +460,7 @@ func (p *Postgres) EnsureVersionTable(ctx context.Context) (err error) { return errors.Wrap(ctx, err, op) } - createStmt := `create table if not exists ` + pq.QuoteIdentifier(defaultMigrationsTable) + ` (version bigint primary key, dirty boolean not null)` + createStmt := `create table if not exists ` + quoteIdentifier(defaultMigrationsTable) + ` (version bigint primary key, dirty boolean not null)` if _, err = extr.ExecContext(ctx, createStmt); err != nil { if wpErr := rollback(); wpErr != nil { err = multierror.Append(err, wpErr) @@ -474,3 +470,8 @@ func (p *Postgres) EnsureVersionTable(ctx context.Context) (err error) { return nil } + +func quoteIdentifier(input string) (output string) { + output = `"` + strings.Replace(input, `"`, `""`, -1) + `"` + return +} diff --git a/internal/db/schema/postgres/postgres_test.go b/internal/db/schema/postgres/postgres_test.go index 2b16c7317..185e9f3f9 100644 --- a/internal/db/schema/postgres/postgres_test.go +++ b/internal/db/schema/postgres/postgres_test.go @@ -28,7 +28,7 @@ package postgres -// error codes https://github.com/lib/pq/blob/master/error.go +// errors: https://pkg.go.dev/github.com/jackc/pgconn#PgError import ( "bytes" diff --git a/internal/db/schema/postgres/testing.go b/internal/db/schema/postgres/testing.go index 42d978d24..854495a36 100644 --- a/internal/db/schema/postgres/testing.go +++ b/internal/db/schema/postgres/testing.go @@ -31,11 +31,11 @@ package postgres import ( "bytes" "context" - "database/sql" "testing" "time" "github.com/golang-migrate/migrate/v4/database" + "github.com/hashicorp/boundary/internal/db/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -123,7 +123,7 @@ func testSetVersion(t *testing.T, d *Postgres) { func open(t *testing.T, ctx context.Context, u string) (*Postgres, error) { t.Helper() - db, err := sql.Open("postgres", u) + db, err := common.SqlOpen("postgres", u) require.NoError(t, err) px, err := New(ctx, db) diff --git a/internal/db/schema/schema.go b/internal/db/schema/schema.go index f300c7308..c33bd505d 100644 --- a/internal/db/schema/schema.go +++ b/internal/db/schema/schema.go @@ -2,8 +2,8 @@ package schema import ( "context" - "database/sql" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/internal/errors" ) @@ -13,7 +13,7 @@ import ( func MigrateStore(ctx context.Context, dialect string, url string, opt ...Option) (bool, error) { const op = "schema.MigrateStore" - d, err := sql.Open(dialect, url) + d, err := common.SqlOpen(dialect, url) if err != nil { return false, errors.Wrap(ctx, err, op) } diff --git a/internal/db/schema/schema_test.go b/internal/db/schema/schema_test.go index 634e881ef..ad2d354c9 100644 --- a/internal/db/schema/schema_test.go +++ b/internal/db/schema/schema_test.go @@ -2,9 +2,9 @@ package schema import ( "context" - "database/sql" "testing" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/testing/dbtest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -53,7 +53,7 @@ func Test_MigrateStore_WithMigrationStates(t *testing.T) { t.Cleanup(func() { require.NoError(c()) }) - d, err := sql.Open(dialect, u) + d, err := common.SqlOpen(dialect, u) require.NoError(err) // migration to the prior migration (before the one we want to test) diff --git a/internal/db/testing.go b/internal/db/testing.go index f95b3694c..c8b76a293 100644 --- a/internal/db/testing.go +++ b/internal/db/testing.go @@ -17,12 +17,11 @@ import ( wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/go-kms-wrapping/wrappers/aead" "github.com/stretchr/testify/assert" - "gorm.io/gorm" "gorm.io/gorm/logger" ) // setup the tests (initialize the database one-time and intialized testDatabaseURL). Do not close the returned db. -func TestSetup(t *testing.T, dialect string, opt ...TestOption) (*gorm.DB, string) { +func TestSetup(t *testing.T, dialect string, opt ...TestOption) (*DB, string) { var cleanup func() error var url string var err error @@ -57,7 +56,7 @@ func TestSetup(t *testing.T, dialect string, opt ...TestOption) (*gorm.DB, strin } db.Logger.LogMode(logger.Error) t.Cleanup(func() { - sqlDB, err := db.DB() + sqlDB, err := db.SqlDB(ctx) assert.NoError(t, err) assert.NoError(t, sqlDB.Close(), "Got error closing gorm db.") }) diff --git a/internal/errors/is_test.go b/internal/errors/is_test.go index f142b7210..beb98c6c8 100644 --- a/internal/errors/is_test.go +++ b/internal/errors/is_test.go @@ -44,7 +44,7 @@ func TestError_IsUnique(t *testing.T) { want: true, }, { - name: "wrapped-pq-is-unique", + name: "wrapped-pg-is-unique", in: errors.E( context.TODO(), errors.WithWrap(&pgconn.PgError{ @@ -107,7 +107,7 @@ func TestError_IsCheckConstraint(t *testing.T) { want: true, }, { - name: "wrapped-pq-is-check-constraint", + name: "wrapped-pg-is-check-constraint", in: errors.E(context.TODO(), errors.WithCode(errors.CheckConstraint), errors.WithWrap(&pgconn.PgError{ Code: "23514", @@ -176,7 +176,7 @@ func TestError_IsNotNullError(t *testing.T) { want: true, }, { - name: "wrapped-pq-is-not-null", + name: "wrapped-pg-is-not-null", in: errors.E(context.TODO(), errors.WithCode(errors.NotNull), errors.WithWrap(&pgconn.PgError{ Code: "23502", diff --git a/internal/host/static/host_catalog_test.go b/internal/host/static/host_catalog_test.go index 292020d2d..0dba8443e 100644 --- a/internal/host/static/host_catalog_test.go +++ b/internal/host/static/host_catalog_test.go @@ -6,7 +6,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gorm.io/gorm" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/host/static/store" @@ -109,7 +108,7 @@ func TestHostCatalog_New(t *testing.T) { } } -func testCatalog(t *testing.T, conn *gorm.DB, scopeId string) *HostCatalog { +func testCatalog(t *testing.T, conn *db.DB, scopeId string) *HostCatalog { t.Helper() cats := TestCatalogs(t, conn, scopeId, 1) return cats[0] diff --git a/internal/host/static/repository_host_catalog_test.go b/internal/host/static/repository_host_catalog_test.go index 4af721d32..3a733193f 100644 --- a/internal/host/static/repository_host_catalog_test.go +++ b/internal/host/static/repository_host_catalog_test.go @@ -179,6 +179,7 @@ func TestRepository_UpdateCatalog(t *testing.T) { conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) wrapper := db.TestWrapper(t) + ctx := context.Background() changeName := func(s string) func(*HostCatalog) *HostCatalog { return func(c *HostCatalog) *HostCatalog { @@ -461,7 +462,7 @@ func TestRepository_UpdateCatalog(t *testing.T) { assert.Equal(tt.wantCount, gotCount, "row count") assert.NotSame(tt.orig, got) assert.Equal(tt.orig.ScopeId, got.ScopeId) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(t, err) dbassert := dbassert.New(t, underlyingDB) if tt.want.Name == "" { diff --git a/internal/host/static/repository_host_set_test.go b/internal/host/static/repository_host_set_test.go index 3e118cbf9..05f3eb43a 100644 --- a/internal/host/static/repository_host_set_test.go +++ b/internal/host/static/repository_host_set_test.go @@ -202,6 +202,7 @@ func TestRepository_CreateSet(t *testing.T) { } func TestRepository_UpdateSet(t *testing.T) { + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) wrapper := db.TestWrapper(t) @@ -493,7 +494,7 @@ func TestRepository_UpdateSet(t *testing.T) { assert.Equal(tt.wantCount, gotCount, "row count") assert.NotSame(tt.orig, got) assert.Equal(tt.orig.CatalogId, got.CatalogId) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if tt.want.Name == "" { diff --git a/internal/host/static/repository_host_test.go b/internal/host/static/repository_host_test.go index 0f699375c..aebf419b7 100644 --- a/internal/host/static/repository_host_test.go +++ b/internal/host/static/repository_host_test.go @@ -251,6 +251,7 @@ func TestRepository_CreateHost(t *testing.T) { } func TestRepository_UpdateHost(t *testing.T) { + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) wrapper := db.TestWrapper(t) @@ -620,7 +621,7 @@ func TestRepository_UpdateHost(t *testing.T) { assert.Equal(tt.wantCount, gotCount, "row count") assert.NotSame(tt.orig, got) assert.Equal(tt.orig.CatalogId, got.CatalogId) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if tt.want.Name == "" { diff --git a/internal/host/static/testing.go b/internal/host/static/testing.go index 3d3a94d3a..8dbca5444 100644 --- a/internal/host/static/testing.go +++ b/internal/host/static/testing.go @@ -7,13 +7,12 @@ import ( "github.com/hashicorp/boundary/internal/db" "github.com/stretchr/testify/assert" - "gorm.io/gorm" ) // TestCatalogs creates count number of static host catalogs to the provided DB // with the provided scope id. If any errors are encountered during the creation of // the host catalog, the test will fail. -func TestCatalogs(t *testing.T, conn *gorm.DB, scopeId string, count int) []*HostCatalog { +func TestCatalogs(t *testing.T, conn *db.DB, scopeId string, count int) []*HostCatalog { t.Helper() assert := assert.New(t) var cats []*HostCatalog @@ -37,7 +36,7 @@ func TestCatalogs(t *testing.T, conn *gorm.DB, scopeId string, count int) []*Hos // TestHosts creates count number of static hosts to the provided DB // with the provided catalog id. The catalog must have been created previously. // If any errors are encountered during the creation of the host, the test will fail. -func TestHosts(t *testing.T, conn *gorm.DB, catalogId string, count int) []*Host { +func TestHosts(t *testing.T, conn *db.DB, catalogId string, count int) []*Host { t.Helper() assert := assert.New(t) var hosts []*Host @@ -63,7 +62,7 @@ func TestHosts(t *testing.T, conn *gorm.DB, catalogId string, count int) []*Host // TestSets creates count number of static host sets in the provided DB // with the provided catalog id. The catalog must have been created // previously. The test will fail if any errors are encountered. -func TestSets(t *testing.T, conn *gorm.DB, catalogId string, count int) []*HostSet { +func TestSets(t *testing.T, conn *db.DB, catalogId string, count int) []*HostSet { t.Helper() assert := assert.New(t) var sets []*HostSet @@ -88,7 +87,7 @@ func TestSets(t *testing.T, conn *gorm.DB, catalogId string, count int) []*HostS // TestSetMembers adds hosts to the specified setId in the provided DB. // The set and hosts must have been created previously and belong to the // same catalog. The test will fail if any errors are encountered. -func TestSetMembers(t *testing.T, conn *gorm.DB, setId string, hosts []*Host) []*HostSetMember { +func TestSetMembers(t *testing.T, conn *db.DB, setId string, hosts []*Host) []*HostSetMember { t.Helper() assert := assert.New(t) diff --git a/internal/iam/account_test.go b/internal/iam/account_test.go index c6ac60eac..76cee0902 100644 --- a/internal/iam/account_test.go +++ b/internal/iam/account_test.go @@ -65,6 +65,7 @@ func TestAccount_GetScope(t *testing.T) { func TestAccount_Clone(t *testing.T) { t.Parallel() + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") wrapper := db.TestWrapper(t) repo := TestRepo(t, conn, wrapper) @@ -83,7 +84,7 @@ func TestAccount_Clone(t *testing.T) { authMethodPublicId := testAuthMethod(t, conn, org.PublicId) acct := testAccount(t, conn, org.PublicId, authMethodPublicId, u.PublicId) acct2 := testAccount(t, conn, org.PublicId, authMethodPublicId, "") - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(t, err) dbassert := dbassert.New(t, underlyingDB) dbassert.IsNull(acct2, "IamUserId") diff --git a/internal/iam/group_test.go b/internal/iam/group_test.go index be6720d95..d08e9b4c7 100644 --- a/internal/iam/group_test.go +++ b/internal/iam/group_test.go @@ -206,6 +206,7 @@ func Test_GroupCreate(t *testing.T) { func Test_GroupUpdate(t *testing.T) { t.Parallel() + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") wrapper := db.TestWrapper(t) repo := TestRepo(t, conn, wrapper) @@ -351,7 +352,7 @@ func Test_GroupUpdate(t *testing.T) { require.NoError(err) assert.True(proto.Equal(updateGrp, foundGrp)) if len(tt.args.nullPaths) != 0 { - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) for _, f := range tt.args.nullPaths { diff --git a/internal/iam/immutable_fields_test.go b/internal/iam/immutable_fields_test.go index cecfb4e38..7bffd66a6 100644 --- a/internal/iam/immutable_fields_test.go +++ b/internal/iam/immutable_fields_test.go @@ -92,10 +92,11 @@ func TestConcreteScope_ImmutableFields(t *testing.T) { update = `update {{rep}} set scope_id = $1 where scope_id = $2;` ) t.Parallel() + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") wrapper := db.TestWrapper(t) repo := TestRepo(t, conn, wrapper) - db, err := conn.DB() + db, err := conn.SqlDB(ctx) require.NoError(t, err) org, proj := TestScopes(t, repo) diff --git a/internal/iam/repository_group_test.go b/internal/iam/repository_group_test.go index 4c5d1bb44..5ea3b4b53 100644 --- a/internal/iam/repository_group_test.go +++ b/internal/iam/repository_group_test.go @@ -173,6 +173,7 @@ func TestRepository_CreateGroup(t *testing.T) { func TestRepository_UpdateGroup(t *testing.T) { t.Parallel() + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") a := assert.New(t) rw := db.New(conn) @@ -450,7 +451,7 @@ func TestRepository_UpdateGroup(t *testing.T) { foundGrp, _, err := repo.LookupGroup(context.Background(), u.PublicId) require.NoError(err) assert.True(proto.Equal(groupAfterUpdate, foundGrp)) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if tt.args.name == "" { diff --git a/internal/iam/repository_role_test.go b/internal/iam/repository_role_test.go index da1ebec39..f1551334c 100644 --- a/internal/iam/repository_role_test.go +++ b/internal/iam/repository_role_test.go @@ -174,6 +174,7 @@ func TestRepository_CreateRole(t *testing.T) { func TestRepository_UpdateRole(t *testing.T) { t.Parallel() + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) wrapper := db.TestWrapper(t) @@ -447,7 +448,7 @@ func TestRepository_UpdateRole(t *testing.T) { foundRole, _, _, err := repo.LookupRole(context.Background(), r.PublicId) assert.NoError(err) assert.True(proto.Equal(roleAfterUpdate, foundRole)) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if tt.args.name == "" { diff --git a/internal/iam/repository_user_iam_pkg_test.go b/internal/iam/repository_user_iam_pkg_test.go index f537db9af..690441d2d 100644 --- a/internal/iam/repository_user_iam_pkg_test.go +++ b/internal/iam/repository_user_iam_pkg_test.go @@ -184,6 +184,7 @@ func TestRepository_associateUserWithAccounts(t *testing.T) { func TestRepository_dissociateUserWithAccount(t *testing.T) { t.Parallel() + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) wrapper := db.TestWrapper(t) @@ -309,7 +310,7 @@ func TestRepository_dissociateUserWithAccount(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { assert, require := assert.New(t), require.New(t) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) err = dissociateUserFromAccounts(context.Background(), kms, rw, rw, tt.args.Ids.user, tt.args.Ids.accts, tt.args.opt...) diff --git a/internal/iam/repository_user_test.go b/internal/iam/repository_user_test.go index da777bfc5..88d8c5240 100644 --- a/internal/iam/repository_user_test.go +++ b/internal/iam/repository_user_test.go @@ -198,6 +198,7 @@ func TestRepository_LookupUser_WithDifferentPrimaryAuthMethods(t *testing.T) { func TestRepository_UpdateUser(t *testing.T) { t.Parallel() + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) wrapper := db.TestWrapper(t) @@ -475,7 +476,7 @@ func TestRepository_UpdateUser(t *testing.T) { assert.True(proto.Equal(userAfterUpdate, foundUser)) sort.Strings(foundAccountIds) assert.Equal(accountIds, foundAccountIds) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if tt.args.name == "" { @@ -710,6 +711,7 @@ func TestRepository_ListUsers_Multiple_Scopes(t *testing.T) { func TestRepository_LookupUserWithLogin(t *testing.T) { t.Parallel() + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) wrapper := db.TestWrapper(t) @@ -847,7 +849,7 @@ func TestRepository_LookupUserWithLogin(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { assert, require := assert.New(t), require.New(t) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) got, err := repo.LookupUserWithLogin(context.Background(), tt.args.withAccountId, tt.args.opt...) diff --git a/internal/iam/role_test.go b/internal/iam/role_test.go index 9af79e7c6..749f9da18 100644 --- a/internal/iam/role_test.go +++ b/internal/iam/role_test.go @@ -206,6 +206,7 @@ func Test_RoleCreate(t *testing.T) { func Test_RoleUpdate(t *testing.T) { t.Parallel() + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") wrapper := db.TestWrapper(t) repo := TestRepo(t, conn, wrapper) @@ -440,7 +441,7 @@ func Test_RoleUpdate(t *testing.T) { } assert.True(proto.Equal(updateRole, foundRole)) if len(tt.args.nullPaths) != 0 { - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) for _, f := range tt.args.nullPaths { diff --git a/internal/iam/testing.go b/internal/iam/testing.go index a0f7197be..3e693a9a5 100644 --- a/internal/iam/testing.go +++ b/internal/iam/testing.go @@ -13,12 +13,11 @@ import ( wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/go-uuid" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) // TestRepo creates a repo that can be used for various purposes. Crucially, it // ensures that the global scope contains a valid root key. -func TestRepo(t *testing.T, conn *gorm.DB, rootWrapper wrapping.Wrapper, opt ...Option) *Repository { +func TestRepo(t *testing.T, conn *db.DB, rootWrapper wrapping.Wrapper, opt ...Option) *Repository { require := require.New(t) rw := db.New(conn) kmsCache := kms.TestKms(t, conn, rootWrapper) @@ -156,7 +155,7 @@ func TestUser(t *testing.T, repo *Repository, scopeId string, opt ...Option) *Us } // TestRole creates a role suitable for testing. -func TestRole(t *testing.T, conn *gorm.DB, scopeId string, opt ...Option) *Role { +func TestRole(t *testing.T, conn *db.DB, scopeId string, opt ...Option) *Role { t.Helper() require := require.New(t) rw := db.New(conn) @@ -176,7 +175,7 @@ func TestRole(t *testing.T, conn *gorm.DB, scopeId string, opt ...Option) *Role return role } -func TestRoleGrant(t *testing.T, conn *gorm.DB, roleId, grant string, opt ...Option) *RoleGrant { +func TestRoleGrant(t *testing.T, conn *db.DB, roleId, grant string, opt ...Option) *RoleGrant { t.Helper() require := require.New(t) rw := db.New(conn) @@ -189,7 +188,7 @@ func TestRoleGrant(t *testing.T, conn *gorm.DB, roleId, grant string, opt ...Opt } // TestGroup creates a group suitable for testing. -func TestGroup(t *testing.T, conn *gorm.DB, scopeId string, opt ...Option) *Group { +func TestGroup(t *testing.T, conn *db.DB, scopeId string, opt ...Option) *Group { t.Helper() require := require.New(t) rw := db.New(conn) @@ -205,7 +204,7 @@ func TestGroup(t *testing.T, conn *gorm.DB, scopeId string, opt ...Option) *Grou return grp } -func TestGroupMember(t *testing.T, conn *gorm.DB, groupId, userId string, opt ...Option) *GroupMemberUser { +func TestGroupMember(t *testing.T, conn *db.DB, groupId, userId string, opt ...Option) *GroupMemberUser { t.Helper() require := require.New(t) rw := db.New(conn) @@ -218,7 +217,7 @@ func TestGroupMember(t *testing.T, conn *gorm.DB, groupId, userId string, opt .. return gm } -func TestUserRole(t *testing.T, conn *gorm.DB, roleId, userId string, opt ...Option) *UserRole { +func TestUserRole(t *testing.T, conn *db.DB, roleId, userId string, opt ...Option) *UserRole { t.Helper() require := require.New(t) rw := db.New(conn) @@ -230,7 +229,7 @@ func TestUserRole(t *testing.T, conn *gorm.DB, roleId, userId string, opt ...Opt return r } -func TestGroupRole(t *testing.T, conn *gorm.DB, roleId, grpId string, opt ...Option) *GroupRole { +func TestGroupRole(t *testing.T, conn *db.DB, roleId, grpId string, opt ...Option) *GroupRole { t.Helper() require := require.New(t) rw := db.New(conn) @@ -242,7 +241,7 @@ func TestGroupRole(t *testing.T, conn *gorm.DB, roleId, grpId string, opt ...Opt return r } -func TestManagedGroupRole(t *testing.T, conn *gorm.DB, roleId, managedGrpId string, opt ...Option) *ManagedGroupRole { +func TestManagedGroupRole(t *testing.T, conn *db.DB, roleId, managedGrpId string, opt ...Option) *ManagedGroupRole { t.Helper() require := require.New(t) rw := db.New(conn) @@ -257,11 +256,13 @@ func TestManagedGroupRole(t *testing.T, conn *gorm.DB, roleId, managedGrpId stri // testAccount is a temporary test function. TODO - replace with an auth // subsystem testAccount function. If userId is zero value, then an auth // account will be created with a null IamUserId -func testAccount(t *testing.T, conn *gorm.DB, scopeId, authMethodId, userId string) *authAccount { +func testAccount(t *testing.T, conn *db.DB, scopeId, authMethodId, userId string) *authAccount { const ( accountPrefix = "aa_" ) t.Helper() + ctx := context.Background() + rw := db.New(conn) require := require.New(t) require.NotNil(conn) @@ -277,7 +278,7 @@ func testAccount(t *testing.T, conn *gorm.DB, scopeId, authMethodId, userId stri } var count int - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) err = underlyingDB.QueryRow(whereValidAuthMethod, authMethodId, scopeId).Scan(&count) require.NoError(err) @@ -299,7 +300,7 @@ func testAccount(t *testing.T, conn *gorm.DB, scopeId, authMethodId, userId stri require.NotEmpty(acct.PublicId) if userId == "" { - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) dbassert.IsNull(acct, "IamUserId") @@ -309,7 +310,7 @@ func testAccount(t *testing.T, conn *gorm.DB, scopeId, authMethodId, userId stri // testAuthMethod is a temporary test function. TODO - replace with an auth // subsystem testAuthMethod function. -func testAuthMethod(t *testing.T, conn *gorm.DB, scopeId string) string { +func testAuthMethod(t *testing.T, conn *db.DB, scopeId string) string { const ( authMethodPrefix = "am_" ) diff --git a/internal/kms/testing.go b/internal/kms/testing.go index e05759772..37ec6da7e 100644 --- a/internal/kms/testing.go +++ b/internal/kms/testing.go @@ -8,10 +8,9 @@ import ( wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/go-kms-wrapping/wrappers/aead" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) -func TestRootKey(t *testing.T, conn *gorm.DB, scopeId string) *RootKey { +func TestRootKey(t *testing.T, conn *db.DB, scopeId string) *RootKey { t.Helper() require := require.New(t) rw := db.New(conn) @@ -26,7 +25,7 @@ func TestRootKey(t *testing.T, conn *gorm.DB, scopeId string) *RootKey { return k } -func TestRootKeyVersion(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, rootId string) (kv *RootKeyVersion, kvWrapper wrapping.Wrapper) { +func TestRootKeyVersion(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, rootId string) (kv *RootKeyVersion, kvWrapper wrapping.Wrapper) { t.Helper() require := require.New(t) rw := db.New(conn) @@ -48,7 +47,7 @@ func TestRootKeyVersion(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, r return k, rootKeyVersionWrapper } -func TestKms(t *testing.T, conn *gorm.DB, rootWrapper wrapping.Wrapper) *Kms { +func TestKms(t *testing.T, conn *db.DB, rootWrapper wrapping.Wrapper) *Kms { t.Helper() require := require.New(t) rw := db.New(conn) @@ -61,7 +60,7 @@ func TestKms(t *testing.T, conn *gorm.DB, rootWrapper wrapping.Wrapper) *Kms { return kms } -func TestDatabaseKey(t *testing.T, conn *gorm.DB, rootKeyId string) *DatabaseKey { +func TestDatabaseKey(t *testing.T, conn *db.DB, rootKeyId string) *DatabaseKey { t.Helper() require := require.New(t) rw := db.New(conn) @@ -77,7 +76,7 @@ func TestDatabaseKey(t *testing.T, conn *gorm.DB, rootKeyId string) *DatabaseKey return k } -func TestDatabaseKeyVersion(t *testing.T, conn *gorm.DB, rootKeyVersionWrapper wrapping.Wrapper, databaseKeyId string, key []byte) *DatabaseKeyVersion { +func TestDatabaseKeyVersion(t *testing.T, conn *db.DB, rootKeyVersionWrapper wrapping.Wrapper, databaseKeyId string, key []byte) *DatabaseKeyVersion { t.Helper() require := require.New(t) rw := db.New(conn) @@ -95,7 +94,7 @@ func TestDatabaseKeyVersion(t *testing.T, conn *gorm.DB, rootKeyVersionWrapper w return k } -func TestOplogKey(t *testing.T, conn *gorm.DB, rootKeyId string) *OplogKey { +func TestOplogKey(t *testing.T, conn *db.DB, rootKeyId string) *OplogKey { t.Helper() require := require.New(t) rw := db.New(conn) @@ -111,7 +110,7 @@ func TestOplogKey(t *testing.T, conn *gorm.DB, rootKeyId string) *OplogKey { return k } -func TestOplogKeyVersion(t *testing.T, conn *gorm.DB, rootKeyVersionWrapper wrapping.Wrapper, oplogKeyId string, key []byte) *OplogKeyVersion { +func TestOplogKeyVersion(t *testing.T, conn *db.DB, rootKeyVersionWrapper wrapping.Wrapper, oplogKeyId string, key []byte) *OplogKeyVersion { t.Helper() require := require.New(t) rw := db.New(conn) @@ -129,7 +128,7 @@ func TestOplogKeyVersion(t *testing.T, conn *gorm.DB, rootKeyVersionWrapper wrap return k } -func TestTokenKey(t *testing.T, conn *gorm.DB, rootKeyId string) *TokenKey { +func TestTokenKey(t *testing.T, conn *db.DB, rootKeyId string) *TokenKey { t.Helper() require := require.New(t) rw := db.New(conn) @@ -145,7 +144,7 @@ func TestTokenKey(t *testing.T, conn *gorm.DB, rootKeyId string) *TokenKey { return k } -func TestTokenKeyVersion(t *testing.T, conn *gorm.DB, rootKeyVersionWrapper wrapping.Wrapper, tokenKeyId string, key []byte) *TokenKeyVersion { +func TestTokenKeyVersion(t *testing.T, conn *db.DB, rootKeyVersionWrapper wrapping.Wrapper, tokenKeyId string, key []byte) *TokenKeyVersion { t.Helper() require := require.New(t) rw := db.New(conn) @@ -163,7 +162,7 @@ func TestTokenKeyVersion(t *testing.T, conn *gorm.DB, rootKeyVersionWrapper wrap return k } -func TestSessionKey(t *testing.T, conn *gorm.DB, rootKeyId string) *SessionKey { +func TestSessionKey(t *testing.T, conn *db.DB, rootKeyId string) *SessionKey { t.Helper() require := require.New(t) rw := db.New(conn) @@ -179,7 +178,7 @@ func TestSessionKey(t *testing.T, conn *gorm.DB, rootKeyId string) *SessionKey { return k } -func TestSessionKeyVersion(t *testing.T, conn *gorm.DB, rootKeyVersionWrapper wrapping.Wrapper, sessionKeyId string, key []byte) *SessionKeyVersion { +func TestSessionKeyVersion(t *testing.T, conn *db.DB, rootKeyVersionWrapper wrapping.Wrapper, sessionKeyId string, key []byte) *SessionKeyVersion { t.Helper() require := require.New(t) rw := db.New(conn) @@ -197,7 +196,7 @@ func TestSessionKeyVersion(t *testing.T, conn *gorm.DB, rootKeyVersionWrapper wr return k } -func TestOidcKey(t *testing.T, conn *gorm.DB, rootKeyId string) *OidcKey { +func TestOidcKey(t *testing.T, conn *db.DB, rootKeyId string) *OidcKey { t.Helper() require := require.New(t) rw := db.New(conn) @@ -213,7 +212,7 @@ func TestOidcKey(t *testing.T, conn *gorm.DB, rootKeyId string) *OidcKey { return k } -func TestOidcKeyVersion(t *testing.T, conn *gorm.DB, rootKeyVersionWrapper wrapping.Wrapper, oidcKeyId string, key []byte) *OidcKeyVersion { +func TestOidcKeyVersion(t *testing.T, conn *db.DB, rootKeyVersionWrapper wrapping.Wrapper, oidcKeyId string, key []byte) *OidcKeyVersion { t.Helper() require := require.New(t) rw := db.New(conn) diff --git a/internal/oplog/testing.go b/internal/oplog/testing.go index f8d7bdc17..dac8f502c 100644 --- a/internal/oplog/testing.go +++ b/internal/oplog/testing.go @@ -3,9 +3,9 @@ package oplog import ( "context" "crypto/rand" - "database/sql" "testing" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/internal/db/schema" "github.com/hashicorp/boundary/internal/oplog/oplog_test" "github.com/hashicorp/boundary/testing/dbtest" @@ -86,7 +86,7 @@ func testInitStore(t *testing.T, cleanup func() error, url string) { ctx := context.Background() dialect := "postgres" - d, err := sql.Open(dialect, url) + d, err := common.SqlOpen(dialect, url) require.NoError(t, err) sm, err := schema.NewManager(ctx, dialect, d) require.NoError(t, err) diff --git a/internal/oplog/testing_test.go b/internal/oplog/testing_test.go index b5d1030a5..93436e7c1 100644 --- a/internal/oplog/testing_test.go +++ b/internal/oplog/testing_test.go @@ -1,9 +1,9 @@ package oplog import ( - "database/sql" "testing" + "github.com/hashicorp/boundary/internal/db/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -77,7 +77,7 @@ func Test_testInitStore(t *testing.T) { const query = ` select count(*) from information_schema."tables" t where table_name = 'db_test_user'; ` - db, err := sql.Open("postgres", url) + db, err := common.SqlOpen("postgres", url) require.NoError(err) var cnt int diff --git a/internal/scheduler/job/testing.go b/internal/scheduler/job/testing.go index 69552c4b3..bd192c93e 100644 --- a/internal/scheduler/job/testing.go +++ b/internal/scheduler/job/testing.go @@ -12,10 +12,9 @@ import ( wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/go-uuid" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) -func testJob(t *testing.T, conn *gorm.DB, name, description string, wrapper wrapping.Wrapper, opt ...Option) *Job { +func testJob(t *testing.T, conn *db.DB, name, description string, wrapper wrapping.Wrapper, opt ...Option) *Job { t.Helper() require := require.New(t) rw := db.New(conn) @@ -31,7 +30,7 @@ func testJob(t *testing.T, conn *gorm.DB, name, description string, wrapper wrap return job } -func testRun(conn *gorm.DB, pluginId, name, cId string) (*Run, error) { +func testRun(conn *db.DB, pluginId, name, cId string) (*Run, error) { query := ` insert into job_run ( job_plugin_id, job_name, server_id @@ -59,7 +58,7 @@ func testRun(conn *gorm.DB, pluginId, name, cId string) (*Run, error) { return run, nil } -func testRunWithUpdateTime(conn *gorm.DB, pluginId, name, cId string, updateTime time.Time) (*Run, error) { +func testRunWithUpdateTime(conn *db.DB, pluginId, name, cId string, updateTime time.Time) (*Run, error) { query := ` insert into job_run ( job_plugin_id, job_name, server_id, update_time @@ -87,7 +86,7 @@ func testRunWithUpdateTime(conn *gorm.DB, pluginId, name, cId string, updateTime return run, nil } -func testController(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper) *servers.Server { +func testController(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper) *servers.Server { t.Helper() rw := db.New(conn) kms := kms.TestKms(t, conn, wrapper) diff --git a/internal/scheduler/testing.go b/internal/scheduler/testing.go index d28e556ba..71646d7d0 100644 --- a/internal/scheduler/testing.go +++ b/internal/scheduler/testing.go @@ -14,7 +14,6 @@ import ( wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/go-uuid" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) // TestScheduler creates a mock controller and a new Scheduler attached to that controller id. @@ -22,7 +21,7 @@ import ( // // WithRunJobsLimit, WithRunJobsInterval, WithMonitorInterval and WithInterruptThreshold are // the only valid options. -func TestScheduler(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, opt ...Option) *Scheduler { +func TestScheduler(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, opt ...Option) *Scheduler { t.Helper() rw := db.New(conn) diff --git a/internal/servers/controller/handlers/authmethods/oidc_test.go b/internal/servers/controller/handlers/authmethods/oidc_test.go index 2f6ed2ca4..d843c4603 100644 --- a/internal/servers/controller/handlers/authmethods/oidc_test.go +++ b/internal/servers/controller/handlers/authmethods/oidc_test.go @@ -41,12 +41,11 @@ import ( "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/wrapperspb" - "gorm.io/gorm" ) type setup struct { ctx context.Context - conn *gorm.DB + conn *db.DB rw *db.Db rootWrapper wrapping.Wrapper kmsCache *kms.Kms diff --git a/internal/servers/controller/handlers/targets/target_service_test.go b/internal/servers/controller/handlers/targets/target_service_test.go index 777a815db..29b185fa3 100644 --- a/internal/servers/controller/handlers/targets/target_service_test.go +++ b/internal/servers/controller/handlers/targets/target_service_test.go @@ -47,7 +47,6 @@ import ( "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/wrapperspb" - "gorm.io/gorm" ) var testAuthorizedActions = []string{ @@ -67,7 +66,7 @@ var testAuthorizedActions = []string{ "authorize-session", } -func testService(t *testing.T, conn *gorm.DB, kms *kms.Kms, wrapper wrapping.Wrapper) (targets.Service, error) { +func testService(t *testing.T, conn *db.DB, kms *kms.Kms, wrapper wrapping.Wrapper) (targets.Service, error) { rw := db.New(conn) sche := scheduler.TestScheduler(t, conn, wrapper) repoFn := func() (*target.Repository, error) { diff --git a/internal/servers/controller/testing.go b/internal/servers/controller/testing.go index f458efcac..85c62ace7 100644 --- a/internal/servers/controller/testing.go +++ b/internal/servers/controller/testing.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/boundary/internal/authtoken" "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/db/schema" "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/intglobals" @@ -26,7 +27,6 @@ import ( wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/go-secure-stdlib/base62" "github.com/hashicorp/go-secure-stdlib/strutil" - "gorm.io/gorm" ) const ( @@ -126,7 +126,7 @@ func (tc *TestController) ClusterAddrs() []string { return tc.addrs("cluster") } -func (tc *TestController) DbConn() *gorm.DB { +func (tc *TestController) DbConn() *db.DB { return tc.b.Database } @@ -272,8 +272,8 @@ func (tc *TestController) Shutdown() { tc.t.Error(err) } if !tc.opts.DisableDatabaseDestruction { - if tc.b.DestroyDevDatabase() != nil { - if err := tc.b.DestroyDevDatabase(); err != nil { + if tc.b.DestroyDevDatabase(tc.ctx) != nil { + if err := tc.b.DestroyDevDatabase(tc.ctx); err != nil { tc.t.Error(err) } } @@ -536,7 +536,7 @@ func NewTestController(t *testing.T, opts *TestControllerOpts) *TestController { if _, err := schema.MigrateStore(ctx, "postgres", tc.b.DatabaseUrl); err != nil { t.Fatal(err) } - if err := tc.b.ConnectToDatabase("postgres"); err != nil { + if err := tc.b.ConnectToDatabase(tc.ctx, "postgres"); err != nil { t.Fatal(err) } if !opts.DisableKmsKeyCreation { diff --git a/internal/session/repository_session_test.go b/internal/session/repository_session_test.go index 9ea29d3d4..890e5b260 100644 --- a/internal/session/repository_session_test.go +++ b/internal/session/repository_session_test.go @@ -19,7 +19,6 @@ import ( wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/jackc/pgconn" "google.golang.org/protobuf/types/known/timestamppb" - "gorm.io/gorm" "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/iam" @@ -1408,13 +1407,13 @@ func TestRepository_CancelSessionViaFKNull(t *testing.T) { rowsDeleted, err := rw.Delete(context.Background(), tt.cancelFk.fkType) if err != nil { - var pqError *pgconn.PgError - if errors.As(err, &pqError) { - t.Log(pqError.Message) - t.Log(pqError.Detail) - t.Log(pqError.Where) - t.Log(pqError.ConstraintName) - t.Log(pqError.TableName) + var pgError *pgconn.PgError + if errors.As(err, &pgError) { + t.Log(pgError.Message) + t.Log(pgError.Detail) + t.Log(pgError.Where) + t.Log(pgError.ConstraintName) + t.Log(pgError.TableName) } } require.NoError(err) @@ -1642,7 +1641,7 @@ func TestRepository_DeleteSession(t *testing.T) { } } -func testSessionCredentialParams(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, iamRepo *iam.Repository) ComposedOf { +func testSessionCredentialParams(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, iamRepo *iam.Repository) ComposedOf { t.Helper() params := TestSessionParams(t, conn, wrapper, iamRepo) require := require.New(t) diff --git a/internal/session/testing.go b/internal/session/testing.go index 445ff499e..652f5ac98 100644 --- a/internal/session/testing.go +++ b/internal/session/testing.go @@ -20,11 +20,10 @@ import ( "github.com/hashicorp/go-uuid" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/timestamppb" - "gorm.io/gorm" ) // TestConnection creates a test connection for the sessionId in the repository. -func TestConnection(t *testing.T, conn *gorm.DB, sessionId, clientTcpAddr string, clientTcpPort uint32, endpointTcpAddr string, endpointTcpPort uint32) *Connection { +func TestConnection(t *testing.T, conn *db.DB, sessionId, clientTcpAddr string, clientTcpPort uint32, endpointTcpAddr string, endpointTcpPort uint32) *Connection { t.Helper() require := require.New(t) rw := db.New(conn) @@ -44,7 +43,7 @@ func TestConnection(t *testing.T, conn *gorm.DB, sessionId, clientTcpAddr string } // TestConnectionState creates a test connection state for the connectionId in the repository. -func TestConnectionState(t *testing.T, conn *gorm.DB, connectionId string, state ConnectionStatus) *ConnectionState { +func TestConnectionState(t *testing.T, conn *db.DB, connectionId string, state ConnectionStatus) *ConnectionState { t.Helper() require := require.New(t) rw := db.New(conn) @@ -56,7 +55,7 @@ func TestConnectionState(t *testing.T, conn *gorm.DB, connectionId string, state } // TestState creates a test state for the sessionId in the repository. -func TestState(t *testing.T, conn *gorm.DB, sessionId string, state Status) *State { +func TestState(t *testing.T, conn *db.DB, sessionId string, state Status) *State { t.Helper() require := require.New(t) rw := db.New(conn) @@ -69,7 +68,7 @@ func TestState(t *testing.T, conn *gorm.DB, sessionId string, state Status) *Sta // TestSession creates a test session composed of c in the repository. Options // are passed into New, and withServerId is handled locally. -func TestSession(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, c ComposedOf, opt ...Option) *Session { +func TestSession(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, c ComposedOf, opt ...Option) *Session { t.Helper() ctx := context.Background() opts := getOpts(opt...) @@ -110,7 +109,7 @@ func TestSession(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, c Compos } // TestDefaultSession creates a test session in the repository using defaults. -func TestDefaultSession(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, iamRepo *iam.Repository, opt ...Option) *Session { +func TestDefaultSession(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, iamRepo *iam.Repository, opt ...Option) *Session { t.Helper() composedOf := TestSessionParams(t, conn, wrapper, iamRepo) future := timestamppb.New(time.Now().Add(time.Hour)) @@ -120,7 +119,7 @@ func TestDefaultSession(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, i // TestSessionParams returns an initialized ComposedOf which can be used to // create a session in the repository. -func TestSessionParams(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, iamRepo *iam.Repository) ComposedOf { +func TestSessionParams(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, iamRepo *iam.Repository) ComposedOf { t.Helper() ctx := context.Background() @@ -176,7 +175,7 @@ func TestTofu(t *testing.T) []byte { // TestWorker inserts a worker into the db to satisfy foreign key constraints. // Supports the WithServerId option. -func TestWorker(t *testing.T, conn *gorm.DB, wrapper wrapping.Wrapper, opt ...Option) *servers.Server { +func TestWorker(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, opt ...Option) *servers.Server { t.Helper() rw := db.New(conn) kms := kms.TestKms(t, conn, wrapper) diff --git a/internal/target/repository_tcp_target_test.go b/internal/target/repository_tcp_target_test.go index 02b3bfd65..89b34dfce 100644 --- a/internal/target/repository_tcp_target_test.go +++ b/internal/target/repository_tcp_target_test.go @@ -219,6 +219,7 @@ func TestRepository_CreateTcpTarget(t *testing.T) { func TestRepository_UpdateTcpTarget(t *testing.T) { t.Parallel() + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) wrapper := db.TestWrapper(t) @@ -491,7 +492,7 @@ func TestRepository_UpdateTcpTarget(t *testing.T) { foundTarget, _, _, err := repo.LookupTarget(context.Background(), target.PublicId) assert.NoError(err) assert.True(proto.Equal(targetAfterUpdate.((*TcpTarget)), foundTarget.((*TcpTarget)))) - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) if tt.args.description == "" { diff --git a/internal/target/tcp_target_test.go b/internal/target/tcp_target_test.go index e0890e55e..faa059033 100644 --- a/internal/target/tcp_target_test.go +++ b/internal/target/tcp_target_test.go @@ -146,6 +146,7 @@ func TestTcpTarget_Delete(t *testing.T) { func TestTcpTarget_Update(t *testing.T) { t.Parallel() id := testId(t) + ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) wrapper := db.TestWrapper(t) @@ -279,7 +280,7 @@ func TestTcpTarget_Update(t *testing.T) { require.NoError(err) assert.True(proto.Equal(updateTarget, foundTarget)) if len(tt.args.nullPaths) != 0 { - underlyingDB, err := conn.DB() + underlyingDB, err := conn.SqlDB(ctx) require.NoError(err) dbassert := dbassert.New(t, underlyingDB) for _, f := range tt.args.nullPaths { diff --git a/internal/target/testing.go b/internal/target/testing.go index 38b35d6e8..a1761a659 100644 --- a/internal/target/testing.go +++ b/internal/target/testing.go @@ -8,10 +8,9 @@ import ( "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/go-uuid" "github.com/stretchr/testify/require" - "gorm.io/gorm" ) -func TestTcpTarget(t *testing.T, conn *gorm.DB, scopeId, name string, opt ...Option) *TcpTarget { +func TestTcpTarget(t *testing.T, conn *db.DB, scopeId, name string, opt ...Option) *TcpTarget { t.Helper() opt = append(opt, WithName(name)) opts := getOpts(opt...) @@ -62,7 +61,7 @@ func testId(t *testing.T) string { // TestCredentialLibrary creates a CredentialLibrary for targetId and // libraryId. -func TestCredentialLibrary(t *testing.T, conn *gorm.DB, targetId, libraryId string) *CredentialLibrary { +func TestCredentialLibrary(t *testing.T, conn *db.DB, targetId, libraryId string) *CredentialLibrary { t.Helper() require := require.New(t) rw := db.New(conn) diff --git a/testing/dbtest/docs.go b/testing/dbtest/docs.go index ada0d0321..546d004b4 100644 --- a/testing/dbtest/docs.go +++ b/testing/dbtest/docs.go @@ -12,7 +12,7 @@ // require.NoError(t, c()) // }) // // use u to get a connection to the new database -// dBase, err := sql.Open("postgres", u) +// dBase, err := common.SqlOpen("postgres", u) // // By default this uses a template that already has all of the boundary // migrations run. If a test needs a database without any migrations, like in diff --git a/testing/dbtest/template.go b/testing/dbtest/template.go index d7ecd88da..5a3a9892e 100644 --- a/testing/dbtest/template.go +++ b/testing/dbtest/template.go @@ -1,14 +1,15 @@ package dbtest import ( - "database/sql" "fmt" "math/rand" "os" "time" // postgres dialect - _ "github.com/lib/pq" + + "github.com/hashicorp/boundary/internal/db/common" + _ "github.com/jackc/pgx/v4/stdlib" ) var testDBPort = "5432" @@ -75,7 +76,10 @@ func startUsingTemplate(dialect string, opt ...Option) (cleanup func() error, re return func() error { return nil }, "", "", fmt.Errorf("unsupported dialect: %s", dialect) } - db, err := sql.Open(dialect, fmt.Sprintf("postgres://boundary:boundary@127.0.0.1:%s/boundary?sslmode=disable", testDBPort)) + if dialect == "postgres" { + dialect = "pgx" + } + db, err := common.SqlOpen(dialect, fmt.Sprintf("postgres://boundary:boundary@127.0.0.1:%s/boundary?sslmode=disable", testDBPort)) if err != nil { return func() error { return nil }, "", "", fmt.Errorf("could not connect to source database: %w", err) } @@ -103,7 +107,7 @@ func startUsingTemplate(dialect string, opt ...Option) (cleanup func() error, re return dropDatabase(dialect, dbname) } - tdb, err := sql.Open(dialect, url) + tdb, err := common.SqlOpen(dialect, url) if err != nil { return func() error { return nil }, "", "", fmt.Errorf("could not create test database: %w", err) } @@ -130,7 +134,7 @@ func dropDatabase(dialect, dbname string) error { return fmt.Errorf("empty dbname") } - db, err := sql.Open(dialect, fmt.Sprintf("postgres://boundary:boundary@127.0.0.1:%s/boundary?sslmode=disable", testDBPort)) + db, err := common.SqlOpen(dialect, fmt.Sprintf("postgres://boundary:boundary@127.0.0.1:%s/boundary?sslmode=disable", testDBPort)) if err != nil { return err } diff --git a/testing/dbtest/template_test.go b/testing/dbtest/template_test.go index dcf305199..786edceae 100644 --- a/testing/dbtest/template_test.go +++ b/testing/dbtest/template_test.go @@ -1,10 +1,10 @@ package dbtest_test import ( - "database/sql" "errors" "testing" + "github.com/hashicorp/boundary/internal/db/common" "github.com/hashicorp/boundary/testing/dbtest" "github.com/stretchr/testify/require" ) @@ -56,7 +56,7 @@ func TestStartUsingTemplate(t *testing.T) { } else { require.NoError(t, err) - db, err := sql.Open(tt.dialect, u) + db, err := common.SqlOpen(tt.dialect, u) require.NoError(t, err) require.NoError(t, db.Ping()) db.Close() @@ -64,7 +64,7 @@ func TestStartUsingTemplate(t *testing.T) { require.NoError(t, c()) // ensure that database is gone after calling c - db, _ = sql.Open(tt.dialect, u) + db, _ = common.SqlOpen(tt.dialect, u) require.Error(t, db.Ping()) } })