Tested-by: Daniel Barboza <danielhb(a)linux.vnet.ibm.com>
It worked perfectly. Good job!
My only recommendation before pushing it upstream: please add the new
'remove_passless_login' parameter in documentation of the 'migrate' API
in docs/API.md. Don't forget to mention that the default behavior if no
password less setup is present between the hosts is to undo any
setup made by Kimchi.
Daniel
On 11/15/2016 02:22 PM, archus(a)linux.vnet.ibm.com wrote:
From: Archana Singh <archus(a)linux.vnet.ibm.com>
Changes to ensure that password less login is removed if its setup by kimchi.
It also provide option for user to specify if user want to keep
the password less login setup by kimchi, if not specified password
less login setup by kimchi will be removed.
However if password less login is not setup by kimchi,
code does not remove the password less login.
Signed-off-by: Archana Singh <archus(a)linux.vnet.ibm.com>
---
model/vms.py | 180 ++++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 129 insertions(+), 51 deletions(-)
diff --git a/model/vms.py b/model/vms.py
index bff7ed2..28aab76 100644
--- a/model/vms.py
+++ b/model/vms.py
@@ -1747,58 +1747,59 @@ class VMModel(object):
if password is None:
raise OperationFailed("KCHVM0056E",
{'host': remote_host, 'user':
user})
- else:
- self._set_password_less_login(remote_host, user, password)
+ return False
+ return True
- def _set_password_less_login(self, remote_host, user, passwd):
- home_dir = '/root' if user is 'root' else '/home/%s' %
user
+ def _read_id_rsa_pub_file(self, id_rsa_pub_file):
+ data = None
+ with open(id_rsa_pub_file, "r") as id_file:
+ data = id_file.read()
+ return data
- id_rsa_file = "%s/.ssh/id_rsa" % home_dir
- id_rsa_pub_file = id_rsa_file + '.pub'
- ssh_port = 22
- ssh_client = None
+ def _create_root_ssh_key_if_required(self, user, id_rsa_pub_file,
+ id_rsa_file):
+ if os.path.isfile(id_rsa_pub_file):
+ return
- def read_id_rsa_pub_file():
- data = None
- with open(id_rsa_pub_file, "r") as id_file:
- data = id_file.read()
- return data
+ with open("/dev/zero") as zero_input:
+ cmd = ['ssh-keygen', '-q', '-N', '',
'-f', id_rsa_file]
+ proc = subprocess.Popen(
+ cmd,
+ stdin=zero_input,
+ stdout=open(os.devnull, 'wb')
+ )
+ out, err = proc.communicate()
- def create_root_ssh_key_if_required():
- if os.path.isfile(id_rsa_pub_file):
- return
+ if not os.path.isfile(id_rsa_pub_file):
+ raise OperationFailed("KCHVM0070E")
- with open("/dev/zero") as zero_input:
- cmd = ['ssh-keygen', '-q', '-N', '',
'-f', id_rsa_file]
- proc = subprocess.Popen(
- cmd,
- stdin=zero_input,
- stdout=open(os.devnull, 'wb')
+ if user != 'root':
+ id_rsa_content = self._read_id_rsa_pub_file(id_rsa_pub_file)
+ updated_content = id_rsa_content.replace(
+ ' root@', ' %s@' % user
)
- out, err = proc.communicate()
+ with open(id_rsa_pub_file, 'w+') as f:
+ f.write(updated_content)
- if not os.path.isfile(id_rsa_pub_file):
- raise OperationFailed("KCHVM0070E")
+ user_uid = pwd.getpwnam(user).pw_uid
+ user_gid = pwd.getpwnam(user).pw_gid
+ os.chown(id_rsa_pub_file, user_uid, user_gid)
+ os.chown(id_rsa_file, user_uid, user_gid)
- if user is not 'root':
- id_rsa_content = read_id_rsa_pub_file()
- updated_content = id_rsa_content.replace(
- ' root@', ' %s@' % user
- )
- with open(id_rsa_pub_file, 'w+') as f:
- f.write(updated_content)
+ def _get_ssh_client(self, remote_host, user, passwd, ssh_port):
+ 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
- user_uid = pwd.getpwnam(user).pw_uid
- user_gid = pwd.getpwnam(user).pw_gid
- os.chown(id_rsa_pub_file, user_uid, user_gid)
- os.chown(id_rsa_file, user_uid, user_gid)
+ def _set_password_less_login(self, remote_host, user, passwd):
+ home_dir = '/root' if user == 'root' else '/home/%s' %
user
- 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
+ id_rsa_file = "%s/.ssh/id_rsa" % home_dir
+ id_rsa_pub_file = id_rsa_file + '.pub'
+ ssh_port = 22
+ ssh_client = None
def append_id_rsa_to_remote_authorized_keys(ssh_client, id_rsa_data):
sftp_client = ssh_client.open_sftp()
@@ -1824,9 +1825,11 @@ class VMModel(object):
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)
+ self._create_root_ssh_key_if_required(user, id_rsa_pub_file,
+ id_rsa_file)
+ id_rsa_data = self._read_id_rsa_pub_file(id_rsa_pub_file)
+ ssh_client = self._get_ssh_client(remote_host, user, passwd,
+ ssh_port)
append_id_rsa_to_remote_authorized_keys(
ssh_client,
id_rsa_data
@@ -1865,17 +1868,21 @@ class VMModel(object):
def migration_pre_check(self, remote_host, user, password):
self._check_if_host_not_localhost(remote_host)
- self._check_if_password_less_login_enabled(
+ default_passless_status = self._check_if_password_less_login_enabled(
remote_host,
user,
password
)
- self._check_remote_libvirt_conn(remote_host, user)
+ if not default_passless_status:
+ self._set_password_less_login(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)
+ return default_passless_status
+
def _check_if_path_exists_in_remote_host(self, path, remote_host, user):
username_host = "%s@%s" % (user, remote_host)
cmd = ['ssh', '-oStrictHostKeyChecking=no', username_host,
@@ -1957,15 +1964,22 @@ class VMModel(object):
user
)
- def migrate(self, name, remote_host, user=None, password=None):
+ def migrate(self, name, remote_host, user=None, password=None,
+ remove_passless_login=True):
name = name.decode('utf-8')
remote_host = remote_host.decode('utf-8')
if user is None:
user = 'root'
+ user = user.encode('utf-8')
+
+ default_passless_status = self.migration_pre_check(remote_host, user,
+ password)
- self.migration_pre_check(remote_host, user, password)
- dest_conn = self._get_remote_libvirt_conn(remote_host, user)
+ if default_passless_status:
+ remove_passless_login = False
+
+ dest_conn = self._get_remote_libvirt_conn(remote_host)
non_shared = self._check_if_nonshared_migration(
name,
@@ -1977,18 +1991,80 @@ class VMModel(object):
'dest_conn': dest_conn,
'non_shared': non_shared,
'remote_host': remote_host,
- 'user': user}
+ 'user': user,
+ 'password': password,
+ 'remove_passless_login': remove_passless_login}
task_id = AsyncTask('/plugins/kimchi/vms/%s/migrate' % name,
self._migrate_task, params).id
return self.task.lookup(task_id)
+ def _remove_password_less_login(self, remote_host, user, passwd):
+ home_dir = '/root' if user == 'root' else '/home/%s' %
user
+
+ id_rsa_file = "%s/.ssh/id_rsa" % home_dir
+ id_rsa_pub_file = id_rsa_file + '.pub'
+ ssh_port = 22
+ ssh_client = None
+
+ def remove_id_rsa_to_remote_authorized_keys(ssh_client, id_rsa_data):
+ sftp_client = ssh_client.open_sftp()
+ ssh_dir = '%s/.ssh' % home_dir
+
+ try:
+ sftp_client.chdir(ssh_dir)
+ except IOError:
+ raise OperationFailed(
+ "KCHVM0089E",
+ {'host': remote_host, 'user': user,
'sshdir': ssh_dir}
+ )
+ file_handler = sftp_client.file(
+ '%s/.ssh/authorized_keys' % home_dir,
+ mode='r',
+ bufsize=1
+ )
+ lines = file_handler.readlines()
+ try:
+ lines.remove(id_rsa_data)
+ except ValueError:
+ pass
+ file_handler = sftp_client.file(
+ '%s/.ssh/authorized_keys' % home_dir,
+ mode='w',
+ bufsize=1
+ )
+ file_handler.writelines(lines)
+ file_handler.flush()
+ file_handler.close()
+ sftp_client.close()
+
+ try:
+ self._create_root_ssh_key_if_required(user, id_rsa_pub_file,
+ id_rsa_file)
+ id_rsa_data = self._read_id_rsa_pub_file(id_rsa_pub_file)
+ ssh_client = self._get_ssh_client(remote_host, user, passwd,
+ ssh_port)
+ remove_id_rsa_to_remote_authorized_keys(
+ ssh_client,
+ id_rsa_data
+ )
+ except Exception, e:
+ raise OperationFailed(
+ "KCHVM0068E",
+ {'host': remote_host, 'user': user, 'error': e}
+ )
+ finally:
+ if ssh_client:
+ ssh_client.close()
+
def _migrate_task(self, cb, params):
name = params['name'].decode('utf-8')
dest_conn = params['dest_conn']
non_shared = params['non_shared']
remote_host = params['remote_host']
user = params['user']
+ password = params['password']
+ remove_passless_login = params['remove_passless_login']
cb('starting a migration')
@@ -2022,6 +2098,8 @@ class VMModel(object):
raise OperationFailed('KCHVM0058E', {'err': e.message,
'name': name})
finally:
+ if remove_passless_login:
+ self._remove_password_less_login(remote_host, user, password)
dest_conn.close()
cb('Migrate finished', True)