[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