Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(85)

Side by Side Diff: client/tests/kvm/kvm_test_utils.py

Issue 4823005: Merge remote branch 'cros/upstream' into tempbranch (Closed) Base URL: http://git.chromium.org/git/autotest.git@master
Patch Set: patch Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « client/tests/kvm/kvm_subprocess.py ('k') | client/tests/kvm/kvm_utils.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 """ 1 """
2 High-level KVM test utility functions. 2 High-level KVM test utility functions.
3 3
4 This module is meant to reduce code size by performing common test procedures. 4 This module is meant to reduce code size by performing common test procedures.
5 Generally, code here should look like test code. 5 Generally, code here should look like test code.
6 More specifically: 6 More specifically:
7 - Functions in this module should raise exceptions if things go wrong 7 - Functions in this module should raise exceptions if things go wrong
8 (unlike functions in kvm_utils.py and kvm_vm.py which report failure via 8 (unlike functions in kvm_utils.py and kvm_vm.py which report failure via
9 their returned values). 9 their returned values).
10 - Functions in this module may use logging.info(), in addition to 10 - Functions in this module may use logging.info(), in addition to
11 logging.debug() and logging.error(), to log messages the user may be 11 logging.debug() and logging.error(), to log messages the user may be
12 interested in (unlike kvm_utils.py and kvm_vm.py which use 12 interested in (unlike kvm_utils.py and kvm_vm.py which use
13 logging.debug() for anything that isn't an error). 13 logging.debug() for anything that isn't an error).
14 - Functions in this module typically use functions and classes from 14 - Functions in this module typically use functions and classes from
15 lower-level modules (e.g. kvm_utils.py, kvm_vm.py, kvm_subprocess.py). 15 lower-level modules (e.g. kvm_utils.py, kvm_vm.py, kvm_subprocess.py).
16 - Functions in this module should not be used by lower-level modules. 16 - Functions in this module should not be used by lower-level modules.
17 - Functions in this module should be used in the right context. 17 - Functions in this module should be used in the right context.
18 For example, a function should not be used where it may display 18 For example, a function should not be used where it may display
19 misleading or inaccurate info or debug messages. 19 misleading or inaccurate info or debug messages.
20 20
21 @copyright: 2008-2009 Red Hat Inc. 21 @copyright: 2008-2009 Red Hat Inc.
22 """ 22 """
23 23
24 import time, os, logging, re, commands 24 import time, os, logging, re, commands, signal
25 from autotest_lib.client.common_lib import error 25 from autotest_lib.client.common_lib import error
26 from autotest_lib.client.bin import utils 26 from autotest_lib.client.bin import utils
27 import kvm_utils, kvm_vm, kvm_subprocess, scan_results 27 import kvm_utils, kvm_vm, kvm_subprocess, scan_results
28 28
29 29
30 def get_living_vm(env, vm_name): 30 def get_living_vm(env, vm_name):
31 """ 31 """
32 Get a VM object from the environment and make sure it's alive. 32 Get a VM object from the environment and make sure it's alive.
33 33
34 @param env: Dictionary with test environment. 34 @param env: Dictionary with test environment.
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 def mig_failed(): 150 def mig_failed():
151 o = vm.monitor.info("migrate") 151 o = vm.monitor.info("migrate")
152 if isinstance(o, str): 152 if isinstance(o, str):
153 return "status: failed" in o 153 return "status: failed" in o
154 else: 154 else:
155 return o.get("status") == "failed" 155 return o.get("status") == "failed"
156 156
157 def mig_cancelled(): 157 def mig_cancelled():
158 o = vm.monitor.info("migrate") 158 o = vm.monitor.info("migrate")
159 if isinstance(o, str): 159 if isinstance(o, str):
160 return "Migration status: cancelled" in o 160 return ("Migration status: cancelled" in o or
161 "Migration status: canceled" in o)
161 else: 162 else:
162 return o.get("status") == "cancelled" 163 return (o.get("status") == "cancelled" or
164 o.get("status") == "canceled")
163 165
164 def wait_for_migration(): 166 def wait_for_migration():
165 if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2, 167 if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2,
166 "Waiting for migration to finish..."): 168 "Waiting for migration to finish..."):
167 raise error.TestFail("Timeout expired while waiting for migration " 169 raise error.TestFail("Timeout expired while waiting for migration "
168 "to finish") 170 "to finish")
169 171
172 dest_vm = vm.clone()
170 173
171 migration_file = os.path.join("/tmp/", 174 if mig_protocol == "exec":
172 mig_protocol + time.strftime("%Y%m%d-%H%M%S"))
173 if mig_protocol == "tcp":
174 mig_extra_params = " -incoming tcp:0:%d"
175 elif mig_protocol == "unix":
176 mig_extra_params = " -incoming unix:%s"
177 elif mig_protocol == "exec":
178 # Exec is a little different from other migrate methods - first we 175 # Exec is a little different from other migrate methods - first we
179 # ask the monitor the migration, then the vm state is dumped to a 176 # ask the monitor the migration, then the vm state is dumped to a
180 # compressed file, then we start the dest vm with -incoming pointing 177 # compressed file, then we start the dest vm with -incoming pointing
181 # to it 178 # to it
182 mig_extra_params = " -incoming \"exec: gzip -c -d %s\"" % migration_file 179 try:
183 uri = "\"exec:gzip -c > %s\"" % migration_file 180 exec_file = "/tmp/exec-%s.gz" % kvm_utils.generate_random_string(8)
184 vm.monitor.cmd("stop") 181 exec_cmd = "gzip -c -d %s" % exec_file
185 o = vm.monitor.migrate(uri) 182 uri = '"exec:gzip -c > %s"' % exec_file
186 wait_for_migration() 183 vm.monitor.cmd("stop")
184 vm.monitor.migrate(uri)
185 wait_for_migration()
187 186
188 # Clone the source VM and ask the clone to wait for incoming migration 187 if not dest_vm.create(migration_mode=mig_protocol,
189 dest_vm = vm.clone() 188 migration_exec_cmd=exec_cmd, mac_source=vm):
190 if not dest_vm.create(extra_params=mig_extra_params): 189 raise error.TestError("Could not create dest VM")
191 raise error.TestError("Could not create dest VM") 190 finally:
191 logging.debug("Removing migration file %s", exec_file)
192 try:
193 os.remove(exec_file)
194 except OSError:
195 pass
196 else:
197 if not dest_vm.create(migration_mode=mig_protocol, mac_source=vm):
198 raise error.TestError("Could not create dest VM")
199 try:
200 if mig_protocol == "tcp":
201 uri = "tcp:localhost:%d" % dest_vm.migration_port
202 elif mig_protocol == "unix":
203 uri = "unix:%s" % dest_vm.migration_file
204 vm.monitor.migrate(uri)
192 205
193 try: 206 if mig_cancel:
194 if mig_protocol == "tcp":
195 uri = "tcp:localhost:%d" % dest_vm.migration_port
196 elif mig_protocol == "unix":
197 uri = "unix:%s" % dest_vm.migration_file
198
199 if mig_protocol != "exec":
200 o = vm.monitor.migrate(uri)
201
202 if mig_protocol == "tcp" and mig_cancel:
203 time.sleep(2) 207 time.sleep(2)
204 o = vm.monitor.cmd("migrate_cancel") 208 vm.monitor.cmd("migrate_cancel")
205 if not kvm_utils.wait_for(mig_cancelled, 60, 2, 2, 209 if not kvm_utils.wait_for(mig_cancelled, 60, 2, 2,
206 "Waiting for migration cancel"): 210 "Waiting for migration "
207 raise error.TestFail("Fail to cancel migration") 211 "cancellation"):
212 raise error.TestFail("Failed to cancel migration")
208 dest_vm.destroy(gracefully=False) 213 dest_vm.destroy(gracefully=False)
209 return vm 214 return vm
215 else:
216 wait_for_migration()
217 except:
218 dest_vm.destroy()
219 raise
210 220
211 wait_for_migration() 221 # Report migration status
222 if mig_succeeded():
223 logging.info("Migration finished successfully")
224 elif mig_failed():
225 raise error.TestFail("Migration failed")
226 else:
227 raise error.TestFail("Migration ended with unknown status")
212 228
213 # Report migration status 229 if "paused" in dest_vm.monitor.info("status"):
214 if mig_succeeded(): 230 logging.debug("Destination VM is paused, resuming it...")
215 logging.info("Migration finished successfully") 231 dest_vm.monitor.cmd("cont")
216 elif mig_failed():
217 raise error.TestFail("Migration failed")
218 else:
219 raise error.TestFail("Migration ended with unknown status")
220 232
221 o = dest_vm.monitor.info("status") 233 # Kill the source VM
222 if "paused" in o: 234 vm.destroy(gracefully=False)
223 logging.debug("Destination VM is paused, resuming it...")
224 dest_vm.monitor.cmd("cont")
225 235
226 if os.path.exists(migration_file): 236 # Replace the source VM with the new cloned VM
227 logging.debug("Removing migration file %s", migration_file) 237 if env is not None:
228 os.remove(migration_file) 238 kvm_utils.env_register_vm(env, vm.name, dest_vm)
229 239
230 # Kill the source VM 240 # Return the new cloned VM
231 vm.destroy(gracefully=False) 241 return dest_vm
232 242
233 # Replace the source VM with the new cloned VM
234 if env is not None:
235 kvm_utils.env_register_vm(env, vm.name, dest_vm)
236 243
237 # Return the new cloned VM 244 def stop_windows_service(session, service, timeout=120):
238 return dest_vm 245 """
246 Stop a Windows service using sc.
247 If the service is already stopped or is not installed, do nothing.
239 248
240 except: 249 @param service: The name of the service
241 dest_vm.destroy() 250 @param timeout: Time duration to wait for service to stop
242 raise 251 @raise error.TestError: Raised if the service can't be stopped
252 """
253 end_time = time.time() + timeout
254 while time.time() < end_time:
255 o = session.get_command_output("sc stop %s" % service, timeout=60)
256 # FAILED 1060 means the service isn't installed.
257 # FAILED 1062 means the service hasn't been started.
258 if re.search(r"\bFAILED (1060|1062)\b", o, re.I):
259 break
260 time.sleep(1)
261 else:
262 raise error.TestError("Could not stop service '%s'" % service)
263
264
265 def start_windows_service(session, service, timeout=120):
266 """
267 Start a Windows service using sc.
268 If the service is already running, do nothing.
269 If the service isn't installed, fail.
270
271 @param service: The name of the service
272 @param timeout: Time duration to wait for service to start
273 @raise error.TestError: Raised if the service can't be started
274 """
275 end_time = time.time() + timeout
276 while time.time() < end_time:
277 o = session.get_command_output("sc start %s" % service, timeout=60)
278 # FAILED 1060 means the service isn't installed.
279 if re.search(r"\bFAILED 1060\b", o, re.I):
280 raise error.TestError("Could not start service '%s' "
281 "(service not installed)" % service)
282 # FAILED 1056 means the service is already running.
283 if re.search(r"\bFAILED 1056\b", o, re.I):
284 break
285 time.sleep(1)
286 else:
287 raise error.TestError("Could not start service '%s'" % service)
243 288
244 289
245 def get_time(session, time_command, time_filter_re, time_format): 290 def get_time(session, time_command, time_filter_re, time_format):
246 """ 291 """
247 Return the host time and guest time. If the guest time cannot be fetched 292 Return the host time and guest time. If the guest time cannot be fetched
248 a TestError exception is raised. 293 a TestError exception is raised.
249 294
250 Note that the shell session should be ready to receive commands 295 Note that the shell session should be ready to receive commands
251 (i.e. should "display" a command prompt and should be done with all 296 (i.e. should "display" a command prompt and should be done with all
252 previous commands). 297 previous commands).
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 raise error.TestFail("Autotest control file run did not produce any " 543 raise error.TestFail("Autotest control file run did not produce any "
499 "recognizable results") 544 "recognizable results")
500 if bad_results: 545 if bad_results:
501 if len(bad_results) == 1: 546 if len(bad_results) == 1:
502 e_msg = ("Test %s failed during control file execution" % 547 e_msg = ("Test %s failed during control file execution" %
503 bad_results[0]) 548 bad_results[0])
504 else: 549 else:
505 e_msg = ("Tests %s failed during control file execution" % 550 e_msg = ("Tests %s failed during control file execution" %
506 " ".join(bad_results)) 551 " ".join(bad_results))
507 raise error.TestFail(e_msg) 552 raise error.TestFail(e_msg)
553
554
555 def get_loss_ratio(output):
556 """
557 Get the packet loss ratio from the output of ping
558 .
559 @param output: Ping output.
560 """
561 try:
562 return int(re.findall('(\d+)% packet loss', output)[0])
563 except IndexError:
564 logging.debug(output)
565 return -1
566
567
568 def raw_ping(command, timeout, session, output_func):
569 """
570 Low-level ping command execution.
571
572 @param command: Ping command.
573 @param timeout: Timeout of the ping command.
574 @param session: Local executon hint or session to execute the ping command.
575 """
576 if session is None:
577 process = kvm_subprocess.run_bg(command, output_func=output_func,
578 timeout=timeout)
579
580 # Send SIGINT signal to notify the timeout of running ping process,
581 # Because ping have the ability to catch the SIGINT signal so we can
582 # always get the packet loss ratio even if timeout.
583 if process.is_alive():
584 kvm_utils.kill_process_tree(process.get_pid(), signal.SIGINT)
585
586 status = process.get_status()
587 output = process.get_output()
588
589 process.close()
590 return status, output
591 else:
592 session.sendline(command)
593 status, output = session.read_up_to_prompt(timeout=timeout,
594 print_func=output_func)
595 if not status:
596 # Send ctrl+c (SIGINT) through ssh session
597 session.send("\003")
598 status, output2 = session.read_up_to_prompt(print_func=output_func)
599 output += output2
600 if not status:
601 # We also need to use this session to query the return value
602 session.send("\003")
603
604 session.sendline(session.status_test_command)
605 s2, o2 = session.read_up_to_prompt()
606 if not s2:
607 status = -1
608 else:
609 try:
610 status = int(re.findall("\d+", o2)[0])
611 except:
612 status = -1
613
614 return status, output
615
616
617 def ping(dest=None, count=None, interval=None, interface=None,
618 packetsize=None, ttl=None, hint=None, adaptive=False,
619 broadcast=False, flood=False, timeout=0,
620 output_func=logging.debug, session=None):
621 """
622 Wrapper of ping.
623
624 @param dest: Destination address.
625 @param count: Count of icmp packet.
626 @param interval: Interval of two icmp echo request.
627 @param interface: Specified interface of the source address.
628 @param packetsize: Packet size of icmp.
629 @param ttl: IP time to live.
630 @param hint: Path mtu discovery hint.
631 @param adaptive: Adaptive ping flag.
632 @param broadcast: Broadcast ping flag.
633 @param flood: Flood ping flag.
634 @param timeout: Timeout for the ping command.
635 @param output_func: Function used to log the result of ping.
636 @param session: Local executon hint or session to execute the ping command.
637 """
638 if dest is not None:
639 command = "ping %s " % dest
640 else:
641 command = "ping localhost "
642 if count is not None:
643 command += " -c %s" % count
644 if interval is not None:
645 command += " -i %s" % interval
646 if interface is not None:
647 command += " -I %s" % interface
648 if packetsize is not None:
649 command += " -s %s" % packetsize
650 if ttl is not None:
651 command += " -t %s" % ttl
652 if hint is not None:
653 command += " -M %s" % hint
654 if adaptive:
655 command += " -A"
656 if broadcast:
657 command += " -b"
658 if flood:
659 command += " -f -q"
660 output_func = None
661
662 return raw_ping(command, timeout, session, output_func)
663
664
665 def get_linux_ifname(session, mac_address):
666 """
667 Get the interface name through the mac address.
668
669 @param session: session to the virtual machine
670 @mac_address: the macaddress of nic
671 """
672
673 output = session.get_command_output("ifconfig -a")
674
675 try:
676 ethname = re.findall("(\w+)\s+Link.*%s" % mac_address, output,
677 re.IGNORECASE)[0]
678 return ethname
679 except:
680 return None
OLDNEW
« no previous file with comments | « client/tests/kvm/kvm_subprocess.py ('k') | client/tests/kvm/kvm_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698