Merge lp:~sylvain-pineau/checkbox/bug1091633 into lp:checkbox

Proposed by Sylvain Pineau
Status: Merged
Merged at revision: 1958
Proposed branch: lp:~sylvain-pineau/checkbox/bug1091633
Merge into: lp:checkbox
Diff against target: 243 lines (+81/-36)
4 files modified
checkbox/parsers/udevadm.py (+21/-0)
debian/changelog (+3/-0)
scripts/network_device_info (+56/-35)
scripts/udev_resource (+1/-1)
To merge this branch: bzr merge lp:~sylvain-pineau/checkbox/bug1091633
Reviewer Review Type Date Requested Status
Zygmunt Krynicki (community) Approve
Brendan Donegan (community) Needs Information
Review via email: mp+141054@code.launchpad.net

Commit message

scripts/network_device_info: Use udev to categorise network devices instead of lspci

Description of the change

scripts/network_device_info: Use udev to categorise network devices instead of lspci

To post a comment you must log in.
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

@Brendan,

As you have a system where the wifi interface is named eth1, I've set you as the first reviewer.
Please check that my udev machinery works well in such config.

Thanks

Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

@Brendan,

As you have a system where the wifi interface is named eth1, I've set you as the first reviewer.
Please check that my udev machinery works well in such config.

Thanks

Revision history for this message
Zygmunt Krynicki (zyga) wrote :

While I don't find anything wrong with it just by looking at it I have a few general comments.

1) There are no comments in the code.

It's really hard to justify if something is correct or not. There is no rationale
explained in the code. I could look at the whole code, the history, etc and try to guess why something's
done the way it is but it's fragile and I'd rather have a code that is self explanatory to some degree.

2) There are layering issues in the coee.

For me something that's called parsers/udevadm should _not_ have any logic in it.
I'm talking about stuff like

14 + if self.bus == "sound":
15 + return "AUDIO"

This is _certainly_ something you want at a separate, higher layer. Otherwise the whole thing is ill defined
and harder to test. I'd like to see a pure parser for udevadm data along with a data layer that just
represents that and a separate mapping layer where we get our magic "WIRELESS" devices and stuff like that.

3) There are no tests being added that verify stuff works.

Writing tests is hard when things are untested and not designed to be tested easily but we just have
to get better at it. Especially for stuff like that, which is causing problems.

While I won't veto landing it we should strive to be better at those things.

Revision history for this message
Brendan Donegan (brendan-donegan) wrote :

Sylvain,

This has been sitting around for a while, can you respond to Zygmunts comments?

review: Needs Information
Revision history for this message
Zygmunt Krynicki (zyga) wrote :

Let's land this, we'll come to a point where we'll start looking at the scripts + testing architecture.

review: Approve
Revision history for this message
Zygmunt Krynicki (zyga) wrote :

Attempt to merge into lp:checkbox failed due to conflicts:

text conflict in debian/changelog

Revision history for this message
Daniel Manrique (roadmr) wrote :

Hello, I manually merged to solve the changelog conflict. Thanks!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'checkbox/parsers/udevadm.py'
--- checkbox/parsers/udevadm.py 2012-11-12 09:59:00 +0000
+++ checkbox/parsers/udevadm.py 2012-12-21 11:10:29 +0000
@@ -92,8 +92,15 @@
92 @property92 @property
93 def category(self):93 def category(self):
94 if "IFINDEX" in self._environment:94 if "IFINDEX" in self._environment:
95 if "DEVTYPE" in self._environment:
96 devtype = self._environment["DEVTYPE"]
97 if devtype == "wlan":
98 return "WIRELESS"
95 return "NETWORK"99 return "NETWORK"
96100
101 if self.bus == "sound":
102 return "AUDIO"
103
97 if self.bus == "ieee80211":104 if self.bus == "ieee80211":
98 return "WIRELESS"105 return "WIRELESS"
99106
@@ -383,6 +390,9 @@
383 if self.driver == "floppy":390 if self.driver == "floppy":
384 return "Platform Device"391 return "Platform Device"
385392
393 if "ID_MODEL_FROM_DATABASE" in self._environment:
394 return self._environment["ID_MODEL_FROM_DATABASE"]
395
386 return None396 return None
387397
388 @property398 @property
@@ -407,6 +417,17 @@
407 and "ID_VENDOR_ENC" in self._environment:417 and "ID_VENDOR_ENC" in self._environment:
408 return decode_id(self._environment["ID_VENDOR_ENC"])418 return decode_id(self._environment["ID_VENDOR_ENC"])
409419
420 if "ID_VENDOR_FROM_DATABASE" in self._environment:
421 return self._environment["ID_VENDOR_FROM_DATABASE"]
422
423 return None
424
425 @property
426 def interface(self):
427 if self.category in ("NETWORK", "WIRELESS") \
428 and "INTERFACE" in self._environment:
429 return self._environment["INTERFACE"]
430
410 return None431 return None
411432
412433
413434
=== modified file 'debian/changelog'
--- debian/changelog 2012-12-17 17:19:04 +0000
+++ debian/changelog 2012-12-21 11:10:29 +0000
@@ -47,6 +47,9 @@
47 unity_support_test and piped to ansi_parser.47 unity_support_test and piped to ansi_parser.
48 * scripts/network_device_info: Set the driver version to 'Unknown' if the48 * scripts/network_device_info: Set the driver version to 'Unknown' if the
49 modinfo_parser returns nothing (LP: #1089911)49 modinfo_parser returns nothing (LP: #1089911)
50 * scripts/network_device_info, scripts/udev_resource,
51 checkbox/parsers/udevadm.py: Use udev to categorise network devices instead
52 of lspci (LP: #1091633)
5053
51 -- Daniel Manrique <roadmr@ubuntu.com> Fri, 16 Nov 2012 12:14:21 -050054 -- Daniel Manrique <roadmr@ubuntu.com> Fri, 16 Nov 2012 12:14:21 -0500
5255
5356
=== modified file 'scripts/network_device_info'
--- scripts/network_device_info 2012-12-13 13:11:40 +0000
+++ scripts/network_device_info 2012-12-21 11:10:29 +0000
@@ -26,6 +26,7 @@
26import dbus26import dbus
27import sys27import sys
28from checkbox.parsers.modinfo import ModinfoParser28from checkbox.parsers.modinfo import ModinfoParser
29from checkbox.parsers.udevadm import UdevadmParser
29from subprocess import check_output, CalledProcessError, STDOUT30from subprocess import check_output, CalledProcessError, STDOUT
3031
31# This example lists basic information about network interfaces known to NM32# This example lists basic information about network interfaces known to NM
@@ -50,6 +51,17 @@
50 110: "Deactivating",51 110: "Deactivating",
51 120: "Failed"}52 120: "Failed"}
5253
54attributes = ("category", "interface", "product", "vendor", "driver", "path")
55
56udev_devices = []
57nm_devices = []
58
59
60class UdevResult:
61 def addDevice(self, device):
62 if device.interface:
63 udev_devices.append(device)
64
5365
54class NetworkingDevice():66class NetworkingDevice():
55 def __init__(self, devtype, props, dev_proxy, bus):67 def __init__(self, devtype, props, dev_proxy, bus):
@@ -68,6 +80,7 @@
68 self._driver = props['Driver']80 self._driver = props['Driver']
69 except KeyError:81 except KeyError:
70 self._driver = "Unknown"82 self._driver = "Unknown"
83 self._driver_ver = "Unknown"
7184
72 if self._driver != "Unknown":85 if self._driver != "Unknown":
73 self._modinfo = self._modinfo_parser(props['Driver'])86 self._modinfo = self._modinfo_parser(props['Driver'])
@@ -87,7 +100,7 @@
87 self._state = "Unknown"100 self._state = "Unknown"
88101
89 def __str__(self):102 def __str__(self):
90 ret = "Type: %s\n" % self._devtype103 ret = "Category: %s\n" % self._devtype
91 ret += "Interface: %s\n" % self._interface104 ret += "Interface: %s\n" % self._interface
92 ret += "IP: %s\n" % self._ip105 ret += "IP: %s\n" % self._ip
93 ret += "Driver: %s (ver: %s)\n" % (self._driver, self._driver_ver)106 ret += "Driver: %s (ver: %s)\n" % (self._driver, self._driver_ver)
@@ -124,7 +137,7 @@
124 else:137 else:
125 parser = ModinfoParser(stream)138 parser = ModinfoParser(stream)
126 modinfo = parser.get_all()139 modinfo = parser.get_all()
127 140
128 return modinfo141 return modinfo
129142
130 def _find_driver_ver(self):143 def _find_driver_ver(self):
@@ -160,7 +173,8 @@
160 nm_devices = manager.GetDevices()173 nm_devices = manager.GetDevices()
161 for d in nm_devices:174 for d in nm_devices:
162 dev_proxy = bus.get_object("org.freedesktop.NetworkManager", d)175 dev_proxy = bus.get_object("org.freedesktop.NetworkManager", d)
163 prop_iface = dbus.Interface(dev_proxy,"org.freedesktop.DBus.Properties")176 prop_iface = dbus.Interface(dev_proxy,
177 "org.freedesktop.DBus.Properties")
164 props = prop_iface.GetAll("org.freedesktop.NetworkManager.Device")178 props = prop_iface.GetAll("org.freedesktop.NetworkManager.Device")
165 try:179 try:
166 devtype = devtypes[props['DeviceType']]180 devtype = devtypes[props['DeviceType']]
@@ -173,7 +187,7 @@
173 return devices187 return devices
174188
175189
176def match_counts(nm_devices, pci_devices, devtype):190def match_counts(nm_devices, udev_devices, devtype):
177 """191 """
178 Ensures that the count of devices matching devtype is the same for the192 Ensures that the count of devices matching devtype is the same for the
179 two passed in lists, devices from Network Manager and devices from lspci.193 two passed in lists, devices from Network Manager and devices from lspci.
@@ -181,41 +195,48 @@
181 # now check that the count (by type) matches - WiFi195 # now check that the count (by type) matches - WiFi
182 nm_type_devices = list(filter(lambda dev: dev.gettype() == devtype,196 nm_type_devices = list(filter(lambda dev: dev.gettype() == devtype,
183 nm_devices))197 nm_devices))
184 pci_type_devices = list(filter(lambda dev: dev['type'] == devtype,198 udevtype = 'WIRELESS' if devtype == 'WiFi' else 'NETWORK'
185 pci_devices))199 udev_type_devices = list(filter(lambda dev: dev.category == udevtype,
186 if len(nm_type_devices) != len(pci_type_devices):200 udev_devices))
187 print("ERROR: %s devices missing: lspci showed %d devices, but "201 if len(nm_type_devices) != len(udev_type_devices):
202 print("ERROR: %s devices missing: udev showed %d devices, but "
188 "NetworkManager saw %d devices" % (devtype,203 "NetworkManager saw %d devices" % (devtype,
189 len(pci_type_devices), len(nm_type_devices)))204 len(udev_type_devices), len(nm_type_devices)))
190 return False205 return False
191 else:206 else:
192 return True207 return True
193208
194209
195def main(args):210def main(args):
196 pci_devices = []211 try:
197 command = "lspci"212 output = check_output(['udevadm', 'info', '--export-db'])
198 for line in os.popen(command).readlines():213 except CalledProcessError as err:
199 if "Ethernet controller: " in line:214 raise SystemExit(err)
200 device = {}215 try:
201 device['name'] = line.split(": ")[1].strip()216 output = output.decode("UTF-8")
202 device['type'] = "Ethernet"217 except UnicodeDecodeError as err:
203 pci_devices.append(device)218 raise SystemExit("udevadm output is not valid UTF-8")
204 elif "Network controller: " in line:219 udev = UdevadmParser(output)
205 device = {}220 result = UdevResult()
206 device['name'] = line.split(": ")[1].strip()221 udev.run(result)
207 device['type'] = "WiFi"222
208 pci_devices.append(device)223 if udev_devices:
209224 print("[ Devices found by udev ]".center(80, '-'))
210 if pci_devices:225 for device in udev_devices:
211 print("Devices found by lspci------------------------------")226 for attribute in attributes:
212 for device in pci_devices:227 value = getattr(device, attribute)
213 print("%s: %s" % (device['type'], device['name']))228 if value is not None:
214 else:229 if attribute == 'driver':
215 print("ERROR: No Networking devices found.", file=sys.stderr)230 props = {}
216 return 1231 props['Driver'] = value
217232 network_dev = NetworkingDevice(None, props, None, None)
218 nm_devices = []233 print("%s: %s (ver: %s)" % (attribute.capitalize(),
234 value, network_dev._driver_ver))
235 else:
236 print("%s: %s" % (attribute.capitalize(), value))
237
238 print()
239
219 try:240 try:
220 nm_devices = get_nm_devices()241 nm_devices = get_nm_devices()
221 except dbus.exceptions.DBusException as e:242 except dbus.exceptions.DBusException as e:
@@ -226,13 +247,13 @@
226 print("The Error Generated was:\n %s" % e, file=sys.stderr)247 print("The Error Generated was:\n %s" % e, file=sys.stderr)
227 return 0248 return 0
228249
229 print("Devices found by Network Manager-------------------------")250 print("[ Devices found by Network Manager ]".center(80, '-'))
230 for nm_dev in nm_devices:251 for nm_dev in nm_devices:
231 print(nm_dev)252 print(nm_dev)
232253
233 if not match_counts(nm_devices, pci_devices, "WiFi"):254 if not match_counts(nm_devices, udev_devices, "WiFi"):
234 return 1255 return 1
235 elif not match_counts(nm_devices, pci_devices, "Ethernet"):256 elif not match_counts(nm_devices, udev_devices, "Ethernet"):
236 return 1257 return 1
237 else:258 else:
238 return 0259 return 0
239260
=== modified file 'scripts/udev_resource'
--- scripts/udev_resource 2012-11-12 10:09:25 +0000
+++ scripts/udev_resource 2012-12-21 11:10:29 +0000
@@ -27,7 +27,7 @@
2727
28 attributes = ("path", "bus", "category", "driver", "product_id",28 attributes = ("path", "bus", "category", "driver", "product_id",
29 "vendor_id", "subproduct_id", "subvendor_id", "product",29 "vendor_id", "subproduct_id", "subvendor_id", "product",
30 "vendor",)30 "vendor", "interface",)
3131
32 def addDevice(self, device):32 def addDevice(self, device):
33 for attribute in self.attributes:33 for attribute in self.attributes:

Subscribers

People subscribed via source and target branches