Remote/VM plugins: Log full remote debug info to job log dir

In order to troubleshoot more effectively problems
happening in remote/vm operations, make all output
coming from fabric and paramiko to a 'remote.log'
file in the top level job directory.
Signed-off-by: NLucas Meneghel Rodrigues <lmr@redhat.com>
上级 8f2e49e0
...@@ -83,6 +83,16 @@ DEFAULT_LOGGING = { ...@@ -83,6 +83,16 @@ DEFAULT_LOGGING = {
'level': 'DEBUG', 'level': 'DEBUG',
'propagate': False, 'propagate': False,
}, },
'avocado.fabric': {
'handlers': ['null'],
'level': 'DEBUG',
'propagate': False,
},
'paramiko': {
'handlers': ['null'],
'level': 'DEBUG',
'propagate': False,
},
'avocado.test.stdout': { 'avocado.test.stdout': {
'handlers': ['null'], 'handlers': ['null'],
'level': 'DEBUG', 'level': 'DEBUG',
......
...@@ -82,8 +82,7 @@ class RemoteTestResult(HumanTestResult): ...@@ -82,8 +82,7 @@ class RemoteTestResult(HumanTestResult):
self.remote = remoter.Remote(self.args.remote_hostname, self.remote = remoter.Remote(self.args.remote_hostname,
self.args.remote_username, self.args.remote_username,
self.args.remote_password, self.args.remote_password,
self.args.remote_port, self.args.remote_port)
quiet=True)
self._copy_tests() self._copy_tests()
def tear_down(self): def tear_down(self):
......
...@@ -17,8 +17,10 @@ import sys ...@@ -17,8 +17,10 @@ import sys
import json import json
import os import os
import re import re
import logging
from .test import RemoteTest from .test import RemoteTest
from .. import output
from .. import exceptions from .. import exceptions
from .. import status from .. import status
from ..runner import TestRunner from ..runner import TestRunner
...@@ -46,6 +48,10 @@ class RemoteTestRunner(TestRunner): ...@@ -46,6 +48,10 @@ class RemoteTestRunner(TestRunner):
:returns: (True, (x, y, z)) if avocado appears to be installed and :returns: (True, (x, y, z)) if avocado appears to be installed and
(False, None) otherwise. (False, None) otherwise.
""" """
# This will be useful as extra debugging info in case avocado
# doesn't seem to be available in the remote system.
self.result.remote.run('env', ignore_status=True, timeout=60)
result = self.result.remote.run('avocado -v', result = self.result.remote.run('avocado -v',
ignore_status=True, ignore_status=True,
timeout=60) timeout=60)
...@@ -128,39 +134,63 @@ class RemoteTestRunner(TestRunner): ...@@ -128,39 +134,63 @@ class RemoteTestRunner(TestRunner):
if not timeout: # avoid timeout = 0 if not timeout: # avoid timeout = 0
timeout = None timeout = None
failures = [] failures = []
stdout_backup = sys.stdout
stderr_backup = sys.stderr
fabric_debugfile = os.path.join(self.job.logdir, 'remote.log')
paramiko_logger = logging.getLogger('paramiko')
fabric_logger = logging.getLogger('avocado.fabric')
app_logger = logging.getLogger('avocado.debug')
fmt = ('%(asctime)s %(module)-10.10s L%(lineno)-.4d %('
'levelname)-5.5s| %(message)s')
formatter = logging.Formatter(fmt=fmt, datefmt='%H:%M:%S')
file_handler = logging.FileHandler(filename=fabric_debugfile)
file_handler.setFormatter(formatter)
fabric_logger.addHandler(file_handler)
paramiko_logger.addHandler(file_handler)
logger_list = [fabric_logger]
if self.result.args.show_job_log:
logger_list.append(app_logger)
output.add_console_handler(paramiko_logger)
sys.stdout = output.LoggingFile(logger=logger_list)
sys.stderr = output.LoggingFile(logger=logger_list)
try: try:
self.result.setup() try:
except Exception, details: self.result.setup()
stacktrace.log_exc_info(sys.exc_info(), logger='avocado.test') except Exception, details:
raise exceptions.JobError(details) stacktrace.log_exc_info(sys.exc_info(), logger='avocado.test')
results = self.run_test(self.result.urls, timeout) raise exceptions.JobError(details)
remote_log_dir = os.path.dirname(results['debuglog']) results = self.run_test(self.result.urls, timeout)
self.result.start_tests() remote_log_dir = os.path.dirname(results['debuglog'])
for tst in results['tests']: self.result.start_tests()
test = RemoteTest(name=tst['test'], for tst in results['tests']:
time=tst['time'], test = RemoteTest(name=tst['test'],
start=tst['start'], time=tst['time'],
end=tst['end'], start=tst['start'],
status=tst['status'], end=tst['end'],
logdir=tst['logdir'], status=tst['status'],
logfile=tst['logfile'], logdir=tst['logdir'],
fail_reason=tst['fail_reason']) logfile=tst['logfile'],
state = test.get_state() fail_reason=tst['fail_reason'])
self.result.start_test(state) state = test.get_state()
self.result.check_test(state) self.result.start_test(state)
if not status.mapping[state['status']]: self.result.check_test(state)
failures.append(state['tagged_name']) if not status.mapping[state['status']]:
local_log_dir = os.path.dirname(self.result.stream.debuglog) failures.append(state['tagged_name'])
zip_filename = remote_log_dir + '.zip' local_log_dir = os.path.dirname(self.result.stream.debuglog)
zip_path_filename = os.path.join(local_log_dir, zip_filename = remote_log_dir + '.zip'
os.path.basename(zip_filename)) zip_path_filename = os.path.join(local_log_dir,
self.result.remote.receive_files(local_log_dir, zip_filename) os.path.basename(zip_filename))
archive.uncompress(zip_path_filename, local_log_dir) self.result.remote.receive_files(local_log_dir, zip_filename)
os.remove(zip_path_filename) archive.uncompress(zip_path_filename, local_log_dir)
self.result.end_tests() os.remove(zip_path_filename)
try: self.result.end_tests()
self.result.tear_down() try:
except Exception, details: self.result.tear_down()
stacktrace.log_exc_info(sys.exc_info(), logger='avocado.test') except Exception, details:
raise exceptions.JobError(details) stacktrace.log_exc_info(sys.exc_info(), logger='avocado.test')
raise exceptions.JobError(details)
finally:
sys.stdout = stdout_backup
sys.stderr = stderr_backup
return failures return failures
...@@ -85,16 +85,10 @@ class Remote(object): ...@@ -85,16 +85,10 @@ class Remote(object):
:rtype: :class:`avocado.utils.process.CmdResult`. :rtype: :class:`avocado.utils.process.CmdResult`.
:raise fabric.exceptions.CommandTimeout: When timeout exhausted. :raise fabric.exceptions.CommandTimeout: When timeout exhausted.
""" """
if not self.quiet:
LOG.info('[%s] Running command %s', self.hostname, command)
result = process.CmdResult() result = process.CmdResult()
stdout = output.LoggingFile(logger=logging.getLogger('avocado.test'))
stderr = output.LoggingFile(logger=logging.getLogger('avocado.test'))
start_time = time.time() start_time = time.time()
fabric_result = fabric.operations.run(command=command, fabric_result = fabric.operations.run(command=command,
quiet=self.quiet, quiet=self.quiet,
stdout=stdout,
stderr=stderr,
warn_only=True, warn_only=True,
timeout=timeout) timeout=timeout)
end_time = time.time() end_time = time.time()
...@@ -138,15 +132,11 @@ class Remote(object): ...@@ -138,15 +132,11 @@ class Remote(object):
:param local_path: the local path. :param local_path: the local path.
:param remote_path: the remote path. :param remote_path: the remote path.
""" """
if not self.quiet: try:
LOG.info('[%s] Sending files %s -> %s', self.hostname, fabric.operations.put(local_path, remote_path,
local_path, remote_path) mirror_local_mode=True)
with fabric.context_managers.quiet(): except ValueError:
try: return False
fabric.operations.put(local_path, remote_path,
mirror_local_mode=True)
except ValueError:
return False
return True return True
def receive_files(self, local_path, remote_path): def receive_files(self, local_path, remote_path):
...@@ -156,13 +146,9 @@ class Remote(object): ...@@ -156,13 +146,9 @@ class Remote(object):
:param local_path: the local path. :param local_path: the local path.
:param remote_path: the remote path. :param remote_path: the remote path.
""" """
if not self.quiet: try:
LOG.info('[%s] Receive remote files %s -> %s', self.hostname, fabric.operations.get(remote_path,
local_path, remote_path) local_path)
with fabric.context_managers.quiet(): except ValueError:
try: return False
fabric.operations.get(remote_path,
local_path)
except ValueError:
return False
return True return True
...@@ -273,8 +273,7 @@ class VM(object): ...@@ -273,8 +273,7 @@ class VM(object):
:param password: the password. :param password: the password.
""" """
if not self.logged: if not self.logged:
self.remote = remoter.Remote(hostname, username, password, self.remote = remoter.Remote(hostname, username, password)
quiet=True)
res = self.remote.uptime() res = self.remote.uptime()
if res.succeeded: if res.succeeded:
self.logged = True self.logged = True
......
...@@ -32,14 +32,44 @@ class RemoteTestRunnerTest(unittest.TestCase): ...@@ -32,14 +32,44 @@ class RemoteTestRunnerTest(unittest.TestCase):
def setUp(self): def setUp(self):
flexmock(remote.RemoteTestRunner).should_receive('__init__') flexmock(remote.RemoteTestRunner).should_receive('__init__')
self.remote = remote.RemoteTestRunner(None, None) self.remote = remote.RemoteTestRunner(None, None)
self.remote.job = flexmock(logdir='.')
test_results = flexmock(stdout=JSON_RESULTS, exit_status=0) test_results = flexmock(stdout=JSON_RESULTS, exit_status=0)
stream = flexmock(job_unique_id='sleeptest.1', stream = flexmock(job_unique_id='sleeptest.1',
debuglog='/local/path/dirname') debuglog='/local/path/dirname')
Remote = flexmock() Remote = flexmock()
args = 'avocado -v' args_version = 'avocado -v'
version_result = flexmock(stdout='Avocado 1.2.3', exit_status=0) version_result = flexmock(stdout='Avocado 1.2.3', exit_status=0)
args_env = 'env'
env_result = flexmock(stdout='''XDG_SESSION_ID=20
HOSTNAME=rhel7.0
SELINUX_ROLE_REQUESTED=
SHELL=/bin/bash
TERM=vt100
HISTSIZE=1000
SSH_CLIENT=192.168.124.1 52948 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
MAIL=/var/spool/mail/root
PWD=/root
LANG=en_US.UTF-8
SELINUX_LEVEL_REQUESTED=
HISTCONTROL=ignoredups
HOME=/root
SHLVL=2
LOGNAME=root
SSH_CONNECTION=192.168.124.1 52948 192.168.124.65 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
_=/usr/bin/env''', exit_status=0)
(Remote.should_receive('run')
.with_args(args_env, ignore_status=True, timeout=60)
.once().and_return(env_result))
(Remote.should_receive('run') (Remote.should_receive('run')
.with_args(args, ignore_status=True, timeout=60) .with_args(args_version, ignore_status=True, timeout=60)
.once().and_return(version_result)) .once().and_return(version_result))
args = 'cd ~/avocado/tests; avocado list sleeptest --paginator=off' args = 'cd ~/avocado/tests; avocado list sleeptest --paginator=off'
...@@ -54,7 +84,8 @@ class RemoteTestRunnerTest(unittest.TestCase): ...@@ -54,7 +84,8 @@ class RemoteTestRunnerTest(unittest.TestCase):
.with_args(args, timeout=61, ignore_status=True) .with_args(args, timeout=61, ignore_status=True)
.once().and_return(test_results)) .once().and_return(test_results))
Results = flexmock(remote=Remote, urls=['sleeptest'], Results = flexmock(remote=Remote, urls=['sleeptest'],
stream=stream, timeout=None) stream=stream, timeout=None,
args=flexmock(show_job_log=False))
Results.should_receive('setup').once().ordered() Results.should_receive('setup').once().ordered()
Results.should_receive('start_tests').once().ordered() Results.should_receive('start_tests').once().ordered()
args = {'status': u'PASS', 'whiteboard': '', 'time_start': 0, args = {'status': u'PASS', 'whiteboard': '', 'time_start': 0,
...@@ -102,7 +133,7 @@ class RemoteTestResultTest(unittest.TestCase): ...@@ -102,7 +133,7 @@ class RemoteTestResultTest(unittest.TestCase):
Stream.should_receive('notify').once().ordered() Stream.should_receive('notify').once().ordered()
remote_remote = flexmock(remoter) remote_remote = flexmock(remoter)
(remote_remote.should_receive('Remote') (remote_remote.should_receive('Remote')
.with_args('hostname', 'username', 'password', 22, quiet=True) .with_args('hostname', 'username', 'password', 22)
.once().ordered() .once().ordered()
.and_return(Remote)) .and_return(Remote))
(Remote.should_receive('makedir').with_args('~/avocado/tests') (Remote.should_receive('makedir').with_args('~/avocado/tests')
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册