Add support for enhanced features to the QNAP Manila driver

This adds enhanced supports to the QNAP Manila driver:
 - Thin Provisioning
 - SSD Cache
 - Deduplication
 - Compression

Change-Id: I0c92ecf6ac55e2f6fbf1d41132e97fa2d40c3ebd
Implements: blueprint qnap-enhance-support
This commit is contained in:
Chris Yang 2017-10-03 15:05:21 +08:00
parent 098546fbf4
commit 487aa691fd
7 changed files with 335 additions and 33 deletions

View File

@ -272,7 +272,7 @@ More information: :ref:`capabilities_and_extra_specs`
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
| MapRFS | \- | N | \- | \- | \- | N | \- | O | \- | \- | P | \- | | MapRFS | \- | N | \- | \- | \- | N | \- | O | \- | \- | P | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
| QNAP | \- | O | \- | \- | O | \- | \- | O | \- | \- | P | \- | | QNAP | \- | O | Q | Q | O | Q | \- | O | \- | \- | P | \- |
+----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+ +----------------------------------------+-----------+------------+--------+-------------+-------------------+--------------------+-----+----------------------------+--------------------+--------------------+--------------+--------------+
.. note:: .. note::

View File

@ -184,7 +184,8 @@ class QnapAPIExecutor(object):
return sanitized_params return sanitized_params
@_connection_checker @_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.""" """Create share."""
LOG.debug('create_share_name: %s', create_share_name) LOG.debug('create_share_name: %s', create_share_name)
@ -194,10 +195,12 @@ class QnapAPIExecutor(object):
'vol_name': create_share_name, 'vol_name': create_share_name,
'vol_size': six.text_type(share['size']) + 'GB', 'vol_size': six.text_type(share['size']) + 'GB',
'threshold': '80', 'threshold': '80',
'dedup': 'off', 'dedup': ('sha512'
'compression': '1', if kwargs['qnap_deduplication'] is True
'thin_pro': '0', else 'off'),
'cache': '0', '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', 'cifs_enable': '0' if share_proto == 'NFS' else '1',
'nfs_enable': '0' if share_proto == 'CIFS' else '1', 'nfs_enable': '0' if share_proto == 'CIFS' else '1',
'afp_enable': '0', 'afp_enable': '0',
@ -497,10 +500,10 @@ class QnapAPIExecutor(object):
'sharename': share_dict['sharename'], 'sharename': share_dict['sharename'],
'old_sharename': share_dict['old_sharename'], 'old_sharename': share_dict['old_sharename'],
'vol_size': six.text_type(share_dict['new_size']) + 'GB', 'vol_size': six.text_type(share_dict['new_size']) + 'GB',
'dedup': '0', 'dedup': 'sha512' if share_dict['deduplication'] else 'off',
'compression': '1', 'compression': '1' if share_dict['compression'] else '0',
'thin_pro': '0', 'thin_pro': '1' if share_dict['thin_provision'] else '0',
'cache': '0', 'cache': '1' if share_dict['ssd_cache'] else '0',
'cifs_enable': '1' if share_dict['share_proto'] == 'CIFS' else '0', 'cifs_enable': '1' if share_dict['share_proto'] == 'CIFS' else '0',
'nfs_enable': '1' if share_dict['share_proto'] == 'NFS' else '0', 'nfs_enable': '1' if share_dict['share_proto'] == 'NFS' else '0',
'afp_enable': '0', 'afp_enable': '0',

View File

@ -31,6 +31,7 @@ from manila.i18n import _
from manila import share from manila import share
from manila.share import driver from manila.share import driver
from manila.share.drivers.qnap import api from manila.share.drivers.qnap import api
from manila.share import share_types
from manila import utils from manila import utils
LOG = logging.getLogger(__name__) 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.1 - Add support for QES fw 1.1.4.
1.0.2 - Fix bug #1736370, QNAP Manila driver: Access rule setting is 1.0.2 - Fix bug #1736370, QNAP Manila driver: Access rule setting is
override by the another access rule. 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): def __init__(self, *args, **kwargs):
"""Initialize QnapShareDriver.""" """Initialize QnapShareDriver."""
@ -254,6 +257,10 @@ class QnapShareDriver(driver.ShareDriver):
"allocated_capacity_gb": alloc_capacity_gb, "allocated_capacity_gb": alloc_capacity_gb,
"reserved_percentage": reserved_percentage, "reserved_percentage": reserved_percentage,
"qos": False, "qos": False,
"dedupe": [True, False],
"compression": [True, False],
"thin_provisioning": [True, False],
"qnap_ssd_cache": [True, False]
} }
data = { data = {
@ -276,6 +283,28 @@ class QnapShareDriver(driver.ShareDriver):
def create_share(self, context, share, share_server=None): def create_share(self, context, share, share_server=None):
"""Create a new share.""" """Create a new share."""
LOG.debug('share: %s', share.__dict__) 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'] share_proto = share['share_proto']
@ -293,11 +322,19 @@ class QnapShareDriver(driver.ShareDriver):
LOG.error(msg) LOG.error(msg)
raise exception.ShareBackendException(msg=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( self.api_executor.create_share(
share, share,
self.configuration.qnap_poolname, self.configuration.qnap_poolname,
create_share_name, 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) created_share = self._get_share_info(create_share_name)
volID = created_share.find('vol_no').text volID = created_share.find('vol_no').text
# Use private_storage to record volume ID and Name created in the NAS. # Use private_storage to record volume ID and Name created in the NAS.
@ -306,7 +343,11 @@ class QnapShareDriver(driver.ShareDriver):
{'volID': volID, {'volID': volID,
'create_share_name': create_share_name}) 'create_share_name': create_share_name})
_metadata = {'volID': volID, _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) self.private_storage.update(share['id'], _metadata)
return self._get_location_path(create_share_name, 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']) LOG.debug('Share %s does not exist', share['id'])
raise exception.ShareResourceNotFound(share_id=share['id']) raise exception.ShareResourceNotFound(share_id=share['id'])
LOG.debug('volName: %s', volName) 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 = { share_dict = {
'sharename': volName, 'sharename': volName,
'old_sharename': volName, 'old_sharename': volName,
'new_size': new_size, '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'] 'share_proto': share['share_proto']
} }
self.api_executor.edit_share(share_dict) self.api_executor.edit_share(share_dict)
@ -492,11 +549,32 @@ class QnapShareDriver(driver.ShareDriver):
context, snapshot['share_instance']['share_id']) context, snapshot['share_instance']['share_id'])
LOG.debug('snap_share[size]: %s', snap_share['size']) 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']): if (share['size'] > snap_share['size']):
share_dict = { share_dict = {
'sharename': create_share_name, 'sharename': create_share_name,
'old_sharename': create_share_name, 'old_sharename': create_share_name,
'new_size': share['size'], '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'] 'share_proto': share['share_proto']
} }
self.api_executor.edit_share(share_dict) self.api_executor.edit_share(share_dict)
@ -505,6 +583,10 @@ class QnapShareDriver(driver.ShareDriver):
_metadata = { _metadata = {
'volID': create_volID, 'volID': create_volID,
'volName': create_share_name, 'volName': create_share_name,
'thin_provision': thin_provision,
'compression': compression,
'deduplication': deduplication,
'ssd_cache': ssd_cache
} }
self.private_storage.update(share['id'], _metadata) self.private_storage.update(share['id'], _metadata)
@ -726,25 +808,62 @@ class QnapShareDriver(driver.ShareDriver):
"backend.") % share['id'] "backend.") % share['id']
raise exception.ManageInvalidShare(reason=msg) 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_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['volID'] = vol_no
_metadata['volName'] = share_name _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) 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 " LOG.info("Share %(shr_path)s was successfully managed with ID "
"%(shr_id)s.", "%(shr_id)s.",
{'shr_path': share['export_locations'][0]['path'], {'shr_path': share['export_locations'][0]['path'],
'shr_id': share['id']}) '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( export_locations = self._get_location_path(
share_name, share_name,
share['share_proto'], share['share_proto'],

View File

@ -138,6 +138,10 @@ FAKE_RES_DETAIL_DATA_VOLUME_INFO = """
<vol_no><![CDATA[fakeNo]]></vol_no> <vol_no><![CDATA[fakeNo]]></vol_no>
<size><![CDATA[10]]></size> <size><![CDATA[10]]></size>
<vol_mount_path>fakeMountPath</vol_mount_path> <vol_mount_path>fakeMountPath</vol_mount_path>
<dedup><![CDATA[off]]></dedup>
<compression><![CDATA[1]]></compression>
<thin_pro><![CDATA[1]]></thin_pro>
<cache><![CDATA[0]]></cache>
</row> </row>
</Volume_Info> </Volume_Info>
<result><![CDATA[0]]></result> <result><![CDATA[0]]></result>
@ -325,7 +329,8 @@ class SnapshotClass(object):
'id': 'fakeSnapshotId', 'id': 'fakeSnapshotId',
'share': {'share_id': 'fakeShareId', 'id': 'fakeId'}, 'share': {'share_id': 'fakeShareId', 'id': 'fakeId'},
'share_instance': {'share_id': 'fakeShareId', 'id': 'fakeId'}, 'share_instance': {'share_id': 'fakeShareId', 'id': 'fakeId'},
'size': self.size 'size': self.size,
'share_instance_id': 'fakeShareId'
}[arg] }[arg]
def __setitem__(self, key, value): def __setitem__(self, key, value):

View File

@ -120,7 +120,11 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
self.share, self.share,
'Storage Pool 1', 'Storage Pool 1',
fake_name, fake_name,
'NFS') 'NFS',
qnap_deduplication=False,
qnap_compression=True,
qnap_thin_provision=True,
qnap_ssd_cache=False)
fake_params = { fake_params = {
'wiz_func': 'share_create', 'wiz_func': 'share_create',
@ -130,7 +134,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
'threshold': '80', 'threshold': '80',
'dedup': 'off', 'dedup': 'off',
'compression': '1', 'compression': '1',
'thin_pro': '0', 'thin_pro': '1',
'cache': '0', 'cache': '0',
'cifs_enable': '0', 'cifs_enable': '0',
'nfs_enable': '1', 'nfs_enable': '1',
@ -457,6 +461,10 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
"sharename": 'fakeVolId', "sharename": 'fakeVolId',
"old_sharename": 'fakeVolId', "old_sharename": 'fakeVolId',
"new_size": 100, "new_size": 100,
"deduplication": False,
"compression": True,
"thin_provision": True,
"ssd_cache": False,
"share_proto": "NFS" "share_proto": "NFS"
} }
self.driver.api_executor.edit_share( self.driver.api_executor.edit_share(
@ -468,9 +476,9 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
'sharename': 'fakeVolId', 'sharename': 'fakeVolId',
'old_sharename': 'fakeVolId', 'old_sharename': 'fakeVolId',
'vol_size': '100GB', 'vol_size': '100GB',
'dedup': '0', 'dedup': 'off',
'compression': '1', 'compression': '1',
'thin_pro': '0', 'thin_pro': '1',
'cache': '0', 'cache': '0',
'cifs_enable': '0', 'cifs_enable': '0',
'nfs_enable': '1', 'nfs_enable': '1',
@ -736,7 +744,11 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
share=self.share, share=self.share,
pool_name='Storage Pool 1', pool_name='Storage Pool 1',
create_share_name='fake_share_name', 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.unpack
@ddt.data(['self.driver.api_executor.get_share_info', @ddt.data(['self.driver.api_executor.get_share_info',
@ -803,6 +815,10 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
{'share_dict': {"sharename": 'fakeVolId', {'share_dict': {"sharename": 'fakeVolId',
"old_sharename": 'fakeVolId', "old_sharename": 'fakeVolId',
"new_size": 100, "new_size": 100,
"deduplication": False,
"compression": True,
"thin_provision": False,
"ssd_cache": False,
"share_proto": "NFS"}}, "share_proto": "NFS"}},
fakes.FakeEsResCodeNegativeResponse(), fakes.FakeEsResCodeNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs_1_1_3()], fakes.FakeGetBasicInfoResponseEs_1_1_3()],
@ -810,6 +826,10 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
{'share_dict': {"sharename": 'fakeVolId', {'share_dict': {"sharename": 'fakeVolId',
"old_sharename": 'fakeVolId', "old_sharename": 'fakeVolId',
"new_size": 100, "new_size": 100,
"deduplication": False,
"compression": True,
"thin_provision": False,
"ssd_cache": False,
"share_proto": "NFS"}}, "share_proto": "NFS"}},
fakes.FakeAuthPassFailResponse(), fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs_1_1_3()], fakes.FakeGetBasicInfoResponseEs_1_1_3()],

View File

@ -29,6 +29,7 @@ from eventlet import greenthread
from manila import exception from manila import exception
from manila.share.drivers.qnap import api from manila.share.drivers.qnap import api
from manila.share.drivers.qnap import qnap from manila.share.drivers.qnap import qnap
from manila.share import share_types
from manila import test from manila import test
from manila.tests import fake_share from manila.tests import fake_share
from manila.tests.share.drivers.qnap import fakes from manila.tests.share.drivers.qnap import fakes
@ -296,12 +297,72 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
return hosts 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'<is> False',
'compression': u'<is> True',
'qnap_ssd_cache': u'<is> 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'<is> 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'<is> False',
'compression': u'false',
'dedupe': u'<is> False',
'qnap_ssd_cache': u'<is> 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, '_get_location_path')
@mock.patch.object(qnap.QnapShareDriver, '_gen_random_name') @mock.patch.object(qnap.QnapShareDriver, '_gen_random_name')
def test_create_share_positive( def test_create_share_positive(
self, self,
mock_gen_random_name, mock_gen_random_name,
mock_get_location_path): mock_get_location_path,
fake_extra_spec, expect_extra_spec):
"""Test create share.""" """Test create share."""
mock_api_executor = qnap.QnapShareDriver._create_api_executor mock_api_executor = qnap.QnapShareDriver._create_api_executor
mock_api_executor.return_value.get_share_info.side_effect = [ 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', self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1', 'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage) 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) self.driver.create_share('context', self.share)
mock_api_return = mock_api_executor.return_value mock_api_return = mock_api_executor.return_value
@ -328,7 +391,8 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
self.share, self.share,
self.driver.configuration.qnap_poolname, self.driver.configuration.qnap_poolname,
'fakeShareName', 'fakeShareName',
'NFS') 'NFS',
**expect_extra_spec)
mock_get_location_path.assert_called_once_with( mock_get_location_path.assert_called_once_with(
'fakeShareName', 'NFS', '1.2.3.4', 'fakeNo') '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', self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1', 'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage) private_storage=mock_private_storage)
self.mock_object(share_types, 'get_extra_specs_from_share',
mock.Mock(return_value={}))
self.assertRaises( self.assertRaises(
exception.ShareBackendException, exception.ShareBackendException,
@ -373,6 +439,8 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin', self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1', 'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage) private_storage=mock_private_storage)
self.mock_object(share_types, 'get_extra_specs_from_share',
mock.Mock(return_value={}))
self.assertRaises( self.assertRaises(
exception.ShareBackendException, exception.ShareBackendException,
@ -380,6 +448,34 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
context='context', context='context',
share=self.share) 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): def test_delete_share_positive(self):
"""Test delete share with fake_share.""" """Test delete share with fake_share."""
mock_api_executor = qnap.QnapShareDriver._create_api_executor mock_api_executor = qnap.QnapShareDriver._create_api_executor
@ -437,7 +533,12 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
self.get_share_info_return_value()) self.get_share_info_return_value())
mock_api_executor.return_value.edit_share.return_value = None mock_api_executor.return_value.edit_share.return_value = None
mock_private_storage = mock.Mock() 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', self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1', 'qnapadmin', 'Storage Pool 1',
@ -448,6 +549,10 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
'sharename': 'fakeVolName', 'sharename': 'fakeVolName',
'old_sharename': 'fakeVolName', 'old_sharename': 'fakeVolName',
'new_size': 100, 'new_size': 100,
'thin_provision': True,
'compression': True,
'deduplication': False,
'ssd_cache': False,
'share_proto': 'NFS' 'share_proto': 'NFS'
} }
mock_api_executor.return_value.edit_share.assert_called_once_with( 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 = [ mock_api_executor.return_value.get_share_info.side_effect = [
None, self.get_share_info_return_value()] None, self.get_share_info_return_value()]
mock_private_storage = mock.Mock() 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_share_api.return_value.get.return_value = {'size': 5}
mock_api_executor.return_value.edit_share.return_value = ( mock_api_executor.return_value.edit_share.return_value = (
None) None)
@ -637,6 +747,10 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
'sharename': 'fakeShareName', 'sharename': 'fakeShareName',
'old_sharename': 'fakeShareName', 'old_sharename': 'fakeShareName',
'new_size': 10, 'new_size': 10,
'thin_provision': True,
'compression': True,
'deduplication': False,
'ssd_cache': False,
'share_proto': 'NFS' 'share_proto': 'NFS'
} }
mock_api_return.edit_share.assert_called_once_with( 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', self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1', 'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage) 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') self.driver.manage_existing(self.share, 'driver_options')
mock_api_return = mock_api_executor.return_value mock_api_return = mock_api_executor.return_value
@ -826,6 +942,39 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
mock_get_location_path.assert_called_once_with( mock_get_location_path.assert_called_once_with(
'fakeShareName', 'NFS', '1.2.3.4', 'fakeNo') '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): def test_manage_invalid_protocol(self):
"""Test manage existing.""" """Test manage existing."""
share = fake_share.fake_share( share = fake_share.fake_share(

View File

@ -0,0 +1,6 @@
---
features:
- |
Added enhanced support to the QNAP Manila driver, including
``Thin Provisioning``, ``SSD Cache``, ``Deduplication``
and ``Compression``.