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 <anant...@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.

Reply via email to