lmr | 1f61a92 | 2009-09-09 22:39:21 +0000 | [diff] [blame] | 1 | """ |
| 2 | High-level KVM test utility functions. |
| 3 | |
| 4 | This module is meant to reduce code size by performing common test procedures. |
| 5 | Generally, code here should look like test code. |
| 6 | More specifically: |
| 7 | - Functions in this module should raise exceptions if things go wrong |
| 8 | (unlike functions in kvm_utils.py and kvm_vm.py which report failure via |
| 9 | their returned values). |
| 10 | - Functions in this module may use logging.info(), in addition to |
| 11 | logging.debug() and logging.error(), to log messages the user may be |
| 12 | interested in (unlike kvm_utils.py and kvm_vm.py which use |
| 13 | logging.debug() for anything that isn't an error). |
| 14 | - Functions in this module typically use functions and classes from |
| 15 | lower-level modules (e.g. kvm_utils.py, kvm_vm.py, kvm_subprocess.py). |
| 16 | - Functions in this module should not be used by lower-level modules. |
| 17 | - Functions in this module should be used in the right context. |
| 18 | For example, a function should not be used where it may display |
| 19 | misleading or inaccurate info or debug messages. |
| 20 | |
| 21 | @copyright: 2008-2009 Red Hat Inc. |
| 22 | """ |
| 23 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 24 | import time, os, logging, re, signal |
lmr | 0bee234 | 2010-02-24 00:01:37 +0000 | [diff] [blame] | 25 | from autotest_lib.client.common_lib import error |
| 26 | from autotest_lib.client.bin import utils |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 27 | from autotest_lib.client.tools import scan_results |
| 28 | import aexpect, virt_utils, virt_vm |
lmr | b635b86 | 2009-09-10 14:53:21 +0000 | [diff] [blame] | 29 | |
lmr | 1f61a92 | 2009-09-09 22:39:21 +0000 | [diff] [blame] | 30 | |
| 31 | def get_living_vm(env, vm_name): |
| 32 | """ |
| 33 | Get a VM object from the environment and make sure it's alive. |
| 34 | |
| 35 | @param env: Dictionary with test environment. |
| 36 | @param vm_name: Name of the desired VM object. |
| 37 | @return: A VM object. |
| 38 | """ |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 39 | vm = env.get_vm(vm_name) |
lmr | 1f61a92 | 2009-09-09 22:39:21 +0000 | [diff] [blame] | 40 | if not vm: |
| 41 | raise error.TestError("VM '%s' not found in environment" % vm_name) |
| 42 | if not vm.is_alive(): |
| 43 | raise error.TestError("VM '%s' seems to be dead; test requires a " |
| 44 | "living VM" % vm_name) |
| 45 | return vm |
| 46 | |
| 47 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 48 | def wait_for_login(vm, nic_index=0, timeout=240, start=0, step=2, serial=None): |
lmr | 1f61a92 | 2009-09-09 22:39:21 +0000 | [diff] [blame] | 49 | """ |
| 50 | Try logging into a VM repeatedly. Stop on success or when timeout expires. |
| 51 | |
| 52 | @param vm: VM object. |
| 53 | @param nic_index: Index of NIC to access in the VM. |
| 54 | @param timeout: Time to wait before giving up. |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 55 | @param serial: Whether to use a serial connection instead of a remote |
| 56 | (ssh, rss) one. |
lmr | 1f61a92 | 2009-09-09 22:39:21 +0000 | [diff] [blame] | 57 | @return: A shell session object. |
| 58 | """ |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 59 | end_time = time.time() + timeout |
| 60 | session = None |
| 61 | if serial: |
| 62 | type = 'serial' |
| 63 | logging.info("Trying to log into guest %s using serial connection," |
| 64 | " timeout %ds", vm.name, timeout) |
| 65 | time.sleep(start) |
| 66 | while time.time() < end_time: |
| 67 | try: |
| 68 | session = vm.serial_login() |
| 69 | break |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 70 | except virt_utils.LoginError, e: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 71 | logging.debug(e) |
| 72 | time.sleep(step) |
| 73 | else: |
| 74 | type = 'remote' |
| 75 | logging.info("Trying to log into guest %s using remote connection," |
| 76 | " timeout %ds", vm.name, timeout) |
| 77 | time.sleep(start) |
| 78 | while time.time() < end_time: |
| 79 | try: |
| 80 | session = vm.login(nic_index=nic_index) |
| 81 | break |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 82 | except (virt_utils.LoginError, virt_vm.VMError), e: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 83 | logging.debug(e) |
| 84 | time.sleep(step) |
lmr | 1f61a92 | 2009-09-09 22:39:21 +0000 | [diff] [blame] | 85 | if not session: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 86 | raise error.TestFail("Could not log into guest %s using %s connection" % |
| 87 | (vm.name, type)) |
| 88 | logging.info("Logged into guest %s using %s connection", vm.name, type) |
lmr | 1f61a92 | 2009-09-09 22:39:21 +0000 | [diff] [blame] | 89 | return session |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 90 | |
| 91 | |
lmr | b9cb23f | 2009-10-13 13:38:55 +0000 | [diff] [blame] | 92 | def reboot(vm, session, method="shell", sleep_before_reset=10, nic_index=0, |
| 93 | timeout=240): |
| 94 | """ |
| 95 | Reboot the VM and wait for it to come back up by trying to log in until |
| 96 | timeout expires. |
| 97 | |
| 98 | @param vm: VM object. |
| 99 | @param session: A shell session object. |
| 100 | @param method: Reboot method. Can be "shell" (send a shell reboot |
| 101 | command) or "system_reset" (send a system_reset monitor command). |
| 102 | @param nic_index: Index of NIC to access in the VM, when logging in after |
| 103 | rebooting. |
| 104 | @param timeout: Time to wait before giving up (after rebooting). |
| 105 | @return: A new shell session object. |
| 106 | """ |
| 107 | if method == "shell": |
| 108 | # Send a reboot command to the guest's shell |
| 109 | session.sendline(vm.get_params().get("reboot_command")) |
Dale Curtis | 456d3c1 | 2011-07-19 11:42:51 -0700 | [diff] [blame] | 110 | logging.info("Reboot command sent. Waiting for guest to go down") |
lmr | b9cb23f | 2009-10-13 13:38:55 +0000 | [diff] [blame] | 111 | elif method == "system_reset": |
| 112 | # Sleep for a while before sending the command |
| 113 | time.sleep(sleep_before_reset) |
lmr | ef30e6f | 2010-06-18 12:51:38 +0000 | [diff] [blame] | 114 | # Clear the event list of all QMP monitors |
| 115 | monitors = [m for m in vm.monitors if m.protocol == "qmp"] |
| 116 | for m in monitors: |
| 117 | m.clear_events() |
lmr | b9cb23f | 2009-10-13 13:38:55 +0000 | [diff] [blame] | 118 | # Send a system_reset monitor command |
lmr | 9e964a0 | 2010-06-18 03:46:21 +0000 | [diff] [blame] | 119 | vm.monitor.cmd("system_reset") |
lmr | 133d11a | 2010-03-09 11:31:25 +0000 | [diff] [blame] | 120 | logging.info("Monitor command system_reset sent. Waiting for guest to " |
Dale Curtis | 456d3c1 | 2011-07-19 11:42:51 -0700 | [diff] [blame] | 121 | "go down") |
lmr | ef30e6f | 2010-06-18 12:51:38 +0000 | [diff] [blame] | 122 | # Look for RESET QMP events |
| 123 | time.sleep(1) |
| 124 | for m in monitors: |
| 125 | if not m.get_event("RESET"): |
| 126 | raise error.TestFail("RESET QMP event not received after " |
| 127 | "system_reset (monitor '%s')" % m.name) |
| 128 | else: |
| 129 | logging.info("RESET QMP event received") |
lmr | b9cb23f | 2009-10-13 13:38:55 +0000 | [diff] [blame] | 130 | else: |
lmr | 133d11a | 2010-03-09 11:31:25 +0000 | [diff] [blame] | 131 | logging.error("Unknown reboot method: %s", method) |
lmr | b9cb23f | 2009-10-13 13:38:55 +0000 | [diff] [blame] | 132 | |
| 133 | # Wait for the session to become unresponsive and close it |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 134 | if not virt_utils.wait_for(lambda: not session.is_responsive(timeout=30), |
lmr | 1565254 | 2009-12-02 13:19:47 +0000 | [diff] [blame] | 135 | 120, 0, 1): |
lmr | b9cb23f | 2009-10-13 13:38:55 +0000 | [diff] [blame] | 136 | raise error.TestFail("Guest refuses to go down") |
| 137 | session.close() |
| 138 | |
| 139 | # Try logging into the guest until timeout expires |
lmr | 133d11a | 2010-03-09 11:31:25 +0000 | [diff] [blame] | 140 | logging.info("Guest is down. Waiting for it to go up again, timeout %ds", |
| 141 | timeout) |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 142 | session = vm.wait_for_login(nic_index, timeout=timeout) |
lmr | b9cb23f | 2009-10-13 13:38:55 +0000 | [diff] [blame] | 143 | logging.info("Guest is up again") |
| 144 | return session |
| 145 | |
| 146 | |
lmr | 1424f3e | 2010-06-17 13:57:09 +0000 | [diff] [blame] | 147 | def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp", |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 148 | mig_cancel=False, offline=False, stable_check=False, |
| 149 | clean=False, save_path=None, dest_host='localhost', mig_port=None): |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 150 | """ |
| 151 | Migrate a VM locally and re-register it in the environment. |
| 152 | |
| 153 | @param vm: The VM to migrate. |
| 154 | @param env: The environment dictionary. If omitted, the migrated VM will |
| 155 | not be registered. |
lmr | 1424f3e | 2010-06-17 13:57:09 +0000 | [diff] [blame] | 156 | @param mig_timeout: timeout value for migration. |
| 157 | @param mig_protocol: migration protocol |
| 158 | @param mig_cancel: Test migrate_cancel or not when protocol is tcp. |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 159 | @param dest_host: Destination host (defaults to 'localhost'). |
| 160 | @param mig_port: Port that will be used for migration. |
| 161 | @return: The post-migration VM, in case of same host migration, True in |
| 162 | case of multi-host migration. |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 163 | """ |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 164 | def mig_finished(): |
lmr | 9e964a0 | 2010-06-18 03:46:21 +0000 | [diff] [blame] | 165 | o = vm.monitor.info("migrate") |
lmr | 134e20c | 2010-06-18 03:49:34 +0000 | [diff] [blame] | 166 | if isinstance(o, str): |
| 167 | return "status: active" not in o |
| 168 | else: |
| 169 | return o.get("status") != "active" |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 170 | |
| 171 | def mig_succeeded(): |
lmr | 9e964a0 | 2010-06-18 03:46:21 +0000 | [diff] [blame] | 172 | o = vm.monitor.info("migrate") |
lmr | 134e20c | 2010-06-18 03:49:34 +0000 | [diff] [blame] | 173 | if isinstance(o, str): |
| 174 | return "status: completed" in o |
| 175 | else: |
| 176 | return o.get("status") == "completed" |
lmr | 1424f3e | 2010-06-17 13:57:09 +0000 | [diff] [blame] | 177 | |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 178 | def mig_failed(): |
lmr | 9e964a0 | 2010-06-18 03:46:21 +0000 | [diff] [blame] | 179 | o = vm.monitor.info("migrate") |
lmr | 134e20c | 2010-06-18 03:49:34 +0000 | [diff] [blame] | 180 | if isinstance(o, str): |
| 181 | return "status: failed" in o |
| 182 | else: |
| 183 | return o.get("status") == "failed" |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 184 | |
lmr | 9e964a0 | 2010-06-18 03:46:21 +0000 | [diff] [blame] | 185 | def mig_cancelled(): |
| 186 | o = vm.monitor.info("migrate") |
lmr | 134e20c | 2010-06-18 03:49:34 +0000 | [diff] [blame] | 187 | if isinstance(o, str): |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 188 | return ("Migration status: cancelled" in o or |
| 189 | "Migration status: canceled" in o) |
lmr | 134e20c | 2010-06-18 03:49:34 +0000 | [diff] [blame] | 190 | else: |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 191 | return (o.get("status") == "cancelled" or |
| 192 | o.get("status") == "canceled") |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 193 | |
lmr | 9e964a0 | 2010-06-18 03:46:21 +0000 | [diff] [blame] | 194 | def wait_for_migration(): |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 195 | if not virt_utils.wait_for(mig_finished, mig_timeout, 2, 2, |
Dale Curtis | 456d3c1 | 2011-07-19 11:42:51 -0700 | [diff] [blame] | 196 | "Waiting for migration to finish"): |
lmr | 9e964a0 | 2010-06-18 03:46:21 +0000 | [diff] [blame] | 197 | raise error.TestFail("Timeout expired while waiting for migration " |
| 198 | "to finish") |
| 199 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 200 | if dest_host == 'localhost': |
| 201 | dest_vm = vm.clone() |
lmr | 9e964a0 | 2010-06-18 03:46:21 +0000 | [diff] [blame] | 202 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 203 | if (dest_host == 'localhost') and stable_check: |
| 204 | # Pause the dest vm after creation |
| 205 | dest_vm.params['extra_params'] = (dest_vm.params.get('extra_params','') |
| 206 | + ' -S') |
lmr | 1424f3e | 2010-06-17 13:57:09 +0000 | [diff] [blame] | 207 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 208 | if dest_host == 'localhost': |
| 209 | dest_vm.create(migration_mode=mig_protocol, mac_source=vm) |
| 210 | |
| 211 | try: |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 212 | try: |
| 213 | if mig_protocol == "tcp": |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 214 | if dest_host == 'localhost': |
| 215 | uri = "tcp:localhost:%d" % dest_vm.migration_port |
| 216 | else: |
| 217 | uri = 'tcp:%s:%d' % (dest_host, mig_port) |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 218 | elif mig_protocol == "unix": |
| 219 | uri = "unix:%s" % dest_vm.migration_file |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 220 | elif mig_protocol == "exec": |
| 221 | uri = '"exec:nc localhost %s"' % dest_vm.migration_port |
| 222 | |
| 223 | if offline: |
| 224 | vm.monitor.cmd("stop") |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 225 | vm.monitor.migrate(uri) |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 226 | |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 227 | if mig_cancel: |
| 228 | time.sleep(2) |
| 229 | vm.monitor.cmd("migrate_cancel") |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 230 | if not virt_utils.wait_for(mig_cancelled, 60, 2, 2, |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 231 | "Waiting for migration " |
| 232 | "cancellation"): |
| 233 | raise error.TestFail("Failed to cancel migration") |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 234 | if offline: |
| 235 | vm.monitor.cmd("cont") |
| 236 | if dest_host == 'localhost': |
| 237 | dest_vm.destroy(gracefully=False) |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 238 | return vm |
| 239 | else: |
| 240 | wait_for_migration() |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 241 | if (dest_host == 'localhost') and stable_check: |
| 242 | save_path = None or "/tmp" |
| 243 | save1 = os.path.join(save_path, "src") |
| 244 | save2 = os.path.join(save_path, "dst") |
| 245 | |
| 246 | vm.save_to_file(save1) |
| 247 | dest_vm.save_to_file(save2) |
| 248 | |
| 249 | # Fail if we see deltas |
| 250 | md5_save1 = utils.hash_file(save1) |
| 251 | md5_save2 = utils.hash_file(save2) |
| 252 | if md5_save1 != md5_save2: |
| 253 | raise error.TestFail("Mismatch of VM state before " |
| 254 | "and after migration") |
| 255 | |
| 256 | if (dest_host == 'localhost') and offline: |
| 257 | dest_vm.monitor.cmd("cont") |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 258 | except: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 259 | if dest_host == 'localhost': |
| 260 | dest_vm.destroy() |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 261 | raise |
lmr | 9ef2fe6 | 2010-06-23 16:52:16 +0000 | [diff] [blame] | 262 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 263 | finally: |
| 264 | if (dest_host == 'localhost') and stable_check and clean: |
| 265 | logging.debug("Cleaning the state files") |
| 266 | if os.path.isfile(save1): |
| 267 | os.remove(save1) |
| 268 | if os.path.isfile(save2): |
| 269 | os.remove(save2) |
| 270 | |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 271 | # Report migration status |
| 272 | if mig_succeeded(): |
| 273 | logging.info("Migration finished successfully") |
| 274 | elif mig_failed(): |
| 275 | raise error.TestFail("Migration failed") |
| 276 | else: |
| 277 | raise error.TestFail("Migration ended with unknown status") |
lmr | 1424f3e | 2010-06-17 13:57:09 +0000 | [diff] [blame] | 278 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 279 | if dest_host == 'localhost': |
| 280 | if "paused" in dest_vm.monitor.info("status"): |
Dale Curtis | 456d3c1 | 2011-07-19 11:42:51 -0700 | [diff] [blame] | 281 | logging.debug("Destination VM is paused, resuming it") |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 282 | dest_vm.monitor.cmd("cont") |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 283 | |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 284 | # Kill the source VM |
| 285 | vm.destroy(gracefully=False) |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 286 | |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 287 | # Replace the source VM with the new cloned VM |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 288 | if (dest_host == 'localhost') and (env is not None): |
| 289 | env.register_vm(vm.name, dest_vm) |
lmr | 60fc92b | 2009-10-13 13:31:50 +0000 | [diff] [blame] | 290 | |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 291 | # Return the new cloned VM |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 292 | if dest_host == 'localhost': |
| 293 | return dest_vm |
| 294 | else: |
| 295 | return vm |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 296 | |
| 297 | |
| 298 | def stop_windows_service(session, service, timeout=120): |
| 299 | """ |
| 300 | Stop a Windows service using sc. |
| 301 | If the service is already stopped or is not installed, do nothing. |
| 302 | |
| 303 | @param service: The name of the service |
| 304 | @param timeout: Time duration to wait for service to stop |
| 305 | @raise error.TestError: Raised if the service can't be stopped |
| 306 | """ |
| 307 | end_time = time.time() + timeout |
| 308 | while time.time() < end_time: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 309 | o = session.cmd_output("sc stop %s" % service, timeout=60) |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 310 | # FAILED 1060 means the service isn't installed. |
| 311 | # FAILED 1062 means the service hasn't been started. |
| 312 | if re.search(r"\bFAILED (1060|1062)\b", o, re.I): |
| 313 | break |
| 314 | time.sleep(1) |
| 315 | else: |
| 316 | raise error.TestError("Could not stop service '%s'" % service) |
| 317 | |
| 318 | |
| 319 | def start_windows_service(session, service, timeout=120): |
| 320 | """ |
| 321 | Start a Windows service using sc. |
| 322 | If the service is already running, do nothing. |
| 323 | If the service isn't installed, fail. |
| 324 | |
| 325 | @param service: The name of the service |
| 326 | @param timeout: Time duration to wait for service to start |
| 327 | @raise error.TestError: Raised if the service can't be started |
| 328 | """ |
| 329 | end_time = time.time() + timeout |
| 330 | while time.time() < end_time: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 331 | o = session.cmd_output("sc start %s" % service, timeout=60) |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 332 | # FAILED 1060 means the service isn't installed. |
| 333 | if re.search(r"\bFAILED 1060\b", o, re.I): |
| 334 | raise error.TestError("Could not start service '%s' " |
| 335 | "(service not installed)" % service) |
| 336 | # FAILED 1056 means the service is already running. |
| 337 | if re.search(r"\bFAILED 1056\b", o, re.I): |
| 338 | break |
| 339 | time.sleep(1) |
| 340 | else: |
| 341 | raise error.TestError("Could not start service '%s'" % service) |
lmr | aea0d49 | 2009-10-13 13:33:12 +0000 | [diff] [blame] | 342 | |
| 343 | |
| 344 | def get_time(session, time_command, time_filter_re, time_format): |
| 345 | """ |
| 346 | Return the host time and guest time. If the guest time cannot be fetched |
| 347 | a TestError exception is raised. |
| 348 | |
| 349 | Note that the shell session should be ready to receive commands |
| 350 | (i.e. should "display" a command prompt and should be done with all |
| 351 | previous commands). |
| 352 | |
| 353 | @param session: A shell session. |
| 354 | @param time_command: Command to issue to get the current guest time. |
| 355 | @param time_filter_re: Regex filter to apply on the output of |
| 356 | time_command in order to get the current time. |
| 357 | @param time_format: Format string to pass to time.strptime() with the |
| 358 | result of the regex filter. |
| 359 | @return: A tuple containing the host time and guest time. |
| 360 | """ |
Eric Li | 6f27d4f | 2010-09-29 10:55:17 -0700 | [diff] [blame] | 361 | if len(re.findall("ntpdate|w32tm", time_command)) == 0: |
| 362 | host_time = time.time() |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 363 | s = session.cmd_output(time_command) |
lmr | b40e8bb | 2010-06-14 17:32:59 +0000 | [diff] [blame] | 364 | |
Eric Li | 6f27d4f | 2010-09-29 10:55:17 -0700 | [diff] [blame] | 365 | try: |
| 366 | s = re.findall(time_filter_re, s)[0] |
| 367 | except IndexError: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 368 | logging.debug("The time string from guest is:\n%s", s) |
Eric Li | 6f27d4f | 2010-09-29 10:55:17 -0700 | [diff] [blame] | 369 | raise error.TestError("The time string from guest is unexpected.") |
| 370 | except Exception, e: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 371 | logging.debug("(time_filter_re, time_string): (%s, %s)", |
| 372 | time_filter_re, s) |
Eric Li | 6f27d4f | 2010-09-29 10:55:17 -0700 | [diff] [blame] | 373 | raise e |
lmr | b40e8bb | 2010-06-14 17:32:59 +0000 | [diff] [blame] | 374 | |
Eric Li | 6f27d4f | 2010-09-29 10:55:17 -0700 | [diff] [blame] | 375 | guest_time = time.mktime(time.strptime(s, time_format)) |
| 376 | else: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 377 | o = session.cmd(time_command) |
Eric Li | 6f27d4f | 2010-09-29 10:55:17 -0700 | [diff] [blame] | 378 | if re.match('ntpdate', time_command): |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 379 | offset = re.findall('offset (.*) sec', o)[0] |
Eric Li | 6f27d4f | 2010-09-29 10:55:17 -0700 | [diff] [blame] | 380 | host_main, host_mantissa = re.findall(time_filter_re, o)[0] |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 381 | host_time = (time.mktime(time.strptime(host_main, time_format)) + |
| 382 | float("0.%s" % host_mantissa)) |
Dale Curtis | 74a314b | 2011-06-23 14:55:46 -0700 | [diff] [blame] | 383 | guest_time = host_time - float(offset) |
Eric Li | 6f27d4f | 2010-09-29 10:55:17 -0700 | [diff] [blame] | 384 | else: |
| 385 | guest_time = re.findall(time_filter_re, o)[0] |
| 386 | offset = re.findall("o:(.*)s", o)[0] |
| 387 | if re.match('PM', guest_time): |
| 388 | hour = re.findall('\d+ (\d+):', guest_time)[0] |
| 389 | hour = str(int(hour) + 12) |
| 390 | guest_time = re.sub('\d+\s\d+:', "\d+\s%s:" % hour, |
| 391 | guest_time)[:-3] |
| 392 | else: |
| 393 | guest_time = guest_time[:-3] |
| 394 | guest_time = time.mktime(time.strptime(guest_time, time_format)) |
Dale Curtis | 74a314b | 2011-06-23 14:55:46 -0700 | [diff] [blame] | 395 | host_time = guest_time + float(offset) |
Eric Li | 6f27d4f | 2010-09-29 10:55:17 -0700 | [diff] [blame] | 396 | |
lmr | aea0d49 | 2009-10-13 13:33:12 +0000 | [diff] [blame] | 397 | return (host_time, guest_time) |
lmr | 0bee234 | 2010-02-24 00:01:37 +0000 | [diff] [blame] | 398 | |
| 399 | |
| 400 | def get_memory_info(lvms): |
| 401 | """ |
| 402 | Get memory information from host and guests in format: |
| 403 | Host: memfree = XXXM; Guests memsh = {XXX,XXX,...} |
| 404 | |
| 405 | @params lvms: List of VM objects |
| 406 | @return: String with memory info report |
| 407 | """ |
| 408 | if not isinstance(lvms, list): |
| 409 | raise error.TestError("Invalid list passed to get_stat: %s " % lvms) |
| 410 | |
| 411 | try: |
| 412 | meminfo = "Host: memfree = " |
| 413 | meminfo += str(int(utils.freememtotal()) / 1024) + "M; " |
| 414 | meminfo += "swapfree = " |
| 415 | mf = int(utils.read_from_meminfo("SwapFree")) / 1024 |
| 416 | meminfo += str(mf) + "M; " |
| 417 | except Exception, e: |
| 418 | raise error.TestFail("Could not fetch host free memory info, " |
| 419 | "reason: %s" % e) |
| 420 | |
| 421 | meminfo += "Guests memsh = {" |
| 422 | for vm in lvms: |
| 423 | shm = vm.get_shared_meminfo() |
| 424 | if shm is None: |
| 425 | raise error.TestError("Could not get shared meminfo from " |
| 426 | "VM %s" % vm) |
| 427 | meminfo += "%dM; " % shm |
| 428 | meminfo = meminfo[0:-2] + "}" |
| 429 | |
| 430 | return meminfo |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 431 | |
| 432 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 433 | def run_autotest(vm, session, control_path, timeout, outputdir, params): |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 434 | """ |
| 435 | Run an autotest control file inside a guest (linux only utility). |
| 436 | |
| 437 | @param vm: VM object. |
| 438 | @param session: A shell session on the VM provided. |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 439 | @param control_path: A path to an autotest control file. |
| 440 | @param timeout: Timeout under which the autotest control file must complete. |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 441 | @param outputdir: Path on host where we should copy the guest autotest |
| 442 | results to. |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 443 | |
| 444 | The following params is used by the migration |
| 445 | @param params: Test params used in the migration test |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 446 | """ |
lmr | 63ef61d | 2010-04-17 17:57:41 +0000 | [diff] [blame] | 447 | def copy_if_hash_differs(vm, local_path, remote_path): |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 448 | """ |
lmr | 63ef61d | 2010-04-17 17:57:41 +0000 | [diff] [blame] | 449 | Copy a file to a guest if it doesn't exist or if its MD5sum differs. |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 450 | |
| 451 | @param vm: VM object. |
| 452 | @param local_path: Local path. |
| 453 | @param remote_path: Remote path. |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 454 | |
| 455 | @return: Whether the hash differs (True) or not (False). |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 456 | """ |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 457 | hash_differs = False |
lmr | 63ef61d | 2010-04-17 17:57:41 +0000 | [diff] [blame] | 458 | local_hash = utils.hash_file(local_path) |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 459 | basename = os.path.basename(local_path) |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 460 | output = session.cmd_output("md5sum %s" % remote_path) |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 461 | if "such file" in output: |
lmr | 63ef61d | 2010-04-17 17:57:41 +0000 | [diff] [blame] | 462 | remote_hash = "0" |
| 463 | elif output: |
| 464 | remote_hash = output.split()[0] |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 465 | else: |
lmr | 63ef61d | 2010-04-17 17:57:41 +0000 | [diff] [blame] | 466 | logging.warning("MD5 check for remote path %s did not return.", |
| 467 | remote_path) |
| 468 | # Let's be a little more lenient here and see if it wasn't a |
| 469 | # temporary problem |
| 470 | remote_hash = "0" |
lmr | 63ef61d | 2010-04-17 17:57:41 +0000 | [diff] [blame] | 471 | if remote_hash != local_hash: |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 472 | hash_differs = True |
| 473 | logging.debug("Copying %s to guest " |
| 474 | "(remote hash: %s, local hash:%s)", |
| 475 | basename, remote_hash, local_hash) |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 476 | vm.copy_files_to(local_path, remote_path) |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 477 | return hash_differs |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 478 | |
| 479 | |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 480 | def extract(vm, remote_path, dest_dir): |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 481 | """ |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 482 | Extract the autotest .tar.bz2 file on the guest, ensuring the final |
| 483 | destination path will be dest_dir. |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 484 | |
| 485 | @param vm: VM object |
| 486 | @param remote_path: Remote file path |
| 487 | @param dest_dir: Destination dir for the contents |
| 488 | """ |
| 489 | basename = os.path.basename(remote_path) |
Dale Curtis | 456d3c1 | 2011-07-19 11:42:51 -0700 | [diff] [blame] | 490 | logging.debug("Extracting %s on VM %s", basename, vm.name) |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 491 | session.cmd("rm -rf %s" % dest_dir) |
| 492 | dirname = os.path.dirname(remote_path) |
| 493 | session.cmd("cd %s" % dirname) |
| 494 | session.cmd("mkdir -p %s" % os.path.dirname(dest_dir)) |
| 495 | e_cmd = "tar xjvf %s -C %s" % (basename, os.path.dirname(dest_dir)) |
| 496 | output = session.cmd(e_cmd, timeout=120) |
| 497 | autotest_dirname = "" |
| 498 | for line in output.splitlines(): |
| 499 | autotest_dirname = line.split("/")[0] |
| 500 | break |
| 501 | if autotest_dirname != os.path.basename(dest_dir): |
| 502 | session.cmd("cd %s" % os.path.dirname(dest_dir)) |
| 503 | session.cmd("mv %s %s" % |
| 504 | (autotest_dirname, os.path.basename(dest_dir))) |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 505 | |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 506 | |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 507 | def get_results(guest_autotest_path): |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 508 | """ |
| 509 | Copy autotest results present on the guest back to the host. |
| 510 | """ |
Dale Curtis | 456d3c1 | 2011-07-19 11:42:51 -0700 | [diff] [blame] | 511 | logging.debug("Trying to copy autotest results from guest") |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 512 | guest_results_dir = os.path.join(outputdir, "guest_autotest_results") |
| 513 | if not os.path.exists(guest_results_dir): |
| 514 | os.mkdir(guest_results_dir) |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 515 | vm.copy_files_from("%s/results/default/*" % guest_autotest_path, |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 516 | guest_results_dir) |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 517 | |
| 518 | |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 519 | def get_results_summary(guest_autotest_path): |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 520 | """ |
| 521 | Get the status of the tests that were executed on the host and close |
| 522 | the session where autotest was being executed. |
| 523 | """ |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 524 | session.cmd("cd %s" % guest_autotest_path) |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 525 | output = session.cmd_output("cat results/*/status") |
lmr | 63ef61d | 2010-04-17 17:57:41 +0000 | [diff] [blame] | 526 | try: |
| 527 | results = scan_results.parse_results(output) |
| 528 | # Report test results |
| 529 | logging.info("Results (test, status, duration, info):") |
| 530 | for result in results: |
| 531 | logging.info(str(result)) |
| 532 | session.close() |
| 533 | return results |
| 534 | except Exception, e: |
| 535 | logging.error("Error processing guest autotest results: %s", e) |
| 536 | return None |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 537 | |
| 538 | |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 539 | if not os.path.isfile(control_path): |
| 540 | raise error.TestError("Invalid path to autotest control file: %s" % |
| 541 | control_path) |
| 542 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 543 | migrate_background = params.get("migrate_background") == "yes" |
| 544 | if migrate_background: |
| 545 | mig_timeout = float(params.get("mig_timeout", "3600")) |
| 546 | mig_protocol = params.get("migration_protocol", "tcp") |
| 547 | |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 548 | compressed_autotest_path = "/tmp/autotest.tar.bz2" |
| 549 | destination_autotest_path = "/usr/local/autotest" |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 550 | |
| 551 | # To avoid problems, let's make the test use the current AUTODIR |
| 552 | # (autotest client path) location |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 553 | autotest_path = os.environ['AUTODIR'] |
| 554 | autotest_basename = os.path.basename(autotest_path) |
| 555 | autotest_parentdir = os.path.dirname(autotest_path) |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 556 | |
| 557 | # tar the contents of bindir/autotest |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 558 | cmd = ("cd %s; tar cvjf %s %s/*" % |
| 559 | (autotest_parentdir, compressed_autotest_path, autotest_basename)) |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 560 | # Until we have nested virtualization, we don't need the kvm test :) |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 561 | cmd += " --exclude=%s/tests/kvm" % autotest_basename |
| 562 | cmd += " --exclude=%s/results" % autotest_basename |
| 563 | cmd += " --exclude=%s/tmp" % autotest_basename |
| 564 | cmd += " --exclude=%s/control*" % autotest_basename |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 565 | cmd += " --exclude=*.pyc" |
| 566 | cmd += " --exclude=*.svn" |
| 567 | cmd += " --exclude=*.git" |
| 568 | utils.run(cmd) |
| 569 | |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 570 | # Copy autotest.tar.bz2 |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 571 | update = copy_if_hash_differs(vm, compressed_autotest_path, |
| 572 | compressed_autotest_path) |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 573 | |
| 574 | # Extract autotest.tar.bz2 |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 575 | if update: |
| 576 | extract(vm, compressed_autotest_path, destination_autotest_path) |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 577 | |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 578 | vm.copy_files_to(control_path, |
| 579 | os.path.join(destination_autotest_path, 'control')) |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 580 | |
| 581 | # Run the test |
lmr | 63ef61d | 2010-04-17 17:57:41 +0000 | [diff] [blame] | 582 | logging.info("Running autotest control file %s on guest, timeout %ss", |
| 583 | os.path.basename(control_path), timeout) |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 584 | session.cmd("cd %s" % destination_autotest_path) |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 585 | try: |
| 586 | session.cmd("rm -f control.state") |
| 587 | session.cmd("rm -rf results/*") |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 588 | except aexpect.ShellError: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 589 | pass |
| 590 | try: |
| 591 | bg = None |
| 592 | try: |
| 593 | logging.info("---------------- Test output ----------------") |
| 594 | if migrate_background: |
| 595 | mig_timeout = float(params.get("mig_timeout", "3600")) |
| 596 | mig_protocol = params.get("migration_protocol", "tcp") |
| 597 | |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 598 | bg = virt_utils.Thread(session.cmd_output, |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 599 | kwargs={'cmd': "bin/autotest control", |
| 600 | 'timeout': timeout, |
| 601 | 'print_func': logging.info}) |
| 602 | |
| 603 | bg.start() |
| 604 | |
| 605 | while bg.is_alive(): |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 606 | logging.info("Autotest job did not end, start a round of " |
Dale Curtis | 456d3c1 | 2011-07-19 11:42:51 -0700 | [diff] [blame] | 607 | "migration") |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 608 | vm.migrate(timeout=mig_timeout, protocol=mig_protocol) |
| 609 | else: |
| 610 | session.cmd_output("bin/autotest control", timeout=timeout, |
| 611 | print_func=logging.info) |
| 612 | finally: |
| 613 | logging.info("------------- End of test output ------------") |
| 614 | if migrate_background and bg: |
| 615 | bg.join() |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 616 | except aexpect.ShellTimeoutError: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 617 | if vm.is_alive(): |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 618 | get_results(destination_autotest_path) |
| 619 | get_results_summary(destination_autotest_path) |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 620 | raise error.TestError("Timeout elapsed while waiting for job to " |
| 621 | "complete") |
| 622 | else: |
lmr | 63ef61d | 2010-04-17 17:57:41 +0000 | [diff] [blame] | 623 | raise error.TestError("Autotest job on guest failed " |
| 624 | "(VM terminated during job)") |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 625 | except aexpect.ShellProcessTerminatedError: |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 626 | get_results(destination_autotest_path) |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 627 | raise error.TestError("Autotest job on guest failed " |
| 628 | "(Remote session terminated during job)") |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 629 | |
Dale Curtis | 8adf789 | 2011-09-08 16:13:36 -0700 | [diff] [blame] | 630 | results = get_results_summary(destination_autotest_path) |
| 631 | get_results(destination_autotest_path) |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 632 | |
| 633 | # Make a list of FAIL/ERROR/ABORT results (make sure FAIL results appear |
| 634 | # before ERROR results, and ERROR results appear before ABORT results) |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 635 | bad_results = [r[0] for r in results if r[1] == "FAIL"] |
| 636 | bad_results += [r[0] for r in results if r[1] == "ERROR"] |
| 637 | bad_results += [r[0] for r in results if r[1] == "ABORT"] |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 638 | |
| 639 | # Fail the test if necessary |
| 640 | if not results: |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 641 | raise error.TestFail("Autotest control file run did not produce any " |
| 642 | "recognizable results") |
lmr | 3c11f25 | 2010-03-17 13:00:07 +0000 | [diff] [blame] | 643 | if bad_results: |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 644 | if len(bad_results) == 1: |
lmr | 63ef61d | 2010-04-17 17:57:41 +0000 | [diff] [blame] | 645 | e_msg = ("Test %s failed during control file execution" % |
| 646 | bad_results[0]) |
lmr | ce013d6 | 2010-04-15 00:01:17 +0000 | [diff] [blame] | 647 | else: |
| 648 | e_msg = ("Tests %s failed during control file execution" % |
| 649 | " ".join(bad_results)) |
| 650 | raise error.TestFail(e_msg) |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 651 | |
| 652 | |
| 653 | def get_loss_ratio(output): |
| 654 | """ |
| 655 | Get the packet loss ratio from the output of ping |
| 656 | . |
| 657 | @param output: Ping output. |
| 658 | """ |
| 659 | try: |
| 660 | return int(re.findall('(\d+)% packet loss', output)[0]) |
| 661 | except IndexError: |
| 662 | logging.debug(output) |
| 663 | return -1 |
| 664 | |
| 665 | |
| 666 | def raw_ping(command, timeout, session, output_func): |
| 667 | """ |
| 668 | Low-level ping command execution. |
| 669 | |
| 670 | @param command: Ping command. |
| 671 | @param timeout: Timeout of the ping command. |
| 672 | @param session: Local executon hint or session to execute the ping command. |
| 673 | """ |
| 674 | if session is None: |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 675 | process = aexpect.run_bg(command, output_func=output_func, |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 676 | timeout=timeout) |
| 677 | |
| 678 | # Send SIGINT signal to notify the timeout of running ping process, |
| 679 | # Because ping have the ability to catch the SIGINT signal so we can |
| 680 | # always get the packet loss ratio even if timeout. |
| 681 | if process.is_alive(): |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 682 | virt_utils.kill_process_tree(process.get_pid(), signal.SIGINT) |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 683 | |
| 684 | status = process.get_status() |
| 685 | output = process.get_output() |
| 686 | |
| 687 | process.close() |
| 688 | return status, output |
| 689 | else: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 690 | output = "" |
| 691 | try: |
| 692 | output = session.cmd_output(command, timeout=timeout, |
| 693 | print_func=output_func) |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 694 | except aexpect.ShellTimeoutError: |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 695 | # Send ctrl+c (SIGINT) through ssh session |
| 696 | session.send("\003") |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 697 | try: |
| 698 | output2 = session.read_up_to_prompt(print_func=output_func) |
| 699 | output += output2 |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 700 | except aexpect.ExpectTimeoutError, e: |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 701 | output += e.output |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 702 | # We also need to use this session to query the return value |
| 703 | session.send("\003") |
| 704 | |
| 705 | session.sendline(session.status_test_command) |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 706 | try: |
| 707 | o2 = session.read_up_to_prompt() |
Eric Li | 22434d4 | 2011-04-28 15:17:19 -0700 | [diff] [blame] | 708 | except aexpect.ExpectError: |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 709 | status = -1 |
| 710 | else: |
| 711 | try: |
| 712 | status = int(re.findall("\d+", o2)[0]) |
| 713 | except: |
| 714 | status = -1 |
| 715 | |
| 716 | return status, output |
| 717 | |
| 718 | |
| 719 | def ping(dest=None, count=None, interval=None, interface=None, |
| 720 | packetsize=None, ttl=None, hint=None, adaptive=False, |
| 721 | broadcast=False, flood=False, timeout=0, |
| 722 | output_func=logging.debug, session=None): |
| 723 | """ |
| 724 | Wrapper of ping. |
| 725 | |
| 726 | @param dest: Destination address. |
| 727 | @param count: Count of icmp packet. |
| 728 | @param interval: Interval of two icmp echo request. |
| 729 | @param interface: Specified interface of the source address. |
| 730 | @param packetsize: Packet size of icmp. |
| 731 | @param ttl: IP time to live. |
| 732 | @param hint: Path mtu discovery hint. |
| 733 | @param adaptive: Adaptive ping flag. |
| 734 | @param broadcast: Broadcast ping flag. |
| 735 | @param flood: Flood ping flag. |
| 736 | @param timeout: Timeout for the ping command. |
| 737 | @param output_func: Function used to log the result of ping. |
| 738 | @param session: Local executon hint or session to execute the ping command. |
| 739 | """ |
| 740 | if dest is not None: |
| 741 | command = "ping %s " % dest |
| 742 | else: |
| 743 | command = "ping localhost " |
| 744 | if count is not None: |
| 745 | command += " -c %s" % count |
| 746 | if interval is not None: |
| 747 | command += " -i %s" % interval |
| 748 | if interface is not None: |
| 749 | command += " -I %s" % interface |
| 750 | if packetsize is not None: |
| 751 | command += " -s %s" % packetsize |
| 752 | if ttl is not None: |
| 753 | command += " -t %s" % ttl |
| 754 | if hint is not None: |
| 755 | command += " -M %s" % hint |
| 756 | if adaptive: |
| 757 | command += " -A" |
| 758 | if broadcast: |
| 759 | command += " -b" |
| 760 | if flood: |
| 761 | command += " -f -q" |
| 762 | output_func = None |
| 763 | |
| 764 | return raw_ping(command, timeout, session, output_func) |
| 765 | |
| 766 | |
| 767 | def get_linux_ifname(session, mac_address): |
| 768 | """ |
| 769 | Get the interface name through the mac address. |
| 770 | |
| 771 | @param session: session to the virtual machine |
| 772 | @mac_address: the macaddress of nic |
| 773 | """ |
| 774 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame] | 775 | output = session.cmd_output("ifconfig -a") |
Eric Li | e0493a4 | 2010-11-15 13:05:43 -0800 | [diff] [blame] | 776 | |
| 777 | try: |
| 778 | ethname = re.findall("(\w+)\s+Link.*%s" % mac_address, output, |
| 779 | re.IGNORECASE)[0] |
| 780 | return ethname |
| 781 | except: |
| 782 | return None |