| 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 |