| #!/usr/bin/env python3 |
| # |
| # Test NBD client reconnection |
| # |
| # Copyright (c) 2019 Virtuozzo International GmbH |
| # |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 2 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| # |
| |
| import os |
| import subprocess |
| import iotests |
| from iotests import file_path, log |
| |
| iotests.script_initialize() |
| |
| |
| nbd_sock, conf_file = file_path('nbd-sock', 'nbd-fault-injector.conf') |
| |
| |
| def make_conf_file(event): |
| """ |
| Create configuration file for the nbd-fault-injector.py |
| |
| :param event: which event the server should close a connection on |
| """ |
| with open(conf_file, 'w') as conff: |
| conff.write('[inject-error]\nevent={}\nwhen=after'.format(event)) |
| |
| |
| def start_server_NBD(event): |
| make_conf_file(event) |
| |
| srv = subprocess.Popen(['nbd-fault-injector.py', '--classic-negotiation', |
| nbd_sock, conf_file], stdout=subprocess.PIPE, |
| stderr=subprocess.STDOUT, universal_newlines=True) |
| line = srv.stdout.readline() |
| if 'Listening on ' in line: |
| log('NBD server: started') |
| else: |
| log('NBD server: ' + line.rstrip()) |
| |
| return srv |
| |
| |
| def start_client_NBD(): |
| log('NBD client: QEMU-IO write') |
| args = iotests.qemu_io_args_no_fmt + \ |
| ['-c', 'write -P 0x7 0 3M', '--image-opts', |
| 'driver=nbd,server.type=unix,server.path={},' |
| 'reconnect-delay=7'.format(nbd_sock)] |
| clt = subprocess.Popen(args, stdout=subprocess.PIPE, |
| stderr=subprocess.STDOUT, |
| universal_newlines=True) |
| return clt |
| |
| |
| def check_proc_NBD(proc, connector): |
| try: |
| outs, errs = proc.communicate(timeout=10) |
| |
| if proc.returncode < 0: |
| log('NBD {}: EXIT SIGNAL {}\n'.format(connector, proc.returncode)) |
| log(outs) |
| else: |
| msg = outs.split('\n', 1) |
| log('NBD {}: {}'.format(connector, msg[0])) |
| |
| except subprocess.TimeoutExpired: |
| proc.kill() |
| log('NBD {}: ERROR timeout expired'.format(connector)) |
| finally: |
| if connector == 'server': |
| os.remove(nbd_sock) |
| os.remove(conf_file) |
| |
| |
| srv = start_server_NBD('data') |
| clt = start_client_NBD() |
| # The server should close the connection after a client write request |
| check_proc_NBD(srv, 'server') |
| # Start the NBD server again |
| srv = start_server_NBD('reply') |
| # The client should reconnect and complete the write operation |
| check_proc_NBD(clt, 'client') |
| # Make it sure that server terminated |
| check_proc_NBD(srv, 'server') |