blob: 87b0ad222921dfd98c8a35af959ed35d6df4ca56 [file] [log] [blame]
lmr5c226e32009-07-27 13:13:01 +00001import time, os, logging, re, commands
lmr6f669ce2009-05-31 19:02:42 +00002from autotest_lib.client.common_lib import utils, error
lmrd85c55b2009-07-23 01:42:10 +00003import kvm_utils, kvm_subprocess, ppm_utils, scan_results
lmr6f669ce2009-05-31 19:02:42 +00004
5"""
6KVM test definitions.
7
8@copyright: 2008-2009 Red Hat Inc.
9"""
10
11
12def run_boot(test, params, env):
13 """
14 KVM reboot test:
15 1) Log into a guest
16 2) Send a reboot command to the guest
17 3) Wait until it's up.
18 4) Log into the guest to verify it's up again.
19
20 @param test: kvm test object
21 @param params: Dictionary with the test parameters
22 @param env: Dictionary with test environment.
23 """
24 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
25 if not vm:
26 raise error.TestError("VM object not found in environment")
27 if not vm.is_alive():
28 raise error.TestError("VM seems to be dead; Test requires a living VM")
29
30 logging.info("Waiting for guest to be up...")
31
lmr912c74b2009-08-17 20:43:27 +000032 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6f669ce2009-05-31 19:02:42 +000033 if not session:
34 raise error.TestFail("Could not log into guest")
35
36 logging.info("Logged in")
37
38 if params.get("reboot") == "yes":
39 # Send the VM's reboot command
lmr912c74b2009-08-17 20:43:27 +000040 session.sendline(vm.get_params().get("reboot_command"))
lmr6f669ce2009-05-31 19:02:42 +000041 logging.info("Reboot command sent; waiting for guest to go down...")
42
43 if not kvm_utils.wait_for(lambda: not session.is_responsive(),
44 120, 0, 1):
45 raise error.TestFail("Guest refuses to go down")
46
47 session.close()
48
49 logging.info("Guest is down; waiting for it to go up again...")
50
lmr912c74b2009-08-17 20:43:27 +000051 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6f669ce2009-05-31 19:02:42 +000052 if not session:
53 raise error.TestFail("Could not log into guest after reboot")
54
55 logging.info("Guest is up again")
56
57 session.close()
58
59
lmr6faadb22009-06-18 14:57:45 +000060def run_shutdown(test, params, env):
61 """
62 KVM shutdown test:
63 1) Log into a guest
64 2) Send a shutdown command to the guest
65 3) Wait until it's down
66
67 @param test: kvm test object
68 @param params: Dictionary with the test parameters
69 @param env: Dictionary with test environment
70 """
71 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
72 if not vm:
73 raise error.TestError("VM object not found in environment")
74 if not vm.is_alive():
75 raise error.TestError("VM seems to be dead; Test requires a living VM")
76
77 logging.info("Waiting for guest to be up...")
78
lmr912c74b2009-08-17 20:43:27 +000079 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6faadb22009-06-18 14:57:45 +000080 if not session:
81 raise error.TestFail("Could not log into guest")
82
lmr20773742009-08-13 04:43:45 +000083 try:
84 logging.info("Logged in")
lmr6faadb22009-06-18 14:57:45 +000085
lmr20773742009-08-13 04:43:45 +000086 # Send the VM's shutdown command
lmr912c74b2009-08-17 20:43:27 +000087 session.sendline(vm.get_params().get("shutdown_command"))
lmr6faadb22009-06-18 14:57:45 +000088
lmr20773742009-08-13 04:43:45 +000089 logging.info("Shutdown command sent; waiting for guest to go down...")
lmr6faadb22009-06-18 14:57:45 +000090
lmr20773742009-08-13 04:43:45 +000091 if not kvm_utils.wait_for(vm.is_dead, 240, 0, 1):
92 raise error.TestFail("Guest refuses to go down")
lmr6faadb22009-06-18 14:57:45 +000093
lmr20773742009-08-13 04:43:45 +000094 logging.info("Guest is down")
95 finally:
96 session.close()
lmr6faadb22009-06-18 14:57:45 +000097
98
lmr6f669ce2009-05-31 19:02:42 +000099def run_migration(test, params, env):
100 """
101 KVM migration test:
102
103 1) Get two live VMs. One will be the 'source', the other will be the
104 'destination'.
105 2) Verify if the source VM supports migration. If it does, proceed with
106 the test
107 3) Send a migration command to the source vm and wait until it's finished.
108 4) Kill off the source vm
109 3) Log into the destination vm after the migration is finished.
110 4) Compare the output of a reference command executed on the source with
111 the output of the same command on the destination machine
112
113 @param test: kvm test object.
114 @param params: Dictionary with test parameters.
115 @param env: Dictionary with the test environment.
116 """
117 src_vm_name = params.get("migration_src")
118 vm = kvm_utils.env_get_vm(env, src_vm_name)
119 if not vm:
120 raise error.TestError("VM '%s' not found in environment" % src_vm_name)
121 if not vm.is_alive():
122 raise error.TestError("VM '%s' seems to be dead; Test requires a"
123 " living VM" % src_vm_name)
124
125 dest_vm_name = params.get("migration_dst")
126 dest_vm = kvm_utils.env_get_vm(env, dest_vm_name)
127 if not dest_vm:
128 raise error.TestError("VM '%s' not found in environment" % dest_vm_name)
129 if not dest_vm.is_alive():
130 raise error.TestError("VM '%s' seems to be dead; Test requires a"
131 " living VM" % dest_vm_name)
132
133 pre_scrdump_filename = os.path.join(test.debugdir, "migration_pre.ppm")
134 post_scrdump_filename = os.path.join(test.debugdir, "migration_post.ppm")
135
136 # See if migration is supported
137 s, o = vm.send_monitor_cmd("help info")
138 if not "info migrate" in o:
139 raise error.TestError("Migration is not supported")
140
141 # Log into guest and get the output of migration_test_command
142 logging.info("Waiting for guest to be up...")
143
lmr912c74b2009-08-17 20:43:27 +0000144 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6f669ce2009-05-31 19:02:42 +0000145 if not session:
146 raise error.TestFail("Could not log into guest")
147
148 logging.info("Logged in")
149
150 reference_output = session.get_command_output(params.get("migration_test_"
151 "command"))
152 session.close()
153
154 # Define the migration command
155 cmd = "migrate -d tcp:localhost:%d" % dest_vm.migration_port
156 logging.debug("Migration command: %s" % cmd)
157
158 # Migrate
159 s, o = vm.send_monitor_cmd(cmd)
160 if s:
161 logging.error("Migration command failed (command: %r, output: %r)" %
162 (cmd, o))
163 raise error.TestFail("Migration command failed")
164
165 # Define some helper functions
166 def mig_finished():
167 s, o = vm.send_monitor_cmd("info migrate")
168 if s:
169 return False
170 if "Migration status: active" in o:
171 return False
172 return True
173
174 def mig_succeeded():
175 s, o = vm.send_monitor_cmd("info migrate")
176 if s == 0 and "Migration status: completed" in o:
177 return True
178 return False
179
180 def mig_failed():
181 s, o = vm.send_monitor_cmd("info migrate")
182 if s == 0 and "Migration status: failed" in o:
183 return True
184 return False
185
186 # Wait for migration to finish
187 if not kvm_utils.wait_for(mig_finished, 90, 2, 2,
188 "Waiting for migration to finish..."):
189 raise error.TestFail("Timeout elapsed while waiting for migration to"
190 "finish")
191
192 # Report migration status
193 if mig_succeeded():
194 logging.info("Migration finished successfully")
195 else:
196 if mig_failed():
197 message = "Migration failed"
198 else:
199 message = "Migration ended with unknown status"
200 raise error.TestFail(message)
201
202 # Get 'post' screendump
203 dest_vm.send_monitor_cmd("screendump %s" % post_scrdump_filename)
204
205 # Get 'pre' screendump
206 vm.send_monitor_cmd("screendump %s" % pre_scrdump_filename)
207
208 # Kill the source VM
209 vm.send_monitor_cmd("quit", block=False)
210
211 # Hack: it seems that the first attempt to communicate with the SSH port
212 # following migration always fails (or succeeds after a very long time).
lmr912c74b2009-08-17 20:43:27 +0000213 # So just connect to the port once so the following call to remote_login
lmr6f669ce2009-05-31 19:02:42 +0000214 # succeeds.
215 dest_vm.is_sshd_running(timeout=0.0)
216
217 # Log into guest and get the output of migration_test_command
218 logging.info("Logging into guest after migration...")
219
lmr912c74b2009-08-17 20:43:27 +0000220 session = dest_vm.remote_login()
lmr6f669ce2009-05-31 19:02:42 +0000221 if not session:
222 raise error.TestFail("Could not log into guest after migration")
223
224 logging.info("Logged in after migration")
225
226 output = session.get_command_output(params.get("migration_test_command"))
227 session.close()
228
229 # Compare output to reference output
230 if output != reference_output:
231 logging.info("Command output before migration differs from command"
232 " output after migration")
233 logging.info("Command: %s" % params.get("migration_test_command"))
234 logging.info("Output before:" +
235 kvm_utils.format_str_for_message(reference_output))
236 logging.info("Output after:" + kvm_utils.format_str_for_message(output))
237 raise error.TestFail("Command produced different output before and"
238 " after migration")
239
240
241def run_autotest(test, params, env):
242 """
243 Run an autotest test inside a guest.
244
245 @param test: kvm test object.
246 @param params: Dictionary with test parameters.
247 @param env: Dictionary with the test environment.
248 """
249 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
250 if not vm:
251 raise error.TestError("VM object not found in environment")
252 if not vm.is_alive():
253 raise error.TestError("VM seems to be dead; Test requires a living VM")
254
255 logging.info("Logging into guest...")
256
lmr912c74b2009-08-17 20:43:27 +0000257 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6f669ce2009-05-31 19:02:42 +0000258 if not session:
259 raise error.TestFail("Could not log into guest")
260
261 logging.info("Logged in")
262
263 # Collect some info
264 test_name = params.get("test_name")
265 test_timeout = int(params.get("test_timeout", 300))
266 test_control_file = params.get("test_control_file", "control")
267 tarred_autotest_path = "/tmp/autotest.tar.bz2"
268 tarred_test_path = "/tmp/%s.tar.bz2" % test_name
269
270 # tar the contents of bindir/autotest
271 cmd = "cd %s; tar cvjf %s autotest/*"
272 cmd += " --exclude=autotest/tests"
273 cmd += " --exclude=autotest/results"
274 cmd += " --exclude=autotest/tmp"
275 cmd += " --exclude=autotest/control"
276 cmd += " --exclude=*.pyc"
277 cmd += " --exclude=*.svn"
278 cmd += " --exclude=*.git"
lmrd85c55b2009-07-23 01:42:10 +0000279 kvm_subprocess.run_fg(cmd % (test.bindir, tarred_autotest_path), timeout=30)
lmr6f669ce2009-05-31 19:02:42 +0000280
281 # tar the contents of bindir/autotest/tests/<test_name>
282 cmd = "cd %s; tar cvjf %s %s/*"
283 cmd += " --exclude=*.pyc"
284 cmd += " --exclude=*.svn"
285 cmd += " --exclude=*.git"
lmrd85c55b2009-07-23 01:42:10 +0000286 kvm_subprocess.run_fg(cmd %
287 (os.path.join(test.bindir, "autotest", "tests"),
288 tarred_test_path, test_name), timeout=30)
lmr6f669ce2009-05-31 19:02:42 +0000289
290 # Check if we need to copy autotest.tar.bz2
291 copy = False
292 output = session.get_command_output("ls -l autotest.tar.bz2")
293 if "such file" in output:
294 copy = True
295 else:
296 size = int(output.split()[4])
297 if size != os.path.getsize(tarred_autotest_path):
298 copy = True
299 # Perform the copy
300 if copy:
301 logging.info("Copying autotest.tar.bz2 to guest"
302 " (file is missing or has a different size)...")
lmr912c74b2009-08-17 20:43:27 +0000303 if not vm.copy_files_to(tarred_autotest_path, ""):
lmr6f669ce2009-05-31 19:02:42 +0000304 raise error.TestFail("Could not copy autotest.tar.bz2 to guest")
305
306 # Check if we need to copy <test_name>.tar.bz2
307 copy = False
308 output = session.get_command_output("ls -l %s.tar.bz2" % test_name)
309 if "such file" in output:
310 copy = True
311 else:
312 size = int(output.split()[4])
313 if size != os.path.getsize(tarred_test_path):
314 copy = True
315 # Perform the copy
316 if copy:
317 logging.info("Copying %s.tar.bz2 to guest (file is missing or has a"
318 " different size)..." % test_name)
lmr912c74b2009-08-17 20:43:27 +0000319 if not vm.copy_files_to(tarred_test_path, ""):
lmr6f669ce2009-05-31 19:02:42 +0000320 raise error.TestFail("Could not copy %s.tar.bz2 to guest" %
321 test_name)
322
323 # Extract autotest.tar.bz2
324 logging.info("Extracting autotest.tar.bz2...")
325 status = session.get_command_status("tar xvfj autotest.tar.bz2")
326 if status != 0:
327 raise error.TestFail("Could not extract autotest.tar.bz2")
328
329 # mkdir autotest/tests
330 session.sendline("mkdir autotest/tests")
331
332 # Extract <test_name>.tar.bz2 into autotest/tests
333 logging.info("Extracting %s.tar.bz2..." % test_name)
334 status = session.get_command_status("tar xvfj %s.tar.bz2 -C "
335 "autotest/tests" % test_name)
336 if status != 0:
337 raise error.TestFail("Could not extract %s.tar.bz2" % test_name)
338
lmr16cf1652009-06-15 21:32:49 +0000339 # Cleaning up old remaining results
340 session.sendline("rm -rf autotest/results/*")
341 # Copying the selected control file (located inside
342 # test.bindir/autotest_control to the autotest dir
343 control_file_path = os.path.join(test.bindir, "autotest_control",
344 test_control_file)
lmr912c74b2009-08-17 20:43:27 +0000345 if not vm.copy_files_to(control_file_path, "autotest/control"):
lmr16cf1652009-06-15 21:32:49 +0000346 raise error.TestFail("Could not copy the test control file to guest")
lmr6f669ce2009-05-31 19:02:42 +0000347 # Run the test
348 logging.info("Running test '%s'..." % test_name)
lmr16cf1652009-06-15 21:32:49 +0000349 session.sendline("cd autotest")
350 session.sendline("rm -f control.state")
lmr6f669ce2009-05-31 19:02:42 +0000351 session.read_up_to_prompt()
lmr16cf1652009-06-15 21:32:49 +0000352 session.sendline("bin/autotest control")
lmr6f669ce2009-05-31 19:02:42 +0000353 logging.info("---------------- Test output ----------------")
lmr16cf1652009-06-15 21:32:49 +0000354 match = session.read_up_to_prompt(timeout=test_timeout,
355 print_func=logging.info)[0]
lmr6f669ce2009-05-31 19:02:42 +0000356 logging.info("---------------- End of test output ----------------")
357 if not match:
lmr16cf1652009-06-15 21:32:49 +0000358 raise error.TestFail("Timeout elapsed while waiting for test to "
359 "complete")
360 # Get the results generated by autotest
361 output = session.get_command_output("cat results/*/status")
lmr6f669ce2009-05-31 19:02:42 +0000362
363 # Parse test results
364 result_list = scan_results.parse_results(output)
365
366 # Report test results and check for FAIL/ERROR status
367 logging.info("Results (test, status, duration, info):")
368 status_error = False
369 status_fail = False
370 if result_list == []:
371 status_fail = True
lmrd16a67d2009-06-10 19:52:59 +0000372 message_fail = ("Test '%s' did not produce any recognizable "
373 "results" % test_name)
lmr6f669ce2009-05-31 19:02:42 +0000374 for result in result_list:
375 logging.info(str(result))
376 if result[1] == "FAIL":
377 status_fail = True
lmr50bece42009-06-15 20:54:43 +0000378 message_fail = ("Test '%s' ended with FAIL "
379 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000380 if result[1] == "ERROR":
381 status_error = True
lmr50bece42009-06-15 20:54:43 +0000382 message_error = ("Test '%s' ended with ERROR "
383 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000384 if result[1] == "ABORT":
385 status_error = True
lmr50bece42009-06-15 20:54:43 +0000386 message_error = ("Test '%s' ended with ABORT "
387 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000388
389 # Copy test results to the local bindir/guest_results
390 logging.info("Copying results back from guest...")
391 guest_results_dir = os.path.join(test.outputdir, "guest_results")
392 if not os.path.exists(guest_results_dir):
393 os.mkdir(guest_results_dir)
lmr912c74b2009-08-17 20:43:27 +0000394 if not vm.copy_files_from("autotest/results/default/*", guest_results_dir):
lmr6f669ce2009-05-31 19:02:42 +0000395 logging.error("Could not copy results back from guest")
396
397 # Fail the test if necessary
398 if status_fail:
399 raise error.TestFail(message_fail)
400 elif status_error:
401 raise error.TestError(message_error)
402
403
404def internal_yum_update(session, command, prompt, timeout):
405 """
406 Helper function to perform the yum update test.
407
lmr912c74b2009-08-17 20:43:27 +0000408 @param session: shell session stablished to the host
409 @param command: Command to be sent to the shell session
lmr6f669ce2009-05-31 19:02:42 +0000410 @param prompt: Machine prompt
411 @param timeout: How long to wait until we get an appropriate output from
lmr912c74b2009-08-17 20:43:27 +0000412 the shell session.
lmr6f669ce2009-05-31 19:02:42 +0000413 """
414 session.sendline(command)
415 end_time = time.time() + timeout
416 while time.time() < end_time:
417 (match, text) = session.read_until_last_line_matches(
418 ["[Ii]s this [Oo][Kk]", prompt], timeout=timeout)
419 if match == 0:
420 logging.info("Got 'Is this ok'; sending 'y'")
421 session.sendline("y")
422 elif match == 1:
423 logging.info("Got shell prompt")
424 return True
425 else:
426 logging.info("Timeout or process exited")
427 return False
428
429
430def run_yum_update(test, params, env):
431 """
432 Runs yum update and yum update kernel on the remote host (yum enabled
433 hosts only).
434
435 @param test: kvm test object.
436 @param params: Dictionary with test parameters.
437 @param env: Dictionary with the test environment.
438 """
439 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
440 if not vm:
441 message = "VM object not found in environment"
442 logging.error(message)
443 raise error.TestError(message)
444 if not vm.is_alive():
445 message = "VM seems to be dead; Test requires a living VM"
446 logging.error(message)
447 raise error.TestError(message)
448
449 logging.info("Logging into guest...")
450
lmr912c74b2009-08-17 20:43:27 +0000451 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6f669ce2009-05-31 19:02:42 +0000452 if not session:
453 message = "Could not log into guest"
454 logging.error(message)
455 raise error.TestFail(message)
456
457 logging.info("Logged in")
458
lmr912c74b2009-08-17 20:43:27 +0000459 internal_yum_update(session, "yum update", params.get("shell_prompt"), 600)
lmr6f669ce2009-05-31 19:02:42 +0000460 internal_yum_update(session, "yum update kernel",
lmr912c74b2009-08-17 20:43:27 +0000461 params.get("shell_prompt"), 600)
lmr6f669ce2009-05-31 19:02:42 +0000462
463 session.close()
464
465
466def run_linux_s3(test, params, env):
467 """
468 Suspend a guest Linux OS to memory.
469
470 @param test: kvm test object.
471 @param params: Dictionary with test parameters.
472 @param env: Dictionary with the test environment.
473 """
474 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
475 if not vm:
476 raise error.TestError("VM object not found in environment")
477 if not vm.is_alive():
478 raise error.TestError("VM seems to be dead; Test requires a living VM")
479
480 logging.info("Waiting for guest to be up...")
481
lmr912c74b2009-08-17 20:43:27 +0000482 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6f669ce2009-05-31 19:02:42 +0000483 if not session:
484 raise error.TestFail("Could not log into guest")
485
486 logging.info("Logged in")
487 logging.info("Checking that VM supports S3")
488
489 status = session.get_command_status("grep -q mem /sys/power/state")
490 if status == None:
491 logging.error("Failed to check if S3 exists")
492 elif status != 0:
493 raise error.TestFail("Guest does not support S3")
494
495 logging.info("Waiting for a while for X to start")
496 time.sleep(10)
497
498 src_tty = session.get_command_output("fgconsole").strip()
499 logging.info("Current virtual terminal is %s" % src_tty)
500 if src_tty not in map(str, range(1,10)):
501 raise error.TestFail("Got a strange current vt (%s)" % src_tty)
502
503 dst_tty = "1"
504 if src_tty == "1":
505 dst_tty = "2"
506
507 logging.info("Putting VM into S3")
508 command = "chvt %s && echo mem > /sys/power/state && chvt %s" % (dst_tty,
509 src_tty)
510 status = session.get_command_status(command, timeout=120)
511 if status != 0:
512 raise error.TestFail("Suspend to mem failed")
513
514 logging.info("VM resumed after S3")
515
516 session.close()
lmra04d7c92009-06-19 13:05:39 +0000517
518
519def run_stress_boot(tests, params, env):
520 """
521 Boots VMs until one of them becomes unresponsive, and records the maximum
522 number of VMs successfully started:
523 1) boot the first vm
524 2) boot the second vm cloned from the first vm, check whether it boots up
lmr912c74b2009-08-17 20:43:27 +0000525 and all booted vms respond to shell commands
lmra04d7c92009-06-19 13:05:39 +0000526 3) go on until cannot create VM anymore or cannot allocate memory for VM
527
528 @param test: kvm test object
529 @param params: Dictionary with the test parameters
530 @param env: Dictionary with test environment.
531 """
532 # boot the first vm
533 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
lmra04d7c92009-06-19 13:05:39 +0000534 if not vm:
535 raise error.TestError("VM object not found in environment")
536 if not vm.is_alive():
537 raise error.TestError("VM seems to be dead; Test requires a living VM")
538
539 logging.info("Waiting for first guest to be up...")
540
lmr912c74b2009-08-17 20:43:27 +0000541 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmra04d7c92009-06-19 13:05:39 +0000542 if not session:
543 raise error.TestFail("Could not log into first guest")
544
545 num = 2
lmra04d7c92009-06-19 13:05:39 +0000546 sessions = [session]
lmr26bac242009-08-13 04:14:24 +0000547 address_index = int(params.get("clone_address_index_base", 10))
lmra04d7c92009-06-19 13:05:39 +0000548
549 # boot the VMs
550 while num <= int(params.get("max_vms")):
551 try:
552 vm_name = "vm" + str(num)
553
554 # clone vm according to the first one
lmr26bac242009-08-13 04:14:24 +0000555 vm_params = vm.get_params().copy()
556 vm_params["address_index"] = str(address_index)
lmra04d7c92009-06-19 13:05:39 +0000557 curr_vm = vm.clone(vm_name, vm_params)
558 kvm_utils.env_register_vm(env, vm_name, curr_vm)
559 params['vms'] += " " + vm_name
560
lmra04d7c92009-06-19 13:05:39 +0000561 logging.info("Booting guest #%d" % num)
562 if not curr_vm.create():
563 raise error.TestFail("Cannot create VM #%d" % num)
564
lmr912c74b2009-08-17 20:43:27 +0000565 curr_vm_session = kvm_utils.wait_for(curr_vm.remote_login, 240, 0, 2)
lmra04d7c92009-06-19 13:05:39 +0000566 if not curr_vm_session:
567 raise error.TestFail("Could not log into guest #%d" % num)
568
569 logging.info("Guest #%d boots up successfully" % num)
570 sessions.append(curr_vm_session)
571
lmr912c74b2009-08-17 20:43:27 +0000572 # check whether all previous shell sessions are responsive
lmr26bac242009-08-13 04:14:24 +0000573 for i, se in enumerate(sessions):
574 if se.get_command_status(params.get("alive_test_cmd")) != 0:
lmra04d7c92009-06-19 13:05:39 +0000575 raise error.TestFail("Session #%d is not responsive" % i)
576 num += 1
lmr26bac242009-08-13 04:14:24 +0000577 address_index += 1
lmra04d7c92009-06-19 13:05:39 +0000578
579 except (error.TestFail, OSError):
580 for se in sessions:
581 se.close()
582 logging.info("Total number booted: %d" % (num - 1))
583 raise
584 else:
585 for se in sessions:
586 se.close()
587 logging.info("Total number booted: %d" % (num -1))
lmr5c226e32009-07-27 13:13:01 +0000588
589
590def run_timedrift(test, params, env):
591 """
592 Time drift test (mainly for Windows guests):
593
594 1) Log into a guest.
595 2) Take a time reading from the guest and host.
596 3) Run load on the guest and host.
597 4) Take a second time reading.
598 5) Stop the load and rest for a while.
599 6) Take a third time reading.
600 7) If the drift immediately after load is higher than a user-
601 specified value (in %), fail.
602 If the drift after the rest period is higher than a user-specified value,
603 fail.
604
605 @param test: KVM test object.
606 @param params: Dictionary with test parameters.
607 @param env: Dictionary with the test environment.
608 """
lmr25e89fc2009-08-07 20:29:16 +0000609 # Helper functions
610 def set_cpu_affinity(pid, mask):
611 """
612 Set the CPU affinity of all threads of the process with PID pid.
613
614 @param pid: The process ID.
615 @param mask: The CPU affinity mask.
616 @return: A dict containing the previous mask for each thread.
617 """
618 tids = commands.getoutput("ps -L --pid=%s -o lwp=" % pid).split()
619 prev_masks = {}
620 for tid in tids:
621 prev_mask = commands.getoutput("taskset -p %s" % tid).split()[-1]
622 prev_masks[tid] = prev_mask
623 commands.getoutput("taskset -p %s %s" % (mask, tid))
624 return prev_masks
625
626 def restore_cpu_affinity(prev_masks):
627 """
628 Restore the CPU affinity of several threads.
629
630 @param prev_masks: A dict containing TIDs as keys and masks as values.
631 """
632 for tid, mask in prev_masks.items():
633 commands.getoutput("taskset -p %s %s" % (mask, tid))
634
lmrff2a7c52009-08-10 00:09:22 +0000635 def get_time(session, time_command, time_filter_re, time_format):
lmr25e89fc2009-08-07 20:29:16 +0000636 """
637 Returns the host time and guest time.
638
lmrff2a7c52009-08-10 00:09:22 +0000639 @param session: A shell session.
640 @param time_command: Command to issue to get the current guest time.
641 @param time_filter_re: Regex filter to apply on the output of
642 time_command in order to get the current time.
643 @param time_format: Format string to pass to time.strptime() with the
644 result of the regex filter.
lmr25e89fc2009-08-07 20:29:16 +0000645 @return: A tuple containing the host time and guest time.
646 """
647 host_time = time.time()
648 session.sendline(time_command)
649 (match, s) = session.read_up_to_prompt()
650 s = re.findall(time_filter_re, s)[0]
651 guest_time = time.mktime(time.strptime(s, time_format))
652 return (host_time, guest_time)
653
lmr5c226e32009-07-27 13:13:01 +0000654 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
655 if not vm:
656 raise error.TestError("VM object not found in environment")
657 if not vm.is_alive():
658 raise error.TestError("VM seems to be dead; Test requires a living VM")
659
660 logging.info("Waiting for guest to be up...")
661
lmr912c74b2009-08-17 20:43:27 +0000662 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr5c226e32009-07-27 13:13:01 +0000663 if not session:
664 raise error.TestFail("Could not log into guest")
665
666 logging.info("Logged in")
667
668 # Collect test parameters:
669 # Command to run to get the current time
670 time_command = params.get("time_command")
671 # Filter which should match a string to be passed to time.strptime()
672 time_filter_re = params.get("time_filter_re")
673 # Time format for time.strptime()
674 time_format = params.get("time_format")
675 guest_load_command = params.get("guest_load_command")
676 guest_load_stop_command = params.get("guest_load_stop_command")
677 host_load_command = params.get("host_load_command")
678 guest_load_instances = int(params.get("guest_load_instances", "1"))
679 host_load_instances = int(params.get("host_load_instances", "0"))
680 # CPU affinity mask for taskset
681 cpu_mask = params.get("cpu_mask", "0xFF")
682 load_duration = float(params.get("load_duration", "30"))
683 rest_duration = float(params.get("rest_duration", "10"))
684 drift_threshold = float(params.get("drift_threshold", "200"))
685 drift_threshold_after_rest = float(params.get("drift_threshold_after_rest",
686 "200"))
687
688 guest_load_sessions = []
689 host_load_sessions = []
690
lmr5c226e32009-07-27 13:13:01 +0000691 # Set the VM's CPU affinity
lmr25e89fc2009-08-07 20:29:16 +0000692 prev_affinity = set_cpu_affinity(vm.get_pid(), cpu_mask)
lmr5c226e32009-07-27 13:13:01 +0000693
694 try:
695 # Get time before load
lmrff2a7c52009-08-10 00:09:22 +0000696 (host_time_0, guest_time_0) = get_time(session, time_command,
697 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000698
699 # Run some load on the guest
700 logging.info("Starting load on guest...")
701 for i in range(guest_load_instances):
lmr912c74b2009-08-17 20:43:27 +0000702 load_session = vm.remote_login()
lmr5c226e32009-07-27 13:13:01 +0000703 if not load_session:
704 raise error.TestFail("Could not log into guest")
705 load_session.set_output_prefix("(guest load %d) " % i)
706 load_session.set_output_func(logging.debug)
707 load_session.sendline(guest_load_command)
708 guest_load_sessions.append(load_session)
709
710 # Run some load on the host
711 logging.info("Starting load on host...")
712 for i in range(host_load_instances):
713 host_load_sessions.append(
714 kvm_subprocess.run_bg(host_load_command,
715 output_func=logging.debug,
716 output_prefix="(host load %d) " % i,
717 timeout=0.5))
718 # Set the CPU affinity of the shell running the load process
719 pid = host_load_sessions[-1].get_shell_pid()
lmr25e89fc2009-08-07 20:29:16 +0000720 set_cpu_affinity(pid, cpu_mask)
lmr5c226e32009-07-27 13:13:01 +0000721 # Try setting the CPU affinity of the load process itself
722 pid = host_load_sessions[-1].get_pid()
723 if pid:
lmr25e89fc2009-08-07 20:29:16 +0000724 set_cpu_affinity(pid, cpu_mask)
lmr5c226e32009-07-27 13:13:01 +0000725
726 # Sleep for a while (during load)
727 logging.info("Sleeping for %s seconds..." % load_duration)
728 time.sleep(load_duration)
729
730 # Get time delta after load
lmrff2a7c52009-08-10 00:09:22 +0000731 (host_time_1, guest_time_1) = get_time(session, time_command,
732 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000733
734 # Report results
735 host_delta = host_time_1 - host_time_0
736 guest_delta = guest_time_1 - guest_time_0
737 drift = 100.0 * (host_delta - guest_delta) / host_delta
738 logging.info("Host duration: %.2f" % host_delta)
739 logging.info("Guest duration: %.2f" % guest_delta)
740 logging.info("Drift: %.2f%%" % drift)
741
742 finally:
743 logging.info("Cleaning up...")
744 # Restore the VM's CPU affinity
lmr25e89fc2009-08-07 20:29:16 +0000745 restore_cpu_affinity(prev_affinity)
lmr5c226e32009-07-27 13:13:01 +0000746 # Stop the guest load
747 if guest_load_stop_command:
748 session.get_command_output(guest_load_stop_command)
749 # Close all load shell sessions
750 for load_session in guest_load_sessions:
751 load_session.close()
752 for load_session in host_load_sessions:
753 load_session.close()
754
755 # Sleep again (rest)
756 logging.info("Sleeping for %s seconds..." % rest_duration)
757 time.sleep(rest_duration)
758
759 # Get time after rest
lmrff2a7c52009-08-10 00:09:22 +0000760 (host_time_2, guest_time_2) = get_time(session, time_command,
761 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000762
763 # Report results
764 host_delta_total = host_time_2 - host_time_0
765 guest_delta_total = guest_time_2 - guest_time_0
766 drift_total = 100.0 * (host_delta_total - guest_delta_total) / host_delta
767 logging.info("Total host duration including rest: %.2f" % host_delta_total)
768 logging.info("Total guest duration including rest: %.2f" % guest_delta_total)
769 logging.info("Total drift after rest: %.2f%%" % drift_total)
770
lmr5b829602009-08-07 20:36:06 +0000771 session.close()
772
lmr5c226e32009-07-27 13:13:01 +0000773 # Fail the test if necessary
774 if drift > drift_threshold:
775 raise error.TestFail("Time drift too large: %.2f%%" % drift)
776 if drift > drift_threshold_after_rest:
777 raise error.TestFail("Time drift too large after rest period: %.2f%%"
778 % drift_total)