blob: e395d9804766a00a5ad200b0fdbde66a3bb6c77b [file] [log] [blame]
lmr6f669ce2009-05-31 19:02:42 +00001import sys, os, time, commands, re, logging
2from autotest_lib.client.bin import test
3from autotest_lib.client.common_lib import error
4import kvm_vm, kvm_utils
5
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):
78 logging.debug("VM's qemu command differs from requested one;"
79 "restarting it...")
80 start_vm = True
81
82 if start_vm:
83 vm.destroy()
84 if not vm.create(name, params, qemu_path, image_dir, iso_dir,
85 for_migration):
86 message = "Could not start VM"
87 logging.error(message)
88 raise error.TestError(message)
89
90 scrdump_filename = os.path.join(test.debugdir, "pre_%s.ppm" % name)
91 vm.send_monitor_cmd("screendump %s" % scrdump_filename)
92
93
94def postprocess_image(test, params):
95 """
96 Postprocess a single QEMU image according to the instructions in params.
97 Currently this function just removes an image if requested.
98
99 @param test: An Autotest test object.
100 @param params: A dict containing image postprocessing parameters.
101 """
102 image_dir = os.path.join(test.bindir, "images")
103
104 if params.get("remove_image") == "yes":
105 kvm_vm.remove_image(params, image_dir)
106
107
108def postprocess_vm(test, params, env, name):
109 """
110 Postprocess a single VM object according to the instructions in params.
111 Kill the VM if requested and get a screendump.
112
113 @param test: An Autotest test object.
114 @param params: A dict containing VM postprocessing parameters.
115 @param env: The environment (a dict-like object).
116 @param name: The name of the VM object.
117 """
118 logging.debug("Postprocessing VM '%s'..." % name)
119 vm = kvm_utils.env_get_vm(env, name)
120 if vm:
121 logging.debug("VM object found in environment")
122 else:
123 logging.debug("VM object does not exist in environment")
124 return
125
126 scrdump_filename = os.path.join(test.debugdir, "post_%s.ppm" % name)
127 vm.send_monitor_cmd("screendump %s" % scrdump_filename)
128
129 if params.get("kill_vm") == "yes":
130 if not kvm_utils.wait_for(vm.is_dead,
131 float(params.get("kill_vm_timeout", 0)), 0.0, 1.0,
132 "Waiting for VM to kill itself..."):
133 logging.debug("'kill_vm' specified; killing VM...")
134 vm.destroy(gracefully = params.get("kill_vm_gracefully") == "yes")
135
136
137def process(test, params, env, image_func, vm_func):
138 """
139 Pre- or post-process VMs and images according to the instructions in params.
140 Call image_func for each image listed in params and vm_func for each VM.
141
142 @param test: An Autotest test object.
143 @param params: A dict containing all VM and image parameters.
144 @param env: The environment (a dict-like object).
145 @param image_func: A function to call for each image.
146 @param vm_func: A function to call for each VM.
147 """
148 # Get list of VMs specified for this test
149 vm_names = kvm_utils.get_sub_dict_names(params, "vms")
150 for vm_name in vm_names:
151 vm_params = kvm_utils.get_sub_dict(params, vm_name)
152 # Get list of images specified for this VM
153 image_names = kvm_utils.get_sub_dict_names(vm_params, "images")
154 for image_name in image_names:
155 image_params = kvm_utils.get_sub_dict(vm_params, image_name)
156 # Call image_func for each image
157 image_func(test, image_params)
158 # Call vm_func for each vm
159 vm_func(test, vm_params, env, vm_name)
160
161
162def preprocess(test, params, env):
163 """
164 Preprocess all VMs and images according to the instructions in params.
165 Also, collect some host information, such as the KVM version.
166
167 @param test: An Autotest test object.
168 @param params: A dict containing all VM and image parameters.
169 @param env: The environment (a dict-like object).
170 """
171 # Verify the identities of all living VMs
172 for vm in env.values():
173 if not kvm_utils.is_vm(vm):
174 continue
175 if vm.is_dead():
176 continue
177 if not vm.verify_process_identity():
178 logging.debug("VM '%s' seems to have been replaced by another"
179 " process" % vm.name)
180 vm.pid = None
181
182 # Destroy and remove VMs that are no longer needed in the environment
183 requested_vms = kvm_utils.get_sub_dict_names(params, "vms")
184 for key in env.keys():
185 vm = env[key]
186 if not kvm_utils.is_vm(vm):
187 continue
188 if not vm.name in requested_vms:
189 logging.debug("VM '%s' found in environment but not required for"
190 " test; removing it..." % vm.name)
191 vm.destroy()
192 del env[key]
193
194 # Preprocess all VMs and images
195 process(test, params, env, preprocess_image, preprocess_vm)
196
197 # Get the KVM kernel module version and write it as a keyval
198 logging.debug("Fetching KVM module version...")
199 if os.path.exists("/dev/kvm"):
200 kvm_version = os.uname()[2]
201 try:
202 file = open("/sys/module/kvm/version", "r")
203 kvm_version = file.read().strip()
204 file.close()
205 except:
206 pass
207 else:
208 kvm_version = "Unknown"
209 logging.debug("KVM module not loaded")
210 logging.debug("KVM version: %s" % kvm_version)
211 test.write_test_keyval({"kvm_version": kvm_version})
212
213 # Get the KVM userspace version and write it as a keyval
214 logging.debug("Fetching KVM userspace version...")
215 qemu_path = os.path.join(test.bindir, "qemu")
216 version_line = commands.getoutput("%s -help | head -n 1" % qemu_path)
217 exp = re.compile("[Vv]ersion .*?,")
218 match = exp.search(version_line)
219 if match:
220 kvm_userspace_version = " ".join(match.group().split()[1:]).strip(",")
221 else:
222 kvm_userspace_version = "Unknown"
223 logging.debug("Could not fetch KVM userspace version")
224 logging.debug("KVM userspace version: %s" % kvm_userspace_version)
225 test.write_test_keyval({"kvm_userspace_version": kvm_userspace_version})
226
227
228def postprocess(test, params, env):
229 """
230 Postprocess all VMs and images according to the instructions in params.
231
232 @param test: An Autotest test object.
233 @param params: Dict containing all VM and image parameters.
234 @param env: The environment (a dict-like object).
235 """
236 process(test, params, env, postprocess_image, postprocess_vm)
237
238 # See if we should get rid of all PPM files
239 if not params.get("keep_ppm_files") == "yes":
240 # Remove them all
241 logging.debug("'keep_ppm_files' not specified; removing all PPM files"
242 " from results dir...")
243 kvm_utils.run_bg("rm -vf %s" % os.path.join(test.debugdir, "*.ppm"),
244 None, logging.debug, "(rm) ", timeout=5.0)
245
246
247def postprocess_on_error(test, params, env):
248 """
249 Perform postprocessing operations required only if the test failed.
250
251 @param test: An Autotest test object.
252 @param params: A dict containing all VM and image parameters.
253 @param env: The environment (a dict-like object).
254 """
255 params.update(kvm_utils.get_sub_dict(params, "on_error"))