Merge lp:~gocept/landscape-client/py3-broker-registration into lp:~landscape/landscape-client/trunk

Proposed by Steffen Allner
Status: Merged
Approved by: Eric Snow
Approved revision: 976
Merged at revision: 978
Proposed branch: lp:~gocept/landscape-client/py3-broker-registration
Merge into: lp:~landscape/landscape-client/trunk
Prerequisite: lp:~gocept/landscape-client/py3-broker-exchange
Diff against target: 306 lines (+54/-42)
6 files modified
landscape/broker/registration.py (+1/-1)
landscape/broker/tests/test_registration.py (+19/-8)
landscape/lib/tests/test_vm_info.py (+14/-14)
landscape/lib/vm_info.py (+18/-17)
landscape/message_schemas.py (+1/-1)
py3_ready_tests (+1/-1)
To merge this branch: bzr merge lp:~gocept/landscape-client/py3-broker-registration
Reviewer Review Type Date Requested Status
Eric Snow (community) Approve
Daniel Havlik (community) Approve
Данило Шеган (community) Approve
🤖 Landscape Builder test results Approve
Review via email: mp+320799@code.launchpad.net

Commit message

This is the port of landscape.broker.registration to Python 3.

This involved fixing bytes/unicode issues. One situation in the tests involved incompatibilities involving io.StringIO. The fix there is not ideal. Applying a better solution is tabled for later.

Description of the change

As the diff for the landscape.broker module would be to large, I MP the sub-modules separately.

Here we have landscape.broker.registration, where the tests were failing because bytes were not uses as input when required by a schema, in particular "api" and "vm-info". The restriction on "vm-info" required larger modifications on landscape.lib.vm_info which returns now bytes for all cases of "vm-info".

The case with the conditional encoding to compare bytes of log messages in unfortunate. I tried a few different approaches but a drop-in replacement of cStringIO with io.StringIO would result in a lot of test failures so I would rather suggest to put that on a trello card and look at this problem separately.

To post a comment you must log in.
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Success
Revno: 976
Branch: lp:~gocept/landscape-client/py3-broker-registration
Jenkins: https://ci.lscape.net/job/latch-test-xenial/3715/

review: Approve (test results)
Revision history for this message
Данило Шеган (danilo) wrote :

Looks good: I agree with your suggestion of adding a separate card to look at at the end, and thanks for putting in an XXX comment too!

review: Approve
Revision history for this message
Daniel Havlik (nilo) wrote :

+1

review: Approve
Revision history for this message
Eric Snow (ericsnowcurrently) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'landscape/broker/registration.py'
2--- landscape/broker/registration.py 2017-02-24 09:38:26 +0000
3+++ landscape/broker/registration.py 2017-03-23 13:00:45 +0000
4@@ -196,7 +196,7 @@
5 # version 14.01 has a different format for the juju-info field,
6 # so this makes sure that the correct schema is used by the server
7 # when validating our message.
8- if self._juju_data and is_version_higher(server_api, "3.3"):
9+ if self._juju_data and is_version_higher(server_api, b"3.3"):
10 message["juju-info"] = {
11 "environment-uuid": self._juju_data["environment-uuid"],
12 "api-addresses": self._juju_data["api-addresses"],
13
14=== modified file 'landscape/broker/tests/test_registration.py'
15--- landscape/broker/tests/test_registration.py 2017-02-24 09:38:26 +0000
16+++ landscape/broker/tests/test_registration.py 2017-03-23 13:00:45 +0000
17@@ -3,6 +3,8 @@
18 import socket
19 import mock
20
21+from twisted.python.compat import _PY3
22+
23 from landscape.broker.registration import RegistrationError, Identity
24 from landscape.tests.helpers import LandscapeTest
25 from landscape.broker.tests.helpers import (
26@@ -167,13 +169,13 @@
27 secure_id is set, and an exchange is about to happen,
28 queue a registration message with VM information.
29 """
30- get_vm_info_mock.return_value = "vmware"
31+ get_vm_info_mock.return_value = b"vmware"
32 self.mstore.set_accepted_types(["register"])
33 self.config.computer_title = "Computer Title"
34 self.config.account_name = "account_name"
35 self.reactor.fire("pre-exchange")
36 messages = self.mstore.get_pending_messages()
37- self.assertEqual("vmware", messages[0]["vm-info"])
38+ self.assertEqual(b"vmware", messages[0]["vm-info"])
39 self.assertEqual(self.logfile.getvalue().strip(),
40 "INFO: Queueing message to register with account "
41 "'account_name' without a password.")
42@@ -261,10 +263,19 @@
43 expected = u"prova\N{LATIN SMALL LETTER J WITH CIRCUMFLEX}o"
44 self.assertEqual(expected, messages[0]["tags"])
45
46- self.assertEqual(self.logfile.getvalue().strip(),
47- "INFO: Queueing message to register with account "
48- "'account_name' and tags prova\xc4\xb5o "
49- "with a password.")
50+ logs = self.logfile.getvalue().strip()
51+ # XXX This is not nice, as it has the origin in a non-consistent way of
52+ # using logging. self.logfile is a cStringIO in Python 2 and
53+ # io.StringIO in Python 3. This results in reading bytes in Python 2
54+ # and unicode in Python 3, but a drop-in replacement of cStringIO with
55+ # io.StringIO in Python 2 is not working. However, we compare bytes
56+ # here, to circumvent that problem.
57+ if _PY3:
58+ logs = logs.encode("utf-8")
59+ self.assertEqual(logs,
60+ b"INFO: Queueing message to register with account "
61+ b"'account_name' and tags prova\xc4\xb5o "
62+ b"with a password.")
63
64 def test_queue_message_on_exchange_with_access_group(self):
65 """
66@@ -541,7 +552,7 @@
67 the registration message.
68 """
69 self.mstore.set_accepted_types(["register"])
70- self.mstore.set_server_api("3.3")
71+ self.mstore.set_server_api(b"3.3")
72 self.config.account_name = "account_name"
73 self.reactor.fire("run")
74 self.reactor.fire("pre-exchange")
75@@ -559,7 +570,7 @@
76 isn't included in the message.
77 """
78 self.mstore.set_accepted_types(["register"])
79- self.mstore.set_server_api("3.2")
80+ self.mstore.set_server_api(b"3.2")
81 self.config.account_name = "account_name"
82 self.reactor.fire("run")
83 self.reactor.fire("pre-exchange")
84
85=== modified file 'landscape/lib/tests/test_vm_info.py'
86--- landscape/lib/tests/test_vm_info.py 2016-09-23 12:51:20 +0000
87+++ landscape/lib/tests/test_vm_info.py 2017-03-23 13:00:45 +0000
88@@ -25,7 +25,7 @@
89 """
90 L{get_vm_info} should be empty when there's no virtualisation.
91 """
92- self.assertEqual(u"", get_vm_info(root_path=self.root_path))
93+ self.assertEqual(b"", get_vm_info(root_path=self.root_path))
94
95 def test_get_vm_info_is_openvz_when_proc_vz_exists(self):
96 """
97@@ -34,7 +34,7 @@
98 proc_vz_path = os.path.join(self.proc_path, "vz")
99 self.makeFile(path=proc_vz_path, content="foo")
100
101- self.assertEqual("openvz", get_vm_info(root_path=self.root_path))
102+ self.assertEqual(b"openvz", get_vm_info(root_path=self.root_path))
103
104 def test_get_vm_info_is_xen_when_sys_bus_xen_is_non_empty(self):
105 """
106@@ -46,7 +46,7 @@
107 foo_devices_path = os.path.join(devices_xen_path, "foo")
108 self.makeFile(path=foo_devices_path, content="bar")
109
110- self.assertEqual("xen", get_vm_info(root_path=self.root_path))
111+ self.assertEqual(b"xen", get_vm_info(root_path=self.root_path))
112
113 def test_get_vm_info_is_empty_without_xen_devices(self):
114 """
115@@ -56,7 +56,7 @@
116 devices_xen_path = os.path.join(self.sys_path, "bus/xen/devices")
117 self.makeDir(path=devices_xen_path)
118
119- self.assertEqual("", get_vm_info(root_path=self.root_path))
120+ self.assertEqual(b"", get_vm_info(root_path=self.root_path))
121
122 def test_get_vm_info_with_bochs_sys_vendor(self):
123 """
124@@ -64,7 +64,7 @@
125 Bochs.
126 """
127 self.make_sys_vendor("Bochs")
128- self.assertEqual("kvm", get_vm_info(root_path=self.root_path))
129+ self.assertEqual(b"kvm", get_vm_info(root_path=self.root_path))
130
131 def test_get_vm_info_with_openstack_sys_vendor(self):
132 """
133@@ -72,7 +72,7 @@
134 Openstack.
135 """
136 self.make_sys_vendor("OpenStack Foundation")
137- self.assertEqual("kvm", get_vm_info(root_path=self.root_path))
138+ self.assertEqual(b"kvm", get_vm_info(root_path=self.root_path))
139
140 def test_get_vm_info_with_qemu_sys_vendor(self):
141 """
142@@ -80,7 +80,7 @@
143 QEMU.
144 """
145 self.make_sys_vendor("QEMU")
146- self.assertEqual("kvm", get_vm_info(root_path=self.root_path))
147+ self.assertEqual(b"kvm", get_vm_info(root_path=self.root_path))
148
149 def test_get_vm_info_with_vmware_sys_vendor(self):
150 """
151@@ -88,7 +88,7 @@
152 VMware Inc.
153 """
154 self.make_sys_vendor("VMware, Inc.")
155- self.assertEqual("vmware", get_vm_info(root_path=self.root_path))
156+ self.assertEqual(b"vmware", get_vm_info(root_path=self.root_path))
157
158 def test_get_vm_info_with_virtualbox_sys_vendor(self):
159 """
160@@ -96,28 +96,28 @@
161 is innotek. GmbH.
162 """
163 self.make_sys_vendor("innotek GmbH")
164- self.assertEqual("virtualbox", get_vm_info(root_path=self.root_path))
165+ self.assertEqual(b"virtualbox", get_vm_info(root_path=self.root_path))
166
167 def test_get_vm_info_with_microsoft_sys_vendor(self):
168 """
169 L{get_vm_info} returns "hyperv" if the sys_vendor is Microsoft.
170 """
171 self.make_sys_vendor("Microsoft Corporation")
172- self.assertEqual("hyperv", get_vm_info(root_path=self.root_path))
173+ self.assertEqual(b"hyperv", get_vm_info(root_path=self.root_path))
174
175 def test_get_vm_info_with_google_sys_vendor(self):
176 """
177 L{get_vm_info} returns "gce" if the sys_vendor is Google.
178 """
179 self.make_sys_vendor("Google")
180- self.assertEqual("gce", get_vm_info(root_path=self.root_path))
181+ self.assertEqual(b"gce", get_vm_info(root_path=self.root_path))
182
183 def test_get_vm_info_matches_insensitive(self):
184 """
185 L{get_vm_info} matches the vendor string in a case-insentive way.
186 """
187 self.make_sys_vendor("openstack foundation")
188- self.assertEqual("kvm", get_vm_info(root_path=self.root_path))
189+ self.assertEqual(b"kvm", get_vm_info(root_path=self.root_path))
190
191 def test_get_vm_info_with_kvm_on_other_architecture(self):
192 """
193@@ -130,7 +130,7 @@
194 "model : Some CPU (emulated by qemu)\n"
195 "machine : Some Machine (emulated by qemu)\n")
196 self.makeFile(path=cpuinfo_path, content=cpuinfo)
197- self.assertEqual("kvm", get_vm_info(root_path=self.root_path))
198+ self.assertEqual(b"kvm", get_vm_info(root_path=self.root_path))
199
200 def test_get_vm_info_with_other_vendor(self):
201 """
202@@ -138,7 +138,7 @@
203 unknown.
204 """
205 self.make_sys_vendor("Some other vendor")
206- self.assertEqual("", get_vm_info(root_path=self.root_path))
207+ self.assertEqual(b"", get_vm_info(root_path=self.root_path))
208
209
210 class GetContainerInfoTest(LandscapeTest):
211
212=== modified file 'landscape/lib/vm_info.py'
213--- landscape/lib/vm_info.py 2017-03-13 15:38:09 +0000
214+++ landscape/lib/vm_info.py 2017-03-23 13:00:45 +0000
215@@ -8,16 +8,16 @@
216
217 def get_vm_info(root_path="/"):
218 """
219- Return a string with the virtualization type if it's known, an empty string
220- otherwise.
221+ Return a bytestring with the virtualization type if it's known, an empty
222+ bytestring otherwise.
223
224- It loops through some possible configurations and return a string with
225+ It loops through some possible configurations and return a bytestring with
226 the name of the technology being used or None if there's no match
227 """
228 if _is_vm_openvz(root_path):
229- return "openvz"
230+ return b"openvz"
231 if _is_vm_xen(root_path):
232- return "xen"
233+ return b"xen"
234
235 sys_vendor_path = os.path.join(root_path, "sys/class/dmi/id/sys_vendor")
236 if os.path.exists(sys_vendor_path):
237@@ -51,22 +51,23 @@
238
239
240 def _get_vm_by_vendor(sys_vendor_path):
241- """Return the VM type string (possibly empty) based on the vendor."""
242+ """Return the VM type byte string (possibly empty) based on the vendor."""
243 vendor = read_text_file(sys_vendor_path).lower()
244 # Use lower-key string for vendors, since we do case-insentive match.
245+ # We need bytes here as required by the message schema.
246 content_vendors_map = (
247- ("bochs", "kvm"),
248- ("google", "gce"),
249- ("innotek", "virtualbox"),
250- ("microsoft", "hyperv"),
251- ("openstack", "kvm"),
252- ("qemu", "kvm"),
253- ("vmware", "vmware"))
254+ ("bochs", b"kvm"),
255+ ("google", b"gce"),
256+ ("innotek", b"virtualbox"),
257+ ("microsoft", b"hyperv"),
258+ ("openstack", b"kvm"),
259+ ("qemu", b"kvm"),
260+ ("vmware", b"vmware"))
261 for name, vm_type in content_vendors_map:
262 if name in vendor:
263 return vm_type
264
265- return ""
266+ return b""
267
268
269 def _get_vm_legacy(root_path):
270@@ -74,9 +75,9 @@
271 try:
272 cpuinfo = read_text_file(os.path.join(root_path, "proc/cpuinfo"))
273 except (IOError, OSError):
274- return ""
275+ return b""
276
277 if "qemu" in cpuinfo:
278- return "kvm"
279+ return b"kvm"
280
281- return ""
282+ return b""
283
284=== modified file 'landscape/message_schemas.py'
285--- landscape/message_schemas.py 2017-03-17 10:08:19 +0000
286+++ landscape/message_schemas.py 2017-03-23 13:00:45 +0000
287@@ -199,7 +199,7 @@
288 "api-addresses": List(Unicode()),
289 "machine-id": Unicode()}),
290 "access_group": Unicode()},
291- api="3.3",
292+ api=b"3.3",
293 optional=["registration_password", "hostname", "tags", "vm-info",
294 "container-info", "access_group", "juju-info"])
295
296
297=== modified file 'py3_ready_tests'
298--- py3_ready_tests 2017-03-23 13:00:45 +0000
299+++ py3_ready_tests 2017-03-23 13:00:45 +0000
300@@ -7,6 +7,6 @@
301
302
303
304-
305+landscape.broker.tests.test_registration
306 landscape.broker.tests.test_exchange
307

Subscribers

People subscribed via source and target branches

to all changes: