Merge "Fujitsu Driver: Improve create snapshot"

This commit is contained in:
Zuul 2024-07-31 21:42:01 +00:00 committed by Gerrit Code Review
commit 0c871f587a
5 changed files with 175 additions and 120 deletions

View File

@ -140,6 +140,7 @@ FAKE_LUN_NO1 = '0x0014'
# Snapshot1 in pool abcd1234_OSVD # Snapshot1 in pool abcd1234_OSVD
FAKE_LUN_ID2 = '600000E00D2A0000002A0115001E0000' FAKE_LUN_ID2 = '600000E00D2A0000002A0115001E0000'
FAKE_LUN_NO2 = '0x001E' FAKE_LUN_NO2 = '0x001E'
FAKE_SDV_NO = '0x001E'
# Volume2 in pool abcd1234_RG # Volume2 in pool abcd1234_RG
FAKE_LUN_ID3 = '600000E00D2800000028075301140000' FAKE_LUN_ID3 = '600000E00D2800000028075301140000'
FAKE_LUN_NO3 = '0x0114' FAKE_LUN_NO3 = '0x0114'
@ -179,7 +180,7 @@ FAKE_POOLS = [{
}] }]
FAKE_STATS = { FAKE_STATS = {
'driver_version': '1.4.4', 'driver_version': '1.4.5',
'storage_protocol': 'iSCSI', 'storage_protocol': 'iSCSI',
'vendor_name': 'FUJITSU', 'vendor_name': 'FUJITSU',
'QoS_support': True, 'QoS_support': True,
@ -189,7 +190,7 @@ FAKE_STATS = {
'pools': FAKE_POOLS, 'pools': FAKE_POOLS,
} }
FAKE_STATS2 = { FAKE_STATS2 = {
'driver_version': '1.4.4', 'driver_version': '1.4.5',
'storage_protocol': 'FC', 'storage_protocol': 'FC',
'vendor_name': 'FUJITSU', 'vendor_name': 'FUJITSU',
'QoS_support': True, 'QoS_support': True,
@ -302,7 +303,14 @@ FAKE_LOCATION2 = {
'vol_name': 'FJosv_OgEZj1mSvKRvIKOExKktlg==' 'vol_name': 'FJosv_OgEZj1mSvKRvIKOExKktlg=='
} }
FAKE_SNAP_META = {
'FJ_Pool_Name': 'abcd1234_OSVD',
'FJ_SDV_Name': u'FJosv_OgEZj1mSvKRvIKOExKktlg==',
'FJ_SDV_No': FAKE_SDV_NO,
}
FAKE_SNAP_INFO = { FAKE_SNAP_INFO = {
'metadata': FAKE_SNAP_META,
'provider_location': str(FAKE_LOCATION2) 'provider_location': str(FAKE_LOCATION2)
} }
@ -1105,6 +1113,10 @@ class FJFCDriverTestCase(test.TestCase):
conn = FakeEternusConnection() conn = FakeEternusConnection()
return conn return conn
def volume_update(self, volume, diction):
for key, value in diction.items():
volume[key] = value
def test_get_volume_stats(self): def test_get_volume_stats(self):
ret = self.driver.get_volume_stats(True) ret = self.driver.get_volume_stats(True)
@ -1112,9 +1124,11 @@ class FJFCDriverTestCase(test.TestCase):
def test_create_and_delete_volume(self): def test_create_and_delete_volume(self):
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) self.assertEqual(FAKE_MODEL_INFO1, model_info)
model_info = self.driver.create_volume(TEST_VOLUME2) model_info = self.driver.create_volume(TEST_VOLUME2)
self.volume_update(TEST_VOLUME2, model_info)
self.assertEqual(FAKE_MODEL_INFO3, model_info) self.assertEqual(FAKE_MODEL_INFO3, model_info)
self.driver.delete_volume(TEST_VOLUME) self.driver.delete_volume(TEST_VOLUME)
@ -1137,6 +1151,7 @@ class FJFCDriverTestCase(test.TestCase):
'data': fake_mapdata} 'data': fake_mapdata}
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) self.assertEqual(FAKE_MODEL_INFO1, model_info)
info = self.driver.initialize_connection(TEST_VOLUME, info = self.driver.initialize_connection(TEST_VOLUME,
@ -1157,9 +1172,11 @@ class FJFCDriverTestCase(test.TestCase):
def test_create_and_delete_snapshot(self): def test_create_and_delete_snapshot(self):
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) self.assertEqual(FAKE_MODEL_INFO1, model_info)
snap_info = self.driver.create_snapshot(TEST_SNAP) snap_info = self.driver.create_snapshot(TEST_SNAP)
self.volume_update(TEST_SNAP, snap_info)
self.assertEqual(FAKE_SNAP_INFO, snap_info) self.assertEqual(FAKE_SNAP_INFO, snap_info)
self.driver.delete_snapshot(TEST_SNAP) self.driver.delete_snapshot(TEST_SNAP)
@ -1167,13 +1184,16 @@ class FJFCDriverTestCase(test.TestCase):
def test_create_volume_from_snapshot(self): def test_create_volume_from_snapshot(self):
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) self.assertEqual(FAKE_MODEL_INFO1, model_info)
snap_info = self.driver.create_snapshot(TEST_SNAP) snap_info = self.driver.create_snapshot(TEST_SNAP)
self.volume_update(TEST_SNAP, snap_info)
self.assertEqual(FAKE_SNAP_INFO, snap_info) self.assertEqual(FAKE_SNAP_INFO, snap_info)
model_info = self.driver.create_volume_from_snapshot(TEST_CLONE, model_info = self.driver.create_volume_from_snapshot(TEST_CLONE,
TEST_SNAP) TEST_SNAP)
self.volume_update(TEST_CLONE, model_info)
self.assertEqual(FAKE_MODEL_INFO2, model_info) self.assertEqual(FAKE_MODEL_INFO2, model_info)
self.driver.delete_snapshot(TEST_SNAP) self.driver.delete_snapshot(TEST_SNAP)
@ -1182,9 +1202,11 @@ class FJFCDriverTestCase(test.TestCase):
def test_create_cloned_volume(self): def test_create_cloned_volume(self):
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) self.assertEqual(FAKE_MODEL_INFO1, model_info)
model_info = self.driver.create_cloned_volume(TEST_CLONE, TEST_VOLUME) model_info = self.driver.create_cloned_volume(TEST_CLONE, TEST_VOLUME)
self.volume_update(TEST_CLONE, model_info)
self.assertEqual(FAKE_MODEL_INFO2, model_info) self.assertEqual(FAKE_MODEL_INFO2, model_info)
self.driver.delete_volume(TEST_CLONE) self.driver.delete_volume(TEST_CLONE)
@ -1195,60 +1217,34 @@ class FJFCDriverTestCase(test.TestCase):
# ThinProvisioningPool separately. # ThinProvisioningPool separately.
TEST_VOLUME_LIST = [TEST_VOLUME, TEST_VOLUME2] TEST_VOLUME_LIST = [TEST_VOLUME, TEST_VOLUME2]
FAKE_MODEL_INFO_LIST = [FAKE_MODEL_INFO1, FAKE_MODEL_INFO3] FAKE_MODEL_INFO_LIST = [FAKE_MODEL_INFO1, FAKE_MODEL_INFO3]
model_info_list = []
for i in range(len(TEST_VOLUME_LIST)): for i in range(len(TEST_VOLUME_LIST)):
model_info = self.driver.create_volume(TEST_VOLUME_LIST[i]) model_info = self.driver.create_volume(TEST_VOLUME_LIST[i])
self.volume_update(TEST_VOLUME_LIST[i], model_info)
self.assertEqual(FAKE_MODEL_INFO_LIST[i], model_info) self.assertEqual(FAKE_MODEL_INFO_LIST[i], model_info)
model_info_list.append(model_info)
for i in range(len(TEST_VOLUME_LIST)): self.driver.extend_volume(TEST_VOLUME_LIST[i], 10)
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)
def test_create_volume_with_qos(self): def test_create_volume_with_qos(self):
self.driver.common._get_qos_specs = mock.Mock() self.driver.common._get_qos_specs = mock.Mock()
self.driver.common._get_qos_specs.return_value = {'maxBWS': '700'} self.driver.common._get_qos_specs.return_value = {'maxBWS': '700'}
self.driver.common._set_qos = mock.Mock() self.driver.common._set_qos = mock.Mock()
model_info = self.driver.create_volume(TEST_VOLUME_QOS) model_info = self.driver.create_volume(TEST_VOLUME_QOS)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO_QOS, model_info) self.assertEqual(FAKE_MODEL_INFO_QOS, model_info)
self.driver.common._set_qos.assert_called() self.driver.common._set_qos.assert_called()
def test_update_migrated_volume(self): def test_update_migrated_volume(self):
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) 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) model_info2 = self.driver.create_volume(TEST_VOLUME2)
self.volume_update(TEST_VOLUME2, model_info2)
self.assertEqual(FAKE_MODEL_INFO3, model_info2) 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, model_update = self.driver.update_migrated_volume(self.context,
volume_info, TEST_VOLUME,
volume_info2, TEST_VOLUME2,
'available') 'available')
FAKE_MIGRATED_MODEL_UPDATE = { FAKE_MIGRATED_MODEL_UPDATE = {
@ -1405,6 +1401,10 @@ class FJISCSIDriverTestCase(test.TestCase):
'target_iqns': ISCSI_TARGET_IQN, 'target_iqns': ISCSI_TARGET_IQN,
'target_lun': 0} 'target_lun': 0}
def volume_update(self, volume, diction):
for key, value in diction.items():
volume[key] = value
def test_get_volume_stats(self): def test_get_volume_stats(self):
ret = self.driver.get_volume_stats(True) ret = self.driver.get_volume_stats(True)
@ -1412,9 +1412,11 @@ class FJISCSIDriverTestCase(test.TestCase):
def test_create_and_delete_volume(self): def test_create_and_delete_volume(self):
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) self.assertEqual(FAKE_MODEL_INFO1, model_info)
model_info = self.driver.create_volume(TEST_VOLUME2) model_info = self.driver.create_volume(TEST_VOLUME2)
self.volume_update(TEST_VOLUME2, model_info)
self.assertEqual(FAKE_MODEL_INFO3, model_info) self.assertEqual(FAKE_MODEL_INFO3, model_info)
self.driver.delete_volume(TEST_VOLUME) self.driver.delete_volume(TEST_VOLUME)
@ -1428,6 +1430,7 @@ class FJISCSIDriverTestCase(test.TestCase):
'data': fake_mapdata} 'data': fake_mapdata}
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) self.assertEqual(FAKE_MODEL_INFO1, model_info)
info = self.driver.initialize_connection(TEST_VOLUME, info = self.driver.initialize_connection(TEST_VOLUME,
@ -1447,9 +1450,11 @@ class FJISCSIDriverTestCase(test.TestCase):
def test_create_and_delete_snapshot(self): def test_create_and_delete_snapshot(self):
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) self.assertEqual(FAKE_MODEL_INFO1, model_info)
snap_info = self.driver.create_snapshot(TEST_SNAP) snap_info = self.driver.create_snapshot(TEST_SNAP)
self.volume_update(TEST_SNAP, snap_info)
self.assertEqual(FAKE_SNAP_INFO, snap_info) self.assertEqual(FAKE_SNAP_INFO, snap_info)
self.driver.delete_snapshot(TEST_SNAP) self.driver.delete_snapshot(TEST_SNAP)
@ -1457,13 +1462,16 @@ class FJISCSIDriverTestCase(test.TestCase):
def test_create_volume_from_snapshot(self): def test_create_volume_from_snapshot(self):
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) self.assertEqual(FAKE_MODEL_INFO1, model_info)
snap_info = self.driver.create_snapshot(TEST_SNAP) snap_info = self.driver.create_snapshot(TEST_SNAP)
self.volume_update(TEST_SNAP, snap_info)
self.assertEqual(FAKE_SNAP_INFO, snap_info) self.assertEqual(FAKE_SNAP_INFO, snap_info)
model_info = self.driver.create_volume_from_snapshot(TEST_CLONE, model_info = self.driver.create_volume_from_snapshot(TEST_CLONE,
TEST_SNAP) TEST_SNAP)
self.volume_update(TEST_CLONE, model_info)
self.assertEqual(FAKE_MODEL_INFO2, model_info) self.assertEqual(FAKE_MODEL_INFO2, model_info)
self.driver.delete_snapshot(TEST_SNAP) self.driver.delete_snapshot(TEST_SNAP)
@ -1472,9 +1480,11 @@ class FJISCSIDriverTestCase(test.TestCase):
def test_create_cloned_volume(self): def test_create_cloned_volume(self):
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) self.assertEqual(FAKE_MODEL_INFO1, model_info)
model_info = self.driver.create_cloned_volume(TEST_CLONE, TEST_VOLUME) model_info = self.driver.create_cloned_volume(TEST_CLONE, TEST_VOLUME)
self.volume_update(TEST_CLONE, model_info)
self.assertEqual(FAKE_MODEL_INFO2, model_info) self.assertEqual(FAKE_MODEL_INFO2, model_info)
self.driver.delete_volume(TEST_CLONE) self.driver.delete_volume(TEST_CLONE)
@ -1485,60 +1495,34 @@ class FJISCSIDriverTestCase(test.TestCase):
# ThinProvisioningPool separately. # ThinProvisioningPool separately.
TEST_VOLUME_LIST = [TEST_VOLUME, TEST_VOLUME2] TEST_VOLUME_LIST = [TEST_VOLUME, TEST_VOLUME2]
FAKE_MODEL_INFO_LIST = [FAKE_MODEL_INFO1, FAKE_MODEL_INFO3] FAKE_MODEL_INFO_LIST = [FAKE_MODEL_INFO1, FAKE_MODEL_INFO3]
model_info_list = []
for i in range(len(TEST_VOLUME_LIST)): for i in range(len(TEST_VOLUME_LIST)):
model_info = self.driver.create_volume(TEST_VOLUME_LIST[i]) model_info = self.driver.create_volume(TEST_VOLUME_LIST[i])
self.volume_update(TEST_VOLUME_LIST[i], model_info)
self.assertEqual(FAKE_MODEL_INFO_LIST[i], model_info) self.assertEqual(FAKE_MODEL_INFO_LIST[i], model_info)
model_info_list.append(model_info)
for i in range(len(TEST_VOLUME_LIST)): self.driver.extend_volume(TEST_VOLUME_LIST[i], 10)
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)
def test_create_volume_with_qos(self): def test_create_volume_with_qos(self):
self.driver.common._get_qos_specs = mock.Mock() self.driver.common._get_qos_specs = mock.Mock()
self.driver.common._get_qos_specs.return_value = {'maxBWS': '700'} self.driver.common._get_qos_specs.return_value = {'maxBWS': '700'}
self.driver.common._set_qos = mock.Mock() self.driver.common._set_qos = mock.Mock()
model_info = self.driver.create_volume(TEST_VOLUME_QOS) model_info = self.driver.create_volume(TEST_VOLUME_QOS)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO_QOS, model_info) self.assertEqual(FAKE_MODEL_INFO_QOS, model_info)
self.driver.common._set_qos.assert_called() self.driver.common._set_qos.assert_called()
def test_update_migrated_volume(self): def test_update_migrated_volume(self):
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) 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) model_info2 = self.driver.create_volume(TEST_VOLUME2)
self.volume_update(TEST_VOLUME2, model_info2)
self.assertEqual(FAKE_MODEL_INFO3, model_info2) 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, model_update = self.driver.update_migrated_volume(self.context,
volume_info, TEST_VOLUME,
volume_info2, TEST_VOLUME2,
'available') 'available')
FAKE_MIGRATED_MODEL_UPDATE = { FAKE_MIGRATED_MODEL_UPDATE = {
@ -1919,13 +1903,21 @@ class FJCommonTestCase(test.TestCase):
volume_no = self.driver.common._get_volume_number(vol_instance) volume_no = self.driver.common._get_volume_number(vol_instance)
self.assertEqual(FAKE_LUN_NO1, volume_no) self.assertEqual(FAKE_LUN_NO1, volume_no)
def volume_update(self, volume, diction):
for key, value in diction.items():
volume[key] = value
def test_get_eternus_model(self): def test_get_eternus_model(self):
ETERNUS_MODEL = self.driver.common._get_eternus_model() ETERNUS_MODEL = self.driver.common._get_eternus_model()
self.assertEqual(3, ETERNUS_MODEL) self.assertEqual(3, ETERNUS_MODEL)
def test_get_matadata(self): def test_get_matadata(self):
model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info)
TEST_METADATA = self.driver.common.get_metadata(TEST_VOLUME) TEST_METADATA = self.driver.common.get_metadata(TEST_VOLUME)
self.assertEqual({}, TEST_METADATA) self.assertEqual(FAKE_LUN_META1, TEST_METADATA)
def test_is_qos_or_format_support(self): def test_is_qos_or_format_support(self):
QOS_SUPPORT = \ QOS_SUPPORT = \
@ -2016,35 +2008,29 @@ class FJCommonTestCase(test.TestCase):
def test_update_migrated_volume(self): def test_update_migrated_volume(self):
model_info = self.driver.create_volume(TEST_VOLUME) model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info) 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) model_info2 = self.driver.create_volume(TEST_VOLUME2)
self.volume_update(TEST_VOLUME2, model_info2)
self.assertEqual(FAKE_MODEL_INFO3, model_info2) 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, model_update = self.driver.common.update_migrated_volume(self.context,
volume_info, TEST_VOLUME,
volume_info2) TEST_VOLUME2)
FAKE_MIGRATED_MODEL_UPDATE = { FAKE_MIGRATED_MODEL_UPDATE = {
'_name_id': TEST_VOLUME2['id'], '_name_id': TEST_VOLUME2['id'],
'provider_location': model_info2['provider_location'] 'provider_location': model_info2['provider_location']
} }
self.assertEqual(FAKE_MIGRATED_MODEL_UPDATE, model_update) self.assertEqual(FAKE_MIGRATED_MODEL_UPDATE, model_update)
def test_create_snapshot(self):
model_info = self.driver.create_volume(TEST_VOLUME)
self.volume_update(TEST_VOLUME, model_info)
self.assertEqual(FAKE_MODEL_INFO1, model_info)
snap_info = self.driver.common._create_snapshot(TEST_SNAP)
self.assertEqual(FAKE_SNAP_INFO, snap_info)
self.driver.delete_volume(TEST_VOLUME)

View File

@ -70,10 +70,11 @@ class FJDXCommon(object):
1.4.2 - Add the secondary check for copy-sessions when deleting volumes. 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.3 - Add fragment capacity information of RAID Group.
1.4.4 - Add support for update migrated volume. 1.4.4 - Add support for update migrated volume.
1.4.5 - Add metadata for snapshot.
""" """
VERSION = "1.4.4" VERSION = "1.4.5"
stats = { stats = {
'driver_version': VERSION, 'driver_version': VERSION,
'storage_protocol': None, 'storage_protocol': None,
@ -636,24 +637,18 @@ class FJDXCommon(object):
LOG.error(msg) LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg) raise exception.VolumeBackendAPIException(data=msg)
@lockutils.synchronized('ETERNUS-vol', 'cinder-', True)
def create_snapshot(self, snapshot): def create_snapshot(self, snapshot):
"""Create snapshot using SnapOPC.""" """Create snapshot using SnapOPC."""
LOG.debug('create_snapshot, ' LOG.debug('create_snapshot, '
'snapshot id: %(sid)s, volume id: %(vid)s.', 'snapshot id: %(sid)s, volume id: %(vid)s.',
{'sid': snapshot['id'], 'vid': snapshot['volume_id']}) {'sid': snapshot['id'], 'vid': snapshot['volume_id']})
self.conn = self._get_eternus_connection()
snapshotname = snapshot['name']
volumename = snapshot['volume_name']
volume = snapshot['volume'] volume = snapshot['volume']
d_volumename = self._get_volume_name(snapshot, use_id=True)
s_volumename = self._get_volume_name(volume) s_volumename = self._get_volume_name(volume)
vol_instance = self._find_lun(volume) vol_instance = self._find_lun(volume)
repservice = self._find_eternus_service(CONSTANTS.REPL)
# Check the existence of volume. # Check the existence of volume.
if vol_instance is None: if not vol_instance:
# Volume not found on ETERNUS. # Volume not found on ETERNUS.
msg = (_('create_snapshot, ' msg = (_('create_snapshot, '
'volumename: %(s_volumename)s, ' 'volumename: %(s_volumename)s, '
@ -662,7 +657,37 @@ class FJDXCommon(object):
LOG.error(msg) LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg) raise exception.VolumeBackendAPIException(data=msg)
if repservice is None: model_update = self._create_snapshot(snapshot)
return model_update
@lockutils.synchronized('ETERNUS-vol', 'cinder-', True)
def _create_snapshot(self, snapshot):
LOG.debug('create_snapshot, '
'snapshot id: %(sid)s, volume id: %(vid)s.',
{'sid': snapshot['id'], 'vid': snapshot['volume_id']})
self.conn = self._get_eternus_connection()
snapshotname = snapshot['name']
volume = snapshot['volume']
volumename = snapshot['volume_name']
d_volumename = self._get_volume_name(snapshot, use_id=True)
s_volumename = self._get_volume_name(volume)
vol_instance = self._find_lun(volume)
smis_service = self._find_eternus_service(CONSTANTS.REPL)
# Check the existence of volume.
if not vol_instance:
# Volume not found on ETERNUS.
msg = (_('create_snapshot, '
'volumename: %(s_volumename)s, '
'source volume not found on ETERNUS.')
% {'s_volumename': s_volumename})
LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg)
if not smis_service:
msg = (_('create_snapshot, ' msg = (_('create_snapshot, '
'volumename: %(volumename)s, ' 'volumename: %(volumename)s, '
'Replication Service not found.') 'Replication Service not found.')
@ -674,7 +699,7 @@ class FJDXCommon(object):
eternus_pool = self._get_drvcfg('EternusSnapPool') eternus_pool = self._get_drvcfg('EternusSnapPool')
# Check the existence of pool # Check the existence of pool
pool = self._find_pool(eternus_pool) pool = self._find_pool(eternus_pool)
if pool is None: if not pool:
msg = (_('create_snapshot, ' msg = (_('create_snapshot, '
'eternus_pool: %(eternus_pool)s, ' 'eternus_pool: %(eternus_pool)s, '
'pool not found.') 'pool not found.')
@ -695,14 +720,26 @@ class FJDXCommon(object):
'd_volumename': d_volumename, 'd_volumename': d_volumename,
'pool': pool}) 'pool': pool})
if self.model_name != CONSTANTS.DX_S2:
smis_method = 'CreateElementReplica'
params = {
'ElementName': d_volumename,
'TargetPool': pool,
'SyncType': self._pywbem_uint(7, '16'),
'SourceElement': vol_instance.path
}
else:
smis_method = 'CreateReplica'
params = {
'ElementName': d_volumename,
'TargetPool': pool,
'CopyType': self._pywbem_uint(4, '16'),
'SourceElement': vol_instance.path
}
# Invoke method for create snapshot # Invoke method for create snapshot
rc, errordesc, job = self._exec_eternus_service( rc, errordesc, job = self._exec_eternus_service(
'CreateElementReplica', smis_method, smis_service,
repservice, **params)
ElementName=d_volumename,
TargetPool=pool,
SyncType=self._pywbem_uint(7, '16'),
SourceElement=vol_instance.path)
if rc != 0: if rc != 0:
msg = (_('create_snapshot, ' msg = (_('create_snapshot, '
@ -724,6 +761,7 @@ class FJDXCommon(object):
raise exception.VolumeBackendAPIException(data=msg) raise exception.VolumeBackendAPIException(data=msg)
else: else:
element = job['TargetElement'] element = job['TargetElement']
d_volume_no = self._get_volume_number(element)
LOG.debug('create_snapshot, ' LOG.debug('create_snapshot, '
'volumename:%(volumename)s, ' 'volumename:%(volumename)s, '
@ -743,11 +781,17 @@ class FJDXCommon(object):
'vol_name': d_volumename, 'vol_name': d_volumename,
} }
sdv_no = self._get_volume_number(element)
metadata = {'FJ_SDV_Name': d_volumename, metadata = {'FJ_SDV_Name': d_volumename,
'FJ_SDV_No': sdv_no, 'FJ_SDV_No': d_volume_no,
'FJ_Pool_Name': eternus_pool} 'FJ_Pool_Name': eternus_pool}
return (element_path, metadata) d_metadata = self.get_metadata(snapshot)
d_metadata.update(metadata)
model_update = {
'provider_location': str(element_path),
'metadata': d_metadata,
}
return model_update
def delete_snapshot(self, snapshot): def delete_snapshot(self, snapshot):
"""Delete snapshot.""" """Delete snapshot."""
@ -1197,7 +1241,7 @@ class FJDXCommon(object):
else: else:
ret = [] ret = []
for e in elem.findall(".//" + tagname): for e in elem.findall(".//" + tagname):
if (e.text is not None) and (e.text not in ret): if e.text and (e.text not in ret):
ret.append(e.text) ret.append(e.text)
if not ret: if not ret:
@ -1250,8 +1294,7 @@ class FJDXCommon(object):
"""Get volume_name on ETERNUS from volume on OpenStack.""" """Get volume_name on ETERNUS from volume on OpenStack."""
LOG.debug('_get_volume_name, volume_id: %s.', volume['id']) LOG.debug('_get_volume_name, volume_id: %s.', volume['id'])
if (not use_id and 'provider_location' in volume and if not use_id and volume['provider_location']:
volume['provider_location']):
location = eval(volume['provider_location']) location = eval(volume['provider_location'])
if 'vol_name' in location: if 'vol_name' in location:
LOG.debug('_get_volume_name, by provider_location, ' LOG.debug('_get_volume_name, by provider_location, '
@ -1609,7 +1652,7 @@ class FJDXCommon(object):
@lockutils.synchronized('ETERNUS-SMIS-getinstance', 'cinder-', True) @lockutils.synchronized('ETERNUS-SMIS-getinstance', 'cinder-', True)
@utils.retry(exception.VolumeBackendAPIException) @utils.retry(exception.VolumeBackendAPIException)
def _get_eternus_instance(self, classname, allownone=False, **param_dict): def _get_eternus_instance(self, classname, AllowNone=False, **param_dict):
"""Get Instance.""" """Get Instance."""
LOG.debug('_get_eternus_instance, ' LOG.debug('_get_eternus_instance, '
'classname: %(cls)s, param: %(param)s.', 'classname: %(cls)s, param: %(param)s.',
@ -1619,7 +1662,7 @@ class FJDXCommon(object):
try: try:
ret = self.conn.GetInstance(classname, **param_dict) ret = self.conn.GetInstance(classname, **param_dict)
except Exception as e: except Exception as e:
if e.args[0] == 6 and allownone: if e.args[0] == 6 and AllowNone:
return ret return ret
else: else:
msg = _('_get_eternus_instance, Error:%s.') % e msg = _('_get_eternus_instance, Error:%s.') % e
@ -1703,6 +1746,7 @@ class FJDXCommon(object):
location = eval(volume['provider_location']) location = eval(volume['provider_location'])
classname = location['classname'] classname = location['classname']
bindings = location['keybindings'] bindings = location['keybindings']
isSuccess = True
if classname and bindings: if classname and bindings:
LOG.debug('_find_lun, ' LOG.debug('_find_lun, '
@ -1718,17 +1762,17 @@ class FJDXCommon(object):
{'volume_instance_name': volume_instance_name}) {'volume_instance_name': volume_instance_name})
vol_instance = self._get_eternus_instance(volume_instance_name, vol_instance = self._get_eternus_instance(volume_instance_name,
allownone=True,) AllowNone=True)
if vol_instance and vol_instance['ElementName'] == volumename: if vol_instance and vol_instance['ElementName'] == volumename:
volumeinstance = vol_instance volumeinstance = vol_instance
except Exception: except Exception:
volumeinstance = None isSuccess = False
LOG.debug('_find_lun, ' LOG.debug('_find_lun, '
'Cannot get volume instance from provider location, ' 'Cannot get volume instance from provider location, '
'Search all volume using EnumerateInstanceNames.') 'Search all volume using EnumerateInstanceNames.')
if not volumeinstance: if not isSuccess and self.model_name == CONSTANTS.DX_S2:
# For old version. # For old version.
LOG.debug('_find_lun, ' LOG.debug('_find_lun, '
'volumename: %(volumename)s.', 'volumename: %(volumename)s.',

View File

@ -97,9 +97,15 @@ class FJDXFCDriver(driver.FibreChannelDriver):
def create_snapshot(self, snapshot): def create_snapshot(self, snapshot):
"""Creates a snapshot.""" """Creates a snapshot."""
location, metadata = self.common.create_snapshot(snapshot) LOG.debug('create_snapshot, '
'snap id: %(sid)s, volume id: %(vid)s, Enter method.',
{'sid': snapshot['id'], 'vid': snapshot['volume_id']})
return {'provider_location': str(location)} model_update = self.common.create_snapshot(snapshot)
LOG.debug('create_snapshot, info: %s, Exit method.',
model_update['metadata'])
return model_update
def delete_snapshot(self, snapshot): def delete_snapshot(self, snapshot):
"""Deletes a snapshot.""" """Deletes a snapshot."""

View File

@ -104,9 +104,15 @@ class FJDXISCSIDriver(driver.ISCSIDriver):
def create_snapshot(self, snapshot): def create_snapshot(self, snapshot):
"""Creates a snapshot.""" """Creates a snapshot."""
element_path, metadata = self.common.create_snapshot(snapshot) LOG.debug('create_snapshot, '
'snap id: %(sid)s, volume id: %(vid)s, Enter method.',
{'sid': snapshot['id'], 'vid': snapshot['volume_id']})
return {'provider_location': str(element_path)} model_update = self.common.create_snapshot(snapshot)
LOG.debug('create_snapshot, info: %s, Exit method.',
model_update['metadata'])
return model_update
def delete_snapshot(self, snapshot): def delete_snapshot(self, snapshot):
"""Deletes a snapshot.""" """Deletes a snapshot."""

View File

@ -0,0 +1,13 @@
---
features:
- |
Fujitsu ETERNUS DX driver: Add metadata to snapshot
After the snapshot is created, upload the information of the snapshot on
the storage to the metadata.
The metadata has the following information:
- ``FJ_SDV_Name``
- ``FJ_SDV_No``
- ``FJ_Pool_Name``