[Kimchi-devel] [PATCH 2/3] Live migration backend: control/vms and model/vms changes

Daniel Henrique Barboza dhbarboza82 at gmail.com
Tue Oct 27 13:37:11 UTC 2015



On 10/27/2015 08:38 AM, Paulo Ricardo Paz Vital wrote:
> On Mon, 2015-10-26 at 16:08 -0200, 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   | 68
>> ++++++++++++++++++++++++++++++++++-
>>   2 files changed, 70 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..5d242e8 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,72 @@ class VMModel(object):
>>               raise OperationFailed('KCHVM0040E', {'name': name,
>>                                                    'err': e.message})
>>
>> +    def _check_if_host_not_localhost(self, remote_host):
>> +        if remote_host in ['localhost', '127.0.0.1']:
>> +            raise OperationFailed("KCHVM0055E", {'host':
>> remote_host})
> Only a curiosity: Is it OK accept the hostname or IP address of my
> 'localhost', or only these two cases are not a good case to migrate?
Libvirt will freak out if you try to do a 'migrateinception' :P

This is why I've made this verification -  to ensure that the user 
doesn't pass the
IP/hostname of the same host Kimchi is running on by accident.


>   
>
>> +
>> +    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)
>> +
>>
>>   class VMScreenshotModel(object):
>>       def __init__(self, **kargs):




More information about the Kimchi-devel mailing list