Merge "NetApp fix for default host type in eseries" into stable/juno
This commit is contained in:
commit
3e6c4e6126
@ -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)
|
||||||
|
@ -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"
|
||||||
|
@ -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:
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user