QNAP: Add support for QES 1.1.4

This patch do the following changes to the QNAP Manila driver:
1. Add support for QNAP QES firmware 1.1.4.
2. Correct the default parameters in edit share function.
2. Remove unused code flow.
4. Add more debug log and write more test cases.

    Implements: blueprint support-qes-114

Change-Id: I977ef3e66a21a52116b44059ad5aeaf1560b47b7
This commit is contained in:
Chris Yang 2017-11-27 12:43:25 +08:00
parent 3088bf8ebf
commit 4c2b5e9335
6 changed files with 515 additions and 145 deletions

View File

@ -39,10 +39,10 @@ MSG_SESSION_EXPIRED = _("Session ID expired")
MSG_UNEXPECT_RESP = _("Unexpected response from QNAP API")
@utils.retry(exception=exception.ShareBackendException,
retries=5)
def _connection_checker(func):
"""Decorator to check session has expired or not."""
@utils.retry(exception=exception.ShareBackendException,
retries=5)
@functools.wraps(func)
def inner_connection_checker(self, *args, **kwargs):
LOG.debug('in _connection_checker')
@ -225,7 +225,8 @@ class QnapAPIExecutor(object):
if root.find('authPassed').text == '0':
raise exception.ShareBackendException(msg=MSG_SESSION_EXPIRED)
if root.find('ES_RET_CODE').text < '0':
msg = _('Create share %s failed') % share['display_name']
msg = _("Fail to create share %s on NAS.") % create_share_name
LOG.error(msg)
raise exception.ShareBackendException(msg=msg)
vol_list = root.find('func').find('ownContent').find('volumeList')
@ -319,26 +320,22 @@ class QnapAPIExecutor(object):
if root.find('authPassed').text == '0':
raise exception.ShareBackendException(msg=MSG_SESSION_EXPIRED)
if ('vol_no' in kwargs) or ('vol_label' in kwargs):
vol_list = root.find('Volume_Info')
vol_info_tree = vol_list.findall('row')
for vol in vol_info_tree:
LOG.debug('Iterating vol name: %(name)s, index: %(id)s',
{'name': vol.find('vol_label').text,
'id': vol.find('vol_no').text})
if 'vol_no' in kwargs:
if kwargs['vol_no'] == vol.find('vol_no').text:
LOG.debug('vol_no:%s',
vol.find('vol_no').text)
return vol
elif 'vol_label' in kwargs:
if kwargs['vol_label'] == vol.find('vol_label').text:
LOG.debug('vol_label:%s', vol.find('vol_label').text)
return vol
if vol is vol_info_tree[-1]:
return None
else:
return res_details['data']
vol_list = root.find('Volume_Info')
vol_info_tree = vol_list.findall('row')
for vol in vol_info_tree:
LOG.debug('Iterating vol name: %(name)s, index: %(id)s',
{'name': vol.find('vol_label').text,
'id': vol.find('vol_no').text})
if 'vol_no' in kwargs:
if kwargs['vol_no'] == vol.find('vol_no').text:
LOG.debug('vol_no:%s',
vol.find('vol_no').text)
return vol
elif 'vol_label' in kwargs:
if kwargs['vol_label'] == vol.find('vol_label').text:
LOG.debug('vol_label:%s', vol.find('vol_label').text)
return vol
return None
@_connection_checker
def get_specific_volinfo(self, vol_id, **kwargs):
@ -453,9 +450,11 @@ class QnapAPIExecutor(object):
raise exception.ShareBackendException(msg=MSG_SESSION_EXPIRED)
# snapshot not exist
if root.find('result').text == '-206021':
LOG.warning('Snapshot id %s does not exist', snapshot_id)
return
# lun not exist
# share not exist
if root.find('result').text == '-200005':
LOG.warning('Share of snapshot id %s does not exist', snapshot_id)
return
if root.find('result').text < '0':
msg = _('Failed to delete snapshot.')
@ -499,8 +498,10 @@ class QnapAPIExecutor(object):
'compression': '1',
'thin_pro': '0',
'cache': '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',
'ftp_enable': '1',
'ftp_enable': '0',
'hidden': '0',
'oplocks': '1',
'sync': 'always',

View File

@ -61,9 +61,10 @@ class QnapShareDriver(driver.ShareDriver):
Version history:
1.0.0 - Initial driver (Only NFS)
1.0.1 - Add support for QES fw 1.1.4.
"""
DRIVER_VERSION = '1.0.0'
DRIVER_VERSION = '1.0.1'
def __init__(self, *args, **kwargs):
"""Initialize QnapShareDriver."""
@ -152,17 +153,14 @@ class QnapShareDriver(driver.ShareDriver):
username=self.configuration.qnap_nas_login,
password=self.configuration.qnap_nas_password,
management_url=self.configuration.qnap_management_url)
if (fw_version.startswith("1.1.2") or
fw_version.startswith("1.1.3")):
elif "1.1.2" <= fw_version <= "1.1.4":
LOG.debug('Create ES API Executor')
return api.QnapAPIExecutor(
username=self.configuration.qnap_nas_login,
password=self.configuration.qnap_nas_password,
management_url=self.configuration.qnap_management_url)
elif model_type in es_model_types:
if (fw_version.startswith("1.1.2") or
fw_version.startswith("1.1.3")):
if "1.1.2" <= fw_version <= "1.1.4":
LOG.debug('Create ES API Executor')
return api.QnapAPIExecutor(
username=self.configuration.qnap_nas_login,
@ -195,13 +193,9 @@ class QnapShareDriver(driver.ShareDriver):
{'ifx': infix,
'time': timeutils.utcnow().strftime('%Y%m%d%H%M%S%f')})
def _get_location_path(self, share_name, share_proto, ip):
def _get_location_path(self, share_name, share_proto, ip, vol_id):
if share_proto == 'NFS':
created_share = self.api_executor.get_share_info(
self.configuration.qnap_poolname,
vol_label=share_name)
vol_no = created_share.find('vol_no').text
vol = self.api_executor.get_specific_volinfo(vol_no)
vol = self.api_executor.get_specific_volinfo(vol_id)
vol_mount_path = vol.find('vol_mount_path').text
location = '%s:%s' % (ip, vol_mount_path)
@ -263,7 +257,8 @@ class QnapShareDriver(driver.ShareDriver):
@utils.retry(exception=exception.ShareBackendException,
interval=3,
retries=200)
retries=5)
@utils.synchronized('qnap-create_share')
def create_share(self, context, share, share_server=None):
"""Create a new share."""
LOG.debug('share: %s', share.__dict__)
@ -277,25 +272,48 @@ class QnapShareDriver(driver.ShareDriver):
created_share = self.api_executor.get_share_info(
self.configuration.qnap_poolname,
vol_label=create_share_name)
LOG.debug('created_share: %s', created_share)
if created_share is not None:
msg = _("Failed to create an unused share name.")
msg = (_("The share name %s is used by other share on NAS.") %
create_share_name)
LOG.error(msg)
raise exception.ShareBackendException(msg=msg)
create_volID = self.api_executor.create_share(
self.api_executor.create_share(
share,
self.configuration.qnap_poolname,
create_share_name,
share_proto)
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.
_metadata = {'volID': create_volID, 'volName': create_share_name}
LOG.debug('volID: %(volID)s '
'volName: %(create_share_name)s',
{'volID': volID,
'create_share_name': create_share_name})
_metadata = {'volID': volID,
'volName': create_share_name}
self.private_storage.update(share['id'], _metadata)
return self._get_location_path(create_share_name,
share['share_proto'],
self.configuration.qnap_share_ip)
self.configuration.qnap_share_ip,
volID)
@utils.retry(exception=exception.ShareBackendException,
interval=5, retries=5, backoff_rate=1)
def _get_share_info(self, share_name):
share = self.api_executor.get_share_info(
self.configuration.qnap_poolname,
vol_label=share_name)
if share is None:
msg = _("Fail to get share info of %s on NAS.") % share_name
LOG.error(msg)
raise exception.ShareBackendException(msg=msg)
else:
return share
@utils.synchronized('qnap-delete_share')
def delete_share(self, context, share, share_server=None):
"""Delete the specified share."""
# Use private_storage to retrieve volume ID created in the NAS.
@ -317,11 +335,15 @@ class QnapShareDriver(driver.ShareDriver):
self.api_executor.delete_share(vol_no)
self.private_storage.delete(share['id'])
@utils.synchronized('qnap-extend_share')
def extend_share(self, share, new_size, share_server=None):
"""Extend an existing share."""
LOG.debug('Entering extend_share share=%(share)s '
LOG.debug('Entering extend_share share_name=%(share_name)s '
'share_id=%(share_id)s '
'new_size=%(size)s',
{'share': share['display_name'], 'size': new_size})
{'share_name': share['display_name'],
'share_id': share['id'],
'size': new_size})
# Use private_storage to retrieve volume Name created in the NAS.
volName = self.private_storage.get(share['id'], 'volName')
@ -331,15 +353,17 @@ class QnapShareDriver(driver.ShareDriver):
LOG.debug('volName: %s', volName)
share_dict = {
"sharename": volName,
"old_sharename": volName,
"new_size": new_size,
'sharename': volName,
'old_sharename': volName,
'new_size': new_size,
'share_proto': share['share_proto']
}
self.api_executor.edit_share(share_dict)
@utils.retry(exception=exception.ShareBackendException,
interval=3,
retries=200)
retries=5)
@utils.synchronized('qnap-create_snapshot')
def create_snapshot(self, context, snapshot, share_server=None):
"""Create a snapshot."""
LOG.debug('snapshot[share][share_id]: %s',
@ -393,6 +417,7 @@ class QnapShareDriver(driver.ShareDriver):
return {'provider_location': snapshot_id}
@utils.synchronized('qnap-delete_snapshot')
def delete_snapshot(self, context, snapshot, share_server=None):
"""Delete a snapshot."""
LOG.debug('Entering delete_snapshot. The deleted snapshot=%(snap)s',
@ -410,7 +435,8 @@ class QnapShareDriver(driver.ShareDriver):
@utils.retry(exception=exception.ShareBackendException,
interval=3,
retries=200)
retries=5)
@utils.synchronized('qnap-create_share_from_snapshot')
def create_share_from_snapshot(self, context, share, snapshot,
share_server=None):
"""Create a share from a snapshot."""
@ -441,20 +467,24 @@ class QnapShareDriver(driver.ShareDriver):
created_share = self.api_executor.get_share_info(
self.configuration.qnap_poolname,
vol_label=create_share_name)
if created_share.find('vol_no') is not None:
if created_share is not None:
create_volID = created_share.find('vol_no').text
LOG.debug('create_volID: %s', create_volID)
else:
msg = _("Failed to clone a snapshot in time.")
raise exception.ShareBackendException(msg=msg)
snap_share = self.share_api.get(context,
snapshot['share_instance']['share_id'])
snap_share = self.share_api.get(
context, snapshot['share_instance']['share_id'])
LOG.debug('snap_share[size]: %s', snap_share['size'])
if (share['size'] > snap_share['size']):
share_dict = {'sharename': create_share_name,
'old_sharename': create_share_name,
'new_size': share['size']}
share_dict = {
'sharename': create_share_name,
'old_sharename': create_share_name,
'new_size': share['size'],
'share_proto': share['share_proto']
}
self.api_executor.edit_share(share_dict)
# Use private_storage to record volume ID and Name created in the NAS.
@ -470,7 +500,8 @@ class QnapShareDriver(driver.ShareDriver):
return self._get_location_path(create_share_name,
share['share_proto'],
self.configuration.qnap_share_ip)
self.configuration.qnap_share_ip,
create_volID)
def _get_manila_hostIPv4s(self, hostlist):
host_dict_IPs = []
@ -656,7 +687,8 @@ class QnapShareDriver(driver.ShareDriver):
export_locations = self._get_location_path(
share_name,
share['share_proto'],
self.configuration.qnap_share_ip)
self.configuration.qnap_share_ip,
vol_no)
return {'size': vol_size_gb, 'export_locations': export_locations}

View File

@ -19,7 +19,18 @@ FAKE_RES_DETAIL_DATA_LOGIN = """
<authSid><![CDATA[fakeSid]]></authSid>
</QDocRoot>"""
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_ES = """
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_ES_1_1_1 = """
<QDocRoot version="1.0">
<model>
<displayModelName><![CDATA[ES1640dc]]></displayModelName>
<internalModelName><![CDATA[ES1640dc]]></internalModelName>
</model>
<firmware>
<version><![CDATA[1.1.1]]></version>
</firmware>
</QDocRoot>"""
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_ES_1_1_3 = """
<QDocRoot version="1.0">
<model>
<displayModelName><![CDATA[ES1640dc]]></displayModelName>
@ -30,7 +41,18 @@ FAKE_RES_DETAIL_DATA_GETBASIC_INFO_ES = """
</firmware>
</QDocRoot>"""
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TS = """
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TS_4_0_0 = """
<QDocRoot version="1.0">
<model>
<displayModelName><![CDATA[TS-870U]]></displayModelName>
<internalModelName><![CDATA[TS-870U]]></internalModelName>
</model>
<firmware>
<version><![CDATA[4.0.0]]></version>
</firmware>
</QDocRoot>"""
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TS_4_3_0 = """
<QDocRoot version="1.0">
<model>
<displayModelName><![CDATA[TS-870U]]></displayModelName>
@ -41,7 +63,18 @@ FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TS = """
</firmware>
</QDocRoot>"""
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_TS = """
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_TS_4_0_0 = """
<QDocRoot version="1.0">
<model>
<displayModelName><![CDATA[TES-1885U]]></displayModelName>
<internalModelName><![CDATA[TS-1885U]]></internalModelName>
</model>
<firmware>
<version><![CDATA[4.0.0]]></version>
</firmware>
</QDocRoot>"""
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_TS_4_3_0 = """
<QDocRoot version="1.0">
<model>
<displayModelName><![CDATA[TES-1885U]]></displayModelName>
@ -52,7 +85,18 @@ FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_TS = """
</firmware>
</QDocRoot>"""
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_ES = """
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_ES_1_1_1 = """
<QDocRoot version="1.0">
<model>
<displayModelName><![CDATA[TES-1885U]]></displayModelName>
<internalModelName><![CDATA[ES-1885U]]></internalModelName>
</model>
<firmware>
<version><![CDATA[1.1.1]]></version>
</firmware>
</QDocRoot>"""
FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_ES_1_1_3 = """
<QDocRoot version="1.0">
<model>
<displayModelName><![CDATA[TES-1885U]]></displayModelName>
@ -208,6 +252,20 @@ FAKE_RES_DETAIL_DATA_DELETE_SNAPSHOT = """
<result>0</result>
</QDocRoot>"""
FAKE_RES_DETAIL_DATA_DELETE_SNAPSHOT_SNAPSHOT_NOT_EXIST = """
<QDocRoot version="1.0">
<authPassed><![CDATA[1]]></authPassed>
<ES_RET_CODE><![CDATA[1]]></ES_RET_CODE>
<result>-206021</result>
</QDocRoot>"""
FAKE_RES_DETAIL_DATA_DELETE_SNAPSHOT_SHARE_NOT_EXIST = """
<QDocRoot version="1.0">
<authPassed><![CDATA[1]]></authPassed>
<ES_RET_CODE><![CDATA[1]]></ES_RET_CODE>
<result>-200005</result>
</QDocRoot>"""
FAKE_RES_DETAIL_DATA_GET_HOST_LIST_API = """
<QDocRoot version="1.0">
<authPassed><![CDATA[1]]></authPassed>
@ -347,44 +405,84 @@ class AccessClass(object):
}[arg]
class FakeGetBasicInfoResponseEs(object):
class FakeGetBasicInfoResponseEs_1_1_1(object):
"""Fake GetBasicInfo response from ES nas."""
status = 'fackStatus'
def read(self):
"""Mock response.read."""
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_ES
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_ES_1_1_1
class FakeGetBasicInfoResponseTs(object):
class FakeGetBasicInfoResponseEs_1_1_3(object):
"""Fake GetBasicInfo response from ES nas."""
status = 'fackStatus'
def read(self):
"""Mock response.read."""
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_ES_1_1_3
class FakeGetBasicInfoResponseTs_4_0_0(object):
"""Fake GetBasicInfoTS response from TS nas."""
status = 'fackStatus'
def read(self):
"""Mock response.read."""
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TS
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TS_4_0_0
class FakeGetBasicInfoResponseTesTs(object):
class FakeGetBasicInfoResponseTs_4_3_0(object):
"""Fake GetBasicInfoTS response from TS nas."""
status = 'fackStatus'
def read(self):
"""Mock response.read."""
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_TS
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TS_4_3_0
class FakeGetBasicInfoResponseTesEs(object):
class FakeGetBasicInfoResponseTesTs_4_0_0(object):
"""Fake GetBasicInfoTS response from TS nas."""
status = 'fackStatus'
def read(self):
"""Mock response.read."""
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_ES
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_TS_4_0_0
class FakeGetBasicInfoResponseTesTs_4_3_0(object):
"""Fake GetBasicInfoTS response from TS nas."""
status = 'fackStatus'
def read(self):
"""Mock response.read."""
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_TS_4_3_0
class FakeGetBasicInfoResponseTesEs_1_1_1(object):
"""Fake GetBasicInfoTS response from TS nas."""
status = 'fackStatus'
def read(self):
"""Mock response.read."""
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_ES_1_1_1
class FakeGetBasicInfoResponseTesEs_1_1_3(object):
"""Fake GetBasicInfoTS response from TS nas."""
status = 'fackStatus'
def read(self):
"""Mock response.read."""
return FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_ES_1_1_3
class FakeGetBasicInfoResponseError(object):
@ -418,7 +516,7 @@ class FakeDeleteShareResponse(object):
class FakeDeleteSnapshotResponse(object):
"""Fake pool info response."""
"""Fake delete snapshot response."""
status = 'fackStatus'
@ -427,6 +525,26 @@ class FakeDeleteSnapshotResponse(object):
return FAKE_RES_DETAIL_DATA_DELETE_SNAPSHOT
class FakeDeleteSnapshotResponseSnapshotNotExist(object):
"""Fake delete snapshot response."""
status = 'fackStatus'
def read(self):
"""Mock response.read."""
return FAKE_RES_DETAIL_DATA_DELETE_SNAPSHOT_SNAPSHOT_NOT_EXIST
class FakeDeleteSnapshotResponseShareNotExist(object):
"""Fake delete snapshot response."""
status = 'fackStatus'
def read(self):
"""Mock response.read."""
return FAKE_RES_DETAIL_DATA_DELETE_SNAPSHOT_SHARE_NOT_EXIST
class FakeGetHostListResponse(object):
"""Fake pool info response."""

View File

@ -19,6 +19,7 @@ import ddt
import mock
import six
from six.moves import urllib
import time
from manila import exception
from manila.share.drivers.qnap import qnap
@ -106,7 +107,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeCreateShareResponse()]
@ -164,7 +165,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeDeleteShareResponse()]
@ -198,7 +199,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeSpecificPoolInfoResponse()]
@ -235,7 +236,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeShareInfoResponse()]
@ -268,7 +269,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeSpecificVolInfoResponse()]
@ -302,7 +303,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeSnapshotInfoResponse()]
@ -337,7 +338,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeCreateSnapshotResponse()]
@ -368,14 +369,17 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
expected_call_list,
mock_http_connection.return_value.request.call_args_list)
def test_delete_snapshot_api(self):
@ddt.data(fakes.FakeDeleteSnapshotResponse(),
fakes.FakeDeleteSnapshotResponseSnapshotNotExist(),
fakes.FakeDeleteSnapshotResponseShareNotExist())
def test_delete_snapshot_api(self, fakeDeleteSnapshotResponse):
"""Test delete snapshot api."""
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeDeleteSnapshotResponse()]
fakeDeleteSnapshotResponse]
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1')
@ -405,7 +409,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeDeleteSnapshotResponse()]
@ -440,7 +444,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseTs(),
fakes.FakeGetBasicInfoResponseTs_4_3_0(),
fakes.FakeLoginResponse(),
fakes.FakeCreateSnapshotResponse()]
@ -450,6 +454,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
"sharename": 'fakeVolId',
"old_sharename": 'fakeVolId',
"new_size": 100,
"share_proto": "NFS"
}
self.driver.api_executor.edit_share(
expect_share_dict)
@ -464,8 +469,10 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
'compression': '1',
'thin_pro': '0',
'cache': '0',
'cifs_enable': '0',
'nfs_enable': '1',
'afp_enable': '0',
'ftp_enable': '1',
'ftp_enable': '0',
'hidden': '0',
'oplocks': '1',
'sync': 'always',
@ -491,7 +498,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeGetHostListResponse()]
@ -523,7 +530,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeGetHostListResponse()]
@ -558,7 +565,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fakes.FakeGetHostListResponse()]
@ -594,7 +601,7 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseTs(),
fakes.FakeGetBasicInfoResponseTs_4_3_0(),
fakes.FakeLoginResponse(),
fakes.FakeSnapshotInfoResponse()]
@ -633,14 +640,20 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
mock_http_connection = six.moves.http_client.HTTPConnection
mock_http_connection.return_value.getresponse.side_effect = [
fakes.FakeLoginResponse(),
fakes.FakeGetBasicInfoResponseEs(),
fakes.FakeGetBasicInfoResponseEs_1_1_3(),
fakes.FakeLoginResponse(),
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response]
self.mock_object(time, 'sleep')
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1')
self.assertRaises(
@ -655,115 +668,117 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
@ddt.data(['self.driver.api_executor.get_share_info',
{'pool_id': 'fakeId'},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.get_specific_volinfo',
{'vol_id': 'fakeId'},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.create_snapshot_api',
{'volumeID': 'fakeVolumeId',
'snapshot_name': 'fakeSnapshotName'},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.create_snapshot_api',
{'volumeID': 'fakeVolumeId',
'snapshot_name': 'fakeSnapshotName'},
fakes.FakeEsResCodeNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.get_snapshot_info',
{'volID': 'volId'},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.get_snapshot_info',
{'volID': 'volId'},
fakes.FakeResultNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.get_specific_poolinfo',
{'pool_id': 'Storage Pool 1'},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.get_specific_poolinfo',
{'pool_id': 'Storage Pool 1'},
fakes.FakeResultNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.delete_share',
{'vol_id': 'fakeId'},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.delete_share',
{'vol_id': 'fakeId'},
fakes.FakeResultNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.delete_snapshot_api',
{'snapshot_id': 'fakeSnapshotId'},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.delete_snapshot_api',
{'snapshot_id': 'fakeSnapshotId'},
fakes.FakeResultNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.clone_snapshot',
{'snapshot_id': 'fakeSnapshotId',
'new_sharename': 'fakeNewShareName'},
fakes.FakeResultNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.clone_snapshot',
{'snapshot_id': 'fakeSnapshotId',
'new_sharename': 'fakeNewShareName'},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.edit_share',
{'share_dict': {"sharename": 'fakeVolId',
"old_sharename": 'fakeVolId',
"new_size": 100}},
"new_size": 100,
"share_proto": "NFS"}},
fakes.FakeEsResCodeNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.edit_share',
{'share_dict': {"sharename": 'fakeVolId',
"old_sharename": 'fakeVolId',
"new_size": 100}},
"new_size": 100,
"share_proto": "NFS"}},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.add_host',
{'hostname': 'fakeHostName',
'ipv4': 'fakeIpV4'},
fakes.FakeResultNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.add_host',
{'hostname': 'fakeHostName',
'ipv4': 'fakeIpV4'},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.get_host_list',
{},
fakes.FakeResultNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.get_host_list',
{},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.set_nfs_access',
{'sharename': 'fakeShareName',
'access': 'fakeAccess',
'host_name': 'fakeHostName'},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.set_nfs_access',
{'sharename': 'fakeShareName',
'access': 'fakeAccess',
'host_name': 'fakeHostName'},
fakes.FakeResultNegativeResponse(),
fakes.FakeGetBasicInfoResponseEs()],
fakes.FakeGetBasicInfoResponseEs_1_1_3()],
['self.driver.api_executor.get_snapshot_info',
{'snapshot_name': 'fakeSnapshoName',
'lun_index': 'fakeLunIndex'},
fakes.FakeAuthPassFailResponse(),
fakes.FakeGetBasicInfoResponseTs()],
fakes.FakeGetBasicInfoResponseTs_4_3_0()],
['self.driver.api_executor.get_snapshot_info',
{'snapshot_name': 'fakeSnapshoName',
'lun_index': 'fakeLunIndex'},
fakes.FakeResultNegativeResponse(),
fakes.FakeGetBasicInfoResponseTs()])
fakes.FakeGetBasicInfoResponseTs_4_3_0()])
def test_get_snapshot_info_ts_with_fail_response(
self, api, dict_parm,
fake_fail_response, fake_basic_info):
@ -777,11 +792,16 @@ class QnapAPITestCase(QnapShareDriverBaseTestCase):
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response,
fake_fail_response]
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1')
self.mock_object(time, 'sleep')
self.assertRaises(
exception.ShareBackendException,
eval(api),

View File

@ -23,8 +23,11 @@ import ddt
import mock
from oslo_config import cfg
import six
import time
from eventlet import greenthread
from manila import exception
from manila.share.drivers.qnap import api
from manila.share.drivers.qnap import qnap
from manila import test
from manila.tests import fake_share
@ -86,7 +89,8 @@ class QnapShareDriverLoginTestCase(QnapShareDriverBaseTestCase):
def test_do_setup_positive(self, mng_url, port, ssl):
"""Test do_setup with http://1.2.3.4:8080."""
fake_login_response = fakes.FakeLoginResponse()
fake_get_basic_info_response_es = fakes.FakeGetBasicInfoResponseEs()
fake_get_basic_info_response_es = (
fakes.FakeGetBasicInfoResponseEs_1_1_3())
if ssl:
mock_connection = six.moves.http_client.HTTPSConnection
else:
@ -117,13 +121,12 @@ class QnapShareDriverLoginTestCase(QnapShareDriverBaseTestCase):
self.assertEqual(port, self.driver.api_executor.port)
self.assertEqual(ssl, self.driver.api_executor.ssl)
@ddt.data(fakes.FakeGetBasicInfoResponseTs(),
fakes.FakeGetBasicInfoResponseTesTs(),
fakes.FakeGetBasicInfoResponseTesEs())
@ddt.data(fakes.FakeGetBasicInfoResponseTs_4_3_0(),
fakes.FakeGetBasicInfoResponseTesTs_4_3_0(),
fakes.FakeGetBasicInfoResponseTesEs_1_1_3())
def test_do_setup_positive_with_diff_nas(self, fake_basic_info):
"""Test do_setup with different NAS model."""
fake_login_response = fakes.FakeLoginResponse()
# fake_get_basic_info_response_ts = FakeGetBasicInfoResponseTs()
mock_connection = six.moves.http_client.HTTPSConnection
mock_connection.return_value.getresponse.side_effect = [
fake_login_response,
@ -140,6 +143,64 @@ class QnapShareDriverLoginTestCase(QnapShareDriverBaseTestCase):
self.assertEqual('443', self.driver.api_executor.port)
self.assertTrue(self.driver.api_executor.ssl)
@ddt.data({
'fake_basic_info': fakes.FakeGetBasicInfoResponseTs_4_3_0(),
'expect_result': api.QnapAPIExecutorTS
}, {
'fake_basic_info': fakes.FakeGetBasicInfoResponseTesTs_4_3_0(),
'expect_result': api.QnapAPIExecutorTS
}, {
'fake_basic_info': fakes.FakeGetBasicInfoResponseTesEs_1_1_3(),
'expect_result': api.QnapAPIExecutor
}, {
'fake_basic_info': fakes.FakeGetBasicInfoResponseEs_1_1_3(),
'expect_result': api.QnapAPIExecutor
})
@ddt.unpack
def test_create_api_executor(self, fake_basic_info, expect_result):
"""Test do_setup with different NAS model."""
fake_login_response = fakes.FakeLoginResponse()
mock_connection = six.moves.http_client.HTTPSConnection
mock_connection.return_value.getresponse.side_effect = [
fake_login_response,
fake_basic_info,
fake_login_response]
self._do_setup('https://1.2.3.4:443', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1')
self.assertIsInstance(self.driver.api_executor, expect_result)
@ddt.data({
'fake_basic_info': fakes.FakeGetBasicInfoResponseTs_4_0_0(),
'expect_result': exception.ShareBackendException
}, {
'fake_basic_info': fakes.FakeGetBasicInfoResponseTesTs_4_0_0(),
'expect_result': exception.ShareBackendException
}, {
'fake_basic_info': fakes.FakeGetBasicInfoResponseTesEs_1_1_1(),
'expect_result': exception.ShareBackendException
}, {
'fake_basic_info': fakes.FakeGetBasicInfoResponseEs_1_1_1(),
'expect_result': exception.ShareBackendException
})
@ddt.unpack
def test_create_api_executor_negative(self,
fake_basic_info, expect_result):
"""Test do_setup with different NAS model."""
fake_login_response = fakes.FakeLoginResponse()
mock_connection = six.moves.http_client.HTTPSConnection
mock_connection.return_value.getresponse.side_effect = [
fake_login_response,
fake_basic_info,
fake_login_response]
self.assertRaises(
exception.ShareBackendException,
self._do_setup,
'https://1.2.3.4:443',
'1.2.3.4',
'admin',
'qnapadmin',
'Storage Pool 1')
def test_do_setup_with_exception(self):
"""Test do_setup with exception."""
fake_login_response = fakes.FakeLoginResponse()
@ -243,28 +304,81 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
mock_get_location_path):
"""Test create share."""
mock_api_executor = qnap.QnapShareDriver._create_api_executor
mock_api_executor.return_value.get_share_info.return_value = None
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_api_executor.return_value.create_share.return_value = (
'fakeCreateShareId')
mock_get_location_path.return_value = None
mock_private_storage = mock.Mock()
self.mock_object(greenthread, 'sleep')
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage)
self.driver.create_share('context', self.share)
mock_api_executor.return_value.get_share_info.assert_called_once_with(
'Storage Pool 1',
vol_label='fakeShareName')
mock_api_return = mock_api_executor.return_value
expected_call_list = [
mock.call('Storage Pool 1', vol_label='fakeShareName'),
mock.call('Storage Pool 1', vol_label='fakeShareName')]
self.assertEqual(
expected_call_list,
mock_api_return.get_share_info.call_args_list)
mock_api_executor.return_value.create_share.assert_called_once_with(
self.share,
self.driver.configuration.qnap_poolname,
'fakeShareName',
'NFS')
mock_get_location_path.assert_called_once_with(
'fakeShareName', 'NFS', '1.2.3.4')
'fakeShareName', 'NFS', '1.2.3.4', 'fakeNo')
@mock.patch.object(qnap.QnapShareDriver, '_get_location_path')
@mock.patch.object(qnap.QnapShareDriver, '_gen_random_name')
def test_create_share_negative_share_exist(
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.return_value = (
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.mock_object(time, 'sleep')
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage)
self.assertRaises(
exception.ShareBackendException,
self.driver.create_share,
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_create_fail(
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.return_value = None
mock_gen_random_name.return_value = 'fakeShareName'
mock_get_location_path.return_value = None
mock_private_storage = mock.Mock()
self.mock_object(time, 'sleep')
self.mock_object(greenthread, 'sleep')
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage)
self.assertRaises(
exception.ShareBackendException,
self.driver.create_share,
context='context',
share=self.share)
def test_delete_share_positive(self):
"""Test delete share with fake_share."""
@ -323,7 +437,7 @@ 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 = 'fakeVolId'
mock_private_storage.get.return_value = 'fakeVolName'
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1',
@ -331,9 +445,10 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
self.driver.extend_share(self.share, 100, share_server=None)
expect_share_dict = {
"sharename": 'fakeVolId',
"old_sharename": 'fakeVolId',
"new_size": 100,
'sharename': 'fakeVolName',
'old_sharename': 'fakeVolName',
'new_size': 100,
'share_proto': 'NFS'
}
mock_api_executor.return_value.edit_share.assert_called_once_with(
expect_share_dict)
@ -455,10 +570,8 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
mock_api_executor = qnap.QnapShareDriver._create_api_executor
mock_gen_random_name.return_value = 'fakeShareName'
mock_api_executor.return_value.get_share_info.side_effect = (
None, self.get_share_info_return_value())
mock_api_executor.return_value.clone_snapshot.return_value = (
None)
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 = 'fakeSnapshotId'
mock_share_api.return_value.get.return_value = {'size': 10}
@ -495,12 +608,10 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
mock_gen_random_name.return_value = 'fakeShareName'
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_api_executor.return_value.clone_snapshot.return_value = (
None)
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 = 'fakeSnapshotId'
mock_private_storage.get.return_value = 'fakeVolName'
mock_share_api.return_value.get.return_value = {'size': 5}
mock_api_executor.return_value.edit_share.return_value = (
None)
@ -525,7 +636,8 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
expect_share_dict = {
'sharename': 'fakeShareName',
'old_sharename': 'fakeShareName',
'new_size': 10
'new_size': 10,
'share_proto': 'NFS'
}
mock_api_return.edit_share.assert_called_once_with(
expect_share_dict)
@ -548,6 +660,67 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
snapshot=fake_snapshot,
share_server=None)
@mock.patch.object(qnap.QnapShareDriver, '_get_location_path')
@mock.patch('manila.share.API')
@mock.patch.object(qnap.QnapShareDriver, '_gen_random_name')
def test_create_share_from_snapshot_negative_name_exist(
self,
mock_gen_random_name,
mock_share_api,
mock_get_location_path):
"""Test create share from snapshot."""
fake_snapshot = fakes.SnapshotClass(
10, 'fakeShareName@fakeSnapshotName')
mock_api_executor = qnap.QnapShareDriver._create_api_executor
mock_gen_random_name.return_value = 'fakeShareName'
mock_api_executor.return_value.get_share_info.return_value = (
self.get_share_info_return_value())
mock_private_storage = mock.Mock()
mock_private_storage.get.return_value = 'fakeSnapshotId'
mock_share_api.return_value.get.return_value = {'size': 10}
self.mock_object(time, 'sleep')
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage)
self.assertRaises(
exception.ShareBackendException,
self.driver.create_share_from_snapshot,
context='context',
share=self.share,
snapshot=fake_snapshot,
share_server=None)
@mock.patch.object(qnap.QnapShareDriver, '_get_location_path')
@mock.patch('manila.share.API')
@mock.patch.object(qnap.QnapShareDriver, '_gen_random_name')
def test_create_share_from_snapshot_negative_clone_fail(
self,
mock_gen_random_name,
mock_share_api,
mock_get_location_path):
"""Test create share from snapshot."""
fake_snapshot = fakes.SnapshotClass(
10, 'fakeShareName@fakeSnapshotName')
mock_api_executor = qnap.QnapShareDriver._create_api_executor
mock_gen_random_name.return_value = 'fakeShareName'
mock_api_executor.return_value.get_share_info.return_value = None
mock_private_storage = mock.Mock()
mock_private_storage.get.return_value = 'fakeSnapshotId'
mock_share_api.return_value.get.return_value = {'size': 10}
self.mock_object(time, 'sleep')
self._do_setup('http://1.2.3.4:8080', '1.2.3.4', 'admin',
'qnapadmin', 'Storage Pool 1',
private_storage=mock_private_storage)
self.assertRaises(
exception.ShareBackendException,
self.driver.create_share_from_snapshot,
context='context',
share=self.share,
snapshot=fake_snapshot,
share_server=None)
@mock.patch.object(qnap.QnapShareDriver, '_allow_access')
def test_update_access_allow_access(
self, mock_allow_access):
@ -644,7 +817,28 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
mock_api_return.get_specific_volinfo.assert_called_once_with(
'fakeNo')
mock_get_location_path.assert_called_once_with(
'fakeShareName', 'NFS', '1.2.3.4')
'fakeShareName', 'NFS', '1.2.3.4', 'fakeNo')
def test_manage_invalid_protocol(self):
"""Test manage existing."""
share = fake_share.fake_share(
share_proto='fakeProtocol',
id='fakeId',
display_name='fakeDisplayName',
export_locations=[{'path': ''}],
host='QnapShareDriver',
size=10)
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.assertRaises(
exception.InvalidInput,
self.driver.manage_existing,
share=share,
driver_options='driver_options')
def test_manage_existing_nfs_without_export_locations(self):
share = fake_share.fake_share(
@ -820,14 +1014,15 @@ class QnapShareDriverTestCase(QnapShareDriverBaseTestCase):
}
self.assertEqual(
expect_result, self.driver._get_location_path(
'fakeShareName', 'NFS', 'fakeIp'))
'fakeShareName', 'NFS', 'fakeIp', 'fakeVolId'))
self.assertRaises(
exception.InvalidInput,
self.driver._get_location_path,
share_name='fakeShareName',
share_proto='fakeProto',
ip='fakeIp')
ip='fakeIp',
vol_id='fakeVolId')
def test_update_share_stats(self):
"""Test update share stats."""

View File

@ -0,0 +1,4 @@
---
features:
- |
QNAP Manila driver adds support for QES fw 1.1.4.