[PATCH v5 2/3] Acceptance test: provides new functions
Provides new functions related to the rdma migration test Adds functions to check if service RDMA is enabled and gets the ip address on the interface where it was configured Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 45 +++ 1 file changed, 45 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index e4c39b85a1..1c3a684395 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -11,12 +11,57 @@ import tempfile +import json from avocado_qemu import Test from avocado import skipUnless from avocado.utils import network from avocado.utils import wait from avocado.utils.path import find_command +from avocado.utils.network.interfaces import NetworkInterface +from avocado.utils.network.hosts import LocalHost +from avocado.utils import service +from avocado.utils import process + + +def get_rdma_status(): +"""Verify the status of RDMA service. + +return: True if rdma service is enabled, False otherwise. +""" +rdma_stat = service.ServiceManager() +return bool(rdma_stat.status('rdma')) + +def get_interface_rdma(): +"""Get the interface name where RDMA is configured. + +return: The interface name or False if none is found +""" +cmd = 'rdma link show -j' +out = json.loads(process.getoutput(cmd)) +try: +for i in out: +if i['state'] == 'ACTIVE': +return i['netdev'] +except KeyError: +pass +return False + +def get_ip_rdma(interface): +"""Get the IP address on a specific interface. + +:param interface: Network interface name +:return: IP addresses as a list, otherwise will return False +""" +local = LocalHost() +network_in = NetworkInterface(interface, local) +try: +ip = network_in.get_ipaddrs() +if ip: +return ip +except: +pass +return False class Migration(Test): -- 2.21.1
[PATCH v5 3/3] Acceptance test: provides to use RDMA transport for migration test
Adds test for RDMA migration check Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 12 1 file changed, 12 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index 1c3a684395..99563ae850 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -120,3 +120,15 @@ class Migration(Test): """ free_port = self._get_free_port() dest_uri = 'exec:nc -l localhost %u' % free_port + +@skipUnless(get_rdma_status(), 'RDMA service is disabled or not installed') +@skipUnless(get_interface_rdma(), 'RDMA interface not configured') +def test_migration_with_rdma_localhost(self): +iface = get_interface_rdma() +ip = get_ip_rdma(iface) +if ip: +free_port = self._get_free_port(address=ip[0]) +else: +self.cancel("Ip address doesn't configured properly on interface:%s" % iface) +dest_uri = 'rdma:%s:%u' % (ip, free_port) +self.do_migrate(dest_uri) -- 2.21.1
[PATCH v5 1/3] Acceptance test: adds param 'address' in _get_free_port
In the migration test function _get_free_port works only for localhost, but in the case to use migration through an RDMA we need to get a free port on the configured network RDMA-interface. This patch is the start for another migration option Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a8367ca023..e4c39b85a1 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -52,8 +52,8 @@ class Migration(Test): source_vm.qmp('migrate', uri=src_uri) self.assert_migration(source_vm, dest_vm) -def _get_free_port(self): -port = network.find_free_port() +def _get_free_port(self, address='localhost'): +port = network.find_free_port(address=address) if port is None: self.cancel('Failed to find a free port') return port -- 2.21.1
[PATCH v5 0/3] Acceptance test: Extension of migration tests
This series adds a new migration test through RDMA. To correct uses of migration need to add a new function to work with RDMA service. And as a part of migration tests, the series makes small updates to EXEC migration and to _get_free_port function V2: - improves commit message in Acceptance test: adds param 'address' in _get_free_port - provides import check for netifaces library - makes fix to _get_ip_rdma function - adds skip to test if not upload python module V3: - removes unrelated changes - updates functions with new avocado features V4: - moves RDMA's functions outside the Migration class V5: - improvement to comments - updates to functions Oksana Vohchana (3): Acceptance test: adds param 'address' in _get_free_port Acceptance test: provides new functions Acceptance test: provides to use RDMA transport for migration test tests/acceptance/migration.py | 61 +-- 1 file changed, 59 insertions(+), 2 deletions(-) -- 2.21.1
[PATCH] Acceptance test: Fix to EXEC migration
The exec migration test isn't run a whole test scenario. This patch fixes it Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a8367ca023..0365289cda 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -70,8 +70,8 @@ class Migration(Test): @skipUnless(find_command('nc', default=False), "'nc' command not found") def test_migration_with_exec(self): -""" -The test works for both netcat-traditional and netcat-openbsd packages -""" +"""The test works for both netcat-traditional and netcat-openbsd packages.""" free_port = self._get_free_port() dest_uri = 'exec:nc -l localhost %u' % free_port +src_uri = 'exec:nc localhost %u' % free_port +self.do_migrate(dest_uri, src_uri) -- 2.21.1
[PATCH v4 1/3] Acceptance test: adds param 'address' in _get_free_port
In the migration test function _get_free_port works only for localhost, but in the case to use migration through an RDMA we need to get a free port on the configured network RDMA-interface. This patch is the start for another migration option Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a8367ca023..e4c39b85a1 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -52,8 +52,8 @@ class Migration(Test): source_vm.qmp('migrate', uri=src_uri) self.assert_migration(source_vm, dest_vm) -def _get_free_port(self): -port = network.find_free_port() +def _get_free_port(self, address='localhost'): +port = network.find_free_port(address=address) if port is None: self.cancel('Failed to find a free port') return port -- 2.21.1
[PATCH v4 3/3] Acceptance test: provides to use RDMA transport for migration test
Adds test for RDMA migration check Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 12 1 file changed, 12 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index 59144f18fd..c96da1dd4b 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -107,3 +107,15 @@ class Migration(Test): """ free_port = self._get_free_port() dest_uri = 'exec:nc -l localhost %u' % free_port + +@skipUnless(_if_rdma_enable(), 'Unit rdma.service could not be found') +@skipUnless(_get_interface_rdma(), 'RDMA service or interface not configured') +def test_migration_with_rdma_localhost(self): +iface = _get_interface_rdma() +ip = _get_ip_rdma(iface) +if ip: +free_port = self._get_free_port(address=ip) +else: +self.cancel("Ip address doesn't configured properly on interface:%s" % iface) +dest_uri = 'rdma:%s:%u' % (ip, free_port) +self.do_migrate(dest_uri) -- 2.21.1
[PATCH v4 2/3] Acceptance test: provides new functions
Provides new functions related to the rdma migration test Adds functions to check if service RDMA is enabled and gets the ip address on the interface where it was configured Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 32 1 file changed, 32 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index e4c39b85a1..59144f18fd 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -11,12 +11,44 @@ import tempfile +import json from avocado_qemu import Test from avocado import skipUnless from avocado.utils import network from avocado.utils import wait from avocado.utils.path import find_command +from avocado.utils.network.interfaces import NetworkInterface +from avocado.utils.network.hosts import LocalHost +from avocado.utils import service +from avocado.utils import process + + +def _if_rdma_enable(): +rdma_stat = service.ServiceManager() +return bool(rdma_stat.status('rdma')) + +def _get_interface_rdma(): +cmd = 'rdma link show -j' +out = json.loads(process.getoutput(cmd)) +try: +for i in out: +if i['state'] == 'ACTIVE': +return i['netdev'] +except KeyError: +return False +return False + +def _get_ip_rdma(interface): +local = LocalHost() +network_in = NetworkInterface(interface, local) +try: +ip = network_in._get_interface_details() +if ip: +return ip[0]['addr_info'][0]['local'] +except (KeyError, process.CmdError): +return False +return False class Migration(Test): -- 2.21.1
[PATCH v4 0/3] Acceptance test: Extension of migration tests
This series adds a new migration test through RDMA. To correct uses of migration need to add a new function to work with RDMA service. And as a part of migration tests, the series makes small updates to EXEC migration and to _get_free_port function V2: - improves commit message in Acceptance test: adds param 'address' in _get_free_port - provides import check for netifaces library - makes fix to _get_ip_rdma function - adds skip to test if not upload python module V3: - removes unrelated changes - updates functions with new avocado features V4: - moves RDMA's functions outside the Migration class Oksana Vohchana (3): Acceptance test: adds param 'address' in _get_free_port Acceptance test: provides new functions Acceptance test: provides to use RDMA transport for migration test tests/acceptance/migration.py | 48 +-- 1 file changed, 46 insertions(+), 2 deletions(-) -- 2.21.1
[PATCH v3 3/3] Acceptance test: provides to use RDMA transport for migration test
Adds test for RDMA migration check Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 12 1 file changed, 12 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a783f3915b..c8673114a9 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -105,3 +105,15 @@ class Migration(Test): """ free_port = self._get_free_port() dest_uri = 'exec:nc -l localhost %u' % free_port + +@skipUnless(_if_rdma_enable(None), "Unit rdma.service could not be found") +@skipUnless(_get_interface_rdma(None), 'RDMA service or interface not configured') +def test_migration_with_rdma_localhost(self): +iface = self._get_interface_rdma() +ip = self._get_ip_rdma(iface) +if ip: +free_port = self._get_free_port(address=ip) +else: +self.cancel("Ip address isn't configured") +dest_uri = 'rdma:%s:%u' % (ip, free_port) +self.do_migrate(dest_uri) -- 2.21.1
[PATCH v3 1/3] Acceptance test: adds param 'address' in _get_free_port
In the migration test function _get_free_port works only for localhost, but in the case to use migration through an RDMA we need to get a free port on the configured network RDMA-interface. This patch is the start for another migration option Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a8367ca023..e4c39b85a1 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -52,8 +52,8 @@ class Migration(Test): source_vm.qmp('migrate', uri=src_uri) self.assert_migration(source_vm, dest_vm) -def _get_free_port(self): -port = network.find_free_port() +def _get_free_port(self, address='localhost'): +port = network.find_free_port(address=address) if port is None: self.cancel('Failed to find a free port') return port -- 2.21.1
[PATCH v3 2/3] Acceptance test: provides new functions
Provides new functions related to the rdma migration test Adds functions to check if service RDMA is enabled and gets the ip address on the interface where it was configured Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 30 ++ 1 file changed, 30 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index e4c39b85a1..a783f3915b 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -11,12 +11,17 @@ import tempfile +import json from avocado_qemu import Test from avocado import skipUnless from avocado.utils import network from avocado.utils import wait from avocado.utils.path import find_command +from avocado.utils.network.interfaces import NetworkInterface +from avocado.utils.network.hosts import LocalHost +from avocado.utils import service +from avocado.utils import process class Migration(Test): @@ -58,6 +63,31 @@ class Migration(Test): self.cancel('Failed to find a free port') return port +def _if_rdma_enable(self): +rdma_stat = service.ServiceManager() +rdma = rdma_stat.status('rdma') +return rdma + +def _get_interface_rdma(self): +cmd = 'rdma link show -j' +out = json.loads(process.getoutput(cmd)) +try: +for i in out: +if i['state'] == 'ACTIVE': +return i['netdev'] +except KeyError: +return None + +def _get_ip_rdma(self, interface): +local = LocalHost() +network_in = NetworkInterface(interface, local) +try: +ip = network_in._get_interface_details() +if ip: +return ip[0]['addr_info'][0]['local'] +except: +self.cancel("Incorrect interface configuration or device name") + def test_migration_with_tcp_localhost(self): dest_uri = 'tcp:localhost:%u' % self._get_free_port() -- 2.21.1
[PATCH v3 0/3] Acceptance test: Extension of migration tests
This series adds a new migration test through RDMA. To correct uses of migration need to add a new function to work with RDMA service. And as a part of migration tests, the series makes small updates to EXEC migration and to _get_free_port function V2: - improves commit message in Acceptance test: adds param 'address' in _get_free_port - provides import check for netifaces library - makes fix to _get_ip_rdma function - adds skip to test if not upload python module V3: - removes unrelated changes - updates functions with new avocado features Oksana Vohchana (3): Acceptance test: adds param 'address' in _get_free_port Acceptance test: provides new functions Acceptance test: provides to use RDMA transport for migration test tests/acceptance/migration.py | 46 +-- 1 file changed, 44 insertions(+), 2 deletions(-) -- 2.21.1
[PATCH v4] python/qemu/qmp.py: QMP debug with VM label
QEMUMachine writes some messages to the default logger. But it sometimes hard to read the output if we have requests to more than one VM. This patch adds a label to the logger in the debug mode. Signed-off-by: Oksana Vohchana --- v2: - Instead of shown the label in the message it provides the label only in the debug logger information. v3: - Fixes coding style problems. v4: - Use a suffix method to get a children's logger process from the parent. --- python/qemu/machine.py | 3 ++- python/qemu/qmp.py | 5 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 183d8f3d38..f53abfa492 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -270,7 +270,8 @@ class QEMUMachine(object): self._vm_monitor = os.path.join(self._sock_dir, self._name + "-monitor.sock") self._remove_files.append(self._vm_monitor) -self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True) +self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True, +nickname=self._name) def _post_launch(self): if self._qmp: diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index f40586eedd..d6c9b2f4b1 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -46,7 +46,7 @@ class QEMUMonitorProtocol: #: Logger object for debugging messages logger = logging.getLogger('QMP') -def __init__(self, address, server=False): +def __init__(self, address, server=False, nickname=None): """ Create a QEMUMonitorProtocol class. @@ -62,6 +62,9 @@ class QEMUMonitorProtocol: self.__address = address self.__sock = self.__get_sock() self.__sockfile = None +self._nickname = nickname +if self._nickname: +self.logger = logging.getLogger('QMP').getChild(self._nickname) if server: self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.__sock.bind(self.__address) -- 2.21.1
[PATCH v3] python/qemu/qmp.py: QMP debug with VM label
QEMUMachine writes some messages to the default logger. But it sometimes hard to read the output if we have requests to more than one VM. This patch adds a label to the logger in the debug mode. Signed-off-by: Oksana Vohchana --- v2: - Instead of shown the label in the message it provides the label only in the debug logger information v3: - Fixes coding style problems --- python/qemu/machine.py | 3 ++- python/qemu/qmp.py | 5 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 183d8f3d38..f53abfa492 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -270,7 +270,8 @@ class QEMUMachine(object): self._vm_monitor = os.path.join(self._sock_dir, self._name + "-monitor.sock") self._remove_files.append(self._vm_monitor) -self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True) +self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True, +nickname=self._name) def _post_launch(self): if self._qmp: diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index f40586eedd..d58b18c304 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -46,7 +46,7 @@ class QEMUMonitorProtocol: #: Logger object for debugging messages logger = logging.getLogger('QMP') -def __init__(self, address, server=False): +def __init__(self, address, server=False, nickname=None): """ Create a QEMUMonitorProtocol class. @@ -62,6 +62,7 @@ class QEMUMonitorProtocol: self.__address = address self.__sock = self.__get_sock() self.__sockfile = None +self._nickname = nickname if server: self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.__sock.bind(self.__address) @@ -188,6 +189,8 @@ class QEMUMonitorProtocol: @return QMP response as a Python dict or None if the connection has been closed """ +if self._nickname: +self.logger.name = 'QMP.{}'.format(self._nickname) self.logger.debug(">>> %s", qmp_cmd) try: self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8')) -- 2.21.1
[PATCH v2] python/qemu/qmp.py: QMP debug with VM label
QEMUMachine writes some messages to the default logger. But it sometimes hard to read the output if we have requests to more than one VM. This patch adds a label to the logger in the debug mode. Signed-off-by: Oksana Vohchana --- v2: - Instead of shown the label in the message it provides the label only in the debug logger information --- python/qemu/machine.py | 2 +- python/qemu/qmp.py | 5 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 183d8f3d38..d0aa774c1c 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -270,7 +270,7 @@ class QEMUMachine(object): self._vm_monitor = os.path.join(self._sock_dir, self._name + "-monitor.sock") self._remove_files.append(self._vm_monitor) -self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True) +self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True, nickname=self._name) def _post_launch(self): if self._qmp: diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index f40586eedd..d58b18c304 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -46,7 +46,7 @@ class QEMUMonitorProtocol: #: Logger object for debugging messages logger = logging.getLogger('QMP') -def __init__(self, address, server=False): +def __init__(self, address, server=False, nickname=None): """ Create a QEMUMonitorProtocol class. @@ -62,6 +62,7 @@ class QEMUMonitorProtocol: self.__address = address self.__sock = self.__get_sock() self.__sockfile = None +self._nickname = nickname if server: self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.__sock.bind(self.__address) @@ -188,6 +189,8 @@ class QEMUMonitorProtocol: @return QMP response as a Python dict or None if the connection has been closed """ +if self._nickname: +self.logger.name = 'QMP.{}'.format(self._nickname) self.logger.debug(">>> %s", qmp_cmd) try: self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8')) -- 2.21.1
[PATCH] python/qemu/qmp.py: QMP debug with VM label
QEMUMachine writes some messages to the default logger. But it sometimes to hard the read the output if we have requested to more than one VM. This patch adds name in QMP command if it needs and labels with it in debug mode. Signed-off-by: Oksana Vohchana --- python/qemu/machine.py | 8 python/qemu/qmp.py | 9 ++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 183d8f3d38..060e68f06b 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -391,7 +391,7 @@ class QEMUMachine(object): self._qmp_set = False self._qmp = None -def qmp(self, cmd, conv_keys=True, **args): +def qmp(self, cmd, conv_keys=True, vm_name=None, **args): """ Invoke a QMP command and return the response dict """ @@ -402,15 +402,15 @@ class QEMUMachine(object): else: qmp_args[key] = value -return self._qmp.cmd(cmd, args=qmp_args) +return self._qmp.cmd(cmd, args=qmp_args, vm_name=vm_name) -def command(self, cmd, conv_keys=True, **args): +def command(self, cmd, conv_keys=True, vm_name=None, **args): """ Invoke a QMP command. On success return the response dict. On failure raise an exception. """ -reply = self.qmp(cmd, conv_keys, **args) +reply = self.qmp(cmd, conv_keys, vm_name, **args) if reply is None: raise qmp.QMPError("Monitor is closed") if "error" in reply: diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py index f40586eedd..96b455b53f 100644 --- a/python/qemu/qmp.py +++ b/python/qemu/qmp.py @@ -180,11 +180,12 @@ class QEMUMonitorProtocol: self.__sockfile = self.__sock.makefile() return self.__negotiate_capabilities() -def cmd_obj(self, qmp_cmd): +def cmd_obj(self, qmp_cmd, vm_name=None): """ Send a QMP command to the QMP Monitor. @param qmp_cmd: QMP command to be sent as a Python dict +@param vm_name: name for the virtual machine (string) @return QMP response as a Python dict or None if the connection has been closed """ @@ -196,10 +197,12 @@ class QEMUMonitorProtocol: return None raise err resp = self.__json_read() +if vm_name: +self.logger.debug("<<< {'vm_name' : %s }", vm_name) self.logger.debug("<<< %s", resp) return resp -def cmd(self, name, args=None, cmd_id=None): +def cmd(self, name, args=None, cmd_id=None, vm_name=None): """ Build a QMP command and send it to the QMP Monitor. @@ -212,7 +215,7 @@ class QEMUMonitorProtocol: qmp_cmd['arguments'] = args if cmd_id: qmp_cmd['id'] = cmd_id -return self.cmd_obj(qmp_cmd) +return self.cmd_obj(qmp_cmd, vm_name) def command(self, cmd, **kwds): """ -- 2.21.1
[PATCH v3 3/3] Acceptance test: add FD migration
The patch adds a new type of migration test through the file descriptor. Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 21 + 1 file changed, 21 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a8367ca023..7f4879ce5d 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -10,7 +10,10 @@ # later. See the COPYING file in the top-level directory. +import os import tempfile +from socket import socketpair, AF_UNIX, SOCK_STREAM + from avocado_qemu import Test from avocado import skipUnless @@ -75,3 +78,21 @@ class Migration(Test): """ free_port = self._get_free_port() dest_uri = 'exec:nc -l localhost %u' % free_port + +def test_migration_with_fd(self): +opaque = 'fd-migration' +data_to_send = b"{\"execute\": \"getfd\", \"arguments\": \ +{\"fdname\": \"fd-migration\"}}" +send_socket, recv_socket = socketpair(AF_UNIX, SOCK_STREAM) +fd1 = send_socket.fileno() +fd2 = recv_socket.fileno() +os.set_inheritable(fd2, True) + +source_vm = self.get_vm() +source_vm.launch() +source_vm.send_fd_scm(fd=fd1, data=data_to_send) + +dest_vm = self.get_vm('-incoming', 'fd:%s' % fd2) +dest_vm.launch() +source_vm.qmp('migrate', uri='fd:%s' % opaque) +self.assert_migration(source_vm, dest_vm) -- 2.21.1
[PATCH v3 2/3] python/qemu/machine: Updates send_fd_scm function
This patch upgrades the send_fd_scm function to use it in way if not provide socket_scm_helper. It uses new provided functions _send_fds and _recv_fds that depend on FD's and data that allow us to send a file/socket descriptor (with access and permissions) from one process to another. The parameter data include qmp message like getfd or add-fd. Signed-off-by: Oksana Vohchana --- python/qemu/machine.py | 64 ++ 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 976316e5f5..906ca118db 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -179,20 +179,27 @@ class QEMUMachine(object): return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array("i", fds))]) -def send_fd_scm(self, fd=None, file_path=None): +def send_fd_scm(self, fd=None, file_path=None, data=None): """ -Send an fd or file_path to socket_scm_helper. +Can be used in two different cases. +Send an fd or file_path to socket_scm_helper or +provide data and fd to send it to the socket. -Exactly one of fd and file_path must be given. -If it is file_path, the helper will open that file and pass its own fd. +Exactly one of fd and file_path must be given to the case of +socket_scm_helper. If it is file_path, the helper will open that file +and pass its own fd. + +To second case need adds data that include a QMP request and fd """ # In iotest.py, the qmp should always use unix socket. assert self._qmp.is_scm_available() -if self._socket_scm_helper is None: -raise QEMUMachineError("No path to socket_scm_helper set") -if not os.path.exists(self._socket_scm_helper): -raise QEMUMachineError("%s does not exist" % - self._socket_scm_helper) +if data is None: +if self._socket_scm_helper is None: +raise QEMUMachineError( +"No path to socket_scm_helper set or data provided") +if not os.path.exists(self._socket_scm_helper): +raise QEMUMachineError("%s does not exist" % + self._socket_scm_helper) # This did not exist before 3.4, but since then it is # mandatory for our purpose @@ -201,24 +208,33 @@ class QEMUMachine(object): if fd is not None: os.set_inheritable(fd, True) -fd_param = ["%s" % self._socket_scm_helper, -"%d" % self._qmp.get_sock_fd()] +if data is None: +fd_param = ["%s" % self._socket_scm_helper, +"%d" % self._qmp.get_sock_fd()] +if file_path is not None: +assert fd is None +fd_param.append(file_path) +else: +assert fd is not None +fd_param.append(str(fd)) -if file_path is not None: -assert fd is None -fd_param.append(file_path) -else: -assert fd is not None -fd_param.append(str(fd)) +devnull = open(os.path.devnull, 'rb') +proc = subprocess.Popen(fd_param, stdin=devnull, +stdout=subprocess.PIPE, +stderr=subprocess.STDOUT, close_fds=False) +output = proc.communicate()[0] +if output: +LOG.debug(output) -devnull = open(os.path.devnull, 'rb') -proc = subprocess.Popen(fd_param, stdin=devnull, stdout=subprocess.PIPE, -stderr=subprocess.STDOUT, close_fds=False) -output = proc.communicate()[0] -if output: -LOG.debug(output) +return proc.returncode -return proc.returncode +else: +sock_fd = socket.fromfd(self._qmp.get_sock_fd(), socket.AF_UNIX, +socket.SOCK_STREAM) +fds_param = [fd, self._qmp.get_sock_fd()] +self._send_fds(sock_fd, data, fds_param) +self._recv_fds(sock_fd) +return self @staticmethod def _remove_if_exists(path): -- 2.21.1
[PATCH v3 1/3] python/qemu/machine: Adding functions _send_fds and _recv_fds
To pass the fd via SCM_RIGHT we should use socket_scm_helper file. And the path to it file should be provided on starting the virtual machine. For acceptance tests, this is not convenient, but sometimes not possible to get this binary file during the testing. This patch provides new possibilities to send or receive data through the Unix domain socket file descriptor. This is useful for obtaining a socket that belongs to a different network namespace. Signed-off-by: Oksana Vohchana --- python/qemu/machine.py | 24 1 file changed, 24 insertions(+) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 183d8f3d38..976316e5f5 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -24,6 +24,7 @@ import subprocess import shutil import socket import tempfile +import array from . import qmp @@ -155,6 +156,29 @@ class QEMUMachine(object): self._args.append(','.join(options)) return self +def _recv_fds(self, sock, msglen=8192, maxfds=4096): +""" +Function from: +https://docs.python.org/3/library/socket.html#socket.socket.recvmsg +""" +fds = array.array("i") +msg, ancdata, flags, addr = sock.recvmsg(msglen, socket.CMSG_LEN( +maxfds * fds.itemsize)) +for cmsg_level, cmsg_type, cmsg_data in ancdata: +if (cmsg_level == socket.SOL_SOCKET and +cmsg_type == socket.SCM_RIGHTS): +fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) +% fds.itemsize)]) +return msg, list(fds) + +def _send_fds(self, sock, msg, fds): +""" +Function from: +https://docs.python.org/3/library/socket.html#socket.socket.sendmsg +""" +return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, + array.array("i", fds))]) + def send_fd_scm(self, fd=None, file_path=None): """ Send an fd or file_path to socket_scm_helper. -- 2.21.1
[PATCH v3 0/3] Acceptance test: Migration mechanism with FD
To test migration through the file descriptor we should build and provide a path to socket_scm_helper file. This way is inconvenient for acceptance testing. This series provides new functions to receive and send messages over a UNIX socket. And adds a new migration test that depends on it v2: - Fix warning of line over 80 characters v3: - Improve commit messages Oksana Vohchana (3): python/qemu/machine: Adding functions _send_fds and _recv_fds python/qemu/machine: Updates send_fd_scm function Acceptance test: add FD migration python/qemu/machine.py| 88 +-- tests/acceptance/migration.py | 21 + 2 files changed, 85 insertions(+), 24 deletions(-) -- 2.21.1
[PATCH v2 0/4] Acceptance test: Extension of migration tests
This series adds a new migration test through RDMA. To correct uses of migration need to add a new function to work with RDMA service. And as a part of migration tests, the series makes small updates to EXEC migration and to _get_free_port function V2: - improves commit message in Acceptance test: adds param 'address' in _get_free_port - provides import check for netifaces library - makes fix to _get_ip_rdma function - adds skip to test if not upload python module Oksana Vohchana (4): Acceptance test: adds param 'address' in _get_free_port Acceptance test: EXEC migration Acceptance test: provides new functions Acceptance test: provides to use RDMA transport for migration test tests/acceptance/migration.py | 41 +-- 1 file changed, 39 insertions(+), 2 deletions(-) -- 2.21.1
[PATCH v2 3/4] Acceptance test: provides new functions
Provides new functions related to the rdma migration test Adds functions to check if service RDMA is enabled and gets the ip address on the interface where it was configured Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 26 ++ 1 file changed, 26 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index 8209dcf71d..5632d74f14 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -11,12 +11,22 @@ import tempfile +import re from avocado_qemu import Test from avocado import skipUnless from avocado.utils import network from avocado.utils import wait from avocado.utils.path import find_command +from avocado.utils import service +from avocado.utils import process + + +NET_AVAILABLE = True +try: +import netifaces +except ImportError: +NET_AVAILABLE = False class Migration(Test): @@ -58,6 +68,22 @@ class Migration(Test): self.cancel('Failed to find a free port') return port +def _if_rdma_enable(self): +rdma_stat = service.ServiceManager() +rdma = rdma_stat.status('rdma') +return rdma + +def _get_ip_rdma(self): +get_ip_rdma = process.run('rdma link show').stdout.decode() +for line in get_ip_rdma.split('\n'): +if re.search(r"ACTIVE", line): +interface = line.split(" ")[-2] +try: + return netifaces.ifaddresses(interface)[netifaces \ + .AF_INET][0]['addr'] +except (IndexError, KeyError): +return None + def test_migration_with_tcp_localhost(self): dest_uri = 'tcp:localhost:%u' % self._get_free_port() -- 2.21.1
[PATCH v2 4/4] Acceptance test: provides to use RDMA transport for migration test
Adds test for RDMA migration check Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 9 + 1 file changed, 9 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index 5632d74f14..9b58b5a629 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -103,3 +103,12 @@ class Migration(Test): dest_uri = 'exec:nc -l localhost %u' % free_port src_uri = 'exec:nc localhost %u' % free_port self.do_migrate(dest_uri, src_uri) + +@skipUnless(NET_AVAILABLE, 'Netifaces module not installed') +@skipUnless(_if_rdma_enable(None), "Unit rdma.service could not be found") +@skipUnless(_get_ip_rdma(None), 'RoCE(RDMA) service or interface not configured') +def test_migration_with_rdma_localhost(self): +ip = self._get_ip_rdma() +free_port = self._get_free_port(address=ip) +dest_uri = 'rdma:%s:%u' % (ip, free_port) +self.do_migrate(dest_uri) -- 2.21.1
[PATCH v2 2/4] Acceptance test: EXEC migration
Improves EXEC migration to run whole test stage Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index e4c39b85a1..8209dcf71d 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -75,3 +75,5 @@ class Migration(Test): """ free_port = self._get_free_port() dest_uri = 'exec:nc -l localhost %u' % free_port +src_uri = 'exec:nc localhost %u' % free_port +self.do_migrate(dest_uri, src_uri) -- 2.21.1
[PATCH v2 1/4] Acceptance test: adds param 'address' in _get_free_port
In the migration test function _get_free_port works only for localhost, but in the case to use migration through an RDMA we need to get a free port on the configured network RDMA-interface. This patch is the start for another migration option Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a8367ca023..e4c39b85a1 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -52,8 +52,8 @@ class Migration(Test): source_vm.qmp('migrate', uri=src_uri) self.assert_migration(source_vm, dest_vm) -def _get_free_port(self): -port = network.find_free_port() +def _get_free_port(self, address='localhost'): +port = network.find_free_port(address=address) if port is None: self.cancel('Failed to find a free port') return port -- 2.21.1
[PATCH v2 1/3] Adding functions _send_fds and _recv_fds
It provides new possibilities to send or receive data through the Unix domain socket file descriptor. This is useful for obtaining a socket that belongs to a different network namespace. Signed-off-by: Oksana Vohchana --- python/qemu/machine.py | 24 1 file changed, 24 insertions(+) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 183d8f3d38..976316e5f5 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -24,6 +24,7 @@ import subprocess import shutil import socket import tempfile +import array from . import qmp @@ -155,6 +156,29 @@ class QEMUMachine(object): self._args.append(','.join(options)) return self +def _recv_fds(self, sock, msglen=8192, maxfds=4096): +""" +Function from: +https://docs.python.org/3/library/socket.html#socket.socket.recvmsg +""" +fds = array.array("i") +msg, ancdata, flags, addr = sock.recvmsg(msglen, socket.CMSG_LEN( +maxfds * fds.itemsize)) +for cmsg_level, cmsg_type, cmsg_data in ancdata: +if (cmsg_level == socket.SOL_SOCKET and +cmsg_type == socket.SCM_RIGHTS): +fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) +% fds.itemsize)]) +return msg, list(fds) + +def _send_fds(self, sock, msg, fds): +""" +Function from: +https://docs.python.org/3/library/socket.html#socket.socket.sendmsg +""" +return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, + array.array("i", fds))]) + def send_fd_scm(self, fd=None, file_path=None): """ Send an fd or file_path to socket_scm_helper. -- 2.21.1
[PATCH v2 2/3] Updates send_fd_scm function
A qemu-iotest uses for FD-migration test a helper program "socket_scm_helper". And it makes some problems if you didn't build it with a QEMU. And now we can use new methods for the socket that allow us to send a file/socket descriptor (with access and permissions) from one process to another. Signed-off-by: Oksana Vohchana --- python/qemu/machine.py | 64 ++ 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 976316e5f5..906ca118db 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -179,20 +179,27 @@ class QEMUMachine(object): return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array("i", fds))]) -def send_fd_scm(self, fd=None, file_path=None): +def send_fd_scm(self, fd=None, file_path=None, data=None): """ -Send an fd or file_path to socket_scm_helper. +Can be used in two different cases. +Send an fd or file_path to socket_scm_helper or +provide data and fd to send it to the socket. -Exactly one of fd and file_path must be given. -If it is file_path, the helper will open that file and pass its own fd. +Exactly one of fd and file_path must be given to the case of +socket_scm_helper. If it is file_path, the helper will open that file +and pass its own fd. + +To second case need adds data that include a QMP request and fd """ # In iotest.py, the qmp should always use unix socket. assert self._qmp.is_scm_available() -if self._socket_scm_helper is None: -raise QEMUMachineError("No path to socket_scm_helper set") -if not os.path.exists(self._socket_scm_helper): -raise QEMUMachineError("%s does not exist" % - self._socket_scm_helper) +if data is None: +if self._socket_scm_helper is None: +raise QEMUMachineError( +"No path to socket_scm_helper set or data provided") +if not os.path.exists(self._socket_scm_helper): +raise QEMUMachineError("%s does not exist" % + self._socket_scm_helper) # This did not exist before 3.4, but since then it is # mandatory for our purpose @@ -201,24 +208,33 @@ class QEMUMachine(object): if fd is not None: os.set_inheritable(fd, True) -fd_param = ["%s" % self._socket_scm_helper, -"%d" % self._qmp.get_sock_fd()] +if data is None: +fd_param = ["%s" % self._socket_scm_helper, +"%d" % self._qmp.get_sock_fd()] +if file_path is not None: +assert fd is None +fd_param.append(file_path) +else: +assert fd is not None +fd_param.append(str(fd)) -if file_path is not None: -assert fd is None -fd_param.append(file_path) -else: -assert fd is not None -fd_param.append(str(fd)) +devnull = open(os.path.devnull, 'rb') +proc = subprocess.Popen(fd_param, stdin=devnull, +stdout=subprocess.PIPE, +stderr=subprocess.STDOUT, close_fds=False) +output = proc.communicate()[0] +if output: +LOG.debug(output) -devnull = open(os.path.devnull, 'rb') -proc = subprocess.Popen(fd_param, stdin=devnull, stdout=subprocess.PIPE, -stderr=subprocess.STDOUT, close_fds=False) -output = proc.communicate()[0] -if output: -LOG.debug(output) +return proc.returncode -return proc.returncode +else: +sock_fd = socket.fromfd(self._qmp.get_sock_fd(), socket.AF_UNIX, +socket.SOCK_STREAM) +fds_param = [fd, self._qmp.get_sock_fd()] +self._send_fds(sock_fd, data, fds_param) +self._recv_fds(sock_fd) +return self @staticmethod def _remove_if_exists(path): -- 2.21.1
[PATCH v2 3/3] Acceptance test: FD migration
Adds a new migration test through the file descriptor. Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 21 + 1 file changed, 21 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a8367ca023..7f4879ce5d 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -10,7 +10,10 @@ # later. See the COPYING file in the top-level directory. +import os import tempfile +from socket import socketpair, AF_UNIX, SOCK_STREAM + from avocado_qemu import Test from avocado import skipUnless @@ -75,3 +78,21 @@ class Migration(Test): """ free_port = self._get_free_port() dest_uri = 'exec:nc -l localhost %u' % free_port + +def test_migration_with_fd(self): +opaque = 'fd-migration' +data_to_send = b"{\"execute\": \"getfd\", \"arguments\": \ +{\"fdname\": \"fd-migration\"}}" +send_socket, recv_socket = socketpair(AF_UNIX, SOCK_STREAM) +fd1 = send_socket.fileno() +fd2 = recv_socket.fileno() +os.set_inheritable(fd2, True) + +source_vm = self.get_vm() +source_vm.launch() +source_vm.send_fd_scm(fd=fd1, data=data_to_send) + +dest_vm = self.get_vm('-incoming', 'fd:%s' % fd2) +dest_vm.launch() +source_vm.qmp('migrate', uri='fd:%s' % opaque) +self.assert_migration(source_vm, dest_vm) -- 2.21.1
[PATCH v2 0/3] Migration mechanism with FD
To test migration through the file descriptor we should build and provide a path to socket_scm_helper file. This way is inconvenient for acceptance testing. This series provides new functions to receive and send messages over a UNIX socket. And adds a new migration test. v2: - Fix warning of line over 80 characters Oksana Vohchana (3): Adding functions _send_fds and _recv_fds Updates send_fd_scm function Acceptance test: FD migration python/qemu/machine.py| 88 +-- tests/acceptance/migration.py | 21 + 2 files changed, 85 insertions(+), 24 deletions(-) -- 2.21.1
[PATCH 2/3] Updates send_fd_scm function
A qemu-iotest uses for FD-migration test a helper program "socket_scm_helper". And it makes some problems if you didn't build it with a QEMU. And now we can use new methods for the socket that allow us to send a file/socket descriptor (with access and permissions) from one process to another. Signed-off-by: Oksana Vohchana --- python/qemu/machine.py | 56 +- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 8c5bd64795..0936b71856 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -173,19 +173,24 @@ class QEMUMachine(object): """ return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array("i", fds))]) -def send_fd_scm(self, fd=None, file_path=None): +def send_fd_scm(self, fd=None, file_path=None, data=None): """ -Send an fd or file_path to socket_scm_helper. +Can be used in two different cases. +Send an fd or file_path to socket_scm_helper or +provide data and fd to send it to the socket. -Exactly one of fd and file_path must be given. +Exactly one of fd and file_path must be given to the case of socket_scm_helper If it is file_path, the helper will open that file and pass its own fd. + +To second case need adds data that include a QMP request and fd """ # In iotest.py, the qmp should always use unix socket. assert self._qmp.is_scm_available() -if self._socket_scm_helper is None: -raise QEMUMachineError("No path to socket_scm_helper set") -if not os.path.exists(self._socket_scm_helper): -raise QEMUMachineError("%s does not exist" % +if data is None: +if self._socket_scm_helper is None: +raise QEMUMachineError("No path to socket_scm_helper set or data not provided") +if not os.path.exists(self._socket_scm_helper): +raise QEMUMachineError("%s does not exist" % self._socket_scm_helper) # This did not exist before 3.4, but since then it is @@ -195,24 +200,31 @@ class QEMUMachine(object): if fd is not None: os.set_inheritable(fd, True) -fd_param = ["%s" % self._socket_scm_helper, -"%d" % self._qmp.get_sock_fd()] +if data is None: +fd_param = ["%s" % self._socket_scm_helper, +"%d" % self._qmp.get_sock_fd()] +if file_path is not None: +assert fd is None +fd_param.append(file_path) +else: +assert fd is not None +fd_param.append(str(fd)) -if file_path is not None: -assert fd is None -fd_param.append(file_path) -else: -assert fd is not None -fd_param.append(str(fd)) +devnull = open(os.path.devnull, 'rb') +proc = subprocess.Popen(fd_param, stdin=devnull, stdout=subprocess.PIPE, +stderr=subprocess.STDOUT, close_fds=False) +output = proc.communicate()[0] +if output: +LOG.debug(output) -devnull = open(os.path.devnull, 'rb') -proc = subprocess.Popen(fd_param, stdin=devnull, stdout=subprocess.PIPE, -stderr=subprocess.STDOUT, close_fds=False) -output = proc.communicate()[0] -if output: -LOG.debug(output) +return proc.returncode -return proc.returncode +else: +sock_fd = socket.fromfd(self._qmp.get_sock_fd(), socket.AF_UNIX, socket.SOCK_STREAM) +fds_param = [fd, self._qmp.get_sock_fd()] +self._send_fds(sock_fd, data, fds_param) +self._recv_fds(sock_fd) +return self @staticmethod def _remove_if_exists(path): -- 2.21.1
[PATCH 1/3] Adding functions _send_fds and _recv_fds
It provides new possibilities to send or receive data through the Unix domain socket file descriptor. This is useful for obtaining a socket that belongs to a different network namespace. Signed-off-by: Oksana Vohchana --- python/qemu/machine.py | 18 ++ 1 file changed, 18 insertions(+) diff --git a/python/qemu/machine.py b/python/qemu/machine.py index 183d8f3d38..8c5bd64795 100644 --- a/python/qemu/machine.py +++ b/python/qemu/machine.py @@ -24,6 +24,7 @@ import subprocess import shutil import socket import tempfile +import array from . import qmp @@ -155,6 +156,23 @@ class QEMUMachine(object): self._args.append(','.join(options)) return self +def _recv_fds(self, sock, msglen=8192, maxfds=4096): +""" +Function from https://docs.python.org/3/library/socket.html#socket.socket.recvmsg +""" +fds = array.array("i") +msg, ancdata, flags, addr = sock.recvmsg(msglen, socket.CMSG_LEN(maxfds * fds.itemsize)) +for cmsg_level, cmsg_type, cmsg_data in ancdata: +if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS: +fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) +return msg, list(fds) + +def _send_fds(self, sock, msg, fds): +""" +Function from https://docs.python.org/3/library/socket.html#socket.socket.sendmsg +""" +return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array("i", fds))]) + def send_fd_scm(self, fd=None, file_path=None): """ Send an fd or file_path to socket_scm_helper. -- 2.21.1
[PATCH 3/3] Acceptance test: FD migration
Adds a new migration test through the file descriptor. Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 20 1 file changed, 20 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a8367ca023..b96a897f3b 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -10,7 +10,10 @@ # later. See the COPYING file in the top-level directory. +import os import tempfile +from socket import socketpair, AF_UNIX, SOCK_STREAM + from avocado_qemu import Test from avocado import skipUnless @@ -75,3 +78,20 @@ class Migration(Test): """ free_port = self._get_free_port() dest_uri = 'exec:nc -l localhost %u' % free_port + +def test_migration_with_fd(self): +opaque = 'fd-migration' +data_to_send = b"{\"execute\": \"getfd\", \"arguments\": {\"fdname\": \"fd-migration\"}}" +send_socket, recv_socket = socketpair(AF_UNIX, SOCK_STREAM) +fd1 = send_socket.fileno() +fd2 = recv_socket.fileno() +os.set_inheritable(fd2, True) + +source_vm = self.get_vm() +source_vm.launch() +source_vm.send_fd_scm(fd=fd1, data=data_to_send) + +dest_vm = self.get_vm('-incoming', 'fd:%s' % fd2) +dest_vm.launch() +source_vm.qmp('migrate', uri='fd:%s' % opaque) +self.assert_migration(source_vm, dest_vm) -- 2.21.1
[PATCH 0/3] Migration mechanism with FD
To test migration through the file descriptor we should build and provide a path to socket_scm_helper file. This way is inconvenient for acceptance testing. This series provides new functions to receive and send messages over a UNIX socket. And adds a new migration test. Oksana Vohchana (3): Adding functions _send_fds and _recv_fds Updates send_fd_scm function Acceptance test: FD migration python/qemu/machine.py| 74 --- tests/acceptance/migration.py | 20 ++ 2 files changed, 72 insertions(+), 22 deletions(-) -- 2.21.1
[PATCH v1 4/4] Acceptance test: provides to use RDMA transport for migration
Adds test for RDMA migration check Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 8 1 file changed, 8 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index bbd88f8dda..c0a3031e67 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -94,3 +94,11 @@ class Migration(Test): dest_uri = 'exec:nc -l localhost %u' % free_port src_uri = 'exec:nc localhost %u' % free_port self.do_migrate(dest_uri, src_uri) + +@skipUnless(_if_rdma_enable(None), "Unit rdma.service could not be found") +@skipUnless(_get_ip_rdma(None), 'RoCE(RDMA) service or interface not configured') +def test_migration_with_rdma_localhost(self): +ip = self._get_ip_rdma() +free_port = self._get_free_port(address=ip) +dest_uri = 'rdma:%s:%u' % (ip, free_port) +self.do_migrate(dest_uri) -- 2.21.1
[PATCH v1 1/4] Acceptance test: add address as param
Provides param address in _get_free_port() because by default it takes free port only on the localhost Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a8367ca023..e4c39b85a1 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -52,8 +52,8 @@ class Migration(Test): source_vm.qmp('migrate', uri=src_uri) self.assert_migration(source_vm, dest_vm) -def _get_free_port(self): -port = network.find_free_port() +def _get_free_port(self, address='localhost'): +port = network.find_free_port(address=address) if port is None: self.cancel('Failed to find a free port') return port -- 2.21.1
[PATCH v1 2/4] Acceptance test: EXEC migration
Improves EXEC migration to run whole test stage Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index e4c39b85a1..8209dcf71d 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -75,3 +75,5 @@ class Migration(Test): """ free_port = self._get_free_port() dest_uri = 'exec:nc -l localhost %u' % free_port +src_uri = 'exec:nc localhost %u' % free_port +self.do_migrate(dest_uri, src_uri) -- 2.21.1
[PATCH v1 3/4] Acceptance test: provides new functions
Adds functions to check if service RDMA is enabled and gets the interface where it was configured Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 17 + 1 file changed, 17 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index 8209dcf71d..bbd88f8dda 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -11,12 +11,16 @@ import tempfile +import re +import netifaces from avocado_qemu import Test from avocado import skipUnless from avocado.utils import network from avocado.utils import wait from avocado.utils.path import find_command +from avocado.utils import service +from avocado.utils import process class Migration(Test): @@ -58,6 +62,19 @@ class Migration(Test): self.cancel('Failed to find a free port') return port +def _if_rdma_enable(self): +rdma_stat = service.ServiceManager() +rdma = rdma_stat.status('rdma') +return rdma + +def _get_ip_rdma(self): +get_ip_rdma = process.run('rdma link show').stdout.decode() +for line in get_ip_rdma.split('\n'): +if re.search(r"ACTIVE", line): +interface = line.split(" ")[-2] +ip = netifaces.ifaddresses(interface)[netifaces.AF_INET][0]['addr'] +return ip + def test_migration_with_tcp_localhost(self): dest_uri = 'tcp:localhost:%u' % self._get_free_port() -- 2.21.1
[PATCH v1 0/4] Extension of migration tests
This series adds a new migration test through RDMA and provides new functions to it. The last update by mistake was not provided a full scenario to the EXEC migration test. One of patch fixed it. Oksana Vohchana (4): Acceptance test: add address as param Acceptance test: EXEC migration Acceptance test: provides new functions Acceptance test: provides to use RDMA transport for migration tests/acceptance/migration.py | 31 +-- 1 file changed, 29 insertions(+), 2 deletions(-) -- 2.21.1
[PATCH v3 2/2] Acceptance test: provides to use different transport for migration
Along with VM migration via TCP, we can use migration through EXEC and UNIX transport protocol Signed-off-by: Oksana Vohchana --- v2: - Removes unnecessary symbols and unused method v3: - Makes refactoring and split into 2 patches - Provides TCP and EXEC migration Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 16 1 file changed, 16 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index 34263d8eeb..4419e38384 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -10,10 +10,13 @@ # later. See the COPYING file in the top-level directory. +import tempfile from avocado_qemu import Test +from avocado import skipUnless from avocado.utils import network from avocado.utils import wait +from avocado.utils.path import find_command class Migration(Test): @@ -54,3 +57,16 @@ class Migration(Test): def test_migration_with_tcp_localhost(self): dest_uri = 'tcp:localhost:%u' % self._get_free_port() self.do_migrate(dest_uri) + +def test_migration_with_unix(self): +with tempfile.TemporaryDirectory(prefix='socket_') as socket_path: +dest_uri = 'unix:%s/qemu-test.sock' % socket_path +self.do_migrate(dest_uri) + +@skipUnless(find_command('nc', default=False), "nc command not found on the system") +def test_migration_with_exec(self): +""" +The test works for both netcat-traditional and netcat-openbsd packages +""" +free_port = self._get_free_port() +dest_uri = 'exec:nc -l localhost %u' % free_port +src_uri = 'exec:nc localhost %u' % free_port +self.do_migrate(dest_uri, src_uri) -- 2.21.1
[PATCH v3 1/2] Acceptance test: provides to use different transport for migration
Along with VM migration via TCP, we can use migration through EXEC and UNIX transport protocol Signed-off-by: Oksana Vohchana --- v2: - Removes unnecessary symbols and unused method v3: - Makes refactoring and split into 2 patches Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 36 --- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a44c1ae58f..34263d8eeb 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -24,6 +24,26 @@ class Migration(Test): def migration_finished(vm): return vm.command('query-migrate')['status'] in ('completed', 'failed') +def assert_migration(self, source_vm, dest_vm): +wait.wait_for(self.migration_finished, + timeout=self.timeout, + step=0.1, + args=(source_vm,)) +self.assertEqual(source_vm.command('query-migrate')['status'], 'completed') +self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed') +self.assertEqual(dest_vm.command('query-status')['status'], 'running') +self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate') + +def do_migrate(self, dest_uri, src_uri=None): +source_vm = self.get_vm() +dest_vm = self.get_vm('-incoming', dest_uri) +dest_vm.launch() +if src_uri is None: +src_uri = dest_uri +source_vm.launch() +source_vm.qmp('migrate', uri=src_uri) +self.assert_migration(source_vm, dest_vm) + def _get_free_port(self): port = network.find_free_port() if port is None: @@ -32,19 +52,5 @@ class Migration(Test): def test_migration_with_tcp_localhost(self): -source_vm = self.get_vm() dest_uri = 'tcp:localhost:%u' % self._get_free_port() -dest_vm = self.get_vm('-incoming', dest_uri) -dest_vm.launch() -source_vm.launch() -source_vm.qmp('migrate', uri=dest_uri) -wait.wait_for( -self.migration_finished, -timeout=self.timeout, -step=0.1, -args=(source_vm,) -) -self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed') -self.assertEqual(source_vm.command('query-migrate')['status'], 'completed') -self.assertEqual(dest_vm.command('query-status')['status'], 'running') -self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate') +self.do_migrate(dest_uri) -- 2.21.1
[PATCH v3 0/2] Acceptance test: provides to use different transport for migration
This series makes refactoring to migration test and adds new tests with EXEC and UNIX protocols --- v2: - Removes unnecessary symbols and unused method v3: - Makes refactoring and split into 2 patches - Provides TCP and EXEC migration Oksana Vohchana (2): Acceptance test: provides to use different transport for migration Acceptance test: provides to use different transport for migration tests/acceptance/migration.py | 52 +-- 1 file changed, 37 insertions(+), 15 deletions(-) -- 2.21.1
[PATCH v3 2/2] Acceptance test: provides to use different transport for migration
Along with VM migration via TCP, we can use migration through EXEC and UNIX transport protocol Signed-off-by: Oksana Vohchana --- v2: - Removes unnecessary symbols and unused method v3: - Makes refactoring and split into 2 patches - Provides TCP and EXEC migration Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 16 1 file changed, 16 insertions(+) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index 34263d8eeb..4419e38384 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -10,10 +10,13 @@ # later. See the COPYING file in the top-level directory. +import tempfile from avocado_qemu import Test +from avocado import skipUnless from avocado.utils import network from avocado.utils import wait +from avocado.utils.path import find_command class Migration(Test): @@ -54,3 +57,16 @@ class Migration(Test): def test_migration_with_tcp_localhost(self): dest_uri = 'tcp:localhost:%u' % self._get_free_port() self.do_migrate(dest_uri) + +def test_migration_with_unix(self): +with tempfile.TemporaryDirectory(prefix='socket_') as socket_path: +dest_uri = 'unix:%s/qemu-test.sock' % socket_path +self.do_migrate(dest_uri) + +@skipUnless(find_command('nc', default=False), "nc command not found on the system") +def test_migration_with_exec(self): +""" +The test works for both netcat-traditional and netcat-openbsd packages +""" +free_port = self._get_free_port() +dest_uri = 'exec:nc -l localhost %u' % free_port -- 2.21.1
[PATCH v3 0/2] Acceptance test: provides to use different transport for migration
This series makes refactoring to migration test and adds new tests with EXEC and UNIX protocols --- v2: - Removes unnecessary symbols and unused method v3: - Makes refactoring and split into 2 patches - Provides TCP and EXEC migration Oksana Vohchana (2): Acceptance test: provides to use different transport for migration Acceptance test: provides to use different transport for migration tests/acceptance/migration.py | 52 +-- 1 file changed, 37 insertions(+), 15 deletions(-) -- 2.21.1
[PATCH v3 1/2] Acceptance test: provides to use different transport for migration
Along with VM migration via TCP, we can use migration through EXEC and UNIX transport protocol Signed-off-by: Oksana Vohchana --- v2: - Removes unnecessary symbols and unused method v3: - Makes refactoring and split into 2 patches Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 36 --- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a44c1ae58f..34263d8eeb 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -24,6 +24,26 @@ class Migration(Test): def migration_finished(vm): return vm.command('query-migrate')['status'] in ('completed', 'failed') +def assert_migration(self, source_vm, dest_vm): +wait.wait_for(self.migration_finished, + timeout=self.timeout, + step=0.1, + args=(source_vm,)) +self.assertEqual(source_vm.command('query-migrate')['status'], 'completed') +self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed') +self.assertEqual(dest_vm.command('query-status')['status'], 'running') +self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate') + +def do_migrate(self, dest_uri, src_uri=None): +source_vm = self.get_vm() +dest_vm = self.get_vm('-incoming', dest_uri) +dest_vm.launch() +if src_uri is None: +src_uri = dest_uri +source_vm.launch() +source_vm.qmp('migrate', uri=src_uri) +self.assert_migration(source_vm, dest_vm) + def _get_free_port(self): port = network.find_free_port() if port is None: @@ -32,19 +52,5 @@ class Migration(Test): def test_migration_with_tcp_localhost(self): -source_vm = self.get_vm() dest_uri = 'tcp:localhost:%u' % self._get_free_port() -dest_vm = self.get_vm('-incoming', dest_uri) -dest_vm.launch() -source_vm.launch() -source_vm.qmp('migrate', uri=dest_uri) -wait.wait_for( -self.migration_finished, -timeout=self.timeout, -step=0.1, -args=(source_vm,) -) -self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed') -self.assertEqual(source_vm.command('query-migrate')['status'], 'completed') -self.assertEqual(dest_vm.command('query-status')['status'], 'running') -self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate') +self.do_migrate(dest_uri) -- 2.21.1
[PATCH v2 REPOST] Acceptance test: provides to use different transport for migration
Along with VM migration via TCP, we can use migration through EXEC and UNIX transport protocol Signed-off-by: Oksana Vohchana --- v2: - Removes unnecessary symbols and unused method --- tests/acceptance/migration.py | 51 --- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a44c1ae58f..1f6a674843 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -10,10 +10,13 @@ # later. See the COPYING file in the top-level directory. +import tempfile from avocado_qemu import Test +from avocado import skipUnless from avocado.utils import network from avocado.utils import wait +from avocado.utils.path import find_command class Migration(Test): @@ -24,6 +27,26 @@ class Migration(Test): def migration_finished(vm): return vm.command('query-migrate')['status'] in ('completed', 'failed') +def do_migrate(self, dest_uri, src_uri=None): +source_vm = self.get_vm() +dest_vm = self.get_vm('-incoming', dest_uri) +dest_vm.launch() +if src_uri is None: +src_uri = dest_uri +source_vm.launch() +source_vm.qmp('migrate', uri=src_uri) +self.assert_migration(source_vm, dest_vm) + +def assert_migration(self, source_vm, dest_vm): +wait.wait_for(self.migration_finished, + timeout=self.timeout, + step=0.1, + args=(source_vm,)) +self.assertEqual(source_vm.command('query-migrate')['status'], 'completed') +self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed') +self.assertEqual(dest_vm.command('query-status')['status'], 'running') +self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate') + def _get_free_port(self): port = network.find_free_port() if port is None: @@ -32,19 +55,17 @@ class Migration(Test): def test_migration_with_tcp_localhost(self): -source_vm = self.get_vm() dest_uri = 'tcp:localhost:%u' % self._get_free_port() -dest_vm = self.get_vm('-incoming', dest_uri) -dest_vm.launch() -source_vm.launch() -source_vm.qmp('migrate', uri=dest_uri) -wait.wait_for( -self.migration_finished, -timeout=self.timeout, -step=0.1, -args=(source_vm,) -) -self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed') -self.assertEqual(source_vm.command('query-migrate')['status'], 'completed') -self.assertEqual(dest_vm.command('query-status')['status'], 'running') -self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate') +self.do_migrate(dest_uri) + +def test_migration_with_unix(self): +with tempfile.TemporaryDirectory(prefix='socket_') as socket_path: +dest_uri = 'unix:%s/qemu-test.sock' % socket_path +self.do_migrate(dest_uri) + +@skipUnless(find_command('nc', default=False), "nc command not found on the system") +def test_migration_with_exec(self): +free_port = self._get_free_port() +dest_uri = 'exec:nc -l localhost %u' % free_port +src_uri = 'exec:nc localhost %u' % free_port +self.do_migrate(dest_uri, src_uri) -- 2.21.1
[PATCH v2] Acceptance test: provides to use different transport for migration
Along with VM migration via TCP, we can use migration through EXEC and UNIX transport protocol --- tests/acceptance/migration.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index 8bbe28d52d..1f6a674843 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -12,11 +12,11 @@ import tempfile from avocado_qemu import Test -from avocado import skipUnless\ +from avocado import skipUnless from avocado.utils import network from avocado.utils import wait -from avocado.utils.path import find_command, CmdNotFoundError +from avocado.utils.path import find_command class Migration(Test): @@ -62,6 +62,7 @@ class Migration(Test): with tempfile.TemporaryDirectory(prefix='socket_') as socket_path: dest_uri = 'unix:%s/qemu-test.sock' % socket_path self.do_migrate(dest_uri) + @skipUnless(find_command('nc', default=False), "nc command not found on the system") def test_migration_with_exec(self): free_port = self._get_free_port() -- 2.21.1
[PATCH] Acceptance test: provides to use different transport for migration
Along with VM migration via TCP, we can use migration through EXEC and UNIX transport protocol Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 50 --- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a44c1ae58f..8bbe28d52d 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -10,10 +10,13 @@ # later. See the COPYING file in the top-level directory. +import tempfile from avocado_qemu import Test +from avocado import skipUnless\ from avocado.utils import network from avocado.utils import wait +from avocado.utils.path import find_command, CmdNotFoundError class Migration(Test): @@ -24,6 +27,26 @@ class Migration(Test): def migration_finished(vm): return vm.command('query-migrate')['status'] in ('completed', 'failed') +def do_migrate(self, dest_uri, src_uri=None): +source_vm = self.get_vm() +dest_vm = self.get_vm('-incoming', dest_uri) +dest_vm.launch() +if src_uri is None: +src_uri = dest_uri +source_vm.launch() +source_vm.qmp('migrate', uri=src_uri) +self.assert_migration(source_vm, dest_vm) + +def assert_migration(self, source_vm, dest_vm): +wait.wait_for(self.migration_finished, + timeout=self.timeout, + step=0.1, + args=(source_vm,)) +self.assertEqual(source_vm.command('query-migrate')['status'], 'completed') +self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed') +self.assertEqual(dest_vm.command('query-status')['status'], 'running') +self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate') + def _get_free_port(self): port = network.find_free_port() if port is None: @@ -32,19 +55,16 @@ class Migration(Test): def test_migration_with_tcp_localhost(self): -source_vm = self.get_vm() dest_uri = 'tcp:localhost:%u' % self._get_free_port() -dest_vm = self.get_vm('-incoming', dest_uri) -dest_vm.launch() -source_vm.launch() -source_vm.qmp('migrate', uri=dest_uri) -wait.wait_for( -self.migration_finished, -timeout=self.timeout, -step=0.1, -args=(source_vm,) -) -self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed') -self.assertEqual(source_vm.command('query-migrate')['status'], 'completed') -self.assertEqual(dest_vm.command('query-status')['status'], 'running') -self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate') +self.do_migrate(dest_uri) + +def test_migration_with_unix(self): +with tempfile.TemporaryDirectory(prefix='socket_') as socket_path: +dest_uri = 'unix:%s/qemu-test.sock' % socket_path +self.do_migrate(dest_uri) +@skipUnless(find_command('nc', default=False), "nc command not found on the system") +def test_migration_with_exec(self): +free_port = self._get_free_port() +dest_uri = 'exec:nc -l localhost %u' % free_port +src_uri = 'exec:nc localhost %u' % free_port +self.do_migrate(dest_uri, src_uri) -- 2.21.1
[PATCH] Acceptance test: provides to use different transport for migration
Along with VM migration via TCP, we can use migration through EXEC and UNIX transport protocol Signed-off-by: Oksana Vohchana --- tests/acceptance/migration.py | 50 --- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a44c1ae58f..8bbe28d52d 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -10,10 +10,13 @@ # later. See the COPYING file in the top-level directory. +import tempfile from avocado_qemu import Test +from avocado import skipUnless\ from avocado.utils import network from avocado.utils import wait +from avocado.utils.path import find_command, CmdNotFoundError class Migration(Test): @@ -24,6 +27,26 @@ class Migration(Test): def migration_finished(vm): return vm.command('query-migrate')['status'] in ('completed', 'failed') +def do_migrate(self, dest_uri, src_uri=None): +source_vm = self.get_vm() +dest_vm = self.get_vm('-incoming', dest_uri) +dest_vm.launch() +if src_uri is None: +src_uri = dest_uri +source_vm.launch() +source_vm.qmp('migrate', uri=src_uri) +self.assert_migration(source_vm, dest_vm) + +def assert_migration(self, source_vm, dest_vm): +wait.wait_for(self.migration_finished, + timeout=self.timeout, + step=0.1, + args=(source_vm,)) +self.assertEqual(source_vm.command('query-migrate')['status'], 'completed') +self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed') +self.assertEqual(dest_vm.command('query-status')['status'], 'running') +self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate') + def _get_free_port(self): port = network.find_free_port() if port is None: @@ -32,19 +55,16 @@ class Migration(Test): def test_migration_with_tcp_localhost(self): -source_vm = self.get_vm() dest_uri = 'tcp:localhost:%u' % self._get_free_port() -dest_vm = self.get_vm('-incoming', dest_uri) -dest_vm.launch() -source_vm.launch() -source_vm.qmp('migrate', uri=dest_uri) -wait.wait_for( -self.migration_finished, -timeout=self.timeout, -step=0.1, -args=(source_vm,) -) -self.assertEqual(dest_vm.command('query-migrate')['status'], 'completed') -self.assertEqual(source_vm.command('query-migrate')['status'], 'completed') -self.assertEqual(dest_vm.command('query-status')['status'], 'running') -self.assertEqual(source_vm.command('query-status')['status'], 'postmigrate') +self.do_migrate(dest_uri) + +def test_migration_with_unix(self): +with tempfile.TemporaryDirectory(prefix='socket_') as socket_path: +dest_uri = 'unix:%s/qemu-test.sock' % socket_path +self.do_migrate(dest_uri) +@skipUnless(find_command('nc', default=False), "nc command not found on the system") +def test_migration_with_exec(self): +free_port = self._get_free_port() +dest_uri = 'exec:nc -l localhost %u' % free_port +src_uri = 'exec:nc localhost %u' % free_port +self.do_migrate(dest_uri, src_uri) -- 2.21.1