You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
7.9 KiB
194 lines
7.9 KiB
# Copyright 2017 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.
|
|
|
|
"""Utility to deploy and run result utils on a DUT.
|
|
|
|
This module is the one imported by other Autotest code and run result
|
|
throttling. Other modules in result_tools are designed to be copied to DUT and
|
|
executed with command line. That's why other modules (except view.py and
|
|
unittests) don't import the common module.
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
|
|
import common
|
|
from autotest_lib.client.common_lib import error
|
|
from autotest_lib.client.common_lib import global_config
|
|
from autotest_lib.client.common_lib import utils as client_utils
|
|
|
|
try:
|
|
from chromite.lib import metrics
|
|
except ImportError:
|
|
metrics = client_utils.metrics_mock
|
|
|
|
|
|
CONFIG = global_config.global_config
|
|
ENABLE_RESULT_THROTTLING = CONFIG.get_config_value(
|
|
'AUTOSERV', 'enable_result_throttling', type=bool, default=False)
|
|
|
|
_THROTTLE_OPTION_FMT = '-m %s'
|
|
_SUMMARY_CMD= '%s/result_tools/utils.py'
|
|
_BUILD_DIR_SUMMARY_CMD = _SUMMARY_CMD + ' -p %s %s'
|
|
_BUILD_DIR_SUMMARY_TIMEOUT = 120
|
|
_FIND_DIR_SUMMARY_TIMEOUT = 10
|
|
_CLEANUP_DIR_SUMMARY_CMD = _SUMMARY_CMD + ' -p %s -d'
|
|
_CLEANUP_DIR_SUMMARY_TIMEOUT = 10
|
|
|
|
# Default autotest directory on host
|
|
DEFAULT_AUTOTEST_DIR = '/usr/local/autotest'
|
|
|
|
# File patterns to be excluded from deploying to the dut.
|
|
_EXCLUDES = ['*.pyc', '*unittest.py', 'common.py', '__init__.py', 'runner.py',
|
|
'view.py']
|
|
|
|
def _deploy_result_tools(host):
|
|
"""Send result tools to the dut.
|
|
|
|
@param host: Host to run the result tools.
|
|
"""
|
|
with metrics.SecondsTimer(
|
|
'chromeos/autotest/job/send_result_tools_duration',
|
|
fields={'dut_host_name': host.hostname}) as fields:
|
|
try:
|
|
result = host.run('test -f %s' %
|
|
(_SUMMARY_CMD % DEFAULT_AUTOTEST_DIR),
|
|
timeout=_FIND_DIR_SUMMARY_TIMEOUT,
|
|
ignore_status=True)
|
|
if result.exit_status == 0:
|
|
logging.debug('result tools are already deployed to %s.',
|
|
host.hostname)
|
|
else:
|
|
logging.debug('Deploy result utilities to %s', host.hostname)
|
|
result_tools_dir = os.path.dirname(__file__)
|
|
host.send_file(result_tools_dir, DEFAULT_AUTOTEST_DIR,
|
|
excludes = _EXCLUDES)
|
|
fields['success'] = True
|
|
except error.AutotestHostRunError:
|
|
logging.debug('Failed to deploy result tools using `excludes`. Try '
|
|
'again without `excludes`.')
|
|
host.send_file(result_tools_dir, DEFAULT_AUTOTEST_DIR)
|
|
fields['success'] = False
|
|
|
|
|
|
def run_on_client(host, client_results_dir, cleanup_only=False):
|
|
"""Run result utils on the given host.
|
|
|
|
@param host: Host to run the result utils.
|
|
@param client_results_dir: Path to the results directory on the client.
|
|
@param cleanup_only: True to delete all existing directory summary files in
|
|
the given directory.
|
|
@return: True: If the command runs on client without error.
|
|
False: If the command failed with error in result throttling.
|
|
"""
|
|
success = False
|
|
with metrics.SecondsTimer(
|
|
'chromeos/autotest/job/dir_summary_collection_duration',
|
|
fields={'dut_host_name': host.hostname}) as fields:
|
|
try:
|
|
_deploy_result_tools(host)
|
|
|
|
if cleanup_only:
|
|
logging.debug('Cleaning up directory summary in %s',
|
|
client_results_dir)
|
|
cmd = (_CLEANUP_DIR_SUMMARY_CMD %
|
|
(DEFAULT_AUTOTEST_DIR, client_results_dir))
|
|
host.run(cmd, ignore_status=False,
|
|
timeout=_CLEANUP_DIR_SUMMARY_TIMEOUT)
|
|
else:
|
|
logging.debug('Getting directory summary for %s',
|
|
client_results_dir)
|
|
throttle_option = ''
|
|
if ENABLE_RESULT_THROTTLING:
|
|
try:
|
|
throttle_option = (_THROTTLE_OPTION_FMT %
|
|
host.job.max_result_size_KB)
|
|
except AttributeError:
|
|
# In case host job is not set, skip throttling.
|
|
logging.warn('host object does not have job attribute, '
|
|
'skipping result throttling.')
|
|
cmd = (_BUILD_DIR_SUMMARY_CMD %
|
|
(DEFAULT_AUTOTEST_DIR, client_results_dir,
|
|
throttle_option))
|
|
host.run(cmd, ignore_status=False,
|
|
timeout=_BUILD_DIR_SUMMARY_TIMEOUT)
|
|
success = True
|
|
fields['success'] = True
|
|
except error.AutoservRunError:
|
|
action = 'cleanup' if cleanup_only else 'create'
|
|
logging.exception(
|
|
'Non-critical failure: Failed to %s directory summary for '
|
|
'%s.', action, client_results_dir)
|
|
fields['success'] = False
|
|
|
|
return success
|
|
|
|
|
|
def collect_last_summary(host, source_path, dest_path,
|
|
skip_summary_collection=False):
|
|
"""Collect the last directory summary next to the given file path.
|
|
|
|
If the given source_path is a directory, return without collecting any
|
|
result summary file, as the summary file should have been collected with the
|
|
directory.
|
|
|
|
@param host: The RemoteHost to collect logs from.
|
|
@param source_path: The remote path to collect the directory summary file
|
|
from. If the source_path is a file
|
|
@param dest_path: A path to write the source_path into. The summary file
|
|
will be saved to the same folder.
|
|
@param skip_summary_collection: True to skip summary file collection, only
|
|
to delete the last summary. This is used in case when result
|
|
collection in the dut failed. Default is set to False.
|
|
"""
|
|
if not os.path.exists(dest_path):
|
|
logging.debug('Source path %s does not exist, no directory summary '
|
|
'will be collected', dest_path)
|
|
return
|
|
|
|
# Test if source_path is a file.
|
|
try:
|
|
host.run('test -f %s' % source_path, timeout=_FIND_DIR_SUMMARY_TIMEOUT)
|
|
is_source_file = True
|
|
except error.AutoservRunError:
|
|
is_source_file = False
|
|
# No need to collect summary files if the source path is a directory,
|
|
# as the summary files should have been copied over with the directory.
|
|
# However, the last summary should be cleaned up so it won't affect
|
|
# later tests.
|
|
skip_summary_collection = True
|
|
|
|
source_dir = os.path.dirname(source_path) if is_source_file else source_path
|
|
dest_dir = dest_path if os.path.isdir(dest_path) else dest_path
|
|
|
|
# Get the latest directory summary file.
|
|
try:
|
|
summary_pattern = os.path.join(source_dir, 'dir_summary_*.json')
|
|
summary_file = host.run(
|
|
'ls -t %s | head -1' % summary_pattern,
|
|
timeout=_FIND_DIR_SUMMARY_TIMEOUT).stdout.strip()
|
|
except error.AutoservRunError:
|
|
logging.exception(
|
|
'Non-critical failure: Failed to locate the latest directory '
|
|
'summary for %s', source_dir)
|
|
return
|
|
|
|
try:
|
|
if not skip_summary_collection:
|
|
host.get_file(
|
|
summary_file,
|
|
os.path.join(dest_dir, os.path.basename(summary_file)),
|
|
preserve_perm=False)
|
|
finally:
|
|
# Remove the collected summary file so it won't affect later tests.
|
|
try:
|
|
# Check and remove the summary file
|
|
if host.path_exists(summary_file):
|
|
host.run('rm %s' % summary_file,
|
|
timeout=_FIND_DIR_SUMMARY_TIMEOUT).stdout.strip()
|
|
except error.AutoservRunError:
|
|
logging.exception(
|
|
'Non-critical failure: Failed to delete the latest '
|
|
'directory summary: %s', summary_file)
|