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 <jzupka@xxxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html