summaryrefslogtreecommitdiff
path: root/nova/tests/unit/test_utils.py
diff options
context:
space:
mode:
authorDavanum Srinivas <davanum@gmail.com>2015-05-06 15:35:02 -0400
committerDavanum Srinivas <davanum@gmail.com>2015-08-21 10:34:30 -0400
commit9cd9e66d0ab828840ca0989b7a8fd48fde2c3de7 (patch)
tree80bb3223896001c58d534c6b1546b49f3962f999 /nova/tests/unit/test_utils.py
parente049553c7312480080091ad2481dcaf49113d571 (diff)
downloadnova-9cd9e66d0ab828840ca0989b7a8fd48fde2c3de7.tar.gz
Add rootwrap daemon mode support
Add a configuration option 'use_rootwrap_daemon' to switch on the rootwrap daemon mode support. This option is switched off by default to keep the current behavior as is. The code honors the various options available in processutils.execute() like 'attempts', 'delay_on_retry' etc to ensure that we don't regress any current behavior. DocImpact Part of blueprint nova-rootwrap-daemon-mode Depends-On: I80c7b9dd8e9e0f940aa4e54a95b241dfc40d3574 Change-Id: I57dc2efa39b86fa1fa20730ad70d056e87617c96
Diffstat (limited to 'nova/tests/unit/test_utils.py')
-rw-r--r--nova/tests/unit/test_utils.py182
1 files changed, 181 insertions, 1 deletions
diff --git a/nova/tests/unit/test_utils.py b/nova/tests/unit/test_utils.py
index e86d7acf36..f4482b19a2 100644
--- a/nova/tests/unit/test_utils.py
+++ b/nova/tests/unit/test_utils.py
@@ -16,6 +16,7 @@ import datetime
import functools
import hashlib
import importlib
+import logging
import os
import os.path
import socket
@@ -34,7 +35,6 @@ from oslo_utils import timeutils
from oslo_utils import units
import six
-
import nova
from nova import context
from nova import exception
@@ -192,6 +192,21 @@ class GenericUtilsTestCase(test.NoDBTestCase):
cmd = utils.get_root_helper()
self.assertEqual('sudo nova-rootwrap foo', cmd)
+ @mock.patch('nova.utils.RootwrapProcessHelper')
+ def test_get_root_helper_proc(self, mock_proc_helper):
+ self.flags(use_rootwrap_daemon=False)
+ self.flags(rootwrap_config="/path/to/conf")
+ utils._get_rootwrap_helper()
+ mock_proc_helper.assert_called_once_with()
+
+ @mock.patch('nova.utils.RootwrapDaemonHelper')
+ def test_get_root_helper_daemon(self, mock_daemon_helper):
+ conf_path = '/path/to/conf'
+ self.flags(use_rootwrap_daemon=True)
+ self.flags(rootwrap_config=conf_path)
+ utils._get_rootwrap_helper()
+ mock_daemon_helper.assert_called_once_with(conf_path)
+
def test_use_sudo(self):
self.flags(disable_rootwrap=True, group='workarounds')
cmd = utils.get_root_helper()
@@ -248,6 +263,171 @@ class TestCachedFile(test.NoDBTestCase):
self.assertNotIn(filename, utils._FILE_CACHE)
+class RootwrapDaemonTesetCase(test.TestCase):
+ @mock.patch('oslo_rootwrap.client.Client')
+ def test_get_client(self, mock_client):
+ mock_conf = mock.MagicMock()
+ utils.RootwrapDaemonHelper(mock_conf)
+ mock_client.assert_called_once_with(
+ ["sudo", "nova-rootwrap-daemon", mock_conf])
+
+ @mock.patch('nova.utils.LOG.info')
+ def test_execute(self, mock_info):
+ mock_conf = mock.MagicMock()
+ daemon = utils.RootwrapDaemonHelper(mock_conf)
+ daemon.client = mock.MagicMock()
+ daemon.client.execute = mock.Mock(return_value=(0, None, None))
+
+ daemon.execute('a', 1, foo='bar', run_as_root=True)
+ daemon.client.execute.assert_called_once_with(['a', '1'], None)
+ mock_info.assert_has_calls([mock.call(
+ u'Executing RootwrapDaemonHelper.execute cmd=[%(cmd)r] '
+ u'kwargs=[%(kwargs)r]',
+ {'cmd': u'a 1', 'kwargs': {'run_as_root': True, 'foo': 'bar'}})])
+
+ def test_execute_with_kwargs(self):
+ mock_conf = mock.MagicMock()
+ daemon = utils.RootwrapDaemonHelper(mock_conf)
+ daemon.client = mock.MagicMock()
+ daemon.client.execute = mock.Mock(return_value=(0, None, None))
+
+ daemon.execute('a', 1, foo='bar', run_as_root=True, process_input=True)
+ daemon.client.execute.assert_called_once_with(['a', '1'], True)
+
+ def test_execute_fail(self):
+ mock_conf = mock.MagicMock()
+ daemon = utils.RootwrapDaemonHelper(mock_conf)
+ daemon.client = mock.MagicMock()
+ daemon.client.execute = mock.Mock(return_value=(-2, None, None))
+
+ self.assertRaises(processutils.ProcessExecutionError,
+ daemon.execute, 'b', 2)
+
+ def test_execute_pass_with_check_exit_code(self):
+ mock_conf = mock.MagicMock()
+ daemon = utils.RootwrapDaemonHelper(mock_conf)
+ daemon.client = mock.MagicMock()
+ daemon.client.execute = mock.Mock(return_value=(-2, None, None))
+ daemon.execute('b', 2, check_exit_code=[-2])
+
+ def test_execute_fail_with_retry(self):
+ mock_conf = mock.MagicMock()
+ daemon = utils.RootwrapDaemonHelper(mock_conf)
+ daemon.client = mock.MagicMock()
+ daemon.client.execute = mock.Mock(return_value=(-2, None, None))
+
+ self.assertRaises(processutils.ProcessExecutionError,
+ daemon.execute, 'b', 2, attempts=2)
+ daemon.client.execute.assert_has_calls(
+ [mock.call(['b', '2'], None),
+ mock.call(['b', '2'], None)])
+
+ @mock.patch('nova.utils.LOG.log')
+ def test_execute_fail_and_logging(self, mock_log):
+ mock_conf = mock.MagicMock()
+ daemon = utils.RootwrapDaemonHelper(mock_conf)
+ daemon.client = mock.MagicMock()
+ daemon.client.execute = mock.Mock(return_value=(-2, None, None))
+
+ self.assertRaises(processutils.ProcessExecutionError,
+ daemon.execute, 'b', 2,
+ attempts=2,
+ loglevel=logging.CRITICAL,
+ log_errors=processutils.LOG_ALL_ERRORS)
+ mock_log.assert_has_calls(
+ [
+ mock.call(logging.CRITICAL, u'Running cmd (subprocess): %s',
+ u'b 2'),
+ mock.call(logging.CRITICAL,
+ 'CMD "%(sanitized_cmd)s" returned: %(return_code)s '
+ 'in %(end_time)0.3fs',
+ {'sanitized_cmd': u'b 2', 'return_code': -2,
+ 'end_time': mock.ANY}),
+ mock.call(logging.CRITICAL,
+ u'%(desc)r\ncommand: %(cmd)r\nexit code: %(code)r'
+ u'\nstdout: %(stdout)r\nstderr: %(stderr)r',
+ {'code': -2, 'cmd': u'b 2', 'stdout': u'None',
+ 'stderr': u'None', 'desc': None}),
+ mock.call(logging.CRITICAL, u'%r failed. Retrying.', u'b 2'),
+ mock.call(logging.CRITICAL, u'Running cmd (subprocess): %s',
+ u'b 2'),
+ mock.call(logging.CRITICAL,
+ 'CMD "%(sanitized_cmd)s" returned: %(return_code)s '
+ 'in %(end_time)0.3fs',
+ {'sanitized_cmd': u'b 2', 'return_code': -2,
+ 'end_time': mock.ANY}),
+ mock.call(logging.CRITICAL,
+ u'%(desc)r\ncommand: %(cmd)r\nexit code: %(code)r'
+ u'\nstdout: %(stdout)r\nstderr: %(stderr)r',
+ {'code': -2, 'cmd': u'b 2', 'stdout': u'None',
+ 'stderr': u'None', 'desc': None}),
+ mock.call(logging.CRITICAL, u'%r failed. Not Retrying.',
+ u'b 2')]
+ )
+
+ def test_trycmd(self):
+ mock_conf = mock.MagicMock()
+ daemon = utils.RootwrapDaemonHelper(mock_conf)
+ daemon.client = mock.MagicMock()
+ daemon.client.execute = mock.Mock(return_value=(0, None, None))
+
+ daemon.trycmd('a', 1, foo='bar', run_as_root=True)
+ daemon.client.execute.assert_called_once_with(['a', '1'], None)
+
+ def test_trycmd_with_kwargs(self):
+ mock_conf = mock.MagicMock()
+ daemon = utils.RootwrapDaemonHelper(mock_conf)
+ daemon.execute = mock.Mock(return_value=('out', 'err'))
+
+ daemon.trycmd('a', 1, foo='bar', run_as_root=True,
+ loglevel=logging.WARN,
+ log_errors=True,
+ process_input=True,
+ delay_on_retry=False,
+ attempts=5,
+ check_exit_code=[200])
+ daemon.execute.assert_called_once_with('a', 1, attempts=5,
+ check_exit_code=[200],
+ delay_on_retry=False, foo='bar',
+ log_errors=True, loglevel=30,
+ process_input=True,
+ run_as_root=True)
+
+ def test_trycmd_fail(self):
+ mock_conf = mock.MagicMock()
+ daemon = utils.RootwrapDaemonHelper(mock_conf)
+ daemon.client = mock.MagicMock()
+ daemon.client.execute = mock.Mock(return_value=(-2, None, None))
+
+ expected_err = six.text_type('''\
+Unexpected error while running command.
+Command: a 1
+Exit code: -2''')
+
+ out, err = daemon.trycmd('a', 1, foo='bar', run_as_root=True)
+ daemon.client.execute.assert_called_once_with(['a', '1'], None)
+ self.assertIn(expected_err, err)
+
+ def test_trycmd_fail_with_rety(self):
+ mock_conf = mock.MagicMock()
+ daemon = utils.RootwrapDaemonHelper(mock_conf)
+ daemon.client = mock.MagicMock()
+ daemon.client.execute = mock.Mock(return_value=(-2, None, None))
+
+ expected_err = six.text_type('''\
+Unexpected error while running command.
+Command: a 1
+Exit code: -2''')
+
+ out, err = daemon.trycmd('a', 1, foo='bar', run_as_root=True,
+ attempts=3)
+ self.assertIn(expected_err, err)
+ daemon.client.execute.assert_has_calls(
+ [mock.call(['a', '1'], None),
+ mock.call(['a', '1'], None),
+ mock.call(['a', '1'], None)])
+
+
class VPNPingTestCase(test.NoDBTestCase):
"""Unit tests for utils.vpn_ping()."""
def setUp(self):