OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2013 The Chromium Authors. All rights reserved. | 3 # Copyright 2013 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 """A class to keep track of devices across builds and report state.""" | 7 """A class to keep track of devices across builds and report state.""" |
8 import json | 8 import json |
9 import logging | 9 import logging |
10 import optparse | 10 import optparse |
11 import os | 11 import os |
12 import psutil | 12 import psutil |
13 import re | 13 import re |
14 import signal | 14 import signal |
15 import smtplib | 15 import smtplib |
16 import subprocess | 16 import subprocess |
17 import sys | 17 import sys |
18 import time | 18 import time |
19 import urllib | 19 import urllib |
20 | 20 |
21 import bb_annotations | 21 import bb_annotations |
22 import bb_utils | 22 import bb_utils |
23 | 23 |
24 sys.path.append(os.path.join(os.path.dirname(__file__), | 24 sys.path.append(os.path.join(os.path.dirname(__file__), |
25 os.pardir, os.pardir, 'util', 'lib', | 25 os.pardir, os.pardir, 'util', 'lib', |
26 'common')) | 26 'common')) |
27 import perf_tests_results_helper # pylint: disable=F0401 | 27 import perf_tests_results_helper # pylint: disable=F0401 |
28 | 28 |
29 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) | 29 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) |
30 from pylib import android_commands | |
31 from pylib import constants | 30 from pylib import constants |
32 from pylib.cmd_helper import GetCmdOutput | 31 from pylib.cmd_helper import GetCmdOutput |
| 32 from pylib.device import adb_wrapper |
33 from pylib.device import battery_utils | 33 from pylib.device import battery_utils |
34 from pylib.device import device_blacklist | 34 from pylib.device import device_blacklist |
35 from pylib.device import device_errors | 35 from pylib.device import device_errors |
36 from pylib.device import device_list | 36 from pylib.device import device_list |
37 from pylib.device import device_utils | 37 from pylib.device import device_utils |
38 from pylib.utils import run_tests_helper | 38 from pylib.utils import run_tests_helper |
39 | 39 |
40 _RE_DEVICE_ID = re.compile('Device ID = (\d+)') | 40 _RE_DEVICE_ID = re.compile('Device ID = (\d+)') |
41 | 41 |
42 def DeviceInfo(serial, options): | 42 def DeviceInfo(device, options): |
43 """Gathers info on a device via various adb calls. | 43 """Gathers info on a device via various adb calls. |
44 | 44 |
45 Args: | 45 Args: |
46 serial: The serial of the attached device to construct info about. | 46 device: A DeviceUtils instance for the device to construct info about. |
47 | 47 |
48 Returns: | 48 Returns: |
49 Tuple of device type, build id, report as a string, error messages, and | 49 Tuple of device type, build id, report as a string, error messages, and |
50 boolean indicating whether or not device can be used for testing. | 50 boolean indicating whether or not device can be used for testing. |
51 """ | 51 """ |
52 device = device_utils.DeviceUtils(serial) | |
53 battery = battery_utils.BatteryUtils(device) | 52 battery = battery_utils.BatteryUtils(device) |
54 | 53 |
55 battery_info = {} | 54 build_product = '' |
| 55 build_id = '' |
56 battery_level = 100 | 56 battery_level = 100 |
57 errors = [] | 57 errors = [] |
58 dev_good = True | 58 dev_good = True |
59 json_data = { | 59 json_data = {} |
60 'serial': serial, | |
61 'type': device.build_product, | |
62 'build': device.build_id, | |
63 'build_detail': device.GetProp('ro.build.fingerprint'), | |
64 'battery': {}, | |
65 'imei_slice': 'Unknown', | |
66 'wifi_ip': device.GetProp('dhcp.wlan0.ipaddress'), | |
67 } | |
68 | 60 |
69 try: | 61 try: |
| 62 build_product = device.build_product |
| 63 build_id = device.build_id |
| 64 |
| 65 json_data = { |
| 66 'serial': device.adb.GetDeviceSerial(), |
| 67 'type': build_product, |
| 68 'build': build_id, |
| 69 'build_detail': device.GetProp('ro.build.fingerprint'), |
| 70 'battery': {}, |
| 71 'imei_slice': 'Unknown', |
| 72 'wifi_ip': device.GetProp('dhcp.wlan0.ipaddress'), |
| 73 } |
| 74 |
| 75 battery_info = {} |
70 try: | 76 try: |
71 battery_info = battery.GetBatteryInfo(timeout=5) | 77 battery_info = battery.GetBatteryInfo(timeout=5) |
72 battery_level = int(battery_info.get('level', battery_level)) | 78 battery_level = int(battery_info.get('level', battery_level)) |
73 json_data['battery'] = battery_info | 79 json_data['battery'] = battery_info |
74 except device_errors.CommandFailedError: | 80 except device_errors.CommandFailedError: |
75 logging.exception('Failed to get battery information for %s', serial) | 81 logging.exception('Failed to get battery information for %s', str(device)) |
76 | 82 |
77 try: | 83 try: |
78 for l in device.RunShellCommand(['dumpsys', 'iphonesubinfo'], | 84 for l in device.RunShellCommand(['dumpsys', 'iphonesubinfo'], |
79 check_return=True, timeout=5): | 85 check_return=True, timeout=5): |
80 m = _RE_DEVICE_ID.match(l) | 86 m = _RE_DEVICE_ID.match(l) |
81 if m: | 87 if m: |
82 json_data['imei_slice'] = m.group(1)[-6:] | 88 json_data['imei_slice'] = m.group(1)[-6:] |
83 except device_errors.CommandFailedError: | 89 except device_errors.CommandFailedError: |
84 logging.exception('Failed to get IMEI slice for %s', serial) | 90 logging.exception('Failed to get IMEI slice for %s', str(device)) |
85 | 91 |
86 if battery_level < 15: | 92 if battery_level < 15: |
87 errors += ['Device critically low in battery.'] | 93 errors += ['Device critically low in battery.'] |
88 dev_good = False | 94 dev_good = False |
89 if not battery.GetCharging(): | 95 if not battery.GetCharging(): |
90 battery.SetCharging(True) | 96 battery.SetCharging(True) |
91 if not options.no_provisioning_check: | 97 if not options.no_provisioning_check: |
92 setup_wizard_disabled = ( | 98 setup_wizard_disabled = ( |
93 device.GetProp('ro.setupwizard.mode') == 'DISABLED') | 99 device.GetProp('ro.setupwizard.mode') == 'DISABLED') |
94 if not setup_wizard_disabled and device.build_type != 'user': | 100 if not setup_wizard_disabled and device.build_type != 'user': |
95 errors += ['Setup wizard not disabled. Was it provisioned correctly?'] | 101 errors += ['Setup wizard not disabled. Was it provisioned correctly?'] |
96 if (device.product_name == 'mantaray' and | 102 if (device.product_name == 'mantaray' and |
97 battery_info.get('AC powered', None) != 'true'): | 103 battery_info.get('AC powered', None) != 'true'): |
98 errors += ['Mantaray device not connected to AC power.'] | 104 errors += ['Mantaray device not connected to AC power.'] |
99 except device_errors.CommandFailedError: | 105 except device_errors.CommandFailedError: |
100 logging.exception('Failure while getting device status.') | 106 logging.exception('Failure while getting device status.') |
101 dev_good = False | 107 dev_good = False |
102 except device_errors.CommandTimeoutError: | 108 except device_errors.CommandTimeoutError: |
103 logging.exception('Timeout while getting device status.') | 109 logging.exception('Timeout while getting device status.') |
104 dev_good = False | 110 dev_good = False |
105 | 111 |
106 return (device.build_product, device.build_id, battery_level, errors, | 112 return (build_product, build_id, battery_level, errors, dev_good, json_data) |
107 dev_good, json_data) | |
108 | 113 |
109 | 114 |
110 def CheckForMissingDevices(options, adb_online_devs): | 115 def CheckForMissingDevices(options, devices): |
111 """Uses file of previous online devices to detect broken phones. | 116 """Uses file of previous online devices to detect broken phones. |
112 | 117 |
113 Args: | 118 Args: |
114 options: out_dir parameter of options argument is used as the base | 119 options: out_dir parameter of options argument is used as the base |
115 directory to load and update the cache file. | 120 directory to load and update the cache file. |
116 adb_online_devs: A list of serial numbers of the currently visible | 121 devices: A list of DeviceUtils instance for the currently visible and |
117 and online attached devices. | 122 online attached devices. |
118 """ | 123 """ |
119 out_dir = os.path.abspath(options.out_dir) | 124 out_dir = os.path.abspath(options.out_dir) |
| 125 device_serials = set(d.adb.GetDeviceSerial() for d in devices) |
120 | 126 |
121 # last_devices denotes all known devices prior to this run | 127 # last_devices denotes all known devices prior to this run |
122 last_devices_path = os.path.join(out_dir, device_list.LAST_DEVICES_FILENAME) | 128 last_devices_path = os.path.join(out_dir, device_list.LAST_DEVICES_FILENAME) |
123 last_missing_devices_path = os.path.join(out_dir, | 129 last_missing_devices_path = os.path.join(out_dir, |
124 device_list.LAST_MISSING_DEVICES_FILENAME) | 130 device_list.LAST_MISSING_DEVICES_FILENAME) |
125 try: | 131 try: |
126 last_devices = device_list.GetPersistentDeviceList(last_devices_path) | 132 last_devices = device_list.GetPersistentDeviceList(last_devices_path) |
127 except IOError: | 133 except IOError: |
128 # Ignore error, file might not exist | 134 # Ignore error, file might not exist |
129 last_devices = [] | 135 last_devices = [] |
130 | 136 |
131 try: | 137 try: |
132 last_missing_devices = device_list.GetPersistentDeviceList( | 138 last_missing_devices = device_list.GetPersistentDeviceList( |
133 last_missing_devices_path) | 139 last_missing_devices_path) |
134 except IOError: | 140 except IOError: |
135 last_missing_devices = [] | 141 last_missing_devices = [] |
136 | 142 |
137 missing_devs = list(set(last_devices) - set(adb_online_devs)) | 143 missing_devs = list(set(last_devices) - device_serials) |
138 new_missing_devs = list(set(missing_devs) - set(last_missing_devices)) | 144 new_missing_devs = list(set(missing_devs) - set(last_missing_devices)) |
139 | 145 |
140 if new_missing_devs and os.environ.get('BUILDBOT_SLAVENAME'): | 146 if new_missing_devs and os.environ.get('BUILDBOT_SLAVENAME'): |
141 logging.info('new_missing_devs %s' % new_missing_devs) | 147 logging.info('new_missing_devs %s' % new_missing_devs) |
142 devices_missing_msg = '%d devices not detected.' % len(missing_devs) | 148 devices_missing_msg = '%d devices not detected.' % len(missing_devs) |
143 bb_annotations.PrintSummaryText(devices_missing_msg) | 149 bb_annotations.PrintSummaryText(devices_missing_msg) |
144 | 150 |
145 from_address = 'chrome-bot@chromium.org' | 151 from_address = 'chrome-bot@chromium.org' |
146 to_addresses = ['chrome-labs-tech-ticket@google.com', | 152 to_addresses = ['chrome-labs-tech-ticket@google.com', |
147 'chrome-android-device-alert@google.com'] | 153 'chrome-android-device-alert@google.com'] |
148 cc_addresses = ['chrome-android-device-alert@google.com'] | 154 cc_addresses = ['chrome-android-device-alert@google.com'] |
149 subject = 'Devices offline on %s, %s, %s' % ( | 155 subject = 'Devices offline on %s, %s, %s' % ( |
150 os.environ.get('BUILDBOT_SLAVENAME'), | 156 os.environ.get('BUILDBOT_SLAVENAME'), |
151 os.environ.get('BUILDBOT_BUILDERNAME'), | 157 os.environ.get('BUILDBOT_BUILDERNAME'), |
152 os.environ.get('BUILDBOT_BUILDNUMBER')) | 158 os.environ.get('BUILDBOT_BUILDNUMBER')) |
153 msg = ('Please reboot the following devices:\n%s' % | 159 msg = ('Please reboot the following devices:\n%s' % |
154 '\n'.join(map(str, new_missing_devs))) | 160 '\n'.join(map(str, new_missing_devs))) |
155 SendEmail(from_address, to_addresses, cc_addresses, subject, msg) | 161 SendEmail(from_address, to_addresses, cc_addresses, subject, msg) |
156 | 162 |
157 all_known_devices = list(set(adb_online_devs) | set(last_devices)) | 163 all_known_devices = list(device_serials | set(last_devices)) |
158 device_list.WritePersistentDeviceList(last_devices_path, all_known_devices) | 164 device_list.WritePersistentDeviceList(last_devices_path, all_known_devices) |
159 device_list.WritePersistentDeviceList(last_missing_devices_path, missing_devs) | 165 device_list.WritePersistentDeviceList(last_missing_devices_path, missing_devs) |
160 | 166 |
161 if not all_known_devices: | 167 if not all_known_devices: |
162 # This can happen if for some reason the .last_devices file is not | 168 # This can happen if for some reason the .last_devices file is not |
163 # present or if it was empty. | 169 # present or if it was empty. |
164 return ['No online devices. Have any devices been plugged in?'] | 170 return ['No online devices. Have any devices been plugged in?'] |
165 if missing_devs: | 171 if missing_devs: |
166 devices_missing_msg = '%d devices not detected.' % len(missing_devs) | 172 devices_missing_msg = '%d devices not detected.' % len(missing_devs) |
167 bb_annotations.PrintSummaryText(devices_missing_msg) | 173 bb_annotations.PrintSummaryText(devices_missing_msg) |
168 | 174 return ['Current online devices: %s' % ', '.join(d for d in device_serials), |
169 # TODO(navabi): Debug by printing both output from GetCmdOutput and | 175 '%s are no longer visible. Were they removed?' % missing_devs] |
170 # GetAttachedDevices to compare results. | |
171 crbug_link = ('https://code.google.com/p/chromium/issues/entry?summary=' | |
172 '%s&comment=%s&labels=Restrict-View-Google,OS-Android,Infra' % | |
173 (urllib.quote('Device Offline'), | |
174 urllib.quote('Buildbot: %s %s\n' | |
175 'Build: %s\n' | |
176 '(please don\'t change any labels)' % | |
177 (os.environ.get('BUILDBOT_BUILDERNAME'), | |
178 os.environ.get('BUILDBOT_SLAVENAME'), | |
179 os.environ.get('BUILDBOT_BUILDNUMBER'))))) | |
180 return ['Current online devices: %s' % adb_online_devs, | |
181 '%s are no longer visible. Were they removed?' % missing_devs, | |
182 'SHERIFF:', | |
183 '@@@STEP_LINK@Click here to file a bug@%s@@@' % crbug_link, | |
184 'Cache file: %s' % last_devices_path, | |
185 'adb devices: %s' % GetCmdOutput(['adb', 'devices']), | |
186 'adb devices(GetAttachedDevices): %s' % adb_online_devs] | |
187 else: | 176 else: |
188 new_devs = set(adb_online_devs) - set(last_devices) | 177 new_devs = device_serials - set(last_devices) |
189 if new_devs and os.path.exists(last_devices_path): | 178 if new_devs and os.path.exists(last_devices_path): |
190 bb_annotations.PrintWarning() | 179 bb_annotations.PrintWarning() |
191 bb_annotations.PrintSummaryText( | 180 bb_annotations.PrintSummaryText( |
192 '%d new devices detected' % len(new_devs)) | 181 '%d new devices detected' % len(new_devs)) |
193 logging.info('New devices detected:') | 182 logging.info('New devices detected:') |
194 for d in new_devs: | 183 for d in new_devs: |
195 logging.info(' %s', d) | 184 logging.info(' %s', d) |
196 | 185 |
197 | 186 |
198 def SendEmail(from_address, to_addresses, cc_addresses, subject, msg): | 187 def SendEmail(from_address, to_addresses, cc_addresses, subject, msg): |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 run_tests_helper.SetLogLevel(options.verbose) | 279 run_tests_helper.SetLogLevel(options.verbose) |
291 | 280 |
292 # Remove the last build's "bad devices" before checking device statuses. | 281 # Remove the last build's "bad devices" before checking device statuses. |
293 device_blacklist.ResetBlacklist() | 282 device_blacklist.ResetBlacklist() |
294 | 283 |
295 try: | 284 try: |
296 expected_devices = device_list.GetPersistentDeviceList( | 285 expected_devices = device_list.GetPersistentDeviceList( |
297 os.path.join(options.out_dir, device_list.LAST_DEVICES_FILENAME)) | 286 os.path.join(options.out_dir, device_list.LAST_DEVICES_FILENAME)) |
298 except IOError: | 287 except IOError: |
299 expected_devices = [] | 288 expected_devices = [] |
300 devices = android_commands.GetAttachedDevices() | 289 devices = device_utils.DeviceUtils.HealthyDevices() |
| 290 device_serials = [d.adb.GetDeviceSerial() for d in devices] |
301 # Only restart usb if devices are missing. | 291 # Only restart usb if devices are missing. |
302 if set(expected_devices) != set(devices): | 292 if set(expected_devices) != set(device_serials): |
303 logging.warning('expected_devices: %s', expected_devices) | 293 logging.warning('expected_devices: %s', expected_devices) |
304 logging.warning('devices: %s', devices) | 294 logging.warning('devices: %s', device_serials) |
305 KillAllAdb() | 295 KillAllAdb() |
306 retries = 5 | 296 retries = 5 |
307 usb_restarted = True | 297 usb_restarted = True |
308 if options.restart_usb: | 298 if options.restart_usb: |
309 if not RestartUsb(): | 299 if not RestartUsb(): |
310 usb_restarted = False | 300 usb_restarted = False |
311 bb_annotations.PrintWarning() | 301 bb_annotations.PrintWarning() |
312 logging.error('USB reset stage failed, ' | 302 logging.error('USB reset stage failed, ' |
313 'wait for any device to come back.') | 303 'wait for any device to come back.') |
314 while retries: | 304 while retries: |
315 logging.info('retry adb devices...') | 305 logging.info('retry adb devices...') |
316 time.sleep(1) | 306 time.sleep(1) |
317 devices = android_commands.GetAttachedDevices() | 307 devices = device_utils.DeviceUtils.HealthyDevices() |
318 if set(expected_devices) == set(devices): | 308 device_serials = [d.adb.GetDeviceSerial() for d in devices] |
| 309 if set(expected_devices) == set(device_serials): |
319 # All devices are online, keep going. | 310 # All devices are online, keep going. |
320 break | 311 break |
321 if not usb_restarted and devices: | 312 if not usb_restarted and devices: |
322 # The USB wasn't restarted, but there's at least one device online. | 313 # The USB wasn't restarted, but there's at least one device online. |
323 # No point in trying to wait for all devices. | 314 # No point in trying to wait for all devices. |
324 break | 315 break |
325 retries -= 1 | 316 retries -= 1 |
326 | 317 |
327 # TODO(navabi): Test to make sure this fails and then fix call | |
328 offline_devices = android_commands.GetAttachedDevices( | |
329 hardware=False, emulator=False, offline=True) | |
330 | |
331 types, builds, batteries, errors, devices_ok, json_data = ( | 318 types, builds, batteries, errors, devices_ok, json_data = ( |
332 [], [], [], [], [], []) | 319 [], [], [], [], [], []) |
333 if devices: | 320 if devices: |
334 types, builds, batteries, errors, devices_ok, json_data = ( | 321 types, builds, batteries, errors, devices_ok, json_data = ( |
335 zip(*[DeviceInfo(dev, options) for dev in devices])) | 322 zip(*[DeviceInfo(dev, options) for dev in devices])) |
336 | 323 |
337 # Write device info to file for buildbot info display. | 324 # Write device info to file for buildbot info display. |
338 if os.path.exists('/home/chrome-bot'): | 325 if os.path.exists('/home/chrome-bot'): |
339 with open('/home/chrome-bot/.adb_device_info', 'w') as f: | 326 with open('/home/chrome-bot/.adb_device_info', 'w') as f: |
340 for device in json_data: | 327 for device in json_data: |
(...skipping 15 matching lines...) Expand all Loading... |
356 for j in json_data: | 343 for j in json_data: |
357 logging.info('Device %s (%s)', j.get('serial'), j.get('type')) | 344 logging.info('Device %s (%s)', j.get('serial'), j.get('type')) |
358 logging.info(' Build: %s (%s)', j.get('build'), j.get('build_detail')) | 345 logging.info(' Build: %s (%s)', j.get('build'), j.get('build_detail')) |
359 logging.info(' Current Battery Service state:') | 346 logging.info(' Current Battery Service state:') |
360 for k, v in j.get('battery', {}).iteritems(): | 347 for k, v in j.get('battery', {}).iteritems(): |
361 logging.info(' %s: %s', k, v) | 348 logging.info(' %s: %s', k, v) |
362 logging.info(' IMEI slice: %s', j.get('imei_slice')) | 349 logging.info(' IMEI slice: %s', j.get('imei_slice')) |
363 logging.info(' WiFi IP: %s', j.get('wifi_ip')) | 350 logging.info(' WiFi IP: %s', j.get('wifi_ip')) |
364 | 351 |
365 | 352 |
366 for serial, dev_errors in zip(devices, errors): | 353 for dev, dev_errors in zip(devices, errors): |
367 if dev_errors: | 354 if dev_errors: |
368 err_msg += ['%s errors:' % serial] | 355 err_msg += ['%s errors:' % str(dev)] |
369 err_msg += [' %s' % error for error in dev_errors] | 356 err_msg += [' %s' % error for error in dev_errors] |
370 | 357 |
371 if err_msg: | 358 if err_msg: |
372 bb_annotations.PrintWarning() | 359 bb_annotations.PrintWarning() |
373 for e in err_msg: | 360 for e in err_msg: |
374 logging.error(e) | 361 logging.error(e) |
375 from_address = 'buildbot@chromium.org' | 362 from_address = 'buildbot@chromium.org' |
376 to_addresses = ['chromium-android-device-alerts@google.com'] | 363 to_addresses = ['chromium-android-device-alerts@google.com'] |
377 bot_name = os.environ.get('BUILDBOT_BUILDERNAME') | 364 bot_name = os.environ.get('BUILDBOT_BUILDERNAME') |
378 slave_name = os.environ.get('BUILDBOT_SLAVENAME') | 365 slave_name = os.environ.get('BUILDBOT_SLAVENAME') |
379 subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name) | 366 subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name) |
380 SendEmail(from_address, to_addresses, [], subject, '\n'.join(err_msg)) | 367 SendEmail(from_address, to_addresses, [], subject, '\n'.join(err_msg)) |
381 | 368 |
382 if options.device_status_dashboard: | 369 if options.device_status_dashboard: |
| 370 offline_devices = [ |
| 371 device_utils.DeviceUtils(a) |
| 372 for a in adb_wrapper.AdbWrapper.Devices(is_ready=False) |
| 373 if a.GetState() == 'offline'] |
| 374 |
383 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OnlineDevices', | 375 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OnlineDevices', |
384 [len(devices)], 'devices') | 376 [len(devices)], 'devices') |
385 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OfflineDevices', | 377 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OfflineDevices', |
386 [len(offline_devices)], 'devices', | 378 [len(offline_devices)], 'devices', |
387 'unimportant') | 379 'unimportant') |
388 for serial, battery in zip(devices, batteries): | 380 for dev, battery in zip(devices, batteries): |
389 perf_tests_results_helper.PrintPerfResult('DeviceBattery', serial, | 381 perf_tests_results_helper.PrintPerfResult('DeviceBattery', str(dev), |
390 [battery], '%', | 382 [battery], '%', |
391 'unimportant') | 383 'unimportant') |
392 | 384 |
393 if options.json_output: | 385 if options.json_output: |
394 with open(options.json_output, 'wb') as f: | 386 with open(options.json_output, 'wb') as f: |
395 f.write(json.dumps(json_data, indent=4)) | 387 f.write(json.dumps(json_data, indent=4)) |
396 | 388 |
397 num_failed_devs = 0 | 389 num_failed_devs = 0 |
398 for device_ok, device in zip(devices_ok, devices): | 390 for device_ok, device in zip(devices_ok, devices): |
399 if not device_ok: | 391 if not device_ok: |
400 logging.warning('Blacklisting %s', str(device)) | 392 logging.warning('Blacklisting %s', str(device)) |
401 device_blacklist.ExtendBlacklist([str(device)]) | 393 device_blacklist.ExtendBlacklist([str(device)]) |
402 num_failed_devs += 1 | 394 num_failed_devs += 1 |
403 | 395 |
404 if num_failed_devs == len(devices): | 396 if num_failed_devs == len(devices): |
405 return 2 | 397 return 2 |
406 | 398 |
407 if not devices: | 399 if not devices: |
408 return 1 | 400 return 1 |
409 | 401 |
410 | 402 |
411 if __name__ == '__main__': | 403 if __name__ == '__main__': |
412 sys.exit(main()) | 404 sys.exit(main()) |
OLD | NEW |