diff --git a/nova_powervm/tests/virt/powervm/test_driver.py b/nova_powervm/tests/virt/powervm/test_driver.py index a721c974..d81f64b1 100644 --- a/nova_powervm/tests/virt/powervm/test_driver.py +++ b/nova_powervm/tests/virt/powervm/test_driver.py @@ -181,17 +181,20 @@ class TestPowerVMDriver(test.TestCase): self.assertTrue( self.drv.session.get_event_listener.return_value.shutdown.called) - def test_get_volume_connector(self): + @mock.patch('nova_powervm.virt.powervm.volume.get_iscsi_initiator') + def test_get_volume_connector(self, mock_initiator): """Tests that a volume connector can be built.""" + mock_initiator.return_value = 'iscsi_initiator' self.flags(volume_adapter='fibre_channel', group='powervm') vol_connector = self.drv.get_volume_connector(mock.Mock()) self.assertIsNotNone(vol_connector['wwpns']) self.assertIsNotNone(vol_connector['host']) + self.assertEqual('iscsi_initiator', vol_connector['initiator']) self.flags(volume_adapter='iscsi', group='powervm') vol_connector = self.drv.get_volume_connector(mock.Mock()) - self.assertIsNotNone(vol_connector['initiator']) + self.assertEqual('iscsi_initiator', vol_connector['initiator']) def test_setup_disk_adapter(self): # Ensure we can handle upper case option and we instantiate the class diff --git a/nova_powervm/tests/virt/powervm/volume/test_driver.py b/nova_powervm/tests/virt/powervm/volume/test_driver.py index 13f787bc..01a23bed 100644 --- a/nova_powervm/tests/virt/powervm/volume/test_driver.py +++ b/nova_powervm/tests/virt/powervm/volume/test_driver.py @@ -15,9 +15,12 @@ # under the License. import mock +from pypowervm.wrappers import virtual_io_server as pvm_vios from nova import test +from nova_powervm.virt.powervm import volume + class TestVolumeAdapter(test.TestCase): @@ -32,3 +35,29 @@ class TestVolumeAdapter(test.TestCase): self.mock_inst_wrap = mock.MagicMock() self.mock_inst_wrap.can_modify_io.return_value = (True, None) self.mock_get_inst_wrap.return_value = self.mock_inst_wrap + + +class TestInitMethods(test.TestCase): + + @mock.patch('pypowervm.tasks.hdisk.discover_iscsi_initiator') + @mock.patch('pypowervm.tasks.partition.get_mgmt_partition') + def test_get_iscsi_initiator(self, mock_mgmt, mock_iscsi_init): + # Set up mocks and clear out data that may have been set by other + # tests + mock_adpt = mock.Mock() + mock_mgmt.return_value = mock.Mock(spec=pvm_vios.VIOS) + mock_iscsi_init.return_value = 'test_initiator' + + self.assertEqual('test_initiator', + volume.get_iscsi_initiator(mock_adpt)) + + # Make sure it gets set properly in the backend + self.assertEqual('test_initiator', volume._ISCSI_INITIATOR) + self.assertTrue(volume._ISCSI_LOOKUP_COMPLETE) + mock_mgmt.assert_called_once_with(mock_adpt) + self.assertEqual(1, mock_mgmt.call_count) + + # Invoke again, make sure it doesn't call down to the mgmt part again + self.assertEqual('test_initiator', + volume.get_iscsi_initiator(mock_adpt)) + self.assertEqual(1, mock_mgmt.call_count) diff --git a/nova_powervm/virt/powervm/driver.py b/nova_powervm/virt/powervm/driver.py index b3853b0c..4769d7c8 100644 --- a/nova_powervm/virt/powervm/driver.py +++ b/nova_powervm/virt/powervm/driver.py @@ -1132,11 +1132,9 @@ class PowerVMDriver(driver.ComputeDriver): # The host ID connector = {'host': CONF.host} - # The WWPNs in case of FC connection. + # Get the contents from the volume driver vol_drv = self._get_inst_vol_adpt(ctx.get_admin_context(), instance) - - # The WWPNs in case of FC connection. if vol_drv is not None: if CONF.powervm.volume_adapter.lower() == "fibre_channel": @@ -1145,7 +1143,8 @@ class PowerVMDriver(driver.ComputeDriver): if wwpn_list is not None: connector["wwpns"] = wwpn_list connector['host'] = vol_drv.host_name() - connector['initiator'] = vol_drv.host_name() + connector['initiator'] = vol_attach.get_iscsi_initiator( + self.adapter) return connector def migrate_disk_and_power_off(self, context, instance, dest, diff --git a/nova_powervm/virt/powervm/volume/__init__.py b/nova_powervm/virt/powervm/volume/__init__.py index 178d082e..d64eec3a 100644 --- a/nova_powervm/virt/powervm/volume/__init__.py +++ b/nova_powervm/virt/powervm/volume/__init__.py @@ -14,6 +14,11 @@ # License for the specific language governing permissions and limitations # under the License. +from oslo_concurrency import lockutils +from pypowervm.tasks import hdisk +from pypowervm.tasks import partition +from pypowervm.wrappers import virtual_io_server as pvm_vios + # Defines the various volume connectors that can be used. from nova_powervm import conf as cfg @@ -26,3 +31,27 @@ FC_STRATEGY_MAPPING = { NETWORK_STRATEGY_MAPPING = { 'iscsi': 'nova_powervm.virt.powervm.volume.iscsi.IscsiVolumeAdapter' } + +_ISCSI_INITIATOR = None +_ISCSI_LOOKUP_COMPLETE = False + + +@lockutils.synchronized("PowerVM_iSCSI_Initiator_Lookup") +def get_iscsi_initiator(adapter): + """Gets the iSCSI initiator. + + This is looked up once at process start up. Stored in memory thereafter. + + :param adapter: The pypowervm adapter. + :return: The initiator name. If the NovaLink is not capable of supporting + iSCSI, None will be returned. + """ + global _ISCSI_INITIATOR, _ISCSI_LOOKUP_COMPLETE + if not _ISCSI_LOOKUP_COMPLETE: + mgmt_w = partition.get_mgmt_partition(adapter) + if isinstance(mgmt_w, pvm_vios.VIOS): + _ISCSI_INITIATOR = hdisk.discover_iscsi_initiator( + adapter, mgmt_w.uuid) + + _ISCSI_LOOKUP_COMPLETE = True + return _ISCSI_INITIATOR diff --git a/nova_powervm/virt/powervm/volume/iscsi.py b/nova_powervm/virt/powervm/volume/iscsi.py index 6cfa062b..5ca62df3 100644 --- a/nova_powervm/virt/powervm/volume/iscsi.py +++ b/nova_powervm/virt/powervm/volume/iscsi.py @@ -26,7 +26,6 @@ from nova_powervm.virt.powervm.volume import driver as v_driver from nova_powervm.virt.powervm.volume import volume as volume from pypowervm import const as pvm_const from pypowervm.tasks import hdisk -from pypowervm.tasks import partition from pypowervm.utils import transaction as tx from pypowervm.wrappers import virtual_io_server as pvm_vios @@ -52,19 +51,13 @@ class IscsiVolumeAdapter(volume.VscsiVolumeAdapter, super(IscsiVolumeAdapter, self).__init__( adapter, host_uuid, instance, connection_info, stg_ftsk=stg_ftsk) - # iSCSI volumes are assumed to be on the novalink partition - mgmt_part = partition.get_mgmt_partition(adapter) - vios_uuid = mgmt_part.uuid - self.initiator_name = hdisk.discover_iscsi_initiator( - adapter, vios_uuid) - @classmethod def vol_type(cls): """The type of volume supported by this type.""" return 'iscsi' def host_name(self): - return self.initiator_name + return CONF.host @classmethod def min_xags(cls):