blob: b61d98cac95d8f44384036d1561252b59d16fec2 [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 """
lmre0dfb452009-09-10 03:07:46 +0000208 # Helper functions
209 def copy_if_size_differs(vm, local_path, remote_path):
210 """
211 Copy a file to a guest if it doesn't exist or if its size differs.
212
213 @param vm: VM object
214 @param local_path: Local path
215 @param remote_path: Remote path
216 """
217 copy = False
218 output = session.get_command_output("ls -l %s" % remote_path)
219 if ("such file" in output or
220 int(output.split()[4]) != os.path.getsize(local_path)):
221 basename = os.path.basename(local_path)
222 logging.info("Copying %s to guest (file is missing or has a "
223 "different size)..." % basename)
224 if not vm.copy_files_to(local_path, remote_path):
225 raise error.TestFail("Could not copy %s to guest" % basename)
226
227 def extract(vm, remote_path, dest_dir="."):
228 """
229 Extract a .tar.bz2 file on the guest.
230
231 @param vm: VM object
232 @param remote_path: Remote file path
233 @param dest_dir: Destination dir for the contents
234 """
235 basename = os.path.basename(remote_path)
236 logging.info("Extracting %s..." % basename)
237 status = session.get_command_status("tar xfj %s -C %s" %
238 (remote_path, dest_dir))
239 if status != 0:
240 raise error.TestFail("Could not extract %s" % basename)
241
lmrfbb672b2009-09-09 22:42:51 +0000242 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
243 session = kvm_test_utils.wait_for_login(vm)
lmr6f669ce2009-05-31 19:02:42 +0000244
lmre0dfb452009-09-10 03:07:46 +0000245 # Collect test parameters
lmr6f669ce2009-05-31 19:02:42 +0000246 test_name = params.get("test_name")
247 test_timeout = int(params.get("test_timeout", 300))
248 test_control_file = params.get("test_control_file", "control")
249 tarred_autotest_path = "/tmp/autotest.tar.bz2"
250 tarred_test_path = "/tmp/%s.tar.bz2" % test_name
251
252 # tar the contents of bindir/autotest
253 cmd = "cd %s; tar cvjf %s autotest/*"
254 cmd += " --exclude=autotest/tests"
255 cmd += " --exclude=autotest/results"
256 cmd += " --exclude=autotest/tmp"
257 cmd += " --exclude=autotest/control"
258 cmd += " --exclude=*.pyc"
259 cmd += " --exclude=*.svn"
260 cmd += " --exclude=*.git"
lmrd85c55b2009-07-23 01:42:10 +0000261 kvm_subprocess.run_fg(cmd % (test.bindir, tarred_autotest_path), timeout=30)
lmr6f669ce2009-05-31 19:02:42 +0000262
263 # tar the contents of bindir/autotest/tests/<test_name>
264 cmd = "cd %s; tar cvjf %s %s/*"
265 cmd += " --exclude=*.pyc"
266 cmd += " --exclude=*.svn"
267 cmd += " --exclude=*.git"
lmrd85c55b2009-07-23 01:42:10 +0000268 kvm_subprocess.run_fg(cmd %
269 (os.path.join(test.bindir, "autotest", "tests"),
270 tarred_test_path, test_name), timeout=30)
lmr6f669ce2009-05-31 19:02:42 +0000271
lmre0dfb452009-09-10 03:07:46 +0000272 # Copy autotest.tar.bz2
273 copy_if_size_differs(vm, tarred_autotest_path, "autotest.tar.bz2")
lmr6f669ce2009-05-31 19:02:42 +0000274
lmre0dfb452009-09-10 03:07:46 +0000275 # Copy <test_name>.tar.bz2
276 copy_if_size_differs(vm, tarred_test_path, test_name + ".tar.bz2")
lmr6f669ce2009-05-31 19:02:42 +0000277
278 # Extract autotest.tar.bz2
lmre0dfb452009-09-10 03:07:46 +0000279 extract(vm, "autotest.tar.bz2")
lmr6f669ce2009-05-31 19:02:42 +0000280
281 # mkdir autotest/tests
282 session.sendline("mkdir autotest/tests")
283
284 # Extract <test_name>.tar.bz2 into autotest/tests
lmre0dfb452009-09-10 03:07:46 +0000285 extract(vm, test_name + ".tar.bz2", "autotest/tests")
lmr6f669ce2009-05-31 19:02:42 +0000286
lmre0dfb452009-09-10 03:07:46 +0000287 # Copy the selected control file (located inside
288 # test.bindir/autotest_control) to the autotest dir
lmr16cf1652009-06-15 21:32:49 +0000289 control_file_path = os.path.join(test.bindir, "autotest_control",
290 test_control_file)
lmr912c74b2009-08-17 20:43:27 +0000291 if not vm.copy_files_to(control_file_path, "autotest/control"):
lmr16cf1652009-06-15 21:32:49 +0000292 raise error.TestFail("Could not copy the test control file to guest")
lmre0dfb452009-09-10 03:07:46 +0000293
lmr6f669ce2009-05-31 19:02:42 +0000294 # Run the test
295 logging.info("Running test '%s'..." % test_name)
lmr16cf1652009-06-15 21:32:49 +0000296 session.sendline("cd autotest")
297 session.sendline("rm -f control.state")
lmre0dfb452009-09-10 03:07:46 +0000298 session.sendline("rm -rf results/*")
lmr6f669ce2009-05-31 19:02:42 +0000299 session.read_up_to_prompt()
lmr6f669ce2009-05-31 19:02:42 +0000300 logging.info("---------------- Test output ----------------")
lmre0dfb452009-09-10 03:07:46 +0000301 status = session.get_command_status("bin/autotest control",
302 timeout=test_timeout,
303 print_func=logging.info)
lmr6f669ce2009-05-31 19:02:42 +0000304 logging.info("---------------- End of test output ----------------")
lmre0dfb452009-09-10 03:07:46 +0000305 if status is None:
lmr16cf1652009-06-15 21:32:49 +0000306 raise error.TestFail("Timeout elapsed while waiting for test to "
307 "complete")
lmre0dfb452009-09-10 03:07:46 +0000308
lmr16cf1652009-06-15 21:32:49 +0000309 # Get the results generated by autotest
310 output = session.get_command_output("cat results/*/status")
lmre0dfb452009-09-10 03:07:46 +0000311 results = scan_results.parse_results(output)
312 session.close
lmr6f669ce2009-05-31 19:02:42 +0000313
314 # Copy test results to the local bindir/guest_results
315 logging.info("Copying results back from guest...")
316 guest_results_dir = os.path.join(test.outputdir, "guest_results")
317 if not os.path.exists(guest_results_dir):
318 os.mkdir(guest_results_dir)
lmr912c74b2009-08-17 20:43:27 +0000319 if not vm.copy_files_from("autotest/results/default/*", guest_results_dir):
lmr6f669ce2009-05-31 19:02:42 +0000320 logging.error("Could not copy results back from guest")
321
lmre0dfb452009-09-10 03:07:46 +0000322 # Report test results
323 logging.info("Results (test, status, duration, info):")
324 for result in results:
325 logging.info(str(result))
326
327 # Make a list of FAIL/ERROR/ABORT results (make sure FAIL results appear
328 # before ERROR results, and ERROR results appear before ABORT results)
329 bad_results = [r for r in results if r[1] == "FAIL"]
330 bad_results += [r for r in results if r[1] == "ERROR"]
331 bad_results += [r for r in results if r[1] == "ABORT"]
332
lmr6f669ce2009-05-31 19:02:42 +0000333 # Fail the test if necessary
lmre0dfb452009-09-10 03:07:46 +0000334 if not results:
335 raise error.TestFail("Test '%s' did not produce any recognizable "
336 "results" % test_name)
337 if bad_results:
338 result = bad_results[0]
339 raise error.TestFail("Test '%s' ended with %s (reason: '%s')"
340 % (result[0], result[1], result[3]))
lmr6f669ce2009-05-31 19:02:42 +0000341
342
343def internal_yum_update(session, command, prompt, timeout):
344 """
345 Helper function to perform the yum update test.
346
lmr912c74b2009-08-17 20:43:27 +0000347 @param session: shell session stablished to the host
348 @param command: Command to be sent to the shell session
lmr6f669ce2009-05-31 19:02:42 +0000349 @param prompt: Machine prompt
350 @param timeout: How long to wait until we get an appropriate output from
lmr912c74b2009-08-17 20:43:27 +0000351 the shell session.
lmr6f669ce2009-05-31 19:02:42 +0000352 """
353 session.sendline(command)
354 end_time = time.time() + timeout
355 while time.time() < end_time:
356 (match, text) = session.read_until_last_line_matches(
357 ["[Ii]s this [Oo][Kk]", prompt], timeout=timeout)
358 if match == 0:
359 logging.info("Got 'Is this ok'; sending 'y'")
360 session.sendline("y")
361 elif match == 1:
362 logging.info("Got shell prompt")
363 return True
364 else:
365 logging.info("Timeout or process exited")
366 return False
367
368
369def run_yum_update(test, params, env):
370 """
371 Runs yum update and yum update kernel on the remote host (yum enabled
372 hosts only).
373
374 @param test: kvm test object.
375 @param params: Dictionary with test parameters.
376 @param env: Dictionary with the test environment.
377 """
lmrfbb672b2009-09-09 22:42:51 +0000378 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
379 session = kvm_test_utils.wait_for_login(vm)
lmr6f669ce2009-05-31 19:02:42 +0000380
lmr912c74b2009-08-17 20:43:27 +0000381 internal_yum_update(session, "yum update", params.get("shell_prompt"), 600)
lmr6f669ce2009-05-31 19:02:42 +0000382 internal_yum_update(session, "yum update kernel",
lmr912c74b2009-08-17 20:43:27 +0000383 params.get("shell_prompt"), 600)
lmr6f669ce2009-05-31 19:02:42 +0000384
385 session.close()
386
387
388def run_linux_s3(test, params, env):
389 """
390 Suspend a guest Linux OS to memory.
391
392 @param test: kvm test object.
393 @param params: Dictionary with test parameters.
394 @param env: Dictionary with the test environment.
395 """
lmrfbb672b2009-09-09 22:42:51 +0000396 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
397 session = kvm_test_utils.wait_for_login(vm)
lmr6f669ce2009-05-31 19:02:42 +0000398
lmr6f669ce2009-05-31 19:02:42 +0000399 logging.info("Checking that VM supports S3")
lmr6f669ce2009-05-31 19:02:42 +0000400 status = session.get_command_status("grep -q mem /sys/power/state")
401 if status == None:
402 logging.error("Failed to check if S3 exists")
403 elif status != 0:
404 raise error.TestFail("Guest does not support S3")
405
406 logging.info("Waiting for a while for X to start")
407 time.sleep(10)
408
409 src_tty = session.get_command_output("fgconsole").strip()
410 logging.info("Current virtual terminal is %s" % src_tty)
411 if src_tty not in map(str, range(1,10)):
412 raise error.TestFail("Got a strange current vt (%s)" % src_tty)
413
414 dst_tty = "1"
415 if src_tty == "1":
416 dst_tty = "2"
417
418 logging.info("Putting VM into S3")
419 command = "chvt %s && echo mem > /sys/power/state && chvt %s" % (dst_tty,
420 src_tty)
421 status = session.get_command_status(command, timeout=120)
422 if status != 0:
423 raise error.TestFail("Suspend to mem failed")
424
425 logging.info("VM resumed after S3")
426
427 session.close()
lmra04d7c92009-06-19 13:05:39 +0000428
429
430def run_stress_boot(tests, params, env):
431 """
432 Boots VMs until one of them becomes unresponsive, and records the maximum
433 number of VMs successfully started:
434 1) boot the first vm
435 2) boot the second vm cloned from the first vm, check whether it boots up
lmr912c74b2009-08-17 20:43:27 +0000436 and all booted vms respond to shell commands
lmra04d7c92009-06-19 13:05:39 +0000437 3) go on until cannot create VM anymore or cannot allocate memory for VM
438
439 @param test: kvm test object
440 @param params: Dictionary with the test parameters
441 @param env: Dictionary with test environment.
442 """
443 # boot the first vm
lmrfbb672b2009-09-09 22:42:51 +0000444 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
lmra04d7c92009-06-19 13:05:39 +0000445
446 logging.info("Waiting for first guest to be up...")
447
lmr912c74b2009-08-17 20:43:27 +0000448 session = kvm_utils.wait_for(vm.remote_login, 240, 0, 2)
lmra04d7c92009-06-19 13:05:39 +0000449 if not session:
450 raise error.TestFail("Could not log into first guest")
451
452 num = 2
lmra04d7c92009-06-19 13:05:39 +0000453 sessions = [session]
lmr26bac242009-08-13 04:14:24 +0000454 address_index = int(params.get("clone_address_index_base", 10))
lmra04d7c92009-06-19 13:05:39 +0000455
456 # boot the VMs
457 while num <= int(params.get("max_vms")):
458 try:
459 vm_name = "vm" + str(num)
460
461 # clone vm according to the first one
lmr26bac242009-08-13 04:14:24 +0000462 vm_params = vm.get_params().copy()
463 vm_params["address_index"] = str(address_index)
lmra04d7c92009-06-19 13:05:39 +0000464 curr_vm = vm.clone(vm_name, vm_params)
465 kvm_utils.env_register_vm(env, vm_name, curr_vm)
466 params['vms'] += " " + vm_name
467
lmra04d7c92009-06-19 13:05:39 +0000468 logging.info("Booting guest #%d" % num)
469 if not curr_vm.create():
470 raise error.TestFail("Cannot create VM #%d" % num)
471
lmr912c74b2009-08-17 20:43:27 +0000472 curr_vm_session = kvm_utils.wait_for(curr_vm.remote_login, 240, 0, 2)
lmra04d7c92009-06-19 13:05:39 +0000473 if not curr_vm_session:
474 raise error.TestFail("Could not log into guest #%d" % num)
475
476 logging.info("Guest #%d boots up successfully" % num)
477 sessions.append(curr_vm_session)
478
lmr912c74b2009-08-17 20:43:27 +0000479 # check whether all previous shell sessions are responsive
lmr26bac242009-08-13 04:14:24 +0000480 for i, se in enumerate(sessions):
481 if se.get_command_status(params.get("alive_test_cmd")) != 0:
lmra04d7c92009-06-19 13:05:39 +0000482 raise error.TestFail("Session #%d is not responsive" % i)
483 num += 1
lmr26bac242009-08-13 04:14:24 +0000484 address_index += 1
lmra04d7c92009-06-19 13:05:39 +0000485
486 except (error.TestFail, OSError):
487 for se in sessions:
488 se.close()
489 logging.info("Total number booted: %d" % (num - 1))
490 raise
491 else:
492 for se in sessions:
493 se.close()
494 logging.info("Total number booted: %d" % (num -1))
lmr5c226e32009-07-27 13:13:01 +0000495
496
497def run_timedrift(test, params, env):
498 """
499 Time drift test (mainly for Windows guests):
500
501 1) Log into a guest.
502 2) Take a time reading from the guest and host.
503 3) Run load on the guest and host.
504 4) Take a second time reading.
505 5) Stop the load and rest for a while.
506 6) Take a third time reading.
507 7) If the drift immediately after load is higher than a user-
508 specified value (in %), fail.
509 If the drift after the rest period is higher than a user-specified value,
510 fail.
511
512 @param test: KVM test object.
513 @param params: Dictionary with test parameters.
514 @param env: Dictionary with the test environment.
515 """
lmr25e89fc2009-08-07 20:29:16 +0000516 # Helper functions
517 def set_cpu_affinity(pid, mask):
518 """
519 Set the CPU affinity of all threads of the process with PID pid.
lmr152da2d2009-09-09 22:16:21 +0000520 Do this recursively for all child processes as well.
lmr25e89fc2009-08-07 20:29:16 +0000521
522 @param pid: The process ID.
523 @param mask: The CPU affinity mask.
524 @return: A dict containing the previous mask for each thread.
525 """
526 tids = commands.getoutput("ps -L --pid=%s -o lwp=" % pid).split()
527 prev_masks = {}
528 for tid in tids:
529 prev_mask = commands.getoutput("taskset -p %s" % tid).split()[-1]
530 prev_masks[tid] = prev_mask
531 commands.getoutput("taskset -p %s %s" % (mask, tid))
lmr152da2d2009-09-09 22:16:21 +0000532 children = commands.getoutput("ps --ppid=%s -o pid=" % pid).split()
533 for child in children:
534 prev_masks.update(set_cpu_affinity(child, mask))
lmr25e89fc2009-08-07 20:29:16 +0000535 return prev_masks
536
537 def restore_cpu_affinity(prev_masks):
538 """
539 Restore the CPU affinity of several threads.
540
541 @param prev_masks: A dict containing TIDs as keys and masks as values.
542 """
543 for tid, mask in prev_masks.items():
544 commands.getoutput("taskset -p %s %s" % (mask, tid))
545
lmrff2a7c52009-08-10 00:09:22 +0000546 def get_time(session, time_command, time_filter_re, time_format):
lmr25e89fc2009-08-07 20:29:16 +0000547 """
548 Returns the host time and guest time.
549
lmrff2a7c52009-08-10 00:09:22 +0000550 @param session: A shell session.
551 @param time_command: Command to issue to get the current guest time.
552 @param time_filter_re: Regex filter to apply on the output of
553 time_command in order to get the current time.
554 @param time_format: Format string to pass to time.strptime() with the
555 result of the regex filter.
lmr25e89fc2009-08-07 20:29:16 +0000556 @return: A tuple containing the host time and guest time.
557 """
558 host_time = time.time()
559 session.sendline(time_command)
560 (match, s) = session.read_up_to_prompt()
561 s = re.findall(time_filter_re, s)[0]
562 guest_time = time.mktime(time.strptime(s, time_format))
563 return (host_time, guest_time)
564
lmrfbb672b2009-09-09 22:42:51 +0000565 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
566 session = kvm_test_utils.wait_for_login(vm)
lmr5c226e32009-07-27 13:13:01 +0000567
568 # Collect test parameters:
569 # Command to run to get the current time
570 time_command = params.get("time_command")
571 # Filter which should match a string to be passed to time.strptime()
572 time_filter_re = params.get("time_filter_re")
573 # Time format for time.strptime()
574 time_format = params.get("time_format")
575 guest_load_command = params.get("guest_load_command")
576 guest_load_stop_command = params.get("guest_load_stop_command")
577 host_load_command = params.get("host_load_command")
578 guest_load_instances = int(params.get("guest_load_instances", "1"))
579 host_load_instances = int(params.get("host_load_instances", "0"))
580 # CPU affinity mask for taskset
581 cpu_mask = params.get("cpu_mask", "0xFF")
582 load_duration = float(params.get("load_duration", "30"))
583 rest_duration = float(params.get("rest_duration", "10"))
584 drift_threshold = float(params.get("drift_threshold", "200"))
585 drift_threshold_after_rest = float(params.get("drift_threshold_after_rest",
586 "200"))
587
588 guest_load_sessions = []
589 host_load_sessions = []
590
lmr5c226e32009-07-27 13:13:01 +0000591 # Set the VM's CPU affinity
lmr25e89fc2009-08-07 20:29:16 +0000592 prev_affinity = set_cpu_affinity(vm.get_pid(), cpu_mask)
lmr5c226e32009-07-27 13:13:01 +0000593
594 try:
595 # Get time before load
lmrff2a7c52009-08-10 00:09:22 +0000596 (host_time_0, guest_time_0) = get_time(session, time_command,
597 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000598
599 # Run some load on the guest
600 logging.info("Starting load on guest...")
601 for i in range(guest_load_instances):
lmr912c74b2009-08-17 20:43:27 +0000602 load_session = vm.remote_login()
lmr5c226e32009-07-27 13:13:01 +0000603 if not load_session:
604 raise error.TestFail("Could not log into guest")
605 load_session.set_output_prefix("(guest load %d) " % i)
606 load_session.set_output_func(logging.debug)
607 load_session.sendline(guest_load_command)
608 guest_load_sessions.append(load_session)
609
610 # Run some load on the host
611 logging.info("Starting load on host...")
612 for i in range(host_load_instances):
613 host_load_sessions.append(
614 kvm_subprocess.run_bg(host_load_command,
615 output_func=logging.debug,
616 output_prefix="(host load %d) " % i,
617 timeout=0.5))
lmr152da2d2009-09-09 22:16:21 +0000618 # Set the CPU affinity of the load process
lmrfb151b52009-09-09 22:19:11 +0000619 pid = host_load_sessions[-1].get_pid()
lmr25e89fc2009-08-07 20:29:16 +0000620 set_cpu_affinity(pid, cpu_mask)
lmr5c226e32009-07-27 13:13:01 +0000621
622 # Sleep for a while (during load)
623 logging.info("Sleeping for %s seconds..." % load_duration)
624 time.sleep(load_duration)
625
626 # Get time delta after load
lmrff2a7c52009-08-10 00:09:22 +0000627 (host_time_1, guest_time_1) = get_time(session, time_command,
628 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000629
630 # Report results
631 host_delta = host_time_1 - host_time_0
632 guest_delta = guest_time_1 - guest_time_0
633 drift = 100.0 * (host_delta - guest_delta) / host_delta
634 logging.info("Host duration: %.2f" % host_delta)
635 logging.info("Guest duration: %.2f" % guest_delta)
636 logging.info("Drift: %.2f%%" % drift)
637
638 finally:
639 logging.info("Cleaning up...")
640 # Restore the VM's CPU affinity
lmr25e89fc2009-08-07 20:29:16 +0000641 restore_cpu_affinity(prev_affinity)
lmr5c226e32009-07-27 13:13:01 +0000642 # Stop the guest load
643 if guest_load_stop_command:
644 session.get_command_output(guest_load_stop_command)
645 # Close all load shell sessions
646 for load_session in guest_load_sessions:
647 load_session.close()
648 for load_session in host_load_sessions:
649 load_session.close()
650
651 # Sleep again (rest)
652 logging.info("Sleeping for %s seconds..." % rest_duration)
653 time.sleep(rest_duration)
654
655 # Get time after rest
lmrff2a7c52009-08-10 00:09:22 +0000656 (host_time_2, guest_time_2) = get_time(session, time_command,
657 time_filter_re, time_format)
lmr5c226e32009-07-27 13:13:01 +0000658
659 # Report results
660 host_delta_total = host_time_2 - host_time_0
661 guest_delta_total = guest_time_2 - guest_time_0
662 drift_total = 100.0 * (host_delta_total - guest_delta_total) / host_delta
663 logging.info("Total host duration including rest: %.2f" % host_delta_total)
664 logging.info("Total guest duration including rest: %.2f" % guest_delta_total)
665 logging.info("Total drift after rest: %.2f%%" % drift_total)
666
lmr5b829602009-08-07 20:36:06 +0000667 session.close()
668
lmr5c226e32009-07-27 13:13:01 +0000669 # Fail the test if necessary
670 if drift > drift_threshold:
671 raise error.TestFail("Time drift too large: %.2f%%" % drift)
lmr67bf4442009-08-28 17:29:45 +0000672 if drift_total > drift_threshold_after_rest:
lmr5c226e32009-07-27 13:13:01 +0000673 raise error.TestFail("Time drift too large after rest period: %.2f%%"
674 % drift_total)
lmr3efa0bd2009-08-18 20:00:56 +0000675
676
677def run_autoit(test, params, env):
678 """
679 A wrapper for AutoIt scripts.
680
681 1) Log into a guest.
682 2) Run AutoIt script.
683 3) Wait for script execution to complete.
684 4) Pass/fail according to exit status of script.
685
686 @param test: KVM test object.
687 @param params: Dictionary with test parameters.
688 @param env: Dictionary with the test environment.
689 """
lmrfbb672b2009-09-09 22:42:51 +0000690 vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
691 session = kvm_test_utils.wait_for_login(vm)
lmr3efa0bd2009-08-18 20:00:56 +0000692
693 try:
lmrfbb672b2009-09-09 22:42:51 +0000694 logging.info("Starting script...")
lmr3efa0bd2009-08-18 20:00:56 +0000695
696 # Collect test parameters
697 binary = params.get("autoit_binary")
698 script = params.get("autoit_script")
699 script_params = params.get("autoit_script_params", "")
700 timeout = float(params.get("autoit_script_timeout", 600))
701
702 # Send AutoIt script to guest (this code will be replaced once we
703 # support sending files to Windows guests)
704 session.sendline("del script.au3")
705 file = open(kvm_utils.get_path(test.bindir, script))
706 for line in file.readlines():
707 # Insert a '^' before each character
708 line = "".join("^" + c for c in line.rstrip())
709 if line:
710 # Append line to the file
711 session.sendline("echo %s>>script.au3" % line)
712 file.close()
713
714 session.read_up_to_prompt()
715
716 command = "cmd /c %s script.au3 %s" % (binary, script_params)
717
718 logging.info("---------------- Script output ----------------")
719 status = session.get_command_status(command,
720 print_func=logging.info,
721 timeout=timeout)
722 logging.info("---------------- End of script output ----------------")
723
724 if status is None:
725 raise error.TestFail("Timeout expired before script execution "
726 "completed (or something weird happened)")
727 if status != 0:
728 raise error.TestFail("Script execution failed")
729
730 finally:
731 session.close()