[PATCH v3 0/3] Acceptance test: Migration mechanism with FD

2020-02-26 Thread Oksana Vohchana
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 v3 1/3] python/qemu/machine: Adding functions _send_fds and _recv_fds

2020-02-26 Thread Oksana Vohchana
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 2/3] python/qemu/machine: Updates send_fd_scm function

2020-02-26 Thread Oksana Vohchana
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 3/3] Acceptance test: add FD migration

2020-02-26 Thread Oksana Vohchana
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] python/qemu/qmp.py: QMP debug with VM label

2020-03-04 Thread Oksana Vohchana
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 v2 3/4] Acceptance test: provides new functions

2020-02-25 Thread Oksana Vohchana
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

2020-02-25 Thread Oksana Vohchana
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 0/4] Acceptance test: Extension of migration tests

2020-02-25 Thread Oksana Vohchana
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 1/4] Acceptance test: adds param 'address' in _get_free_port

2020-02-25 Thread Oksana Vohchana
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 2/4] Acceptance test: EXEC migration

2020-02-25 Thread Oksana Vohchana
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] Acceptance test: provides to use different transport for migration

2020-01-23 Thread Oksana Vohchana
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 v3 0/2] Acceptance test: provides to use different transport for migration

2020-02-03 Thread Oksana Vohchana
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

2020-02-03 Thread Oksana Vohchana
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 2/2] Acceptance test: provides to use different transport for migration

2020-02-03 Thread Oksana Vohchana
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

2020-02-03 Thread Oksana Vohchana
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

2020-02-03 Thread Oksana Vohchana
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 2/2] Acceptance test: provides to use different transport for migration

2020-02-03 Thread Oksana Vohchana
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 v2 REPOST] Acceptance test: provides to use different transport for migration

2020-01-30 Thread Oksana Vohchana
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] Acceptance test: provides to use different transport for migration

2020-01-23 Thread Oksana Vohchana
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 v2] Acceptance test: provides to use different transport for migration

2020-01-29 Thread Oksana Vohchana
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 v1 0/4] Extension of migration tests

2020-02-14 Thread Oksana Vohchana
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 v1 2/4] Acceptance test: EXEC migration

2020-02-14 Thread Oksana Vohchana
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

2020-02-14 Thread Oksana Vohchana
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 1/4] Acceptance test: add address as param

2020-02-14 Thread Oksana Vohchana
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 4/4] Acceptance test: provides to use RDMA transport for migration

2020-02-14 Thread Oksana Vohchana
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 v2 3/3] Acceptance test: FD migration

2020-02-20 Thread Oksana Vohchana
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 2/3] Updates send_fd_scm function

2020-02-20 Thread Oksana Vohchana
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 1/3] Adding functions _send_fds and _recv_fds

2020-02-20 Thread Oksana Vohchana
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 0/3] Migration mechanism with FD

2020-02-20 Thread Oksana Vohchana
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 0/3] Migration mechanism with FD

2020-02-19 Thread Oksana Vohchana
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 1/3] Adding functions _send_fds and _recv_fds

2020-02-19 Thread Oksana Vohchana
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

2020-02-19 Thread Oksana Vohchana
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 2/3] Updates send_fd_scm function

2020-02-19 Thread Oksana Vohchana
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 v2] python/qemu/qmp.py: QMP debug with VM label

2020-03-12 Thread Oksana Vohchana
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 v3] python/qemu/qmp.py: QMP debug with VM label

2020-03-12 Thread Oksana Vohchana
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 v5 0/3] Acceptance test: Extension of migration tests

2020-04-07 Thread Oksana Vohchana
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 v5 1/3] Acceptance test: adds param 'address' in _get_free_port

2020-04-07 Thread Oksana Vohchana
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 3/3] Acceptance test: provides to use RDMA transport for migration test

2020-04-07 Thread Oksana Vohchana
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 2/3] Acceptance test: provides new functions

2020-04-07 Thread Oksana Vohchana
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 v4] python/qemu/qmp.py: QMP debug with VM label

2020-03-16 Thread Oksana Vohchana
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] Acceptance test: Fix to EXEC migration

2020-03-25 Thread Oksana Vohchana
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 v3 2/3] Acceptance test: provides new functions

2020-03-20 Thread Oksana Vohchana
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 1/3] Acceptance test: adds param 'address' in _get_free_port

2020-03-20 Thread Oksana Vohchana
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 3/3] Acceptance test: provides to use RDMA transport for migration test

2020-03-20 Thread Oksana Vohchana
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 0/3] Acceptance test: Extension of migration tests

2020-03-20 Thread Oksana Vohchana
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 3/3] Acceptance test: provides to use RDMA transport for migration test

2020-03-23 Thread Oksana Vohchana
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

2020-03-23 Thread Oksana Vohchana
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

2020-03-23 Thread Oksana Vohchana
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 v4 1/3] Acceptance test: adds param 'address' in _get_free_port

2020-03-23 Thread Oksana Vohchana
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