xref: /aosp_15_r20/external/autotest/site_utils/admin_audit/main.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li#!/usr/bin/env python3
2*9c5db199SXin Li# Copyright 2020 The Chromium OS Authors. All rights reserved.
3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
4*9c5db199SXin Li# found in the LICENSE file.
5*9c5db199SXin Li
6*9c5db199SXin Li
7*9c5db199SXin Li"""Tool to audit a DUT in the lab."""
8*9c5db199SXin Li
9*9c5db199SXin Lifrom __future__ import absolute_import
10*9c5db199SXin Lifrom __future__ import division
11*9c5db199SXin Lifrom __future__ import print_function
12*9c5db199SXin Li
13*9c5db199SXin Liimport argparse
14*9c5db199SXin Liimport logging
15*9c5db199SXin Liimport logging.config
16*9c5db199SXin Liimport os
17*9c5db199SXin Liimport sys
18*9c5db199SXin Liimport socket
19*9c5db199SXin Liimport errno
20*9c5db199SXin Li
21*9c5db199SXin Liimport common
22*9c5db199SXin Lifrom autotest_lib.client.common_lib import autotest_enum
23*9c5db199SXin Lifrom autotest_lib.client.common_lib import logging_manager
24*9c5db199SXin Lifrom autotest_lib.server import server_logging_config
25*9c5db199SXin Lifrom autotest_lib.server.hosts import factory
26*9c5db199SXin Lifrom autotest_lib.server.hosts import servo_host
27*9c5db199SXin Li
28*9c5db199SXin Liimport verifiers
29*9c5db199SXin Li
30*9c5db199SXin LiRETURN_CODES = autotest_enum.AutotestEnum(
31*9c5db199SXin Li        'OK',
32*9c5db199SXin Li        'VERIFY_FAILURE',
33*9c5db199SXin Li        'OTHER_FAILURES'
34*9c5db199SXin Li)
35*9c5db199SXin Li
36*9c5db199SXin LiACTION_VERIFY_DUT_STORAGE = 'verify-dut-storage'
37*9c5db199SXin LiACTION_VERIFY_SERVO_USB = 'verify-servo-usb-drive'
38*9c5db199SXin LiACTION_VERIFY_SERVO_FW = 'verify-servo-fw'
39*9c5db199SXin LiACTION_FLASH_SERVO_KEYBOARD_MAP = 'flash-servo-keyboard-map'
40*9c5db199SXin LiACTION_VERIFY_DUT_MACADDR = 'verify-dut-macaddr'
41*9c5db199SXin LiACTION_VERIFY_RPM_CONFIG = 'verify-rpm-config'
42*9c5db199SXin Li
43*9c5db199SXin Li_LOG_FILE = 'audit.log'
44*9c5db199SXin Li_SERVO_UART_LOGS = 'servo_uart'
45*9c5db199SXin Li
46*9c5db199SXin LiVERIFIER_MAP = {
47*9c5db199SXin Li        ACTION_VERIFY_DUT_STORAGE: verifiers.VerifyDutStorage,
48*9c5db199SXin Li        ACTION_VERIFY_SERVO_USB: verifiers.VerifyServoUsb,
49*9c5db199SXin Li        ACTION_VERIFY_SERVO_FW: verifiers.VerifyServoFw,
50*9c5db199SXin Li        ACTION_FLASH_SERVO_KEYBOARD_MAP:
51*9c5db199SXin Li        verifiers.FlashServoKeyboardMapVerifier,
52*9c5db199SXin Li        ACTION_VERIFY_DUT_MACADDR: verifiers.VerifyDUTMacAddress,
53*9c5db199SXin Li        ACTION_VERIFY_RPM_CONFIG: verifiers.VerifyRPMConfig,
54*9c5db199SXin Li}
55*9c5db199SXin Li
56*9c5db199SXin Li# Actions required Servod service
57*9c5db199SXin LiACTIONS_REQUIRED_SERVOD = set([
58*9c5db199SXin Li        ACTION_VERIFY_DUT_STORAGE,
59*9c5db199SXin Li        ACTION_VERIFY_SERVO_USB,
60*9c5db199SXin Li        ACTION_FLASH_SERVO_KEYBOARD_MAP,
61*9c5db199SXin Li        ACTION_VERIFY_DUT_MACADDR,
62*9c5db199SXin Li])
63*9c5db199SXin Li
64*9c5db199SXin Li# Actions required ServoHost without Servod process
65*9c5db199SXin LiACTIONS_REQUIRED_SERVO_HOST = set([
66*9c5db199SXin Li    ACTION_VERIFY_SERVO_FW,
67*9c5db199SXin Li])
68*9c5db199SXin Li
69*9c5db199SXin Liclass DutAuditError(Exception):
70*9c5db199SXin Li    """Generic error raised during DUT audit."""
71*9c5db199SXin Li
72*9c5db199SXin Li
73*9c5db199SXin Lidef main():
74*9c5db199SXin Li    """Tool to audit a DUT."""
75*9c5db199SXin Li    opts = _parse_args()
76*9c5db199SXin Li
77*9c5db199SXin Li    # Create logging setting
78*9c5db199SXin Li    logging_manager.configure_logging(
79*9c5db199SXin Li        server_logging_config.ServerLoggingConfig(),
80*9c5db199SXin Li        results_dir=opts.results_dir)
81*9c5db199SXin Li
82*9c5db199SXin Li    logging.debug('autoserv is running in drone %s.', socket.gethostname())
83*9c5db199SXin Li    logging.debug('audit environment: %r', os.environ)
84*9c5db199SXin Li    logging.debug('audit command was: %s', ' '.join(sys.argv))
85*9c5db199SXin Li    logging.debug('audit parsed options: %s', opts)
86*9c5db199SXin Li
87*9c5db199SXin Li    # Initialize ServoHost without running Servod process.
88*9c5db199SXin Li    need_servo_host = bool(set(opts.actions) & ACTIONS_REQUIRED_SERVO_HOST)
89*9c5db199SXin Li    # Initialize ServoHost with running Servod process.
90*9c5db199SXin Li    need_servod = bool(set(opts.actions) & ACTIONS_REQUIRED_SERVOD)
91*9c5db199SXin Li
92*9c5db199SXin Li    # Create folder for servo uart logs.
93*9c5db199SXin Li    servo_uart_logs_dir = None
94*9c5db199SXin Li    if need_servod:
95*9c5db199SXin Li        servo_uart_logs_dir = _create_servo_uart_path(opts.results_dir)
96*9c5db199SXin Li
97*9c5db199SXin Li    try:
98*9c5db199SXin Li        host_object = factory.create_target_host(
99*9c5db199SXin Li                opts.hostname,
100*9c5db199SXin Li                host_info_path=opts.host_info_file,
101*9c5db199SXin Li                try_lab_servo=need_servod,
102*9c5db199SXin Li                try_servo_repair=need_servod,
103*9c5db199SXin Li                try_servo_recovery=need_servod,
104*9c5db199SXin Li                servo_uart_logs_dir=servo_uart_logs_dir)
105*9c5db199SXin Li    except Exception as err:
106*9c5db199SXin Li        logging.error("fail to create host: %s", err)
107*9c5db199SXin Li        return RETURN_CODES.OTHER_FAILURES
108*9c5db199SXin Li
109*9c5db199SXin Li    with host_object as host:
110*9c5db199SXin Li        if need_servo_host and not need_servod:
111*9c5db199SXin Li            try:
112*9c5db199SXin Li                host.set_servo_host(servo_host.ServoHost(
113*9c5db199SXin Li                    **servo_host.get_servo_args_for_host(host)
114*9c5db199SXin Li                ))
115*9c5db199SXin Li            except Exception as err:
116*9c5db199SXin Li                logging.error("fail to init servo host: %s", err)
117*9c5db199SXin Li                return RETURN_CODES.OTHER_FAILURES
118*9c5db199SXin Li        for action in opts.actions:
119*9c5db199SXin Li            if opts.dry_run:
120*9c5db199SXin Li                logging.info('DRY RUN: Would have run actions %s', action)
121*9c5db199SXin Li                return
122*9c5db199SXin Li
123*9c5db199SXin Li            response = _verify(action, host, opts.results_dir)
124*9c5db199SXin Li            if response:
125*9c5db199SXin Li                return response
126*9c5db199SXin Li
127*9c5db199SXin Li    return RETURN_CODES.OK
128*9c5db199SXin Li
129*9c5db199SXin Li
130*9c5db199SXin Lidef _verify(action, host, resultdir):
131*9c5db199SXin Li    """Run verifier for the action with targeted host.
132*9c5db199SXin Li
133*9c5db199SXin Li    @param action: The action requested to run the verifier.
134*9c5db199SXin Li    @param host: The host presentation of the DUT.
135*9c5db199SXin Li    """
136*9c5db199SXin Li    try:
137*9c5db199SXin Li        _log("START", action)
138*9c5db199SXin Li        verifier = VERIFIER_MAP[action]
139*9c5db199SXin Li        if verifier:
140*9c5db199SXin Li            v = verifier(host)
141*9c5db199SXin Li            v.set_result_dir(resultdir)
142*9c5db199SXin Li            v.verify()
143*9c5db199SXin Li        else:
144*9c5db199SXin Li            logging.info('Verifier is not specified')
145*9c5db199SXin Li        _log("END_GOOD", action)
146*9c5db199SXin Li    except Exception as err:
147*9c5db199SXin Li        _log("END_FAIL", action, err)
148*9c5db199SXin Li        return RETURN_CODES.VERIFY_FAILURE
149*9c5db199SXin Li
150*9c5db199SXin Li
151*9c5db199SXin Lidef _log(status, action, err=None):
152*9c5db199SXin Li    if err:
153*9c5db199SXin Li        message = '%s:%s; %s' % (action, status, str(err))
154*9c5db199SXin Li    else:
155*9c5db199SXin Li        message = '%s:%s' % (action, status)
156*9c5db199SXin Li    logging.info(message)
157*9c5db199SXin Li
158*9c5db199SXin Li
159*9c5db199SXin Lidef _create_servo_uart_path(results_dir):
160*9c5db199SXin Li    servo_uart_logs = os.path.join(results_dir, _SERVO_UART_LOGS)
161*9c5db199SXin Li    try:
162*9c5db199SXin Li        if not os.path.exists(servo_uart_logs):
163*9c5db199SXin Li            os.makedirs(servo_uart_logs)
164*9c5db199SXin Li    except OSError as e:
165*9c5db199SXin Li        logging.debug(
166*9c5db199SXin Li                '(not critical) Fail to create dir for servo logs;'
167*9c5db199SXin Li                ' %s', e)
168*9c5db199SXin Li        if not (e.errno == errno.EEXIST):
169*9c5db199SXin Li            servo_uart_logs = None
170*9c5db199SXin Li    return servo_uart_logs
171*9c5db199SXin Li
172*9c5db199SXin Li
173*9c5db199SXin Lidef _parse_args():
174*9c5db199SXin Li    parser = argparse.ArgumentParser(description='Audit DUT in a lab.')
175*9c5db199SXin Li
176*9c5db199SXin Li    parser.add_argument(
177*9c5db199SXin Li            'actions',
178*9c5db199SXin Li            nargs='+',
179*9c5db199SXin Li            choices=list(VERIFIER_MAP),
180*9c5db199SXin Li            help='DUT audit actions to execute.',
181*9c5db199SXin Li    )
182*9c5db199SXin Li    parser.add_argument(
183*9c5db199SXin Li            '--dry-run',
184*9c5db199SXin Li            action='store_true',
185*9c5db199SXin Li            default=False,
186*9c5db199SXin Li            help='Run in dry-run mode. No changes will be made to the DUT.',
187*9c5db199SXin Li    )
188*9c5db199SXin Li    parser.add_argument(
189*9c5db199SXin Li            '--results-dir',
190*9c5db199SXin Li            required=True,
191*9c5db199SXin Li            help='Directory to drop logs and output artifacts in.',
192*9c5db199SXin Li    )
193*9c5db199SXin Li
194*9c5db199SXin Li    parser.add_argument(
195*9c5db199SXin Li            '--hostname',
196*9c5db199SXin Li            required=True,
197*9c5db199SXin Li            help='Hostname of the DUT to audit.',
198*9c5db199SXin Li    )
199*9c5db199SXin Li    parser.add_argument(
200*9c5db199SXin Li            '--host-info-file',
201*9c5db199SXin Li            required=True,
202*9c5db199SXin Li            help=('Full path to HostInfo file.'
203*9c5db199SXin Li                  ' DUT inventory information is read from the HostInfo file.'
204*9c5db199SXin Li                  ),
205*9c5db199SXin Li    )
206*9c5db199SXin Li
207*9c5db199SXin Li    return parser.parse_args()
208*9c5db199SXin Li
209*9c5db199SXin Li
210*9c5db199SXin Liif __name__ == '__main__':
211*9c5db199SXin Li    sys.exit(main())
212