Merge lp:~sylvain-pineau/checkbox/bug1091633 into lp:checkbox
- bug1091633
- Merge into trunk
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 |
Related bugs: |
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/
Description of the change
scripts/
Sylvain Pineau (sylvain-pineau) wrote : | # |
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
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.
Brendan Donegan (brendan-donegan) wrote : | # |
Sylvain,
This has been sitting around for a while, can you respond to Zygmunts comments?
Zygmunt Krynicki (zyga) wrote : | # |
Let's land this, we'll come to a point where we'll start looking at the scripts + testing architecture.
Zygmunt Krynicki (zyga) wrote : | # |
Attempt to merge into lp:checkbox failed due to conflicts:
text conflict in debian/changelog
Daniel Manrique (roadmr) wrote : | # |
Hello, I manually merged to solve the changelog conflict. Thanks!
Preview Diff
1 | === modified file 'checkbox/parsers/udevadm.py' | |||
2 | --- checkbox/parsers/udevadm.py 2012-11-12 09:59:00 +0000 | |||
3 | +++ checkbox/parsers/udevadm.py 2012-12-21 11:10:29 +0000 | |||
4 | @@ -92,8 +92,15 @@ | |||
5 | 92 | @property | 92 | @property |
6 | 93 | def category(self): | 93 | def category(self): |
7 | 94 | if "IFINDEX" in self._environment: | 94 | if "IFINDEX" in self._environment: |
8 | 95 | if "DEVTYPE" in self._environment: | ||
9 | 96 | devtype = self._environment["DEVTYPE"] | ||
10 | 97 | if devtype == "wlan": | ||
11 | 98 | return "WIRELESS" | ||
12 | 95 | return "NETWORK" | 99 | return "NETWORK" |
13 | 96 | 100 | ||
14 | 101 | if self.bus == "sound": | ||
15 | 102 | return "AUDIO" | ||
16 | 103 | |||
17 | 97 | if self.bus == "ieee80211": | 104 | if self.bus == "ieee80211": |
18 | 98 | return "WIRELESS" | 105 | return "WIRELESS" |
19 | 99 | 106 | ||
20 | @@ -383,6 +390,9 @@ | |||
21 | 383 | if self.driver == "floppy": | 390 | if self.driver == "floppy": |
22 | 384 | return "Platform Device" | 391 | return "Platform Device" |
23 | 385 | 392 | ||
24 | 393 | if "ID_MODEL_FROM_DATABASE" in self._environment: | ||
25 | 394 | return self._environment["ID_MODEL_FROM_DATABASE"] | ||
26 | 395 | |||
27 | 386 | return None | 396 | return None |
28 | 387 | 397 | ||
29 | 388 | @property | 398 | @property |
30 | @@ -407,6 +417,17 @@ | |||
31 | 407 | and "ID_VENDOR_ENC" in self._environment: | 417 | and "ID_VENDOR_ENC" in self._environment: |
32 | 408 | return decode_id(self._environment["ID_VENDOR_ENC"]) | 418 | return decode_id(self._environment["ID_VENDOR_ENC"]) |
33 | 409 | 419 | ||
34 | 420 | if "ID_VENDOR_FROM_DATABASE" in self._environment: | ||
35 | 421 | return self._environment["ID_VENDOR_FROM_DATABASE"] | ||
36 | 422 | |||
37 | 423 | return None | ||
38 | 424 | |||
39 | 425 | @property | ||
40 | 426 | def interface(self): | ||
41 | 427 | if self.category in ("NETWORK", "WIRELESS") \ | ||
42 | 428 | and "INTERFACE" in self._environment: | ||
43 | 429 | return self._environment["INTERFACE"] | ||
44 | 430 | |||
45 | 410 | return None | 431 | return None |
46 | 411 | 432 | ||
47 | 412 | 433 | ||
48 | 413 | 434 | ||
49 | === modified file 'debian/changelog' | |||
50 | --- debian/changelog 2012-12-17 17:19:04 +0000 | |||
51 | +++ debian/changelog 2012-12-21 11:10:29 +0000 | |||
52 | @@ -47,6 +47,9 @@ | |||
53 | 47 | unity_support_test and piped to ansi_parser. | 47 | unity_support_test and piped to ansi_parser. |
54 | 48 | * scripts/network_device_info: Set the driver version to 'Unknown' if the | 48 | * scripts/network_device_info: Set the driver version to 'Unknown' if the |
55 | 49 | modinfo_parser returns nothing (LP: #1089911) | 49 | modinfo_parser returns nothing (LP: #1089911) |
56 | 50 | * scripts/network_device_info, scripts/udev_resource, | ||
57 | 51 | checkbox/parsers/udevadm.py: Use udev to categorise network devices instead | ||
58 | 52 | of lspci (LP: #1091633) | ||
59 | 50 | 53 | ||
60 | 51 | -- Daniel Manrique <roadmr@ubuntu.com> Fri, 16 Nov 2012 12:14:21 -0500 | 54 | -- Daniel Manrique <roadmr@ubuntu.com> Fri, 16 Nov 2012 12:14:21 -0500 |
61 | 52 | 55 | ||
62 | 53 | 56 | ||
63 | === modified file 'scripts/network_device_info' | |||
64 | --- scripts/network_device_info 2012-12-13 13:11:40 +0000 | |||
65 | +++ scripts/network_device_info 2012-12-21 11:10:29 +0000 | |||
66 | @@ -26,6 +26,7 @@ | |||
67 | 26 | import dbus | 26 | import dbus |
68 | 27 | import sys | 27 | import sys |
69 | 28 | from checkbox.parsers.modinfo import ModinfoParser | 28 | from checkbox.parsers.modinfo import ModinfoParser |
70 | 29 | from checkbox.parsers.udevadm import UdevadmParser | ||
71 | 29 | from subprocess import check_output, CalledProcessError, STDOUT | 30 | from subprocess import check_output, CalledProcessError, STDOUT |
72 | 30 | 31 | ||
73 | 31 | # This example lists basic information about network interfaces known to NM | 32 | # This example lists basic information about network interfaces known to NM |
74 | @@ -50,6 +51,17 @@ | |||
75 | 50 | 110: "Deactivating", | 51 | 110: "Deactivating", |
76 | 51 | 120: "Failed"} | 52 | 120: "Failed"} |
77 | 52 | 53 | ||
78 | 54 | attributes = ("category", "interface", "product", "vendor", "driver", "path") | ||
79 | 55 | |||
80 | 56 | udev_devices = [] | ||
81 | 57 | nm_devices = [] | ||
82 | 58 | |||
83 | 59 | |||
84 | 60 | class UdevResult: | ||
85 | 61 | def addDevice(self, device): | ||
86 | 62 | if device.interface: | ||
87 | 63 | udev_devices.append(device) | ||
88 | 64 | |||
89 | 53 | 65 | ||
90 | 54 | class NetworkingDevice(): | 66 | class NetworkingDevice(): |
91 | 55 | def __init__(self, devtype, props, dev_proxy, bus): | 67 | def __init__(self, devtype, props, dev_proxy, bus): |
92 | @@ -68,6 +80,7 @@ | |||
93 | 68 | self._driver = props['Driver'] | 80 | self._driver = props['Driver'] |
94 | 69 | except KeyError: | 81 | except KeyError: |
95 | 70 | self._driver = "Unknown" | 82 | self._driver = "Unknown" |
96 | 83 | self._driver_ver = "Unknown" | ||
97 | 71 | 84 | ||
98 | 72 | if self._driver != "Unknown": | 85 | if self._driver != "Unknown": |
99 | 73 | self._modinfo = self._modinfo_parser(props['Driver']) | 86 | self._modinfo = self._modinfo_parser(props['Driver']) |
100 | @@ -87,7 +100,7 @@ | |||
101 | 87 | self._state = "Unknown" | 100 | self._state = "Unknown" |
102 | 88 | 101 | ||
103 | 89 | def __str__(self): | 102 | def __str__(self): |
105 | 90 | ret = "Type: %s\n" % self._devtype | 103 | ret = "Category: %s\n" % self._devtype |
106 | 91 | ret += "Interface: %s\n" % self._interface | 104 | ret += "Interface: %s\n" % self._interface |
107 | 92 | ret += "IP: %s\n" % self._ip | 105 | ret += "IP: %s\n" % self._ip |
108 | 93 | ret += "Driver: %s (ver: %s)\n" % (self._driver, self._driver_ver) | 106 | ret += "Driver: %s (ver: %s)\n" % (self._driver, self._driver_ver) |
109 | @@ -124,7 +137,7 @@ | |||
110 | 124 | else: | 137 | else: |
111 | 125 | parser = ModinfoParser(stream) | 138 | parser = ModinfoParser(stream) |
112 | 126 | modinfo = parser.get_all() | 139 | modinfo = parser.get_all() |
114 | 127 | 140 | ||
115 | 128 | return modinfo | 141 | return modinfo |
116 | 129 | 142 | ||
117 | 130 | def _find_driver_ver(self): | 143 | def _find_driver_ver(self): |
118 | @@ -160,7 +173,8 @@ | |||
119 | 160 | nm_devices = manager.GetDevices() | 173 | nm_devices = manager.GetDevices() |
120 | 161 | for d in nm_devices: | 174 | for d in nm_devices: |
121 | 162 | dev_proxy = bus.get_object("org.freedesktop.NetworkManager", d) | 175 | dev_proxy = bus.get_object("org.freedesktop.NetworkManager", d) |
123 | 163 | prop_iface = dbus.Interface(dev_proxy,"org.freedesktop.DBus.Properties") | 176 | prop_iface = dbus.Interface(dev_proxy, |
124 | 177 | "org.freedesktop.DBus.Properties") | ||
125 | 164 | props = prop_iface.GetAll("org.freedesktop.NetworkManager.Device") | 178 | props = prop_iface.GetAll("org.freedesktop.NetworkManager.Device") |
126 | 165 | try: | 179 | try: |
127 | 166 | devtype = devtypes[props['DeviceType']] | 180 | devtype = devtypes[props['DeviceType']] |
128 | @@ -173,7 +187,7 @@ | |||
129 | 173 | return devices | 187 | return devices |
130 | 174 | 188 | ||
131 | 175 | 189 | ||
133 | 176 | def match_counts(nm_devices, pci_devices, devtype): | 190 | def match_counts(nm_devices, udev_devices, devtype): |
134 | 177 | """ | 191 | """ |
135 | 178 | Ensures that the count of devices matching devtype is the same for the | 192 | Ensures that the count of devices matching devtype is the same for the |
136 | 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. |
137 | @@ -181,41 +195,48 @@ | |||
138 | 181 | # now check that the count (by type) matches - WiFi | 195 | # now check that the count (by type) matches - WiFi |
139 | 182 | nm_type_devices = list(filter(lambda dev: dev.gettype() == devtype, | 196 | nm_type_devices = list(filter(lambda dev: dev.gettype() == devtype, |
140 | 183 | nm_devices)) | 197 | nm_devices)) |
145 | 184 | pci_type_devices = list(filter(lambda dev: dev['type'] == devtype, | 198 | udevtype = 'WIRELESS' if devtype == 'WiFi' else 'NETWORK' |
146 | 185 | pci_devices)) | 199 | udev_type_devices = list(filter(lambda dev: dev.category == udevtype, |
147 | 186 | if len(nm_type_devices) != len(pci_type_devices): | 200 | udev_devices)) |
148 | 187 | print("ERROR: %s devices missing: lspci showed %d devices, but " | 201 | if len(nm_type_devices) != len(udev_type_devices): |
149 | 202 | print("ERROR: %s devices missing: udev showed %d devices, but " | ||
150 | 188 | "NetworkManager saw %d devices" % (devtype, | 203 | "NetworkManager saw %d devices" % (devtype, |
152 | 189 | len(pci_type_devices), len(nm_type_devices))) | 204 | len(udev_type_devices), len(nm_type_devices))) |
153 | 190 | return False | 205 | return False |
154 | 191 | else: | 206 | else: |
155 | 192 | return True | 207 | return True |
156 | 193 | 208 | ||
157 | 194 | 209 | ||
158 | 195 | def main(args): | 210 | def main(args): |
182 | 196 | pci_devices = [] | 211 | try: |
183 | 197 | command = "lspci" | 212 | output = check_output(['udevadm', 'info', '--export-db']) |
184 | 198 | for line in os.popen(command).readlines(): | 213 | except CalledProcessError as err: |
185 | 199 | if "Ethernet controller: " in line: | 214 | raise SystemExit(err) |
186 | 200 | device = {} | 215 | try: |
187 | 201 | device['name'] = line.split(": ")[1].strip() | 216 | output = output.decode("UTF-8") |
188 | 202 | device['type'] = "Ethernet" | 217 | except UnicodeDecodeError as err: |
189 | 203 | pci_devices.append(device) | 218 | raise SystemExit("udevadm output is not valid UTF-8") |
190 | 204 | elif "Network controller: " in line: | 219 | udev = UdevadmParser(output) |
191 | 205 | device = {} | 220 | result = UdevResult() |
192 | 206 | device['name'] = line.split(": ")[1].strip() | 221 | udev.run(result) |
193 | 207 | device['type'] = "WiFi" | 222 | |
194 | 208 | pci_devices.append(device) | 223 | if udev_devices: |
195 | 209 | 224 | print("[ Devices found by udev ]".center(80, '-')) | |
196 | 210 | if pci_devices: | 225 | for device in udev_devices: |
197 | 211 | print("Devices found by lspci------------------------------") | 226 | for attribute in attributes: |
198 | 212 | for device in pci_devices: | 227 | value = getattr(device, attribute) |
199 | 213 | print("%s: %s" % (device['type'], device['name'])) | 228 | if value is not None: |
200 | 214 | else: | 229 | if attribute == 'driver': |
201 | 215 | print("ERROR: No Networking devices found.", file=sys.stderr) | 230 | props = {} |
202 | 216 | return 1 | 231 | props['Driver'] = value |
203 | 217 | 232 | network_dev = NetworkingDevice(None, props, None, None) | |
204 | 218 | nm_devices = [] | 233 | print("%s: %s (ver: %s)" % (attribute.capitalize(), |
205 | 234 | value, network_dev._driver_ver)) | ||
206 | 235 | else: | ||
207 | 236 | print("%s: %s" % (attribute.capitalize(), value)) | ||
208 | 237 | |||
209 | 238 | print() | ||
210 | 239 | |||
211 | 219 | try: | 240 | try: |
212 | 220 | nm_devices = get_nm_devices() | 241 | nm_devices = get_nm_devices() |
213 | 221 | except dbus.exceptions.DBusException as e: | 242 | except dbus.exceptions.DBusException as e: |
214 | @@ -226,13 +247,13 @@ | |||
215 | 226 | print("The Error Generated was:\n %s" % e, file=sys.stderr) | 247 | print("The Error Generated was:\n %s" % e, file=sys.stderr) |
216 | 227 | return 0 | 248 | return 0 |
217 | 228 | 249 | ||
219 | 229 | print("Devices found by Network Manager-------------------------") | 250 | print("[ Devices found by Network Manager ]".center(80, '-')) |
220 | 230 | for nm_dev in nm_devices: | 251 | for nm_dev in nm_devices: |
221 | 231 | print(nm_dev) | 252 | print(nm_dev) |
222 | 232 | 253 | ||
224 | 233 | if not match_counts(nm_devices, pci_devices, "WiFi"): | 254 | if not match_counts(nm_devices, udev_devices, "WiFi"): |
225 | 234 | return 1 | 255 | return 1 |
227 | 235 | elif not match_counts(nm_devices, pci_devices, "Ethernet"): | 256 | elif not match_counts(nm_devices, udev_devices, "Ethernet"): |
228 | 236 | return 1 | 257 | return 1 |
229 | 237 | else: | 258 | else: |
230 | 238 | return 0 | 259 | return 0 |
231 | 239 | 260 | ||
232 | === modified file 'scripts/udev_resource' | |||
233 | --- scripts/udev_resource 2012-11-12 10:09:25 +0000 | |||
234 | +++ scripts/udev_resource 2012-12-21 11:10:29 +0000 | |||
235 | @@ -27,7 +27,7 @@ | |||
236 | 27 | 27 | ||
237 | 28 | attributes = ("path", "bus", "category", "driver", "product_id", | 28 | attributes = ("path", "bus", "category", "driver", "product_id", |
238 | 29 | "vendor_id", "subproduct_id", "subvendor_id", "product", | 29 | "vendor_id", "subproduct_id", "subvendor_id", "product", |
240 | 30 | "vendor",) | 30 | "vendor", "interface",) |
241 | 31 | 31 | ||
242 | 32 | def addDevice(self, device): | 32 | def addDevice(self, device): |
243 | 33 | for attribute in self.attributes: | 33 | for attribute in self.attributes: |
@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