1#!/usr/bin/env python3 2# group: rw quick 3# 4# Tests for qmp command nbd-server-remove. 5# 6# Copyright (c) 2017 Virtuozzo International GmbH 7# 8# This program is free software; you can redistribute it and/or modify 9# it under the terms of the GNU General Public License as published by 10# the Free Software Foundation; either version 2 of the License, or 11# (at your option) any later version. 12# 13# This program is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16# GNU General Public License for more details. 17# 18# You should have received a copy of the GNU General Public License 19# along with this program. If not, see <http://www.gnu.org/licenses/>. 20# 21 22import os 23import sys 24import iotests 25import time 26from iotests import qemu_img_create, qemu_io, filter_qemu_io, QemuIoInteractive 27 28nbd_sock = os.path.join(iotests.sock_dir, 'nbd_sock') 29nbd_uri = 'nbd+unix:///exp?socket=' + nbd_sock 30disk = os.path.join(iotests.test_dir, 'disk') 31 32 33class TestNbdServerRemove(iotests.QMPTestCase): 34 def setUp(self): 35 qemu_img_create('-f', iotests.imgfmt, disk, '1M') 36 37 self.vm = iotests.VM().add_drive(disk) 38 self.vm.launch() 39 40 address = { 41 'type': 'unix', 42 'data': { 43 'path': nbd_sock 44 } 45 } 46 47 self.vm.cmd('nbd-server-start', addr=address) 48 self.vm.cmd('nbd-server-add', device='drive0', name='exp') 49 50 def tearDown(self): 51 self.vm.shutdown() 52 os.remove(nbd_sock) 53 os.remove(disk) 54 55 def remove_export(self, name, mode=None): 56 if mode is None: 57 return self.vm.qmp('nbd-server-remove', name=name) 58 else: 59 return self.vm.qmp('nbd-server-remove', name=name, mode=mode) 60 61 def assertExportNotFound(self, name): 62 result = self.vm.qmp('nbd-server-remove', name=name) 63 self.assert_qmp(result, 'error/desc', "Export 'exp' is not found") 64 65 def assertExistingClients(self, result): 66 self.assert_qmp(result, 'error/desc', "export 'exp' still in use") 67 68 def assertReadOk(self, qemu_io_output): 69 self.assertEqual( 70 filter_qemu_io(qemu_io_output).strip(), 71 'read 512/512 bytes at offset 0\n' + 72 '512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)') 73 74 def assertReadFailed(self, qemu_io_output): 75 self.assertEqual(filter_qemu_io(qemu_io_output).strip(), 76 'read failed: Input/output error') 77 78 def assertConnectFailed(self, qemu_io_output): 79 self.assertEqual(filter_qemu_io(qemu_io_output).strip(), 80 "qemu-io: can't open device " + nbd_uri + 81 ": Requested export not available\n" 82 "server reported: export 'exp' not present") 83 84 def do_test_connect_after_remove(self, mode=None): 85 args = ('-r', '-f', 'raw', '-c', 'read 0 512', nbd_uri) 86 self.assertReadOk(qemu_io(*args).stdout) 87 88 result = self.remove_export('exp', mode) 89 self.assert_qmp(result, 'return', {}) 90 91 self.assertExportNotFound('exp') 92 self.assertConnectFailed(qemu_io(*args, check=False).stdout) 93 94 def test_connect_after_remove_default(self): 95 self.do_test_connect_after_remove() 96 97 def test_connect_after_remove_safe(self): 98 self.do_test_connect_after_remove('safe') 99 100 def test_connect_after_remove_force(self): 101 self.do_test_connect_after_remove('hard') 102 103 def do_test_remove_during_connect_safe(self, mode=None): 104 qio = QemuIoInteractive('-r', '-f', 'raw', nbd_uri) 105 self.assertReadOk(qio.cmd('read 0 512')) 106 107 result = self.remove_export('exp', mode) 108 self.assertExistingClients(result) 109 110 self.assertReadOk(qio.cmd('read 0 512')) 111 112 qio.close() 113 114 result = self.remove_export('exp', mode) 115 self.assert_qmp(result, 'return', {}) 116 117 self.assertExportNotFound('exp') 118 119 def test_remove_during_connect_default(self): 120 self.do_test_remove_during_connect_safe() 121 122 def test_remove_during_connect_safe(self): 123 self.do_test_remove_during_connect_safe('safe') 124 125 def test_remove_during_connect_hard(self): 126 qio = QemuIoInteractive('-r', '-f', 'raw', nbd_uri) 127 self.assertReadOk(qio.cmd('read 0 512')) 128 129 result = self.remove_export('exp', 'hard') 130 self.assert_qmp(result, 'return', {}) 131 132 self.assertReadFailed(qio.cmd('read 0 512')) 133 self.assertExportNotFound('exp') 134 135 qio.close() 136 137 def test_remove_during_connect_safe_hard(self): 138 qio = QemuIoInteractive('-r', '-f', 'raw', nbd_uri) 139 self.assertReadOk(qio.cmd('read 0 512')) 140 141 result = self.remove_export('exp', 'safe') 142 self.assertExistingClients(result) 143 144 self.assertReadOk(qio.cmd('read 0 512')) 145 146 result = self.remove_export('exp', 'hard') 147 self.assert_qmp(result, 'return', {}) 148 149 self.assertExportNotFound('exp') 150 self.assertReadFailed(qio.cmd('read 0 512')) 151 qio.close() 152 153 154if __name__ == '__main__': 155 iotests.main(supported_fmts=['raw'], 156 supported_protocols=['nbd']) 157