blob: 863b863084ed77eb8fb65f90537c50d6720a4b99 [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
lmr9ce347d2009-09-09 22:26:53 +000016 2) Send a reboot command or a system_reset monitor command (optional)
17 3) Wait until the guest is up again
18 4) Log into the guest to verify it's up again
lmr6f669ce2009-05-31 19:02:42 +000019
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
lmr9ce347d2009-09-09 22:26:53 +000036 try:
37 logging.info("Logged in")
lmr6f669ce2009-05-31 19:02:42 +000038
lmr9ce347d2009-09-09 22:26:53 +000039 if params.get("reboot_method") == "shell":
40 # Send a reboot command to the guest's shell
41 session.sendline(vm.get_params().get("reboot_command"))
42 logging.info("Reboot command sent; waiting for guest to go "
43 "down...")
44 elif params.get("reboot_method") == "system_reset":
45 # Sleep for a while -- give the guest a chance to finish booting
46 time.sleep(float(params.get("sleep_before_reset", 10)))
47 # Send a system_reset monitor command
48 vm.send_monitor_cmd("system_reset")
49 logging.info("system_reset monitor command sent; waiting for "
50 "guest to go down...")
51 else: return
lmr6f669ce2009-05-31 19:02:42 +000052
lmr9ce347d2009-09-09 22:26:53 +000053 # Wait for the session to become unresponsive
lmr6f669ce2009-05-31 19:02:42 +000054 if not kvm_utils.wait_for(lambda: not session.is_responsive(),
55 120, 0, 1):
56 raise error.TestFail("Guest refuses to go down")
57
58 session.close()
59
60 logging.info("Guest is down; waiting for it to go up again...")
61
lmr912c74b2009-08-17 20:43:27 +000062 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6f669ce2009-05-31 19:02:42 +000063 if not session:
64 raise error.TestFail("Could not log into guest after reboot")
65
66 logging.info("Guest is up again")
67
lmr9ce347d2009-09-09 22:26:53 +000068 finally:
69 session.close()
lmr6f669ce2009-05-31 19:02:42 +000070
71
lmr6faadb22009-06-18 14:57:45 +000072def run_shutdown(test, params, env):
73 """
74 KVM shutdown test:
75 1) Log into a guest
lmr6e840e32009-09-09 22:38:07 +000076 2) Send a shutdown command to the guest, or issue a system_powerdown
77 monitor command (depending on the value of shutdown_method)
78 3) Wait until the guest is down
lmr6faadb22009-06-18 14:57:45 +000079
80 @param test: kvm test object
81 @param params: Dictionary with the test parameters
82 @param env: Dictionary with test environment
83 """
84 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
85 if not vm:
86 raise error.TestError("VM object not found in environment")
87 if not vm.is_alive():
88 raise error.TestError("VM seems to be dead; Test requires a living VM")
89
90 logging.info("Waiting for guest to be up...")
91
lmr912c74b2009-08-17 20:43:27 +000092 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6faadb22009-06-18 14:57:45 +000093 if not session:
94 raise error.TestFail("Could not log into guest")
95
lmr20773742009-08-13 04:43:45 +000096 try:
97 logging.info("Logged in")
lmr6faadb22009-06-18 14:57:45 +000098
lmr6e840e32009-09-09 22:38:07 +000099 if params.get("shutdown_method") == "shell":
100 # Send a shutdown command to the guest's shell
101 session.sendline(vm.get_params().get("shutdown_command"))
102 logging.info("Shutdown command sent; waiting for guest to go "
103 "down...")
104 elif params.get("shutdown_method") == "system_powerdown":
105 # Sleep for a while -- give the guest a chance to finish booting
106 time.sleep(float(params.get("sleep_before_powerdown", 10)))
107 # Send a system_powerdown monitor command
108 vm.send_monitor_cmd("system_powerdown")
109 logging.info("system_powerdown monitor command sent; waiting for "
110 "guest to go down...")
lmr6faadb22009-06-18 14:57:45 +0000111
lmr20773742009-08-13 04:43:45 +0000112 if not kvm_utils.wait_for(vm.is_dead, 240, 0, 1):
113 raise error.TestFail("Guest refuses to go down")
lmr6faadb22009-06-18 14:57:45 +0000114
lmr20773742009-08-13 04:43:45 +0000115 logging.info("Guest is down")
lmr6e840e32009-09-09 22:38:07 +0000116
lmr20773742009-08-13 04:43:45 +0000117 finally:
118 session.close()
lmr6faadb22009-06-18 14:57:45 +0000119
120
lmr6f669ce2009-05-31 19:02:42 +0000121def run_migration(test, params, env):
122 """
123 KVM migration test:
lmr4d5cc792009-09-09 22:01:57 +0000124 1) Get a live VM and clone it.
125 2) Verify that the source VM supports migration. If it does, proceed with
126 the test.
127 3) Send a migration command to the source VM and wait until it's finished.
128 4) Kill off the source VM.
129 3) Log into the destination VM after the migration is finished.
lmr6f669ce2009-05-31 19:02:42 +0000130 4) Compare the output of a reference command executed on the source with
lmr4d5cc792009-09-09 22:01:57 +0000131 the output of the same command on the destination machine.
lmr6f669ce2009-05-31 19:02:42 +0000132
133 @param test: kvm test object.
134 @param params: Dictionary with test parameters.
135 @param env: Dictionary with the test environment.
136 """
lmr4d5cc792009-09-09 22:01:57 +0000137 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
lmr6f669ce2009-05-31 19:02:42 +0000138 if not vm:
lmr4d5cc792009-09-09 22:01:57 +0000139 raise error.TestError("VM object not found in environment")
lmr6f669ce2009-05-31 19:02:42 +0000140 if not vm.is_alive():
lmr4d5cc792009-09-09 22:01:57 +0000141 raise error.TestError("VM seems to be dead; Test requires a living VM")
lmr6f669ce2009-05-31 19:02:42 +0000142
143 # See if migration is supported
144 s, o = vm.send_monitor_cmd("help info")
145 if not "info migrate" in o:
146 raise error.TestError("Migration is not supported")
147
lmr4d5cc792009-09-09 22:01:57 +0000148 dest_vm = vm.clone()
149 dest_vm.create(for_migration=True)
150
lmr6f669ce2009-05-31 19:02:42 +0000151 # Log into guest and get the output of migration_test_command
152 logging.info("Waiting for guest to be up...")
153
lmr912c74b2009-08-17 20:43:27 +0000154 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6f669ce2009-05-31 19:02:42 +0000155 if not session:
156 raise error.TestFail("Could not log into guest")
157
158 logging.info("Logged in")
159
160 reference_output = session.get_command_output(params.get("migration_test_"
161 "command"))
162 session.close()
163
164 # Define the migration command
165 cmd = "migrate -d tcp:localhost:%d" % dest_vm.migration_port
166 logging.debug("Migration command: %s" % cmd)
167
168 # Migrate
169 s, o = vm.send_monitor_cmd(cmd)
170 if s:
171 logging.error("Migration command failed (command: %r, output: %r)" %
172 (cmd, o))
173 raise error.TestFail("Migration command failed")
174
175 # Define some helper functions
176 def mig_finished():
177 s, o = vm.send_monitor_cmd("info migrate")
lmr4d5cc792009-09-09 22:01:57 +0000178 return s == 0 and not "Migration status: active" in o
lmr6f669ce2009-05-31 19:02:42 +0000179
180 def mig_succeeded():
181 s, o = vm.send_monitor_cmd("info migrate")
lmr4d5cc792009-09-09 22:01:57 +0000182 return s == 0 and "Migration status: completed" in o
lmr6f669ce2009-05-31 19:02:42 +0000183
184 def mig_failed():
185 s, o = vm.send_monitor_cmd("info migrate")
lmr4d5cc792009-09-09 22:01:57 +0000186 return s == 0 and "Migration status: failed" in o
lmr6f669ce2009-05-31 19:02:42 +0000187
188 # Wait for migration to finish
189 if not kvm_utils.wait_for(mig_finished, 90, 2, 2,
190 "Waiting for migration to finish..."):
lmr4d5cc792009-09-09 22:01:57 +0000191 raise error.TestFail("Timeout elapsed while waiting for migration to "
lmr6f669ce2009-05-31 19:02:42 +0000192 "finish")
193
194 # Report migration status
195 if mig_succeeded():
196 logging.info("Migration finished successfully")
lmr4d5cc792009-09-09 22:01:57 +0000197 elif mig_failed():
198 raise error.TestFail("Migration failed")
lmr6f669ce2009-05-31 19:02:42 +0000199 else:
lmr4d5cc792009-09-09 22:01:57 +0000200 raise error.TestFail("Migration ended with unknown status")
lmr6f669ce2009-05-31 19:02:42 +0000201
202 # Kill the source VM
lmr4d5cc792009-09-09 22:01:57 +0000203 vm.destroy(gracefully=False)
lmr6f669ce2009-05-31 19:02:42 +0000204
205 # Log into guest and get the output of migration_test_command
206 logging.info("Logging into guest after migration...")
207
lmr912c74b2009-08-17 20:43:27 +0000208 session = dest_vm.remote_login()
lmr6f669ce2009-05-31 19:02:42 +0000209 if not session:
210 raise error.TestFail("Could not log into guest after migration")
211
212 logging.info("Logged in after migration")
213
214 output = session.get_command_output(params.get("migration_test_command"))
215 session.close()
216
217 # Compare output to reference output
218 if output != reference_output:
lmr4d5cc792009-09-09 22:01:57 +0000219 logging.info("Command output before migration differs from command "
220 "output after migration")
lmr6f669ce2009-05-31 19:02:42 +0000221 logging.info("Command: %s" % params.get("migration_test_command"))
222 logging.info("Output before:" +
223 kvm_utils.format_str_for_message(reference_output))
224 logging.info("Output after:" + kvm_utils.format_str_for_message(output))
lmr4d5cc792009-09-09 22:01:57 +0000225 raise error.TestFail("Command produced different output before and "
226 "after migration")
227
228 kvm_utils.env_register_vm(env, params.get("main_vm"), dest_vm)
lmr6f669ce2009-05-31 19:02:42 +0000229
230
231def run_autotest(test, params, env):
232 """
233 Run an autotest test inside a guest.
234
235 @param test: kvm test object.
236 @param params: Dictionary with test parameters.
237 @param env: Dictionary with the test environment.
238 """
239 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
240 if not vm:
241 raise error.TestError("VM object not found in environment")
242 if not vm.is_alive():
243 raise error.TestError("VM seems to be dead; Test requires a living VM")
244
245 logging.info("Logging into guest...")
246
lmr912c74b2009-08-17 20:43:27 +0000247 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6f669ce2009-05-31 19:02:42 +0000248 if not session:
249 raise error.TestFail("Could not log into guest")
250
251 logging.info("Logged in")
252
253 # Collect some info
254 test_name = params.get("test_name")
255 test_timeout = int(params.get("test_timeout", 300))
256 test_control_file = params.get("test_control_file", "control")
257 tarred_autotest_path = "/tmp/autotest.tar.bz2"
258 tarred_test_path = "/tmp/%s.tar.bz2" % test_name
259
260 # tar the contents of bindir/autotest
261 cmd = "cd %s; tar cvjf %s autotest/*"
262 cmd += " --exclude=autotest/tests"
263 cmd += " --exclude=autotest/results"
264 cmd += " --exclude=autotest/tmp"
265 cmd += " --exclude=autotest/control"
266 cmd += " --exclude=*.pyc"
267 cmd += " --exclude=*.svn"
268 cmd += " --exclude=*.git"
lmrd85c55b2009-07-23 01:42:10 +0000269 kvm_subprocess.run_fg(cmd % (test.bindir, tarred_autotest_path), timeout=30)
lmr6f669ce2009-05-31 19:02:42 +0000270
271 # tar the contents of bindir/autotest/tests/<test_name>
272 cmd = "cd %s; tar cvjf %s %s/*"
273 cmd += " --exclude=*.pyc"
274 cmd += " --exclude=*.svn"
275 cmd += " --exclude=*.git"
lmrd85c55b2009-07-23 01:42:10 +0000276 kvm_subprocess.run_fg(cmd %
277 (os.path.join(test.bindir, "autotest", "tests"),
278 tarred_test_path, test_name), timeout=30)
lmr6f669ce2009-05-31 19:02:42 +0000279
280 # Check if we need to copy autotest.tar.bz2
281 copy = False
282 output = session.get_command_output("ls -l autotest.tar.bz2")
283 if "such file" in output:
284 copy = True
285 else:
286 size = int(output.split()[4])
287 if size != os.path.getsize(tarred_autotest_path):
288 copy = True
289 # Perform the copy
290 if copy:
291 logging.info("Copying autotest.tar.bz2 to guest"
292 " (file is missing or has a different size)...")
lmr912c74b2009-08-17 20:43:27 +0000293 if not vm.copy_files_to(tarred_autotest_path, ""):
lmr6f669ce2009-05-31 19:02:42 +0000294 raise error.TestFail("Could not copy autotest.tar.bz2 to guest")
295
296 # Check if we need to copy <test_name>.tar.bz2
297 copy = False
298 output = session.get_command_output("ls -l %s.tar.bz2" % test_name)
299 if "such file" in output:
300 copy = True
301 else:
302 size = int(output.split()[4])
303 if size != os.path.getsize(tarred_test_path):
304 copy = True
305 # Perform the copy
306 if copy:
307 logging.info("Copying %s.tar.bz2 to guest (file is missing or has a"
308 " different size)..." % test_name)
lmr912c74b2009-08-17 20:43:27 +0000309 if not vm.copy_files_to(tarred_test_path, ""):
lmr6f669ce2009-05-31 19:02:42 +0000310 raise error.TestFail("Could not copy %s.tar.bz2 to guest" %
311 test_name)
312
313 # Extract autotest.tar.bz2
314 logging.info("Extracting autotest.tar.bz2...")
315 status = session.get_command_status("tar xvfj autotest.tar.bz2")
316 if status != 0:
317 raise error.TestFail("Could not extract autotest.tar.bz2")
318
319 # mkdir autotest/tests
320 session.sendline("mkdir autotest/tests")
321
322 # Extract <test_name>.tar.bz2 into autotest/tests
323 logging.info("Extracting %s.tar.bz2..." % test_name)
324 status = session.get_command_status("tar xvfj %s.tar.bz2 -C "
325 "autotest/tests" % test_name)
326 if status != 0:
327 raise error.TestFail("Could not extract %s.tar.bz2" % test_name)
328
lmr16cf1652009-06-15 21:32:49 +0000329 # Cleaning up old remaining results
330 session.sendline("rm -rf autotest/results/*")
331 # Copying the selected control file (located inside
332 # test.bindir/autotest_control to the autotest dir
333 control_file_path = os.path.join(test.bindir, "autotest_control",
334 test_control_file)
lmr912c74b2009-08-17 20:43:27 +0000335 if not vm.copy_files_to(control_file_path, "autotest/control"):
lmr16cf1652009-06-15 21:32:49 +0000336 raise error.TestFail("Could not copy the test control file to guest")
lmr6f669ce2009-05-31 19:02:42 +0000337 # Run the test
338 logging.info("Running test '%s'..." % test_name)
lmr16cf1652009-06-15 21:32:49 +0000339 session.sendline("cd autotest")
340 session.sendline("rm -f control.state")
lmr6f669ce2009-05-31 19:02:42 +0000341 session.read_up_to_prompt()
lmr16cf1652009-06-15 21:32:49 +0000342 session.sendline("bin/autotest control")
lmr6f669ce2009-05-31 19:02:42 +0000343 logging.info("---------------- Test output ----------------")
lmr16cf1652009-06-15 21:32:49 +0000344 match = session.read_up_to_prompt(timeout=test_timeout,
345 print_func=logging.info)[0]
lmr6f669ce2009-05-31 19:02:42 +0000346 logging.info("---------------- End of test output ----------------")
347 if not match:
lmr16cf1652009-06-15 21:32:49 +0000348 raise error.TestFail("Timeout elapsed while waiting for test to "
349 "complete")
350 # Get the results generated by autotest
351 output = session.get_command_output("cat results/*/status")
lmr6f669ce2009-05-31 19:02:42 +0000352
353 # Parse test results
354 result_list = scan_results.parse_results(output)
355
356 # Report test results and check for FAIL/ERROR status
357 logging.info("Results (test, status, duration, info):")
358 status_error = False
359 status_fail = False
360 if result_list == []:
361 status_fail = True
lmrd16a67d2009-06-10 19:52:59 +0000362 message_fail = ("Test '%s' did not produce any recognizable "
363 "results" % test_name)
lmr6f669ce2009-05-31 19:02:42 +0000364 for result in result_list:
365 logging.info(str(result))
366 if result[1] == "FAIL":
367 status_fail = True
lmr50bece42009-06-15 20:54:43 +0000368 message_fail = ("Test '%s' ended with FAIL "
369 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000370 if result[1] == "ERROR":
371 status_error = True
lmr50bece42009-06-15 20:54:43 +0000372 message_error = ("Test '%s' ended with ERROR "
373 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000374 if result[1] == "ABORT":
375 status_error = True
lmr50bece42009-06-15 20:54:43 +0000376 message_error = ("Test '%s' ended with ABORT "
377 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000378
379 # Copy test results to the local bindir/guest_results
380 logging.info("Copying results back from guest...")
381 guest_results_dir = os.path.join(test.outputdir, "guest_results")
382 if not os.path.exists(guest_results_dir):
383 os.mkdir(guest_results_dir)
lmr912c74b2009-08-17 20:43:27 +0000384 if not vm.copy_files_from("autotest/results/default/*", guest_results_dir):
lmr6f669ce2009-05-31 19:02:42 +0000385 logging.error("Could not copy results back from guest")
386
387 # Fail the test if necessary
388 if status_fail:
389 raise error.TestFail(message_fail)
390 elif status_error:
391 raise error.TestError(message_error)
392
393
394def internal_yum_update(session, command, prompt, timeout):
395 """
396 Helper function to perform the yum update test.
397
lmr912c74b2009-08-17 20:43:27 +0000398 @param session: shell session stablished to the host
399 @param command: Command to be sent to the shell session
lmr6f669ce2009-05-31 19:02:42 +0000400 @param prompt: Machine prompt
401 @param timeout: How long to wait until we get an appropriate output from
lmr912c74b2009-08-17 20:43:27 +0000402 the shell session.
lmr6f669ce2009-05-31 19:02:42 +0000403 """
404 session.sendline(command)
405 end_time = time.time() + timeout
406 while time.time() < end_time:
407 (match, text) = session.read_until_last_line_matches(
408 ["[Ii]s this [Oo][Kk]", prompt], timeout=timeout)
409 if match == 0:
410 logging.info("Got 'Is this ok'; sending 'y'")
411 session.sendline("y")
412 elif match == 1:
413 logging.info("Got shell prompt")
414 return True
415 else:
416 logging.info("Timeout or process exited")
417 return False
418
419
420def run_yum_update(test, params, env):
421 """
422 Runs yum update and yum update kernel on the remote host (yum enabled
423 hosts only).
424
425 @param test: kvm test object.
426 @param params: Dictionary with test parameters.
427 @param env: Dictionary with the test environment.
428 """
429 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
430 if not vm:
431 message = "VM object not found in environment"
432 logging.error(message)
433 raise error.TestError(message)
434 if not vm.is_alive():
435 message = "VM seems to be dead; Test requires a living VM"
436 logging.error(message)
437 raise error.TestError(message)
438
439 logging.info("Logging into guest...")
440
lmr912c74b2009-08-17 20:43:27 +0000441 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6f669ce2009-05-31 19:02:42 +0000442 if not session:
443 message = "Could not log into guest"
444 logging.error(message)
445 raise error.TestFail(message)
446
447 logging.info("Logged in")
448
lmr912c74b2009-08-17 20:43:27 +0000449 internal_yum_update(session, "yum update", params.get("shell_prompt"), 600)
lmr6f669ce2009-05-31 19:02:42 +0000450 internal_yum_update(session, "yum update kernel",
lmr912c74b2009-08-17 20:43:27 +0000451 params.get("shell_prompt"), 600)
lmr6f669ce2009-05-31 19:02:42 +0000452
453 session.close()
454
455
456def run_linux_s3(test, params, env):
457 """
458 Suspend a guest Linux OS to memory.
459
460 @param test: kvm test object.
461 @param params: Dictionary with test parameters.
462 @param env: Dictionary with the test environment.
463 """
464 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
465 if not vm:
466 raise error.TestError("VM object not found in environment")
467 if not vm.is_alive():
468 raise error.TestError("VM seems to be dead; Test requires a living VM")
469
470 logging.info("Waiting for guest to be up...")
471
lmr912c74b2009-08-17 20:43:27 +0000472 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr6f669ce2009-05-31 19:02:42 +0000473 if not session:
474 raise error.TestFail("Could not log into guest")
475
476 logging.info("Logged in")
477 logging.info("Checking that VM supports S3")
478
479 status = session.get_command_status("grep -q mem /sys/power/state")
480 if status == None:
481 logging.error("Failed to check if S3 exists")
482 elif status != 0:
483 raise error.TestFail("Guest does not support S3")
484
485 logging.info("Waiting for a while for X to start")
486 time.sleep(10)
487
488 src_tty = session.get_command_output("fgconsole").strip()
489 logging.info("Current virtual terminal is %s" % src_tty)
490 if src_tty not in map(str, range(1,10)):
491 raise error.TestFail("Got a strange current vt (%s)" % src_tty)
492
493 dst_tty = "1"
494 if src_tty == "1":
495 dst_tty = "2"
496
497 logging.info("Putting VM into S3")
498 command = "chvt %s && echo mem > /sys/power/state && chvt %s" % (dst_tty,
499 src_tty)
500 status = session.get_command_status(command, timeout=120)
501 if status != 0:
502 raise error.TestFail("Suspend to mem failed")
503
504 logging.info("VM resumed after S3")
505
506 session.close()
lmra04d7c92009-06-19 13:05:39 +0000507
508
509def run_stress_boot(tests, params, env):
510 """
511 Boots VMs until one of them becomes unresponsive, and records the maximum
512 number of VMs successfully started:
513 1) boot the first vm
514 2) boot the second vm cloned from the first vm, check whether it boots up
lmr912c74b2009-08-17 20:43:27 +0000515 and all booted vms respond to shell commands
lmra04d7c92009-06-19 13:05:39 +0000516 3) go on until cannot create VM anymore or cannot allocate memory for VM
517
518 @param test: kvm test object
519 @param params: Dictionary with the test parameters
520 @param env: Dictionary with test environment.
521 """
522 # boot the first vm
523 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
lmra04d7c92009-06-19 13:05:39 +0000524 if not vm:
525 raise error.TestError("VM object not found in environment")
526 if not vm.is_alive():
527 raise error.TestError("VM seems to be dead; Test requires a living VM")
528
529 logging.info("Waiting for first guest to be up...")
530
lmr912c74b2009-08-17 20:43:27 +0000531 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmra04d7c92009-06-19 13:05:39 +0000532 if not session:
533 raise error.TestFail("Could not log into first guest")
534
535 num = 2
lmra04d7c92009-06-19 13:05:39 +0000536 sessions = [session]
lmr26bac242009-08-13 04:14:24 +0000537 address_index = int(params.get("clone_address_index_base", 10))
lmra04d7c92009-06-19 13:05:39 +0000538
539 # boot the VMs
540 while num <= int(params.get("max_vms")):
541 try:
542 vm_name = "vm" + str(num)
543
544 # clone vm according to the first one
lmr26bac242009-08-13 04:14:24 +0000545 vm_params = vm.get_params().copy()
546 vm_params["address_index"] = str(address_index)
lmra04d7c92009-06-19 13:05:39 +0000547 curr_vm = vm.clone(vm_name, vm_params)
548 kvm_utils.env_register_vm(env, vm_name, curr_vm)
549 params['vms'] += " " + vm_name
550
lmra04d7c92009-06-19 13:05:39 +0000551 logging.info("Booting guest #%d" % num)
552 if not curr_vm.create():
553 raise error.TestFail("Cannot create VM #%d" % num)
554
lmr912c74b2009-08-17 20:43:27 +0000555 curr_vm_session = kvm_utils.wait_for(curr_vm.remote_login, 240, 0, 2)
lmra04d7c92009-06-19 13:05:39 +0000556 if not curr_vm_session:
557 raise error.TestFail("Could not log into guest #%d" % num)
558
559 logging.info("Guest #%d boots up successfully" % num)
560 sessions.append(curr_vm_session)
561
lmr912c74b2009-08-17 20:43:27 +0000562 # check whether all previous shell sessions are responsive
lmr26bac242009-08-13 04:14:24 +0000563 for i, se in enumerate(sessions):
564 if se.get_command_status(params.get("alive_test_cmd")) != 0:
lmra04d7c92009-06-19 13:05:39 +0000565 raise error.TestFail("Session #%d is not responsive" % i)
566 num += 1
lmr26bac242009-08-13 04:14:24 +0000567 address_index += 1
lmra04d7c92009-06-19 13:05:39 +0000568
569 except (error.TestFail, OSError):
570 for se in sessions:
571 se.close()
572 logging.info("Total number booted: %d" % (num - 1))
573 raise
574 else:
575 for se in sessions:
576 se.close()
577 logging.info("Total number booted: %d" % (num -1))
lmr5c226e32009-07-27 13:13:01 +0000578
579
580def run_timedrift(test, params, env):
581 """
582 Time drift test (mainly for Windows guests):
583
584 1) Log into a guest.
585 2) Take a time reading from the guest and host.
586 3) Run load on the guest and host.
587 4) Take a second time reading.
588 5) Stop the load and rest for a while.
589 6) Take a third time reading.
590 7) If the drift immediately after load is higher than a user-
591 specified value (in %), fail.
592 If the drift after the rest period is higher than a user-specified value,
593 fail.
594
595 @param test: KVM test object.
596 @param params: Dictionary with test parameters.
597 @param env: Dictionary with the test environment.
598 """
lmr25e89fc2009-08-07 20:29:16 +0000599 # Helper functions
600 def set_cpu_affinity(pid, mask):
601 """
602 Set the CPU affinity of all threads of the process with PID pid.
lmr152da2d2009-09-09 22:16:21 +0000603 Do this recursively for all child processes as well.
lmr25e89fc2009-08-07 20:29:16 +0000604
605 @param pid: The process ID.
606 @param mask: The CPU affinity mask.
607 @return: A dict containing the previous mask for each thread.
608 """
609 tids = commands.getoutput("ps -L --pid=%s -o lwp=" % pid).split()
610 prev_masks = {}
611 for tid in tids:
612 prev_mask = commands.getoutput("taskset -p %s" % tid).split()[-1]
613 prev_masks[tid] = prev_mask
614 commands.getoutput("taskset -p %s %s" % (mask, tid))
lmr152da2d2009-09-09 22:16:21 +0000615 children = commands.getoutput("ps --ppid=%s -o pid=" % pid).split()
616 for child in children:
617 prev_masks.update(set_cpu_affinity(child, mask))
lmr25e89fc2009-08-07 20:29:16 +0000618 return prev_masks
619
620 def restore_cpu_affinity(prev_masks):
621 """
622 Restore the CPU affinity of several threads.
623
624 @param prev_masks: A dict containing TIDs as keys and masks as values.
625 """
626 for tid, mask in prev_masks.items():
627 commands.getoutput("taskset -p %s %s" % (mask, tid))
628
lmrff2a7c52009-08-10 00:09:22 +0000629 def get_time(session, time_command, time_filter_re, time_format):
lmr25e89fc2009-08-07 20:29:16 +0000630 """
631 Returns the host time and guest time.
632
lmrff2a7c52009-08-10 00:09:22 +0000633 @param session: A shell session.
634 @param time_command: Command to issue to get the current guest time.
635 @param time_filter_re: Regex filter to apply on the output of
636 time_command in order to get the current time.
637 @param time_format: Format string to pass to time.strptime() with the
638 result of the regex filter.
lmr25e89fc2009-08-07 20:29:16 +0000639 @return: A tuple containing the host time and guest time.
640 """
641 host_time = time.time()
642 session.sendline(time_command)
643 (match, s) = session.read_up_to_prompt()
644 s = re.findall(time_filter_re, s)[0]
645 guest_time = time.mktime(time.strptime(s, time_format))
646 return (host_time, guest_time)
647
lmr5c226e32009-07-27 13:13:01 +0000648 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
649 if not vm:
650 raise error.TestError("VM object not found in environment")
651 if not vm.is_alive():
652 raise error.TestError("VM seems to be dead; Test requires a living VM")
653
654 logging.info("Waiting for guest to be up...")
655
lmr912c74b2009-08-17 20:43:27 +0000656 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmr5c226e32009-07-27 13:13:01 +0000657 if not session:
658 raise error.TestFail("Could not log into guest")
659
660 logging.info("Logged in")
661
662 # Collect test parameters:
663 # Command to run to get the current time
664 time_command = params.get("time_command")
665 # Filter which should match a string to be passed to time.strptime()
666 time_filter_re = params.get("time_filter_re")
667 # Time format for time.strptime()
668 time_format = params.get("time_format")
669 guest_load_command = params.get("guest_load_command")
670 guest_load_stop_command = params.get("guest_load_stop_command")
671 host_load_command = params.get("host_load_command")
672 guest_load_instances = int(params.get("guest_load_instances", "1"))
673 host_load_instances = int(params.get("host_load_instances", "0"))
674 # CPU affinity mask for taskset
675 cpu_mask = params.get("cpu_mask", "0xFF")
676 load_duration = float(params.get("load_duration", "30"))
677 rest_duration = float(params.get("rest_duration", "10"))
678 drift_threshold = float(params.get("drift_threshold", "200"))
679 drift_threshold_after_rest = float(params.get("drift_threshold_after_rest",
680 "200"))
681
682 guest_load_sessions = []
683 host_load_sessions = []
684
lmr5c226e32009-07-27 13:13:01 +0000685 # Set the VM's CPU affinity
lmr25e89fc2009-08-07 20:29:16 +0000686 prev_affinity = set_cpu_affinity(vm.get_pid(), cpu_mask)
lmr5c226e32009-07-27 13:13:01 +0000687
688 try:
689 # Get time before load
lmrff2a7c52009-08-10 00:09:22 +0000690 (host_time_0, guest_time_0) = get_time(session, time_command,
691 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000692
693 # Run some load on the guest
694 logging.info("Starting load on guest...")
695 for i in range(guest_load_instances):
lmr912c74b2009-08-17 20:43:27 +0000696 load_session = vm.remote_login()
lmr5c226e32009-07-27 13:13:01 +0000697 if not load_session:
698 raise error.TestFail("Could not log into guest")
699 load_session.set_output_prefix("(guest load %d) " % i)
700 load_session.set_output_func(logging.debug)
701 load_session.sendline(guest_load_command)
702 guest_load_sessions.append(load_session)
703
704 # Run some load on the host
705 logging.info("Starting load on host...")
706 for i in range(host_load_instances):
707 host_load_sessions.append(
708 kvm_subprocess.run_bg(host_load_command,
709 output_func=logging.debug,
710 output_prefix="(host load %d) " % i,
711 timeout=0.5))
lmr152da2d2009-09-09 22:16:21 +0000712 # Set the CPU affinity of the load process
lmrfb151b52009-09-09 22:19:11 +0000713 pid = host_load_sessions[-1].get_pid()
lmr25e89fc2009-08-07 20:29:16 +0000714 set_cpu_affinity(pid, cpu_mask)
lmr5c226e32009-07-27 13:13:01 +0000715
716 # Sleep for a while (during load)
717 logging.info("Sleeping for %s seconds..." % load_duration)
718 time.sleep(load_duration)
719
720 # Get time delta after load
lmrff2a7c52009-08-10 00:09:22 +0000721 (host_time_1, guest_time_1) = get_time(session, time_command,
722 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000723
724 # Report results
725 host_delta = host_time_1 - host_time_0
726 guest_delta = guest_time_1 - guest_time_0
727 drift = 100.0 * (host_delta - guest_delta) / host_delta
728 logging.info("Host duration: %.2f" % host_delta)
729 logging.info("Guest duration: %.2f" % guest_delta)
730 logging.info("Drift: %.2f%%" % drift)
731
732 finally:
733 logging.info("Cleaning up...")
734 # Restore the VM's CPU affinity
lmr25e89fc2009-08-07 20:29:16 +0000735 restore_cpu_affinity(prev_affinity)
lmr5c226e32009-07-27 13:13:01 +0000736 # Stop the guest load
737 if guest_load_stop_command:
738 session.get_command_output(guest_load_stop_command)
739 # Close all load shell sessions
740 for load_session in guest_load_sessions:
741 load_session.close()
742 for load_session in host_load_sessions:
743 load_session.close()
744
745 # Sleep again (rest)
746 logging.info("Sleeping for %s seconds..." % rest_duration)
747 time.sleep(rest_duration)
748
749 # Get time after rest
lmrff2a7c52009-08-10 00:09:22 +0000750 (host_time_2, guest_time_2) = get_time(session, time_command,
751 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000752
753 # Report results
754 host_delta_total = host_time_2 - host_time_0
755 guest_delta_total = guest_time_2 - guest_time_0
756 drift_total = 100.0 * (host_delta_total - guest_delta_total) / host_delta
757 logging.info("Total host duration including rest: %.2f" % host_delta_total)
758 logging.info("Total guest duration including rest: %.2f" % guest_delta_total)
759 logging.info("Total drift after rest: %.2f%%" % drift_total)
760
lmr5b829602009-08-07 20:36:06 +0000761 session.close()
762
lmr5c226e32009-07-27 13:13:01 +0000763 # Fail the test if necessary
764 if drift > drift_threshold:
765 raise error.TestFail("Time drift too large: %.2f%%" % drift)
lmr67bf4442009-08-28 17:29:45 +0000766 if drift_total > drift_threshold_after_rest:
lmr5c226e32009-07-27 13:13:01 +0000767 raise error.TestFail("Time drift too large after rest period: %.2f%%"
768 % drift_total)
lmr3efa0bd2009-08-18 20:00:56 +0000769
770
771def run_autoit(test, params, env):
772 """
773 A wrapper for AutoIt scripts.
774
775 1) Log into a guest.
776 2) Run AutoIt script.
777 3) Wait for script execution to complete.
778 4) Pass/fail according to exit status of script.
779
780 @param test: KVM test object.
781 @param params: Dictionary with test parameters.
782 @param env: Dictionary with the test environment.
783 """
784 vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
785 if not vm:
786 raise error.TestError("VM object not found in environment")
787 if not vm.is_alive():
788 raise error.TestError("VM seems to be dead; Test requires a living VM")
789
790 logging.info("Waiting for guest to be up...")
791
792 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
793 if not session:
794 raise error.TestFail("Could not log into guest")
795
796 try:
797 logging.info("Logged in; starting script...")
798
799 # Collect test parameters
800 binary = params.get("autoit_binary")
801 script = params.get("autoit_script")
802 script_params = params.get("autoit_script_params", "")
803 timeout = float(params.get("autoit_script_timeout", 600))
804
805 # Send AutoIt script to guest (this code will be replaced once we
806 # support sending files to Windows guests)
807 session.sendline("del script.au3")
808 file = open(kvm_utils.get_path(test.bindir, script))
809 for line in file.readlines():
810 # Insert a '^' before each character
811 line = "".join("^" + c for c in line.rstrip())
812 if line:
813 # Append line to the file
814 session.sendline("echo %s>>script.au3" % line)
815 file.close()
816
817 session.read_up_to_prompt()
818
819 command = "cmd /c %s script.au3 %s" % (binary, script_params)
820
821 logging.info("---------------- Script output ----------------")
822 status = session.get_command_status(command,
823 print_func=logging.info,
824 timeout=timeout)
825 logging.info("---------------- End of script output ----------------")
826
827 if status is None:
828 raise error.TestFail("Timeout expired before script execution "
829 "completed (or something weird happened)")
830 if status != 0:
831 raise error.TestFail("Script execution failed")
832
833 finally:
834 session.close()