Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 1 | # Copyright 2016 The Chromium OS Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
| 5 | """This class defines the CrosHost Label class.""" |
| 6 | |
C Shapiro | 05dd322 | 2017-09-22 10:42:33 -0600 | [diff] [blame] | 7 | import collections |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 8 | import logging |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 9 | import re |
| 10 | |
| 11 | import common |
| 12 | |
| 13 | from autotest_lib.client.bin import utils |
Kevin Cheng | 80ad573 | 2016-03-31 16:01:56 -0700 | [diff] [blame] | 14 | from autotest_lib.client.common_lib import global_config |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 15 | from autotest_lib.client.cros.audio import cras_utils |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 16 | from autotest_lib.server.cros.dynamic_suite import constants as ds_constants |
| 17 | from autotest_lib.server.hosts import base_label |
| 18 | from autotest_lib.server.hosts import common_label |
Garry Wang | 11b5e87 | 2020-03-11 15:14:08 -0700 | [diff] [blame] | 19 | from autotest_lib.server.hosts import servo_constants |
Kevin Cheng | 80ad573 | 2016-03-31 16:01:56 -0700 | [diff] [blame] | 20 | from autotest_lib.site_utils import hwid_lib |
Otabek Kasimov | 40ccb97 | 2020-05-26 15:14:39 -0700 | [diff] [blame^] | 21 | from autotest_lib.site_utils.admin_audit import verifiers as audit_verify |
| 22 | from autotest_lib.site_utils.admin_audit import constants as audit_const |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 23 | |
| 24 | # pylint: disable=missing-docstring |
C Shapiro | 05dd322 | 2017-09-22 10:42:33 -0600 | [diff] [blame] | 25 | LsbOutput = collections.namedtuple('LsbOutput', ['unibuild', 'board']) |
| 26 | |
Gregory Nisbet | fb68a1f | 2019-08-22 10:27:33 -0700 | [diff] [blame] | 27 | # fallback values if we can't contact the HWID server |
| 28 | HWID_LABELS_FALLBACK = ['sku', 'phase', 'touchscreen', 'touchpad', 'variant', 'stylus'] |
| 29 | |
Eshwar Narayan | 871a2c0 | 2020-02-06 11:15:24 -0800 | [diff] [blame] | 30 | # Repair and Deploy taskName |
| 31 | REPAIR_TASK_NAME = 'repair' |
| 32 | DEPLOY_TASK_NAME = 'deploy' |
| 33 | |
Gregory Nisbet | fb68a1f | 2019-08-22 10:27:33 -0700 | [diff] [blame] | 34 | |
C Shapiro | 05dd322 | 2017-09-22 10:42:33 -0600 | [diff] [blame] | 35 | def _parse_lsb_output(host): |
Allen Li | a0c7afc | 2019-02-26 15:50:06 -0800 | [diff] [blame] | 36 | """Parses the LSB output and returns key data points for labeling. |
C Shapiro | 05dd322 | 2017-09-22 10:42:33 -0600 | [diff] [blame] | 37 | |
Allen Li | a0c7afc | 2019-02-26 15:50:06 -0800 | [diff] [blame] | 38 | @param host: Host that the command will be executed against |
| 39 | @returns: LsbOutput with the result of parsing the /etc/lsb-release output |
| 40 | """ |
| 41 | release_info = utils.parse_cmd_output('cat /etc/lsb-release', |
| 42 | run_method=host.run) |
C Shapiro | 05dd322 | 2017-09-22 10:42:33 -0600 | [diff] [blame] | 43 | |
Allen Li | a0c7afc | 2019-02-26 15:50:06 -0800 | [diff] [blame] | 44 | unibuild = release_info.get('CHROMEOS_RELEASE_UNIBUILD') == '1' |
| 45 | return LsbOutput(unibuild, release_info['CHROMEOS_RELEASE_BOARD']) |
C Shapiro | 05dd322 | 2017-09-22 10:42:33 -0600 | [diff] [blame] | 46 | |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 47 | |
C Shapiro | be0ff8d | 2019-06-14 10:41:43 -0600 | [diff] [blame] | 48 | class DeviceSkuLabel(base_label.StringPrefixLabel): |
| 49 | """Determine the correct device_sku label for the device.""" |
| 50 | |
| 51 | _NAME = ds_constants.DEVICE_SKU_LABEL |
| 52 | |
| 53 | def generate_labels(self, host): |
| 54 | device_sku = host.host_info_store.get().device_sku |
| 55 | if device_sku: |
| 56 | return [device_sku] |
| 57 | |
| 58 | mosys_cmd = 'mosys platform sku' |
| 59 | result = host.run(command=mosys_cmd, ignore_status=True) |
| 60 | if result.exit_status == 0: |
| 61 | return [result.stdout.strip()] |
| 62 | |
| 63 | return [] |
| 64 | |
Eshwar Narayan | 871a2c0 | 2020-02-06 11:15:24 -0800 | [diff] [blame] | 65 | def update_for_task(self, task_name): |
| 66 | # This label is stored in the lab config, so only deploy tasks update it |
| 67 | # or when no task name is mentioned. |
| 68 | return task_name in (DEPLOY_TASK_NAME, '') |
| 69 | |
C Shapiro | be0ff8d | 2019-06-14 10:41:43 -0600 | [diff] [blame] | 70 | |
Ned Nguyen | e0a619d | 2019-07-01 15:50:23 -0600 | [diff] [blame] | 71 | class BrandCodeLabel(base_label.StringPrefixLabel): |
| 72 | """Determine the correct brand_code (aka RLZ-code) for the device.""" |
| 73 | |
| 74 | _NAME = ds_constants.BRAND_CODE_LABEL |
| 75 | |
| 76 | def generate_labels(self, host): |
| 77 | brand_code = host.host_info_store.get().brand_code |
| 78 | if brand_code: |
| 79 | return [brand_code] |
| 80 | |
Greg Edelston | 7cea0c4 | 2019-11-26 15:17:22 -0700 | [diff] [blame] | 81 | cros_config_cmd = 'cros_config / brand-code' |
| 82 | result = host.run(command=cros_config_cmd, ignore_status=True) |
Ned Nguyen | e0a619d | 2019-07-01 15:50:23 -0600 | [diff] [blame] | 83 | if result.exit_status == 0: |
| 84 | return [result.stdout.strip()] |
| 85 | |
| 86 | return [] |
| 87 | |
| 88 | |
Shijin Abraham | c09587d | 2020-02-14 20:46:55 -0800 | [diff] [blame] | 89 | class BluetoothPeerLabel(base_label.StringPrefixLabel): |
| 90 | """Return the Bluetooth peer labels. |
| 91 | |
| 92 | working_bluetooth_btpeer label is applied if a Raspberry Pi Bluetooth peer |
| 93 | is detected.There can be up to 4 Bluetooth peers. Labels |
| 94 | working_bluetooth_btpeer:[1-4] will be assigned depending on the number of |
| 95 | peers present. |
| 96 | |
| 97 | """ |
| 98 | |
| 99 | _NAME = 'working_bluetooth_btpeer' |
| 100 | |
| 101 | def exists(self, host): |
| 102 | return len(host._btpeer_host_list) > 0 |
| 103 | |
| 104 | def generate_labels(self, host): |
| 105 | labels_list = [] |
| 106 | count = 1 |
| 107 | |
| 108 | for (btpeer, btpeer_host) in \ |
| 109 | zip(host.btpeer_list, host._btpeer_host_list): |
| 110 | try: |
| 111 | # Initialize one device type to make sure the peer is working |
| 112 | bt_hid_device = btpeer.get_bluetooth_hid_mouse() |
| 113 | if bt_hid_device.CheckSerialConnection(): |
| 114 | labels_list.append(str(count)) |
| 115 | count += 1 |
| 116 | except Exception as e: |
| 117 | logging.error('Error with initializing bt_hid_mouse on ' |
| 118 | 'btpeer %s %s', btpeer_host.hostname, e) |
| 119 | |
| 120 | logging.info('Bluetooth Peer labels are %s', labels_list) |
| 121 | return labels_list |
| 122 | |
| 123 | def update_for_task(self, task_name): |
Shijin Abraham | 76bc1db | 2020-03-06 10:52:10 -0800 | [diff] [blame] | 124 | # This label is stored in the state config, so only repair tasks update |
| 125 | # it or when no task name is mentioned. |
| 126 | return task_name in (REPAIR_TASK_NAME, '') |
Shijin Abraham | c09587d | 2020-02-14 20:46:55 -0800 | [diff] [blame] | 127 | |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 128 | |
Mary Ruthven | 935ebad | 2018-06-13 16:13:20 -0700 | [diff] [blame] | 129 | class Cr50Label(base_label.StringPrefixLabel): |
Mary Ruthven | 6c46264 | 2019-09-17 19:13:36 -0700 | [diff] [blame] | 130 | """Label indicating the cr50 image type.""" |
Mary Ruthven | 935ebad | 2018-06-13 16:13:20 -0700 | [diff] [blame] | 131 | |
| 132 | _NAME = 'cr50' |
| 133 | |
| 134 | def __init__(self): |
| 135 | self.ver = None |
| 136 | |
Mary Ruthven | 935ebad | 2018-06-13 16:13:20 -0700 | [diff] [blame] | 137 | def exists(self, host): |
| 138 | # Make sure the gsctool version command runs ok |
| 139 | self.ver = host.run('gsctool -a -f', ignore_status=True) |
| 140 | return self.ver.exit_status == 0 |
| 141 | |
Mary Ruthven | 6c46264 | 2019-09-17 19:13:36 -0700 | [diff] [blame] | 142 | def _get_version(self, region): |
| 143 | """Get the version number of the given region""" |
| 144 | return re.search(region + ' (\d+\.\d+\.\d+)', self.ver.stdout).group(1) |
Mary Ruthven | 935ebad | 2018-06-13 16:13:20 -0700 | [diff] [blame] | 145 | |
| 146 | def generate_labels(self, host): |
| 147 | # Check the major version to determine prePVT vs PVT |
Mary Ruthven | 6c46264 | 2019-09-17 19:13:36 -0700 | [diff] [blame] | 148 | version = self._get_version('RW') |
| 149 | major_version = int(version.split('.')[1]) |
Mary Ruthven | 935ebad | 2018-06-13 16:13:20 -0700 | [diff] [blame] | 150 | # PVT images have a odd major version prePVT have even |
Mary Ruthven | 6c46264 | 2019-09-17 19:13:36 -0700 | [diff] [blame] | 151 | return ['pvt' if (major_version % 2) else 'prepvt'] |
| 152 | |
Xixuan Wu | 61b2b26 | 2020-03-06 10:09:55 -0800 | [diff] [blame] | 153 | def update_for_task(self, task_name): |
| 154 | # This label is stored in the state config, so only repair tasks update |
| 155 | # it or when no task name is mentioned. |
| 156 | return task_name in (REPAIR_TASK_NAME, '') |
| 157 | |
Mary Ruthven | 6c46264 | 2019-09-17 19:13:36 -0700 | [diff] [blame] | 158 | |
| 159 | class Cr50RWKeyidLabel(Cr50Label): |
| 160 | """Label indicating the cr50 RW version.""" |
| 161 | _REGION = 'RW' |
| 162 | _NAME = 'cr50-rw-keyid' |
| 163 | |
| 164 | def _get_keyid_info(self, region): |
| 165 | """Get the keyid of the given region.""" |
| 166 | match = re.search('keyids:.*%s (\S+)' % region, self.ver.stdout) |
| 167 | keyid = match.group(1).rstrip(',') |
| 168 | is_prod = int(keyid, 16) & (1 << 2) |
| 169 | return [keyid, 'prod' if is_prod else 'dev'] |
| 170 | |
| 171 | def generate_labels(self, host): |
| 172 | """Get the key type.""" |
| 173 | return self._get_keyid_info(self._REGION) |
| 174 | |
| 175 | |
| 176 | class Cr50ROKeyidLabel(Cr50RWKeyidLabel): |
| 177 | """Label indicating the RO key type.""" |
| 178 | _REGION = 'RO' |
| 179 | _NAME = 'cr50-ro-keyid' |
| 180 | |
| 181 | |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 182 | class ChameleonLabel(base_label.BaseLabel): |
| 183 | """Determine if a Chameleon is connected to this host.""" |
| 184 | |
| 185 | _NAME = 'chameleon' |
| 186 | |
| 187 | def exists(self, host): |
Xixuan Wu | 7afb54f | 2019-09-17 11:45:20 -0700 | [diff] [blame] | 188 | # See crbug.com/1004500#2 for details. |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 189 | has_chameleon = host._chameleon_host is not None |
Gregory Nisbet | b2f6d79 | 2019-09-11 14:30:47 -0700 | [diff] [blame] | 190 | # TODO(crbug.com/995900) -- debug why chameleon label is flipping |
| 191 | try: |
| 192 | logging.info("has_chameleon %s", has_chameleon) |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 193 | logging.info("_chameleon_host %s", |
| 194 | getattr(host, "_chameleon_host", "NO_ATTRIBUTE")) |
| 195 | logging.info("chameleon %s", |
| 196 | getattr(host, "chameleon", "NO_ATTRIBUTE")) |
Gregory Nisbet | b2f6d79 | 2019-09-11 14:30:47 -0700 | [diff] [blame] | 197 | except: |
| 198 | pass |
| 199 | return has_chameleon |
| 200 | |
Eshwar Narayan | 871a2c0 | 2020-02-06 11:15:24 -0800 | [diff] [blame] | 201 | def update_for_task(self, task_name): |
| 202 | # This label is stored in the state config, so only repair tasks update |
| 203 | # it or when no task name is mentioned. |
| 204 | return task_name in (REPAIR_TASK_NAME, '') |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 205 | |
| 206 | |
| 207 | class ChameleonConnectionLabel(base_label.StringPrefixLabel): |
| 208 | """Return the Chameleon connection label.""" |
| 209 | |
| 210 | _NAME = 'chameleon' |
| 211 | |
| 212 | def exists(self, host): |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 213 | return host._chameleon_host is not None |
Joseph Hwang | eac4431 | 2016-08-31 12:08:38 +0800 | [diff] [blame] | 214 | |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 215 | def generate_labels(self, host): |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 216 | return [host.chameleon.get_label()] |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 217 | |
Eshwar Narayan | 871a2c0 | 2020-02-06 11:15:24 -0800 | [diff] [blame] | 218 | def update_for_task(self, task_name): |
| 219 | # This label is stored in the lab config, so only deploy tasks update it |
| 220 | # or when no task name is mentioned. |
| 221 | return task_name in (DEPLOY_TASK_NAME, '') |
| 222 | |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 223 | |
Joseph Hwang | eac4431 | 2016-08-31 12:08:38 +0800 | [diff] [blame] | 224 | class ChameleonPeripheralsLabel(base_label.StringPrefixLabel): |
| 225 | """Return the Chameleon peripherals labels. |
| 226 | |
| 227 | The 'chameleon:bt_hid' label is applied if the bluetooth |
| 228 | classic hid device, i.e, RN-42 emulation kit, is detected. |
| 229 | |
| 230 | Any peripherals plugged into the chameleon board would be |
| 231 | detected and applied proper labels in this class. |
| 232 | """ |
| 233 | |
| 234 | _NAME = 'chameleon' |
| 235 | |
| 236 | def exists(self, host): |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 237 | return host._chameleon_host is not None |
Joseph Hwang | eac4431 | 2016-08-31 12:08:38 +0800 | [diff] [blame] | 238 | |
| 239 | def generate_labels(self, host): |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 240 | labels = [] |
| 241 | try: |
| 242 | bt_hid_device = host.chameleon.get_bluetooth_hid_mouse() |
| 243 | if bt_hid_device.CheckSerialConnection(): |
| 244 | labels.append('bt_hid') |
| 245 | except: |
| 246 | logging.error('Error with initializing bt_hid_mouse') |
howardchung | 83e5527 | 2019-08-08 14:08:05 +0800 | [diff] [blame] | 247 | |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 248 | try: |
| 249 | ble_hid_device = host.chameleon.get_ble_mouse() |
| 250 | if ble_hid_device.CheckSerialConnection(): |
| 251 | labels.append('bt_ble_hid') |
| 252 | except: |
| 253 | logging.error('Error with initializing ble_hid_mouse') |
howardchung | 83e5527 | 2019-08-08 14:08:05 +0800 | [diff] [blame] | 254 | |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 255 | try: |
| 256 | bt_a2dp_sink = host.chameleon.get_bluetooth_a2dp_sink() |
| 257 | if bt_a2dp_sink.CheckSerialConnection(): |
| 258 | labels.append('bt_a2dp_sink') |
| 259 | except: |
| 260 | logging.error('Error with initializing bt_a2dp_sink') |
howardchung | 83e5527 | 2019-08-08 14:08:05 +0800 | [diff] [blame] | 261 | |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 262 | try: |
Joseph Hwang | 94044ea | 2020-01-03 14:47:43 +0800 | [diff] [blame] | 263 | bt_audio_device = host.chameleon.get_bluetooth_audio() |
| 264 | if bt_audio_device.IsDetected(): |
| 265 | labels.append('bt_audio') |
| 266 | except: |
| 267 | logging.error('Error in detecting bt_audio') |
| 268 | |
| 269 | try: |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 270 | bt_base_device = host.chameleon.get_bluetooth_base() |
| 271 | if bt_base_device.IsDetected(): |
| 272 | labels.append('bt_base') |
| 273 | except: |
| 274 | logging.error('Error in detecting bt_base') |
howardchung | 83e5527 | 2019-08-08 14:08:05 +0800 | [diff] [blame] | 275 | |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 276 | if labels != []: |
| 277 | labels.append('bt_peer') |
Joseph Hwang | 89e779c | 2019-12-24 16:05:56 +0800 | [diff] [blame] | 278 | |
Shijin Abraham | 783a7dd | 2020-02-14 15:36:11 -0800 | [diff] [blame] | 279 | logging.info('Chameleon Bluetooth labels are %s', labels) |
| 280 | return labels |
Shijin Abraham | ff61ac3 | 2019-05-20 12:35:44 -0700 | [diff] [blame] | 281 | |
Eshwar Narayan | 871a2c0 | 2020-02-06 11:15:24 -0800 | [diff] [blame] | 282 | def update_for_task(self, task_name): |
| 283 | # This label is stored in the lab config, so only deploy tasks update it |
| 284 | # or when no task name is mentioned. |
| 285 | return task_name in (DEPLOY_TASK_NAME, '') |
Joseph Hwang | eac4431 | 2016-08-31 12:08:38 +0800 | [diff] [blame] | 286 | |
| 287 | |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 288 | class AudioLoopbackDongleLabel(base_label.BaseLabel): |
| 289 | """Return the label if an audio loopback dongle is plugged in.""" |
| 290 | |
| 291 | _NAME = 'audio_loopback_dongle' |
| 292 | |
| 293 | def exists(self, host): |
Gregory Nisbet | e280ea2 | 2019-08-16 17:50:03 -0700 | [diff] [blame] | 294 | # Based on crbug.com/991285, AudioLoopbackDongle sometimes flips. |
| 295 | # Ensure that AudioLoopbackDongle.exists returns True |
| 296 | # forever, after it returns True *once*. |
| 297 | if self._cached_exists(host): |
| 298 | # If the current state is True, return it, don't run the command on |
| 299 | # the DUT and potentially flip the state. |
| 300 | return True |
| 301 | # If the current state is not True, run the command on |
| 302 | # the DUT. The new state will be set to whatever the command |
| 303 | # produces. |
| 304 | return self._host_run_exists(host) |
| 305 | |
| 306 | def _cached_exists(self, host): |
| 307 | """Get the state of AudioLoopbackDongle in the data store""" |
| 308 | info = host.host_info_store.get() |
| 309 | for label in info.labels: |
| 310 | if label.startswith(self._NAME): |
| 311 | return True |
| 312 | return False |
| 313 | |
| 314 | def _host_run_exists(self, host): |
| 315 | """Detect presence of audio_loopback_dongle by physically |
| 316 | running a command on the DUT.""" |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 317 | nodes_info = host.run(command=cras_utils.get_cras_nodes_cmd(), |
| 318 | ignore_status=True).stdout |
| 319 | if (cras_utils.node_type_is_plugged('HEADPHONE', nodes_info) and |
| 320 | cras_utils.node_type_is_plugged('MIC', nodes_info)): |
Otabek Kasimov | cefc0d1 | 2020-02-07 17:13:52 -0800 | [diff] [blame] | 321 | return True |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 322 | return False |
| 323 | |
Eshwar Narayan | 871a2c0 | 2020-02-06 11:15:24 -0800 | [diff] [blame] | 324 | def update_for_task(self, task_name): |
| 325 | # This label is stored in the state config, so only repair tasks update |
| 326 | # it or when no task name is mentioned. |
| 327 | return task_name in (REPAIR_TASK_NAME, '') |
| 328 | |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 329 | |
Otabek Kasimov | 4318591 | 2020-03-11 16:01:52 -0700 | [diff] [blame] | 330 | class ServoTypeLabel(base_label.StringPrefixLabel): |
Otabek Kasimov | e756528 | 2020-04-14 13:26:12 -0700 | [diff] [blame] | 331 | _NAME = servo_constants.SERVO_TYPE_LABEL_PREFIX |
Otabek Kasimov | 4318591 | 2020-03-11 16:01:52 -0700 | [diff] [blame] | 332 | |
| 333 | def generate_labels(self, host): |
| 334 | info = host.host_info_store.get() |
| 335 | |
| 336 | servo_type = self._get_from_labels(info) |
| 337 | if servo_type != '': |
Otabek Kasimov | 1b67c00 | 2020-04-15 13:27:38 -0700 | [diff] [blame] | 338 | logging.info("Using servo_type: %s from cache!", servo_type) |
Otabek Kasimov | 4318591 | 2020-03-11 16:01:52 -0700 | [diff] [blame] | 339 | return [servo_type] |
| 340 | |
| 341 | if host.servo is not None: |
| 342 | try: |
| 343 | servo_type = host.servo.get_servo_version() |
| 344 | if servo_type != '': |
| 345 | return [servo_type] |
Otabek Kasimov | 1b67c00 | 2020-04-15 13:27:38 -0700 | [diff] [blame] | 346 | logging.warning('Cannot collect servo_type from servo' |
| 347 | ' by `dut-control servo_type`! Please file a bug' |
| 348 | ' and inform infra team as we are not expected ' |
| 349 | ' to reach this point.') |
Otabek Kasimov | 4318591 | 2020-03-11 16:01:52 -0700 | [diff] [blame] | 350 | except Exception as e: |
| 351 | # We don't want fail the label and break DUTs here just |
| 352 | # because of servo issue. |
| 353 | logging.error("Failed to update servo_type, %s", str(e)) |
| 354 | return [] |
| 355 | |
| 356 | def _get_from_labels(self, info): |
| 357 | prefix = self._NAME + ':' |
| 358 | for label in info.labels: |
| 359 | if label.startswith(prefix): |
| 360 | suffix_length = len(prefix) |
| 361 | return label[suffix_length:] |
| 362 | return '' |
| 363 | |
| 364 | def update_for_task(self, task_name): |
| 365 | # This label is stored in the lab config, |
| 366 | # only deploy and repair tasks update it |
| 367 | # or when no task name is mentioned. |
Otabek Kasimov | e7908f5 | 2020-05-05 18:13:33 -0700 | [diff] [blame] | 368 | return task_name in (DEPLOY_TASK_NAME, '') |
Otabek Kasimov | 4318591 | 2020-03-11 16:01:52 -0700 | [diff] [blame] | 369 | |
| 370 | |
Xixuan Wu | 78569d0 | 2019-09-15 16:08:25 -0700 | [diff] [blame] | 371 | def _parse_hwid_labels(hwid_info_list): |
| 372 | if len(hwid_info_list) == 0: |
| 373 | return hwid_info_list |
| 374 | |
| 375 | res = [] |
| 376 | # See crbug.com/997816#c7 for details of two potential formats of returns |
| 377 | # from HWID server. |
| 378 | if isinstance(hwid_info_list[0], dict): |
| 379 | # Format of hwid_info: |
| 380 | # [{u'name': u'sku', u'value': u'xxx'}, ..., ] |
| 381 | for hwid_info in hwid_info_list: |
| 382 | value = hwid_info.get('value', '') |
| 383 | name = hwid_info.get('name', '') |
| 384 | # There should always be a name but just in case there is not. |
| 385 | if name: |
| 386 | new_label = name if not value else '%s:%s' % (name, value) |
| 387 | res.append(new_label) |
| 388 | else: |
| 389 | # Format of hwid_info: |
| 390 | # [<DUTLabel name: 'sku' value: u'xxx'>, ..., ] |
| 391 | for hwid_info in hwid_info_list: |
| 392 | new_label = str(hwid_info) |
| 393 | logging.info('processing hwid label: %s', new_label) |
| 394 | res.append(new_label) |
| 395 | |
| 396 | return res |
| 397 | |
| 398 | |
Kevin Cheng | 80ad573 | 2016-03-31 16:01:56 -0700 | [diff] [blame] | 399 | class HWIDLabel(base_label.StringLabel): |
| 400 | """Return all the labels generated from the hwid.""" |
| 401 | |
| 402 | # We leave out _NAME because hwid_lib will generate everything for us. |
| 403 | |
| 404 | def __init__(self): |
| 405 | # Grab the key file needed to access the hwid service. |
| 406 | self.key_file = global_config.global_config.get_config_value( |
| 407 | 'CROS', 'HWID_KEY', type=str) |
| 408 | |
| 409 | |
Gregory Nisbet | fb68a1f | 2019-08-22 10:27:33 -0700 | [diff] [blame] | 410 | @staticmethod |
| 411 | def _merge_hwid_label_lists(new, old): |
| 412 | """merge a list of old and new values for hwid_labels. |
| 413 | preferring new values if available |
| 414 | |
| 415 | @returns: list of labels""" |
| 416 | # TODO(gregorynisbet): what is the appropriate way to merge |
| 417 | # old and new information? |
| 418 | retained = set(x for x in old) |
| 419 | for label in new: |
| 420 | key, sep, value = label.partition(':') |
| 421 | # If we have a key-value key such as variant:aaa, |
| 422 | # then we remove all the old labels with the same key. |
| 423 | if sep: |
| 424 | retained = set(x for x in retained if (not x.startswith(key + ':'))) |
| 425 | return list(sorted(retained.union(new))) |
| 426 | |
| 427 | |
| 428 | def _hwid_label_names(self): |
| 429 | """get the labels that hwid_lib controls. |
| 430 | |
| 431 | @returns: hwid_labels |
| 432 | """ |
| 433 | all_hwid_labels, _ = self.get_all_labels() |
| 434 | # If and only if get_all_labels was unsuccessful, |
| 435 | # it will return a falsey value. |
Gregory Nisbet | bfd120f | 2019-09-04 14:49:46 -0700 | [diff] [blame] | 436 | out = all_hwid_labels or HWID_LABELS_FALLBACK |
| 437 | |
| 438 | # TODO(gregorynisbet): remove this |
| 439 | # TODO(crbug.com/999785) |
| 440 | if "sku" not in out: |
| 441 | logging.info("sku-less label names %s", out) |
| 442 | |
| 443 | return out |
Gregory Nisbet | fb68a1f | 2019-08-22 10:27:33 -0700 | [diff] [blame] | 444 | |
| 445 | |
| 446 | def _old_label_values(self, host): |
| 447 | """get the hwid_lib labels on previous run |
| 448 | |
| 449 | @returns: hwid_labels""" |
| 450 | out = [] |
| 451 | info = host.host_info_store.get() |
| 452 | for hwid_label in self._hwid_label_names(): |
| 453 | for label in info.labels: |
| 454 | # NOTE: we want *all* the labels starting |
| 455 | # with this prefix. |
| 456 | if label.startswith(hwid_label): |
| 457 | out.append(label) |
| 458 | return out |
| 459 | |
| 460 | |
Kevin Cheng | 80ad573 | 2016-03-31 16:01:56 -0700 | [diff] [blame] | 461 | def generate_labels(self, host): |
Gregory Nisbet | fb68a1f | 2019-08-22 10:27:33 -0700 | [diff] [blame] | 462 | # use previous values as default |
| 463 | old_hwid_labels = self._old_label_values(host) |
Xixuan Wu | e63f835 | 2019-09-13 15:18:03 -0700 | [diff] [blame] | 464 | logging.info("old_hwid_labels: %r", old_hwid_labels) |
Kevin Cheng | 80ad573 | 2016-03-31 16:01:56 -0700 | [diff] [blame] | 465 | hwid = host.run_output('crossystem hwid').strip() |
Gregory Nisbet | fb68a1f | 2019-08-22 10:27:33 -0700 | [diff] [blame] | 466 | hwid_info_list = [] |
| 467 | try: |
| 468 | hwid_info_response = hwid_lib.get_hwid_info( |
| 469 | hwid=hwid, |
| 470 | info_type=hwid_lib.HWID_INFO_LABEL, |
| 471 | key_file=self.key_file, |
| 472 | ) |
Xixuan Wu | e63f835 | 2019-09-13 15:18:03 -0700 | [diff] [blame] | 473 | logging.info("hwid_info_response: %r", hwid_info_response) |
Gregory Nisbet | fb68a1f | 2019-08-22 10:27:33 -0700 | [diff] [blame] | 474 | hwid_info_list = hwid_info_response.get('labels', []) |
| 475 | except hwid_lib.HwIdException as e: |
| 476 | logging.info("HwIdException: %s", e) |
Kevin Cheng | 80ad573 | 2016-03-31 16:01:56 -0700 | [diff] [blame] | 477 | |
Xixuan Wu | 78569d0 | 2019-09-15 16:08:25 -0700 | [diff] [blame] | 478 | new_hwid_labels = _parse_hwid_labels(hwid_info_list) |
| 479 | logging.info("new HWID labels: %r", new_hwid_labels) |
Gregory Nisbet | bfd120f | 2019-09-04 14:49:46 -0700 | [diff] [blame] | 480 | |
Gregory Nisbet | fb68a1f | 2019-08-22 10:27:33 -0700 | [diff] [blame] | 481 | return HWIDLabel._merge_hwid_label_lists( |
| 482 | old=old_hwid_labels, |
Xixuan Wu | 78569d0 | 2019-09-15 16:08:25 -0700 | [diff] [blame] | 483 | new=new_hwid_labels, |
Gregory Nisbet | fb68a1f | 2019-08-22 10:27:33 -0700 | [diff] [blame] | 484 | ) |
Kevin Cheng | 80ad573 | 2016-03-31 16:01:56 -0700 | [diff] [blame] | 485 | |
| 486 | |
| 487 | def get_all_labels(self): |
| 488 | """We need to try all labels as a prefix and as standalone. |
| 489 | |
| 490 | We don't know for sure which labels are prefix labels and which are |
| 491 | standalone so we try all of them as both. |
| 492 | """ |
| 493 | all_hwid_labels = [] |
| 494 | try: |
| 495 | all_hwid_labels = hwid_lib.get_all_possible_dut_labels( |
| 496 | self.key_file) |
| 497 | except IOError: |
| 498 | logging.error('Can not open key file: %s', self.key_file) |
| 499 | except hwid_lib.HwIdException as e: |
| 500 | logging.error('hwid service: %s', e) |
| 501 | return all_hwid_labels, all_hwid_labels |
| 502 | |
| 503 | |
Otabek Kasimov | 40ccb97 | 2020-05-26 15:14:39 -0700 | [diff] [blame^] | 504 | class DutStorageLabel(base_label.StringPrefixLabel): |
| 505 | """Return the DUT storage label.""" |
| 506 | |
| 507 | _NAME = audit_const.DUT_STORAGE_STATE_PREFIX |
| 508 | |
| 509 | def exists(self, host): |
| 510 | return host.servo is not None |
| 511 | |
| 512 | def generate_labels(self, host): |
| 513 | verifier = audit_verify.VerifyDutStorage(host) |
| 514 | verifier.verify(set_label=False) |
| 515 | state = verifier.get_state() |
| 516 | return [state] |
| 517 | |
| 518 | def update_for_task(self, task_name): |
| 519 | # This label is part of audit task, so updating it during deploy tasks |
| 520 | # update it or when no task name is mentioned. |
| 521 | return task_name in (DEPLOY_TASK_NAME, '') |
| 522 | |
| 523 | |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 524 | CROS_LABELS = [ |
Eshwar Narayan | f46904c | 2020-02-11 17:57:31 -0800 | [diff] [blame] | 525 | AudioLoopbackDongleLabel(), #STATECONFIG |
Shijin Abraham | 76bc1db | 2020-03-06 10:52:10 -0800 | [diff] [blame] | 526 | BluetoothPeerLabel(), #STATECONFIG |
Eshwar Narayan | f46904c | 2020-02-11 17:57:31 -0800 | [diff] [blame] | 527 | ChameleonConnectionLabel(), #LABCONFIG |
| 528 | ChameleonLabel(), #STATECONFIG |
| 529 | ChameleonPeripheralsLabel(), #LABCONFIG |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 530 | common_label.OSLabel(), |
Eshwar Narayan | f46904c | 2020-02-11 17:57:31 -0800 | [diff] [blame] | 531 | DeviceSkuLabel(), #LABCONFIG |
Kevin Cheng | 80ad573 | 2016-03-31 16:01:56 -0700 | [diff] [blame] | 532 | HWIDLabel(), |
Otabek Kasimov | 4318591 | 2020-03-11 16:01:52 -0700 | [diff] [blame] | 533 | ServoTypeLabel(), #LABCONFIG |
Xixuan Wu | 457b4ac | 2020-03-02 14:39:08 -0800 | [diff] [blame] | 534 | # Temporarily add back as there's no way to reference cr50 configs. |
| 535 | # See crbug.com/1057145 for the root cause. |
| 536 | # See crbug.com/1057719 for future tracking. |
| 537 | Cr50Label(), |
| 538 | Cr50ROKeyidLabel(), |
Otabek Kasimov | 40ccb97 | 2020-05-26 15:14:39 -0700 | [diff] [blame^] | 539 | DutStorageLabel(), #STATECONFIG |
Kevin Cheng | a2619dc | 2016-03-28 11:42:08 -0700 | [diff] [blame] | 540 | ] |
Garry Wang | e4b6d6e | 2019-06-17 17:08:46 -0700 | [diff] [blame] | 541 | |
| 542 | LABSTATION_LABELS = [ |
Garry Wang | e4b6d6e | 2019-06-17 17:08:46 -0700 | [diff] [blame] | 543 | common_label.OSLabel(), |
| 544 | ] |