| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 1 | # Copyright (c) 2011 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 | import common | 
|  | 6 | import inspect, new, socket, sys | 
|  | 7 |  | 
| Simran Basi | be7b65b | 2012-11-21 09:33:27 -0800 | [diff] [blame] | 8 | from autotest_lib.client.bin import utils | 
| Jiaxi Luo | c342f9f | 2014-05-19 16:22:03 -0700 | [diff] [blame] | 9 | from autotest_lib.cli import host, rpc | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 10 | from autotest_lib.server import hosts | 
| Kevin Cheng | 3a4a57a | 2015-09-30 12:09:50 -0700 | [diff] [blame] | 11 | from autotest_lib.server.cros.dynamic_suite import frontend_wrappers | 
| Jiaxi Luo | c342f9f | 2014-05-19 16:22:03 -0700 | [diff] [blame] | 12 | from autotest_lib.client.common_lib import error, host_protections | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 13 |  | 
|  | 14 |  | 
|  | 15 | # In order for hosts to work correctly, some of its variables must be setup. | 
|  | 16 | hosts.factory.ssh_user = 'root' | 
|  | 17 | hosts.factory.ssh_pass = '' | 
|  | 18 | hosts.factory.ssh_port = 22 | 
| Fang Deng | 6bee3de | 2013-09-04 20:17:26 -0700 | [diff] [blame] | 19 | hosts.factory.ssh_verbosity_flag = '' | 
|  | 20 | hosts.factory.ssh_options = '' | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 21 |  | 
|  | 22 |  | 
| Kevin Cheng | 49f7b81 | 2015-12-15 15:24:23 -0800 | [diff] [blame] | 23 | # pylint: disable=missing-docstring | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 24 | class site_host(host.host): | 
|  | 25 | pass | 
|  | 26 |  | 
|  | 27 |  | 
|  | 28 | class site_host_create(site_host, host.host_create): | 
|  | 29 | """ | 
|  | 30 | site_host_create subclasses host_create in host.py. | 
|  | 31 | """ | 
|  | 32 |  | 
| Jiaxi Luo | c342f9f | 2014-05-19 16:22:03 -0700 | [diff] [blame] | 33 | @classmethod | 
|  | 34 | def construct_without_parse( | 
|  | 35 | cls, web_server, hosts, platform=None, | 
| Matthew Sartori | 6818633 | 2015-04-27 17:19:53 -0700 | [diff] [blame] | 36 | locked=False, lock_reason='', labels=[], acls=[], | 
| Jiaxi Luo | c342f9f | 2014-05-19 16:22:03 -0700 | [diff] [blame] | 37 | protection=host_protections.Protection.NO_PROTECTION): | 
|  | 38 | """Construct an site_host_create object and fill in data from args. | 
|  | 39 |  | 
|  | 40 | Do not need to call parse after the construction. | 
|  | 41 |  | 
|  | 42 | Return an object of site_host_create ready to execute. | 
|  | 43 |  | 
|  | 44 | @param web_server: A string specifies the autotest webserver url. | 
|  | 45 | It is needed to setup comm to make rpc. | 
|  | 46 | @param hosts: A list of hostnames as strings. | 
|  | 47 | @param platform: A string or None. | 
|  | 48 | @param locked: A boolean. | 
| Matthew Sartori | 6818633 | 2015-04-27 17:19:53 -0700 | [diff] [blame] | 49 | @param lock_reason: A string. | 
| Jiaxi Luo | c342f9f | 2014-05-19 16:22:03 -0700 | [diff] [blame] | 50 | @param labels: A list of labels as strings. | 
|  | 51 | @param acls: A list of acls as strings. | 
|  | 52 | @param protection: An enum defined in host_protections. | 
|  | 53 | """ | 
|  | 54 | obj = cls() | 
|  | 55 | obj.web_server = web_server | 
|  | 56 | try: | 
|  | 57 | # Setup stuff needed for afe comm. | 
|  | 58 | obj.afe = rpc.afe_comm(web_server) | 
|  | 59 | except rpc.AuthError, s: | 
|  | 60 | obj.failure(str(s), fatal=True) | 
|  | 61 | obj.hosts = hosts | 
|  | 62 | obj.platform = platform | 
|  | 63 | obj.locked = locked | 
| Matthew Sartori | 6818633 | 2015-04-27 17:19:53 -0700 | [diff] [blame] | 64 | if locked and lock_reason.strip(): | 
|  | 65 | obj.data['lock_reason'] = lock_reason.strip() | 
| Jiaxi Luo | c342f9f | 2014-05-19 16:22:03 -0700 | [diff] [blame] | 66 | obj.labels = labels | 
|  | 67 | obj.acls = acls | 
|  | 68 | if protection: | 
|  | 69 | obj.data['protection'] = protection | 
| Kevin Cheng | bdedeb1 | 2016-01-12 16:28:43 -0800 | [diff] [blame] | 70 | # TODO(kevcheng): Update the admin page to take in serials? | 
|  | 71 | obj.serials = None | 
| Jiaxi Luo | c342f9f | 2014-05-19 16:22:03 -0700 | [diff] [blame] | 72 | return obj | 
|  | 73 |  | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 74 |  | 
|  | 75 | def _execute_add_one_host(self, host): | 
|  | 76 | # Always add the hosts as locked to avoid the host | 
| Jiaxi Luo | b0e6c60 | 2014-05-13 16:06:24 -0700 | [diff] [blame] | 77 | # being picked up by the scheduler before it's ACL'ed. | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 78 | self.data['locked'] = True | 
| Matthew Sartori | 6818633 | 2015-04-27 17:19:53 -0700 | [diff] [blame] | 79 | if not self.locked: | 
|  | 80 | self.data['lock_reason'] = 'Forced lock on device creation' | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 81 | self.execute_rpc('add_host', hostname=host, | 
|  | 82 | status="Ready", **self.data) | 
|  | 83 | # If there are labels avaliable for host, use them. | 
|  | 84 | host_info = self.host_info_map[host] | 
| Jiaxi Luo | b0e6c60 | 2014-05-13 16:06:24 -0700 | [diff] [blame] | 85 | labels = set(self.labels) | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 86 | if host_info.labels: | 
| Jiaxi Luo | b0e6c60 | 2014-05-13 16:06:24 -0700 | [diff] [blame] | 87 | labels.update(host_info.labels) | 
|  | 88 | # Now add the platform label. | 
|  | 89 | # If a platform was not provided and we were able to retrieve it | 
|  | 90 | # from the host, use the retrieved platform. | 
|  | 91 | platform = self.platform if self.platform else host_info.platform | 
|  | 92 | if platform: | 
|  | 93 | labels.add(platform) | 
|  | 94 |  | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 95 | if len(labels): | 
| Jiaxi Luo | b0e6c60 | 2014-05-13 16:06:24 -0700 | [diff] [blame] | 96 | self.execute_rpc('host_add_labels', id=host, labels=list(labels)) | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 97 |  | 
| Kevin Cheng | 3a4a57a | 2015-09-30 12:09:50 -0700 | [diff] [blame] | 98 | if self.serials: | 
|  | 99 | afe = frontend_wrappers.RetryingAFE(timeout_min=5, delay_sec=10) | 
|  | 100 | afe.set_host_attribute('serials', ','.join(self.serials), | 
|  | 101 | hostname=host) | 
|  | 102 |  | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 103 |  | 
|  | 104 | def execute(self): | 
|  | 105 | # Check to see if the platform or any other labels can be grabbed from | 
|  | 106 | # the hosts. | 
|  | 107 | self.host_info_map = {} | 
|  | 108 | for host in self.hosts: | 
|  | 109 | try: | 
| Simran Basi | be7b65b | 2012-11-21 09:33:27 -0800 | [diff] [blame] | 110 | if utils.ping(host, tries=1, deadline=1) == 0: | 
| Kevin Cheng | 49f7b81 | 2015-12-15 15:24:23 -0800 | [diff] [blame] | 111 | if self.serials and len(self.serials) > 1: | 
|  | 112 | host_dut = hosts.create_testbed( | 
|  | 113 | host, adb_serials=self.serials) | 
|  | 114 | else: | 
| Kevin Cheng | d7ef5d3 | 2016-01-08 16:19:28 -0800 | [diff] [blame] | 115 | adb_serial = None | 
|  | 116 | if self.serials: | 
|  | 117 | adb_serial = self.serials[0] | 
|  | 118 | host_dut = hosts.create_host(host, | 
|  | 119 | adb_serial=adb_serial) | 
| Simran Basi | be7b65b | 2012-11-21 09:33:27 -0800 | [diff] [blame] | 120 | host_info = host_information(host, | 
| Kevin Cheng | 49f7b81 | 2015-12-15 15:24:23 -0800 | [diff] [blame] | 121 | host_dut.get_platform(), | 
|  | 122 | host_dut.get_labels()) | 
| Simran Basi | be7b65b | 2012-11-21 09:33:27 -0800 | [diff] [blame] | 123 | else: | 
|  | 124 | # Can't ping the host, use default information. | 
|  | 125 | host_info = host_information(host, None, []) | 
|  | 126 | except (socket.gaierror, error.AutoservRunError, | 
|  | 127 | error.AutoservSSHTimeout): | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 128 | # We may be adding a host that does not exist yet or we can't | 
| Simran Basi | be7b65b | 2012-11-21 09:33:27 -0800 | [diff] [blame] | 129 | # reach due to hostname/address issues or if the host is down. | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 130 | host_info = host_information(host, None, []) | 
|  | 131 | self.host_info_map[host] = host_info | 
|  | 132 | # We need to check if these labels & ACLs exist, | 
|  | 133 | # and create them if not. | 
|  | 134 | if self.platform: | 
|  | 135 | self.check_and_create_items('get_labels', 'add_label', | 
|  | 136 | [self.platform], | 
|  | 137 | platform=True) | 
|  | 138 | else: | 
|  | 139 | # No platform was provided so check and create the platform label | 
|  | 140 | # for each host. | 
|  | 141 | platforms = [] | 
|  | 142 | for host_info in self.host_info_map.values(): | 
|  | 143 | if host_info.platform and host_info.platform not in platforms: | 
|  | 144 | platforms.append(host_info.platform) | 
| Jiaxi Luo | c342f9f | 2014-05-19 16:22:03 -0700 | [diff] [blame] | 145 | if platforms: | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 146 | self.check_and_create_items('get_labels', 'add_label', | 
|  | 147 | platforms, | 
|  | 148 | platform=True) | 
|  | 149 | labels_to_check_and_create = self.labels[:] | 
|  | 150 | for host_info in self.host_info_map.values(): | 
|  | 151 | labels_to_check_and_create = (host_info.labels + | 
|  | 152 | labels_to_check_and_create) | 
|  | 153 | if labels_to_check_and_create: | 
|  | 154 | self.check_and_create_items('get_labels', 'add_label', | 
|  | 155 | labels_to_check_and_create, | 
|  | 156 | platform=False) | 
|  | 157 |  | 
|  | 158 | if self.acls: | 
|  | 159 | self.check_and_create_items('get_acl_groups', | 
|  | 160 | 'add_acl_group', | 
|  | 161 | self.acls) | 
|  | 162 |  | 
| Jiaxi Luo | c342f9f | 2014-05-19 16:22:03 -0700 | [diff] [blame] | 163 | return self._execute_add_hosts() | 
| Simran Basi | c6f1f7a | 2012-10-16 10:47:46 -0700 | [diff] [blame] | 164 |  | 
|  | 165 |  | 
|  | 166 | class host_information(object): | 
|  | 167 | """Store host information so we don't have to keep looking it up.""" | 
|  | 168 |  | 
|  | 169 |  | 
|  | 170 | def __init__(self, hostname, platform, labels): | 
|  | 171 | self.hostname = hostname | 
|  | 172 | self.platform = platform | 
|  | 173 | self.labels = labels | 
|  | 174 |  | 
|  | 175 |  | 
|  | 176 | # Any classes we don't override in host should be copied automatically | 
|  | 177 | for cls in [getattr(host, n) for n in dir(host) if not n.startswith("_")]: | 
|  | 178 | if not inspect.isclass(cls): | 
|  | 179 | continue | 
|  | 180 | cls_name = cls.__name__ | 
|  | 181 | site_cls_name = 'site_' + cls_name | 
|  | 182 | if hasattr(sys.modules[__name__], site_cls_name): | 
|  | 183 | continue | 
|  | 184 | bases = (site_host, cls) | 
|  | 185 | members = {'__doc__': cls.__doc__} | 
|  | 186 | site_cls = new.classobj(site_cls_name, bases, members) | 
|  | 187 | setattr(sys.modules[__name__], site_cls_name, site_cls) |