summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRadu Moisan <radu.moisan@intel.com>2013-06-28 08:27:56 (GMT)
committerRichard Purdie <richard.purdie@linuxfoundation.org>2013-07-09 09:53:45 (GMT)
commit88a6eb8027ae999fb53362d864301a3d525877d3 (patch)
tree3c68965bb36b149ddd6df503233d4340788e2ae3
parent962c0a1fc0694403b385a6f11d710c8675399352 (diff)
downloadpoky-88a6eb8027ae999fb53362d864301a3d525877d3.tar.gz
lib/oeqa/utils/qemurunner.py: class to handle qemu instance
Handles qemu instances (launch, kill, restart, serial connection, logging) Launch is blocking until login prompt and returns to the task. A qemu serial connection is used to save the boot log and get the ip from the image. Changed runqemu script not to error out when using custom serial option. (From OE-Core rev: ee7d64dfcc02ba8f568b17d181e0a58d3c810076) Signed-off-by: Radu Moisan <radu.moisan@intel.com> Signed-off-by: Stefan Stanacar <stefanx.stanacar@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/lib/oeqa/utils/qemurunner.py164
-rwxr-xr-xscripts/runqemu2
2 files changed, 165 insertions, 1 deletions
diff --git a/meta/lib/oeqa/utils/qemurunner.py b/meta/lib/oeqa/utils/qemurunner.py
new file mode 100644
index 0000000..3132b68
--- /dev/null
+++ b/meta/lib/oeqa/utils/qemurunner.py
@@ -0,0 +1,164 @@
1import subprocess
2import optparse
3import sys
4import os
5import time
6import signal
7import re
8import bb
9from oeqa.utils.oeqemuconsole import oeQemuConsole
10
11class QemuRunner:
12
13 def __init__(self, machine, rootfs, display = None, tmpdir = None, logfile = None):
14 # Popen object
15 self.runqemu = None
16
17 self.machine = machine
18 self.rootfs = rootfs
19
20 self.streampath = '/tmp/qemuconnection.%s' % os.getpid()
21 self.qemuparams = 'bootparams="console=ttyS0" qemuparams="-snapshot -serial unix:%s,server,nowait"' % self.streampath
22 self.qemupid = None
23 self.ip = None
24
25 self.display = display
26 self.tmpdir = tmpdir
27 self.logfile = logfile
28
29 def launch(self, qemuparams = None):
30
31 if qemuparams:
32 self.qemuparams = self.qemuparams[:-1] + " " + qemuparams + " " + '\"'
33
34 if self.display:
35 os.environ["DISPLAY"] = self.display
36 else:
37 bb.error("To start qemu I need a X desktop, please set DISPLAY correctly (e.g. DISPLAY=:1)")
38 return False
39 if not os.path.exists(self.rootfs):
40 bb.error("Invalid rootfs %s" % self.rootfs)
41 return False
42 if not os.path.exists(self.tmpdir):
43 bb.error("Invalid TMPDIR path %s" % self.tmpdir)
44 return False
45 else:
46 os.environ["OE_TMPDIR"] = self.tmpdir
47
48 launch_cmd = 'runqemu %s %s %s' % (self.machine, self.rootfs, self.qemuparams)
49 self.runqemu = subprocess.Popen(launch_cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,preexec_fn=os.setpgrp)
50
51 bb.note("runqemu started, pid is %s" % self.runqemu.pid)
52 # wait at most 30 seconds until qemu pid appears
53 bb.note("waiting at most 60 seconds for qemu pid")
54 endtime = time.time() + 60
55 while not self.is_alive() and time.time() < endtime:
56 time.sleep(1)
57
58 if self.is_alive():
59 bb.note("qemu started - qemu procces pid is %s" % self.qemupid)
60
61 console = oeQemuConsole(self.streampath, self.logfile)
62 bb.note("Waiting at most 200 seconds for login banner")
63 (match, text) = console.read_all_timeout("login:", 200)
64
65 if match:
66 bb.note("Reached login banner")
67 console.write("root\n")
68 (index, match, text) = console.expect([r"(root@[\w-]+:~#)"],10)
69 if not match:
70 bb.note("Couldn't get prompt, all I got was:\n%s" % match.group(0))
71 return False
72 console.write("ip addr show eth0 | sed -n '3p' | awk '{ print $2 }' | cut -f 1 -d \"/\"\n")
73 (index, match, text) = console.expect([r"((?:[0-9]{1,3}\.){3}[0-9]{1,3})"],10)
74 console.close()
75 if match:
76 self.ip = match.group(0)
77 bb.note("Ip found: %s" % self.ip)
78 else:
79 bb.note("Couldn't determine ip, all I got was:\n%s" % text)
80 return False
81 else:
82 console.close()
83 bb.note("Target didn't reached login boot in 120 seconds")
84 lines = "\n".join(text.splitlines()[-5:])
85 bb.note("Last 5 lines of text:\n%s" % lines)
86 bb.note("Check full boot log: %s" % self.logfile)
87 return False
88 else:
89 bb.note("Qemu pid didn't appeared in 30 seconds")
90 self.runqemu.terminate()
91 self.runqemu.kill()
92 bb.note("Output from runqemu: %s " % self.runqemu.stdout.read())
93 self.runqemu.stdout.close()
94 return False
95
96 return self.is_alive()
97
98
99 def kill(self):
100 if self.runqemu:
101 os.kill(-self.runqemu.pid,signal.SIGTERM)
102 self.qemupid = None
103 self.ip = None
104 if os.path.exists(self.streampath):
105 os.remove(self.streampath)
106
107 def restart(self, qemuparams = None):
108 if self.is_alive():
109 self.kill()
110 bb.note("Qemu Restart required...")
111 return self.launch(qemuparams)
112
113 def is_alive(self):
114 qemu_child = self.find_child(str(self.runqemu.pid))
115 if qemu_child:
116 self.qemupid = qemu_child[0]
117 if os.path.exists("/proc/" + str(self.qemupid)) and os.path.exists(self.streampath):
118 return True
119 return False
120
121 def find_child(self,parent_pid):
122 #
123 # Walk the process tree from the process specified looking for a qemu-system. Return its [pid'cmd]
124 #
125 ps = subprocess.Popen(['ps', 'axww', '-o', 'pid,ppid,command'], stdout=subprocess.PIPE).communicate()[0]
126 processes = ps.split('\n')
127 nfields = len(processes[0].split()) - 1
128 pids = {}
129 commands = {}
130 for row in processes[1:]:
131 data = row.split(None, nfields)
132 if len(data) != 3:
133 continue
134 if data[1] not in pids:
135 pids[data[1]] = []
136
137 pids[data[1]].append(data[0])
138 commands[data[0]] = data[2]
139
140 if parent_pid not in pids:
141 sys.stderr.write("No children found matching %s\n" % parent_pid)
142 return []
143
144 parents = []
145 newparents = pids[parent_pid]
146 while newparents:
147 next = []
148 for p in newparents:
149 if p in pids:
150 for n in pids[p]:
151 if n not in parents and n not in next:
152 next.append(n)
153 if p not in parents:
154 parents.append(p)
155 newparents = next
156 #print "Children matching %s:" % str(parents)
157 for p in parents:
158 # Need to be careful here since runqemu-internal runs "ldd qemu-system-xxxx"
159 # Also, old versions of ldd (2.11) run "LD_XXXX qemu-system-xxxx"
160 basecmd = commands[p].split()[0]
161 basecmd = os.path.basename(basecmd)
162 if "qemu-system" in basecmd and "-serial unix" in commands[p]:
163 return [int(p),commands[p]]
164
diff --git a/scripts/runqemu b/scripts/runqemu
index f2eb2e1..406092b 100755
--- a/scripts/runqemu
+++ b/scripts/runqemu
@@ -156,7 +156,7 @@ while true; do
156 serial_option=`expr "$SCRIPT_QEMU_EXTRA_OPT" : '.*\(-serial\)'` 156 serial_option=`expr "$SCRIPT_QEMU_EXTRA_OPT" : '.*\(-serial\)'`
157 kvm_option=`expr "$SCRIPT_QEMU_EXTRA_OPT" : '.*\(-enable-kvm\)'` 157 kvm_option=`expr "$SCRIPT_QEMU_EXTRA_OPT" : '.*\(-enable-kvm\)'`
158 [ ! -z "$serial_option" -o ! -z "$kvm_option" ] && \ 158 [ ! -z "$serial_option" -o ! -z "$kvm_option" ] && \
159 error "Please use simplified serial or kvm options instead" 159 echo "Please use simplified serial or kvm options instead"
160 ;; 160 ;;
161 "bootparams="*) 161 "bootparams="*)
162 SCRIPT_KERNEL_OPT="$SCRIPT_KERNEL_OPT ${arg##bootparams=}" 162 SCRIPT_KERNEL_OPT="$SCRIPT_KERNEL_OPT ${arg##bootparams=}"