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:
parent
098546fbf4
commit
487aa691fd
@ -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::
|
||||||
|
@ -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',
|
||||||
|
@ -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'],
|
||||||
|
@ -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):
|
||||||
|
@ -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()],
|
||||||
|
@ -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(
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added enhanced support to the QNAP Manila driver, including
|
||||||
|
``Thin Provisioning``, ``SSD Cache``, ``Deduplication``
|
||||||
|
and ``Compression``.
|
Loading…
Reference in New Issue
Block a user