diff --git a/doc/source/admin/share_back_ends_feature_support_mapping.rst b/doc/source/admin/share_back_ends_feature_support_mapping.rst
index bc16a14cc0..d929afdf4a 100644
--- a/doc/source/admin/share_back_ends_feature_support_mapping.rst
+++ b/doc/source/admin/share_back_ends_feature_support_mapping.rst
@@ -272,7 +272,7 @@ More information: :ref:`capabilities_and_extra_specs`
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
| MapRFS | \- | N | \- | \- | \- | N | \- | O | \- | \- | P | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
-| QNAP | \- | O | \- | \- | O | \- | \- | O | \- | \- | P | \- |
+| QNAP | \- | O | Q | Q | O | Q | \- | O | \- | \- | P | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
.. note::
diff --git a/manila/share/drivers/qnap/api.py b/manila/share/drivers/qnap/api.py
index 8a8a355e43..46c1e39686 100644
--- a/manila/share/drivers/qnap/api.py
+++ b/manila/share/drivers/qnap/api.py
@@ -184,7 +184,8 @@ class QnapAPIExecutor(object):
return sanitized_params
@_connection_checker
- def create_share(self, share, pool_name, create_share_name, share_proto):
+ def create_share(self, share, pool_name, create_share_name,
+ share_proto, **kwargs):
"""Create share."""
LOG.debug('create_share_name: %s', create_share_name)
@@ -194,10 +195,12 @@ class QnapAPIExecutor(object):
'vol_name': create_share_name,
'vol_size': six.text_type(share['size']) + 'GB',
'threshold': '80',
- 'dedup': 'off',
- 'compression': '1',
- 'thin_pro': '0',
- 'cache': '0',
+ 'dedup': ('sha512'
+ if kwargs['qnap_deduplication'] is True
+ else 'off'),
+ 'compression': '1' if kwargs['qnap_compression'] is True else '0',
+ 'thin_pro': '1' if kwargs['qnap_thin_provision'] is True else '0',
+ 'cache': '1' if kwargs['qnap_ssd_cache'] is True else '0',
'cifs_enable': '0' if share_proto == 'NFS' else '1',
'nfs_enable': '0' if share_proto == 'CIFS' else '1',
'afp_enable': '0',
@@ -497,10 +500,10 @@ class QnapAPIExecutor(object):
'sharename': share_dict['sharename'],
'old_sharename': share_dict['old_sharename'],
'vol_size': six.text_type(share_dict['new_size']) + 'GB',
- 'dedup': '0',
- 'compression': '1',
- 'thin_pro': '0',
- 'cache': '0',
+ 'dedup': 'sha512' if share_dict['deduplication'] else 'off',
+ 'compression': '1' if share_dict['compression'] else '0',
+ 'thin_pro': '1' if share_dict['thin_provision'] else '0',
+ 'cache': '1' if share_dict['ssd_cache'] else '0',
'cifs_enable': '1' if share_dict['share_proto'] == 'CIFS' else '0',
'nfs_enable': '1' if share_dict['share_proto'] == 'NFS' else '0',
'afp_enable': '0',
diff --git a/manila/share/drivers/qnap/qnap.py b/manila/share/drivers/qnap/qnap.py
index ec4ab1b3eb..1a67a0eb4d 100644
--- a/manila/share/drivers/qnap/qnap.py
+++ b/manila/share/drivers/qnap/qnap.py
@@ -31,6 +31,7 @@ from manila.i18n import _
from manila import share
from manila.share import driver
from manila.share.drivers.qnap import api
+from manila.share import share_types
from manila import utils
LOG = logging.getLogger(__name__)
@@ -66,9 +67,11 @@ class QnapShareDriver(driver.ShareDriver):
1.0.1 - Add support for QES fw 1.1.4.
1.0.2 - Fix bug #1736370, QNAP Manila driver: Access rule setting is
override by the another access rule.
+ 1.0.3 - Add supports for Thin Provisioning, SSD Cache, Deduplication
+ and Compression.
"""
- DRIVER_VERSION = '1.0.2'
+ DRIVER_VERSION = '1.0.3'
def __init__(self, *args, **kwargs):
"""Initialize QnapShareDriver."""
@@ -254,6 +257,10 @@ class QnapShareDriver(driver.ShareDriver):
"allocated_capacity_gb": alloc_capacity_gb,
"reserved_percentage": reserved_percentage,
"qos": False,
+ "dedupe": [True, False],
+ "compression": [True, False],
+ "thin_provisioning": [True, False],
+ "qnap_ssd_cache": [True, False]
}
data = {
@@ -276,6 +283,28 @@ class QnapShareDriver(driver.ShareDriver):
def create_share(self, context, share, share_server=None):
"""Create a new share."""
LOG.debug('share: %s', share.__dict__)
+ extra_specs = share_types.get_extra_specs_from_share(share)
+ LOG.debug('extra_specs: %s', extra_specs)
+ qnap_thin_provision = share_types.parse_boolean_extra_spec(
+ 'thin_provisioning', extra_specs.get("thin_provisioning") or
+ extra_specs.get('capabilities:thin_provisioning') or 'true')
+ qnap_compression = share_types.parse_boolean_extra_spec(
+ 'compression', extra_specs.get("compression") or
+ extra_specs.get('capabilities:compression') or 'true')
+ qnap_deduplication = share_types.parse_boolean_extra_spec(
+ 'dedupe', extra_specs.get("dedupe") or
+ extra_specs.get('capabilities:dedupe') or 'false')
+ qnap_ssd_cache = share_types.parse_boolean_extra_spec(
+ 'qnap_ssd_cache', extra_specs.get("qnap_ssd_cache") or
+ extra_specs.get("capabilities:qnap_ssd_cache") or 'false')
+ LOG.debug('qnap_thin_provision: %(qnap_thin_provision)s '
+ 'qnap_compression: %(qnap_compression)s '
+ 'qnap_deduplication: %(qnap_deduplication)s '
+ 'qnap_ssd_cache: %(qnap_ssd_cache)s',
+ {'qnap_thin_provision': qnap_thin_provision,
+ 'qnap_compression': qnap_compression,
+ 'qnap_deduplication': qnap_deduplication,
+ 'qnap_ssd_cache': qnap_ssd_cache})
share_proto = share['share_proto']
@@ -293,11 +322,19 @@ class QnapShareDriver(driver.ShareDriver):
LOG.error(msg)
raise exception.ShareBackendException(msg=msg)
+ if (qnap_deduplication and not qnap_thin_provision):
+ msg = _("Dedupe cannot be enabled without thin_provisioning.")
+ LOG.debug('Dedupe cannot be enabled without thin_provisioning.')
+ raise exception.InvalidExtraSpec(reason=msg)
self.api_executor.create_share(
share,
self.configuration.qnap_poolname,
create_share_name,
- share_proto)
+ share_proto,
+ qnap_thin_provision=qnap_thin_provision,
+ qnap_compression=qnap_compression,
+ qnap_deduplication=qnap_deduplication,
+ qnap_ssd_cache=qnap_ssd_cache)
created_share = self._get_share_info(create_share_name)
volID = created_share.find('vol_no').text
# Use private_storage to record volume ID and Name created in the NAS.
@@ -306,7 +343,11 @@ class QnapShareDriver(driver.ShareDriver):
{'volID': volID,
'create_share_name': create_share_name})
_metadata = {'volID': volID,
- 'volName': create_share_name}
+ 'volName': create_share_name,
+ 'thin_provision': qnap_thin_provision,
+ 'compression': qnap_compression,
+ 'deduplication': qnap_deduplication,
+ 'ssd_cache': qnap_ssd_cache}
self.private_storage.update(share['id'], _metadata)
return self._get_location_path(create_share_name,
@@ -365,11 +406,27 @@ class QnapShareDriver(driver.ShareDriver):
LOG.debug('Share %s does not exist', share['id'])
raise exception.ShareResourceNotFound(share_id=share['id'])
LOG.debug('volName: %s', volName)
-
+ thin_provision = self.private_storage.get(
+ share['id'], 'thin_provision')
+ compression = self.private_storage.get(share['id'], 'compression')
+ deduplication = self.private_storage.get(share['id'], 'deduplication')
+ ssd_cache = self.private_storage.get(share['id'], 'ssd_cache')
+ LOG.debug('thin_provision: %(thin_provision)s '
+ 'compression: %(compression)s '
+ 'deduplication: %(deduplication)s '
+ 'ssd_cache: %(ssd_cache)s',
+ {'thin_provision': thin_provision,
+ 'compression': compression,
+ 'deduplication': deduplication,
+ 'ssd_cache': ssd_cache})
share_dict = {
'sharename': volName,
'old_sharename': volName,
'new_size': new_size,
+ 'thin_provision': thin_provision == 'True',
+ 'compression': compression == 'True',
+ 'deduplication': deduplication == 'True',
+ 'ssd_cache': ssd_cache == 'True',
'share_proto': share['share_proto']
}
self.api_executor.edit_share(share_dict)
@@ -492,11 +549,32 @@ class QnapShareDriver(driver.ShareDriver):
context, snapshot['share_instance']['share_id'])
LOG.debug('snap_share[size]: %s', snap_share['size'])
+ thin_provision = self.private_storage.get(
+ snapshot['share_instance_id'], 'thin_provision')
+ compression = self.private_storage.get(
+ snapshot['share_instance_id'], 'compression')
+ deduplication = self.private_storage.get(
+ snapshot['share_instance_id'], 'deduplication')
+ ssd_cache = self.private_storage.get(
+ snapshot['share_instance_id'], 'ssd_cache')
+ LOG.debug('thin_provision: %(thin_provision)s '
+ 'compression: %(compression)s '
+ 'deduplication: %(deduplication)s '
+ 'ssd_cache: %(ssd_cache)s',
+ {'thin_provision': thin_provision,
+ 'compression': compression,
+ 'deduplication': deduplication,
+ 'ssd_cache': ssd_cache})
+
if (share['size'] > snap_share['size']):
share_dict = {
'sharename': create_share_name,
'old_sharename': create_share_name,
'new_size': share['size'],
+ 'thin_provision': thin_provision == 'True',
+ 'compression': compression == 'True',
+ 'deduplication': deduplication == 'True',
+ 'ssd_cache': ssd_cache == 'True',
'share_proto': share['share_proto']
}
self.api_executor.edit_share(share_dict)
@@ -505,6 +583,10 @@ class QnapShareDriver(driver.ShareDriver):
_metadata = {
'volID': create_volID,
'volName': create_share_name,
+ 'thin_provision': thin_provision,
+ 'compression': compression,
+ 'deduplication': deduplication,
+ 'ssd_cache': ssd_cache
}
self.private_storage.update(share['id'], _metadata)
@@ -726,25 +808,62 @@ class QnapShareDriver(driver.ShareDriver):
"backend.") % share['id']
raise exception.ManageInvalidShare(reason=msg)
- _metadata = {}
+ extra_specs = share_types.get_extra_specs_from_share(share)
+ qnap_thin_provision = share_types.parse_boolean_extra_spec(
+ 'thin_provisioning', extra_specs.get("thin_provisioning") or
+ extra_specs.get('capabilities:thin_provisioning') or 'true')
+ qnap_compression = share_types.parse_boolean_extra_spec(
+ 'compression', extra_specs.get("compression") or
+ extra_specs.get('capabilities:compression') or 'true')
+ qnap_deduplication = share_types.parse_boolean_extra_spec(
+ 'dedupe', extra_specs.get("dedupe") or
+ extra_specs.get('capabilities:dedupe') or 'false')
+ qnap_ssd_cache = share_types.parse_boolean_extra_spec(
+ 'qnap_ssd_cache', extra_specs.get("qnap_ssd_cache") or
+ extra_specs.get("capabilities:qnap_ssd_cache") or 'false')
+ LOG.debug('qnap_thin_provision: %(qnap_thin_provision)s '
+ 'qnap_compression: %(qnap_compression)s '
+ 'qnap_deduplication: %(qnap_deduplication)s '
+ 'qnap_ssd_cache: %(qnap_ssd_cache)s',
+ {'qnap_thin_provision': qnap_thin_provision,
+ 'qnap_compression': qnap_compression,
+ 'qnap_deduplication': qnap_deduplication,
+ 'qnap_ssd_cache': qnap_ssd_cache})
+ if (qnap_deduplication and not qnap_thin_provision):
+ msg = _("Dedupe cannot be enabled without thin_provisioning.")
+ LOG.debug('Dedupe cannot be enabled without thin_provisioning.')
+ raise exception.InvalidExtraSpec(reason=msg)
+
vol_no = existing_share.find('vol_no').text
+ vol = self.api_executor.get_specific_volinfo(vol_no)
+ vol_size_gb = int(vol.find('size').text) / units.Gi
+
+ share_dict = {
+ 'sharename': share_name,
+ 'old_sharename': share_name,
+ 'new_size': vol_size_gb,
+ 'thin_provision': qnap_thin_provision,
+ 'compression': qnap_compression,
+ 'deduplication': qnap_deduplication,
+ 'ssd_cache': qnap_ssd_cache,
+ 'share_proto': share['share_proto']
+ }
+ self.api_executor.edit_share(share_dict)
+
+ _metadata = {}
_metadata['volID'] = vol_no
_metadata['volName'] = share_name
+ _metadata['thin_provision'] = qnap_thin_provision
+ _metadata['compression'] = qnap_compression
+ _metadata['deduplication'] = qnap_deduplication
+ _metadata['ssd_cache'] = qnap_ssd_cache
self.private_storage.update(share['id'], _metadata)
- # Test to get value from private_storage.
- volID = self.private_storage.get(share['id'], 'volID')
- LOG.debug('volID: %s', volID)
- volName = self.private_storage.get(share['id'], 'volName')
- LOG.debug('volName: %s', volName)
-
LOG.info("Share %(shr_path)s was successfully managed with ID "
"%(shr_id)s.",
{'shr_path': share['export_locations'][0]['path'],
'shr_id': share['id']})
- vol = self.api_executor.get_specific_volinfo(vol_no)
- vol_size_gb = int(vol.find('size').text) / units.Gi
export_locations = self._get_location_path(
share_name,
share['share_proto'],
diff --git a/manila/tests/share/drivers/qnap/fakes.py b/manila/tests/share/drivers/qnap/fakes.py
index 90fa364136..f9d4a2f2fa 100644
--- a/manila/tests/share/drivers/qnap/fakes.py
+++ b/manila/tests/share/drivers/qnap/fakes.py
@@ -138,6 +138,10 @@ FAKE_RES_DETAIL_DATA_VOLUME_INFO = """
fakeMountPath
+
+
+
+
@@ -325,7 +329,8 @@ class SnapshotClass(object):
'id': 'fakeSnapshotId',
'share': {'share_id': 'fakeShareId', 'id': 'fakeId'},
'share_instance': {'share_id': 'fakeShareId', 'id': 'fakeId'},
- 'size': self.size
+ 'size': self.size,
+ 'share_instance_id': 'fakeShareId'
}[arg]
def __setitem__(self, key, value):
diff --git a/manila/tests/share/drivers/qnap/test_api.py b/manila/tests/share/drivers/qnap/test_api.py
index 19c404a86c..e19a00c047 100644
--- a/manila/tests/share/drivers/qnap/test_api.py
+++ b/manila/tests/share/drivers/qnap/test_api.py
@@ -120,7 +120,11 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
self.share,
'Storage Pool 1',
fake_name,
- 'NFS')
+ 'NFS',
+ qnap_deduplication=False,
+ qnap_compression=True,
+ qnap_thin_provision=True,
+ qnap_ssd_cache=False)
fake_params = {
'wiz_func': 'share_create',
@@ -130,7 +134,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
'threshold': '80',
'dedup': 'off',
'compression': '1',
- 'thin_pro': '0',
+ 'thin_pro': '1',
'cache': '0',
'cifs_enable': '0',
'nfs_enable': '1',
@@ -457,6 +461,10 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
"sharename": 'fakeVolId',
"old_sharename": 'fakeVolId',
"new_size": 100,
+ "deduplication": False,
+ "compression": True,
+ "thin_provision": True,
+ "ssd_cache": False,
"share_proto": "NFS"
}
self.driver.api_executor.edit_share(
@@ -468,9 +476,9 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
'sharename': 'fakeVolId',
'old_sharename': 'fakeVolId',
'vol_size': '100GB',
- 'dedup': '0',
+ 'dedup': 'off',
'compression': '1',
- 'thin_pro': '0',
+ 'thin_pro': '1',
'cache': '0',
'cifs_enable': '0',
'nfs_enable': '1',
@@ -736,7 +744,11 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
share=self.share,
pool_name='Storage Pool 1',
create_share_name='fake_share_name',
- share_proto='NFS')
+ share_proto='NFS',
+ qnap_deduplication=False,
+ qnap_compression=True,
+ qnap_thin_provision=True,
+ qnap_ssd_cache=False)
@ddt.unpack
@ddt.data(['self.driver.api_executor.get_share_info',
@@ -803,6 +815,10 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
{'share_dict': {"sharename": 'fakeVolId',
"old_sharename": 'fakeVolId',
"new_size": 100,
+ "deduplication": False,
+ "compression": True,
+ "thin_provision": False,
+ "ssd_cache": False,
"share_proto": "NFS"}},
fakes.FakeEsResCodeNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
@@ -810,6 +826,10 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
{'share_dict': {"sharename": 'fakeVolId',
"old_sharename": 'fakeVolId',
"new_size": 100,
+ "deduplication": False,
+ "compression": True,
+ "thin_provision": False,
+ "ssd_cache": False,
"share_proto": "NFS"}},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
diff --git a/manila/tests/share/drivers/qnap/test_qnap.py b/manila/tests/share/drivers/qnap/test_qnap.py
index e5a861fc4f..8e5974a718 100644
--- a/manila/tests/share/drivers/qnap/test_qnap.py
+++ b/manila/tests/share/drivers/qnap/test_qnap.py
@@ -29,6 +29,7 @@ from eventlet import greenthread
from manila import exception
from manila.share.drivers.qnap import api
from manila.share.drivers.qnap import qnap
+from manila.share import share_types
from manila import test
from manila.tests import fake_share
from manila.tests.share.drivers.qnap import fakes
@@ -296,12 +297,72 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
return hosts
+ @ddt.data({
+ 'fake_extra_spec': {},
+ 'expect_extra_spec': {
+ 'qnap_thin_provision': True,
+ 'qnap_compression': True,
+ 'qnap_deduplication': False,
+ 'qnap_ssd_cache': False
+ }
+ }, {
+ 'fake_extra_spec': {
+ 'thin_provisioning': u'true',
+ 'compression': u'true',
+ 'qnap_ssd_cache': u'true'
+ },
+ 'expect_extra_spec': {
+ 'qnap_thin_provision': True,
+ 'qnap_compression': True,
+ 'qnap_deduplication': False,
+ 'qnap_ssd_cache': True
+ }
+ }, {
+ 'fake_extra_spec': {
+ 'thin_provisioning': u' False',
+ 'compression': u' True',
+ 'qnap_ssd_cache': u' True'
+ },
+ 'expect_extra_spec': {
+ 'qnap_thin_provision': False,
+ 'qnap_compression': True,
+ 'qnap_deduplication': False,
+ 'qnap_ssd_cache': True
+ }
+ }, {
+ 'fake_extra_spec': {
+ 'thin_provisioning': u'true',
+ 'dedupe': u' True',
+ 'qnap_ssd_cache': u'False'
+ },
+ 'expect_extra_spec': {
+ 'qnap_thin_provision': True,
+ 'qnap_compression': True,
+ 'qnap_deduplication': True,
+ 'qnap_ssd_cache': False
+ }
+ }, {
+ 'fake_extra_spec': {
+ 'thin_provisioning': u' False',
+ 'compression': u'false',
+ 'dedupe': u' False',
+ 'qnap_ssd_cache': u' False'
+ },
+ 'expect_extra_spec': {
+ 'qnap_thin_provision': False,
+ 'qnap_compression': False,
+ 'qnap_deduplication': False,
+ 'qnap_ssd_cache': False
+ }
+ })
+ @ddt.unpack
@mock.patch.object(qnap.QnapShareDriver, '_get_location_path')
@mock.patch.object(qnap.QnapShareDriver, '_gen_random_name')
def test_create_share_positive(
self,
mock_gen_random_name,
- mock_get_location_path):
+ mock_get_location_path,
+ fake_extra_spec, expect_extra_spec):
"""Test create share."""
mock_api_executor = qnap.QnapShareDriver._create_api_executor
mock_api_executor.return_value.get_share_info.side_effect = [
@@ -315,6 +376,8 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage)
+ self.mock_object(share_types, 'get_extra_specs_from_share',
+ mock.Mock(return_value=fake_extra_spec))
self.driver.create_share('context', self.share)
mock_api_return = mock_api_executor.return_value
@@ -328,7 +391,8 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
self.share,
self.driver.configuration.qnap_poolname,
'fakeShareName',
- 'NFS')
+ 'NFS',
+ **expect_extra_spec)
mock_get_location_path.assert_called_once_with(
'fakeShareName', 'NFS', '1.2.3.4', 'fakeNo')
@@ -349,6 +413,8 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage)
+ self.mock_object(share_types, 'get_extra_specs_from_share',
+ mock.Mock(return_value={}))
self.assertRaises(
exception.ShareBackendException,
@@ -373,6 +439,8 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage)
+ self.mock_object(share_types, 'get_extra_specs_from_share',
+ mock.Mock(return_value={}))
self.assertRaises(
exception.ShareBackendException,
@@ -380,6 +448,34 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
context='context',
share=self.share)
+ @mock.patch.object(qnap.QnapShareDriver, '_get_location_path')
+ @mock.patch.object(qnap.QnapShareDriver, '_gen_random_name')
+ def test_create_share_negative_configutarion(
+ self,
+ mock_gen_random_name,
+ mock_get_location_path):
+ """Test create share."""
+ mock_api_executor = qnap.QnapShareDriver._create_api_executor
+ mock_api_executor.return_value.get_share_info.side_effect = [
+ None, self.get_share_info_return_value()]
+ mock_gen_random_name.return_value = 'fakeShareName'
+ mock_get_location_path.return_value = None
+ mock_private_storage = mock.Mock()
+
+ self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
+ 'qnapadmin', 'Storage Pool 1',
+ private_storage=mock_private_storage)
+ self.mock_object(share_types, 'get_extra_specs_from_share',
+ mock.Mock(return_value={
+ 'dedupe': 'true',
+ 'thin_provisioning': 'false'}))
+
+ self.assertRaises(
+ exception.InvalidExtraSpec,
+ self.driver.create_share,
+ context='context',
+ share=self.share)
+
def test_delete_share_positive(self):
"""Test delete share with fake_share."""
mock_api_executor = qnap.QnapShareDriver._create_api_executor
@@ -437,7 +533,12 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
self.get_share_info_return_value())
mock_api_executor.return_value.edit_share.return_value = None
mock_private_storage = mock.Mock()
- mock_private_storage.get.return_value = 'fakeVolName'
+ mock_private_storage.get.side_effect = [
+ 'fakeVolName',
+ 'True',
+ 'True',
+ 'False',
+ 'False']
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1',
@@ -448,6 +549,10 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
'sharename': 'fakeVolName',
'old_sharename': 'fakeVolName',
'new_size': 100,
+ 'thin_provision': True,
+ 'compression': True,
+ 'deduplication': False,
+ 'ssd_cache': False,
'share_proto': 'NFS'
}
mock_api_executor.return_value.edit_share.assert_called_once_with(
@@ -611,7 +716,12 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
mock_api_executor.return_value.get_share_info.side_effect = [
None, self.get_share_info_return_value()]
mock_private_storage = mock.Mock()
- mock_private_storage.get.return_value = 'fakeVolName'
+ mock_private_storage.get.side_effect = [
+ 'True',
+ 'True',
+ 'False',
+ 'False',
+ 'fakeVolName']
mock_share_api.return_value.get.return_value = {'size': 5}
mock_api_executor.return_value.edit_share.return_value = (
None)
@@ -637,6 +747,10 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
'sharename': 'fakeShareName',
'old_sharename': 'fakeShareName',
'new_size': 10,
+ 'thin_provision': True,
+ 'compression': True,
+ 'deduplication': False,
+ 'ssd_cache': False,
'share_proto': 'NFS'
}
mock_api_return.edit_share.assert_called_once_with(
@@ -816,6 +930,8 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage)
+ self.mock_object(share_types, 'get_extra_specs_from_share',
+ mock.Mock(return_value={}))
self.driver.manage_existing(self.share, 'driver_options')
mock_api_return = mock_api_executor.return_value
@@ -826,6 +942,39 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
mock_get_location_path.assert_called_once_with(
'fakeShareName', 'NFS', '1.2.3.4', 'fakeNo')
+ @mock.patch.object(qnap.QnapShareDriver, '_get_location_path')
+ def test_manage_existing_nfs_negative_configutarion(
+ self,
+ mock_get_location_path):
+ """Test manage existing."""
+ mock_api_executor = qnap.QnapShareDriver._create_api_executor
+ mock_api_executor.return_value.get_share_info.return_value = (
+ self.get_share_info_return_value())
+ mock_private_storage = mock.Mock()
+ mock_private_storage.update.return_value = None
+ mock_private_storage.get.side_effect = [
+ 'fakeVolId',
+ 'fakeVolName']
+ mock_api_executor.return_value.get_specific_volinfo.return_value = (
+ self.get_specific_volinfo_return_value())
+ mock_api_executor.return_value.get_share_info.return_value = (
+ self.get_share_info_return_value())
+ mock_get_location_path.return_value = None
+
+ self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
+ 'qnapadmin', 'Storage Pool 1',
+ private_storage=mock_private_storage)
+ self.mock_object(share_types, 'get_extra_specs_from_share',
+ mock.Mock(return_value={
+ 'dedupe': 'true',
+ 'thin_provisioning': 'false'}))
+
+ self.assertRaises(
+ exception.InvalidExtraSpec,
+ self.driver.manage_existing,
+ share=self.share,
+ driver_options='driver_options')
+
def test_manage_invalid_protocol(self):
"""Test manage existing."""
share = fake_share.fake_share(
diff --git a/releasenotes/notes/qnap-enhance-support-53848fda525b7ea4.yaml b/releasenotes/notes/qnap-enhance-support-53848fda525b7ea4.yaml
new file mode 100644
index 0000000000..528424ceee
--- /dev/null
+++ b/releasenotes/notes/qnap-enhance-support-53848fda525b7ea4.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Added enhanced support to the QNAP Manila driver, including
+ ``Thin Provisioning``, ``SSD Cache``, ``Deduplication``
+ and ``Compression``.