summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2020-11-04 17:00:28 +0000
committerGerrit Code Review <review@openstack.org>2020-11-04 17:00:28 +0000
commitd1eab14c0a968b6a2c2e4603b0ed855958cff438 (patch)
tree7b7f997b64fbb7ddaee651cdeab4691d833e7c39
parent8c9aa6164837b6297c2c8d93d188de6888228998 (diff)
parent836cda0121e052a18b725053501b8b309fa041c1 (diff)
downloadcinder-d1eab14c0a968b6a2c2e4603b0ed855958cff438.tar.gz
Merge "NetApp ONTAP: Fix extend volume for iSCSI/FCP" into stable/stein
-rw-r--r--cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_base.py157
-rw-r--r--cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py2
-rw-r--r--cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py17
-rw-r--r--cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py117
-rw-r--r--cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py4
-rw-r--r--cinder/volume/drivers/netapp/dataontap/block_base.py23
-rw-r--r--cinder/volume/drivers/netapp/dataontap/block_cmode.py2
-rw-r--r--cinder/volume/drivers/netapp/dataontap/client/api.py6
-rw-r--r--cinder/volume/drivers/netapp/dataontap/client/client_base.py55
-rw-r--r--cinder/volume/drivers/netapp/dataontap/client/client_cmode.py2
-rw-r--r--doc/source/reference/support-matrix.ini2
-rw-r--r--releasenotes/notes/bug-1874134-netapp-ONTAP-fix-max-resize-size-ad2d88da8721560e.yaml6
12 files changed, 332 insertions, 61 deletions
diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_base.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_base.py
index 8d18e07cb..9f61be8ba 100644
--- a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_base.py
+++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_base.py
@@ -16,6 +16,7 @@
import uuid
+import ddt
from lxml import etree
import mock
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,
diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py
index 4c7de390e..c50a4e4b5 100644
--- a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py
+++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py
@@ -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)):
diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py
index 48f303a03..79d6d04e1 100644
--- a/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py
+++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py
@@ -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,
diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py
index 6581e484d..12d76b9c0 100644
--- a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py
+++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py
@@ -1134,7 +1134,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
@@ -1143,6 +1144,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,
@@ -1161,16 +1165,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
@@ -1182,6 +1193,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,
@@ -1196,20 +1210,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
@@ -1218,6 +1239,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,
@@ -1236,29 +1260,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)
@@ -1272,21 +1310,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
@@ -1296,6 +1348,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,
@@ -1318,6 +1372,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):
diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py
index 0786bf2df..954c442ae 100644
--- a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py
+++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py
@@ -92,6 +92,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')
@@ -419,7 +421,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})
diff --git a/cinder/volume/drivers/netapp/dataontap/block_base.py b/cinder/volume/drivers/netapp/dataontap/block_base.py
index 8ca86bf5c..c09be26c0 100644
--- a/cinder/volume/drivers/netapp/dataontap/block_base.py
+++ b/cinder/volume/drivers/netapp/dataontap/block_base.py
@@ -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."""
diff --git a/cinder/volume/drivers/netapp/dataontap/block_cmode.py b/cinder/volume/drivers/netapp/dataontap/block_cmode.py
index e25d58a94..2de799699 100644
--- a/cinder/volume/drivers/netapp/dataontap/block_cmode.py
+++ b/cinder/volume/drivers/netapp/dataontap/block_cmode.py
@@ -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
diff --git a/cinder/volume/drivers/netapp/dataontap/client/api.py b/cinder/volume/drivers/netapp/dataontap/client/api.py
index 4e530dd2e..61b89cd25 100644
--- a/cinder/volume/drivers/netapp/dataontap/client/api.py
+++ b/cinder/volume/drivers/netapp/dataontap/client/api.py
@@ -135,6 +135,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:
diff --git a/cinder/volume/drivers/netapp/dataontap/client/client_base.py b/cinder/volume/drivers/netapp/dataontap/client/client_base.py
index 7fe19604e..6104dd4e0 100644
--- a/cinder/volume/drivers/netapp/dataontap/client/client_base.py
+++ b/cinder/volume/drivers/netapp/dataontap/client/client_base.py
@@ -32,6 +32,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)
@@ -62,6 +63,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."""
@@ -89,9 +111,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'
@@ -111,6 +147,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(
diff --git a/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py b/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py
index 4a34fb21e..82e7f9120 100644
--- a/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py
+++ b/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py
@@ -51,6 +51,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()
diff --git a/doc/source/reference/support-matrix.ini b/doc/source/reference/support-matrix.ini
index 0e1e717e0..adc4b1d4c 100644
--- a/doc/source/reference/support-matrix.ini
+++ b/doc/source/reference/support-matrix.ini
@@ -313,7 +313,7 @@ driver.linbit_drbd=complete
driver.linbit_linstor=complete
driver.lvm=complete
driver.nec=complete
-driver.netapp_ontap=missing
+driver.netapp_ontap=complete
driver.netapp_solidfire=complete
driver.nexenta=complete
driver.nfs=complete
diff --git a/releasenotes/notes/bug-1874134-netapp-ONTAP-fix-max-resize-size-ad2d88da8721560e.yaml b/releasenotes/notes/bug-1874134-netapp-ONTAP-fix-max-resize-size-ad2d88da8721560e.yaml
new file mode 100644
index 000000000..24f4a8b6e
--- /dev/null
+++ b/releasenotes/notes/bug-1874134-netapp-ONTAP-fix-max-resize-size-ad2d88da8721560e.yaml
@@ -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.