blob: 35666cfe1b79a9be3d7d19396cfe137b63ee9975 [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
lmrfbb672b2009-09-09 22:42:51 +00003import kvm_utils, kvm_subprocess, ppm_utils, scan_results, kvm_test_utils
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 """
lmrfbb672b2009-09-09 22:42:51 +000024 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
25 session = kvm_test_utils.wait_for_login(vm)
lmr6f669ce2009-05-31 19:02:42 +000026
lmr9ce347d2009-09-09 22:26:53 +000027 try:
lmr9ce347d2009-09-09 22:26:53 +000028 if params.get("reboot_method") == "shell":
29 # Send a reboot command to the guest's shell
30 session.sendline(vm.get_params().get("reboot_command"))
31 logging.info("Reboot command sent; waiting for guest to go "
32 "down...")
33 elif params.get("reboot_method") == "system_reset":
34 # Sleep for a while -- give the guest a chance to finish booting
35 time.sleep(float(params.get("sleep_before_reset", 10)))
36 # Send a system_reset monitor command
37 vm.send_monitor_cmd("system_reset")
38 logging.info("system_reset monitor command sent; waiting for "
39 "guest to go down...")
40 else: return
lmr6f669ce2009-05-31 19:02:42 +000041
lmr9ce347d2009-09-09 22:26:53 +000042 # Wait for the session to become unresponsive
lmr6f669ce2009-05-31 19:02:42 +000043 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
lmr9ce347d2009-09-09 22:26:53 +000057 finally:
58 session.close()
lmr6f669ce2009-05-31 19:02:42 +000059
60
lmr6faadb22009-06-18 14:57:45 +000061def run_shutdown(test, params, env):
62 """
63 KVM shutdown test:
64 1) Log into a guest
lmr6e840e32009-09-09 22:38:07 +000065 2) Send a shutdown command to the guest, or issue a system_powerdown
66 monitor command (depending on the value of shutdown_method)
67 3) Wait until the guest is down
lmr6faadb22009-06-18 14:57:45 +000068
69 @param test: kvm test object
70 @param params: Dictionary with the test parameters
71 @param env: Dictionary with test environment
72 """
lmrfbb672b2009-09-09 22:42:51 +000073 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
74 session = kvm_test_utils.wait_for_login(vm)
lmr6faadb22009-06-18 14:57:45 +000075
lmr20773742009-08-13 04:43:45 +000076 try:
lmr6e840e32009-09-09 22:38:07 +000077 if params.get("shutdown_method") == "shell":
78 # Send a shutdown command to the guest's shell
79 session.sendline(vm.get_params().get("shutdown_command"))
80 logging.info("Shutdown command sent; waiting for guest to go "
81 "down...")
82 elif params.get("shutdown_method") == "system_powerdown":
83 # Sleep for a while -- give the guest a chance to finish booting
84 time.sleep(float(params.get("sleep_before_powerdown", 10)))
85 # Send a system_powerdown monitor command
86 vm.send_monitor_cmd("system_powerdown")
87 logging.info("system_powerdown monitor command sent; waiting for "
88 "guest to go down...")
lmr6faadb22009-06-18 14:57:45 +000089
lmr20773742009-08-13 04:43:45 +000090 if not kvm_utils.wait_for(vm.is_dead, 240, 0, 1):
91 raise error.TestFail("Guest refuses to go down")
lmr6faadb22009-06-18 14:57:45 +000092
lmr20773742009-08-13 04:43:45 +000093 logging.info("Guest is down")
lmr6e840e32009-09-09 22:38:07 +000094
lmr20773742009-08-13 04:43:45 +000095 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:
lmr4d5cc792009-09-09 22:01:57 +0000102 1) Get a live VM and clone it.
103 2) Verify that 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.
lmr6f669ce2009-05-31 19:02:42 +0000108 4) Compare the output of a reference command executed on the source with
lmr4d5cc792009-09-09 22:01:57 +0000109 the output of the same command on the destination machine.
lmr6f669ce2009-05-31 19:02:42 +0000110
111 @param test: kvm test object.
112 @param params: Dictionary with test parameters.
113 @param env: Dictionary with the test environment.
114 """
lmrfbb672b2009-09-09 22:42:51 +0000115 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
lmr6f669ce2009-05-31 19:02:42 +0000116
117 # See if migration is supported
118 s, o = vm.send_monitor_cmd("help info")
119 if not "info migrate" in o:
120 raise error.TestError("Migration is not supported")
121
lmrfbb672b2009-09-09 22:42:51 +0000122 # Log into guest and get the output of migration_test_command
123 session = kvm_test_utils.wait_for_login(vm)
124 migration_test_command = params.get("migration_test_command")
125 reference_output = session.get_command_output(migration_test_command)
126 session.close()
127
128 # Clone the main VM and ask it to wait for incoming migration
lmr4d5cc792009-09-09 22:01:57 +0000129 dest_vm = vm.clone()
130 dest_vm.create(for_migration=True)
131
lmr6f669ce2009-05-31 19:02:42 +0000132 # Define the migration command
133 cmd = "migrate -d tcp:localhost:%d" % dest_vm.migration_port
134 logging.debug("Migration command: %s" % cmd)
135
136 # Migrate
137 s, o = vm.send_monitor_cmd(cmd)
138 if s:
139 logging.error("Migration command failed (command: %r, output: %r)" %
140 (cmd, o))
141 raise error.TestFail("Migration command failed")
142
143 # Define some helper functions
144 def mig_finished():
145 s, o = vm.send_monitor_cmd("info migrate")
lmr4d5cc792009-09-09 22:01:57 +0000146 return s == 0 and not "Migration status: active" in o
lmr6f669ce2009-05-31 19:02:42 +0000147
148 def mig_succeeded():
149 s, o = vm.send_monitor_cmd("info migrate")
lmr4d5cc792009-09-09 22:01:57 +0000150 return s == 0 and "Migration status: completed" in o
lmr6f669ce2009-05-31 19:02:42 +0000151
152 def mig_failed():
153 s, o = vm.send_monitor_cmd("info migrate")
lmr4d5cc792009-09-09 22:01:57 +0000154 return s == 0 and "Migration status: failed" in o
lmr6f669ce2009-05-31 19:02:42 +0000155
156 # Wait for migration to finish
157 if not kvm_utils.wait_for(mig_finished, 90, 2, 2,
158 "Waiting for migration to finish..."):
lmr4d5cc792009-09-09 22:01:57 +0000159 raise error.TestFail("Timeout elapsed while waiting for migration to "
lmr6f669ce2009-05-31 19:02:42 +0000160 "finish")
161
162 # Report migration status
163 if mig_succeeded():
164 logging.info("Migration finished successfully")
lmr4d5cc792009-09-09 22:01:57 +0000165 elif mig_failed():
166 raise error.TestFail("Migration failed")
lmr6f669ce2009-05-31 19:02:42 +0000167 else:
lmr4d5cc792009-09-09 22:01:57 +0000168 raise error.TestFail("Migration ended with unknown status")
lmr6f669ce2009-05-31 19:02:42 +0000169
170 # Kill the source VM
lmr4d5cc792009-09-09 22:01:57 +0000171 vm.destroy(gracefully=False)
lmr6f669ce2009-05-31 19:02:42 +0000172
173 # Log into guest and get the output of migration_test_command
174 logging.info("Logging into guest after migration...")
175
lmr912c74b2009-08-17 20:43:27 +0000176 session = dest_vm.remote_login()
lmr6f669ce2009-05-31 19:02:42 +0000177 if not session:
178 raise error.TestFail("Could not log into guest after migration")
179
180 logging.info("Logged in after migration")
181
lmrfbb672b2009-09-09 22:42:51 +0000182 output = session.get_command_output(migration_test_command)
lmr6f669ce2009-05-31 19:02:42 +0000183 session.close()
184
185 # Compare output to reference output
186 if output != reference_output:
lmr4d5cc792009-09-09 22:01:57 +0000187 logging.info("Command output before migration differs from command "
188 "output after migration")
lmr6f669ce2009-05-31 19:02:42 +0000189 logging.info("Command: %s" % params.get("migration_test_command"))
190 logging.info("Output before:" +
191 kvm_utils.format_str_for_message(reference_output))
192 logging.info("Output after:" + kvm_utils.format_str_for_message(output))
lmr4d5cc792009-09-09 22:01:57 +0000193 raise error.TestFail("Command produced different output before and "
194 "after migration")
195
lmrfbb672b2009-09-09 22:42:51 +0000196 # Replace the main VM with the new cloned VM
lmr4d5cc792009-09-09 22:01:57 +0000197 kvm_utils.env_register_vm(env, params.get("main_vm"), dest_vm)
lmr6f669ce2009-05-31 19:02:42 +0000198
199
200def run_autotest(test, params, env):
201 """
202 Run an autotest test inside a guest.
203
204 @param test: kvm test object.
205 @param params: Dictionary with test parameters.
206 @param env: Dictionary with the test environment.
207 """
lmrfbb672b2009-09-09 22:42:51 +0000208 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
209 session = kvm_test_utils.wait_for_login(vm)
lmr6f669ce2009-05-31 19:02:42 +0000210
211 # Collect some info
212 test_name = params.get("test_name")
213 test_timeout = int(params.get("test_timeout", 300))
214 test_control_file = params.get("test_control_file", "control")
215 tarred_autotest_path = "/tmp/autotest.tar.bz2"
216 tarred_test_path = "/tmp/%s.tar.bz2" % test_name
217
218 # tar the contents of bindir/autotest
219 cmd = "cd %s; tar cvjf %s autotest/*"
220 cmd += " --exclude=autotest/tests"
221 cmd += " --exclude=autotest/results"
222 cmd += " --exclude=autotest/tmp"
223 cmd += " --exclude=autotest/control"
224 cmd += " --exclude=*.pyc"
225 cmd += " --exclude=*.svn"
226 cmd += " --exclude=*.git"
lmrd85c55b2009-07-23 01:42:10 +0000227 kvm_subprocess.run_fg(cmd % (test.bindir, tarred_autotest_path), timeout=30)
lmr6f669ce2009-05-31 19:02:42 +0000228
229 # tar the contents of bindir/autotest/tests/<test_name>
230 cmd = "cd %s; tar cvjf %s %s/*"
231 cmd += " --exclude=*.pyc"
232 cmd += " --exclude=*.svn"
233 cmd += " --exclude=*.git"
lmrd85c55b2009-07-23 01:42:10 +0000234 kvm_subprocess.run_fg(cmd %
235 (os.path.join(test.bindir, "autotest", "tests"),
236 tarred_test_path, test_name), timeout=30)
lmr6f669ce2009-05-31 19:02:42 +0000237
238 # Check if we need to copy autotest.tar.bz2
239 copy = False
240 output = session.get_command_output("ls -l autotest.tar.bz2")
241 if "such file" in output:
242 copy = True
243 else:
244 size = int(output.split()[4])
245 if size != os.path.getsize(tarred_autotest_path):
246 copy = True
247 # Perform the copy
248 if copy:
249 logging.info("Copying autotest.tar.bz2 to guest"
250 " (file is missing or has a different size)...")
lmr912c74b2009-08-17 20:43:27 +0000251 if not vm.copy_files_to(tarred_autotest_path, ""):
lmr6f669ce2009-05-31 19:02:42 +0000252 raise error.TestFail("Could not copy autotest.tar.bz2 to guest")
253
254 # Check if we need to copy <test_name>.tar.bz2
255 copy = False
256 output = session.get_command_output("ls -l %s.tar.bz2" % test_name)
257 if "such file" in output:
258 copy = True
259 else:
260 size = int(output.split()[4])
261 if size != os.path.getsize(tarred_test_path):
262 copy = True
263 # Perform the copy
264 if copy:
265 logging.info("Copying %s.tar.bz2 to guest (file is missing or has a"
266 " different size)..." % test_name)
lmr912c74b2009-08-17 20:43:27 +0000267 if not vm.copy_files_to(tarred_test_path, ""):
lmr6f669ce2009-05-31 19:02:42 +0000268 raise error.TestFail("Could not copy %s.tar.bz2 to guest" %
269 test_name)
270
271 # Extract autotest.tar.bz2
272 logging.info("Extracting autotest.tar.bz2...")
273 status = session.get_command_status("tar xvfj autotest.tar.bz2")
274 if status != 0:
275 raise error.TestFail("Could not extract autotest.tar.bz2")
276
277 # mkdir autotest/tests
278 session.sendline("mkdir autotest/tests")
279
280 # Extract <test_name>.tar.bz2 into autotest/tests
281 logging.info("Extracting %s.tar.bz2..." % test_name)
282 status = session.get_command_status("tar xvfj %s.tar.bz2 -C "
283 "autotest/tests" % test_name)
284 if status != 0:
285 raise error.TestFail("Could not extract %s.tar.bz2" % test_name)
286
lmr16cf1652009-06-15 21:32:49 +0000287 # Cleaning up old remaining results
288 session.sendline("rm -rf autotest/results/*")
289 # Copying the selected control file (located inside
290 # test.bindir/autotest_control to the autotest dir
291 control_file_path = os.path.join(test.bindir, "autotest_control",
292 test_control_file)
lmr912c74b2009-08-17 20:43:27 +0000293 if not vm.copy_files_to(control_file_path, "autotest/control"):
lmr16cf1652009-06-15 21:32:49 +0000294 raise error.TestFail("Could not copy the test control file to guest")
lmr6f669ce2009-05-31 19:02:42 +0000295 # Run the test
296 logging.info("Running test '%s'..." % test_name)
lmr16cf1652009-06-15 21:32:49 +0000297 session.sendline("cd autotest")
298 session.sendline("rm -f control.state")
lmr6f669ce2009-05-31 19:02:42 +0000299 session.read_up_to_prompt()
lmr16cf1652009-06-15 21:32:49 +0000300 session.sendline("bin/autotest control")
lmr6f669ce2009-05-31 19:02:42 +0000301 logging.info("---------------- Test output ----------------")
lmr16cf1652009-06-15 21:32:49 +0000302 match = session.read_up_to_prompt(timeout=test_timeout,
303 print_func=logging.info)[0]
lmr6f669ce2009-05-31 19:02:42 +0000304 logging.info("---------------- End of test output ----------------")
305 if not match:
lmr16cf1652009-06-15 21:32:49 +0000306 raise error.TestFail("Timeout elapsed while waiting for test to "
307 "complete")
308 # Get the results generated by autotest
309 output = session.get_command_output("cat results/*/status")
lmr6f669ce2009-05-31 19:02:42 +0000310
311 # Parse test results
312 result_list = scan_results.parse_results(output)
313
314 # Report test results and check for FAIL/ERROR status
315 logging.info("Results (test, status, duration, info):")
316 status_error = False
317 status_fail = False
318 if result_list == []:
319 status_fail = True
lmrd16a67d2009-06-10 19:52:59 +0000320 message_fail = ("Test '%s' did not produce any recognizable "
321 "results" % test_name)
lmr6f669ce2009-05-31 19:02:42 +0000322 for result in result_list:
323 logging.info(str(result))
324 if result[1] == "FAIL":
325 status_fail = True
lmr50bece42009-06-15 20:54:43 +0000326 message_fail = ("Test '%s' ended with FAIL "
327 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000328 if result[1] == "ERROR":
329 status_error = True
lmr50bece42009-06-15 20:54:43 +0000330 message_error = ("Test '%s' ended with ERROR "
331 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000332 if result[1] == "ABORT":
333 status_error = True
lmr50bece42009-06-15 20:54:43 +0000334 message_error = ("Test '%s' ended with ABORT "
335 "(info: '%s')" % (result[0], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000336
337 # Copy test results to the local bindir/guest_results
338 logging.info("Copying results back from guest...")
339 guest_results_dir = os.path.join(test.outputdir, "guest_results")
340 if not os.path.exists(guest_results_dir):
341 os.mkdir(guest_results_dir)
lmr912c74b2009-08-17 20:43:27 +0000342 if not vm.copy_files_from("autotest/results/default/*", guest_results_dir):
lmr6f669ce2009-05-31 19:02:42 +0000343 logging.error("Could not copy results back from guest")
344
345 # Fail the test if necessary
346 if status_fail:
347 raise error.TestFail(message_fail)
348 elif status_error:
349 raise error.TestError(message_error)
350
351
352def internal_yum_update(session, command, prompt, timeout):
353 """
354 Helper function to perform the yum update test.
355
lmr912c74b2009-08-17 20:43:27 +0000356 @param session: shell session stablished to the host
357 @param command: Command to be sent to the shell session
lmr6f669ce2009-05-31 19:02:42 +0000358 @param prompt: Machine prompt
359 @param timeout: How long to wait until we get an appropriate output from
lmr912c74b2009-08-17 20:43:27 +0000360 the shell session.
lmr6f669ce2009-05-31 19:02:42 +0000361 """
362 session.sendline(command)
363 end_time = time.time() + timeout
364 while time.time() < end_time:
365 (match, text) = session.read_until_last_line_matches(
366 ["[Ii]s this [Oo][Kk]", prompt], timeout=timeout)
367 if match == 0:
368 logging.info("Got 'Is this ok'; sending 'y'")
369 session.sendline("y")
370 elif match == 1:
371 logging.info("Got shell prompt")
372 return True
373 else:
374 logging.info("Timeout or process exited")
375 return False
376
377
378def run_yum_update(test, params, env):
379 """
380 Runs yum update and yum update kernel on the remote host (yum enabled
381 hosts only).
382
383 @param test: kvm test object.
384 @param params: Dictionary with test parameters.
385 @param env: Dictionary with the test environment.
386 """
lmrfbb672b2009-09-09 22:42:51 +0000387 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
388 session = kvm_test_utils.wait_for_login(vm)
lmr6f669ce2009-05-31 19:02:42 +0000389
lmr912c74b2009-08-17 20:43:27 +0000390 internal_yum_update(session, "yum update", params.get("shell_prompt"), 600)
lmr6f669ce2009-05-31 19:02:42 +0000391 internal_yum_update(session, "yum update kernel",
lmr912c74b2009-08-17 20:43:27 +0000392 params.get("shell_prompt"), 600)
lmr6f669ce2009-05-31 19:02:42 +0000393
394 session.close()
395
396
397def run_linux_s3(test, params, env):
398 """
399 Suspend a guest Linux OS to memory.
400
401 @param test: kvm test object.
402 @param params: Dictionary with test parameters.
403 @param env: Dictionary with the test environment.
404 """
lmrfbb672b2009-09-09 22:42:51 +0000405 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
406 session = kvm_test_utils.wait_for_login(vm)
lmr6f669ce2009-05-31 19:02:42 +0000407
lmr6f669ce2009-05-31 19:02:42 +0000408 logging.info("Checking that VM supports S3")
lmr6f669ce2009-05-31 19:02:42 +0000409 status = session.get_command_status("grep -q mem /sys/power/state")
410 if status == None:
411 logging.error("Failed to check if S3 exists")
412 elif status != 0:
413 raise error.TestFail("Guest does not support S3")
414
415 logging.info("Waiting for a while for X to start")
416 time.sleep(10)
417
418 src_tty = session.get_command_output("fgconsole").strip()
419 logging.info("Current virtual terminal is %s" % src_tty)
420 if src_tty not in map(str, range(1,10)):
421 raise error.TestFail("Got a strange current vt (%s)" % src_tty)
422
423 dst_tty = "1"
424 if src_tty == "1":
425 dst_tty = "2"
426
427 logging.info("Putting VM into S3")
428 command = "chvt %s && echo mem > /sys/power/state && chvt %s" % (dst_tty,
429 src_tty)
430 status = session.get_command_status(command, timeout=120)
431 if status != 0:
432 raise error.TestFail("Suspend to mem failed")
433
434 logging.info("VM resumed after S3")
435
436 session.close()
lmra04d7c92009-06-19 13:05:39 +0000437
438
439def run_stress_boot(tests, params, env):
440 """
441 Boots VMs until one of them becomes unresponsive, and records the maximum
442 number of VMs successfully started:
443 1) boot the first vm
444 2) boot the second vm cloned from the first vm, check whether it boots up
lmr912c74b2009-08-17 20:43:27 +0000445 and all booted vms respond to shell commands
lmra04d7c92009-06-19 13:05:39 +0000446 3) go on until cannot create VM anymore or cannot allocate memory for VM
447
448 @param test: kvm test object
449 @param params: Dictionary with the test parameters
450 @param env: Dictionary with test environment.
451 """
452 # boot the first vm
lmrfbb672b2009-09-09 22:42:51 +0000453 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
lmra04d7c92009-06-19 13:05:39 +0000454
455 logging.info("Waiting for first guest to be up...")
456
lmr912c74b2009-08-17 20:43:27 +0000457 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmra04d7c92009-06-19 13:05:39 +0000458 if not session:
459 raise error.TestFail("Could not log into first guest")
460
461 num = 2
lmra04d7c92009-06-19 13:05:39 +0000462 sessions = [session]
lmr26bac242009-08-13 04:14:24 +0000463 address_index = int(params.get("clone_address_index_base", 10))
lmra04d7c92009-06-19 13:05:39 +0000464
465 # boot the VMs
466 while num <= int(params.get("max_vms")):
467 try:
468 vm_name = "vm" + str(num)
469
470 # clone vm according to the first one
lmr26bac242009-08-13 04:14:24 +0000471 vm_params = vm.get_params().copy()
472 vm_params["address_index"] = str(address_index)
lmra04d7c92009-06-19 13:05:39 +0000473 curr_vm = vm.clone(vm_name, vm_params)
474 kvm_utils.env_register_vm(env, vm_name, curr_vm)
475 params['vms'] += " " + vm_name
476
lmra04d7c92009-06-19 13:05:39 +0000477 logging.info("Booting guest #%d" % num)
478 if not curr_vm.create():
479 raise error.TestFail("Cannot create VM #%d" % num)
480
lmr912c74b2009-08-17 20:43:27 +0000481 curr_vm_session = kvm_utils.wait_for(curr_vm.remote_login, 240, 0, 2)
lmra04d7c92009-06-19 13:05:39 +0000482 if not curr_vm_session:
483 raise error.TestFail("Could not log into guest #%d" % num)
484
485 logging.info("Guest #%d boots up successfully" % num)
486 sessions.append(curr_vm_session)
487
lmr912c74b2009-08-17 20:43:27 +0000488 # check whether all previous shell sessions are responsive
lmr26bac242009-08-13 04:14:24 +0000489 for i, se in enumerate(sessions):
490 if se.get_command_status(params.get("alive_test_cmd")) != 0:
lmra04d7c92009-06-19 13:05:39 +0000491 raise error.TestFail("Session #%d is not responsive" % i)
492 num += 1
lmr26bac242009-08-13 04:14:24 +0000493 address_index += 1
lmra04d7c92009-06-19 13:05:39 +0000494
495 except (error.TestFail, OSError):
496 for se in sessions:
497 se.close()
498 logging.info("Total number booted: %d" % (num - 1))
499 raise
500 else:
501 for se in sessions:
502 se.close()
503 logging.info("Total number booted: %d" % (num -1))
lmr5c226e32009-07-27 13:13:01 +0000504
505
506def run_timedrift(test, params, env):
507 """
508 Time drift test (mainly for Windows guests):
509
510 1) Log into a guest.
511 2) Take a time reading from the guest and host.
512 3) Run load on the guest and host.
513 4) Take a second time reading.
514 5) Stop the load and rest for a while.
515 6) Take a third time reading.
516 7) If the drift immediately after load is higher than a user-
517 specified value (in %), fail.
518 If the drift after the rest period is higher than a user-specified value,
519 fail.
520
521 @param test: KVM test object.
522 @param params: Dictionary with test parameters.
523 @param env: Dictionary with the test environment.
524 """
lmr25e89fc2009-08-07 20:29:16 +0000525 # Helper functions
526 def set_cpu_affinity(pid, mask):
527 """
528 Set the CPU affinity of all threads of the process with PID pid.
lmr152da2d2009-09-09 22:16:21 +0000529 Do this recursively for all child processes as well.
lmr25e89fc2009-08-07 20:29:16 +0000530
531 @param pid: The process ID.
532 @param mask: The CPU affinity mask.
533 @return: A dict containing the previous mask for each thread.
534 """
535 tids = commands.getoutput("ps -L --pid=%s -o lwp=" % pid).split()
536 prev_masks = {}
537 for tid in tids:
538 prev_mask = commands.getoutput("taskset -p %s" % tid).split()[-1]
539 prev_masks[tid] = prev_mask
540 commands.getoutput("taskset -p %s %s" % (mask, tid))
lmr152da2d2009-09-09 22:16:21 +0000541 children = commands.getoutput("ps --ppid=%s -o pid=" % pid).split()
542 for child in children:
543 prev_masks.update(set_cpu_affinity(child, mask))
lmr25e89fc2009-08-07 20:29:16 +0000544 return prev_masks
545
546 def restore_cpu_affinity(prev_masks):
547 """
548 Restore the CPU affinity of several threads.
549
550 @param prev_masks: A dict containing TIDs as keys and masks as values.
551 """
552 for tid, mask in prev_masks.items():
553 commands.getoutput("taskset -p %s %s" % (mask, tid))
554
lmrff2a7c52009-08-10 00:09:22 +0000555 def get_time(session, time_command, time_filter_re, time_format):
lmr25e89fc2009-08-07 20:29:16 +0000556 """
557 Returns the host time and guest time.
558
lmrff2a7c52009-08-10 00:09:22 +0000559 @param session: A shell session.
560 @param time_command: Command to issue to get the current guest time.
561 @param time_filter_re: Regex filter to apply on the output of
562 time_command in order to get the current time.
563 @param time_format: Format string to pass to time.strptime() with the
564 result of the regex filter.
lmr25e89fc2009-08-07 20:29:16 +0000565 @return: A tuple containing the host time and guest time.
566 """
567 host_time = time.time()
568 session.sendline(time_command)
569 (match, s) = session.read_up_to_prompt()
570 s = re.findall(time_filter_re, s)[0]
571 guest_time = time.mktime(time.strptime(s, time_format))
572 return (host_time, guest_time)
573
lmrfbb672b2009-09-09 22:42:51 +0000574 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
575 session = kvm_test_utils.wait_for_login(vm)
lmr5c226e32009-07-27 13:13:01 +0000576
577 # Collect test parameters:
578 # Command to run to get the current time
579 time_command = params.get("time_command")
580 # Filter which should match a string to be passed to time.strptime()
581 time_filter_re = params.get("time_filter_re")
582 # Time format for time.strptime()
583 time_format = params.get("time_format")
584 guest_load_command = params.get("guest_load_command")
585 guest_load_stop_command = params.get("guest_load_stop_command")
586 host_load_command = params.get("host_load_command")
587 guest_load_instances = int(params.get("guest_load_instances", "1"))
588 host_load_instances = int(params.get("host_load_instances", "0"))
589 # CPU affinity mask for taskset
590 cpu_mask = params.get("cpu_mask", "0xFF")
591 load_duration = float(params.get("load_duration", "30"))
592 rest_duration = float(params.get("rest_duration", "10"))
593 drift_threshold = float(params.get("drift_threshold", "200"))
594 drift_threshold_after_rest = float(params.get("drift_threshold_after_rest",
595 "200"))
596
597 guest_load_sessions = []
598 host_load_sessions = []
599
lmr5c226e32009-07-27 13:13:01 +0000600 # Set the VM's CPU affinity
lmr25e89fc2009-08-07 20:29:16 +0000601 prev_affinity = set_cpu_affinity(vm.get_pid(), cpu_mask)
lmr5c226e32009-07-27 13:13:01 +0000602
603 try:
604 # Get time before load
lmrff2a7c52009-08-10 00:09:22 +0000605 (host_time_0, guest_time_0) = get_time(session, time_command,
606 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000607
608 # Run some load on the guest
609 logging.info("Starting load on guest...")
610 for i in range(guest_load_instances):
lmr912c74b2009-08-17 20:43:27 +0000611 load_session = vm.remote_login()
lmr5c226e32009-07-27 13:13:01 +0000612 if not load_session:
613 raise error.TestFail("Could not log into guest")
614 load_session.set_output_prefix("(guest load %d) " % i)
615 load_session.set_output_func(logging.debug)
616 load_session.sendline(guest_load_command)
617 guest_load_sessions.append(load_session)
618
619 # Run some load on the host
620 logging.info("Starting load on host...")
621 for i in range(host_load_instances):
622 host_load_sessions.append(
623 kvm_subprocess.run_bg(host_load_command,
624 output_func=logging.debug,
625 output_prefix="(host load %d) " % i,
626 timeout=0.5))
lmr152da2d2009-09-09 22:16:21 +0000627 # Set the CPU affinity of the load process
lmrfb151b52009-09-09 22:19:11 +0000628 pid = host_load_sessions[-1].get_pid()
lmr25e89fc2009-08-07 20:29:16 +0000629 set_cpu_affinity(pid, cpu_mask)
lmr5c226e32009-07-27 13:13:01 +0000630
631 # Sleep for a while (during load)
632 logging.info("Sleeping for %s seconds..." % load_duration)
633 time.sleep(load_duration)
634
635 # Get time delta after load
lmrff2a7c52009-08-10 00:09:22 +0000636 (host_time_1, guest_time_1) = get_time(session, time_command,
637 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000638
639 # Report results
640 host_delta = host_time_1 - host_time_0
641 guest_delta = guest_time_1 - guest_time_0
642 drift = 100.0 * (host_delta - guest_delta) / host_delta
643 logging.info("Host duration: %.2f" % host_delta)
644 logging.info("Guest duration: %.2f" % guest_delta)
645 logging.info("Drift: %.2f%%" % drift)
646
647 finally:
648 logging.info("Cleaning up...")
649 # Restore the VM's CPU affinity
lmr25e89fc2009-08-07 20:29:16 +0000650 restore_cpu_affinity(prev_affinity)
lmr5c226e32009-07-27 13:13:01 +0000651 # Stop the guest load
652 if guest_load_stop_command:
653 session.get_command_output(guest_load_stop_command)
654 # Close all load shell sessions
655 for load_session in guest_load_sessions:
656 load_session.close()
657 for load_session in host_load_sessions:
658 load_session.close()
659
660 # Sleep again (rest)
661 logging.info("Sleeping for %s seconds..." % rest_duration)
662 time.sleep(rest_duration)
663
664 # Get time after rest
lmrff2a7c52009-08-10 00:09:22 +0000665 (host_time_2, guest_time_2) = get_time(session, time_command,
666 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000667
668 # Report results
669 host_delta_total = host_time_2 - host_time_0
670 guest_delta_total = guest_time_2 - guest_time_0
671 drift_total = 100.0 * (host_delta_total - guest_delta_total) / host_delta
672 logging.info("Total host duration including rest: %.2f" % host_delta_total)
673 logging.info("Total guest duration including rest: %.2f" % guest_delta_total)
674 logging.info("Total drift after rest: %.2f%%" % drift_total)
675
lmr5b829602009-08-07 20:36:06 +0000676 session.close()
677
lmr5c226e32009-07-27 13:13:01 +0000678 # Fail the test if necessary
679 if drift > drift_threshold:
680 raise error.TestFail("Time drift too large: %.2f%%" % drift)
lmr67bf4442009-08-28 17:29:45 +0000681 if drift_total > drift_threshold_after_rest:
lmr5c226e32009-07-27 13:13:01 +0000682 raise error.TestFail("Time drift too large after rest period: %.2f%%"
683 % drift_total)
lmr3efa0bd2009-08-18 20:00:56 +0000684
685
686def run_autoit(test, params, env):
687 """
688 A wrapper for AutoIt scripts.
689
690 1) Log into a guest.
691 2) Run AutoIt script.
692 3) Wait for script execution to complete.
693 4) Pass/fail according to exit status of script.
694
695 @param test: KVM test object.
696 @param params: Dictionary with test parameters.
697 @param env: Dictionary with the test environment.
698 """
lmrfbb672b2009-09-09 22:42:51 +0000699 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
700 session = kvm_test_utils.wait_for_login(vm)
lmr3efa0bd2009-08-18 20:00:56 +0000701
702 try:
lmrfbb672b2009-09-09 22:42:51 +0000703 logging.info("Starting script...")
lmr3efa0bd2009-08-18 20:00:56 +0000704
705 # Collect test parameters
706 binary = params.get("autoit_binary")
707 script = params.get("autoit_script")
708 script_params = params.get("autoit_script_params", "")
709 timeout = float(params.get("autoit_script_timeout", 600))
710
711 # Send AutoIt script to guest (this code will be replaced once we
712 # support sending files to Windows guests)
713 session.sendline("del script.au3")
714 file = open(kvm_utils.get_path(test.bindir, script))
715 for line in file.readlines():
716 # Insert a '^' before each character
717 line = "".join("^" + c for c in line.rstrip())
718 if line:
719 # Append line to the file
720 session.sendline("echo %s>>script.au3" % line)
721 file.close()
722
723 session.read_up_to_prompt()
724
725 command = "cmd /c %s script.au3 %s" % (binary, script_params)
726
727 logging.info("---------------- Script output ----------------")
728 status = session.get_command_status(command,
729 print_func=logging.info,
730 timeout=timeout)
731 logging.info("---------------- End of script output ----------------")
732
733 if status is None:
734 raise error.TestFail("Timeout expired before script execution "
735 "completed (or something weird happened)")
736 if status != 0:
737 raise error.TestFail("Script execution failed")
738
739 finally:
740 session.close()