diff --git a/manila/share/drivers/qnap/api.py b/manila/share/drivers/qnap/api.py
index e3aa7ea1a6..7d70208568 100644
--- a/manila/share/drivers/qnap/api.py
+++ b/manila/share/drivers/qnap/api.py
@@ -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',
diff --git a/manila/share/drivers/qnap/qnap.py b/manila/share/drivers/qnap/qnap.py
index 87e6df1c9b..fedde37c10 100644
--- a/manila/share/drivers/qnap/qnap.py
+++ b/manila/share/drivers/qnap/qnap.py
@@ -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}
diff --git a/manila/tests/share/drivers/qnap/fakes.py b/manila/tests/share/drivers/qnap/fakes.py
index bd735e21bf..22b514d1f0 100644
--- a/manila/tests/share/drivers/qnap/fakes.py
+++ b/manila/tests/share/drivers/qnap/fakes.py
@@ -19,7 +19,18 @@ FAKE_RES_DETAIL_DATA_LOGIN = """
"""
-FAKE_RES_DETAIL_DATA_GETBASIC_INFO_ES = """
+FAKE_RES_DETAIL_DATA_GETBASIC_INFO_ES_1_1_1 = """
+
+
+
+
+
+
+
+
+ """
+
+FAKE_RES_DETAIL_DATA_GETBASIC_INFO_ES_1_1_3 = """
@@ -30,7 +41,18 @@ FAKE_RES_DETAIL_DATA_GETBASIC_INFO_ES = """
"""
-FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TS = """
+FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TS_4_0_0 = """
+
+
+
+
+
+
+
+
+ """
+
+FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TS_4_3_0 = """
@@ -41,7 +63,18 @@ FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TS = """
"""
-FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_TS = """
+FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_TS_4_0_0 = """
+
+
+
+
+
+
+
+
+ """
+
+FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_TS_4_3_0 = """
@@ -52,7 +85,18 @@ FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_TS = """
"""
-FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_ES = """
+FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_ES_1_1_1 = """
+
+
+
+
+
+
+
+
+ """
+
+FAKE_RES_DETAIL_DATA_GETBASIC_INFO_TES_ES_1_1_3 = """
@@ -208,6 +252,20 @@ FAKE_RES_DETAIL_DATA_DELETE_SNAPSHOT = """
0
"""
+FAKE_RES_DETAIL_DATA_DELETE_SNAPSHOT_SNAPSHOT_NOT_EXIST = """
+
+
+
+ -206021
+ """
+
+FAKE_RES_DETAIL_DATA_DELETE_SNAPSHOT_SHARE_NOT_EXIST = """
+
+
+
+ -200005
+ """
+
FAKE_RES_DETAIL_DATA_GET_HOST_LIST_API = """
@@ -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."""
diff --git a/manila/tests/share/drivers/qnap/test_api.py b/manila/tests/share/drivers/qnap/test_api.py
index da46734748..693c7e038c 100644
--- a/manila/tests/share/drivers/qnap/test_api.py
+++ b/manila/tests/share/drivers/qnap/test_api.py
@@ -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),
diff --git a/manila/tests/share/drivers/qnap/test_qnap.py b/manila/tests/share/drivers/qnap/test_qnap.py
index 4fa06dcd2d..41b81f3da5 100644
--- a/manila/tests/share/drivers/qnap/test_qnap.py
+++ b/manila/tests/share/drivers/qnap/test_qnap.py
@@ -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."""
diff --git a/releasenotes/notes/support-qes-114-5881c0ff0e7da512.yaml b/releasenotes/notes/support-qes-114-5881c0ff0e7da512.yaml
new file mode 100644
index 0000000000..27039f74b3
--- /dev/null
+++ b/releasenotes/notes/support-qes-114-5881c0ff0e7da512.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ QNAP Manila driver adds support for QES fw 1.1.4.