diff --git a/cinder/privsep/targets/iet.py b/cinder/privsep/targets/iet.py deleted file mode 100644 index afbbf41b0f9..00000000000 --- a/cinder/privsep/targets/iet.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2018 Red Hat, Inc -# Copyright 2017 Rackspace Australia -# Copyright 2018 Michael Still and Aptira -# -# 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. - -""" -Helpers for ietadm related routines. -""" - -from oslo_concurrency import processutils - -import cinder.privsep - - -@cinder.privsep.sys_admin_pctxt.entrypoint -def new_target(name, tid): - """Create new scsi target using specified parameters. - - If the target already exists, ietadm returns - 'Invalid argument' and error code '234'. - This should be ignored for ensure export case. - """ - processutils.execute('ietadm', '--op', 'new', - '--tid=%s' % tid, - '--params', 'Name=%s' % name, - check_exit_code=[0, 234]) - - -@cinder.privsep.sys_admin_pctxt.entrypoint -def delete_target(tid): - processutils.execute('ietadm', '--op', 'delete', - '--tid=%s' % tid) - - -@cinder.privsep.sys_admin_pctxt.entrypoint -def force_delete_target(tid, sid, cid): - processutils.execute('ietadm', '--op', 'delete', - '--tid=%s' % tid, - '--sid=%s' % sid, - '--cid=%s' % cid) - - -@cinder.privsep.sys_admin_pctxt.entrypoint -def new_logicalunit(tid, lun, path, iotype): - """Attach a new volume to scsi target as a logical unit. - - If a logical unit exists on the specified target lun, - ietadm returns 'File exists' and error code '239'. - This should be ignored for ensure export case. - """ - - processutils.execute('ietadm', '--op', 'new', - '--tid=%s' % tid, - '--lun=%d' % lun, - '--params', - 'Path=%s,Type=%s' % (path, iotype), - check_exit_code=[0, 239]) - - -@cinder.privsep.sys_admin_pctxt.entrypoint -def delete_logicalunit(tid, lun): - processutils.execute('ietadm', '--op', 'delete', - '--tid=%s' % tid, - '--lun=%d' % lun) - - -@cinder.privsep.sys_admin_pctxt.entrypoint -def new_auth(tid, type, username, password): - processutils.execute('ietadm', '--op', 'new', - '--tid=%s' % tid, - '--user', - '--params=%s=%s,Password=%s' % (type, - username, - password)) diff --git a/cinder/tests/unit/targets/test_iet_driver.py b/cinder/tests/unit/targets/test_iet_driver.py deleted file mode 100644 index 4d265e10bb5..00000000000 --- a/cinder/tests/unit/targets/test_iet_driver.py +++ /dev/null @@ -1,214 +0,0 @@ -# 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 io -from unittest import mock - -from oslo_concurrency import processutils as putils - -from cinder import context -from cinder import exception -from cinder.tests.unit.targets import targets_fixture as tf -from cinder import utils -from cinder.volume.targets import iet - - -class TestIetAdmDriver(tf.TargetDriverFixture): - - def setUp(self): - super(TestIetAdmDriver, self).setUp() - self.target = iet.IetAdm(root_helper=utils.get_root_helper(), - configuration=self.configuration) - - def test_get_target(self): - tmp_file = io.StringIO() - tmp_file.write( - 'tid:1 name:iqn.2010-10.org.openstack:' - 'volume-83c2e877-feed-46be-8435-77884fe55b45\n' - ' sid:844427031282176 initiator:' - 'iqn.1994-05.com.redhat:5a6894679665\n' - ' cid:0 ip:10.9.8.7 state:active hd:none dd:none') - tmp_file.seek(0) - with mock.patch('builtins.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' - )) - - # Test the failure case: Failed to handle the config file - mock_open.side_effect = MemoryError() - self.assertRaises(MemoryError, - self.target._get_target, - '') - - @mock.patch('cinder.volume.targets.iet.IetAdm._get_target', - return_value=0) - @mock.patch('cinder.privsep.targets.iet.new_target') - @mock.patch('cinder.privsep.targets.iet.new_logicalunit') - @mock.patch('os.path.exists', return_value=True) - @mock.patch('cinder.utils.temporary_chown') - @mock.patch.object(iet, 'LOG') - def test_create_iscsi_target(self, mock_log, mock_chown, mock_exists, - mock_new_logical_unit, mock_new_target, - mock_get_targ): - tmp_file = io.StringIO() - with mock.patch('builtins.open') as mock_open: - mock_open.return_value = contextlib.closing(tmp_file) - self.assertEqual( - 0, - self.target.create_iscsi_target( - self.test_vol, - 0, - 0, - self.fake_volumes_dir)) - self.assertTrue(mock_new_target.called) - self.assertTrue(mock_open.called) - self.assertTrue(mock_get_targ.called) - self.assertTrue(mock_new_logical_unit.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, - self.test_vol, - 0, - 0, - self.fake_volumes_dir) - - # Test the failure case: Failed to set new auth - mock_new_target.side_effect = putils.ProcessExecutionError - self.assertRaises(exception.ISCSITargetCreateFailed, - self.target.create_iscsi_target, - self.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 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, - self.test_vol, - 0, - self.fake_volumes_dir, - "foo bar") - - @mock.patch('cinder.volume.targets.iet.IetAdm._get_target', - return_value=1) - @mock.patch('cinder.privsep.targets.iet.new_target') - @mock.patch('cinder.privsep.targets.iet.new_logicalunit') - def test_create_iscsi_target_already_exists( - self, mock_new_logical_unit, mock_new_target, mock_get_targ): - self.assertEqual( - 1, - self.target.create_iscsi_target( - self.test_vol, - 1, - 0, - self.fake_volumes_dir)) - self.assertTrue(mock_get_targ.called) - self.assertTrue(mock_new_target.called) - self.assertTrue(mock_new_logical_unit.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('cinder.privsep.targets.iet.delete_logicalunit') - @mock.patch('cinder.privsep.targets.iet.delete_target') - def test_remove_iscsi_target( - self, mock_delete_target, - mock_delete_logicalunit, mock_exists, mock_find): - - # Test the normal case - self.target.remove_iscsi_target(1, - 0, - self.testvol['id'], - self.testvol['name']) - mock_delete_logicalunit.assert_called_once_with(1, 0) - mock_delete_target.assert_called_once_with(1) - - # Test the failure case: putils.ProcessExecutionError - mock_delete_logicalunit.side_effect = putils.ProcessExecutionError - self.assertRaises(exception.ISCSITargetRemoveFailed, - self.target.remove_iscsi_target, - 1, - 0, - self.testvol['id'], - self.testvol['name']) - - @mock.patch('cinder.privsep.targets.iet.delete_target') - def test_find_sid_cid_for_target(self, mock_delete_target): - tmp_file = io.StringIO() - tmp_file.write( - 'tid:1 name:iqn.2010-10.org.openstack:' - 'volume-83c2e877-feed-46be-8435-77884fe55b45\n' - ' sid:844427031282176 initiator:' - 'iqn.1994-05.com.redhat:5a6894679665\n' - ' cid:0 ip:10.9.8.7 state:active hd:none dd:none') - tmp_file.seek(0) - with mock.patch('builtins.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', - 'volume-83c2e877-feed-46be-8435-77884fe55b45' - )) - - @mock.patch('cinder.volume.targets.iet.IetAdm._get_target', - return_value=1) - @mock.patch('cinder.privsep.targets.iet.new_target') - @mock.patch('cinder.privsep.targets.iet.new_logicalunit') - @mock.patch('cinder.privsep.targets.iet.new_auth') - @mock.patch.object(iet.IetAdm, '_get_target_chap_auth') - def test_create_export( - self, mock_get_chap, mock_new_auth, mock_new_logicalunit, - mock_new_target, mock_get_targ): - 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_new_logicalunit.called) - self.assertTrue(mock_new_target.called) - - @mock.patch('cinder.volume.targets.iet.IetAdm._get_target_chap_auth', - return_value=None) - @mock.patch('cinder.volume.targets.iet.IetAdm._get_target', - return_value=1) - def test_ensure_export(self, mock_get_targetm, mock_get_chap): - 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, - portals_ips=[self.configuration.target_ip_address], - portals_port=int(self.configuration.target_port), - check_exit_code=False, - old_name=None) diff --git a/cinder/volume/targets/iet.py b/cinder/volume/targets/iet.py deleted file mode 100644 index 592ac56df94..00000000000 --- a/cinder/volume/targets/iet.py +++ /dev/null @@ -1,230 +0,0 @@ -# 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 os -import re -import stat - -from oslo_concurrency import processutils as putils -from oslo_log import log as logging -from oslo_log import versionutils - -from cinder import exception -import cinder.privsep.targets.iet -from cinder import utils -from cinder.volume.targets import iscsi - -LOG = logging.getLogger(__name__) - - -class IetAdm(iscsi.ISCSITarget): - VERSION = '0.1' - - def __init__(self, *args, **kwargs): - super(IetAdm, self).__init__(*args, **kwargs) - self.iet_conf = self.configuration.safe_get('iet_conf') - self.iscsi_iotype = self.configuration.safe_get('iscsi_iotype') - self.auth_type = 'IncomingUser' - self.iet_sessions = '/proc/net/iet/session' - versionutils.report_deprecated_feature( - LOG, - 'The IET iSCSI target is deprecated and will be removed in the ' - '"V" release. It is recommended to use the LIO or TGT targets ' - 'instead.') - - def _get_target(self, iqn): - - # Find existing iSCSI target session from /proc/net/iet/session - # - # tid:2 name:iqn.2010-10.org:volume-222 - # sid:562950561399296 initiator:iqn.1994-05.com:5a6894679665 - # cid:0 ip:192.168.122.1 state:active hd:none dd:none - # tid:1 name:iqn.2010-10.org:volume-111 - # sid:281475567911424 initiator:iqn.1994-05.com:5a6894679665 - # cid:0 ip:192.168.122.1 state:active hd:none dd:none - - iscsi_target = 0 - try: - with open(self.iet_sessions, 'r') as f: - sessions = f.read() - except Exception: - LOG.exception("Failed to open iet session list for %s", iqn) - raise - - session_list = re.split('(?m)^tid:', sessions)[1:] - for ses in session_list: - m = re.match(r'(\d+) name:(\S+)\s+', ses) - if m and iqn in m.group(2): - return m.group(1) - - return iscsi_target - - def _get_iscsi_target(self, context, vol_id): - pass - - def _get_target_and_lun(self, context, volume): - - # For ietadm dev starts at lun 0 - lun = 0 - - # Using 0, ietadm tries to search empty tid for creating - # new iSCSI target - iscsi_target = 0 - - # Find existing iSCSI target based on iqn - iqn = '%svolume-%s' % (self.iscsi_target_prefix, volume['id']) - iscsi_target = self._get_target(iqn) - - return iscsi_target, lun - - def create_iscsi_target(self, name, tid, lun, path, - chap_auth=None, **kwargs): - - config_auth = None - vol_id = name.split(':')[1] - - # Check the target is already existing. - tmp_tid = self._get_target(name) - - # Create a new iSCSI target. If a target already exists, - # the command returns 234, but we ignore it. - try: - cinder.privsep.targets.iet.new_target(name, tid) - tid = self._get_target(name) - cinder.privsep.targets.iet.new_logicalunit( - tid, lun, path, self._iotype(path)) - - if chap_auth is not None: - (username, password) = chap_auth - config_auth = ' '.join((self.auth_type,) + chap_auth) - cinder.privsep.targets.iet.new_auth( - tid, self.auth_type, username, password) - except putils.ProcessExecutionError: - LOG.exception("Failed to create iscsi target for volume " - "id:%s", vol_id) - raise exception.ISCSITargetCreateFailed(volume_id=vol_id) - - # Update config file only if new scsi target is created. - if not tmp_tid: - self.update_config_file(name, tid, path, config_auth) - - return tid - - def update_config_file(self, name, tid, path, config_auth): - - conf_file = self.iet_conf - vol_id = name.split(':')[1] - - # If config file does not exist, create a blank conf file and - # add configuration for the volume on the new file. - if not os.path.exists(conf_file): - try: - utils.execute("truncate", conf_file, "--size=0", - run_as_root=True) - except putils.ProcessExecutionError: - LOG.exception("Failed to create %(conf)s for volume " - "id:%(vol_id)s", - {'conf': conf_file, 'vol_id': vol_id}) - raise exception.ISCSITargetCreateFailed(volume_id=vol_id) - - try: - volume_conf = """ - Target %s - %s - Lun 0 Path=%s,Type=%s - """ % (name, config_auth, path, self._iotype(path)) - - with utils.temporary_chown(conf_file): - with open(conf_file, 'a+') as f: - f.write(volume_conf) - except Exception: - LOG.exception("Failed to update %(conf)s for volume " - "id:%(vol_id)s", - {'conf': conf_file, 'vol_id': vol_id}) - raise exception.ISCSITargetCreateFailed(volume_id=vol_id) - - def remove_iscsi_target(self, tid, lun, vol_id, vol_name, **kwargs): - LOG.info("Removing iscsi_target for volume: %s", vol_id) - - try: - cinder.privsep.targets.iet.delete_logicalunit(tid, lun) - session_info = self._find_sid_cid_for_target(tid, vol_name, vol_id) - if session_info: - sid, cid = session_info - cinder.privsep.targets.iet.force_delete_target(tid, sid, cid) - - cinder.privsep.targets.iet.delete_target(tid) - except putils.ProcessExecutionError: - LOG.exception("Failed to remove iscsi target for volume " - "id:%s", vol_id) - raise exception.ISCSITargetRemoveFailed(volume_id=vol_id) - - vol_uuid_file = vol_name - conf_file = self.iet_conf - if os.path.exists(conf_file): - try: - with utils.temporary_chown(conf_file): - with open(conf_file, 'r+') as iet_conf_text: - full_txt = iet_conf_text.readlines() - new_iet_conf_txt = [] - count = 0 - for line in full_txt: - if count > 0: - count -= 1 - continue - elif vol_uuid_file in line: - count = 2 - continue - else: - new_iet_conf_txt.append(line) - - iet_conf_text.seek(0) - iet_conf_text.truncate(0) - iet_conf_text.writelines(new_iet_conf_txt) - except Exception: - LOG.exception("Failed to update %(conf)s for volume id " - "%(vol_id)s after removing iscsi target", - {'conf': conf_file, 'vol_id': vol_id}) - raise exception.ISCSITargetRemoveFailed(volume_id=vol_id) - else: - LOG.warning("Failed to update %(conf)s for volume id " - "%(vol_id)s after removing iscsi target. " - "%(conf)s does not exist.", - {'conf': conf_file, 'vol_id': vol_id}) - - def _find_sid_cid_for_target(self, tid, name, vol_id): - """Find sid, cid for existing iscsi target""" - - try: - with open(self.iet_sessions, 'r') as f: - sessions = f.read() - except Exception as e: - LOG.info("Failed to open iet session list for " - "%(vol_id)s: %(e)s", - {'vol_id': vol_id, 'e': e}) - return None - - session_list = re.split('(?m)^tid:', sessions)[1:] - for ses in session_list: - m = re.match(r'(\d+) name:(\S+)\s+sid:(\d+).+\s+cid:(\d+)', ses) - if m and tid in m.group(1) and name in m.group(2): - return m.group(3), m.group(4) - - def _is_block(self, path): - mode = os.stat(path).st_mode - return stat.S_ISBLK(mode) - - def _iotype(self, path): - if self.iscsi_iotype == 'auto': - return 'blockio' if self._is_block(path) else 'fileio' - else: - return self.iscsi_iotype diff --git a/releasenotes/notes/IET_iSCSI_target-dea5f68dc297510d.yaml b/releasenotes/notes/IET_iSCSI_target-dea5f68dc297510d.yaml new file mode 100644 index 00000000000..444597e409e --- /dev/null +++ b/releasenotes/notes/IET_iSCSI_target-dea5f68dc297510d.yaml @@ -0,0 +1,4 @@ +--- +upgrade: + - | + IET iSCSI target removed. IET iSCSI target was deprecated in the V release.