site_utils.py revision 05ae2a45397188dd7d7adbc49a61095ebf85e151
1a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi# Copyright (c) 2013 The Chromium Authors. All rights reserved.
2a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi# Use of this source code is governed by a BSD-style license that can be
3a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi# found in the LICENSE file.
4a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
5dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller
618699fef3341507c6b0d415ced96f6e25e3c03eaFang Dengimport grp
73cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnetteimport httplib
83cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnetteimport json
9a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shiimport logging
1035d661e09666d315325f8942d06949ca7283666fMK Ryuimport os
11023afc65f9377db51ff6122977a9f529a32422d3beepsimport random
12dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Millerimport re
133cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnetteimport time
14bef578d9163c6574d626e8b98298c59a5ab79221Paul Drewsimport urllib2
15a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
163cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnetteimport common
17ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shifrom autotest_lib.client.common_lib import utils
18023afc65f9377db51ff6122977a9f529a32422d3beepsfrom autotest_lib.client.common_lib import error
19023afc65f9377db51ff6122977a9f529a32422d3beepsfrom autotest_lib.client.common_lib import global_config
200c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryufrom autotest_lib.client.common_lib import host_queue_entry_states
217756a0b6949729cb5a632955ebd8fe5dbd308c08Simran Basifrom autotest_lib.server.cros import provision
22a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shifrom autotest_lib.server.cros.dynamic_suite import constants
237e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shifrom autotest_lib.server.cros.dynamic_suite import job_status
24a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
2582997b9a9791105d81c9db14e75ed14946f78f94Dan Shitry:
2682997b9a9791105d81c9db14e75ed14946f78f94Dan Shi    from chromite.lib import cros_build_lib
2782997b9a9791105d81c9db14e75ed14946f78f94Dan Shiexcept ImportError:
2882997b9a9791105d81c9db14e75ed14946f78f94Dan Shi    logging.warn('Unable to import chromite.')
2982997b9a9791105d81c9db14e75ed14946f78f94Dan Shi    # Init the module variable to None. Access to this module can check if it
3082997b9a9791105d81c9db14e75ed14946f78f94Dan Shi    # is not None before making calls.
3182997b9a9791105d81c9db14e75ed14946f78f94Dan Shi    cros_build_lib = None
3282997b9a9791105d81c9db14e75ed14946f78f94Dan Shi
33a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
34d37736b67febeebd991d0209dd030635f7ff5cfdDan ShiCONFIG = global_config.global_config
35d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi
36d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi_SHERIFF_JS = CONFIG.get_config_value('NOTIFICATIONS', 'sheriffs', default='')
37d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi_LAB_SHERIFF_JS = CONFIG.get_config_value(
38d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi        'NOTIFICATIONS', 'lab_sheriffs', default='')
39d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi_CHROMIUM_BUILD_URL = CONFIG.get_config_value(
40d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi        'NOTIFICATIONS', 'chromium_build_url', default='')
41dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller
423cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard BarnetteLAB_GOOD_STATES = ('open', 'throttled')
433cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
44d37736b67febeebd991d0209dd030635f7ff5cfdDan ShiENABLE_DRONE_IN_RESTRICTED_SUBNET = CONFIG.get_config_value(
45d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi        'CROS', 'enable_drone_in_restricted_subnet', type=bool,
46d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi        default=False)
473cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
48abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnetteclass TestLabException(Exception):
49abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    """Exception raised when the Test Lab blocks a test or suite."""
503cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    pass
513cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
523cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
533cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnetteclass ParseBuildNameException(Exception):
543cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    """Raised when ParseBuildName() cannot parse a build name."""
553cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    pass
563cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
573cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
58f08814a436cdff50ea26571001e72a09e3d57aafFang Dengclass Singleton(type):
59f08814a436cdff50ea26571001e72a09e3d57aafFang Deng    """Enforce that only one client class is instantiated per process."""
60f08814a436cdff50ea26571001e72a09e3d57aafFang Deng    _instances = {}
61f08814a436cdff50ea26571001e72a09e3d57aafFang Deng
62f08814a436cdff50ea26571001e72a09e3d57aafFang Deng    def __call__(cls, *args, **kwargs):
63f08814a436cdff50ea26571001e72a09e3d57aafFang Deng        """Fetch the instance of a class to use for subsequent calls."""
64f08814a436cdff50ea26571001e72a09e3d57aafFang Deng        if cls not in cls._instances:
65f08814a436cdff50ea26571001e72a09e3d57aafFang Deng            cls._instances[cls] = super(Singleton, cls).__call__(
66f08814a436cdff50ea26571001e72a09e3d57aafFang Deng                    *args, **kwargs)
67f08814a436cdff50ea26571001e72a09e3d57aafFang Deng        return cls._instances[cls]
68f08814a436cdff50ea26571001e72a09e3d57aafFang Deng
6905ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Chengclass EmptyAFEHost(object):
7005ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng    """Object to represent an AFE host object when there is no AFE."""
7105ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng
7205ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng    def __init__(self):
7305ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        """
7405ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        We'll be setting the instance attributes as we use them.  Right now
7505ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        we only use attributes and labels but as time goes by and other
7605ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        attributes are used from an actual AFE Host object (check
7705ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        rpc_interfaces.get_hosts()), we'll add them in here so users won't be
7805ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        perplexed why their host's afe_host object complains that attribute
7905ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        doesn't exist.
8005ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        """
8105ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        self.attributes = {}
8205ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        self.labels = []
8305ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng
84f08814a436cdff50ea26571001e72a09e3d57aafFang Deng
853cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnettedef ParseBuildName(name):
863cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    """Format a build name, given board, type, milestone, and manifest num.
873cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
88b7d2116ad62dd09c52791c8f27dfa61b9df186b9Simran Basi    @param name: a build name, e.g. 'x86-alex-release/R20-2015.0.0' or a
89b7d2116ad62dd09c52791c8f27dfa61b9df186b9Simran Basi                 relative build name, e.g. 'x86-alex-release/LATEST'
903cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
913cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    @return board: board the manifest is for, e.g. x86-alex.
923cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    @return type: one of 'release', 'factory', or 'firmware'
933cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    @return milestone: (numeric) milestone the manifest was associated with.
94b7d2116ad62dd09c52791c8f27dfa61b9df186b9Simran Basi                        Will be None for relative build names.
95b7d2116ad62dd09c52791c8f27dfa61b9df186b9Simran Basi    @return manifest: manifest number, e.g. '2015.0.0'.
96b7d2116ad62dd09c52791c8f27dfa61b9df186b9Simran Basi                      Will be None for relative build names.
973cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
983cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    """
99f8f648e049ca2f8777fa55c0ea9c4f886efecea9Simran Basi    match = re.match(r'(trybot-)?(?P<board>[\w-]+)-(?P<type>\w+)/'
100f8f648e049ca2f8777fa55c0ea9c4f886efecea9Simran Basi                     r'(R(?P<milestone>\d+)-(?P<manifest>[\d.ab-]+)|LATEST)',
101f8f648e049ca2f8777fa55c0ea9c4f886efecea9Simran Basi                     name)
102f8f648e049ca2f8777fa55c0ea9c4f886efecea9Simran Basi    if match and len(match.groups()) >= 5:
103b7d2116ad62dd09c52791c8f27dfa61b9df186b9Simran Basi        return (match.group('board'), match.group('type'),
104b7d2116ad62dd09c52791c8f27dfa61b9df186b9Simran Basi                match.group('milestone'), match.group('manifest'))
1053cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    raise ParseBuildNameException('%s is a malformed build name.' % name)
1063cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
107dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller
1083d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shidef get_labels_from_afe(hostname, label_prefix, afe):
1093d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    """Retrieve a host's specific labels from the AFE.
1103d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi
1113d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    Looks for the host labels that have the form <label_prefix>:<value>
1123d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    and returns the "<value>" part of the label. None is returned
1133d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    if there is not a label matching the pattern
1143d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi
1153d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    @param hostname: hostname of given DUT.
1163d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    @param label_prefix: prefix of label to be matched, e.g., |board:|
1173d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    @param afe: afe instance.
1183d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi
1193d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    @returns A list of labels that match the prefix or 'None'
1203d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi
1213d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    """
1223d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    labels = afe.get_labels(name__startswith=label_prefix,
1233d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi                            host__hostname__in=[hostname])
1243d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    if labels:
1253d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi        return [l.name.split(label_prefix, 1)[1] for l in labels]
1263d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi
1273d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi
128a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shidef get_label_from_afe(hostname, label_prefix, afe):
129a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    """Retrieve a host's specific label from the AFE.
130a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
131a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    Looks for a host label that has the form <label_prefix>:<value>
132a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    and returns the "<value>" part of the label. None is returned
133a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    if there is not a label matching the pattern
134a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
135a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    @param hostname: hostname of given DUT.
136a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    @param label_prefix: prefix of label to be matched, e.g., |board:|
137a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    @param afe: afe instance.
138a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    @returns the label that matches the prefix or 'None'
139a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
140a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    """
1413d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi    labels = get_labels_from_afe(hostname, label_prefix, afe)
142a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    if labels and len(labels) == 1:
1433d7a0e14e220d7ea2cbe00013959c6d967a6a41aDan Shi        return labels[0]
144a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
145a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
146a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shidef get_board_from_afe(hostname, afe):
147a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    """Retrieve given host's board from its labels in the AFE.
148a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
149a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    Looks for a host label of the form "board:<board>", and
150a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    returns the "<board>" part of the label.  `None` is returned
151a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    if there is not a single, unique label matching the pattern.
152a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
153a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    @param hostname: hostname of given DUT.
154a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    @param afe: afe instance.
155a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    @returns board from label, or `None`.
156a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
157a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    """
158a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    return get_label_from_afe(hostname, constants.BOARD_PREFIX, afe)
159a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
160a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
161a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shidef get_build_from_afe(hostname, afe):
162a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    """Retrieve the current build for given host from the AFE.
163a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
164a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    Looks through the host's labels in the AFE to determine its build.
165a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
166a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    @param hostname: hostname of given DUT.
167a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    @param afe: afe instance.
168a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    @returns The current build or None if it could not find it or if there
169a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi             were multiple build labels assigned to this host.
170a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
171a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi    """
1727756a0b6949729cb5a632955ebd8fe5dbd308c08Simran Basi    for prefix in [provision.CROS_VERSION_PREFIX,
1737756a0b6949729cb5a632955ebd8fe5dbd308c08Simran Basi                   provision.ANDROID_BUILD_VERSION_PREFIX]:
1747756a0b6949729cb5a632955ebd8fe5dbd308c08Simran Basi        build = get_label_from_afe(hostname, prefix + ':', afe)
1757756a0b6949729cb5a632955ebd8fe5dbd308c08Simran Basi        if build:
1767756a0b6949729cb5a632955ebd8fe5dbd308c08Simran Basi            return build
1777756a0b6949729cb5a632955ebd8fe5dbd308c08Simran Basi    return None
178a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
179a1ecd5c903928f359cd6cbcff5c986652e109599Dan Shi
1803197b39f82eb92afff33c7d44b805afe120c7627Fang Dengdef get_sheriffs(lab_only=False):
181dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller    """
182dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller    Polls the javascript file that holds the identity of the sheriff and
183dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller    parses it's output to return a list of chromium sheriff email addresses.
184dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller    The javascript file can contain the ldap of more than one sheriff, eg:
185dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller    document.write('sheriff_one, sheriff_two').
186dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller
1873197b39f82eb92afff33c7d44b805afe120c7627Fang Deng    @param lab_only: if True, only pulls lab sheriff.
1883197b39f82eb92afff33c7d44b805afe120c7627Fang Deng    @return: A list of chroium.org sheriff email addresses to cc on the bug.
1893197b39f82eb92afff33c7d44b805afe120c7627Fang Deng             An empty list if failed to parse the javascript.
190dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller    """
191dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller    sheriff_ids = []
1923197b39f82eb92afff33c7d44b805afe120c7627Fang Deng    sheriff_js_list = _LAB_SHERIFF_JS.split(',')
1933197b39f82eb92afff33c7d44b805afe120c7627Fang Deng    if not lab_only:
1943197b39f82eb92afff33c7d44b805afe120c7627Fang Deng        sheriff_js_list.extend(_SHERIFF_JS.split(','))
1953197b39f82eb92afff33c7d44b805afe120c7627Fang Deng
1963197b39f82eb92afff33c7d44b805afe120c7627Fang Deng    for sheriff_js in sheriff_js_list:
197dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller        try:
198ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi            url_content = utils.urlopen('%s%s'% (
199dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller                _CHROMIUM_BUILD_URL, sheriff_js)).read()
200dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller        except (ValueError, IOError) as e:
2014efdf03d1057f9d38e043b7c2affe842109805d2beeps            logging.warning('could not parse sheriff from url %s%s: %s',
2024efdf03d1057f9d38e043b7c2affe842109805d2beeps                             _CHROMIUM_BUILD_URL, sheriff_js, str(e))
203bef578d9163c6574d626e8b98298c59a5ab79221Paul Drews        except (urllib2.URLError, httplib.HTTPException) as e:
204bef578d9163c6574d626e8b98298c59a5ab79221Paul Drews            logging.warning('unexpected error reading from url "%s%s": %s',
205bef578d9163c6574d626e8b98298c59a5ab79221Paul Drews                             _CHROMIUM_BUILD_URL, sheriff_js, str(e))
206dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller        else:
207dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller            ldaps = re.search(r"document.write\('(.*)'\)", url_content)
208dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller            if not ldaps:
2094efdf03d1057f9d38e043b7c2affe842109805d2beeps                logging.warning('Could not retrieve sheriff ldaps for: %s',
2104efdf03d1057f9d38e043b7c2affe842109805d2beeps                                 url_content)
211dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller                continue
212dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller            sheriff_ids += ['%s@chromium.org' % alias.replace(' ', '')
213dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller                            for alias in ldaps.group(1).split(',')]
214dadc2c21c0b0b904067ea6400e179a187c0247d4Alex Miller    return sheriff_ids
21546dadc9439355f72d394dcc4700902001bd797ffbeeps
21646dadc9439355f72d394dcc4700902001bd797ffbeeps
21746dadc9439355f72d394dcc4700902001bd797ffbeepsdef remote_wget(source_url, dest_path, ssh_cmd):
21846dadc9439355f72d394dcc4700902001bd797ffbeeps    """wget source_url from localhost to dest_path on remote host using ssh.
21946dadc9439355f72d394dcc4700902001bd797ffbeeps
22046dadc9439355f72d394dcc4700902001bd797ffbeeps    @param source_url: The complete url of the source of the package to send.
22146dadc9439355f72d394dcc4700902001bd797ffbeeps    @param dest_path: The path on the remote host's file system where we would
22246dadc9439355f72d394dcc4700902001bd797ffbeeps        like to store the package.
22346dadc9439355f72d394dcc4700902001bd797ffbeeps    @param ssh_cmd: The ssh command to use in performing the remote wget.
22446dadc9439355f72d394dcc4700902001bd797ffbeeps    """
22546dadc9439355f72d394dcc4700902001bd797ffbeeps    wget_cmd = ("wget -O - %s | %s 'cat >%s'" %
22646dadc9439355f72d394dcc4700902001bd797ffbeeps                (source_url, ssh_cmd, dest_path))
227ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi    utils.run(wget_cmd)
22846dadc9439355f72d394dcc4700902001bd797ffbeeps
2293cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
230266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette_MAX_LAB_STATUS_ATTEMPTS = 5
231266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnettedef _get_lab_status(status_url):
2323cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    """Grabs the current lab status and message.
2333cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
234266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette    @returns The JSON object obtained from the given URL.
235266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette
2363cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    """
2373cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    retry_waittime = 1
238266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette    for _ in range(_MAX_LAB_STATUS_ATTEMPTS):
2393cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette        try:
2403cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette            response = urllib2.urlopen(status_url)
2413cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette        except IOError as e:
242266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette            logging.debug('Error occurred when grabbing the lab status: %s.',
2433cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette                          e)
2443cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette            time.sleep(retry_waittime)
2453cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette            continue
2463cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette        # Check for successful response code.
2473cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette        if response.getcode() == 200:
248266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette            return json.load(response)
2493cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette        time.sleep(retry_waittime)
250266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette    return None
2513cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
2523cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
253abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnettedef _decode_lab_status(lab_status, build):
254266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette    """Decode lab status, and report exceptions as needed.
2553cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
256abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    Take a deserialized JSON object from the lab status page, and
257abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    interpret it to determine the actual lab status.  Raise
258266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette    exceptions as required to report when the lab is down.
2593cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
260abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    @param build: build name that we want to check the status of.
2613cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
262abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    @raises TestLabException Raised if a request to test for the given
263abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette                             status and build should be blocked.
2643cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    """
2653cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    # First check if the lab is up.
266266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette    if not lab_status['general_state'] in LAB_GOOD_STATES:
267abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette        raise TestLabException('Chromium OS Test Lab is closed: '
268abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette                               '%s.' % lab_status['message'])
2693cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette
270abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    # Check if the build we wish to use is disabled.
2713cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    # Lab messages should be in the format of:
272abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    #    Lab is 'status' [regex ...] (comment)
273abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    # If the build name matches any regex, it will be blocked.
274abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    build_exceptions = re.search('\[(.*)\]', lab_status['message'])
275ae43721d4a11c6ecd2d502bba73b185b05bfce29Prashanth Balasubramanian    if not build_exceptions or not build:
276abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette        return
277abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    for build_pattern in build_exceptions.group(1).split():
2787f215d3906ac204694d64b7eaa85155777f88f39J. Richard Barnette        if re.match(build_pattern, build):
279abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette            raise TestLabException('Chromium OS Test Lab is closed: '
280abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette                                   '%s matches %s.' % (
281abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette                                           build, build_pattern))
2823cbd76b06c383d8bc3e4ba959659a0bd04180761J. Richard Barnette    return
283266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette
284266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette
28594234cb747dc067b159789a4b63f21b23d706922Dan Shidef is_in_lab():
28694234cb747dc067b159789a4b63f21b23d706922Dan Shi    """Check if current Autotest instance is in lab
28794234cb747dc067b159789a4b63f21b23d706922Dan Shi
28894234cb747dc067b159789a4b63f21b23d706922Dan Shi    @return: True if the Autotest instance is in lab.
28994234cb747dc067b159789a4b63f21b23d706922Dan Shi    """
290d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi    test_server_name = CONFIG.get_config_value('SERVER', 'hostname')
29194234cb747dc067b159789a4b63f21b23d706922Dan Shi    return test_server_name.startswith('cautotest')
29294234cb747dc067b159789a4b63f21b23d706922Dan Shi
29394234cb747dc067b159789a4b63f21b23d706922Dan Shi
294abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnettedef check_lab_status(build):
295abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    """Check if the lab status allows us to schedule for a build.
296266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette
297abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    Checks if the lab is down, or if testing for the requested build
298abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    should be blocked.
299266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette
300abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    @param build: Name of the build to be scheduled for testing.
301266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette
302abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    @raises TestLabException Raised if a request to test for the given
303abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette                             status and build should be blocked.
304266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette
305266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette    """
306266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette    # Ensure we are trying to schedule on the actual lab.
30794234cb747dc067b159789a4b63f21b23d706922Dan Shi    if not is_in_lab():
308266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette        return
309266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette
310266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette    # Download the lab status from its home on the web.
311d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi    status_url = CONFIG.get_config_value('CROS', 'lab_status_url')
312266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette    json_status = _get_lab_status(status_url)
313266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette    if json_status is None:
314266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette        # We go ahead and say the lab is open if we can't get the status.
31504be2bd5e4666a5c253e9c30ab20555e04286032Ilja H. Friedel        logging.warning('Could not get a status from %s', status_url)
316266da2a226391a7153df264d54dcb54635df7bfcJ. Richard Barnette        return
317abbe09600d73d77af92157027a20661c035be01eJ. Richard Barnette    _decode_lab_status(json_status, build)
318023afc65f9377db51ff6122977a9f529a32422d3beeps
319023afc65f9377db51ff6122977a9f529a32422d3beeps
320023afc65f9377db51ff6122977a9f529a32422d3beepsdef lock_host_with_labels(afe, lock_manager, labels):
321023afc65f9377db51ff6122977a9f529a32422d3beeps    """Lookup and lock one host that matches the list of input labels.
322023afc65f9377db51ff6122977a9f529a32422d3beeps
323023afc65f9377db51ff6122977a9f529a32422d3beeps    @param afe: An instance of the afe class, as defined in server.frontend.
324023afc65f9377db51ff6122977a9f529a32422d3beeps    @param lock_manager: A lock manager capable of locking hosts, eg the
325023afc65f9377db51ff6122977a9f529a32422d3beeps        one defined in server.cros.host_lock_manager.
326023afc65f9377db51ff6122977a9f529a32422d3beeps    @param labels: A list of labels to look for on hosts.
327023afc65f9377db51ff6122977a9f529a32422d3beeps
328023afc65f9377db51ff6122977a9f529a32422d3beeps    @return: The hostname of a host matching all labels, and locked through the
329023afc65f9377db51ff6122977a9f529a32422d3beeps        lock_manager. The hostname will be as specified in the database the afe
330023afc65f9377db51ff6122977a9f529a32422d3beeps        object is associated with, i.e if it exists in afe_hosts with a .cros
331023afc65f9377db51ff6122977a9f529a32422d3beeps        suffix, the hostname returned will contain a .cros suffix.
332023afc65f9377db51ff6122977a9f529a32422d3beeps
333023afc65f9377db51ff6122977a9f529a32422d3beeps    @raises: error.NoEligibleHostException: If no hosts matching the list of
334023afc65f9377db51ff6122977a9f529a32422d3beeps        input labels are available.
335023afc65f9377db51ff6122977a9f529a32422d3beeps    @raises: error.TestError: If unable to lock a host matching the labels.
336023afc65f9377db51ff6122977a9f529a32422d3beeps    """
337023afc65f9377db51ff6122977a9f529a32422d3beeps    potential_hosts = afe.get_hosts(multiple_labels=labels)
338023afc65f9377db51ff6122977a9f529a32422d3beeps    if not potential_hosts:
339023afc65f9377db51ff6122977a9f529a32422d3beeps        raise error.NoEligibleHostException(
340023afc65f9377db51ff6122977a9f529a32422d3beeps                'No devices found with labels %s.' % labels)
341023afc65f9377db51ff6122977a9f529a32422d3beeps
342023afc65f9377db51ff6122977a9f529a32422d3beeps    # This prevents errors where a fault might seem repeatable
343023afc65f9377db51ff6122977a9f529a32422d3beeps    # because we lock, say, the same packet capturer for each test run.
344023afc65f9377db51ff6122977a9f529a32422d3beeps    random.shuffle(potential_hosts)
345023afc65f9377db51ff6122977a9f529a32422d3beeps    for host in potential_hosts:
346023afc65f9377db51ff6122977a9f529a32422d3beeps        if lock_manager.lock([host.hostname]):
347023afc65f9377db51ff6122977a9f529a32422d3beeps            logging.info('Locked device %s with labels %s.',
348023afc65f9377db51ff6122977a9f529a32422d3beeps                         host.hostname, labels)
349023afc65f9377db51ff6122977a9f529a32422d3beeps            return host.hostname
350023afc65f9377db51ff6122977a9f529a32422d3beeps        else:
351023afc65f9377db51ff6122977a9f529a32422d3beeps            logging.info('Unable to lock device %s with labels %s.',
352023afc65f9377db51ff6122977a9f529a32422d3beeps                         host.hostname, labels)
353023afc65f9377db51ff6122977a9f529a32422d3beeps
354023afc65f9377db51ff6122977a9f529a32422d3beeps    raise error.TestError('Could not lock a device with labels %s' % labels)
3557e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3567e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3577e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shidef get_test_views_from_tko(suite_job_id, tko):
3587e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """Get test name and result for given suite job ID.
3597e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3607e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @param suite_job_id: ID of suite job.
3617e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @param tko: an instance of TKO as defined in server/frontend.py.
3627e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @return: A dictionary of test status keyed by test name, e.g.,
3637e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi             {'dummy_Fail.Error': 'ERROR', 'dummy_Fail.NAError': 'TEST_NA'}
3647e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @raise: Exception when there is no test view found.
3657e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3667e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """
3677e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    views = tko.run('get_detailed_test_views', afe_job_id=suite_job_id)
3687e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    relevant_views = filter(job_status.view_is_relevant, views)
3697e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if not relevant_views:
3707e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        raise Exception('Failed to retrieve job results.')
3717e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3727e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    test_views = {}
3737e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    for view in relevant_views:
3747e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        test_views[view['test_name']] = view['status']
3757e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3767e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    return test_views
37735d661e09666d315325f8942d06949ca7283666fMK Ryu
37835d661e09666d315325f8942d06949ca7283666fMK Ryu
379c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef get_data_key(prefix, suite, build, board):
380c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    """
381c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    Constructs a key string from parameters.
382c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu
383c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    @param prefix: Prefix for the generating key.
384c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    @param suite: a suite name. e.g., bvt-cq, bvt-inline, dummy
385c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    @param build: The build string. This string should have a consistent
386c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        format eg: x86-mario-release/R26-3570.0.0. If the format of this
387c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        string changes such that we can't determine build_type or branch
388c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        we give up and use the parametes we're sure of instead (suite,
389c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        board). eg:
390c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu            1. build = x86-alex-pgo-release/R26-3570.0.0
391c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu               branch = 26
392c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu               build_type = pgo-release
393c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu            2. build = lumpy-paladin/R28-3993.0.0-rc5
394c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu               branch = 28
395c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu               build_type = paladin
396c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    @param board: The board that this suite ran on.
397c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    @return: The key string used for a dictionary.
398c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    """
399c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    try:
400c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        _board, build_type, branch = ParseBuildName(build)[:3]
401c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    except ParseBuildNameException as e:
402c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        logging.error(str(e))
403c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        branch = 'Unknown'
404c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        build_type = 'Unknown'
405c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    else:
406c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        embedded_str = re.search(r'x86-\w+-(.*)', _board)
407c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        if embedded_str:
408c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu            build_type = embedded_str.group(1) + '-' + build_type
409c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu
410c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    data_key_dict = {
411c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        'prefix': prefix,
412c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        'board': board,
413c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        'branch': branch,
414c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        'build_type': build_type,
415c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu        'suite': suite,
416c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    }
417c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu    return ('%(prefix)s.%(board)s.%(build_type)s.%(branch)s.%(suite)s'
418c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu            % data_key_dict)
41983184356b60f4352e46e69488d54222032d426c0MK Ryu
42083184356b60f4352e46e69488d54222032d426c0MK Ryu
4212d0a364b21297418bef4d7f32acee8831e4eeefeMK Ryudef setup_logging(logfile=None, prefix=False):
42283184356b60f4352e46e69488d54222032d426c0MK Ryu    """Setup basic logging with all logging info stripped.
42383184356b60f4352e46e69488d54222032d426c0MK Ryu
42483184356b60f4352e46e69488d54222032d426c0MK Ryu    Calls to logging will only show the message. No severity is logged.
42583184356b60f4352e46e69488d54222032d426c0MK Ryu
42683184356b60f4352e46e69488d54222032d426c0MK Ryu    @param logfile: If specified dump output to a file as well.
4272d0a364b21297418bef4d7f32acee8831e4eeefeMK Ryu    @param prefix: Flag for log prefix. Set to True to add prefix to log
4282d0a364b21297418bef4d7f32acee8831e4eeefeMK Ryu        entries to include timestamp and log level. Default is False.
42983184356b60f4352e46e69488d54222032d426c0MK Ryu    """
43083184356b60f4352e46e69488d54222032d426c0MK Ryu    # Remove all existing handlers. client/common_lib/logging_config adds
43183184356b60f4352e46e69488d54222032d426c0MK Ryu    # a StreamHandler to logger when modules are imported, e.g.,
43283184356b60f4352e46e69488d54222032d426c0MK Ryu    # autotest_lib.client.bin.utils. A new StreamHandler will be added here to
43383184356b60f4352e46e69488d54222032d426c0MK Ryu    # log only messages, not severity.
43483184356b60f4352e46e69488d54222032d426c0MK Ryu    logging.getLogger().handlers = []
43583184356b60f4352e46e69488d54222032d426c0MK Ryu
4362d0a364b21297418bef4d7f32acee8831e4eeefeMK Ryu    if prefix:
4372d0a364b21297418bef4d7f32acee8831e4eeefeMK Ryu        log_format = '%(asctime)s %(levelname)-5s| %(message)s'
4382d0a364b21297418bef4d7f32acee8831e4eeefeMK Ryu    else:
4392d0a364b21297418bef4d7f32acee8831e4eeefeMK Ryu        log_format = '%(message)s'
4402d0a364b21297418bef4d7f32acee8831e4eeefeMK Ryu
44183184356b60f4352e46e69488d54222032d426c0MK Ryu    screen_handler = logging.StreamHandler()
4422d0a364b21297418bef4d7f32acee8831e4eeefeMK Ryu    screen_handler.setFormatter(logging.Formatter(log_format))
44383184356b60f4352e46e69488d54222032d426c0MK Ryu    logging.getLogger().addHandler(screen_handler)
44483184356b60f4352e46e69488d54222032d426c0MK Ryu    logging.getLogger().setLevel(logging.INFO)
44583184356b60f4352e46e69488d54222032d426c0MK Ryu    if logfile:
44683184356b60f4352e46e69488d54222032d426c0MK Ryu        file_handler = logging.FileHandler(logfile)
4472d0a364b21297418bef4d7f32acee8831e4eeefeMK Ryu        file_handler.setFormatter(logging.Formatter(log_format))
44883184356b60f4352e46e69488d54222032d426c0MK Ryu        file_handler.setLevel(logging.DEBUG)
44983184356b60f4352e46e69488d54222032d426c0MK Ryu        logging.getLogger().addHandler(file_handler)
4508c98ac10beaa08bfb975c412b0b3bda23178763aPrashanth Balasubramanian
4518c98ac10beaa08bfb975c412b0b3bda23178763aPrashanth Balasubramanian
4528c98ac10beaa08bfb975c412b0b3bda23178763aPrashanth Balasubramaniandef is_shard():
4538c98ac10beaa08bfb975c412b0b3bda23178763aPrashanth Balasubramanian    """Determines if this instance is running as a shard.
4548c98ac10beaa08bfb975c412b0b3bda23178763aPrashanth Balasubramanian
4558c98ac10beaa08bfb975c412b0b3bda23178763aPrashanth Balasubramanian    Reads the global_config value shard_hostname in the section SHARD.
4568c98ac10beaa08bfb975c412b0b3bda23178763aPrashanth Balasubramanian
4578c98ac10beaa08bfb975c412b0b3bda23178763aPrashanth Balasubramanian    @return True, if shard_hostname is set, False otherwise.
4588c98ac10beaa08bfb975c412b0b3bda23178763aPrashanth Balasubramanian    """
459d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi    hostname = CONFIG.get_config_value('SHARD', 'shard_hostname', default=None)
4600c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    return bool(hostname)
4610c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
4620c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
4630cb2a3b1d2d86d70da06a3f45be9297139e48207Fang Dengdef get_global_afe_hostname():
4640cb2a3b1d2d86d70da06a3f45be9297139e48207Fang Deng    """Read the hostname of the global AFE from the global configuration."""
465d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi    return CONFIG.get_config_value('SERVER', 'global_afe_hostname')
4660cb2a3b1d2d86d70da06a3f45be9297139e48207Fang Deng
4670cb2a3b1d2d86d70da06a3f45be9297139e48207Fang Deng
46818699fef3341507c6b0d415ced96f6e25e3c03eaFang Dengdef is_restricted_user(username):
46918699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng    """Determines if a user is in a restricted group.
47018699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng
47118699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng    User in restricted group only have access to master.
47218699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng
47318699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng    @param username: A string, representing a username.
47418699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng
47518699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng    @returns: True if the user is in a restricted group.
47618699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng    """
47718699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng    if not username:
47818699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng        return False
47918699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng
480d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi    restricted_groups = CONFIG.get_config_value(
48118699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng            'AUTOTEST_WEB', 'restricted_groups', default='').split(',')
48218699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng    for group in restricted_groups:
4835229c85219e09d6a7857701be20f286ba04809b3Fang Deng        try:
4845229c85219e09d6a7857701be20f286ba04809b3Fang Deng            if group and username in grp.getgrnam(group).gr_mem:
4855229c85219e09d6a7857701be20f286ba04809b3Fang Deng                return True
4865229c85219e09d6a7857701be20f286ba04809b3Fang Deng        except KeyError as e:
4875229c85219e09d6a7857701be20f286ba04809b3Fang Deng            logging.debug("%s is not a valid group.", group)
48818699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng    return False
48918699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng
49018699fef3341507c6b0d415ced96f6e25e3c03eaFang Deng
4910c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryudef get_special_task_status(is_complete, success, is_active):
4920c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    """Get the status of a special task.
4930c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
4940c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    Emulate a host queue entry status for a special task
4950c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    Although SpecialTasks are not HostQueueEntries, it is helpful to
4960c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    the user to present similar statuses.
4970c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
4980c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @param is_complete    Boolean if the task is completed.
4990c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @param success        Boolean if the task succeeded.
5000c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @param is_active      Boolean if the task is active.
5010c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5020c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @return The status of a special task.
5030c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    """
5040c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    if is_complete:
5050c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu        if success:
5060c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu            return host_queue_entry_states.Status.COMPLETED
5070c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu        return host_queue_entry_states.Status.FAILED
5080c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    if is_active:
5090c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu        return host_queue_entry_states.Status.RUNNING
5100c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    return host_queue_entry_states.Status.QUEUED
5110c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5120c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5130c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryudef get_special_task_exec_path(hostname, task_id, task_name, time_requested):
5140c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    """Get the execution path of the SpecialTask.
5150c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5160c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    This method returns different paths depending on where a
5170c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    the task ran:
5180c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu        * Master: hosts/hostname/task_id-task_type
5190c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu        * Shard: Master_path/time_created
5200c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    This is to work around the fact that a shard can fail independent
5210c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    of the master, and be replaced by another shard that has the same
5220c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    hosts. Without the time_created stamp the logs of the tasks running
5230c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    on the second shard will clobber the logs from the first in google
5240c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    storage, because task ids are not globally unique.
5250c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5260c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @param hostname        Hostname
5270c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @param task_id         Special task id
5280c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @param task_name       Special task name (e.g., Verify, Repair, etc)
5290c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @param time_requested  Special task requested time.
5300c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5310c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @return An execution path for the task.
5320c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    """
5330c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    results_path = 'hosts/%s/%s-%s' % (hostname, task_id, task_name.lower())
5340c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5350c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # If we do this on the master it will break backward compatibility,
5360c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # as there are tasks that currently don't have timestamps. If a host
5370c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # or job has been sent to a shard, the rpc for that host/job will
5380c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # be redirected to the shard, so this global_config check will happen
5390c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # on the shard the logs are on.
5400c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    if not is_shard():
5410c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu        return results_path
5420c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5430c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # Generate a uid to disambiguate special task result directories
5440c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # in case this shard fails. The simplest uid is the job_id, however
5450c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # in rare cases tasks do not have jobs associated with them (eg:
5460c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # frontend verify), so just use the creation timestamp. The clocks
5470c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # between a shard and master should always be in sync. Any discrepancies
5480c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # will be brought to our attention in the form of job timeouts.
5490c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    uid = time_requested.strftime('%Y%d%m%H%M%S')
5500c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5510c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # TODO: This is a hack, however it is the easiest way to achieve
5520c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # correctness. There is currently some debate over the future of
5530c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # tasks in our infrastructure and refactoring everything right
5540c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    # now isn't worth the time.
5550c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    return '%s/%s' % (results_path, uid)
5560c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5570c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5580c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryudef get_job_tag(id, owner):
5590c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    """Returns a string tag for a job.
5600c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5610c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @param id    Job id
5620c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @param owner Job owner
5630c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5640c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    """
5650c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    return '%s-%s' % (id, owner)
5660c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5670c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5680c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryudef get_hqe_exec_path(tag, execution_subdir):
5690c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    """Returns a execution path to a HQE's results.
5700c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5710c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @param tag               Tag string for a job associated with a HQE.
5720c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    @param execution_subdir  Execution sub-directory string of a HQE.
5730c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu
5740c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    """
5750c1a37dd9b1237fe8d43c7f911ce601104806339MK Ryu    return os.path.join(tag, execution_subdir)
57682997b9a9791105d81c9db14e75ed14946f78f94Dan Shi
57782997b9a9791105d81c9db14e75ed14946f78f94Dan Shi
57882997b9a9791105d81c9db14e75ed14946f78f94Dan Shidef is_inside_chroot():
57982997b9a9791105d81c9db14e75ed14946f78f94Dan Shi    """Check if the process is running inside chroot.
58082997b9a9791105d81c9db14e75ed14946f78f94Dan Shi
58182997b9a9791105d81c9db14e75ed14946f78f94Dan Shi    This is a wrapper around chromite.lib.cros_build_lib.IsInsideChroot(). The
58282997b9a9791105d81c9db14e75ed14946f78f94Dan Shi    method checks if cros_build_lib can be imported first.
58382997b9a9791105d81c9db14e75ed14946f78f94Dan Shi
58482997b9a9791105d81c9db14e75ed14946f78f94Dan Shi    @return: True if the process is running inside chroot or cros_build_lib
58582997b9a9791105d81c9db14e75ed14946f78f94Dan Shi             cannot be imported.
58682997b9a9791105d81c9db14e75ed14946f78f94Dan Shi
58782997b9a9791105d81c9db14e75ed14946f78f94Dan Shi    """
5887f215d3906ac204694d64b7eaa85155777f88f39J. Richard Barnette    return not cros_build_lib or cros_build_lib.IsInsideChroot()
58970647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi
59070647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi
59170647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shidef parse_job_name(name):
59270647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    """Parse job name to get information including build, board and suite etc.
59370647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi
59470647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    Suite job created by run_suite follows the naming convention of:
59570647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    [build]-test_suites/control.[suite]
59670647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    For example: lumpy-release/R46-7272.0.0-test_suites/control.bvt
59770647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    The naming convention is defined in site_rpc_interface.create_suite_job.
59870647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi
59970647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    Test job created by suite job follows the naming convention of:
60070647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    [build]/[suite]/[test name]
60170647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    For example: lumpy-release/R46-7272.0.0/bvt/login_LoginSuccess
60270647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    The naming convention is defined in
60370647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    server/cros/dynamic_suite/tools.create_job_name
60470647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi
60570647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    Note that pgo and chrome-perf builds will fail the method. Since lab does
60670647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    not run test for these builds, they can be ignored.
607ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi    Also, tests for Launch Control builds have different naming convention.
608ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi    The build ID will be used as build_version.
60970647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi
61070647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    @param name: Name of the job.
61170647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi
61270647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    @return: A dictionary containing the test information. The keyvals include:
61370647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi             build: Name of the build, e.g., lumpy-release/R46-7272.0.0
61470647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi             build_version: The version of the build, e.g., R46-7272.0.0
61570647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi             board: Name of the board, e.g., lumpy
61670647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi             suite: Name of the test suite, e.g., bvt
61770647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi
61870647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    """
61970647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    info = {}
620ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi    suite_job_regex = '([^/]*/[^/]*(?:/\d+)?)-test_suites/control\.(.*)'
621ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi    test_job_regex = '([^/]*/[^/]*(?:/\d+)?)/([^/]+)/.*'
62270647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    match = re.match(suite_job_regex, name)
62370647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    if not match:
62470647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi        match = re.match(test_job_regex, name)
62570647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    if match:
62670647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi        info['build'] = match.groups()[0]
62770647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi        info['suite'] = match.groups()[1]
62870647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi        info['build_version'] = info['build'].split('/')[1]
62970647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi        try:
63070647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi            info['board'], _, _, _ = ParseBuildName(info['build'])
63170647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi        except ParseBuildNameException:
632ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi            # Try to parse it as Launch Control build
633ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi            # Launch Control builds have name format:
634ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi            # branch/build_target-build_type/build_id.
635ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi            try:
636ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi                _, target, build_id = utils.parse_launch_control_build(
637ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi                        info['build'])
638ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi                build_target, _ = utils.parse_launch_control_target(target)
639ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi                if build_target:
640ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi                    info['board'] = build_target
641ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi                    info['build_version'] = build_id
642ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi            except ValueError:
643ef31f03d7347b40c431754a6280b5ff9eea2903fDan Shi                pass
64470647cafbd061a7754ac304fd9dc067f2b6dbab4Dan Shi    return info
6453a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng
6463a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng
6473a4a57a7704ab15136286628f465dbb2d1a56171Kevin Chengdef add_label_detector(label_function_list, label_list=None, label=None):
6483a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng    """Decorator used to group functions together into the provided list.
6493a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng
6503a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng    This is a helper function to automatically add label functions that have
6513a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng    the label decorator.  This is to help populate the class list of label
6523a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng    functions to be retrieved by the get_labels class method.
6533a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng
6543a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng    @param label_function_list: List of label detecting functions to add
6553a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng                                decorated function to.
6563a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng    @param label_list: List of detectable labels to add detectable labels to.
6573a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng                       (Default: None)
6583a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng    @param label: Label string that is detectable by this detection function
6593a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng                  (Default: None)
6603a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng    """
6613a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng    def add_func(func):
6623a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng        """
6633a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng        @param func: The function to be added as a detector.
6643a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng        """
6653a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng        label_function_list.append(func)
6663a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng        if label and label_list is not None:
6673a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng            label_list.append(label)
6683a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng        return func
6693a4a57a7704ab15136286628f465dbb2d1a56171Kevin Cheng    return add_func
6709f364a6fe1fedaecc652f111cd143ab2ee7ca825Simran Basi
6719f364a6fe1fedaecc652f111cd143ab2ee7ca825Simran Basi
6729f364a6fe1fedaecc652f111cd143ab2ee7ca825Simran Basidef verify_not_root_user():
6739f364a6fe1fedaecc652f111cd143ab2ee7ca825Simran Basi    """Simple function to error out if running with uid == 0"""
6749f364a6fe1fedaecc652f111cd143ab2ee7ca825Simran Basi    if os.getuid() == 0:
6751bf60eb788365f083d0ee8045a6556f906149decSimran Basi        raise error.IllegalUser('This script can not be ran as root.')
6761bf60eb788365f083d0ee8045a6556f906149decSimran Basi
6771bf60eb788365f083d0ee8045a6556f906149decSimran Basi
6781bf60eb788365f083d0ee8045a6556f906149decSimran Basidef get_hostname_from_machine(machine):
6791bf60eb788365f083d0ee8045a6556f906149decSimran Basi    """Lookup hostname from a machine string or dict.
6801bf60eb788365f083d0ee8045a6556f906149decSimran Basi
6811bf60eb788365f083d0ee8045a6556f906149decSimran Basi    @returns: Machine hostname in string format.
6821bf60eb788365f083d0ee8045a6556f906149decSimran Basi    """
6831bf60eb788365f083d0ee8045a6556f906149decSimran Basi    hostname, _ = get_host_info_from_machine(machine)
6841bf60eb788365f083d0ee8045a6556f906149decSimran Basi    return hostname
6851bf60eb788365f083d0ee8045a6556f906149decSimran Basi
6861bf60eb788365f083d0ee8045a6556f906149decSimran Basi
6871bf60eb788365f083d0ee8045a6556f906149decSimran Basidef get_host_info_from_machine(machine):
6881bf60eb788365f083d0ee8045a6556f906149decSimran Basi    """Lookup host information from a machine string or dict.
6891bf60eb788365f083d0ee8045a6556f906149decSimran Basi
69005ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng    @returns: Tuple of (hostname, afe_host)
6911bf60eb788365f083d0ee8045a6556f906149decSimran Basi    """
6921bf60eb788365f083d0ee8045a6556f906149decSimran Basi    if isinstance(machine, dict):
69305ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        return (machine['hostname'], machine['afe_host'])
6941bf60eb788365f083d0ee8045a6556f906149decSimran Basi    else:
69505ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng        return (machine, EmptyAFEHost())
69605ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng
69705ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng
69805ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Chengdef get_afe_host_from_machine(machine):
69905ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng    """Return the afe_host from the machine dict if possible.
70005ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng
70105ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng    @returns: AFE host object.
70205ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng    """
70305ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng    _, afe_host = get_host_info_from_machine(machine)
70405ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng    return afe_host
705f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng
706f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng
707f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Dengdef get_creds_abspath(creds_file):
708f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng    """Returns the abspath of the credentials file.
709f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng
710f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng    If creds_file is already an absolute path, just return it.
711f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng    Otherwise, assume it is located in the creds directory
712f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng    specified in global_config and return the absolute path.
713f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng
714f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng    @param: creds_path, a path to the credentials.
715f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng    @return: An absolute path to the credentials file.
716f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng    """
717f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng    if not creds_file:
718f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng        return None
719f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng    if os.path.isabs(creds_file):
720f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng        return creds_file
721d37736b67febeebd991d0209dd030635f7ff5cfdDan Shi    creds_dir = CONFIG.get_config_value('SERVER', 'creds_dir', default='')
722f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng    if not creds_dir or not os.path.exists(creds_dir):
723f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng        creds_dir = common.autotest_dir
724f8a94e2adf24e017be4e9d0687d4ab8f46ac4fceFang Deng    return os.path.join(creds_dir, creds_file)
7253b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Cheng
7263b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Cheng
7273b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Chengdef machine_is_testbed(machine):
7283b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Cheng    """Checks if the machine is a testbed.
7293b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Cheng
7303b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Cheng    The signal we use to determine if the machine is a testbed
7313b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Cheng    is if the host attributes contain more than 1 serial.
7323b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Cheng
7333b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Cheng    @param machine: is a list of dicts
7343b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Cheng
7353b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Cheng    @return: True if the machine is a testbed, False otherwise.
7363b11181c9ea282d584663d362bcfe2d1b4f9ba51Kevin Cheng    """
73705ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng    _, afe_host = get_host_info_from_machine(machine)
73805ae2a45397188dd7d7adbc49a61095ebf85e151Kevin Cheng    return len(afe_host.attributes.get('serials', '').split(',')) > 1
739