Implements bp migrate-nova-volumes-to-cinder
Helper cmds to transition from nova to cinder Implements an import section in cinder-manage to transfer applicable tables from local or remote Nova database into a fresh Cinder database. Also implements optional method to copy persistent target files. Change-Id: I2e655e26c55f1986f3b1554726cead9e73ee9bd6
This commit is contained in:
parent
5f31f6e697
commit
11545df5cb
@ -54,17 +54,15 @@
|
|||||||
CLI interface for cinder management.
|
CLI interface for cinder management.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ast
|
|
||||||
import errno
|
|
||||||
import gettext
|
import gettext
|
||||||
import json
|
|
||||||
import math
|
|
||||||
import netaddr
|
|
||||||
import optparse
|
import optparse
|
||||||
import os
|
import os
|
||||||
import StringIO
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from sqlalchemy import create_engine, MetaData, Table
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
|
||||||
|
|
||||||
# If ../cinder/__init__.py exists, add ../ to Python search path, so that
|
# If ../cinder/__init__.py exists, add ../ to Python search path, so that
|
||||||
# it will override what happens to be installed in /usr/(local/)lib/python...
|
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||||
@ -83,12 +81,9 @@ from cinder import exception
|
|||||||
from cinder import flags
|
from cinder import flags
|
||||||
from cinder.openstack.common import log as logging
|
from cinder.openstack.common import log as logging
|
||||||
from cinder.openstack.common import cfg
|
from cinder.openstack.common import cfg
|
||||||
from cinder.openstack.common import importutils
|
|
||||||
from cinder.openstack.common import rpc
|
from cinder.openstack.common import rpc
|
||||||
from cinder import quota
|
|
||||||
from cinder import utils
|
from cinder import utils
|
||||||
from cinder import version
|
from cinder import version
|
||||||
from cinder.volume import volume_types
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
@ -236,6 +231,126 @@ class VersionCommands(object):
|
|||||||
self.list()
|
self.list()
|
||||||
|
|
||||||
|
|
||||||
|
class ImportCommands(object):
|
||||||
|
"""Methods for importing Nova volumes to Cinder.
|
||||||
|
|
||||||
|
EXPECTATIONS:
|
||||||
|
These methods will do two things:
|
||||||
|
1. Import relevant Nova DB info in to Cinder
|
||||||
|
2. Import persistent tgt files from Nova to Cinder (see copy_tgt_files)
|
||||||
|
|
||||||
|
If you're using VG's (local storage) for your backend YOU MUST install
|
||||||
|
Cinder on the same node that you're migrating from.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _map_table(self, table):
|
||||||
|
class Mapper(declarative_base()):
|
||||||
|
__table__ = table
|
||||||
|
return Mapper
|
||||||
|
|
||||||
|
def _open_session(self, con_info):
|
||||||
|
engine = create_engine(con_info,
|
||||||
|
convert_unicode=True,
|
||||||
|
echo=True)
|
||||||
|
session = sessionmaker(bind=engine)
|
||||||
|
return (session(), engine)
|
||||||
|
|
||||||
|
def _backup_cinder_db(self):
|
||||||
|
#First, dump the dest_db as a backup incase this goes wrong
|
||||||
|
cinder_dump = utils.execute('mysqldump', 'cinder')
|
||||||
|
if 'Dump completed on' in cinder_dump[0]:
|
||||||
|
with open('./cinder_db_bkup.sql', 'w+') as fo:
|
||||||
|
for line in cinder_dump:
|
||||||
|
fo.write(line)
|
||||||
|
else:
|
||||||
|
raise exception.InvalidResults()
|
||||||
|
|
||||||
|
def _import_db(self, src_db, dest_db, backup_db):
|
||||||
|
# Remember order matters due to FK's
|
||||||
|
table_list = ['sm_flavors',
|
||||||
|
'sm_backend_config',
|
||||||
|
'snapshots',
|
||||||
|
'volume_types',
|
||||||
|
'volumes',
|
||||||
|
'iscsi_targets',
|
||||||
|
'sm_volume',
|
||||||
|
'volume_metadata',
|
||||||
|
'volume_type_extra_specs']
|
||||||
|
|
||||||
|
if backup_db > 0:
|
||||||
|
if 'mysql:' not in dest_db:
|
||||||
|
print (_('Sorry, only mysql backups are supported!'))
|
||||||
|
raise exception.InvalidRequest()
|
||||||
|
else:
|
||||||
|
self._backup_cinder_db()
|
||||||
|
|
||||||
|
(src, src_engine) = self._open_session(src_db)
|
||||||
|
src_meta = MetaData(bind=src_engine)
|
||||||
|
(dest, dest_engine) = self._open_session(dest_db)
|
||||||
|
|
||||||
|
for table_name in table_list:
|
||||||
|
print (_('Importing table %s...' % table_name))
|
||||||
|
table = Table(table_name, src_meta, autoload=True)
|
||||||
|
new_row = self._map_table(table)
|
||||||
|
columns = table.columns.keys()
|
||||||
|
for row in src.query(table).all():
|
||||||
|
data = dict([(str(column), getattr(row, column))
|
||||||
|
for column in columns])
|
||||||
|
dest.add(new_row(**data))
|
||||||
|
dest.commit()
|
||||||
|
|
||||||
|
@args('--src', dest='src_db', metavar='<Nova DB>',
|
||||||
|
help='db-engine://db_user[:passwd]@db_host[:port]\t\t'
|
||||||
|
'example: mysql://root:secrete@192.168.137.1')
|
||||||
|
@args('--dest', dest='dest_db', metavar='<Cinder DB>',
|
||||||
|
help='db-engine://db_user[:passwd]@db_host[:port]\t\t'
|
||||||
|
'example: mysql://root:secrete@192.168.137.1')
|
||||||
|
@args('--backup', dest='backup_db', metavar='<0|1>',
|
||||||
|
help='Perform mysqldump of cinder db before writing to it')
|
||||||
|
def import_db(self, src_db, dest_db, backup_db=1):
|
||||||
|
"""Import relevant volume DB entries from Nova into Cinder.
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
Your Cinder DB should be clean WRT volume entries.
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
We take an sqldump of the cinder DB before mods
|
||||||
|
If you're not using mysql, set backup_db=0
|
||||||
|
and create your own backup.
|
||||||
|
"""
|
||||||
|
src_db = '%s/nova' % src_db
|
||||||
|
dest_db = '%s/cinder' % dest_db
|
||||||
|
self._import_db(src_db, dest_db, backup_db)
|
||||||
|
|
||||||
|
@args('--src', dest='src_tgts', metavar='<src tgts>',
|
||||||
|
help='[login@src_host:]/opt/stack/nova/volumes/')
|
||||||
|
@args('--dest', dest='dest_tgts', metavar='<dest tgts>',
|
||||||
|
help='[login@src_host:/opt/stack/cinder/volumes/]')
|
||||||
|
def copy_ptgt_files(self, src_tgts, dest_tgts=None):
|
||||||
|
"""Copy persistent scsi tgt files from nova to cinder.
|
||||||
|
|
||||||
|
Default destination is FLAGS.volume_dir or state_path/volumes/
|
||||||
|
|
||||||
|
PREREQUISITES:
|
||||||
|
Persistent tgts were introduced in Folsom. If you're running
|
||||||
|
Essex or other release, this script is unnecessary.
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
If you're using local VG's and LVM for your nova volume backend
|
||||||
|
there's no point in copying these files over. Leave them on
|
||||||
|
your Nova system as they won't do any good here.
|
||||||
|
"""
|
||||||
|
if dest_tgts is None:
|
||||||
|
try:
|
||||||
|
dest_tgts = FLAGS.volumes_dir
|
||||||
|
except:
|
||||||
|
dest_tgts = '%s/volumes' % FLAGS.state_path
|
||||||
|
|
||||||
|
utils.execute('rsync', '-avz', src_tgts, dest_tgts)
|
||||||
|
|
||||||
|
|
||||||
class VolumeCommands(object):
|
class VolumeCommands(object):
|
||||||
"""Methods for dealing with a cloud in an odd state"""
|
"""Methods for dealing with a cloud in an odd state"""
|
||||||
|
|
||||||
@ -492,6 +607,7 @@ CATEGORIES = [
|
|||||||
('sm', StorageManagerCommands),
|
('sm', StorageManagerCommands),
|
||||||
('version', VersionCommands),
|
('version', VersionCommands),
|
||||||
('volume', VolumeCommands),
|
('volume', VolumeCommands),
|
||||||
|
('migrate', ImportCommands),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -239,6 +239,10 @@ class InvalidRequest(Invalid):
|
|||||||
message = _("The request is invalid.")
|
message = _("The request is invalid.")
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidResults(Invalid):
|
||||||
|
message = _("The results are invalid.")
|
||||||
|
|
||||||
|
|
||||||
class InvalidSignature(Invalid):
|
class InvalidSignature(Invalid):
|
||||||
message = _("Invalid signature %(signature)s for user %(user)s.")
|
message = _("Invalid signature %(signature)s for user %(user)s.")
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user