blob: 4daafece2ea8de8db10d09561dd1c95b0c7fb703 [file] [log] [blame]
lmr0e4056d2010-04-01 02:58:01 +00001import sys, os, time, commands, re, logging, signal, glob, threading, shutil
lmr47a853b2010-02-04 13:56:48 +00002from autotest_lib.client.bin import test, utils
lmr6f669ce2009-05-31 19:02:42 +00003from autotest_lib.client.common_lib import error
lmr9e964a02010-06-18 03:46:21 +00004import kvm_vm, kvm_utils, kvm_subprocess, kvm_monitor, ppm_utils
lmre9f528e2009-08-12 15:18:10 +00005try:
6 import PIL.Image
7except ImportError:
8 logging.warning('No python imaging library installed. PPM image '
9 'conversion to JPEG disabled. In order to enable it, '
10 'please install python-imaging or the equivalent for your '
11 'distro.')
lmr6f669ce2009-05-31 19:02:42 +000012
13
lmr0e4056d2010-04-01 02:58:01 +000014_screendump_thread = None
15_screendump_thread_termination_event = None
16
17
lmr6f669ce2009-05-31 19:02:42 +000018def preprocess_image(test, params):
19 """
20 Preprocess a single QEMU image according to the instructions in params.
21
22 @param test: Autotest test object.
23 @param params: A dict containing image preprocessing parameters.
24 @note: Currently this function just creates an image if requested.
25 """
lmr90b9fd52009-08-17 20:48:18 +000026 image_filename = kvm_vm.get_image_filename(params, test.bindir)
lmr6f669ce2009-05-31 19:02:42 +000027
28 create_image = False
29
30 if params.get("force_create_image") == "yes":
31 logging.debug("'force_create_image' specified; creating image...")
32 create_image = True
lmr52800ba2009-08-17 20:49:58 +000033 elif (params.get("create_image") == "yes" and not
34 os.path.exists(image_filename)):
lmr6f669ce2009-05-31 19:02:42 +000035 logging.debug("Creating image...")
36 create_image = True
37
lmr0294de32009-09-09 22:44:28 +000038 if create_image and not kvm_vm.create_image(params, test.bindir):
39 raise error.TestError("Could not create image")
lmr6f669ce2009-05-31 19:02:42 +000040
41
42def preprocess_vm(test, params, env, name):
43 """
44 Preprocess a single VM object according to the instructions in params.
45 Start the VM if requested and get a screendump.
46
47 @param test: An Autotest test object.
48 @param params: A dict containing VM preprocessing parameters.
49 @param env: The environment (a dict-like object).
50 @param name: The name of the VM object.
51 """
lmr6f669ce2009-05-31 19:02:42 +000052 logging.debug("Preprocessing VM '%s'..." % name)
Eric Li7edb3042011-01-06 17:57:17 -080053 vm = env.get_vm(name)
lmr6f669ce2009-05-31 19:02:42 +000054 if vm:
55 logging.debug("VM object found in environment")
56 else:
57 logging.debug("VM object does not exist; creating it")
lmr52800ba2009-08-17 20:49:58 +000058 vm = kvm_vm.VM(name, params, test.bindir, env.get("address_cache"))
Eric Li7edb3042011-01-06 17:57:17 -080059 env.register_vm(name, vm)
lmr6f669ce2009-05-31 19:02:42 +000060
61 start_vm = False
lmr6f669ce2009-05-31 19:02:42 +000062
Eric Li7edb3042011-01-06 17:57:17 -080063 migration_mode = params.get("migration_mode", None)
64
Eric Lie0493a42010-11-15 13:05:43 -080065 if params.get("restart_vm") == "yes":
lmr6f669ce2009-05-31 19:02:42 +000066 logging.debug("'restart_vm' specified; (re)starting VM...")
67 start_vm = True
68 elif params.get("start_vm") == "yes":
69 if not vm.is_alive():
70 logging.debug("VM is not alive; starting it...")
71 start_vm = True
72 elif vm.make_qemu_command() != vm.make_qemu_command(name, params,
lmr90b9fd52009-08-17 20:48:18 +000073 test.bindir):
lmra4967622009-07-23 01:36:32 +000074 logging.debug("VM's qemu command differs from requested one; "
lmr6f669ce2009-05-31 19:02:42 +000075 "restarting it...")
76 start_vm = True
Eric Li7edb3042011-01-06 17:57:17 -080077 elif migration_mode is not None:
78 logging.debug("Starting VM on migration incoming mode...")
79 start_vm = True
lmr6f669ce2009-05-31 19:02:42 +000080
lmre9a9cf32010-06-18 12:15:25 +000081 if start_vm:
Eric Li7edb3042011-01-06 17:57:17 -080082 if migration_mode is not None:
83 if not vm.create(name, params, test.bindir,
84 migration_mode=migration_mode):
85 raise error.TestError("Could not start VM for migration")
86 else:
87 # Start the VM (or restart it if it's already up)
88 if not vm.create(name, params, test.bindir):
89 raise error.TestError("Could not start VM")
lmre9a9cf32010-06-18 12:15:25 +000090 else:
91 # Don't start the VM, just update its params
92 vm.params = params
lmr6f669ce2009-05-31 19:02:42 +000093
94 scrdump_filename = os.path.join(test.debugdir, "pre_%s.ppm" % name)
lmr9e964a02010-06-18 03:46:21 +000095 try:
96 if vm.monitor:
97 vm.monitor.screendump(scrdump_filename)
98 except kvm_monitor.MonitorError, e:
99 logging.warn(e)
lmr6f669ce2009-05-31 19:02:42 +0000100
101
102def postprocess_image(test, params):
103 """
104 Postprocess a single QEMU image according to the instructions in params.
105 Currently this function just removes an image if requested.
106
107 @param test: An Autotest test object.
108 @param params: A dict containing image postprocessing parameters.
109 """
lmr6f669ce2009-05-31 19:02:42 +0000110 if params.get("remove_image") == "yes":
lmr90b9fd52009-08-17 20:48:18 +0000111 kvm_vm.remove_image(params, test.bindir)
lmr6f669ce2009-05-31 19:02:42 +0000112
113
114def postprocess_vm(test, params, env, name):
115 """
116 Postprocess a single VM object according to the instructions in params.
117 Kill the VM if requested and get a screendump.
118
119 @param test: An Autotest test object.
120 @param params: A dict containing VM postprocessing parameters.
121 @param env: The environment (a dict-like object).
122 @param name: The name of the VM object.
123 """
124 logging.debug("Postprocessing VM '%s'..." % name)
Eric Li7edb3042011-01-06 17:57:17 -0800125 vm = env.get_vm(name)
lmr6f669ce2009-05-31 19:02:42 +0000126 if vm:
127 logging.debug("VM object found in environment")
128 else:
129 logging.debug("VM object does not exist in environment")
130 return
131
132 scrdump_filename = os.path.join(test.debugdir, "post_%s.ppm" % name)
lmr9e964a02010-06-18 03:46:21 +0000133 try:
134 if vm.monitor:
135 vm.monitor.screendump(scrdump_filename)
136 except kvm_monitor.MonitorError, e:
137 logging.warn(e)
lmr6f669ce2009-05-31 19:02:42 +0000138
139 if params.get("kill_vm") == "yes":
lmradbfb1a2009-10-13 13:44:14 +0000140 kill_vm_timeout = float(params.get("kill_vm_timeout", 0))
141 if kill_vm_timeout:
142 logging.debug("'kill_vm' specified; waiting for VM to shut down "
143 "before killing it...")
144 kvm_utils.wait_for(vm.is_dead, kill_vm_timeout, 0, 1)
145 else:
lmr6f669ce2009-05-31 19:02:42 +0000146 logging.debug("'kill_vm' specified; killing VM...")
147 vm.destroy(gracefully = params.get("kill_vm_gracefully") == "yes")
148
149
lmr12b98a72010-02-09 11:13:57 +0000150def process_command(test, params, env, command, command_timeout,
lmr86d1ea52009-06-15 20:34:39 +0000151 command_noncritical):
152 """
153 Pre- or post- custom commands to be executed before/after a test is run
154
155 @param test: An Autotest test object.
156 @param params: A dict containing all VM and image parameters.
157 @param env: The environment (a dict-like object).
lmr12b98a72010-02-09 11:13:57 +0000158 @param command: Command to be run.
lmr0bc6efc2009-07-27 13:27:42 +0000159 @param command_timeout: Timeout for command execution.
160 @param command_noncritical: If True test will not fail if command fails.
lmr86d1ea52009-06-15 20:34:39 +0000161 """
lmr0bc6efc2009-07-27 13:27:42 +0000162 # Export environment vars
lmr0ce407d2010-03-23 15:46:30 +0000163 for k in params:
lmr0bc6efc2009-07-27 13:27:42 +0000164 os.putenv("KVM_TEST_%s" % k, str(params[k]))
lmrb1ef8472010-02-05 11:21:13 +0000165 # Execute commands
lmr12b98a72010-02-09 11:13:57 +0000166 try:
167 utils.system("cd %s; %s" % (test.bindir, command))
168 except error.CmdError, e:
lmr10845532010-06-18 12:54:46 +0000169 if command_noncritical:
170 logging.warn(e)
171 else:
172 raise
lmr86d1ea52009-06-15 20:34:39 +0000173
lmr6f669ce2009-05-31 19:02:42 +0000174def process(test, params, env, image_func, vm_func):
175 """
176 Pre- or post-process VMs and images according to the instructions in params.
177 Call image_func for each image listed in params and vm_func for each VM.
178
179 @param test: An Autotest test object.
180 @param params: A dict containing all VM and image parameters.
181 @param env: The environment (a dict-like object).
182 @param image_func: A function to call for each image.
183 @param vm_func: A function to call for each VM.
184 """
185 # Get list of VMs specified for this test
Eric Li7edb3042011-01-06 17:57:17 -0800186 for vm_name in params.objects("vms"):
187 vm_params = params.object_params(vm_name)
lmr6f669ce2009-05-31 19:02:42 +0000188 # Get list of images specified for this VM
Eric Li7edb3042011-01-06 17:57:17 -0800189 for image_name in vm_params.objects("images"):
190 image_params = vm_params.object_params(image_name)
lmr6f669ce2009-05-31 19:02:42 +0000191 # Call image_func for each image
192 image_func(test, image_params)
193 # Call vm_func for each vm
194 vm_func(test, vm_params, env, vm_name)
195
196
197def preprocess(test, params, env):
198 """
199 Preprocess all VMs and images according to the instructions in params.
200 Also, collect some host information, such as the KVM version.
201
202 @param test: An Autotest test object.
203 @param params: A dict containing all VM and image parameters.
204 @param env: The environment (a dict-like object).
205 """
lmr965bcd22009-08-13 04:12:19 +0000206 # Start tcpdump if it isn't already running
lmr8a47ce32010-03-23 15:27:12 +0000207 if "address_cache" not in env:
lmr965bcd22009-08-13 04:12:19 +0000208 env["address_cache"] = {}
lmr8a47ce32010-03-23 15:27:12 +0000209 if "tcpdump" in env and not env["tcpdump"].is_alive():
lmr965bcd22009-08-13 04:12:19 +0000210 env["tcpdump"].close()
211 del env["tcpdump"]
lmrb1f76462010-05-25 23:44:03 +0000212 if "tcpdump" not in env and params.get("run_tcpdump", "yes") == "yes":
lmr3eb39c72010-07-08 23:34:05 +0000213 cmd = "%s -npvi any 'dst port 68'" % kvm_utils.find_command("tcpdump")
214 logging.debug("Starting tcpdump (%s)...", cmd)
Eric Li7edb3042011-01-06 17:57:17 -0800215 env["tcpdump"] = kvm_subprocess.Tail(
lmr3eb39c72010-07-08 23:34:05 +0000216 command=cmd,
lmr965bcd22009-08-13 04:12:19 +0000217 output_func=_update_address_cache,
218 output_params=(env["address_cache"],))
219 if kvm_utils.wait_for(lambda: not env["tcpdump"].is_alive(),
220 0.1, 0.1, 1.0):
221 logging.warn("Could not start tcpdump")
222 logging.warn("Status: %s" % env["tcpdump"].get_status())
223 logging.warn("Output:" + kvm_utils.format_str_for_message(
224 env["tcpdump"].get_output()))
225
lmr6f669ce2009-05-31 19:02:42 +0000226 # Destroy and remove VMs that are no longer needed in the environment
Eric Li7edb3042011-01-06 17:57:17 -0800227 requested_vms = params.objects("vms")
lmr0ce407d2010-03-23 15:46:30 +0000228 for key in env.keys():
lmr6f669ce2009-05-31 19:02:42 +0000229 vm = env[key]
230 if not kvm_utils.is_vm(vm):
231 continue
232 if not vm.name in requested_vms:
lmr8a47ce32010-03-23 15:27:12 +0000233 logging.debug("VM '%s' found in environment but not required for "
234 "test; removing it..." % vm.name)
lmr6f669ce2009-05-31 19:02:42 +0000235 vm.destroy()
236 del env[key]
237
lmr6f669ce2009-05-31 19:02:42 +0000238 # Get the KVM kernel module version and write it as a keyval
239 logging.debug("Fetching KVM module version...")
240 if os.path.exists("/dev/kvm"):
lmr6f669ce2009-05-31 19:02:42 +0000241 try:
lmr8a47ce32010-03-23 15:27:12 +0000242 kvm_version = open("/sys/module/kvm/version").read().strip()
lmr6f669ce2009-05-31 19:02:42 +0000243 except:
lmr8a47ce32010-03-23 15:27:12 +0000244 kvm_version = os.uname()[2]
lmr6f669ce2009-05-31 19:02:42 +0000245 else:
246 kvm_version = "Unknown"
247 logging.debug("KVM module not loaded")
248 logging.debug("KVM version: %s" % kvm_version)
249 test.write_test_keyval({"kvm_version": kvm_version})
250
251 # Get the KVM userspace version and write it as a keyval
252 logging.debug("Fetching KVM userspace version...")
lmr52800ba2009-08-17 20:49:58 +0000253 qemu_path = kvm_utils.get_path(test.bindir, params.get("qemu_binary",
254 "qemu"))
lmr6f669ce2009-05-31 19:02:42 +0000255 version_line = commands.getoutput("%s -help | head -n 1" % qemu_path)
lmr8a47ce32010-03-23 15:27:12 +0000256 matches = re.findall("[Vv]ersion .*?,", version_line)
257 if matches:
258 kvm_userspace_version = " ".join(matches[0].split()[1:]).strip(",")
lmr6f669ce2009-05-31 19:02:42 +0000259 else:
260 kvm_userspace_version = "Unknown"
261 logging.debug("Could not fetch KVM userspace version")
262 logging.debug("KVM userspace version: %s" % kvm_userspace_version)
263 test.write_test_keyval({"kvm_userspace_version": kvm_userspace_version})
264
lmr8a47ce32010-03-23 15:27:12 +0000265 # Execute any pre_commands
266 if params.get("pre_command"):
267 process_command(test, params, env, params.get("pre_command"),
268 int(params.get("pre_command_timeout", "600")),
269 params.get("pre_command_noncritical") == "yes")
270
271 # Preprocess all VMs and images
272 process(test, params, env, preprocess_image, preprocess_vm)
273
lmr0e4056d2010-04-01 02:58:01 +0000274 # Start the screendump thread
275 if params.get("take_regular_screendumps") == "yes":
276 logging.debug("Starting screendump thread")
277 global _screendump_thread, _screendump_thread_termination_event
278 _screendump_thread_termination_event = threading.Event()
279 _screendump_thread = threading.Thread(target=_take_screendumps,
280 args=(test, params, env))
281 _screendump_thread.start()
282
lmr6f669ce2009-05-31 19:02:42 +0000283
284def postprocess(test, params, env):
285 """
286 Postprocess all VMs and images according to the instructions in params.
287
288 @param test: An Autotest test object.
289 @param params: Dict containing all VM and image parameters.
290 @param env: The environment (a dict-like object).
291 """
lmr0e4056d2010-04-01 02:58:01 +0000292 # Postprocess all VMs and images
lmr6f669ce2009-05-31 19:02:42 +0000293 process(test, params, env, postprocess_image, postprocess_vm)
294
lmr0e4056d2010-04-01 02:58:01 +0000295 # Terminate the screendump thread
296 global _screendump_thread, _screendump_thread_termination_event
297 if _screendump_thread:
298 logging.debug("Terminating screendump thread...")
299 _screendump_thread_termination_event.set()
300 _screendump_thread.join(10)
lmr327729b2010-06-14 17:14:00 +0000301 _screendump_thread = None
302 _screendump_thread_termination_event = None
lmr0e4056d2010-04-01 02:58:01 +0000303
lmr665975c2009-12-27 20:01:41 +0000304 # Warn about corrupt PPM files
305 for f in glob.glob(os.path.join(test.debugdir, "*.ppm")):
306 if not ppm_utils.image_verify_ppm_file(f):
307 logging.warn("Found corrupt PPM file: %s", f)
308
lmr0ee0a9c2009-07-24 19:23:29 +0000309 # Should we convert PPM files to PNG format?
310 if params.get("convert_ppm_files_to_png") == "yes":
lmr8a47ce32010-03-23 15:27:12 +0000311 logging.debug("'convert_ppm_files_to_png' specified; converting PPM "
312 "files to PNG format...")
lmre9f528e2009-08-12 15:18:10 +0000313 try:
314 for f in glob.glob(os.path.join(test.debugdir, "*.ppm")):
lmr15c44862009-09-10 03:23:45 +0000315 if ppm_utils.image_verify_ppm_file(f):
316 new_path = f.replace(".ppm", ".png")
317 image = PIL.Image.open(f)
318 image.save(new_path, format='PNG')
lmre9f528e2009-08-12 15:18:10 +0000319 except NameError:
320 pass
lmr0ee0a9c2009-07-24 19:23:29 +0000321
322 # Should we keep the PPM files?
323 if params.get("keep_ppm_files") != "yes":
lmr8a47ce32010-03-23 15:27:12 +0000324 logging.debug("'keep_ppm_files' not specified; removing all PPM files "
325 "from debug dir...")
lmre9f528e2009-08-12 15:18:10 +0000326 for f in glob.glob(os.path.join(test.debugdir, '*.ppm')):
327 os.unlink(f)
lmr6f669ce2009-05-31 19:02:42 +0000328
lmr0e4056d2010-04-01 02:58:01 +0000329 # Should we keep the screendump dirs?
330 if params.get("keep_screendumps") != "yes":
331 logging.debug("'keep_screendumps' not specified; removing screendump "
332 "dirs...")
333 for d in glob.glob(os.path.join(test.debugdir, "screendumps_*")):
334 if os.path.isdir(d) and not os.path.islink(d):
335 shutil.rmtree(d, ignore_errors=True)
lmr86d1ea52009-06-15 20:34:39 +0000336
lmr588f4972009-10-13 13:43:10 +0000337 # Kill all unresponsive VMs
338 if params.get("kill_unresponsive_vms") == "yes":
339 logging.debug("'kill_unresponsive_vms' specified; killing all VMs "
340 "that fail to respond to a remote login request...")
Eric Li7edb3042011-01-06 17:57:17 -0800341 for vm in env.get_all_vms():
lmr588f4972009-10-13 13:43:10 +0000342 if vm.is_alive():
343 session = vm.remote_login()
344 if session:
345 session.close()
346 else:
347 vm.destroy(gracefully=False)
348
lmree4338e2010-07-08 23:40:10 +0000349 # Kill all kvm_subprocess tail threads
350 kvm_subprocess.kill_tail_threads()
lmra4197002009-08-13 05:00:51 +0000351
lmr965bcd22009-08-13 04:12:19 +0000352 # Terminate tcpdump if no VMs are alive
Eric Li7edb3042011-01-06 17:57:17 -0800353 living_vms = [vm for vm in env.get_all_vms() if vm.is_alive()]
lmr8a47ce32010-03-23 15:27:12 +0000354 if not living_vms and "tcpdump" in env:
lmr965bcd22009-08-13 04:12:19 +0000355 env["tcpdump"].close()
356 del env["tcpdump"]
357
lmr0e4056d2010-04-01 02:58:01 +0000358 # Execute any post_commands
359 if params.get("post_command"):
360 process_command(test, params, env, params.get("post_command"),
361 int(params.get("post_command_timeout", "600")),
362 params.get("post_command_noncritical") == "yes")
363
lmr6f669ce2009-05-31 19:02:42 +0000364
365def postprocess_on_error(test, params, env):
366 """
367 Perform postprocessing operations required only if the test failed.
368
369 @param test: An Autotest test object.
370 @param params: A dict containing all VM and image parameters.
371 @param env: The environment (a dict-like object).
372 """
Eric Li7edb3042011-01-06 17:57:17 -0800373 params.update(params.object_params("on_error"))
lmr965bcd22009-08-13 04:12:19 +0000374
375
376def _update_address_cache(address_cache, line):
377 if re.search("Your.IP", line, re.IGNORECASE):
378 matches = re.findall(r"\d*\.\d*\.\d*\.\d*", line)
379 if matches:
380 address_cache["last_seen"] = matches[0]
381 if re.search("Client.Ethernet.Address", line, re.IGNORECASE):
382 matches = re.findall(r"\w*:\w*:\w*:\w*:\w*:\w*", line)
383 if matches and address_cache.get("last_seen"):
384 mac_address = matches[0].lower()
Eric Li7edb3042011-01-06 17:57:17 -0800385 if time.time() - address_cache.get("time_%s" % mac_address, 0) > 5:
386 logging.debug("(address cache) Adding cache entry: %s ---> %s",
387 mac_address, address_cache.get("last_seen"))
lmr965bcd22009-08-13 04:12:19 +0000388 address_cache[mac_address] = address_cache.get("last_seen")
Eric Li7edb3042011-01-06 17:57:17 -0800389 address_cache["time_%s" % mac_address] = time.time()
lmr965bcd22009-08-13 04:12:19 +0000390 del address_cache["last_seen"]
lmr0e4056d2010-04-01 02:58:01 +0000391
392
393def _take_screendumps(test, params, env):
394 global _screendump_thread_termination_event
395 temp_dir = test.debugdir
396 if params.get("screendump_temp_dir"):
397 temp_dir = kvm_utils.get_path(test.bindir,
398 params.get("screendump_temp_dir"))
399 try:
400 os.makedirs(temp_dir)
401 except OSError:
402 pass
403 temp_filename = os.path.join(temp_dir, "scrdump-%s.ppm" %
404 kvm_utils.generate_random_string(6))
405 delay = float(params.get("screendump_delay", 5))
406 quality = int(params.get("screendump_quality", 30))
407
408 cache = {}
409
410 while True:
Eric Li7edb3042011-01-06 17:57:17 -0800411 for vm in env.get_all_vms():
lmr7fa9fe72010-06-22 01:46:47 +0000412 if not vm.is_alive():
lmr0e4056d2010-04-01 02:58:01 +0000413 continue
lmr9e964a02010-06-18 03:46:21 +0000414 try:
415 vm.monitor.screendump(temp_filename)
416 except kvm_monitor.MonitorError, e:
417 logging.warn(e)
418 continue
lmr0e4056d2010-04-01 02:58:01 +0000419 if not os.path.exists(temp_filename):
420 logging.warn("VM '%s' failed to produce a screendump", vm.name)
421 continue
422 if not ppm_utils.image_verify_ppm_file(temp_filename):
423 logging.warn("VM '%s' produced an invalid screendump", vm.name)
424 os.unlink(temp_filename)
425 continue
426 screendump_dir = os.path.join(test.debugdir,
427 "screendumps_%s" % vm.name)
428 try:
429 os.makedirs(screendump_dir)
430 except OSError:
431 pass
432 screendump_filename = os.path.join(screendump_dir,
433 "%s_%s.jpg" % (vm.name,
434 time.strftime("%Y-%m-%d_%H-%M-%S")))
435 hash = utils.hash_file(temp_filename)
436 if hash in cache:
437 try:
438 os.link(cache[hash], screendump_filename)
439 except OSError:
440 pass
441 else:
442 try:
443 image = PIL.Image.open(temp_filename)
444 image.save(screendump_filename, format="JPEG", quality=quality)
445 cache[hash] = screendump_filename
446 except NameError:
447 pass
448 os.unlink(temp_filename)
449 if _screendump_thread_termination_event.isSet():
450 break
451 _screendump_thread_termination_event.wait(delay)