|
@@ -0,0 +1,156 @@
|
|
|
|
+#!/usr/bin/env python
|
|
|
|
+#
|
|
|
|
+# Tests for qmp command nbd-server-remove.
|
|
|
|
+#
|
|
|
|
+# Copyright (c) 2017 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 sys
|
|
|
|
+import iotests
|
|
|
|
+import time
|
|
|
|
+from iotests import qemu_img, qemu_io, filter_qemu_io, QemuIoInteractive
|
|
|
|
+
|
|
|
|
+nbd_sock = 'nbd_sock'
|
|
|
|
+nbd_uri = 'nbd+unix:///exp?socket=' + nbd_sock
|
|
|
|
+disk = os.path.join(iotests.test_dir, 'disk')
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class TestNbdServerRemove(iotests.QMPTestCase):
|
|
|
|
+ def setUp(self):
|
|
|
|
+ qemu_img('create', '-f', iotests.imgfmt, disk, '1M')
|
|
|
|
+
|
|
|
|
+ self.vm = iotests.VM().add_drive(disk)
|
|
|
|
+ self.vm.launch()
|
|
|
|
+
|
|
|
|
+ address = {
|
|
|
|
+ 'type': 'unix',
|
|
|
|
+ 'data': {
|
|
|
|
+ 'path': nbd_sock
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ result = self.vm.qmp('nbd-server-start', addr=address)
|
|
|
|
+ self.assert_qmp(result, 'return', {})
|
|
|
|
+ result = self.vm.qmp('nbd-server-add', device='drive0', name='exp')
|
|
|
|
+ self.assert_qmp(result, 'return', {})
|
|
|
|
+
|
|
|
|
+ def tearDown(self):
|
|
|
|
+ self.vm.shutdown()
|
|
|
|
+ os.remove(nbd_sock)
|
|
|
|
+ os.remove(disk)
|
|
|
|
+
|
|
|
|
+ def remove_export(self, name, mode=None):
|
|
|
|
+ if mode is None:
|
|
|
|
+ return self.vm.qmp('nbd-server-remove', name=name)
|
|
|
|
+ else:
|
|
|
|
+ return self.vm.qmp('nbd-server-remove', name=name, mode=mode)
|
|
|
|
+
|
|
|
|
+ def assertExportNotFound(self, name):
|
|
|
|
+ result = self.vm.qmp('nbd-server-remove', name=name)
|
|
|
|
+ self.assert_qmp(result, 'error/desc', "Export 'exp' is not found")
|
|
|
|
+
|
|
|
|
+ def assertExistingClients(self, result):
|
|
|
|
+ self.assert_qmp(result, 'error/desc', "export 'exp' still in use")
|
|
|
|
+
|
|
|
|
+ def assertReadOk(self, qemu_io_output):
|
|
|
|
+ self.assertEqual(
|
|
|
|
+ filter_qemu_io(qemu_io_output).strip(),
|
|
|
|
+ 'read 512/512 bytes at offset 0\n' +
|
|
|
|
+ '512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)')
|
|
|
|
+
|
|
|
|
+ def assertReadFailed(self, qemu_io_output):
|
|
|
|
+ self.assertEqual(filter_qemu_io(qemu_io_output).strip(),
|
|
|
|
+ 'read failed: Input/output error')
|
|
|
|
+
|
|
|
|
+ def assertConnectFailed(self, qemu_io_output):
|
|
|
|
+ self.assertEqual(filter_qemu_io(qemu_io_output).strip(),
|
|
|
|
+ "can't open device " + nbd_uri +
|
|
|
|
+ ": Requested export not available\n"
|
|
|
|
+ "server reported: export 'exp' not present")
|
|
|
|
+
|
|
|
|
+ def do_test_connect_after_remove(self, mode=None):
|
|
|
|
+ args = ('-r', '-f', 'raw', '-c', 'read 0 512', nbd_uri)
|
|
|
|
+ self.assertReadOk(qemu_io(*args))
|
|
|
|
+
|
|
|
|
+ result = self.remove_export('exp', mode)
|
|
|
|
+ self.assert_qmp(result, 'return', {})
|
|
|
|
+
|
|
|
|
+ self.assertExportNotFound('exp')
|
|
|
|
+ self.assertConnectFailed(qemu_io(*args))
|
|
|
|
+
|
|
|
|
+ def test_connect_after_remove_default(self):
|
|
|
|
+ self.do_test_connect_after_remove()
|
|
|
|
+
|
|
|
|
+ def test_connect_after_remove_safe(self):
|
|
|
|
+ self.do_test_connect_after_remove('safe')
|
|
|
|
+
|
|
|
|
+ def test_connect_after_remove_force(self):
|
|
|
|
+ self.do_test_connect_after_remove('hard')
|
|
|
|
+
|
|
|
|
+ def do_test_remove_during_connect_safe(self, mode=None):
|
|
|
|
+ qio = QemuIoInteractive('-r', '-f', 'raw', nbd_uri)
|
|
|
|
+ self.assertReadOk(qio.cmd('read 0 512'))
|
|
|
|
+
|
|
|
|
+ result = self.remove_export('exp', mode)
|
|
|
|
+ self.assertExistingClients(result)
|
|
|
|
+
|
|
|
|
+ self.assertReadOk(qio.cmd('read 0 512'))
|
|
|
|
+
|
|
|
|
+ qio.close()
|
|
|
|
+
|
|
|
|
+ result = self.remove_export('exp', mode)
|
|
|
|
+ self.assert_qmp(result, 'return', {})
|
|
|
|
+
|
|
|
|
+ self.assertExportNotFound('exp')
|
|
|
|
+
|
|
|
|
+ def test_remove_during_connect_default(self):
|
|
|
|
+ self.do_test_remove_during_connect_safe()
|
|
|
|
+
|
|
|
|
+ def test_remove_during_connect_safe(self):
|
|
|
|
+ self.do_test_remove_during_connect_safe('safe')
|
|
|
|
+
|
|
|
|
+ def test_remove_during_connect_hard(self):
|
|
|
|
+ qio = QemuIoInteractive('-r', '-f', 'raw', nbd_uri)
|
|
|
|
+ self.assertReadOk(qio.cmd('read 0 512'))
|
|
|
|
+
|
|
|
|
+ result = self.remove_export('exp', 'hard')
|
|
|
|
+ self.assert_qmp(result, 'return', {})
|
|
|
|
+
|
|
|
|
+ self.assertReadFailed(qio.cmd('read 0 512'))
|
|
|
|
+ self.assertExportNotFound('exp')
|
|
|
|
+
|
|
|
|
+ qio.close()
|
|
|
|
+
|
|
|
|
+ def test_remove_during_connect_safe_hard(self):
|
|
|
|
+ qio = QemuIoInteractive('-r', '-f', 'raw', nbd_uri)
|
|
|
|
+ self.assertReadOk(qio.cmd('read 0 512'))
|
|
|
|
+
|
|
|
|
+ result = self.remove_export('exp', 'safe')
|
|
|
|
+ self.assertExistingClients(result)
|
|
|
|
+
|
|
|
|
+ self.assertReadOk(qio.cmd('read 0 512'))
|
|
|
|
+
|
|
|
|
+ result = self.remove_export('exp', 'hard')
|
|
|
|
+ self.assert_qmp(result, 'return', {})
|
|
|
|
+
|
|
|
|
+ self.assertExportNotFound('exp')
|
|
|
|
+ self.assertReadFailed(qio.cmd('read 0 512'))
|
|
|
|
+ qio.close()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+if __name__ == '__main__':
|
|
|
|
+ iotests.main()
|