| OLD | NEW |
| 1 """ | 1 """ |
| 2 High-level KVM test utility functions. | 2 High-level KVM test utility functions. |
| 3 | 3 |
| 4 This module is meant to reduce code size by performing common test procedures. | 4 This module is meant to reduce code size by performing common test procedures. |
| 5 Generally, code here should look like test code. | 5 Generally, code here should look like test code. |
| 6 More specifically: | 6 More specifically: |
| 7 - Functions in this module should raise exceptions if things go wrong | 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 | 8 (unlike functions in kvm_utils.py and kvm_vm.py which report failure via |
| 9 their returned values). | 9 their returned values). |
| 10 - Functions in this module may use logging.info(), in addition to | 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 | 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 | 12 interested in (unlike kvm_utils.py and kvm_vm.py which use |
| 13 logging.debug() for anything that isn't an error). | 13 logging.debug() for anything that isn't an error). |
| 14 - Functions in this module typically use functions and classes from | 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). | 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. | 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. | 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 | 18 For example, a function should not be used where it may display |
| 19 misleading or inaccurate info or debug messages. | 19 misleading or inaccurate info or debug messages. |
| 20 | 20 |
| 21 @copyright: 2008-2009 Red Hat Inc. | 21 @copyright: 2008-2009 Red Hat Inc. |
| 22 """ | 22 """ |
| 23 | 23 |
| 24 import time, os, logging, re, commands, signal, threading | 24 import time, os, logging, re, commands, signal |
| 25 from autotest_lib.client.common_lib import error | 25 from autotest_lib.client.common_lib import error |
| 26 from autotest_lib.client.bin import utils | 26 from autotest_lib.client.bin import utils |
| 27 import kvm_utils, kvm_vm, kvm_subprocess, scan_results | 27 import kvm_utils, kvm_vm, kvm_subprocess, scan_results |
| 28 | 28 |
| 29 | 29 |
| 30 def get_living_vm(env, vm_name): | 30 def get_living_vm(env, vm_name): |
| 31 """ | 31 """ |
| 32 Get a VM object from the environment and make sure it's alive. | 32 Get a VM object from the environment and make sure it's alive. |
| 33 | 33 |
| 34 @param env: Dictionary with test environment. | 34 @param env: Dictionary with test environment. |
| 35 @param vm_name: Name of the desired VM object. | 35 @param vm_name: Name of the desired VM object. |
| 36 @return: A VM object. | 36 @return: A VM object. |
| 37 """ | 37 """ |
| 38 vm = env.get_vm(vm_name) | 38 vm = kvm_utils.env_get_vm(env, vm_name) |
| 39 if not vm: | 39 if not vm: |
| 40 raise error.TestError("VM '%s' not found in environment" % vm_name) | 40 raise error.TestError("VM '%s' not found in environment" % vm_name) |
| 41 if not vm.is_alive(): | 41 if not vm.is_alive(): |
| 42 raise error.TestError("VM '%s' seems to be dead; test requires a " | 42 raise error.TestError("VM '%s' seems to be dead; test requires a " |
| 43 "living VM" % vm_name) | 43 "living VM" % vm_name) |
| 44 return vm | 44 return vm |
| 45 | 45 |
| 46 | 46 |
| 47 def wait_for_login(vm, nic_index=0, timeout=240, start=0, step=2, serial=None): | 47 def wait_for_login(vm, nic_index=0, timeout=240, start=0, step=2): |
| 48 """ | 48 """ |
| 49 Try logging into a VM repeatedly. Stop on success or when timeout expires. | 49 Try logging into a VM repeatedly. Stop on success or when timeout expires. |
| 50 | 50 |
| 51 @param vm: VM object. | 51 @param vm: VM object. |
| 52 @param nic_index: Index of NIC to access in the VM. | 52 @param nic_index: Index of NIC to access in the VM. |
| 53 @param timeout: Time to wait before giving up. | 53 @param timeout: Time to wait before giving up. |
| 54 @param serial: Whether to use a serial connection instead of a remote | |
| 55 (ssh, rss) one. | |
| 56 @return: A shell session object. | 54 @return: A shell session object. |
| 57 """ | 55 """ |
| 58 type = 'remote' | 56 logging.info("Trying to log into guest '%s', timeout %ds", vm.name, timeout) |
| 59 if serial: | 57 session = kvm_utils.wait_for(lambda: vm.remote_login(nic_index=nic_index), |
| 60 type = 'serial' | 58 timeout, start, step) |
| 61 logging.info("Trying to log into guest %s using serial connection," | |
| 62 " timeout %ds", vm.name, timeout) | |
| 63 session = kvm_utils.wait_for(lambda: vm.serial_login(), timeout, | |
| 64 start, step) | |
| 65 else: | |
| 66 logging.info("Trying to log into guest %s using remote connection," | |
| 67 " timeout %ds", vm.name, timeout) | |
| 68 session = kvm_utils.wait_for(lambda: vm.remote_login( | |
| 69 nic_index=nic_index), timeout, start, step) | |
| 70 if not session: | 59 if not session: |
| 71 raise error.TestFail("Could not log into guest %s using %s connection" % | 60 raise error.TestFail("Could not log into guest '%s'" % vm.name) |
| 72 (vm.name, type)) | 61 logging.info("Logged into guest '%s'" % vm.name) |
| 73 logging.info("Logged into guest %s using %s connection", vm.name, type) | |
| 74 return session | 62 return session |
| 75 | 63 |
| 76 | 64 |
| 77 def reboot(vm, session, method="shell", sleep_before_reset=10, nic_index=0, | 65 def reboot(vm, session, method="shell", sleep_before_reset=10, nic_index=0, |
| 78 timeout=240): | 66 timeout=240): |
| 79 """ | 67 """ |
| 80 Reboot the VM and wait for it to come back up by trying to log in until | 68 Reboot the VM and wait for it to come back up by trying to log in until |
| 81 timeout expires. | 69 timeout expires. |
| 82 | 70 |
| 83 @param vm: VM object. | 71 @param vm: VM object. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 timeout) | 114 timeout) |
| 127 session = kvm_utils.wait_for(lambda: vm.remote_login(nic_index=nic_index), | 115 session = kvm_utils.wait_for(lambda: vm.remote_login(nic_index=nic_index), |
| 128 timeout, 0, 2) | 116 timeout, 0, 2) |
| 129 if not session: | 117 if not session: |
| 130 raise error.TestFail("Could not log into guest after reboot") | 118 raise error.TestFail("Could not log into guest after reboot") |
| 131 logging.info("Guest is up again") | 119 logging.info("Guest is up again") |
| 132 return session | 120 return session |
| 133 | 121 |
| 134 | 122 |
| 135 def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp", | 123 def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp", |
| 136 mig_cancel=False, offline=False, stable_check=False, | 124 mig_cancel=False): |
| 137 clean=False, save_path=None, dest_host='localhost', mig_port=None): | |
| 138 """ | 125 """ |
| 139 Migrate a VM locally and re-register it in the environment. | 126 Migrate a VM locally and re-register it in the environment. |
| 140 | 127 |
| 141 @param vm: The VM to migrate. | 128 @param vm: The VM to migrate. |
| 142 @param env: The environment dictionary. If omitted, the migrated VM will | 129 @param env: The environment dictionary. If omitted, the migrated VM will |
| 143 not be registered. | 130 not be registered. |
| 144 @param mig_timeout: timeout value for migration. | 131 @param mig_timeout: timeout value for migration. |
| 145 @param mig_protocol: migration protocol | 132 @param mig_protocol: migration protocol |
| 146 @param mig_cancel: Test migrate_cancel or not when protocol is tcp. | 133 @param mig_cancel: Test migrate_cancel or not when protocol is tcp. |
| 147 @param dest_host: Destination host (defaults to 'localhost'). | 134 @return: The post-migration VM. |
| 148 @param mig_port: Port that will be used for migration. | |
| 149 @return: The post-migration VM, in case of same host migration, True in | |
| 150 case of multi-host migration. | |
| 151 """ | 135 """ |
| 152 def mig_finished(): | 136 def mig_finished(): |
| 153 o = vm.monitor.info("migrate") | 137 o = vm.monitor.info("migrate") |
| 154 if isinstance(o, str): | 138 if isinstance(o, str): |
| 155 return "status: active" not in o | 139 return "status: active" not in o |
| 156 else: | 140 else: |
| 157 return o.get("status") != "active" | 141 return o.get("status") != "active" |
| 158 | 142 |
| 159 def mig_succeeded(): | 143 def mig_succeeded(): |
| 160 o = vm.monitor.info("migrate") | 144 o = vm.monitor.info("migrate") |
| (...skipping 17 matching lines...) Expand all Loading... |
| 178 else: | 162 else: |
| 179 return (o.get("status") == "cancelled" or | 163 return (o.get("status") == "cancelled" or |
| 180 o.get("status") == "canceled") | 164 o.get("status") == "canceled") |
| 181 | 165 |
| 182 def wait_for_migration(): | 166 def wait_for_migration(): |
| 183 if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2, | 167 if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2, |
| 184 "Waiting for migration to finish..."): | 168 "Waiting for migration to finish..."): |
| 185 raise error.TestFail("Timeout expired while waiting for migration " | 169 raise error.TestFail("Timeout expired while waiting for migration " |
| 186 "to finish") | 170 "to finish") |
| 187 | 171 |
| 188 if dest_host == 'localhost': | 172 dest_vm = vm.clone() |
| 189 dest_vm = vm.clone() | |
| 190 | 173 |
| 191 if (dest_host == 'localhost') and stable_check: | 174 if mig_protocol == "exec": |
| 192 # Pause the dest vm after creation | 175 # Exec is a little different from other migrate methods - first we |
| 193 dest_vm.params['extra_params'] = (dest_vm.params.get('extra_params','') | 176 # ask the monitor the migration, then the vm state is dumped to a |
| 194 + ' -S') | 177 # compressed file, then we start the dest vm with -incoming pointing |
| 178 # to it |
| 179 try: |
| 180 exec_file = "/tmp/exec-%s.gz" % kvm_utils.generate_random_string(8) |
| 181 exec_cmd = "gzip -c -d %s" % exec_file |
| 182 uri = '"exec:gzip -c > %s"' % exec_file |
| 183 vm.monitor.cmd("stop") |
| 184 vm.monitor.migrate(uri) |
| 185 wait_for_migration() |
| 195 | 186 |
| 196 if dest_host == 'localhost': | 187 if not dest_vm.create(migration_mode=mig_protocol, |
| 188 migration_exec_cmd=exec_cmd, mac_source=vm): |
| 189 raise error.TestError("Could not create dest VM") |
| 190 finally: |
| 191 logging.debug("Removing migration file %s", exec_file) |
| 192 try: |
| 193 os.remove(exec_file) |
| 194 except OSError: |
| 195 pass |
| 196 else: |
| 197 if not dest_vm.create(migration_mode=mig_protocol, mac_source=vm): | 197 if not dest_vm.create(migration_mode=mig_protocol, mac_source=vm): |
| 198 raise error.TestError("Could not create dest VM") | 198 raise error.TestError("Could not create dest VM") |
| 199 | |
| 200 try: | |
| 201 try: | 199 try: |
| 202 if mig_protocol == "tcp": | 200 if mig_protocol == "tcp": |
| 203 if dest_host == 'localhost': | 201 uri = "tcp:localhost:%d" % dest_vm.migration_port |
| 204 uri = "tcp:localhost:%d" % dest_vm.migration_port | |
| 205 else: | |
| 206 uri = 'tcp:%s:%d' % (dest_host, mig_port) | |
| 207 elif mig_protocol == "unix": | 202 elif mig_protocol == "unix": |
| 208 uri = "unix:%s" % dest_vm.migration_file | 203 uri = "unix:%s" % dest_vm.migration_file |
| 209 elif mig_protocol == "exec": | |
| 210 uri = '"exec:nc localhost %s"' % dest_vm.migration_port | |
| 211 | |
| 212 if offline: | |
| 213 vm.monitor.cmd("stop") | |
| 214 vm.monitor.migrate(uri) | 204 vm.monitor.migrate(uri) |
| 215 | 205 |
| 216 if mig_cancel: | 206 if mig_cancel: |
| 217 time.sleep(2) | 207 time.sleep(2) |
| 218 vm.monitor.cmd("migrate_cancel") | 208 vm.monitor.cmd("migrate_cancel") |
| 219 if not kvm_utils.wait_for(mig_cancelled, 60, 2, 2, | 209 if not kvm_utils.wait_for(mig_cancelled, 60, 2, 2, |
| 220 "Waiting for migration " | 210 "Waiting for migration " |
| 221 "cancellation"): | 211 "cancellation"): |
| 222 raise error.TestFail("Failed to cancel migration") | 212 raise error.TestFail("Failed to cancel migration") |
| 223 if offline: | 213 dest_vm.destroy(gracefully=False) |
| 224 vm.monitor.cmd("cont") | |
| 225 if dest_host == 'localhost': | |
| 226 dest_vm.destroy(gracefully=False) | |
| 227 return vm | 214 return vm |
| 228 else: | 215 else: |
| 229 wait_for_migration() | 216 wait_for_migration() |
| 230 if (dest_host == 'localhost') and stable_check: | |
| 231 save_path = None or "/tmp" | |
| 232 save1 = os.path.join(save_path, "src") | |
| 233 save2 = os.path.join(save_path, "dst") | |
| 234 | |
| 235 vm.save_to_file(save1) | |
| 236 dest_vm.save_to_file(save2) | |
| 237 | |
| 238 # Fail if we see deltas | |
| 239 md5_save1 = utils.hash_file(save1) | |
| 240 md5_save2 = utils.hash_file(save2) | |
| 241 if md5_save1 != md5_save2: | |
| 242 raise error.TestFail("Mismatch of VM state before " | |
| 243 "and after migration") | |
| 244 | |
| 245 if (dest_host == 'localhost') and offline: | |
| 246 dest_vm.monitor.cmd("cont") | |
| 247 except: | 217 except: |
| 248 if dest_host == 'localhost': | 218 dest_vm.destroy() |
| 249 dest_vm.destroy() | |
| 250 raise | 219 raise |
| 251 | 220 |
| 252 finally: | |
| 253 if (dest_host == 'localhost') and stable_check and clean: | |
| 254 logging.debug("Cleaning the state files") | |
| 255 if os.path.isfile(save1): | |
| 256 os.remove(save1) | |
| 257 if os.path.isfile(save2): | |
| 258 os.remove(save2) | |
| 259 | |
| 260 # Report migration status | 221 # Report migration status |
| 261 if mig_succeeded(): | 222 if mig_succeeded(): |
| 262 logging.info("Migration finished successfully") | 223 logging.info("Migration finished successfully") |
| 263 elif mig_failed(): | 224 elif mig_failed(): |
| 264 raise error.TestFail("Migration failed") | 225 raise error.TestFail("Migration failed") |
| 265 else: | 226 else: |
| 266 raise error.TestFail("Migration ended with unknown status") | 227 raise error.TestFail("Migration ended with unknown status") |
| 267 | 228 |
| 268 if dest_host == 'localhost': | 229 if "paused" in dest_vm.monitor.info("status"): |
| 269 if "paused" in dest_vm.monitor.info("status"): | 230 logging.debug("Destination VM is paused, resuming it...") |
| 270 logging.debug("Destination VM is paused, resuming it...") | 231 dest_vm.monitor.cmd("cont") |
| 271 dest_vm.monitor.cmd("cont") | |
| 272 | 232 |
| 273 # Kill the source VM | 233 # Kill the source VM |
| 274 vm.destroy(gracefully=False) | 234 vm.destroy(gracefully=False) |
| 275 | 235 |
| 276 # Replace the source VM with the new cloned VM | 236 # Replace the source VM with the new cloned VM |
| 277 if (dest_host == 'localhost') and (env is not None): | 237 if env is not None: |
| 278 env.register_vm(vm.name, dest_vm) | 238 kvm_utils.env_register_vm(env, vm.name, dest_vm) |
| 279 | 239 |
| 280 # Return the new cloned VM | 240 # Return the new cloned VM |
| 281 if dest_host == 'localhost': | 241 return dest_vm |
| 282 return dest_vm | |
| 283 else: | |
| 284 return vm | |
| 285 | 242 |
| 286 | 243 |
| 287 def stop_windows_service(session, service, timeout=120): | 244 def stop_windows_service(session, service, timeout=120): |
| 288 """ | 245 """ |
| 289 Stop a Windows service using sc. | 246 Stop a Windows service using sc. |
| 290 If the service is already stopped or is not installed, do nothing. | 247 If the service is already stopped or is not installed, do nothing. |
| 291 | 248 |
| 292 @param service: The name of the service | 249 @param service: The name of the service |
| 293 @param timeout: Time duration to wait for service to stop | 250 @param timeout: Time duration to wait for service to stop |
| 294 @raise error.TestError: Raised if the service can't be stopped | 251 @raise error.TestError: Raised if the service can't be stopped |
| 295 """ | 252 """ |
| 296 end_time = time.time() + timeout | 253 end_time = time.time() + timeout |
| 297 while time.time() < end_time: | 254 while time.time() < end_time: |
| 298 o = session.cmd_output("sc stop %s" % service, timeout=60) | 255 o = session.get_command_output("sc stop %s" % service, timeout=60) |
| 299 # FAILED 1060 means the service isn't installed. | 256 # FAILED 1060 means the service isn't installed. |
| 300 # FAILED 1062 means the service hasn't been started. | 257 # FAILED 1062 means the service hasn't been started. |
| 301 if re.search(r"\bFAILED (1060|1062)\b", o, re.I): | 258 if re.search(r"\bFAILED (1060|1062)\b", o, re.I): |
| 302 break | 259 break |
| 303 time.sleep(1) | 260 time.sleep(1) |
| 304 else: | 261 else: |
| 305 raise error.TestError("Could not stop service '%s'" % service) | 262 raise error.TestError("Could not stop service '%s'" % service) |
| 306 | 263 |
| 307 | 264 |
| 308 def start_windows_service(session, service, timeout=120): | 265 def start_windows_service(session, service, timeout=120): |
| 309 """ | 266 """ |
| 310 Start a Windows service using sc. | 267 Start a Windows service using sc. |
| 311 If the service is already running, do nothing. | 268 If the service is already running, do nothing. |
| 312 If the service isn't installed, fail. | 269 If the service isn't installed, fail. |
| 313 | 270 |
| 314 @param service: The name of the service | 271 @param service: The name of the service |
| 315 @param timeout: Time duration to wait for service to start | 272 @param timeout: Time duration to wait for service to start |
| 316 @raise error.TestError: Raised if the service can't be started | 273 @raise error.TestError: Raised if the service can't be started |
| 317 """ | 274 """ |
| 318 end_time = time.time() + timeout | 275 end_time = time.time() + timeout |
| 319 while time.time() < end_time: | 276 while time.time() < end_time: |
| 320 o = session.cmd_output("sc start %s" % service, timeout=60) | 277 o = session.get_command_output("sc start %s" % service, timeout=60) |
| 321 # FAILED 1060 means the service isn't installed. | 278 # FAILED 1060 means the service isn't installed. |
| 322 if re.search(r"\bFAILED 1060\b", o, re.I): | 279 if re.search(r"\bFAILED 1060\b", o, re.I): |
| 323 raise error.TestError("Could not start service '%s' " | 280 raise error.TestError("Could not start service '%s' " |
| 324 "(service not installed)" % service) | 281 "(service not installed)" % service) |
| 325 # FAILED 1056 means the service is already running. | 282 # FAILED 1056 means the service is already running. |
| 326 if re.search(r"\bFAILED 1056\b", o, re.I): | 283 if re.search(r"\bFAILED 1056\b", o, re.I): |
| 327 break | 284 break |
| 328 time.sleep(1) | 285 time.sleep(1) |
| 329 else: | 286 else: |
| 330 raise error.TestError("Could not start service '%s'" % service) | 287 raise error.TestError("Could not start service '%s'" % service) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 342 @param session: A shell session. | 299 @param session: A shell session. |
| 343 @param time_command: Command to issue to get the current guest time. | 300 @param time_command: Command to issue to get the current guest time. |
| 344 @param time_filter_re: Regex filter to apply on the output of | 301 @param time_filter_re: Regex filter to apply on the output of |
| 345 time_command in order to get the current time. | 302 time_command in order to get the current time. |
| 346 @param time_format: Format string to pass to time.strptime() with the | 303 @param time_format: Format string to pass to time.strptime() with the |
| 347 result of the regex filter. | 304 result of the regex filter. |
| 348 @return: A tuple containing the host time and guest time. | 305 @return: A tuple containing the host time and guest time. |
| 349 """ | 306 """ |
| 350 if len(re.findall("ntpdate|w32tm", time_command)) == 0: | 307 if len(re.findall("ntpdate|w32tm", time_command)) == 0: |
| 351 host_time = time.time() | 308 host_time = time.time() |
| 352 s = session.cmd_output(time_command) | 309 session.sendline(time_command) |
| 310 (match, s) = session.read_up_to_prompt() |
| 311 if not match: |
| 312 raise error.TestError("Could not get guest time") |
| 353 | 313 |
| 354 try: | 314 try: |
| 355 s = re.findall(time_filter_re, s)[0] | 315 s = re.findall(time_filter_re, s)[0] |
| 356 except IndexError: | 316 except IndexError: |
| 357 logging.debug("The time string from guest is:\n%s" % s) | 317 logging.debug("The time string from guest is:\n%s" % s) |
| 358 raise error.TestError("The time string from guest is unexpected.") | 318 raise error.TestError("The time string from guest is unexpected.") |
| 359 except Exception, e: | 319 except Exception, e: |
| 360 logging.debug("(time_filter_re, time_string): (%s, %s)" % | 320 logging.debug("(time_filter_re, time_string): (%s, %s)" % |
| 361 (time_filter_re, s)) | 321 (time_filter_re, s)) |
| 362 raise e | 322 raise e |
| 363 | 323 |
| 364 guest_time = time.mktime(time.strptime(s, time_format)) | 324 guest_time = time.mktime(time.strptime(s, time_format)) |
| 365 else: | 325 else: |
| 366 o = session.cmd(time_command) | 326 s , o = session.get_command_status_output(time_command) |
| 327 if s != 0: |
| 328 raise error.TestError("Could not get guest time") |
| 367 if re.match('ntpdate', time_command): | 329 if re.match('ntpdate', time_command): |
| 368 offset = re.findall('offset (.*) sec',o)[0] | 330 offset = re.findall('offset (.*) sec',o)[0] |
| 369 host_main, host_mantissa = re.findall(time_filter_re, o)[0] | 331 host_main, host_mantissa = re.findall(time_filter_re, o)[0] |
| 370 host_time = time.mktime(time.strptime(host_main, time_format)) \ | 332 host_time = time.mktime(time.strptime(host_main, time_format)) \ |
| 371 + float("0.%s" % host_mantissa) | 333 + float("0.%s" % host_mantissa) |
| 372 guest_time = host_time + float(offset) | 334 guest_time = host_time + float(offset) |
| 373 else: | 335 else: |
| 374 guest_time = re.findall(time_filter_re, o)[0] | 336 guest_time = re.findall(time_filter_re, o)[0] |
| 375 offset = re.findall("o:(.*)s", o)[0] | 337 offset = re.findall("o:(.*)s", o)[0] |
| 376 if re.match('PM', guest_time): | 338 if re.match('PM', guest_time): |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 """ | 396 """ |
| 435 Copy a file to a guest if it doesn't exist or if its MD5sum differs. | 397 Copy a file to a guest if it doesn't exist or if its MD5sum differs. |
| 436 | 398 |
| 437 @param vm: VM object. | 399 @param vm: VM object. |
| 438 @param local_path: Local path. | 400 @param local_path: Local path. |
| 439 @param remote_path: Remote path. | 401 @param remote_path: Remote path. |
| 440 """ | 402 """ |
| 441 copy = False | 403 copy = False |
| 442 local_hash = utils.hash_file(local_path) | 404 local_hash = utils.hash_file(local_path) |
| 443 basename = os.path.basename(local_path) | 405 basename = os.path.basename(local_path) |
| 444 output = session.cmd_output("md5sum %s" % remote_path) | 406 output = session.get_command_output("md5sum %s" % remote_path) |
| 445 if "such file" in output: | 407 if "such file" in output: |
| 446 remote_hash = "0" | 408 remote_hash = "0" |
| 447 elif output: | 409 elif output: |
| 448 remote_hash = output.split()[0] | 410 remote_hash = output.split()[0] |
| 449 else: | 411 else: |
| 450 logging.warning("MD5 check for remote path %s did not return.", | 412 logging.warning("MD5 check for remote path %s did not return.", |
| 451 remote_path) | 413 remote_path) |
| 452 # Let's be a little more lenient here and see if it wasn't a | 414 # Let's be a little more lenient here and see if it wasn't a |
| 453 # temporary problem | 415 # temporary problem |
| 454 remote_hash = "0" | 416 remote_hash = "0" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 466 """ | 428 """ |
| 467 Extract a .tar.bz2 file on the guest. | 429 Extract a .tar.bz2 file on the guest. |
| 468 | 430 |
| 469 @param vm: VM object | 431 @param vm: VM object |
| 470 @param remote_path: Remote file path | 432 @param remote_path: Remote file path |
| 471 @param dest_dir: Destination dir for the contents | 433 @param dest_dir: Destination dir for the contents |
| 472 """ | 434 """ |
| 473 basename = os.path.basename(remote_path) | 435 basename = os.path.basename(remote_path) |
| 474 logging.info("Extracting %s...", basename) | 436 logging.info("Extracting %s...", basename) |
| 475 e_cmd = "tar xjvf %s -C %s" % (remote_path, dest_dir) | 437 e_cmd = "tar xjvf %s -C %s" % (remote_path, dest_dir) |
| 476 session.cmd(e_cmd, timeout=120) | 438 s, o = session.get_command_status_output(e_cmd, timeout=120) |
| 439 if s != 0: |
| 440 logging.error("Uncompress output:\n%s", o) |
| 441 raise error.TestFail("Failed to extract %s on guest" % basename) |
| 477 | 442 |
| 478 | 443 |
| 479 def get_results(): | 444 def get_results(): |
| 480 """ | 445 """ |
| 481 Copy autotest results present on the guest back to the host. | 446 Copy autotest results present on the guest back to the host. |
| 482 """ | 447 """ |
| 483 logging.info("Trying to copy autotest results from guest") | 448 logging.info("Trying to copy autotest results from guest") |
| 484 guest_results_dir = os.path.join(outputdir, "guest_autotest_results") | 449 guest_results_dir = os.path.join(outputdir, "guest_autotest_results") |
| 485 if not os.path.exists(guest_results_dir): | 450 if not os.path.exists(guest_results_dir): |
| 486 os.mkdir(guest_results_dir) | 451 os.mkdir(guest_results_dir) |
| 487 if not vm.copy_files_from("%s/results/default/*" % autotest_path, | 452 if not vm.copy_files_from("%s/results/default/*" % autotest_path, |
| 488 guest_results_dir): | 453 guest_results_dir): |
| 489 logging.error("Could not copy autotest results from guest") | 454 logging.error("Could not copy autotest results from guest") |
| 490 | 455 |
| 491 | 456 |
| 492 def get_results_summary(): | 457 def get_results_summary(): |
| 493 """ | 458 """ |
| 494 Get the status of the tests that were executed on the host and close | 459 Get the status of the tests that were executed on the host and close |
| 495 the session where autotest was being executed. | 460 the session where autotest was being executed. |
| 496 """ | 461 """ |
| 497 output = session.cmd_output("cat results/*/status") | 462 output = session.get_command_output("cat results/*/status") |
| 498 try: | 463 try: |
| 499 results = scan_results.parse_results(output) | 464 results = scan_results.parse_results(output) |
| 500 # Report test results | 465 # Report test results |
| 501 logging.info("Results (test, status, duration, info):") | 466 logging.info("Results (test, status, duration, info):") |
| 502 for result in results: | 467 for result in results: |
| 503 logging.info(str(result)) | 468 logging.info(str(result)) |
| 504 session.close() | 469 session.close() |
| 505 return results | 470 return results |
| 506 except Exception, e: | 471 except Exception, e: |
| 507 logging.error("Error processing guest autotest results: %s", e) | 472 logging.error("Error processing guest autotest results: %s", e) |
| (...skipping 28 matching lines...) Expand all Loading... |
| 536 # Extract autotest.tar.bz2 | 501 # Extract autotest.tar.bz2 |
| 537 extract(vm, compressed_autotest_path, "/") | 502 extract(vm, compressed_autotest_path, "/") |
| 538 | 503 |
| 539 if not vm.copy_files_to(control_path, | 504 if not vm.copy_files_to(control_path, |
| 540 os.path.join(autotest_path, 'control')): | 505 os.path.join(autotest_path, 'control')): |
| 541 raise error.TestFail("Could not copy the test control file to guest") | 506 raise error.TestFail("Could not copy the test control file to guest") |
| 542 | 507 |
| 543 # Run the test | 508 # Run the test |
| 544 logging.info("Running autotest control file %s on guest, timeout %ss", | 509 logging.info("Running autotest control file %s on guest, timeout %ss", |
| 545 os.path.basename(control_path), timeout) | 510 os.path.basename(control_path), timeout) |
| 546 session.cmd("cd %s" % autotest_path) | 511 session.get_command_output("cd %s" % autotest_path) |
| 547 try: | 512 session.get_command_output("rm -f control.state") |
| 548 session.cmd("rm -f control.state") | 513 session.get_command_output("rm -rf results/*") |
| 549 session.cmd("rm -rf results/*") | 514 logging.info("---------------- Test output ----------------") |
| 550 except kvm_subprocess.ShellError: | 515 status = session.get_command_status("bin/autotest control", |
| 551 pass | 516 timeout=timeout, |
| 552 try: | 517 print_func=logging.info) |
| 553 try: | 518 logging.info("------------- End of test output ------------") |
| 554 logging.info("---------------- Test output ----------------") | 519 if status is None: |
| 555 session.cmd_output("bin/autotest control", timeout=timeout, | 520 if not vm.is_alive(): |
| 556 print_func=logging.info) | |
| 557 finally: | |
| 558 logging.info("------------- End of test output ------------") | |
| 559 except kvm_subprocess.ShellTimeoutError: | |
| 560 if vm.is_alive(): | |
| 561 get_results() | |
| 562 get_results_summary() | |
| 563 raise error.TestError("Timeout elapsed while waiting for job to " | |
| 564 "complete") | |
| 565 else: | |
| 566 raise error.TestError("Autotest job on guest failed " | 521 raise error.TestError("Autotest job on guest failed " |
| 567 "(VM terminated during job)") | 522 "(VM terminated during job)") |
| 568 except kvm_subprocess.ShellProcessTerminatedError: | 523 if not session.is_alive(): |
| 524 get_results() |
| 525 raise error.TestError("Autotest job on guest failed " |
| 526 "(Remote session terminated during job)") |
| 569 get_results() | 527 get_results() |
| 570 raise error.TestError("Autotest job on guest failed " | 528 get_results_summary() |
| 571 "(Remote session terminated during job)") | 529 raise error.TestError("Timeout elapsed while waiting for job to " |
| 530 "complete") |
| 572 | 531 |
| 573 results = get_results_summary() | 532 results = get_results_summary() |
| 574 get_results() | 533 get_results() |
| 575 | 534 |
| 576 # Make a list of FAIL/ERROR/ABORT results (make sure FAIL results appear | 535 # Make a list of FAIL/ERROR/ABORT results (make sure FAIL results appear |
| 577 # before ERROR results, and ERROR results appear before ABORT results) | 536 # before ERROR results, and ERROR results appear before ABORT results) |
| 578 bad_results = [r[0] for r in results if r[1] == "FAIL"] | 537 bad_results = [r[0] for r in results if r[1] == "FAIL"] |
| 579 bad_results += [r[0] for r in results if r[1] == "ERROR"] | 538 bad_results += [r[0] for r in results if r[1] == "ERROR"] |
| 580 bad_results += [r[0] for r in results if r[1] == "ABORT"] | 539 bad_results += [r[0] for r in results if r[1] == "ABORT"] |
| 581 | 540 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 # always get the packet loss ratio even if timeout. | 582 # always get the packet loss ratio even if timeout. |
| 624 if process.is_alive(): | 583 if process.is_alive(): |
| 625 kvm_utils.kill_process_tree(process.get_pid(), signal.SIGINT) | 584 kvm_utils.kill_process_tree(process.get_pid(), signal.SIGINT) |
| 626 | 585 |
| 627 status = process.get_status() | 586 status = process.get_status() |
| 628 output = process.get_output() | 587 output = process.get_output() |
| 629 | 588 |
| 630 process.close() | 589 process.close() |
| 631 return status, output | 590 return status, output |
| 632 else: | 591 else: |
| 633 try: | 592 session.sendline(command) |
| 634 output = session.cmd_output(command, timeout=timeout, | 593 status, output = session.read_up_to_prompt(timeout=timeout, |
| 635 print_func=output_func) | 594 print_func=output_func) |
| 636 except kvm_subprocess.ShellTimeoutError: | 595 if not status: |
| 637 # Send ctrl+c (SIGINT) through ssh session | 596 # Send ctrl+c (SIGINT) through ssh session |
| 638 session.send("\003") | 597 session.send("\003") |
| 639 try: | 598 status, output2 = session.read_up_to_prompt(print_func=output_func) |
| 640 output2 = session.read_up_to_prompt(print_func=output_func) | 599 output += output2 |
| 641 output += output2 | 600 if not status: |
| 642 except kvm_subprocess.ExpectTimeoutError, e: | |
| 643 output += e.output | |
| 644 # We also need to use this session to query the return value | 601 # We also need to use this session to query the return value |
| 645 session.send("\003") | 602 session.send("\003") |
| 646 | 603 |
| 647 session.sendline(session.status_test_command) | 604 session.sendline(session.status_test_command) |
| 648 try: | 605 s2, o2 = session.read_up_to_prompt() |
| 649 o2 = session.read_up_to_prompt() | 606 if not s2: |
| 650 except kvm_subprocess.ExpectError: | |
| 651 status = -1 | 607 status = -1 |
| 652 else: | 608 else: |
| 653 try: | 609 try: |
| 654 status = int(re.findall("\d+", o2)[0]) | 610 status = int(re.findall("\d+", o2)[0]) |
| 655 except: | 611 except: |
| 656 status = -1 | 612 status = -1 |
| 657 | 613 |
| 658 return status, output | 614 return status, output |
| 659 | 615 |
| 660 | 616 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 707 | 663 |
| 708 | 664 |
| 709 def get_linux_ifname(session, mac_address): | 665 def get_linux_ifname(session, mac_address): |
| 710 """ | 666 """ |
| 711 Get the interface name through the mac address. | 667 Get the interface name through the mac address. |
| 712 | 668 |
| 713 @param session: session to the virtual machine | 669 @param session: session to the virtual machine |
| 714 @mac_address: the macaddress of nic | 670 @mac_address: the macaddress of nic |
| 715 """ | 671 """ |
| 716 | 672 |
| 717 output = session.cmd_output("ifconfig -a") | 673 output = session.get_command_output("ifconfig -a") |
| 718 | 674 |
| 719 try: | 675 try: |
| 720 ethname = re.findall("(\w+)\s+Link.*%s" % mac_address, output, | 676 ethname = re.findall("(\w+)\s+Link.*%s" % mac_address, output, |
| 721 re.IGNORECASE)[0] | 677 re.IGNORECASE)[0] |
| 722 return ethname | 678 return ethname |
| 723 except: | 679 except: |
| 724 return None | 680 return None |
| OLD | NEW |