Test create socket get descriptor from socket and migrate through
the descriptor.

This test allow migration only of one machine at once.

Signed-off-by: Jiří Župka <jzu...@redhat.com>
---
 client/tests/kvm/tests/migration_multi_host_fd.py |  124 +++++++++++++++++++++
 client/virt/virt_utils.py                         |   27 +++--
 2 files changed, 141 insertions(+), 10 deletions(-)
 create mode 100644 client/tests/kvm/tests/migration_multi_host_fd.py

diff --git a/client/tests/kvm/tests/migration_multi_host_fd.py 
b/client/tests/kvm/tests/migration_multi_host_fd.py
new file mode 100644
index 0000000..6f3c72b
--- /dev/null
+++ b/client/tests/kvm/tests/migration_multi_host_fd.py
@@ -0,0 +1,124 @@
+import logging, socket, time, errno, os, fcntl
+from autotest.client.virt import virt_utils
+from autotest.client.shared.syncdata import SyncData
+
+def run_migration_multi_host_fd(test, params, env):
+    """
+    KVM multi-host migration over fd test:
+
+    Migrate machine over socket's fd. Migration execution progress is
+    described in documentation for migrate method in class MultihostMigration.
+    This test allows migrate only one machine at once.
+
+    @param test: kvm test object.
+    @param params: Dictionary with test parameters.
+    @param env: Dictionary with the test environment.
+    """
+    class TestMultihostMigrationFd(virt_utils.MultihostMigration):
+        def __init__(self, test, params, env):
+            super(TestMultihostMigrationFd, self).__init__(test, params, env)
+
+        def migrate_vms_src(self, mig_data):
+            """
+            Migrate vms source.
+
+            @param mig_Data: Data for migration.
+
+            For change way how machine migrates is necessary
+            re implement this method.
+            """
+            logging.info("Start migrating now...")
+            vm = mig_data.vms[0]
+            vm.migrate(dest_host=mig_data.dst,
+                       protocol="fd",
+                       fd_src=mig_data.params['migration_fd'])
+
+        def _check_vms_source(self, mig_data):
+            for vm in mig_data.vms:
+                vm.wait_for_login(timeout=self.login_timeout)
+            self._hosts_barrier(mig_data.hosts, mig_data.mig_id,
+                                'prepare_VMS', 60)
+
+        def _check_vms_dest(self, mig_data):
+            self._hosts_barrier(mig_data.hosts, mig_data.mig_id,
+                                 'prepare_VMS', 120)
+            os.close(mig_data.params['migration_fd'])
+
+        def _connect_to_server(self, host, port, timeout=60):
+            """
+            Connect to network server.
+            """
+            endtime = time.time() + timeout
+            sock = None
+            while endtime > time.time():
+                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                try:
+                    sock.connect((host, port))
+                    break
+                except socket.error, err:
+                    (code, _) = err
+                    if (code != errno.ECONNREFUSED):
+                        raise
+                    time.sleep(1)
+
+            return sock
+
+        def _create_server(self, port, timeout=60):
+            """
+            Create network server.
+            """
+            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            sock.settimeout(timeout)
+            sock.bind(('', port))
+            sock.listen(1)
+            return sock
+
+        def migration_scenario(self):
+            srchost = self.params.get("hosts")[0]
+            dsthost = self.params.get("hosts")[1]
+            mig_port = None
+
+            if params.get("hostid") == self.master_id():
+                mig_port = virt_utils.find_free_port(5200, 6000)
+
+            sync = SyncData(self.master_id(), self.hostid,
+                             self.params.get("hosts"),
+                             {'src': srchost, 'dst': dsthost,
+                              'port': "ports"}, self.sync_server)
+            mig_port = sync.sync(mig_port, timeout=120)
+            mig_port = mig_port[srchost]
+            logging.debug("Migration port %d" % (mig_port))
+
+            if params.get("hostid") != self.master_id():
+                s = self._connect_to_server(srchost, mig_port)
+                try:
+                    fd = s.fileno()
+                    logging.debug("File descrtiptor %d used for"
+                                  " migration." % (fd))
+
+                    self.migrate_wait(["vm1"], srchost, dsthost, mig_mode="fd",
+                                      params_append={"migration_fd": fd})
+                finally:
+                    s.close()
+            else:
+                s = self._create_server(mig_port)
+                try:
+                    conn, _ = s.accept()
+                    fd = conn.fileno()
+                    logging.debug("File descrtiptor %d used for"
+                                  " migration." % (fd))
+
+                    #Prohibits descriptor inheritance.
+                    flags = fcntl.fcntl(fd, fcntl.F_GETFD)
+                    flags |= fcntl.FD_CLOEXEC
+                    fcntl.fcntl(fd, fcntl.F_SETFD, flags)
+
+                    self.migrate_wait(["vm1"], srchost, dsthost, mig_mode="fd",
+                                      params_append={"migration_fd": fd})
+                    conn.close()
+                finally:
+                    s.close()
+
+    mig = TestMultihostMigrationFd(test, params, env)
+    mig.run()
diff --git a/client/virt/virt_utils.py b/client/virt/virt_utils.py
index 079bb87..2da4864 100644
--- a/client/virt/virt_utils.py
+++ b/client/virt/virt_utils.py
@@ -3790,11 +3790,12 @@ def postprocess_images(bindir, params):
 
 
 class MigrationData(object):
-    def __init__(self, params, srchost, dsthost, vms_name):
+    def __init__(self, params, srchost, dsthost, vms_name, params_append):
         """
         Class that contains data needed for one migration.
         """
-        self.params = params
+        self.params = params.copy()
+        self.params.update(params_append)
 
         self.source = False
         if params.get("hostid") == srchost:
@@ -4106,7 +4107,7 @@ class MultihostMigration(object):
 
 
     def migrate(self, vms_name, srchost, dsthost, start_work=None,
-                check_work=None):
+                check_work=None, mig_mode="tcp", params_append=None):
         """
         Migrate machine from srchost to dsthost. It executes start_work on
         source machine before migration and executes check_work on dsthost
@@ -4134,19 +4135,22 @@ class MultihostMigration(object):
         @param dsthost: dst host id.
         @param start_work: Function started before migration.
         @param check_work: Function started after migration.
+        @param mig_mode: Migration mode.
+        @param params_append: Append params to self.params only for migration.
         """
         def migrate_wrap(vms_name, srchost, dsthost, start_work=None,
-                check_work=None):
+                check_work=None, params_append=None):
             logging.info("Starting migrate vms %s from host %s to %s" %
                          (vms_name, srchost, dsthost))
             error = None
-            mig_data = MigrationData(self.params, srchost, dsthost, vms_name)
+            mig_data = MigrationData(self.params, srchost, dsthost,
+                                     vms_name, params_append)
             try:
                 try:
                     if mig_data.is_src():
                         self.prepare_for_migration(mig_data, None)
                     elif self.hostid == dsthost:
-                        self.prepare_for_migration(mig_data, "tcp")
+                        self.prepare_for_migration(mig_data, mig_mode)
                     else:
                         return
 
@@ -4178,7 +4182,8 @@ class MultihostMigration(object):
                                         self.finish_timeout)
 
         def wait_wrap(vms_name, srchost, dsthost):
-            mig_data = MigrationData(self.params, srchost, dsthost, vms_name)
+            mig_data = MigrationData(self.params, srchost, dsthost, vms_name,
+                                     None)
             timeout = (self.login_timeout + self.mig_timeout +
                        self.finish_timeout)
 
@@ -4190,7 +4195,8 @@ class MultihostMigration(object):
                                                                 srchost,
                                                                 dsthost,
                                                                 start_work,
-                                                                check_work))
+                                                                check_work,
+                                                                params_append))
         else:
             mig_thread = utils.InterruptedThread(wait_wrap, (vms_name,
                                                              srchost,
@@ -4200,7 +4206,7 @@ class MultihostMigration(object):
 
 
     def migrate_wait(self, vms_name, srchost, dsthost, start_work=None,
-                     check_work=None):
+                      check_work=None, mig_mode="tcp", params_append=None):
         """
         Migrate machine from srchost to dsthost and wait for finish.
         It executes start_work on source machine before migration and executes
@@ -4213,7 +4219,8 @@ class MultihostMigration(object):
         @param check_work: Function which is started after
                            done of migration.
         """
-        self.migrate(vms_name, srchost, dsthost, start_work, check_work).join()
+        self.migrate(vms_name, srchost, dsthost, start_work, check_work,
+                     mig_mode, params_append).join()
 
 
     def cleanup(self):
-- 
1.7.7.6

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to