blob: 2e55b34f7e42d73d6b3936e9cfa0f3432a6f2874 [file] [log] [blame]
lmre9f528e2009-08-12 15:18:10 +00001import sys, os, time, commands, re, logging, signal, glob
lmr6f669ce2009-05-31 19:02:42 +00002from autotest_lib.client.bin import test
3from autotest_lib.client.common_lib import error
lmra4967622009-07-23 01:36:32 +00004import kvm_vm, kvm_utils, kvm_subprocess
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 """
22 qemu_img_path = os.path.join(test.bindir, "qemu-img")
23 image_dir = os.path.join(test.bindir, "images")
24 image_filename = kvm_vm.get_image_filename(params, image_dir)
25
26 create_image = False
27
28 if params.get("force_create_image") == "yes":
29 logging.debug("'force_create_image' specified; creating image...")
30 create_image = True
31 elif params.get("create_image") == "yes" and not \
32 os.path.exists(image_filename):
33 logging.debug("Creating image...")
34 create_image = True
35
36 if create_image:
37 if not kvm_vm.create_image(params, qemu_img_path, image_dir):
38 message = "Could not create image"
39 logging.error(message)
40 raise error.TestError(message)
41
42
43def preprocess_vm(test, params, env, name):
44 """
45 Preprocess a single VM object according to the instructions in params.
46 Start the VM if requested and get a screendump.
47
48 @param test: An Autotest test object.
49 @param params: A dict containing VM preprocessing parameters.
50 @param env: The environment (a dict-like object).
51 @param name: The name of the VM object.
52 """
53 qemu_path = os.path.join(test.bindir, "qemu")
54 image_dir = os.path.join(test.bindir, "images")
55 iso_dir = os.path.join(test.bindir, "isos")
56
57 logging.debug("Preprocessing VM '%s'..." % name)
58 vm = kvm_utils.env_get_vm(env, name)
59 if vm:
60 logging.debug("VM object found in environment")
61 else:
62 logging.debug("VM object does not exist; creating it")
63 vm = kvm_vm.VM(name, params, qemu_path, image_dir, iso_dir)
64 kvm_utils.env_register_vm(env, name, vm)
65
66 start_vm = False
67 for_migration = False
68
69 if params.get("start_vm_for_migration") == "yes":
70 logging.debug("'start_vm_for_migration' specified; (re)starting VM with"
71 " -incoming option...")
72 start_vm = True
73 for_migration = True
74 elif params.get("restart_vm") == "yes":
75 logging.debug("'restart_vm' specified; (re)starting VM...")
76 start_vm = True
77 elif params.get("start_vm") == "yes":
78 if not vm.is_alive():
79 logging.debug("VM is not alive; starting it...")
80 start_vm = True
81 elif vm.make_qemu_command() != vm.make_qemu_command(name, params,
82 qemu_path,
83 image_dir,
84 iso_dir):
lmra4967622009-07-23 01:36:32 +000085 logging.debug("VM's qemu command differs from requested one; "
lmr6f669ce2009-05-31 19:02:42 +000086 "restarting it...")
87 start_vm = True
88
89 if start_vm:
lmr6f669ce2009-05-31 19:02:42 +000090 if not vm.create(name, params, qemu_path, image_dir, iso_dir,
91 for_migration):
92 message = "Could not start VM"
93 logging.error(message)
94 raise error.TestError(message)
95
96 scrdump_filename = os.path.join(test.debugdir, "pre_%s.ppm" % name)
97 vm.send_monitor_cmd("screendump %s" % scrdump_filename)
98
99
100def postprocess_image(test, params):
101 """
102 Postprocess a single QEMU image according to the instructions in params.
103 Currently this function just removes an image if requested.
104
105 @param test: An Autotest test object.
106 @param params: A dict containing image postprocessing parameters.
107 """
108 image_dir = os.path.join(test.bindir, "images")
109
110 if params.get("remove_image") == "yes":
111 kvm_vm.remove_image(params, image_dir)
112
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)
125 vm = kvm_utils.env_get_vm(env, name)
126 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)
133 vm.send_monitor_cmd("screendump %s" % scrdump_filename)
134
135 if params.get("kill_vm") == "yes":
136 if not kvm_utils.wait_for(vm.is_dead,
137 float(params.get("kill_vm_timeout", 0)), 0.0, 1.0,
138 "Waiting for VM to kill itself..."):
139 logging.debug("'kill_vm' specified; killing VM...")
140 vm.destroy(gracefully = params.get("kill_vm_gracefully") == "yes")
141
142
lmr86d1ea52009-06-15 20:34:39 +0000143def process_command(test, params, env, command, command_timeout,
144 command_noncritical):
145 """
146 Pre- or post- custom commands to be executed before/after a test is run
147
148 @param test: An Autotest test object.
149 @param params: A dict containing all VM and image parameters.
150 @param env: The environment (a dict-like object).
lmr0bc6efc2009-07-27 13:27:42 +0000151 @param command: Command to be run.
152 @param command_timeout: Timeout for command execution.
153 @param command_noncritical: If True test will not fail if command fails.
lmr86d1ea52009-06-15 20:34:39 +0000154 """
lmr0bc6efc2009-07-27 13:27:42 +0000155 # Export environment vars
lmr86d1ea52009-06-15 20:34:39 +0000156 for k in params.keys():
lmr0bc6efc2009-07-27 13:27:42 +0000157 os.putenv("KVM_TEST_%s" % k, str(params[k]))
158 # Execute command
lmr86d1ea52009-06-15 20:34:39 +0000159 logging.info("Executing command '%s'..." % command)
lmra4967622009-07-23 01:36:32 +0000160 (status, output) = kvm_subprocess.run_fg("cd %s; %s" % (test.bindir,
lmr86d1ea52009-06-15 20:34:39 +0000161 command),
lmra4967622009-07-23 01:36:32 +0000162 logging.debug, "(command) ",
lmr0bc6efc2009-07-27 13:27:42 +0000163 timeout=command_timeout)
lmr86d1ea52009-06-15 20:34:39 +0000164 if status != 0:
lmr0bc6efc2009-07-27 13:27:42 +0000165 logging.warn("Custom processing command failed: '%s'" % command)
166 if not command_noncritical:
lmr86d1ea52009-06-15 20:34:39 +0000167 raise error.TestError("Custom processing command failed")
168
169
lmr6f669ce2009-05-31 19:02:42 +0000170def process(test, params, env, image_func, vm_func):
171 """
172 Pre- or post-process VMs and images according to the instructions in params.
173 Call image_func for each image listed in params and vm_func for each VM.
174
175 @param test: An Autotest test object.
176 @param params: A dict containing all VM and image parameters.
177 @param env: The environment (a dict-like object).
178 @param image_func: A function to call for each image.
179 @param vm_func: A function to call for each VM.
180 """
181 # Get list of VMs specified for this test
182 vm_names = kvm_utils.get_sub_dict_names(params, "vms")
183 for vm_name in vm_names:
184 vm_params = kvm_utils.get_sub_dict(params, vm_name)
185 # Get list of images specified for this VM
186 image_names = kvm_utils.get_sub_dict_names(vm_params, "images")
187 for image_name in image_names:
188 image_params = kvm_utils.get_sub_dict(vm_params, image_name)
189 # Call image_func for each image
190 image_func(test, image_params)
191 # Call vm_func for each vm
192 vm_func(test, vm_params, env, vm_name)
193
194
195def preprocess(test, params, env):
196 """
197 Preprocess all VMs and images according to the instructions in params.
198 Also, collect some host information, such as the KVM version.
199
200 @param test: An Autotest test object.
201 @param params: A dict containing all VM and image parameters.
202 @param env: The environment (a dict-like object).
203 """
lmr6f669ce2009-05-31 19:02:42 +0000204 # Destroy and remove VMs that are no longer needed in the environment
205 requested_vms = kvm_utils.get_sub_dict_names(params, "vms")
206 for key in env.keys():
207 vm = env[key]
208 if not kvm_utils.is_vm(vm):
209 continue
210 if not vm.name in requested_vms:
211 logging.debug("VM '%s' found in environment but not required for"
212 " test; removing it..." % vm.name)
213 vm.destroy()
214 del env[key]
215
lmr0bc6efc2009-07-27 13:27:42 +0000216 # Execute any pre_commands
lmr86d1ea52009-06-15 20:34:39 +0000217 if params.get("pre_command"):
218 process_command(test, params, env, params.get("pre_command"),
lmr0bc6efc2009-07-27 13:27:42 +0000219 int(params.get("pre_command_timeout", "600")),
220 params.get("pre_command_noncritical") == "yes")
lmr86d1ea52009-06-15 20:34:39 +0000221
lmr6f669ce2009-05-31 19:02:42 +0000222 # Preprocess all VMs and images
223 process(test, params, env, preprocess_image, preprocess_vm)
224
225 # Get the KVM kernel module version and write it as a keyval
226 logging.debug("Fetching KVM module version...")
227 if os.path.exists("/dev/kvm"):
228 kvm_version = os.uname()[2]
229 try:
230 file = open("/sys/module/kvm/version", "r")
231 kvm_version = file.read().strip()
232 file.close()
233 except:
234 pass
235 else:
236 kvm_version = "Unknown"
237 logging.debug("KVM module not loaded")
238 logging.debug("KVM version: %s" % kvm_version)
239 test.write_test_keyval({"kvm_version": kvm_version})
240
241 # Get the KVM userspace version and write it as a keyval
242 logging.debug("Fetching KVM userspace version...")
243 qemu_path = os.path.join(test.bindir, "qemu")
244 version_line = commands.getoutput("%s -help | head -n 1" % qemu_path)
245 exp = re.compile("[Vv]ersion .*?,")
246 match = exp.search(version_line)
247 if match:
248 kvm_userspace_version = " ".join(match.group().split()[1:]).strip(",")
249 else:
250 kvm_userspace_version = "Unknown"
251 logging.debug("Could not fetch KVM userspace version")
252 logging.debug("KVM userspace version: %s" % kvm_userspace_version)
253 test.write_test_keyval({"kvm_userspace_version": kvm_userspace_version})
254
255
256def postprocess(test, params, env):
257 """
258 Postprocess all VMs and images according to the instructions in params.
259
260 @param test: An Autotest test object.
261 @param params: Dict containing all VM and image parameters.
262 @param env: The environment (a dict-like object).
263 """
264 process(test, params, env, postprocess_image, postprocess_vm)
265
lmr0ee0a9c2009-07-24 19:23:29 +0000266 # Should we convert PPM files to PNG format?
267 if params.get("convert_ppm_files_to_png") == "yes":
268 logging.debug("'convert_ppm_files_to_png' specified; converting PPM"
269 " files to PNG format...")
lmre9f528e2009-08-12 15:18:10 +0000270 try:
271 for f in glob.glob(os.path.join(test.debugdir, "*.ppm")):
272 image = PIL.Image.open(f)
273 image.save(history_scrdump_filename, format = 'PNG')
274 except NameError:
275 pass
lmr0ee0a9c2009-07-24 19:23:29 +0000276
277 # Should we keep the PPM files?
278 if params.get("keep_ppm_files") != "yes":
lmr6f669ce2009-05-31 19:02:42 +0000279 logging.debug("'keep_ppm_files' not specified; removing all PPM files"
lmr0ee0a9c2009-07-24 19:23:29 +0000280 " from debug dir...")
lmre9f528e2009-08-12 15:18:10 +0000281 for f in glob.glob(os.path.join(test.debugdir, '*.ppm')):
282 os.unlink(f)
lmr6f669ce2009-05-31 19:02:42 +0000283
lmr0bc6efc2009-07-27 13:27:42 +0000284 # Execute any post_commands
lmr86d1ea52009-06-15 20:34:39 +0000285 if params.get("post_command"):
286 process_command(test, params, env, params.get("post_command"),
lmr0bc6efc2009-07-27 13:27:42 +0000287 int(params.get("post_command_timeout", "600")),
288 params.get("post_command_noncritical") == "yes")
lmr86d1ea52009-06-15 20:34:39 +0000289
lmr6f669ce2009-05-31 19:02:42 +0000290
291def postprocess_on_error(test, params, env):
292 """
293 Perform postprocessing operations required only if the test failed.
294
295 @param test: An Autotest test object.
296 @param params: A dict containing all VM and image parameters.
297 @param env: The environment (a dict-like object).
298 """
299 params.update(kvm_utils.get_sub_dict(params, "on_error"))