NetApp fix for default host type in eseries

This fixes the issue where the default host type
provided in mapping should be high performing LnxALUA
type for eseries. It also makes it configurable in case
users want to configure a different host type.

Closes-Bug: #1365884

Change-Id: I30992ca69c25c3c02334470aae90c32731a5f3f4
(cherry picked from commit a120ede9ae)
This commit is contained in:
Navneet Singh 2014-05-23 10:27:33 +05:30 committed by Tom Barron
parent 390259bb40
commit 71b53158d2
5 changed files with 124 additions and 14 deletions

View File

@ -184,8 +184,8 @@ class FakeEseriesServerHandler(object):
"index" : 5
}, {
"id" : "6",
"code" : "LNX",
"name" : "Linux",
"code" : "LnxALUA",
"name" : "LnxALUA",
"index" : 6
}]"""
elif re.match("^/storage-systems/[0-9a-zA-Z]+/snapshot-groups$", path):
@ -698,3 +698,59 @@ class NetAppEseriesIscsiDriverTestCase(test.TestCase):
self.volume_clone_large, self.snapshot)
self.driver.delete_snapshot(self.snapshot)
self.driver.delete_volume(self.volume)
def test_get_host_right_type(self):
self.driver._get_host_with_port = mock.Mock(
return_value={'hostTypeIndex': 2, 'name': 'test'})
self.driver._get_host_type_definition = mock.Mock(
return_value={'index': 2, 'name': 'LnxALUA'})
host = self.driver._get_or_create_host('port', 'LinuxALUA')
self.assertEqual(host, {'hostTypeIndex': 2, 'name': 'test'})
self.driver._get_host_with_port.assert_called_once_with('port')
self.driver._get_host_type_definition.assert_called_once_with(
'LinuxALUA')
def test_get_host_update_type(self):
self.driver._get_host_with_port = mock.Mock(
return_value={'hostTypeIndex': 2, 'hostRef': 'test'})
self.driver._get_host_type_definition = mock.Mock(
return_value={'index': 3, 'name': 'LnxALUA'})
self.driver._client.update_host_type = mock.Mock(
return_value={'hostTypeIndex': 3, 'hostRef': 'test'})
host = self.driver._get_or_create_host('port', 'LinuxALUA')
self.assertEqual(host, {'hostTypeIndex': 3, 'hostRef': 'test'})
self.driver._get_host_with_port.assert_called_once_with('port')
self.driver._get_host_type_definition.assert_called_once_with(
'LinuxALUA')
self.assertEqual(self.driver._client.update_host_type.call_count, 1)
def test_get_host_update_type_failed(self):
self.driver._get_host_with_port = mock.Mock(
return_value={'hostTypeIndex': 2, 'hostRef': 'test',
'label': 'test'})
self.driver._get_host_type_definition = mock.Mock(
return_value={'index': 3, 'name': 'LnxALUA'})
self.driver._client.update_host_type = mock.Mock(
side_effect=exception.NetAppDriverException)
host = self.driver._get_or_create_host('port', 'LinuxALUA')
self.assertEqual(host, {'hostTypeIndex': 2, 'hostRef': 'test',
'label': 'test'})
self.driver._get_host_with_port.assert_called_once_with('port')
self.driver._get_host_type_definition.assert_called_once_with(
'LinuxALUA')
self.assertEqual(self.driver._client.update_host_type.call_count, 1)
def test_get_host_not_found(self):
self.driver._get_host_with_port = mock.Mock(
side_effect=exception.NotFound)
self.driver._create_host = mock.Mock()
self.driver._get_or_create_host('port', 'LnxALUA')
self.driver._get_host_with_port.assert_called_once_with('port')
self.driver._create_host.assert_called_once_with('port', 'LnxALUA')
def test_setup_error_unsupported_host_type(self):
configuration = self._set_config(create_configuration())
configuration.netapp_eseries_host_type = 'garbage'
driver = common.NetAppDriver(configuration=configuration)
self.assertRaises(exception.NetAppDriverException,
driver.check_for_setup_error)

View File

@ -216,6 +216,12 @@ class RestClient(WebserviceClient):
port = {'type': port_type, 'port': port_id, 'label': port_label}
return self.create_host(label, host_type, [port], group_id)
def update_host_type(self, host_ref, host_type):
"""Updates host type for a given host."""
path = "/storage-systems/{system-id}/hosts/{object-id}"
data = {'hostType': host_type}
return self._invoke('POST', path, data, **{'object-id': host_ref})
def list_host_types(self):
"""Lists host types in storage system."""
path = "/storage-systems/{system-id}/host-types"

View File

@ -54,6 +54,26 @@ class Driver(driver.ISCSIDriver):
'netapp_storage_pools']
SLEEP_SECS = 5
MAX_LUNS_PER_HOST = 255
HOST_TYPES = {'aix': 'AIX MPIO',
'avt': 'AVT_4M',
'factoryDefault': 'FactoryDefault',
'hpux': 'HP-UX TPGS',
'linux_atto': 'LnxTPGSALUA',
'linux_dm_mp': 'LnxALUA',
'linux_mpp_rdac': 'Linux',
'linux_pathmanager': 'LnxTPGSALUA_PM',
'macos': 'MacTPGSALUA',
'ontap': 'ONTAP',
'svc': 'SVC',
'solaris_v11': 'SolTPGSALUA',
'solaris_v10': 'Solaris',
'vmware': 'VmwTPGSALUA',
'windows':
'Windows 2000/Server 2003/Server 2008 Non-Clustered',
'windows_atto': 'WinTPGSALUA',
'windows_clustered':
'Windows 2000/Server 2003/Server 2008 Clustered'
}
def __init__(self, *args, **kwargs):
super(Driver, self).__init__(*args, **kwargs)
@ -87,6 +107,12 @@ class Driver(driver.ISCSIDriver):
raise exception.InvalidInput(reason=msg)
def check_for_setup_error(self):
self.host_type =\
self.HOST_TYPES.get(self.configuration.netapp_eseries_host_type,
None)
if not self.host_type:
raise exception.NetAppDriverException(
_('Configured host type is not supported.'))
self._check_storage_system()
self._populate_system_objects()
@ -514,35 +540,45 @@ class Driver(driver.ISCSIDriver):
def _map_volume_to_host(self, vol, initiator):
"""Maps the e-series volume to host with initiator."""
host = self._get_or_create_host(initiator)
host = self._get_or_create_host(initiator, self.host_type)
lun = self._get_free_lun(host)
return self._client.create_volume_mapping(vol['volumeRef'],
host['hostRef'], lun)
def _get_or_create_host(self, port_id, host_type='linux'):
def _get_or_create_host(self, port_id, host_type):
"""Fetch or create a host by given port."""
try:
return self._get_host_with_port(port_id, host_type)
host = self._get_host_with_port(port_id)
ht_def = self._get_host_type_definition(host_type)
if host.get('hostTypeIndex') == ht_def.get('index'):
return host
else:
try:
return self._client.update_host_type(
host['hostRef'], ht_def)
except exception.NetAppDriverException as e:
msg = _("Unable to update host type for host with"
" label %(l)s. %(e)s")
LOG.warn(msg % {'l': host['label'], 'e': e.msg})
return host
except exception.NotFound as e:
LOG.warn(_("Message - %s."), e.msg)
return self._create_host(port_id, host_type)
def _get_host_with_port(self, port_id, host_type='linux'):
def _get_host_with_port(self, port_id):
"""Gets or creates a host with given port id."""
hosts = self._client.list_hosts()
ht_def = self._get_host_type_definition(host_type)
for host in hosts:
if (host.get('hostTypeIndex') == ht_def.get('index')
and host.get('hostSidePorts')):
if host.get('hostSidePorts'):
ports = host.get('hostSidePorts')
for port in ports:
if (port.get('type') == 'iscsi'
and port.get('address') == port_id):
return host
msg = _("Host with port %(port)s and type %(type)s not found.")
raise exception.NotFound(msg % {'port': port_id, 'type': host_type})
msg = _("Host with port %(port)s not found.")
raise exception.NotFound(msg % {'port': port_id})
def _create_host(self, port_id, host_type='linux'):
def _create_host(self, port_id, host_type):
"""Creates host on system with given initiator as port_id."""
LOG.info(_("Creating host with port %s."), port_id)
label = utils.convert_uuid_to_es_fmt(uuid.uuid4())
@ -551,7 +587,7 @@ class Driver(driver.ISCSIDriver):
return self._client.create_host_with_port(label, host_type,
port_id, port_label)
def _get_host_type_definition(self, host_type='linux'):
def _get_host_type_definition(self, host_type):
"""Gets supported host type if available on storage system."""
host_types = self._client.list_host_types()
for ht in host_types:

View File

@ -161,7 +161,13 @@ netapp_eseries_opts = [
'specified storage pools. Only dynamic disk pools are '
'currently supported. Specify the value of this option to'
' be a comma separated list of disk pool names to be used'
' for provisioning.')), ]
' for provisioning.')),
cfg.StrOpt('netapp_eseries_host_type',
default='linux_dm_mp',
help=('This option is used to define how the controllers in '
'the E-Series storage array will work with the '
'particular operating system on the hosts that are '
'connected to it.')), ]
netapp_nfs_extra_opts = [
cfg.StrOpt('netapp_copyoffload_tool_path',
default=None,

View File

@ -1328,6 +1328,12 @@
# provisioning. (string value)
#netapp_storage_pools=<None>
# This option is used to define how the controllers in the
# E-Series storage array will work with the particular
# operating system on the hosts that are connected to it.
# (string value)
#netapp_eseries_host_type=linux_dm_mp
# If the percentage of available space for an NFS share has
# dropped below the value specified by this option, the NFS
# image cache will be cleaned. (integer value)