284 lines
13 KiB
Python
284 lines
13 KiB
Python
# 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 contextlib
|
|
import os
|
|
import shutil
|
|
import StringIO
|
|
import tempfile
|
|
|
|
import mock
|
|
from oslo_concurrency import processutils as putils
|
|
from oslo_utils import timeutils
|
|
|
|
from cinder import context
|
|
from cinder import exception
|
|
from cinder.openstack.common import fileutils
|
|
from cinder import test
|
|
from cinder import utils
|
|
from cinder.volume import configuration as conf
|
|
from cinder.volume.targets import iet
|
|
|
|
|
|
class TestIetAdmDriver(test.TestCase):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(TestIetAdmDriver, self).__init__(*args, **kwargs)
|
|
self.configuration = conf.Configuration(None)
|
|
self.configuration.append_config_values = mock.Mock(return_value=0)
|
|
self.configuration.iscsi_ip_address = '10.9.8.7'
|
|
self.fake_project_id = 'ed2c1fd4-5fc0-11e4-aa15-123b93f75cba'
|
|
self.fake_volume_id = '83c2e877-feed-46be-8435-77884fe55b45'
|
|
self.target = iet.IetAdm(root_helper=utils.get_root_helper(),
|
|
configuration=self.configuration)
|
|
self.testvol =\
|
|
{'project_id': self.fake_project_id,
|
|
'name': 'testvol',
|
|
'size': 1,
|
|
'id': self.fake_volume_id,
|
|
'volume_type_id': None,
|
|
'provider_location': '10.9.8.7:3260 '
|
|
'iqn.2010-10.org.openstack:'
|
|
'volume-%s 0' % self.fake_volume_id,
|
|
'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
|
|
'c76370d66b 2FE0CQ8J196R',
|
|
'provider_geometry': '512 512',
|
|
'created_at': timeutils.utcnow(),
|
|
'host': 'fake_host@lvm#lvm'}
|
|
|
|
self.expected_iscsi_properties = \
|
|
{'auth_method': 'CHAP',
|
|
'auth_password': '2FE0CQ8J196R',
|
|
'auth_username': 'stack-1-a60e2611875f40199931f2c76370d66b',
|
|
'encrypted': False,
|
|
'logical_block_size': '512',
|
|
'physical_block_size': '512',
|
|
'target_discovered': False,
|
|
'target_iqn': 'iqn.2010-10.org.openstack:volume-%s' %
|
|
self.fake_volume_id,
|
|
'target_lun': 0,
|
|
'target_portal': '10.10.7.1:3260',
|
|
'volume_id': self.fake_volume_id}
|
|
|
|
def setUp(self):
|
|
super(TestIetAdmDriver, self).setUp()
|
|
self.fake_volumes_dir = tempfile.mkdtemp()
|
|
fileutils.ensure_tree(self.fake_volumes_dir)
|
|
self.addCleanup(self._cleanup)
|
|
|
|
self.exec_patcher = mock.patch.object(utils, 'execute')
|
|
self.mock_execute = self.exec_patcher.start()
|
|
self.addCleanup(self.exec_patcher.stop)
|
|
|
|
def _cleanup(self):
|
|
if os.path.exists(self.fake_volumes_dir):
|
|
shutil.rmtree(self.fake_volumes_dir)
|
|
|
|
def test_get_target(self):
|
|
tmp_file = StringIO.StringIO()
|
|
tmp_file.write(
|
|
'tid:1 name:iqn.2010-10.org.openstack:volume-83c2e877-feed-46be-8435-77884fe55b45\n' # noqa
|
|
' sid:844427031282176 initiator:iqn.1994-05.com.redhat:5a6894679665\n' # noqa
|
|
' cid:0 ip:10.9.8.7 state:active hd:none dd:none')
|
|
tmp_file.seek(0)
|
|
with mock.patch('__builtin__.open') as mock_open:
|
|
mock_open.return_value = contextlib.closing(tmp_file)
|
|
self.assertEqual('1',
|
|
self.target._get_target(
|
|
'iqn.2010-10.org.openstack:volume-83c2e877-feed-46be-8435-77884fe55b45' # noqa
|
|
))
|
|
|
|
# Test the failure case: Failed to handle the config file
|
|
mock_open.side_effect = StandardError()
|
|
self.assertRaises(StandardError,
|
|
self.target._get_target,
|
|
'')
|
|
|
|
@mock.patch('os.path.exists', return_value=True)
|
|
@mock.patch('cinder.utils.temporary_chown')
|
|
def test_get_target_chap_auth(self, mock_chown, mock_exists):
|
|
tmp_file = StringIO.StringIO()
|
|
tmp_file.write(
|
|
'Target iqn.2010-10.org.openstack:volume-83c2e877-feed-46be-8435-77884fe55b45\n' # noqa
|
|
' IncomingUser otzLy2UYbYfnP4zXLG5z 234Zweo38VGBBvrpK9nt\n'
|
|
' Lun 0 Path=/dev/stack-volumes-lvmdriver-1/volume-83c2e877-feed-46be-8435-77884fe55b45,Type=fileio\n' # noqa
|
|
)
|
|
tmp_file.seek(0)
|
|
test_vol = ('iqn.2010-10.org.openstack:'
|
|
'volume-83c2e877-feed-46be-8435-77884fe55b45')
|
|
expected = ('otzLy2UYbYfnP4zXLG5z', '234Zweo38VGBBvrpK9nt')
|
|
with mock.patch('__builtin__.open') as mock_open:
|
|
ictx = context.get_admin_context()
|
|
mock_open.return_value = contextlib.closing(tmp_file)
|
|
self.assertEqual(expected,
|
|
self.target._get_target_chap_auth(ictx, test_vol))
|
|
self.assertTrue(mock_open.called)
|
|
|
|
# Test the failure case: Failed to handle the config file
|
|
mock_open.side_effect = StandardError()
|
|
self.assertRaises(StandardError,
|
|
self.target._get_target_chap_auth,
|
|
ictx,
|
|
test_vol)
|
|
|
|
@mock.patch('cinder.volume.targets.iet.IetAdm._get_target',
|
|
return_value=0)
|
|
@mock.patch('cinder.utils.execute')
|
|
@mock.patch('os.path.exists', return_value=True)
|
|
@mock.patch('cinder.utils.temporary_chown')
|
|
def test_create_iscsi_target(self, mock_chown, mock_exists,
|
|
mock_execute, mock_get_targ):
|
|
mock_execute.return_value = ('', '')
|
|
tmp_file = StringIO.StringIO()
|
|
test_vol = ('iqn.2010-10.org.openstack:'
|
|
'volume-83c2e877-feed-46be-8435-77884fe55b45')
|
|
with mock.patch('__builtin__.open') as mock_open:
|
|
mock_open.return_value = contextlib.closing(tmp_file)
|
|
self.assertEqual(
|
|
0,
|
|
self.target.create_iscsi_target(
|
|
test_vol,
|
|
0,
|
|
0,
|
|
self.fake_volumes_dir))
|
|
self.assertTrue(mock_execute.called)
|
|
self.assertTrue(mock_open.called)
|
|
self.assertTrue(mock_get_targ.called)
|
|
|
|
# Test the failure case: Failed to chown the config file
|
|
mock_open.side_effect = putils.ProcessExecutionError
|
|
self.assertRaises(exception.ISCSITargetCreateFailed,
|
|
self.target.create_iscsi_target,
|
|
test_vol,
|
|
0,
|
|
0,
|
|
self.fake_volumes_dir)
|
|
|
|
# Test the failure case: Failed to set new auth
|
|
mock_execute.side_effect = putils.ProcessExecutionError
|
|
self.assertRaises(exception.ISCSITargetCreateFailed,
|
|
self.target.create_iscsi_target,
|
|
test_vol,
|
|
0,
|
|
0,
|
|
self.fake_volumes_dir)
|
|
|
|
@mock.patch('cinder.utils.execute')
|
|
@mock.patch('os.path.exists', return_value=True)
|
|
def test_update_config_file_failure(self, mock_exists, mock_execute):
|
|
test_vol = ('iqn.2010-10.org.openstack:'
|
|
'volume-83c2e877-feed-46be-8435-77884fe55b45')
|
|
|
|
# Test the failure case: conf file does not exist
|
|
mock_exists.return_value = False
|
|
mock_execute.side_effect = putils.ProcessExecutionError
|
|
self.assertRaises(exception.ISCSITargetCreateFailed,
|
|
self.target.update_config_file,
|
|
test_vol,
|
|
0,
|
|
self.fake_volumes_dir,
|
|
"foo bar")
|
|
|
|
@mock.patch('cinder.volume.targets.iet.IetAdm._get_target',
|
|
return_value=1)
|
|
@mock.patch('cinder.utils.execute')
|
|
def test_create_iscsi_target_already_exists(self, mock_execute,
|
|
mock_get_targ):
|
|
mock_execute.return_value = ('fake out', 'fake err')
|
|
test_vol = 'iqn.2010-10.org.openstack:'\
|
|
'volume-83c2e877-feed-46be-8435-77884fe55b45'
|
|
self.assertEqual(
|
|
1,
|
|
self.target.create_iscsi_target(
|
|
test_vol,
|
|
1,
|
|
0,
|
|
self.fake_volumes_dir))
|
|
self.assertTrue(mock_get_targ.called)
|
|
self.assertTrue(mock_execute.called)
|
|
|
|
@mock.patch('cinder.volume.targets.iet.IetAdm._find_sid_cid_for_target',
|
|
return_value=None)
|
|
@mock.patch('os.path.exists', return_value=False)
|
|
@mock.patch.object(utils, 'execute')
|
|
def test_remove_iscsi_target(self, mock_execute, mock_exists, mock_find):
|
|
|
|
# Test the normal case
|
|
self.target.remove_iscsi_target(1,
|
|
0,
|
|
self.testvol['id'],
|
|
self.testvol['name'])
|
|
mock_execute.assert_any_calls('ietadm',
|
|
'--op',
|
|
'delete',
|
|
'--tid=1',
|
|
run_as_root=True)
|
|
|
|
# Test the failure case: putils.ProcessExecutionError
|
|
mock_execute.side_effect = putils.ProcessExecutionError
|
|
self.assertRaises(exception.ISCSITargetRemoveFailed,
|
|
self.target.remove_iscsi_target,
|
|
1,
|
|
0,
|
|
self.testvol['id'],
|
|
self.testvol['name'])
|
|
|
|
def test_find_sid_cid_for_target(self):
|
|
tmp_file = StringIO.StringIO()
|
|
tmp_file.write(
|
|
'tid:1 name:iqn.2010-10.org.openstack:volume-83c2e877-feed-46be-8435-77884fe55b45\n' # noqa
|
|
' sid:844427031282176 initiator:iqn.1994-05.com.redhat:5a6894679665\n' # noqa
|
|
' cid:0 ip:10.9.8.7 state:active hd:none dd:none')
|
|
tmp_file.seek(0)
|
|
with mock.patch('__builtin__.open') as mock_open:
|
|
mock_open.return_value = contextlib.closing(tmp_file)
|
|
self.assertEqual(('844427031282176', '0'),
|
|
self.target._find_sid_cid_for_target(
|
|
'1',
|
|
'iqn.2010-10.org.openstack:volume-83c2e877-feed-46be-8435-77884fe55b45', # noqa
|
|
'volume-83c2e877-feed-46be-8435-77884fe55b45' # noqa
|
|
))
|
|
|
|
@mock.patch('cinder.volume.targets.iet.IetAdm._get_target',
|
|
return_value=1)
|
|
@mock.patch('cinder.utils.execute')
|
|
@mock.patch.object(iet.IetAdm, '_get_target_chap_auth')
|
|
def test_create_export(self, mock_get_chap, mock_execute,
|
|
mock_get_targ):
|
|
mock_execute.return_value = ('', '')
|
|
mock_get_chap.return_value = ('QZJbisGmn9AL954FNF4D',
|
|
'P68eE7u9eFqDGexd28DQ')
|
|
expected_result = {'location': '10.9.8.7:3260,1 '
|
|
'iqn.2010-10.org.openstack:testvol 0',
|
|
'auth': 'CHAP '
|
|
'QZJbisGmn9AL954FNF4D P68eE7u9eFqDGexd28DQ'}
|
|
ctxt = context.get_admin_context()
|
|
self.assertEqual(expected_result,
|
|
self.target.create_export(ctxt,
|
|
self.testvol,
|
|
self.fake_volumes_dir))
|
|
self.assertTrue(mock_execute.called)
|
|
|
|
@mock.patch('cinder.volume.targets.iet.IetAdm._get_target',
|
|
return_value=1)
|
|
def test_ensure_export(self, mock_get_target):
|
|
ctxt = context.get_admin_context()
|
|
with mock.patch.object(self.target, 'create_iscsi_target'):
|
|
self.target.ensure_export(ctxt,
|
|
self.testvol,
|
|
self.fake_volumes_dir)
|
|
self.target.create_iscsi_target.assert_called_once_with(
|
|
'iqn.2010-10.org.openstack:testvol',
|
|
1, 0, self.fake_volumes_dir, None,
|
|
check_exit_code=False,
|
|
old_name=None)
|