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

Daniel Henrique Barboza dhbarboza82 at gmail.com
Tue Oct 27 17:23:39 UTC 2015



On 10/27/2015 03:11 PM, Paulo Ricardo Paz Vital wrote:
> On Tue, 2015-10-27 at 11:37 -0200, Daniel Henrique Barboza wrote:
>> 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.
>>
>>
> So, if I'm running Kimchi in a machine called 'bla.br.ibm.com' and use
> this hostname to realize a migration, libvirt will freakout, right?!?!
>
> I suggest to check not only the name 'localhost' and IP '127.0.0.1',
> but also the IP address and real hostname of the machine.

hahahaha you're right

I'll fix it in v2

>
>>>    
>>>
>>>> +
>>>> +    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