16
16
# License for the specific language governing permissions and limitations
17
17
# under the License.
19
import distutils.version as dist_version
22
from nova.db import migration
23
from nova.db.sqlalchemy.session import get_engine
22
24
from nova import exception
23
25
from nova import flags
26
from nova import log as logging
30
from migrate.versioning import util as migrate_util
34
LOG = logging.getLogger(__name__)
37
@migrate_util.decorator
38
def patched_with_engine(f, *a, **kw):
40
engine = migrate_util.construct_engine(url, **kw)
46
if isinstance(engine, migrate_util.Engine) and engine is not url:
47
migrate_util.log.debug('Disposing SQLAlchemy engine %s', engine)
51
# TODO(jkoelker) When migrate 0.7.3 is released and nova depends
52
# on that version or higher, this can be removed
53
MIN_PKG_VERSION = dist_version.StrictVersion('0.7.3')
54
if (not hasattr(migrate, '__version__') or
55
dist_version.StrictVersion(migrate.__version__) < MIN_PKG_VERSION):
56
migrate_util.with_engine = patched_with_engine
59
# NOTE(jkoelker) Delay importing migrate until we are patched
60
from migrate import exceptions as versioning_exceptions
26
61
from migrate.versioning import api as versioning_api
29
from migrate.versioning import exceptions as versioning_exceptions
32
# python-migration changed location of exceptions after 1.6.3
34
from migrate import exceptions as versioning_exceptions
36
sys.exit(_("python-migrate is not installed. Exiting."))
62
from migrate.versioning.repository import Repository
38
64
FLAGS = flags.FLAGS
41
69
def db_sync(version=None):
42
70
if version is not None:
44
72
version = int(version)
46
raise exception.Error(_("version should be an integer"))
74
raise exception.NovaException(_("version should be an integer"))
48
76
current_version = db_version()
49
repo_path = _find_migrate_repo()
77
repository = _find_migrate_repo()
50
78
if version is None or version > current_version:
51
return versioning_api.upgrade(FLAGS.sql_connection, repo_path, version)
79
return versioning_api.upgrade(get_engine(), repository, version)
53
return versioning_api.downgrade(FLAGS.sql_connection, repo_path,
81
return versioning_api.downgrade(get_engine(), repository,
58
repo_path = _find_migrate_repo()
86
repository = _find_migrate_repo()
60
return versioning_api.db_version(FLAGS.sql_connection, repo_path)
88
return versioning_api.db_version(get_engine(), repository)
61
89
except versioning_exceptions.DatabaseNotControlledError:
62
# If we aren't version controlled we may already have the database
63
# in the state from before we started version control, check for that
64
# and set up version_control appropriately
65
90
meta = sqlalchemy.MetaData()
66
engine = sqlalchemy.create_engine(FLAGS.sql_connection, echo=False)
67
92
meta.reflect(bind=engine)
69
for table in ('auth_tokens', 'zones', 'export_devices',
70
'fixed_ips', 'floating_ips', 'instances',
71
'key_pairs', 'networks', 'projects', 'quotas',
72
'security_group_instance_association',
73
'security_group_rules', 'security_groups',
74
'services', 'migrations',
75
'users', 'user_project_association',
76
'user_project_role_association',
77
'user_role_association',
78
'virtual_storage_arrays',
79
'volumes', 'volume_metadata',
80
'volume_types', 'volume_type_extra_specs'):
81
assert table in meta.tables
82
return db_version_control(1)
83
except AssertionError:
84
return db_version_control(0)
95
db_version_control(migration.INIT_VERSION)
96
return versioning_api.db_version(get_engine(), repository)
98
# Some pre-Essex DB's may not be version controlled.
99
# Require them to upgrade using Essex first.
100
raise exception.Error(_("Upgrade DB using Essex release first."))
87
103
def db_version_control(version=None):
88
repo_path = _find_migrate_repo()
89
versioning_api.version_control(FLAGS.sql_connection, repo_path, version)
104
repository = _find_migrate_repo()
105
versioning_api.version_control(get_engine(), repository, version)
93
109
def _find_migrate_repo():
94
110
"""Get the path for the migrate repository."""
95
112
path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
97
114
assert os.path.exists(path)
115
if _REPOSITORY is None:
116
_REPOSITORY = Repository(path)