[Kimchi-devel] [PATCH 3/4] Live migration: model changes for the new features
dhbarboza82 at gmail.com
dhbarboza82 at gmail.com
Mon Nov 16 23:04:46 UTC 2015
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.AutoAddPolicy())
+ 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(
--
2.4.3
More information about the Kimchi-devel
mailing list