Browse Source

Merge "[NetApp] Adding support for Adaptive QoS in NetApp driver."

tags/17.0.0.0rc1
Zuul 1 week ago
committed by Gerrit Code Review
parent
commit
fb7edff4d0
11 changed files with 96 additions and 38 deletions
  1. +2
    -2
      cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py
  2. +7
    -4
      cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py
  3. +5
    -2
      cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py
  4. +8
    -8
      cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py
  5. +11
    -4
      cinder/volume/drivers/netapp/dataontap/block_base.py
  6. +14
    -9
      cinder/volume/drivers/netapp/dataontap/block_cmode.py
  7. +8
    -2
      cinder/volume/drivers/netapp/dataontap/client/client_base.py
  8. +14
    -5
      cinder/volume/drivers/netapp/dataontap/client/client_cmode.py
  9. +7
    -2
      cinder/volume/drivers/netapp/dataontap/nfs_cmode.py
  10. +6
    -0
      doc/source/configuration/tables/manual/cinder-netapp_cdot_extraspecs.inc
  11. +14
    -0
      releasenotes/notes/netapp-add-support-for-adaptive-qos-0b76dadf7c044cd8.yaml

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

@@ -808,8 +808,8 @@ class NetAppCmodeClientTestCase(test.TestCase):
'vserver': self.vserver
}

self.client.file_assign_qos(
fake.FLEXVOL, fake.QOS_POLICY_GROUP_NAME, fake.NFS_FILE_PATH)
self.client.file_assign_qos(fake.FLEXVOL, fake.QOS_POLICY_GROUP_NAME,
False, fake.NFS_FILE_PATH)

self.mock_send_request.assert_has_calls([
mock.call('file-assign-qos', api_args, False)])


+ 7
- 4
cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py View File

@@ -117,7 +117,8 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):

def test_create_volume(self):
volume_size_in_bytes = int(fake.SIZE) * units.Gi
self.mock_object(na_utils, 'get_volume_extra_specs')
self.mock_object(na_utils, 'get_volume_extra_specs',
return_value={})
self.mock_object(na_utils, 'log_extra_spec_warnings')
self.mock_object(block_base, 'LOG')
self.mock_object(volume_utils, 'extract_host',
@@ -134,7 +135,7 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):

self.library._create_lun.assert_called_once_with(
fake.POOL_NAME, fake.LUN_NAME, volume_size_in_bytes,
fake.LUN_METADATA, None)
fake.LUN_METADATA, None, False)
self.library._get_volume_model_update.assert_called_once_with(
fake.VOLUME)
self.assertEqual(
@@ -1062,7 +1063,8 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
self.library._clone_lun.assert_called_once_with(
fake.CLONE_SOURCE_NAME, fake.CLONE_DESTINATION_NAME,
space_reserved='false',
qos_policy_group_name=fake.QOS_POLICY_GROUP_NAME)
qos_policy_group_name=fake.QOS_POLICY_GROUP_NAME,
qos_policy_group_is_adaptive=False)
self.library._extend_volume.assert_called_once_with(
fake.CLONE_DESTINATION, fake.CLONE_DESTINATION_SIZE,
fake.QOS_POLICY_GROUP_NAME)
@@ -1092,7 +1094,8 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
self.library._clone_lun.assert_called_once_with(
fake.CLONE_SOURCE_NAME, fake.CLONE_DESTINATION_NAME,
space_reserved='true',
qos_policy_group_name=fake.QOS_POLICY_GROUP_NAME)
qos_policy_group_name=fake.QOS_POLICY_GROUP_NAME,
qos_policy_group_is_adaptive=False)
self.library._extend_volume.assert_called_once_with(
fake.CLONE_DESTINATION, fake.CLONE_DESTINATION_SIZE,
fake.QOS_POLICY_GROUP_NAME)


+ 5
- 2
cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py View File

@@ -273,7 +273,8 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
self.library.zapi_client.clone_lun.assert_called_once_with(
'fakeLUN', 'fakeLUN', 'newFakeLUN', 'false', block_count=0,
dest_block=0, src_block=0, qos_policy_group_name=None,
source_snapshot=None, is_snapshot=False)
qos_policy_group_is_adaptive=False, source_snapshot=None,
is_snapshot=False)

def test_clone_lun_blocks(self):
"""Test for when clone lun is passed block information."""
@@ -298,6 +299,7 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
'fakeLUN', 'fakeLUN', 'newFakeLUN', 'false',
block_count=block_count, dest_block=dest_block,
src_block=src_block, qos_policy_group_name=None,
qos_policy_group_is_adaptive=False,
source_snapshot=None, is_snapshot=False)

def test_clone_lun_no_space_reservation(self):
@@ -318,6 +320,7 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
self.library.zapi_client.clone_lun.assert_called_once_with(
'fakeLUN', 'fakeLUN', 'newFakeLUN', 'false', block_count=0,
dest_block=0, src_block=0, qos_policy_group_name=None,
qos_policy_group_is_adaptive=False,
source_snapshot=None, is_snapshot=True)

def test_get_fc_target_wwpns(self):
@@ -335,7 +338,7 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):

self.library.zapi_client.create_lun.assert_called_once_with(
fake.VOLUME_ID, fake.LUN_ID, fake.LUN_SIZE, fake.LUN_METADATA,
None)
None, False)

@ddt.data({'replication_backends': [], 'cluster_credentials': False},
{'replication_backends': ['target_1', 'target_2'],


+ 8
- 8
cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py View File

@@ -635,7 +635,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
mock_provision_qos.assert_has_calls([
mock.call(fake.QOS_POLICY_GROUP_INFO)])
mock_set_policy.assert_has_calls([
mock.call(fake.NFS_VOLUME, fake.QOS_POLICY_GROUP_INFO)])
mock.call(fake.NFS_VOLUME, fake.QOS_POLICY_GROUP_INFO, False)])
self.assertEqual(0, mock_error_log.call_count)
self.assertEqual(0, mock_debug_log.call_count)
self.assertEqual(0, mock_cleanup.call_count)
@@ -663,7 +663,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
mock_provision_qos.assert_has_calls([
mock.call(fake.QOS_POLICY_GROUP_INFO)])
mock_set_policy.assert_has_calls([
mock.call(fake.NFS_VOLUME, fake.QOS_POLICY_GROUP_INFO)])
mock.call(fake.NFS_VOLUME, fake.QOS_POLICY_GROUP_INFO, False)])
self.assertEqual(1, mock_error_log.call_count)
self.assertEqual(1, mock_debug_log.call_count)
mock_cleanup.assert_has_calls([
@@ -708,8 +708,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):

mock_file_assign_qos = self.driver.zapi_client.file_assign_qos

self.driver._set_qos_policy_group_on_volume(fake.NFS_VOLUME,
fake.QOS_POLICY_GROUP_INFO)
self.driver._set_qos_policy_group_on_volume(
fake.NFS_VOLUME, fake.QOS_POLICY_GROUP_INFO, False)

mock_get_name_from_info.assert_has_calls([
mock.call(fake.QOS_POLICY_GROUP_INFO)])
@@ -719,7 +719,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
mock.call(fake.VSERVER_NAME, fake.EXPORT_PATH)])
mock_file_assign_qos.assert_has_calls([
mock.call(fake.FLEXVOL, fake.QOS_POLICY_GROUP_NAME,
fake.NFS_VOLUME['name'])])
False, fake.NFS_VOLUME['name'])])

def test_set_qos_policy_group_on_volume_no_info(self):

@@ -734,7 +734,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
mock_file_assign_qos = self.driver.zapi_client.file_assign_qos

self.driver._set_qos_policy_group_on_volume(fake.NFS_VOLUME,
None)
None, False)

self.assertEqual(0, mock_get_name_from_info.call_count)
self.assertEqual(0, mock_extract_host.call_count)
@@ -754,8 +754,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):

mock_file_assign_qos = self.driver.zapi_client.file_assign_qos

self.driver._set_qos_policy_group_on_volume(fake.NFS_VOLUME,
fake.QOS_POLICY_GROUP_INFO)
self.driver._set_qos_policy_group_on_volume(
fake.NFS_VOLUME, fake.QOS_POLICY_GROUP_INFO, False)

mock_get_name_from_info.assert_has_calls([
mock.call(fake.QOS_POLICY_GROUP_INFO)])


+ 11
- 4
cinder/volume/drivers/netapp/dataontap/block_base.py View File

@@ -237,10 +237,13 @@ class NetAppBlockStorageLibrary(object):
qos_policy_group_name = (
na_utils.get_qos_policy_group_name_from_info(
qos_policy_group_info))
qos_policy_group_is_adaptive = volume_utils.is_boolean_str(
extra_specs.get('netapp:qos_policy_group_is_adaptive'))

try:
self._create_lun(pool_name, lun_name, size, metadata,
qos_policy_group_name)
qos_policy_group_name,
qos_policy_group_is_adaptive)
except Exception:
LOG.exception("Exception creating LUN %(name)s in pool %(pool)s.",
{'name': lun_name, 'pool': pool_name})
@@ -357,11 +360,15 @@ class NetAppBlockStorageLibrary(object):
qos_policy_group_name = (
na_utils.get_qos_policy_group_name_from_info(
qos_policy_group_info))
qos_policy_group_is_adaptive = volume_utils.is_boolean_str(
extra_specs.get('netapp:qos_policy_group_is_adaptive'))

try:
self._clone_lun(source_name, destination_name,
space_reserved=self.lun_space_reservation,
qos_policy_group_name=qos_policy_group_name)
self._clone_lun(
source_name, destination_name,
space_reserved=self.lun_space_reservation,
qos_policy_group_name=qos_policy_group_name,
qos_policy_group_is_adaptive=qos_policy_group_is_adaptive)

if destination_size != source_size:



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

@@ -165,11 +165,13 @@ class NetAppBlockStorageCmodeLibrary(block_base.NetAppBlockStorageLibrary,
self.zapi_client.send_ems_log_message(pool_ems_message)

def _create_lun(self, volume_name, lun_name, size,
metadata, qos_policy_group_name=None):
metadata, qos_policy_group_name=None,
qos_policy_group_is_adaptive=False):
"""Creates a LUN, handling Data ONTAP differences as needed."""

self.zapi_client.create_lun(
volume_name, lun_name, size, metadata, qos_policy_group_name)
volume_name, lun_name, size, metadata, qos_policy_group_name,
qos_policy_group_is_adaptive)

def _create_lun_handle(self, metadata, vserver=None):
"""Returns LUN handle based on filer type."""
@@ -192,19 +194,22 @@ class NetAppBlockStorageCmodeLibrary(block_base.NetAppBlockStorageLibrary,

def _clone_lun(self, name, new_name, space_reserved=None,
qos_policy_group_name=None, src_block=0, dest_block=0,
block_count=0, source_snapshot=None, is_snapshot=False):
block_count=0, source_snapshot=None, is_snapshot=False,
qos_policy_group_is_adaptive=False):
"""Clone LUN with the given handle to the new name."""
if not space_reserved:
space_reserved = self.lun_space_reservation
metadata = self._get_lun_attr(name, 'metadata')
volume = metadata['Volume']

self.zapi_client.clone_lun(volume, name, new_name, space_reserved,
qos_policy_group_name=qos_policy_group_name,
src_block=src_block, dest_block=dest_block,
block_count=block_count,
source_snapshot=source_snapshot,
is_snapshot=is_snapshot)
self.zapi_client.clone_lun(
volume, name, new_name, space_reserved,
qos_policy_group_name=qos_policy_group_name,
src_block=src_block, dest_block=dest_block,
block_count=block_count,
source_snapshot=source_snapshot,
is_snapshot=is_snapshot,
qos_policy_group_is_adaptive=qos_policy_group_is_adaptive)

LOG.debug("Cloned LUN with new name %s", new_name)
lun = self.zapi_client.get_lun_by_args(vserver=self.vserver,


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

@@ -105,7 +105,8 @@ class Client(object):
raise ValueError('Expects NaElement')

def create_lun(self, volume_name, lun_name, size, metadata,
qos_policy_group_name=None):
qos_policy_group_name=None,
qos_policy_group_is_adaptive=False):
"""Issues API request for creating LUN on volume."""

path = '/vol/%s/%s' % (volume_name, lun_name)
@@ -133,7 +134,12 @@ class Client(object):
'lun-create-by-size',
**params)
if qos_policy_group_name:
lun_create.add_new_child('qos-policy-group', qos_policy_group_name)
if qos_policy_group_is_adaptive:
lun_create.add_new_child(
'qos-adaptive-policy-group', qos_policy_group_name)
else:
lun_create.add_new_child(
'qos-policy-group', qos_policy_group_name)

try:
self.connection.invoke_successfully(lun_create, True)


+ 14
- 5
cinder/volume/drivers/netapp/dataontap/client/client_cmode.py View File

@@ -453,7 +453,8 @@ class Client(client_base.Client):

def clone_lun(self, volume, name, new_name, space_reserved='true',
qos_policy_group_name=None, src_block=0, dest_block=0,
block_count=0, source_snapshot=None, is_snapshot=False):
block_count=0, source_snapshot=None, is_snapshot=False,
qos_policy_group_is_adaptive=False):
# ONTAP handles only 128 MB per call as of v9.1
bc_limit = 2 ** 18 # 2^18 blocks * 512 bytes/block = 128 MB
z_calls = int(math.ceil(block_count / float(bc_limit)))
@@ -480,8 +481,13 @@ class Client(client_base.Client):
clone_create = netapp_api.NaElement.create_node_with_children(
'clone-create', **zapi_args)
if qos_policy_group_name is not None:
clone_create.add_new_child('qos-policy-group-name',
qos_policy_group_name)
if qos_policy_group_is_adaptive:
clone_create.add_new_child(
'qos-adaptive-policy-group-name',
qos_policy_group_name)
else:
clone_create.add_new_child('qos-policy-group-name',
qos_policy_group_name)
if block_count > 0:
block_ranges = netapp_api.NaElement("block-ranges")
segments = int(math.ceil(block_count / float(bc_limit)))
@@ -520,11 +526,14 @@ class Client(client_base.Client):
return []
return attr_list.get_children()

def file_assign_qos(self, flex_vol, qos_policy_group_name, file_path):
def file_assign_qos(self, flex_vol, qos_policy_group_name,
qos_policy_group_is_adaptive, file_path):
"""Assigns the named QoS policy-group to a file."""
qos_arg_name = "qos-%spolicy-group-name" % (
"adaptive-" if qos_policy_group_is_adaptive else "")
api_args = {
'volume': flex_vol,
'qos-policy-group-name': qos_policy_group_name,
qos_arg_name: qos_policy_group_name,
'file': file_path,
'vserver': self.vserver,
}


+ 7
- 2
cinder/volume/drivers/netapp/dataontap/nfs_cmode.py View File

@@ -161,11 +161,14 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
self.ssc_library.get_ssc_flexvol_names())

def _do_qos_for_volume(self, volume, extra_specs, cleanup=True):
qos_policy_group_is_adaptive = volume_utils.is_boolean_str(
extra_specs.get('netapp:qos_policy_group_is_adaptive'))
try:
qos_policy_group_info = na_utils.get_valid_qos_policy_group_info(
volume, extra_specs)
self.zapi_client.provision_qos_policy_group(qos_policy_group_info)
self._set_qos_policy_group_on_volume(volume, qos_policy_group_info)
self._set_qos_policy_group_on_volume(volume, qos_policy_group_info,
qos_policy_group_is_adaptive)
except Exception:
with excutils.save_and_reraise_exception():
LOG.error("Setting QoS for %s failed", volume['id'])
@@ -178,7 +181,8 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
if self.replication_enabled:
return {'replication_status': fields.ReplicationStatus.ENABLED}

def _set_qos_policy_group_on_volume(self, volume, qos_policy_group_info):
def _set_qos_policy_group_on_volume(self, volume, qos_policy_group_info,
qos_policy_group_is_adaptive):
if qos_policy_group_info is None:
return
qos_policy_group_name = na_utils.get_qos_policy_group_name_from_info(
@@ -192,6 +196,7 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
export_path)
self.zapi_client.file_assign_qos(flex_vol_name,
qos_policy_group_name,
qos_policy_group_is_adaptive,
target_path)

def _clone_backing_file_for_volume(self, volume_name, clone_name,


+ 6
- 0
doc/source/configuration/tables/manual/cinder-netapp_cdot_extraspecs.inc View File

@@ -21,6 +21,12 @@
object within Data ONTAP should be defined before an OpenStack Block
Storage volume is created, and that the QoS policy group is not
associated with the destination FlexVol volume.
* - ``netapp:qos_policy_group_is_adaptive``
- Boolean
- Set to "<is> True" in order to instruct the driver to use an Adaptive
QoS policy group for the netapp:qos_policy_group setting. Leave this
unset or set to "<is> False" in order to use a standard QoS policy
group for the netapp:qos_policy_group setting.
* - ``netapp_mirrored``
- Boolean
- Limit the candidate volume list to only the ones that are mirrored on


+ 14
- 0
releasenotes/notes/netapp-add-support-for-adaptive-qos-0b76dadf7c044cd8.yaml View File

@@ -0,0 +1,14 @@
---
features:
- |
NetApp ONTAP:
Added support for Adaptive QoS policies that have been pre-created on
the storage system, with the NetApp driver and clustered ONTAP version
9.4 or higher. To use this feature, configure a Cinder volume type with
the following extra-specs::

netapp:qos_policy_group=<name_of_precreated_aqos_policy>
netapp:qos_policy_group_is_adaptive="<is> True"

Note that a cluster scoped account must be used in the driver
configuration in order to use QoS in clustered ONTAP.

Loading…
Cancel
Save