OLD | NEW |
1 import sys, os, time, commands, re, logging, signal, glob, threading, shutil | 1 import sys, os, time, commands, re, logging, signal, glob, threading, shutil |
2 from autotest_lib.client.bin import test, utils | 2 from autotest_lib.client.bin import test, utils |
3 from autotest_lib.client.common_lib import error | 3 from autotest_lib.client.common_lib import error |
4 import kvm_vm, kvm_utils, kvm_subprocess, kvm_monitor, ppm_utils | 4 import kvm_vm, kvm_utils, kvm_subprocess, kvm_monitor, ppm_utils |
5 try: | 5 try: |
6 import PIL.Image | 6 import PIL.Image |
7 except ImportError: | 7 except ImportError: |
8 logging.warning('No python imaging library installed. PPM image ' | 8 logging.warning('No python imaging library installed. PPM image ' |
9 'conversion to JPEG disabled. In order to enable it, ' | 9 'conversion to JPEG disabled. In order to enable it, ' |
10 'please install python-imaging or the equivalent for your ' | 10 'please install python-imaging or the equivalent for your ' |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 """ | 43 """ |
44 Preprocess a single VM object according to the instructions in params. | 44 Preprocess a single VM object according to the instructions in params. |
45 Start the VM if requested and get a screendump. | 45 Start the VM if requested and get a screendump. |
46 | 46 |
47 @param test: An Autotest test object. | 47 @param test: An Autotest test object. |
48 @param params: A dict containing VM preprocessing parameters. | 48 @param params: A dict containing VM preprocessing parameters. |
49 @param env: The environment (a dict-like object). | 49 @param env: The environment (a dict-like object). |
50 @param name: The name of the VM object. | 50 @param name: The name of the VM object. |
51 """ | 51 """ |
52 logging.debug("Preprocessing VM '%s'..." % name) | 52 logging.debug("Preprocessing VM '%s'..." % name) |
53 vm = env.get_vm(name) | 53 vm = kvm_utils.env_get_vm(env, name) |
54 if vm: | 54 if vm: |
55 logging.debug("VM object found in environment") | 55 logging.debug("VM object found in environment") |
56 else: | 56 else: |
57 logging.debug("VM object does not exist; creating it") | 57 logging.debug("VM object does not exist; creating it") |
58 vm = kvm_vm.VM(name, params, test.bindir, env.get("address_cache")) | 58 vm = kvm_vm.VM(name, params, test.bindir, env.get("address_cache")) |
59 env.register_vm(name, vm) | 59 kvm_utils.env_register_vm(env, name, vm) |
60 | 60 |
61 start_vm = False | 61 start_vm = False |
62 | 62 |
63 migration_mode = params.get("migration_mode", None) | |
64 | |
65 if params.get("restart_vm") == "yes": | 63 if params.get("restart_vm") == "yes": |
66 logging.debug("'restart_vm' specified; (re)starting VM...") | 64 logging.debug("'restart_vm' specified; (re)starting VM...") |
67 start_vm = True | 65 start_vm = True |
68 elif params.get("start_vm") == "yes": | 66 elif params.get("start_vm") == "yes": |
69 if not vm.is_alive(): | 67 if not vm.is_alive(): |
70 logging.debug("VM is not alive; starting it...") | 68 logging.debug("VM is not alive; starting it...") |
71 start_vm = True | 69 start_vm = True |
72 elif vm.make_qemu_command() != vm.make_qemu_command(name, params, | 70 elif vm.make_qemu_command() != vm.make_qemu_command(name, params, |
73 test.bindir): | 71 test.bindir): |
74 logging.debug("VM's qemu command differs from requested one; " | 72 logging.debug("VM's qemu command differs from requested one; " |
75 "restarting it...") | 73 "restarting it...") |
76 start_vm = True | 74 start_vm = True |
77 elif migration_mode is not None: | |
78 logging.debug("Starting VM on migration incoming mode...") | |
79 start_vm = True | |
80 | 75 |
81 if start_vm: | 76 if start_vm: |
82 if migration_mode is not None: | 77 # Start the VM (or restart it if it's already up) |
83 if not vm.create(name, params, test.bindir, | 78 if not vm.create(name, params, test.bindir): |
84 migration_mode=migration_mode): | 79 raise error.TestError("Could not start VM") |
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") | |
90 else: | 80 else: |
91 # Don't start the VM, just update its params | 81 # Don't start the VM, just update its params |
92 vm.params = params | 82 vm.params = params |
93 | 83 |
94 scrdump_filename = os.path.join(test.debugdir, "pre_%s.ppm" % name) | 84 scrdump_filename = os.path.join(test.debugdir, "pre_%s.ppm" % name) |
95 try: | 85 try: |
96 if vm.monitor: | 86 if vm.monitor: |
97 vm.monitor.screendump(scrdump_filename) | 87 vm.monitor.screendump(scrdump_filename) |
98 except kvm_monitor.MonitorError, e: | 88 except kvm_monitor.MonitorError, e: |
99 logging.warn(e) | 89 logging.warn(e) |
(...skipping 15 matching lines...) Expand all Loading... |
115 """ | 105 """ |
116 Postprocess a single VM object according to the instructions in params. | 106 Postprocess a single VM object according to the instructions in params. |
117 Kill the VM if requested and get a screendump. | 107 Kill the VM if requested and get a screendump. |
118 | 108 |
119 @param test: An Autotest test object. | 109 @param test: An Autotest test object. |
120 @param params: A dict containing VM postprocessing parameters. | 110 @param params: A dict containing VM postprocessing parameters. |
121 @param env: The environment (a dict-like object). | 111 @param env: The environment (a dict-like object). |
122 @param name: The name of the VM object. | 112 @param name: The name of the VM object. |
123 """ | 113 """ |
124 logging.debug("Postprocessing VM '%s'..." % name) | 114 logging.debug("Postprocessing VM '%s'..." % name) |
125 vm = env.get_vm(name) | 115 vm = kvm_utils.env_get_vm(env, name) |
126 if vm: | 116 if vm: |
127 logging.debug("VM object found in environment") | 117 logging.debug("VM object found in environment") |
128 else: | 118 else: |
129 logging.debug("VM object does not exist in environment") | 119 logging.debug("VM object does not exist in environment") |
130 return | 120 return |
131 | 121 |
132 scrdump_filename = os.path.join(test.debugdir, "post_%s.ppm" % name) | 122 scrdump_filename = os.path.join(test.debugdir, "post_%s.ppm" % name) |
133 try: | 123 try: |
134 if vm.monitor: | 124 if vm.monitor: |
135 vm.monitor.screendump(scrdump_filename) | 125 vm.monitor.screendump(scrdump_filename) |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 Pre- or post-process VMs and images according to the instructions in params. | 166 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. | 167 Call image_func for each image listed in params and vm_func for each VM. |
178 | 168 |
179 @param test: An Autotest test object. | 169 @param test: An Autotest test object. |
180 @param params: A dict containing all VM and image parameters. | 170 @param params: A dict containing all VM and image parameters. |
181 @param env: The environment (a dict-like object). | 171 @param env: The environment (a dict-like object). |
182 @param image_func: A function to call for each image. | 172 @param image_func: A function to call for each image. |
183 @param vm_func: A function to call for each VM. | 173 @param vm_func: A function to call for each VM. |
184 """ | 174 """ |
185 # Get list of VMs specified for this test | 175 # Get list of VMs specified for this test |
186 for vm_name in params.objects("vms"): | 176 vm_names = kvm_utils.get_sub_dict_names(params, "vms") |
187 vm_params = params.object_params(vm_name) | 177 for vm_name in vm_names: |
| 178 vm_params = kvm_utils.get_sub_dict(params, vm_name) |
188 # Get list of images specified for this VM | 179 # Get list of images specified for this VM |
189 for image_name in vm_params.objects("images"): | 180 image_names = kvm_utils.get_sub_dict_names(vm_params, "images") |
190 image_params = vm_params.object_params(image_name) | 181 for image_name in image_names: |
| 182 image_params = kvm_utils.get_sub_dict(vm_params, image_name) |
191 # Call image_func for each image | 183 # Call image_func for each image |
192 image_func(test, image_params) | 184 image_func(test, image_params) |
193 # Call vm_func for each vm | 185 # Call vm_func for each vm |
194 vm_func(test, vm_params, env, vm_name) | 186 vm_func(test, vm_params, env, vm_name) |
195 | 187 |
196 | 188 |
197 def preprocess(test, params, env): | 189 def preprocess(test, params, env): |
198 """ | 190 """ |
199 Preprocess all VMs and images according to the instructions in params. | 191 Preprocess all VMs and images according to the instructions in params. |
200 Also, collect some host information, such as the KVM version. | 192 Also, collect some host information, such as the KVM version. |
201 | 193 |
202 @param test: An Autotest test object. | 194 @param test: An Autotest test object. |
203 @param params: A dict containing all VM and image parameters. | 195 @param params: A dict containing all VM and image parameters. |
204 @param env: The environment (a dict-like object). | 196 @param env: The environment (a dict-like object). |
205 """ | 197 """ |
206 # Start tcpdump if it isn't already running | 198 # Start tcpdump if it isn't already running |
207 if "address_cache" not in env: | 199 if "address_cache" not in env: |
208 env["address_cache"] = {} | 200 env["address_cache"] = {} |
209 if "tcpdump" in env and not env["tcpdump"].is_alive(): | 201 if "tcpdump" in env and not env["tcpdump"].is_alive(): |
210 env["tcpdump"].close() | 202 env["tcpdump"].close() |
211 del env["tcpdump"] | 203 del env["tcpdump"] |
212 if "tcpdump" not in env and params.get("run_tcpdump", "yes") == "yes": | 204 if "tcpdump" not in env and params.get("run_tcpdump", "yes") == "yes": |
213 cmd = "%s -npvi any 'dst port 68'" % kvm_utils.find_command("tcpdump") | 205 cmd = "%s -npvi any 'dst port 68'" % kvm_utils.find_command("tcpdump") |
214 logging.debug("Starting tcpdump (%s)...", cmd) | 206 logging.debug("Starting tcpdump (%s)...", cmd) |
215 env["tcpdump"] = kvm_subprocess.Tail( | 207 env["tcpdump"] = kvm_subprocess.kvm_tail( |
216 command=cmd, | 208 command=cmd, |
217 output_func=_update_address_cache, | 209 output_func=_update_address_cache, |
218 output_params=(env["address_cache"],)) | 210 output_params=(env["address_cache"],)) |
219 if kvm_utils.wait_for(lambda: not env["tcpdump"].is_alive(), | 211 if kvm_utils.wait_for(lambda: not env["tcpdump"].is_alive(), |
220 0.1, 0.1, 1.0): | 212 0.1, 0.1, 1.0): |
221 logging.warn("Could not start tcpdump") | 213 logging.warn("Could not start tcpdump") |
222 logging.warn("Status: %s" % env["tcpdump"].get_status()) | 214 logging.warn("Status: %s" % env["tcpdump"].get_status()) |
223 logging.warn("Output:" + kvm_utils.format_str_for_message( | 215 logging.warn("Output:" + kvm_utils.format_str_for_message( |
224 env["tcpdump"].get_output())) | 216 env["tcpdump"].get_output())) |
225 | 217 |
226 # Destroy and remove VMs that are no longer needed in the environment | 218 # Destroy and remove VMs that are no longer needed in the environment |
227 requested_vms = params.objects("vms") | 219 requested_vms = kvm_utils.get_sub_dict_names(params, "vms") |
228 for key in env.keys(): | 220 for key in env.keys(): |
229 vm = env[key] | 221 vm = env[key] |
230 if not kvm_utils.is_vm(vm): | 222 if not kvm_utils.is_vm(vm): |
231 continue | 223 continue |
232 if not vm.name in requested_vms: | 224 if not vm.name in requested_vms: |
233 logging.debug("VM '%s' found in environment but not required for " | 225 logging.debug("VM '%s' found in environment but not required for " |
234 "test; removing it..." % vm.name) | 226 "test; removing it..." % vm.name) |
235 vm.destroy() | 227 vm.destroy() |
236 del env[key] | 228 del env[key] |
237 | 229 |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 logging.debug("'keep_screendumps' not specified; removing screendump " | 323 logging.debug("'keep_screendumps' not specified; removing screendump " |
332 "dirs...") | 324 "dirs...") |
333 for d in glob.glob(os.path.join(test.debugdir, "screendumps_*")): | 325 for d in glob.glob(os.path.join(test.debugdir, "screendumps_*")): |
334 if os.path.isdir(d) and not os.path.islink(d): | 326 if os.path.isdir(d) and not os.path.islink(d): |
335 shutil.rmtree(d, ignore_errors=True) | 327 shutil.rmtree(d, ignore_errors=True) |
336 | 328 |
337 # Kill all unresponsive VMs | 329 # Kill all unresponsive VMs |
338 if params.get("kill_unresponsive_vms") == "yes": | 330 if params.get("kill_unresponsive_vms") == "yes": |
339 logging.debug("'kill_unresponsive_vms' specified; killing all VMs " | 331 logging.debug("'kill_unresponsive_vms' specified; killing all VMs " |
340 "that fail to respond to a remote login request...") | 332 "that fail to respond to a remote login request...") |
341 for vm in env.get_all_vms(): | 333 for vm in kvm_utils.env_get_all_vms(env): |
342 if vm.is_alive(): | 334 if vm.is_alive(): |
343 session = vm.remote_login() | 335 session = vm.remote_login() |
344 if session: | 336 if session: |
345 session.close() | 337 session.close() |
346 else: | 338 else: |
347 vm.destroy(gracefully=False) | 339 vm.destroy(gracefully=False) |
348 | 340 |
349 # Kill all kvm_subprocess tail threads | 341 # Kill all kvm_subprocess tail threads |
350 kvm_subprocess.kill_tail_threads() | 342 kvm_subprocess.kill_tail_threads() |
351 | 343 |
352 # Terminate tcpdump if no VMs are alive | 344 # Terminate tcpdump if no VMs are alive |
353 living_vms = [vm for vm in env.get_all_vms() if vm.is_alive()] | 345 living_vms = [vm for vm in kvm_utils.env_get_all_vms(env) if vm.is_alive()] |
354 if not living_vms and "tcpdump" in env: | 346 if not living_vms and "tcpdump" in env: |
355 env["tcpdump"].close() | 347 env["tcpdump"].close() |
356 del env["tcpdump"] | 348 del env["tcpdump"] |
357 | 349 |
358 # Execute any post_commands | 350 # Execute any post_commands |
359 if params.get("post_command"): | 351 if params.get("post_command"): |
360 process_command(test, params, env, params.get("post_command"), | 352 process_command(test, params, env, params.get("post_command"), |
361 int(params.get("post_command_timeout", "600")), | 353 int(params.get("post_command_timeout", "600")), |
362 params.get("post_command_noncritical") == "yes") | 354 params.get("post_command_noncritical") == "yes") |
363 | 355 |
364 | 356 |
365 def postprocess_on_error(test, params, env): | 357 def postprocess_on_error(test, params, env): |
366 """ | 358 """ |
367 Perform postprocessing operations required only if the test failed. | 359 Perform postprocessing operations required only if the test failed. |
368 | 360 |
369 @param test: An Autotest test object. | 361 @param test: An Autotest test object. |
370 @param params: A dict containing all VM and image parameters. | 362 @param params: A dict containing all VM and image parameters. |
371 @param env: The environment (a dict-like object). | 363 @param env: The environment (a dict-like object). |
372 """ | 364 """ |
373 params.update(params.object_params("on_error")) | 365 params.update(kvm_utils.get_sub_dict(params, "on_error")) |
374 | 366 |
375 | 367 |
376 def _update_address_cache(address_cache, line): | 368 def _update_address_cache(address_cache, line): |
377 if re.search("Your.IP", line, re.IGNORECASE): | 369 if re.search("Your.IP", line, re.IGNORECASE): |
378 matches = re.findall(r"\d*\.\d*\.\d*\.\d*", line) | 370 matches = re.findall(r"\d*\.\d*\.\d*\.\d*", line) |
379 if matches: | 371 if matches: |
380 address_cache["last_seen"] = matches[0] | 372 address_cache["last_seen"] = matches[0] |
381 if re.search("Client.Ethernet.Address", line, re.IGNORECASE): | 373 if re.search("Client.Ethernet.Address", line, re.IGNORECASE): |
382 matches = re.findall(r"\w*:\w*:\w*:\w*:\w*:\w*", line) | 374 matches = re.findall(r"\w*:\w*:\w*:\w*:\w*:\w*", line) |
383 if matches and address_cache.get("last_seen"): | 375 if matches and address_cache.get("last_seen"): |
384 mac_address = matches[0].lower() | 376 mac_address = matches[0].lower() |
385 if time.time() - address_cache.get("time_%s" % mac_address, 0) > 5: | 377 logging.debug("(address cache) Adding cache entry: %s ---> %s", |
386 logging.debug("(address cache) Adding cache entry: %s ---> %s", | 378 mac_address, address_cache.get("last_seen")) |
387 mac_address, address_cache.get("last_seen")) | |
388 address_cache[mac_address] = address_cache.get("last_seen") | 379 address_cache[mac_address] = address_cache.get("last_seen") |
389 address_cache["time_%s" % mac_address] = time.time() | |
390 del address_cache["last_seen"] | 380 del address_cache["last_seen"] |
391 | 381 |
392 | 382 |
393 def _take_screendumps(test, params, env): | 383 def _take_screendumps(test, params, env): |
394 global _screendump_thread_termination_event | 384 global _screendump_thread_termination_event |
395 temp_dir = test.debugdir | 385 temp_dir = test.debugdir |
396 if params.get("screendump_temp_dir"): | 386 if params.get("screendump_temp_dir"): |
397 temp_dir = kvm_utils.get_path(test.bindir, | 387 temp_dir = kvm_utils.get_path(test.bindir, |
398 params.get("screendump_temp_dir")) | 388 params.get("screendump_temp_dir")) |
399 try: | 389 try: |
400 os.makedirs(temp_dir) | 390 os.makedirs(temp_dir) |
401 except OSError: | 391 except OSError: |
402 pass | 392 pass |
403 temp_filename = os.path.join(temp_dir, "scrdump-%s.ppm" % | 393 temp_filename = os.path.join(temp_dir, "scrdump-%s.ppm" % |
404 kvm_utils.generate_random_string(6)) | 394 kvm_utils.generate_random_string(6)) |
405 delay = float(params.get("screendump_delay", 5)) | 395 delay = float(params.get("screendump_delay", 5)) |
406 quality = int(params.get("screendump_quality", 30)) | 396 quality = int(params.get("screendump_quality", 30)) |
407 | 397 |
408 cache = {} | 398 cache = {} |
409 | 399 |
410 while True: | 400 while True: |
411 for vm in env.get_all_vms(): | 401 for vm in kvm_utils.env_get_all_vms(env): |
412 if not vm.is_alive(): | 402 if not vm.is_alive(): |
413 continue | 403 continue |
414 try: | 404 try: |
415 vm.monitor.screendump(temp_filename) | 405 vm.monitor.screendump(temp_filename) |
416 except kvm_monitor.MonitorError, e: | 406 except kvm_monitor.MonitorError, e: |
417 logging.warn(e) | 407 logging.warn(e) |
418 continue | 408 continue |
419 if not os.path.exists(temp_filename): | 409 if not os.path.exists(temp_filename): |
420 logging.warn("VM '%s' failed to produce a screendump", vm.name) | 410 logging.warn("VM '%s' failed to produce a screendump", vm.name) |
421 continue | 411 continue |
(...skipping 20 matching lines...) Expand all Loading... |
442 try: | 432 try: |
443 image = PIL.Image.open(temp_filename) | 433 image = PIL.Image.open(temp_filename) |
444 image.save(screendump_filename, format="JPEG", quality=quali
ty) | 434 image.save(screendump_filename, format="JPEG", quality=quali
ty) |
445 cache[hash] = screendump_filename | 435 cache[hash] = screendump_filename |
446 except NameError: | 436 except NameError: |
447 pass | 437 pass |
448 os.unlink(temp_filename) | 438 os.unlink(temp_filename) |
449 if _screendump_thread_termination_event.isSet(): | 439 if _screendump_thread_termination_event.isSet(): |
450 break | 440 break |
451 _screendump_thread_termination_event.wait(delay) | 441 _screendump_thread_termination_event.wait(delay) |
OLD | NEW |