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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « client/virt/virt_utils.py ('k') | server/autotest_unittest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: client/virt/virt_vm.py
diff --git a/client/virt/virt_vm.py b/client/virt/virt_vm.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd28966de43297242fede8b8170ac26e832b13c6
--- /dev/null
+++ b/client/virt/virt_vm.py
@@ -0,0 +1,829 @@
+import os, logging, time, glob, re
+from autotest_lib.client.common_lib import error
+from autotest_lib.client.bin import utils
+import virt_utils
+
+class VMError(Exception):
+ pass
+
+
+class VMCreateError(VMError):
+ def __init__(self, cmd, status, output):
+ VMError.__init__(self, cmd, status, output)
+ self.cmd = cmd
+ self.status = status
+ self.output = output
+
+ def __str__(self):
+ return ("VM creation command failed: %r (status: %s, "
+ "output: %r)" % (self.cmd, self.status, self.output))
+
+
+class VMHashMismatchError(VMError):
+ def __init__(self, actual, expected):
+ VMError.__init__(self, actual, expected)
+ self.actual_hash = actual
+ self.expected_hash = expected
+
+ def __str__(self):
+ return ("CD image hash (%s) differs from expected one (%s)" %
+ (self.actual_hash, self.expected_hash))
+
+
+class VMImageMissingError(VMError):
+ def __init__(self, filename):
+ VMError.__init__(self, filename)
+ self.filename = filename
+
+ def __str__(self):
+ return "CD image file not found: %r" % self.filename
+
+
+class VMImageCheckError(VMError):
+ def __init__(self, filename):
+ VMError.__init__(self, filename)
+ self.filename = filename
+
+ def __str__(self):
+ return "Errors found on image: %r" % self.filename
+
+
+class VMBadPATypeError(VMError):
+ def __init__(self, pa_type):
+ VMError.__init__(self, pa_type)
+ self.pa_type = pa_type
+
+ def __str__(self):
+ return "Unsupported PCI assignable type: %r" % self.pa_type
+
+
+class VMPAError(VMError):
+ def __init__(self, pa_type):
+ VMError.__init__(self, pa_type)
+ self.pa_type = pa_type
+
+ def __str__(self):
+ return ("No PCI assignable devices could be assigned "
+ "(pci_assignable=%r)" % self.pa_type)
+
+
+class VMPostCreateError(VMError):
+ def __init__(self, cmd, output):
+ VMError.__init__(self, cmd, output)
+ self.cmd = cmd
+ self.output = output
+
+
+class VMHugePageError(VMPostCreateError):
+ def __str__(self):
+ return ("Cannot allocate hugepage memory (command: %r, "
+ "output: %r)" % (self.cmd, self.output))
+
+
+class VMKVMInitError(VMPostCreateError):
+ def __str__(self):
+ return ("Cannot initialize KVM (command: %r, output: %r)" %
+ (self.cmd, self.output))
+
+
+class VMDeadError(VMError):
+ def __init__(self, reason='', detail=''):
+ VMError.__init__(self)
+ self.reason = reason
+ self.detail = detail
+
+ def __str__(self):
+ msg = "VM is dead"
+ if self.reason:
+ msg += " reason: %s" % self.reason
+ if self.detail:
+ msg += " detail: %r" % self.detail
+ return (msg)
+
+
+class VMDeadKernelCrashError(VMError):
+ def __init__(self, kernel_crash):
+ VMError.__init__(self, kernel_crash)
+ self.kernel_crash = kernel_crash
+
+ def __str__(self):
+ return ("VM is dead due to a kernel crash:\n%s" % self.kernel_crash)
+
+
+class VMAddressError(VMError):
+ pass
+
+
+class VMPortNotRedirectedError(VMAddressError):
+ def __init__(self, port):
+ VMAddressError.__init__(self, port)
+ self.port = port
+
+ def __str__(self):
+ return "Port not redirected: %s" % self.port
+
+
+class VMAddressVerificationError(VMAddressError):
+ def __init__(self, mac, ip):
+ VMAddressError.__init__(self, mac, ip)
+ self.mac = mac
+ self.ip = ip
+
+ def __str__(self):
+ return ("Cannot verify MAC-IP address mapping using arping: "
+ "%s ---> %s" % (self.mac, self.ip))
+
+
+class VMMACAddressMissingError(VMAddressError):
+ def __init__(self, nic_index):
+ VMAddressError.__init__(self, nic_index)
+ self.nic_index = nic_index
+
+ def __str__(self):
+ return "No MAC address defined for NIC #%s" % self.nic_index
+
+
+class VMIPAddressMissingError(VMAddressError):
+ def __init__(self, mac):
+ VMAddressError.__init__(self, mac)
+ self.mac = mac
+
+ def __str__(self):
+ return "Cannot find IP address for MAC address %s" % self.mac
+
+
+class VMMigrateError(VMError):
+ pass
+
+
+class VMMigrateTimeoutError(VMMigrateError):
+ pass
+
+
+class VMMigrateCancelError(VMMigrateError):
+ pass
+
+
+class VMMigrateFailedError(VMMigrateError):
+ pass
+
+class VMMigrateProtoUnsupportedError(VMMigrateError):
+ pass
+
+
+class VMMigrateStateMismatchError(VMMigrateError):
+ def __init__(self, src_hash, dst_hash):
+ VMMigrateError.__init__(self, src_hash, dst_hash)
+ self.src_hash = src_hash
+ self.dst_hash = dst_hash
+
+ def __str__(self):
+ return ("Mismatch of VM state before and after migration (%s != %s)" %
+ (self.src_hash, self.dst_hash))
+
+
+class VMRebootError(VMError):
+ pass
+
+
+def get_image_filename(params, root_dir):
+ """
+ Generate an image path from params and root_dir.
+
+ @param params: Dictionary containing the test parameters.
+ @param root_dir: Base directory for relative filenames.
+
+ @note: params should contain:
+ image_name -- the name of the image file, without extension
+ image_format -- the format of the image (qcow2, raw etc)
+ """
+ image_name = params.get("image_name", "image")
+ image_format = params.get("image_format", "qcow2")
+ if params.get("image_raw_device") == "yes":
+ return image_name
+ image_filename = "%s.%s" % (image_name, image_format)
+ image_filename = virt_utils.get_path(root_dir, image_filename)
+ return image_filename
+
+
+def create_image(params, root_dir):
+ """
+ Create an image using qemu_image.
+
+ @param params: Dictionary containing the test parameters.
+ @param root_dir: Base directory for relative filenames.
+
+ @note: params should contain:
+ image_name -- the name of the image file, without extension
+ image_format -- the format of the image (qcow2, raw etc)
+ image_size -- the requested size of the image (a string
+ qemu-img can understand, such as '10G')
+ """
+ qemu_img_cmd = virt_utils.get_path(root_dir, params.get("qemu_img_binary",
+ "qemu-img"))
+ qemu_img_cmd += " create"
+
+ format = params.get("image_format", "qcow2")
+ qemu_img_cmd += " -f %s" % format
+
+ image_filename = get_image_filename(params, root_dir)
+ qemu_img_cmd += " %s" % image_filename
+
+ size = params.get("image_size", "10G")
+ qemu_img_cmd += " %s" % size
+
+ utils.system(qemu_img_cmd)
+ logging.info("Image created in %r", image_filename)
+ return image_filename
+
+
+def remove_image(params, root_dir):
+ """
+ Remove an image file.
+
+ @param params: A dict
+ @param root_dir: Base directory for relative filenames.
+
+ @note: params should contain:
+ image_name -- the name of the image file, without extension
+ image_format -- the format of the image (qcow2, raw etc)
+ """
+ image_filename = get_image_filename(params, root_dir)
+ logging.debug("Removing image file %s...", image_filename)
+ if os.path.exists(image_filename):
+ os.unlink(image_filename)
+ else:
+ logging.debug("Image file %s not found")
+
+
+def check_image(params, root_dir):
+ """
+ Check an image using the appropriate tools for each virt backend.
+
+ @param params: Dictionary containing the test parameters.
+ @param root_dir: Base directory for relative filenames.
+
+ @note: params should contain:
+ image_name -- the name of the image file, without extension
+ image_format -- the format of the image (qcow2, raw etc)
+
+ @raise VMImageCheckError: In case qemu-img check fails on the image.
+ """
+ vm_type = params.get("vm_type")
+ if vm_type == 'kvm':
+ image_filename = get_image_filename(params, root_dir)
+ logging.debug("Checking image file %s...", image_filename)
+ qemu_img_cmd = virt_utils.get_path(root_dir,
+ params.get("qemu_img_binary", "qemu-img"))
+ image_is_qcow2 = params.get("image_format") == 'qcow2'
+ if os.path.exists(image_filename) and image_is_qcow2:
+ # Verifying if qemu-img supports 'check'
+ q_result = utils.run(qemu_img_cmd, ignore_status=True)
+ q_output = q_result.stdout
+ check_img = True
+ if not "check" in q_output:
+ logging.error("qemu-img does not support 'check', "
+ "skipping check...")
+ check_img = False
+ if not "info" in q_output:
+ logging.error("qemu-img does not support 'info', "
+ "skipping check...")
+ check_img = False
+ if check_img:
+ try:
+ utils.system("%s info %s" % (qemu_img_cmd, image_filename))
+ except error.CmdError:
+ logging.error("Error getting info from image %s",
+ image_filename)
+
+ cmd_result = utils.run("%s check %s" %
+ (qemu_img_cmd, image_filename),
+ ignore_status=True)
+ # Error check, large chances of a non-fatal problem.
+ # There are chances that bad data was skipped though
+ if cmd_result.exit_status == 1:
+ for e_line in cmd_result.stdout.splitlines():
+ logging.error("[stdout] %s", e_line)
+ for e_line in cmd_result.stderr.splitlines():
+ logging.error("[stderr] %s", e_line)
+ raise error.TestWarn("qemu-img check error. Some bad data "
+ "in the image may have gone unnoticed")
+ # Exit status 2 is data corruption for sure, so fail the test
+ elif cmd_result.exit_status == 2:
+ for e_line in cmd_result.stdout.splitlines():
+ logging.error("[stdout] %s", e_line)
+ for e_line in cmd_result.stderr.splitlines():
+ logging.error("[stderr] %s", e_line)
+ raise VMImageCheckError(image_filename)
+ # Leaked clusters, they are known to be harmless to data
+ # integrity
+ elif cmd_result.exit_status == 3:
+ raise error.TestWarn("Leaked clusters were noticed during "
+ "image check. No data integrity "
+ "problem was found though.")
+
+ else:
+ if not os.path.exists(image_filename):
+ logging.debug("Image file %s not found, skipping check...",
+ image_filename)
+ elif not image_is_qcow2:
+ logging.debug("Image file %s not qcow2, skipping check...",
+ image_filename)
+
+
+class BaseVM(object):
+ """
+ Base class for all hypervisor specific VM subclasses.
+
+ This class should not be used directly, that is, do not attempt to
+ instantiate and use this class. Instead, one should implement a subclass
+ that implements, at the very least, all methods defined right after the
+ the comment blocks that are marked with:
+
+ "Public API - *must* be reimplemented with virt specific code"
+
+ and
+
+ "Protected API - *must* be reimplemented with virt specific classes"
+
+ The current proposal regarding methods naming convention is:
+
+ - Public API methods: named in the usual way, consumed by tests
+ - Protected API methods: name begins with a single underline, to be
+ consumed only by BaseVM and subclasses
+ - Private API methods: name begins with double underline, to be consumed
+ only by the VM subclass itself (usually implements virt specific
+ functionality: example: __make_qemu_command())
+
+ So called "protected" methods are intended to be used only by VM classes,
+ and not be consumed by tests. Theses should respect a naming convention
+ and always be preceeded by a single underline.
+
+ Currently most (if not all) methods are public and appears to be consumed
+ by tests. It is a ongoing task to determine whether methods should be
+ "public" or "protected".
+ """
+
+ #
+ # Assuming that all low-level hypervisor have at least migration via tcp
+ # (true for xen & kvm). Also true for libvirt (using xen and kvm drivers)
+ #
+ MIGRATION_PROTOS = ['tcp', ]
+
+ def __init__(self, name, params):
+ self.name = name
+ self.params = params
+
+ #
+ # Assuming all low-level hypervisors will have a serial (like) console
+ # connection to the guest. libvirt also supports serial (like) consoles
+ # (virDomainOpenConsole). subclasses should set this to an object that
+ # is or behaves like aexpect.ShellSession.
+ #
+ self.serial_console = None
+
+ self._generate_unique_id()
+
+
+ def _generate_unique_id(self):
+ """
+ Generate a unique identifier for this VM
+ """
+ while True:
+ self.instance = (time.strftime("%Y%m%d-%H%M%S-") +
+ virt_utils.generate_random_string(4))
+ if not glob.glob("/tmp/*%s" % self.instance):
+ break
+
+
+ #
+ # Public API - could be reimplemented with virt specific code
+ #
+ def verify_alive(self):
+ """
+ Make sure the VM is alive and that the main monitor is responsive.
+
+ Can be subclassed to provide better information on why the VM is
+ not alive (reason, detail)
+
+ @raise VMDeadError: If the VM is dead
+ @raise: Various monitor exceptions if the monitor is unresponsive
+ """
+ if self.is_dead():
+ raise VMDeadError
+
+
+ def get_mac_address(self, nic_index=0):
+ """
+ Return the MAC address of a NIC.
+
+ @param nic_index: Index of the NIC
+ @raise VMMACAddressMissingError: If no MAC address is defined for the
+ requested NIC
+ """
+ nic_name = self.params.objects("nics")[nic_index]
+ nic_params = self.params.object_params(nic_name)
+ mac = (nic_params.get("nic_mac") or
+ virt_utils.get_mac_address(self.instance, nic_index))
+ if not mac:
+ raise VMMACAddressMissingError(nic_index)
+ return mac
+
+
+ def verify_kernel_crash(self):
+ """
+ Find kernel crash message on the VM serial console.
+
+ @raise: VMDeadKernelCrashError, in case a kernel crash message was
+ found.
+ """
+ if self.serial_console is not None:
+ data = self.serial_console.get_output()
+ match = re.search(r"BUG:.*---\[ end trace .* \]---", data,
+ re.DOTALL|re.MULTILINE)
+ if match is not None:
+ raise VMDeadKernelCrashError(match.group(0))
+
+
+ def get_params(self):
+ """
+ Return the VM's params dict. Most modified params take effect only
+ upon VM.create().
+ """
+ return self.params
+
+
+ def get_serial_console_filename(self):
+ """
+ Return the serial console filename.
+ """
+ return "/tmp/serial-%s" % self.instance
+
+
+ def get_testlog_filename(self):
+ """
+ Return the testlog filename.
+ """
+ return "/tmp/testlog-%s" % self.instance
+
+
+ @error.context_aware
+ def login(self, nic_index=0, timeout=10):
+ """
+ Log into the guest via SSH/Telnet/Netcat.
+ If timeout expires while waiting for output from the guest (e.g. a
+ password prompt or a shell prompt) -- fail.
+
+ @param nic_index: The index of the NIC to connect to.
+ @param timeout: Time (seconds) before giving up logging into the
+ guest.
+ @return: A ShellSession object.
+ """
+ error.context("logging into '%s'" % self.name)
+ username = self.params.get("username", "")
+ password = self.params.get("password", "")
+ prompt = self.params.get("shell_prompt", "[\#\$]")
+ linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
+ client = self.params.get("shell_client")
+ address = self.get_address(nic_index)
+ port = self.get_port(int(self.params.get("shell_port")))
+ log_filename = ("session-%s-%s.log" %
+ (self.name, virt_utils.generate_random_string(4)))
+ session = virt_utils.remote_login(client, address, port, username,
+ password, prompt, linesep,
+ log_filename, timeout)
+ session.set_status_test_command(self.params.get("status_test_command",
+ ""))
+ return session
+
+
+ def remote_login(self, nic_index=0, timeout=10):
+ """
+ Alias for login() for backward compatibility.
+ """
+ return self.login(nic_index, timeout)
+
+
+ def wait_for_login(self, nic_index=0, timeout=240, internal_timeout=10):
+ """
+ Make multiple attempts to log into the guest via SSH/Telnet/Netcat.
+
+ @param nic_index: The index of the NIC to connect to.
+ @param timeout: Time (seconds) to keep trying to log in.
+ @param internal_timeout: Timeout to pass to login().
+ @return: A ShellSession object.
+ """
+ logging.debug("Attempting to log into '%s' (timeout %ds)", self.name,
+ timeout)
+ end_time = time.time() + timeout
+ while time.time() < end_time:
+ try:
+ return self.login(nic_index, internal_timeout)
+ except (virt_utils.LoginError, VMError), e:
+ logging.debug(e)
+ time.sleep(2)
+ # Timeout expired; try one more time but don't catch exceptions
+ return self.login(nic_index, internal_timeout)
+
+
+ @error.context_aware
+ def copy_files_to(self, host_path, guest_path, nic_index=0, verbose=False,
+ timeout=600):
+ """
+ Transfer files to the remote host(guest).
+
+ @param host_path: Host path
+ @param guest_path: Guest path
+ @param nic_index: The index of the NIC to connect to.
+ @param verbose: If True, log some stats using logging.debug (RSS only)
+ @param timeout: Time (seconds) before giving up on doing the remote
+ copy.
+ """
+ error.context("sending file(s) to '%s'" % self.name)
+ username = self.params.get("username", "")
+ password = self.params.get("password", "")
+ client = self.params.get("file_transfer_client")
+ address = self.get_address(nic_index)
+ port = self.get_port(int(self.params.get("file_transfer_port")))
+ log_filename = ("transfer-%s-to-%s-%s.log" %
+ (self.name, address,
+ virt_utils.generate_random_string(4)))
+ virt_utils.copy_files_to(address, client, username, password, port,
+ host_path, guest_path, log_filename, verbose,
+ timeout)
+
+
+ @error.context_aware
+ def copy_files_from(self, guest_path, host_path, nic_index=0,
+ verbose=False, timeout=600):
+ """
+ Transfer files from the guest.
+
+ @param host_path: Guest path
+ @param guest_path: Host path
+ @param nic_index: The index of the NIC to connect to.
+ @param verbose: If True, log some stats using logging.debug (RSS only)
+ @param timeout: Time (seconds) before giving up on doing the remote
+ copy.
+ """
+ error.context("receiving file(s) from '%s'" % self.name)
+ username = self.params.get("username", "")
+ password = self.params.get("password", "")
+ client = self.params.get("file_transfer_client")
+ address = self.get_address(nic_index)
+ port = self.get_port(int(self.params.get("file_transfer_port")))
+ log_filename = ("transfer-%s-from-%s-%s.log" %
+ (self.name, address,
+ virt_utils.generate_random_string(4)))
+ virt_utils.copy_files_from(address, client, username, password, port,
+ guest_path, host_path, log_filename,
+ verbose, timeout)
+
+
+ @error.context_aware
+ def serial_login(self, timeout=10):
+ """
+ Log into the guest via the serial console.
+ If timeout expires while waiting for output from the guest (e.g. a
+ password prompt or a shell prompt) -- fail.
+
+ @param timeout: Time (seconds) before giving up logging into the guest.
+ @return: ShellSession object on success and None on failure.
+ """
+ error.context("logging into '%s' via serial console" % self.name)
+ username = self.params.get("username", "")
+ password = self.params.get("password", "")
+ prompt = self.params.get("shell_prompt", "[\#\$]")
+ linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
+ status_test_command = self.params.get("status_test_command", "")
+
+ self.serial_console.set_linesep(linesep)
+ self.serial_console.set_status_test_command(status_test_command)
+
+ # Try to get a login prompt
+ self.serial_console.sendline()
+
+ virt_utils._remote_login(self.serial_console, username, password,
+ prompt, timeout)
+ return self.serial_console
+
+
+ def wait_for_serial_login(self, timeout=240, internal_timeout=10):
+ """
+ Make multiple attempts to log into the guest via serial console.
+
+ @param timeout: Time (seconds) to keep trying to log in.
+ @param internal_timeout: Timeout to pass to serial_login().
+ @return: A ShellSession object.
+ """
+ logging.debug("Attempting to log into '%s' via serial console "
+ "(timeout %ds)", self.name, timeout)
+ end_time = time.time() + timeout
+ while time.time() < end_time:
+ try:
+ return self.serial_login(internal_timeout)
+ except virt_utils.LoginError, e:
+ logging.debug(e)
+ time.sleep(2)
+ # Timeout expired; try one more time but don't catch exceptions
+ return self.serial_login(internal_timeout)
+
+
+ def get_uuid(self):
+ """
+ Catch UUID of the VM.
+
+ @return: None,if not specified in config file
+ """
+ if self.params.get("uuid") == "random":
+ return self.uuid
+ else:
+ return self.params.get("uuid", None)
+
+
+ def send_string(self, str):
+ """
+ Send a string to the VM.
+
+ @param str: String, that must consist of alphanumeric characters only.
+ Capital letters are allowed.
+ """
+ for char in str:
+ if char.isupper():
+ self.send_key("shift-%s" % char.lower())
+ else:
+ self.send_key(char)
+
+
+ def get_cpu_count(self):
+ """
+ Get the cpu count of the VM.
+ """
+ session = self.login()
+ try:
+ return int(session.cmd(self.params.get("cpu_chk_cmd")))
+ finally:
+ session.close()
+
+
+ def get_memory_size(self, cmd=None):
+ """
+ Get bootup memory size of the VM.
+
+ @param check_cmd: Command used to check memory. If not provided,
+ self.params.get("mem_chk_cmd") will be used.
+ """
+ session = self.login()
+ try:
+ if not cmd:
+ cmd = self.params.get("mem_chk_cmd")
+ mem_str = session.cmd(cmd)
+ mem = re.findall("([0-9]+)", mem_str)
+ mem_size = 0
+ for m in mem:
+ mem_size += int(m)
+ if "GB" in mem_str:
+ mem_size *= 1024
+ elif "MB" in mem_str:
+ pass
+ else:
+ mem_size /= 1024
+ return int(mem_size)
+ finally:
+ session.close()
+
+
+ def get_current_memory_size(self):
+ """
+ Get current memory size of the VM, rather than bootup memory.
+ """
+ cmd = self.params.get("mem_chk_cur_cmd")
+ return self.get_memory_size(cmd)
+
+
+ #
+ # Public API - *must* be reimplemented with virt specific code
+ #
+ def is_alive(self):
+ """
+ Return True if the VM is alive and the management interface is responsive.
+ """
+ raise NotImplementedError
+
+
+ def is_dead(self):
+ """
+ Return True if the the VM is dead.
+ """
+ raise NotImplementedError
+
+
+ def get_address(self, index=0):
+ """
+ Return the IP address of a NIC of the guest
+
+ @param index: Index of the NIC whose address is requested.
+ @raise VMMACAddressMissingError: If no MAC address is defined for the
+ requested NIC
+ @raise VMIPAddressMissingError: If no IP address is found for the the
+ NIC's MAC address
+ @raise VMAddressVerificationError: If the MAC-IP address mapping cannot
+ be verified (using arping)
+ """
+ raise NotImplementedError
+
+
+ def clone(self, name, **params):
+ """
+ Return a clone of the VM object with optionally modified parameters.
+
+ This method should be implemented by
+ """
+ raise NotImplementedError
+
+
+ def destroy(self, gracefully=True, free_mac_addresses=True):
+ """
+ Destroy the VM.
+
+ If gracefully is True, first attempt to shutdown the VM with a shell
+ command. Then, attempt to destroy the VM via the monitor with a 'quit'
+ command. If that fails, send SIGKILL to the qemu process.
+
+ @param gracefully: If True, an attempt will be made to end the VM
+ using a shell command before trying to end the qemu process
+ with a 'quit' or a kill signal.
+ @param free_mac_addresses: If True, the MAC addresses used by the VM
+ will be freed.
+ """
+ raise NotImplementedError
+
+
+ def migrate(self, timeout=3600, protocol="tcp", cancel_delay=None,
+ offline=False, stable_check=False, clean=True,
+ save_path="/tmp", dest_host="localhost", remote_port=None):
+ """
+ Migrate the VM.
+
+ If the migration is local, the VM object's state is switched with that
+ of the destination VM. Otherwise, the state is switched with that of
+ a dead VM (returned by self.clone()).
+
+ @param timeout: Time to wait for migration to complete.
+ @param protocol: Migration protocol ('tcp', 'unix' or 'exec').
+ @param cancel_delay: If provided, specifies a time duration after which
+ migration will be canceled. Used for testing migrate_cancel.
+ @param offline: If True, pause the source VM before migration.
+ @param stable_check: If True, compare the VM's state after migration to
+ its state before migration and raise an exception if they
+ differ.
+ @param clean: If True, delete the saved state files (relevant only if
+ stable_check is also True).
+ @save_path: The path for state files.
+ @param dest_host: Destination host (defaults to 'localhost').
+ @param remote_port: Port to use for remote migration.
+ """
+ raise NotImplementedError
+
+
+ def reboot(self, session=None, method="shell", nic_index=0, timeout=240):
+ """
+ Reboot the VM and wait for it to come back up by trying to log in until
+ timeout expires.
+
+ @param session: A shell session object or None.
+ @param method: Reboot method. Can be "shell" (send a shell reboot
+ command) or "system_reset" (send a system_reset monitor command).
+ @param nic_index: Index of NIC to access in the VM, when logging in
+ after rebooting.
+ @param timeout: Time to wait for login to succeed (after rebooting).
+ @return: A new shell session object.
+ """
+ raise NotImplementedError
+
+
+ # should this really be expected from VMs of all hypervisor types?
+ def send_key(self, keystr):
+ """
+ Send a key event to the VM.
+
+ @param: keystr: A key event string (e.g. "ctrl-alt-delete")
+ """
+ raise NotImplementedError
+
+
+ def save_to_file(self, path):
+ """
+ Save the state of virtual machine to a file through migrate to
+ exec
+ """
+ raise NotImplementedError
+
+
+ def needs_restart(self, name, params, basedir):
+ """
+ Based on virt preprocessing information, decide whether the VM needs
+ a restart.
+ """
+ raise NotImplementedError
+
« 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