Return iSCSI Initiator for VIOSes
Adding the get_iscsi_initiators method in iscsi volume adapter to discover all iSCSI initiators for active VIOSes and return the first initiator from the sorted collection of initiators. Change-Id: Ic842bd49e0a3dc6e4f4a3bf14409ca2f70369a26
This commit is contained in:
parent
ec454b725d
commit
390347afc6
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2014, 2017 IBM Corp.
|
||||
# Copyright 2014, 2018 IBM Corp.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
|
@ -15,7 +15,7 @@
|
|||
# under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import collections
|
||||
import fixtures
|
||||
import logging
|
||||
import mock
|
||||
|
@ -206,21 +206,21 @@ class TestPowerVMDriver(test.NoDBTestCase):
|
|||
self.assertTrue(
|
||||
self.drv.session.get_event_listener.return_value.shutdown.called)
|
||||
|
||||
@mock.patch('nova_powervm.virt.powervm.volume.get_iscsi_initiator',
|
||||
autospec=True)
|
||||
def test_get_volume_connector(self, mock_initiator):
|
||||
@mock.patch('nova_powervm.virt.powervm.volume.iscsi.get_iscsi_initiators')
|
||||
def test_get_volume_connector(self, mock_initiators):
|
||||
"""Tests that a volume connector can be built."""
|
||||
mock_initiator.return_value = 'iscsi_initiator'
|
||||
|
||||
initiators = [('1300C76F-9814-4A4D-B1F0-5B69352A7DEA', 'fake_iqn1'),
|
||||
('7DBBE705-E4C4-4458-8223-3EBE07015CA9', 'fake_iqn2')]
|
||||
initiators = collections.OrderedDict(initiators)
|
||||
|
||||
mock_initiators.return_value = initiators
|
||||
|
||||
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.assertEqual('iscsi_initiator', vol_connector['initiator'])
|
||||
self.assertEqual('fake_iqn1', vol_connector['initiator'])
|
||||
|
||||
def test_setup_disk_adapter(self):
|
||||
# Ensure we can handle upper case option and we instantiate the class
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2015, 2017 IBM Corp.
|
||||
# Copyright 2015, 2018 IBM Corp.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
|
@ -15,7 +15,6 @@
|
|||
# under the License.
|
||||
|
||||
import mock
|
||||
from pypowervm.wrappers import virtual_io_server as pvm_vios
|
||||
import six
|
||||
|
||||
from nova import test
|
||||
|
@ -54,34 +53,6 @@ class TestInitMethods(test.NoDBTestCase):
|
|||
'gpfs': gpfs.GPFSVolumeAdapter,
|
||||
}
|
||||
|
||||
@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)
|
||||
|
||||
# Check if initiator returned does not have newline character
|
||||
mock_iscsi_init.return_value = 'test_initiator\n'
|
||||
self.assertEqual('test_initiator',
|
||||
volume.get_iscsi_initiator(mock_adpt))
|
||||
|
||||
def test_get_volume_class(self):
|
||||
for vol_type, class_type in six.iteritems(self.volume_drivers):
|
||||
self.assertEqual(class_type, volume.get_volume_class(vol_type))
|
||||
|
|
|
@ -392,3 +392,64 @@ class TestISCSIAdapter(test_vol.TestVolumeAdapter):
|
|||
retrieved_devname = self.vol_drv._get_devname()
|
||||
# Check key not found
|
||||
self.assertIsNone(retrieved_devname)
|
||||
|
||||
@mock.patch('pypowervm.tasks.partition.get_active_vioses')
|
||||
@mock.patch('pypowervm.tasks.hdisk.discover_iscsi_initiator')
|
||||
def test_get_iscsi_initiators(self, mock_iscsi_init, mock_active_vioses):
|
||||
# Set up mocks and clear out data that may have been set by other
|
||||
# tests
|
||||
iscsi._ISCSI_INITIATORS = dict()
|
||||
mock_iscsi_init.return_value = 'test_initiator'
|
||||
|
||||
vios_ids = ['1300C76F-9814-4A4D-B1F0-5B69352A7DEA',
|
||||
'7DBBE705-E4C4-4458-8223-3EBE07015CA9']
|
||||
|
||||
mock_active_vioses.return_value = vios_ids
|
||||
|
||||
expected_output = {
|
||||
'1300C76F-9814-4A4D-B1F0-5B69352A7DEA': 'test_initiator',
|
||||
'7DBBE705-E4C4-4458-8223-3EBE07015CA9': 'test_initiator'
|
||||
}
|
||||
|
||||
self.assertEqual(expected_output,
|
||||
iscsi.get_iscsi_initiators(self.adpt, vios_ids))
|
||||
|
||||
# Make sure it gets set properly in the backend
|
||||
self.assertEqual(expected_output, iscsi._ISCSI_INITIATORS)
|
||||
self.assertEqual(mock_active_vioses.call_count, 0)
|
||||
self.assertEqual(mock_iscsi_init.call_count, 2)
|
||||
|
||||
# Invoke again, make sure it doesn't call down to the mgmt part again
|
||||
mock_iscsi_init.reset_mock()
|
||||
self.assertEqual(expected_output,
|
||||
iscsi.get_iscsi_initiators(self.adpt, vios_ids))
|
||||
self.assertEqual(mock_active_vioses.call_count, 0)
|
||||
self.assertEqual(mock_iscsi_init.call_count, 0)
|
||||
|
||||
# Invoke iscsi.get_iscsi_initiators with vios_id=None
|
||||
iscsi._ISCSI_INITIATORS = dict()
|
||||
mock_iscsi_init.reset_mock()
|
||||
self.assertEqual(expected_output,
|
||||
iscsi.get_iscsi_initiators(self.adpt, None))
|
||||
self.assertEqual(expected_output, iscsi._ISCSI_INITIATORS)
|
||||
self.assertEqual(mock_active_vioses.call_count, 1)
|
||||
self.assertEqual(mock_iscsi_init.call_count, 2)
|
||||
|
||||
# Invoke again with vios_id=None to ensure get_active_vioses,
|
||||
# discover_iscsi_initiator is not called
|
||||
mock_iscsi_init.reset_mock()
|
||||
mock_active_vioses.reset_mock()
|
||||
self.assertEqual(expected_output,
|
||||
iscsi.get_iscsi_initiators(self.adpt, None))
|
||||
self.assertEqual(mock_active_vioses.call_count, 0)
|
||||
self.assertEqual(mock_iscsi_init.call_count, 0)
|
||||
|
||||
# Invoke iscsi.get_iscsi_initiators with discover_iscsi_initiator()
|
||||
# raises ISCSIDiscoveryFailed exception
|
||||
iscsi._ISCSI_INITIATORS = dict()
|
||||
mock_iscsi_init.reset_mock()
|
||||
mock_iscsi_init.side_effect = pvm_exc.ISCSIDiscoveryFailed(
|
||||
vios_uuid='fake_vios_uid', status="fake_status")
|
||||
self.assertEqual(dict(),
|
||||
iscsi.get_iscsi_initiators(self.adpt, vios_ids))
|
||||
self.assertEqual(dict(), iscsi._ISCSI_INITIATORS)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2014, 2017 IBM Corp.
|
||||
# Copyright 2014, 2018 IBM Corp.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
|
@ -66,7 +66,7 @@ from nova_powervm.virt.powervm.tasks import storage as tf_stg
|
|||
from nova_powervm.virt.powervm.tasks import vm as tf_vm
|
||||
from nova_powervm.virt.powervm import vm
|
||||
from nova_powervm.virt.powervm import volume as vol_attach
|
||||
|
||||
from nova_powervm.virt.powervm.volume import iscsi
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
|
@ -1103,7 +1103,9 @@ class PowerVMDriver(driver.ComputeDriver):
|
|||
connector["wwpns"] = wwpn_list
|
||||
connector["multipath"] = CONF.powervm.volume_use_multipath
|
||||
connector['host'] = vol_attach.get_hostname_for_volume(instance)
|
||||
connector['initiator'] = vol_attach.get_iscsi_initiator(self.adapter)
|
||||
initiator_dict = iscsi.get_iscsi_initiators(self.adapter)
|
||||
if initiator_dict:
|
||||
connector['initiator'] = list(initiator_dict.values())[0]
|
||||
return connector
|
||||
|
||||
def migrate_disk_and_power_off(self, context, instance, dest,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2015, 2017 IBM Corp.
|
||||
# Copyright 2015, 2018 IBM Corp.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
|
@ -14,11 +14,6 @@
|
|||
# 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 import exception
|
||||
|
@ -85,28 +80,3 @@ def get_wwpns_for_volume_connector(adapter, host_uuid, instance):
|
|||
fc_vol_drv = build_volume_driver(adapter, host_uuid, instance,
|
||||
fake_fc_conn_info)
|
||||
return fc_vol_drv.wwpns()
|
||||
|
||||
|
||||
_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).strip()
|
||||
|
||||
_ISCSI_LOOKUP_COMPLETE = True
|
||||
return _ISCSI_INITIATOR
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import collections
|
||||
import copy
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_log import log as logging
|
||||
|
@ -26,6 +27,7 @@ from nova_powervm.virt.powervm.volume import volume
|
|||
from pypowervm import const as pvm_const
|
||||
from pypowervm import exceptions as pvm_exc
|
||||
from pypowervm.tasks import hdisk
|
||||
from pypowervm.tasks import partition as pvm_partition
|
||||
from pypowervm.utils import transaction as tx
|
||||
from pypowervm.wrappers import virtual_io_server as pvm_vios
|
||||
|
||||
|
@ -37,6 +39,56 @@ import six
|
|||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
DEVNAME_KEY = 'target_devname'
|
||||
_ISCSI_INITIATORS = collections.OrderedDict()
|
||||
|
||||
|
||||
def get_iscsi_initiators(adapter, vios_ids=None):
|
||||
"""Gets the VIOS iSCSI initiators.
|
||||
|
||||
For the first time invocation of this method after process start up,
|
||||
it populates initiators data for VIOSes (if specified, otherwise it
|
||||
gets active VIOSes from the host) and stores in memory for futher
|
||||
lookup.
|
||||
|
||||
:param adapter: The pypowervm adapter
|
||||
:param vios_ids: List of VIOS ids to get the initiators. If not
|
||||
specified, a list of active VIOSes for the
|
||||
host is fetched (but only for the first time)
|
||||
through the pypowervm adapter.
|
||||
:return: A dict of the form
|
||||
{<vios_id>: <list of initiators>}
|
||||
"""
|
||||
|
||||
global _ISCSI_INITIATORS
|
||||
|
||||
def discover_initiator(vios_id):
|
||||
|
||||
# Get the VIOS id lock for initiator lookup
|
||||
@lockutils.synchronized('inititator-lookup-' + vios_id)
|
||||
def _discover_initiator():
|
||||
if (vios_id in _ISCSI_INITIATORS and
|
||||
_ISCSI_INITIATORS[vios_id]):
|
||||
return
|
||||
else:
|
||||
try:
|
||||
initiator = hdisk.discover_iscsi_initiator(
|
||||
adapter, vios_id)
|
||||
_ISCSI_INITIATORS[vios_id] = initiator
|
||||
except pvm_exc.ISCSIDiscoveryFailed as e:
|
||||
# TODO(chhagarw): handle differently based on
|
||||
# error codes
|
||||
LOG.error(e)
|
||||
|
||||
_discover_initiator()
|
||||
|
||||
if vios_ids is None and not _ISCSI_INITIATORS:
|
||||
vios_ids = pvm_partition.get_active_vioses(adapter)
|
||||
|
||||
for vios_id in vios_ids or []:
|
||||
discover_initiator(vios_id)
|
||||
|
||||
LOG.debug("iSCSI initiator info: %s" % _ISCSI_INITIATORS)
|
||||
return _ISCSI_INITIATORS
|
||||
|
||||
|
||||
class IscsiVolumeAdapter(volume.VscsiVolumeAdapter,
|
||||
|
|
Loading…
Reference in New Issue