blob: f8e45b6bbc04e6ced3285572f57a7b1ec39a023c [file] [log] [blame]
import os, re, sys, subprocess, socket
from autotest_lib.client.common_lib import utils, error
from autotest_lib.server.hosts import remote
class NetconsoleHost(remote.RemoteHost):
def _initialize(self, console_log="netconsole.log", *args, **dargs):
super(NetconsoleHost, self)._initialize(*args, **dargs)
self.__logger = None
self.__console_log = console_log
# get a socket for us to listen on
self.__socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.__socket.bind(('', 0))
self.__port = self.__socket.getsockname()[1]
@classmethod
def host_is_supported(cls, run_func):
local_ip = socket.gethostbyname(socket.gethostname())
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(1)
s.bind((local_ip, 0))
local_port = s.getsockname()[1]
send_udp_packet = (
"""python -c "from socket import *; """
"""s = socket(AF_INET, SOCK_DGRAM); """
"""s.sendto('ping', ('%s', %d))" """ % (local_ip, local_port))
run_func(send_udp_packet)
try:
msg = s.recv(4)
except Exception:
supported = False
else:
supported = (msg == "ping")
s.close()
return supported
def start_loggers(self):
super(NetconsoleHost, self).start_loggers()
if not self.__console_log:
return
self.__netconsole_params = self.__determine_netconsole_params()
if self.__netconsole_params is None:
return
r, w = os.pipe()
script_path = os.path.join(self.monitordir, "console.py")
cmd = [sys.executable, script_path, self.__console_log, str(w)]
self.__warning_stream = os.fdopen(r, "r", 0)
if self.job:
self.job.warning_loggers.add(self.__warning_stream)
stdin = self.__socket.fileno()
stdout = stderr = open(os.devnull, "w")
self.__logger = subprocess.Popen(cmd, stdin=stdin, stdout=stdout,
stderr=stderr)
os.close(w)
self.__unload_netconsole_module()
self.__load_netconsole_module()
def stop_loggers(self):
super(NetconsoleHost, self).stop_loggers()
if self.__logger:
utils.nuke_subprocess(self.__logger)
self.__logger = None
if self.job:
self.job.warning_loggers.discard(self.__warning_stream)
self.__warning_stream.close()
def reboot_setup(self, *args, **dargs):
super(NetconsoleHost, self).reboot_setup(*args, **dargs)
if self.__netconsole_params is not None:
label = dargs.get("label", None)
if not label:
label = self.bootloader.get_default_title()
args = "debug " + self.__netconsole_params
self.bootloader.add_args(label, args)
self.__unload_netconsole_module()
def reboot_followup(self, *args, **dargs):
super(NetconsoleHost, self).reboot_followup(*args, **dargs)
self.__load_netconsole_module()
def __determine_netconsole_params(self):
"""
Connect to the remote machine and determine the values to use for the
required netconsole parameters.
"""
# determine the IP addresses of the local and remote machine
# PROBLEM: on machines with multiple IPs this may not make any sense
# It also doesn't work with IPv6
remote_ip = socket.gethostbyname(self.hostname)
local_ip = socket.gethostbyname(socket.gethostname())
# Get the gateway of the remote machine
try:
traceroute = self.run('traceroute -n %s' % local_ip)
except error.AutoservRunError:
return
first_node = traceroute.stdout.split("\n")[0]
match = re.search(r'\s+((\d+\.){3}\d+)\s+', first_node)
if match:
router_ip = match.group(1)
else:
return
# Look up the MAC address of the gateway
try:
self.run('ping -c 1 %s' % router_ip)
arp = self.run('arp -n -a %s' % router_ip)
except error.AutoservRunError:
return
match = re.search(r'\s+(([0-9A-F]{2}:){5}[0-9A-F]{2})\s+', arp.stdout)
if match:
gateway_mac = match.group(1)
else:
return None
return 'netconsole=@%s/,%s@%s/%s' % (remote_ip, self.__port, local_ip,
gateway_mac)
def __load_netconsole_module(self):
"""
Make a best effort to load the netconsole module.
Note that loading the module can fail even when the remote machine is
working correctly if netconsole is already compiled into the kernel
and started.
"""
if self.__netconsole_params is None:
return
try:
self.run('dmesg -n 8')
self.run('modprobe netconsole %s' % self.__netconsole_params)
except error.AutoservRunError, e:
# if it fails there isn't much we can do, just keep going
print "ERROR occured while loading netconsole: %s" % e
def __unload_netconsole_module(self):
try:
self.run('modprobe -r netconsole')
except error.AutoservRunError:
pass