blob: fcb7cac707aac605bb26d0b712b0c41a059e0219 [file] [log] [blame]
#!/usr/bin/env python2
# Copyright 2020 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Tool to audit a DUT in the lab."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import logging
import logging.config
import os
import sys
import socket
import errno
import common
from autotest_lib.client.common_lib import autotest_enum
from autotest_lib.client.common_lib import logging_manager
from autotest_lib.server import server_logging_config
from autotest_lib.server.hosts import factory
from autotest_lib.server.hosts import servo_host
import verifiers
RETURN_CODES = autotest_enum.AutotestEnum(
'OK',
'VERIFY_FAILURE',
'OTHER_FAILURES'
)
ACTION_VERIFY_DUT_STORAGE = 'verify-dut-storage'
ACTION_VERIFY_SERVO_USB = 'verify-servo-usb-drive'
ACTION_VERIFY_SERVO_FW = 'verify-servo-fw'
ACTION_FLASH_SERVO_KEYBOARD_MAP = 'flash-servo-keyboard-map'
ACTION_VERIFY_DUT_MACADDR = 'verify-dut-macaddr'
ACTION_VERIFY_RPM_CONFIG = 'verify-rpm-config'
_LOG_FILE = 'audit.log'
_SERVO_UART_LOGS = 'servo_uart'
VERIFIER_MAP = {
ACTION_VERIFY_DUT_STORAGE: verifiers.VerifyDutStorage,
ACTION_VERIFY_SERVO_USB: verifiers.VerifyServoUsb,
ACTION_VERIFY_SERVO_FW: verifiers.VerifyServoFw,
ACTION_FLASH_SERVO_KEYBOARD_MAP:
verifiers.FlashServoKeyboardMapVerifier,
ACTION_VERIFY_DUT_MACADDR: verifiers.VerifyDUTMacAddress,
ACTION_VERIFY_RPM_CONFIG: verifiers.VerifyRPMConfig,
}
# Actions required Servod service
ACTIONS_REQUIRED_SERVOD = set([
ACTION_VERIFY_DUT_STORAGE,
ACTION_VERIFY_SERVO_USB,
ACTION_FLASH_SERVO_KEYBOARD_MAP,
ACTION_VERIFY_DUT_MACADDR,
])
# Actions required ServoHost without Servod process
ACTIONS_REQUIRED_SERVO_HOST = set([
ACTION_VERIFY_SERVO_FW,
])
class DutAuditError(Exception):
"""Generic error raised during DUT audit."""
def main():
"""Tool to audit a DUT."""
opts = _parse_args()
# Create logging setting
logging_manager.configure_logging(
server_logging_config.ServerLoggingConfig(),
results_dir=opts.results_dir)
logging.debug('autoserv is running in drone %s.', socket.gethostname())
logging.debug('audit environment: %r', os.environ)
logging.debug('audit command was: %s', ' '.join(sys.argv))
logging.debug('audit parsed options: %s', opts)
# Initialize ServoHost without running Servod process.
need_servo_host = bool(set(opts.actions) & ACTIONS_REQUIRED_SERVO_HOST)
# Initialize ServoHost with running Servod process.
need_servod = bool(set(opts.actions) & ACTIONS_REQUIRED_SERVOD)
# Create folder for servo uart logs.
servo_uart_logs_dir = None
if need_servod:
servo_uart_logs_dir = _create_servo_uart_path(opts.results_dir)
try:
host_object = factory.create_target_host(
opts.hostname,
host_info_path=opts.host_info_file,
try_lab_servo=need_servod,
try_servo_repair=need_servod,
servo_uart_logs_dir=servo_uart_logs_dir)
except Exception as err:
logging.error("fail to create host: %s", err)
return RETURN_CODES.OTHER_FAILURES
with host_object as host:
if need_servo_host and not need_servod:
try:
host.set_servo_host(servo_host.ServoHost(
**servo_host.get_servo_args_for_host(host)
))
except Exception as err:
logging.error("fail to init servo host: %s", err)
return RETURN_CODES.OTHER_FAILURES
for action in opts.actions:
if opts.dry_run:
logging.info('DRY RUN: Would have run actions %s', action)
return
response = _verify(action, host, opts.results_dir)
if response:
return response
return RETURN_CODES.OK
def _verify(action, host, resultdir):
"""Run verifier for the action with targeted host.
@param action: The action requested to run the verifier.
@param host: The host presentation of the DUT.
"""
try:
_log("START", action)
verifier = VERIFIER_MAP[action]
if verifier:
v = verifier(host)
v.set_result_dir(resultdir)
v.verify()
else:
logging.info('Verifier is not specified')
_log("END_GOOD", action)
except Exception as err:
_log("END_FAIL", action, err)
return RETURN_CODES.VERIFY_FAILURE
def _log(status, action, err=None):
if err:
message = '%s:%s; %s' % (action, status, str(err))
else:
message = '%s:%s' % (action, status)
logging.info(message)
def _create_servo_uart_path(results_dir):
servo_uart_logs = os.path.join(results_dir, _SERVO_UART_LOGS)
try:
if not os.path.exists(servo_uart_logs):
os.makedirs(servo_uart_logs)
except OSError as e:
logging.debug(
'(not critical) Fail to create dir for servo logs;'
' %s', e)
if not (e.errno == errno.EEXIST):
servo_uart_logs = None
return servo_uart_logs
def _parse_args():
parser = argparse.ArgumentParser(description='Audit DUT in a lab.')
parser.add_argument(
'actions',
nargs='+',
choices=list(VERIFIER_MAP),
help='DUT audit actions to execute.',
)
parser.add_argument(
'--dry-run',
action='store_true',
default=False,
help='Run in dry-run mode. No changes will be made to the DUT.',
)
parser.add_argument(
'--results-dir',
required=True,
help='Directory to drop logs and output artifacts in.',
)
parser.add_argument(
'--hostname',
required=True,
help='Hostname of the DUT to audit.',
)
parser.add_argument(
'--host-info-file',
required=True,
help=('Full path to HostInfo file.'
' DUT inventory information is read from the HostInfo file.'
),
)
return parser.parse_args()
if __name__ == '__main__':
sys.exit(main())