Browse Source

Merge "NetApp ONTAP: Fix extend volume for iSCSI/FCP" into stable/ussuri

changes/43/738543/1
Zuul 2 weeks ago
committed by Gerrit Code Review
parent
commit
7e175873be
12 changed files with 332 additions and 61 deletions
  1. +141
    -16
      cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_base.py
  2. +2
    -0
      cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py
  3. +17
    -0
      cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py
  4. +86
    -31
      cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py
  5. +3
    -1
      cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py
  6. +14
    -9
      cinder/volume/drivers/netapp/dataontap/block_base.py
  7. +1
    -1
      cinder/volume/drivers/netapp/dataontap/block_cmode.py
  8. +6
    -0
      cinder/volume/drivers/netapp/dataontap/client/api.py
  9. +53
    -2
      cinder/volume/drivers/netapp/dataontap/client/client_base.py
  10. +2
    -0
      cinder/volume/drivers/netapp/dataontap/client/client_cmode.py
  11. +1
    -1
      doc/source/reference/support-matrix.ini
  12. +6
    -0
      releasenotes/notes/bug-1874134-netapp-ONTAP-fix-max-resize-size-ad2d88da8721560e.yaml

+ 141
- 16
cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_base.py View File

@@ -18,6 +18,7 @@ import time
from unittest import mock
import uuid

import ddt
from lxml import etree
import six

@@ -38,6 +39,7 @@ CONNECTION_INFO = {'hostname': 'hostname',
'api_trace_pattern': 'fake_regex'}


@ddt.ddt
class NetAppBaseClientTestCase(test.TestCase):

def setUp(self):
@@ -87,8 +89,27 @@ class NetAppBaseClientTestCase(test.TestCase):
self.assertIsNone(self.client.check_is_naelement(element))
self.assertRaises(ValueError, self.client.check_is_naelement, None)

def test_create_lun(self):
@ddt.data({'ontap_version': '9.4', 'space_reservation': 'true'},
{'ontap_version': '9.4', 'space_reservation': 'false'},
{'ontap_version': '9.6', 'space_reservation': 'true'},
{'ontap_version': '9.6', 'space_reservation': 'false'})
@ddt.unpack
def test_create_lun(self, ontap_version, space_reservation):
expected_path = '/vol/%s/%s' % (self.fake_volume, self.fake_lun)
self.fake_metadata['SpaceReserved'] = space_reservation
expected_space_reservation = space_reservation
self.mock_object(self.client, 'get_ontap_version',
return_value=ontap_version)
mock_resize_lun = self.mock_object(
client_base.Client, 'do_direct_resize')
mock_set_space_reservation = self.mock_object(
client_base.Client, 'set_lun_space_reservation')
initial_size = self.fake_size

if ontap_version < '9.5':
initial_size = fake.MAX_SIZE_FOR_A_LUN
expected_space_reservation = 'false'

with mock.patch.object(netapp_api.NaElement,
'create_node_with_children',
) as mock_create_node:
@@ -97,19 +118,48 @@ class NetAppBaseClientTestCase(test.TestCase):
self.fake_size,
self.fake_metadata)

mock_create_node.assert_called_once_with(
mock_create_node.assert_called_with(
'lun-create-by-size',
**{'path': expected_path,
'size': self.fake_size,
'size': initial_size,
'ostype': self.fake_metadata['OsType'],
'space-reservation-enabled':
self.fake_metadata['SpaceReserved']})
self.connection.invoke_successfully.assert_called_once_with(
expected_space_reservation})
self.connection.invoke_successfully.assert_called_with(
mock.ANY, True)

def test_create_lun_exact_size(self):
if ontap_version < '9.5':
mock_resize_lun.assert_called_once_with(
expected_path, self.fake_size)

if ontap_version < '9.5' and space_reservation == 'true':
mock_set_space_reservation.assert_called_once_with(
expected_path, True)
else:
mock_set_space_reservation.assert_not_called()

@ddt.data({'ontap_version': '9.4', 'space_reservation': 'true'},
{'ontap_version': '9.4', 'space_reservation': 'false'},
{'ontap_version': '9.6', 'space_reservation': 'true'},
{'ontap_version': '9.6', 'space_reservation': 'false'})
@ddt.unpack
def test_create_lun_exact_size(self, ontap_version, space_reservation):
expected_path = '/vol/%s/%s' % (self.fake_volume, self.fake_lun)
self.connection.get_api_version.return_value = (1, 110)
self.fake_metadata['SpaceReserved'] = space_reservation
expected_space_reservation = self.fake_metadata['SpaceReserved']
self.mock_object(self.client, 'get_ontap_version',
return_value=ontap_version)
mock_resize_lun = self.mock_object(
client_base.Client, 'do_direct_resize')
mock_set_space_reservation = self.mock_object(
client_base.Client, 'set_lun_space_reservation')
initial_size = self.fake_size

if ontap_version < '9.5':
initial_size = fake.MAX_SIZE_FOR_A_LUN
expected_space_reservation = 'false'

with mock.patch.object(netapp_api.NaElement,
'create_node_with_children',
) as mock_create_node:
@@ -118,22 +168,52 @@ class NetAppBaseClientTestCase(test.TestCase):
self.fake_size,
self.fake_metadata)

mock_create_node.assert_called_once_with(
mock_create_node.assert_called_with(
'lun-create-by-size',
**{'path': expected_path,
'size': self.fake_size,
'size': initial_size,
'ostype': self.fake_metadata['OsType'],
'use-exact-size': 'true',
'space-reservation-enabled':
self.fake_metadata['SpaceReserved']})
self.connection.invoke_successfully.assert_called_once_with(
expected_space_reservation})
self.connection.invoke_successfully.assert_called_with(
mock.ANY, True)

def test_create_lun_with_qos_policy_group_name(self):
if ontap_version < '9.5':
mock_resize_lun.assert_called_once_with(
expected_path, self.fake_size)

if ontap_version < '9.5' and space_reservation == 'true':
mock_set_space_reservation.assert_called_once_with(
expected_path, True)
else:
mock_set_space_reservation.assert_not_called()

@ddt.data({'ontap_version': '9.4', 'space_reservation': 'true'},
{'ontap_version': '9.4', 'space_reservation': 'false'},
{'ontap_version': '9.6', 'space_reservation': 'true'},
{'ontap_version': '9.6', 'space_reservation': 'false'})
@ddt.unpack
def test_create_lun_with_qos_policy_group_name(
self, ontap_version, space_reservation):
expected_path = '/vol/%s/%s' % (self.fake_volume, self.fake_lun)
expected_qos_group_name = 'qos_1'
mock_request = mock.Mock()

self.fake_metadata['SpaceReserved'] = space_reservation
expected_space_reservation = self.fake_metadata['SpaceReserved']
self.mock_object(self.client, 'get_ontap_version',
return_value=ontap_version)
mock_resize_lun = self.mock_object(
client_base.Client, 'do_direct_resize')
mock_set_space_reservation = self.mock_object(
client_base.Client, 'set_lun_space_reservation')
initial_size = self.fake_size

if ontap_version < '9.5':
initial_size = fake.MAX_SIZE_FOR_A_LUN
expected_space_reservation = 'false'

with mock.patch.object(netapp_api.NaElement,
'create_node_with_children',
return_value=mock_request
@@ -145,20 +225,65 @@ class NetAppBaseClientTestCase(test.TestCase):
self.fake_metadata,
qos_policy_group_name=expected_qos_group_name)

mock_create_node.assert_called_once_with(
mock_create_node.assert_called_with(
'lun-create-by-size',
**{'path': expected_path, 'size': self.fake_size,
**{'path': expected_path, 'size': initial_size,
'ostype': self.fake_metadata['OsType'],
'space-reservation-enabled':
self.fake_metadata['SpaceReserved']})
mock_request.add_new_child.assert_called_once_with(
expected_space_reservation})
mock_request.add_new_child.assert_called_with(
'qos-policy-group', expected_qos_group_name)
self.connection.invoke_successfully.assert_called_with(
mock.ANY, True)

if ontap_version < '9.5':
mock_resize_lun.assert_called_once_with(
expected_path, self.fake_size)

if ontap_version < '9.5' and space_reservation == 'true':
mock_set_space_reservation.assert_called_once_with(
expected_path, True)
else:
mock_set_space_reservation.assert_not_called()

def test_get_ontap_version(self):
version_response = netapp_api.NaElement(
fake.SYSTEM_GET_VERSION_RESPONSE)
self.connection.invoke_successfully.return_value = version_response

result = self.client.get_ontap_version(cached=False)

self.assertEqual(('9.6'), result)

def test_get_ontap_version_cached(self):
self.connection.get_ontap_version.return_value = '9.6'

result = self.client.get_ontap_version()

self.connection.get_ontap_version.assert_called_once_with()
self.assertEqual(('9.6'), result)

def test_set_lun_space_reservation(self):
path = '/vol/%s/%s' % (self.fake_volume, self.fake_lun)

with mock.patch.object(netapp_api.NaElement,
'create_node_with_children',
) as mock_set_space_reservation:
self.client.set_lun_space_reservation(path, True)

mock_set_space_reservation.assert_called_once_with(
'lun-set-space-reservation-info',
**{'path': path,
'enable': 'True'})
self.connection.invoke_successfully.assert_called_once_with(
mock.ANY, True)

def test_create_lun_raises_on_failure(self):
@ddt.data('9.4', '9.6')
def test_create_lun_raises_on_failure(self, ontap_version):
self.connection.invoke_successfully = mock.Mock(
side_effect=netapp_api.NaApiError)
self.mock_object(self.client, 'get_ontap_version',
return_value=ontap_version)

self.assertRaises(netapp_api.NaApiError,
self.client.create_lun,


+ 2
- 0
cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py View File

@@ -53,6 +53,8 @@ class NetAppCmodeClientTestCase(test.TestCase):
super(NetAppCmodeClientTestCase, self).setUp()

self.mock_object(client_cmode.Client, '_init_ssh_client')
self.mock_object(client_cmode.Client, 'get_ontap_version',
return_value='9.6')
with mock.patch.object(client_cmode.Client,
'get_ontapi_version',
return_value=(1, 20)):


+ 17
- 0
cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py View File

@@ -421,6 +421,21 @@ CG_VOLUME_SNAPSHOT = {
'volume_id': CG_VOLUME_ID,
}

SYSTEM_GET_VERSION_RESPONSE = etree.XML("""
<results status="passed">
<build-timestamp>1395426307</build-timestamp>
<is-clustered>true</is-clustered>
<version>NetApp Release 9.6P2: Fri Jul 19 06:06:59 UTC 2019</version>
<version-tuple>
<system-version-tuple>
<generation>9</generation>
<major>6</major>
<minor>0</minor>
</system-version-tuple>
</version-tuple>
</results>
""")


VG_VOLUME_NAME = 'fake_vg_volume'
VG_GROUP_NAME = 'fake_volume_group'
@@ -435,6 +450,8 @@ VOLUME_GROUP_ID = 'fake_vg_id'
VG_SNAPSHOT_ID = 'fake_vg_snapshot_id'
VG_SNAPSHOT_NAME = 'snapshot-' + VG_SNAPSHOT_ID
VG_VOLUME_SNAPSHOT_ID = 'fake_vg_volume_snapshot_id'
MIN_SIZE_FOR_A_LUN = '4194304'
MAX_SIZE_FOR_A_LUN = '17555678822400'

VG_LUN_METADATA = {
'OsType': None,


+ 86
- 31
cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py View File

@@ -1203,7 +1203,8 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
mock_extend_volume.assert_called_once_with(
fake.VOLUME, new_size, fake.QOS_POLICY_GROUP_NAME)

def test__extend_volume_direct(self):
@ddt.data('9.4', '9.6')
def test__extend_volume_direct(self, ontap_version):

current_size = fake.LUN_SIZE
current_size_bytes = current_size * units.Gi
@@ -1212,6 +1213,9 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
max_size = fake.LUN_SIZE * 10
max_size_bytes = max_size * units.Gi

mock_get_ontap_version = self.mock_object(
self.library.zapi_client, 'get_ontap_version',
return_value=ontap_version)
fake_lun = block_base.NetAppLun(fake.LUN_HANDLE,
fake.LUN_ID,
current_size_bytes,
@@ -1230,16 +1234,23 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):

self.library._extend_volume(fake.VOLUME, new_size, 'fake_qos_policy')

mock_get_ontap_version.assert_called_once_with(cached=True)
mock_get_lun_from_table.assert_called_once_with(fake.VOLUME['name'])
mock_get_lun_geometry.assert_called_once_with(
fake.LUN_METADATA['Path'])

if ontap_version < '9.5':
mock_get_lun_geometry.assert_called_once_with(
fake.LUN_METADATA['Path'])
else:
mock_get_lun_geometry.assert_not_called()

mock_do_direct_resize.assert_called_once_with(
fake.LUN_METADATA['Path'], six.text_type(new_size_bytes))
self.assertFalse(mock_do_sub_clone_resize.called)
self.assertEqual(six.text_type(new_size_bytes),
self.library.lun_table[fake.VOLUME['name']].size)

def test__extend_attached_volume_direct(self):
@ddt.data('9.4', '9.6')
def test__extend_attached_volume_direct(self, ontap_version):

current_size = fake.LUN_SIZE
current_size_bytes = current_size * units.Gi
@@ -1251,6 +1262,9 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
volume_copy['size'] = new_size
volume_copy['attach_status'] = fake.ATTACHED

mock_get_ontap_version = self.mock_object(
self.library.zapi_client, 'get_ontap_version',
return_value=ontap_version)
fake_lun = block_base.NetAppLun(fake.LUN_HANDLE,
fake.LUN_ID,
current_size_bytes,
@@ -1265,20 +1279,27 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
'do_direct_resize')
mock_do_sub_clone_resize = self.mock_object(self.library,
'_do_sub_clone_resize')
self.library.lun_table = {volume_copy['name']: fake_lun}

self.library.lun_table = {volume_copy['name']: fake_lun}
self.library._extend_volume(volume_copy, new_size, 'fake_qos_policy')

mock_get_lun_from_table.assert_called_once_with(volume_copy['name'])
mock_get_lun_geometry.assert_called_once_with(
fake.LUN_METADATA['Path'])
mock_get_ontap_version.assert_called_once_with(cached=True)

if ontap_version < '9.5':
mock_get_lun_geometry.assert_called_once_with(
fake.LUN_METADATA['Path'])
else:
mock_get_lun_geometry.assert_not_called()

mock_do_direct_resize.assert_called_once_with(
fake.LUN_METADATA['Path'], six.text_type(new_size_bytes))
self.assertFalse(mock_do_sub_clone_resize.called)
self.assertEqual(six.text_type(new_size_bytes),
self.library.lun_table[volume_copy['name']].size)

def test__extend_volume_clone(self):
@ddt.data('9.4', '9.6')
def test__extend_volume_clone(self, ontap_version):

current_size = fake.LUN_SIZE
current_size_bytes = current_size * units.Gi
@@ -1287,6 +1308,9 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
max_size = fake.LUN_SIZE * 10
max_size_bytes = max_size * units.Gi

mock_get_ontap_version = self.mock_object(
self.library.zapi_client, 'get_ontap_version',
return_value=ontap_version)
fake_lun = block_base.NetAppLun(fake.LUN_HANDLE,
fake.LUN_ID,
current_size_bytes,
@@ -1305,29 +1329,43 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):

self.library._extend_volume(fake.VOLUME, new_size, 'fake_qos_policy')

mock_get_ontap_version.assert_called_once_with(cached=True)
mock_get_lun_from_table.assert_called_once_with(fake.VOLUME['name'])
mock_get_lun_geometry.assert_called_once_with(
fake.LUN_METADATA['Path'])
self.assertFalse(mock_do_direct_resize.called)
mock_do_sub_clone_resize.assert_called_once_with(
fake.LUN_METADATA['Path'], six.text_type(new_size_bytes),
qos_policy_group_name='fake_qos_policy')

if ontap_version < '9.5':
self.assertFalse(mock_do_direct_resize.called)
mock_get_lun_geometry.assert_called_once_with(
fake.LUN_METADATA['Path'])
mock_do_sub_clone_resize.assert_called_once_with(
fake.LUN_METADATA['Path'], six.text_type(new_size_bytes),
qos_policy_group_name='fake_qos_policy')
else:
mock_get_lun_geometry.assert_not_called()
mock_do_sub_clone_resize.assert_not_called()
mock_do_direct_resize.assert_called_once_with(
fake.LUN_METADATA['Path'], six.text_type(new_size_bytes))

self.assertEqual(six.text_type(new_size_bytes),
self.library.lun_table[fake.VOLUME['name']].size)

def test__extend_attached_volume_clone_error(self):
@ddt.data('9.4', '9.6')
def test__extend_attached_volume_clone_error(self, ontap_version):

current_size = fake.LUN_SIZE
current_size_bytes = current_size * units.Gi
new_size = fake.LUN_SIZE * 20
new_size_bytes = new_size * units.Gi
max_size = fake.LUN_SIZE * 10
max_size_bytes = max_size * units.Gi
volume_copy = copy.copy(fake.VOLUME)
volume_copy['attach_status'] = fake.ATTACHED

mock_get_ontap_version = self.mock_object(
self.library.zapi_client, 'get_ontap_version',
return_value=ontap_version)
fake_lun = block_base.NetAppLun(fake.LUN_HANDLE,
fake.LUN_ID,
current_size_bytes,
six.text_type(current_size_bytes),
fake.LUN_METADATA)
mock_get_lun_from_table = self.mock_object(
self.library, '_get_lun_from_table', return_value=fake_lun)
@@ -1341,21 +1379,35 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
'_do_sub_clone_resize')
self.library.lun_table = {volume_copy['name']: fake_lun}

self.assertRaises(exception.VolumeBackendAPIException,
self.library._extend_volume,
volume_copy,
new_size,
fake.QOS_POLICY_GROUP_NAME)

mock_get_lun_from_table.assert_called_once_with(volume_copy['name'])
mock_get_lun_geometry.assert_called_once_with(
fake.LUN_METADATA['Path'])
self.assertFalse(mock_do_direct_resize.called)
self.assertFalse(mock_do_sub_clone_resize.called)
self.assertEqual(current_size_bytes,
self.library.lun_table[volume_copy['name']].size)

def test__extend_volume_no_change(self):
# (throne82) This error occurs only with versions older than 9.5
if ontap_version < '9.5':
self.assertRaises(exception.VolumeBackendAPIException,
self.library._extend_volume,
volume_copy,
new_size,
fake.QOS_POLICY_GROUP_NAME)
self.assertFalse(mock_do_direct_resize.called)
self.assertFalse(mock_do_sub_clone_resize.called)
mock_get_lun_geometry.assert_called_once_with(
fake.LUN_METADATA['Path'])
self.assertEqual(six.text_type(current_size_bytes),
self.library.lun_table[volume_copy['name']].size)
else:
self.library._extend_volume(volume_copy,
new_size, fake.QOS_POLICY_GROUP_NAME)
mock_do_direct_resize.assert_called_once_with(
fake.LUN_METADATA['Path'], six.text_type(new_size_bytes))
mock_do_sub_clone_resize.assert_not_called()
mock_get_lun_geometry.assert_not_called()
self.assertEqual(six.text_type(new_size_bytes),
self.library.lun_table[volume_copy['name']].size)

mock_get_ontap_version.assert_called_once_with(cached=True)
mock_get_lun_from_table.assert_called_once_with(
volume_copy['name'])

@ddt.data('9.4', '9.6')
def test__extend_volume_no_change(self, ontap_version):

current_size = fake.LUN_SIZE
current_size_bytes = current_size * units.Gi
@@ -1365,6 +1417,8 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
volume_copy = copy.copy(fake.VOLUME)
volume_copy['size'] = new_size

mock_get_ontap_version = self.mock_object(
self.library.zapi_client, 'get_ontap_version')
fake_lun = block_base.NetAppLun(fake.LUN_HANDLE,
fake.LUN_ID,
current_size_bytes,
@@ -1387,6 +1441,7 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
self.assertFalse(mock_get_lun_geometry.called)
self.assertFalse(mock_do_direct_resize.called)
self.assertFalse(mock_do_sub_clone_resize.called)
self.assertFalse(mock_get_ontap_version.called)

def test_do_sub_clone_resize(self):



+ 3
- 1
cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py View File

@@ -91,6 +91,8 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
'check_api_permissions')
@mock.patch.object(na_utils, 'check_flags')
@mock.patch.object(block_base.NetAppBlockStorageLibrary, 'do_setup')
@mock.patch.object(client_base.Client, 'get_ontap_version',
mock.MagicMock(return_value='9.6'))
def test_do_setup(self, super_do_setup, mock_check_flags,
mock_check_api_permissions, mock_cluster_user_supported):
self.mock_object(client_base.Client, '_init_ssh_client')
@@ -418,7 +420,7 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
'netapp_raid_type': 'raid_dp',
'netapp_disk_type': 'SSD',
'replication_enabled': False,
'online_extend_support': False,
'online_extend_support': True,
}]

expected[0].update({'QoS_support': cluster_credentials})


+ 14
- 9
cinder/volume/drivers/netapp/dataontap/block_base.py View File

@@ -592,18 +592,26 @@ class NetAppBlockStorageLibrary(object):
new_size_bytes = six.text_type(int(new_size) * units.Gi)
# Reused by clone scenarios.
# Hence comparing the stored size.
if curr_size_bytes != new_size_bytes:
if curr_size_bytes == new_size_bytes:
LOG.info("No need to extend volume %s"
" as it is already the requested new size.", name)
return

ontap_version = self.zapi_client.get_ontap_version(cached=True)

if ontap_version >= '9.5':
self.zapi_client.do_direct_resize(path, new_size_bytes)
else:
lun_geometry = self.zapi_client.get_lun_geometry(path)
if (lun_geometry and lun_geometry.get("max_resize")
and int(lun_geometry.get("max_resize")) >=
if (lun_geometry and int(lun_geometry.get("max_resize", 0)) >=
int(new_size_bytes)):
self.zapi_client.do_direct_resize(path, new_size_bytes)
else:
if volume['attach_status'] != 'detached':
msg = _('Volume %(vol_id)s cannot be resized from '
'%(old_size)s to %(new_size)s, because would '
'exceed its max geometry %(max_geo)s while not '
'being detached.')
'exceed its max geometry %(max_geo)s while '
'not being detached.')
raise exception.VolumeBackendAPIException(data=msg % {
'vol_id': name,
'old_size': curr_size_bytes,
@@ -612,10 +620,7 @@ class NetAppBlockStorageLibrary(object):
self._do_sub_clone_resize(
path, new_size_bytes,
qos_policy_group_name=qos_policy_group_name)
self.lun_table[name].size = new_size_bytes
else:
LOG.info("No need to extend volume %s"
" as it is already the requested new size.", name)
self.lun_table[name].size = new_size_bytes

def _get_vol_option(self, volume_name, option_name):
"""Get the value for the volume option."""


+ 1
- 1
cinder/volume/drivers/netapp/dataontap/block_cmode.py View File

@@ -296,7 +296,7 @@ class NetAppBlockStorageCmodeLibrary(block_base.NetAppBlockStorageLibrary,
# Add driver capabilities and config info
pool['QoS_support'] = self.using_cluster_credentials
pool['multiattach'] = True
pool['online_extend_support'] = False
pool['online_extend_support'] = True
pool['consistencygroup_support'] = True
pool['consistent_group_snapshot_enabled'] = True
pool['reserved_percentage'] = self.reserved_percentage


+ 6
- 0
cinder/volume/drivers/netapp/dataontap/client/api.py View File

@@ -133,6 +133,12 @@ class NaServer(object):
self._ns = NaServer.NETAPP_NS
self._refresh_conn = True

def set_ontap_version(self, version):
self._ontap_version = version

def get_ontap_version(self):
return self._ontap_version

def set_api_version(self, major, minor):
"""Set the API version."""
try:


+ 53
- 2
cinder/volume/drivers/netapp/dataontap/client/client_base.py View File

@@ -30,6 +30,7 @@ from cinder.volume.drivers.netapp import utils as na_utils
LOG = logging.getLogger(__name__)

DELETED_PREFIX = 'deleted_cinder_'
MAX_SIZE_FOR_A_LUN = '17555678822400'


@six.add_metaclass(utils.TraceWrapperMetaclass)
@@ -60,6 +61,27 @@ class Client(object):
"""Set up the repository of available Data ONTAP features."""
self.features = na_utils.Features()

def get_ontap_version(self, cached=True):
"""Gets the ONTAP version."""

if cached:
return self.connection.get_ontap_version()

ontap_version = netapp_api.NaElement("system-get-version")
result = self.connection.invoke_successfully(ontap_version, True)

version_tuple = result.get_child_by_name(
'version-tuple') or netapp_api.NaElement('none')
system_version_tuple = version_tuple.get_child_by_name(
'system-version-tuple') or netapp_api.NaElement('none')

generation = system_version_tuple.get_child_content("generation")
major = system_version_tuple.get_child_content("major")

return '%(generation)s.%(major)s' % {
'generation': generation,
'major': major}

def get_ontapi_version(self, cached=True):
"""Gets the supported ontapi version."""

@@ -87,9 +109,23 @@ class Client(object):
"""Issues API request for creating LUN on volume."""

path = '/vol/%s/%s' % (volume_name, lun_name)
params = {'path': path, 'size': six.text_type(size),
space_reservation = metadata['SpaceReserved']
initial_size = size
ontap_version = self.get_ontap_version()

# On older ONTAP versions the extend size is limited to its
# geometry on max_resize_size. In order to remove this
# limitation we create the LUN with its maximum possible size
# and then shrink to the requested size.
if ontap_version < '9.5':
initial_size = MAX_SIZE_FOR_A_LUN
# In order to create a LUN with its maximum size (16TB),
# the space_reservation needs to be disabled
space_reservation = 'false'

params = {'path': path, 'size': str(initial_size),
'ostype': metadata['OsType'],
'space-reservation-enabled': metadata['SpaceReserved']}
'space-reservation-enabled': space_reservation}
version = self.get_ontapi_version()
if version >= (1, 110):
params['use-exact-size'] = 'true'
@@ -109,6 +145,21 @@ class Client(object):
'volume_name': volume_name,
'ex': ex})

if ontap_version < '9.5':
self.do_direct_resize(path, six.text_type(size))
if metadata['SpaceReserved'] == 'true':
self.set_lun_space_reservation(path, True)

def set_lun_space_reservation(self, path, flag):
"""Sets the LUN space reservation on ONTAP."""

lun_modify_space_reservation = (
netapp_api.NaElement.create_node_with_children(
'lun-set-space-reservation-info', **{
'path': path,
'enable': str(flag)}))
self.connection.invoke_successfully(lun_modify_space_reservation, True)

def destroy_lun(self, path, force=True):
"""Destroys the LUN at the path."""
lun_destroy = netapp_api.NaElement.create_node_with_children(


+ 2
- 0
cinder/volume/drivers/netapp/dataontap/client/client_cmode.py View File

@@ -50,6 +50,8 @@ class Client(client_base.Client):
(major, minor) = self.get_ontapi_version(cached=False)
self.connection.set_api_version(major, minor)
self._init_features()
ontap_version = self.get_ontap_version(cached=False)
self.connection.set_ontap_version(ontap_version)

def _init_features(self):
super(Client, self)._init_features()


+ 1
- 1
doc/source/reference/support-matrix.ini View File

@@ -295,7 +295,7 @@ driver.linbit_linstor=complete
driver.lvm=complete
driver.macrosan=complete
driver.nec=complete
driver.netapp_ontap=missing
driver.netapp_ontap=complete
driver.netapp_solidfire=complete
driver.nexenta=complete
driver.nfs=complete


+ 6
- 0
releasenotes/notes/bug-1874134-netapp-ONTAP-fix-max-resize-size-ad2d88da8721560e.yaml View File

@@ -0,0 +1,6 @@
---
fixes:
- |
Fix bug `#1874134 <https://bugs.launchpad.net/cinder/+bug/1874134>`_,
allowing an iSCSI or FCP volume to be extended to a size up to 16TB
regardless of its original size, even if it's attached to an instance.

Loading…
Cancel
Save