blob: 1f8a6f2cf58c1d19ac45015f738cedb776766616 [file] [log] [blame]
Chris Masone44e4d6c2012-08-15 14:25:53 -07001# Copyright (c) 2012 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
Wade Guthrie44668f92012-10-18 09:44:49 -07006import random
7
Chris Masone44e4d6c2012-08-15 14:25:53 -07008from autotest_lib.client.common_lib import global_config
9from autotest_lib.client.common_lib.cros import dev_server
10
11
12_CONFIG = global_config.global_config
13
14
15def image_url_pattern():
16 return _CONFIG.get_config_value('CROS', 'image_url_pattern', type=str)
17
18
19def sharding_factor():
20 return _CONFIG.get_config_value('CROS', 'sharding_factor', type=int)
21
22
Chris Masonee99bcf22012-08-17 15:09:49 -070023def infrastructure_user_list():
24 return _CONFIG.get_config_value('CROS', 'infrastructure_users', type=list,
25 default=[])
26
27
Chris Masone44e4d6c2012-08-15 14:25:53 -070028def package_url_pattern():
29 return _CONFIG.get_config_value('CROS', 'package_url_pattern', type=str)
30
31
Chris Sosaaccb5ce2012-08-30 17:29:15 -070032def get_package_url(devserver_url, build):
33 """Returns the package url from the |devserver_url| and |build|.
34
35 @param devserver_url: a string specifying the host to contact e.g.
36 http://my_host:9090.
37 @param build: the build/image string to use e.g. mario-release/R19-123.0.1.
38 @return the url where you can find the packages for the build.
39 """
Chris Masone44e4d6c2012-08-15 14:25:53 -070040 return package_url_pattern() % (devserver_url, build)
41
42
Wade Guthrie44668f92012-10-18 09:44:49 -070043def get_random_best_host(afe, host_list, require_usable_hosts=True):
44 """
45 Randomly choose the 'best' host from host_list, using fresh status.
46
47 Hit the AFE to get latest status for the listed hosts. Then apply
48 the following heuristic to pick the 'best' set:
49
50 Remove unusable hosts (not tools.is_usable()), then
51 'Ready' > 'Running, Cleaning, Verifying, etc'
52
53 If any 'Ready' hosts exist, return a random choice. If not, randomly
54 choose from the next tier. If there are none of those either, None.
55
56 @param afe: autotest front end that holds the hosts being managed.
57 @param host_list: an iterable of Host objects, per server/frontend.py
58 @param require_usable_hosts: only return hosts currently in a usable
59 state.
60 @return a Host object, or None if no appropriate host is found.
61 """
62 if not host_list:
63 return None
64 hostnames = [host.hostname for host in host_list]
65 updated_hosts = afe.get_hosts(hostnames=hostnames)
66 usable_hosts = [host for host in updated_hosts if is_usable(host)]
67 ready_hosts = [host for host in usable_hosts if host.status == 'Ready']
68 unusable_hosts = [h for h in updated_hosts if not is_usable(h)]
69 if ready_hosts:
70 return random.choice(ready_hosts)
71 if usable_hosts:
72 return random.choice(usable_hosts)
73 if not require_usable_hosts and unusable_hosts:
74 return random.choice(unusable_hosts)
75 return None
76
77
Chris Masone44e4d6c2012-08-15 14:25:53 -070078def inject_vars(vars, control_file_in):
79 """
80 Inject the contents of |vars| into |control_file_in|.
81
82 @param vars: a dict to shoehorn into the provided control file string.
83 @param control_file_in: the contents of a control file to munge.
84 @return the modified control file string.
85 """
86 control_file = ''
87 for key, value in vars.iteritems():
88 # None gets injected as 'None' without this check; same for digits.
89 if isinstance(value, str):
90 control_file += "%s='%s'\n" % (key, value)
91 else:
92 control_file += "%s=%r\n" % (key, value)
93 return control_file + control_file_in
Chris Masone8906ab12012-07-23 15:37:56 -070094
95
96def is_usable(host):
97 """
98 Given a host, determine if the host is usable right now.
99
100 @param host: Host instance (as in server/frontend.py)
101 @return True if host is alive and not incorrectly locked. Else, False.
102 """
103 return alive(host) and not incorrectly_locked(host)
104
105
106def alive(host):
107 """
108 Given a host, determine if the host is alive.
109
110 @param host: Host instance (as in server/frontend.py)
111 @return True if host is not under, or in need of, repair. Else, False.
112 """
113 return host.status not in ['Repair Failed', 'Repairing']
114
115
116def incorrectly_locked(host):
117 """
118 Given a host, determine if the host is locked by some user.
119
120 If the host is unlocked, or locked by the test infrastructure,
121 this will return False. Usernames defined as 'part of the test
122 infrastructure' are listed in global_config.ini under the [CROS]
123 section in the 'infrastructure_users' field.
124
125 @param host: Host instance (as in server/frontend.py)
126 @return False if the host is not locked, or locked by the infra.
127 True if the host is locked by someone we haven't blessed.
128 """
129 return (host.locked and host.locked_by not in infrastructure_user_list())