blob: a92282ad034418ac48d17af6f3d8b55eff0caa2b [file] [log] [blame]
lmre9f528e2009-08-12 15:18:10 +00001import sys, os, time, commands, re, logging, signal, glob
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
lmr15c44862009-09-10 03:23:45 +00004import kvm_vm, kvm_utils, kvm_subprocess, 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
14def preprocess_image(test, params):
15 """
16 Preprocess a single QEMU image according to the instructions in params.
17
18 @param test: Autotest test object.
19 @param params: A dict containing image preprocessing parameters.
20 @note: Currently this function just creates an image if requested.
21 """
lmr90b9fd52009-08-17 20:48:18 +000022 image_filename = kvm_vm.get_image_filename(params, test.bindir)
lmr6f669ce2009-05-31 19:02:42 +000023
24 create_image = False
25
26 if params.get("force_create_image") == "yes":
27 logging.debug("'force_create_image' specified; creating image...")
28 create_image = True
lmr52800ba2009-08-17 20:49:58 +000029 elif (params.get("create_image") == "yes" and not
30 os.path.exists(image_filename)):
lmr6f669ce2009-05-31 19:02:42 +000031 logging.debug("Creating image...")
32 create_image = True
33
lmr0294de32009-09-09 22:44:28 +000034 if create_image and not kvm_vm.create_image(params, test.bindir):
35 raise error.TestError("Could not create image")
lmr6f669ce2009-05-31 19:02:42 +000036
37
38def preprocess_vm(test, params, env, name):
39 """
40 Preprocess a single VM object according to the instructions in params.
41 Start the VM if requested and get a screendump.
42
43 @param test: An Autotest test object.
44 @param params: A dict containing VM preprocessing parameters.
45 @param env: The environment (a dict-like object).
46 @param name: The name of the VM object.
47 """
lmr6f669ce2009-05-31 19:02:42 +000048 logging.debug("Preprocessing VM '%s'..." % name)
49 vm = kvm_utils.env_get_vm(env, name)
50 if vm:
51 logging.debug("VM object found in environment")
52 else:
53 logging.debug("VM object does not exist; creating it")
lmr52800ba2009-08-17 20:49:58 +000054 vm = kvm_vm.VM(name, params, test.bindir, env.get("address_cache"))
lmr6f669ce2009-05-31 19:02:42 +000055 kvm_utils.env_register_vm(env, name, vm)
56
57 start_vm = False
58 for_migration = False
59
60 if params.get("start_vm_for_migration") == "yes":
lmr8a47ce32010-03-23 15:27:12 +000061 logging.debug("'start_vm_for_migration' specified; (re)starting VM "
62 "with -incoming option...")
lmr6f669ce2009-05-31 19:02:42 +000063 start_vm = True
64 for_migration = True
65 elif params.get("restart_vm") == "yes":
66 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
77
lmr0294de32009-09-09 22:44:28 +000078 if start_vm and not vm.create(name, params, test.bindir, for_migration):
79 raise error.TestError("Could not start VM")
lmr6f669ce2009-05-31 19:02:42 +000080
81 scrdump_filename = os.path.join(test.debugdir, "pre_%s.ppm" % name)
82 vm.send_monitor_cmd("screendump %s" % scrdump_filename)
83
84
85def postprocess_image(test, params):
86 """
87 Postprocess a single QEMU image according to the instructions in params.
88 Currently this function just removes an image if requested.
89
90 @param test: An Autotest test object.
91 @param params: A dict containing image postprocessing parameters.
92 """
lmr6f669ce2009-05-31 19:02:42 +000093 if params.get("remove_image") == "yes":
lmr90b9fd52009-08-17 20:48:18 +000094 kvm_vm.remove_image(params, test.bindir)
lmr6f669ce2009-05-31 19:02:42 +000095
96
97def postprocess_vm(test, params, env, name):
98 """
99 Postprocess a single VM object according to the instructions in params.
100 Kill the VM if requested and get a screendump.
101
102 @param test: An Autotest test object.
103 @param params: A dict containing VM postprocessing parameters.
104 @param env: The environment (a dict-like object).
105 @param name: The name of the VM object.
106 """
107 logging.debug("Postprocessing VM '%s'..." % name)
108 vm = kvm_utils.env_get_vm(env, name)
109 if vm:
110 logging.debug("VM object found in environment")
111 else:
112 logging.debug("VM object does not exist in environment")
113 return
114
115 scrdump_filename = os.path.join(test.debugdir, "post_%s.ppm" % name)
116 vm.send_monitor_cmd("screendump %s" % scrdump_filename)
117
118 if params.get("kill_vm") == "yes":
lmradbfb1a2009-10-13 13:44:14 +0000119 kill_vm_timeout = float(params.get("kill_vm_timeout", 0))
120 if kill_vm_timeout:
121 logging.debug("'kill_vm' specified; waiting for VM to shut down "
122 "before killing it...")
123 kvm_utils.wait_for(vm.is_dead, kill_vm_timeout, 0, 1)
124 else:
lmr6f669ce2009-05-31 19:02:42 +0000125 logging.debug("'kill_vm' specified; killing VM...")
126 vm.destroy(gracefully = params.get("kill_vm_gracefully") == "yes")
127
128
lmr12b98a72010-02-09 11:13:57 +0000129def process_command(test, params, env, command, command_timeout,
lmr86d1ea52009-06-15 20:34:39 +0000130 command_noncritical):
131 """
132 Pre- or post- custom commands to be executed before/after a test is run
133
134 @param test: An Autotest test object.
135 @param params: A dict containing all VM and image parameters.
136 @param env: The environment (a dict-like object).
lmr12b98a72010-02-09 11:13:57 +0000137 @param command: Command to be run.
lmr0bc6efc2009-07-27 13:27:42 +0000138 @param command_timeout: Timeout for command execution.
139 @param command_noncritical: If True test will not fail if command fails.
lmr86d1ea52009-06-15 20:34:39 +0000140 """
lmr0bc6efc2009-07-27 13:27:42 +0000141 # Export environment vars
lmr0ce407d2010-03-23 15:46:30 +0000142 for k in params:
lmr0bc6efc2009-07-27 13:27:42 +0000143 os.putenv("KVM_TEST_%s" % k, str(params[k]))
lmrb1ef8472010-02-05 11:21:13 +0000144 # Execute commands
lmr12b98a72010-02-09 11:13:57 +0000145 try:
146 utils.system("cd %s; %s" % (test.bindir, command))
147 except error.CmdError, e:
148 logging.warn("Custom processing command '%s' failed, output is: %s",
149 command, str(e))
150 if not command_noncritical:
151 raise error.TestError("Custom processing command failed: %s" %
152 str(e))
lmr86d1ea52009-06-15 20:34:39 +0000153
154
lmr6f669ce2009-05-31 19:02:42 +0000155def process(test, params, env, image_func, vm_func):
156 """
157 Pre- or post-process VMs and images according to the instructions in params.
158 Call image_func for each image listed in params and vm_func for each VM.
159
160 @param test: An Autotest test object.
161 @param params: A dict containing all VM and image parameters.
162 @param env: The environment (a dict-like object).
163 @param image_func: A function to call for each image.
164 @param vm_func: A function to call for each VM.
165 """
166 # Get list of VMs specified for this test
167 vm_names = kvm_utils.get_sub_dict_names(params, "vms")
168 for vm_name in vm_names:
169 vm_params = kvm_utils.get_sub_dict(params, vm_name)
170 # Get list of images specified for this VM
171 image_names = kvm_utils.get_sub_dict_names(vm_params, "images")
172 for image_name in image_names:
173 image_params = kvm_utils.get_sub_dict(vm_params, image_name)
174 # Call image_func for each image
175 image_func(test, image_params)
176 # Call vm_func for each vm
177 vm_func(test, vm_params, env, vm_name)
178
179
180def preprocess(test, params, env):
181 """
182 Preprocess all VMs and images according to the instructions in params.
183 Also, collect some host information, such as the KVM version.
184
185 @param test: An Autotest test object.
186 @param params: A dict containing all VM and image parameters.
187 @param env: The environment (a dict-like object).
188 """
lmr965bcd22009-08-13 04:12:19 +0000189 # Start tcpdump if it isn't already running
lmr8a47ce32010-03-23 15:27:12 +0000190 if "address_cache" not in env:
lmr965bcd22009-08-13 04:12:19 +0000191 env["address_cache"] = {}
lmr8a47ce32010-03-23 15:27:12 +0000192 if "tcpdump" in env and not env["tcpdump"].is_alive():
lmr965bcd22009-08-13 04:12:19 +0000193 env["tcpdump"].close()
194 del env["tcpdump"]
lmr8a47ce32010-03-23 15:27:12 +0000195 if "tcpdump" not in env:
lmr965bcd22009-08-13 04:12:19 +0000196 command = "/usr/sbin/tcpdump -npvi any 'dst port 68'"
197 logging.debug("Starting tcpdump (%s)...", command)
198 env["tcpdump"] = kvm_subprocess.kvm_tail(
199 command=command,
200 output_func=_update_address_cache,
201 output_params=(env["address_cache"],))
202 if kvm_utils.wait_for(lambda: not env["tcpdump"].is_alive(),
203 0.1, 0.1, 1.0):
204 logging.warn("Could not start tcpdump")
205 logging.warn("Status: %s" % env["tcpdump"].get_status())
206 logging.warn("Output:" + kvm_utils.format_str_for_message(
207 env["tcpdump"].get_output()))
208
lmr6f669ce2009-05-31 19:02:42 +0000209 # Destroy and remove VMs that are no longer needed in the environment
210 requested_vms = kvm_utils.get_sub_dict_names(params, "vms")
lmr0ce407d2010-03-23 15:46:30 +0000211 for key in env.keys():
lmr6f669ce2009-05-31 19:02:42 +0000212 vm = env[key]
213 if not kvm_utils.is_vm(vm):
214 continue
215 if not vm.name in requested_vms:
lmr8a47ce32010-03-23 15:27:12 +0000216 logging.debug("VM '%s' found in environment but not required for "
217 "test; removing it..." % vm.name)
lmr6f669ce2009-05-31 19:02:42 +0000218 vm.destroy()
219 del env[key]
220
lmr6f669ce2009-05-31 19:02:42 +0000221 # Get the KVM kernel module version and write it as a keyval
222 logging.debug("Fetching KVM module version...")
223 if os.path.exists("/dev/kvm"):
lmr6f669ce2009-05-31 19:02:42 +0000224 try:
lmr8a47ce32010-03-23 15:27:12 +0000225 kvm_version = open("/sys/module/kvm/version").read().strip()
lmr6f669ce2009-05-31 19:02:42 +0000226 except:
lmr8a47ce32010-03-23 15:27:12 +0000227 kvm_version = os.uname()[2]
lmr6f669ce2009-05-31 19:02:42 +0000228 else:
229 kvm_version = "Unknown"
230 logging.debug("KVM module not loaded")
231 logging.debug("KVM version: %s" % kvm_version)
232 test.write_test_keyval({"kvm_version": kvm_version})
233
234 # Get the KVM userspace version and write it as a keyval
235 logging.debug("Fetching KVM userspace version...")
lmr52800ba2009-08-17 20:49:58 +0000236 qemu_path = kvm_utils.get_path(test.bindir, params.get("qemu_binary",
237 "qemu"))
lmr6f669ce2009-05-31 19:02:42 +0000238 version_line = commands.getoutput("%s -help | head -n 1" % qemu_path)
lmr8a47ce32010-03-23 15:27:12 +0000239 matches = re.findall("[Vv]ersion .*?,", version_line)
240 if matches:
241 kvm_userspace_version = " ".join(matches[0].split()[1:]).strip(",")
lmr6f669ce2009-05-31 19:02:42 +0000242 else:
243 kvm_userspace_version = "Unknown"
244 logging.debug("Could not fetch KVM userspace version")
245 logging.debug("KVM userspace version: %s" % kvm_userspace_version)
246 test.write_test_keyval({"kvm_userspace_version": kvm_userspace_version})
247
lmr8a47ce32010-03-23 15:27:12 +0000248 # Execute any pre_commands
249 if params.get("pre_command"):
250 process_command(test, params, env, params.get("pre_command"),
251 int(params.get("pre_command_timeout", "600")),
252 params.get("pre_command_noncritical") == "yes")
253
254 # Preprocess all VMs and images
255 process(test, params, env, preprocess_image, preprocess_vm)
256
lmr6f669ce2009-05-31 19:02:42 +0000257
258def postprocess(test, params, env):
259 """
260 Postprocess all VMs and images according to the instructions in params.
261
262 @param test: An Autotest test object.
263 @param params: Dict containing all VM and image parameters.
264 @param env: The environment (a dict-like object).
265 """
266 process(test, params, env, postprocess_image, postprocess_vm)
267
lmr665975c2009-12-27 20:01:41 +0000268 # Warn about corrupt PPM files
269 for f in glob.glob(os.path.join(test.debugdir, "*.ppm")):
270 if not ppm_utils.image_verify_ppm_file(f):
271 logging.warn("Found corrupt PPM file: %s", f)
272
lmr0ee0a9c2009-07-24 19:23:29 +0000273 # Should we convert PPM files to PNG format?
274 if params.get("convert_ppm_files_to_png") == "yes":
lmr8a47ce32010-03-23 15:27:12 +0000275 logging.debug("'convert_ppm_files_to_png' specified; converting PPM "
276 "files to PNG format...")
lmre9f528e2009-08-12 15:18:10 +0000277 try:
278 for f in glob.glob(os.path.join(test.debugdir, "*.ppm")):
lmr15c44862009-09-10 03:23:45 +0000279 if ppm_utils.image_verify_ppm_file(f):
280 new_path = f.replace(".ppm", ".png")
281 image = PIL.Image.open(f)
282 image.save(new_path, format='PNG')
lmre9f528e2009-08-12 15:18:10 +0000283 except NameError:
284 pass
lmr0ee0a9c2009-07-24 19:23:29 +0000285
286 # Should we keep the PPM files?
287 if params.get("keep_ppm_files") != "yes":
lmr8a47ce32010-03-23 15:27:12 +0000288 logging.debug("'keep_ppm_files' not specified; removing all PPM files "
289 "from debug dir...")
lmre9f528e2009-08-12 15:18:10 +0000290 for f in glob.glob(os.path.join(test.debugdir, '*.ppm')):
291 os.unlink(f)
lmr6f669ce2009-05-31 19:02:42 +0000292
lmr0bc6efc2009-07-27 13:27:42 +0000293 # Execute any post_commands
lmr86d1ea52009-06-15 20:34:39 +0000294 if params.get("post_command"):
lmr12b98a72010-02-09 11:13:57 +0000295 process_command(test, params, env, params.get("post_command"),
lmr0bc6efc2009-07-27 13:27:42 +0000296 int(params.get("post_command_timeout", "600")),
297 params.get("post_command_noncritical") == "yes")
lmr86d1ea52009-06-15 20:34:39 +0000298
lmr588f4972009-10-13 13:43:10 +0000299 # Kill all unresponsive VMs
300 if params.get("kill_unresponsive_vms") == "yes":
301 logging.debug("'kill_unresponsive_vms' specified; killing all VMs "
302 "that fail to respond to a remote login request...")
303 for vm in kvm_utils.env_get_all_vms(env):
304 if vm.is_alive():
305 session = vm.remote_login()
306 if session:
307 session.close()
308 else:
309 vm.destroy(gracefully=False)
310
lmra4197002009-08-13 05:00:51 +0000311 # Kill the tailing threads of all VMs
312 for vm in kvm_utils.env_get_all_vms(env):
313 vm.kill_tail_thread()
314
lmr965bcd22009-08-13 04:12:19 +0000315 # Terminate tcpdump if no VMs are alive
316 living_vms = [vm for vm in kvm_utils.env_get_all_vms(env) if vm.is_alive()]
lmr8a47ce32010-03-23 15:27:12 +0000317 if not living_vms and "tcpdump" in env:
lmr965bcd22009-08-13 04:12:19 +0000318 env["tcpdump"].close()
319 del env["tcpdump"]
320
lmr6f669ce2009-05-31 19:02:42 +0000321
322def postprocess_on_error(test, params, env):
323 """
324 Perform postprocessing operations required only if the test failed.
325
326 @param test: An Autotest test object.
327 @param params: A dict containing all VM and image parameters.
328 @param env: The environment (a dict-like object).
329 """
330 params.update(kvm_utils.get_sub_dict(params, "on_error"))
lmr965bcd22009-08-13 04:12:19 +0000331
332
333def _update_address_cache(address_cache, line):
334 if re.search("Your.IP", line, re.IGNORECASE):
335 matches = re.findall(r"\d*\.\d*\.\d*\.\d*", line)
336 if matches:
337 address_cache["last_seen"] = matches[0]
338 if re.search("Client.Ethernet.Address", line, re.IGNORECASE):
339 matches = re.findall(r"\w*:\w*:\w*:\w*:\w*:\w*", line)
340 if matches and address_cache.get("last_seen"):
341 mac_address = matches[0].lower()
342 logging.debug("(address cache) Adding cache entry: %s ---> %s",
343 mac_address, address_cache.get("last_seen"))
344 address_cache[mac_address] = address_cache.get("last_seen")
345 del address_cache["last_seen"]