Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(520)

Side by Side Diff: client/tests/kvm/kvm_test_utils.py

Issue 6246035: Merge remote branch 'cros/upstream' into master (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/autotest.git@master
Patch Set: patch Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 24 import time, os, logging, re, 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 = kvm_utils.env_get_vm(env, vm_name) 38 vm = env.get_vm(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): 47 def wait_for_login(vm, nic_index=0, timeout=240, start=0, step=2, serial=None):
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.
54 @return: A shell session object. 56 @return: A shell session object.
55 """ 57 """
56 logging.info("Trying to log into guest '%s', timeout %ds", vm.name, timeout) 58 end_time = time.time() + timeout
57 session = kvm_utils.wait_for(lambda: vm.remote_login(nic_index=nic_index), 59 session = None
58 timeout, start, step) 60 if serial:
61 type = 'serial'
62 logging.info("Trying to log into guest %s using serial connection,"
63 " timeout %ds", vm.name, timeout)
64 time.sleep(start)
65 while time.time() < end_time:
66 try:
67 session = vm.serial_login()
68 break
69 except kvm_utils.LoginError, e:
70 logging.debug(e)
71 time.sleep(step)
72 else:
73 type = 'remote'
74 logging.info("Trying to log into guest %s using remote connection,"
75 " timeout %ds", vm.name, timeout)
76 time.sleep(start)
77 while time.time() < end_time:
78 try:
79 session = vm.login(nic_index=nic_index)
80 break
81 except (kvm_utils.LoginError, kvm_vm.VMError), e:
82 logging.debug(e)
83 time.sleep(step)
59 if not session: 84 if not session:
60 raise error.TestFail("Could not log into guest '%s'" % vm.name) 85 raise error.TestFail("Could not log into guest %s using %s connection" %
61 logging.info("Logged into guest '%s'" % vm.name) 86 (vm.name, type))
87 logging.info("Logged into guest %s using %s connection", vm.name, type)
62 return session 88 return session
63 89
64 90
65 def reboot(vm, session, method="shell", sleep_before_reset=10, nic_index=0, 91 def reboot(vm, session, method="shell", sleep_before_reset=10, nic_index=0,
66 timeout=240): 92 timeout=240):
67 """ 93 """
68 Reboot the VM and wait for it to come back up by trying to log in until 94 Reboot the VM and wait for it to come back up by trying to log in until
69 timeout expires. 95 timeout expires.
70 96
71 @param vm: VM object. 97 @param vm: VM object.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 131
106 # Wait for the session to become unresponsive and close it 132 # Wait for the session to become unresponsive and close it
107 if not kvm_utils.wait_for(lambda: not session.is_responsive(timeout=30), 133 if not kvm_utils.wait_for(lambda: not session.is_responsive(timeout=30),
108 120, 0, 1): 134 120, 0, 1):
109 raise error.TestFail("Guest refuses to go down") 135 raise error.TestFail("Guest refuses to go down")
110 session.close() 136 session.close()
111 137
112 # Try logging into the guest until timeout expires 138 # Try logging into the guest until timeout expires
113 logging.info("Guest is down. Waiting for it to go up again, timeout %ds", 139 logging.info("Guest is down. Waiting for it to go up again, timeout %ds",
114 timeout) 140 timeout)
115 session = kvm_utils.wait_for(lambda: vm.remote_login(nic_index=nic_index), 141 session = vm.wait_for_login(nic_index, timeout=timeout)
116 timeout, 0, 2)
117 if not session:
118 raise error.TestFail("Could not log into guest after reboot")
119 logging.info("Guest is up again") 142 logging.info("Guest is up again")
120 return session 143 return session
121 144
122 145
123 def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp", 146 def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp",
124 mig_cancel=False): 147 mig_cancel=False, offline=False, stable_check=False,
148 clean=False, save_path=None, dest_host='localhost', mig_port=None):
125 """ 149 """
126 Migrate a VM locally and re-register it in the environment. 150 Migrate a VM locally and re-register it in the environment.
127 151
128 @param vm: The VM to migrate. 152 @param vm: The VM to migrate.
129 @param env: The environment dictionary. If omitted, the migrated VM will 153 @param env: The environment dictionary. If omitted, the migrated VM will
130 not be registered. 154 not be registered.
131 @param mig_timeout: timeout value for migration. 155 @param mig_timeout: timeout value for migration.
132 @param mig_protocol: migration protocol 156 @param mig_protocol: migration protocol
133 @param mig_cancel: Test migrate_cancel or not when protocol is tcp. 157 @param mig_cancel: Test migrate_cancel or not when protocol is tcp.
134 @return: The post-migration VM. 158 @param dest_host: Destination host (defaults to 'localhost').
159 @param mig_port: Port that will be used for migration.
160 @return: The post-migration VM, in case of same host migration, True in
161 case of multi-host migration.
135 """ 162 """
136 def mig_finished(): 163 def mig_finished():
137 o = vm.monitor.info("migrate") 164 o = vm.monitor.info("migrate")
138 if isinstance(o, str): 165 if isinstance(o, str):
139 return "status: active" not in o 166 return "status: active" not in o
140 else: 167 else:
141 return o.get("status") != "active" 168 return o.get("status") != "active"
142 169
143 def mig_succeeded(): 170 def mig_succeeded():
144 o = vm.monitor.info("migrate") 171 o = vm.monitor.info("migrate")
(...skipping 17 matching lines...) Expand all
162 else: 189 else:
163 return (o.get("status") == "cancelled" or 190 return (o.get("status") == "cancelled" or
164 o.get("status") == "canceled") 191 o.get("status") == "canceled")
165 192
166 def wait_for_migration(): 193 def wait_for_migration():
167 if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2, 194 if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2,
168 "Waiting for migration to finish..."): 195 "Waiting for migration to finish..."):
169 raise error.TestFail("Timeout expired while waiting for migration " 196 raise error.TestFail("Timeout expired while waiting for migration "
170 "to finish") 197 "to finish")
171 198
172 dest_vm = vm.clone() 199 if dest_host == 'localhost':
200 dest_vm = vm.clone()
173 201
174 if mig_protocol == "exec": 202 if (dest_host == 'localhost') and stable_check:
175 # Exec is a little different from other migrate methods - first we 203 # Pause the dest vm after creation
176 # ask the monitor the migration, then the vm state is dumped to a 204 dest_vm.params['extra_params'] = (dest_vm.params.get('extra_params','')
177 # compressed file, then we start the dest vm with -incoming pointing 205 + ' -S')
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()
186 206
187 if not dest_vm.create(migration_mode=mig_protocol, 207 if dest_host == 'localhost':
188 migration_exec_cmd=exec_cmd, mac_source=vm): 208 dest_vm.create(migration_mode=mig_protocol, mac_source=vm)
189 raise error.TestError("Could not create dest VM") 209
190 finally: 210 try:
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):
198 raise error.TestError("Could not create dest VM")
199 try: 211 try:
200 if mig_protocol == "tcp": 212 if mig_protocol == "tcp":
201 uri = "tcp:localhost:%d" % dest_vm.migration_port 213 if dest_host == 'localhost':
214 uri = "tcp:localhost:%d" % dest_vm.migration_port
215 else:
216 uri = 'tcp:%s:%d' % (dest_host, mig_port)
202 elif mig_protocol == "unix": 217 elif mig_protocol == "unix":
203 uri = "unix:%s" % dest_vm.migration_file 218 uri = "unix:%s" % dest_vm.migration_file
219 elif mig_protocol == "exec":
220 uri = '"exec:nc localhost %s"' % dest_vm.migration_port
221
222 if offline:
223 vm.monitor.cmd("stop")
204 vm.monitor.migrate(uri) 224 vm.monitor.migrate(uri)
205 225
206 if mig_cancel: 226 if mig_cancel:
207 time.sleep(2) 227 time.sleep(2)
208 vm.monitor.cmd("migrate_cancel") 228 vm.monitor.cmd("migrate_cancel")
209 if not kvm_utils.wait_for(mig_cancelled, 60, 2, 2, 229 if not kvm_utils.wait_for(mig_cancelled, 60, 2, 2,
210 "Waiting for migration " 230 "Waiting for migration "
211 "cancellation"): 231 "cancellation"):
212 raise error.TestFail("Failed to cancel migration") 232 raise error.TestFail("Failed to cancel migration")
213 dest_vm.destroy(gracefully=False) 233 if offline:
234 vm.monitor.cmd("cont")
235 if dest_host == 'localhost':
236 dest_vm.destroy(gracefully=False)
214 return vm 237 return vm
215 else: 238 else:
216 wait_for_migration() 239 wait_for_migration()
240 if (dest_host == 'localhost') and stable_check:
241 save_path = None or "/tmp"
242 save1 = os.path.join(save_path, "src")
243 save2 = os.path.join(save_path, "dst")
244
245 vm.save_to_file(save1)
246 dest_vm.save_to_file(save2)
247
248 # Fail if we see deltas
249 md5_save1 = utils.hash_file(save1)
250 md5_save2 = utils.hash_file(save2)
251 if md5_save1 != md5_save2:
252 raise error.TestFail("Mismatch of VM state before "
253 "and after migration")
254
255 if (dest_host == 'localhost') and offline:
256 dest_vm.monitor.cmd("cont")
217 except: 257 except:
218 dest_vm.destroy() 258 if dest_host == 'localhost':
259 dest_vm.destroy()
219 raise 260 raise
220 261
262 finally:
263 if (dest_host == 'localhost') and stable_check and clean:
264 logging.debug("Cleaning the state files")
265 if os.path.isfile(save1):
266 os.remove(save1)
267 if os.path.isfile(save2):
268 os.remove(save2)
269
221 # Report migration status 270 # Report migration status
222 if mig_succeeded(): 271 if mig_succeeded():
223 logging.info("Migration finished successfully") 272 logging.info("Migration finished successfully")
224 elif mig_failed(): 273 elif mig_failed():
225 raise error.TestFail("Migration failed") 274 raise error.TestFail("Migration failed")
226 else: 275 else:
227 raise error.TestFail("Migration ended with unknown status") 276 raise error.TestFail("Migration ended with unknown status")
228 277
229 if "paused" in dest_vm.monitor.info("status"): 278 if dest_host == 'localhost':
230 logging.debug("Destination VM is paused, resuming it...") 279 if "paused" in dest_vm.monitor.info("status"):
231 dest_vm.monitor.cmd("cont") 280 logging.debug("Destination VM is paused, resuming it...")
281 dest_vm.monitor.cmd("cont")
232 282
233 # Kill the source VM 283 # Kill the source VM
234 vm.destroy(gracefully=False) 284 vm.destroy(gracefully=False)
235 285
236 # Replace the source VM with the new cloned VM 286 # Replace the source VM with the new cloned VM
237 if env is not None: 287 if (dest_host == 'localhost') and (env is not None):
238 kvm_utils.env_register_vm(env, vm.name, dest_vm) 288 env.register_vm(vm.name, dest_vm)
239 289
240 # Return the new cloned VM 290 # Return the new cloned VM
241 return dest_vm 291 if dest_host == 'localhost':
292 return dest_vm
293 else:
294 return vm
242 295
243 296
244 def stop_windows_service(session, service, timeout=120): 297 def stop_windows_service(session, service, timeout=120):
245 """ 298 """
246 Stop a Windows service using sc. 299 Stop a Windows service using sc.
247 If the service is already stopped or is not installed, do nothing. 300 If the service is already stopped or is not installed, do nothing.
248 301
249 @param service: The name of the service 302 @param service: The name of the service
250 @param timeout: Time duration to wait for service to stop 303 @param timeout: Time duration to wait for service to stop
251 @raise error.TestError: Raised if the service can't be stopped 304 @raise error.TestError: Raised if the service can't be stopped
252 """ 305 """
253 end_time = time.time() + timeout 306 end_time = time.time() + timeout
254 while time.time() < end_time: 307 while time.time() < end_time:
255 o = session.get_command_output("sc stop %s" % service, timeout=60) 308 o = session.cmd_output("sc stop %s" % service, timeout=60)
256 # FAILED 1060 means the service isn't installed. 309 # FAILED 1060 means the service isn't installed.
257 # FAILED 1062 means the service hasn't been started. 310 # FAILED 1062 means the service hasn't been started.
258 if re.search(r"\bFAILED (1060|1062)\b", o, re.I): 311 if re.search(r"\bFAILED (1060|1062)\b", o, re.I):
259 break 312 break
260 time.sleep(1) 313 time.sleep(1)
261 else: 314 else:
262 raise error.TestError("Could not stop service '%s'" % service) 315 raise error.TestError("Could not stop service '%s'" % service)
263 316
264 317
265 def start_windows_service(session, service, timeout=120): 318 def start_windows_service(session, service, timeout=120):
266 """ 319 """
267 Start a Windows service using sc. 320 Start a Windows service using sc.
268 If the service is already running, do nothing. 321 If the service is already running, do nothing.
269 If the service isn't installed, fail. 322 If the service isn't installed, fail.
270 323
271 @param service: The name of the service 324 @param service: The name of the service
272 @param timeout: Time duration to wait for service to start 325 @param timeout: Time duration to wait for service to start
273 @raise error.TestError: Raised if the service can't be started 326 @raise error.TestError: Raised if the service can't be started
274 """ 327 """
275 end_time = time.time() + timeout 328 end_time = time.time() + timeout
276 while time.time() < end_time: 329 while time.time() < end_time:
277 o = session.get_command_output("sc start %s" % service, timeout=60) 330 o = session.cmd_output("sc start %s" % service, timeout=60)
278 # FAILED 1060 means the service isn't installed. 331 # FAILED 1060 means the service isn't installed.
279 if re.search(r"\bFAILED 1060\b", o, re.I): 332 if re.search(r"\bFAILED 1060\b", o, re.I):
280 raise error.TestError("Could not start service '%s' " 333 raise error.TestError("Could not start service '%s' "
281 "(service not installed)" % service) 334 "(service not installed)" % service)
282 # FAILED 1056 means the service is already running. 335 # FAILED 1056 means the service is already running.
283 if re.search(r"\bFAILED 1056\b", o, re.I): 336 if re.search(r"\bFAILED 1056\b", o, re.I):
284 break 337 break
285 time.sleep(1) 338 time.sleep(1)
286 else: 339 else:
287 raise error.TestError("Could not start service '%s'" % service) 340 raise error.TestError("Could not start service '%s'" % service)
(...skipping 11 matching lines...) Expand all
299 @param session: A shell session. 352 @param session: A shell session.
300 @param time_command: Command to issue to get the current guest time. 353 @param time_command: Command to issue to get the current guest time.
301 @param time_filter_re: Regex filter to apply on the output of 354 @param time_filter_re: Regex filter to apply on the output of
302 time_command in order to get the current time. 355 time_command in order to get the current time.
303 @param time_format: Format string to pass to time.strptime() with the 356 @param time_format: Format string to pass to time.strptime() with the
304 result of the regex filter. 357 result of the regex filter.
305 @return: A tuple containing the host time and guest time. 358 @return: A tuple containing the host time and guest time.
306 """ 359 """
307 if len(re.findall("ntpdate|w32tm", time_command)) == 0: 360 if len(re.findall("ntpdate|w32tm", time_command)) == 0:
308 host_time = time.time() 361 host_time = time.time()
309 session.sendline(time_command) 362 s = session.cmd_output(time_command)
310 (match, s) = session.read_up_to_prompt()
311 if not match:
312 raise error.TestError("Could not get guest time")
313 363
314 try: 364 try:
315 s = re.findall(time_filter_re, s)[0] 365 s = re.findall(time_filter_re, s)[0]
316 except IndexError: 366 except IndexError:
317 logging.debug("The time string from guest is:\n%s" % s) 367 logging.debug("The time string from guest is:\n%s", s)
318 raise error.TestError("The time string from guest is unexpected.") 368 raise error.TestError("The time string from guest is unexpected.")
319 except Exception, e: 369 except Exception, e:
320 logging.debug("(time_filter_re, time_string): (%s, %s)" % 370 logging.debug("(time_filter_re, time_string): (%s, %s)",
321 (time_filter_re, s)) 371 time_filter_re, s)
322 raise e 372 raise e
323 373
324 guest_time = time.mktime(time.strptime(s, time_format)) 374 guest_time = time.mktime(time.strptime(s, time_format))
325 else: 375 else:
326 s , o = session.get_command_status_output(time_command) 376 o = session.cmd(time_command)
327 if s != 0:
328 raise error.TestError("Could not get guest time")
329 if re.match('ntpdate', time_command): 377 if re.match('ntpdate', time_command):
330 offset = re.findall('offset (.*) sec',o)[0] 378 offset = re.findall('offset (.*) sec', o)[0]
331 host_main, host_mantissa = re.findall(time_filter_re, o)[0] 379 host_main, host_mantissa = re.findall(time_filter_re, o)[0]
332 host_time = time.mktime(time.strptime(host_main, time_format)) \ 380 host_time = (time.mktime(time.strptime(host_main, time_format)) +
333 + float("0.%s" % host_mantissa) 381 float("0.%s" % host_mantissa))
334 guest_time = host_time + float(offset) 382 guest_time = host_time + float(offset)
335 else: 383 else:
336 guest_time = re.findall(time_filter_re, o)[0] 384 guest_time = re.findall(time_filter_re, o)[0]
337 offset = re.findall("o:(.*)s", o)[0] 385 offset = re.findall("o:(.*)s", o)[0]
338 if re.match('PM', guest_time): 386 if re.match('PM', guest_time):
339 hour = re.findall('\d+ (\d+):', guest_time)[0] 387 hour = re.findall('\d+ (\d+):', guest_time)[0]
340 hour = str(int(hour) + 12) 388 hour = str(int(hour) + 12)
341 guest_time = re.sub('\d+\s\d+:', "\d+\s%s:" % hour, 389 guest_time = re.sub('\d+\s\d+:', "\d+\s%s:" % hour,
342 guest_time)[:-3] 390 guest_time)[:-3]
343 else: 391 else:
(...skipping 30 matching lines...) Expand all
374 shm = vm.get_shared_meminfo() 422 shm = vm.get_shared_meminfo()
375 if shm is None: 423 if shm is None:
376 raise error.TestError("Could not get shared meminfo from " 424 raise error.TestError("Could not get shared meminfo from "
377 "VM %s" % vm) 425 "VM %s" % vm)
378 meminfo += "%dM; " % shm 426 meminfo += "%dM; " % shm
379 meminfo = meminfo[0:-2] + "}" 427 meminfo = meminfo[0:-2] + "}"
380 428
381 return meminfo 429 return meminfo
382 430
383 431
384 def run_autotest(vm, session, control_path, timeout, outputdir): 432 def run_autotest(vm, session, control_path, timeout, outputdir, params):
385 """ 433 """
386 Run an autotest control file inside a guest (linux only utility). 434 Run an autotest control file inside a guest (linux only utility).
387 435
388 @param vm: VM object. 436 @param vm: VM object.
389 @param session: A shell session on the VM provided. 437 @param session: A shell session on the VM provided.
390 @param control_path: A path to an autotest control file. 438 @param control_path: A path to an autotest control file.
391 @param timeout: Timeout under which the autotest control file must complete. 439 @param timeout: Timeout under which the autotest control file must complete.
392 @param outputdir: Path on host where we should copy the guest autotest 440 @param outputdir: Path on host where we should copy the guest autotest
393 results to. 441 results to.
442
443 The following params is used by the migration
444 @param params: Test params used in the migration test
394 """ 445 """
395 def copy_if_hash_differs(vm, local_path, remote_path): 446 def copy_if_hash_differs(vm, local_path, remote_path):
396 """ 447 """
397 Copy a file to a guest if it doesn't exist or if its MD5sum differs. 448 Copy a file to a guest if it doesn't exist or if its MD5sum differs.
398 449
399 @param vm: VM object. 450 @param vm: VM object.
400 @param local_path: Local path. 451 @param local_path: Local path.
401 @param remote_path: Remote path. 452 @param remote_path: Remote path.
402 """ 453 """
403 copy = False
404 local_hash = utils.hash_file(local_path) 454 local_hash = utils.hash_file(local_path)
405 basename = os.path.basename(local_path) 455 basename = os.path.basename(local_path)
406 output = session.get_command_output("md5sum %s" % remote_path) 456 output = session.cmd_output("md5sum %s" % remote_path)
407 if "such file" in output: 457 if "such file" in output:
408 remote_hash = "0" 458 remote_hash = "0"
409 elif output: 459 elif output:
410 remote_hash = output.split()[0] 460 remote_hash = output.split()[0]
411 else: 461 else:
412 logging.warning("MD5 check for remote path %s did not return.", 462 logging.warning("MD5 check for remote path %s did not return.",
413 remote_path) 463 remote_path)
414 # Let's be a little more lenient here and see if it wasn't a 464 # Let's be a little more lenient here and see if it wasn't a
415 # temporary problem 465 # temporary problem
416 remote_hash = "0" 466 remote_hash = "0"
417
418 if remote_hash != local_hash: 467 if remote_hash != local_hash:
419 logging.debug("Copying %s to guest", basename) 468 logging.debug("Copying %s to guest", basename)
420 copy = True 469 vm.copy_files_to(local_path, remote_path)
421
422 if copy:
423 if not vm.copy_files_to(local_path, remote_path):
424 raise error.TestFail("Could not copy %s to guest" % local_path)
425 470
426 471
427 def extract(vm, remote_path, dest_dir="."): 472 def extract(vm, remote_path, dest_dir="."):
428 """ 473 """
429 Extract a .tar.bz2 file on the guest. 474 Extract a .tar.bz2 file on the guest.
430 475
431 @param vm: VM object 476 @param vm: VM object
432 @param remote_path: Remote file path 477 @param remote_path: Remote file path
433 @param dest_dir: Destination dir for the contents 478 @param dest_dir: Destination dir for the contents
434 """ 479 """
435 basename = os.path.basename(remote_path) 480 basename = os.path.basename(remote_path)
436 logging.info("Extracting %s...", basename) 481 logging.info("Extracting %s...", basename)
437 e_cmd = "tar xjvf %s -C %s" % (remote_path, dest_dir) 482 e_cmd = "tar xjvf %s -C %s" % (remote_path, dest_dir)
438 s, o = session.get_command_status_output(e_cmd, timeout=120) 483 session.cmd(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)
442 484
443 485
444 def get_results(): 486 def get_results():
445 """ 487 """
446 Copy autotest results present on the guest back to the host. 488 Copy autotest results present on the guest back to the host.
447 """ 489 """
448 logging.info("Trying to copy autotest results from guest") 490 logging.info("Trying to copy autotest results from guest")
449 guest_results_dir = os.path.join(outputdir, "guest_autotest_results") 491 guest_results_dir = os.path.join(outputdir, "guest_autotest_results")
450 if not os.path.exists(guest_results_dir): 492 if not os.path.exists(guest_results_dir):
451 os.mkdir(guest_results_dir) 493 os.mkdir(guest_results_dir)
452 if not vm.copy_files_from("%s/results/default/*" % autotest_path, 494 vm.copy_files_from("%s/results/default/*" % autotest_path,
453 guest_results_dir): 495 guest_results_dir)
454 logging.error("Could not copy autotest results from guest")
455 496
456 497
457 def get_results_summary(): 498 def get_results_summary():
458 """ 499 """
459 Get the status of the tests that were executed on the host and close 500 Get the status of the tests that were executed on the host and close
460 the session where autotest was being executed. 501 the session where autotest was being executed.
461 """ 502 """
462 output = session.get_command_output("cat results/*/status") 503 output = session.cmd_output("cat results/*/status")
463 try: 504 try:
464 results = scan_results.parse_results(output) 505 results = scan_results.parse_results(output)
465 # Report test results 506 # Report test results
466 logging.info("Results (test, status, duration, info):") 507 logging.info("Results (test, status, duration, info):")
467 for result in results: 508 for result in results:
468 logging.info(str(result)) 509 logging.info(str(result))
469 session.close() 510 session.close()
470 return results 511 return results
471 except Exception, e: 512 except Exception, e:
472 logging.error("Error processing guest autotest results: %s", e) 513 logging.error("Error processing guest autotest results: %s", e)
473 return None 514 return None
474 515
475 516
476 if not os.path.isfile(control_path): 517 if not os.path.isfile(control_path):
477 raise error.TestError("Invalid path to autotest control file: %s" % 518 raise error.TestError("Invalid path to autotest control file: %s" %
478 control_path) 519 control_path)
479 520
521 migrate_background = params.get("migrate_background") == "yes"
522 if migrate_background:
523 mig_timeout = float(params.get("mig_timeout", "3600"))
524 mig_protocol = params.get("migration_protocol", "tcp")
525
480 compressed_autotest_path = "/tmp/autotest.tar.bz2" 526 compressed_autotest_path = "/tmp/autotest.tar.bz2"
481 527
482 # To avoid problems, let's make the test use the current AUTODIR 528 # To avoid problems, let's make the test use the current AUTODIR
483 # (autotest client path) location 529 # (autotest client path) location
484 autotest_path = os.environ['AUTODIR'] 530 autotest_path = os.environ['AUTODIR']
485 531
486 # tar the contents of bindir/autotest 532 # tar the contents of bindir/autotest
487 cmd = "tar cvjf %s %s/*" % (compressed_autotest_path, autotest_path) 533 cmd = "tar cvjf %s %s/*" % (compressed_autotest_path, autotest_path)
488 # Until we have nested virtualization, we don't need the kvm test :) 534 # Until we have nested virtualization, we don't need the kvm test :)
489 cmd += " --exclude=%s/tests/kvm" % autotest_path 535 cmd += " --exclude=%s/tests/kvm" % autotest_path
490 cmd += " --exclude=%s/results" % autotest_path 536 cmd += " --exclude=%s/results" % autotest_path
491 cmd += " --exclude=%s/tmp" % autotest_path 537 cmd += " --exclude=%s/tmp" % autotest_path
492 cmd += " --exclude=%s/control*" % autotest_path 538 cmd += " --exclude=%s/control*" % autotest_path
493 cmd += " --exclude=*.pyc" 539 cmd += " --exclude=*.pyc"
494 cmd += " --exclude=*.svn" 540 cmd += " --exclude=*.svn"
495 cmd += " --exclude=*.git" 541 cmd += " --exclude=*.git"
496 utils.run(cmd) 542 utils.run(cmd)
497 543
498 # Copy autotest.tar.bz2 544 # Copy autotest.tar.bz2
499 copy_if_hash_differs(vm, compressed_autotest_path, compressed_autotest_path) 545 copy_if_hash_differs(vm, compressed_autotest_path, compressed_autotest_path)
500 546
501 # Extract autotest.tar.bz2 547 # Extract autotest.tar.bz2
502 extract(vm, compressed_autotest_path, "/") 548 extract(vm, compressed_autotest_path, "/")
503 549
504 if not vm.copy_files_to(control_path, 550 vm.copy_files_to(control_path, os.path.join(autotest_path, 'control'))
505 os.path.join(autotest_path, 'control')):
506 raise error.TestFail("Could not copy the test control file to guest")
507 551
508 # Run the test 552 # Run the test
509 logging.info("Running autotest control file %s on guest, timeout %ss", 553 logging.info("Running autotest control file %s on guest, timeout %ss",
510 os.path.basename(control_path), timeout) 554 os.path.basename(control_path), timeout)
511 session.get_command_output("cd %s" % autotest_path) 555 session.cmd("cd %s" % autotest_path)
512 session.get_command_output("rm -f control.state") 556 try:
513 session.get_command_output("rm -rf results/*") 557 session.cmd("rm -f control.state")
514 logging.info("---------------- Test output ----------------") 558 session.cmd("rm -rf results/*")
515 status = session.get_command_status("bin/autotest control", 559 except kvm_subprocess.ShellError:
516 timeout=timeout, 560 pass
517 print_func=logging.info) 561 try:
518 logging.info("------------- End of test output ------------") 562 bg = None
519 if status is None: 563 try:
520 if not vm.is_alive(): 564 logging.info("---------------- Test output ----------------")
565 if migrate_background:
566 mig_timeout = float(params.get("mig_timeout", "3600"))
567 mig_protocol = params.get("migration_protocol", "tcp")
568
569 bg = kvm_utils.Thread(session.cmd_output,
570 kwargs={'cmd': "bin/autotest control",
571 'timeout': timeout,
572 'print_func': logging.info})
573
574 bg.start()
575
576 while bg.is_alive():
577 logging.info("Tests is not ended, start a round of"
578 "migration ...")
579 vm.migrate(timeout=mig_timeout, protocol=mig_protocol)
580 else:
581 session.cmd_output("bin/autotest control", timeout=timeout,
582 print_func=logging.info)
583 finally:
584 logging.info("------------- End of test output ------------")
585 if migrate_background and bg:
586 bg.join()
587 except kvm_subprocess.ShellTimeoutError:
588 if vm.is_alive():
589 get_results()
590 get_results_summary()
591 raise error.TestError("Timeout elapsed while waiting for job to "
592 "complete")
593 else:
521 raise error.TestError("Autotest job on guest failed " 594 raise error.TestError("Autotest job on guest failed "
522 "(VM terminated during job)") 595 "(VM terminated during job)")
523 if not session.is_alive(): 596 except kvm_subprocess.ShellProcessTerminatedError:
524 get_results()
525 raise error.TestError("Autotest job on guest failed "
526 "(Remote session terminated during job)")
527 get_results() 597 get_results()
528 get_results_summary() 598 raise error.TestError("Autotest job on guest failed "
529 raise error.TestError("Timeout elapsed while waiting for job to " 599 "(Remote session terminated during job)")
530 "complete")
531 600
532 results = get_results_summary() 601 results = get_results_summary()
533 get_results() 602 get_results()
534 603
535 # Make a list of FAIL/ERROR/ABORT results (make sure FAIL results appear 604 # Make a list of FAIL/ERROR/ABORT results (make sure FAIL results appear
536 # before ERROR results, and ERROR results appear before ABORT results) 605 # before ERROR results, and ERROR results appear before ABORT results)
537 bad_results = [r[0] for r in results if r[1] == "FAIL"] 606 bad_results = [r[0] for r in results if r[1] == "FAIL"]
538 bad_results += [r[0] for r in results if r[1] == "ERROR"] 607 bad_results += [r[0] for r in results if r[1] == "ERROR"]
539 bad_results += [r[0] for r in results if r[1] == "ABORT"] 608 bad_results += [r[0] for r in results if r[1] == "ABORT"]
540 609
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 # always get the packet loss ratio even if timeout. 651 # always get the packet loss ratio even if timeout.
583 if process.is_alive(): 652 if process.is_alive():
584 kvm_utils.kill_process_tree(process.get_pid(), signal.SIGINT) 653 kvm_utils.kill_process_tree(process.get_pid(), signal.SIGINT)
585 654
586 status = process.get_status() 655 status = process.get_status()
587 output = process.get_output() 656 output = process.get_output()
588 657
589 process.close() 658 process.close()
590 return status, output 659 return status, output
591 else: 660 else:
592 session.sendline(command) 661 output = ""
593 status, output = session.read_up_to_prompt(timeout=timeout, 662 try:
594 print_func=output_func) 663 output = session.cmd_output(command, timeout=timeout,
595 if not status: 664 print_func=output_func)
665 except kvm_subprocess.ShellTimeoutError:
596 # Send ctrl+c (SIGINT) through ssh session 666 # Send ctrl+c (SIGINT) through ssh session
597 session.send("\003") 667 session.send("\003")
598 status, output2 = session.read_up_to_prompt(print_func=output_func) 668 try:
599 output += output2 669 output2 = session.read_up_to_prompt(print_func=output_func)
600 if not status: 670 output += output2
671 except kvm_subprocess.ExpectTimeoutError, e:
672 output += e.output
601 # We also need to use this session to query the return value 673 # We also need to use this session to query the return value
602 session.send("\003") 674 session.send("\003")
603 675
604 session.sendline(session.status_test_command) 676 session.sendline(session.status_test_command)
605 s2, o2 = session.read_up_to_prompt() 677 try:
606 if not s2: 678 o2 = session.read_up_to_prompt()
679 except kvm_subprocess.ExpectError:
607 status = -1 680 status = -1
608 else: 681 else:
609 try: 682 try:
610 status = int(re.findall("\d+", o2)[0]) 683 status = int(re.findall("\d+", o2)[0])
611 except: 684 except:
612 status = -1 685 status = -1
613 686
614 return status, output 687 return status, output
615 688
616 689
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
663 736
664 737
665 def get_linux_ifname(session, mac_address): 738 def get_linux_ifname(session, mac_address):
666 """ 739 """
667 Get the interface name through the mac address. 740 Get the interface name through the mac address.
668 741
669 @param session: session to the virtual machine 742 @param session: session to the virtual machine
670 @mac_address: the macaddress of nic 743 @mac_address: the macaddress of nic
671 """ 744 """
672 745
673 output = session.get_command_output("ifconfig -a") 746 output = session.cmd_output("ifconfig -a")
674 747
675 try: 748 try:
676 ethname = re.findall("(\w+)\s+Link.*%s" % mac_address, output, 749 ethname = re.findall("(\w+)\s+Link.*%s" % mac_address, output,
677 re.IGNORECASE)[0] 750 re.IGNORECASE)[0]
678 return ethname 751 return ethname
679 except: 752 except:
680 return None 753 return None
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698