blob: 5991aed66ee7971a17e86188c4d014ec7b031b38 [file] [log] [blame]
lmr6f669ce2009-05-31 19:02:42 +00001import time, os, logging
2from 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
32 session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
33 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
40 session.sendline(vm.get_params().get("cmd_reboot"))
41 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
51 session = kvm_utils.wait_for(vm.ssh_login, 120, 0, 2)
52 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
79 session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
80 if not session:
81 raise error.TestFail("Could not log into guest")
82
83 logging.info("Logged in")
84
85 # Send the VM's shutdown command
86 session.sendline(vm.get_params().get("cmd_shutdown"))
87 session.close()
88
89 logging.info("Shutdown command sent; waiting for guest to go down...")
90
91 if not kvm_utils.wait_for(vm.is_dead, 120, 0, 1):
92 raise error.TestFail("Guest refuses to go down")
93
94 logging.info("Guest is down")
95
96
lmr6f669ce2009-05-31 19:02:42 +000097def run_migration(test, params, env):
98 """
99 KVM migration test:
100
101 1) Get two live VMs. One will be the 'source', the other will be the
102 'destination'.
103 2) Verify if the source VM supports migration. If it does, proceed with
104 the test
105 3) Send a migration command to the source vm and wait until it's finished.
106 4) Kill off the source vm
107 3) Log into the destination vm after the migration is finished.
108 4) Compare the output of a reference command executed on the source with
109 the output of the same command on the destination machine
110
111 @param test: kvm test object.
112 @param params: Dictionary with test parameters.
113 @param env: Dictionary with the test environment.
114 """
115 src_vm_name = params.get("migration_src")
116 vm = kvm_utils.env_get_vm(env, src_vm_name)
117 if not vm:
118 raise error.TestError("VM '%s' not found in environment" % src_vm_name)
119 if not vm.is_alive():
120 raise error.TestError("VM '%s' seems to be dead; Test requires a"
121 " living VM" % src_vm_name)
122
123 dest_vm_name = params.get("migration_dst")
124 dest_vm = kvm_utils.env_get_vm(env, dest_vm_name)
125 if not dest_vm:
126 raise error.TestError("VM '%s' not found in environment" % dest_vm_name)
127 if not dest_vm.is_alive():
128 raise error.TestError("VM '%s' seems to be dead; Test requires a"
129 " living VM" % dest_vm_name)
130
131 pre_scrdump_filename = os.path.join(test.debugdir, "migration_pre.ppm")
132 post_scrdump_filename = os.path.join(test.debugdir, "migration_post.ppm")
133
134 # See if migration is supported
135 s, o = vm.send_monitor_cmd("help info")
136 if not "info migrate" in o:
137 raise error.TestError("Migration is not supported")
138
139 # Log into guest and get the output of migration_test_command
140 logging.info("Waiting for guest to be up...")
141
142 session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
143 if not session:
144 raise error.TestFail("Could not log into guest")
145
146 logging.info("Logged in")
147
148 reference_output = session.get_command_output(params.get("migration_test_"
149 "command"))
150 session.close()
151
152 # Define the migration command
153 cmd = "migrate -d tcp:localhost:%d" % dest_vm.migration_port
154 logging.debug("Migration command: %s" % cmd)
155
156 # Migrate
157 s, o = vm.send_monitor_cmd(cmd)
158 if s:
159 logging.error("Migration command failed (command: %r, output: %r)" %
160 (cmd, o))
161 raise error.TestFail("Migration command failed")
162
163 # Define some helper functions
164 def mig_finished():
165 s, o = vm.send_monitor_cmd("info migrate")
166 if s:
167 return False
168 if "Migration status: active" in o:
169 return False
170 return True
171
172 def mig_succeeded():
173 s, o = vm.send_monitor_cmd("info migrate")
174 if s == 0 and "Migration status: completed" in o:
175 return True
176 return False
177
178 def mig_failed():
179 s, o = vm.send_monitor_cmd("info migrate")
180 if s == 0 and "Migration status: failed" in o:
181 return True
182 return False
183
184 # Wait for migration to finish
185 if not kvm_utils.wait_for(mig_finished, 90, 2, 2,
186 "Waiting for migration to finish..."):
187 raise error.TestFail("Timeout elapsed while waiting for migration to"
188 "finish")
189
190 # Report migration status
191 if mig_succeeded():
192 logging.info("Migration finished successfully")
193 else:
194 if mig_failed():
195 message = "Migration failed"
196 else:
197 message = "Migration ended with unknown status"
198 raise error.TestFail(message)
199
200 # Get 'post' screendump
201 dest_vm.send_monitor_cmd("screendump %s" % post_scrdump_filename)
202
203 # Get 'pre' screendump
204 vm.send_monitor_cmd("screendump %s" % pre_scrdump_filename)
205
206 # Kill the source VM
207 vm.send_monitor_cmd("quit", block=False)
208
209 # Hack: it seems that the first attempt to communicate with the SSH port
210 # following migration always fails (or succeeds after a very long time).
211 # So just connect to the port once so the following call to ssh_login
212 # succeeds.
213 dest_vm.is_sshd_running(timeout=0.0)
214
215 # Log into guest and get the output of migration_test_command
216 logging.info("Logging into guest after migration...")
217
218 session = dest_vm.ssh_login()
219 if not session:
220 raise error.TestFail("Could not log into guest after migration")
221
222 logging.info("Logged in after migration")
223
224 output = session.get_command_output(params.get("migration_test_command"))
225 session.close()
226
227 # Compare output to reference output
228 if output != reference_output:
229 logging.info("Command output before migration differs from command"
230 " output after migration")
231 logging.info("Command: %s" % params.get("migration_test_command"))
232 logging.info("Output before:" +
233 kvm_utils.format_str_for_message(reference_output))
234 logging.info("Output after:" + kvm_utils.format_str_for_message(output))
235 raise error.TestFail("Command produced different output before and"
236 " after migration")
237
238
239def run_autotest(test, params, env):
240 """
241 Run an autotest test inside a guest.
242
243 @param test: kvm test object.
244 @param params: Dictionary with test parameters.
245 @param env: Dictionary with the test environment.
246 """
247 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
248 if not vm:
249 raise error.TestError("VM object not found in environment")
250 if not vm.is_alive():
251 raise error.TestError("VM seems to be dead; Test requires a living VM")
252
253 logging.info("Logging into guest...")
254
255 session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
256 if not session:
257 raise error.TestFail("Could not log into guest")
258
259 logging.info("Logged in")
260
261 # Collect some info
262 test_name = params.get("test_name")
263 test_timeout = int(params.get("test_timeout", 300))
264 test_control_file = params.get("test_control_file", "control")
265 tarred_autotest_path = "/tmp/autotest.tar.bz2"
266 tarred_test_path = "/tmp/%s.tar.bz2" % test_name
267
268 # tar the contents of bindir/autotest
269 cmd = "cd %s; tar cvjf %s autotest/*"
270 cmd += " --exclude=autotest/tests"
271 cmd += " --exclude=autotest/results"
272 cmd += " --exclude=autotest/tmp"
273 cmd += " --exclude=autotest/control"
274 cmd += " --exclude=*.pyc"
275 cmd += " --exclude=*.svn"
276 cmd += " --exclude=*.git"
lmrd85c55b2009-07-23 01:42:10 +0000277 kvm_subprocess.run_fg(cmd % (test.bindir, tarred_autotest_path), timeout=30)
lmr6f669ce2009-05-31 19:02:42 +0000278
279 # tar the contents of bindir/autotest/tests/<test_name>
280 cmd = "cd %s; tar cvjf %s %s/*"
281 cmd += " --exclude=*.pyc"
282 cmd += " --exclude=*.svn"
283 cmd += " --exclude=*.git"
lmrd85c55b2009-07-23 01:42:10 +0000284 kvm_subprocess.run_fg(cmd %
285 (os.path.join(test.bindir, "autotest", "tests"),
286 tarred_test_path, test_name), timeout=30)
lmr6f669ce2009-05-31 19:02:42 +0000287
288 # Check if we need to copy autotest.tar.bz2
289 copy = False
290 output = session.get_command_output("ls -l autotest.tar.bz2")
291 if "such file" in output:
292 copy = True
293 else:
294 size = int(output.split()[4])
295 if size != os.path.getsize(tarred_autotest_path):
296 copy = True
297 # Perform the copy
298 if copy:
299 logging.info("Copying autotest.tar.bz2 to guest"
300 " (file is missing or has a different size)...")
301 if not vm.scp_to_remote(tarred_autotest_path, ""):
302 raise error.TestFail("Could not copy autotest.tar.bz2 to guest")
303
304 # Check if we need to copy <test_name>.tar.bz2
305 copy = False
306 output = session.get_command_output("ls -l %s.tar.bz2" % test_name)
307 if "such file" in output:
308 copy = True
309 else:
310 size = int(output.split()[4])
311 if size != os.path.getsize(tarred_test_path):
312 copy = True
313 # Perform the copy
314 if copy:
315 logging.info("Copying %s.tar.bz2 to guest (file is missing or has a"
316 " different size)..." % test_name)
317 if not vm.scp_to_remote(tarred_test_path, ""):
318 raise error.TestFail("Could not copy %s.tar.bz2 to guest" %
319 test_name)
320
321 # Extract autotest.tar.bz2
322 logging.info("Extracting autotest.tar.bz2...")
323 status = session.get_command_status("tar xvfj autotest.tar.bz2")
324 if status != 0:
325 raise error.TestFail("Could not extract autotest.tar.bz2")
326
327 # mkdir autotest/tests
328 session.sendline("mkdir autotest/tests")
329
330 # Extract <test_name>.tar.bz2 into autotest/tests
331 logging.info("Extracting %s.tar.bz2..." % test_name)
332 status = session.get_command_status("tar xvfj %s.tar.bz2 -C "
333 "autotest/tests" % test_name)
334 if status != 0:
335 raise error.TestFail("Could not extract %s.tar.bz2" % test_name)
336
lmr16cf1652009-06-15 21:32:49 +0000337 # Cleaning up old remaining results
338 session.sendline("rm -rf autotest/results/*")
339 # Copying the selected control file (located inside
340 # test.bindir/autotest_control to the autotest dir
341 control_file_path = os.path.join(test.bindir, "autotest_control",
342 test_control_file)
343 if not vm.scp_to_remote(control_file_path, "autotest/control"):
344 raise error.TestFail("Could not copy the test control file to guest")
lmr6f669ce2009-05-31 19:02:42 +0000345 # Run the test
346 logging.info("Running test '%s'..." % test_name)
lmr16cf1652009-06-15 21:32:49 +0000347 session.sendline("cd autotest")
348 session.sendline("rm -f control.state")
lmr6f669ce2009-05-31 19:02:42 +0000349 session.read_up_to_prompt()
lmr16cf1652009-06-15 21:32:49 +0000350 session.sendline("bin/autotest control")
lmr6f669ce2009-05-31 19:02:42 +0000351 logging.info("---------------- Test output ----------------")
lmr16cf1652009-06-15 21:32:49 +0000352 match = session.read_up_to_prompt(timeout=test_timeout,
353 print_func=logging.info)[0]
lmr6f669ce2009-05-31 19:02:42 +0000354 logging.info("---------------- End of test output ----------------")
355 if not match:
lmr16cf1652009-06-15 21:32:49 +0000356 raise error.TestFail("Timeout elapsed while waiting for test to "
357 "complete")
358 # Get the results generated by autotest
359 output = session.get_command_output("cat results/*/status")
lmr6f669ce2009-05-31 19:02:42 +0000360
361 # Parse test results
362 result_list = scan_results.parse_results(output)
363
364 # Report test results and check for FAIL/ERROR status
365 logging.info("Results (test, status, duration, info):")
366 status_error = False
367 status_fail = False
368 if result_list == []:
369 status_fail = True
lmrd16a67d2009-06-10 19:52:59 +0000370 message_fail = ("Test '%s' did not produce any recognizable "
371 "results" % test_name)
lmr6f669ce2009-05-31 19:02:42 +0000372 for result in result_list:
373 logging.info(str(result))
374 if result[1] == "FAIL":
375 status_fail = True
lmr50bece42009-06-15 20:54:43 +0000376 message_fail = ("Test '%s' ended with FAIL "
377 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000378 if result[1] == "ERROR":
379 status_error = True
lmr50bece42009-06-15 20:54:43 +0000380 message_error = ("Test '%s' ended with ERROR "
381 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000382 if result[1] == "ABORT":
383 status_error = True
lmr50bece42009-06-15 20:54:43 +0000384 message_error = ("Test '%s' ended with ABORT "
385 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000386
387 # Copy test results to the local bindir/guest_results
388 logging.info("Copying results back from guest...")
389 guest_results_dir = os.path.join(test.outputdir, "guest_results")
390 if not os.path.exists(guest_results_dir):
391 os.mkdir(guest_results_dir)
392 if not vm.scp_from_remote("autotest/results/default/*", guest_results_dir):
393 logging.error("Could not copy results back from guest")
394
395 # Fail the test if necessary
396 if status_fail:
397 raise error.TestFail(message_fail)
398 elif status_error:
399 raise error.TestError(message_error)
400
401
402def internal_yum_update(session, command, prompt, timeout):
403 """
404 Helper function to perform the yum update test.
405
406 @param session: SSH session stablished to the host
407 @param command: Command to be sent to the SSH connection
408 @param prompt: Machine prompt
409 @param timeout: How long to wait until we get an appropriate output from
410 the SSH session.
411 """
412 session.sendline(command)
413 end_time = time.time() + timeout
414 while time.time() < end_time:
415 (match, text) = session.read_until_last_line_matches(
416 ["[Ii]s this [Oo][Kk]", prompt], timeout=timeout)
417 if match == 0:
418 logging.info("Got 'Is this ok'; sending 'y'")
419 session.sendline("y")
420 elif match == 1:
421 logging.info("Got shell prompt")
422 return True
423 else:
424 logging.info("Timeout or process exited")
425 return False
426
427
428def run_yum_update(test, params, env):
429 """
430 Runs yum update and yum update kernel on the remote host (yum enabled
431 hosts only).
432
433 @param test: kvm test object.
434 @param params: Dictionary with test parameters.
435 @param env: Dictionary with the test environment.
436 """
437 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
438 if not vm:
439 message = "VM object not found in environment"
440 logging.error(message)
441 raise error.TestError(message)
442 if not vm.is_alive():
443 message = "VM seems to be dead; Test requires a living VM"
444 logging.error(message)
445 raise error.TestError(message)
446
447 logging.info("Logging into guest...")
448
449 session = kvm_utils.wait_for(vm.ssh_login, 120, 0, 2)
450 if not session:
451 message = "Could not log into guest"
452 logging.error(message)
453 raise error.TestFail(message)
454
455 logging.info("Logged in")
456
457 internal_yum_update(session, "yum update", params.get("ssh_prompt"), 600)
458 internal_yum_update(session, "yum update kernel",
459 params.get("ssh_prompt"), 600)
460
461 session.close()
462
463
464def run_linux_s3(test, params, env):
465 """
466 Suspend a guest Linux OS to memory.
467
468 @param test: kvm test object.
469 @param params: Dictionary with test parameters.
470 @param env: Dictionary with the test environment.
471 """
472 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
473 if not vm:
474 raise error.TestError("VM object not found in environment")
475 if not vm.is_alive():
476 raise error.TestError("VM seems to be dead; Test requires a living VM")
477
478 logging.info("Waiting for guest to be up...")
479
480 session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
481 if not session:
482 raise error.TestFail("Could not log into guest")
483
484 logging.info("Logged in")
485 logging.info("Checking that VM supports S3")
486
487 status = session.get_command_status("grep -q mem /sys/power/state")
488 if status == None:
489 logging.error("Failed to check if S3 exists")
490 elif status != 0:
491 raise error.TestFail("Guest does not support S3")
492
493 logging.info("Waiting for a while for X to start")
494 time.sleep(10)
495
496 src_tty = session.get_command_output("fgconsole").strip()
497 logging.info("Current virtual terminal is %s" % src_tty)
498 if src_tty not in map(str, range(1,10)):
499 raise error.TestFail("Got a strange current vt (%s)" % src_tty)
500
501 dst_tty = "1"
502 if src_tty == "1":
503 dst_tty = "2"
504
505 logging.info("Putting VM into S3")
506 command = "chvt %s && echo mem > /sys/power/state && chvt %s" % (dst_tty,
507 src_tty)
508 status = session.get_command_status(command, timeout=120)
509 if status != 0:
510 raise error.TestFail("Suspend to mem failed")
511
512 logging.info("VM resumed after S3")
513
514 session.close()
lmra04d7c92009-06-19 13:05:39 +0000515
516
517def run_stress_boot(tests, params, env):
518 """
519 Boots VMs until one of them becomes unresponsive, and records the maximum
520 number of VMs successfully started:
521 1) boot the first vm
522 2) boot the second vm cloned from the first vm, check whether it boots up
523 and all booted vms can ssh-login
524 3) go on until cannot create VM anymore or cannot allocate memory for VM
525
526 @param test: kvm test object
527 @param params: Dictionary with the test parameters
528 @param env: Dictionary with test environment.
529 """
530 # boot the first vm
531 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
532
533 if not vm:
534 raise error.TestError("VM object not found in environment")
535 if not vm.is_alive():
536 raise error.TestError("VM seems to be dead; Test requires a living VM")
537
538 logging.info("Waiting for first guest to be up...")
539
540 session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
541 if not session:
542 raise error.TestFail("Could not log into first guest")
543
544 num = 2
545 vms = []
546 sessions = [session]
547
548 # boot the VMs
549 while num <= int(params.get("max_vms")):
550 try:
551 vm_name = "vm" + str(num)
552
553 # clone vm according to the first one
554 vm_params = params.copy()
555 vm_params['image_snapshot'] = "yes"
556 vm_params['kill_vm'] = "yes"
557 vm_params['kill_vm_gracefully'] = "no"
558 curr_vm = vm.clone(vm_name, vm_params)
559 kvm_utils.env_register_vm(env, vm_name, curr_vm)
560 params['vms'] += " " + vm_name
561
562 #vms.append(curr_vm)
563 logging.info("Booting guest #%d" % num)
564 if not curr_vm.create():
565 raise error.TestFail("Cannot create VM #%d" % num)
566
567 curr_vm_session = kvm_utils.wait_for(curr_vm.ssh_login, 240, 0, 2)
568 if not curr_vm_session:
569 raise error.TestFail("Could not log into guest #%d" % num)
570
571 logging.info("Guest #%d boots up successfully" % num)
572 sessions.append(curr_vm_session)
573
574 # check whether all previous ssh sessions are responsive
575 for i, vm_session in enumerate(sessions):
576 if vm_session.get_command_status(params.get("alive_test_cmd")):
577 raise error.TestFail("Session #%d is not responsive" % i)
578 num += 1
579
580 except (error.TestFail, OSError):
581 for se in sessions:
582 se.close()
583 logging.info("Total number booted: %d" % (num - 1))
584 raise
585 else:
586 for se in sessions:
587 se.close()
588 logging.info("Total number booted: %d" % (num -1))