Best Python code snippet using lisa_python
test_volume.py
Source:test_volume.py
1# Copyright 2010 OpenStack Foundation2# Copyright 2012 University Of Minho3#4# Licensed under the Apache License, Version 2.0 (the "License"); you may5# not use this file except in compliance with the License. You may obtain6# a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing, software11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the13# License for the specific language governing permissions and limitations14# under the License.15import contextlib16import glob17import os18import platform19import time20import eventlet21import fixtures22import mock23from oslo_concurrency import processutils24from oslo_config import cfg25from nova.compute import arch26from nova import exception27from nova.storage import linuxscsi28from nova import test29from nova.tests.unit.virt.libvirt import fake_libvirt_utils30from nova.tests.unit.virt.libvirt import fakelibvirt31from nova import utils32from nova.virt.libvirt import host33from nova.virt.libvirt import quobyte34from nova.virt.libvirt import utils as libvirt_utils35from nova.virt.libvirt import volume36CONF = cfg.CONF37SECRET_UUID = '2a0a0d6c-babf-454d-b93e-9ac9957b95e0'38class FakeSecret(object):39 def __init__(self):40 self.uuid = SECRET_UUID41 def getUUIDString(self):42 return self.uuid43 def UUIDString(self):44 return self.uuid45 def setValue(self, value):46 self.value = value47 return 048 def getValue(self, value):49 return self.value50 def undefine(self):51 self.value = None52 return 053class LibvirtVolumeTestCase(test.NoDBTestCase):54 def setUp(self):55 super(LibvirtVolumeTestCase, self).setUp()56 self.executes = []57 def fake_execute(*cmd, **kwargs):58 self.executes.append(cmd)59 return None, None60 self.stubs.Set(utils, 'execute', fake_execute)61 self.useFixture(fakelibvirt.FakeLibvirtFixture())62 class FakeLibvirtDriver(object):63 def __init__(self):64 self._host = host.Host("qemu:///system")65 def _get_all_block_devices(self):66 return []67 self.fake_conn = FakeLibvirtDriver()68 self.connr = {69 'ip': '127.0.0.1',70 'initiator': 'fake_initiator',71 'host': 'fake_host'72 }73 self.disk_info = {74 "bus": "virtio",75 "dev": "vde",76 "type": "disk",77 }78 self.name = 'volume-00000001'79 self.location = '10.0.2.15:3260'80 self.iqn = 'iqn.2010-10.org.openstack:%s' % self.name81 self.vol = {'id': 1, 'name': self.name}82 self.uuid = '875a8070-d0b9-4949-8b31-104d125c9a64'83 self.user = 'foo'84 def _assertNetworkAndProtocolEquals(self, tree):85 self.assertEqual(tree.get('type'), 'network')86 self.assertEqual(tree.find('./source').get('protocol'), 'rbd')87 rbd_name = '%s/%s' % ('rbd', self.name)88 self.assertEqual(tree.find('./source').get('name'), rbd_name)89 def _assertISCSINetworkAndProtocolEquals(self, tree):90 self.assertEqual(tree.get('type'), 'network')91 self.assertEqual(tree.find('./source').get('protocol'), 'iscsi')92 iscsi_name = '%s/%s' % (self.iqn, self.vol['id'])93 self.assertEqual(tree.find('./source').get('name'), iscsi_name)94 def _assertFileTypeEquals(self, tree, file_path):95 self.assertEqual(tree.get('type'), 'file')96 self.assertEqual(tree.find('./source').get('file'), file_path)97 def _assertDiskInfoEquals(self, tree, disk_info):98 self.assertEqual(tree.get('device'), disk_info['type'])99 self.assertEqual(tree.find('./target').get('bus'),100 disk_info['bus'])101 self.assertEqual(tree.find('./target').get('dev'),102 disk_info['dev'])103 def _test_libvirt_volume_driver_disk_info(self):104 libvirt_driver = volume.LibvirtVolumeDriver(self.fake_conn)105 connection_info = {106 'driver_volume_type': 'fake',107 'data': {108 'device_path': '/foo',109 },110 'serial': 'fake_serial',111 }112 conf = libvirt_driver.get_config(connection_info, self.disk_info)113 tree = conf.format_dom()114 self._assertDiskInfoEquals(tree, self.disk_info)115 def test_libvirt_volume_disk_info_type(self):116 self.disk_info['type'] = 'cdrom'117 self._test_libvirt_volume_driver_disk_info()118 def test_libvirt_volume_disk_info_dev(self):119 self.disk_info['dev'] = 'hdc'120 self._test_libvirt_volume_driver_disk_info()121 def test_libvirt_volume_disk_info_bus(self):122 self.disk_info['bus'] = 'scsi'123 self._test_libvirt_volume_driver_disk_info()124 def test_libvirt_volume_driver_serial(self):125 libvirt_driver = volume.LibvirtVolumeDriver(self.fake_conn)126 connection_info = {127 'driver_volume_type': 'fake',128 'data': {129 'device_path': '/foo',130 },131 'serial': 'fake_serial',132 }133 conf = libvirt_driver.get_config(connection_info, self.disk_info)134 tree = conf.format_dom()135 self.assertEqual('block', tree.get('type'))136 self.assertEqual('fake_serial', tree.find('./serial').text)137 self.assertIsNone(tree.find('./blockio'))138 def test_libvirt_volume_driver_blockio(self):139 libvirt_driver = volume.LibvirtVolumeDriver(self.fake_conn)140 connection_info = {141 'driver_volume_type': 'fake',142 'data': {143 'device_path': '/foo',144 'logical_block_size': '4096',145 'physical_block_size': '4096',146 },147 'serial': 'fake_serial',148 }149 disk_info = {150 "bus": "virtio",151 "dev": "vde",152 "type": "disk",153 }154 conf = libvirt_driver.get_config(connection_info, disk_info)155 tree = conf.format_dom()156 blockio = tree.find('./blockio')157 self.assertEqual('4096', blockio.get('logical_block_size'))158 self.assertEqual('4096', blockio.get('physical_block_size'))159 def test_libvirt_volume_driver_iotune(self):160 libvirt_driver = volume.LibvirtVolumeDriver(self.fake_conn)161 connection_info = {162 'driver_volume_type': 'fake',163 'data': {164 "device_path": "/foo",165 'qos_specs': 'bar',166 },167 }168 disk_info = {169 "bus": "virtio",170 "dev": "vde",171 "type": "disk",172 }173 conf = libvirt_driver.get_config(connection_info, disk_info)174 tree = conf.format_dom()175 iotune = tree.find('./iotune')176 # ensure invalid qos_specs is ignored177 self.assertIsNone(iotune)178 specs = {179 'total_bytes_sec': '102400',180 'read_bytes_sec': '51200',181 'write_bytes_sec': '0',182 'total_iops_sec': '0',183 'read_iops_sec': '200',184 'write_iops_sec': '200',185 }186 del connection_info['data']['qos_specs']187 connection_info['data'].update(dict(qos_specs=specs))188 conf = libvirt_driver.get_config(connection_info, disk_info)189 tree = conf.format_dom()190 self.assertEqual('102400', tree.find('./iotune/total_bytes_sec').text)191 self.assertEqual('51200', tree.find('./iotune/read_bytes_sec').text)192 self.assertEqual('0', tree.find('./iotune/write_bytes_sec').text)193 self.assertEqual('0', tree.find('./iotune/total_iops_sec').text)194 self.assertEqual('200', tree.find('./iotune/read_iops_sec').text)195 self.assertEqual('200', tree.find('./iotune/write_iops_sec').text)196 def test_libvirt_volume_driver_readonly(self):197 libvirt_driver = volume.LibvirtVolumeDriver(self.fake_conn)198 connection_info = {199 'driver_volume_type': 'fake',200 'data': {201 "device_path": "/foo",202 'access_mode': 'bar',203 },204 }205 disk_info = {206 "bus": "virtio",207 "dev": "vde",208 "type": "disk",209 }210 self.assertRaises(exception.InvalidVolumeAccessMode,211 libvirt_driver.get_config,212 connection_info, self.disk_info)213 connection_info['data']['access_mode'] = 'rw'214 conf = libvirt_driver.get_config(connection_info, disk_info)215 tree = conf.format_dom()216 readonly = tree.find('./readonly')217 self.assertIsNone(readonly)218 connection_info['data']['access_mode'] = 'ro'219 conf = libvirt_driver.get_config(connection_info, disk_info)220 tree = conf.format_dom()221 readonly = tree.find('./readonly')222 self.assertIsNotNone(readonly)223 def iscsi_connection(self, volume, location, iqn, auth=False,224 transport=None):225 dev_name = 'ip-%s-iscsi-%s-lun-1' % (location, iqn)226 if transport is not None:227 dev_name = 'pci-0000:00:00.0-' + dev_name228 dev_path = '/dev/disk/by-path/%s' % (dev_name)229 ret = {230 'driver_volume_type': 'iscsi',231 'data': {232 'volume_id': volume['id'],233 'target_portal': location,234 'target_iqn': iqn,235 'target_lun': 1,236 'device_path': dev_path,237 'qos_specs': {238 'total_bytes_sec': '102400',239 'read_iops_sec': '200',240 }241 }242 }243 if auth:244 ret['data']['auth_method'] = 'CHAP'245 ret['data']['auth_username'] = 'foo'246 ret['data']['auth_password'] = 'bar'247 return ret248 def iscsi_connection_discovery_chap_enable(self, volume, location, iqn):249 dev_name = 'ip-%s-iscsi-%s-lun-1' % (location, iqn)250 dev_path = '/dev/disk/by-path/%s' % (dev_name)251 return {252 'driver_volume_type': 'iscsi',253 'data': {254 'volume_id': volume['id'],255 'target_portal': location,256 'target_iqn': iqn,257 'target_lun': 1,258 'device_path': dev_path,259 'discovery_auth_method': 'CHAP',260 'discovery_auth_username': "testuser",261 'discovery_auth_password': '123456',262 'qos_specs': {263 'total_bytes_sec': '102400',264 'read_iops_sec': '200',265 }266 }267 }268 def generate_device(self, transport=None, lun=1, short=False):269 dev_format = "ip-%s-iscsi-%s-lun-%s" % (self.location, self.iqn, lun)270 if transport:271 dev_format = "pci-0000:00:00.0-" + dev_format272 if short:273 return dev_format274 fake_dev_path = "/dev/disk/by-path/" + dev_format275 return fake_dev_path276 def test_rescan_multipath(self):277 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)278 libvirt_driver._rescan_multipath()279 expected_multipath_cmd = ('multipath', '-r')280 self.assertIn(expected_multipath_cmd, self.executes)281 def test_iscsiadm_discover_parsing(self):282 # Ensure that parsing iscsiadm discover ignores cruft.283 targets = [284 ["192.168.204.82:3260,1",285 ("iqn.2010-10.org.openstack:volume-"286 "f9b12623-6ce3-4dac-a71f-09ad4249bdd3")],287 ["192.168.204.82:3261,1",288 ("iqn.2010-10.org.openstack:volume-"289 "f9b12623-6ce3-4dac-a71f-09ad4249bdd4")]]290 # This slight wonkiness brought to you by pep8, as the actual291 # example output runs about 97 chars wide.292 sample_input = """Loading iscsi modules: done293Starting iSCSI initiator service: done294Setting up iSCSI targets: unused295%s %s296%s %s297""" % (targets[0][0], targets[0][1], targets[1][0], targets[1][1])298 driver = volume.LibvirtISCSIVolumeDriver("none")299 out = driver._get_target_portals_from_iscsiadm_output(sample_input)300 self.assertEqual(out, targets)301 def test_libvirt_iscsi_get_host_device(self, transport=None):302 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)303 connection_info = self.iscsi_connection(self.vol, self.location,304 self.iqn)305 iscsi_properties = connection_info['data']306 expected_device = self.generate_device(transport, 1, False)307 if transport:308 self.stubs.Set(glob, 'glob', lambda x: [expected_device])309 self.stubs.Set(libvirt_driver, '_validate_transport',310 lambda x: True)311 device = libvirt_driver._get_host_device(iscsi_properties)312 self.assertEqual(expected_device, device)313 def test_libvirt_iscsi_get_host_device_with_transport(self):314 self.flags(iscsi_iface='fake_transport', group='libvirt')315 self.test_libvirt_iscsi_get_host_device('fake_transport')316 @mock.patch.object(volume.utils, 'execute')317 def test_libvirt_iscsi_validate_transport(self, mock_execute):318 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)319 sample_output = ('# BEGIN RECORD 2.0-872\n'320 'iface.iscsi_ifacename = %s.fake_suffix\n'321 'iface.net_ifacename = <empty>\n'322 'iface.ipaddress = <empty>\n'323 'iface.hwaddress = 00:53:00:00:53:00\n'324 'iface.transport_name = %s\n'325 'iface.initiatorname = <empty>\n'326 '# END RECORD')327 for tport in libvirt_driver.supported_transports:328 mock_execute.return_value = (sample_output % (tport, tport), '')329 self.assertTrue(libvirt_driver._validate_transport(330 tport + '.fake_suffix'))331 mock_execute.return_value = ("", 'iscsiadm: Could not '332 'read iface fake_transport (6)')333 self.assertFalse(libvirt_driver._validate_transport('fake_transport'))334 def test_libvirt_iscsi_driver(self, transport=None):335 # NOTE(vish) exists is to make driver assume connecting worked336 self.stubs.Set(os.path, 'exists', lambda x: True)337 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)338 connection_info = self.iscsi_connection(self.vol, self.location,339 self.iqn, False, transport)340 if transport is not None:341 self.stubs.Set(libvirt_driver, '_get_host_device',342 lambda x: self.generate_device(transport, 1, False))343 self.stubs.Set(libvirt_driver, '_validate_transport',344 lambda x: True)345 libvirt_driver.connect_volume(connection_info, self.disk_info)346 libvirt_driver.disconnect_volume(connection_info, "vde")347 expected_commands = [('iscsiadm', '-m', 'node', '-T', self.iqn,348 '-p', self.location),349 ('iscsiadm', '-m', 'session'),350 ('iscsiadm', '-m', 'node', '-T', self.iqn,351 '-p', self.location, '--login'),352 ('iscsiadm', '-m', 'node', '-T', self.iqn,353 '-p', self.location, '--op', 'update',354 '-n', 'node.startup', '-v', 'automatic'),355 ('iscsiadm', '-m', 'node', '-T', self.iqn,356 '-p', self.location, '--rescan'),357 ('iscsiadm', '-m', 'node', '-T', self.iqn,358 '-p', self.location, '--op', 'update',359 '-n', 'node.startup', '-v', 'manual'),360 ('iscsiadm', '-m', 'node', '-T', self.iqn,361 '-p', self.location, '--logout'),362 ('iscsiadm', '-m', 'node', '-T', self.iqn,363 '-p', self.location, '--op', 'delete')]364 self.assertEqual(expected_commands, self.executes)365 def test_libvirt_iscsi_driver_with_transport(self):366 self.flags(iscsi_iface='fake_transport', group='libvirt')367 self.test_libvirt_iscsi_driver('fake_transport')368 def test_libvirt_iscsi_driver_still_in_use(self, transport=None):369 # NOTE(vish) exists is to make driver assume connecting worked370 self.stubs.Set(os.path, 'exists', lambda x: True)371 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)372 dev_name = self.generate_device(transport, 1, True)373 if transport is not None:374 self.stubs.Set(libvirt_driver, '_get_host_device',375 lambda x: self.generate_device(transport, 1, False))376 self.stubs.Set(libvirt_driver, '_validate_transport',377 lambda x: True)378 devs = [self.generate_device(transport, 2, False)]379 self.stubs.Set(self.fake_conn, '_get_all_block_devices', lambda: devs)380 vol = {'id': 1, 'name': self.name}381 connection_info = self.iscsi_connection(vol, self.location, self.iqn)382 libvirt_driver.connect_volume(connection_info, self.disk_info)383 libvirt_driver.disconnect_volume(connection_info, "vde")384 expected_commands = [('iscsiadm', '-m', 'node', '-T', self.iqn,385 '-p', self.location),386 ('iscsiadm', '-m', 'session'),387 ('iscsiadm', '-m', 'node', '-T', self.iqn,388 '-p', self.location, '--login'),389 ('iscsiadm', '-m', 'node', '-T', self.iqn,390 '-p', self.location, '--op', 'update',391 '-n', 'node.startup', '-v', 'automatic'),392 ('iscsiadm', '-m', 'node', '-T', self.iqn,393 '-p', self.location, '--rescan'),394 ('cp', '/dev/stdin',395 '/sys/block/%s/device/delete' % dev_name)]396 self.assertEqual(self.executes, expected_commands)397 def test_libvirt_iscsi_driver_still_in_use_with_transport(self):398 self.flags(iscsi_iface='fake_transport', group='libvirt')399 self.test_libvirt_iscsi_driver_still_in_use('fake_transport')400 def test_libvirt_iscsi_driver_disconnect_multipath_error(self,401 transport=None):402 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)403 if transport is None:404 prefix = ""405 else:406 prefix = "pci-0000:00:00.0-"407 devs = [self.generate_device(transport, 2, False)]408 iscsi_devs = ['%sip-fake-ip-iscsi-fake-portal-lun-2' % prefix]409 with contextlib.nested(410 mock.patch.object(os.path, 'exists', return_value=True),411 mock.patch.object(self.fake_conn, '_get_all_block_devices',412 return_value=devs),413 mock.patch.object(libvirt_driver, '_rescan_multipath'),414 mock.patch.object(libvirt_driver, '_run_multipath'),415 mock.patch.object(libvirt_driver, '_get_multipath_device_name',416 return_value='/dev/mapper/fake-multipath-devname'),417 mock.patch.object(libvirt_driver, '_get_iscsi_devices',418 return_value=iscsi_devs),419 mock.patch.object(libvirt_driver,420 '_get_target_portals_from_iscsiadm_output',421 return_value=[('fake-ip', 'fake-portal')]),422 mock.patch.object(libvirt_driver, '_get_multipath_iqn',423 return_value='fake-portal'),424 ) as (mock_exists, mock_devices, mock_rescan_multipath,425 mock_run_multipath, mock_device_name, mock_iscsi_devices,426 mock_get_portals, mock_get_iqn):427 mock_run_multipath.side_effect = processutils.ProcessExecutionError428 vol = {'id': 1, 'name': self.name}429 connection_info = self.iscsi_connection(vol, self.location,430 self.iqn)431 libvirt_driver.connect_volume(connection_info, self.disk_info)432 libvirt_driver.use_multipath = True433 libvirt_driver.disconnect_volume(connection_info, "vde")434 mock_run_multipath.assert_called_once_with(435 ['-f', 'fake-multipath-devname'],436 check_exit_code=[0, 1])437 def test_libvirt_iscsi_driver_get_config(self, transport=None):438 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)439 dev_name = self.generate_device(transport, 1, True)440 dev_path = '/dev/disk/by-path/%s' % (dev_name)441 vol = {'id': 1, 'name': self.name}442 connection_info = self.iscsi_connection(vol, self.location,443 self.iqn, False, transport)444 conf = libvirt_driver.get_config(connection_info, self.disk_info)445 tree = conf.format_dom()446 self.assertEqual('block', tree.get('type'))447 self.assertEqual(dev_path, tree.find('./source').get('dev'))448 libvirt_driver.use_multipath = True449 conf = libvirt_driver.get_config(connection_info, self.disk_info)450 tree = conf.format_dom()451 self.assertEqual('block', tree.get('type'))452 self.assertEqual(dev_path, tree.find('./source').get('dev'))453 def test_libvirt_iscsi_driver_get_config_with_transport(self):454 self.flags(iscsi_iface = 'fake_transport', group='libvirt')455 self.test_libvirt_iscsi_driver_get_config('fake_transport')456 def test_libvirt_iscsi_driver_multipath_id(self):457 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)458 libvirt_driver.use_multipath = True459 self.stubs.Set(libvirt_driver, '_run_iscsiadm_bare',460 lambda x, check_exit_code: ('',))461 self.stubs.Set(libvirt_driver, '_rescan_iscsi', lambda: None)462 self.stubs.Set(libvirt_driver, '_get_host_device', lambda x: None)463 self.stubs.Set(libvirt_driver, '_rescan_multipath', lambda: None)464 fake_multipath_id = 'fake_multipath_id'465 fake_multipath_device = '/dev/mapper/%s' % fake_multipath_id466 self.stubs.Set(libvirt_driver, '_get_multipath_device_name',467 lambda x: fake_multipath_device)468 def fake_disconnect_volume_multipath_iscsi(iscsi_properties,469 multipath_device):470 if fake_multipath_device != multipath_device:471 raise Exception('Invalid multipath_device.')472 self.stubs.Set(libvirt_driver, '_disconnect_volume_multipath_iscsi',473 fake_disconnect_volume_multipath_iscsi)474 with mock.patch.object(os.path, 'exists', return_value=True):475 vol = {'id': 1, 'name': self.name}476 connection_info = self.iscsi_connection(vol, self.location,477 self.iqn)478 libvirt_driver.connect_volume(connection_info,479 self.disk_info)480 self.assertEqual(fake_multipath_id,481 connection_info['data']['multipath_id'])482 libvirt_driver.disconnect_volume(connection_info, "fake")483 def test_sanitize_log_run_iscsiadm(self):484 # Tests that the parameters to the _run_iscsiadm function are sanitized485 # for passwords when logged.486 def fake_debug(*args, **kwargs):487 self.assertIn('node.session.auth.password', args[0])488 self.assertNotIn('scrubme', args[0])489 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)490 connection_info = self.iscsi_connection(self.vol, self.location,491 self.iqn)492 iscsi_properties = connection_info['data']493 with mock.patch.object(volume.LOG, 'debug',494 side_effect=fake_debug) as debug_mock:495 libvirt_driver._iscsiadm_update(iscsi_properties,496 'node.session.auth.password',497 'scrubme')498 # we don't care what the log message is, we just want to make sure499 # our stub method is called which asserts the password is scrubbed500 self.assertTrue(debug_mock.called)501 def iser_connection(self, volume, location, iqn):502 return {503 'driver_volume_type': 'iser',504 'data': {505 'volume_id': volume['id'],506 'target_portal': location,507 'target_iqn': iqn,508 'target_lun': 1,509 }510 }511 def sheepdog_connection(self, volume):512 return {513 'driver_volume_type': 'sheepdog',514 'data': {515 'name': volume['name']516 }517 }518 def test_libvirt_sheepdog_driver(self):519 libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)520 connection_info = self.sheepdog_connection(self.vol)521 conf = libvirt_driver.get_config(connection_info, self.disk_info)522 tree = conf.format_dom()523 self.assertEqual(tree.get('type'), 'network')524 self.assertEqual(tree.find('./source').get('protocol'), 'sheepdog')525 self.assertEqual(tree.find('./source').get('name'), self.name)526 libvirt_driver.disconnect_volume(connection_info, "vde")527 def rbd_connection(self, volume):528 return {529 'driver_volume_type': 'rbd',530 'data': {531 'name': '%s/%s' % ('rbd', volume['name']),532 'auth_enabled': CONF.libvirt.rbd_secret_uuid is not None,533 'auth_username': CONF.libvirt.rbd_user,534 'secret_type': 'ceph',535 'secret_uuid': CONF.libvirt.rbd_secret_uuid,536 'qos_specs': {537 'total_bytes_sec': '1048576',538 'read_iops_sec': '500',539 }540 }541 }542 def test_libvirt_rbd_driver(self):543 libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)544 connection_info = self.rbd_connection(self.vol)545 conf = libvirt_driver.get_config(connection_info, self.disk_info)546 tree = conf.format_dom()547 self._assertNetworkAndProtocolEquals(tree)548 self.assertIsNone(tree.find('./source/auth'))549 self.assertEqual('1048576', tree.find('./iotune/total_bytes_sec').text)550 self.assertEqual('500', tree.find('./iotune/read_iops_sec').text)551 libvirt_driver.disconnect_volume(connection_info, "vde")552 def test_libvirt_rbd_driver_hosts(self):553 libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)554 connection_info = self.rbd_connection(self.vol)555 hosts = ['example.com', '1.2.3.4', '::1']556 ports = [None, '6790', '6791']557 connection_info['data']['hosts'] = hosts558 connection_info['data']['ports'] = ports559 conf = libvirt_driver.get_config(connection_info, self.disk_info)560 tree = conf.format_dom()561 self._assertNetworkAndProtocolEquals(tree)562 self.assertIsNone(tree.find('./source/auth'))563 found_hosts = tree.findall('./source/host')564 self.assertEqual([host.get('name') for host in found_hosts], hosts)565 self.assertEqual([host.get('port') for host in found_hosts], ports)566 libvirt_driver.disconnect_volume(connection_info, "vde")567 def test_libvirt_rbd_driver_auth_enabled(self):568 libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)569 connection_info = self.rbd_connection(self.vol)570 secret_type = 'ceph'571 connection_info['data']['auth_enabled'] = True572 connection_info['data']['auth_username'] = self.user573 connection_info['data']['secret_type'] = secret_type574 connection_info['data']['secret_uuid'] = self.uuid575 conf = libvirt_driver.get_config(connection_info, self.disk_info)576 tree = conf.format_dom()577 self._assertNetworkAndProtocolEquals(tree)578 self.assertEqual(tree.find('./auth').get('username'), self.user)579 self.assertEqual(tree.find('./auth/secret').get('type'), secret_type)580 self.assertEqual(tree.find('./auth/secret').get('uuid'), self.uuid)581 libvirt_driver.disconnect_volume(connection_info, "vde")582 def test_libvirt_rbd_driver_auth_enabled_flags_override(self):583 libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)584 connection_info = self.rbd_connection(self.vol)585 secret_type = 'ceph'586 connection_info['data']['auth_enabled'] = True587 connection_info['data']['auth_username'] = self.user588 connection_info['data']['secret_type'] = secret_type589 connection_info['data']['secret_uuid'] = self.uuid590 flags_uuid = '37152720-1785-11e2-a740-af0c1d8b8e4b'591 flags_user = 'bar'592 self.flags(rbd_user=flags_user,593 rbd_secret_uuid=flags_uuid,594 group='libvirt')595 conf = libvirt_driver.get_config(connection_info, self.disk_info)596 tree = conf.format_dom()597 self._assertNetworkAndProtocolEquals(tree)598 self.assertEqual(tree.find('./auth').get('username'), flags_user)599 self.assertEqual(tree.find('./auth/secret').get('type'), secret_type)600 self.assertEqual(tree.find('./auth/secret').get('uuid'), flags_uuid)601 libvirt_driver.disconnect_volume(connection_info, "vde")602 def test_libvirt_rbd_driver_auth_disabled(self):603 libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)604 connection_info = self.rbd_connection(self.vol)605 secret_type = 'ceph'606 connection_info['data']['auth_enabled'] = False607 connection_info['data']['auth_username'] = self.user608 connection_info['data']['secret_type'] = secret_type609 connection_info['data']['secret_uuid'] = self.uuid610 conf = libvirt_driver.get_config(connection_info, self.disk_info)611 tree = conf.format_dom()612 self._assertNetworkAndProtocolEquals(tree)613 self.assertIsNone(tree.find('./auth'))614 libvirt_driver.disconnect_volume(connection_info, "vde")615 def test_libvirt_rbd_driver_auth_disabled_flags_override(self):616 libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)617 connection_info = self.rbd_connection(self.vol)618 secret_type = 'ceph'619 connection_info['data']['auth_enabled'] = False620 connection_info['data']['auth_username'] = self.user621 connection_info['data']['secret_type'] = secret_type622 connection_info['data']['secret_uuid'] = self.uuid623 # NOTE: Supplying the rbd_secret_uuid will enable authentication624 # locally in nova-compute even if not enabled in nova-volume/cinder625 flags_uuid = '37152720-1785-11e2-a740-af0c1d8b8e4b'626 flags_user = 'bar'627 self.flags(rbd_user=flags_user,628 rbd_secret_uuid=flags_uuid,629 group='libvirt')630 conf = libvirt_driver.get_config(connection_info, self.disk_info)631 tree = conf.format_dom()632 self._assertNetworkAndProtocolEquals(tree)633 self.assertEqual(tree.find('./auth').get('username'), flags_user)634 self.assertEqual(tree.find('./auth/secret').get('type'), secret_type)635 self.assertEqual(tree.find('./auth/secret').get('uuid'), flags_uuid)636 libvirt_driver.disconnect_volume(connection_info, "vde")637 @mock.patch.object(host.Host, 'find_secret')638 @mock.patch.object(host.Host, 'create_secret')639 @mock.patch.object(host.Host, 'delete_secret')640 def test_libvirt_iscsi_net_driver(self, mock_delete, mock_create,641 mock_find):642 mock_find.return_value = FakeSecret()643 mock_create.return_value = FakeSecret()644 libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)645 connection_info = self.iscsi_connection(self.vol, self.location,646 self.iqn, auth=True)647 secret_type = 'iscsi'648 flags_user = connection_info['data']['auth_username']649 conf = libvirt_driver.get_config(connection_info, self.disk_info)650 tree = conf.format_dom()651 self._assertISCSINetworkAndProtocolEquals(tree)652 self.assertEqual(tree.find('./auth').get('username'), flags_user)653 self.assertEqual(tree.find('./auth/secret').get('type'), secret_type)654 self.assertEqual(tree.find('./auth/secret').get('uuid'), SECRET_UUID)655 libvirt_driver.disconnect_volume(connection_info, 'vde')656 def test_libvirt_iscsi_driver_discovery_chap_enable(self):657 # NOTE(vish) exists is to make driver assume connecting worked658 self.stubs.Set(os.path, 'exists', lambda x: True)659 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)660 libvirt_driver.use_multipath = True661 connection_info = self.iscsi_connection_discovery_chap_enable(662 self.vol, self.location,663 self.iqn)664 mpdev_filepath = '/dev/mapper/foo'665 libvirt_driver._get_multipath_device_name = lambda x: mpdev_filepath666 libvirt_driver.connect_volume(connection_info, self.disk_info)667 libvirt_driver.disconnect_volume(connection_info, "vde")668 expected_commands = [('iscsiadm', '-m', 'discoverydb',669 '-t', 'sendtargets',670 '-p', self.location, '--op', 'update',671 '-n', 'discovery.sendtargets.auth.authmethod',672 '-v', 'CHAP',673 '-n', 'discovery.sendtargets.auth.username',674 '-v', 'testuser',675 '-n', 'discovery.sendtargets.auth.password',676 '-v', '123456'),677 ('iscsiadm', '-m', 'discoverydb',678 '-t', 'sendtargets',679 '-p', self.location, '--discover'),680 ('iscsiadm', '-m', 'node', '--rescan'),681 ('iscsiadm', '-m', 'session', '--rescan'),682 ('multipath', '-r'),683 ('iscsiadm', '-m', 'node', '--rescan'),684 ('iscsiadm', '-m', 'session', '--rescan'),685 ('multipath', '-r'),686 ('iscsiadm', '-m', 'discoverydb',687 '-t', 'sendtargets',688 '-p', self.location, '--op', 'update',689 '-n', 'discovery.sendtargets.auth.authmethod',690 '-v', 'CHAP',691 '-n', 'discovery.sendtargets.auth.username',692 '-v', 'testuser',693 '-n', 'discovery.sendtargets.auth.password',694 '-v', '123456'),695 ('iscsiadm', '-m', 'discoverydb',696 '-t', 'sendtargets',697 '-p', self.location, '--discover'),698 ('multipath', '-r')]699 self.assertEqual(self.executes, expected_commands)700 def test_libvirt_kvm_volume(self):701 self.stubs.Set(os.path, 'exists', lambda x: True)702 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)703 connection_info = self.iscsi_connection(self.vol, self.location,704 self.iqn)705 conf = libvirt_driver.get_config(connection_info, self.disk_info)706 tree = conf.format_dom()707 dev_str = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-1' % (self.location,708 self.iqn)709 self.assertEqual(tree.get('type'), 'block')710 self.assertEqual(tree.find('./source').get('dev'), dev_str)711 libvirt_driver.disconnect_volume(connection_info, 'vde')712 def test_libvirt_kvm_volume_with_multipath(self):713 self.flags(iscsi_use_multipath=True, group='libvirt')714 self.stubs.Set(os.path, 'exists', lambda x: True)715 devs = ['/dev/mapper/sda', '/dev/mapper/sdb']716 self.stubs.Set(self.fake_conn, '_get_all_block_devices', lambda: devs)717 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)718 connection_info = self.iscsi_connection(self.vol, self.location,719 self.iqn)720 mpdev_filepath = '/dev/mapper/foo'721 connection_info['data']['device_path'] = mpdev_filepath722 libvirt_driver._get_multipath_device_name = lambda x: mpdev_filepath723 iscsi_devs = ['ip-%s-iscsi-%s-lun-0' % (self.location, self.iqn)]724 self.stubs.Set(libvirt_driver, '_get_iscsi_devices',725 lambda: iscsi_devs)726 self.stubs.Set(libvirt_driver,727 '_get_target_portals_from_iscsiadm_output',728 lambda x: [[self.location, self.iqn]])729 libvirt_driver.connect_volume(connection_info, self.disk_info)730 conf = libvirt_driver.get_config(connection_info, self.disk_info)731 tree = conf.format_dom()732 self.assertEqual(tree.find('./source').get('dev'), mpdev_filepath)733 libvirt_driver._get_multipath_iqn = lambda x: self.iqn734 libvirt_driver.disconnect_volume(connection_info, 'vde')735 expected_multipath_cmd = ('multipath', '-f', 'foo')736 self.assertIn(expected_multipath_cmd, self.executes)737 def test_libvirt_kvm_volume_with_multipath_connecting(self):738 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)739 ip_iqns = [[self.location, self.iqn],740 ['10.0.2.16:3260', self.iqn],741 [self.location,742 'iqn.2010-10.org.openstack:volume-00000002']]743 with contextlib.nested(744 mock.patch.object(os.path, 'exists', return_value=True),745 mock.patch.object(libvirt_driver, '_run_iscsiadm_bare'),746 mock.patch.object(libvirt_driver,747 '_get_target_portals_from_iscsiadm_output',748 return_value=ip_iqns),749 mock.patch.object(libvirt_driver, '_connect_to_iscsi_portal'),750 mock.patch.object(libvirt_driver, '_rescan_iscsi'),751 mock.patch.object(libvirt_driver, '_get_host_device',752 return_value='fake-device'),753 mock.patch.object(libvirt_driver, '_rescan_multipath'),754 mock.patch.object(libvirt_driver, '_get_multipath_device_name',755 return_value='/dev/mapper/fake-mpath-devname')756 ) as (mock_exists, mock_run_iscsiadm_bare, mock_get_portals,757 mock_connect_iscsi, mock_rescan_iscsi, mock_host_device,758 mock_rescan_multipath, mock_device_name):759 vol = {'id': 1, 'name': self.name}760 connection_info = self.iscsi_connection(vol, self.location,761 self.iqn)762 libvirt_driver.use_multipath = True763 libvirt_driver.connect_volume(connection_info, self.disk_info)764 # Verify that the supplied iqn is used when it shares the same765 # iqn between multiple portals.766 connection_info = self.iscsi_connection(vol, self.location,767 self.iqn)768 props1 = connection_info['data'].copy()769 props2 = connection_info['data'].copy()770 props2['target_portal'] = '10.0.2.16:3260'771 expected_calls = [mock.call(props1), mock.call(props2),772 mock.call(props1)]773 self.assertEqual(expected_calls, mock_connect_iscsi.call_args_list)774 def test_libvirt_kvm_volume_with_multipath_still_in_use(self):775 name = 'volume-00000001'776 location = '10.0.2.15:3260'777 iqn = 'iqn.2010-10.org.openstack:%s' % name778 mpdev_filepath = '/dev/mapper/foo'779 def _get_multipath_device_name(path):780 if '%s-lun-1' % iqn in path:781 return mpdev_filepath782 return '/dev/mapper/donotdisconnect'783 self.flags(iscsi_use_multipath=True, group='libvirt')784 self.stubs.Set(os.path, 'exists', lambda x: True)785 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)786 libvirt_driver._get_multipath_device_name =\787 lambda x: _get_multipath_device_name(x)788 block_devs = ['/dev/disks/by-path/%s-iscsi-%s-lun-2' % (location, iqn)]789 self.stubs.Set(self.fake_conn, '_get_all_block_devices',790 lambda: block_devs)791 vol = {'id': 1, 'name': name}792 connection_info = self.iscsi_connection(vol, location, iqn)793 connection_info['data']['device_path'] = mpdev_filepath794 libvirt_driver._get_multipath_iqn = lambda x: iqn795 iscsi_devs = ['1.2.3.4-iscsi-%s-lun-1' % iqn,796 '%s-iscsi-%s-lun-1' % (location, iqn),797 '%s-iscsi-%s-lun-2' % (location, iqn),798 'pci-0000:00:00.0-ip-%s-iscsi-%s-lun-3' % (location,799 iqn)]800 libvirt_driver._get_iscsi_devices = lambda: iscsi_devs801 self.stubs.Set(libvirt_driver,802 '_get_target_portals_from_iscsiadm_output',803 lambda x: [[location, iqn]])804 # Set up disconnect volume mock expectations805 self.mox.StubOutWithMock(libvirt_driver, '_delete_device')806 self.mox.StubOutWithMock(libvirt_driver, '_rescan_multipath')807 libvirt_driver._rescan_multipath()808 libvirt_driver._delete_device('/dev/disk/by-path/%s' % iscsi_devs[0])809 libvirt_driver._delete_device('/dev/disk/by-path/%s' % iscsi_devs[1])810 libvirt_driver._rescan_multipath()811 # Ensure that the mpath devices are deleted812 self.mox.ReplayAll()813 libvirt_driver.disconnect_volume(connection_info, 'vde')814 def test_libvirt_kvm_volume_with_multipath_disconnected(self):815 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)816 volumes = [{'name': self.name,817 'location': self.location,818 'iqn': self.iqn,819 'mpdev_filepath': '/dev/mapper/disconnect'},820 {'name': 'volume-00000002',821 'location': '10.0.2.15:3260',822 'iqn': 'iqn.2010-10.org.openstack:volume-00000002',823 'mpdev_filepath': '/dev/mapper/donotdisconnect'}]824 iscsi_devs = ['ip-%s-iscsi-%s-lun-1' % (volumes[0]['location'],825 volumes[0]['iqn']),826 'ip-%s-iscsi-%s-lun-1' % (volumes[1]['location'],827 volumes[1]['iqn'])]828 def _get_multipath_device_name(path):829 if '%s-lun-1' % volumes[0]['iqn'] in path:830 return volumes[0]['mpdev_filepath']831 else:832 return volumes[1]['mpdev_filepath']833 def _get_multipath_iqn(mpdev):834 if volumes[0]['mpdev_filepath'] == mpdev:835 return volumes[0]['iqn']836 else:837 return volumes[1]['iqn']838 with contextlib.nested(839 mock.patch.object(os.path, 'exists', return_value=True),840 mock.patch.object(self.fake_conn, '_get_all_block_devices',841 retrun_value=[volumes[1]['mpdev_filepath']]),842 mock.patch.object(libvirt_driver, '_get_multipath_device_name',843 _get_multipath_device_name),844 mock.patch.object(libvirt_driver, '_get_multipath_iqn',845 _get_multipath_iqn),846 mock.patch.object(libvirt_driver, '_get_iscsi_devices',847 return_value=iscsi_devs),848 mock.patch.object(libvirt_driver,849 '_get_target_portals_from_iscsiadm_output',850 return_value=[[volumes[0]['location'],851 volumes[0]['iqn']],852 [volumes[1]['location'],853 volumes[1]['iqn']]]),854 mock.patch.object(libvirt_driver, '_disconnect_mpath')855 ) as (mock_exists, mock_devices, mock_device_name, mock_get_iqn,856 mock_iscsi_devices, mock_get_portals, mock_disconnect_mpath):857 vol = {'id': 1, 'name': volumes[0]['name']}858 connection_info = self.iscsi_connection(vol,859 volumes[0]['location'],860 volumes[0]['iqn'])861 connection_info['data']['device_path'] =\862 volumes[0]['mpdev_filepath']863 libvirt_driver.use_multipath = True864 libvirt_driver.disconnect_volume(connection_info, 'vde')865 # Ensure that the mpath device is disconnected.866 ips_iqns = []867 ips_iqns.append([volumes[0]['location'], volumes[0]['iqn']])868 mock_disconnect_mpath.assert_called_once_with(869 connection_info['data'], ips_iqns)870 def test_libvirt_kvm_volume_with_multipath_getmpdev(self):871 self.flags(iscsi_use_multipath=True, group='libvirt')872 self.stubs.Set(os.path, 'exists', lambda x: True)873 libvirt_driver = volume.LibvirtISCSIVolumeDriver(self.fake_conn)874 name0 = 'volume-00000000'875 iqn0 = 'iqn.2010-10.org.openstack:%s' % name0876 dev0 = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-0' % (self.location, iqn0)877 dev = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-1' % (self.location,878 self.iqn)879 devs = [dev0, dev]880 self.stubs.Set(self.fake_conn, '_get_all_block_devices', lambda: devs)881 connection_info = self.iscsi_connection(self.vol, self.location,882 self.iqn)883 mpdev_filepath = '/dev/mapper/foo'884 libvirt_driver._get_multipath_device_name = lambda x: mpdev_filepath885 self.stubs.Set(libvirt_driver,886 '_get_target_portals_from_iscsiadm_output',887 lambda x: [['fake_portal1', 'fake_iqn1']])888 libvirt_driver.connect_volume(connection_info, self.disk_info)889 conf = libvirt_driver.get_config(connection_info, self.disk_info)890 tree = conf.format_dom()891 self.assertEqual(tree.find('./source').get('dev'), mpdev_filepath)892 libvirt_driver.disconnect_volume(connection_info, 'vde')893 def test_libvirt_kvm_iser_volume_with_multipath(self):894 self.flags(iser_use_multipath=True, group='libvirt')895 self.stubs.Set(os.path, 'exists', lambda x: True)896 self.stubs.Set(time, 'sleep', lambda x: eventlet.sleep(0.1))897 devs = ['/dev/mapper/sda', '/dev/mapper/sdb']898 self.stubs.Set(self.fake_conn, '_get_all_block_devices', lambda: devs)899 libvirt_driver = volume.LibvirtISERVolumeDriver(self.fake_conn)900 name = 'volume-00000001'901 location = '10.0.2.15:3260'902 iqn = 'iqn.2010-10.org.iser.openstack:%s' % name903 vol = {'id': 1, 'name': name}904 connection_info = self.iser_connection(vol, location, iqn)905 mpdev_filepath = '/dev/mapper/foo'906 connection_info['data']['device_path'] = mpdev_filepath907 disk_info = {908 "bus": "virtio",909 "dev": "vde",910 "type": "disk",911 }912 libvirt_driver._get_multipath_device_name = lambda x: mpdev_filepath913 iscsi_devs = ['ip-%s-iscsi-%s-lun-0' % (location, iqn)]914 self.stubs.Set(libvirt_driver, '_get_iscsi_devices',915 lambda: iscsi_devs)916 self.stubs.Set(libvirt_driver,917 '_get_target_portals_from_iscsiadm_output',918 lambda x: [[location, iqn]])919 self.stubs.Set(libvirt_driver, '_get_host_device',920 lambda x: self.generate_device('iser', 0, False))921 libvirt_driver.connect_volume(connection_info, disk_info)922 conf = libvirt_driver.get_config(connection_info, disk_info)923 tree = conf.format_dom()924 self.assertEqual(tree.find('./source').get('dev'), mpdev_filepath)925 libvirt_driver._get_multipath_iqn = lambda x: iqn926 libvirt_driver.disconnect_volume(connection_info, 'vde')927 expected_multipath_cmd = ('multipath', '-f', 'foo')928 self.assertIn(expected_multipath_cmd, self.executes)929 def test_libvirt_kvm_iser_volume_with_multipath_getmpdev(self):930 self.flags(iser_use_multipath=True, group='libvirt')931 self.stubs.Set(os.path, 'exists', lambda x: True)932 self.stubs.Set(time, 'sleep', lambda x: eventlet.sleep(0.1))933 libvirt_driver = volume.LibvirtISERVolumeDriver(self.fake_conn)934 name0 = 'volume-00000000'935 location0 = '10.0.2.15:3260'936 iqn0 = 'iqn.2010-10.org.iser.openstack:%s' % name0937 dev0 = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-0' % (location0, iqn0)938 name = 'volume-00000001'939 location = '10.0.2.15:3260'940 iqn = 'iqn.2010-10.org.iser.openstack:%s' % name941 vol = {'id': 1, 'name': name}942 dev = '/dev/disk/by-path/ip-%s-iscsi-%s-lun-1' % (location, iqn)943 devs = [dev0, dev]944 self.stubs.Set(self.fake_conn, '_get_all_block_devices', lambda: devs)945 self.stubs.Set(libvirt_driver, '_get_iscsi_devices', lambda: [])946 self.stubs.Set(libvirt_driver, '_get_host_device',947 lambda x: self.generate_device('iser', 1, False))948 connection_info = self.iser_connection(vol, location, iqn)949 mpdev_filepath = '/dev/mapper/foo'950 disk_info = {951 "bus": "virtio",952 "dev": "vde",953 "type": "disk",954 }955 libvirt_driver._get_multipath_device_name = lambda x: mpdev_filepath956 self.stubs.Set(libvirt_driver,957 '_get_target_portals_from_iscsiadm_output',958 lambda x: [['fake_portal1', 'fake_iqn1']])959 libvirt_driver.connect_volume(connection_info, disk_info)960 conf = libvirt_driver.get_config(connection_info, disk_info)961 tree = conf.format_dom()962 self.assertEqual(tree.find('./source').get('dev'), mpdev_filepath)963 libvirt_driver.disconnect_volume(connection_info, 'vde')964 def test_libvirt_nfs_driver(self):965 # NOTE(vish) exists is to make driver assume connecting worked966 mnt_base = '/mnt'967 self.flags(nfs_mount_point_base=mnt_base, group='libvirt')968 libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)969 self.stubs.Set(libvirt_utils, 'is_mounted', lambda x, d: False)970 export_string = '192.168.1.1:/nfs/share1'971 export_mnt_base = os.path.join(mnt_base,972 utils.get_hash_str(export_string))973 connection_info = {'data': {'export': export_string,974 'name': self.name}}975 libvirt_driver.connect_volume(connection_info, self.disk_info)976 libvirt_driver.disconnect_volume(connection_info, "vde")977 device_path = os.path.join(export_mnt_base,978 connection_info['data']['name'])979 self.assertEqual(device_path, connection_info['data']['device_path'])980 expected_commands = [981 ('mkdir', '-p', export_mnt_base),982 ('mount', '-t', 'nfs', export_string, export_mnt_base),983 ('umount', export_mnt_base)]984 self.assertEqual(expected_commands, self.executes)985 @mock.patch.object(volume.utils, 'execute')986 @mock.patch.object(volume.LOG, 'debug')987 @mock.patch.object(volume.LOG, 'exception')988 def test_libvirt_nfs_driver_umount_error(self, mock_LOG_exception,989 mock_LOG_debug, mock_utils_exe):990 export_string = '192.168.1.1:/nfs/share1'991 connection_info = {'data': {'export': export_string,992 'name': self.name}}993 libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)994 mock_utils_exe.side_effect = processutils.ProcessExecutionError(995 None, None, None, 'umount', 'umount: device is busy.')996 libvirt_driver.disconnect_volume(connection_info, "vde")997 self.assertTrue(mock_LOG_debug.called)998 mock_utils_exe.side_effect = processutils.ProcessExecutionError(999 None, None, None, 'umount', 'umount: target is busy.')1000 libvirt_driver.disconnect_volume(connection_info, "vde")1001 self.assertTrue(mock_LOG_debug.called)1002 mock_utils_exe.side_effect = processutils.ProcessExecutionError(1003 None, None, None, 'umount', 'umount: Other error.')1004 libvirt_driver.disconnect_volume(connection_info, "vde")1005 self.assertTrue(mock_LOG_exception.called)1006 def test_libvirt_nfs_driver_get_config(self):1007 libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)1008 mnt_base = '/mnt'1009 self.flags(nfs_mount_point_base=mnt_base, group='libvirt')1010 export_string = '192.168.1.1:/nfs/share1'1011 export_mnt_base = os.path.join(mnt_base,1012 utils.get_hash_str(export_string))1013 file_path = os.path.join(export_mnt_base, self.name)1014 connection_info = {'data': {'export': export_string,1015 'name': self.name,1016 'device_path': file_path}}1017 conf = libvirt_driver.get_config(connection_info, self.disk_info)1018 tree = conf.format_dom()1019 self._assertFileTypeEquals(tree, file_path)1020 self.assertEqual('raw', tree.find('./driver').get('type'))1021 def test_libvirt_nfs_driver_already_mounted(self):1022 # NOTE(vish) exists is to make driver assume connecting worked1023 mnt_base = '/mnt'1024 self.flags(nfs_mount_point_base=mnt_base, group='libvirt')1025 libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)1026 export_string = '192.168.1.1:/nfs/share1'1027 export_mnt_base = os.path.join(mnt_base,1028 utils.get_hash_str(export_string))1029 connection_info = {'data': {'export': export_string,1030 'name': self.name}}1031 libvirt_driver.connect_volume(connection_info, self.disk_info)1032 libvirt_driver.disconnect_volume(connection_info, "vde")1033 expected_commands = [1034 ('findmnt', '--target', export_mnt_base, '--source',1035 export_string),1036 ('umount', export_mnt_base)]1037 self.assertEqual(self.executes, expected_commands)1038 def test_libvirt_nfs_driver_with_opts(self):1039 mnt_base = '/mnt'1040 self.flags(nfs_mount_point_base=mnt_base, group='libvirt')1041 libvirt_driver = volume.LibvirtNFSVolumeDriver(self.fake_conn)1042 self.stubs.Set(libvirt_utils, 'is_mounted', lambda x, d: False)1043 export_string = '192.168.1.1:/nfs/share1'1044 options = '-o intr,nfsvers=3'1045 export_mnt_base = os.path.join(mnt_base,1046 utils.get_hash_str(export_string))1047 connection_info = {'data': {'export': export_string,1048 'name': self.name,1049 'options': options}}1050 libvirt_driver.connect_volume(connection_info, self.disk_info)1051 libvirt_driver.disconnect_volume(connection_info, "vde")1052 expected_commands = [1053 ('mkdir', '-p', export_mnt_base),1054 ('mount', '-t', 'nfs', '-o', 'intr,nfsvers=3',1055 export_string, export_mnt_base),1056 ('umount', export_mnt_base),1057 ]1058 self.assertEqual(expected_commands, self.executes)1059 def aoe_connection(self, shelf, lun):1060 aoedev = 'e%s.%s' % (shelf, lun)1061 aoedevpath = '/dev/etherd/%s' % (aoedev)1062 return {1063 'driver_volume_type': 'aoe',1064 'data': {1065 'target_shelf': shelf,1066 'target_lun': lun,1067 'device_path': aoedevpath1068 }1069 }1070 @mock.patch('os.path.exists', return_value=True)1071 def test_libvirt_aoe_driver(self, exists):1072 libvirt_driver = volume.LibvirtAOEVolumeDriver(self.fake_conn)1073 shelf = '100'1074 lun = '1'1075 connection_info = self.aoe_connection(shelf, lun)1076 aoedev = 'e%s.%s' % (shelf, lun)1077 aoedevpath = '/dev/etherd/%s' % (aoedev)1078 libvirt_driver.connect_volume(connection_info, self.disk_info)1079 exists.assert_called_with(aoedevpath)1080 libvirt_driver.disconnect_volume(connection_info, "vde")1081 self.assertEqual(aoedevpath, connection_info['data']['device_path'])1082 expected_commands = [('aoe-revalidate', aoedev)]1083 self.assertEqual(expected_commands, self.executes)1084 def test_libvirt_aoe_driver_get_config(self):1085 libvirt_driver = volume.LibvirtAOEVolumeDriver(self.fake_conn)1086 shelf = '100'1087 lun = '1'1088 connection_info = self.aoe_connection(shelf, lun)1089 conf = libvirt_driver.get_config(connection_info, self.disk_info)1090 tree = conf.format_dom()1091 aoedevpath = '/dev/etherd/e%s.%s' % (shelf, lun)1092 self.assertEqual('block', tree.get('type'))1093 self.assertEqual(aoedevpath, tree.find('./source').get('dev'))1094 libvirt_driver.disconnect_volume(connection_info, "vde")1095 def test_libvirt_glusterfs_driver(self):1096 mnt_base = '/mnt'1097 self.flags(glusterfs_mount_point_base=mnt_base, group='libvirt')1098 libvirt_driver = volume.LibvirtGlusterfsVolumeDriver(self.fake_conn)1099 self.stubs.Set(libvirt_utils, 'is_mounted', lambda x, d: False)1100 export_string = '192.168.1.1:/volume-00001'1101 export_mnt_base = os.path.join(mnt_base,1102 utils.get_hash_str(export_string))1103 connection_info = {'data': {'export': export_string,1104 'name': self.name}}1105 libvirt_driver.connect_volume(connection_info, self.disk_info)1106 libvirt_driver.disconnect_volume(connection_info, "vde")1107 device_path = os.path.join(export_mnt_base,1108 connection_info['data']['name'])1109 self.assertEqual(device_path, connection_info['data']['device_path'])1110 expected_commands = [1111 ('mkdir', '-p', export_mnt_base),1112 ('mount', '-t', 'glusterfs', export_string, export_mnt_base),1113 ('umount', export_mnt_base)]1114 self.assertEqual(expected_commands, self.executes)1115 def test_libvirt_glusterfs_driver_get_config(self):1116 mnt_base = '/mnt'1117 self.flags(glusterfs_mount_point_base=mnt_base, group='libvirt')1118 libvirt_driver = volume.LibvirtGlusterfsVolumeDriver(self.fake_conn)1119 export_string = '192.168.1.1:/volume-00001'1120 export_mnt_base = os.path.join(mnt_base,1121 utils.get_hash_str(export_string))1122 file_path = os.path.join(export_mnt_base, self.name)1123 # Test default format - raw1124 connection_info = {'data': {'export': export_string,1125 'name': self.name,1126 'device_path': file_path}}1127 conf = libvirt_driver.get_config(connection_info, self.disk_info)1128 tree = conf.format_dom()1129 self._assertFileTypeEquals(tree, file_path)1130 self.assertEqual('raw', tree.find('./driver').get('type'))1131 # Test specified format - qcow21132 connection_info = {'data': {'export': export_string,1133 'name': self.name,1134 'device_path': file_path,1135 'format': 'qcow2'}}1136 conf = libvirt_driver.get_config(connection_info, self.disk_info)1137 tree = conf.format_dom()1138 self._assertFileTypeEquals(tree, file_path)1139 self.assertEqual('qcow2', tree.find('./driver').get('type'))1140 def test_libvirt_glusterfs_driver_already_mounted(self):1141 mnt_base = '/mnt'1142 self.flags(glusterfs_mount_point_base=mnt_base, group='libvirt')1143 libvirt_driver = volume.LibvirtGlusterfsVolumeDriver(self.fake_conn)1144 export_string = '192.168.1.1:/volume-00001'1145 export_mnt_base = os.path.join(mnt_base,1146 utils.get_hash_str(export_string))1147 connection_info = {'data': {'export': export_string,1148 'name': self.name}}1149 libvirt_driver.connect_volume(connection_info, self.disk_info)1150 libvirt_driver.disconnect_volume(connection_info, "vde")1151 expected_commands = [1152 ('findmnt', '--target', export_mnt_base,1153 '--source', export_string),1154 ('umount', export_mnt_base)]1155 self.assertEqual(self.executes, expected_commands)1156 def test_libvirt_glusterfs_driver_with_opts(self):1157 mnt_base = '/mnt'1158 self.flags(glusterfs_mount_point_base=mnt_base, group='libvirt')1159 libvirt_driver = volume.LibvirtGlusterfsVolumeDriver(self.fake_conn)1160 self.stubs.Set(libvirt_utils, 'is_mounted', lambda x, d: False)1161 export_string = '192.168.1.1:/volume-00001'1162 options = '-o backupvolfile-server=192.168.1.2'1163 export_mnt_base = os.path.join(mnt_base,1164 utils.get_hash_str(export_string))1165 connection_info = {'data': {'export': export_string,1166 'name': self.name,1167 'options': options}}1168 libvirt_driver.connect_volume(connection_info, self.disk_info)1169 libvirt_driver.disconnect_volume(connection_info, "vde")1170 expected_commands = [1171 ('mkdir', '-p', export_mnt_base),1172 ('mount', '-t', 'glusterfs',1173 '-o', 'backupvolfile-server=192.168.1.2',1174 export_string, export_mnt_base),1175 ('umount', export_mnt_base),1176 ]1177 self.assertEqual(self.executes, expected_commands)1178 def test_libvirt_glusterfs_libgfapi(self):1179 self.flags(qemu_allowed_storage_drivers=['gluster'], group='libvirt')1180 libvirt_driver = volume.LibvirtGlusterfsVolumeDriver(self.fake_conn)1181 self.stubs.Set(libvirt_utils, 'is_mounted', lambda x, d: False)1182 export_string = '192.168.1.1:/volume-00001'1183 name = 'volume-00001'1184 connection_info = {'data': {'export': export_string, 'name': name}}1185 disk_info = {1186 "dev": "vde",1187 "type": "disk",1188 "bus": "virtio",1189 }1190 libvirt_driver.connect_volume(connection_info, disk_info)1191 conf = libvirt_driver.get_config(connection_info, disk_info)1192 tree = conf.format_dom()1193 self.assertEqual(tree.get('type'), 'network')1194 self.assertEqual(tree.find('./driver').get('type'), 'raw')1195 source = tree.find('./source')1196 self.assertEqual(source.get('protocol'), 'gluster')1197 self.assertEqual(source.get('name'), 'volume-00001/volume-00001')1198 self.assertEqual(source.find('./host').get('name'), '192.168.1.1')1199 self.assertEqual(source.find('./host').get('port'), '24007')1200 libvirt_driver.disconnect_volume(connection_info, "vde")1201 def fibrechan_connection(self, volume, location, wwn):1202 return {1203 'driver_volume_type': 'fibrechan',1204 'data': {1205 'volume_id': volume['id'],1206 'target_portal': location,1207 'target_wwn': wwn,1208 'target_lun': 1,1209 }1210 }1211 def test_libvirt_fibrechan_driver(self):1212 self.stubs.Set(libvirt_utils, 'get_fc_hbas',1213 fake_libvirt_utils.get_fc_hbas)1214 self.stubs.Set(libvirt_utils, 'get_fc_hbas_info',1215 fake_libvirt_utils.get_fc_hbas_info)1216 # NOTE(vish) exists is to make driver assume connecting worked1217 self.stubs.Set(os.path, 'exists', lambda x: True)1218 self.stubs.Set(os.path, 'realpath', lambda x: '/dev/sdb')1219 libvirt_driver = volume.LibvirtFibreChannelVolumeDriver(self.fake_conn)1220 multipath_devname = '/dev/md-1'1221 devices = {"device": multipath_devname,1222 "id": "1234567890",1223 "devices": [{'device': '/dev/sdb',1224 'address': '1:0:0:1',1225 'host': 1, 'channel': 0,1226 'id': 0, 'lun': 1}]}1227 self.stubs.Set(linuxscsi, 'find_multipath_device', lambda x: devices)1228 self.stubs.Set(linuxscsi, 'remove_device', lambda x: None)1229 # Should work for string, unicode, and list1230 wwns = ['1234567890123456', unicode('1234567890123456'),1231 ['1234567890123456', '1234567890123457']]1232 for wwn in wwns:1233 connection_info = self.fibrechan_connection(self.vol,1234 self.location, wwn)1235 mount_device = "vde"1236 libvirt_driver.connect_volume(connection_info, self.disk_info)1237 # Test the scenario where multipath_id is returned1238 libvirt_driver.disconnect_volume(connection_info, mount_device)1239 self.assertEqual(multipath_devname,1240 connection_info['data']['device_path'])1241 expected_commands = []1242 self.assertEqual(expected_commands, self.executes)1243 # Test the scenario where multipath_id is not returned1244 connection_info["data"]["devices"] = devices["devices"]1245 del connection_info["data"]["multipath_id"]1246 libvirt_driver.disconnect_volume(connection_info, mount_device)1247 expected_commands = []1248 self.assertEqual(expected_commands, self.executes)1249 # Should not work for anything other than string, unicode, and list1250 connection_info = self.fibrechan_connection(self.vol,1251 self.location, 123)1252 self.assertRaises(exception.NovaException,1253 libvirt_driver.connect_volume,1254 connection_info, self.disk_info)1255 self.stubs.Set(libvirt_utils, 'get_fc_hbas', lambda: [])1256 self.stubs.Set(libvirt_utils, 'get_fc_hbas_info', lambda: [])1257 self.assertRaises(exception.NovaException,1258 libvirt_driver.connect_volume,1259 connection_info, self.disk_info)1260 @mock.patch.object(volume.LibvirtFibreChannelVolumeDriver,1261 '_remove_lun_from_s390')1262 def _test_libvirt_fibrechan_driver_s390(self, mock_remove_lun):1263 self.stubs.Set(libvirt_utils, 'get_fc_hbas',1264 fake_libvirt_utils.get_fc_hbas)1265 self.stubs.Set(libvirt_utils, 'get_fc_hbas_info',1266 fake_libvirt_utils.get_fc_hbas_info)1267 # NOTE(vish) exists is to make driver assume connecting worked1268 self.stubs.Set(os.path, 'exists', lambda x: True)1269 self.stubs.Set(os.path, 'realpath', lambda x: '/dev/sdb')1270 libvirt_driver = volume.LibvirtFibreChannelVolumeDriver(self.fake_conn)1271 multipath_devname = '/dev/md-1'1272 devices = {"device": multipath_devname,1273 "id": "1234567890",1274 "devices": [{'device': '/dev/sdb',1275 'address': '1:0:0:1',1276 'host': 1, 'channel': 0,1277 'id': 0, 'lun': 1}]}1278 self.stubs.Set(linuxscsi, 'find_multipath_device', lambda x: devices)1279 self.stubs.Set(linuxscsi, 'remove_device', lambda x: None)1280 # Should work for string, unicode, and list1281 wwns = ['1234567890123456', unicode('1234567890123456'),1282 ['1234567890123456']]1283 expected_remove_calls = []1284 for wwn in wwns:1285 self.executes = []1286 connection_info = self.fibrechan_connection(self.vol,1287 self.location, wwn)1288 expected_remove_calls.append(mock.call(connection_info))1289 mount_device = "vde"1290 libvirt_driver.connect_volume(connection_info, self.disk_info)1291 # Test the scenario where multipath_id is returned1292 libvirt_driver.disconnect_volume(connection_info, mount_device)1293 self.assertEqual(multipath_devname,1294 connection_info['data']['device_path'])1295 expected_commands = [('tee', '-a',1296 '/sys/bus/ccw/drivers/zfcp/0000:05:00.2/'1297 '0x1234567890123456/unit_add')]1298 self.assertEqual(expected_commands, self.executes)1299 # Test the scenario where multipath_id is not returned1300 connection_info["data"]["devices"] = devices["devices"]1301 del connection_info["data"]["multipath_id"]1302 libvirt_driver.disconnect_volume(connection_info, mount_device)1303 mock_remove_lun.assert_has_calls(expected_remove_calls)1304 # Should not work for anything other than string, unicode, and list1305 connection_info = self.fibrechan_connection(self.vol,1306 self.location, 123)1307 self.assertRaises(exception.NovaException,1308 libvirt_driver.connect_volume,1309 connection_info, self.disk_info)1310 self.stubs.Set(libvirt_utils, 'get_fc_hbas', lambda: [])1311 self.stubs.Set(libvirt_utils, 'get_fc_hbas_info', lambda: [])1312 self.assertRaises(exception.NovaException,1313 libvirt_driver.connect_volume,1314 connection_info, self.disk_info)1315 @mock.patch.object(platform, 'machine', return_value=arch.S390)1316 def test_libvirt_fibrechan_driver_s390(self, mock_machine):1317 self._test_libvirt_fibrechan_driver_s390()1318 @mock.patch.object(platform, 'machine', return_value=arch.S390X)1319 def test_libvirt_fibrechan_driver_s390x(self, mock_machine):1320 self._test_libvirt_fibrechan_driver_s390()1321 def test_libvirt_fibrechan_driver_get_config(self):1322 libvirt_driver = volume.LibvirtFibreChannelVolumeDriver(self.fake_conn)1323 connection_info = self.fibrechan_connection(self.vol,1324 self.location, 123)1325 connection_info['data']['device_path'] = ("/sys/devices/pci0000:00"1326 "/0000:00:03.0/0000:05:00.3/host2/fc_host/host2")1327 conf = libvirt_driver.get_config(connection_info, self.disk_info)1328 tree = conf.format_dom()1329 self.assertEqual('block', tree.get('type'))1330 self.assertEqual(connection_info['data']['device_path'],1331 tree.find('./source').get('dev'))1332 def test_libvirt_fibrechan_getpci_num(self):1333 libvirt_driver = volume.LibvirtFibreChannelVolumeDriver(self.fake_conn)1334 hba = {'device_path': "/sys/devices/pci0000:00/0000:00:03.0"1335 "/0000:05:00.3/host2/fc_host/host2"}1336 pci_num = libvirt_driver._get_pci_num(hba)1337 self.assertEqual("0000:05:00.3", pci_num)1338 hba = {'device_path': "/sys/devices/pci0000:00/0000:00:03.0"1339 "/0000:05:00.3/0000:06:00.6/host2/fc_host/host2"}1340 pci_num = libvirt_driver._get_pci_num(hba)1341 self.assertEqual("0000:06:00.6", pci_num)1342 def test_libvirt_fibrechan_get_device_file_path_s390(self):1343 libvirt_driver = volume.LibvirtFibreChannelVolumeDriver(self.fake_conn)1344 pci_num = "2310"1345 wwn = '1234567890123456'1346 lun = 11347 file_path = libvirt_driver._get_device_file_path_s390(pci_num,1348 wwn, lun)1349 expected_path = ("/dev/disk/by-path/ccw-2310-zfcp-"1350 "1234567890123456:1")1351 self.assertEqual(expected_path, file_path)1352 @mock.patch.object(libvirt_utils, 'get_fc_hbas_info',1353 fake_libvirt_utils.get_fc_hbas_info)1354 @mock.patch.object(libvirt_utils, 'perform_unit_remove_for_s390')1355 def test_libvirt_fibrechan_remove_lun_from_s390(self, mock_unit_remove):1356 libvirt_driver = volume.LibvirtFibreChannelVolumeDriver(self.fake_conn)1357 connection_info = {1358 'driver_volume_type': 'fibrechan',1359 'data': {1360 'target_wwn': ['50014380242b9751',1361 '50014380242b9752'],1362 'target_lun': 1,1363 }}1364 libvirt_driver._remove_lun_from_s390(connection_info)1365 expected_calls = []1366 for target_wwn in connection_info['data']['target_wwn']:1367 # NOTE(mriedem): The device_num value comes from ClassDevicePath1368 # in fake_libvirt_utils.fake_libvirt_utils.1369 expected_calls.append(mock.call('0000:05:00.2',1370 '0x' + target_wwn,1371 '0x0001000000000000'))1372 mock_unit_remove.assert_has_calls(expected_calls)1373 def test_libvirt_scality_driver(self):1374 tempdir = self.useFixture(fixtures.TempDir()).path1375 TEST_MOUNT = os.path.join(tempdir, 'fake_mount')1376 TEST_CONFIG = os.path.join(tempdir, 'fake_config')1377 TEST_VOLDIR = 'volumes'1378 TEST_VOLNAME = 'volume_name'1379 TEST_CONN_INFO = {1380 'data': {1381 'sofs_path': os.path.join(TEST_VOLDIR, TEST_VOLNAME)1382 }1383 }1384 TEST_VOLPATH = os.path.join(TEST_MOUNT,1385 TEST_VOLDIR,1386 TEST_VOLNAME)1387 open(TEST_CONFIG, "w+").close()1388 os.makedirs(os.path.join(TEST_MOUNT, 'sys'))1389 def _access_wrapper(path, flags):1390 if path == '/sbin/mount.sofs':1391 return True1392 else:1393 return os.access(path, flags)1394 self.stubs.Set(os, 'access', _access_wrapper)1395 self.flags(scality_sofs_config=TEST_CONFIG,1396 scality_sofs_mount_point=TEST_MOUNT,1397 group='libvirt')1398 driver = volume.LibvirtScalityVolumeDriver(self.fake_conn)1399 driver.connect_volume(TEST_CONN_INFO, self.disk_info)1400 device_path = os.path.join(TEST_MOUNT,1401 TEST_CONN_INFO['data']['sofs_path'])1402 self.assertEqual(device_path,1403 TEST_CONN_INFO['data']['device_path'])1404 conf = driver.get_config(TEST_CONN_INFO, self.disk_info)1405 tree = conf.format_dom()1406 self._assertFileTypeEquals(tree, TEST_VOLPATH)1407 @mock.patch.object(libvirt_utils, 'is_mounted')1408 def test_libvirt_smbfs_driver(self, mock_is_mounted):1409 mnt_base = '/mnt'1410 self.flags(smbfs_mount_point_base=mnt_base, group='libvirt')1411 mock_is_mounted.return_value = False1412 libvirt_driver = volume.LibvirtSMBFSVolumeDriver(self.fake_conn)1413 export_string = '//192.168.1.1/volumes'1414 export_mnt_base = os.path.join(mnt_base,1415 utils.get_hash_str(export_string))1416 connection_info = {'data': {'export': export_string,1417 'name': self.name}}1418 libvirt_driver.connect_volume(connection_info, self.disk_info)1419 libvirt_driver.disconnect_volume(connection_info, "vde")1420 expected_commands = [1421 ('mkdir', '-p', export_mnt_base),1422 ('mount', '-t', 'cifs', '-o', 'username=guest',1423 export_string, export_mnt_base),1424 ('umount', export_mnt_base)]1425 self.assertEqual(expected_commands, self.executes)1426 def test_libvirt_smbfs_driver_already_mounted(self):1427 mnt_base = '/mnt'1428 self.flags(smbfs_mount_point_base=mnt_base, group='libvirt')1429 libvirt_driver = volume.LibvirtSMBFSVolumeDriver(self.fake_conn)1430 export_string = '//192.168.1.1/volumes'1431 export_mnt_base = os.path.join(mnt_base,1432 utils.get_hash_str(export_string))1433 connection_info = {'data': {'export': export_string,1434 'name': self.name}}1435 libvirt_driver.connect_volume(connection_info, self.disk_info)1436 libvirt_driver.disconnect_volume(connection_info, "vde")1437 expected_commands = [1438 ('findmnt', '--target', export_mnt_base,1439 '--source', export_string),1440 ('umount', export_mnt_base)]1441 self.assertEqual(expected_commands, self.executes)1442 def test_libvirt_smbfs_driver_get_config(self):1443 mnt_base = '/mnt'1444 self.flags(smbfs_mount_point_base=mnt_base, group='libvirt')1445 libvirt_driver = volume.LibvirtSMBFSVolumeDriver(self.fake_conn)1446 export_string = '//192.168.1.1/volumes'1447 export_mnt_base = os.path.join(mnt_base,1448 utils.get_hash_str(export_string))1449 file_path = os.path.join(export_mnt_base, self.name)1450 connection_info = {'data': {'export': export_string,1451 'name': self.name,1452 'device_path': file_path}}1453 conf = libvirt_driver.get_config(connection_info, self.disk_info)1454 tree = conf.format_dom()1455 self._assertFileTypeEquals(tree, file_path)1456 @mock.patch.object(libvirt_utils, 'is_mounted')1457 def test_libvirt_smbfs_driver_with_opts(self, mock_is_mounted):1458 mnt_base = '/mnt'1459 self.flags(smbfs_mount_point_base=mnt_base, group='libvirt')1460 mock_is_mounted.return_value = False1461 libvirt_driver = volume.LibvirtSMBFSVolumeDriver(self.fake_conn)1462 export_string = '//192.168.1.1/volumes'1463 options = '-o user=guest,uid=107,gid=105'1464 export_mnt_base = os.path.join(mnt_base,1465 utils.get_hash_str(export_string))1466 connection_info = {'data': {'export': export_string,1467 'name': self.name,1468 'options': options}}1469 libvirt_driver.connect_volume(connection_info, self.disk_info)1470 libvirt_driver.disconnect_volume(connection_info, "vde")1471 expected_commands = [1472 ('mkdir', '-p', export_mnt_base),1473 ('mount', '-t', 'cifs', '-o', 'user=guest,uid=107,gid=105',1474 export_string, export_mnt_base),1475 ('umount', export_mnt_base)]1476 self.assertEqual(expected_commands, self.executes)1477 def test_libvirt_gpfs_driver_get_config(self):1478 libvirt_driver = volume.LibvirtGPFSVolumeDriver(self.fake_conn)1479 connection_info = {1480 'driver_volume_type': 'gpfs',1481 'data': {1482 'device_path': '/gpfs/foo',1483 },1484 'serial': 'fake_serial',1485 }1486 conf = libvirt_driver.get_config(connection_info, self.disk_info)1487 tree = conf.format_dom()1488 self.assertEqual('file', tree.get('type'))1489 self.assertEqual('fake_serial', tree.find('./serial').text)1490 @mock.patch.object(quobyte, 'validate_volume')1491 @mock.patch.object(quobyte, 'mount_volume')1492 @mock.patch.object(libvirt_utils, 'is_mounted', return_value=False)1493 def test_libvirt_quobyte_driver_mount(self,1494 mock_is_mounted,1495 mock_mount_volume,1496 mock_validate_volume1497 ):1498 mnt_base = '/mnt'1499 self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')1500 libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)1501 export_string = 'quobyte://192.168.1.1/volume-00001'1502 quobyte_volume = '192.168.1.1/volume-00001'1503 export_mnt_base = os.path.join(mnt_base,1504 utils.get_hash_str(quobyte_volume))1505 file_path = os.path.join(export_mnt_base, self.name)1506 connection_info = {'data': {'export': export_string,1507 'name': self.name}}1508 libvirt_driver.connect_volume(connection_info, self.disk_info)1509 conf = libvirt_driver.get_config(connection_info, self.disk_info)1510 tree = conf.format_dom()1511 self._assertFileTypeEquals(tree, file_path)1512 mock_mount_volume.assert_called_once_with(quobyte_volume,1513 export_mnt_base,1514 mock.ANY)1515 mock_validate_volume.assert_called_with(export_mnt_base)1516 @mock.patch.object(quobyte, 'validate_volume')1517 @mock.patch.object(quobyte, 'umount_volume')1518 @mock.patch.object(libvirt_utils, 'is_mounted', return_value=True)1519 def test_libvirt_quobyte_driver_umount(self, mock_is_mounted,1520 mock_umount_volume,1521 mock_validate_volume):1522 mnt_base = '/mnt'1523 self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')1524 libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)1525 export_string = 'quobyte://192.168.1.1/volume-00001'1526 quobyte_volume = '192.168.1.1/volume-00001'1527 export_mnt_base = os.path.join(mnt_base,1528 utils.get_hash_str(quobyte_volume))1529 file_path = os.path.join(export_mnt_base, self.name)1530 connection_info = {'data': {'export': export_string,1531 'name': self.name}}1532 libvirt_driver.connect_volume(connection_info, self.disk_info)1533 conf = libvirt_driver.get_config(connection_info, self.disk_info)1534 tree = conf.format_dom()1535 self._assertFileTypeEquals(tree, file_path)1536 libvirt_driver.disconnect_volume(connection_info, "vde")1537 mock_validate_volume.assert_called_once_with(export_mnt_base)1538 mock_umount_volume.assert_called_once_with(export_mnt_base)1539 @mock.patch.object(quobyte, 'validate_volume')1540 @mock.patch.object(quobyte, 'umount_volume')1541 def test_libvirt_quobyte_driver_already_mounted(self,1542 mock_umount_volume,1543 mock_validate_volume1544 ):1545 mnt_base = '/mnt'1546 self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')1547 libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)1548 export_string = 'quobyte://192.168.1.1/volume-00001'1549 quobyte_volume = '192.168.1.1/volume-00001'1550 export_mnt_base = os.path.join(mnt_base,1551 utils.get_hash_str(quobyte_volume))1552 file_path = os.path.join(export_mnt_base, self.name)1553 connection_info = {'data': {'export': export_string,1554 'name': self.name}}1555 libvirt_driver.connect_volume(connection_info, self.disk_info)1556 conf = libvirt_driver.get_config(connection_info, self.disk_info)1557 tree = conf.format_dom()1558 self._assertFileTypeEquals(tree, file_path)1559 libvirt_driver.disconnect_volume(connection_info, "vde")1560 expected_commands = [1561 ('findmnt', '--target', export_mnt_base,1562 '--source', "quobyte@" + quobyte_volume),1563 ('findmnt', '--target', export_mnt_base,1564 '--source', "quobyte@" + quobyte_volume),1565 ]1566 self.assertEqual(expected_commands, self.executes)1567 mock_umount_volume.assert_called_once_with(export_mnt_base)1568 mock_validate_volume.assert_called_once_with(export_mnt_base)1569 @mock.patch.object(quobyte, 'validate_volume')1570 @mock.patch.object(quobyte, 'mount_volume')1571 @mock.patch.object(libvirt_utils, 'is_mounted', return_value=False)1572 def test_libvirt_quobyte_driver_qcow2(self, mock_is_mounted,1573 mock_mount_volume,1574 mock_validate_volume1575 ):1576 mnt_base = '/mnt'1577 self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')1578 libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)1579 export_string = 'quobyte://192.168.1.1/volume-00001'1580 name = 'volume-00001'1581 image_format = 'qcow2'1582 quobyte_volume = '192.168.1.1/volume-00001'1583 connection_info = {'data': {'export': export_string,1584 'name': name,1585 'format': image_format}}1586 export_mnt_base = os.path.join(mnt_base,1587 utils.get_hash_str(quobyte_volume))1588 libvirt_driver.connect_volume(connection_info, self.disk_info)1589 conf = libvirt_driver.get_config(connection_info, self.disk_info)1590 tree = conf.format_dom()1591 self.assertEqual(tree.get('type'), 'file')1592 self.assertEqual(tree.find('./driver').get('type'), 'qcow2')1593 (mock_mount_volume.1594 assert_called_once_with('192.168.1.1/volume-00001',1595 export_mnt_base,1596 mock.ANY))1597 mock_validate_volume.assert_called_with(export_mnt_base)1598 libvirt_driver.disconnect_volume(connection_info, "vde")1599 def test_libvirt_quobyte_driver_mount_non_quobyte_volume(self):1600 mnt_base = '/mnt'1601 self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')1602 libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)1603 export_string = 'quobyte://192.168.1.1/volume-00001'1604 connection_info = {'data': {'export': export_string,1605 'name': self.name}}1606 def exe_side_effect(*cmd, **kwargs):1607 if cmd == mock.ANY:1608 raise exception.NovaException()1609 with mock.patch.object(quobyte,1610 'validate_volume') as mock_execute:1611 mock_execute.side_effect = exe_side_effect1612 self.assertRaises(exception.NovaException,1613 libvirt_driver.connect_volume,1614 connection_info,1615 self.disk_info)1616 def test_libvirt_quobyte_driver_normalize_url_with_protocol(self):1617 mnt_base = '/mnt'1618 self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')1619 libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)1620 export_string = 'quobyte://192.168.1.1/volume-00001'1621 self.assertEqual(libvirt_driver._normalize_url(export_string),1622 "192.168.1.1/volume-00001")1623 def test_libvirt_quobyte_driver_normalize_url_without_protocol(self):1624 mnt_base = '/mnt'1625 self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')1626 libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)1627 export_string = '192.168.1.1/volume-00001'1628 self.assertEqual(libvirt_driver._normalize_url(export_string),...
volumeops.py
Source:volumeops.py
1# Copyright 2012 Pedro Navarro Perez2# Copyright 2013 Cloudbase Solutions Srl3# All Rights Reserved.4#5# Licensed under the Apache License, Version 2.0 (the "License"); you may6# not use this file except in compliance with the License. You may obtain7# a copy of the License at8#9# http://www.apache.org/licenses/LICENSE-2.010#11# Unless required by applicable law or agreed to in writing, software12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the14# License for the specific language governing permissions and limitations15# under the License.16"""17Management class for Storage-related functions (attach, detach, etc).18"""19import collections20import os21import re22import time23from oslo_config import cfg24from oslo_log import log as logging25from oslo_utils import excutils26from nova import exception27from nova.i18n import _, _LE, _LW28from nova.virt import driver29from nova.virt.hyperv import utilsfactory30from nova.virt.hyperv import vmutils31LOG = logging.getLogger(__name__)32hyper_volumeops_opts = [33 cfg.IntOpt('volume_attach_retry_count',34 default=10,35 help='The number of times to retry to attach a volume'),36 cfg.IntOpt('volume_attach_retry_interval',37 default=5,38 help='Interval between volume attachment attempts, in seconds'),39 cfg.IntOpt('mounted_disk_query_retry_count',40 default=10,41 help='The number of times to retry checking for a disk mounted '42 'via iSCSI.'),43 cfg.IntOpt('mounted_disk_query_retry_interval',44 default=5,45 help='Interval between checks for a mounted iSCSI '46 'disk, in seconds.'),47]48CONF = cfg.CONF49CONF.register_opts(hyper_volumeops_opts, 'hyperv')50CONF.import_opt('host', 'nova.netconf')51CONF.import_opt('my_ip', 'nova.netconf')52class VolumeOps(object):53 """Management class for Volume-related tasks54 """55 def __init__(self):56 self._vmutils = utilsfactory.get_vmutils()57 self._volutils = utilsfactory.get_volumeutils()58 self._initiator = None59 self._default_root_device = 'vda'60 self.volume_drivers = {'smbfs': SMBFSVolumeDriver(),61 'iscsi': ISCSIVolumeDriver()}62 def _get_volume_driver(self, driver_type=None, connection_info=None):63 if connection_info:64 driver_type = connection_info.get('driver_volume_type')65 if driver_type not in self.volume_drivers:66 raise exception.VolumeDriverNotFound(driver_type=driver_type)67 return self.volume_drivers[driver_type]68 def attach_volumes(self, block_device_info, instance_name, ebs_root):69 mapping = driver.block_device_info_get_mapping(block_device_info)70 if ebs_root:71 self.attach_volume(mapping[0]['connection_info'],72 instance_name, True)73 mapping = mapping[1:]74 for vol in mapping:75 self.attach_volume(vol['connection_info'], instance_name)76 def disconnect_volumes(self, block_device_info):77 mapping = driver.block_device_info_get_mapping(block_device_info)78 block_devices = self._group_block_devices_by_type(79 mapping)80 for driver_type, block_device_mapping in block_devices.items():81 volume_driver = self._get_volume_driver(driver_type)82 volume_driver.disconnect_volumes(block_device_mapping)83 def attach_volume(self, connection_info, instance_name, ebs_root=False):84 volume_driver = self._get_volume_driver(85 connection_info=connection_info)86 volume_driver.attach_volume(connection_info, instance_name, ebs_root)87 def detach_volume(self, connection_info, instance_name):88 volume_driver = self._get_volume_driver(89 connection_info=connection_info)90 volume_driver.detach_volume(connection_info, instance_name)91 def ebs_root_in_block_devices(self, block_device_info):92 if block_device_info:93 root_device = block_device_info.get('root_device_name')94 if not root_device:95 root_device = self._default_root_device96 return self._volutils.volume_in_mapping(root_device,97 block_device_info)98 def fix_instance_volume_disk_paths(self, instance_name, block_device_info):99 mapping = driver.block_device_info_get_mapping(block_device_info)100 if self.ebs_root_in_block_devices(block_device_info):101 mapping = mapping[1:]102 disk_address = 0103 for vol in mapping:104 connection_info = vol['connection_info']105 volume_driver = self._get_volume_driver(106 connection_info=connection_info)107 volume_driver.fix_instance_volume_disk_path(108 instance_name, connection_info, disk_address)109 disk_address += 1110 def get_volume_connector(self, instance):111 if not self._initiator:112 self._initiator = self._volutils.get_iscsi_initiator()113 if not self._initiator:114 LOG.warning(_LW('Could not determine iscsi initiator name'),115 instance=instance)116 return {117 'ip': CONF.my_block_storage_ip,118 'host': CONF.host,119 'initiator': self._initiator,120 }121 def initialize_volumes_connection(self, block_device_info):122 mapping = driver.block_device_info_get_mapping(block_device_info)123 for vol in mapping:124 connection_info = vol['connection_info']125 volume_driver = self._get_volume_driver(126 connection_info=connection_info)127 volume_driver.initialize_volume_connection(connection_info)128 def _group_block_devices_by_type(self, block_device_mapping):129 block_devices = collections.defaultdict(list)130 for volume in block_device_mapping:131 connection_info = volume['connection_info']132 volume_type = connection_info.get('driver_volume_type')133 block_devices[volume_type].append(volume)134 return block_devices135class ISCSIVolumeDriver(object):136 def __init__(self):137 self._vmutils = utilsfactory.get_vmutils()138 self._volutils = utilsfactory.get_volumeutils()139 def login_storage_target(self, connection_info):140 data = connection_info['data']141 target_lun = data['target_lun']142 target_iqn = data['target_iqn']143 target_portal = data['target_portal']144 auth_method = data.get('auth_method')145 auth_username = data.get('auth_username')146 auth_password = data.get('auth_password')147 if auth_method and auth_method.upper() != 'CHAP':148 raise vmutils.HyperVException(149 _("Cannot log in target %(target_iqn)s. Unsupported iSCSI "150 "authentication method: %(auth_method)s.") %151 {'target_iqn': target_iqn,152 'auth_method': auth_method})153 # Check if we already logged in154 if self._volutils.get_device_number_for_target(target_iqn, target_lun):155 LOG.debug("Already logged in on storage target. No need to "156 "login. Portal: %(target_portal)s, "157 "IQN: %(target_iqn)s, LUN: %(target_lun)s",158 {'target_portal': target_portal,159 'target_iqn': target_iqn, 'target_lun': target_lun})160 else:161 LOG.debug("Logging in on storage target. Portal: "162 "%(target_portal)s, IQN: %(target_iqn)s, "163 "LUN: %(target_lun)s",164 {'target_portal': target_portal,165 'target_iqn': target_iqn, 'target_lun': target_lun})166 self._volutils.login_storage_target(target_lun, target_iqn,167 target_portal, auth_username,168 auth_password)169 # Wait for the target to be mounted170 self._get_mounted_disk_from_lun(target_iqn, target_lun, True)171 def disconnect_volumes(self, block_device_mapping):172 iscsi_targets = collections.defaultdict(int)173 for vol in block_device_mapping:174 target_iqn = vol['connection_info']['data']['target_iqn']175 iscsi_targets[target_iqn] += 1176 for target_iqn, disconnected_luns in iscsi_targets.items():177 self.logout_storage_target(target_iqn, disconnected_luns)178 def logout_storage_target(self, target_iqn, disconnected_luns_count=1):179 total_available_luns = self._volutils.get_target_lun_count(180 target_iqn)181 if total_available_luns == disconnected_luns_count:182 LOG.debug("Logging off storage target %s", target_iqn)183 self._volutils.logout_storage_target(target_iqn)184 else:185 LOG.debug("Skipping disconnecting target %s as there "186 "are LUNs still being used.", target_iqn)187 def attach_volume(self, connection_info, instance_name, ebs_root=False):188 """Attach a volume to the SCSI controller or to the IDE controller if189 ebs_root is True190 """191 target_iqn = None192 LOG.debug("Attach_volume: %(connection_info)s to %(instance_name)s",193 {'connection_info': connection_info,194 'instance_name': instance_name})195 try:196 self.login_storage_target(connection_info)197 data = connection_info['data']198 target_lun = data['target_lun']199 target_iqn = data['target_iqn']200 # Getting the mounted disk201 mounted_disk_path = self._get_mounted_disk_from_lun(target_iqn,202 target_lun)203 if ebs_root:204 # Find the IDE controller for the vm.205 ctrller_path = self._vmutils.get_vm_ide_controller(206 instance_name, 0)207 # Attaching to the first slot208 slot = 0209 else:210 # Find the SCSI controller for the vm211 ctrller_path = self._vmutils.get_vm_scsi_controller(212 instance_name)213 slot = self._vmutils.get_free_controller_slot(ctrller_path)214 self._vmutils.attach_volume_to_controller(instance_name,215 ctrller_path,216 slot,217 mounted_disk_path)218 except Exception:219 with excutils.save_and_reraise_exception():220 LOG.error(_LE('Unable to attach volume to instance %s'),221 instance_name)222 if target_iqn:223 self.logout_storage_target(target_iqn)224 def detach_volume(self, connection_info, instance_name):225 """Detach a volume to the SCSI controller."""226 LOG.debug("Detach_volume: %(connection_info)s "227 "from %(instance_name)s",228 {'connection_info': connection_info,229 'instance_name': instance_name})230 data = connection_info['data']231 target_lun = data['target_lun']232 target_iqn = data['target_iqn']233 # Getting the mounted disk234 mounted_disk_path = self._get_mounted_disk_from_lun(target_iqn,235 target_lun)236 LOG.debug("Detaching physical disk from instance: %s",237 mounted_disk_path)238 self._vmutils.detach_vm_disk(instance_name, mounted_disk_path)239 self.logout_storage_target(target_iqn)240 def _get_mounted_disk_from_lun(self, target_iqn, target_lun,241 wait_for_device=False):242 # The WMI query in get_device_number_for_target can incorrectly243 # return no data when the system is under load. This issue can244 # be avoided by adding a retry.245 for i in xrange(CONF.hyperv.mounted_disk_query_retry_count):246 device_number = self._volutils.get_device_number_for_target(247 target_iqn, target_lun)248 if device_number in (None, -1):249 attempt = i + 1250 LOG.debug('Attempt %d to get device_number '251 'from get_device_number_for_target failed. '252 'Retrying...', attempt)253 time.sleep(CONF.hyperv.mounted_disk_query_retry_interval)254 else:255 break256 if device_number in (None, -1):257 raise exception.NotFound(_('Unable to find a mounted disk for '258 'target_iqn: %s') % target_iqn)259 LOG.debug('Device number: %(device_number)s, '260 'target lun: %(target_lun)s',261 {'device_number': device_number, 'target_lun': target_lun})262 # Finding Mounted disk drive263 for i in range(0, CONF.hyperv.volume_attach_retry_count):264 mounted_disk_path = self._vmutils.get_mounted_disk_by_drive_number(265 device_number)266 if mounted_disk_path or not wait_for_device:267 break268 time.sleep(CONF.hyperv.volume_attach_retry_interval)269 if not mounted_disk_path:270 raise exception.NotFound(_('Unable to find a mounted disk for '271 'target_iqn: %s. Please ensure that '272 'the host\'s SAN policy is set to '273 '"OfflineAll" or "OfflineShared"') %274 target_iqn)275 return mounted_disk_path276 def get_target_from_disk_path(self, physical_drive_path):277 return self._volutils.get_target_from_disk_path(physical_drive_path)278 def fix_instance_volume_disk_path(self, instance_name, connection_info,279 disk_address):280 data = connection_info['data']281 target_lun = data['target_lun']282 target_iqn = data['target_iqn']283 mounted_disk_path = self._get_mounted_disk_from_lun(284 target_iqn, target_lun, True)285 ctrller_path = self._vmutils.get_vm_scsi_controller(instance_name)286 self._vmutils.set_disk_host_resource(287 instance_name, ctrller_path, disk_address, mounted_disk_path)288 def get_target_lun_count(self, target_iqn):289 return self._volutils.get_target_lun_count(target_iqn)290 def initialize_volume_connection(self, connection_info):291 self.login_storage_target(connection_info)292class SMBFSVolumeDriver(object):293 def __init__(self):294 self._pathutils = utilsfactory.get_pathutils()295 self._vmutils = utilsfactory.get_vmutils()296 self._volutils = utilsfactory.get_volumeutils()297 self._username_regex = re.compile(r'user(?:name)?=([^, ]+)')298 self._password_regex = re.compile(r'pass(?:word)?=([^, ]+)')299 def attach_volume(self, connection_info, instance_name, ebs_root=False):300 self.ensure_share_mounted(connection_info)301 disk_path = self._get_disk_path(connection_info)302 try:303 if ebs_root:304 ctrller_path = self._vmutils.get_vm_ide_controller(305 instance_name, 0)306 slot = 0307 else:308 ctrller_path = self._vmutils.get_vm_scsi_controller(309 instance_name)310 slot = self._vmutils.get_free_controller_slot(ctrller_path)311 self._vmutils.attach_drive(instance_name,312 disk_path,313 ctrller_path,314 slot)315 except vmutils.HyperVException as exn:316 LOG.exception(_LE('Attach volume failed: %s'), exn)317 raise vmutils.HyperVException(_('Unable to attach volume '318 'to instance %s') % instance_name)319 def detach_volume(self, connection_info, instance_name):320 LOG.debug("Detaching volume: %(connection_info)s "321 "from %(instance_name)s",322 {'connection_info': connection_info,323 'instance_name': instance_name})324 disk_path = self._get_disk_path(connection_info)325 export_path = self._get_export_path(connection_info)326 self._vmutils.detach_vm_disk(instance_name, disk_path,327 is_physical=False)328 self._pathutils.unmount_smb_share(export_path)329 def disconnect_volumes(self, block_device_mapping):330 export_paths = set()331 for vol in block_device_mapping:332 connection_info = vol['connection_info']333 export_path = self._get_export_path(connection_info)334 export_paths.add(export_path)335 for export_path in export_paths:336 self._pathutils.unmount_smb_share(export_path)337 def _get_export_path(self, connection_info):338 return connection_info['data']['export'].replace('/', '\\')339 def _get_disk_path(self, connection_info):340 export = self._get_export_path(connection_info)341 disk_name = connection_info['data']['name']342 disk_path = os.path.join(export, disk_name)343 return disk_path344 def ensure_share_mounted(self, connection_info):345 export_path = self._get_export_path(connection_info)346 if not self._pathutils.check_smb_mapping(export_path):347 opts_str = connection_info['data'].get('options', '')348 username, password = self._parse_credentials(opts_str)349 self._pathutils.mount_smb_share(export_path,350 username=username,351 password=password)352 def _parse_credentials(self, opts_str):353 match = self._username_regex.findall(opts_str)354 username = match[0] if match and match[0] != 'guest' else None355 match = self._password_regex.findall(opts_str)356 password = match[0] if match else None357 return username, password358 def fix_instance_volume_disk_path(self, instance_name, connection_info,359 disk_address):360 self.ensure_share_mounted(connection_info)361 def initialize_volume_connection(self, connection_info):...
graph.py
Source:graph.py
1# case 1 (ììë
¸ëë¶í° ëë
¸ëê¹ì§ ì ë¶ íì)2connection_info = {3 'A': ['B', 'C'],4 'B': ['C', 'D'],5 'C': ['D'],6 'D': ['C'],7 'E': ['F'],8 'F': ['C']9 }10def search_route(connection_info, start_node, end_node, route=[]):11 # 1. route = ['B']12 # 2. route = ['B', 'C']13 # 3. route = ['B', 'C', 'D']14 route = route + [start_node] 15 # 1. pass16 # 2. pass17 # 3. start_node = 'D' , end_node = 'D'ì´ëê¹ stop. íì¬ route = ['B', 'C', 'D'] ë°í18 if start_node == end_node:19 return route 20 21 # 1. pass22 # 2. pass23 if not connection_info.__contains__(start_node):24 return None 25 # 1. node = 'C', 'D'26 # 2. node = 'D'27 for node in connection_info[start_node]: 28 # 1. node = 'C' ì´ë©´ route = ['B']ì ìì¼ëê¹ ì¬ê· í¸ì¶29 # 2. node = 'D' ì´ë©´ route = ['B', 'C']ì ìì¼ëê¹ ì¬ê· í¸ì¶30 if node not in route : 31 # 1. new_route = search_route(connection_info, 'C', 'D', ['B'])32 # 2. new_route = search_route(connection_info, 'D', 'D', ['B', 'C']) 33 new_route = search_route(connection_info, node, end_node, route)34 # 3. new_route = ['B', 'C', 'D']35 # 2. new_route = ['B', 'C', 'D']36 # 1. new_route = ['B', 'C', 'D']37 if new_route :38 return new_route39 40 return None41search_route(connection_info, 'B', 'D') # ['B', 'C', 'D']42# case 2 (ììë
¸ëë¶í° ëë
¸ëê¹ì§ ì ë¶ íì)43connection_info = {44 'A': ['B', 'C'],45 'B': ['C'],46 'C': ['E', 'F'],47 'D': ['C'],48 'E': ['F'],49 'F': ['C']50}51def search_route(connection_info, start_node, end_node, route=[]):52 # 1. route = ['B']53 # 2. route = ['B', 'C']54 # 3. route = ['B', 'C', 'E']55 # 4. route = ['B', 'C', 'E', 'F']56 route = route + [start_node] 57 # 1. pass58 # 2. pass59 # 3. pass60 # 4. pass61 if start_node == end_node:62 return route 63 64 # 1. pass65 # 2. pass66 # 3. pass67 # 4. pass68 if not connection_info.__contains__(start_node):69 return None 70 # 1. node = 'C', 'D'71 # 2. node = 'E', 'F'72 # 3. node = 'F'73 # 4. node = 'C'74 for node in connection_info[start_node]: 75 # 1. node = 'C' ì´ë©´ route = ['B']ì ìì¼ëê¹ ì¬ê· í¸ì¶76 # 2. node = 'E' ì´ë©´ route = ['B', 'C']ì ìì¼ëê¹ ì¬ê· í¸ì¶77 # 3. node = 'F' ì´ë©´ route = ['B', 'C', 'E']ì ìì¼ëê¹ ì¬ê· í¸ì¶78 if node not in route : 79 # 1. new_route = search_route(connection_info, 'C', 'D', ['B'])80 # 2. new_route = search_route(connection_info, 'E', 'D', ['B', 'C']) 81 # 3. new_route = search_route(connection_info, 'F', 'D', ['B', 'C', 'E']) 82 new_route = search_route(connection_info, node, end_node, route)83 if new_route :84 return new_route85 # 4. node = 'C'ê° route = ['B', 'C', 'E', 'F']ì ì기 ë문ì return None 86 return None87search_route(connection_info, 'B', 'D') # None88# case 3 (ììë
¸ëì ëë
¸ëì ìµë¨ ê²½ë¡ íì)89connection_info = {90 'A': ['B', 'C'],91 'B': ['C', 'D'],92 'C': ['D'],93 'D': ['C'],94 'E': ['F'],95 'F': ['C']96 }97# ë³µì¡í´ì ê·¸ë¥ í¸ì¶ ììëë¡ ì ì98def search_shortest_route(connection_info, start_node, end_node, route=[]):99 # 1. route = ['B']100 # 4. route = ['B', 'C']101 # 7. route = ['B', 'C', 'D']102 # 14. route = ['B', 'D']103 route = route + [start_node]104 # 8. return ['B', 'C', 'D']105 # 15. return ['B', 'D']106 if start_node == end_node:107 return route108 if not connection_info.__contains__(start_node):109 return None110 shortest = None111 # 2. route = ['B'], node = 'C'112 # 5. route = ['B', 'C'], node = 'D'113 # 12. route = ['B'], node = 'D'114 for node in connection_info[start_node]:115 if node in route :116 return None117 # 3. new_route = search_shortest_route(connection_info, 'C', 'D', ['B'])118 # 6. new_route = search_shortest_route(connection_info, 'D', 'D', ['B', 'C'])119 # 9. 6ë²ì new_route = ['B', 'C', 'D']120 # 13. new_route = search_shortest_route(connection_info, 'D', 'D', ['B'])121 # 16. 13ë²ì new_route = ['B', 'D']122 new_route = search_shortest_route(connection_info, node, end_node, route)123 # 10. 4ë²ì new_route = ['B', 'C', 'D'], shortest = None124 # 17. 10ë²ì new_route = ['B', 'D'], shortest = ['B', 'C', 'D']125 if new_route :126 # 11. 4ë²ì new_route = ['B', 'C', 'D'] = shortest127 if shortest is None :128 shortest = new_route129 # 18. 10ë²ì len(new_route) = len(shortest) 2 < 3ì´ê¸° ë문ì shortest = ['B', 'D']130 elif len(new_route) < len(shortest):131 shortest = new_route132 # 19. íì¬ shortest = ['B', 'D']133 return shortest...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!