Fujitsu Driver: Support for update migrated volume
After migrated volume is completed, cinder invokes function 'update_migrated_volume'. It updates provider_location, which possesses the new volume ID, to match the provider_location of original volume. Change-Id: I1fe29d077a657963016a581b6c87642a62979653
This commit is contained in:
@@ -19,6 +19,7 @@ from unittest import mock
|
||||
|
||||
from oslo_utils import units
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder import ssh_utils
|
||||
from cinder.tests.unit import test
|
||||
@@ -178,7 +179,7 @@ FAKE_POOLS = [{
|
||||
}]
|
||||
|
||||
FAKE_STATS = {
|
||||
'driver_version': '1.4.3',
|
||||
'driver_version': '1.4.4',
|
||||
'storage_protocol': 'iSCSI',
|
||||
'vendor_name': 'FUJITSU',
|
||||
'QoS_support': True,
|
||||
@@ -188,7 +189,7 @@ FAKE_STATS = {
|
||||
'pools': FAKE_POOLS,
|
||||
}
|
||||
FAKE_STATS2 = {
|
||||
'driver_version': '1.4.3',
|
||||
'driver_version': '1.4.4',
|
||||
'storage_protocol': 'FC',
|
||||
'vendor_name': 'FUJITSU',
|
||||
'QoS_support': True,
|
||||
@@ -198,7 +199,6 @@ FAKE_STATS2 = {
|
||||
'pools': FAKE_POOLS,
|
||||
}
|
||||
|
||||
|
||||
# Volume1 in pool abcd1234_TPP
|
||||
FAKE_KEYBIND1 = {
|
||||
'SystemName': STORAGE_SYSTEM,
|
||||
@@ -1007,6 +1007,8 @@ class FJFCDriverTestCase(test.TestCase):
|
||||
driver = dx_fc.FJDXFCDriver(configuration=self.configuration)
|
||||
self.driver = driver
|
||||
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
def fake_exec_cli_with_eternus(self, exec_cmdline):
|
||||
if exec_cmdline == "show users":
|
||||
ret = ('\r\nCLI> %s\r\n00\r\n'
|
||||
@@ -1219,6 +1221,42 @@ class FJFCDriverTestCase(test.TestCase):
|
||||
self.assertEqual(FAKE_MODEL_INFO_QOS, model_info)
|
||||
self.driver.common._set_qos.assert_called()
|
||||
|
||||
def test_update_migrated_volume(self):
|
||||
model_info = self.driver.create_volume(TEST_VOLUME)
|
||||
self.assertEqual(FAKE_MODEL_INFO1, 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]
|
||||
|
||||
model_info2 = self.driver.create_volume(TEST_VOLUME2)
|
||||
self.assertEqual(FAKE_MODEL_INFO3, model_info2)
|
||||
|
||||
volume_info2 = {}
|
||||
for key in TEST_VOLUME:
|
||||
if key == 'provider_location':
|
||||
volume_info2[key] = model_info2[key]
|
||||
elif key == 'metadata':
|
||||
volume_info2[key] = model_info2[key]
|
||||
else:
|
||||
volume_info2[key] = TEST_VOLUME2[key]
|
||||
|
||||
model_update = self.driver.update_migrated_volume(self.context,
|
||||
volume_info,
|
||||
volume_info2,
|
||||
'available')
|
||||
|
||||
FAKE_MIGRATED_MODEL_UPDATE = {
|
||||
'_name_id': TEST_VOLUME2['id'],
|
||||
'provider_location': model_info2['provider_location']
|
||||
}
|
||||
self.assertEqual(FAKE_MIGRATED_MODEL_UPDATE, model_update)
|
||||
|
||||
|
||||
class FJISCSIDriverTestCase(test.TestCase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -1260,6 +1298,8 @@ class FJISCSIDriverTestCase(test.TestCase):
|
||||
driver = dx_iscsi.FJDXISCSIDriver(configuration=self.configuration)
|
||||
self.driver = driver
|
||||
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
def fake_exec_cli_with_eternus(self, exec_cmdline):
|
||||
if exec_cmdline == "show users":
|
||||
ret = ('\r\nCLI> %s\r\n00\r\n'
|
||||
@@ -1471,6 +1511,42 @@ class FJISCSIDriverTestCase(test.TestCase):
|
||||
self.assertEqual(FAKE_MODEL_INFO_QOS, model_info)
|
||||
self.driver.common._set_qos.assert_called()
|
||||
|
||||
def test_update_migrated_volume(self):
|
||||
model_info = self.driver.create_volume(TEST_VOLUME)
|
||||
self.assertEqual(FAKE_MODEL_INFO1, 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]
|
||||
|
||||
model_info2 = self.driver.create_volume(TEST_VOLUME2)
|
||||
self.assertEqual(FAKE_MODEL_INFO3, model_info2)
|
||||
|
||||
volume_info2 = {}
|
||||
for key in TEST_VOLUME:
|
||||
if key == 'provider_location':
|
||||
volume_info2[key] = model_info2[key]
|
||||
elif key == 'metadata':
|
||||
volume_info2[key] = model_info2[key]
|
||||
else:
|
||||
volume_info2[key] = TEST_VOLUME2[key]
|
||||
|
||||
model_update = self.driver.update_migrated_volume(self.context,
|
||||
volume_info,
|
||||
volume_info2,
|
||||
'available')
|
||||
|
||||
FAKE_MIGRATED_MODEL_UPDATE = {
|
||||
'_name_id': TEST_VOLUME2['id'],
|
||||
'provider_location': model_info2['provider_location']
|
||||
}
|
||||
self.assertEqual(FAKE_MIGRATED_MODEL_UPDATE, model_update)
|
||||
|
||||
|
||||
class FJCLITestCase(test.TestCase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -1765,6 +1841,8 @@ class FJCommonTestCase(test.TestCase):
|
||||
driver = dx_iscsi.FJDXISCSIDriver(configuration=self.configuration)
|
||||
self.driver = driver
|
||||
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
def fake_exec_cli_with_eternus(self, exec_cmdline):
|
||||
if exec_cmdline == "show users":
|
||||
ret = ('\r\nCLI> %s\r\n00\r\n'
|
||||
@@ -1935,3 +2013,38 @@ class FJCommonTestCase(test.TestCase):
|
||||
}]
|
||||
copy_session_list = self.driver.common._get_copy_sessions_list()
|
||||
self.assertEqual(FAKE_COPY_SESSION, copy_session_list)
|
||||
|
||||
def test_update_migrated_volume(self):
|
||||
model_info = self.driver.create_volume(TEST_VOLUME)
|
||||
self.assertEqual(FAKE_MODEL_INFO1, 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]
|
||||
|
||||
model_info2 = self.driver.create_volume(TEST_VOLUME2)
|
||||
self.assertEqual(FAKE_MODEL_INFO3, model_info2)
|
||||
|
||||
volume_info2 = {}
|
||||
for key in TEST_VOLUME:
|
||||
if key == 'provider_location':
|
||||
volume_info2[key] = model_info2[key]
|
||||
elif key == 'metadata':
|
||||
volume_info2[key] = model_info2[key]
|
||||
else:
|
||||
volume_info2[key] = TEST_VOLUME2[key]
|
||||
|
||||
model_update = self.driver.common.update_migrated_volume(self.context,
|
||||
volume_info,
|
||||
volume_info2)
|
||||
|
||||
FAKE_MIGRATED_MODEL_UPDATE = {
|
||||
'_name_id': TEST_VOLUME2['id'],
|
||||
'provider_location': model_info2['provider_location']
|
||||
}
|
||||
self.assertEqual(FAKE_MIGRATED_MODEL_UPDATE, model_update)
|
||||
|
||||
@@ -69,10 +69,11 @@ class FJDXCommon(object):
|
||||
1.4.1 - Add the method for expanding RAID volumes by CLI.
|
||||
1.4.2 - Add the secondary check for copy-sessions when deleting volumes.
|
||||
1.4.3 - Add fragment capacity information of RAID Group.
|
||||
1.4.4 - Add support for update migrated volume.
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "1.4.3"
|
||||
VERSION = "1.4.4"
|
||||
stats = {
|
||||
'driver_version': VERSION,
|
||||
'storage_protocol': None,
|
||||
@@ -2595,6 +2596,34 @@ class FJDXCommon(object):
|
||||
{'poolname': poolname, 'target_pool': target_pool})
|
||||
return poolname, target_pool
|
||||
|
||||
def update_migrated_volume(self, ctxt, volume, new_volume):
|
||||
"""Update migrated volume."""
|
||||
LOG.debug('update_migrated_volume, '
|
||||
'source volume id: %(s_id)s, '
|
||||
'target volume id: %(t_id)s.',
|
||||
{'s_id': volume['id'], 't_id': new_volume['id']})
|
||||
|
||||
model_update = None
|
||||
|
||||
dst_metadata = self.get_metadata(new_volume)
|
||||
src_metadata = self.get_metadata(volume)
|
||||
|
||||
LOG.debug('source: (%(src_meta)s)(%(src_loc)s), '
|
||||
'target: (%(dst_meta)s)(%(dst_loc)s).',
|
||||
{'src_meta': src_metadata,
|
||||
'src_loc': volume['provider_location'],
|
||||
'dst_meta': dst_metadata,
|
||||
'dst_loc': new_volume['provider_location']})
|
||||
|
||||
if volume['provider_location']:
|
||||
dst_location = new_volume['provider_location']
|
||||
model_update = {'_name_id': new_volume['id'],
|
||||
'provider_location': dst_location}
|
||||
|
||||
LOG.debug('update_migrated_volume, model_update: %s.',
|
||||
model_update)
|
||||
return model_update
|
||||
|
||||
def _get_eternus_model(self):
|
||||
"""Get ENTERNUS model."""
|
||||
self.conn = self._get_eternus_connection()
|
||||
|
||||
@@ -173,6 +173,22 @@ class FJDXFCDriver(driver.FibreChannelDriver):
|
||||
LOG.debug('extend_volume, '
|
||||
'used pool name: %s, Exit method.', used_pool_name)
|
||||
|
||||
def update_migrated_volume(self, ctxt, volume, new_volume,
|
||||
original_volume_status):
|
||||
"""Update migrated volume."""
|
||||
LOG.debug('update_migrated_volume, '
|
||||
'source volume id: %(s_id)s, '
|
||||
'target volume id: %(t_id)s, Enter method.',
|
||||
{'s_id': volume['id'], 't_id': new_volume['id']})
|
||||
|
||||
model_update = self.common.update_migrated_volume(
|
||||
ctxt, volume, new_volume)
|
||||
|
||||
LOG.debug('update_migrated_volume, '
|
||||
'target volume meta: %s, Exit method.', model_update)
|
||||
|
||||
return model_update
|
||||
|
||||
def _get_metadata(self, volume):
|
||||
v_metadata = volume.get('volume_metadata')
|
||||
if v_metadata:
|
||||
|
||||
@@ -159,3 +159,19 @@ class FJDXISCSIDriver(driver.ISCSIDriver):
|
||||
|
||||
LOG.debug('extend_volume, '
|
||||
'used pool name: %s, Exit method.', used_pool_name)
|
||||
|
||||
def update_migrated_volume(self, ctxt, volume, new_volume,
|
||||
original_volume_status):
|
||||
"""Update migrated volume."""
|
||||
LOG.debug('update_migrated_volume, '
|
||||
'source volume id: %(s_id)s, '
|
||||
'target volume id: %(t_id)s, Enter method.',
|
||||
{'s_id': volume['id'], 't_id': new_volume['id']})
|
||||
|
||||
model_update = self.common.update_migrated_volume(
|
||||
ctxt, volume, new_volume)
|
||||
|
||||
LOG.debug('update_migrated_volume, '
|
||||
'target volume meta: %s, Exit method.', model_update)
|
||||
|
||||
return model_update
|
||||
|
||||
@@ -46,6 +46,7 @@ Supported operations
|
||||
* Clone a volume.
|
||||
* Extend a volume.
|
||||
* Get volume statistics.
|
||||
* Migrate Volume.
|
||||
|
||||
Preparation
|
||||
~~~~~~~~~~~
|
||||
@@ -241,6 +242,65 @@ Configuration example
|
||||
and the type ``DX_ISCSI`` is associated with the ``ISCSI``.
|
||||
|
||||
|
||||
Supported Functions of the ETERNUS OpenStack VolumeDriver
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Migrate Volume
|
||||
--------------
|
||||
|
||||
Moves volumes to a different storage pool.
|
||||
|
||||
#. ETERNUS AF/DX functions
|
||||
|
||||
* Creates migration destination volumes / deletes migration
|
||||
source volumes.
|
||||
|
||||
* Sets access paths to migration volumes / deletes migration
|
||||
access paths to migration source volumes.
|
||||
|
||||
* Uses Create Volume, Delete Volume, Attach Volume and Detach
|
||||
Volume.
|
||||
|
||||
#. Cinder operation
|
||||
|
||||
* Copies data in the migration source volume to the migration
|
||||
destination volume.
|
||||
|
||||
.. note::
|
||||
|
||||
Host information must be specified in Migrated Volume.
|
||||
|
||||
The input format is as follows:
|
||||
|
||||
``Host-Name@Backend-Name#Pool-Name``
|
||||
|
||||
For the following environment or settings, specify
|
||||
``test.localhost@Backend1#PoolA`` for the host.
|
||||
|
||||
* PoolA is a pool specified in ``/etc/cinder/cinder_fujitsu_eternus_dx.xml``.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ hostname
|
||||
test.localhost
|
||||
|
||||
$ cat /etc/cinder/cinder.conf
|
||||
(snip)
|
||||
[Backend1]
|
||||
volume_driver=cinder.volume.drivers.fujitsu.eternus_dx.eternus_dx_fc.FJDXFCDriver
|
||||
cinder_eternus_config_file = /etc/cinder/cinder_fujitsu_eternus_dx.xml
|
||||
volume_backend_name=volume_backend_name1
|
||||
|
||||
.. warning::
|
||||
|
||||
There are some restrictions for volume migration:
|
||||
|
||||
#. You cannot migrate a volume that has snapshots.
|
||||
|
||||
#. You cannot use driver-assisted migration to move a volume to or from a
|
||||
backend that does not use the ETERNUS OpenStack volume driver.
|
||||
|
||||
|
||||
Supplementary Information for the Supported Functions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Fujitsu ETERNUS DX driver: Added support for update migrated volume
|
||||
|
||||
Now we update the required values to successfully complete the migration.
|
||||
|
||||
See the `Fujitsu ETERNUS DX driver documentation
|
||||
<https://docs.openstack.org/cinder/latest/configuration/block-storage/drivers/fujitsu-eternus-dx-driver.html>`_
|
||||
for details.
|
||||
Reference in New Issue
Block a user