Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 1 | # Copyright 2016 The Chromium 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 | |
Simran Basi | aa467ad | 2016-02-03 16:56:22 -0800 | [diff] [blame] | 5 | """Utility functions for AFE-based interactions. |
| 6 | |
| 7 | NOTE: This module should only be used in the context of a running test. Any |
| 8 | utilities that require accessing the AFE, should do so by creating |
| 9 | their own instance of the AFE client and interact with it directly. |
| 10 | """ |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 11 | |
| 12 | import common |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 13 | from autotest_lib.client.common_lib import error |
xixuan | 5dc64ea | 2016-05-20 17:27:51 -0700 | [diff] [blame] | 14 | from autotest_lib.client.common_lib import global_config |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 15 | from autotest_lib.server.cros.dynamic_suite import frontend_wrappers |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 16 | |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 17 | |
| 18 | AFE = frontend_wrappers.RetryingAFE(timeout_min=5, delay_sec=10) |
Richard Barnette | 260cbd0 | 2016-10-06 12:23:28 -0700 | [diff] [blame] | 19 | _CROS_VERSION_MAP = AFE.get_stable_version_map(AFE.CROS_IMAGE_TYPE) |
Richard Barnette | e50453e | 2016-10-10 16:43:44 -0700 | [diff] [blame] | 20 | _FIRMWARE_VERSION_MAP = AFE.get_stable_version_map(AFE.FIRMWARE_IMAGE_TYPE) |
Richard Barnette | 260cbd0 | 2016-10-06 12:23:28 -0700 | [diff] [blame] | 21 | _FAFT_VERSION_MAP = AFE.get_stable_version_map(AFE.FAFT_IMAGE_TYPE) |
| 22 | _ANDROID_VERSION_MAP = AFE.get_stable_version_map(AFE.ANDROID_IMAGE_TYPE) |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 23 | |
xixuan | 5dc64ea | 2016-05-20 17:27:51 -0700 | [diff] [blame] | 24 | _CONFIG = global_config.global_config |
| 25 | ENABLE_DEVSERVER_TRIGGER_AUTO_UPDATE = _CONFIG.get_config_value( |
| 26 | 'CROS', 'enable_devserver_trigger_auto_update', type=bool, |
| 27 | default=False) |
| 28 | |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 29 | |
Richard Barnette | 260cbd0 | 2016-10-06 12:23:28 -0700 | [diff] [blame] | 30 | def _host_in_lab(host): |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 31 | """Check if the host is in the lab and an object the AFE knows. |
| 32 | |
| 33 | This check ensures that autoserv and the host's current job is running |
| 34 | inside a fully Autotest instance, aka a lab environment. If this is the |
| 35 | case it then verifies the host is registed with the configured AFE |
| 36 | instance. |
| 37 | |
| 38 | @param host: Host object to verify. |
| 39 | |
| 40 | @returns The host model object. |
| 41 | """ |
Simran Basi | aa467ad | 2016-02-03 16:56:22 -0800 | [diff] [blame] | 42 | if not host.job or not host.job.in_lab: |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 43 | return False |
Kevin Cheng | 05ae2a4 | 2016-06-06 10:12:48 -0700 | [diff] [blame] | 44 | return host._afe_host |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 45 | |
| 46 | |
Kevin Cheng | 84a71ba | 2016-07-14 11:03:57 -0700 | [diff] [blame] | 47 | def get_labels(host, prefix=None): |
| 48 | """Get labels of a host with name started with given prefix. |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 49 | |
Kevin Cheng | 84a71ba | 2016-07-14 11:03:57 -0700 | [diff] [blame] | 50 | @param prefix: Prefix of label names, if None, return all labels. |
| 51 | |
| 52 | @returns List of labels that match the prefix or if prefix is None, all |
| 53 | labels. |
| 54 | """ |
| 55 | if not prefix: |
| 56 | return host._afe_host.labels |
| 57 | |
| 58 | return [label for label in host._afe_host.labels |
| 59 | if label.startswith(prefix)] |
| 60 | |
| 61 | |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 62 | def clear_version_labels(host): |
| 63 | """Clear version labels for a given host. |
| 64 | |
| 65 | @param host: Host whose version labels to clear. |
| 66 | """ |
Kevin Cheng | 4ce6761 | 2016-07-29 13:34:17 -0700 | [diff] [blame] | 67 | host._afe_host.labels = [label for label in host._afe_host.labels |
| 68 | if not label.startswith(host.VERSION_PREFIX)] |
Richard Barnette | 260cbd0 | 2016-10-06 12:23:28 -0700 | [diff] [blame] | 69 | if not _host_in_lab(host): |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 70 | return |
| 71 | |
| 72 | host_list = [host.hostname] |
| 73 | labels = AFE.get_labels( |
| 74 | name__startswith=host.VERSION_PREFIX, |
| 75 | host__hostname=host.hostname) |
| 76 | |
| 77 | for label in labels: |
| 78 | label.remove_hosts(hosts=host_list) |
| 79 | |
| 80 | |
| 81 | def add_version_label(host, image_name): |
| 82 | """Add version labels to a host. |
| 83 | |
| 84 | @param host: Host to add the version label for. |
| 85 | @param image_name: Name of the build version to add to the host. |
| 86 | """ |
Kevin Cheng | 4ce6761 | 2016-07-29 13:34:17 -0700 | [diff] [blame] | 87 | label = '%s:%s' % (host.VERSION_PREFIX, image_name) |
| 88 | host._afe_host.labels.append(label) |
Richard Barnette | 260cbd0 | 2016-10-06 12:23:28 -0700 | [diff] [blame] | 89 | if not _host_in_lab(host): |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 90 | return |
Simran Basi | 5ace6f2 | 2016-01-06 17:30:44 -0800 | [diff] [blame] | 91 | AFE.run('label_add_hosts', id=label, hosts=[host.hostname]) |
| 92 | |
| 93 | |
Richard Barnette | 383ef9c | 2016-12-13 11:56:49 -0800 | [diff] [blame] | 94 | def get_stable_cros_image_name(board): |
| 95 | """Retrieve the Chrome OS stable image name for a given board. |
Simran Basi | beb2bb2 | 2016-02-03 15:25:48 -0800 | [diff] [blame] | 96 | |
| 97 | @param board: Board to lookup. |
Simran Basi | beb2bb2 | 2016-02-03 15:25:48 -0800 | [diff] [blame] | 98 | |
Richard Barnette | 383ef9c | 2016-12-13 11:56:49 -0800 | [diff] [blame] | 99 | @returns Name of a Chrome OS image to be installed in order to |
Richard Barnette | 260cbd0 | 2016-10-06 12:23:28 -0700 | [diff] [blame] | 100 | repair the given board. |
Simran Basi | beb2bb2 | 2016-02-03 15:25:48 -0800 | [diff] [blame] | 101 | """ |
Richard Barnette | 383ef9c | 2016-12-13 11:56:49 -0800 | [diff] [blame] | 102 | return _CROS_VERSION_MAP.get_image_name(board) |
Richard Barnette | 260cbd0 | 2016-10-06 12:23:28 -0700 | [diff] [blame] | 103 | |
| 104 | |
Richard Barnette | e50453e | 2016-10-10 16:43:44 -0700 | [diff] [blame] | 105 | def get_stable_firmware_version(board): |
| 106 | """Retrieve the stable firmware version for a given board. |
| 107 | |
| 108 | @param board: Board to lookup. |
| 109 | |
| 110 | @returns A version of firmware to be installed via |
| 111 | `chromeos-firmwareupdate` from a repair build. |
| 112 | """ |
| 113 | return _FIRMWARE_VERSION_MAP.get_version(board) |
| 114 | |
| 115 | |
Richard Barnette | 260cbd0 | 2016-10-06 12:23:28 -0700 | [diff] [blame] | 116 | def get_stable_faft_version(board): |
| 117 | """Retrieve the stable firmware version for FAFT DUTs. |
| 118 | |
| 119 | @param board: Board to lookup. |
| 120 | |
| 121 | @returns A version of firmware to be installed in order to |
| 122 | repair firmware on a DUT used for FAFT testing. |
| 123 | """ |
| 124 | return _FAFT_VERSION_MAP.get_version(board) |
| 125 | |
| 126 | |
| 127 | def get_stable_android_version(board): |
| 128 | """Retrieve the stable Android version a given board. |
| 129 | |
| 130 | @param board: Board to lookup. |
| 131 | |
| 132 | @returns Stable version of Android for the given board. |
| 133 | """ |
| 134 | return _ANDROID_VERSION_MAP.get_version(board) |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 135 | |
| 136 | |
Kevin Cheng | 05ae2a4 | 2016-06-06 10:12:48 -0700 | [diff] [blame] | 137 | def get_host_attribute(host, attribute, use_local_value=True): |
Dan Shi | e4256c8 | 2016-02-18 00:23:49 -0800 | [diff] [blame] | 138 | """Looks up the value of host attribute for the host. |
| 139 | |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 140 | @param host: A Host object to lookup for attribute value. |
| 141 | @param attribute: Name of the host attribute. |
Kevin Cheng | 05ae2a4 | 2016-06-06 10:12:48 -0700 | [diff] [blame] | 142 | @param use_local_value: Boolean to indicate if the local value or AFE value |
| 143 | should be retrieved. |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 144 | |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 145 | @returns value for the given attribute or None if not found. |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 146 | """ |
Kevin Cheng | 05ae2a4 | 2016-06-06 10:12:48 -0700 | [diff] [blame] | 147 | local_value = host._afe_host.attributes.get(attribute) |
Richard Barnette | 260cbd0 | 2016-10-06 12:23:28 -0700 | [diff] [blame] | 148 | if not _host_in_lab(host) or use_local_value: |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 149 | return local_value |
| 150 | |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 151 | hosts = AFE.get_hosts(hostname=host.hostname) |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 152 | if hosts and attribute in hosts[0].attributes: |
| 153 | return hosts[0].attributes[attribute] |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 154 | else: |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 155 | return local_value |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 156 | |
| 157 | |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 158 | def clear_host_attributes_before_provision(host): |
Dan Shi | e4256c8 | 2016-02-18 00:23:49 -0800 | [diff] [blame] | 159 | """Clear host attributes before provision, e.g., job_repo_url. |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 160 | |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 161 | @param host: A Host object to clear attributes before provision. |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 162 | """ |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 163 | attributes = host.get_attributes_to_clear_before_provision() |
| 164 | for attribute in attributes: |
Kevin Cheng | 05ae2a4 | 2016-06-06 10:12:48 -0700 | [diff] [blame] | 165 | host._afe_host.attributes.pop(attribute, None) |
Richard Barnette | 260cbd0 | 2016-10-06 12:23:28 -0700 | [diff] [blame] | 166 | if not _host_in_lab(host): |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 167 | return |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 168 | |
| 169 | for attribute in attributes: |
| 170 | update_host_attribute(host, attribute, None) |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 171 | |
| 172 | |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 173 | def update_host_attribute(host, attribute, value): |
| 174 | """Updates the host attribute with given value. |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 175 | |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 176 | @param host: A Host object to update attribute value. |
| 177 | @param attribute: Name of the host attribute. |
| 178 | @param value: Value for the host attribute. |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 179 | |
Dan Shi | e4256c8 | 2016-02-18 00:23:49 -0800 | [diff] [blame] | 180 | @raises AutoservError: If we failed to update the attribute. |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 181 | """ |
Kevin Cheng | 05ae2a4 | 2016-06-06 10:12:48 -0700 | [diff] [blame] | 182 | host._afe_host.attributes[attribute] = value |
Richard Barnette | 260cbd0 | 2016-10-06 12:23:28 -0700 | [diff] [blame] | 183 | if not _host_in_lab(host): |
Dan Shi | 8190eb8 | 2016-02-11 17:15:58 -0800 | [diff] [blame] | 184 | return |
| 185 | |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 186 | AFE.set_host_attribute(attribute, value, hostname=host.hostname) |
Kevin Cheng | 05ae2a4 | 2016-06-06 10:12:48 -0700 | [diff] [blame] | 187 | if get_host_attribute(host, attribute, use_local_value=False) != value: |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 188 | raise error.AutoservError( |
| 189 | 'Failed to update host attribute `%s` with %s, host %s' % |
| 190 | (attribute, value, host.hostname)) |
| 191 | |
| 192 | |
| 193 | def machine_install_and_update_labels(host, *args, **dargs): |
| 194 | """Calls machine_install and updates the version labels on a host. |
| 195 | |
| 196 | @param host: Host object to run machine_install on. |
| 197 | @param *args: Args list to pass to machine_install. |
| 198 | @param **dargs: dargs dict to pass to machine_install. |
| 199 | """ |
| 200 | clear_version_labels(host) |
| 201 | clear_host_attributes_before_provision(host) |
xixuan | ec801e3 | 2016-08-25 10:20:22 -0700 | [diff] [blame] | 202 | # If ENABLE_DEVSERVER_TRIGGER_AUTO_UPDATE is enabled and the host is a |
| 203 | # CrosHost, devserver will be used to trigger auto-update. |
| 204 | if host.support_devserver_provision: |
xixuan | 5dc64ea | 2016-05-20 17:27:51 -0700 | [diff] [blame] | 205 | image_name, host_attributes = host.machine_install_by_devserver( |
| 206 | *args, **dargs) |
xixuan | ec801e3 | 2016-08-25 10:20:22 -0700 | [diff] [blame] | 207 | else: |
| 208 | image_name, host_attributes = host.machine_install(*args, **dargs) |
Dan Shi | be3636a | 2016-02-14 22:48:01 -0800 | [diff] [blame] | 209 | for attribute, value in host_attributes.items(): |
| 210 | update_host_attribute(host, attribute, value) |
Kevin Cheng | e12e71d | 2016-08-15 11:37:18 -0700 | [diff] [blame] | 211 | add_version_label(host, image_name) |