blob: 52d82d268bec8280ea887918acb9f1467e38435d [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
Chris Sosab76e0ee2013-05-22 16:55:41 -07007import re
Wade Guthrie44668f92012-10-18 09:44:49 -07008
Chris Masone44e4d6c2012-08-15 14:25:53 -07009from autotest_lib.client.common_lib import global_config
Chris Masone44e4d6c2012-08-15 14:25:53 -070010
11
12_CONFIG = global_config.global_config
13
14
15def image_url_pattern():
Chris Sosab76e0ee2013-05-22 16:55:41 -070016 """Returns image_url_pattern from global_config."""
Chris Masone44e4d6c2012-08-15 14:25:53 -070017 return _CONFIG.get_config_value('CROS', 'image_url_pattern', type=str)
18
19
Vadim Bendeburyab14bf12012-12-28 13:51:46 -080020def firmware_url_pattern():
Chris Sosab76e0ee2013-05-22 16:55:41 -070021 """Returns firmware_url_pattern from global_config."""
Vadim Bendeburyab14bf12012-12-28 13:51:46 -080022 return _CONFIG.get_config_value('CROS', 'firmware_url_pattern', type=str)
23
24
Chris Masone44e4d6c2012-08-15 14:25:53 -070025def sharding_factor():
Chris Sosab76e0ee2013-05-22 16:55:41 -070026 """Returns sharding_factor from global_config."""
Chris Masone44e4d6c2012-08-15 14:25:53 -070027 return _CONFIG.get_config_value('CROS', 'sharding_factor', type=int)
28
29
Chris Sosa66dfb372013-01-29 16:36:19 -080030def infrastructure_user():
Chris Sosab76e0ee2013-05-22 16:55:41 -070031 """Returns infrastructure_user from global_config."""
Chris Sosa66dfb372013-01-29 16:36:19 -080032 return _CONFIG.get_config_value('CROS', 'infrastructure_user', type=str)
Chris Masonee99bcf22012-08-17 15:09:49 -070033
34
Chris Masone44e4d6c2012-08-15 14:25:53 -070035def package_url_pattern():
Chris Sosab76e0ee2013-05-22 16:55:41 -070036 """Returns package_url_pattern from global_config."""
Chris Masone44e4d6c2012-08-15 14:25:53 -070037 return _CONFIG.get_config_value('CROS', 'package_url_pattern', type=str)
38
39
Alex Millerf8aafe62013-02-25 14:39:46 -080040def try_job_timeout_mins():
Chris Sosab76e0ee2013-05-22 16:55:41 -070041 """Returns try_job_timeout_mins from global_config."""
Alex Millerf8aafe62013-02-25 14:39:46 -080042 return _CONFIG.get_config_value('SCHEDULER', 'try_job_timeout_mins',
43 type=int, default=4*60)
44
45
Chris Sosaaccb5ce2012-08-30 17:29:15 -070046def get_package_url(devserver_url, build):
47 """Returns the package url from the |devserver_url| and |build|.
48
49 @param devserver_url: a string specifying the host to contact e.g.
50 http://my_host:9090.
51 @param build: the build/image string to use e.g. mario-release/R19-123.0.1.
52 @return the url where you can find the packages for the build.
53 """
Chris Masone44e4d6c2012-08-15 14:25:53 -070054 return package_url_pattern() % (devserver_url, build)
55
56
Chris Sosab76e0ee2013-05-22 16:55:41 -070057def get_devserver_build_from_package_url(package_url):
58 """The inverse method of get_package_url.
59
60 @param package_url: a string specifying the package url.
61
62 @return tuple containing the devserver_url, build.
63 """
64 pattern = package_url_pattern()
65 re_pattern = pattern.replace('%s', '(\S+)')
66 return re.search(re_pattern, package_url).groups()
67
68
Wade Guthrie44668f92012-10-18 09:44:49 -070069def get_random_best_host(afe, host_list, require_usable_hosts=True):
70 """
71 Randomly choose the 'best' host from host_list, using fresh status.
72
73 Hit the AFE to get latest status for the listed hosts. Then apply
74 the following heuristic to pick the 'best' set:
75
76 Remove unusable hosts (not tools.is_usable()), then
77 'Ready' > 'Running, Cleaning, Verifying, etc'
78
79 If any 'Ready' hosts exist, return a random choice. If not, randomly
80 choose from the next tier. If there are none of those either, None.
81
82 @param afe: autotest front end that holds the hosts being managed.
83 @param host_list: an iterable of Host objects, per server/frontend.py
84 @param require_usable_hosts: only return hosts currently in a usable
85 state.
86 @return a Host object, or None if no appropriate host is found.
87 """
88 if not host_list:
89 return None
90 hostnames = [host.hostname for host in host_list]
91 updated_hosts = afe.get_hosts(hostnames=hostnames)
92 usable_hosts = [host for host in updated_hosts if is_usable(host)]
93 ready_hosts = [host for host in usable_hosts if host.status == 'Ready']
94 unusable_hosts = [h for h in updated_hosts if not is_usable(h)]
95 if ready_hosts:
96 return random.choice(ready_hosts)
97 if usable_hosts:
98 return random.choice(usable_hosts)
99 if not require_usable_hosts and unusable_hosts:
100 return random.choice(unusable_hosts)
101 return None
102
103
Chris Masone44e4d6c2012-08-15 14:25:53 -0700104def inject_vars(vars, control_file_in):
105 """
106 Inject the contents of |vars| into |control_file_in|.
107
108 @param vars: a dict to shoehorn into the provided control file string.
109 @param control_file_in: the contents of a control file to munge.
110 @return the modified control file string.
111 """
112 control_file = ''
113 for key, value in vars.iteritems():
114 # None gets injected as 'None' without this check; same for digits.
115 if isinstance(value, str):
116 control_file += "%s='%s'\n" % (key, value)
117 else:
118 control_file += "%s=%r\n" % (key, value)
119 return control_file + control_file_in
Chris Masone8906ab12012-07-23 15:37:56 -0700120
121
122def is_usable(host):
123 """
124 Given a host, determine if the host is usable right now.
125
126 @param host: Host instance (as in server/frontend.py)
127 @return True if host is alive and not incorrectly locked. Else, False.
128 """
129 return alive(host) and not incorrectly_locked(host)
130
131
132def alive(host):
133 """
134 Given a host, determine if the host is alive.
135
136 @param host: Host instance (as in server/frontend.py)
137 @return True if host is not under, or in need of, repair. Else, False.
138 """
139 return host.status not in ['Repair Failed', 'Repairing']
140
141
142def incorrectly_locked(host):
143 """
144 Given a host, determine if the host is locked by some user.
145
146 If the host is unlocked, or locked by the test infrastructure,
Chris Sosa66dfb372013-01-29 16:36:19 -0800147 this will return False. There is only one system user defined as part
148 of the test infrastructure and is listed in global_config.ini under the
149 [CROS] section in the 'infrastructure_user' field.
Chris Masone8906ab12012-07-23 15:37:56 -0700150
151 @param host: Host instance (as in server/frontend.py)
152 @return False if the host is not locked, or locked by the infra.
Chris Sosa66dfb372013-01-29 16:36:19 -0800153 True if the host is locked by the infra user.
Chris Masone8906ab12012-07-23 15:37:56 -0700154 """
Chris Sosa66dfb372013-01-29 16:36:19 -0800155 return (host.locked and host.locked_by != infrastructure_user())