Add support for enhanced features to the QNAP Cinder driver
This adds enhanced supports to the QNAP Cinder driver: - CHAP - Thin Provision - SSD Cache - Dedupe - Compression DocImpact Implements: blueprint qnap-enhance-support Change-Id: I2a7440789753bb0e42ac0e8d0190b21652a87e2f
This commit is contained in:
parent
92d9f19f99
commit
08dcf03541
@ -22,6 +22,7 @@ except ImportError:
|
||||
from ddt import data
|
||||
from ddt import ddt
|
||||
from ddt import unpack
|
||||
import eventlet
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import units
|
||||
@ -594,19 +595,26 @@ def create_configuration(
|
||||
management_url,
|
||||
san_iscsi_ip,
|
||||
poolname,
|
||||
thin_provision=True):
|
||||
thin_provision=True,
|
||||
compression=True,
|
||||
deduplication=False,
|
||||
ssd_cache=False):
|
||||
"""Create configuration."""
|
||||
configuration = mock.Mock()
|
||||
configuration.san_login = username
|
||||
configuration.san_password = password
|
||||
configuration.qnap_management_url = management_url
|
||||
configuration.san_thin_provision = thin_provision
|
||||
configuration.qnap_compression = compression
|
||||
configuration.qnap_deduplication = deduplication
|
||||
configuration.qnap_ssd_cache = ssd_cache
|
||||
configuration.san_iscsi_ip = san_iscsi_ip
|
||||
configuration.qnap_poolname = poolname
|
||||
configuration.safe_get.return_value = 'QNAP'
|
||||
configuration.iscsi_ip_address = '1.2.3.4'
|
||||
configuration.qnap_storage_protocol = 'iscsi'
|
||||
configuration.reserved_percentage = 0
|
||||
configuration.use_chap_auth = False
|
||||
return configuration
|
||||
|
||||
|
||||
@ -679,6 +687,14 @@ class VolumeClass(object):
|
||||
'name': 'fakeTargetIqn',
|
||||
'tgt_lun': '1'
|
||||
}
|
||||
self.volume_type = {
|
||||
'extra_specs': {
|
||||
'qnap_thin_provision': 'True',
|
||||
'qnap_compression': 'True',
|
||||
'qnap_deduplication': 'False',
|
||||
'qnap_ssd_cache': 'False'
|
||||
}
|
||||
}
|
||||
|
||||
def __getitem__(self, arg):
|
||||
"""Getitem."""
|
||||
@ -689,7 +705,8 @@ class VolumeClass(object):
|
||||
'name': self.name,
|
||||
'volume_metadata': self.volume_metadata,
|
||||
'metadata': self.metadata,
|
||||
'provider_location': self.provider_location
|
||||
'provider_location': self.provider_location,
|
||||
'volume_type': self.volume_type
|
||||
}[arg]
|
||||
|
||||
def __contains__(self, arg):
|
||||
@ -701,7 +718,8 @@ class VolumeClass(object):
|
||||
'name': self.name,
|
||||
'volume_metadata': self.volume_metadata,
|
||||
'metadata': self.metadata,
|
||||
'provider_location': self.provider_location
|
||||
'provider_location': self.provider_location,
|
||||
'volume_type': self.volume_type
|
||||
}[arg]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
@ -1288,6 +1306,7 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
'1.2.3.4',
|
||||
'Pool1',
|
||||
True))
|
||||
self.mock_object(eventlet, 'sleep')
|
||||
self.driver.do_setup('context')
|
||||
self.driver.create_volume(fake_volume)
|
||||
|
||||
@ -1295,7 +1314,7 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
fake_volume,
|
||||
self.driver.configuration.qnap_poolname,
|
||||
'fakeLun',
|
||||
True)
|
||||
True, False, True, False)
|
||||
|
||||
expected_call_list = [
|
||||
mock.call(LUNName='fakeLun'),
|
||||
@ -1442,6 +1461,7 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
'http://1.2.3.4:8080',
|
||||
'Pool1',
|
||||
True))
|
||||
self.mock_object(eventlet, 'sleep')
|
||||
self.driver.do_setup('context')
|
||||
self.driver.create_cloned_volume(fake_volume, fake_src_vref)
|
||||
|
||||
@ -1506,19 +1526,18 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
'1.2.3.4',
|
||||
'Pool1',
|
||||
True))
|
||||
self.mock_object(eventlet, 'sleep')
|
||||
self.driver.do_setup('context')
|
||||
self.driver.create_cloned_volume(fake_volume, fake_src_vref)
|
||||
|
||||
mock_extend_lun.assert_called_once_with(fake_volume, 'fakeLunNaa')
|
||||
|
||||
@mock.patch('eventlet.greenthread.sleep', return_value=None)
|
||||
@mock.patch.object(qnap.QnapISCSIDriver, '_create_snapshot_name')
|
||||
@mock.patch('cinder.volume.drivers.qnap.QnapAPIExecutor')
|
||||
def test_create_snapshot_positive(
|
||||
self,
|
||||
mock_api_executor,
|
||||
mock_create_snapshot_name,
|
||||
mock_greenthread_sleep):
|
||||
mock_create_snapshot_name):
|
||||
"""Test create snapshot."""
|
||||
fake_volume = VolumeClass(
|
||||
'fakeDisplayName', 'fakeId', 100, 'fakeLunName')
|
||||
@ -1542,6 +1561,7 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
'1.2.3.4',
|
||||
'Pool1',
|
||||
True))
|
||||
self.mock_object(eventlet, 'sleep')
|
||||
self.driver.do_setup('context')
|
||||
self.driver.create_snapshot(snapshot)
|
||||
|
||||
@ -1647,6 +1667,7 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
'1.2.3.4',
|
||||
'Pool1',
|
||||
True))
|
||||
self.mock_object(eventlet, 'sleep')
|
||||
self.driver.do_setup('context')
|
||||
self.driver.create_volume_from_snapshot(fake_volume, fake_snapshot)
|
||||
|
||||
@ -1743,7 +1764,11 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
free_capacity_gb=928732941681 / units.Gi,
|
||||
provisioned_capacity_gb=1480470528 / units.Gi,
|
||||
reserved_percentage=self.driver.configuration.reserved_percentage,
|
||||
QoS_support=False)
|
||||
QoS_support=False,
|
||||
qnap_thin_provision=['True', 'False'],
|
||||
qnap_compression=['True', 'False'],
|
||||
qnap_deduplication=['True', 'False'],
|
||||
qnap_ssd_cache=['True', 'False'])
|
||||
expected_res['pools'] = [single_pool]
|
||||
|
||||
self.assertEqual(
|
||||
@ -1819,7 +1844,6 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
'LUNStatus': '1'}
|
||||
mock_api_return.edit_lun.assert_called_once_with(expect_lun)
|
||||
|
||||
@mock.patch('eventlet.greenthread.sleep', return_value=None)
|
||||
@mock.patch.object(qnap.QnapISCSIDriver,
|
||||
'_get_lun_naa_from_volume_metadata')
|
||||
@mock.patch.object(qnap.QnapISCSIDriver, '_gen_random_name')
|
||||
@ -1828,8 +1852,7 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
self,
|
||||
mock_api_executor,
|
||||
mock_gen_random_name,
|
||||
mock_get_lun_naa_from_volume_metadata,
|
||||
mock_greenthread_sleep):
|
||||
mock_get_lun_naa_from_volume_metadata):
|
||||
"""Test create export."""
|
||||
fake_volume = VolumeClass(
|
||||
'fakeDisplayName', 'fakeId', 100, 'fakeLunName')
|
||||
@ -1847,8 +1870,6 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
mock_api_return.create_target.return_value = 'fakeTargetIndex'
|
||||
mock_api_return.get_target_info.return_value = (
|
||||
self.get_target_info_return_value())
|
||||
mock_api_return.get_all_iscsi_portal_setting.return_value = (
|
||||
FAKE_RES_DETAIL_GET_ALL_ISCSI_PORTAL_SETTING)
|
||||
mock_api_return.map_lun.return_value = None
|
||||
mock_api_return.get_ethernet_ip.return_value = ['1.2.3.4'], None
|
||||
|
||||
@ -1860,7 +1881,11 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
'1.2.3.4',
|
||||
'Pool1',
|
||||
True))
|
||||
self.driver.configuration.use_chap_auth = False
|
||||
self.driver.configuration.chap_username = ''
|
||||
self.driver.configuration.chap_password = ''
|
||||
self.driver.iscsi_port = 'fakeServicePort'
|
||||
self.mock_object(eventlet, 'sleep')
|
||||
self.driver.do_setup('context')
|
||||
|
||||
expected_properties = '%(host)s:%(port)s,1 %(name)s %(tgt_lun)s' % {
|
||||
@ -1874,7 +1899,6 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
self.assertEqual(expected_return, self.driver.create_export(
|
||||
'context', fake_volume, fake_connector))
|
||||
|
||||
@mock.patch('eventlet.greenthread.sleep', return_value=None)
|
||||
@mock.patch.object(qnap.QnapISCSIDriver,
|
||||
'_get_lun_naa_from_volume_metadata')
|
||||
@mock.patch.object(qnap.QnapISCSIDriver, '_gen_random_name')
|
||||
@ -1883,8 +1907,7 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
self,
|
||||
mock_api_executor,
|
||||
mock_gen_random_name,
|
||||
mock_get_lun_naa_from_volume_metadata,
|
||||
mock_greenthread_sleep):
|
||||
mock_get_lun_naa_from_volume_metadata):
|
||||
"""Test create export."""
|
||||
fake_volume = VolumeClass(
|
||||
'fakeDisplayName', 'fakeId', 100, 'fakeLunName')
|
||||
@ -1902,8 +1925,6 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
mock_api_return.create_target.return_value = 'fakeTargetIndex'
|
||||
mock_api_return.get_target_info.return_value = (
|
||||
self.get_target_info_return_value())
|
||||
mock_api_return.get_all_iscsi_portal_setting.return_value = (
|
||||
FAKE_RES_DETAIL_GET_ALL_ISCSI_PORTAL_SETTING)
|
||||
mock_api_return.map_lun.return_value = None
|
||||
mock_api_return.get_ethernet_ip.return_value = ['1.2.3.4'], None
|
||||
|
||||
@ -1915,7 +1936,11 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
'1.2.3.4',
|
||||
'Pool1',
|
||||
True))
|
||||
self.driver.configuration.use_chap_auth = False
|
||||
self.driver.configuration.chap_username = ''
|
||||
self.driver.configuration.chap_password = ''
|
||||
self.driver.iscsi_port = 'fakeServicePort'
|
||||
self.mock_object(eventlet, 'sleep')
|
||||
self.driver.do_setup('context')
|
||||
|
||||
expected_properties = '%(host)s:%(port)s,1 %(name)s %(tgt_lun)s' % {
|
||||
@ -1929,7 +1954,6 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
self.assertEqual(expected_return, self.driver.create_export(
|
||||
'context', fake_volume, fake_connector))
|
||||
|
||||
@mock.patch('eventlet.greenthread.sleep', return_value=None)
|
||||
@mock.patch.object(qnap.QnapISCSIDriver,
|
||||
'_get_lun_naa_from_volume_metadata')
|
||||
@mock.patch.object(qnap.QnapISCSIDriver, '_gen_random_name')
|
||||
@ -1938,8 +1962,7 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
self,
|
||||
mock_api_executor,
|
||||
mock_gen_random_name,
|
||||
mock_get_lun_naa_from_volume_metadata,
|
||||
mock_greenthread_sleep):
|
||||
mock_get_lun_naa_from_volume_metadata):
|
||||
"""Test create export."""
|
||||
fake_volume = VolumeClass(
|
||||
'fakeDisplayName', 'fakeId', 100, 'fakeLunName')
|
||||
@ -1954,8 +1977,6 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
FAKE_RES_DETAIL_ISCSI_PORTAL_INFO)
|
||||
mock_gen_random_name.return_value = 'fakeTargetName'
|
||||
mock_get_lun_naa_from_volume_metadata.return_value = 'fakeLunNaa'
|
||||
mock_api_return.get_target_info_by_initiator.return_value = (
|
||||
'fakeTargetIndex', 'fakeTargetIqn')
|
||||
mock_api_return.create_target.return_value = 'fakeTargetIndex'
|
||||
mock_api_return.get_target_info.return_value = (
|
||||
self.get_target_info_return_value())
|
||||
@ -1971,7 +1992,11 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
'1.2.3.4',
|
||||
'Pool1',
|
||||
True))
|
||||
self.driver.configuration.use_chap_auth = False
|
||||
self.driver.configuration.chap_username = ''
|
||||
self.driver.configuration.chap_password = ''
|
||||
self.driver.iscsi_port = 'fakeServicePort'
|
||||
self.mock_object(eventlet, 'sleep')
|
||||
self.driver.do_setup('context')
|
||||
|
||||
expected_properties = '%(host)s:%(port)s,1 %(name)s %(tgt_lun)s' % {
|
||||
@ -1985,7 +2010,6 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
self.assertEqual(expected_return, self.driver.create_export(
|
||||
'context', fake_volume, fake_connector))
|
||||
|
||||
@mock.patch('eventlet.greenthread.sleep', return_value=None)
|
||||
@mock.patch.object(qnap.QnapISCSIDriver,
|
||||
'_get_lun_naa_from_volume_metadata')
|
||||
@mock.patch.object(qnap.QnapISCSIDriver, '_gen_random_name')
|
||||
@ -1996,8 +2020,7 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
mock_api_executor,
|
||||
mock_api_executor_ts,
|
||||
mock_gen_random_name,
|
||||
mock_get_lun_naa_from_volume_metadata,
|
||||
mock_greenthread_sleep):
|
||||
mock_get_lun_naa_from_volume_metadata):
|
||||
"""Test create export."""
|
||||
fake_volume = VolumeClass(
|
||||
'fakeDisplayName', 'fakeId', 100, 'fakeLunName')
|
||||
@ -2016,8 +2039,6 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
mock_api_return.create_target.return_value = 'fakeTargetIndex'
|
||||
mock_api_return.get_target_info.return_value = (
|
||||
self.get_target_info_return_value())
|
||||
mock_api_return.get_all_iscsi_portal_setting.return_value = (
|
||||
FAKE_RES_DETAIL_GET_ALL_ISCSI_PORTAL_SETTING)
|
||||
mock_api_return.map_lun.return_value = None
|
||||
mock_api_return.get_ethernet_ip.return_value = ['1.2.3.4'], None
|
||||
|
||||
@ -2029,7 +2050,11 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
'1.2.3.4',
|
||||
'Storage Pool 1',
|
||||
True))
|
||||
self.driver.configuration.use_chap_auth = False
|
||||
self.driver.configuration.chap_username = ''
|
||||
self.driver.configuration.chap_password = ''
|
||||
self.driver.iscsi_port = 'fakeServicePort'
|
||||
self.mock_object(eventlet, 'sleep')
|
||||
self.driver.do_setup('context')
|
||||
|
||||
expected_properties = '%(host)s:%(port)s,1 %(name)s %(tgt_lun)s' % {
|
||||
@ -2109,6 +2134,9 @@ class QnapDriverVolumeTestCase(QnapDriverBaseTestCase):
|
||||
'1.2.3.4',
|
||||
'Pool1',
|
||||
True))
|
||||
self.driver.configuration.use_chap_auth = False
|
||||
self.driver.configuration.chap_username = ''
|
||||
self.driver.configuration.chap_password = ''
|
||||
self.driver.iscsi_port = 'fakeServicePort'
|
||||
self.driver.do_setup('context')
|
||||
|
||||
@ -2332,7 +2360,7 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
self.assertEqual(
|
||||
'fakeLunIndex',
|
||||
self.driver.api_executor.create_lun(
|
||||
fake_volume, 'fakepool', 'fakeLun', True))
|
||||
fake_volume, 'fakepool', 'fakeLun', True, False, True, False))
|
||||
|
||||
fake_params = {}
|
||||
fake_params['func'] = 'add_lun'
|
||||
@ -2342,6 +2370,8 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
fake_params['LUNPath'] = 'fakeLun'
|
||||
fake_params['poolID'] = 'fakepool'
|
||||
fake_params['lv_ifssd'] = 'no'
|
||||
fake_params['compression'] = '1'
|
||||
fake_params['dedup'] = 'off'
|
||||
fake_params['LUNCapacity'] = 100
|
||||
fake_params['lv_threshold'] = '80'
|
||||
fake_params['sid'] = 'fakeSid'
|
||||
@ -2392,7 +2422,7 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
self.assertEqual(
|
||||
'fakeLunIndex',
|
||||
self.driver.api_executor.create_lun(
|
||||
fake_volume, 'fakepool', 'fakeLun', False))
|
||||
fake_volume, 'fakepool', 'fakeLun', False, False, True, False))
|
||||
|
||||
fake_params = {}
|
||||
fake_params['func'] = 'add_lun'
|
||||
@ -2402,6 +2432,8 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
fake_params['LUNPath'] = 'fakeLun'
|
||||
fake_params['poolID'] = 'fakepool'
|
||||
fake_params['lv_ifssd'] = 'no'
|
||||
fake_params['compression'] = '1'
|
||||
fake_params['dedup'] = 'off'
|
||||
fake_params['LUNCapacity'] = 100
|
||||
fake_params['lv_threshold'] = '80'
|
||||
fake_params['sid'] = 'fakeSid'
|
||||
@ -2453,7 +2485,8 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.api_executor.create_lun,
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False')
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False',
|
||||
'False', 'True', 'False')
|
||||
|
||||
@mock.patch('six.moves.http_client.HTTPConnection')
|
||||
def test_create_lun_negative_with_wrong_result(
|
||||
@ -2481,7 +2514,8 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.api_executor.create_lun,
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False')
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False',
|
||||
'False', 'True', 'False')
|
||||
|
||||
@mock.patch('six.moves.http_client.HTTPConnection')
|
||||
def test_delete_lun(
|
||||
@ -2845,7 +2879,7 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
True))
|
||||
self.driver.do_setup('context')
|
||||
self.driver.api_executor.add_target_init(
|
||||
'fakeTargetIqn', 'fakeInitiatorIqn')
|
||||
'fakeTargetIqn', 'fakeInitiatorIqn', False, '', '')
|
||||
|
||||
fake_params = {}
|
||||
fake_params['func'] = 'add_init'
|
||||
@ -2905,7 +2939,7 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
self.driver.do_setup('context')
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.api_executor.add_target_init,
|
||||
'fakeTargetIqn', 'fakeInitiatorIqn')
|
||||
'fakeTargetIqn', 'fakeInitiatorIqn', False, '', '')
|
||||
|
||||
@mock.patch('six.moves.http_client.HTTPConnection')
|
||||
def test_add_target_init_negative_with_wrong_result(
|
||||
@ -2929,7 +2963,7 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
self.driver.do_setup('context')
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.api_executor.add_target_init,
|
||||
'fakeTargetIqn', 'fakeInitiatorIqn')
|
||||
'fakeTargetIqn', 'fakeInitiatorIqn', False, '', '')
|
||||
|
||||
@mock.patch('six.moves.http_client.HTTPConnection')
|
||||
def test_remove_target_init(
|
||||
@ -4531,7 +4565,7 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
True))
|
||||
self.driver.do_setup('context')
|
||||
self.driver.api_executor.get_target_info_by_initiator(
|
||||
'fakeInitiatorIQN', 'fakeLunSlotId')
|
||||
'fakeInitiatorIQN')
|
||||
|
||||
fake_params = {}
|
||||
fake_params['func'] = 'extra_get'
|
||||
@ -4582,7 +4616,7 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.api_executor.
|
||||
get_target_info_by_initiator,
|
||||
'fakeInitiatorIQN', 'fakeLunSlotId')
|
||||
'fakeInitiatorIQN')
|
||||
|
||||
@mock.patch('six.moves.http_client.HTTPConnection')
|
||||
def test_get_target_info_by_initiator_with_wrong_result(
|
||||
@ -4605,7 +4639,7 @@ class QnapAPIExecutorEsTestCase(QnapDriverBaseTestCase):
|
||||
True))
|
||||
self.driver.do_setup('context')
|
||||
self.driver.api_executor.get_target_info_by_initiator(
|
||||
'fakeInitiatorIQN', 'fakeLunSlotId')
|
||||
'fakeInitiatorIQN')
|
||||
|
||||
fake_params = {}
|
||||
fake_params['func'] = 'extra_get'
|
||||
@ -4662,7 +4696,7 @@ class QnapAPIExecutorTsTestCase(QnapDriverBaseTestCase):
|
||||
self.assertEqual(
|
||||
'fakeLunIndex',
|
||||
self.driver.api_executor.create_lun(
|
||||
fake_volume, 'fakepool', 'fakeLun', True))
|
||||
fake_volume, 'fakepool', 'fakeLun', True, False, True, False))
|
||||
|
||||
fake_params = {}
|
||||
fake_params['func'] = 'add_lun'
|
||||
@ -4722,7 +4756,7 @@ class QnapAPIExecutorTsTestCase(QnapDriverBaseTestCase):
|
||||
self.assertEqual(
|
||||
'fakeLunIndex',
|
||||
self.driver.api_executor.create_lun(
|
||||
fake_volume, 'fakepool', 'fakeLun', False))
|
||||
fake_volume, 'fakepool', 'fakeLun', False, False, True, False))
|
||||
|
||||
fake_params = {}
|
||||
fake_params['func'] = 'add_lun'
|
||||
@ -4783,7 +4817,8 @@ class QnapAPIExecutorTsTestCase(QnapDriverBaseTestCase):
|
||||
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.api_executor.create_lun,
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False')
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False',
|
||||
'False', 'True', 'False')
|
||||
|
||||
@mock.patch('six.moves.http_client.HTTPConnection')
|
||||
def test_create_lun_negative_with_wrong_result(
|
||||
@ -4811,7 +4846,8 @@ class QnapAPIExecutorTsTestCase(QnapDriverBaseTestCase):
|
||||
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.api_executor.create_lun,
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False')
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False',
|
||||
'False', 'True', 'False')
|
||||
|
||||
@mock.patch('six.moves.http_client.HTTPConnection')
|
||||
def test_delete_lun(
|
||||
@ -5742,7 +5778,7 @@ class QnapAPIExecutorTesTestCase(QnapDriverBaseTestCase):
|
||||
self.assertEqual(
|
||||
'fakeLunIndex',
|
||||
self.driver.api_executor.create_lun(
|
||||
fake_volume, 'fakepool', 'fakeLun', True))
|
||||
fake_volume, 'fakepool', 'fakeLun', True, False, True, False))
|
||||
|
||||
fake_params = {}
|
||||
fake_params['func'] = 'add_lun'
|
||||
@ -5752,6 +5788,8 @@ class QnapAPIExecutorTesTestCase(QnapDriverBaseTestCase):
|
||||
fake_params['LUNPath'] = 'fakeLun'
|
||||
fake_params['poolID'] = 'fakepool'
|
||||
fake_params['lv_ifssd'] = 'no'
|
||||
fake_params['compression'] = '1'
|
||||
fake_params['dedup'] = 'off'
|
||||
fake_params['sync'] = 'disabled'
|
||||
fake_params['LUNCapacity'] = 100
|
||||
fake_params['lv_threshold'] = '80'
|
||||
@ -5803,7 +5841,7 @@ class QnapAPIExecutorTesTestCase(QnapDriverBaseTestCase):
|
||||
self.assertEqual(
|
||||
'fakeLunIndex',
|
||||
self.driver.api_executor.create_lun(
|
||||
fake_volume, 'fakepool', 'fakeLun', False))
|
||||
fake_volume, 'fakepool', 'fakeLun', False, False, True, False))
|
||||
|
||||
fake_params = {}
|
||||
fake_params['func'] = 'add_lun'
|
||||
@ -5813,6 +5851,8 @@ class QnapAPIExecutorTesTestCase(QnapDriverBaseTestCase):
|
||||
fake_params['LUNPath'] = 'fakeLun'
|
||||
fake_params['poolID'] = 'fakepool'
|
||||
fake_params['lv_ifssd'] = 'no'
|
||||
fake_params['compression'] = '1'
|
||||
fake_params['dedup'] = 'off'
|
||||
fake_params['sync'] = 'disabled'
|
||||
fake_params['LUNCapacity'] = 100
|
||||
fake_params['lv_threshold'] = '80'
|
||||
@ -5865,7 +5905,8 @@ class QnapAPIExecutorTesTestCase(QnapDriverBaseTestCase):
|
||||
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.api_executor.create_lun,
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False')
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False',
|
||||
'False', 'True', 'False')
|
||||
|
||||
@mock.patch('six.moves.http_client.HTTPConnection')
|
||||
def test_create_lun_negative_with_wrong_result(
|
||||
@ -5893,7 +5934,8 @@ class QnapAPIExecutorTesTestCase(QnapDriverBaseTestCase):
|
||||
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.api_executor.create_lun,
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False')
|
||||
fake_volume, 'fakepool', 'fakeLun', 'False',
|
||||
'False', 'True', 'False')
|
||||
|
||||
@mock.patch('six.moves.http_client.HTTPConnection')
|
||||
def test_get_ethernet_ip_with_type(
|
||||
|
@ -31,6 +31,7 @@ except ImportError:
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import strutils
|
||||
from oslo_utils import timeutils
|
||||
from oslo_utils import units
|
||||
import six
|
||||
@ -62,16 +63,23 @@ CONF.register_opts(qnap_opts, group=configuration.SHARED_CONF_GROUP)
|
||||
|
||||
@interface.volumedriver
|
||||
class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
"""OpenStack driver to enable QNAP Storage.
|
||||
"""QNAP iSCSI based cinder driver
|
||||
|
||||
.. code-block:: default
|
||||
|
||||
Version History:
|
||||
1.0.0:
|
||||
Initial driver (Only iSCSI).
|
||||
1.2.001:
|
||||
Add supports for Thin Provisioning, SSD Cache, Deduplication
|
||||
, Compression and CHAP.
|
||||
|
||||
Version history:
|
||||
1.0.0 - Initial driver (Only iSCSI)
|
||||
"""
|
||||
|
||||
# ThirdPartySystems wiki page
|
||||
CI_WIKI_NAME = "QNAP_CI"
|
||||
|
||||
VERSION = '1.1.021'
|
||||
VERSION = '1.2.001'
|
||||
|
||||
TIME_INTERVAL = 3
|
||||
|
||||
@ -103,6 +111,22 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
raise exception.InvalidInput(
|
||||
reason=_('%s is not set.') % attr)
|
||||
|
||||
if not self.configuration.use_chap_auth:
|
||||
self.configuration.chap_username = ''
|
||||
self.configuration.chap_password = ''
|
||||
else:
|
||||
if not str.isalnum(self.configuration.chap_username):
|
||||
# invalid chap_username
|
||||
LOG.error('Username must be single-byte alphabet or number.')
|
||||
raise exception.InvalidInput(
|
||||
reason=_('Username must be single-byte '
|
||||
'alphabet or number.'))
|
||||
if not 12 <= len(self.configuration.chap_password) <= 16:
|
||||
# invalid chap_password
|
||||
LOG.error('Password must contain 12-16 characters.')
|
||||
raise exception.InvalidInput(
|
||||
reason=_('Password must contain 12-16 characters.'))
|
||||
|
||||
def do_setup(self, context):
|
||||
"""Setup the QNAP Cinder volume driver."""
|
||||
self._check_config()
|
||||
@ -111,7 +135,7 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
|
||||
# Setup API Executor
|
||||
try:
|
||||
self.api_executor = self.creat_api_executor()
|
||||
self.api_executor = self.create_api_executor()
|
||||
except Exception:
|
||||
LOG.error('Failed to create HTTP client. '
|
||||
'Check ip, port, username, password'
|
||||
@ -123,7 +147,7 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
"""Check the status of setup."""
|
||||
pass
|
||||
|
||||
def creat_api_executor(self):
|
||||
def create_api_executor(self):
|
||||
"""Create api executor by nas model."""
|
||||
self.api_executor = QnapAPIExecutor(
|
||||
username=self.configuration.san_login,
|
||||
@ -229,12 +253,60 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
break
|
||||
return create_lun_name
|
||||
|
||||
def _parse_boolean_extra_spec(self, extra_spec_value):
|
||||
"""Parse boolean value from extra spec.
|
||||
|
||||
Parse extra spec values of the form '<is> True' , '<is> False',
|
||||
'True' and 'False'.
|
||||
"""
|
||||
|
||||
if not isinstance(extra_spec_value, six.string_types):
|
||||
extra_spec_value = six.text_type(extra_spec_value)
|
||||
|
||||
match = re.match(r'^<is>\s*(?P<value>True|False)$',
|
||||
extra_spec_value.strip(),
|
||||
re.IGNORECASE)
|
||||
if match:
|
||||
extra_spec_value = match.group('value')
|
||||
return strutils.bool_from_string(extra_spec_value, strict=True)
|
||||
|
||||
def create_volume(self, volume):
|
||||
"""Create a new volume."""
|
||||
start_time = time.time()
|
||||
LOG.debug('in create_volume')
|
||||
LOG.debug('volume: %s', volume.__dict__)
|
||||
reserve = self.configuration.san_thin_provision
|
||||
try:
|
||||
extra_specs = volume["volume_type"]["extra_specs"]
|
||||
LOG.debug('extra_spec: %s', extra_specs)
|
||||
qnap_thin_provision = self._parse_boolean_extra_spec(
|
||||
extra_specs.get('qnap_thin_provision', 'true'))
|
||||
qnap_compression = self._parse_boolean_extra_spec(
|
||||
extra_specs.get('qnap_compression', 'true'))
|
||||
qnap_deduplication = self._parse_boolean_extra_spec(
|
||||
extra_specs.get('qnap_deduplication', 'false'))
|
||||
qnap_ssd_cache = self._parse_boolean_extra_spec(
|
||||
extra_specs.get('qnap_ssd_cache', 'false'))
|
||||
except TypeError:
|
||||
LOG.debug('Unable to retrieve extra specs info. '
|
||||
'Use default extra spec.')
|
||||
qnap_thin_provision = True
|
||||
qnap_compression = True
|
||||
qnap_deduplication = False
|
||||
qnap_ssd_cache = 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):
|
||||
LOG.debug('Dedupe cannot be enabled without thin_provisioning.')
|
||||
raise exception.VolumeBackendAPIException(
|
||||
data=_('Dedupe cannot be enabled without thin_provisioning.'))
|
||||
|
||||
# User could create two volume with the same name on horizon.
|
||||
# Therefore, We should not use display name to create lun on nas.
|
||||
@ -244,7 +316,10 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
volume,
|
||||
self.configuration.qnap_poolname,
|
||||
create_lun_name,
|
||||
reserve)
|
||||
qnap_thin_provision,
|
||||
qnap_ssd_cache,
|
||||
qnap_compression,
|
||||
qnap_deduplication)
|
||||
|
||||
max_wait_sec = 600
|
||||
try_times = 0
|
||||
@ -590,7 +665,11 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
free_capacity_gb=freesize_bytes / units.Gi,
|
||||
provisioned_capacity_gb=provisioned_bytes / units.Gi,
|
||||
reserved_percentage=self.configuration.reserved_percentage,
|
||||
QoS_support=False)
|
||||
QoS_support=False,
|
||||
qnap_thin_provision=["True", "False"],
|
||||
qnap_compression=["True", "False"],
|
||||
qnap_deduplication=["True", "False"],
|
||||
qnap_ssd_cache=["True", "False"])
|
||||
self.group_stats['pools'] = [single_pool]
|
||||
|
||||
return self.group_stats
|
||||
@ -627,51 +706,6 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
|
||||
target_index = ''
|
||||
target_iqn = ''
|
||||
if 'ES' in internal_model_name.upper() and fw_version == "1.1.4":
|
||||
LOG.debug('in ES FW after 1.1.4: get_target_info_by_initiator')
|
||||
target_index, target_iqn = (self.api_executor
|
||||
.get_target_info_by_initiator
|
||||
(connector['initiator'], lun_slot_id))
|
||||
LOG.debug('get_target_info_by_initiator target_index: %s',
|
||||
target_index)
|
||||
LOG.debug('get_target_info_by_initiator target_iqn: %s',
|
||||
target_iqn)
|
||||
else:
|
||||
ret = self.api_executor.get_all_iscsi_portal_setting()
|
||||
root = ET.fromstring(ret['data'])
|
||||
# find the targets have acl with connector['initiator']
|
||||
target_with_initiator_list = []
|
||||
target_acl_tree = root.find('targetACL')
|
||||
target_acl_list = target_acl_tree.findall('row')
|
||||
tmp_target_iqn = ''
|
||||
for targetACL in target_acl_list:
|
||||
tmp_target_iqn = targetACL.find('targetIQN').text
|
||||
# If lun and the targetiqn in different controller,
|
||||
# skip the targetiqn, in case lun in sca map to target of scb
|
||||
LOG.debug('lun_slot_id: %s', lun_slot_id)
|
||||
LOG.debug('tmp_target_iqn[-1]: %s', tmp_target_iqn[-1])
|
||||
if (lun_slot_id != ''):
|
||||
if (lun_slot_id != tmp_target_iqn[-1]):
|
||||
LOG.debug('skip the targetiqn')
|
||||
continue
|
||||
|
||||
target_init_info_list = targetACL.findall('targetInitInfo')
|
||||
for targetInitInfo in target_init_info_list:
|
||||
if(targetInitInfo.find('initiatorIQN').text ==
|
||||
connector['initiator']):
|
||||
target_with_initiator_list.append(
|
||||
targetACL.find('targetIndex').text)
|
||||
|
||||
# find the target in target_with_initiator_list with ready status
|
||||
target_tree = root.find('iSCSITargetList')
|
||||
target_list = target_tree.findall('targetInfo')
|
||||
for target_with_initiator in target_with_initiator_list:
|
||||
for target in target_list:
|
||||
if(target_with_initiator ==
|
||||
target.find('targetIndex').text):
|
||||
if int(target.find('targetStatus').text) >= 0:
|
||||
target_index = target_with_initiator
|
||||
target_iqn = target.find('targetIQN').text
|
||||
|
||||
# create a new target if no target has ACL connector['initiator']
|
||||
LOG.debug('exist target_index: %s', target_index)
|
||||
@ -703,7 +737,10 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
self.api_executor.remove_target_init(target_iqn, default_acl)
|
||||
# add ACL
|
||||
self.api_executor.add_target_init(
|
||||
target_iqn, connector['initiator'])
|
||||
target_iqn, connector['initiator'],
|
||||
self.configuration.use_chap_auth,
|
||||
self.configuration.chap_username,
|
||||
self.configuration.chap_password)
|
||||
|
||||
# Get information for multipath
|
||||
target_iqns = []
|
||||
@ -799,11 +836,7 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
LOG.debug('connector: %s', connector['initiator'])
|
||||
|
||||
iscsi_port, target_index, target_iqn, target_iqns, target_portals = (
|
||||
Util.retriveFormCache(connector['initiator'] +
|
||||
self.configuration.qnap_management_url,
|
||||
lambda: self._get_portal_info(
|
||||
volume, connector, lun_slot_id, lun_owner),
|
||||
30))
|
||||
self._get_portal_info(volume, connector, lun_slot_id, lun_owner))
|
||||
|
||||
self.api_executor.map_lun(lun_index, target_index)
|
||||
|
||||
@ -882,6 +915,12 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
'tgt_lun': target_lun_id,
|
||||
}
|
||||
|
||||
if self.configuration.use_chap_auth:
|
||||
provider_auth = 'CHAP %s %s' % (self.configuration.chap_username,
|
||||
self.configuration.chap_password)
|
||||
else:
|
||||
provider_auth = None
|
||||
|
||||
elapsed_time = time.time() - start_time
|
||||
LOG.debug('create_export elapsed_time: %s', elapsed_time)
|
||||
|
||||
@ -890,7 +929,7 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
|
||||
return (
|
||||
{'provider_location': provider_location,
|
||||
'provider_auth': None})
|
||||
'provider_auth': provider_auth})
|
||||
|
||||
def initialize_connection(self, volume, connector):
|
||||
start_time = time.time()
|
||||
@ -921,6 +960,11 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
properties['target_lun'] = target_lun_id
|
||||
properties['volume_id'] = volume['id'] # used by xen currently
|
||||
|
||||
if self.configuration.use_chap_auth:
|
||||
properties['auth_method'] = 'CHAP'
|
||||
properties['auth_username'] = self.configuration.chap_username
|
||||
properties['auth_password'] = self.configuration.chap_password
|
||||
|
||||
elapsed_time = time.time() - start_time
|
||||
LOG.debug('initialize_connection elapsed_time: %s', elapsed_time)
|
||||
|
||||
@ -1007,6 +1051,7 @@ class QnapISCSIDriver(san.SanISCSIDriver):
|
||||
elapsed_time = time.time() - start_time
|
||||
|
||||
LOG.debug('terminate_connection elapsed_time : %s', elapsed_time)
|
||||
self.api_executor.delete_target(target_index)
|
||||
|
||||
def update_migrated_volume(
|
||||
self, context, volume, new_volume, original_volume_status):
|
||||
@ -1217,7 +1262,8 @@ class QnapAPIExecutor(object):
|
||||
return res_details
|
||||
|
||||
@_connection_checker
|
||||
def create_lun(self, volume, pool_name, create_lun_name, reserve):
|
||||
def create_lun(self, volume, pool_name, create_lun_name, reserve,
|
||||
ssd_cache, compress, dedup):
|
||||
"""Create lun."""
|
||||
self.es_create_lun_lock.acquire()
|
||||
|
||||
@ -1236,7 +1282,9 @@ class QnapAPIExecutor(object):
|
||||
LUNName=create_lun_name,
|
||||
LUNPath=create_lun_name,
|
||||
poolID=pool_name,
|
||||
lv_ifssd='no',
|
||||
lv_ifssd='yes' if ssd_cache else 'no',
|
||||
compression='1' if compress else '0',
|
||||
dedup='sha256' if dedup else 'off',
|
||||
LUNCapacity=volume['size'],
|
||||
lv_threshold='80',
|
||||
sid=self.sid)
|
||||
@ -1337,7 +1385,24 @@ class QnapAPIExecutor(object):
|
||||
return targetIndex
|
||||
|
||||
@_connection_checker
|
||||
def add_target_init(self, target_iqn, init_iqn):
|
||||
def delete_target(self, target_index):
|
||||
"""Delete target on nas."""
|
||||
res_details = self._get_res_details(
|
||||
'/cgi-bin/disk/iscsi_target_setting.cgi?',
|
||||
func='remove_target',
|
||||
targetIndex=target_index,
|
||||
sid=self.sid)
|
||||
root = ET.fromstring(res_details['data'])
|
||||
if root.find('authPassed').text == '0':
|
||||
raise exception.VolumeBackendAPIException(
|
||||
data=_('Session id expired'))
|
||||
if root.find('result').text != '0':
|
||||
raise exception.VolumeBackendAPIException(
|
||||
data=_('Delete target failed'))
|
||||
|
||||
@_connection_checker
|
||||
def add_target_init(self, target_iqn, init_iqn, use_chap_auth,
|
||||
chap_username, chap_password):
|
||||
"""Add target acl."""
|
||||
res_details = self._get_res_details(
|
||||
'/cgi-bin/disk/iscsi_target_setting.cgi?',
|
||||
@ -1345,9 +1410,9 @@ class QnapAPIExecutor(object):
|
||||
targetIQN=target_iqn,
|
||||
initiatorIQN=init_iqn,
|
||||
initiatorAlias=init_iqn,
|
||||
bCHAPEnable='0',
|
||||
CHAPUserName='',
|
||||
CHAPPasswd='',
|
||||
bCHAPEnable='1' if use_chap_auth else '0',
|
||||
CHAPUserName=chap_username,
|
||||
CHAPPasswd=chap_password,
|
||||
bMutualCHAPEnable='0',
|
||||
mutualCHAPUserName='',
|
||||
mutualCHAPPasswd='',
|
||||
@ -1694,12 +1759,12 @@ class QnapAPIExecutor(object):
|
||||
return target
|
||||
|
||||
@_connection_checker
|
||||
def get_target_info_by_initiator(self, initiator_iqn, lun_slot_id):
|
||||
def get_target_info_by_initiator(self, initiatorIQN):
|
||||
"""Get target info by initiatorIQN."""
|
||||
res_details = self._get_res_details(
|
||||
'/cgi-bin/disk/iscsi_portal_setting.cgi?',
|
||||
func='extra_get',
|
||||
initiatorIQN=initiator_iqn,
|
||||
initiatorIQN=initiatorIQN,
|
||||
sid=self.sid)
|
||||
|
||||
root = ET.fromstring(res_details['data'])
|
||||
@ -1709,22 +1774,11 @@ class QnapAPIExecutor(object):
|
||||
if root.find('result').text < '0':
|
||||
return "", ""
|
||||
|
||||
target_acl_tree = root.find('targetACL')
|
||||
target_acl_list = target_acl_tree.findall('row')
|
||||
for target_acl in target_acl_list:
|
||||
target_iqn = target_acl.find('targetIQN').text
|
||||
# If lun and the targetiqn in different controller,
|
||||
# skip the targetiqn, in case lun in sca map to target of scb
|
||||
LOG.debug('lun_slot_id: %s', lun_slot_id)
|
||||
LOG.debug('target_iqn[-1]: %s', target_iqn[-1])
|
||||
if (lun_slot_id != ''):
|
||||
if (lun_slot_id != target_iqn[-1]):
|
||||
LOG.debug('skip the targetiqn')
|
||||
continue
|
||||
target_index = target_acl.find('targetIndex').text
|
||||
if int(target_acl.find('targetStatus').text) >= 0:
|
||||
return target_index, target_iqn
|
||||
return "", ""
|
||||
target = root.find('targetACL').find('row')
|
||||
targetIndex = target.find('targetIndex').text
|
||||
targetIQN = target.find('targetIQN').text
|
||||
|
||||
return targetIndex, targetIQN
|
||||
|
||||
|
||||
class QnapAPIExecutorTS(QnapAPIExecutor):
|
||||
@ -1734,7 +1788,8 @@ class QnapAPIExecutorTS(QnapAPIExecutor):
|
||||
lun_locks = {}
|
||||
|
||||
@_connection_checker
|
||||
def create_lun(self, volume, pool_name, create_lun_name, reserve):
|
||||
def create_lun(self, volume, pool_name, create_lun_name, reserve,
|
||||
ssd_cache, compress, dedup):
|
||||
"""Create lun."""
|
||||
self.create_lun_lock.acquire()
|
||||
|
||||
@ -1753,7 +1808,7 @@ class QnapAPIExecutorTS(QnapAPIExecutor):
|
||||
LUNName=create_lun_name,
|
||||
LUNPath=create_lun_name,
|
||||
poolID=pool_name,
|
||||
lv_ifssd='no',
|
||||
lv_ifssd='yes' if ssd_cache else 'no',
|
||||
LUNCapacity=volume['size'],
|
||||
lv_threshold='80',
|
||||
sid=self.sid)
|
||||
@ -2006,13 +2061,30 @@ class QnapAPIExecutorTS(QnapAPIExecutor):
|
||||
targetIndex = root.find('result').text
|
||||
return targetIndex
|
||||
|
||||
@_connection_checker
|
||||
def delete_target(self, target_index):
|
||||
"""Delete target on nas."""
|
||||
res_details = self._get_res_details(
|
||||
'/cgi-bin/disk/iscsi_target_setting.cgi?',
|
||||
func='remove_target',
|
||||
targetIndex=target_index,
|
||||
sid=self.sid)
|
||||
root = ET.fromstring(res_details['data'])
|
||||
if root.find('authPassed').text == '0':
|
||||
raise exception.VolumeBackendAPIException(
|
||||
data=_('Session id expired'))
|
||||
if root.find('result').text != target_index:
|
||||
raise exception.VolumeBackendAPIException(
|
||||
data=_('Delete target failed'))
|
||||
|
||||
|
||||
class QnapAPIExecutorTES(QnapAPIExecutor):
|
||||
"""Makes QNAP API calls for TES NAS."""
|
||||
tes_create_lun_lock = threading.Lock()
|
||||
|
||||
@_connection_checker
|
||||
def create_lun(self, volume, pool_name, create_lun_name, reserve):
|
||||
def create_lun(self, volume, pool_name, create_lun_name, reserve,
|
||||
ssd_cache, compress, dedup):
|
||||
"""Create lun."""
|
||||
self.tes_create_lun_lock.acquire()
|
||||
|
||||
@ -2031,7 +2103,9 @@ class QnapAPIExecutorTES(QnapAPIExecutor):
|
||||
LUNName=create_lun_name,
|
||||
LUNPath=create_lun_name,
|
||||
poolID=pool_name,
|
||||
lv_ifssd='no',
|
||||
lv_ifssd='yes' if ssd_cache else 'no',
|
||||
compression='1' if compress else '0',
|
||||
dedup='sha256' if dedup else 'off',
|
||||
sync='disabled',
|
||||
LUNCapacity=volume['size'],
|
||||
lv_threshold='80',
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add enhanced support to the QNAP Cinder driver, including
|
||||
'CHAP', 'Thin Provision', 'SSD Cache', 'Dedup' and 'Compression'.
|
Loading…
Reference in New Issue
Block a user