Skip to content
This repository has been archived by the owner on Mar 11, 2021. It is now read-only.

Support migration of the database schema and data #184

Closed
kwk opened this issue Sep 5, 2016 · 12 comments · Fixed by #278
Closed

Support migration of the database schema and data #184

kwk opened this issue Sep 5, 2016 · 12 comments · Fixed by #278

Comments

@kwk
Copy link
Collaborator

kwk commented Sep 5, 2016

We could add a version table which helps in figuring out what migration code needs to be executed.

@kwk kwk self-assigned this Sep 5, 2016
@aslakknutsen aslakknutsen changed the title Support migration of the database schema Support migration of the database schema and data Sep 5, 2016
@kwk kwk added the database label Sep 5, 2016
@sbose78
Copy link
Member

sbose78 commented Sep 6, 2016

Is this the flow you would be proposing during an upgrade ?

  1. Update version details in the database via a SQL.
  2. Deploy latest version of the ALM app.
  3. The app code reads the version details from the database and runs the relevant migrations.

@kwk
Copy link
Collaborator Author

kwk commented Sep 6, 2016

@sbose78 no, so far we have the Perfrom() function from migration.go.

Here's a possible layout for a migration/schema-version table:

ID version updated_at
1 1 2016-09-06 10:00
2 2 2016-12-07 14:00
3 3 2017-01-12 09:00

The ID column might not be needed in the end.

The migration.go file might be a place to start doing the migration in a way similar to this:

  1. Check if version table exists
    1. Version table doesn't exist.
      1. We must be in the original schema, so create version table and enter 1, then proceed as if the version table existed all the time.
    2. Version table exists
      1. Check the version column for the highest (in SQL: max()) number and call it OLD_VERSION.
      2. Jump to case in which to update from version OLD_VERSION to OLD_VERSION + 1.
        1. Insert OLD_VERSION+1 with the updated_at into the SQL table.
      3. Fall through other cases in the swtich to perform all required version updates until we've reached the current desired schema.

Does that sound logical?

I've implemented the above logic in SQL once and it worked okay.

@tsmaeder any ideas?

@aslakknutsen aslakknutsen modified the milestone: Sprint #120 Sep 6, 2016
@baijum
Copy link
Contributor

baijum commented Sep 13, 2016

Can we check this project?
https://github.com/rubenv/sql-migrate

@kwk
Copy link
Collaborator Author

kwk commented Sep 13, 2016

Taken from @aslakknutsen 's gist:

var order [][]func()

order = append(order, []func(db) {ExecSQLFile("add_customer.sql"), MigrateCustomerFieldName})
order = append(order, []func(db) {ExecSQLFile("add_some_other")})

// db.tx.begin // TODO: Make sure currentVersion is read inside TX
for verison := currentVersion() && version < size(order) {
    for migrationFun := order[version] {
        migrationFunc(db)
    }
    updateVersion()
}
// db.tx.comit

@kwk
Copy link
Collaborator Author

kwk commented Sep 13, 2016

Idea from @aslakknutsen: turn on postgres driver output during migration for better mid-way error detection .

@kwk
Copy link
Collaborator Author

kwk commented Sep 13, 2016

Group idea: Think about how to handle great version deltas: If delta is bigger than 2, require a downtime.

@kwk
Copy link
Collaborator Author

kwk commented Sep 14, 2016

Can we check this project?
https://github.com/rubenv/sql-migrate

Hi @baijum . Just to recap yesterday's meeting:

We decided that we ( @aslakknutsen , @tsmaeder , @sbose78 , and @pranavgore09 ) won't use this library for a few reasons. It is mostly related to the features not being pretty relevant to us.

  1. We only have to support one database (PostgreSQL) and not the many others supported by the project.
  2. We want to have pre- and post-migration scripts (probably in Go) that need to run smart migration steps, that would otherwise be too cumbersome to write in pure SQL files.
  3. We don't want to support down-migrations.

@kwk
Copy link
Collaborator Author

kwk commented Sep 14, 2016

We should embed the migration in the code by using bindata: https://github.com/rubenv/sql-migrate#embedding-migrations-with-bindata

@aslakknutsen
Copy link
Contributor

@kwk jut fyi, we're already using bindata; https://github.com/almighty/almighty-core/blob/master/Makefile#L160

@kwk
Copy link
Collaborator Author

kwk commented Sep 21, 2016

@kwk jut fyi, we're already using bindata; https://github.com/almighty/almighty-core/blob/master/Makefile#L160

Thanks @aslakknutsen for pointing out.

@tsmaeder
Copy link
Contributor

Two points I'd like to make:

  1. We need to replace our use of "db.Automigrate()" with sql code
  2. We have multiple db setup locations now (migration pkg, but also remotrworkitem/schedulertest.go). We should offer a SPI for "plugins" and always use the same migration code (also in tests)

@baijum
Copy link
Contributor

baijum commented Sep 25, 2016

@kwk I found a project with similar scope and removed unwanted features. Here it is: https://github.com/baijum/pgmigration

@kwk kwk closed this as completed Sep 26, 2016
@kwk kwk reopened this Sep 26, 2016
kwk added a commit to kwk/fabric8-wit that referenced this issue Sep 27, 2016
…nd data

Build sqlbindata.go with go-bindata from migration/sql-files

To be able to have all migration/sql-files/*.sql files bundled
in the alm core binary, I've used go-bindata to pack them into
the migration/sqlbindata.go file. The prefix `migration/sql-files`
is removed from the filepaths inside of `migration/sqlbinata.go`.

The first sql file (./migration/sql-files/000-bootstrap.sql) creates
the basic layout of the versioning table.

The auto migration portion in migration/migration.go has been removed.

Logic to get the current version and to execute all remaining version
is implemented.
kwk added a commit to kwk/fabric8-wit that referenced this issue Sep 27, 2016
…nd data

Build sqlbindata.go with go-bindata from migration/sql-files

To be able to have all migration/sql-files/*.sql files bundled
in the alm core binary, I've used go-bindata to pack them into
the migration/sqlbindata.go file. The prefix `migration/sql-files`
is removed from the filepaths inside of `migration/sqlbinata.go`.

The first sql file (./migration/sql-files/000-bootstrap.sql) creates
the basic layout of the versioning table.

The auto migration portion in migration/migration.go has been removed.

Logic to get the current version and to execute all remaining version
is implemented.
kwk added a commit to kwk/fabric8-wit that referenced this issue Sep 27, 2016
…nd data

Build sqlbindata.go with go-bindata from migration/sql-files

To be able to have all migration/sql-files/*.sql files bundled
in the alm core binary, I've used go-bindata to pack them into
the migration/sqlbindata.go file. The prefix `migration/sql-files`
is removed from the filepaths inside of `migration/sqlbinata.go`.

The first sql file (./migration/sql-files/000-bootstrap.sql) creates
the basic layout of the versioning table.

The auto migration portion in migration/migration.go has been removed.

Logic to get the current version and to execute all remaining version
is implemented.
kwk added a commit to kwk/fabric8-wit that referenced this issue Sep 27, 2016
…nd data

Build sqlbindata.go with go-bindata from migration/sql-files

To be able to have all migration/sql-files/*.sql files bundled
in the alm core binary, I've used go-bindata to pack them into
the migration/sqlbindata.go file. The prefix `migration/sql-files`
is removed from the filepaths inside of `migration/sqlbinata.go`.

The first sql file (./migration/sql-files/000-bootstrap.sql) creates
the basic layout of the versioning table.

The auto migration portion in migration/migration.go has been removed.

Logic to get the current version and to execute all remaining version
is implemented.
@aslakknutsen aslakknutsen modified the milestones: Sprint #120, Sprint #121 Sep 28, 2016
kwk added a commit to kwk/fabric8-wit that referenced this issue Sep 28, 2016
…nd data

Build sqlbindata.go with go-bindata from migration/sql-files

To be able to have all migration/sql-files/*.sql files bundled
in the alm core binary, I've used go-bindata to pack them into
the migration/sqlbindata.go file. The prefix `migration/sql-files`
is removed from the filepaths inside of `migration/sqlbinata.go`.

The first sql file (./migration/sql-files/000-bootstrap.sql) creates
the basic layout of the versioning table.

The auto migration portion in migration/migration.go has been removed.

Logic to get the current version and to execute all remaining version
is implemented.
kwk added a commit to kwk/fabric8-wit that referenced this issue Sep 30, 2016
…nd data

Build sqlbindata.go with go-bindata from migration/sql-files

To be able to have all migration/sql-files/*.sql files bundled
in the alm core binary, I've used go-bindata to pack them into
the migration/sqlbindata.go file. The prefix `migration/sql-files`
is removed from the filepaths inside of `migration/sqlbinata.go`.

The first sql file (./migration/sql-files/000-bootstrap.sql) creates
the basic layout of the versioning table.

The auto migration portion in migration/migration.go has been removed.

Logic to get the current version and to execute all remaining version
is implemented.
kwk added a commit to kwk/fabric8-wit that referenced this issue Oct 5, 2016
…nd data

Build sqlbindata.go with go-bindata from migration/sql-files

To be able to have all migration/sql-files/*.sql files bundled
in the alm core binary, I've used go-bindata to pack them into
the migration/sqlbindata.go file. The prefix `migration/sql-files`
is removed from the filepaths inside of `migration/sqlbinata.go`.

The first sql file (./migration/sql-files/000-bootstrap.sql) creates
the basic layout of the versioning table.

The auto migration portion in migration/migration.go has been removed.

Logic to get the current version and to execute all remaining version
is implemented.
kwk added a commit to kwk/fabric8-wit that referenced this issue Oct 6, 2016
Fixes fabric8-services#184

* To be able to have all migration/sql-files/*.sql files bundled in the
  alm core binary, I've used go-bindata to pack them intothe
  migration/sqlbindata.go file. The prefix migration/sql-files is removed
  from the filepaths inside of migration/sqlbinata.go.

  The purpose of the migration/sql-files is to store all files that are
  relevant for updating the database over time.

  The SQL files themselves are packaged into the alm core binary with
  go-bindata.

  The filenames of the SQL files have no meaning but we prefix them with
  the version they stand for so it is easier to find out what's happening.
  The migration.go file has the control over the updates and the SQL files
  are not blindly executed just because they exist. Instead we allow the
  developers to run Go code as well.

  I've made sqlbindata.go a dependency of test-unit and test-integration.
  Otherwise the migration/sqlbindata.go file will not exist.

* The auto migration portion in migration/migration.go and other places has
  been removed.

* Added postgres.database config option

* Added pg_dump of all tables except version

  This was command used to create all the common tables that are currently
  in existence.

       $ pg_dump \
              --schema-only \
              --exclude-table=version \
              --no-privileges \
              --no-owner \
              --encoding=utf-8 \
              --serializable-deferrable \
              --host=$(\
                      docker inspect \
                              --format '{{ .NetworkSettings.IPAddress }}' \
                              make_postgres_integration_test_1 \
                      ) \
              --username=postgres -W \
         > migration/sql-files/001-common.sql

  As you can see I've tried to limit the schema as must as possible to
  make it universally applicable. Still in a follow up commit I'm going to
  have to make some adjustments to this dump before we can apply it.

  After dumping the database schema, I've manipulated it:

  - Simplified primary key in tables
    - Removed most sequences and ALTER statements and used simpler bigserial type and PRIMARY KEY constraint.
      See https://www.postgresql.org/docs/current/static/datatype-numeric.html

* Added -migrateDatabase CLI switch

  If the -migrateDatabase switch is given, we start the core as usal but
  exit as soon as the migration of the database is done.

  If -printConfig is also given, -printConfig wins. That means, after
  printing the config, we exit the program before even going to the
  migration.

  The -migrateDatabase switch can also be toggled from the "migrate-database" make target

  We run the database migration before running integration tests

* Make sure the database is populated with the correct types (e.g. system.bug etc.)

  It is okay for integration tests to create the database entries that
  they need. That is what the migration.PopulateCommonTypes() function does.
  Previously this function was called PopulateCommonTypes() for historical reasons.
  The actual structural migration of a database is performed in the
  Migrate() function and not in PopulateCommonTypes(). Whether or not this should be
  outsourced can be discussed. But for now the integration tests that need
  some test data to be present in the database are responsible for
  initiating the population themselves.

  (We can refactor the whole concept of resource.Require() in another issue
  but not here.)

* Added config option populate.commontypes

  By default populate.commontypes is `true` to ensure that the
  system will try to create the common work item types such as system.bug,
  systen, feature, and so forth.

* Test support for concurrent migrations (by @baijum)

* Serializable transactions during migration

  No matter what the default connection setting is for transactions, the
  transactions created for the migration code will be serializable. This
  is the most secure way that doesn't allow other transactions to read or
  write.

  We ignore a postgres error of serialization_failure in migration.

* Lock version table

  In addition to the transaction isolation level "serializable" we're
  loccking the "version" table" for exclusive access for the current
  transaction.
aslakknutsen pushed a commit that referenced this issue Oct 11, 2016
To be able to have all `migration/sql-files/*.sql` files bundled in the alm core binary, I've used go-bindata to pack them intothe `migration/sqlbindata.go` file. The prefix `migration/sql-files` is removed from the filepaths inside of `migration/sqlbinata.go`.

The purpose of the `migration/sql-files` is to store all files that are relevant for updating the database over time.

The SQL files themselves are packaged into the alm core binary with [go-bindata](https://github.com/jteeuwen/go-bindata).

The filenames of the SQL files have no meaning but we prefix them with the version they stand for so it is easier to find out what's happening. The `migration.go` file has the control over the updates and the SQL files are *not* blindly executed just because they exist. Instead we allow the developers to run Go code as well.

## Version 0

The first sql file (`./migration/sql-files/000-bootstrap.sql`) creates the basic layout of the versioning table.

### Database table layout

This is how the `version` table looks like in Postgres:

```
postgres=# select * from version;
 id |          updated_at           | version 
----+-------------------------------+---------
  1 | 2016-09-27 10:13:30.423206+00 |       0
(1 row)
```

The auto migration portion in migration/migration.go has been removed.

Logic to get the current version and to execute all remaining version is implemented.


* Support migration of the database schema and data

* Added -migrateDatabase CLI switch

  If the -migrateDatabase switch is given, we start the core as usal but
  exit as soon as the migration of the database is done.

  If -printConfig is also given, -printConfig wins. That means, after
  printing the config, we exit the program before even going to the
  migration.

  The -migrateDatabase switch can also be toggled from the "migrate-database" make target

  We run the database migration before running integration tests

* Make sure the database is populated with the correct types (e.g. system.bug etc.)

  It is okay for integration tests to create the database entries that
  they need. That is what the migration.PopulateCommonTypes() function does.
  Previously this function was called PopulateCommonTypes() for historical reasons.
  The actual structural migration of a database is performed in the
  Migrate() function and not in PopulateCommonTypes(). Whether or not this should be
  outsourced can be discussed. But for now the integration tests that need
  some test data to be present in the database are responsible for
  initiating the population themselves.

* Added config option populate.commontypes

  By default populate.commontypes is `true` to ensure that the
  system will try to create the common work item types such as system.bug,
  systen, feature, and so forth.

* Test support for concurrent migrations (by @baijum)

* Lock version table

  In addition to the transaction isolation level "serializable" we're
  loccking the "version" table" for exclusive access for the current
  transaction.

* Introduce configuration.GetPostgresConfigString()

GetPostgresConfigString returns a ready to use string for usage in
sql.Open()

Contributed-by Konrad Kleine <kwk@users.noreply.github.com>
Contributed-by Baiju Muthukadan <baiju.m.mail@gmail.com>

Fixes #184
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants