[Kimchi-devel] [PATCH 2/3 v2] Live migration backend: control/vms and model/vms changes
Aline Manera
alinefm at linux.vnet.ibm.com
Wed Oct 28 20:04:56 UTC 2015
On 28/10/2015 15:41, dhbarboza82 at gmail.com wrote:
> From: Daniel Henrique Barboza <dhbarboza82 at gmail.com>
>
> This patch adds the backend code to support live (and cold) migration
> in Kimchi.
>
> Signed-off-by: Daniel Henrique Barboza <dhbarboza82 at gmail.com>
> ---
> src/wok/plugins/kimchi/control/vms.py | 3 ++
> src/wok/plugins/kimchi/model/vms.py | 73 ++++++++++++++++++++++++++++++++++-
> 2 files changed, 75 insertions(+), 1 deletion(-)
>
> diff --git a/src/wok/plugins/kimchi/control/vms.py b/src/wok/plugins/kimchi/control/vms.py
> index 58d4b67..5e24538 100644
> --- a/src/wok/plugins/kimchi/control/vms.py
> +++ b/src/wok/plugins/kimchi/control/vms.py
> @@ -49,6 +49,9 @@ class VM(Resource):
> destructive=True)
> self.connect = self.generate_action_handler('connect')
> self.clone = self.generate_action_handler_task('clone')
> + self.migrate = self.generate_action_handler_task('migrate',
> + ['remote_host',
> + 'user'])
> self.suspend = self.generate_action_handler('suspend')
> self.resume = self.generate_action_handler('resume')
>
> diff --git a/src/wok/plugins/kimchi/model/vms.py b/src/wok/plugins/kimchi/model/vms.py
> index 60145d0..e90b5ed 100644
> --- a/src/wok/plugins/kimchi/model/vms.py
> +++ b/src/wok/plugins/kimchi/model/vms.py
> @@ -36,7 +36,7 @@ from wok.exception import NotFoundError, OperationFailed
> from wok.model.tasks import TaskModel
> from wok.rollbackcontext import RollbackContext
> from wok.utils import add_task, convert_data_size, get_next_clone_name
> -from wok.utils import import_class, run_setfacl_set_attr, wok_log
> +from wok.utils import import_class, run_setfacl_set_attr, run_command, wok_log
> from wok.xmlutils.utils import xpath_get_text, xml_item_update
> from wok.xmlutils.utils import dictize
>
> @@ -1294,6 +1294,77 @@ class VMModel(object):
> raise OperationFailed('KCHVM0040E', {'name': name,
> 'err': e.message})
>
> + def _check_if_host_not_localhost(self, remote_host):
> + hostname, _, returncode = run_command(['hostname'], 5, silent=True)
> +
Please, use the python API to get the system hostname
>>> import socket
>>> socket.gethostname()
'alinefm-ThinkPad-T440'
> + if returncode != 0:
> + raise OperationFailed("KCHVM0061E", {'host': remote_host})
> +
> + if remote_host in ['localhost', '127.0.0.1', hostname]:
> + raise OperationFailed("KCHVM0055E", {'host': remote_host})
> +
> + def _check_if_password_less_login_enabled(self, remote_host, user):
> + username_host = "%s@%s" % (user, remote_host)
> + ssh_cmd = ['ssh', '-oNumberOfPasswordPrompts=0',
> + '-oStrictHostKeyChecking=no', username_host,
> + 'echo', 'hello']
> + stdout, stderr, returncode = run_command(ssh_cmd, 5, silent=True)
> + if returncode != 0:
> + raise OperationFailed("KCHVM0056E",
> + {'host': remote_host, 'user': user})
> +
> + def _get_remote_libvirt_conn(self, remote_host,
> + user='root', transport='ssh'):
> + dest_uri = 'qemu+%s://%s@%s/system' % (transport, user, remote_host)
> + # TODO: verify why LibvirtConnection(dest_uri) does not work here
> + return libvirt.open(dest_uri)
> +
> + def migration_pre_check(self, remote_host, user):
> + self._check_if_host_not_localhost(remote_host)
> + self._check_if_password_less_login_enabled(remote_host, user)
> +
> + def migrate(self, name, remote_host, user='root'):
> + name = name.decode('utf-8')
> + remote_host = remote_host.decode('utf-8')
> +
> + self.migration_pre_check(remote_host, user)
> + dest_conn = self._get_remote_libvirt_conn(remote_host)
> +
> + params = {'name': name,
> + 'dest_conn': dest_conn}
> + task_id = add_task('/vms/%s/migrate' % name, self._migrate_task,
> + self.objstore, params)
> +
> + return self.task.lookup(task_id)
> +
> + def _migrate_task(self, cb, params):
> + name = params['name'].decode('utf-8')
> + dest_conn = params['dest_conn']
> +
> + cb('starting a migration')
> +
> + dom = self.get_vm(name, self.conn)
> + state = DOM_STATE_MAP[dom.info()[0]]
> +
> + flags = libvirt.VIR_MIGRATE_PEER2PEER
> + if state == 'shutoff':
> + flags |= (libvirt.VIR_MIGRATE_OFFLINE |
> + libvirt.VIR_MIGRATE_PERSIST_DEST)
> + elif state in ['running', 'paused']:
> + flags |= libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_TUNNELLED
> + if dom.isPersistent():
> + flags |= libvirt.VIR_MIGRATE_PERSIST_DEST
> + else:
> + raise OperationFailed("KCHVM0057E", {'name': name,
> + 'state': state})
> + try:
> + dom.migrate(dest_conn, flags)
> + except libvirt.libvirtError as e:
> + cb('Migrate failed', False)
> + raise OperationFailed('KCHVM0058E', {'err': e.message,
> + 'name': name})
> + cb('Migrate finished', True)
> +
Remember to close the libvirt connection 'dest_conn' to avoid problem
with memory leak. =)
> class VMScreenshotModel(object):
> def __init__(self, **kargs):
More information about the Kimchi-devel
mailing list