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