blob: 18074da0219104b61a5dd27bb67e704dde3faab7 [file] [log] [blame]
Kuang-che Wu2ea804f2017-11-28 17:11:41 +08001#!/usr/bin/env python2
Kuang-che Wu6e4beca2018-06-27 17:45:02 +08002# -*- coding: utf-8 -*-
Kuang-che Wu2ea804f2017-11-28 17:11:41 +08003# Copyright 2017 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.
Kuang-che Wu68db08a2018-03-30 11:50:34 +08006"""Helper script to manipulate chromeos DUT or query info."""
Kuang-che Wu2ea804f2017-11-28 17:11:41 +08007from __future__ import print_function
8import argparse
Kuang-che Wuc45cfa42019-01-15 00:15:01 +08009import collections
10import functools
Kuang-che Wu2ea804f2017-11-28 17:11:41 +080011import json
12import logging
13
14from bisect_kit import common
Kuang-che Wuc45cfa42019-01-15 00:15:01 +080015from bisect_kit import cros_lab_util
Kuang-che Wu2ea804f2017-11-28 17:11:41 +080016from bisect_kit import cros_util
17
18logger = logging.getLogger(__name__)
19
20
21def cmd_version_info(opts):
22 info = cros_util.version_info(opts.board, opts.version)
23 if opts.name:
24 if opts.name not in info:
25 logger.error('unknown name=%s', opts.name)
26 print(info[opts.name])
27 else:
28 print(json.dumps(info, sort_keys=True, indent=4))
29
30
31def cmd_query_dut_board(opts):
32 assert cros_util.is_dut(opts.dut)
33 print(cros_util.query_dut_board(opts.dut))
34
35
36def cmd_reboot(opts):
37 assert cros_util.is_dut(opts.dut)
38 cros_util.reboot(opts.dut)
39
40
Kuang-che Wuc45cfa42019-01-15 00:15:01 +080041def _get_label_by_prefix(info, prefix):
42 for label in info['Labels']:
43 if label.startswith(prefix + ':'):
44 return label
45 return None
46
47
48def cmd_search_dut(opts):
49 labels = []
50 if opts.label:
51 labels += opts.label.split(',')
52
53 def match(info):
54 if not opts.condition:
55 return True
56
57 for label in info['Labels']:
58 for condition in opts.condition:
59 if ':' in condition:
60 keys = [condition]
61 else:
62 keys = [
63 'board:' + condition,
64 'model:' + condition,
65 'sku:' + condition,
66 ]
67 for key in keys:
68 if label.lower().startswith(key.lower()):
69 return True
70 return False
71
72 for pool in opts.pools.split(','):
73 print('pool:' + pool)
74
75 group = collections.defaultdict(dict)
76 counter = collections.defaultdict(collections.Counter)
77 for host, info in cros_lab_util.list_host(labels=labels +
78 ['pool:' + pool]).items():
79 if not match(info):
80 continue
81
82 model = _get_label_by_prefix(info, 'model')
83 if info.get('Locked') == 'True':
84 state = 'Locked'
85 else:
86 state = info['Status']
87 if state not in group[model]:
88 group[model][state] = {}
89 group[model][state][host] = info
90 counter[model][state] += 1
91
92 def availability(counter, model):
93 return -counter[model]['Ready']
94
95 for model in sorted(group, key=functools.partial(availability, counter)):
96 print('%s\t%s' % (model, dict(counter[model])))
97 for host, info in group[model].get('Ready', {}).items():
98 print('\t%s\t%s' % (host, _get_label_by_prefix(info, 'board')))
99 if not opts.all:
100 break
101 print('-' * 30)
102
103 if not opts.all:
104 print('Only list one host per model by default. Use --all to output all.')
105
106
Kuang-che Wu2ea804f2017-11-28 17:11:41 +0800107def main():
108 common.init()
109 parser = argparse.ArgumentParser()
110 common.add_common_arguments(parser)
111 subparsers = parser.add_subparsers(
112 dest='command', title='commands', metavar='<command>')
113
114 parser_version_info = subparsers.add_parser(
115 'version_info',
116 help='Query version info of given chromeos build',
117 description='Given chromeos `board` and `version`, '
118 'print version information of components.')
119 parser_version_info.add_argument(
120 'board', help='ChromeOS board name, like "samus".')
121 parser_version_info.add_argument(
122 'version',
123 type=cros_util.argtype_cros_version,
124 help='ChromeOS version, like "9876.0.0" or "R62-9876.0.0"')
125 parser_version_info.add_argument(
126 'name',
127 nargs='?',
128 help='Component name. If specified, output its version string. '
129 'Otherwise output all version info as dict in json format.')
130 parser_version_info.set_defaults(func=cmd_version_info)
131
132 parser_query_dut_board = subparsers.add_parser(
133 'query_dut_board', help='Query board name of given DUT')
134 parser_query_dut_board.add_argument('dut')
135 parser_query_dut_board.set_defaults(func=cmd_query_dut_board)
136
137 parser_reboot = subparsers.add_parser(
138 'reboot',
139 help='Reboot a DUT',
140 description='Reboot a DUT and verify the reboot is successful.')
141 parser_reboot.add_argument('dut')
142 parser_reboot.set_defaults(func=cmd_reboot)
143
Kuang-che Wuc45cfa42019-01-15 00:15:01 +0800144 parser_search_dut = subparsers.add_parser(
145 'search_dut',
146 help='Search DUT with conditions',
147 description='Search hosts in the lab. Grouped by model and ordered by '
148 'availability. When your test could be run on many models, this command '
149 'help you to decide what model to use.')
150 parser_search_dut.add_argument(
151 '--pools',
152 default='performance,crosperf,suites',
153 help='Pools to search, comma separated. The searching will be performed '
154 'for each pool.')
155 parser_search_dut.add_argument(
156 '--label',
157 '-b',
158 help='Additional required labels, comma separated. '
159 'If more than one, all need to be satisfied.')
160 parser_search_dut.add_argument(
161 '--all',
162 action='store_true',
163 help='List all DUTs; (list only one DUT per board by default)')
164 parser_search_dut.add_argument(
165 'condition',
166 nargs='*',
167 help='Conditions, ex. board name, model name, sku name, etc. If more '
168 'than one is specified, matching any one is sufficient. If none is '
169 'specified, all hosts will be listed.')
170 parser_search_dut.set_defaults(func=cmd_search_dut)
171
Kuang-che Wu2ea804f2017-11-28 17:11:41 +0800172 opts = parser.parse_args()
173 common.config_logging(opts)
174 opts.func(opts)
175
176
177if __name__ == '__main__':
178 main()