blob: 4b87a764111d75dfdc99e74283ab312de979c61a [file] [log] [blame]
lmr6f669ce2009-05-31 19:02:42 +00001import time, os, logging
2from autotest_lib.client.common_lib import utils, error
3import kvm_utils, ppm_utils, scan_results
4
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
60def run_migration(test, params, env):
61 """
62 KVM migration test:
63
64 1) Get two live VMs. One will be the 'source', the other will be the
65 'destination'.
66 2) Verify if the source VM supports migration. If it does, proceed with
67 the test
68 3) Send a migration command to the source vm and wait until it's finished.
69 4) Kill off the source vm
70 3) Log into the destination vm after the migration is finished.
71 4) Compare the output of a reference command executed on the source with
72 the output of the same command on the destination machine
73
74 @param test: kvm test object.
75 @param params: Dictionary with test parameters.
76 @param env: Dictionary with the test environment.
77 """
78 src_vm_name = params.get("migration_src")
79 vm = kvm_utils.env_get_vm(env, src_vm_name)
80 if not vm:
81 raise error.TestError("VM '%s' not found in environment" % src_vm_name)
82 if not vm.is_alive():
83 raise error.TestError("VM '%s' seems to be dead; Test requires a"
84 " living VM" % src_vm_name)
85
86 dest_vm_name = params.get("migration_dst")
87 dest_vm = kvm_utils.env_get_vm(env, dest_vm_name)
88 if not dest_vm:
89 raise error.TestError("VM '%s' not found in environment" % dest_vm_name)
90 if not dest_vm.is_alive():
91 raise error.TestError("VM '%s' seems to be dead; Test requires a"
92 " living VM" % dest_vm_name)
93
94 pre_scrdump_filename = os.path.join(test.debugdir, "migration_pre.ppm")
95 post_scrdump_filename = os.path.join(test.debugdir, "migration_post.ppm")
96
97 # See if migration is supported
98 s, o = vm.send_monitor_cmd("help info")
99 if not "info migrate" in o:
100 raise error.TestError("Migration is not supported")
101
102 # Log into guest and get the output of migration_test_command
103 logging.info("Waiting for guest to be up...")
104
105 session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
106 if not session:
107 raise error.TestFail("Could not log into guest")
108
109 logging.info("Logged in")
110
111 reference_output = session.get_command_output(params.get("migration_test_"
112 "command"))
113 session.close()
114
115 # Define the migration command
116 cmd = "migrate -d tcp:localhost:%d" % dest_vm.migration_port
117 logging.debug("Migration command: %s" % cmd)
118
119 # Migrate
120 s, o = vm.send_monitor_cmd(cmd)
121 if s:
122 logging.error("Migration command failed (command: %r, output: %r)" %
123 (cmd, o))
124 raise error.TestFail("Migration command failed")
125
126 # Define some helper functions
127 def mig_finished():
128 s, o = vm.send_monitor_cmd("info migrate")
129 if s:
130 return False
131 if "Migration status: active" in o:
132 return False
133 return True
134
135 def mig_succeeded():
136 s, o = vm.send_monitor_cmd("info migrate")
137 if s == 0 and "Migration status: completed" in o:
138 return True
139 return False
140
141 def mig_failed():
142 s, o = vm.send_monitor_cmd("info migrate")
143 if s == 0 and "Migration status: failed" in o:
144 return True
145 return False
146
147 # Wait for migration to finish
148 if not kvm_utils.wait_for(mig_finished, 90, 2, 2,
149 "Waiting for migration to finish..."):
150 raise error.TestFail("Timeout elapsed while waiting for migration to"
151 "finish")
152
153 # Report migration status
154 if mig_succeeded():
155 logging.info("Migration finished successfully")
156 else:
157 if mig_failed():
158 message = "Migration failed"
159 else:
160 message = "Migration ended with unknown status"
161 raise error.TestFail(message)
162
163 # Get 'post' screendump
164 dest_vm.send_monitor_cmd("screendump %s" % post_scrdump_filename)
165
166 # Get 'pre' screendump
167 vm.send_monitor_cmd("screendump %s" % pre_scrdump_filename)
168
169 # Kill the source VM
170 vm.send_monitor_cmd("quit", block=False)
171
172 # Hack: it seems that the first attempt to communicate with the SSH port
173 # following migration always fails (or succeeds after a very long time).
174 # So just connect to the port once so the following call to ssh_login
175 # succeeds.
176 dest_vm.is_sshd_running(timeout=0.0)
177
178 # Log into guest and get the output of migration_test_command
179 logging.info("Logging into guest after migration...")
180
181 session = dest_vm.ssh_login()
182 if not session:
183 raise error.TestFail("Could not log into guest after migration")
184
185 logging.info("Logged in after migration")
186
187 output = session.get_command_output(params.get("migration_test_command"))
188 session.close()
189
190 # Compare output to reference output
191 if output != reference_output:
192 logging.info("Command output before migration differs from command"
193 " output after migration")
194 logging.info("Command: %s" % params.get("migration_test_command"))
195 logging.info("Output before:" +
196 kvm_utils.format_str_for_message(reference_output))
197 logging.info("Output after:" + kvm_utils.format_str_for_message(output))
198 raise error.TestFail("Command produced different output before and"
199 " after migration")
200
201
202def run_autotest(test, params, env):
203 """
204 Run an autotest test inside a guest.
205
206 @param test: kvm test object.
207 @param params: Dictionary with test parameters.
208 @param env: Dictionary with the test environment.
209 """
210 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
211 if not vm:
212 raise error.TestError("VM object not found in environment")
213 if not vm.is_alive():
214 raise error.TestError("VM seems to be dead; Test requires a living VM")
215
216 logging.info("Logging into guest...")
217
218 session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
219 if not session:
220 raise error.TestFail("Could not log into guest")
221
222 logging.info("Logged in")
223
224 # Collect some info
225 test_name = params.get("test_name")
226 test_timeout = int(params.get("test_timeout", 300))
227 test_control_file = params.get("test_control_file", "control")
228 tarred_autotest_path = "/tmp/autotest.tar.bz2"
229 tarred_test_path = "/tmp/%s.tar.bz2" % test_name
230
231 # tar the contents of bindir/autotest
232 cmd = "cd %s; tar cvjf %s autotest/*"
233 cmd += " --exclude=autotest/tests"
234 cmd += " --exclude=autotest/results"
235 cmd += " --exclude=autotest/tmp"
236 cmd += " --exclude=autotest/control"
237 cmd += " --exclude=*.pyc"
238 cmd += " --exclude=*.svn"
239 cmd += " --exclude=*.git"
240 kvm_utils.run_bg(cmd % (test.bindir, tarred_autotest_path), timeout=30)
241
242 # tar the contents of bindir/autotest/tests/<test_name>
243 cmd = "cd %s; tar cvjf %s %s/*"
244 cmd += " --exclude=*.pyc"
245 cmd += " --exclude=*.svn"
246 cmd += " --exclude=*.git"
247 kvm_utils.run_bg(cmd % (os.path.join(test.bindir, "autotest", "tests"),
248 tarred_test_path, test_name), timeout=30)
249
250 # Check if we need to copy autotest.tar.bz2
251 copy = False
252 output = session.get_command_output("ls -l autotest.tar.bz2")
253 if "such file" in output:
254 copy = True
255 else:
256 size = int(output.split()[4])
257 if size != os.path.getsize(tarred_autotest_path):
258 copy = True
259 # Perform the copy
260 if copy:
261 logging.info("Copying autotest.tar.bz2 to guest"
262 " (file is missing or has a different size)...")
263 if not vm.scp_to_remote(tarred_autotest_path, ""):
264 raise error.TestFail("Could not copy autotest.tar.bz2 to guest")
265
266 # Check if we need to copy <test_name>.tar.bz2
267 copy = False
268 output = session.get_command_output("ls -l %s.tar.bz2" % test_name)
269 if "such file" in output:
270 copy = True
271 else:
272 size = int(output.split()[4])
273 if size != os.path.getsize(tarred_test_path):
274 copy = True
275 # Perform the copy
276 if copy:
277 logging.info("Copying %s.tar.bz2 to guest (file is missing or has a"
278 " different size)..." % test_name)
279 if not vm.scp_to_remote(tarred_test_path, ""):
280 raise error.TestFail("Could not copy %s.tar.bz2 to guest" %
281 test_name)
282
283 # Extract autotest.tar.bz2
284 logging.info("Extracting autotest.tar.bz2...")
285 status = session.get_command_status("tar xvfj autotest.tar.bz2")
286 if status != 0:
287 raise error.TestFail("Could not extract autotest.tar.bz2")
288
289 # mkdir autotest/tests
290 session.sendline("mkdir autotest/tests")
291
292 # Extract <test_name>.tar.bz2 into autotest/tests
293 logging.info("Extracting %s.tar.bz2..." % test_name)
294 status = session.get_command_status("tar xvfj %s.tar.bz2 -C "
295 "autotest/tests" % test_name)
296 if status != 0:
297 raise error.TestFail("Could not extract %s.tar.bz2" % test_name)
298
299 # Run the test
300 logging.info("Running test '%s'..." % test_name)
301 session.sendline("cd autotest/tests/%s" % test_name)
302 session.sendline("rm -f ./%s.state" % test_control_file)
303 session.read_up_to_prompt()
304 session.sendline("../../bin/autotest ./%s" % test_control_file)
305 logging.info("---------------- Test output ----------------")
306 match, output = session.read_up_to_prompt(timeout=test_timeout,
307 print_func=logging.info)
308 logging.info("---------------- End of test output ----------------")
309 if not match:
310 raise error.TestFail("Timeout elapsed while waiting for test to"
311 " complete")
312
313 session.close()
314
315 # Parse test results
316 result_list = scan_results.parse_results(output)
317
318 # Report test results and check for FAIL/ERROR status
319 logging.info("Results (test, status, duration, info):")
320 status_error = False
321 status_fail = False
322 if result_list == []:
323 status_fail = True
lmrd16a67d2009-06-10 19:52:59 +0000324 message_fail = ("Test '%s' did not produce any recognizable "
325 "results" % test_name)
lmr6f669ce2009-05-31 19:02:42 +0000326 for result in result_list:
327 logging.info(str(result))
328 if result[1] == "FAIL":
329 status_fail = True
lmr50bece42009-06-15 20:54:43 +0000330 message_fail = ("Test '%s' ended with FAIL "
331 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000332 if result[1] == "ERROR":
333 status_error = True
lmr50bece42009-06-15 20:54:43 +0000334 message_error = ("Test '%s' ended with ERROR "
335 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000336 if result[1] == "ABORT":
337 status_error = True
lmr50bece42009-06-15 20:54:43 +0000338 message_error = ("Test '%s' ended with ABORT "
339 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000340
341 # Copy test results to the local bindir/guest_results
342 logging.info("Copying results back from guest...")
343 guest_results_dir = os.path.join(test.outputdir, "guest_results")
344 if not os.path.exists(guest_results_dir):
345 os.mkdir(guest_results_dir)
346 if not vm.scp_from_remote("autotest/results/default/*", guest_results_dir):
347 logging.error("Could not copy results back from guest")
348
349 # Fail the test if necessary
350 if status_fail:
351 raise error.TestFail(message_fail)
352 elif status_error:
353 raise error.TestError(message_error)
354
355
356def internal_yum_update(session, command, prompt, timeout):
357 """
358 Helper function to perform the yum update test.
359
360 @param session: SSH session stablished to the host
361 @param command: Command to be sent to the SSH connection
362 @param prompt: Machine prompt
363 @param timeout: How long to wait until we get an appropriate output from
364 the SSH session.
365 """
366 session.sendline(command)
367 end_time = time.time() + timeout
368 while time.time() < end_time:
369 (match, text) = session.read_until_last_line_matches(
370 ["[Ii]s this [Oo][Kk]", prompt], timeout=timeout)
371 if match == 0:
372 logging.info("Got 'Is this ok'; sending 'y'")
373 session.sendline("y")
374 elif match == 1:
375 logging.info("Got shell prompt")
376 return True
377 else:
378 logging.info("Timeout or process exited")
379 return False
380
381
382def run_yum_update(test, params, env):
383 """
384 Runs yum update and yum update kernel on the remote host (yum enabled
385 hosts only).
386
387 @param test: kvm test object.
388 @param params: Dictionary with test parameters.
389 @param env: Dictionary with the test environment.
390 """
391 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
392 if not vm:
393 message = "VM object not found in environment"
394 logging.error(message)
395 raise error.TestError(message)
396 if not vm.is_alive():
397 message = "VM seems to be dead; Test requires a living VM"
398 logging.error(message)
399 raise error.TestError(message)
400
401 logging.info("Logging into guest...")
402
403 session = kvm_utils.wait_for(vm.ssh_login, 120, 0, 2)
404 if not session:
405 message = "Could not log into guest"
406 logging.error(message)
407 raise error.TestFail(message)
408
409 logging.info("Logged in")
410
411 internal_yum_update(session, "yum update", params.get("ssh_prompt"), 600)
412 internal_yum_update(session, "yum update kernel",
413 params.get("ssh_prompt"), 600)
414
415 session.close()
416
417
418def run_linux_s3(test, params, env):
419 """
420 Suspend a guest Linux OS to memory.
421
422 @param test: kvm test object.
423 @param params: Dictionary with test parameters.
424 @param env: Dictionary with the test environment.
425 """
426 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
427 if not vm:
428 raise error.TestError("VM object not found in environment")
429 if not vm.is_alive():
430 raise error.TestError("VM seems to be dead; Test requires a living VM")
431
432 logging.info("Waiting for guest to be up...")
433
434 session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
435 if not session:
436 raise error.TestFail("Could not log into guest")
437
438 logging.info("Logged in")
439 logging.info("Checking that VM supports S3")
440
441 status = session.get_command_status("grep -q mem /sys/power/state")
442 if status == None:
443 logging.error("Failed to check if S3 exists")
444 elif status != 0:
445 raise error.TestFail("Guest does not support S3")
446
447 logging.info("Waiting for a while for X to start")
448 time.sleep(10)
449
450 src_tty = session.get_command_output("fgconsole").strip()
451 logging.info("Current virtual terminal is %s" % src_tty)
452 if src_tty not in map(str, range(1,10)):
453 raise error.TestFail("Got a strange current vt (%s)" % src_tty)
454
455 dst_tty = "1"
456 if src_tty == "1":
457 dst_tty = "2"
458
459 logging.info("Putting VM into S3")
460 command = "chvt %s && echo mem > /sys/power/state && chvt %s" % (dst_tty,
461 src_tty)
462 status = session.get_command_status(command, timeout=120)
463 if status != 0:
464 raise error.TestFail("Suspend to mem failed")
465
466 logging.info("VM resumed after S3")
467
468 session.close()