Support upgrading from old migration table name (#889)
This commit is contained in:
1 parent
3461dcbd0c
commit
955ae41215
10 files changed
+489
-161
No files matched your search
@@ -15,7 +15,7 @@ import (
|
||||
// It owns the reporting to the UI any errors.
|
||||
// Returns a cleanup function which must be called even if an error is returned and
|
||||
// an error code where a non-zero value indicates an error happened.
|
||||
func migrateDatabase(ctx context.Context, ui cli.Ui, dialect, u string) (func(), int) {
|
||||
func migrateDatabase(ctx context.Context, ui cli.Ui, dialect, u string, requireFresh bool) (func(), int) {
|
||||
noop := func() {}
|
||||
// This database is used to keep an exclusive lock on the database for the
|
||||
// remainder of the command
|
||||
@@ -52,6 +52,10 @@ func migrateDatabase(ctx context.Context, ui cli.Ui, dialect, u string) (func(),
|
||||
ui.Error(fmt.Errorf("Error getting database state: %w", err).Error())
|
||||
return unlock, 1
|
||||
}
|
||||
if requireFresh && st.InitializationStarted {
|
||||
ui.Error(base.WrapAtLength("Database has already been initialized. Please use 'boundary database migrate'."))
|
||||
return unlock, 1
|
||||
}
|
||||
if st.Dirty {
|
||||
ui.Error(base.WrapAtLength("Database is in a bad state. Please revert back to the last known good state."))
|
||||
return unlock, 1
|
||||
|
||||
@@ -19,6 +19,7 @@ func TestMigrateDatabase(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
requireFresh bool
|
||||
urlProvider func() string
|
||||
expectedCode int
|
||||
expectedOutput string
|
||||
@@ -37,6 +38,25 @@ func TestMigrateDatabase(t *testing.T) {
|
||||
expectedCode: 0,
|
||||
expectedOutput: "Migrations successfully run.\n",
|
||||
},
|
||||
{
|
||||
name: "old_version_table_used",
|
||||
urlProvider: func() string {
|
||||
c, u, _, err := db.StartDbInDocker(dialect)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, c())
|
||||
})
|
||||
dBase, err := sql.Open(dialect, u)
|
||||
require.NoError(t, err)
|
||||
|
||||
createStmt := `create table if not exists schema_migrations (version bigint primary key, dirty boolean not null)`
|
||||
_, err = dBase.Exec(createStmt)
|
||||
require.NoError(t, err)
|
||||
return u
|
||||
},
|
||||
expectedCode: 0,
|
||||
expectedOutput: "Migrations successfully run.\n",
|
||||
},
|
||||
{
|
||||
name: "bad_url",
|
||||
urlProvider: func() string { return "badurl" },
|
||||
@@ -65,13 +85,77 @@ func TestMigrateDatabase(t *testing.T) {
|
||||
expectedCode: 1,
|
||||
expectedError: "Unable to capture a lock on the database.\n",
|
||||
},
|
||||
{
|
||||
name: "basic_require_fresh",
|
||||
requireFresh: true,
|
||||
urlProvider: func() string {
|
||||
c, u, _, err := db.StartDbInDocker(dialect)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, c())
|
||||
})
|
||||
return u
|
||||
},
|
||||
expectedCode: 0,
|
||||
expectedOutput: "Migrations successfully run.\n",
|
||||
},
|
||||
{
|
||||
name: "old_version_table_used_require_fresh",
|
||||
requireFresh: true,
|
||||
urlProvider: func() string {
|
||||
c, u, _, err := db.StartDbInDocker(dialect)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, c())
|
||||
})
|
||||
dBase, err := sql.Open(dialect, u)
|
||||
require.NoError(t, err)
|
||||
|
||||
createStmt := `create table if not exists schema_migrations (version bigint primary key, dirty boolean not null)`
|
||||
_, err = dBase.Exec(createStmt)
|
||||
require.NoError(t, err)
|
||||
return u
|
||||
},
|
||||
expectedCode: 1,
|
||||
expectedError: "Database has already been initialized. Please use 'boundary database\nmigrate'.\n",
|
||||
},
|
||||
{
|
||||
name: "bad_url_require_fresh",
|
||||
requireFresh: true,
|
||||
urlProvider: func() string { return "badurl" },
|
||||
expectedCode: 1,
|
||||
expectedError: "Unable to connect to the database at \"badurl\"\n",
|
||||
},
|
||||
{
|
||||
name: "cant_get_lock_require_fresh",
|
||||
requireFresh: true,
|
||||
urlProvider: func() string {
|
||||
c, u, _, err := db.StartDbInDocker(dialect)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, c())
|
||||
})
|
||||
dBase, err := sql.Open(dialect, u)
|
||||
require.NoError(t, err)
|
||||
|
||||
man, err := schema.NewManager(ctx, dialect, dBase)
|
||||
require.NoError(t, err)
|
||||
// This is an advisory lock on the DB which is released when the DB session ends.
|
||||
err = man.ExclusiveLock(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
return u
|
||||
},
|
||||
expectedCode: 1,
|
||||
expectedError: "Unable to capture a lock on the database.\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
u := tc.urlProvider()
|
||||
ui := cli.NewMockUi()
|
||||
clean, errCode := migrateDatabase(ctx, ui, dialect, u)
|
||||
clean, errCode := migrateDatabase(ctx, ui, dialect, u, tc.requireFresh)
|
||||
clean()
|
||||
assert.EqualValues(t, tc.expectedCode, errCode)
|
||||
assert.Equal(t, tc.expectedOutput, ui.OutputWriter.String())
|
||||
|
||||
@@ -260,7 +260,7 @@ func (c *InitCommand) Run(args []string) (retCode int) {
|
||||
return 1
|
||||
}
|
||||
|
||||
clean, errCode := migrateDatabase(c.Context, c.UI, dialect, migrationUrl)
|
||||
clean, errCode := migrateDatabase(c.Context, c.UI, dialect, migrationUrl, true)
|
||||
defer clean()
|
||||
if errCode != 0 {
|
||||
return errCode
|
||||
|
||||
@@ -200,7 +200,7 @@ func (c *MigrateCommand) Run(args []string) (retCode int) {
|
||||
return 1
|
||||
}
|
||||
|
||||
clean, errCode := migrateDatabase(c.Context, c.UI, dialect, migrationUrl)
|
||||
clean, errCode := migrateDatabase(c.Context, c.UI, dialect, migrationUrl, false)
|
||||
defer clean()
|
||||
if errCode != 0 {
|
||||
return errCode
|
||||
|
||||
Reference in new issue
Block a user