Hello everyone, I like to resubmit patch to add support for "remote migration" in kvm-autotest, based on Michael Goldish's suggestions. To use this patch the following seven parameters should be added to the existing migration test remote_dst = yes hostip = <localhost ip or name> remoteip = <remote host ip or name> remuser = root rempassword = <password> qemu_path_dst = <qemu binary path on remote host> image_dir_dst = <images dir on remote host> For example: - migrate: install setup type = migration vms += " dst" migration_test_command = help kill_vm_on_error = yes hostip = 192.168.1.2 remoteip = 192.168.1.3 remuser = root rempassword = 123456 remote_dst = yes qemu_path_dst = /tmp/kvm_autotest_root/qemu image_dir_dst = /tmp/kvm_autotest_root/images variants: The parameter "remote_dst = yes", indicates that the VM "dst" should be started on the remote host.If the parameter qemu_path_dst and image_dir_dst, it is assumed tht the qemu binary images path is same on both local and remote host. > Regarding remote_login: > > - Why should remote_login return a session when it gets an unexpected login prompt? If you get a login prompt doesn't that mean something went wrong? The username is always provided in the ssh command line, so we shouldn't expect to receive a login prompt -- or am I missing something? I am pretty confident this is true in the general case, but maybe it's different when ssh keys have been exchanged between the hosts. > > - I think it makes little sense to return a session object when you see a login prompt because that session will be useless. You can't send any commands to it because you don't have a shell prompt yet. Any command you send will be interpreted as a username, and will most likely be the wrong username. > > - When a guest is in the process of booting and we try to log into it, remote_login sometimes fails because it gets an unexpected login prompt. This is good, as far as I understand, because it means the guest isn't ready yet (still booting). The next time remote_login attempts to log in, it usually succeeds. If we consider an unexpected login prompt OK, we pass login attempts that actually should have failed (and the resulting sessions will be useless anyway). > I have removed this from the current patch, so now the remote_login function is unchanged.I will recheck my machine configuration and submit it as new patch if necessary. I had exchanged ssh keys between the hosts(both local and remote hosts), but the login sessions seem to terminates with "Got unexpected login prompt". > Other things: > > - If I understand correctly, remote migration will only work if the remote qemu binary path is exactly the same as the local one. Maybe we should receive a qemu path parameter that will allow for some flexibility. update the patch with this option by providing 2 new parameters qemu_path_dst and image_dir_dst > - In VM.make_qemu_command(), in the code that handles redirections, you add 'self.ssh_port = host_port'. I don't think this is correct because there can be multiple redirections, unrelated to SSH, so you certainly shouldn't assume that the only redirection is an SSH one. When you want the host port redirected to the guest's SSH port, you should use self.get_port(int(self.params.get("ssh_port"))). This will also work if for some reason 'ssh_port' changes while the guest is alive. yes,should not have done that. So also removed it from this patch > - It seems that the purpose of 'remote = dst' is to indicate to 'dst' that it should be started as a remote VM. The preferred way to do this is to pass something like 'remote_dst = yes' and then in VM.create() you can test for params.get("remote") == "yes". See "Addressing objects" in the wiki (http://www.linux-kvm.org/page/KVM-Autotest/Parameters#Addressing_objects_.28VMs.2C_images.2C_NICs_etc.29). > In general, any parameter you want to pass to a specific VM, you pass using <param>_<vmname> = <value>, e.g. 'mem_dst = 128', and then in VM.create() the parameter is accessible without the VM name extension (e.g. self.params.get("mem") will equal "128"). updated the patch with the above suggestion Thank you,for your suggestion Michael, they were very helpful(srry i took so long to reply,was traveling,so was not able to reply and resubmit the patch). Thx yogi
kvm_tests.py | 2 +- kvm_vm.py | 54 +++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 12 deletions(-) Signed-off-by: Yogananth Subramanian <anantyog@xxxxxxxxxx> --- diff -aurp kvm-autotest.orgi/client/tests/kvm_runtest_2//kvm_tests.py kvm-autotest/client/tests/kvm_runtest_2//kvm_tests.py --- kvm-autotest.orgi/client/tests/kvm_runtest_2//kvm_tests.py 2009-04-29 18:33:10.000000000 +0000 +++ kvm-autotest/client/tests/kvm_runtest_2//kvm_tests.py 2009-04-30 05:59:24.000000000 +0000 @@ -81,7 +81,7 @@ def run_migration(test, params, env): session.close() # Define the migration command - cmd = "migrate -d tcp:localhost:%d" % dest_vm.migration_port + cmd = "migrate -d tcp:%s:%d" % (dest_vm.hostip,dest_vm.migration_port) kvm_log.debug("Migration command: %s" % cmd) # Migrate diff -aurp kvm-autotest.orgi/client/tests/kvm_runtest_2//kvm_vm.py kvm-autotest/client/tests/kvm_runtest_2//kvm_vm.py --- kvm-autotest.orgi/client/tests/kvm_runtest_2//kvm_vm.py 2009-04-29 18:33:10.000000000 +0000 +++ kvm-autotest/client/tests/kvm_runtest_2//kvm_vm.py 2009-05-04 09:06:32.000000000 +0000 @@ -3,6 +3,7 @@ import time import socket import os +import re import kvm_utils import kvm_log @@ -105,6 +106,7 @@ class VM: self.qemu_path = qemu_path self.image_dir = image_dir self.iso_dir = iso_dir + self.remote = False def verify_process_identity(self): """Make sure .pid really points to the original qemu process. @@ -124,8 +126,6 @@ class VM: file.close() if not self.qemu_path in cmdline: return False - if not self.monitor_file_name in cmdline: - return False return True def make_qemu_command(self, name=None, params=None, qemu_path=None, image_dir=None, iso_dir=None): @@ -173,7 +173,6 @@ class VM: qemu_cmd = qemu_path qemu_cmd += " -name '%s'" % name - qemu_cmd += " -monitor unix:%s,server,nowait" % self.monitor_file_name for image_name in kvm_utils.get_sub_dict_names(params, "images"): image_params = kvm_utils.get_sub_dict(params, image_name) @@ -254,6 +253,19 @@ class VM: image_dir = self.image_dir iso_dir = self.iso_dir + # If VM is remote, set hostip to ip of the remote machine + # If VM is local set hostip to localhost or hostip param + if params.get("remote") == "yes": + self.remote = True + self.hostip = params.get("remoteip") + self.qemu_path = params.get("qemu_path",qemu_path) + qemu_path = self.qemu_path + self.image_dir = params.get("image_dir",image_dir) + image_dir = self.image_dir + else: + self.remote = False + self.hostip = params.get("hostip","localhost") + # Verify the md5sum of the ISO image iso = params.get("cdrom") if iso: @@ -310,8 +322,28 @@ class VM: # Add -incoming option to the qemu command qemu_command += " -incoming tcp:0:%d" % self.migration_port - kvm_log.debug("Running qemu command:\n%s" % qemu_command) - (status, pid, output) = kvm_utils.run_bg(qemu_command, None, kvm_log.debug, "(qemu) ") + self.monitor_port = kvm_utils.find_free_port(5400, 6000) + qemu_command +=" -monitor tcp:0:%d,server,nowait" % self.monitor_port + + # If the VM is remote, get the username and password of remote host and lanch qemu + # command on the remote machine. + if self.remote: + remuser = params.get("remuser") + rempassword = params.get("rempassword") + sub = kvm_utils.ssh(self.hostip,22,remuser,rempassword,self.params.get("ssh_prompt", "[\#\$]")) + qemu_command +=" &" + kvm_log.debug("Running qemu command:\n%s" % qemu_command) + sub.sendline(qemu_command) + + (status,output) = sub.read_up_to_prompt() + if "Exit " in output: + status = int(re.findall("Exit\s(\d+)",output)[0]) + else: + pid = int(re.findall(".*] (\d+)",output)[0]) + status = 0 + else: + kvm_log.debug("Running qemu command:\n%s" % qemu_command) + (status, pid, output) = kvm_utils.run_bg(qemu_command, None, kvm_log.debug, "(qemu) ") if status: kvm_log.debug("qemu exited with status %d" % status) @@ -363,9 +395,8 @@ class VM: # Connect to monitor kvm_log.debug("Sending monitor command: %s" % command) try: - s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - s.setblocking(False) - s.connect(self.monitor_file_name) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((self.hostip,self.monitor_port)) except: kvm_log.debug("Could not connect to monitor socket") return (1, "") @@ -442,8 +473,9 @@ class VM: def is_alive(self): """Return True iff the VM's monitor is responsive.""" # Check if the process exists - if not kvm_utils.pid_exists(self.pid): - return False + if not self.remote: + if not kvm_utils.pid_exists(self.pid): + return False # Try sending a monitor command (status, output) = self.send_monitor_cmd("help") if status: @@ -468,7 +500,7 @@ class VM: address of its own). Otherwise return the guest's IP address. """ # Currently redirection is always used, so return 'localhost' - return "localhost" + return self.hostip def get_port(self, port): """Return the port in host space corresponding to port in guest space.