Merge "[NetApp] Improve Adaptive QoS functionality"
This commit is contained in:
commit
22823526c5
@ -1650,6 +1650,10 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
|||||||
qos_policy_group=None, adaptive_qos_policy_group=None,
|
qos_policy_group=None, adaptive_qos_policy_group=None,
|
||||||
encrypt=False, **options):
|
encrypt=False, **options):
|
||||||
"""Creates a volume."""
|
"""Creates a volume."""
|
||||||
|
if adaptive_qos_policy_group and not self.features.ADAPTIVE_QOS:
|
||||||
|
msg = 'Adaptive QoS not supported on this backend ONTAP version.'
|
||||||
|
raise exception.NetAppException(msg)
|
||||||
|
|
||||||
api_args = {
|
api_args = {
|
||||||
'containing-aggr-name': aggregate_name,
|
'containing-aggr-name': aggregate_name,
|
||||||
'size': six.text_type(size_gb) + 'g',
|
'size': six.text_type(size_gb) + 'g',
|
||||||
@ -1920,8 +1924,13 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
|||||||
language=None, dedup_enabled=False,
|
language=None, dedup_enabled=False,
|
||||||
compression_enabled=False, max_files=None,
|
compression_enabled=False, max_files=None,
|
||||||
qos_policy_group=None, hide_snapdir=None,
|
qos_policy_group=None, hide_snapdir=None,
|
||||||
autosize_attributes=None, **options):
|
autosize_attributes=None,
|
||||||
|
adaptive_qos_policy_group=None, **options):
|
||||||
"""Update backend volume for a share as necessary."""
|
"""Update backend volume for a share as necessary."""
|
||||||
|
if adaptive_qos_policy_group and not self.features.ADAPTIVE_QOS:
|
||||||
|
msg = 'Adaptive QoS not supported on this backend ONTAP version.'
|
||||||
|
raise exception.NetAppException(msg)
|
||||||
|
|
||||||
api_args = {
|
api_args = {
|
||||||
'query': {
|
'query': {
|
||||||
'volume-attributes': {
|
'volume-attributes': {
|
||||||
@ -1961,6 +1970,11 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
|||||||
'volume-qos-attributes'] = {
|
'volume-qos-attributes'] = {
|
||||||
'policy-group-name': qos_policy_group,
|
'policy-group-name': qos_policy_group,
|
||||||
}
|
}
|
||||||
|
if adaptive_qos_policy_group:
|
||||||
|
api_args['attributes']['volume-attributes'][
|
||||||
|
'volume-qos-attributes'] = {
|
||||||
|
'adaptive-policy-group-name': adaptive_qos_policy_group,
|
||||||
|
}
|
||||||
if hide_snapdir in (True, False):
|
if hide_snapdir in (True, False):
|
||||||
# Value of hide_snapdir needs to be inverted for ZAPI parameter
|
# Value of hide_snapdir needs to be inverted for ZAPI parameter
|
||||||
api_args['attributes']['volume-attributes'][
|
api_args['attributes']['volume-attributes'][
|
||||||
|
@ -550,6 +550,7 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
share, snapshot, src_vserver, src_vserver_client)
|
share, snapshot, src_vserver, src_vserver_client)
|
||||||
return self._create_export(share, share_server, src_vserver,
|
return self._create_export(share, share_server, src_vserver,
|
||||||
src_vserver_client)
|
src_vserver_client)
|
||||||
|
|
||||||
parent_share_server = {}
|
parent_share_server = {}
|
||||||
if parent_share['share_server'] is not None:
|
if parent_share['share_server'] is not None:
|
||||||
# Get only the information needed by Data Motion
|
# Get only the information needed by Data Motion
|
||||||
@ -1040,20 +1041,9 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
self._check_extra_specs_validity(share, extra_specs)
|
self._check_extra_specs_validity(share, extra_specs)
|
||||||
provisioning_options = self._get_provisioning_options(extra_specs)
|
provisioning_options = self._get_provisioning_options(extra_specs)
|
||||||
qos_specs = self._get_normalized_qos_specs(extra_specs)
|
qos_specs = self._get_normalized_qos_specs(extra_specs)
|
||||||
if (provisioning_options.get('adaptive_qos_policy_group') is not None
|
self.validate_provisioning_options_for_share(provisioning_options,
|
||||||
and qos_specs):
|
extra_specs=extra_specs,
|
||||||
msg = _('Share cannot be provisioned with both qos_specs '
|
qos_specs=qos_specs)
|
||||||
'%(qos_specs_string)s and adaptive_qos_policy_group '
|
|
||||||
'%(adaptive_qos_policy_group)s.')
|
|
||||||
qos_specs_string = ""
|
|
||||||
for key in qos_specs:
|
|
||||||
qos_specs_string += key + "=" + str(qos_specs[key]) + " "
|
|
||||||
msg_args = {
|
|
||||||
'adaptive_qos_policy_group':
|
|
||||||
provisioning_options['adaptive_qos_policy_group'],
|
|
||||||
'qos_specs_string': qos_specs_string
|
|
||||||
}
|
|
||||||
raise exception.NetAppException(msg % msg_args)
|
|
||||||
if qos_specs and not replica:
|
if qos_specs and not replica:
|
||||||
qos_policy_group = self._create_qos_policy_group(
|
qos_policy_group = self._create_qos_policy_group(
|
||||||
share, vserver, qos_specs, vserver_client)
|
share, vserver, qos_specs, vserver_client)
|
||||||
@ -1075,6 +1065,41 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def validate_provisioning_options_for_share(self, provisioning_options,
|
||||||
|
extra_specs=None,
|
||||||
|
qos_specs=None):
|
||||||
|
"""Checks if provided provisioning options are valid."""
|
||||||
|
adaptive_qos = provisioning_options.get('adaptive_qos_policy_group')
|
||||||
|
replication_type = (extra_specs.get('replication_type')
|
||||||
|
if extra_specs else None)
|
||||||
|
if adaptive_qos and qos_specs:
|
||||||
|
msg = _('Share cannot be provisioned with both qos_specs '
|
||||||
|
'%(qos_specs_string)s and adaptive_qos_policy_group '
|
||||||
|
'%(adaptive_qos_policy_group)s.')
|
||||||
|
qos_specs_string = ""
|
||||||
|
for key in qos_specs:
|
||||||
|
qos_specs_string += key + "=" + str(qos_specs[key]) + " "
|
||||||
|
msg_args = {
|
||||||
|
'adaptive_qos_policy_group':
|
||||||
|
provisioning_options['adaptive_qos_policy_group'],
|
||||||
|
'qos_specs_string': qos_specs_string
|
||||||
|
}
|
||||||
|
raise exception.NetAppException(msg % msg_args)
|
||||||
|
|
||||||
|
if adaptive_qos and replication_type:
|
||||||
|
msg = _("The extra spec 'adaptive_qos_policy_group' is not "
|
||||||
|
"supported by share replication feature.")
|
||||||
|
raise exception.NetAppException(msg)
|
||||||
|
|
||||||
|
# NOTE(dviroel): This validation will need to be updated if newer
|
||||||
|
# versions of ONTAP stop requiring cluster credentials to associate
|
||||||
|
# QoS to volumes.
|
||||||
|
if (adaptive_qos or qos_specs) and not self._have_cluster_creds:
|
||||||
|
msg = _('Share cannot be provisioned with QoS without having '
|
||||||
|
'cluster credentials.')
|
||||||
|
raise exception.NetAppException(msg)
|
||||||
|
|
||||||
def _get_nve_option(self, specs):
|
def _get_nve_option(self, specs):
|
||||||
if 'netapp_flexvol_encryption' in specs:
|
if 'netapp_flexvol_encryption' in specs:
|
||||||
nve = specs['netapp_flexvol_encryption'].lower() == 'true'
|
nve = specs['netapp_flexvol_encryption'].lower() == 'true'
|
||||||
@ -1407,6 +1432,10 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
self._validate_volume_for_manage(volume, vserver_client)
|
self._validate_volume_for_manage(volume, vserver_client)
|
||||||
|
|
||||||
provisioning_options = self._get_provisioning_options(extra_specs)
|
provisioning_options = self._get_provisioning_options(extra_specs)
|
||||||
|
qos_specs = self._get_normalized_qos_specs(extra_specs)
|
||||||
|
self.validate_provisioning_options_for_share(provisioning_options,
|
||||||
|
extra_specs=extra_specs,
|
||||||
|
qos_specs=qos_specs)
|
||||||
|
|
||||||
debug_args = {
|
debug_args = {
|
||||||
'share': share_name,
|
'share': share_name,
|
||||||
@ -2393,6 +2422,14 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
destination_share)
|
destination_share)
|
||||||
self._check_extra_specs_validity(
|
self._check_extra_specs_validity(
|
||||||
destination_share, extra_specs)
|
destination_share, extra_specs)
|
||||||
|
# NOTE(dviroel): Check if the destination share-type has valid
|
||||||
|
# provisioning options.
|
||||||
|
provisioning_options = self._get_provisioning_options(
|
||||||
|
extra_specs)
|
||||||
|
qos_specs = self._get_normalized_qos_specs(extra_specs)
|
||||||
|
self.validate_provisioning_options_for_share(
|
||||||
|
provisioning_options, extra_specs=extra_specs,
|
||||||
|
qos_specs=qos_specs)
|
||||||
|
|
||||||
# NOTE (felipe_rodrigues): NetApp only can migrate within the
|
# NOTE (felipe_rodrigues): NetApp only can migrate within the
|
||||||
# same server, so it does not need to check that the
|
# same server, so it does not need to check that the
|
||||||
@ -2411,6 +2448,10 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
share_volume = self._get_backend_share_name(
|
share_volume = self._get_backend_share_name(
|
||||||
source_share['id'])
|
source_share['id'])
|
||||||
|
|
||||||
|
# NOTE(dviroel): If source and destination vservers are
|
||||||
|
# compatible for volume move, the provisioning option
|
||||||
|
# 'adaptive_qos_policy_group' will also be supported since the
|
||||||
|
# share will remain in the same vserver.
|
||||||
self._check_destination_vserver_for_vol_move(
|
self._check_destination_vserver_for_vol_move(
|
||||||
source_share, source_vserver, destination_share_server)
|
source_share, source_vserver, destination_share_server)
|
||||||
|
|
||||||
|
@ -1318,3 +1318,17 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
|||||||
# Modify volume to match extra specs
|
# Modify volume to match extra specs
|
||||||
dest_client.modify_volume(dest_aggregate, volume_name,
|
dest_client.modify_volume(dest_aggregate, volume_name,
|
||||||
**provisioning_options)
|
**provisioning_options)
|
||||||
|
|
||||||
|
def validate_provisioning_options_for_share(self, provisioning_options,
|
||||||
|
extra_specs=None,
|
||||||
|
qos_specs=None):
|
||||||
|
if provisioning_options.get('adaptive_qos_policy_group') is not None:
|
||||||
|
msg = _("The extra spec 'adaptive_qos_policy_group' is not "
|
||||||
|
"supported by backends configured with "
|
||||||
|
"'driver_handles_share_server' == True mode.")
|
||||||
|
raise exception.NetAppException(msg)
|
||||||
|
|
||||||
|
(super(NetAppCmodeMultiSVMFileStorageLibrary, self)
|
||||||
|
.validate_provisioning_options_for_share(provisioning_options,
|
||||||
|
extra_specs=extra_specs,
|
||||||
|
qos_specs=qos_specs))
|
||||||
|
@ -74,6 +74,7 @@ DELETED_EXPORT_POLICIES = {
|
|||||||
}
|
}
|
||||||
QOS_POLICY_GROUP_NAME = 'fake_qos_policy_group_name'
|
QOS_POLICY_GROUP_NAME = 'fake_qos_policy_group_name'
|
||||||
QOS_MAX_THROUGHPUT = '5000B/s'
|
QOS_MAX_THROUGHPUT = '5000B/s'
|
||||||
|
ADAPTIVE_QOS_POLICY_GROUP_NAME = 'fake_adaptive_qos_policy_group_name'
|
||||||
VSERVER_TYPE_DEFAULT = 'default'
|
VSERVER_TYPE_DEFAULT = 'default'
|
||||||
VSERVER_TYPE_DP_DEST = 'dp_destination'
|
VSERVER_TYPE_DP_DEST = 'dp_destination'
|
||||||
VSERVER_OP_STATE_RUNNING = 'running'
|
VSERVER_OP_STATE_RUNNING = 'running'
|
||||||
|
@ -2844,12 +2844,13 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||||||
{'qos_policy_group_name': fake.QOS_POLICY_GROUP_NAME,
|
{'qos_policy_group_name': fake.QOS_POLICY_GROUP_NAME,
|
||||||
'adaptive_policy_group_name': None},
|
'adaptive_policy_group_name': None},
|
||||||
{'qos_policy_group_name': None,
|
{'qos_policy_group_name': None,
|
||||||
'adaptive_policy_group_name': fake.QOS_POLICY_GROUP_NAME},
|
'adaptive_policy_group_name':
|
||||||
|
fake.ADAPTIVE_QOS_POLICY_GROUP_NAME},
|
||||||
)
|
)
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
def test_create_volume_with_extra_specs(self, qos_policy_group_name,
|
def test_create_volume_with_extra_specs(self, qos_policy_group_name,
|
||||||
adaptive_policy_group_name):
|
adaptive_policy_group_name):
|
||||||
|
self.client.features.add_feature('ADAPTIVE_QOS')
|
||||||
self.mock_object(self.client, 'set_volume_max_files')
|
self.mock_object(self.client, 'set_volume_max_files')
|
||||||
self.mock_object(self.client, 'enable_dedup')
|
self.mock_object(self.client, 'enable_dedup')
|
||||||
self.mock_object(self.client, 'enable_compression')
|
self.mock_object(self.client, 'enable_compression')
|
||||||
@ -3211,8 +3212,12 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||||||
mock_update_volume_efficiency_attributes.assert_called_once_with(
|
mock_update_volume_efficiency_attributes.assert_called_once_with(
|
||||||
fake.SHARE_NAME, False, False)
|
fake.SHARE_NAME, False, False)
|
||||||
|
|
||||||
def test_modify_volume_all_optional_args(self):
|
@ddt.data((fake.QOS_POLICY_GROUP_NAME, None),
|
||||||
|
(None, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME))
|
||||||
|
@ddt.unpack
|
||||||
|
def test_modify_volume_all_optional_args(self, qos_group,
|
||||||
|
adaptive_qos_group):
|
||||||
|
self.client.features.add_feature('ADAPTIVE_QOS')
|
||||||
self.mock_object(self.client, 'send_request')
|
self.mock_object(self.client, 'send_request')
|
||||||
mock_update_volume_efficiency_attributes = self.mock_object(
|
mock_update_volume_efficiency_attributes = self.mock_object(
|
||||||
self.client, 'update_volume_efficiency_attributes')
|
self.client, 'update_volume_efficiency_attributes')
|
||||||
@ -3226,7 +3231,8 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||||||
dedup_enabled=True,
|
dedup_enabled=True,
|
||||||
compression_enabled=False,
|
compression_enabled=False,
|
||||||
max_files=fake.MAX_FILES,
|
max_files=fake.MAX_FILES,
|
||||||
qos_policy_group=fake.QOS_POLICY_GROUP_NAME,
|
qos_policy_group=qos_group,
|
||||||
|
adaptive_qos_policy_group=adaptive_qos_group,
|
||||||
autosize_attributes=fake.VOLUME_AUTOSIZE_ATTRS,
|
autosize_attributes=fake.VOLUME_AUTOSIZE_ATTRS,
|
||||||
hide_snapdir=True)
|
hide_snapdir=True)
|
||||||
|
|
||||||
@ -3254,13 +3260,26 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||||||
'volume-space-attributes': {
|
'volume-space-attributes': {
|
||||||
'space-guarantee': 'none',
|
'space-guarantee': 'none',
|
||||||
},
|
},
|
||||||
'volume-qos-attributes': {
|
|
||||||
'policy-group-name': fake.QOS_POLICY_GROUP_NAME,
|
|
||||||
},
|
|
||||||
'volume-autosize-attributes': fake.VOLUME_AUTOSIZE_ATTRS,
|
'volume-autosize-attributes': fake.VOLUME_AUTOSIZE_ATTRS,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if qos_group:
|
||||||
|
qos_update = {
|
||||||
|
'volume-qos-attributes': {
|
||||||
|
'policy-group-name': qos_group,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
volume_modify_iter_api_args[
|
||||||
|
'attributes']['volume-attributes'].update(qos_update)
|
||||||
|
if adaptive_qos_group:
|
||||||
|
qos_update = {
|
||||||
|
'volume-qos-attributes': {
|
||||||
|
'adaptive-policy-group-name': adaptive_qos_group,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
volume_modify_iter_api_args[
|
||||||
|
'attributes']['volume-attributes'].update(qos_update)
|
||||||
|
|
||||||
self.client.send_request.assert_called_once_with(
|
self.client.send_request.assert_called_once_with(
|
||||||
'volume-modify-iter', volume_modify_iter_api_args)
|
'volume-modify-iter', volume_modify_iter_api_args)
|
||||||
@ -3981,12 +4000,13 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||||||
{'qos_policy_group_name': fake.QOS_POLICY_GROUP_NAME,
|
{'qos_policy_group_name': fake.QOS_POLICY_GROUP_NAME,
|
||||||
'adaptive_qos_policy_group_name': None},
|
'adaptive_qos_policy_group_name': None},
|
||||||
{'qos_policy_group_name': None,
|
{'qos_policy_group_name': None,
|
||||||
'adaptive_qos_policy_group_name': fake.QOS_POLICY_GROUP_NAME},
|
'adaptive_qos_policy_group_name':
|
||||||
|
fake.ADAPTIVE_QOS_POLICY_GROUP_NAME},
|
||||||
)
|
)
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
def test_create_volume_clone(self, qos_policy_group_name,
|
def test_create_volume_clone(self, qos_policy_group_name,
|
||||||
adaptive_qos_policy_group_name):
|
adaptive_qos_policy_group_name):
|
||||||
|
self.client.features.add_feature('ADAPTIVE_QOS')
|
||||||
self.mock_object(self.client, 'send_request')
|
self.mock_object(self.client, 'send_request')
|
||||||
self.mock_object(self.client, 'split_volume_clone')
|
self.mock_object(self.client, 'split_volume_clone')
|
||||||
set_qos_adapt_mock = self.mock_object(
|
set_qos_adapt_mock = self.mock_object(
|
||||||
@ -4012,7 +4032,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||||||
{'qos-policy-group-name': fake.QOS_POLICY_GROUP_NAME})
|
{'qos-policy-group-name': fake.QOS_POLICY_GROUP_NAME})
|
||||||
if adaptive_qos_policy_group_name:
|
if adaptive_qos_policy_group_name:
|
||||||
set_qos_adapt_mock.assert_called_once_with(
|
set_qos_adapt_mock.assert_called_once_with(
|
||||||
fake.SHARE_NAME, fake.QOS_POLICY_GROUP_NAME
|
fake.SHARE_NAME, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME
|
||||||
)
|
)
|
||||||
self.client.send_request.assert_has_calls([
|
self.client.send_request.assert_has_calls([
|
||||||
mock.call('volume-clone-create', volume_clone_create_args)])
|
mock.call('volume-clone-create', volume_clone_create_args)])
|
||||||
|
@ -1409,6 +1409,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
|
|
||||||
qos = True if fake.QOS_EXTRA_SPEC in extra_specs else False
|
qos = True if fake.QOS_EXTRA_SPEC in extra_specs else False
|
||||||
vserver_client = mock.Mock()
|
vserver_client = mock.Mock()
|
||||||
|
self.library._have_cluster_creds = True
|
||||||
mock_get_extra_specs_from_share = self.mock_object(
|
mock_get_extra_specs_from_share = self.mock_object(
|
||||||
share_types, 'get_extra_specs_from_share',
|
share_types, 'get_extra_specs_from_share',
|
||||||
mock.Mock(return_value=extra_specs))
|
mock.Mock(return_value=extra_specs))
|
||||||
@ -2208,6 +2209,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
def test_manage_container_with_qos(self, qos):
|
def test_manage_container_with_qos(self, qos):
|
||||||
|
|
||||||
vserver_client = mock.Mock()
|
vserver_client = mock.Mock()
|
||||||
|
self.library._have_cluster_creds = True
|
||||||
qos_policy_group_name = fake.QOS_POLICY_GROUP_NAME if qos else None
|
qos_policy_group_name = fake.QOS_POLICY_GROUP_NAME if qos else None
|
||||||
extra_specs = fake.EXTRA_SPEC_WITH_QOS if qos else fake.EXTRA_SPEC
|
extra_specs = fake.EXTRA_SPEC_WITH_QOS if qos else fake.EXTRA_SPEC
|
||||||
provisioning_opts = self.library._get_provisioning_options(extra_specs)
|
provisioning_opts = self.library._get_provisioning_options(extra_specs)
|
||||||
@ -4960,6 +4962,34 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
mock_exception_log.assert_called_once()
|
mock_exception_log.assert_called_once()
|
||||||
self.assertFalse(data_motion.get_backend_configuration.called)
|
self.assertFalse(data_motion.get_backend_configuration.called)
|
||||||
|
|
||||||
|
def test_migration_check_compatibility_invalid_qos_configuration(self):
|
||||||
|
self.library._have_cluster_creds = True
|
||||||
|
self.mock_object(self.library, '_get_backend_share_name',
|
||||||
|
mock.Mock(return_value=fake.SHARE_NAME))
|
||||||
|
mock_exception_log = self.mock_object(lib_base.LOG, 'exception')
|
||||||
|
self.mock_object(share_types, 'get_extra_specs_from_share')
|
||||||
|
self.mock_object(self.library, '_check_extra_specs_validity')
|
||||||
|
self.mock_object(
|
||||||
|
self.library, '_get_provisioning_options',
|
||||||
|
mock.Mock(return_value=fake.PROVISIONING_OPTS_WITH_ADAPT_QOS))
|
||||||
|
self.mock_object(self.library, '_get_normalized_qos_specs',
|
||||||
|
mock.Mock(return_value=fake.QOS_NORMALIZED_SPEC))
|
||||||
|
|
||||||
|
migration_compatibility = self.library.migration_check_compatibility(
|
||||||
|
self.context, fake_share.fake_share_instance(),
|
||||||
|
fake_share.fake_share_instance(), share_server=fake.SHARE_SERVER,
|
||||||
|
destination_share_server=None)
|
||||||
|
|
||||||
|
expected_compatibility = {
|
||||||
|
'compatible': False,
|
||||||
|
'writable': False,
|
||||||
|
'nondisruptive': False,
|
||||||
|
'preserve_metadata': False,
|
||||||
|
'preserve_snapshots': False,
|
||||||
|
}
|
||||||
|
self.assertDictMatch(expected_compatibility, migration_compatibility)
|
||||||
|
mock_exception_log.assert_called_once()
|
||||||
|
|
||||||
def test_migration_check_compatibility_destination_not_configured(self):
|
def test_migration_check_compatibility_destination_not_configured(self):
|
||||||
self.library._have_cluster_creds = True
|
self.library._have_cluster_creds = True
|
||||||
self.mock_object(self.library, '_get_backend_share_name',
|
self.mock_object(self.library, '_get_backend_share_name',
|
||||||
@ -4974,6 +5004,10 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
self.mock_object(share_types, 'get_extra_specs_from_share')
|
self.mock_object(share_types, 'get_extra_specs_from_share')
|
||||||
self.mock_object(self.library, '_check_extra_specs_validity')
|
self.mock_object(self.library, '_check_extra_specs_validity')
|
||||||
self.mock_object(self.library, '_check_aggregate_extra_specs_validity')
|
self.mock_object(self.library, '_check_aggregate_extra_specs_validity')
|
||||||
|
self.mock_object(self.library, '_get_provisioning_options')
|
||||||
|
self.mock_object(self.library, '_get_normalized_qos_specs')
|
||||||
|
self.mock_object(self.library,
|
||||||
|
'validate_provisioning_options_for_share')
|
||||||
mock_vserver_compatibility_check = self.mock_object(
|
mock_vserver_compatibility_check = self.mock_object(
|
||||||
self.library, '_check_destination_vserver_for_vol_move')
|
self.library, '_check_destination_vserver_for_vol_move')
|
||||||
self.mock_object(self.library, '_get_dest_flexvol_encryption_value',
|
self.mock_object(self.library, '_get_dest_flexvol_encryption_value',
|
||||||
@ -5012,6 +5046,10 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
self.mock_object(self.library, '_check_aggregate_extra_specs_validity')
|
self.mock_object(self.library, '_check_aggregate_extra_specs_validity')
|
||||||
self.mock_object(self.library, '_get_backend_share_name',
|
self.mock_object(self.library, '_get_backend_share_name',
|
||||||
mock.Mock(return_value=fake.SHARE_NAME))
|
mock.Mock(return_value=fake.SHARE_NAME))
|
||||||
|
self.mock_object(self.library, '_get_provisioning_options')
|
||||||
|
self.mock_object(self.library, '_get_normalized_qos_specs')
|
||||||
|
self.mock_object(self.library,
|
||||||
|
'validate_provisioning_options_for_share')
|
||||||
self.mock_object(data_motion, 'get_backend_configuration')
|
self.mock_object(data_motion, 'get_backend_configuration')
|
||||||
self.mock_object(self.library, '_get_vserver',
|
self.mock_object(self.library, '_get_vserver',
|
||||||
mock.Mock(side_effect=side_effects))
|
mock.Mock(side_effect=side_effects))
|
||||||
@ -5047,6 +5085,10 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
self.mock_object(self.library, '_get_backend_share_name',
|
self.mock_object(self.library, '_get_backend_share_name',
|
||||||
mock.Mock(return_value=fake.SHARE_NAME))
|
mock.Mock(return_value=fake.SHARE_NAME))
|
||||||
self.mock_object(data_motion, 'get_backend_configuration')
|
self.mock_object(data_motion, 'get_backend_configuration')
|
||||||
|
self.mock_object(self.library, '_get_provisioning_options')
|
||||||
|
self.mock_object(self.library, '_get_normalized_qos_specs')
|
||||||
|
self.mock_object(self.library,
|
||||||
|
'validate_provisioning_options_for_share')
|
||||||
mock_exception_log = self.mock_object(lib_base.LOG, 'exception')
|
mock_exception_log = self.mock_object(lib_base.LOG, 'exception')
|
||||||
get_vserver_returns = [
|
get_vserver_returns = [
|
||||||
(fake.VSERVER1, mock.Mock()),
|
(fake.VSERVER1, mock.Mock()),
|
||||||
@ -5084,6 +5126,10 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
self.mock_object(share_types, 'get_extra_specs_from_share')
|
self.mock_object(share_types, 'get_extra_specs_from_share')
|
||||||
self.mock_object(self.library, '_check_extra_specs_validity')
|
self.mock_object(self.library, '_check_extra_specs_validity')
|
||||||
self.mock_object(self.library, '_check_aggregate_extra_specs_validity')
|
self.mock_object(self.library, '_check_aggregate_extra_specs_validity')
|
||||||
|
self.mock_object(self.library, '_get_provisioning_options')
|
||||||
|
self.mock_object(self.library, '_get_normalized_qos_specs')
|
||||||
|
self.mock_object(self.library,
|
||||||
|
'validate_provisioning_options_for_share')
|
||||||
self.mock_object(self.library, '_get_backend_share_name',
|
self.mock_object(self.library, '_get_backend_share_name',
|
||||||
mock.Mock(return_value=fake.SHARE_NAME))
|
mock.Mock(return_value=fake.SHARE_NAME))
|
||||||
mock_exception_log = self.mock_object(lib_base.LOG, 'exception')
|
mock_exception_log = self.mock_object(lib_base.LOG, 'exception')
|
||||||
@ -5136,6 +5182,10 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
mock_move_check = self.mock_object(self.client, 'check_volume_move')
|
mock_move_check = self.mock_object(self.client, 'check_volume_move')
|
||||||
self.mock_object(self.library, '_get_dest_flexvol_encryption_value',
|
self.mock_object(self.library, '_get_dest_flexvol_encryption_value',
|
||||||
mock.Mock(return_value=False))
|
mock.Mock(return_value=False))
|
||||||
|
self.mock_object(self.library, '_get_provisioning_options')
|
||||||
|
self.mock_object(self.library, '_get_normalized_qos_specs')
|
||||||
|
self.mock_object(self.library,
|
||||||
|
'validate_provisioning_options_for_share')
|
||||||
|
|
||||||
migration_compatibility = self.library.migration_check_compatibility(
|
migration_compatibility = self.library.migration_check_compatibility(
|
||||||
self.context, fake_share.fake_share_instance(),
|
self.context, fake_share.fake_share_instance(),
|
||||||
@ -5177,6 +5227,10 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
'_check_extra_specs_validity')
|
'_check_extra_specs_validity')
|
||||||
self.mock_object(self.library,
|
self.mock_object(self.library,
|
||||||
'_check_aggregate_extra_specs_validity')
|
'_check_aggregate_extra_specs_validity')
|
||||||
|
self.mock_object(self.library, '_get_provisioning_options')
|
||||||
|
self.mock_object(self.library, '_get_normalized_qos_specs')
|
||||||
|
self.mock_object(self.library,
|
||||||
|
'validate_provisioning_options_for_share')
|
||||||
|
|
||||||
migration_compatibility = self.library.migration_check_compatibility(
|
migration_compatibility = self.library.migration_check_compatibility(
|
||||||
self.context, fake_share.fake_share_instance(),
|
self.context, fake_share.fake_share_instance(),
|
||||||
@ -5941,3 +5995,30 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
result = self.library._check_capacity_compatibility(pools, thin, size)
|
result = self.library._check_capacity_compatibility(pools, thin, size)
|
||||||
|
|
||||||
self.assertEqual(compatible, result)
|
self.assertEqual(compatible, result)
|
||||||
|
|
||||||
|
@ddt.data({'provisioning_opts': fake.PROVISIONING_OPTS_WITH_ADAPT_QOS,
|
||||||
|
'qos_specs': {fake.QOS_NORMALIZED_SPEC: 3000},
|
||||||
|
'extra_specs': None,
|
||||||
|
'cluster_credentials': True},
|
||||||
|
{'provisioning_opts': fake.PROVISIONING_OPTS_WITH_ADAPT_QOS,
|
||||||
|
'qos_specs': None,
|
||||||
|
'extra_specs': fake.EXTRA_SPEC_WITH_REPLICATION,
|
||||||
|
'cluster_credentials': True},
|
||||||
|
{'provisioning_opts': fake.PROVISIONING_OPTIONS,
|
||||||
|
'qos_specs': {fake.QOS_NORMALIZED_SPEC: 3000},
|
||||||
|
'extra_specs': None,
|
||||||
|
'cluster_credentials': False},
|
||||||
|
{'provisioning_opts': fake.PROVISIONING_OPTS_WITH_ADAPT_QOS,
|
||||||
|
'qos_specs': None,
|
||||||
|
'extra_specs': None,
|
||||||
|
'cluster_credentials': False},)
|
||||||
|
@ddt.unpack
|
||||||
|
def test_validate_provisioning_options_for_share_invalid_params(
|
||||||
|
self, provisioning_opts, qos_specs, extra_specs,
|
||||||
|
cluster_credentials):
|
||||||
|
self.library._have_cluster_creds = cluster_credentials
|
||||||
|
|
||||||
|
self.assertRaises(exception.NetAppException,
|
||||||
|
self.library.validate_provisioning_options_for_share,
|
||||||
|
provisioning_opts, extra_specs=extra_specs,
|
||||||
|
qos_specs=qos_specs)
|
||||||
|
@ -2544,3 +2544,22 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
mock_get_vol_autosize_attrs.assert_called_once_with(fake_share_name)
|
mock_get_vol_autosize_attrs.assert_called_once_with(fake_share_name)
|
||||||
mock_modify_volume.assert_called_once_with(
|
mock_modify_volume.assert_called_once_with(
|
||||||
fake_aggregate, fake_share_name, **fake_provisioning_opts)
|
fake_aggregate, fake_share_name, **fake_provisioning_opts)
|
||||||
|
|
||||||
|
def test_validate_provisioning_options_for_share(self):
|
||||||
|
mock_create_from_snap = self.mock_object(
|
||||||
|
lib_base.NetAppCmodeFileStorageLibrary,
|
||||||
|
'validate_provisioning_options_for_share')
|
||||||
|
|
||||||
|
self.library.validate_provisioning_options_for_share(
|
||||||
|
fake.PROVISIONING_OPTIONS, extra_specs=fake.EXTRA_SPEC,
|
||||||
|
qos_specs=fake.QOS_NORMALIZED_SPEC)
|
||||||
|
|
||||||
|
mock_create_from_snap.assert_called_once_with(
|
||||||
|
fake.PROVISIONING_OPTIONS, extra_specs=fake.EXTRA_SPEC,
|
||||||
|
qos_specs=fake.QOS_NORMALIZED_SPEC)
|
||||||
|
|
||||||
|
def test_validate_provisioning_options_for_share_aqos_not_supported(self):
|
||||||
|
self.assertRaises(
|
||||||
|
exception.NetAppException,
|
||||||
|
self.library.validate_provisioning_options_for_share,
|
||||||
|
fake.PROVISIONING_OPTS_WITH_ADAPT_QOS, qos_specs=None)
|
||||||
|
@ -194,6 +194,11 @@ EXTRA_SPEC = {
|
|||||||
'netapp:adaptive_qos_policy_group': None,
|
'netapp:adaptive_qos_policy_group': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXTRA_SPEC_WITH_REPLICATION = copy.copy(EXTRA_SPEC)
|
||||||
|
EXTRA_SPEC_WITH_REPLICATION.update({
|
||||||
|
'replication_type': 'dr'
|
||||||
|
})
|
||||||
|
|
||||||
NFS_CONFIG_DEFAULT = {
|
NFS_CONFIG_DEFAULT = {
|
||||||
'tcp-max-xfer-size': 65536,
|
'tcp-max-xfer-size': 65536,
|
||||||
'udp-max-xfer-size': 32768,
|
'udp-max-xfer-size': 32768,
|
||||||
|
@ -13,4 +13,6 @@ features:
|
|||||||
configuration in order to use QoS in clustered ONTAP. Other notes:
|
configuration in order to use QoS in clustered ONTAP. Other notes:
|
||||||
|
|
||||||
- This only works for backends without share server management.
|
- This only works for backends without share server management.
|
||||||
- This does not work for share replicas or share migration.
|
- This does not work for share replicas or can fail when creating share
|
||||||
|
from snapshot across backends, if the destination backend does not have
|
||||||
|
the pre-created "adaptive_qos_policy_group".
|
||||||
|
Loading…
Reference in New Issue
Block a user