blob: d118826a87538b22d7e3f3fc7fb61f702d2667bf [file] [log] [blame]
lmr86d1ea52009-06-15 20:34:39 +00001import sys, os, time, commands, re, logging, signal
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
lmr6f669ce2009-05-31 19:02:42 +00005
6
7def preprocess_image(test, params):
8 """
9 Preprocess a single QEMU image according to the instructions in params.
10
11 @param test: Autotest test object.
12 @param params: A dict containing image preprocessing parameters.
13 @note: Currently this function just creates an image if requested.
14 """
15 qemu_img_path = os.path.join(test.bindir, "qemu-img")
16 image_dir = os.path.join(test.bindir, "images")
17 image_filename = kvm_vm.get_image_filename(params, image_dir)
18
19 create_image = False
20
21 if params.get("force_create_image") == "yes":
22 logging.debug("'force_create_image' specified; creating image...")
23 create_image = True
24 elif params.get("create_image") == "yes" and not \
25 os.path.exists(image_filename):
26 logging.debug("Creating image...")
27 create_image = True
28
29 if create_image:
30 if not kvm_vm.create_image(params, qemu_img_path, image_dir):
31 message = "Could not create image"
32 logging.error(message)
33 raise error.TestError(message)
34
35
36def preprocess_vm(test, params, env, name):
37 """
38 Preprocess a single VM object according to the instructions in params.
39 Start the VM if requested and get a screendump.
40
41 @param test: An Autotest test object.
42 @param params: A dict containing VM preprocessing parameters.
43 @param env: The environment (a dict-like object).
44 @param name: The name of the VM object.
45 """
46 qemu_path = os.path.join(test.bindir, "qemu")
47 image_dir = os.path.join(test.bindir, "images")
48 iso_dir = os.path.join(test.bindir, "isos")
49
50 logging.debug("Preprocessing VM '%s'..." % name)
51 vm = kvm_utils.env_get_vm(env, name)
52 if vm:
53 logging.debug("VM object found in environment")
54 else:
55 logging.debug("VM object does not exist; creating it")
56 vm = kvm_vm.VM(name, params, qemu_path, image_dir, iso_dir)
57 kvm_utils.env_register_vm(env, name, vm)
58
59 start_vm = False
60 for_migration = False
61
62 if params.get("start_vm_for_migration") == "yes":
63 logging.debug("'start_vm_for_migration' specified; (re)starting VM with"
64 " -incoming option...")
65 start_vm = True
66 for_migration = True
67 elif params.get("restart_vm") == "yes":
68 logging.debug("'restart_vm' specified; (re)starting VM...")
69 start_vm = True
70 elif params.get("start_vm") == "yes":
71 if not vm.is_alive():
72 logging.debug("VM is not alive; starting it...")
73 start_vm = True
74 elif vm.make_qemu_command() != vm.make_qemu_command(name, params,
75 qemu_path,
76 image_dir,
77 iso_dir):
lmra4967622009-07-23 01:36:32 +000078 logging.debug("VM's qemu command differs from requested one; "
lmr6f669ce2009-05-31 19:02:42 +000079 "restarting it...")
80 start_vm = True
81
82 if start_vm:
lmr6f669ce2009-05-31 19:02:42 +000083 if not vm.create(name, params, qemu_path, image_dir, iso_dir,
84 for_migration):
85 message = "Could not start VM"
86 logging.error(message)
87 raise error.TestError(message)
88
89 scrdump_filename = os.path.join(test.debugdir, "pre_%s.ppm" % name)
90 vm.send_monitor_cmd("screendump %s" % scrdump_filename)
91
92
93def postprocess_image(test, params):
94 """
95 Postprocess a single QEMU image according to the instructions in params.
96 Currently this function just removes an image if requested.
97
98 @param test: An Autotest test object.
99 @param params: A dict containing image postprocessing parameters.
100 """
101 image_dir = os.path.join(test.bindir, "images")
102
103 if params.get("remove_image") == "yes":
104 kvm_vm.remove_image(params, image_dir)
105
106
107def postprocess_vm(test, params, env, name):
108 """
109 Postprocess a single VM object according to the instructions in params.
110 Kill the VM if requested and get a screendump.
111
112 @param test: An Autotest test object.
113 @param params: A dict containing VM postprocessing parameters.
114 @param env: The environment (a dict-like object).
115 @param name: The name of the VM object.
116 """
117 logging.debug("Postprocessing VM '%s'..." % name)
118 vm = kvm_utils.env_get_vm(env, name)
119 if vm:
120 logging.debug("VM object found in environment")
121 else:
122 logging.debug("VM object does not exist in environment")
123 return
124
125 scrdump_filename = os.path.join(test.debugdir, "post_%s.ppm" % name)
126 vm.send_monitor_cmd("screendump %s" % scrdump_filename)
127
128 if params.get("kill_vm") == "yes":
129 if not kvm_utils.wait_for(vm.is_dead,
130 float(params.get("kill_vm_timeout", 0)), 0.0, 1.0,
131 "Waiting for VM to kill itself..."):
132 logging.debug("'kill_vm' specified; killing VM...")
133 vm.destroy(gracefully = params.get("kill_vm_gracefully") == "yes")
134
135
lmr86d1ea52009-06-15 20:34:39 +0000136def process_command(test, params, env, command, command_timeout,
137 command_noncritical):
138 """
139 Pre- or post- custom commands to be executed before/after a test is run
140
141 @param test: An Autotest test object.
142 @param params: A dict containing all VM and image parameters.
143 @param env: The environment (a dict-like object).
lmr0bc6efc2009-07-27 13:27:42 +0000144 @param command: Command to be run.
145 @param command_timeout: Timeout for command execution.
146 @param command_noncritical: If True test will not fail if command fails.
lmr86d1ea52009-06-15 20:34:39 +0000147 """
lmr0bc6efc2009-07-27 13:27:42 +0000148 # Export environment vars
lmr86d1ea52009-06-15 20:34:39 +0000149 for k in params.keys():
lmr0bc6efc2009-07-27 13:27:42 +0000150 os.putenv("KVM_TEST_%s" % k, str(params[k]))
151 # Execute command
lmr86d1ea52009-06-15 20:34:39 +0000152 logging.info("Executing command '%s'..." % command)
lmra4967622009-07-23 01:36:32 +0000153 (status, output) = kvm_subprocess.run_fg("cd %s; %s" % (test.bindir,
lmr86d1ea52009-06-15 20:34:39 +0000154 command),
lmra4967622009-07-23 01:36:32 +0000155 logging.debug, "(command) ",
lmr0bc6efc2009-07-27 13:27:42 +0000156 timeout=command_timeout)
lmr86d1ea52009-06-15 20:34:39 +0000157 if status != 0:
lmr0bc6efc2009-07-27 13:27:42 +0000158 logging.warn("Custom processing command failed: '%s'" % command)
159 if not command_noncritical:
lmr86d1ea52009-06-15 20:34:39 +0000160 raise error.TestError("Custom processing command failed")
161
162
lmr6f669ce2009-05-31 19:02:42 +0000163def process(test, params, env, image_func, vm_func):
164 """
165 Pre- or post-process VMs and images according to the instructions in params.
166 Call image_func for each image listed in params and vm_func for each VM.
167
168 @param test: An Autotest test object.
169 @param params: A dict containing all VM and image parameters.
170 @param env: The environment (a dict-like object).
171 @param image_func: A function to call for each image.
172 @param vm_func: A function to call for each VM.
173 """
174 # Get list of VMs specified for this test
175 vm_names = kvm_utils.get_sub_dict_names(params, "vms")
176 for vm_name in vm_names:
177 vm_params = kvm_utils.get_sub_dict(params, vm_name)
178 # Get list of images specified for this VM
179 image_names = kvm_utils.get_sub_dict_names(vm_params, "images")
180 for image_name in image_names:
181 image_params = kvm_utils.get_sub_dict(vm_params, image_name)
182 # Call image_func for each image
183 image_func(test, image_params)
184 # Call vm_func for each vm
185 vm_func(test, vm_params, env, vm_name)
186
187
188def preprocess(test, params, env):
189 """
190 Preprocess all VMs and images according to the instructions in params.
191 Also, collect some host information, such as the KVM version.
192
193 @param test: An Autotest test object.
194 @param params: A dict containing all VM and image parameters.
195 @param env: The environment (a dict-like object).
196 """
lmr6f669ce2009-05-31 19:02:42 +0000197 # Destroy and remove VMs that are no longer needed in the environment
198 requested_vms = kvm_utils.get_sub_dict_names(params, "vms")
199 for key in env.keys():
200 vm = env[key]
201 if not kvm_utils.is_vm(vm):
202 continue
203 if not vm.name in requested_vms:
204 logging.debug("VM '%s' found in environment but not required for"
205 " test; removing it..." % vm.name)
206 vm.destroy()
207 del env[key]
208
lmr0bc6efc2009-07-27 13:27:42 +0000209 # Execute any pre_commands
lmr86d1ea52009-06-15 20:34:39 +0000210 if params.get("pre_command"):
211 process_command(test, params, env, params.get("pre_command"),
lmr0bc6efc2009-07-27 13:27:42 +0000212 int(params.get("pre_command_timeout", "600")),
213 params.get("pre_command_noncritical") == "yes")
lmr86d1ea52009-06-15 20:34:39 +0000214
lmr6f669ce2009-05-31 19:02:42 +0000215 # Preprocess all VMs and images
216 process(test, params, env, preprocess_image, preprocess_vm)
217
218 # Get the KVM kernel module version and write it as a keyval
219 logging.debug("Fetching KVM module version...")
220 if os.path.exists("/dev/kvm"):
221 kvm_version = os.uname()[2]
222 try:
223 file = open("/sys/module/kvm/version", "r")
224 kvm_version = file.read().strip()
225 file.close()
226 except:
227 pass
228 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...")
236 qemu_path = os.path.join(test.bindir, "qemu")
237 version_line = commands.getoutput("%s -help | head -n 1" % qemu_path)
238 exp = re.compile("[Vv]ersion .*?,")
239 match = exp.search(version_line)
240 if match:
241 kvm_userspace_version = " ".join(match.group().split()[1:]).strip(",")
242 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
248
249def postprocess(test, params, env):
250 """
251 Postprocess all VMs and images according to the instructions in params.
252
253 @param test: An Autotest test object.
254 @param params: Dict containing all VM and image parameters.
255 @param env: The environment (a dict-like object).
256 """
257 process(test, params, env, postprocess_image, postprocess_vm)
258
lmr0ee0a9c2009-07-24 19:23:29 +0000259 # Should we convert PPM files to PNG format?
260 if params.get("convert_ppm_files_to_png") == "yes":
261 logging.debug("'convert_ppm_files_to_png' specified; converting PPM"
262 " files to PNG format...")
263 mogrify_cmd = ("mogrify -format png %s" %
264 os.path.join(test.debugdir, "*.ppm"))
265 kvm_subprocess.run_fg(mogrify_cmd, logging.debug, "(mogrify) ",
266 timeout=30.0)
267
268 # Should we keep the PPM files?
269 if params.get("keep_ppm_files") != "yes":
lmr6f669ce2009-05-31 19:02:42 +0000270 logging.debug("'keep_ppm_files' not specified; removing all PPM files"
lmr0ee0a9c2009-07-24 19:23:29 +0000271 " from debug dir...")
lmra4967622009-07-23 01:36:32 +0000272 rm_cmd = "rm -vf %s" % os.path.join(test.debugdir, "*.ppm")
273 kvm_subprocess.run_fg(rm_cmd, logging.debug, "(rm) ", timeout=5.0)
lmr6f669ce2009-05-31 19:02:42 +0000274
lmr0bc6efc2009-07-27 13:27:42 +0000275 # Execute any post_commands
lmr86d1ea52009-06-15 20:34:39 +0000276 if params.get("post_command"):
277 process_command(test, params, env, params.get("post_command"),
lmr0bc6efc2009-07-27 13:27:42 +0000278 int(params.get("post_command_timeout", "600")),
279 params.get("post_command_noncritical") == "yes")
lmr86d1ea52009-06-15 20:34:39 +0000280
lmr6f669ce2009-05-31 19:02:42 +0000281
282def postprocess_on_error(test, params, env):
283 """
284 Perform postprocessing operations required only if the test failed.
285
286 @param test: An Autotest test object.
287 @param params: A dict containing all VM and image parameters.
288 @param env: The environment (a dict-like object).
289 """
290 params.update(kvm_utils.get_sub_dict(params, "on_error"))