blob: 47d56367d196ebefebd9afa6aad3af6ac0b0f920 [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+)')
joychen03eaad92013-06-26 09:55:21 -070066
67 devserver_build_tuple = re.search(re_pattern, package_url).groups()
68
69 # TODO(beeps): This is a temporary hack around the fact that all
70 # job_repo_urls in the database currently contain 'archive'. Remove
71 # when all hosts have been reimaged at least once. Ref: crbug.com/214373.
72 return (devserver_build_tuple[0],
73 devserver_build_tuple[1].replace('archive/', ''))
Chris Sosab76e0ee2013-05-22 16:55:41 -070074
75
Wade Guthrie44668f92012-10-18 09:44:49 -070076def get_random_best_host(afe, host_list, require_usable_hosts=True):
77 """
78 Randomly choose the 'best' host from host_list, using fresh status.
79
80 Hit the AFE to get latest status for the listed hosts. Then apply
81 the following heuristic to pick the 'best' set:
82
83 Remove unusable hosts (not tools.is_usable()), then
84 'Ready' > 'Running, Cleaning, Verifying, etc'
85
86 If any 'Ready' hosts exist, return a random choice. If not, randomly
87 choose from the next tier. If there are none of those either, None.
88
89 @param afe: autotest front end that holds the hosts being managed.
90 @param host_list: an iterable of Host objects, per server/frontend.py
91 @param require_usable_hosts: only return hosts currently in a usable
92 state.
93 @return a Host object, or None if no appropriate host is found.
94 """
95 if not host_list:
96 return None
97 hostnames = [host.hostname for host in host_list]
98 updated_hosts = afe.get_hosts(hostnames=hostnames)
99 usable_hosts = [host for host in updated_hosts if is_usable(host)]
100 ready_hosts = [host for host in usable_hosts if host.status == 'Ready']
101 unusable_hosts = [h for h in updated_hosts if not is_usable(h)]
102 if ready_hosts:
103 return random.choice(ready_hosts)
104 if usable_hosts:
105 return random.choice(usable_hosts)
106 if not require_usable_hosts and unusable_hosts:
107 return random.choice(unusable_hosts)
108 return None
109
110
Chris Masone44e4d6c2012-08-15 14:25:53 -0700111def inject_vars(vars, control_file_in):
112 """
113 Inject the contents of |vars| into |control_file_in|.
114
115 @param vars: a dict to shoehorn into the provided control file string.
116 @param control_file_in: the contents of a control file to munge.
117 @return the modified control file string.
118 """
119 control_file = ''
120 for key, value in vars.iteritems():
121 # None gets injected as 'None' without this check; same for digits.
122 if isinstance(value, str):
123 control_file += "%s='%s'\n" % (key, value)
124 else:
125 control_file += "%s=%r\n" % (key, value)
126 return control_file + control_file_in
Chris Masone8906ab12012-07-23 15:37:56 -0700127
128
129def is_usable(host):
130 """
131 Given a host, determine if the host is usable right now.
132
133 @param host: Host instance (as in server/frontend.py)
134 @return True if host is alive and not incorrectly locked. Else, False.
135 """
136 return alive(host) and not incorrectly_locked(host)
137
138
139def alive(host):
140 """
141 Given a host, determine if the host is alive.
142
143 @param host: Host instance (as in server/frontend.py)
144 @return True if host is not under, or in need of, repair. Else, False.
145 """
146 return host.status not in ['Repair Failed', 'Repairing']
147
148
149def incorrectly_locked(host):
150 """
151 Given a host, determine if the host is locked by some user.
152
153 If the host is unlocked, or locked by the test infrastructure,
Chris Sosa66dfb372013-01-29 16:36:19 -0800154 this will return False. There is only one system user defined as part
155 of the test infrastructure and is listed in global_config.ini under the
156 [CROS] section in the 'infrastructure_user' field.
Chris Masone8906ab12012-07-23 15:37:56 -0700157
158 @param host: Host instance (as in server/frontend.py)
159 @return False if the host is not locked, or locked by the infra.
Chris Sosa66dfb372013-01-29 16:36:19 -0800160 True if the host is locked by the infra user.
Chris Masone8906ab12012-07-23 15:37:56 -0700161 """
Chris Sosa66dfb372013-01-29 16:36:19 -0800162 return (host.locked and host.locked_by != infrastructure_user())