blob: 4270cae9a81d8f6533f067f0234ebc9c531fd167 [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
lmr16cf1652009-06-15 21:32:49 +0000299 # Cleaning up old remaining results
300 session.sendline("rm -rf autotest/results/*")
301 # Copying the selected control file (located inside
302 # test.bindir/autotest_control to the autotest dir
303 control_file_path = os.path.join(test.bindir, "autotest_control",
304 test_control_file)
305 if not vm.scp_to_remote(control_file_path, "autotest/control"):
306 raise error.TestFail("Could not copy the test control file to guest")
lmr6f669ce2009-05-31 19:02:42 +0000307 # Run the test
308 logging.info("Running test '%s'..." % test_name)
lmr16cf1652009-06-15 21:32:49 +0000309 session.sendline("cd autotest")
310 session.sendline("rm -f control.state")
lmr6f669ce2009-05-31 19:02:42 +0000311 session.read_up_to_prompt()
lmr16cf1652009-06-15 21:32:49 +0000312 session.sendline("bin/autotest control")
lmr6f669ce2009-05-31 19:02:42 +0000313 logging.info("---------------- Test output ----------------")
lmr16cf1652009-06-15 21:32:49 +0000314 match = session.read_up_to_prompt(timeout=test_timeout,
315 print_func=logging.info)[0]
lmr6f669ce2009-05-31 19:02:42 +0000316 logging.info("---------------- End of test output ----------------")
317 if not match:
lmr16cf1652009-06-15 21:32:49 +0000318 raise error.TestFail("Timeout elapsed while waiting for test to "
319 "complete")
320 # Get the results generated by autotest
321 output = session.get_command_output("cat results/*/status")
lmr6f669ce2009-05-31 19:02:42 +0000322
323 # Parse test results
324 result_list = scan_results.parse_results(output)
325
326 # Report test results and check for FAIL/ERROR status
327 logging.info("Results (test, status, duration, info):")
328 status_error = False
329 status_fail = False
330 if result_list == []:
331 status_fail = True
lmrd16a67d2009-06-10 19:52:59 +0000332 message_fail = ("Test '%s' did not produce any recognizable "
333 "results" % test_name)
lmr6f669ce2009-05-31 19:02:42 +0000334 for result in result_list:
335 logging.info(str(result))
336 if result[1] == "FAIL":
337 status_fail = True
lmr50bece42009-06-15 20:54:43 +0000338 message_fail = ("Test '%s' ended with FAIL "
339 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000340 if result[1] == "ERROR":
341 status_error = True
lmr50bece42009-06-15 20:54:43 +0000342 message_error = ("Test '%s' ended with ERROR "
343 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000344 if result[1] == "ABORT":
345 status_error = True
lmr50bece42009-06-15 20:54:43 +0000346 message_error = ("Test '%s' ended with ABORT "
347 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000348
349 # Copy test results to the local bindir/guest_results
350 logging.info("Copying results back from guest...")
351 guest_results_dir = os.path.join(test.outputdir, "guest_results")
352 if not os.path.exists(guest_results_dir):
353 os.mkdir(guest_results_dir)
354 if not vm.scp_from_remote("autotest/results/default/*", guest_results_dir):
355 logging.error("Could not copy results back from guest")
356
357 # Fail the test if necessary
358 if status_fail:
359 raise error.TestFail(message_fail)
360 elif status_error:
361 raise error.TestError(message_error)
362
363
364def internal_yum_update(session, command, prompt, timeout):
365 """
366 Helper function to perform the yum update test.
367
368 @param session: SSH session stablished to the host
369 @param command: Command to be sent to the SSH connection
370 @param prompt: Machine prompt
371 @param timeout: How long to wait until we get an appropriate output from
372 the SSH session.
373 """
374 session.sendline(command)
375 end_time = time.time() + timeout
376 while time.time() < end_time:
377 (match, text) = session.read_until_last_line_matches(
378 ["[Ii]s this [Oo][Kk]", prompt], timeout=timeout)
379 if match == 0:
380 logging.info("Got 'Is this ok'; sending 'y'")
381 session.sendline("y")
382 elif match == 1:
383 logging.info("Got shell prompt")
384 return True
385 else:
386 logging.info("Timeout or process exited")
387 return False
388
389
390def run_yum_update(test, params, env):
391 """
392 Runs yum update and yum update kernel on the remote host (yum enabled
393 hosts only).
394
395 @param test: kvm test object.
396 @param params: Dictionary with test parameters.
397 @param env: Dictionary with the test environment.
398 """
399 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
400 if not vm:
401 message = "VM object not found in environment"
402 logging.error(message)
403 raise error.TestError(message)
404 if not vm.is_alive():
405 message = "VM seems to be dead; Test requires a living VM"
406 logging.error(message)
407 raise error.TestError(message)
408
409 logging.info("Logging into guest...")
410
411 session = kvm_utils.wait_for(vm.ssh_login, 120, 0, 2)
412 if not session:
413 message = "Could not log into guest"
414 logging.error(message)
415 raise error.TestFail(message)
416
417 logging.info("Logged in")
418
419 internal_yum_update(session, "yum update", params.get("ssh_prompt"), 600)
420 internal_yum_update(session, "yum update kernel",
421 params.get("ssh_prompt"), 600)
422
423 session.close()
424
425
426def run_linux_s3(test, params, env):
427 """
428 Suspend a guest Linux OS to memory.
429
430 @param test: kvm test object.
431 @param params: Dictionary with test parameters.
432 @param env: Dictionary with the test environment.
433 """
434 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
435 if not vm:
436 raise error.TestError("VM object not found in environment")
437 if not vm.is_alive():
438 raise error.TestError("VM seems to be dead; Test requires a living VM")
439
440 logging.info("Waiting for guest to be up...")
441
442 session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2)
443 if not session:
444 raise error.TestFail("Could not log into guest")
445
446 logging.info("Logged in")
447 logging.info("Checking that VM supports S3")
448
449 status = session.get_command_status("grep -q mem /sys/power/state")
450 if status == None:
451 logging.error("Failed to check if S3 exists")
452 elif status != 0:
453 raise error.TestFail("Guest does not support S3")
454
455 logging.info("Waiting for a while for X to start")
456 time.sleep(10)
457
458 src_tty = session.get_command_output("fgconsole").strip()
459 logging.info("Current virtual terminal is %s" % src_tty)
460 if src_tty not in map(str, range(1,10)):
461 raise error.TestFail("Got a strange current vt (%s)" % src_tty)
462
463 dst_tty = "1"
464 if src_tty == "1":
465 dst_tty = "2"
466
467 logging.info("Putting VM into S3")
468 command = "chvt %s && echo mem > /sys/power/state && chvt %s" % (dst_tty,
469 src_tty)
470 status = session.get_command_status(command, timeout=120)
471 if status != 0:
472 raise error.TestFail("Suspend to mem failed")
473
474 logging.info("VM resumed after S3")
475
476 session.close()