cinder/cinder/tests/unit/volume/drivers/hitachi/test_hitachi_hnas_backend.py

878 lines
38 KiB
Python

# Copyright (c) 2014 Hitachi Data Systems, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import mock
import os
import paramiko
import time
from oslo_concurrency import processutils as putils
from cinder import exception
from cinder import test
from cinder import utils
from cinder.volume.drivers.hitachi import hnas_backend
evsfs_list = "\n\
FS ID FS Label FS Permanent ID EVS ID EVS Label\n\
----- ----------- ------------------ ------ ---------\n\
1026 gold 0xaadee0e035cfc0b7 1 EVS-Manila\n\
1029 test_hdp 0xaadee09634acfcac 1 EVS-Manila\n\
1030 fs-cinder 0xaadfcf742fba644e 2 EVS-Cinder\n\
1031 cinder2 0xaadfcf7e0769a6bc 3 EVS-Test\n\
1024 fs02-husvm 0xaac8715e2e9406cd 3 EVS-Test\n\
\n"
cluster_getmac = "cluster MAC: 83-68-96-AA-DA-5D"
version = "\n\
Model: HNAS 4040 \n\n\
Software: 11.2.3319.14 (built 2013-09-19 12:34:24+01:00) \n\n\
Hardware: NAS Platform (M2SEKW1339109) \n\n\
board MMB1 \n\
mmb 11.2.3319.14 release (2013-09-19 12:34:24+01:00)\n\n\
board MFB1 \n\
mfb1hw MB v0883 WL v002F TD v002F FD v002F TC v0059 \
RY v0059 TY v0059 IC v0059 WF v00E2 FS v00E2 OS v00E2 \
WD v00E2 DI v001A FC v0002 \n\
Serial no B1339745 (Thu Jan 1 00:00:50 2009) \n\n\
board MCP \n\
Serial no B1339109 (Thu Jan 1 00:00:49 2009) \n\
\n"
evsipaddr = "\n\
EVS Type Label IP Address Mask Port \n\
---------- --------------- ------------------ --------------- ------\n\
admin hnas4040 192.0.2.2 255.255.255.0 eth1 \n\
admin hnas4040 172.24.44.15 255.255.255.0 eth0 \n\
evs 1 EVSTest1 172.24.44.20 255.255.255.0 ag1 \n\
evs 1 EVSTest1 10.0.0.20 255.255.255.0 ag1 \n\
evs 2 EVSTest2 172.24.44.21 255.255.255.0 ag1 \n\
\n"
df_f = "\n\
ID Label EVS Size Used Snapshots Deduped Avail \
Thin ThinSize ThinAvail FS Type\n\
---- ---------- --- ------ ------------ --------- ------- ------------ \
---- -------- --------- --------------------\n\
1025 fs-cinder 2 250 GB 21.4 GB (9%) 0 B (0%) NA 228 GB (91%) \
No 32 KB,WFS-2,128 DSBs\n\
\n"
df_f_tb = "\n\
ID Label EVS Size Used Snapshots Deduped Avail \
Thin ThinSize ThinAvail FS Type\n\
---- ---------- --- ------ ------------ --------- ------- ------------ \
---- -------- --------- --------------------\n\
1025 fs-cinder 2 250 TB 21.4 TB (9%) 0 B (0%) NA 228 TB (91%) \
No 32 KB,WFS-2,128 DSBs\n\
\n"
nfs_export = "\n\
Export name: /export01-husvm \n\
Export path: /export01-husvm \n\
File system label: fs-cinder \n\
File system size: 250 GB \n\
File system free space: 228 GB \n\
File system state: \n\
formatted = Yes \n\
mounted = Yes \n\
failed = No \n\
thin provisioned = No \n\
Access snapshots: Yes \n\
Display snapshots: Yes \n\
Read Caching: Disabled \n\
Disaster recovery setting: \n\
Recovered = No \n\
Transfer setting = Use file system default \n\n\
Export configuration: \n\
127.0.0.1 \n\
\n"
iscsi_one_target = "\n\
Alias : cinder-default \n\
Globally unique name: iqn.2014-12.10.10.10.10:evstest1.cinder-default \n\
Comment : \n\
Secret : pxr6U37LZZJBoMc \n\
Authentication : Enabled \n\
Logical units : No logical units. \n\
\n\
LUN Logical Unit \n\
---- -------------------------------- \n\
0 cinder-lu \n\
1 volume-99da7ae7-1e7f-4d57-8bf... \n\
\n\
Access configuration: \n\
"
df_f_single_evs = "\n\
ID Label Size Used Snapshots Deduped Avail \
Thin ThinSize ThinAvail FS Type\n\
---- ---------- ------ ------------ --------- ------- ------------ \
---- -------- --------- --------------------\n\
1025 fs-cinder 250 GB 21.4 GB (9%) 0 B (0%) NA 228 GB (91%) \
No 32 KB,WFS-2,128 DSBs\n\
\n"
nfs_export_tb = "\n\
Export name: /export01-husvm \n\
Export path: /export01-husvm \n\
File system label: fs-cinder \n\
File system size: 250 TB \n\
File system free space: 228 TB \n\
\n"
nfs_export_not_available = "\n\
Export name: /export01-husvm \n\
Export path: /export01-husvm \n\
File system label: fs-cinder \n\
*** not available *** \n\
\n"
evs_list = "\n\
Node EVS ID Type Label Enabled Status IP Address Port \n\
---- ------ ------- --------------- ------- ------ ------------------- ---- \n\
1 Cluster hnas4040 Yes Online 192.0.2.200 eth1 \n\
1 0 Admin hnas4040 Yes Online 192.0.2.2 eth1 \n\
172.24.44.15 eth0 \n\
172.24.49.101 ag2 \n\
1 1 Service EVS-Manila Yes Online 172.24.49.32 ag2 \n\
172.24.48.32 ag4 \n\
1 2 Service EVS-Cinder Yes Online 172.24.49.21 ag2 \n\
1 3 Service EVS-Test Yes Online 192.168.100.100 ag2 \n\
\n"
iscsilu_list = "Name : cinder-lu \n\
Comment: \n\
Path : /.cinder/cinder-lu.iscsi \n\
Size : 2 GB \n\
File System : fs-cinder \n\
File System Mounted : YES \n\
Logical Unit Mounted: No"
iscsilu_list_tb = "Name : test-lu \n\
Comment: \n\
Path : /.cinder/test-lu.iscsi \n\
Size : 2 TB \n\
File System : fs-cinder \n\
File System Mounted : YES \n\
Logical Unit Mounted: No"
hnas_fs_list = "%(l1)s\n\n%(l2)s\n\n " % {'l1': iscsilu_list,
'l2': iscsilu_list_tb}
add_targetsecret = "Target created successfully."
iscsi_target_list = "\n\
Alias : cinder-GoldIsh\n\
Globally unique name: iqn.2015-06.10.10.10.10:evstest1.cinder-goldish\n\
Comment :\n\
Secret : None\n\
Authentication : Enabled\n\
Logical units : No logical units.\n\
Access configuration :\n\
\n\
Alias : cinder-default\n\
Globally unique name: iqn.2014-12.10.10.10.10:evstest1.cinder-default\n\
Comment :\n\
Secret : pxr6U37LZZJBoMc\n\
Authentication : Enabled\n\
Logical units : Logical units :\n\
\n\
LUN Logical Unit\n\
---- --------------------------------\n\
0 cinder-lu\n\
1 volume-99da7ae7-1e7f-4d57-8bf...\n\
\n\
Access configuration :\n\
"
backend_opts = {'mgmt_ip0': '0.0.0.0',
'cluster_admin_ip0': None,
'ssh_port': '22',
'username': 'supervisor',
'password': 'supervisor',
'ssh_private_key': 'test_key'}
target_chap_disable = "\n\
Alias : cinder-default \n\
Globally unique name: iqn.2014-12.10.10.10.10:evstest1.cinder-default \n\
Comment : \n\
Secret : \n\
Authentication : Disabled \n\
Logical units : No logical units. \n\
\n\
LUN Logical Unit \n\
---- -------------------------------- \n\
0 cinder-lu \n\
1 volume-99da7ae7-1e7f-4d57-8bf... \n\
\n\
Access configuration: \n\
"
file_clone_stat = "Clone: /nfs_cinder/cinder-lu \n\
SnapshotFile: FileHandle[00000000004010000d20116826ffffffffffffff] \n\
\n\
SnapshotFile: FileHandle[00000000004029000d81f26826ffffffffffffff] \n\
"
file_clone_stat_snap_file1 = "\
FileHandle[00000000004010000d20116826ffffffffffffff] \n\n\
References: \n\
Clone: /nfs_cinder/cinder-lu \n\
Clone: /nfs_cinder/snapshot-lu-1 \n\
Clone: /nfs_cinder/snapshot-lu-2 \n\
"
file_clone_stat_snap_file2 = "\
FileHandle[00000000004010000d20116826ffffffffffffff] \n\n\
References: \n\
Clone: /nfs_cinder/volume-not-used \n\
Clone: /nfs_cinder/snapshot-1 \n\
Clone: /nfs_cinder/snapshot-2 \n\
"
not_a_clone = "\
file-clone-stat: failed to get predecessor snapshot-files: File is not a clone"
class HDSHNASBackendTest(test.TestCase):
def __init__(self, *args, **kwargs):
super(HDSHNASBackendTest, self).__init__(*args, **kwargs)
def setUp(self):
super(HDSHNASBackendTest, self).setUp()
self.hnas_backend = hnas_backend.HNASSSHBackend(backend_opts)
def test_run_cmd(self):
self.mock_object(os.path, 'isfile',
mock.Mock(return_value=True))
self.mock_object(utils, 'execute')
self.mock_object(time, 'sleep')
self.mock_object(paramiko, 'SSHClient')
self.mock_object(paramiko.RSAKey, 'from_private_key_file')
self.mock_object(putils, 'ssh_execute',
mock.Mock(return_value=(df_f, '')))
out, err = self.hnas_backend._run_cmd('ssh', '0.0.0.0',
'supervisor', 'supervisor',
'df', '-a')
self.assertIn('fs-cinder', out)
self.assertIn('WFS-2,128 DSBs', out)
def test_run_cmd_retry_exception(self):
self.hnas_backend.cluster_admin_ip0 = '172.24.44.11'
exceptions = [putils.ProcessExecutionError(stderr='Connection reset'),
putils.ProcessExecutionError(stderr='Failed to establish'
' SSC connection'),
putils.ProcessExecutionError(stderr='Connection reset'),
putils.ProcessExecutionError(stderr='Connection reset'),
putils.ProcessExecutionError(stderr='Connection reset')]
self.mock_object(os.path, 'isfile',
mock.Mock(return_value=True))
self.mock_object(utils, 'execute')
self.mock_object(time, 'sleep')
self.mock_object(paramiko, 'SSHClient')
self.mock_object(paramiko.RSAKey, 'from_private_key_file')
self.mock_object(putils, 'ssh_execute',
mock.Mock(side_effect=exceptions))
self.assertRaises(exception.HNASConnError, self.hnas_backend._run_cmd,
'ssh', '0.0.0.0', 'supervisor', 'supervisor', 'df',
'-a')
def test_run_cmd_exception_without_retry(self):
self.mock_object(os.path, 'isfile',
mock.Mock(return_value=True))
self.mock_object(utils, 'execute')
self.mock_object(time, 'sleep')
self.mock_object(paramiko, 'SSHClient')
self.mock_object(paramiko.RSAKey, 'from_private_key_file')
self.mock_object(putils, 'ssh_execute',
mock.Mock(side_effect=putils.ProcessExecutionError
(stderr='Error')))
self.assertRaises(putils.ProcessExecutionError,
self.hnas_backend._run_cmd, 'ssh', '0.0.0.0',
'supervisor', 'supervisor', 'df', '-a')
def test_get_targets_empty_list(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=('No targets', '')))
out = self.hnas_backend._get_targets('2')
self.assertEqual([], out)
def test_get_targets_not_found(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(iscsi_target_list, '')))
out = self.hnas_backend._get_targets('2', 'fake-volume')
self.assertEqual([], out)
def test__get_unused_luid_number_0(self):
tgt_info = {
'alias': 'cinder-default',
'secret': 'pxr6U37LZZJBoMc',
'iqn': 'iqn.2014-12.10.10.10.10:evstest1.cinder-default',
'lus': [
{'id': '1',
'name': 'cinder-lu2'},
{'id': '2',
'name': 'volume-test2'}
],
'auth': 'Enabled'
}
out = self.hnas_backend._get_unused_luid(tgt_info)
self.assertEqual(0, out)
def test__get_unused_no_luns(self):
tgt_info = {
'alias': 'cinder-default',
'secret': 'pxr6U37LZZJBoMc',
'iqn': 'iqn.2014-12.10.10.10.10:evstest1.cinder-default',
'lus': [],
'auth': 'Enabled'
}
out = self.hnas_backend._get_unused_luid(tgt_info)
self.assertEqual(0, out)
def test_get_version(self):
expected_out = {
'hardware': 'NAS Platform (M2SEKW1339109)',
'mac': '83-68-96-AA-DA-5D',
'version': '11.2.3319.14',
'model': 'HNAS 4040',
'serial': 'B1339745'
}
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[
(cluster_getmac, ''),
(version, '')]))
out = self.hnas_backend.get_version()
self.assertEqual(expected_out, out)
def test_get_evs(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(evsfs_list, '')))
out = self.hnas_backend.get_evs('fs-cinder')
self.assertEqual('2', out)
def test_get_export_list(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(nfs_export, ''),
(evsfs_list, ''),
(evs_list, '')]))
out = self.hnas_backend.get_export_list()
self.assertEqual('fs-cinder', out[0]['fs'])
self.assertEqual(250.0, out[0]['size'])
self.assertEqual(228.0, out[0]['free'])
self.assertEqual('/export01-husvm', out[0]['path'])
def test_get_export_list_data_not_available(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(nfs_export_not_available, ''),
(evsfs_list, ''),
(evs_list, '')]))
out = self.hnas_backend.get_export_list()
self.assertEqual('fs-cinder', out[0]['fs'])
self.assertEqual('/export01-husvm', out[0]['path'])
self.assertEqual(-1, out[0]['size'])
self.assertEqual(-1, out[0]['free'])
def test_get_export_list_tb(self):
size = float(250 * 1024)
free = float(228 * 1024)
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(nfs_export_tb, ''),
(evsfs_list, ''),
(evs_list, '')]))
out = self.hnas_backend.get_export_list()
self.assertEqual('fs-cinder', out[0]['fs'])
self.assertEqual(size, out[0]['size'])
self.assertEqual(free, out[0]['free'])
self.assertEqual('/export01-husvm', out[0]['path'])
def test_file_clone(self):
path1 = '/.cinder/path1'
path2 = '/.cinder/path2'
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(evsfs_list, '')))
self.hnas_backend.file_clone('fs-cinder', path1, path2)
calls = [mock.call('evsfs', 'list'), mock.call('console-context',
'--evs', '2',
'file-clone-create',
'-f', 'fs-cinder',
path1, path2)]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_file_clone_wrong_fs(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(evsfs_list, '')))
self.assertRaises(exception.InvalidParameterValue,
self.hnas_backend.file_clone, 'fs-fake', 'src',
'dst')
def test_get_evs_info(self):
expected_out = {'evs_number': '1'}
expected_out2 = {'evs_number': '2'}
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(evsipaddr, '')))
out = self.hnas_backend.get_evs_info()
self.hnas_backend._run_cmd.assert_called_with('evsipaddr', '-l')
self.assertEqual(expected_out, out['10.0.0.20'])
self.assertEqual(expected_out, out['172.24.44.20'])
self.assertEqual(expected_out2, out['172.24.44.21'])
def test_get_fs_info(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(df_f, ''),
(evsfs_list, ''),
(hnas_fs_list, '')]))
out = self.hnas_backend.get_fs_info('fs-cinder')
self.assertEqual('2', out['evs_id'])
self.assertEqual('fs-cinder', out['label'])
self.assertEqual('228', out['available_size'])
self.assertEqual('250', out['total_size'])
self.assertEqual(2050.0, out['provisioned_capacity'])
def test_get_fs_empty_return(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=('Not mounted', '')))
out = self.hnas_backend.get_fs_info('fs-cinder')
self.assertEqual({}, out)
def test_get_fs_info_single_evs(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(df_f_single_evs, ''),
(evsfs_list, ''),
(hnas_fs_list, '')]))
out = self.hnas_backend.get_fs_info('fs-cinder')
self.assertEqual('fs-cinder', out['label'])
self.assertEqual('228', out['available_size'])
self.assertEqual('250', out['total_size'])
self.assertEqual(2050.0, out['provisioned_capacity'])
def test_get_fs_tb(self):
available_size = float(228 * 1024 ** 2)
total_size = float(250 * 1024 ** 2)
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(df_f_tb, ''),
(evsfs_list, ''),
(hnas_fs_list, '')]))
out = self.hnas_backend.get_fs_info('fs-cinder')
self.assertEqual('fs-cinder', out['label'])
self.assertEqual(str(available_size), out['available_size'])
self.assertEqual(str(total_size), out['total_size'])
self.assertEqual(2050.0, out['provisioned_capacity'])
def test_get_fs_single_evs_tb(self):
available_size = float(228 * 1024 ** 2)
total_size = float(250 * 1024 ** 2)
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(df_f_tb, ''),
(evsfs_list, ''),
(hnas_fs_list, '')]))
out = self.hnas_backend.get_fs_info('fs-cinder')
self.assertEqual('fs-cinder', out['label'])
self.assertEqual(str(available_size), out['available_size'])
self.assertEqual(str(total_size), out['total_size'])
self.assertEqual(2050.0, out['provisioned_capacity'])
def test_create_lu(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(evsfs_list, '')))
self.hnas_backend.create_lu('fs-cinder', '128', 'cinder-lu')
calls = [mock.call('evsfs', 'list'), mock.call('console-context',
'--evs', '2',
'iscsi-lu', 'add',
'-e', 'cinder-lu',
'fs-cinder',
'/.cinder/cinder-lu.'
'iscsi', '128G')]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_delete_lu(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(evsfs_list, '')))
self.hnas_backend.delete_lu('fs-cinder', 'cinder-lu')
calls = [mock.call('evsfs', 'list'), mock.call('console-context',
'--evs', '2',
'iscsi-lu', 'del', '-d',
'-f', 'cinder-lu')]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_extend_lu(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(evsfs_list, '')))
self.hnas_backend.extend_lu('fs-cinder', '128', 'cinder-lu')
calls = [mock.call('evsfs', 'list'), mock.call('console-context',
'--evs', '2',
'iscsi-lu', 'expand',
'cinder-lu', '128G')]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_cloned_lu(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(evsfs_list, '')))
self.hnas_backend.create_cloned_lu('cinder-lu', 'fs-cinder', 'snap')
calls = [mock.call('evsfs', 'list'), mock.call('console-context',
'--evs', '2',
'iscsi-lu', 'clone',
'-e', 'cinder-lu',
'snap',
'/.cinder/snap.iscsi')]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_get_existing_lu_info(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(iscsilu_list, '')]))
out = self.hnas_backend.get_existing_lu_info('cinder-lu', None, None)
self.assertEqual('cinder-lu', out['name'])
self.assertEqual('fs-cinder', out['filesystem'])
self.assertEqual(2.0, out['size'])
def test_get_existing_lu_info_tb(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(iscsilu_list_tb, '')]))
out = self.hnas_backend.get_existing_lu_info('test-lu', None, None)
self.assertEqual('test-lu', out['name'])
self.assertEqual('fs-cinder', out['filesystem'])
self.assertEqual(2048.0, out['size'])
def test_rename_existing_lu(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(evsfs_list, '')))
self.hnas_backend.rename_existing_lu('fs-cinder', 'cinder-lu',
'new-lu-name')
calls = [mock.call('evsfs', 'list'), mock.call('console-context',
'--evs', '2',
'iscsi-lu', 'mod', '-n',
"'new-lu-name'",
'cinder-lu')]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_check_lu(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(iscsi_target_list, '')]))
out = self.hnas_backend.check_lu('cinder-lu', 'fs-cinder')
self.assertEqual('cinder-lu', out['tgt']['lus'][0]['name'])
self.assertEqual('pxr6U37LZZJBoMc', out['tgt']['secret'])
self.assertTrue(out['mapped'])
calls = [mock.call('evsfs', 'list'), mock.call('console-context',
'--evs', '2',
'iscsi-target', 'list')]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_check_lu_not_found(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(iscsi_target_list, '')]))
# passing a volume fake-volume not mapped
out = self.hnas_backend.check_lu('fake-volume', 'fs-cinder')
self.assertFalse(out['mapped'])
self.assertEqual(0, out['id'])
self.assertIsNone(out['tgt'])
def test_add_iscsi_conn(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(iscsi_target_list, ''),
(evsfs_list, '')]))
out = self.hnas_backend.add_iscsi_conn('cinder-lu', 'fs-cinder', 3260,
'cinder-default', 'initiator')
self.assertEqual('cinder-lu', out['lu_name'])
self.assertEqual('fs-cinder', out['fs'])
self.assertEqual('0', out['lu_id'])
self.assertEqual(3260, out['port'])
calls = [mock.call('evsfs', 'list'),
mock.call('console-context', '--evs', '2', 'iscsi-target',
'list')]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_add_iscsi_conn_not_mapped_volume(self):
not_mapped = {'mapped': False,
'id': 0,
'tgt': None}
self.mock_object(self.hnas_backend, 'check_lu',
mock.Mock(return_value=not_mapped))
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(iscsi_target_list, ''),
('', '')]))
out = self.hnas_backend.add_iscsi_conn('cinder-lu', 'fs-cinder', 3260,
'cinder-default', 'initiator')
self.assertEqual('cinder-lu', out['lu_name'])
self.assertEqual('fs-cinder', out['fs'])
self.assertEqual(2, out['lu_id'])
self.assertEqual(3260, out['port'])
calls = [mock.call('evsfs', 'list'),
mock.call('console-context', '--evs', '2', 'iscsi-target',
'list')]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_del_iscsi_conn(self):
iqn = 'iqn.2014-12.10.10.10.10:evstest1.cinder-default'
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(iscsi_one_target, '')))
self.hnas_backend.del_iscsi_conn('2', iqn, '0')
calls = [mock.call('console-context', '--evs', '2', 'iscsi-target',
'list', iqn),
mock.call('console-context', '--evs', '2', 'iscsi-target',
'dellu', '-f', iqn, '0')]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_del_iscsi_conn_volume_not_found(self):
iqn = 'iqn.2014-12.10.10.10.10:evstest1.cinder-fake'
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(iscsi_one_target, '')))
self.hnas_backend.del_iscsi_conn('2', iqn, '10')
self.hnas_backend._run_cmd.assert_called_with('console-context',
'--evs', '2',
'iscsi-target', 'list',
iqn)
def test_check_target(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(iscsi_target_list, '')]))
out = self.hnas_backend.check_target('fs-cinder', 'cinder-default')
self.assertTrue(out['found'])
self.assertEqual('cinder-lu', out['tgt']['lus'][0]['name'])
self.assertEqual('cinder-default', out['tgt']['alias'])
self.assertEqual('pxr6U37LZZJBoMc', out['tgt']['secret'])
def test_check_target_not_found(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(iscsi_target_list, '')]))
out = self.hnas_backend.check_target('fs-cinder', 'cinder-fake')
self.assertFalse(out['found'])
self.assertIsNone(out['tgt'])
def test_set_target_secret(self):
targetalias = 'cinder-default'
secret = 'pxr6U37LZZJBoMc'
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(evsfs_list, '')))
self.hnas_backend.set_target_secret(targetalias, 'fs-cinder', secret)
calls = [mock.call('evsfs', 'list'),
mock.call('console-context', '--evs', '2', 'iscsi-target',
'mod', '-s', 'pxr6U37LZZJBoMc', '-a', 'enable',
'cinder-default')]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_set_target_secret_empty_target_list(self):
targetalias = 'cinder-default'
secret = 'pxr6U37LZZJBoMc'
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
('does not exist', ''),
('', '')]))
self.hnas_backend.set_target_secret(targetalias, 'fs-cinder', secret)
calls = [mock.call('console-context', '--evs', '2', 'iscsi-target',
'mod', '-s', 'pxr6U37LZZJBoMc', '-a', 'enable',
'cinder-default')]
self.hnas_backend._run_cmd.assert_has_calls(calls, any_order=False)
def test_get_target_secret(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(iscsi_one_target, '')]))
out = self.hnas_backend.get_target_secret('cinder-default',
'fs-cinder')
self.assertEqual('pxr6U37LZZJBoMc', out)
self.hnas_backend._run_cmd.assert_called_with('console-context',
'--evs', '2',
'iscsi-target', 'list',
'cinder-default')
def test_get_target_secret_chap_disabled(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(target_chap_disable, '')]))
out = self.hnas_backend.get_target_secret('cinder-default',
'fs-cinder')
self.assertEqual('', out)
self.hnas_backend._run_cmd.assert_called_with('console-context',
'--evs', '2',
'iscsi-target', 'list',
'cinder-default')
def test_get_target_iqn(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(iscsi_one_target, ''),
(add_targetsecret, '')]))
out = self.hnas_backend.get_target_iqn('cinder-default', 'fs-cinder')
self.assertEqual('iqn.2014-12.10.10.10.10:evstest1.cinder-default',
out)
def test_create_target(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(return_value=(evsfs_list, '')))
self.hnas_backend.create_target('cinder-default', 'fs-cinder',
'pxr6U37LZZJBoMc')
def test_check_snapshot_parent_true(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(
side_effect=[(evsfs_list, ''),
(file_clone_stat, ''),
(file_clone_stat_snap_file1, ''),
(file_clone_stat_snap_file2, '')]))
out = self.hnas_backend.check_snapshot_parent('cinder-lu',
'snapshot-lu-1',
'fs-cinder')
self.assertTrue(out)
self.hnas_backend._run_cmd.assert_called_with('console-context',
'--evs', '2',
'file-clone-stat'
'-snapshot-file', '-f',
'fs-cinder',
'00000000004010000d2011'
'6826ffffffffffffff]')
def test_check_snapshot_parent_false(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(
side_effect=[(evsfs_list, ''),
(file_clone_stat, ''),
(file_clone_stat_snap_file1, ''),
(file_clone_stat_snap_file2, '')]))
out = self.hnas_backend.check_snapshot_parent('cinder-lu',
'snapshot-lu-3',
'fs-cinder')
self.assertFalse(out)
self.hnas_backend._run_cmd.assert_called_with('console-context',
'--evs', '2',
'file-clone-stat'
'-snapshot-file', '-f',
'fs-cinder',
'00000000004029000d81f26'
'826ffffffffffffff]')
def test_check_a_not_cloned_file(self):
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(
side_effect=[(evsfs_list, ''),
(not_a_clone, '')]))
self.assertRaises(exception.ManageExistingInvalidReference,
self.hnas_backend.check_snapshot_parent,
'cinder-lu', 'snapshot-name', 'fs-cinder')
def test_get_export_path(self):
export_out = '/export01-husvm'
self.mock_object(self.hnas_backend, '_run_cmd',
mock.Mock(side_effect=[(evsfs_list, ''),
(nfs_export, '')]))
out = self.hnas_backend.get_export_path(export_out, 'fs-cinder')
self.assertEqual(export_out, out)
self.hnas_backend._run_cmd.assert_called_with('console-context',
'--evs', '2',
'nfs-export', 'list',
export_out)