Merge "NetApp fix for default host type in eseries" into stable/juno

This commit is contained in:
Jenkins 2014-10-28 22:13:56 +00:00 committed by Gerrit Code Review
commit 3e6c4e6126
5 changed files with 124 additions and 14 deletions

View File

@ -216,8 +216,8 @@ class FakeEseriesServerHandler(object):
"index" : 5 "index" : 5
}, { }, {
"id" : "6", "id" : "6",
"code" : "LNX", "code" : "LnxALUA",
"name" : "Linux", "name" : "LnxALUA",
"index" : 6 "index" : 6
}]""" }]"""
elif re.match("^/storage-systems/[0-9a-zA-Z]+/snapshot-groups$", path): elif re.match("^/storage-systems/[0-9a-zA-Z]+/snapshot-groups$", path):
@ -878,3 +878,59 @@ class NetAppEseriesIscsiDriverTestCase(test.TestCase):
self.assertRaises(exception.NetAppDriverException, self.assertRaises(exception.NetAppDriverException,
self.driver._get_iscsi_portal_for_vol, self.driver._get_iscsi_portal_for_vol,
vol_nomatch, portals, False) vol_nomatch, portals, False)
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

@ -217,6 +217,12 @@ class RestClient(WebserviceClient):
port = {'type': port_type, 'port': port_id, 'label': port_label} port = {'type': port_type, 'port': port_id, 'label': port_label}
return self.create_host(label, host_type, [port], group_id) 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): def list_host_types(self):
"""Lists host types in storage system.""" """Lists host types in storage system."""
path = "/storage-systems/{system-id}/host-types" path = "/storage-systems/{system-id}/host-types"

View File

@ -58,6 +58,26 @@ class Driver(driver.ISCSIDriver):
'netapp_storage_pools'] 'netapp_storage_pools']
SLEEP_SECS = 5 SLEEP_SECS = 5
MAX_LUNS_PER_HOST = 255 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): def __init__(self, *args, **kwargs):
super(Driver, self).__init__(*args, **kwargs) super(Driver, self).__init__(*args, **kwargs)
@ -91,6 +111,12 @@ class Driver(driver.ISCSIDriver):
raise exception.InvalidInput(reason=msg) raise exception.InvalidInput(reason=msg)
def check_for_setup_error(self): 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._check_storage_system()
self._populate_system_objects() self._populate_system_objects()
@ -579,7 +605,7 @@ class Driver(driver.ISCSIDriver):
@cinder_utils.synchronized('map_es_volume') @cinder_utils.synchronized('map_es_volume')
def _map_volume_to_host(self, vol, initiator): def _map_volume_to_host(self, vol, initiator):
"""Maps the e-series volume to host with 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)
vol_maps = self._get_host_mapping_for_vol_frm_array(vol) vol_maps = self._get_host_mapping_for_vol_frm_array(vol)
for vol_map in vol_maps: for vol_map in vol_maps:
if vol_map.get('mapRef') == host['hostRef']: if vol_map.get('mapRef') == host['hostRef']:
@ -592,30 +618,40 @@ class Driver(driver.ISCSIDriver):
return self._client.create_volume_mapping(vol['volumeRef'], return self._client.create_volume_mapping(vol['volumeRef'],
host['hostRef'], lun) 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.""" """Fetch or create a host by given port."""
try: 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: except exception.NotFound as e:
LOG.warn(_("Message - %s."), e.msg) LOG.warn(_("Message - %s."), e.msg)
return self._create_host(port_id, host_type) 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.""" """Gets or creates a host with given port id."""
hosts = self._client.list_hosts() hosts = self._client.list_hosts()
ht_def = self._get_host_type_definition(host_type)
for host in hosts: for host in hosts:
if (host.get('hostTypeIndex') == ht_def.get('index') if host.get('hostSidePorts'):
and host.get('hostSidePorts')):
ports = host.get('hostSidePorts') ports = host.get('hostSidePorts')
for port in ports: for port in ports:
if (port.get('type') == 'iscsi' if (port.get('type') == 'iscsi'
and port.get('address') == port_id): and port.get('address') == port_id):
return host return host
msg = _("Host with port %(port)s and type %(type)s not found.") msg = _("Host with port %(port)s not found.")
raise exception.NotFound(msg % {'port': port_id, 'type': host_type}) 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.""" """Creates host on system with given initiator as port_id."""
LOG.info(_("Creating host with port %s."), port_id) LOG.info(_("Creating host with port %s."), port_id)
label = utils.convert_uuid_to_es_fmt(uuid.uuid4()) label = utils.convert_uuid_to_es_fmt(uuid.uuid4())
@ -624,7 +660,7 @@ class Driver(driver.ISCSIDriver):
return self._client.create_host_with_port(label, host_type, return self._client.create_host_with_port(label, host_type,
port_id, port_label) 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.""" """Gets supported host type if available on storage system."""
host_types = self._client.list_host_types() host_types = self._client.list_host_types()
for ht in host_types: for ht in host_types:

View File

@ -161,7 +161,13 @@ netapp_eseries_opts = [
'specified storage pools. Only dynamic disk pools are ' 'specified storage pools. Only dynamic disk pools are '
'currently supported. Specify the value of this option to' 'currently supported. Specify the value of this option to'
' be a comma separated list of disk pool names to be used' ' 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 = [ netapp_nfs_extra_opts = [
cfg.StrOpt('netapp_copyoffload_tool_path', cfg.StrOpt('netapp_copyoffload_tool_path',
default=None, default=None,

View File

@ -1641,6 +1641,12 @@
# provisioning. (string value) # provisioning. (string value)
#netapp_storage_pools=<None> #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 # If the percentage of available space for an NFS share has
# dropped below the value specified by this option, the NFS # dropped below the value specified by this option, the NFS
# image cache will be cleaned. (integer value) # image cache will be cleaned. (integer value)