diff --git a/cinder/tests/unit/targets/test_tgt_driver.py b/cinder/tests/unit/targets/test_tgt_driver.py index e9455af85c8..efcbe089df9 100644 --- a/cinder/tests/unit/targets/test_tgt_driver.py +++ b/cinder/tests/unit/targets/test_tgt_driver.py @@ -28,6 +28,8 @@ class TestTgtAdmDriver(tf.TargetDriverFixture): def setUp(self): super(TestTgtAdmDriver, self).setUp() + self.configuration.get = mock.Mock(side_effect=self.fake_get) + self.target = tgt.TgtAdm(root_helper=utils.get_root_helper(), configuration=self.configuration) self.testvol_path = \ @@ -74,6 +76,10 @@ class TestTgtAdmDriver(tf.TargetDriverFixture): ' ALL"\n' % {'test_vol': self.test_vol, 'bspath': self.testvol_path}) + def fake_get(self, value, default): + if value in ('iscsi_target_flags', 'iscsi_write_cache'): + return getattr(self, value, default) + def test_iscsi_protocol(self): self.assertEqual(self.target.iscsi_protocol, 'iscsi') @@ -183,6 +189,42 @@ class TestTgtAdmDriver(tf.TargetDriverFixture): 0, self.fake_volumes_dir)) + def test_create_iscsi_target_content(self): + + self.iscsi_target_flags = 'foo' + self.iscsi_write_cache = 'bar' + + mock_open = mock.mock_open() + with mock.patch('cinder.utils.execute', return_value=('', '')),\ + mock.patch.object(self.target, '_get_target', + side_effect=lambda x: 1),\ + mock.patch.object(self.target, '_verify_backing_lun', + side_effect=lambda x, y: True),\ + mock.patch('cinder.volume.targets.tgt.open', + mock_open, create=True): + self.assertEqual( + 1, + self.target.create_iscsi_target( + self.test_vol, + 1, + 0, + self.testvol_path, + chap_auth=('chap_foo', 'chap_bar'))) + + mock_open.assert_called_once_with( + os.path.join(self.fake_volumes_dir, self.test_vol.split(':')[1]), + 'w+') + expected = ('\n\n' + ' backing-store %(bspath)s\n' + ' driver iscsi\n' + ' incominguser chap_foo chap_bar\n' + ' bsoflags foo\n' + ' write-cache bar\n' + '\n' % {'id': self.VOLUME_ID, + 'bspath': self.testvol_path}) + self.assertEqual(expected, + mock_open.return_value.write.call_args[0][0]) + def test_create_iscsi_target_already_exists(self): def _fake_execute(*args, **kwargs): if 'update' in args: diff --git a/cinder/volume/driver.py b/cinder/volume/driver.py index 97044969564..84ae879e6eb 100644 --- a/cinder/volume/driver.py +++ b/cinder/volume/driver.py @@ -143,6 +143,12 @@ volume_opts = [ 'perform write-back(on) or write-through(off). ' 'This parameter is valid if iscsi_helper is set ' 'to tgtadm or iseradm.'), + cfg.StrOpt('iscsi_target_flags', + default='', + help='Sets the target-specific flags for the iSCSI target. ' + 'Only used for tgtadm to specify backing device flags ' + 'using bsoflags option. The specified string is passed ' + 'as is to the underlying tool.'), cfg.StrOpt('iscsi_protocol', default='iscsi', choices=['iscsi', 'iser'], diff --git a/cinder/volume/targets/tgt.py b/cinder/volume/targets/tgt.py index 2b29536d922..89be331b9ca 100644 --- a/cinder/volume/targets/tgt.py +++ b/cinder/volume/targets/tgt.py @@ -12,6 +12,7 @@ import os import re +import textwrap import time from oslo_concurrency import processutils as putils @@ -35,21 +36,15 @@ class TgtAdm(iscsi.ISCSITarget): etc. """ - VOLUME_CONF = """ - - backing-store %s - driver %s - write-cache %s + VOLUME_CONF = textwrap.dedent(""" + + backing-store %(path)s + driver %(driver)s + %(chap_auth)s + %(target_flags)s + write-cache %(write_cache)s - """ - VOLUME_CONF_WITH_CHAP_AUTH = """ - - backing-store %s - driver %s - %s - write-cache %s - - """ + """) def __init__(self, *args, **kwargs): super(TgtAdm, self).__init__(*args, **kwargs) @@ -178,14 +173,20 @@ class TgtAdm(iscsi.ISCSITarget): vol_id = name.split(':')[1] write_cache = self.configuration.get('iscsi_write_cache', 'on') driver = self.iscsi_protocol + chap_str = '' - if chap_auth is None: - volume_conf = self.VOLUME_CONF % (name, path, driver, write_cache) - else: + if chap_auth is not None: chap_str = 'incominguser %s %s' % chap_auth - volume_conf = self.VOLUME_CONF_WITH_CHAP_AUTH % (name, path, - driver, chap_str, - write_cache) + + target_flags = self.configuration.get('iscsi_target_flags', '') + if target_flags: + target_flags = 'bsoflags ' + target_flags + + volume_conf = self.VOLUME_CONF % { + 'name': name, 'path': path, 'driver': driver, + 'chap_auth': chap_str, 'target_flags': target_flags, + 'write_cache': write_cache} + LOG.debug('Creating iscsi_target for Volume ID: %s', vol_id) volumes_dir = self.volumes_dir volume_path = os.path.join(volumes_dir, vol_id)