Add log monitoring to lmc --no-virt installation
Previously if there was an error during a novirt installation that didn't exit the process there was no way to detect it. This uses the new --remotelog option for anaconda to monitor the logs for errors using the same criteria as it does when monitoring a virt install. If there is an error the anaconda process will be terminated and the logs will be gathered up into ./anaconda/
This commit is contained in:
parent
bd501cccef
commit
d96ed99621
@ -23,6 +23,7 @@
|
|||||||
import os, sys
|
import os, sys
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger("pylorax")
|
log = logging.getLogger("pylorax")
|
||||||
@ -66,7 +67,7 @@ class tee(threading.Thread):
|
|||||||
|
|
||||||
def execWithRedirect(command, argv, stdin = None, stdout = None,
|
def execWithRedirect(command, argv, stdin = None, stdout = None,
|
||||||
stderr = None, root = None, preexec_fn=None, cwd=None,
|
stderr = None, root = None, preexec_fn=None, cwd=None,
|
||||||
raise_err=False):
|
raise_err=False, callback=None):
|
||||||
""" Run an external program and redirect the output to a file.
|
""" Run an external program and redirect the output to a file.
|
||||||
@param command The command to run.
|
@param command The command to run.
|
||||||
@param argv A list of arguments.
|
@param argv A list of arguments.
|
||||||
@ -77,7 +78,11 @@ def execWithRedirect(command, argv, stdin = None, stdout = None,
|
|||||||
@param preexec_fn function to pass to Popen
|
@param preexec_fn function to pass to Popen
|
||||||
@param cwd working directory to pass to Popen
|
@param cwd working directory to pass to Popen
|
||||||
@param raise_err raise CalledProcessError when the returncode is not 0
|
@param raise_err raise CalledProcessError when the returncode is not 0
|
||||||
|
@param callback method to call while waiting for process to exit.
|
||||||
@return The return code of command.
|
@return The return code of command.
|
||||||
|
|
||||||
|
The callback is passed the Popen object. It should return False if
|
||||||
|
the polling loop should be exited.
|
||||||
"""
|
"""
|
||||||
def chroot ():
|
def chroot ():
|
||||||
os.chroot(root)
|
os.chroot(root)
|
||||||
@ -143,6 +148,9 @@ def execWithRedirect(command, argv, stdin = None, stdout = None,
|
|||||||
preexec_fn=preexec_fn, cwd=cwd,
|
preexec_fn=preexec_fn, cwd=cwd,
|
||||||
env=env)
|
env=env)
|
||||||
|
|
||||||
|
if callback:
|
||||||
|
while callback(proc) and proc.poll() is None:
|
||||||
|
sleep(1)
|
||||||
proc.wait()
|
proc.wait()
|
||||||
ret = proc.returncode
|
ret = proc.returncode
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ class LogRequestHandler(SocketServer.BaseRequestHandler):
|
|||||||
if self.server.log_path:
|
if self.server.log_path:
|
||||||
self.fp = open(self.server.log_path, "w") # pylint: disable=attribute-defined-outside-init
|
self.fp = open(self.server.log_path, "w") # pylint: disable=attribute-defined-outside-init
|
||||||
else:
|
else:
|
||||||
print "no log_path specified"
|
self.fp = None
|
||||||
self.request.settimeout(10)
|
self.request.settimeout(10)
|
||||||
|
|
||||||
def handle(self):
|
def handle(self):
|
||||||
@ -107,6 +107,7 @@ class LogRequestHandler(SocketServer.BaseRequestHandler):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
data = self.request.recv(4096)
|
data = self.request.recv(4096)
|
||||||
|
if self.fp:
|
||||||
self.fp.write(data)
|
self.fp.write(data)
|
||||||
self.fp.flush()
|
self.fp.flush()
|
||||||
|
|
||||||
@ -130,6 +131,7 @@ class LogRequestHandler(SocketServer.BaseRequestHandler):
|
|||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
self.request.close()
|
self.request.close()
|
||||||
|
if self.fp:
|
||||||
self.fp.close()
|
self.fp.close()
|
||||||
|
|
||||||
def iserror(self, line):
|
def iserror(self, line):
|
||||||
@ -193,7 +195,7 @@ class LogMonitor(object):
|
|||||||
This needs to be running before the virt-install runs, it expects
|
This needs to be running before the virt-install runs, it expects
|
||||||
there to be a listener on the port used for the virtio log port.
|
there to be a listener on the port used for the virtio log port.
|
||||||
"""
|
"""
|
||||||
def __init__(self, log_path, host="localhost", port=0):
|
def __init__(self, log_path=None, host="localhost", port=0):
|
||||||
"""
|
"""
|
||||||
Start a thread to monitor the logs.
|
Start a thread to monitor the logs.
|
||||||
|
|
||||||
@ -203,6 +205,9 @@ class LogMonitor(object):
|
|||||||
|
|
||||||
If 0 is passed for the port the dynamically assigned port will be
|
If 0 is passed for the port the dynamically assigned port will be
|
||||||
available as self.port
|
available as self.port
|
||||||
|
|
||||||
|
If log_path isn't set then it only monitors the logs, instead of
|
||||||
|
also writing them to disk.
|
||||||
"""
|
"""
|
||||||
self.server = LogServer(log_path, (host, port), LogRequestHandler)
|
self.server = LogServer(log_path, (host, port), LogRequestHandler)
|
||||||
self.host, self.port = self.server.server_address
|
self.host, self.port = self.server.server_address
|
||||||
@ -590,6 +595,23 @@ def make_livecd(opts, mount_dir, work_dir):
|
|||||||
return work_dir
|
return work_dir
|
||||||
|
|
||||||
|
|
||||||
|
def novirt_log_check(log_check, proc):
|
||||||
|
"""
|
||||||
|
Check to see if there has been an error in the logs
|
||||||
|
|
||||||
|
:param log_check: method to call to check for an error in the logs
|
||||||
|
:param proc: Popen object for the anaconda process
|
||||||
|
:returns: True if the process has been terminated
|
||||||
|
|
||||||
|
The log_check method should return a True if an error has been detected.
|
||||||
|
When an error is detected the process is terminated and this returns True
|
||||||
|
"""
|
||||||
|
if log_check():
|
||||||
|
proc.terminate()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def novirt_install(opts, disk_img, disk_size, repo_url):
|
def novirt_install(opts, disk_img, disk_size, repo_url):
|
||||||
"""
|
"""
|
||||||
Use Anaconda to install to a disk image
|
Use Anaconda to install to a disk image
|
||||||
@ -648,12 +670,16 @@ def novirt_install(opts, disk_img, disk_size, repo_url):
|
|||||||
# Create the sparse image
|
# Create the sparse image
|
||||||
mksparse(disk_img, disk_size * 1024**2)
|
mksparse(disk_img, disk_size * 1024**2)
|
||||||
|
|
||||||
|
log_monitor = LogMonitor()
|
||||||
|
args += ["--remotelog", "%s:%s" % (log_monitor.host, log_monitor.port)]
|
||||||
|
|
||||||
# Make sure anaconda has the right product and release
|
# Make sure anaconda has the right product and release
|
||||||
os.environ["ANACONDA_PRODUCTNAME"] = opts.project
|
os.environ["ANACONDA_PRODUCTNAME"] = opts.project
|
||||||
os.environ["ANACONDA_PRODUCTVERSION"] = opts.releasever
|
os.environ["ANACONDA_PRODUCTVERSION"] = opts.releasever
|
||||||
log.info("Running anaconda.")
|
log.info("Running anaconda.")
|
||||||
try:
|
try:
|
||||||
execWithRedirect("anaconda", args, raise_err=True)
|
execWithRedirect("anaconda", args, raise_err=True,
|
||||||
|
callback=lambda p: not novirt_log_check(log_monitor.server.log_check, p))
|
||||||
|
|
||||||
# Make sure the new filesystem is correctly labeled
|
# Make sure the new filesystem is correctly labeled
|
||||||
args = ["-e", "/proc", "-e", "/sys", "-e", "/dev",
|
args = ["-e", "/proc", "-e", "/sys", "-e", "/dev",
|
||||||
@ -668,6 +694,8 @@ def novirt_install(opts, disk_img, disk_size, repo_url):
|
|||||||
log.error("Running anaconda failed: %s", e)
|
log.error("Running anaconda failed: %s", e)
|
||||||
raise InstallError("novirt_install failed")
|
raise InstallError("novirt_install failed")
|
||||||
finally:
|
finally:
|
||||||
|
log_monitor.shutdown()
|
||||||
|
|
||||||
# Move the anaconda logs over to a log directory
|
# Move the anaconda logs over to a log directory
|
||||||
log_dir = os.path.abspath(os.path.dirname(opts.logfile))
|
log_dir = os.path.abspath(os.path.dirname(opts.logfile))
|
||||||
log_anaconda = joinpaths(log_dir, "anaconda")
|
log_anaconda = joinpaths(log_dir, "anaconda")
|
||||||
|
Loading…
Reference in New Issue
Block a user