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