Merge lp:~allenap/maas/systemd-status-unicode-error--bug-1491822 into lp:~maas-committers/maas/trunk

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: 4236
Proposed branch: lp:~allenap/maas/systemd-status-unicode-error--bug-1491822
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 84 lines (+29/-10)
2 files modified
src/provisioningserver/service_monitor.py (+5/-5)
src/provisioningserver/tests/test_service_monitor.py (+24/-5)
To merge this branch: bzr merge lp:~allenap/maas/systemd-status-unicode-error--bug-1491822
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+270056@code.launchpad.net

Commit message

In the system monitor, decode output from the init system as UTF-8.

Always invoke the init system using the C.UTF-8 locale. Previously LANG=en_US.UTF-8 and LC_CTYPE=C was used.

To post a comment you must log in.
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/provisioningserver/service_monitor.py'
2--- src/provisioningserver/service_monitor.py 2015-06-27 00:28:40 +0000
3+++ src/provisioningserver/service_monitor.py 2015-09-03 14:26:15 +0000
4@@ -186,17 +186,17 @@
5
6 :return: tuple (exit code, output)
7 """
8- # Force systemd to output in UTF-8 instead of unicode. This doesn't
9- # have any affect on upstart.
10+ # Force systemd to output in UTF-8 by selecting the C.UTF-8 locale.
11+ # This doesn't have any effect on upstart.
12 env = os.environ.copy()
13- env["LANG"] = "en_US.UTF-8"
14- env["LC_CTYPE"] = "C"
15+ env["LANG"] = "C.UTF-8"
16+ env["LC_ALL"] = "C.UTF-8"
17 process = Popen(
18 ["sudo", "service", service_name, action],
19 stdin=PIPE, stdout=PIPE,
20 stderr=STDOUT, close_fds=True, env=env)
21 output, _ = process.communicate()
22- return process.wait(), output.strip()
23+ return process.wait(), output.decode("utf-8").strip()
24
25 def _service_action(self, service, action):
26 """Start or stop the service."""
27
28=== modified file 'src/provisioningserver/tests/test_service_monitor.py'
29--- src/provisioningserver/tests/test_service_monitor.py 2015-07-01 21:29:33 +0000
30+++ src/provisioningserver/tests/test_service_monitor.py 2015-09-03 14:26:15 +0000
31@@ -44,6 +44,7 @@
32 )
33 from provisioningserver.utils.testing import RegistryFixture
34 from testtools import ExpectedException
35+from testtools.matchers import Equals
36
37
38 class TestServiceMonitor(MAASTestCase):
39@@ -294,22 +295,40 @@
40 service_name = factory.make_name("service")
41 action = factory.make_name("action")
42 mock_popen = self.patch(service_monitor_module, "Popen")
43- mock_popen.return_value.communicate.return_value = ("", "")
44+ mock_popen.return_value.communicate.return_value = (b"", b"")
45 service_monitor._exec_service_action(service_name, action)
46 self.assertEquals(
47 ["sudo", "service", service_name, action],
48 mock_popen.call_args[0][0])
49
50- def test__exec_service_action_calls_service_with_LC_CTYPE_in_env(self):
51+ def test__exec_service_action_calls_service_with_LC_ALL_in_env(self):
52 service_monitor = ServiceMonitor()
53 service_name = factory.make_name("service")
54 action = factory.make_name("action")
55 mock_popen = self.patch(service_monitor_module, "Popen")
56- mock_popen.return_value.communicate.return_value = ("", "")
57+ mock_popen.return_value.communicate.return_value = (b"", b"")
58 service_monitor._exec_service_action(service_name, action)
59 self.assertEquals(
60- "C",
61- mock_popen.call_args[1]['env']['LC_CTYPE'])
62+ "C.UTF-8",
63+ mock_popen.call_args[1]['env']['LC_ALL'])
64+
65+ def test__exec_service_action_decodes_stdout(self):
66+ # From https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt.
67+ example_text = (
68+ '\u16bb\u16d6 \u16b3\u16b9\u16ab\u16a6 \u16a6\u16ab\u16cf '
69+ '\u16bb\u16d6 \u16d2\u16a2\u16de\u16d6 \u16a9\u16be \u16a6'
70+ '\u16ab\u16d7 \u16da\u16aa\u16be\u16de\u16d6 \u16be\u16a9'
71+ '\u16b1\u16a6\u16b9\u16d6\u16aa\u16b1\u16de\u16a2\u16d7 '
72+ '\u16b9\u16c1\u16a6 \u16a6\u16aa \u16b9\u16d6\u16e5\u16ab'
73+ )
74+ service_monitor = ServiceMonitor()
75+ service_name = factory.make_name("service")
76+ action = factory.make_name("action")
77+ mock_popen = self.patch(service_monitor_module, "Popen")
78+ mock_popen.return_value.communicate.return_value = (
79+ example_text.encode("utf-8"), b"")
80+ _, output = service_monitor._exec_service_action(service_name, action)
81+ self.assertThat(output, Equals(example_text))
82
83 def test__service_action_calls__exec_service_action(self):
84 service = self.make_service_driver(SERVICE_STATE.ON)