blob: 3a6f21b136fdb3b4fc785e52a5db8631016af4d8 [file] [log] [blame]
Dan Shi54682e72014-10-08 19:10:56 +00001#!/usr/bin/env python
2
3# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""
8This script provides functions to:
91. collect: Collect all hosts and their labels to metaDB, can be scheduled
10 run daily, e.g.,
Dan Shi17ecbbf2014-10-06 13:56:34 -070011 ./site_utils/host_label_utils.py collect
Dan Shi54682e72014-10-08 19:10:56 +0000122. query: Query for hosts and their labels information at a given day, e.g.,
Dan Shi17ecbbf2014-10-06 13:56:34 -070013 ./site_utils/host_label_utils.py query -n 172.27.213.193 -l peppy
Dan Shi54682e72014-10-08 19:10:56 +000014"""
15
16import argparse
Dan Shi1c3b0d12014-09-26 17:15:41 -070017import itertools
Dan Shi54682e72014-10-08 19:10:56 +000018import logging
19import pprint
20import time
21
22import common
23from autotest_lib.client.common_lib import time_utils
Gabe Blackb72f4fb2015-01-20 16:47:13 -080024from autotest_lib.client.common_lib.cros.graphite import autotest_es
Dan Shi54682e72014-10-08 19:10:56 +000025from autotest_lib.frontend import setup_django_environment
26from autotest_lib.frontend.afe import models
27
28
29# _type used for ES
30_HOST_LABEL_TYPE = 'host_labels'
31_HOST_LABEL_TIME_INDEX_TYPE = 'host_labels_time_index'
32
33
David James8352bc22015-05-05 16:37:05 -070034def get_all_boards(labels=None):
Dan Shi1c3b0d12014-09-26 17:15:41 -070035 """Get a list of boards from host labels.
36
37 Scan through all labels of all duts and get all possible boards based on
38 label of name board:*
39
David James8352bc22015-05-05 16:37:05 -070040 @param labels: A list of labels to filter hosts.
Dan Shi1c3b0d12014-09-26 17:15:41 -070041 @return: A list of board names, e.g., ['peppy', 'daisy']
42 """
David James8352bc22015-05-05 16:37:05 -070043 host_labels = get_host_labels(labels=labels)
Dan Shi1c3b0d12014-09-26 17:15:41 -070044 board_labels = [[label[6:] for label in labels
45 if label.startswith('board:')]
46 for labels in host_labels.values()]
47 boards = list(set(itertools.chain.from_iterable(board_labels)))
48 return boards
49
50
Dan Shi54682e72014-10-08 19:10:56 +000051def get_host_labels(days_back=0, hostname=None, labels=None):
52 """Get the labels for a given host or all hosts.
53
54 @param days_back: Get the label info around that number of days back. The
55 default is 0, i.e., the latest label information.
56 @param hostname: Name of the host, if set to None, return labels for all
57 hosts. Default is None.
58 @param labels: A list of labels to filter hosts.
59 @return: A dictionary of host labels, key is the hostname, and value is a
60 list of labels, e.g.,
61 {'host1': ['board:daisy', 'pool:bvt']}
62 """
63 # Search for the latest logged labels before the given days_back.
64 # Default is 0, which means the last time host labels were logged.
65 t_end = time.time() - days_back*24*3600
Gabe Blackb72f4fb2015-01-20 16:47:13 -080066 results = autotest_es.query(
Dan Shi54682e72014-10-08 19:10:56 +000067 fields_returned=['time_index'],
68 equality_constraints=[('_type', _HOST_LABEL_TIME_INDEX_TYPE),],
69 range_constraints=[('time_index', None, t_end)],
70 size=1,
71 sort_specs=[{'time_index': 'desc'}])
Dan Shi54682e72014-10-08 19:10:56 +000072 t_end_str = time_utils.epoch_time_to_date_string(t_end)
Gabe Blackb72f4fb2015-01-20 16:47:13 -080073 if results.total == 0:
Dan Shi54682e72014-10-08 19:10:56 +000074 logging.error('No label information was logged before %s.', t_end_str)
75 return
Dan Shif242c202015-02-20 09:21:49 -080076 time_index = results.hits[0]['time_index']
Dan Shi54682e72014-10-08 19:10:56 +000077 logging.info('Host labels were recorded at %s',
78 time_utils.epoch_time_to_date_string(time_index))
79
80 # Search for labels for a given host or all hosts, at time_index.
81 equality_constraints=[('_type', _HOST_LABEL_TYPE),
82 ('time_index', time_index),]
83 if hostname:
84 equality_constraints.append(('hostname', hostname))
85 if labels:
86 for label in labels:
87 equality_constraints.append(('labels', label))
Gabe Blackb72f4fb2015-01-20 16:47:13 -080088 results = autotest_es.query(
Dan Shi54682e72014-10-08 19:10:56 +000089 fields_returned=['hostname', 'labels'],
90 equality_constraints=equality_constraints)
Dan Shi54682e72014-10-08 19:10:56 +000091
92 host_labels = {}
Gabe Blackb72f4fb2015-01-20 16:47:13 -080093 for hit in results.hits:
Dan Shic6509e62014-10-20 11:19:51 -070094 if 'labels' in hit:
95 host_labels[hit['hostname']] = hit['labels']
Dan Shi54682e72014-10-08 19:10:56 +000096
97 return host_labels
98
99
100def collect_info():
101 """Collect label info and report to metaDB.
102 """
103 # time_index is to index all host labels collected together. It's
104 # converted to int to make search faster.
105 time_index = int(time.time())
106 hosts = models.Host.objects.filter(invalid=False)
Dan Shi1e290c92015-05-11 12:54:48 -0700107 data_list = []
Dan Shi54682e72014-10-08 19:10:56 +0000108 for host in hosts:
Dan Shi1e290c92015-05-11 12:54:48 -0700109 info = {'_type': _HOST_LABEL_TYPE,
110 'hostname': host.hostname,
Dan Shi54682e72014-10-08 19:10:56 +0000111 'labels': [label.name for label in host.labels.all()],
112 'time_index': time_index}
Dan Shi1e290c92015-05-11 12:54:48 -0700113 data_list.append(info)
114 autotest_es.bulk_post(data_list, log_time_recorded=False)
Dan Shi54682e72014-10-08 19:10:56 +0000115
116 # After all host label information is logged, save the time stamp.
Dan Shi1d59a672015-03-31 14:09:03 -0700117 autotest_es.post(use_http=True, type_str=_HOST_LABEL_TIME_INDEX_TYPE,
118 metadata={'time_index': time_index},
119 log_time_recorded=False)
Dan Shi54682e72014-10-08 19:10:56 +0000120 logging.info('Finished collecting host labels for %d hosts.', len(hosts))
121
122
123def main():
124 """Main script.
125 """
126 parser = argparse.ArgumentParser()
127 parser.add_argument('action',
128 help=('collect or query. Action collect will collect '
129 'all hosts and their labels to metaDB. Action '
130 'query will query for hosts and their labels '
131 'information at a given day'))
132 parser.add_argument('-d', '--days_back', type=int, dest='days_back',
133 help=('Number of days before current time. Query will '
134 'get host label information collected before that'
135 ' time. The option is applicable to query only. '
136 'Default to 0, i.e., get the latest label info.'),
137 default=0)
138 parser.add_argument('-n', '--hostname', type=str, dest='hostname',
139 help=('Name of the host to query label information for.'
140 'The option is applicable to query only. '
141 'Default to None, i.e., return label info for all'
142 ' hosts.'),
143 default=None)
144 parser.add_argument('-l', '--labels', nargs='+', dest='labels',
145 help=('A list of labels to filter hosts. The option is '
146 'applicable to query only. Default to None.'),
147 default=None)
148 parser.add_argument('-v', '--verbose', action="store_true", dest='verbose',
149 help='Allow more detail information to be shown.')
150 options = parser.parse_args()
151
152 logging.getLogger().setLevel(logging.INFO if options.verbose
153 else logging.WARN)
154 if options.action == 'collect':
155 collect_info()
156 elif options.action == 'query':
157 host_labels = get_host_labels(options.days_back, options.hostname,
158 options.labels)
159 pprint.pprint(host_labels)
160 else:
161 logging.error('action %s is not supported, can only be collect or '
162 'query!', options.action)
163
164
165if __name__ == '__main__':
166 main()