diff --git a/nova/tests/virt/vmwareapi/test_driver_api.py b/nova/tests/virt/vmwareapi/test_driver_api.py index e5d547bb88eb..67b802c348ed 100644 --- a/nova/tests/virt/vmwareapi/test_driver_api.py +++ b/nova/tests/virt/vmwareapi/test_driver_api.py @@ -276,7 +276,6 @@ class VMwareAPIVMTestCase(test.NoDBTestCase): self.flags(host_ip='test_url', host_username='test_username', host_password='test_pass', - cluster_name='test_cluster', datastore_regex='.*', api_retry_count=1, use_linked_clone=False, group='vmware') @@ -1554,14 +1553,22 @@ class VMwareAPIVMTestCase(test.NoDBTestCase): def test_attach_iscsi_disk_to_vm(self): self._create_vm() connection_info = self._test_vmdk_connection_info('iscsi') - connection_info['data']['target_portal'] = 'fake_target_portal' + connection_info['data']['target_portal'] = 'fake_target_host:port' connection_info['data']['target_iqn'] = 'fake_target_iqn' mount_point = '/dev/vdc' discover = ('fake_name', 'fake_uuid') - self.mox.StubOutWithMock(volumeops.VMwareVolumeOps, - 'discover_st') - volumeops.VMwareVolumeOps.discover_st( - connection_info['data']).AndReturn(discover) + self.mox.StubOutWithMock(volume_util, 'find_st') + # simulate target not found + volume_util.find_st(mox.IgnoreArg(), connection_info['data'], + mox.IgnoreArg()).AndReturn((None, None)) + self.mox.StubOutWithMock(volume_util, '_add_iscsi_send_target_host') + # rescan gets called with target portal + volume_util.rescan_iscsi_hba( + self.conn._session, + target_portal=connection_info['data']['target_portal']) + # simulate target found + volume_util.find_st(mox.IgnoreArg(), connection_info['data'], + mox.IgnoreArg()).AndReturn(discover) self.mox.StubOutWithMock(volumeops.VMwareVolumeOps, 'attach_disk_to_vm') volumeops.VMwareVolumeOps.attach_disk_to_vm(mox.IgnoreArg(), @@ -1571,6 +1578,27 @@ class VMwareAPIVMTestCase(test.NoDBTestCase): self.conn.attach_volume(None, connection_info, self.instance, mount_point) + def test_rescan_iscsi_hba(self): + fake_target_portal = 'fake_target_host:port' + host_storage_sys = vmwareapi_fake._get_objects( + "HostStorageSystem").objects[0] + iscsi_hba_array = host_storage_sys.get('storageDeviceInfo' + '.hostBusAdapter') + iscsi_hba = iscsi_hba_array.HostHostBusAdapter[0] + # Check the host system does not have the send target + self.assertRaises(AttributeError, getattr, iscsi_hba, + 'configuredSendTarget') + # Rescan HBA with the target portal + volume_util.rescan_iscsi_hba(self.conn._session, None, + fake_target_portal) + # Check if HBA has the target portal configured + self.assertEqual('fake_target_host', + iscsi_hba.configuredSendTarget[0].address) + # Rescan HBA with same portal + volume_util.rescan_iscsi_hba(self.conn._session, None, + fake_target_portal) + self.assertEqual(1, len(iscsi_hba.configuredSendTarget)) + def test_find_st(self): data = {'target_portal': 'fake_target_host:port', 'target_iqn': 'fake_target_iqn'} diff --git a/nova/virt/vmwareapi/fake.py b/nova/virt/vmwareapi/fake.py index 3247e31166f9..04a6b4eb73b4 100644 --- a/nova/virt/vmwareapi/fake.py +++ b/nova/virt/vmwareapi/fake.py @@ -1289,6 +1289,18 @@ class FakeVim(object): host_mdo = _db_content["HostSystem"][_host_sk] host_mdo._add_port_group(kwargs.get("portgrp")) + def _add_iscsi_send_tgt(self, method, *args, **kwargs): + """Adds a iscsi send target to the hba.""" + send_targets = kwargs.get('targets') + host_storage_sys = _get_objects('HostStorageSystem').objects[0] + iscsi_hba_array = host_storage_sys.get('storageDeviceInfo' + '.hostBusAdapter') + iscsi_hba = iscsi_hba_array.HostHostBusAdapter[0] + if hasattr(iscsi_hba, 'configuredSendTarget'): + iscsi_hba.configuredSendTarget.extend(send_targets) + else: + iscsi_hba.configuredSendTarget = send_targets + def __getattr__(self, attr_name): if attr_name != "Login": self._check_session() @@ -1388,3 +1400,8 @@ class FakeVim(object): return lambda *args, **kwargs: self._just_return_task(attr_name) elif attr_name == "ExitMaintenanceMode_Task": return lambda *args, **kwargs: self._just_return_task(attr_name) + elif attr_name == "AddInternetScsiSendTargets": + return lambda *args, **kwargs: self._add_iscsi_send_tgt(attr_name, + *args, **kwargs) + elif attr_name == "RescanHba": + return lambda *args, **kwargs: self._just_return_task(attr_name) diff --git a/nova/virt/vmwareapi/volume_util.py b/nova/virt/vmwareapi/volume_util.py index f0b689e29ae8..45421bf2bde5 100644 --- a/nova/virt/vmwareapi/volume_util.py +++ b/nova/virt/vmwareapi/volume_util.py @@ -121,7 +121,7 @@ def find_st(session, data, cluster=None): return result -def rescan_iscsi_hba(session, cluster=None): +def rescan_iscsi_hba(session, cluster=None, target_portal=None): """Rescan the iSCSI HBA to discover iSCSI targets.""" host_mor = vm_util.get_host_ref(session, cluster) storage_system_mor = session._call_method(vim_util, "get_dynamic_property", @@ -141,11 +141,30 @@ def rescan_iscsi_hba(session, cluster=None): for hba in host_hbas: if hba.__class__.__name__ == 'HostInternetScsiHba': hba_device = hba.device + if target_portal: + # Check if iscsi host is already in the send target host list + send_targets = getattr(hba, 'configuredSendTarget', []) + send_tgt_portals = ['%s:%s' % (s.address, s.port) for s in + send_targets] + if target_portal not in send_tgt_portals: + _add_iscsi_send_target_host(session, storage_system_mor, + hba_device, target_portal) break else: return - LOG.debug(_("Rescanning HBA %s") % hba_device) session._call_method(session._get_vim(), "RescanHba", storage_system_mor, hbaDevice=hba_device) LOG.debug(_("Rescanned HBA %s ") % hba_device) + + +def _add_iscsi_send_target_host(session, storage_system_mor, hba_device, + target_portal): + """Adds the iscsi host to send target host list.""" + client_factory = session._get_vim().client.factory + send_tgt = client_factory.create('ns0:HostInternetScsiHbaSendTarget') + (send_tgt.address, send_tgt.port) = target_portal.split(':') + LOG.debug(_("Adding iSCSI host %s to send targets"), send_tgt.address) + session._call_method( + session._get_vim(), "AddInternetScsiSendTargets", storage_system_mor, + iScsiHbaDevice=hba_device, targets=[send_tgt]) diff --git a/nova/virt/vmwareapi/volumeops.py b/nova/virt/vmwareapi/volumeops.py index 318106178e06..80f6ebd50f7b 100644 --- a/nova/virt/vmwareapi/volumeops.py +++ b/nova/virt/vmwareapi/volumeops.py @@ -144,8 +144,9 @@ class VMwareVolumeOps(object): if device_name: LOG.debug(_("Storage target found. No need to discover")) return (device_name, uuid) - # Rescan iSCSI HBA - volume_util.rescan_iscsi_hba(self._session, self._cluster) + # Rescan iSCSI HBA with iscsi target host + volume_util.rescan_iscsi_hba(self._session, self._cluster, + target_portal) # Find iSCSI Target again device_name, uuid = volume_util.find_st(self._session, data, self._cluster)