summaryrefslogtreecommitdiffstats
path: root/meta/lib/oeqa/utils
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2015-09-04 16:59:38 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-09-06 15:26:18 +0100
commitef0fe3193eb546757f7c98274b88c4f2eafd7ad0 (patch)
tree4e3222722ee7fa29409fde8e2f614b8d12683a0e /meta/lib/oeqa/utils
parent3d81a56912fb2c6ca1c5aafb93cbc6e2cfea20b3 (diff)
downloadpoky-ef0fe3193eb546757f7c98274b88c4f2eafd7ad0.tar.gz
oeqa: Test failure/cleanup improvements
Currently, if qemu segfaults, the tests merrily continue trying to execute which takes time for them to timeout and is a bit silly. Worse, no logs about the segfault are shown to the user, its silent! This patch tries to unravel the tangled web of issues and ensures that we: * install a SIGCHLD handler which tells the user qemu exited * check if qemu is running, if it isn't fail the test outright * don't leave processes behind in sshcontrol which would hold bitbake.lock and block shutdown (From OE-Core rev: 5c04b1ca1e989f569d5755a646734d01a0c56cae) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib/oeqa/utils')
-rw-r--r--meta/lib/oeqa/utils/qemurunner.py35
-rw-r--r--meta/lib/oeqa/utils/sshcontrol.py14
2 files changed, 37 insertions, 12 deletions
diff --git a/meta/lib/oeqa/utils/qemurunner.py b/meta/lib/oeqa/utils/qemurunner.py
index 3ad747a503..2d485379e8 100644
--- a/meta/lib/oeqa/utils/qemurunner.py
+++ b/meta/lib/oeqa/utils/qemurunner.py
@@ -64,6 +64,22 @@ class QemuRunner:
64 with open(self.logfile, "a") as f: 64 with open(self.logfile, "a") as f:
65 f.write("%s" % msg) 65 f.write("%s" % msg)
66 66
67 def getOutput(self, o):
68 import fcntl
69 fl = fcntl.fcntl(o, fcntl.F_GETFL)
70 fcntl.fcntl(o, fcntl.F_SETFL, fl | os.O_NONBLOCK)
71 return os.read(o.fileno(), 1000000)
72
73
74 def handleSIGCHLD(self, signum, frame):
75 if self.runqemu and self.runqemu.poll():
76 if self.runqemu.returncode:
77 logger.info('runqemu exited with code %d' % self.runqemu.returncode)
78 logger.info("Output from runqemu:\n%s" % self.getOutput(self.runqemu.stdout))
79 self.stop()
80 self._dump_host()
81 raise SystemExit
82
67 def start(self, qemuparams = None): 83 def start(self, qemuparams = None):
68 if self.display: 84 if self.display:
69 os.environ["DISPLAY"] = self.display 85 os.environ["DISPLAY"] = self.display
@@ -98,11 +114,8 @@ class QemuRunner:
98 if qemuparams: 114 if qemuparams:
99 self.qemuparams = self.qemuparams[:-1] + " " + qemuparams + " " + '\"' 115 self.qemuparams = self.qemuparams[:-1] + " " + qemuparams + " " + '\"'
100 116
101 def getOutput(o): 117 self.origchldhandler = signal.getsignal(signal.SIGCHLD)
102 import fcntl 118 signal.signal(signal.SIGCHLD, self.handleSIGCHLD)
103 fl = fcntl.fcntl(o, fcntl.F_GETFL)
104 fcntl.fcntl(o, fcntl.F_SETFL, fl | os.O_NONBLOCK)
105 return os.read(o.fileno(), 1000000)
106 119
107 launch_cmd = 'runqemu tcpserial=%s %s %s %s' % (self.serverport, self.machine, self.rootfs, self.qemuparams) 120 launch_cmd = 'runqemu tcpserial=%s %s %s %s' % (self.serverport, self.machine, self.rootfs, self.qemuparams)
108 # FIXME: We pass in stdin=subprocess.PIPE here to work around stty 121 # FIXME: We pass in stdin=subprocess.PIPE here to work around stty
@@ -122,7 +135,7 @@ class QemuRunner:
122 logger.info('runqemu exited with code %d' % self.runqemu.returncode) 135 logger.info('runqemu exited with code %d' % self.runqemu.returncode)
123 self._dump_host() 136 self._dump_host()
124 self.stop() 137 self.stop()
125 logger.info("Output from runqemu:\n%s" % getOutput(output)) 138 logger.info("Output from runqemu:\n%s" % self.getOutput(output))
126 return False 139 return False
127 time.sleep(1) 140 time.sleep(1)
128 141
@@ -139,7 +152,7 @@ class QemuRunner:
139 self.ip = ips[0] 152 self.ip = ips[0]
140 self.server_ip = ips[1] 153 self.server_ip = ips[1]
141 except IndexError, ValueError: 154 except IndexError, ValueError:
142 logger.info("Couldn't get ip from qemu process arguments! Here is the qemu command line used:\n%s\nand output from runqemu:\n%s" % (cmdline, getOutput(output))) 155 logger.info("Couldn't get ip from qemu process arguments! Here is the qemu command line used:\n%s\nand output from runqemu:\n%s" % (cmdline, self.getOutput(output)))
143 self._dump_host() 156 self._dump_host()
144 self.stop() 157 self.stop()
145 return False 158 return False
@@ -154,7 +167,7 @@ class QemuRunner:
154 logger.error("Didn't receive a console connection from qemu. " 167 logger.error("Didn't receive a console connection from qemu. "
155 "Here is the qemu command line used:\n%s\nand " 168 "Here is the qemu command line used:\n%s\nand "
156 "output from runqemu:\n%s" % (cmdline, 169 "output from runqemu:\n%s" % (cmdline,
157 getOutput(output))) 170 self.getOutput(output)))
158 self.stop_thread() 171 self.stop_thread()
159 return False 172 return False
160 173
@@ -213,15 +226,15 @@ class QemuRunner:
213 logger.info("Qemu pid didn't appeared in %s seconds" % self.runqemutime) 226 logger.info("Qemu pid didn't appeared in %s seconds" % self.runqemutime)
214 self._dump_host() 227 self._dump_host()
215 self.stop() 228 self.stop()
216 logger.info("Output from runqemu:\n%s" % getOutput(output)) 229 logger.info("Output from runqemu:\n%s" % self.getOutput(output))
217 return False 230 return False
218 231
219 return self.is_alive() 232 return self.is_alive()
220 233
221 def stop(self): 234 def stop(self):
222
223 self.stop_thread() 235 self.stop_thread()
224 if self.runqemu: 236 if self.runqemu:
237 signal.signal(signal.SIGCHLD, self.origchldhandler)
225 logger.info("Sending SIGTERM to runqemu") 238 logger.info("Sending SIGTERM to runqemu")
226 try: 239 try:
227 os.killpg(self.runqemu.pid, signal.SIGTERM) 240 os.killpg(self.runqemu.pid, signal.SIGTERM)
@@ -255,6 +268,8 @@ class QemuRunner:
255 return False 268 return False
256 269
257 def is_alive(self): 270 def is_alive(self):
271 if not self.runqemu:
272 return False
258 qemu_child = self.find_child(str(self.runqemu.pid)) 273 qemu_child = self.find_child(str(self.runqemu.pid))
259 if qemu_child: 274 if qemu_child:
260 self.qemupid = qemu_child[0] 275 self.qemupid = qemu_child[0]
diff --git a/meta/lib/oeqa/utils/sshcontrol.py b/meta/lib/oeqa/utils/sshcontrol.py
index 6ed48badc8..00f5051053 100644
--- a/meta/lib/oeqa/utils/sshcontrol.py
+++ b/meta/lib/oeqa/utils/sshcontrol.py
@@ -42,7 +42,7 @@ class SSHProcess(object):
42 with open(self.logfile, "a") as f: 42 with open(self.logfile, "a") as f:
43 f.write("%s" % msg) 43 f.write("%s" % msg)
44 44
45 def run(self, command, timeout=None, logfile=None): 45 def _run(self, command, timeout=None, logfile=None):
46 self.logfile = logfile 46 self.logfile = logfile
47 self.starttime = time.time() 47 self.starttime = time.time()
48 output = '' 48 output = ''
@@ -79,8 +79,18 @@ class SSHProcess(object):
79 79
80 self.status = self.process.wait() 80 self.status = self.process.wait()
81 self.output = output.rstrip() 81 self.output = output.rstrip()
82 return (self.status, self.output)
83 82
83 def run(self, command, timeout=None, logfile=None):
84 try:
85 self._run(command, timeout, logfile)
86 except:
87 # Need to guard against a SystemExit or other exception occuring whilst running
88 # and ensure we don't leave a process behind.
89 if self.process.poll() is None:
90 self.process.kill()
91 self.status = self.process.wait()
92 raise
93 return (self.status, self.output)
84 94
85class SSHControl(object): 95class SSHControl(object):
86 def __init__(self, ip, logfile=None, timeout=300, user='root', port=None): 96 def __init__(self, ip, logfile=None, timeout=300, user='root', port=None):