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

Side by Side Diff: client/virt/virt_vm.py

Issue 6883246: Merge autotest upstream from @5318 ~ @5336 (Closed) Base URL: ssh://gitrw.chromium.org:9222/autotest.git@master
Patch Set: patch Created 9 years, 8 months 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/virt/virt_utils.py ('k') | server/autotest_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 import os, logging, time, glob, re
2 from autotest_lib.client.common_lib import error
3 from autotest_lib.client.bin import utils
4 import virt_utils
5
6 class VMError(Exception):
7 pass
8
9
10 class VMCreateError(VMError):
11 def __init__(self, cmd, status, output):
12 VMError.__init__(self, cmd, status, output)
13 self.cmd = cmd
14 self.status = status
15 self.output = output
16
17 def __str__(self):
18 return ("VM creation command failed: %r (status: %s, "
19 "output: %r)" % (self.cmd, self.status, self.output))
20
21
22 class VMHashMismatchError(VMError):
23 def __init__(self, actual, expected):
24 VMError.__init__(self, actual, expected)
25 self.actual_hash = actual
26 self.expected_hash = expected
27
28 def __str__(self):
29 return ("CD image hash (%s) differs from expected one (%s)" %
30 (self.actual_hash, self.expected_hash))
31
32
33 class VMImageMissingError(VMError):
34 def __init__(self, filename):
35 VMError.__init__(self, filename)
36 self.filename = filename
37
38 def __str__(self):
39 return "CD image file not found: %r" % self.filename
40
41
42 class VMImageCheckError(VMError):
43 def __init__(self, filename):
44 VMError.__init__(self, filename)
45 self.filename = filename
46
47 def __str__(self):
48 return "Errors found on image: %r" % self.filename
49
50
51 class VMBadPATypeError(VMError):
52 def __init__(self, pa_type):
53 VMError.__init__(self, pa_type)
54 self.pa_type = pa_type
55
56 def __str__(self):
57 return "Unsupported PCI assignable type: %r" % self.pa_type
58
59
60 class VMPAError(VMError):
61 def __init__(self, pa_type):
62 VMError.__init__(self, pa_type)
63 self.pa_type = pa_type
64
65 def __str__(self):
66 return ("No PCI assignable devices could be assigned "
67 "(pci_assignable=%r)" % self.pa_type)
68
69
70 class VMPostCreateError(VMError):
71 def __init__(self, cmd, output):
72 VMError.__init__(self, cmd, output)
73 self.cmd = cmd
74 self.output = output
75
76
77 class VMHugePageError(VMPostCreateError):
78 def __str__(self):
79 return ("Cannot allocate hugepage memory (command: %r, "
80 "output: %r)" % (self.cmd, self.output))
81
82
83 class VMKVMInitError(VMPostCreateError):
84 def __str__(self):
85 return ("Cannot initialize KVM (command: %r, output: %r)" %
86 (self.cmd, self.output))
87
88
89 class VMDeadError(VMError):
90 def __init__(self, reason='', detail=''):
91 VMError.__init__(self)
92 self.reason = reason
93 self.detail = detail
94
95 def __str__(self):
96 msg = "VM is dead"
97 if self.reason:
98 msg += " reason: %s" % self.reason
99 if self.detail:
100 msg += " detail: %r" % self.detail
101 return (msg)
102
103
104 class VMDeadKernelCrashError(VMError):
105 def __init__(self, kernel_crash):
106 VMError.__init__(self, kernel_crash)
107 self.kernel_crash = kernel_crash
108
109 def __str__(self):
110 return ("VM is dead due to a kernel crash:\n%s" % self.kernel_crash)
111
112
113 class VMAddressError(VMError):
114 pass
115
116
117 class VMPortNotRedirectedError(VMAddressError):
118 def __init__(self, port):
119 VMAddressError.__init__(self, port)
120 self.port = port
121
122 def __str__(self):
123 return "Port not redirected: %s" % self.port
124
125
126 class VMAddressVerificationError(VMAddressError):
127 def __init__(self, mac, ip):
128 VMAddressError.__init__(self, mac, ip)
129 self.mac = mac
130 self.ip = ip
131
132 def __str__(self):
133 return ("Cannot verify MAC-IP address mapping using arping: "
134 "%s ---> %s" % (self.mac, self.ip))
135
136
137 class VMMACAddressMissingError(VMAddressError):
138 def __init__(self, nic_index):
139 VMAddressError.__init__(self, nic_index)
140 self.nic_index = nic_index
141
142 def __str__(self):
143 return "No MAC address defined for NIC #%s" % self.nic_index
144
145
146 class VMIPAddressMissingError(VMAddressError):
147 def __init__(self, mac):
148 VMAddressError.__init__(self, mac)
149 self.mac = mac
150
151 def __str__(self):
152 return "Cannot find IP address for MAC address %s" % self.mac
153
154
155 class VMMigrateError(VMError):
156 pass
157
158
159 class VMMigrateTimeoutError(VMMigrateError):
160 pass
161
162
163 class VMMigrateCancelError(VMMigrateError):
164 pass
165
166
167 class VMMigrateFailedError(VMMigrateError):
168 pass
169
170 class VMMigrateProtoUnsupportedError(VMMigrateError):
171 pass
172
173
174 class VMMigrateStateMismatchError(VMMigrateError):
175 def __init__(self, src_hash, dst_hash):
176 VMMigrateError.__init__(self, src_hash, dst_hash)
177 self.src_hash = src_hash
178 self.dst_hash = dst_hash
179
180 def __str__(self):
181 return ("Mismatch of VM state before and after migration (%s != %s)" %
182 (self.src_hash, self.dst_hash))
183
184
185 class VMRebootError(VMError):
186 pass
187
188
189 def get_image_filename(params, root_dir):
190 """
191 Generate an image path from params and root_dir.
192
193 @param params: Dictionary containing the test parameters.
194 @param root_dir: Base directory for relative filenames.
195
196 @note: params should contain:
197 image_name -- the name of the image file, without extension
198 image_format -- the format of the image (qcow2, raw etc)
199 """
200 image_name = params.get("image_name", "image")
201 image_format = params.get("image_format", "qcow2")
202 if params.get("image_raw_device") == "yes":
203 return image_name
204 image_filename = "%s.%s" % (image_name, image_format)
205 image_filename = virt_utils.get_path(root_dir, image_filename)
206 return image_filename
207
208
209 def create_image(params, root_dir):
210 """
211 Create an image using qemu_image.
212
213 @param params: Dictionary containing the test parameters.
214 @param root_dir: Base directory for relative filenames.
215
216 @note: params should contain:
217 image_name -- the name of the image file, without extension
218 image_format -- the format of the image (qcow2, raw etc)
219 image_size -- the requested size of the image (a string
220 qemu-img can understand, such as '10G')
221 """
222 qemu_img_cmd = virt_utils.get_path(root_dir, params.get("qemu_img_binary",
223 "qemu-img"))
224 qemu_img_cmd += " create"
225
226 format = params.get("image_format", "qcow2")
227 qemu_img_cmd += " -f %s" % format
228
229 image_filename = get_image_filename(params, root_dir)
230 qemu_img_cmd += " %s" % image_filename
231
232 size = params.get("image_size", "10G")
233 qemu_img_cmd += " %s" % size
234
235 utils.system(qemu_img_cmd)
236 logging.info("Image created in %r", image_filename)
237 return image_filename
238
239
240 def remove_image(params, root_dir):
241 """
242 Remove an image file.
243
244 @param params: A dict
245 @param root_dir: Base directory for relative filenames.
246
247 @note: params should contain:
248 image_name -- the name of the image file, without extension
249 image_format -- the format of the image (qcow2, raw etc)
250 """
251 image_filename = get_image_filename(params, root_dir)
252 logging.debug("Removing image file %s...", image_filename)
253 if os.path.exists(image_filename):
254 os.unlink(image_filename)
255 else:
256 logging.debug("Image file %s not found")
257
258
259 def check_image(params, root_dir):
260 """
261 Check an image using the appropriate tools for each virt backend.
262
263 @param params: Dictionary containing the test parameters.
264 @param root_dir: Base directory for relative filenames.
265
266 @note: params should contain:
267 image_name -- the name of the image file, without extension
268 image_format -- the format of the image (qcow2, raw etc)
269
270 @raise VMImageCheckError: In case qemu-img check fails on the image.
271 """
272 vm_type = params.get("vm_type")
273 if vm_type == 'kvm':
274 image_filename = get_image_filename(params, root_dir)
275 logging.debug("Checking image file %s...", image_filename)
276 qemu_img_cmd = virt_utils.get_path(root_dir,
277 params.get("qemu_img_binary", "qemu-img"))
278 image_is_qcow2 = params.get("image_format") == 'qcow2'
279 if os.path.exists(image_filename) and image_is_qcow2:
280 # Verifying if qemu-img supports 'check'
281 q_result = utils.run(qemu_img_cmd, ignore_status=True)
282 q_output = q_result.stdout
283 check_img = True
284 if not "check" in q_output:
285 logging.error("qemu-img does not support 'check', "
286 "skipping check...")
287 check_img = False
288 if not "info" in q_output:
289 logging.error("qemu-img does not support 'info', "
290 "skipping check...")
291 check_img = False
292 if check_img:
293 try:
294 utils.system("%s info %s" % (qemu_img_cmd, image_filename))
295 except error.CmdError:
296 logging.error("Error getting info from image %s",
297 image_filename)
298
299 cmd_result = utils.run("%s check %s" %
300 (qemu_img_cmd, image_filename),
301 ignore_status=True)
302 # Error check, large chances of a non-fatal problem.
303 # There are chances that bad data was skipped though
304 if cmd_result.exit_status == 1:
305 for e_line in cmd_result.stdout.splitlines():
306 logging.error("[stdout] %s", e_line)
307 for e_line in cmd_result.stderr.splitlines():
308 logging.error("[stderr] %s", e_line)
309 raise error.TestWarn("qemu-img check error. Some bad data "
310 "in the image may have gone unnoticed")
311 # Exit status 2 is data corruption for sure, so fail the test
312 elif cmd_result.exit_status == 2:
313 for e_line in cmd_result.stdout.splitlines():
314 logging.error("[stdout] %s", e_line)
315 for e_line in cmd_result.stderr.splitlines():
316 logging.error("[stderr] %s", e_line)
317 raise VMImageCheckError(image_filename)
318 # Leaked clusters, they are known to be harmless to data
319 # integrity
320 elif cmd_result.exit_status == 3:
321 raise error.TestWarn("Leaked clusters were noticed during "
322 "image check. No data integrity "
323 "problem was found though.")
324
325 else:
326 if not os.path.exists(image_filename):
327 logging.debug("Image file %s not found, skipping check...",
328 image_filename)
329 elif not image_is_qcow2:
330 logging.debug("Image file %s not qcow2, skipping check...",
331 image_filename)
332
333
334 class BaseVM(object):
335 """
336 Base class for all hypervisor specific VM subclasses.
337
338 This class should not be used directly, that is, do not attempt to
339 instantiate and use this class. Instead, one should implement a subclass
340 that implements, at the very least, all methods defined right after the
341 the comment blocks that are marked with:
342
343 "Public API - *must* be reimplemented with virt specific code"
344
345 and
346
347 "Protected API - *must* be reimplemented with virt specific classes"
348
349 The current proposal regarding methods naming convention is:
350
351 - Public API methods: named in the usual way, consumed by tests
352 - Protected API methods: name begins with a single underline, to be
353 consumed only by BaseVM and subclasses
354 - Private API methods: name begins with double underline, to be consumed
355 only by the VM subclass itself (usually implements virt specific
356 functionality: example: __make_qemu_command())
357
358 So called "protected" methods are intended to be used only by VM classes,
359 and not be consumed by tests. Theses should respect a naming convention
360 and always be preceeded by a single underline.
361
362 Currently most (if not all) methods are public and appears to be consumed
363 by tests. It is a ongoing task to determine whether methods should be
364 "public" or "protected".
365 """
366
367 #
368 # Assuming that all low-level hypervisor have at least migration via tcp
369 # (true for xen & kvm). Also true for libvirt (using xen and kvm drivers)
370 #
371 MIGRATION_PROTOS = ['tcp', ]
372
373 def __init__(self, name, params):
374 self.name = name
375 self.params = params
376
377 #
378 # Assuming all low-level hypervisors will have a serial (like) console
379 # connection to the guest. libvirt also supports serial (like) consoles
380 # (virDomainOpenConsole). subclasses should set this to an object that
381 # is or behaves like aexpect.ShellSession.
382 #
383 self.serial_console = None
384
385 self._generate_unique_id()
386
387
388 def _generate_unique_id(self):
389 """
390 Generate a unique identifier for this VM
391 """
392 while True:
393 self.instance = (time.strftime("%Y%m%d-%H%M%S-") +
394 virt_utils.generate_random_string(4))
395 if not glob.glob("/tmp/*%s" % self.instance):
396 break
397
398
399 #
400 # Public API - could be reimplemented with virt specific code
401 #
402 def verify_alive(self):
403 """
404 Make sure the VM is alive and that the main monitor is responsive.
405
406 Can be subclassed to provide better information on why the VM is
407 not alive (reason, detail)
408
409 @raise VMDeadError: If the VM is dead
410 @raise: Various monitor exceptions if the monitor is unresponsive
411 """
412 if self.is_dead():
413 raise VMDeadError
414
415
416 def get_mac_address(self, nic_index=0):
417 """
418 Return the MAC address of a NIC.
419
420 @param nic_index: Index of the NIC
421 @raise VMMACAddressMissingError: If no MAC address is defined for the
422 requested NIC
423 """
424 nic_name = self.params.objects("nics")[nic_index]
425 nic_params = self.params.object_params(nic_name)
426 mac = (nic_params.get("nic_mac") or
427 virt_utils.get_mac_address(self.instance, nic_index))
428 if not mac:
429 raise VMMACAddressMissingError(nic_index)
430 return mac
431
432
433 def verify_kernel_crash(self):
434 """
435 Find kernel crash message on the VM serial console.
436
437 @raise: VMDeadKernelCrashError, in case a kernel crash message was
438 found.
439 """
440 if self.serial_console is not None:
441 data = self.serial_console.get_output()
442 match = re.search(r"BUG:.*---\[ end trace .* \]---", data,
443 re.DOTALL|re.MULTILINE)
444 if match is not None:
445 raise VMDeadKernelCrashError(match.group(0))
446
447
448 def get_params(self):
449 """
450 Return the VM's params dict. Most modified params take effect only
451 upon VM.create().
452 """
453 return self.params
454
455
456 def get_serial_console_filename(self):
457 """
458 Return the serial console filename.
459 """
460 return "/tmp/serial-%s" % self.instance
461
462
463 def get_testlog_filename(self):
464 """
465 Return the testlog filename.
466 """
467 return "/tmp/testlog-%s" % self.instance
468
469
470 @error.context_aware
471 def login(self, nic_index=0, timeout=10):
472 """
473 Log into the guest via SSH/Telnet/Netcat.
474 If timeout expires while waiting for output from the guest (e.g. a
475 password prompt or a shell prompt) -- fail.
476
477 @param nic_index: The index of the NIC to connect to.
478 @param timeout: Time (seconds) before giving up logging into the
479 guest.
480 @return: A ShellSession object.
481 """
482 error.context("logging into '%s'" % self.name)
483 username = self.params.get("username", "")
484 password = self.params.get("password", "")
485 prompt = self.params.get("shell_prompt", "[\#\$]")
486 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
487 client = self.params.get("shell_client")
488 address = self.get_address(nic_index)
489 port = self.get_port(int(self.params.get("shell_port")))
490 log_filename = ("session-%s-%s.log" %
491 (self.name, virt_utils.generate_random_string(4)))
492 session = virt_utils.remote_login(client, address, port, username,
493 password, prompt, linesep,
494 log_filename, timeout)
495 session.set_status_test_command(self.params.get("status_test_command",
496 ""))
497 return session
498
499
500 def remote_login(self, nic_index=0, timeout=10):
501 """
502 Alias for login() for backward compatibility.
503 """
504 return self.login(nic_index, timeout)
505
506
507 def wait_for_login(self, nic_index=0, timeout=240, internal_timeout=10):
508 """
509 Make multiple attempts to log into the guest via SSH/Telnet/Netcat.
510
511 @param nic_index: The index of the NIC to connect to.
512 @param timeout: Time (seconds) to keep trying to log in.
513 @param internal_timeout: Timeout to pass to login().
514 @return: A ShellSession object.
515 """
516 logging.debug("Attempting to log into '%s' (timeout %ds)", self.name,
517 timeout)
518 end_time = time.time() + timeout
519 while time.time() < end_time:
520 try:
521 return self.login(nic_index, internal_timeout)
522 except (virt_utils.LoginError, VMError), e:
523 logging.debug(e)
524 time.sleep(2)
525 # Timeout expired; try one more time but don't catch exceptions
526 return self.login(nic_index, internal_timeout)
527
528
529 @error.context_aware
530 def copy_files_to(self, host_path, guest_path, nic_index=0, verbose=False,
531 timeout=600):
532 """
533 Transfer files to the remote host(guest).
534
535 @param host_path: Host path
536 @param guest_path: Guest path
537 @param nic_index: The index of the NIC to connect to.
538 @param verbose: If True, log some stats using logging.debug (RSS only)
539 @param timeout: Time (seconds) before giving up on doing the remote
540 copy.
541 """
542 error.context("sending file(s) to '%s'" % self.name)
543 username = self.params.get("username", "")
544 password = self.params.get("password", "")
545 client = self.params.get("file_transfer_client")
546 address = self.get_address(nic_index)
547 port = self.get_port(int(self.params.get("file_transfer_port")))
548 log_filename = ("transfer-%s-to-%s-%s.log" %
549 (self.name, address,
550 virt_utils.generate_random_string(4)))
551 virt_utils.copy_files_to(address, client, username, password, port,
552 host_path, guest_path, log_filename, verbose,
553 timeout)
554
555
556 @error.context_aware
557 def copy_files_from(self, guest_path, host_path, nic_index=0,
558 verbose=False, timeout=600):
559 """
560 Transfer files from the guest.
561
562 @param host_path: Guest path
563 @param guest_path: Host path
564 @param nic_index: The index of the NIC to connect to.
565 @param verbose: If True, log some stats using logging.debug (RSS only)
566 @param timeout: Time (seconds) before giving up on doing the remote
567 copy.
568 """
569 error.context("receiving file(s) from '%s'" % self.name)
570 username = self.params.get("username", "")
571 password = self.params.get("password", "")
572 client = self.params.get("file_transfer_client")
573 address = self.get_address(nic_index)
574 port = self.get_port(int(self.params.get("file_transfer_port")))
575 log_filename = ("transfer-%s-from-%s-%s.log" %
576 (self.name, address,
577 virt_utils.generate_random_string(4)))
578 virt_utils.copy_files_from(address, client, username, password, port,
579 guest_path, host_path, log_filename,
580 verbose, timeout)
581
582
583 @error.context_aware
584 def serial_login(self, timeout=10):
585 """
586 Log into the guest via the serial console.
587 If timeout expires while waiting for output from the guest (e.g. a
588 password prompt or a shell prompt) -- fail.
589
590 @param timeout: Time (seconds) before giving up logging into the guest.
591 @return: ShellSession object on success and None on failure.
592 """
593 error.context("logging into '%s' via serial console" % self.name)
594 username = self.params.get("username", "")
595 password = self.params.get("password", "")
596 prompt = self.params.get("shell_prompt", "[\#\$]")
597 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
598 status_test_command = self.params.get("status_test_command", "")
599
600 self.serial_console.set_linesep(linesep)
601 self.serial_console.set_status_test_command(status_test_command)
602
603 # Try to get a login prompt
604 self.serial_console.sendline()
605
606 virt_utils._remote_login(self.serial_console, username, password,
607 prompt, timeout)
608 return self.serial_console
609
610
611 def wait_for_serial_login(self, timeout=240, internal_timeout=10):
612 """
613 Make multiple attempts to log into the guest via serial console.
614
615 @param timeout: Time (seconds) to keep trying to log in.
616 @param internal_timeout: Timeout to pass to serial_login().
617 @return: A ShellSession object.
618 """
619 logging.debug("Attempting to log into '%s' via serial console "
620 "(timeout %ds)", self.name, timeout)
621 end_time = time.time() + timeout
622 while time.time() < end_time:
623 try:
624 return self.serial_login(internal_timeout)
625 except virt_utils.LoginError, e:
626 logging.debug(e)
627 time.sleep(2)
628 # Timeout expired; try one more time but don't catch exceptions
629 return self.serial_login(internal_timeout)
630
631
632 def get_uuid(self):
633 """
634 Catch UUID of the VM.
635
636 @return: None,if not specified in config file
637 """
638 if self.params.get("uuid") == "random":
639 return self.uuid
640 else:
641 return self.params.get("uuid", None)
642
643
644 def send_string(self, str):
645 """
646 Send a string to the VM.
647
648 @param str: String, that must consist of alphanumeric characters only.
649 Capital letters are allowed.
650 """
651 for char in str:
652 if char.isupper():
653 self.send_key("shift-%s" % char.lower())
654 else:
655 self.send_key(char)
656
657
658 def get_cpu_count(self):
659 """
660 Get the cpu count of the VM.
661 """
662 session = self.login()
663 try:
664 return int(session.cmd(self.params.get("cpu_chk_cmd")))
665 finally:
666 session.close()
667
668
669 def get_memory_size(self, cmd=None):
670 """
671 Get bootup memory size of the VM.
672
673 @param check_cmd: Command used to check memory. If not provided,
674 self.params.get("mem_chk_cmd") will be used.
675 """
676 session = self.login()
677 try:
678 if not cmd:
679 cmd = self.params.get("mem_chk_cmd")
680 mem_str = session.cmd(cmd)
681 mem = re.findall("([0-9]+)", mem_str)
682 mem_size = 0
683 for m in mem:
684 mem_size += int(m)
685 if "GB" in mem_str:
686 mem_size *= 1024
687 elif "MB" in mem_str:
688 pass
689 else:
690 mem_size /= 1024
691 return int(mem_size)
692 finally:
693 session.close()
694
695
696 def get_current_memory_size(self):
697 """
698 Get current memory size of the VM, rather than bootup memory.
699 """
700 cmd = self.params.get("mem_chk_cur_cmd")
701 return self.get_memory_size(cmd)
702
703
704 #
705 # Public API - *must* be reimplemented with virt specific code
706 #
707 def is_alive(self):
708 """
709 Return True if the VM is alive and the management interface is responsiv e.
710 """
711 raise NotImplementedError
712
713
714 def is_dead(self):
715 """
716 Return True if the the VM is dead.
717 """
718 raise NotImplementedError
719
720
721 def get_address(self, index=0):
722 """
723 Return the IP address of a NIC of the guest
724
725 @param index: Index of the NIC whose address is requested.
726 @raise VMMACAddressMissingError: If no MAC address is defined for the
727 requested NIC
728 @raise VMIPAddressMissingError: If no IP address is found for the the
729 NIC's MAC address
730 @raise VMAddressVerificationError: If the MAC-IP address mapping cannot
731 be verified (using arping)
732 """
733 raise NotImplementedError
734
735
736 def clone(self, name, **params):
737 """
738 Return a clone of the VM object with optionally modified parameters.
739
740 This method should be implemented by
741 """
742 raise NotImplementedError
743
744
745 def destroy(self, gracefully=True, free_mac_addresses=True):
746 """
747 Destroy the VM.
748
749 If gracefully is True, first attempt to shutdown the VM with a shell
750 command. Then, attempt to destroy the VM via the monitor with a 'quit'
751 command. If that fails, send SIGKILL to the qemu process.
752
753 @param gracefully: If True, an attempt will be made to end the VM
754 using a shell command before trying to end the qemu process
755 with a 'quit' or a kill signal.
756 @param free_mac_addresses: If True, the MAC addresses used by the VM
757 will be freed.
758 """
759 raise NotImplementedError
760
761
762 def migrate(self, timeout=3600, protocol="tcp", cancel_delay=None,
763 offline=False, stable_check=False, clean=True,
764 save_path="/tmp", dest_host="localhost", remote_port=None):
765 """
766 Migrate the VM.
767
768 If the migration is local, the VM object's state is switched with that
769 of the destination VM. Otherwise, the state is switched with that of
770 a dead VM (returned by self.clone()).
771
772 @param timeout: Time to wait for migration to complete.
773 @param protocol: Migration protocol ('tcp', 'unix' or 'exec').
774 @param cancel_delay: If provided, specifies a time duration after which
775 migration will be canceled. Used for testing migrate_cancel.
776 @param offline: If True, pause the source VM before migration.
777 @param stable_check: If True, compare the VM's state after migration to
778 its state before migration and raise an exception if they
779 differ.
780 @param clean: If True, delete the saved state files (relevant only if
781 stable_check is also True).
782 @save_path: The path for state files.
783 @param dest_host: Destination host (defaults to 'localhost').
784 @param remote_port: Port to use for remote migration.
785 """
786 raise NotImplementedError
787
788
789 def reboot(self, session=None, method="shell", nic_index=0, timeout=240):
790 """
791 Reboot the VM and wait for it to come back up by trying to log in until
792 timeout expires.
793
794 @param session: A shell session object or None.
795 @param method: Reboot method. Can be "shell" (send a shell reboot
796 command) or "system_reset" (send a system_reset monitor command) .
797 @param nic_index: Index of NIC to access in the VM, when logging in
798 after rebooting.
799 @param timeout: Time to wait for login to succeed (after rebooting).
800 @return: A new shell session object.
801 """
802 raise NotImplementedError
803
804
805 # should this really be expected from VMs of all hypervisor types?
806 def send_key(self, keystr):
807 """
808 Send a key event to the VM.
809
810 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
811 """
812 raise NotImplementedError
813
814
815 def save_to_file(self, path):
816 """
817 Save the state of virtual machine to a file through migrate to
818 exec
819 """
820 raise NotImplementedError
821
822
823 def needs_restart(self, name, params, basedir):
824 """
825 Based on virt preprocessing information, decide whether the VM needs
826 a restart.
827 """
828 raise NotImplementedError
829
OLDNEW
« no previous file with comments | « client/virt/virt_utils.py ('k') | server/autotest_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698