diff --git a/azurelinuxagent/common/osutil/default.py b/azurelinuxagent/common/osutil/default.py index 189d8fe8fc..72824d7754 100644 --- a/azurelinuxagent/common/osutil/default.py +++ b/azurelinuxagent/common/osutil/default.py @@ -1116,7 +1116,7 @@ def set_dhcp_hostname(self, hostname): def restart_if(self, ifname, retries=3, wait=5): retry_limit=retries+1 for attempt in range(1, retry_limit): - return_code=shellutil.run("ifdown {0} && ifup {0}".format(ifname)) + return_code=shellutil.run("ifdown {0} && ifup {0}".format(ifname), expected_errors=[1] if attempt < retries else []) if return_code == 0: return logger.warn("failed to restart {0}: return code {1}".format(ifname, return_code)) diff --git a/azurelinuxagent/common/utils/shellutil.py b/azurelinuxagent/common/utils/shellutil.py index a17f8c27c9..0e3ee644c9 100644 --- a/azurelinuxagent/common/utils/shellutil.py +++ b/azurelinuxagent/common/utils/shellutil.py @@ -63,13 +63,13 @@ def has_command(cmd): """ return not run(cmd, False) -def run(cmd, chk_err=True): +def run(cmd, chk_err=True, expected_errors=[]): """ Calls run_get_output on 'cmd', returning only the return code. If chk_err=True then errors will be reported in the log. If chk_err=False then errors will be suppressed from the log. """ - retcode, out = run_get_output(cmd, chk_err) + retcode, out = run_get_output(cmd, chk_err=chk_err, expected_errors=expected_errors) return retcode diff --git a/tests/utils/test_shell_util.py b/tests/utils/test_shell_util.py index 2d9b393965..fbc6b6cbc5 100644 --- a/tests/utils/test_shell_util.py +++ b/tests/utils/test_shell_util.py @@ -23,7 +23,32 @@ import azurelinuxagent.common.utils.shellutil as shellutil import test -class TestrunCmd(AgentTestCase): + +class ShellQuoteTestCase(AgentTestCase): + def test_shellquote(self): + self.assertEqual("\'foo\'", shellutil.quote("foo")) + self.assertEqual("\'foo bar\'", shellutil.quote("foo bar")) + self.assertEqual("'foo'\\''bar'", shellutil.quote("foo\'bar")) + + +class RunTestCase(AgentTestCase): + def test_it_should_return_the_exit_code_of_the_command(self): + exit_code = shellutil.run("exit 123") + self.assertEquals(123, exit_code) + + def test_it_should_be_a_pass_thru_to_run_get_output(self): + with patch.object(shellutil, "run_get_output", return_value=(0, "")) as mock_run_get_output: + shellutil.run("echo hello word!", chk_err=False, expected_errors=[1, 2, 3]) + + self.assertEquals(mock_run_get_output.call_count, 1) + + args, kwargs = mock_run_get_output.call_args + self.assertEquals(args[0], "echo hello word!") + self.assertEquals(kwargs["chk_err"], False) + self.assertEquals(kwargs["expected_errors"], [1, 2, 3]) + + +class RunGetOutputTestCase(AgentTestCase): def test_run_get_output(self): output = shellutil.run_get_output(u"ls /") self.assertNotEquals(None, output) @@ -35,10 +60,18 @@ def test_run_get_output(self): err = shellutil.run_get_output(u"ls 我") self.assertNotEquals(0, err[0]) - def test_shellquote(self): - self.assertEqual("\'foo\'", shellutil.quote("foo")) - self.assertEqual("\'foo bar\'", shellutil.quote("foo bar")) - self.assertEqual("'foo'\\''bar'", shellutil.quote("foo\'bar")) + def test_it_should_log_the_command(self): + command = "echo hello world!" + + with patch("azurelinuxagent.common.utils.shellutil.logger", autospec=True) as mock_logger: + shellutil.run_get_output(command) + + self.assertEquals(mock_logger.verbose.call_count, 1) + + args, kwargs = mock_logger.verbose.call_args + command_in_message = args[1] + self.assertEqual(command_in_message, command) + def test_it_should_log_command_failures_as_errors(self): return_code = 99