Merge "Add multiattach in Nimble driver"
This commit is contained in:
commit
0ca496fc48
@ -17,12 +17,14 @@
|
||||
import sys
|
||||
from unittest import mock
|
||||
|
||||
from oslo_utils import uuidutils
|
||||
from six.moves import http_client
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.objects import volume as obj_volume
|
||||
from cinder.tests.unit import fake_constants as fake
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.tests.unit import test
|
||||
from cinder.volume.drivers import nimble
|
||||
from cinder.volume import volume_types
|
||||
@ -83,6 +85,9 @@ FAKE_CREATE_VOLUME_POSITIVE_RESPONSE_QOS = {
|
||||
'clone': False,
|
||||
'name': "testvolume-qos"}
|
||||
|
||||
FAKE_EXTRA_SPECS = {'multiattach': '<is> True',
|
||||
'nimble:iops-limit': '1024'}
|
||||
|
||||
FAKE_GET_VOL_INFO_RESPONSE = {'name': 'testvolume',
|
||||
'clone': False,
|
||||
'target_name': 'iqn.test',
|
||||
@ -99,6 +104,13 @@ FAKE_GET_VOL_INFO_ONLINE = {'name': 'testvolume',
|
||||
'online': True,
|
||||
'agent_type': 'none'}
|
||||
|
||||
FAKE_GET_VOL_INFO_RETYPE = {'name': 'testvolume',
|
||||
'size': 2048,
|
||||
'online': True,
|
||||
'agent_type': 'none',
|
||||
'pool_id': 'none',
|
||||
'pool_name': 'none'}
|
||||
|
||||
FAKE_GET_VOL_INFO_BACKUP_RESPONSE = {'name': 'testvolume',
|
||||
'clone': True,
|
||||
'target_name': 'iqn.test',
|
||||
@ -250,6 +262,26 @@ class NimbleDriverBaseTestCase(test.TestCase):
|
||||
return inner_client_mock
|
||||
return client_mock_wrapper
|
||||
|
||||
@staticmethod
|
||||
def client_mock_decorator_nimble_api(username, password, ip, verify):
|
||||
def client_mock_wrapper(func):
|
||||
def inner_client_mock(
|
||||
self, mock_client_class, mock_urllib2, *args, **kwargs):
|
||||
self.mock_client_class = mock_client_class
|
||||
self.mock_client_service = mock.MagicMock(name='Client')
|
||||
self.mock_client_class.return_value = (
|
||||
self.mock_client_service)
|
||||
self.driver = nimble.NimbleRestAPIExecutor(
|
||||
username=username, password=password, ip=ip, verify=verify)
|
||||
mock_login_response = mock_urllib2.post.return_value
|
||||
mock_login_response = mock.MagicMock()
|
||||
mock_login_response.status_code.return_value = http_client.OK
|
||||
mock_login_response.json.return_value = (
|
||||
FAKE_LOGIN_POST_RESPONSE)
|
||||
func(self, *args, **kwargs)
|
||||
return inner_client_mock
|
||||
return client_mock_wrapper
|
||||
|
||||
|
||||
class NimbleDriverLoginTestCase(NimbleDriverBaseTestCase):
|
||||
|
||||
@ -371,7 +403,7 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
|
||||
mock.Mock(type_id=FAKE_TYPE_ID, return_value={
|
||||
'nimble:perfpol-name': 'default',
|
||||
'nimble:encryption': 'yes',
|
||||
'nimble:multi-initiator': 'false'}))
|
||||
'multiattach': 'false'}))
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||
def test_create_volume_encryption_positive(self):
|
||||
@ -412,7 +444,7 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
|
||||
mock.Mock(type_id=FAKE_TYPE_ID, return_value={
|
||||
'nimble:perfpol-name': 'VMware ESX',
|
||||
'nimble:encryption': 'no',
|
||||
'nimble:multi-initiator': 'false'}))
|
||||
'multiattach': 'false'}))
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||
def test_create_volume_perfpolicy_positive(self):
|
||||
@ -452,7 +484,7 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
|
||||
mock.Mock(type_id=FAKE_TYPE_ID, return_value={
|
||||
'nimble:perfpol-name': 'default',
|
||||
'nimble:encryption': 'no',
|
||||
'nimble:multi-initiator': 'true'}))
|
||||
'multiattach': 'true'}))
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||
def test_create_volume_multi_initiator_positive(self):
|
||||
@ -573,7 +605,7 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
|
||||
mock.Mock(type_id=FAKE_TYPE_ID, return_value={
|
||||
'nimble:perfpol-name': 'default',
|
||||
'nimble:encryption': 'no',
|
||||
'nimble:multi-initiator': 'true'}))
|
||||
'multiattach': 'false'}))
|
||||
def test_create_volume_negative(self):
|
||||
self.mock_client_service.get_vol_info.side_effect = (
|
||||
FAKE_CREATE_VOLUME_NEGATIVE_RESPONSE)
|
||||
@ -761,7 +793,7 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
|
||||
return_value={
|
||||
'nimble:perfpol-name': 'default',
|
||||
'nimble:encryption': 'yes',
|
||||
'nimble:multi-initiator': 'false',
|
||||
'multiattach': False,
|
||||
'nimble:iops-limit': '1024'}))
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*', False))
|
||||
@ -979,7 +1011,7 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
|
||||
'extra_specs':
|
||||
{'nimble:perfpol-name': 'default',
|
||||
'nimble:encryption': 'yes',
|
||||
'nimble:multi-initiator': 'false',
|
||||
'multiattach': False,
|
||||
'nimble:iops-limit': '1024'}}))
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||
@ -994,6 +1026,27 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
|
||||
self.assertTrue(retype)
|
||||
self.assertIsNone(update)
|
||||
|
||||
@mock.patch(NIMBLE_URLLIB2)
|
||||
@mock.patch(NIMBLE_ISCSI_DRIVER)
|
||||
@mock.patch.object(nimble.NimbleRestAPIExecutor, 'login')
|
||||
@mock.patch.object(nimble.NimbleRestAPIExecutor,
|
||||
'get_performance_policy_id')
|
||||
@mock.patch.object(nimble.NimbleRestAPIExecutor, 'get_pool_info')
|
||||
@mock.patch.object(nimble.NimbleRestAPIExecutor, 'get_folder_id')
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator_nimble_api(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'False')
|
||||
def test_nimble_extraspecs_retype(self, mock_folder,
|
||||
mock_pool, mock_perf_id,
|
||||
mock_login):
|
||||
mock_folder.return_value = None
|
||||
mock_pool.return_value = None
|
||||
mock_perf_id.return_value = None
|
||||
mock_login.return_value = None
|
||||
data = self.driver.get_valid_nimble_extraspecs(
|
||||
FAKE_EXTRA_SPECS,
|
||||
FAKE_GET_VOL_INFO_RETYPE)
|
||||
self.assertTrue(data['multi_initiator'])
|
||||
|
||||
@mock.patch(NIMBLE_URLLIB2)
|
||||
@mock.patch(NIMBLE_CLIENT)
|
||||
@mock.patch.object(obj_volume.VolumeList, 'get_all_by_host',
|
||||
@ -1011,7 +1064,8 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
|
||||
'total_capacity_gb': 7466.30419921875,
|
||||
'free_capacity_gb': 7463.567649364471,
|
||||
'reserved_percentage': 0,
|
||||
'QoS_support': False}]}
|
||||
'QoS_support': False,
|
||||
'multiattach': True}]}
|
||||
self.assertEqual(
|
||||
expected_res,
|
||||
self.driver.get_volume_stats(refresh=True))
|
||||
@ -1095,7 +1149,7 @@ class NimbleDriverSnapshotTestCase(NimbleDriverBaseTestCase):
|
||||
mock.Mock(type_id=FAKE_TYPE_ID, return_value={
|
||||
'nimble:perfpol-name': 'default',
|
||||
'nimble:encryption': 'yes',
|
||||
'nimble:multi-initiator': 'false'}))
|
||||
'multiattach': False}))
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||
def test_create_volume_from_snapshot(self):
|
||||
@ -1361,10 +1415,15 @@ class NimbleDriverConnectionTestCase(NimbleDriverBaseTestCase):
|
||||
def test_terminate_connection_positive(self):
|
||||
self.mock_client_service.get_initiator_grp_list.return_value = (
|
||||
FAKE_IGROUP_LIST_RESPONSE)
|
||||
ctx = context.get_admin_context()
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
ctx, name='test-volume',
|
||||
host='fakehost@nimble#Openstack',
|
||||
provider_location='12 13',
|
||||
id=12, multiattach=False)
|
||||
|
||||
self.driver.terminate_connection(
|
||||
{'name': 'test-volume',
|
||||
'provider_location': '12 13',
|
||||
'id': 12},
|
||||
volume,
|
||||
{'initiator': 'test-initiator1'})
|
||||
expected_calls = [mock.call._get_igroupname_for_initiator(
|
||||
'test-initiator1'),
|
||||
@ -1406,10 +1465,15 @@ class NimbleDriverConnectionTestCase(NimbleDriverBaseTestCase):
|
||||
mock_wwpns.return_value = ["1111111111111101"]
|
||||
self.mock_client_service.get_initiator_grp_list.return_value = (
|
||||
FAKE_IGROUP_LIST_RESPONSE_FC)
|
||||
ctx = context.get_admin_context()
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
ctx, name='test-volume',
|
||||
host='fakehost@nimble#Openstack',
|
||||
provider_location='12 13',
|
||||
id=14, multiattach=False)
|
||||
|
||||
self.driver.terminate_connection(
|
||||
{'name': 'test-volume',
|
||||
'provider_location': 'array1',
|
||||
'id': 12},
|
||||
volume,
|
||||
{'initiator': 'test-initiator1',
|
||||
'wwpns': ['1000000000000000']})
|
||||
expected_calls = [
|
||||
@ -1430,9 +1494,159 @@ class NimbleDriverConnectionTestCase(NimbleDriverBaseTestCase):
|
||||
def test_terminate_connection_negative(self):
|
||||
self.mock_client_service.get_initiator_grp_list.return_value = (
|
||||
FAKE_IGROUP_LIST_RESPONSE)
|
||||
ctx = context.get_admin_context()
|
||||
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
ctx, name='test-volume',
|
||||
host='fakehost@nimble#Openstack',
|
||||
provider_location='12 13',
|
||||
id=12, multiattach=False)
|
||||
|
||||
self.assertRaises(
|
||||
exception.VolumeDriverException,
|
||||
self.driver.terminate_connection,
|
||||
{'name': 'test-volume',
|
||||
'provider_location': '12 13', 'id': 12},
|
||||
volume,
|
||||
{'initiator': 'test-initiator3'})
|
||||
|
||||
@mock.patch(NIMBLE_URLLIB2)
|
||||
@mock.patch(NIMBLE_CLIENT)
|
||||
@mock.patch.object(obj_volume.VolumeList, 'get_all_by_host',
|
||||
mock.Mock(return_value=[]))
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator_fc(create_configuration(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||
@mock.patch(NIMBLE_FC_DRIVER + ".get_wwpns_from_array")
|
||||
def test_terminate_connection_negative_fc(self, mock_wwpns):
|
||||
mock_wwpns.return_value = ["1111111111111101"]
|
||||
self.mock_client_service.get_initiator_grp_list.return_value = (
|
||||
FAKE_IGROUP_LIST_RESPONSE_FC)
|
||||
ctx = context.get_admin_context()
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
ctx, name='test-volume',
|
||||
host='fakehost@nimble#Openstack',
|
||||
provider_location='12 13',
|
||||
id=12, multiattach=False)
|
||||
self.assertRaises(
|
||||
exception.VolumeDriverException,
|
||||
self.driver.terminate_connection,
|
||||
volume,
|
||||
{'initiator': 'test-initiator3',
|
||||
'wwpns': ['1000000000000010']})
|
||||
|
||||
@mock.patch(NIMBLE_URLLIB2)
|
||||
@mock.patch(NIMBLE_CLIENT)
|
||||
@mock.patch.object(obj_volume.VolumeList, 'get_all_by_host',
|
||||
mock.Mock(return_value=[]))
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||
def test_terminate_connection_multiattach(self):
|
||||
self.mock_client_service.get_initiator_grp_list.return_value = (
|
||||
FAKE_IGROUP_LIST_RESPONSE)
|
||||
ctx = context.get_admin_context()
|
||||
|
||||
att_1 = fake_volume.volume_attachment_ovo(
|
||||
ctx, id=uuidutils.generate_uuid())
|
||||
att_2 = fake_volume.volume_attachment_ovo(
|
||||
ctx, id=uuidutils.generate_uuid())
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
ctx, name='test-volume',
|
||||
host='fakehost@nimble#Openstack',
|
||||
provider_location='12 13',
|
||||
id=12, multiattach=True)
|
||||
volume.volume_attachment.objects = [att_1, att_2]
|
||||
self.driver.terminate_connection(
|
||||
volume,
|
||||
{'initiator': 'test-initiator1'})
|
||||
self.mock_client_service.remove_acl.assert_not_called()
|
||||
|
||||
@mock.patch(NIMBLE_URLLIB2)
|
||||
@mock.patch(NIMBLE_CLIENT)
|
||||
@mock.patch.object(obj_volume.VolumeList, 'get_all_by_host',
|
||||
mock.Mock(return_value=[]))
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||
def test_terminate_connection_multiattach_complete(self):
|
||||
self.mock_client_service.get_initiator_grp_list.return_value = (
|
||||
FAKE_IGROUP_LIST_RESPONSE)
|
||||
ctx = context.get_admin_context()
|
||||
|
||||
att_1 = fake_volume.volume_attachment_ovo(
|
||||
ctx, id=uuidutils.generate_uuid())
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
ctx, name='test-volume',
|
||||
host='fakehost@nimble#Openstack',
|
||||
provider_location='12 13',
|
||||
id=12, multiattach=True)
|
||||
volume.volume_attachment.objects = [att_1]
|
||||
self.driver.terminate_connection(
|
||||
volume,
|
||||
{'initiator': 'test-initiator1'})
|
||||
expected_calls = [mock.call._get_igroupname_for_initiator(
|
||||
'test-initiator1'),
|
||||
mock.call.remove_acl({'name': 'test-volume'},
|
||||
'test-igrp1')]
|
||||
self.mock_client_service.assert_has_calls(
|
||||
self.mock_client_service.method_calls,
|
||||
expected_calls)
|
||||
|
||||
@mock.patch(NIMBLE_URLLIB2)
|
||||
@mock.patch(NIMBLE_CLIENT)
|
||||
@mock.patch.object(obj_volume.VolumeList, 'get_all_by_host',
|
||||
mock.Mock(return_value=[]))
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator_fc(create_configuration(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||
@mock.patch(NIMBLE_FC_DRIVER + ".get_wwpns_from_array")
|
||||
def test_terminate_connection_multiattach_fc(self, mock_wwpns):
|
||||
mock_wwpns.return_value = ["1111111111111101"]
|
||||
self.mock_client_service.get_initiator_grp_list.return_value = (
|
||||
FAKE_IGROUP_LIST_RESPONSE_FC)
|
||||
ctx = context.get_admin_context()
|
||||
|
||||
att_1 = fake_volume.volume_attachment_ovo(
|
||||
ctx, id=uuidutils.generate_uuid())
|
||||
att_2 = fake_volume.volume_attachment_ovo(
|
||||
ctx, id=uuidutils.generate_uuid())
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
ctx, name='test-volume',
|
||||
host='fakehost@nimble#Openstack',
|
||||
provider_location='12 13',
|
||||
id=12, multiattach=True)
|
||||
volume.volume_attachment.objects = [att_1, att_2]
|
||||
self.driver.terminate_connection(
|
||||
volume,
|
||||
{'initiator': 'test-initiator1',
|
||||
'wwpns': ['1000000000000000']})
|
||||
self.mock_client_service.remove_acl.assert_not_called()
|
||||
|
||||
@mock.patch(NIMBLE_URLLIB2)
|
||||
@mock.patch(NIMBLE_CLIENT)
|
||||
@mock.patch.object(obj_volume.VolumeList, 'get_all_by_host',
|
||||
mock.Mock(return_value=[]))
|
||||
@NimbleDriverBaseTestCase.client_mock_decorator_fc(create_configuration(
|
||||
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||
@mock.patch(NIMBLE_FC_DRIVER + ".get_wwpns_from_array")
|
||||
def test_terminate_connection_multiattach_complete_fc(self, mock_wwpns):
|
||||
mock_wwpns.return_value = ["1111111111111101"]
|
||||
self.mock_client_service.get_initiator_grp_list.return_value = (
|
||||
FAKE_IGROUP_LIST_RESPONSE_FC)
|
||||
ctx = context.get_admin_context()
|
||||
|
||||
att_1 = fake_volume.volume_attachment_ovo(
|
||||
ctx, id=uuidutils.generate_uuid())
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
ctx, name='test-volume',
|
||||
host='fakehost@nimble#Openstack',
|
||||
provider_location='12 13',
|
||||
id=12, multiattach=True)
|
||||
volume.volume_attachment.objects = [att_1]
|
||||
self.driver.terminate_connection(
|
||||
volume,
|
||||
{'initiator': 'test-initiator1',
|
||||
'wwpns': ['1000000000000000']})
|
||||
expected_calls = [
|
||||
mock.call.get_igroupname_for_initiator_fc(
|
||||
"10:00:00:00:00:00:00:00"),
|
||||
mock.call.remove_acl({'name': 'test-volume'},
|
||||
'test-igrp1')]
|
||||
self.mock_client_service.assert_has_calls(
|
||||
self.mock_client_service.method_calls,
|
||||
expected_calls)
|
||||
|
@ -50,7 +50,6 @@ AES_256_XTS_CIPHER = 'aes_256_xts'
|
||||
DEFAULT_CIPHER = 'none'
|
||||
EXTRA_SPEC_ENCRYPTION = 'nimble:encryption'
|
||||
EXTRA_SPEC_PERF_POLICY = 'nimble:perfpol-name'
|
||||
EXTRA_SPEC_MULTI_INITIATOR = 'nimble:multi-initiator'
|
||||
EXTRA_SPEC_DEDUPE = 'nimble:dedupe'
|
||||
EXTRA_SPEC_IOPS_LIMIT = 'nimble:iops-limit'
|
||||
EXTRA_SPEC_FOLDER = 'nimble:folder'
|
||||
@ -58,7 +57,6 @@ DEFAULT_PERF_POLICY_SETTING = 'default'
|
||||
DEFAULT_ENCRYPTION_SETTING = 'no'
|
||||
DEFAULT_DEDUPE_SETTING = 'false'
|
||||
DEFAULT_IOPS_LIMIT_SETTING = None
|
||||
DEFAULT_MULTI_INITIATOR_SETTING = 'false'
|
||||
DEFAULT_FOLDER_SETTING = None
|
||||
DEFAULT_SNAP_QUOTA = sys.maxsize
|
||||
BACKUP_VOL_PREFIX = 'backup-vol-'
|
||||
@ -393,7 +391,8 @@ class NimbleBaseVolumeDriver(san.SanDriver):
|
||||
total_capacity_gb=total_capacity,
|
||||
free_capacity_gb=free_space,
|
||||
reserved_percentage=0,
|
||||
QoS_support=False)
|
||||
QoS_support=False,
|
||||
multiattach=True)
|
||||
self.group_stats['pools'] = [single_pool]
|
||||
return self.group_stats
|
||||
|
||||
@ -721,6 +720,24 @@ class NimbleBaseVolumeDriver(san.SanDriver):
|
||||
{'vol': volume['name'],
|
||||
'igroup': initiator_group_name})
|
||||
|
||||
def _is_multiattach(self, volume):
|
||||
if volume.multiattach:
|
||||
attachment_list = volume.volume_attachment
|
||||
try:
|
||||
attachment_list = attachment_list.objects
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if attachment_list is not None and len(attachment_list) > 1:
|
||||
LOG.info("Volume %(volume)s is attached to multiple "
|
||||
"instances on host %(host_name)s, "
|
||||
"skip terminate volume connection",
|
||||
{'volume': volume.name,
|
||||
'host_name': volume.host.split('@')[0]})
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
@interface.volumedriver
|
||||
class NimbleISCSIDriver(NimbleBaseVolumeDriver, san.SanISCSIDriver):
|
||||
@ -799,6 +816,8 @@ class NimbleISCSIDriver(NimbleBaseVolumeDriver, san.SanISCSIDriver):
|
||||
volume)
|
||||
self.APIExecutor.remove_all_acls(volume)
|
||||
return
|
||||
if self._is_multiattach(volume):
|
||||
return
|
||||
|
||||
initiator_name = connector['initiator']
|
||||
initiator_group_name = self._get_igroupname_for_initiator(
|
||||
@ -996,6 +1015,8 @@ class NimbleFCDriver(NimbleBaseVolumeDriver, driver.FibreChannelDriver):
|
||||
volume)
|
||||
self.APIExecutor.remove_all_acls(volume)
|
||||
return
|
||||
if self._is_multiattach(volume):
|
||||
return
|
||||
|
||||
initiator_name = connector['initiator']
|
||||
for wwpn in connector['wwpns']:
|
||||
@ -1161,8 +1182,6 @@ class NimbleRestAPIExecutor(object):
|
||||
DEFAULT_PERF_POLICY_SETTING)
|
||||
encryption = extra_specs.get(EXTRA_SPEC_ENCRYPTION,
|
||||
DEFAULT_ENCRYPTION_SETTING)
|
||||
multi_initiator = extra_specs.get(EXTRA_SPEC_MULTI_INITIATOR,
|
||||
DEFAULT_MULTI_INITIATOR_SETTING)
|
||||
iops_limit = extra_specs.get(EXTRA_SPEC_IOPS_LIMIT,
|
||||
DEFAULT_IOPS_LIMIT_SETTING)
|
||||
folder_name = extra_specs.get(EXTRA_SPEC_FOLDER,
|
||||
@ -1172,11 +1191,9 @@ class NimbleRestAPIExecutor(object):
|
||||
extra_specs_map = {}
|
||||
extra_specs_map[EXTRA_SPEC_PERF_POLICY] = perf_policy_name
|
||||
extra_specs_map[EXTRA_SPEC_ENCRYPTION] = encryption
|
||||
extra_specs_map[EXTRA_SPEC_MULTI_INITIATOR] = multi_initiator
|
||||
extra_specs_map[EXTRA_SPEC_IOPS_LIMIT] = iops_limit
|
||||
extra_specs_map[EXTRA_SPEC_DEDUPE] = dedupe
|
||||
extra_specs_map[EXTRA_SPEC_FOLDER] = folder_name
|
||||
|
||||
return extra_specs_map
|
||||
|
||||
def get_valid_nimble_extraspecs(self, extra_specs_map, vol_info):
|
||||
@ -1192,10 +1209,10 @@ class NimbleRestAPIExecutor(object):
|
||||
if encrypt.lower() == 'yes':
|
||||
cipher = AES_256_XTS_CIPHER
|
||||
data['cipher'] = cipher
|
||||
|
||||
multi_initiator = extra_specs_map_updated[EXTRA_SPEC_MULTI_INITIATOR]
|
||||
data['multi_initiator'] = multi_initiator
|
||||
|
||||
if extra_specs_map.get('multiattach') == "<is> True":
|
||||
data['multi_initiator'] = True
|
||||
else:
|
||||
data['multi_initiator'] = False
|
||||
folder_name = extra_specs_map_updated[EXTRA_SPEC_FOLDER]
|
||||
folder_id = None
|
||||
pool_id = vol_info['pool_id']
|
||||
@ -1290,7 +1307,7 @@ class NimbleRestAPIExecutor(object):
|
||||
perf_policy_name = extra_specs_map[EXTRA_SPEC_PERF_POLICY]
|
||||
perf_policy_id = self.get_performance_policy_id(perf_policy_name)
|
||||
encrypt = extra_specs_map[EXTRA_SPEC_ENCRYPTION]
|
||||
multi_initiator = extra_specs_map[EXTRA_SPEC_MULTI_INITIATOR]
|
||||
multi_initiator = volume.get('multiattach', False)
|
||||
folder_name = extra_specs_map[EXTRA_SPEC_FOLDER]
|
||||
iops_limit = extra_specs_map[EXTRA_SPEC_IOPS_LIMIT]
|
||||
dedupe = extra_specs_map[EXTRA_SPEC_DEDUPE]
|
||||
@ -1521,11 +1538,11 @@ class NimbleRestAPIExecutor(object):
|
||||
"initiator_group_id": initiator_group_id}
|
||||
api = "access_control_records"
|
||||
r = self.get_query(api, filter)
|
||||
LOG.info("ACL record is %result", {'result': r.json()})
|
||||
if not r.json()['data']:
|
||||
raise NimbleAPIException(_("Unable to retrieve ACL for volume: "
|
||||
"%(vol)s %(igroup)s ") %
|
||||
{'vol': volume_id,
|
||||
'igroup': initiator_group_id})
|
||||
LOG.warning('ACL is not available for this volume %vol_id', {
|
||||
'vol_id': volume_id})
|
||||
return
|
||||
return r.json()['data'][0]
|
||||
|
||||
def get_volume_acl_records(self, volume_id):
|
||||
@ -1560,9 +1577,10 @@ class NimbleRestAPIExecutor(object):
|
||||
try:
|
||||
acl_record = self.get_acl_record(volume_id, initiator_group_id)
|
||||
LOG.debug("ACL Record %(acl)s", {"acl": acl_record})
|
||||
acl_id = acl_record['id']
|
||||
api = 'access_control_records/' + six.text_type(acl_id)
|
||||
self.delete(api)
|
||||
if acl_record is not None:
|
||||
acl_id = acl_record['id']
|
||||
api = 'access_control_records/' + six.text_type(acl_id)
|
||||
self.delete(api)
|
||||
except NimbleAPIException as ex:
|
||||
LOG.debug("remove_acl_exception: %s", ex)
|
||||
if SM_OBJ_ENOENT_MSG in six.text_type(ex):
|
||||
@ -1700,7 +1718,7 @@ class NimbleRestAPIExecutor(object):
|
||||
perf_policy_name = extra_specs_map.get(EXTRA_SPEC_PERF_POLICY)
|
||||
perf_policy_id = self.get_performance_policy_id(perf_policy_name)
|
||||
encrypt = extra_specs_map.get(EXTRA_SPEC_ENCRYPTION)
|
||||
multi_initiator = extra_specs_map.get(EXTRA_SPEC_MULTI_INITIATOR)
|
||||
multi_initiator = volume.get('multiattach', False)
|
||||
iops_limit = extra_specs_map[EXTRA_SPEC_IOPS_LIMIT]
|
||||
folder_name = extra_specs_map[EXTRA_SPEC_FOLDER]
|
||||
pool_id = self.get_pool_id(pool_name)
|
||||
|
@ -37,6 +37,8 @@ Supported operations
|
||||
* Force backup of an in-use volume
|
||||
* Retype a volume
|
||||
* Create a Thinly Provisioned Volume
|
||||
* Attach a volume to multiple servers simultaneously (multiattach)
|
||||
|
||||
|
||||
Nimble Storage driver configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -126,9 +128,6 @@ The Nimble volume driver also supports the following extra spec options:
|
||||
PERF_POL_NAME is the name of a performance policy which exists on the
|
||||
Nimble array and should be enabled for every volume in a volume type.
|
||||
|
||||
'nimble:multi-initiator'='true'
|
||||
Used to enable multi-initiator access for a volume-type.
|
||||
|
||||
nimble:dedupe'='true'
|
||||
Used to enable dedupe support for a volume-type.
|
||||
|
||||
|
@ -768,7 +768,7 @@ driver.netapp_ontap=complete
|
||||
driver.netapp_solidfire=complete
|
||||
driver.nexenta=missing
|
||||
driver.nfs=missing
|
||||
driver.nimble=missing
|
||||
driver.nimble=complete
|
||||
driver.prophetstor=missing
|
||||
driver.pure=complete
|
||||
driver.qnap=missing
|
||||
|
8
releasenotes/notes/1885946-17bc5c3dc0535044.yaml
Normal file
8
releasenotes/notes/1885946-17bc5c3dc0535044.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add Multi-attach feature in Nimble driver.
|
||||
upgrade:
|
||||
- |
|
||||
Nimble specific extra-spec nimble:multi-initiator is removed.
|
||||
Common extra-spec multiattach is added.
|
Loading…
Reference in New Issue
Block a user