Enable migration autogenerate

These changes allow a developer to generate migrations using the
autogenerate function without the need to pass in a config file that
includes sql connection information.

Change-Id: I6b3942f7747e8f73e52925c24340e20daeb78911
This commit is contained in:
Sam Betts 2015-10-16 17:48:51 +01:00
parent 2132f942bb
commit c07cfc6655
5 changed files with 55 additions and 30 deletions

View File

@ -239,16 +239,15 @@ Writing a Plugin
.. _ironic_inspector.plugins.base: https://github.com/openstack/ironic-inspector/blob/master/ironic_inspector/plugins/base.py .. _ironic_inspector.plugins.base: https://github.com/openstack/ironic-inspector/blob/master/ironic_inspector/plugins/base.py
.. _Introspection Rules: https://github.com/openstack/ironic-inspector#introspection-rules .. _Introspection Rules: https://github.com/openstack/ironic-inspector#introspection-rules
Adding migrations to the database Making changes to the database
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order to make any changes to the database, you must add a new migration. In order to make a change to the ironic-inspector database you must update the
This can be done using alembic:: database models found in ironic_inspector.db_ and then create a migration to
reflect that change.
alembic --config ironic_inspector/alembic.ini revision -m "A short description" There are two ways to create a migration which are described below, both of
these generate a new migration file. In this file there are two functions:
This will generate an empty migration file, with the correct revision
information already included. In this file there are two functions:
* upgrade - The upgrade function is run when * upgrade - The upgrade function is run when
``ironic-inspector-dbsync upgrade`` is run, and should be populated with ``ironic-inspector-dbsync upgrade`` is run, and should be populated with
@ -262,4 +261,31 @@ information already included. In this file there are two functions:
For further information on creating a migration, refer to For further information on creating a migration, refer to
`Create a Migration Script`_ from the alembic documentation. `Create a Migration Script`_ from the alembic documentation.
Autogenerate
------------
This is the simplest way to create a migration. Alembic will compare the models
to an up to date database, and then attempt to write a migration based on the
differences. This should generate correct migrations in most cases however
there are some cases when it can not detect some changes and may require
manual modification, see `What does Autogenerate Detect (and what does it not
detect?)`_ from the alembic documentation.
::
ironic-inspector-dbsync upgrade
ironic-inspector-dbsync revision -m "A short description" --autogenerate
Manual
------
This will generate an empty migration file, with the correct revision
information already included. However upgrade and downgrade are left empty and
must be manually populated in order to perform the correct actions on the
database::
ironic-inspector-dbsync revision -m "A short description"
.. _Create a Migration Script: https://alembic.readthedocs.org/en/latest/tutorial.html#create-a-migration-script .. _Create a Migration Script: https://alembic.readthedocs.org/en/latest/tutorial.html#create-a-migration-script
.. _ironic_inspector.db: https://github.com/openstack/ironic-inspector/blob/master/ironic_inspector/db.py
.. _What does Autogenerate Detect (and what does it not detect?): http://alembic.readthedocs.org/en/latest/autogenerate.html#what-does-autogenerate-detect-and-what-does-it-not-detect

View File

@ -27,6 +27,8 @@ from sqlalchemy import (Boolean, Column, DateTime, Float, ForeignKey, Integer,
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import orm from sqlalchemy import orm
from ironic_inspector import conf # noqa
class ModelBase(models.ModelBase): class ModelBase(models.ModelBase):
__table_args__ = {'mysql_engine': "InnoDB", __table_args__ = {'mysql_engine': "InnoDB",
@ -35,9 +37,16 @@ class ModelBase(models.ModelBase):
Base = declarative_base(cls=ModelBase) Base = declarative_base(cls=ModelBase)
CONF = cfg.CONF CONF = cfg.CONF
_DEFAULT_SQL_CONNECTION = 'sqlite:///ironic_inspector.sqlite'
_FACADE = None _FACADE = None
db_opts.set_defaults(cfg.CONF, _DEFAULT_SQL_CONNECTION,
'ironic_inspector.sqlite')
if CONF.discoverd.database:
db_opts.set_defaults(CONF,
connection='sqlite:///%s' %
str(CONF.discoverd.database).strip())
class Node(Base): class Node(Base):
__tablename__ = 'nodes' __tablename__ = 'nodes'
@ -110,20 +119,16 @@ class RuleAction(Base):
def init(): def init():
"""Initialize the database.""" """Initialize the database."""
if CONF.discoverd.database:
db_opts.set_defaults(CONF,
connection='sqlite:///%s' %
str(CONF.discoverd.database).strip())
return get_session() return get_session()
def get_session(**kwargs): def get_session(**kwargs):
facade = _create_facade_lazily() facade = create_facade_lazily()
return facade.get_session(**kwargs) return facade.get_session(**kwargs)
def get_engine(): def get_engine():
facade = _create_facade_lazily() facade = create_facade_lazily()
return facade.get_engine() return facade.get_engine()
@ -138,7 +143,7 @@ def model_query(model, *args, **kwargs):
return query return query
def _create_facade_lazily(): def create_facade_lazily():
global _FACADE global _FACADE
if _FACADE is None: if _FACADE is None:
_FACADE = db_session.EngineFacade.from_config(cfg.CONF) _FACADE = db_session.EngineFacade.from_config(cfg.CONF)

View File

@ -22,13 +22,11 @@ from alembic import config as alembic_config
from alembic import util as alembic_util from alembic import util as alembic_util
from oslo_config import cfg from oslo_config import cfg
from oslo_db import options as db_opts
from oslo_log import log from oslo_log import log
from ironic_inspector import conf # noqa from ironic_inspector import conf # noqa
CONF = cfg.CONF CONF = cfg.CONF
db_opts.set_defaults(CONF)
def add_alembic_command(subparsers, name): def add_alembic_command(subparsers, name):
@ -53,6 +51,7 @@ def add_command_parsers(subparsers):
parser = add_alembic_command(subparsers, 'revision') parser = add_alembic_command(subparsers, 'revision')
parser.set_defaults(func=do_revision) parser.set_defaults(func=do_revision)
parser.add_argument('-m', '--message') parser.add_argument('-m', '--message')
parser.add_argument('--autogenerate', action='store_true')
command_opt = cfg.SubCommandOpt('command', command_opt = cfg.SubCommandOpt('command',
@ -64,7 +63,8 @@ CONF.register_cli_opt(command_opt)
def do_revision(config, cmd, *args, **kwargs): def do_revision(config, cmd, *args, **kwargs):
do_alembic_command(config, cmd, message=CONF.command.message) do_alembic_command(config, cmd, message=CONF.command.message,
autogenerate=CONF.command.autogenerate)
def with_revision(config, cmd, *args, **kwargs): def with_revision(config, cmd, *args, **kwargs):

View File

@ -14,7 +14,8 @@
from alembic import context from alembic import context
from logging.config import fileConfig from logging.config import fileConfig
from sqlalchemy import create_engine
from ironic_inspector import db
# this is the Alembic Config object, which provides # this is the Alembic Config object, which provides
# access to the values within the .ini file in use. # access to the values within the .ini file in use.
@ -29,7 +30,6 @@ fileConfig(config.config_file_name)
# for 'autogenerate' support # for 'autogenerate' support
# from myapp import mymodel # from myapp import mymodel
# target_metadata = mymodel.Base.metadata # target_metadata = mymodel.Base.metadata
from ironic_inspector import db
target_metadata = db.Base.metadata target_metadata = db.Base.metadata
# other values from the config, defined by the needs of env.py, # other values from the config, defined by the needs of env.py,
@ -65,8 +65,7 @@ def run_migrations_online():
and associate a connection with the context. and associate a connection with the context.
""" """
connectable = create_engine(ironic_inspector_config.database.connection) connectable = db.create_facade_lazily().get_engine()
with connectable.connect() as connection: with connectable.connect() as connection:
context.configure( context.configure(
connection=connection, connection=connection,

View File

@ -15,7 +15,6 @@ import unittest
import mock import mock
from oslo_config import cfg from oslo_config import cfg
from oslo_db import options as db_opts
from oslo_log import log from oslo_log import log
from ironic_inspector.common import i18n from ironic_inspector.common import i18n
@ -35,7 +34,7 @@ def init_test_conf():
# Unit tests # Unit tests
except Exception: except Exception:
CONF.reset() CONF.reset()
for group in ('firewall', 'processing', 'ironic'): for group in ('firewall', 'processing', 'ironic', 'discoverd'):
CONF.register_group(cfg.OptGroup(group)) CONF.register_group(cfg.OptGroup(group))
try: try:
# Functional tests # Functional tests
@ -43,13 +42,9 @@ def init_test_conf():
except Exception: except Exception:
# Unit tests # Unit tests
pass pass
db_opts.set_defaults(CONF) CONF.set_default('connection', "sqlite:///", group='database')
CONF.set_default('slave_connection', False, group='database') CONF.set_default('slave_connection', False, group='database')
CONF.set_default('max_retries', 10, group='database') CONF.set_default('max_retries', 10, group='database')
if not CONF.database.connection:
# Might be set in functional tests
db_opts.set_defaults(CONF,
connection='sqlite:///')
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):