Use metadata.create_all() to initialise DB schema

There is no need to run database migration each time, when we want to
get a new actual database schema. Running all migration scripts takes a
long time on production databases and can be not suitable for SQLite
because of Alembic limitation.

Added create_schema() method, which supposes to be used for initial
installation instead of upgrade('head').

Partial-Bug: #1347604

Change-Id: I039d955f051eda015bef2299122fd1f0fb5c46da
This commit is contained in:
Victor Sergeyev 2014-07-17 13:13:20 +03:00
parent b56db42aa3
commit e76932a073
4 changed files with 61 additions and 5 deletions

View File

@ -47,6 +47,9 @@ class DBCommand(object):
def version(self): def version(self):
print(migration.version()) print(migration.version())
def create_schema(self):
migration.create_schema()
def add_command_parsers(subparsers): def add_command_parsers(subparsers):
command_object = DBCommand() command_object = DBCommand()
@ -71,6 +74,9 @@ def add_command_parsers(subparsers):
parser = subparsers.add_parser('version') parser = subparsers.add_parser('version')
parser.set_defaults(func=command_object.version) parser.set_defaults(func=command_object.version)
parser = subparsers.add_parser('create_schema')
parser.set_defaults(func=command_object.create_schema)
command_opt = cfg.SubCommandOpt('command', command_opt = cfg.SubCommandOpt('command',
title='Command', title='Command',
@ -85,7 +91,7 @@ def main():
# pls change it to ironic-dbsync upgrade # pls change it to ironic-dbsync upgrade
valid_commands = set([ valid_commands = set([
'upgrade', 'downgrade', 'revision', 'upgrade', 'downgrade', 'revision',
'version', 'stamp' 'version', 'stamp', 'create_schema',
]) ])
if not set(sys.argv) & valid_commands: if not set(sys.argv) & valid_commands:
sys.argv.append('upgrade') sys.argv.append('upgrade')

View File

@ -45,3 +45,7 @@ def stamp(version):
def revision(message, autogenerate): def revision(message, autogenerate):
return IMPL.revision(message, autogenerate) return IMPL.revision(message, autogenerate)
def create_schema():
return IMPL.create_schema()

View File

@ -19,8 +19,10 @@ import os
import alembic import alembic
from alembic import config as alembic_config from alembic import config as alembic_config
import alembic.migration as alembic_migration import alembic.migration as alembic_migration
from oslo.db import exception as db_exc
from ironic.db.sqlalchemy import api as sqla_api from ironic.db.sqlalchemy import api as sqla_api
from ironic.db.sqlalchemy import models
def _alembic_config(): def _alembic_config():
@ -29,12 +31,13 @@ def _alembic_config():
return config return config
def version(config=None): def version(config=None, engine=None):
"""Current database version. """Current database version.
:returns: Database version :returns: Database version
:rtype: string :rtype: string
""" """
if engine is None:
engine = sqla_api.get_engine() engine = sqla_api.get_engine()
with engine.connect() as conn: with engine.connect() as conn:
context = alembic_migration.MigrationContext.configure(conn) context = alembic_migration.MigrationContext.configure(conn)
@ -53,6 +56,25 @@ def upgrade(revision, config=None):
alembic.command.upgrade(config, revision or 'head') alembic.command.upgrade(config, revision or 'head')
def create_schema(config=None, engine=None):
"""Create database schema from models description.
Can be used for initial installation instead of upgrade('head').
"""
if engine is None:
engine = sqla_api.get_engine()
# NOTE(viktors): If we will use metadata.create_all() for non empty db
# schema, it will only add the new tables, but leave
# existing as is. So we should avoid of this situation.
if version(engine=engine) is not None:
raise db_exc.DbMigrationError("DB schema is already under version"
" control. Use upgrade() instead")
models.Base.metadata.create_all(engine)
stamp('head', config=config)
def downgrade(revision, config=None): def downgrade(revision, config=None):
"""Used for downgrading database. """Used for downgrading database.

View File

@ -42,7 +42,7 @@ import contextlib
from alembic import script from alembic import script
import mock import mock
from oslo.db import exception from oslo.db import exception as db_exc
from oslo.db.sqlalchemy import test_base from oslo.db.sqlalchemy import test_base
from oslo.db.sqlalchemy import test_migrations from oslo.db.sqlalchemy import test_migrations
from oslo.db.sqlalchemy import utils as db_utils from oslo.db.sqlalchemy import utils as db_utils
@ -315,9 +315,33 @@ class MigrationCheckersMixin(object):
# Ironic will use oslo.db 0.4.0 or higher. # Ironic will use oslo.db 0.4.0 or higher.
# See bug #1214341 for details. # See bug #1214341 for details.
self.assertRaises( self.assertRaises(
(sqlalchemy.exc.IntegrityError, exception.DBDuplicateEntry), (sqlalchemy.exc.IntegrityError, db_exc.DBDuplicateEntry),
nodes.insert().execute, data) nodes.insert().execute, data)
def test_upgrade_and_version(self):
with patch_with_engine(self.engine):
self.migration_api.upgrade('head')
self.assertIsNotNone(self.migration_api.version())
def test_create_schema_and_version(self):
with patch_with_engine(self.engine):
self.migration_api.create_schema()
self.assertIsNotNone(self.migration_api.version())
def test_upgrade_and_create_schema(self):
with patch_with_engine(self.engine):
self.migration_api.upgrade('31baaf680d2b')
self.assertRaises(db_exc.DbMigrationError,
self.migration_api.create_schema)
def test_upgrade_twice(self):
with patch_with_engine(self.engine):
self.migration_api.upgrade('31baaf680d2b')
v1 = self.migration_api.version()
self.migration_api.upgrade('head')
v2 = self.migration_api.version()
self.assertNotEqual(v1, v2)
class TestMigrationsMySQL(MigrationCheckersMixin, class TestMigrationsMySQL(MigrationCheckersMixin,
WalkVersionsMixin, WalkVersionsMixin,