[Kimchi-devel] [PATCH 3/4] Live migration: model changes for the new features

Paulo Ricardo Paz Vital pvital at linux.vnet.ibm.com
Tue Nov 17 11:24:39 UTC 2015


Reviewed-By: Paulo Vital <pvital at linux.vnet.ibm.com>

On Mon, 2015-11-16 at 21:04 -0200, dhbarboza82 at gmail.com wrote:
> From: Daniel Henrique Barboza <dhbarboza82 at gmail.com>
> 
> - added extra pre migration checks to ensure that the
> migration process will not fail due to a predictable
> error
> 
> - added the capability of set up a password-less root
> login to a remote host if given a valid user/password.
> 
> Signed-off-by: Daniel Henrique Barboza <dhbarboza82 at gmail.com>
> ---
>  src/wok/plugins/kimchi/model/vms.py | 177
> +++++++++++++++++++++++++++++++++---
>  1 file changed, 166 insertions(+), 11 deletions(-)
> 
> diff --git a/src/wok/plugins/kimchi/model/vms.py
> b/src/wok/plugins/kimchi/model/vms.py
> index c98558c..48e99a3 100644
> --- a/src/wok/plugins/kimchi/model/vms.py
> +++ b/src/wok/plugins/kimchi/model/vms.py
> @@ -21,8 +21,11 @@ import copy
>  import libvirt
>  import lxml.etree as ET
>  import os
> +import paramiko
> +import platform
>  import random
>  import socket
> +import subprocess
>  import string
>  import threading
>  import time
> @@ -1323,15 +1326,156 @@ class VMModel(object):
>          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)
> +    def _check_if_migrating_same_arch_hypervisor(self, remote_host,
> +                                                 user='root'):
> +        remote_conn = None
> +        try:
> +            remote_conn = self._get_remote_libvirt_conn(
> +                remote_host,
> +                user
> +            )
> +            source_hyp = self.conn.get().getType()
> +            dest_hyp = remote_conn.getType()
> +            if source_hyp != dest_hyp:
> +                raise OperationFailed(
> +                    "KCHVM0065E",
> +                    {
> +                        'host': remote_host,
> +                        'srchyp': source_hyp,
> +                        'desthyp': dest_hyp
> +                    }
> +                )
> +            source_arch = self.conn.get().getInfo()[0]
> +            dest_arch = remote_conn.getInfo()[0]
> +            if source_arch != dest_arch:
> +                raise OperationFailed(
> +                    "KCHVM0064E",
> +                    {
> +                        'host': remote_host,
> +                        'srcarch': source_arch,
> +                        'destarch': dest_arch
> +                    }
> +                )
> +        except Exception, e:
> +            raise OperationFailed("KCHVM0066E", {'error':
> e.message})
> +
> +        finally:
> +            if remote_conn:
> +                remote_conn.close()
> +
> +    def _check_ppc64_subcores_per_core(self, remote_host, user):
> +        """
> +        Output expected from command-line:
> +
> +        $ ppc64_cpu --subcores-per-core
> +        Subcores per core: N
> +        """
> +
> +        def _get_local_ppc64_subpercore():
> +            local_cmd = ['ppc64_cpu', '--subcores-per-core']
> +            out, err, returncode = run_command(local_cmd, 5,
> silent=True)
> +            if returncode != 0:
> +                return None
> +            local_sub_per_core = out.strip()[-1]
> +            return local_sub_per_core
> +
> +        def _get_remote_ppc64_subpercore(remote_host, user):
> +            username_host = "%s@%s" % ('root', remote_host)
> +            ssh_cmd = ['ssh', '-oNumberOfPasswordPrompts=0',
> +                       '-oStrictHostKeyChecking=no', username_host,
> +                       'ppc64_cpu', '--subcores-per-core']
> +            out, err, returncode = run_command(ssh_cmd, 5,
> silent=True)
> +            if returncode != 0:
> +                return None
> +            remote_sub_per_core = out.strip()[-1]
> +            return remote_sub_per_core
> +
> +        local_sub_per_core = _get_local_ppc64_subpercore()
> +        if local_sub_per_core is None:
> +            return
> +
> +        remote_sub_per_core =
> _get_remote_ppc64_subpercore(remote_host, user)
> +
> +        if local_sub_per_core != remote_sub_per_core:
> +            raise OperationFailed("KCHVM0067E", {'host':
> remote_host})
> +
> +    def _check_if_password_less_login_enabled(self, remote_host,
> +                                              user, password):
> +        username_host = "%s@%s" % ('root', 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})
> +            if password is None:
> +                raise OperationFailed("KCHVM0056E",
> +                                      {'host': remote_host, 'user':
> 'root'})
> +            else:
> +                self._set_password_less_login(remote_host, user,
> password)
> +
> +    def _set_password_less_login(self, remote_host, user, passwd):
> +        id_rsa_file = "/root/.ssh/id_rsa.pub"
> +        ssh_port = 22
> +        ssh_client = None
> +
> +        def create_root_ssh_key_if_required():
> +            if not os.path.isfile(id_rsa_file):
> +
> +                with open("/dev/zero") as zero_input:
> +                    cmd = ['ssh-keygen', '-q', '-N', '']
> +                    proc = subprocess.Popen(
> +                        cmd,
> +                        stdin=zero_input,
> +                        stdout=open(os.devnull, 'wb')
> +                    )
> +                    out, err = proc.communicate()
> +                    if not os.path.isfile(id_rsa_file):
> +                        raise OperationFailed("KCHVM0070E")
> +
> +        def read_id_rsa_pub_file():
> +            data = None
> +            with open(id_rsa_file, "r") as id_file:
> +                data = id_file.read()
> +            return data
> +
> +        def get_ssh_client(remote_host, user, passwd):
> +            ssh_client = paramiko.SSHClient()
> +            ssh_client.set_missing_host_key_policy(paramiko.AutoAddP
> olicy())
> +            ssh_client.connect(remote_host, ssh_port, username=user,
> +                               password=passwd, timeout=4)
> +            return ssh_client
> +
> +        def append_id_rsa_to_remote_authorized_keys(ssh_client,
> id_rsa_data):
> +            sftp_client = ssh_client.open_sftp()
> +
> +            file_handler = sftp_client.file(
> +                '/root/.ssh/authorized_keys',
> +                mode='a',
> +                bufsize=1
> +            )
> +            file_handler.write(id_rsa_data)
> +            file_handler.flush()
> +            file_handler.close()
> +
> +            sftp_client.close()
> +
> +        try:
> +            create_root_ssh_key_if_required()
> +            id_rsa_data = read_id_rsa_pub_file()
> +            ssh_client = get_ssh_client(remote_host, user, passwd)
> +            append_id_rsa_to_remote_authorized_keys(
> +                ssh_client,
> +                id_rsa_data
> +            )
> +        except Exception, e:
> +            raise OperationFailed(
> +                "KCHVM0068E",
> +                {'host': remote_host, 'user': user, 'error':
> e.message}
> +            )
> +
> +        finally:
> +            if ssh_client:
> +                ssh_client.close()
> 
>      def _get_remote_libvirt_conn(self, remote_host,
>                                   user='root', transport='ssh'):
> @@ -1339,12 +1483,20 @@ class VMModel(object):
>          # TODO: verify why LibvirtConnection(dest_uri) does not work
> here
>          return libvirt.open(dest_uri)
> 
> -    def migration_pre_check(self, remote_host, user):
> +    def migration_pre_check(self, remote_host, user, password):
>          self._check_if_host_not_localhost(remote_host)
> -        self._check_if_password_less_login_enabled(remote_host,
> user)
> +        self._check_if_password_less_login_enabled(
> +           remote_host,
> +           user,
> +           password
> +        )
> +        self._check_if_migrating_same_arch_hypervisor(remote_host,
> user)
> +
> +        if platform.machine() in ['ppc64', 'ppc64le']:
> +            self._check_ppc64_subcores_per_core(remote_host, user)
> 
>      def _check_if_path_exists_in_remote_host(self, path,
> remote_host, user):
> -        username_host = "%s@%s" % (user, remote_host)
> +        username_host = "%s@%s" % ('root', remote_host)
>          cmd = ['ssh', '-oStrictHostKeyChecking=no', username_host,
>                 'test', '-f', path]
>          _, _, returncode = run_command(cmd, 5, silent=True)
> @@ -1365,7 +1517,7 @@ class VMModel(object):
>          return False
> 
>      def _create_remote_path(self, path, remote_host, user):
> -        username_host = "%s@%s" % (user, remote_host)
> +        username_host = "%s@%s" % ('root', remote_host)
>          cmd = ['ssh', '-oStrictHostKeyChecking=no', username_host,
>                 'touch', path]
>          _, _, returncode = run_command(cmd, 5, silent=True)
> @@ -1387,7 +1539,7 @@ class VMModel(object):
>              )
> 
>      def _create_remote_disk(self, disk_info, remote_host, user):
> -        username_host = "%s@%s" % (user, remote_host)
> +        username_host = "%s@%s" % ('root', remote_host)
>          disk_fmt = disk_info.get('format')
>          disk_path = disk_info.get('path')
>          disk_size = self._get_img_size(disk_path)
> @@ -1424,11 +1576,14 @@ class VMModel(object):
>                          user
>                      )
> 
> -    def migrate(self, name, remote_host, user='root'):
> +    def migrate(self, name, remote_host, user=None, password=None):
>          name = name.decode('utf-8')
>          remote_host = remote_host.decode('utf-8')
> 
> -        self.migration_pre_check(remote_host, user)
> +        if user is None:
> +            user = 'root'
> +
> +        self.migration_pre_check(remote_host, user, password)
>          dest_conn = self._get_remote_libvirt_conn(remote_host)
> 
>          non_shared = self._check_if_nonshared_migration(




More information about the Kimchi-devel mailing list