self.assertEqual(('foo', 'bar'),
self.target._get_target_chap_auth(ctxt, test_vol))
+ @mock.patch.object(lio.LioAdm, '_persist_configuration')
@mock.patch.object(utils, 'execute')
@mock.patch.object(lio.LioAdm, '_get_target')
- def test_create_iscsi_target(self, mget_target, mexecute):
+ def test_create_iscsi_target(self, mget_target, mexecute, mpersist_cfg):
mget_target.return_value = 1
- test_vol = 'iqn.2010-10.org.openstack:'\
- 'volume-83c2e877-feed-46be-8435-77884fe55b45'
+ # create_iscsi_target sends volume_name instead of volume_id on error
+ volume_name = 'volume-83c2e877-feed-46be-8435-77884fe55b45'
+ test_vol = 'iqn.2010-10.org.openstack:' + volume_name
self.assertEqual(
1,
self.target.create_iscsi_target(
1,
0,
self.fake_volumes_dir))
+ mpersist_cfg.assert_called_once_with(volume_name)
+ @mock.patch.object(lio.LioAdm, '_persist_configuration')
@mock.patch.object(utils, 'execute')
@mock.patch.object(lio.LioAdm, '_get_target')
- def test_create_iscsi_target_already_exists(self, mget_target, mexecute):
+ def test_create_iscsi_target_already_exists(self, mget_target, mexecute,
+ mpersist_cfg):
mexecute.side_effect = putils.ProcessExecutionError
test_vol = 'iqn.2010-10.org.openstack:'\
0,
self.fake_volumes_dir,
chap_auth)
+ self.assertEqual(0, mpersist_cfg.call_count)
+ @mock.patch.object(lio.LioAdm, '_persist_configuration')
@mock.patch.object(utils, 'execute')
- def test_remove_iscsi_target(self, mexecute):
+ def test_remove_iscsi_target(self, mexecute, mpersist_cfg):
- test_vol = 'iqn.2010-10.org.openstack:'\
- 'volume-83c2e877-feed-46be-8435-77884fe55b45'
+ volume_id = '83c2e877-feed-46be-8435-77884fe55b45'
+ test_vol = 'iqn.2010-10.org.openstack:volume-' + volume_id
# Test the normal case
self.target.remove_iscsi_target(0,
test_vol,
run_as_root=True)
+ mpersist_cfg.assert_called_once_with(volume_id)
+
# Test the failure case: putils.ProcessExecutionError
mexecute.side_effect = putils.ProcessExecutionError
self.assertRaises(exception.ISCSITargetRemoveFailed,
self.testvol['id'],
self.testvol['name'])
+ # Ensure there have been no more calls to persist configuration
+ self.assertEqual(1, mpersist_cfg.call_count)
+
@mock.patch.object(lio.LioAdm, '_get_target_chap_auth')
@mock.patch.object(lio.LioAdm, 'create_iscsi_target')
def test_ensure_export(self, _mock_create, mock_get_chap):
check_exit_code=False,
old_name=None)
+ @mock.patch.object(lio.LioAdm, '_persist_configuration')
@mock.patch.object(utils, 'execute')
@mock.patch.object(lio.LioAdm, '_get_iscsi_properties')
- def test_initialize_connection(self, mock_get_iscsi, mock_execute):
-
+ def test_initialize_connection(self, mock_get_iscsi, mock_execute,
+ mpersist_cfg):
+ volume_id = '83c2e877-feed-46be-8435-77884fe55b45'
+ target_id = 'iqn.2010-10.org.openstack:volume-' + volume_id
connector = {'initiator': 'fake_init'}
# Test the normal case
connector))
mock_execute.assert_called_once_with(
- 'cinder-rtstool', 'add-initiator',
- 'iqn.2010-10.org.openstack:'
- 'volume-83c2e877-feed-46be-8435-77884fe55b45',
+ 'cinder-rtstool', 'add-initiator', target_id,
'c76370d66b', '2FE0CQ8J196R',
connector['initiator'],
run_as_root=True)
+ mpersist_cfg.assert_called_once_with(volume_id)
+
# Test the failure case: putils.ProcessExecutionError
mock_execute.side_effect = putils.ProcessExecutionError
self.assertRaises(exception.ISCSITargetAttachFailed,
self.testvol,
connector)
+ @mock.patch.object(lio.LioAdm, '_persist_configuration')
@mock.patch.object(utils, 'execute')
- def test_terminate_connection(self, _mock_execute):
+ def test_terminate_connection(self, _mock_execute, mpersist_cfg):
+
+ volume_id = '83c2e877-feed-46be-8435-77884fe55b45'
+ target_id = 'iqn.2010-10.org.openstack:volume-' + volume_id
connector = {'initiator': 'fake_init'}
self.target.terminate_connection(self.testvol,
connector)
_mock_execute.assert_called_once_with(
- 'cinder-rtstool', 'delete-initiator',
- 'iqn.2010-10.org.openstack:'
- 'volume-83c2e877-feed-46be-8435-77884fe55b45',
+ 'cinder-rtstool', 'delete-initiator', target_id,
connector['initiator'],
run_as_root=True)
+ mpersist_cfg.assert_called_once_with(volume_id)
+
+ @mock.patch.object(lio.LioAdm, '_persist_configuration')
@mock.patch.object(utils, 'execute')
- def test_terminate_connection_fail(self, _mock_execute):
+ def test_terminate_connection_fail(self, _mock_execute, mpersist_cfg):
_mock_execute.side_effect = putils.ProcessExecutionError
connector = {'initiator': 'fake_init'}
self.target.terminate_connection,
self.testvol,
connector)
+ self.assertEqual(0, mpersist_cfg.call_count)
def test_iscsi_protocol(self):
self.assertEqual(self.target.iscsi_protocol, 'iscsi')
target.delete.assert_called_once_with()
storage_object.delete.assert_called_once_with()
+ @mock.patch.object(cinder_rtstool, 'rtslib', autospec=True)
+ def test_save(self, mock_rtslib):
+ filename = mock.sentinel.filename
+ cinder_rtstool.save_to_file(filename)
+ rtsroot = mock_rtslib.root.RTSRoot
+ rtsroot.assert_called_once_with()
+ rtsroot.return_value.save_to_file.assert_called_once_with(filename)
+
def test_usage(self):
exit = self.assertRaises(SystemExit, cinder_rtstool.usage)
self.assertTrue(usage.called)
self.assertEqual(exit.code, 1)
+ @mock.patch('cinder.cmd.rtstool.save_to_file')
+ def test_main_save(self, mock_save):
+ sys.argv = ['cinder-rtstool',
+ 'save']
+ rc = cinder_rtstool.main()
+ mock_save.assert_called_once_with(None)
+ self.assertEqual(0, rc)
+
+ @mock.patch('cinder.cmd.rtstool.save_to_file')
+ def test_main_save_with_file(self, mock_save):
+ sys.argv = ['cinder-rtstool',
+ 'save',
+ mock.sentinel.filename]
+ rc = cinder_rtstool.main()
+ mock_save.assert_called_once_with(mock.sentinel.filename)
+ self.assertEqual(0, rc)
+
def test_main_create(self):
with mock.patch('cinder.cmd.rtstool.create') as create:
sys.argv = ['cinder-rtstool',
iscsi_target = 0 # NOTE: Not used by lio.
return iscsi_target, lun
+ def _persist_configuration(self, vol_id):
+ try:
+ utils.execute('cinder-rtstool', 'save', run_as_root=True)
+
+ # On persistence failure we don't raise an exception, as target has
+ # been successfully created.
+ except putils.ProcessExecutionError:
+ LOG.warning(_LW("Failed to save iscsi LIO configuration when "
+ "modifying volume id: %(vol_id)s."),
+ {'vol_id': vol_id})
+
def create_iscsi_target(self, name, tid, lun, path,
chap_auth=None, **kwargs):
# tid and lun are not used
"id:%s.") % vol_id)
raise exception.NotFound()
+ # We make changes persistent
+ self._persist_configuration(vol_id)
+
return tid
def remove_iscsi_target(self, tid, lun, vol_id, vol_name, **kwargs):
LOG.error(_LE("%s") % e)
raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
+ # We make changes persistent
+ self._persist_configuration(vol_id)
+
def initialize_connection(self, volume, connector):
volume_iqn = volume['provider_location'].split(' ')[1]
raise exception.ISCSITargetAttachFailed(
volume_id=volume['id'])
+ # We make changes persistent
+ self._persist_configuration(volume['id'])
+
iscsi_properties = self._get_iscsi_properties(volume,
connector.get(
'multipath'))
LOG.error(_LE("Failed to delete initiator iqn %s to target.") %
connector['initiator'])
raise exception.ISCSITargetDetachFailed(volume_id=volume['id'])
+
+ # We make changes persistent
+ self._persist_configuration(volume['id'])