diff mbox

[KVM-AUTOTEST] support for remote migration

Message ID 1241446531.7676.52.camel@yogi-laptop (mailing list archive)
State New, archived
Headers show

Commit Message

yogi May 4, 2009, 2:15 p.m. UTC
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
diff mbox

Patch

 kvm_tests.py |    2 +-
 kvm_vm.py    |   54 +++++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 44 insertions(+), 12 deletions(-)


Signed-off-by: Yogananth Subramanian <anantyog@in.ibm.com>
---
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.