Fujitsu Driver: Update extend volume functionality

Revised the 'Extend Volume' process on the RaidGroup 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 RAID group, the process has been
  updated to use CLI for volume extension.

Change-Id: Ifcd93b9c9d94b214e890c57afd588b43b568478a
This commit is contained in:
inori 2023-09-27 06:11:30 -04:00
parent 8a9f9a7c36
commit 1491eecfd3
7 changed files with 181 additions and 87 deletions

View File

@ -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

View File

@ -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)

View File

@ -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, '

View File

@ -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')

View File

@ -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)

View File

@ -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
~~~~~~~~~~~

View File

@ -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.