@@ -105,6 +105,15 @@ class VMDeadError(VMError):
(self.status, self.output))
+class VMDeadKernelCrashError(VMError):
+ def __init__(self, kernel_crash):
+ VMError.__init__(self, kernel_crash)
+ self.kernel_crash = kernel_crash
+
+ def __str__(self):
+ return ("VM is dead due to a kernel crash: %s" % self.kernel_crash)
+
+
class VMAddressError(VMError):
pass
@@ -1471,6 +1480,29 @@ class VM:
return self.serial_login(internal_timeout)
+ def verify_kernel_crash(self, timeout=2):
+ """
+ Find kernel crash message on serial console.
+
+ @param timeout: Timeout used to verify expected output.
+
+ @raise: VMDeadKernelCrashError, in case a kernel crash message was
+ found.
+ """
+ data = self.serial_console.read_nonblocking()
+ match = re.search("BUG:", data, re.MULTILINE)
+ if match is not None:
+ match = re.search(r"BUG:.*---\[ end trace .* \]---",
+ data, re.DOTALL |re.MULTILINE)
+ if match is None:
+ data += self.serial_console.read_until_last_line_matches(
+ ["---\[ end trace .* \]---"],
+ timeout)
+ match = re.search(r"(BUG:.*---\[ end trace .* \]---)",
+ data, re.DOTALL |re.MULTILINE)
+ raise VMDeadKernelCrashError(match.group(0))
+
+
@error.context_aware
def migrate(self, timeout=3600, protocol="tcp", cancel_delay=None,
offline=False, stable_check=False, clean=True,
@@ -33,6 +33,7 @@ def run_unattended_install(test, params, env):
start_time = time.time()
while (time.time() - start_time) < install_timeout:
vm.verify_alive()
+ vm.verify_kernel_crash()
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client.connect((vm.get_address(), port))