• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 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
5import json
6import logging
7import urllib2
8
9from autotest_lib.client.common_lib import global_config
10
11# HWID info types to request.
12HWID_INFO_LABEL = 'dutlabel'
13HWID_INFO_BOM = 'bom'
14HWID_INFO_SKU = 'sku'
15HWID_INFO_TYPES = [HWID_INFO_BOM, HWID_INFO_SKU, HWID_INFO_LABEL]
16
17# HWID url vars.
18HWID_VERSION = 'v1'
19HWID_BASE_URL = 'https://www.googleapis.com/chromeoshwid'
20CHROMEOS_HWID_SERVER_URL = "https://chromeos-hwid.appspot.com/api/chromeoshwid"
21URL_FORMAT_STRING='%(base_url)s/%(version)s/%(info_type)s/%(hwid)s/?key=%(key)s'
22
23# Key file name to use when we don't want hwid labels.
24KEY_FILENAME_NO_HWID = 'no_hwid_labels'
25
26class HwIdException(Exception):
27    """Raised whenever anything fails in the hwid info request."""
28
29
30def get_hwid_info(hwid, info_type, key_file):
31    """Given a hwid and info type, return a dict of the requested info.
32
33    @param hwid: hwid to use for the query.
34    @param info_type: String of info type requested.
35    @param key_file: Filename that holds the key for authentication.
36
37    @return: A dict of the info.
38
39    @raises HwIdException: If hwid/info_type/key_file is invalid or there's an
40                           error anywhere related to getting the raw hwid info
41                           or decoding it.
42    """
43    # There are situations we don't want to call out to the hwid service, we use
44    # the key_file name as the indicator for that.
45    if key_file == KEY_FILENAME_NO_HWID:
46        return {}
47
48    if not isinstance(hwid, str):
49        raise ValueError('hwid is not a string.')
50
51    if info_type not in HWID_INFO_TYPES:
52        raise ValueError('invalid info type: "%s".' % info_type)
53
54    hwid_info_dict = _try_hwid_v1(hwid, info_type)
55    if hwid_info_dict is not None:
56        return hwid_info_dict
57    else:
58        logging.debug("Switch back to use old endpoint")
59
60    key = None
61    with open(key_file) as f:
62        key = f.read().strip()
63
64    url_format_dict = {'base_url': HWID_BASE_URL,
65                       'version': HWID_VERSION,
66                       'info_type': info_type,
67                       'hwid': urllib2.quote(hwid),
68                       'key': key}
69    return _fetch_hwid_response(url_format_dict)
70
71
72def get_all_possible_dut_labels(key_file):
73    """Return all possible labels that can be supplied by dutlabels.
74
75    We can send a dummy key to the service to retrieve all the possible
76    labels the service will provide under the dutlabel api call.  We need
77    this in order to track which labels we can remove if they're not detected
78    on a dut anymore.
79
80    @param key_file: Filename that holds the key for authentication.
81
82    @return: A list of all possible labels.
83    """
84    return get_hwid_info('dummy_hwid', HWID_INFO_LABEL, key_file).get(
85            'possible_labels', [])
86
87
88def _try_hwid_v1(hwid, info_type):
89    """Try chromeos-hwid endpoints for fetching hwid info.
90
91    @param hwid: a string hardware ID.
92    @param info_type: String of info type requested.
93
94    @return a dict of hwid info.
95    """
96    key_file_path = global_config.global_config.get_config_value(
97            'CROS', 'NEW_HWID_KEY', type=str, default="")
98    if key_file_path == "":
99        return None
100
101    key = None
102    with open(key_file_path) as f:
103        key = f.read().strip()
104
105    if key is None:
106        return None
107
108    url_format_dict = {'base_url': CHROMEOS_HWID_SERVER_URL,
109                       'version': HWID_VERSION,
110                       'info_type': info_type,
111                       'hwid': urllib2.quote(hwid),
112                       'key': key}
113
114    try:
115        return _fetch_hwid_response(url_format_dict)
116    except Exception as e:
117        logging.debug("fail to call new HWID endpoint: %s", str(e))
118        return None
119
120
121def _fetch_hwid_response(req_parameter_dict):
122    """Fetch and parse hwid response.
123
124    @param req_parameter_dict: A dict of url parameters.
125
126    @return a dict of hwid info.
127    """
128    url_request = URL_FORMAT_STRING % req_parameter_dict
129    try:
130        page_contents = urllib2.urlopen(url_request)
131    except (urllib2.URLError, urllib2.HTTPError) as e:
132        # TODO(kevcheng): Might need to scrub out key from exception message.
133        raise HwIdException('error retrieving raw hwid info: %s' % e)
134
135    try:
136        hwid_info_dict = json.load(page_contents)
137    except ValueError as e:
138        raise HwIdException('error decoding hwid info: %s - "%s"' %
139                            (e, page_contents.getvalue()))
140    finally:
141        page_contents.close()
142
143    return hwid_info_dict
144