Merge "Fujitsu driver: Improve volume deletion"
This commit is contained in:
commit
e28867ba8d
@ -175,7 +175,7 @@ FAKE_POOLS = [{
|
|||||||
}]
|
}]
|
||||||
|
|
||||||
FAKE_STATS = {
|
FAKE_STATS = {
|
||||||
'driver_version': '1.4.1',
|
'driver_version': '1.4.2',
|
||||||
'storage_protocol': 'iSCSI',
|
'storage_protocol': 'iSCSI',
|
||||||
'vendor_name': 'FUJITSU',
|
'vendor_name': 'FUJITSU',
|
||||||
'QoS_support': True,
|
'QoS_support': True,
|
||||||
@ -185,7 +185,7 @@ FAKE_STATS = {
|
|||||||
'pools': FAKE_POOLS,
|
'pools': FAKE_POOLS,
|
||||||
}
|
}
|
||||||
FAKE_STATS2 = {
|
FAKE_STATS2 = {
|
||||||
'driver_version': '1.4.1',
|
'driver_version': '1.4.2',
|
||||||
'storage_protocol': 'FC',
|
'storage_protocol': 'FC',
|
||||||
'vendor_name': 'FUJITSU',
|
'vendor_name': 'FUJITSU',
|
||||||
'QoS_support': True,
|
'QoS_support': True,
|
||||||
@ -375,8 +375,11 @@ class FakeCIMInstanceName(dict):
|
|||||||
snaps = FakeCIMInstanceName()
|
snaps = FakeCIMInstanceName()
|
||||||
snaps['ElementName'] = 'FJosv_OgEZj1mSvKRvIKOExKktlg=='
|
snaps['ElementName'] = 'FJosv_OgEZj1mSvKRvIKOExKktlg=='
|
||||||
snaps['Name'] = None
|
snaps['Name'] = None
|
||||||
|
snaps['DeviceID'] = FAKE_LUN_ID2
|
||||||
|
snaps['SystemName'] = STORAGE_SYSTEM
|
||||||
ret.append(snaps)
|
ret.append(snaps)
|
||||||
snaps.path = ''
|
snaps.path = ''
|
||||||
|
snaps.classname = 'FUJITSU_StorageVolume'
|
||||||
|
|
||||||
map = FakeCIMInstanceName()
|
map = FakeCIMInstanceName()
|
||||||
map['ElementName'] = 'FJosv_hhJsV9lcMBvAPADrGqucwg=='
|
map['ElementName'] = 'FJosv_hhJsV9lcMBvAPADrGqucwg=='
|
||||||
@ -1037,6 +1040,16 @@ class FJFCDriverTestCase(test.TestCase):
|
|||||||
'0002\t\r\n0000\tFJosv_0qJ4rpOHgFE8ipcJOMfBmg==\t0F'
|
'0002\t\r\n0000\tFJosv_0qJ4rpOHgFE8ipcJOMfBmg==\t0F'
|
||||||
'\t\r\n0001\tFJosv_OgEZj1mSvKRvIKOExKktlg==\t0D'
|
'\t\r\n0001\tFJosv_OgEZj1mSvKRvIKOExKktlg==\t0D'
|
||||||
'\t\r\nCLI> ' % exec_cmdline)
|
'\t\r\nCLI> ' % exec_cmdline)
|
||||||
|
elif exec_cmdline.startswith('show copy-sessions'):
|
||||||
|
ret = ('\r\nCLI> %s\r\n00\r\n0001\t\r\n'
|
||||||
|
'0001\tFFFF\t01\t08\tFF\tFF\t03\t02\tFF\tFF\t05ABD7D2\t'
|
||||||
|
'########################################\t'
|
||||||
|
'########################################\t'
|
||||||
|
'00000281\t00000286\t0001\t00\tFF\t0000000000000800\t'
|
||||||
|
'0000000000000000\t0000000000000100\t0000000000000800\t'
|
||||||
|
'04\t00\t00000000\t2020101009341400\t01\t10\tFFFF\tFFFF\t'
|
||||||
|
'0000000000000000\tFFFFFFFFFFFFFFFF\tFFFFFFFFFFFFFFFF\tFF\t'
|
||||||
|
'FF\t64\t00\t07\t00\t00\t00\r\nCLI> ' % exec_cmdline)
|
||||||
elif exec_cmdline.startswith('show qos-bandwidth-limit'):
|
elif exec_cmdline.startswith('show qos-bandwidth-limit'):
|
||||||
ret = ('\r\nCLI> %s\r\n00\r\n0010\t\r\n00\t0000ffff\t0000ffff'
|
ret = ('\r\nCLI> %s\r\n00\r\n0010\t\r\n00\t0000ffff\t0000ffff'
|
||||||
'\t0000ffff\t0000ffff\t0000ffff\t0000ffff\t0000ffff'
|
'\t0000ffff\t0000ffff\t0000ffff\t0000ffff\t0000ffff'
|
||||||
@ -1080,6 +1093,8 @@ class FJFCDriverTestCase(test.TestCase):
|
|||||||
'\r\nCLI> ' % exec_cmdline)
|
'\r\nCLI> ' % exec_cmdline)
|
||||||
elif exec_cmdline.startswith('set qos-bandwidth-limit'):
|
elif exec_cmdline.startswith('set qos-bandwidth-limit'):
|
||||||
ret = '%s\r\n00\r\n0001\r\nCLI> ' % exec_cmdline
|
ret = '%s\r\n00\r\n0001\r\nCLI> ' % exec_cmdline
|
||||||
|
elif exec_cmdline.startswith('stop copy-session'):
|
||||||
|
ret = '%s\r\n00\r\nCLI> ' % exec_cmdline
|
||||||
else:
|
else:
|
||||||
ret = None
|
ret = None
|
||||||
return ret
|
return ret
|
||||||
@ -1284,6 +1299,16 @@ class FJISCSIDriverTestCase(test.TestCase):
|
|||||||
'0002\t\r\n0000\tFJosv_0qJ4rpOHgFE8ipcJOMfBmg==\t0F'
|
'0002\t\r\n0000\tFJosv_0qJ4rpOHgFE8ipcJOMfBmg==\t0F'
|
||||||
'\t\r\n0001\tFJosv_OgEZj1mSvKRvIKOExKktlg==\t0D'
|
'\t\r\n0001\tFJosv_OgEZj1mSvKRvIKOExKktlg==\t0D'
|
||||||
'\t\r\nCLI> ' % exec_cmdline)
|
'\t\r\nCLI> ' % exec_cmdline)
|
||||||
|
elif exec_cmdline.startswith('show copy-sessions'):
|
||||||
|
ret = ('\r\nCLI> %s\r\n00\r\n0001\t\r\n'
|
||||||
|
'0001\tFFFF\t01\t08\tFF\tFF\t03\t02\tFF\tFF\t05ABD7D2\t'
|
||||||
|
'########################################\t'
|
||||||
|
'########################################\t'
|
||||||
|
'00000281\t00000286\t0001\t00\tFF\t0000000000000800\t'
|
||||||
|
'0000000000000000\t0000000000000100\t0000000000000800\t'
|
||||||
|
'04\t00\t00000000\t2020101009341400\t01\t10\tFFFF\tFFFF\t'
|
||||||
|
'0000000000000000\tFFFFFFFFFFFFFFFF\tFFFFFFFFFFFFFFFF\tFF\t'
|
||||||
|
'FF\t64\t00\t07\t00\t00\t00\r\nCLI> ' % exec_cmdline)
|
||||||
elif exec_cmdline.startswith('show qos-bandwidth-limit'):
|
elif exec_cmdline.startswith('show qos-bandwidth-limit'):
|
||||||
ret = ('\r\nCLI> %s\r\n00\r\n0010\t\r\n00\t0000ffff\t0000ffff'
|
ret = ('\r\nCLI> %s\r\n00\r\n0010\t\r\n00\t0000ffff\t0000ffff'
|
||||||
'\t0000ffff\t0000ffff\t0000ffff\t0000ffff\t0000ffff'
|
'\t0000ffff\t0000ffff\t0000ffff\t0000ffff\t0000ffff'
|
||||||
@ -1515,6 +1540,16 @@ class FJCLITestCase(test.TestCase):
|
|||||||
ret = ('\r\nCLI> %s\r\n00\r\n'
|
ret = ('\r\nCLI> %s\r\n00\r\n'
|
||||||
'0001\r\n0000\tFJosv_0qJ4rpOHgFE8ipcJOMfBmg==\t01\t00\t00'
|
'0001\r\n0000\tFJosv_0qJ4rpOHgFE8ipcJOMfBmg==\t01\t00\t00'
|
||||||
'\r\nCLI> ' % exec_cmdline)
|
'\r\nCLI> ' % exec_cmdline)
|
||||||
|
elif exec_cmdline.startswith('show copy-sessions'):
|
||||||
|
ret = ('\r\nCLI> %s\r\n00\r\n0001\t\r\n'
|
||||||
|
'0001\tFFFF\t01\t08\tFF\tFF\t03\t02\tFF\tFF\t05ABD7D2\t'
|
||||||
|
'########################################\t'
|
||||||
|
'########################################\t'
|
||||||
|
'00000281\t00000286\t0001\t00\tFF\t0000000000000800\t'
|
||||||
|
'0000000000000000\t0000000000000100\t0000000000000800\t'
|
||||||
|
'04\t00\t00000000\t2020101009341400\t01\t10\tFFFF\tFFFF\t'
|
||||||
|
'0000000000000000\tFFFFFFFFFFFFFFFF\tFFFFFFFFFFFFFFFF\tFF\t'
|
||||||
|
'FF\t64\t00\t07\t00\t00\t00\r\nCLI> ' % exec_cmdline)
|
||||||
elif exec_cmdline.startswith('show qos-bandwidth-limit'):
|
elif exec_cmdline.startswith('show qos-bandwidth-limit'):
|
||||||
ret = ('\r\nCLI> %s\r\n00\r\n0001\t\r\n00\t0000ffff\t0000ffff'
|
ret = ('\r\nCLI> %s\r\n00\r\n0001\t\r\n00\t0000ffff\t0000ffff'
|
||||||
'\t0000ffff\t0000ffff\t0000ffff\t0000ffff\t0000ffff'
|
'\t0000ffff\t0000ffff\t0000ffff\t0000ffff\t0000ffff'
|
||||||
@ -1522,6 +1557,8 @@ class FJCLITestCase(test.TestCase):
|
|||||||
'CLI> ' % exec_cmdline)
|
'CLI> ' % exec_cmdline)
|
||||||
elif exec_cmdline.startswith('set qos-bandwidth-limit'):
|
elif exec_cmdline.startswith('set qos-bandwidth-limit'):
|
||||||
ret = '%s\r\n00\r\n0001\r\nCLI> ' % exec_cmdline
|
ret = '%s\r\n00\r\n0001\r\nCLI> ' % exec_cmdline
|
||||||
|
elif exec_cmdline.startswith('stop copy-session'):
|
||||||
|
ret = '%s\r\n00\r\nCLI> ' % exec_cmdline
|
||||||
elif exec_cmdline.startswith('delete volume'):
|
elif exec_cmdline.startswith('delete volume'):
|
||||||
ret = '%s\r\n00\r\nCLI> ' % exec_cmdline
|
ret = '%s\r\n00\r\nCLI> ' % exec_cmdline
|
||||||
else:
|
else:
|
||||||
@ -1608,6 +1645,21 @@ class FJCLITestCase(test.TestCase):
|
|||||||
volume_number = self.cli._set_volume_qos(**FAKE_QOS_OPTION)
|
volume_number = self.cli._set_volume_qos(**FAKE_QOS_OPTION)
|
||||||
self.assertEqual(FAKE_QOS_OUTPUT, volume_number)
|
self.assertEqual(FAKE_QOS_OUTPUT, volume_number)
|
||||||
|
|
||||||
|
def test_show_copy_sessions(self):
|
||||||
|
FAKE_COPY_SESSION = [{
|
||||||
|
'Source Num': 641,
|
||||||
|
'Dest Num': 646,
|
||||||
|
'Type': 'Snap',
|
||||||
|
'Status': 'Active',
|
||||||
|
'Phase': 'Tracking',
|
||||||
|
'Session ID': 1,
|
||||||
|
}]
|
||||||
|
FAKE_COPY_SESSION_OUTPUT = {**FAKE_CLI_OUTPUT,
|
||||||
|
'message': FAKE_COPY_SESSION}
|
||||||
|
|
||||||
|
cpdatalist = self.cli._show_copy_sessions()
|
||||||
|
self.assertEqual(FAKE_COPY_SESSION_OUTPUT, cpdatalist)
|
||||||
|
|
||||||
def test_show_pool_provision(self):
|
def test_show_pool_provision(self):
|
||||||
FAKE_POOL_PROVIOSN_OPTION = self.create_fake_options(
|
FAKE_POOL_PROVIOSN_OPTION = self.create_fake_options(
|
||||||
pool_name='abcd1234_TPP')
|
pool_name='abcd1234_TPP')
|
||||||
@ -1666,6 +1718,15 @@ class FJCLITestCase(test.TestCase):
|
|||||||
versioninfo = self.cli._show_enclosure_status()
|
versioninfo = self.cli._show_enclosure_status()
|
||||||
self.assertEqual(FAKE_VERSION_INFO, versioninfo)
|
self.assertEqual(FAKE_VERSION_INFO, versioninfo)
|
||||||
|
|
||||||
|
def test_stop_copy_session(self):
|
||||||
|
FAKE_SESSION_ID = '0001'
|
||||||
|
FAKE_STOP_OUTPUT = {**FAKE_CLI_OUTPUT, 'message': []}
|
||||||
|
FAKE_STOP_COPY_SESSION_OPTION = self.create_fake_options(
|
||||||
|
session_id=FAKE_SESSION_ID)
|
||||||
|
stop_output = self.cli._stop_copy_session(
|
||||||
|
**FAKE_STOP_COPY_SESSION_OPTION)
|
||||||
|
self.assertEqual(FAKE_STOP_OUTPUT, stop_output)
|
||||||
|
|
||||||
def test_delete_volume(self):
|
def test_delete_volume(self):
|
||||||
FAKE_VOLUME_NAME = 'FJosv_0qJ4rpOHgFE8ipcJOMfBmg=='
|
FAKE_VOLUME_NAME = 'FJosv_0qJ4rpOHgFE8ipcJOMfBmg=='
|
||||||
FAKE_DELETE_OUTPUT = {**FAKE_CLI_OUTPUT, 'message': []}
|
FAKE_DELETE_OUTPUT = {**FAKE_CLI_OUTPUT, 'message': []}
|
||||||
@ -1746,13 +1807,25 @@ class FJCommonTestCase(test.TestCase):
|
|||||||
ret = ('\r\nCLI> %s\r\n00\r\n'
|
ret = ('\r\nCLI> %s\r\n00\r\n'
|
||||||
'0001\r\n0000\tFJosv_0qJ4rpOHgFE8ipcJOMfBmg==\t01\t00\t00'
|
'0001\r\n0000\tFJosv_0qJ4rpOHgFE8ipcJOMfBmg==\t01\t00\t00'
|
||||||
'\r\nCLI> ' % exec_cmdline)
|
'\r\nCLI> ' % exec_cmdline)
|
||||||
|
elif exec_cmdline.startswith('show copy-sessions'):
|
||||||
|
ret = ('\r\nCLI> %s\r\n00\r\n0001\t\r\n'
|
||||||
|
'0001\tFFFF\t01\t08\tFF\tFF\t03\t02\tFF\tFF\t05ABD7D2\t'
|
||||||
|
'########################################\t'
|
||||||
|
'########################################\t'
|
||||||
|
'00000281\t00000286\t0001\t00\tFF\t0000000000000800\t'
|
||||||
|
'0000000000000000\t0000000000000100\t0000000000000800\t'
|
||||||
|
'04\t00\t00000000\t2020101009341400\t01\t10\tFFFF\tFFFF\t'
|
||||||
|
'0000000000000000\tFFFFFFFFFFFFFFFF\tFFFFFFFFFFFFFFFF\tFF\t'
|
||||||
|
'FF\t64\t00\t07\t00\t00\t00\r\nCLI> ' % exec_cmdline)
|
||||||
elif exec_cmdline.startswith('show qos-bandwidth-limit'):
|
elif exec_cmdline.startswith('show qos-bandwidth-limit'):
|
||||||
ret = ('\r\nCLI> %s\r\n00\r\n0001\t\r\n00\t0000ffff\t0000ffff'
|
ret = ('\r\nCLI> %s\r\n00\r\n0001\t\r\n00\t0000ffff\t0000ffff'
|
||||||
'\t0000ffff\t0000ffff\t0000ffff\t0000ffff\t0000ffff'
|
'\t0000ffff\t0000ffff\t0000ffff\t0000ffff\t0000ffff'
|
||||||
'\t0000ffff\t0000ffff\t0000ffff\t0000ffff\t0000ffff\r\n'
|
'\t0000ffff\t0000ffff\t0000ffff\t0000ffff\t0000ffff\r\n'
|
||||||
'CLI> ' % exec_cmdline)
|
'CLI> ' % exec_cmdline)
|
||||||
elif exec_cmdline.startswith('set qos-bandwidth-limit'):
|
elif exec_cmdline.startswith('set qos-bandwidth-limit'):
|
||||||
ret = '\r\nCLI> %s\r\n00\r\n0001\r\nCLI> ' % exec_cmdline
|
ret = '%s\r\n00\r\n0001\r\nCLI> ' % exec_cmdline
|
||||||
|
elif exec_cmdline.startswith('stop copy-session'):
|
||||||
|
ret = '%s\r\n00\r\nCLI> ' % exec_cmdline
|
||||||
else:
|
else:
|
||||||
ret = None
|
ret = None
|
||||||
return ret
|
return ret
|
||||||
@ -1764,6 +1837,19 @@ class FJCommonTestCase(test.TestCase):
|
|||||||
conn = FakeEternusConnection()
|
conn = FakeEternusConnection()
|
||||||
return conn
|
return conn
|
||||||
|
|
||||||
|
def test_get_volume_number(self):
|
||||||
|
vol_instance = FakeCIMInstanceName()
|
||||||
|
vol_instance['ElementName'] = 'FJosv_0qJ4rpOHgFE8ipcJOMfBmg=='
|
||||||
|
vol_instance['Purpose'] = '00228+0x06'
|
||||||
|
vol_instance['Name'] = None
|
||||||
|
vol_instance['DeviceID'] = FAKE_LUN_ID1
|
||||||
|
vol_instance['SystemName'] = STORAGE_SYSTEM
|
||||||
|
vol_instance.path = ''
|
||||||
|
vol_instance.classname = 'FUJITSU_StorageVolume'
|
||||||
|
|
||||||
|
volume_no = self.driver.common._get_volume_number(vol_instance)
|
||||||
|
self.assertEqual(FAKE_LUN_NO1, volume_no)
|
||||||
|
|
||||||
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)
|
||||||
@ -1846,3 +1932,15 @@ class FJCommonTestCase(test.TestCase):
|
|||||||
self.driver.common._set_limit(FAKE_MODE, FAKE_LIMIT,
|
self.driver.common._set_limit(FAKE_MODE, FAKE_LIMIT,
|
||||||
FAKE_IOPS, FAKE_THROUGHOUTPUT)
|
FAKE_IOPS, FAKE_THROUGHOUTPUT)
|
||||||
mock_exec_cli_with_eternus.assert_called_with(exec_cmdline)
|
mock_exec_cli_with_eternus.assert_called_with(exec_cmdline)
|
||||||
|
|
||||||
|
def test_get_copy_sessions_list(self):
|
||||||
|
FAKE_COPY_SESSION = [{
|
||||||
|
'Source Num': 641,
|
||||||
|
'Dest Num': 646,
|
||||||
|
'Type': 'Snap',
|
||||||
|
'Status': 'Active',
|
||||||
|
'Phase': 'Tracking',
|
||||||
|
'Session ID': 1,
|
||||||
|
}]
|
||||||
|
copy_session_list = self.driver.common._get_copy_sessions_list()
|
||||||
|
self.assertEqual(FAKE_COPY_SESSION, copy_session_list)
|
||||||
|
@ -50,8 +50,10 @@ class FJDXCLI(object):
|
|||||||
'show_qos_bandwidth_limit': self._show_qos_bandwidth_limit,
|
'show_qos_bandwidth_limit': self._show_qos_bandwidth_limit,
|
||||||
'set_qos_bandwidth_limit': self._set_qos_bandwidth_limit,
|
'set_qos_bandwidth_limit': self._set_qos_bandwidth_limit,
|
||||||
'set_volume_qos': self._set_volume_qos,
|
'set_volume_qos': self._set_volume_qos,
|
||||||
|
'show_copy_sessions': self._show_copy_sessions,
|
||||||
'show_volume_qos': self._show_volume_qos,
|
'show_volume_qos': self._show_volume_qos,
|
||||||
'show_enclosure_status': self._show_enclosure_status,
|
'show_enclosure_status': self._show_enclosure_status,
|
||||||
|
'stop_copy_session': self._stop_copy_session,
|
||||||
'delete_volume': self._delete_volume
|
'delete_volume': self._delete_volume
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,6 +278,92 @@ class FJDXCLI(object):
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
def _show_copy_sessions(self, **option):
|
||||||
|
"""Get copy sessions."""
|
||||||
|
try:
|
||||||
|
output = self._exec_cli("show copy-sessions", **option)
|
||||||
|
|
||||||
|
# return error
|
||||||
|
rc = output['rc']
|
||||||
|
|
||||||
|
if rc != "0":
|
||||||
|
return output
|
||||||
|
|
||||||
|
cpsdatalist = []
|
||||||
|
clidatalist = output.get('message')
|
||||||
|
|
||||||
|
for clidataline in clidatalist[1:]:
|
||||||
|
clidata = clidataline.split('\t')
|
||||||
|
# Get CopyType
|
||||||
|
if clidata[2] == '01':
|
||||||
|
# CopyKind: OPC
|
||||||
|
if bin(int(clidata[3], 16) & 16) != 0:
|
||||||
|
# eg. 0b10010000
|
||||||
|
temp_type = 'Snap'
|
||||||
|
elif bin(int(clidata[3], 16) & 64) != 0:
|
||||||
|
# eg. 0b11000000
|
||||||
|
temp_type = 'Snap+'
|
||||||
|
else:
|
||||||
|
temp_type = 'Other'
|
||||||
|
elif clidata[2] == '02':
|
||||||
|
# CopyKind: EC
|
||||||
|
if clidata[5] == 'FF':
|
||||||
|
temp_type = 'EC'
|
||||||
|
elif clidata[5] == '10':
|
||||||
|
temp_type = 'Sync_REC'
|
||||||
|
else:
|
||||||
|
temp_type = 'Other'
|
||||||
|
else:
|
||||||
|
temp_type = 'Other'
|
||||||
|
|
||||||
|
# Get Phases
|
||||||
|
if clidata[6] == '00':
|
||||||
|
temp_phase = 'No_Pair'
|
||||||
|
elif clidata[6] == '01':
|
||||||
|
temp_phase = 'Copying'
|
||||||
|
elif clidata[6] == '02':
|
||||||
|
temp_phase = 'Equivalent'
|
||||||
|
elif clidata[6] == '03':
|
||||||
|
temp_phase = 'Tracking'
|
||||||
|
elif clidata[6] == '04':
|
||||||
|
temp_phase = 'Tracking_Copying'
|
||||||
|
elif clidata[6] == '06':
|
||||||
|
temp_phase = 'Readying'
|
||||||
|
else:
|
||||||
|
temp_phase = 'Other'
|
||||||
|
|
||||||
|
# Get CopyStatus
|
||||||
|
if clidata[7] == '00':
|
||||||
|
temp_status = 'Idle'
|
||||||
|
elif clidata[7] == '01':
|
||||||
|
temp_status = 'Reserve'
|
||||||
|
elif clidata[7] == '02':
|
||||||
|
temp_status = 'Active'
|
||||||
|
elif clidata[7] == '03':
|
||||||
|
temp_status = 'Error_Suspend'
|
||||||
|
elif clidata[7] == '04':
|
||||||
|
temp_status = 'Suspend'
|
||||||
|
elif clidata[7] == '05':
|
||||||
|
temp_status = 'Halt'
|
||||||
|
else:
|
||||||
|
temp_status = 'Other'
|
||||||
|
|
||||||
|
cpsdatalist.append({'Source Num': int(clidata[13], 16),
|
||||||
|
'Dest Num': int(clidata[14], 16),
|
||||||
|
'Type': temp_type,
|
||||||
|
'Status': temp_status,
|
||||||
|
'Phase': temp_phase,
|
||||||
|
'Session ID': int(clidata[0], 16)})
|
||||||
|
|
||||||
|
output['message'] = cpsdatalist
|
||||||
|
except Exception as ex:
|
||||||
|
output = {'result': 0,
|
||||||
|
'rc': '4',
|
||||||
|
'message': "Show copy sessions error: %s"
|
||||||
|
% str(ex)}
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
def _show_qos_bandwidth_limit(self, **option):
|
def _show_qos_bandwidth_limit(self, **option):
|
||||||
"""Get qos bandwidth limit."""
|
"""Get qos bandwidth limit."""
|
||||||
clidata = None
|
clidata = None
|
||||||
@ -394,6 +482,10 @@ class FJDXCLI(object):
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
def _stop_copy_session(self, **option):
|
||||||
|
"""Exec stop copy-session."""
|
||||||
|
return self._exec_cli("stop copy-session", **option)
|
||||||
|
|
||||||
def _delete_volume(self, **option):
|
def _delete_volume(self, **option):
|
||||||
"""Exec delete volume."""
|
"""Exec delete volume."""
|
||||||
return self._exec_cli('delete volume', **option)
|
return self._exec_cli('delete volume', **option)
|
||||||
|
@ -67,10 +67,11 @@ class FJDXCommon(object):
|
|||||||
1.3.0 - Community base version
|
1.3.0 - Community base version
|
||||||
1.4.0 - Add support for QoS.
|
1.4.0 - Add support for QoS.
|
||||||
1.4.1 - Add the method for expanding RAID volumes by CLI.
|
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.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "1.4.1"
|
VERSION = "1.4.2"
|
||||||
stats = {
|
stats = {
|
||||||
'driver_version': VERSION,
|
'driver_version': VERSION,
|
||||||
'storage_protocol': None,
|
'storage_protocol': None,
|
||||||
@ -261,7 +262,7 @@ class FJDXCommon(object):
|
|||||||
'vol_name': volumename,
|
'vol_name': volumename,
|
||||||
}
|
}
|
||||||
|
|
||||||
volume_no = "0x" + element['DeviceID'][24:28]
|
volume_no = self._get_volume_number(element)
|
||||||
metadata = {
|
metadata = {
|
||||||
'FJ_Backend': systemnamelist[0]['IdentifyingNumber'],
|
'FJ_Backend': systemnamelist[0]['IdentifyingNumber'],
|
||||||
'FJ_Volume_Name': volumename,
|
'FJ_Volume_Name': volumename,
|
||||||
@ -445,36 +446,37 @@ class FJDXCommon(object):
|
|||||||
|
|
||||||
def delete_volume(self, volume):
|
def delete_volume(self, volume):
|
||||||
"""Delete volume on ETERNUS."""
|
"""Delete volume on ETERNUS."""
|
||||||
LOG.debug('delete_volume, volume id: %s.', volume['id'])
|
LOG.debug('delete_volume, volume id: %(vid)s.',
|
||||||
|
{'vid': volume['id']})
|
||||||
|
|
||||||
self.conn = self._get_eternus_connection()
|
|
||||||
vol_exist = self._delete_volume_setting(volume)
|
vol_exist = self._delete_volume_setting(volume)
|
||||||
|
|
||||||
if not vol_exist:
|
if not vol_exist:
|
||||||
LOG.debug('delete_volume, volume not found in 1st check.')
|
LOG.debug('delete_volume, volume not found in 1st check.')
|
||||||
return False
|
return
|
||||||
|
|
||||||
# Check volume existence on ETERNUS again
|
try:
|
||||||
# because volume is deleted when SnapOPC copysession is deleted.
|
self._delete_volume(volume)
|
||||||
vol_instance = self._find_lun(volume)
|
except Exception as ex:
|
||||||
if vol_instance is None:
|
msg = (_('delete_volume, '
|
||||||
LOG.debug('delete_volume, volume not found in 2nd check, '
|
'delete volume failed, '
|
||||||
'but no problem.')
|
'Error information: %s.')
|
||||||
return True
|
% ex)
|
||||||
|
LOG.error(msg)
|
||||||
self._delete_volume(vol_instance)
|
raise exception.VolumeBackendAPIException(data=msg)
|
||||||
return True
|
|
||||||
|
|
||||||
@lockutils.synchronized('ETERNUS-vol', 'cinder-', True)
|
@lockutils.synchronized('ETERNUS-vol', 'cinder-', True)
|
||||||
def _delete_volume_setting(self, volume):
|
def _delete_volume_setting(self, volume):
|
||||||
"""Delete volume setting (HostAffinity, CopySession) on ETERNUS."""
|
"""Delete volume setting (HostAffinity, CopySession) on ETERNUS."""
|
||||||
LOG.debug('_delete_volume_setting, volume id: %s.', volume['id'])
|
LOG.debug('_delete_volume_setting, '
|
||||||
|
'volume id: %(vid)s.',
|
||||||
|
{'vid': volume['id']})
|
||||||
|
|
||||||
# Check the existence of volume.
|
# Check the existence of volume.
|
||||||
volumename = self._get_volume_name(volume)
|
volumename = self._get_volume_name(volume)
|
||||||
vol_instance = self._find_lun(volume)
|
vol_instance = self._find_lun(volume)
|
||||||
|
|
||||||
if vol_instance is None:
|
if not vol_instance:
|
||||||
LOG.info('_delete_volume_setting, volumename:%(volumename)s, '
|
LOG.info('_delete_volume_setting, volumename:%(volumename)s, '
|
||||||
'volume not found on ETERNUS.',
|
'volume not found on ETERNUS.',
|
||||||
{'volumename': volumename})
|
{'volumename': volumename})
|
||||||
@ -514,6 +516,33 @@ class FJDXCommon(object):
|
|||||||
for cpsession in delete_copysession_list:
|
for cpsession in delete_copysession_list:
|
||||||
self._delete_copysession(cpsession)
|
self._delete_copysession(cpsession)
|
||||||
|
|
||||||
|
volume_no = self._get_volume_number(vol_instance)
|
||||||
|
|
||||||
|
cp_session_list = self._get_copy_sessions_list()
|
||||||
|
for cp in cp_session_list:
|
||||||
|
if cp['Dest Num'] != int(volume_no, 16):
|
||||||
|
continue
|
||||||
|
if cp['Type'] == 'Snap':
|
||||||
|
session_id = cp['Session ID']
|
||||||
|
|
||||||
|
param_dict = ({'session-id': session_id})
|
||||||
|
rc, emsg, clidata = self._exec_eternus_cli(
|
||||||
|
'stop_copy_session',
|
||||||
|
**param_dict)
|
||||||
|
|
||||||
|
if rc != 0:
|
||||||
|
msg = (_('_delete_volume_setting, '
|
||||||
|
'stop_copy_session failed. '
|
||||||
|
'Return code: %(rc)lu, '
|
||||||
|
'Error: %(errormsg)s, '
|
||||||
|
'Message: %(clidata)s.')
|
||||||
|
% {'rc': rc,
|
||||||
|
'errormsg': emsg,
|
||||||
|
'clidata': clidata})
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.VolumeBackendAPIException(data=msg)
|
||||||
|
break
|
||||||
|
|
||||||
LOG.debug('_delete_volume_setting, '
|
LOG.debug('_delete_volume_setting, '
|
||||||
'wait_cpsession: %(wait_cpsession)s, '
|
'wait_cpsession: %(wait_cpsession)s, '
|
||||||
'delete_cpsession: %(delete_cpsession)s, complete.',
|
'delete_cpsession: %(delete_cpsession)s, complete.',
|
||||||
@ -522,15 +551,22 @@ class FJDXCommon(object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@lockutils.synchronized('ETERNUS-vol', 'cinder-', True)
|
@lockutils.synchronized('ETERNUS-vol', 'cinder-', True)
|
||||||
def _delete_volume(self, vol_instance):
|
def _delete_volume(self, volume):
|
||||||
"""Delete volume on ETERNUS."""
|
"""Delete volume on ETERNUS."""
|
||||||
LOG.debug('_delete_volume, volume name: %s.',
|
LOG.debug('_delete_volume, volume id: %(vid)s.',
|
||||||
vol_instance['ElementName'])
|
{'vid': volume['id']})
|
||||||
|
|
||||||
|
vol_instance = self._find_lun(volume)
|
||||||
|
|
||||||
|
if not vol_instance:
|
||||||
|
LOG.debug('_delete_volume, volume not found in 2nd check, '
|
||||||
|
'but no problem.')
|
||||||
|
return
|
||||||
|
|
||||||
volumename = vol_instance['ElementName']
|
volumename = vol_instance['ElementName']
|
||||||
|
|
||||||
configservice = self._find_eternus_service(CONSTANTS.STOR_CONF)
|
configservice = self._find_eternus_service(CONSTANTS.STOR_CONF)
|
||||||
if configservice is None:
|
if not configservice:
|
||||||
msg = (_('_delete_volume, volumename: %(volumename)s, '
|
msg = (_('_delete_volume, volumename: %(volumename)s, '
|
||||||
'Storage Configuration Service not found.')
|
'Storage Configuration Service not found.')
|
||||||
% {'volumename': volumename})
|
% {'volumename': volumename})
|
||||||
@ -698,7 +734,7 @@ class FJDXCommon(object):
|
|||||||
'vol_name': d_volumename,
|
'vol_name': d_volumename,
|
||||||
}
|
}
|
||||||
|
|
||||||
sdv_no = "0x" + element['DeviceID'][24:28]
|
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': sdv_no,
|
||||||
'FJ_Pool_Name': eternus_pool}
|
'FJ_Pool_Name': eternus_pool}
|
||||||
@ -710,9 +746,7 @@ class FJDXCommon(object):
|
|||||||
'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']})
|
||||||
|
|
||||||
vol_exist = self.delete_volume(snapshot)
|
self.delete_volume(snapshot)
|
||||||
LOG.debug('delete_snapshot, vol_exist: %s.', vol_exist)
|
|
||||||
return vol_exist
|
|
||||||
|
|
||||||
def initialize_connection(self, volume, connector):
|
def initialize_connection(self, volume, connector):
|
||||||
"""Allow connection to connector and return connection info."""
|
"""Allow connection to connector and return connection info."""
|
||||||
@ -1421,8 +1455,7 @@ class FJDXCommon(object):
|
|||||||
'classname: %s.', classname)
|
'classname: %s.', classname)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
services = self._enum_eternus_instance_names(
|
services = self._enum_eternus_instance_names(str(classname))
|
||||||
str(classname))
|
|
||||||
except Exception:
|
except Exception:
|
||||||
msg = (_('_find_eternus_service, '
|
msg = (_('_find_eternus_service, '
|
||||||
'classname: %(classname)s, '
|
'classname: %(classname)s, '
|
||||||
@ -2426,7 +2459,7 @@ class FJDXCommon(object):
|
|||||||
|
|
||||||
for vol_instance in vollist:
|
for vol_instance in vollist:
|
||||||
if src_id:
|
if src_id:
|
||||||
volume_no = "0x" + vol_instance['DeviceID'][24:28]
|
volume_no = self._get_volume_number(vol_instance)
|
||||||
try:
|
try:
|
||||||
# Skip hidden tppv volumes.
|
# Skip hidden tppv volumes.
|
||||||
if int(src_id) == int(volume_no, 16):
|
if int(src_id) == int(volume_no, 16):
|
||||||
@ -2536,6 +2569,22 @@ class FJDXCommon(object):
|
|||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def _get_volume_number(self, vol):
|
||||||
|
"""Get volume no(return a hex string)."""
|
||||||
|
if self.model_name == CONSTANTS.DX_S2:
|
||||||
|
volume_number = "0x%04X" % int(vol['DeviceID'][-5:])
|
||||||
|
else:
|
||||||
|
volume_number = "0x" + vol['DeviceID'][24:28]
|
||||||
|
|
||||||
|
LOG.debug('_get_volume_number: %s.', volume_number)
|
||||||
|
return volume_number
|
||||||
|
|
||||||
|
def _exec_eternus_smis_ReferenceNames(self, classname,
|
||||||
|
conn=None,
|
||||||
|
**param_dict):
|
||||||
|
ret = conn.ReferenceNames(classname, **param_dict)
|
||||||
|
return ret
|
||||||
|
|
||||||
def _check_user(self):
|
def _check_user(self):
|
||||||
"""Check whether user's role is accessible to ETERNUS and Software."""
|
"""Check whether user's role is accessible to ETERNUS and Software."""
|
||||||
ret = True
|
ret = True
|
||||||
@ -3131,3 +3180,30 @@ class FJDXCommon(object):
|
|||||||
'clidata': clidata})
|
'clidata': clidata})
|
||||||
LOG.warning(msg)
|
LOG.warning(msg)
|
||||||
raise exception.VolumeBackendAPIException(data=msg)
|
raise exception.VolumeBackendAPIException(data=msg)
|
||||||
|
|
||||||
|
def _get_copy_sessions_list(self, **param):
|
||||||
|
"""Get copy sessions list."""
|
||||||
|
LOG.debug('_get_copy_sessions_list, Enter method.')
|
||||||
|
|
||||||
|
rc, emsg, clidata = self._exec_eternus_cli(
|
||||||
|
'show_copy_sessions',
|
||||||
|
**param
|
||||||
|
)
|
||||||
|
|
||||||
|
if rc != 0:
|
||||||
|
msg = (_('_get_copy_sessions_list, '
|
||||||
|
'get copy sessions failed. '
|
||||||
|
'Return code: %(rc)lu, '
|
||||||
|
'Error: %(emsg)s, '
|
||||||
|
'Message: %(clidata)s.')
|
||||||
|
% {'rc': rc,
|
||||||
|
'emsg': emsg,
|
||||||
|
'clidata': clidata})
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.VolumeBackendAPIException(data=msg)
|
||||||
|
|
||||||
|
LOG.debug('_get_copy_sessions_list, Exit method, '
|
||||||
|
'copy sessions list: %(clidata)s. ',
|
||||||
|
{'clidata': clidata})
|
||||||
|
|
||||||
|
return clidata
|
||||||
|
@ -87,8 +87,14 @@ class FJDXFCDriver(driver.FibreChannelDriver):
|
|||||||
|
|
||||||
def delete_volume(self, volume):
|
def delete_volume(self, volume):
|
||||||
"""Delete volume on ETERNUS."""
|
"""Delete volume on ETERNUS."""
|
||||||
|
LOG.debug('delete_volume, '
|
||||||
|
'volume id: %s, Enter method.', volume['id'])
|
||||||
|
|
||||||
self.common.delete_volume(volume)
|
self.common.delete_volume(volume)
|
||||||
|
|
||||||
|
LOG.debug('delete_volume, '
|
||||||
|
'volume id: %s, delete succeed.', volume['id'])
|
||||||
|
|
||||||
def create_snapshot(self, snapshot):
|
def create_snapshot(self, snapshot):
|
||||||
"""Creates a snapshot."""
|
"""Creates a snapshot."""
|
||||||
location, metadata = self.common.create_snapshot(snapshot)
|
location, metadata = self.common.create_snapshot(snapshot)
|
||||||
|
@ -94,8 +94,14 @@ class FJDXISCSIDriver(driver.ISCSIDriver):
|
|||||||
|
|
||||||
def delete_volume(self, volume):
|
def delete_volume(self, volume):
|
||||||
"""Delete volume on ETERNUS."""
|
"""Delete volume on ETERNUS."""
|
||||||
|
LOG.debug('delete_volume, '
|
||||||
|
'volume id: %s, Enter method.', volume['id'])
|
||||||
|
|
||||||
self.common.delete_volume(volume)
|
self.common.delete_volume(volume)
|
||||||
|
|
||||||
|
LOG.debug('delete_volume, '
|
||||||
|
'volume id: %s, delete succeed.', volume['id'])
|
||||||
|
|
||||||
def create_snapshot(self, snapshot):
|
def create_snapshot(self, snapshot):
|
||||||
"""Creates a snapshot."""
|
"""Creates a snapshot."""
|
||||||
element_path, metadata = self.common.create_snapshot(snapshot)
|
element_path, metadata = self.common.create_snapshot(snapshot)
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Fujitsu ETERNUS DX driver: Improve volume deletion
|
||||||
|
|
||||||
|
To improve the volume deletion process, add a step to check associated copy
|
||||||
|
sessions. Additionally, it also improves the process of retrieving
|
||||||
|
storage-managed volume numbers.
|
||||||
|
|
||||||
|
There was a problem where the volume could not be deleted because the copy
|
||||||
|
session information acquired by SMI-S IF from ETERNUS DX Storage, which was
|
||||||
|
cached and did not reflect the information that had just been executed.
|
||||||
|
|
||||||
|
This problem has been addressed through improvements in information
|
||||||
|
retrieval.
|
Loading…
x
Reference in New Issue
Block a user