Merge "Fujitsu Driver: Update extend volume functionality"
This commit is contained in:
commit
2a18843ab9
@ -176,7 +176,7 @@ FAKE_POOLS = [{
|
||||
}]
|
||||
|
||||
FAKE_STATS = {
|
||||
'driver_version': '1.4.0',
|
||||
'driver_version': '1.4.1',
|
||||
'storage_protocol': 'iSCSI',
|
||||
'vendor_name': 'FUJITSU',
|
||||
'QoS_support': True,
|
||||
@ -186,7 +186,7 @@ FAKE_STATS = {
|
||||
'pools': FAKE_POOLS,
|
||||
}
|
||||
FAKE_STATS2 = {
|
||||
'driver_version': '1.4.0',
|
||||
'driver_version': '1.4.1',
|
||||
'storage_protocol': 'FC',
|
||||
'vendor_name': 'FUJITSU',
|
||||
'QoS_support': True,
|
||||
@ -1008,6 +1008,8 @@ class FJFCDriverTestCase(test.TestCase):
|
||||
'3B\r\nf.ce\tMaintainer\t01\t00'
|
||||
'\t00\t00\r\ntestuser\tSoftware'
|
||||
'\t01\t01\t00\t00\r\nCLI> ' % exec_cmdline)
|
||||
elif exec_cmdline.startswith('expand volume'):
|
||||
ret = '%s\r\n00\r\nCLI> ' % exec_cmdline
|
||||
elif exec_cmdline.startswith('set volume-qos'):
|
||||
ret = '%s\r\n00\r\n0001\r\nCLI> ' % exec_cmdline
|
||||
elif exec_cmdline.startswith('show volumes'):
|
||||
@ -1176,19 +1178,27 @@ class FJFCDriverTestCase(test.TestCase):
|
||||
self.driver.delete_volume(TEST_VOLUME)
|
||||
|
||||
def test_extend_volume(self):
|
||||
model_info = self.driver.create_volume(TEST_VOLUME)
|
||||
self.assertEqual(FAKE_MODEL_INFO1, model_info)
|
||||
# Test the extension of volume created on RaidGroup and
|
||||
# ThinProvisioningPool separately.
|
||||
TEST_VOLUME_LIST = [TEST_VOLUME, TEST_VOLUME2]
|
||||
FAKE_MODEL_INFO_LIST = [FAKE_MODEL_INFO1, FAKE_MODEL_INFO3]
|
||||
model_info_list = []
|
||||
for i in range(len(TEST_VOLUME_LIST)):
|
||||
model_info = self.driver.create_volume(TEST_VOLUME_LIST[i])
|
||||
self.assertEqual(FAKE_MODEL_INFO_LIST[i], model_info)
|
||||
model_info_list.append(model_info)
|
||||
|
||||
volume_info = {}
|
||||
for key in TEST_VOLUME:
|
||||
if key == 'provider_location':
|
||||
volume_info[key] = model_info[key]
|
||||
elif key == 'metadata':
|
||||
volume_info[key] = model_info[key]
|
||||
else:
|
||||
volume_info[key] = TEST_VOLUME[key]
|
||||
for i in range(len(TEST_VOLUME_LIST)):
|
||||
volume_info = {}
|
||||
for key in TEST_VOLUME_LIST[i]:
|
||||
if key == 'provider_location':
|
||||
volume_info[key] = model_info_list[i][key]
|
||||
elif key == 'metadata':
|
||||
volume_info[key] = model_info_list[i][key]
|
||||
else:
|
||||
volume_info[key] = TEST_VOLUME_LIST[i][key]
|
||||
|
||||
self.driver.extend_volume(volume_info, 10)
|
||||
self.driver.extend_volume(volume_info, 10)
|
||||
|
||||
def test_create_volume_with_qos(self):
|
||||
self.driver.common._get_qos_specs = mock.Mock()
|
||||
@ -1245,6 +1255,8 @@ class FJISCSIDriverTestCase(test.TestCase):
|
||||
'3B\r\nf.ce\tMaintainer\t01\t00'
|
||||
'\t00\t00\r\ntestuser\tSoftware'
|
||||
'\t01\t01\t00\t00\r\nCLI> ' % exec_cmdline)
|
||||
elif exec_cmdline.startswith('expand volume'):
|
||||
ret = '%s\r\n00\r\nCLI> ' % exec_cmdline
|
||||
elif exec_cmdline.startswith('set volume-qos'):
|
||||
ret = '%s\r\n00\r\n0001\r\nCLI> ' % exec_cmdline
|
||||
elif exec_cmdline.startswith('show volumes'):
|
||||
@ -1414,19 +1426,27 @@ class FJISCSIDriverTestCase(test.TestCase):
|
||||
self.driver.delete_volume(TEST_VOLUME)
|
||||
|
||||
def test_extend_volume(self):
|
||||
model_info = self.driver.create_volume(TEST_VOLUME)
|
||||
self.assertEqual(FAKE_MODEL_INFO1, model_info)
|
||||
# Test the extension of volume created on RaidGroup and
|
||||
# ThinProvisioningPool separately.
|
||||
TEST_VOLUME_LIST = [TEST_VOLUME, TEST_VOLUME2]
|
||||
FAKE_MODEL_INFO_LIST = [FAKE_MODEL_INFO1, FAKE_MODEL_INFO3]
|
||||
model_info_list = []
|
||||
for i in range(len(TEST_VOLUME_LIST)):
|
||||
model_info = self.driver.create_volume(TEST_VOLUME_LIST[i])
|
||||
self.assertEqual(FAKE_MODEL_INFO_LIST[i], model_info)
|
||||
model_info_list.append(model_info)
|
||||
|
||||
volume_info = {}
|
||||
for key in TEST_VOLUME:
|
||||
if key == 'provider_location':
|
||||
volume_info[key] = model_info[key]
|
||||
elif key == 'metadata':
|
||||
volume_info[key] = model_info[key]
|
||||
else:
|
||||
volume_info[key] = TEST_VOLUME[key]
|
||||
for i in range(len(TEST_VOLUME_LIST)):
|
||||
volume_info = {}
|
||||
for key in TEST_VOLUME_LIST[i]:
|
||||
if key == 'provider_location':
|
||||
volume_info[key] = model_info_list[i][key]
|
||||
elif key == 'metadata':
|
||||
volume_info[key] = model_info_list[i][key]
|
||||
else:
|
||||
volume_info[key] = TEST_VOLUME_LIST[i][key]
|
||||
|
||||
self.driver.extend_volume(volume_info, 10)
|
||||
self.driver.extend_volume(volume_info, 10)
|
||||
|
||||
def test_create_volume_with_qos(self):
|
||||
self.driver.common._get_qos_specs = mock.Mock()
|
||||
@ -1467,6 +1487,8 @@ class FJCLITestCase(test.TestCase):
|
||||
'3B\r\nf.ce\tMaintainer\t01\t00'
|
||||
'\t00\t00\r\ntestuser\tSoftware'
|
||||
'\t01\t01\t00\t00\r\nCLI> ' % exec_cmdline)
|
||||
elif exec_cmdline.startswith('expand volume'):
|
||||
ret = '%s\r\n00\r\nCLI> ' % exec_cmdline
|
||||
elif exec_cmdline.startswith('set volume-qos'):
|
||||
ret = '%s\r\n00\r\n0001\r\nCLI> ' % exec_cmdline
|
||||
elif exec_cmdline.startswith('show volumes'):
|
||||
@ -1561,6 +1583,19 @@ class FJCLITestCase(test.TestCase):
|
||||
role = self.cli._check_user_role()
|
||||
self.assertEqual(FAKE_ROLE, role)
|
||||
|
||||
def test_expand_volume(self):
|
||||
FAKE_VOLME_NAME = 'FJosv_0qJ4rpOHgFE8ipcJOMfBmg=='
|
||||
FAKE_RG_NAME = 'abcd1234_RG'
|
||||
FAKE_SIZE = '10gb'
|
||||
FAKE_EXPAND_OPTION = self.create_fake_options(
|
||||
volume_name=FAKE_VOLME_NAME,
|
||||
rg_name=FAKE_RG_NAME,
|
||||
size=FAKE_SIZE)
|
||||
|
||||
EXPAND_OUTPUT = self.cli._expand_volume(**FAKE_EXPAND_OPTION)
|
||||
FAKE_EXPAND_OUTPUT = {**FAKE_CLI_OUTPUT, 'message': []}
|
||||
self.assertEqual(FAKE_EXPAND_OUTPUT, EXPAND_OUTPUT)
|
||||
|
||||
def test_set_volume_qos(self):
|
||||
FAKE_VOLUME_NAME = 'FJosv_0qJ4rpOHgFE8ipcJOMfBmg=='
|
||||
FAKE_BANDWIDTH_LIMIT = 2
|
||||
|
@ -47,6 +47,7 @@ class FJDXCLI(object):
|
||||
self.ce_support = False
|
||||
self.CMD_dic = {
|
||||
'check_user_role': self._check_user_role,
|
||||
'expand_volume': self._expand_volume,
|
||||
'show_pool_provision': self._show_pool_provision,
|
||||
'show_qos_bandwidth_limit': self._show_qos_bandwidth_limit,
|
||||
'set_qos_bandwidth_limit': self._set_qos_bandwidth_limit,
|
||||
@ -239,6 +240,10 @@ class FJDXCLI(object):
|
||||
}
|
||||
return output
|
||||
|
||||
def _expand_volume(self, **option):
|
||||
"""Exec expand volume."""
|
||||
return self._exec_cli("expand volume", **option)
|
||||
|
||||
def _set_volume_qos(self, **option):
|
||||
"""Exec set volume-qos."""
|
||||
return self._exec_cli("set volume-qos", **option)
|
||||
|
@ -67,10 +67,11 @@ class FJDXCommon(object):
|
||||
1.0 - Initial driver
|
||||
1.3.0 - Community base version
|
||||
1.4.0 - Add support for QoS.
|
||||
1.4.1 - Add the method for expanding RAID volumes by CLI.
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "1.4.0"
|
||||
VERSION = "1.4.1"
|
||||
stats = {
|
||||
'driver_version': VERSION,
|
||||
'storage_protocol': None,
|
||||
@ -821,32 +822,33 @@ class FJDXCommon(object):
|
||||
'size': volume['size'], 'nsize': new_size})
|
||||
|
||||
self.conn = self._get_eternus_connection()
|
||||
volumesize = new_size * units.Gi
|
||||
volumename = self._get_volume_name(volume)
|
||||
|
||||
# Get source volume instance.
|
||||
vol_instance = self._find_lun(volume)
|
||||
if vol_instance is None:
|
||||
# Get volume instance.
|
||||
volume_instance = self._find_lun(volume)
|
||||
if not volume_instance:
|
||||
msg = (_('extend_volume, '
|
||||
'volumename: %(volumename)s, '
|
||||
'volume not found.')
|
||||
'not found.')
|
||||
% {'volumename': volumename})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
|
||||
LOG.debug('extend_volume, volumename: %(volumename)s, '
|
||||
'volumesize: %(volumesize)u, '
|
||||
'volume instance: %(vol_instance)s.',
|
||||
'volume instance: %(volume_instance)s.',
|
||||
{'volumename': volumename,
|
||||
'volumesize': volumesize,
|
||||
'vol_instance': vol_instance.path})
|
||||
'volumesize': new_size,
|
||||
'volume_instance': volume_instance.path})
|
||||
|
||||
# Get poolname from driver configuration file.
|
||||
pool_name, pool = self._find_pool_from_volume(vol_instance)
|
||||
if pool is None:
|
||||
pool_name, pool = self._find_pool_from_volume(volume_instance)
|
||||
|
||||
# Check the existence of pool.
|
||||
if not pool:
|
||||
msg = (_('extend_volume, '
|
||||
'eternus_pool: %(eternus_pool)s, '
|
||||
'pool not found.')
|
||||
'not found.')
|
||||
% {'eternus_pool': pool_name})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
@ -857,56 +859,84 @@ class FJDXCommon(object):
|
||||
else:
|
||||
pooltype = CONSTANTS.TPPOOL
|
||||
|
||||
configservice = self._find_eternus_service(CONSTANTS.STOR_CONF)
|
||||
if not configservice:
|
||||
msg = (_('extend_volume, volume: %(volume)s, '
|
||||
'volumename: %(volumename)s, '
|
||||
'eternus_pool: %(eternus_pool)s, '
|
||||
'Storage Configuration Service not found.')
|
||||
% {'volume': volume,
|
||||
'volumename': volumename,
|
||||
'eternus_pool': pool_name})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
if pooltype == CONSTANTS.RAIDGROUP:
|
||||
extend_size = str(new_size - volume['size']) + 'gb'
|
||||
param_dict = {
|
||||
'volume-name': volumename,
|
||||
'rg-name': pool_name,
|
||||
'size': extend_size
|
||||
}
|
||||
rc, errordesc, data = self._exec_eternus_cli(
|
||||
'expand_volume',
|
||||
**param_dict)
|
||||
|
||||
LOG.debug('extend_volume, '
|
||||
'CreateOrModifyElementFromStoragePool, '
|
||||
'ConfigService: %(service)s, '
|
||||
'ElementName: %(volumename)s, '
|
||||
'InPool: %(eternus_pool)s, '
|
||||
'ElementType: %(pooltype)u, '
|
||||
'Size: %(volumesize)u, '
|
||||
'TheElement: %(vol_instance)s.',
|
||||
{'service': configservice,
|
||||
'volumename': volumename,
|
||||
'eternus_pool': pool_name,
|
||||
'pooltype': pooltype,
|
||||
'volumesize': volumesize,
|
||||
'vol_instance': vol_instance.path})
|
||||
if rc != 0:
|
||||
msg = (_('extend_volume, '
|
||||
'volumename: %(volumename)s, '
|
||||
'Return code: %(rc)lu, '
|
||||
'Error: %(errordesc)s, '
|
||||
'Message: %(job)s, '
|
||||
'PoolType: %(pooltype)s.')
|
||||
% {'volumename': volumename,
|
||||
'rc': rc,
|
||||
'errordesc': errordesc,
|
||||
'pooltype': CONSTANTS.POOL_TYPE_dic[pooltype],
|
||||
'job': data})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
|
||||
# Invoke method for extend volume
|
||||
rc, errordesc, job = self._exec_eternus_service(
|
||||
'CreateOrModifyElementFromStoragePool',
|
||||
configservice,
|
||||
ElementName=volumename,
|
||||
InPool=pool,
|
||||
ElementType=self._pywbem_uint(pooltype, '16'),
|
||||
Size=self._pywbem_uint(volumesize, '64'),
|
||||
TheElement=vol_instance.path)
|
||||
else: # Pooltype is TPPOOL.
|
||||
volumesize = new_size * units.Gi
|
||||
configservice = self._find_eternus_service(CONSTANTS.STOR_CONF)
|
||||
if not configservice:
|
||||
msg = (_('extend_volume, volume: %(volume)s, '
|
||||
'volumename: %(volumename)s, '
|
||||
'eternus_pool: %(eternus_pool)s, '
|
||||
'Storage Configuration Service not found.')
|
||||
% {'volume': volume,
|
||||
'volumename': volumename,
|
||||
'eternus_pool': pool_name})
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
|
||||
if rc != 0:
|
||||
msg = (_('extend_volume, '
|
||||
'volumename: %(volumename)s, '
|
||||
'Return code: %(rc)lu, '
|
||||
'Error: %(errordesc)s, '
|
||||
'PoolType: %(pooltype)s.')
|
||||
% {'volumename': volumename,
|
||||
'rc': rc,
|
||||
'errordesc': errordesc,
|
||||
'pooltype': CONSTANTS.POOL_TYPE_dic[pooltype]})
|
||||
LOG.debug('extend_volume, '
|
||||
'CreateOrModifyElementFromStoragePool, '
|
||||
'ConfigService: %(service)s, '
|
||||
'ElementName: %(volumename)s, '
|
||||
'InPool: %(eternus_pool)s, '
|
||||
'ElementType: %(pooltype)u, '
|
||||
'Size: %(volumesize)u, '
|
||||
'TheElement: %(vol_instance)s.',
|
||||
{'service': configservice,
|
||||
'volumename': volumename,
|
||||
'eternus_pool': pool_name,
|
||||
'pooltype': pooltype,
|
||||
'volumesize': volumesize,
|
||||
'vol_instance': volume_instance.path})
|
||||
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
# Invoke method for extend volume.
|
||||
rc, errordesc, _x = self._exec_eternus_service(
|
||||
'CreateOrModifyElementFromStoragePool',
|
||||
configservice,
|
||||
ElementName=volumename,
|
||||
InPool=pool,
|
||||
ElementType=self._pywbem_uint(pooltype, '16'),
|
||||
Size=self._pywbem_uint(volumesize, '64'),
|
||||
TheElement=volume_instance.path)
|
||||
|
||||
if rc != 0:
|
||||
msg = (_('extend_volume, '
|
||||
'volumename: %(volumename)s, '
|
||||
'Return code: %(rc)lu, '
|
||||
'Error: %(errordesc)s, '
|
||||
'PoolType: %(pooltype)s.')
|
||||
% {'volumename': volumename,
|
||||
'rc': rc,
|
||||
'errordesc': errordesc,
|
||||
'pooltype': CONSTANTS.POOL_TYPE_dic[pooltype]})
|
||||
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
|
||||
LOG.debug('extend_volume, '
|
||||
'volumename: %(volumename)s, '
|
||||
|
@ -157,7 +157,13 @@ class FJDXFCDriver(driver.FibreChannelDriver):
|
||||
|
||||
def extend_volume(self, volume, new_size):
|
||||
"""Extend volume."""
|
||||
self.common.extend_volume(volume, new_size)
|
||||
LOG.debug('extend_volume, '
|
||||
'volume id: %s, Enter method.', volume['id'])
|
||||
|
||||
used_pool_name = self.common.extend_volume(volume, new_size)
|
||||
|
||||
LOG.debug('extend_volume, '
|
||||
'used pool name: %s, Exit method.', used_pool_name)
|
||||
|
||||
def _get_metadata(self, volume):
|
||||
v_metadata = volume.get('volume_metadata')
|
||||
|
@ -144,4 +144,10 @@ class FJDXISCSIDriver(driver.ISCSIDriver):
|
||||
|
||||
def extend_volume(self, volume, new_size):
|
||||
"""Extend volume."""
|
||||
self.common.extend_volume(volume, new_size)
|
||||
LOG.debug('extend_volume, '
|
||||
'volume id: %s, Enter method.', volume['id'])
|
||||
|
||||
used_pool_name = self.common.extend_volume(volume, new_size)
|
||||
|
||||
LOG.debug('extend_volume, '
|
||||
'used pool name: %s, Exit method.', used_pool_name)
|
||||
|
@ -44,11 +44,9 @@ Supported operations
|
||||
* Copy an image to a volume.
|
||||
* Copy a volume to an image.
|
||||
* Clone a volume.
|
||||
* Extend a volume. (\*1)
|
||||
* Extend a volume.
|
||||
* Get volume statistics.
|
||||
|
||||
(\*1): It is executable only when you use TPP as a storage pool.
|
||||
|
||||
Preparation
|
||||
~~~~~~~~~~~
|
||||
|
||||
|
@ -0,0 +1,14 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Fujitsu ETERNUS DX driver: Added support to extend a volume on RAID Group
|
||||
using CLI.
|
||||
|
||||
Revised the 'Extend Volume' process on the RAID Group to improve processing
|
||||
speed as follows:
|
||||
|
||||
* When extending a volume created on ThinProvisionPool, the process will
|
||||
still use SMI-S for volume extension.
|
||||
|
||||
* When extending a volume created on RaidGroup, the process has been
|
||||
updated to use CLI for volume extension.
|
Loading…
Reference in New Issue
Block a user