4 # Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
40 from bitarray import bitarray
42 import affinity # pylint: disable=F0401
46 import fdsend # pylint: disable=F0401
50 from ganeti import utils
51 from ganeti import constants
52 from ganeti import errors
53 from ganeti import serializer
54 from ganeti import objects
55 from ganeti import uidpool
56 from ganeti import ssconf
57 from ganeti import netutils
58 from ganeti import pathutils
59 from ganeti.hypervisor import hv_base
60 from ganeti.utils import wrapper as utils_wrapper
63 _KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
64 _KVM_START_PAUSED_FLAG = "-S"
66 # TUN/TAP driver constants, taken from <linux/if_tun.h>
67 # They are architecture-independent and already hardcoded in qemu-kvm source,
68 # so we can safely include them here.
69 TUNSETIFF = 0x400454ca
70 TUNGETIFF = 0x800454d2
71 TUNGETFEATURES = 0x800454cf
76 #: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
77 _SPICE_ADDITIONAL_PARAMS = frozenset([
78 constants.HV_KVM_SPICE_IP_VERSION,
79 constants.HV_KVM_SPICE_PASSWORD_FILE,
80 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
81 constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
82 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
83 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
84 constants.HV_KVM_SPICE_USE_TLS,
87 # Constant bitarray that reflects to a free pci slot
88 # Use it with bitarray.search()
89 _AVAILABLE_PCI_SLOT = bitarray("0")
91 # below constants show the format of runtime file
92 # the nics are in second possition, while the disks in 4th (last)
93 # moreover disk entries are stored in tupples of L{objects.Disk}, dev_path
94 _KVM_NICS_RUNTIME_INDEX = 1
95 _KVM_DISKS_RUNTIME_INDEX = 3
96 _DEVICE_RUNTIME_INDEX = {
97 constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
98 constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
100 _FIND_RUNTIME_ENTRY = {
101 constants.HOTPLUG_TARGET_NIC:
102 lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
103 constants.HOTPLUG_TARGET_DISK:
104 lambda disk, kvm_disks: [(d, l) for (d, l) in kvm_disks
105 if d.uuid == disk.uuid]
108 constants.HOTPLUG_TARGET_NIC: lambda d: d,
109 constants.HOTPLUG_TARGET_DISK: lambda (d, e): d
112 constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
113 constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e)
117 def _GenerateDeviceKVMId(dev_type, dev):
118 """Helper function to generate a unique device name used by KVM
120 QEMU monitor commands use names to identify devices. Here we use their pci
121 slot and a part of their UUID to name them. dev.pci might be None for old
122 devices in the cluster.
124 @type dev_type: sting
125 @param dev_type: device type of param dev
126 @type dev: L{objects.Disk} or L{objects.NIC}
127 @param dev: the device object for which we generate a kvm name
128 @raise errors.HotplugError: in case a device has no pci slot (old devices)
133 raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
134 (dev_type, dev.uuid))
136 return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
139 def _UpdatePCISlots(dev, pci_reservations):
140 """Update pci configuration for a stopped instance
142 If dev has a pci slot the reserve it, else find first available
143 in pci_reservations bitarray. It acts on the same objects passed
144 as params so there is no need to return anything.
146 @type dev: L{objects.Disk} or L{objects.NIC}
147 @param dev: the device object for which we update its pci slot
148 @type pci_reservations: bitarray
149 @param pci_reservations: existing pci reservations for an instance
150 @raise errors.HotplugError: in case an instance has all its slot occupied
155 else: # pylint: disable=E1103
156 [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
158 raise errors.HypervisorError("All PCI slots occupied")
161 pci_reservations[free] = True
164 def _GetExistingDeviceInfo(dev_type, device, runtime):
165 """Helper function to get an existing device inside the runtime file
167 Used when an instance is running. Load kvm runtime file and search
168 for a device based on its type and uuid.
170 @type dev_type: sting
171 @param dev_type: device type of param dev
172 @type device: L{objects.Disk} or L{objects.NIC}
173 @param device: the device object for which we generate a kvm name
174 @type runtime: tuple (cmd, nics, hvparams, disks)
175 @param runtime: the runtime data to search for the device
176 @raise errors.HotplugError: in case the requested device does not
177 exist (e.g. device has been added without --hotplug option) or
178 device info has not pci slot (e.g. old devices in the cluster)
181 index = _DEVICE_RUNTIME_INDEX[dev_type]
182 found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
184 raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
185 (dev_type, device.uuid))
190 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
191 """Retrieves supported TUN features from file descriptor.
193 @see: L{_ProbeTapVnetHdr}
196 req = struct.pack("I", 0)
198 buf = _ioctl(fd, TUNGETFEATURES, req)
199 except EnvironmentError, err:
200 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
203 (flags, ) = struct.unpack("I", buf)
207 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
208 """Check whether to enable the IFF_VNET_HDR flag.
210 To do this, _all_ of the following conditions must be met:
211 1. TUNGETFEATURES ioctl() *must* be implemented
212 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
213 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
214 drivers/net/tun.c there is no way to test this until after the tap device
215 has been created using TUNSETIFF, and there is no way to change the
216 IFF_VNET_HDR flag after creating the interface, catch-22! However both
217 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
218 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
221 @param fd: the file descriptor of /dev/net/tun
224 flags = _features_fn(fd)
230 result = bool(flags & IFF_VNET_HDR)
233 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
238 def _OpenTap(vnet_hdr=True):
239 """Open a new tap device and return its file descriptor.
241 This is intended to be used by a qemu-type hypervisor together with the -net
242 tap,fd=<fd> command line parameter.
244 @type vnet_hdr: boolean
245 @param vnet_hdr: Enable the VNET Header
246 @return: (ifname, tapfd)
251 tapfd = os.open("/dev/net/tun", os.O_RDWR)
252 except EnvironmentError:
253 raise errors.HypervisorError("Failed to open /dev/net/tun")
255 flags = IFF_TAP | IFF_NO_PI
257 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
258 flags |= IFF_VNET_HDR
260 # The struct ifreq ioctl request (see netdevice(7))
261 ifr = struct.pack("16sh", "", flags)
264 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
265 except EnvironmentError, err:
266 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
269 # Get the interface name from the ioctl
270 ifname = struct.unpack("16sh", res)[0].strip("\x00")
271 return (ifname, tapfd)
275 """QEMU Messaging Protocol (QMP) message.
278 def __init__(self, data):
279 """Creates a new QMP message based on the passed data.
282 if not isinstance(data, dict):
283 raise TypeError("QmpMessage must be initialized with a dict")
287 def __getitem__(self, field_name):
288 """Get the value of the required field if present, or None.
290 Overrides the [] operator to provide access to the message data,
291 returning None if the required item is not in the message
292 @return: the value of the field_name field, or None if field_name
293 is not contained in the message
296 return self.data.get(field_name, None)
298 def __setitem__(self, field_name, field_value):
299 """Set the value of the required field_name to field_value.
302 self.data[field_name] = field_value
305 def BuildFromJsonString(json_string):
306 """Build a QmpMessage from a JSON encoded string.
308 @type json_string: str
309 @param json_string: JSON string representing the message
310 @rtype: L{QmpMessage}
311 @return: a L{QmpMessage} built from json_string
315 data = serializer.LoadJson(json_string)
316 return QmpMessage(data)
319 # The protocol expects the JSON object to be sent as a single line.
320 return serializer.DumpJson(self.data)
322 def __eq__(self, other):
323 # When comparing two QmpMessages, we are interested in comparing
324 # their internal representation of the message data
325 return self.data == other.data
328 class MonitorSocket(object):
331 def __init__(self, monitor_filename):
332 """Instantiates the MonitorSocket object.
334 @type monitor_filename: string
335 @param monitor_filename: the filename of the UNIX raw socket on which the
336 monitor (QMP or simple one) is listening
339 self.monitor_filename = monitor_filename
340 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
341 # We want to fail if the server doesn't send a complete message
342 # in a reasonable amount of time
343 self.sock.settimeout(self._SOCKET_TIMEOUT)
344 self._connected = False
346 def _check_socket(self):
349 sock_stat = os.stat(self.monitor_filename)
350 except EnvironmentError, err:
351 if err.errno == errno.ENOENT:
352 raise errors.HypervisorError("No monitor socket found")
354 raise errors.HypervisorError("Error checking monitor socket: %s",
355 utils.ErrnoOrStr(err))
356 if not stat.S_ISSOCK(sock_stat.st_mode):
357 raise errors.HypervisorError("Monitor socket is not a socket")
359 def _check_connection(self):
360 """Make sure that the connection is established.
363 if not self._connected:
364 raise errors.ProgrammerError("To use a MonitorSocket you need to first"
365 " invoke connect() on it")
368 """Connects to the monitor.
370 Connects to the UNIX socket
372 @raise errors.HypervisorError: when there are communication errors
376 raise errors.ProgrammerError("Cannot connect twice")
380 # Check file existance/stuff
382 self.sock.connect(self.monitor_filename)
383 except EnvironmentError:
384 raise errors.HypervisorError("Can't connect to qmp socket")
385 self._connected = True
390 It cannot be used after this call.
396 class QmpConnection(MonitorSocket):
397 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
400 _FIRST_MESSAGE_KEY = "QMP"
403 _RETURN_KEY = RETURN_KEY = "return"
404 _ACTUAL_KEY = ACTUAL_KEY = "actual"
405 _ERROR_CLASS_KEY = "class"
406 _ERROR_DATA_KEY = "data"
407 _ERROR_DESC_KEY = "desc"
408 _EXECUTE_KEY = "execute"
409 _ARGUMENTS_KEY = "arguments"
410 _CAPABILITIES_COMMAND = "qmp_capabilities"
411 _MESSAGE_END_TOKEN = "\r\n"
413 def __init__(self, monitor_filename):
414 super(QmpConnection, self).__init__(monitor_filename)
418 """Connects to the QMP monitor.
420 Connects to the UNIX socket and makes sure that we can actually send and
421 receive data to the kvm instance via QMP.
423 @raise errors.HypervisorError: when there are communication errors
424 @raise errors.ProgrammerError: when there are data serialization errors
427 super(QmpConnection, self).connect()
428 # Check if we receive a correct greeting message from the server
429 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
430 greeting = self._Recv()
431 if not greeting[self._FIRST_MESSAGE_KEY]:
432 self._connected = False
433 raise errors.HypervisorError("kvm: QMP communication error (wrong"
436 # Let's put the monitor in command mode using the qmp_capabilities
437 # command, or else no command will be executable.
438 # (As per the QEMU Protocol Specification 0.1 - section 4)
439 self.Execute(self._CAPABILITIES_COMMAND)
441 def _ParseMessage(self, buf):
442 """Extract and parse a QMP message from the given buffer.
444 Seeks for a QMP message in the given buf. If found, it parses it and
445 returns it together with the rest of the characters in the buf.
446 If no message is found, returns None and the whole buffer.
448 @raise errors.ProgrammerError: when there are data serialization errors
452 # Check if we got the message end token (CRLF, as per the QEMU Protocol
453 # Specification 0.1 - Section 2.1.1)
454 pos = buf.find(self._MESSAGE_END_TOKEN)
457 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
458 except Exception, err:
459 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
462 return (message, buf)
465 """Receives a message from QMP and decodes the received JSON object.
468 @return: the received message
469 @raise errors.HypervisorError: when there are communication errors
470 @raise errors.ProgrammerError: when there are data serialization errors
473 self._check_connection()
475 # Check if there is already a message in the buffer
476 (message, self._buf) = self._ParseMessage(self._buf)
480 recv_buffer = StringIO.StringIO(self._buf)
481 recv_buffer.seek(len(self._buf))
484 data = self.sock.recv(4096)
487 recv_buffer.write(data)
489 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
493 except socket.timeout, err:
494 raise errors.HypervisorError("Timeout while receiving a QMP message: "
496 except socket.error, err:
497 raise errors.HypervisorError("Unable to receive data from KVM using the"
498 " QMP protocol: %s" % err)
500 def _Send(self, message):
501 """Encodes and sends a message to KVM using QMP.
503 @type message: QmpMessage
504 @param message: message to send to KVM
505 @raise errors.HypervisorError: when there are communication errors
506 @raise errors.ProgrammerError: when there are data serialization errors
509 self._check_connection()
511 message_str = str(message)
512 except Exception, err:
513 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
516 self.sock.sendall(message_str)
517 except socket.timeout, err:
518 raise errors.HypervisorError("Timeout while sending a QMP message: "
519 "%s (%s)" % (err.string, err.errno))
520 except socket.error, err:
521 raise errors.HypervisorError("Unable to send data from KVM using the"
522 " QMP protocol: %s" % err)
524 def Execute(self, command, arguments=None):
525 """Executes a QMP command and returns the response of the server.
528 @param command: the command to execute
529 @type arguments: dict
530 @param arguments: dictionary of arguments to be passed to the command
532 @return: dictionary representing the received JSON object
533 @raise errors.HypervisorError: when there are communication errors
534 @raise errors.ProgrammerError: when there are data serialization errors
537 self._check_connection()
538 message = QmpMessage({self._EXECUTE_KEY: command})
540 message[self._ARGUMENTS_KEY] = arguments
543 # Events can occur between the sending of the command and the reception
544 # of the response, so we need to filter out messages with the event key.
546 response = self._Recv()
547 err = response[self._ERROR_KEY]
549 raise errors.HypervisorError("kvm: error executing the %s"
550 " command: %s (%s, %s):" %
552 err[self._ERROR_DESC_KEY],
553 err[self._ERROR_CLASS_KEY],
554 err[self._ERROR_DATA_KEY]))
556 elif not response[self._EVENT_KEY]:
560 class KVMHypervisor(hv_base.BaseHypervisor):
561 """KVM hypervisor interface
566 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
567 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
568 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
569 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
570 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
571 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
572 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
573 # KVM instances with chroot enabled are started in empty chroot directories.
574 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
575 # After an instance is stopped, its chroot directory is removed.
576 # If the chroot directory is not empty, it can't be removed.
577 # A non-empty chroot directory indicates a possible security incident.
578 # To support forensics, the non-empty chroot directory is quarantined in
579 # a separate directory, called 'chroot-quarantine'.
580 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
581 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
582 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
585 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
586 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
587 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
588 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
589 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
590 constants.HV_ACPI: hv_base.NO_CHECK,
591 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
592 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
593 constants.HV_VNC_BIND_ADDRESS:
594 (False, lambda x: (netutils.IP4Address.IsValid(x) or
595 utils.IsNormAbsPath(x)),
596 "The VNC bind address must be either a valid IP address or an absolute"
597 " pathname", None, None),
598 constants.HV_VNC_TLS: hv_base.NO_CHECK,
599 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
600 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
601 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
602 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
603 constants.HV_KVM_SPICE_IP_VERSION:
604 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
605 x in constants.VALID_IP_VERSIONS),
606 "The SPICE IP version should be 4 or 6",
608 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
609 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
611 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
612 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
614 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
615 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
617 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
618 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
620 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
621 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
622 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
623 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
624 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
625 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
626 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
627 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
628 constants.HV_BOOT_ORDER:
629 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
630 constants.HV_NIC_TYPE:
631 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
632 constants.HV_DISK_TYPE:
633 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
634 constants.HV_KVM_CDROM_DISK_TYPE:
635 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
636 constants.HV_USB_MOUSE:
637 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
638 constants.HV_KEYMAP: hv_base.NO_CHECK,
639 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
640 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
641 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
642 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
643 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
644 constants.HV_DISK_CACHE:
645 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
646 constants.HV_SECURITY_MODEL:
647 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
648 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
649 constants.HV_KVM_FLAG:
650 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
651 constants.HV_VHOST_NET: hv_base.NO_CHECK,
652 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
653 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
654 constants.HV_REBOOT_BEHAVIOR:
655 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
656 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
657 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
658 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
659 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
660 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
661 constants.HV_SOUNDHW: hv_base.NO_CHECK,
662 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
663 constants.HV_VGA: hv_base.NO_CHECK,
664 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
665 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
666 constants.HV_VNET_HDR: hv_base.NO_CHECK,
670 _VIRTIO_NET_PCI = "virtio-net-pci"
671 _VIRTIO_BLK_PCI = "virtio-blk-pci"
673 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
675 _MIGRATION_PROGRESS_RE = \
676 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
677 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
678 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
680 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
681 _MIGRATION_INFO_RETRY_DELAY = 2
683 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
685 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
686 _CPU_INFO_CMD = "info cpus"
689 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
690 _CHECK_MACHINE_VERSION_RE = \
691 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
693 _QMP_RE = re.compile(r"^-qmp\s", re.M)
694 _SPICE_RE = re.compile(r"^-spice\s", re.M)
695 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
696 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
697 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
698 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
699 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
700 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
701 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
702 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
703 # match -drive.*boot=on|off on different lines, but in between accept only
704 # dashes not preceeded by a new line (which would mean another option
705 # different than -drive is starting)
706 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
708 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
709 _INFO_PCI_CMD = "info pci"
711 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
712 _INFO_VERSION_CMD = "info version"
714 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
719 ANCILLARY_FILES_OPT = [
723 # Supported kvm options to get output from
724 _KVMOPT_HELP = "help"
725 _KVMOPT_MLIST = "mlist"
726 _KVMOPT_DEVICELIST = "devicelist"
728 # Command to execute to get the output from kvm, and whether to
729 # accept the output even on failure.
731 _KVMOPT_HELP: (["--help"], False),
732 _KVMOPT_MLIST: (["-M", "?"], False),
733 _KVMOPT_DEVICELIST: (["-device", "?"], True),
737 hv_base.BaseHypervisor.__init__(self)
738 # Let's make sure the directories we need exist, even if the RUN_DIR lives
739 # in a tmpfs filesystem or has been otherwise wiped out.
740 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
741 utils.EnsureDirs(dirs)
744 def _InstancePidFile(cls, instance_name):
745 """Returns the instance pidfile.
748 return utils.PathJoin(cls._PIDS_DIR, instance_name)
751 def _InstanceUidFile(cls, instance_name):
752 """Returns the instance uidfile.
755 return utils.PathJoin(cls._UIDS_DIR, instance_name)
758 def _InstancePidInfo(cls, pid):
759 """Check pid file for instance information.
761 Check that a pid file is associated with an instance, and retrieve
762 information from its command line.
764 @type pid: string or int
765 @param pid: process id of the instance to check
767 @return: (instance_name, memory, vcpus)
768 @raise errors.HypervisorError: when an instance cannot be found
771 alive = utils.IsProcessAlive(pid)
773 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
775 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
777 cmdline = utils.ReadFile(cmdline_file)
778 except EnvironmentError, err:
779 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
786 arg_list = cmdline.split("\x00")
788 arg = arg_list.pop(0)
790 instance = arg_list.pop(0)
792 memory = int(arg_list.pop(0))
794 vcpus = int(arg_list.pop(0).split(",")[0])
797 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
800 return (instance, memory, vcpus)
802 def _InstancePidAlive(self, instance_name):
803 """Returns the instance pidfile, pid, and liveness.
805 @type instance_name: string
806 @param instance_name: instance name
808 @return: (pid file name, pid, liveness)
811 pidfile = self._InstancePidFile(instance_name)
812 pid = utils.ReadPidFile(pidfile)
816 cmd_instance = self._InstancePidInfo(pid)[0]
817 alive = (cmd_instance == instance_name)
818 except errors.HypervisorError:
821 return (pidfile, pid, alive)
823 def _CheckDown(self, instance_name):
824 """Raises an error unless the given instance is down.
827 alive = self._InstancePidAlive(instance_name)[2]
829 raise errors.HypervisorError("Failed to start instance %s: %s" %
830 (instance_name, "already running"))
833 def _InstanceMonitor(cls, instance_name):
834 """Returns the instance monitor socket name
837 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
840 def _InstanceSerial(cls, instance_name):
841 """Returns the instance serial socket name
844 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
847 def _InstanceQmpMonitor(cls, instance_name):
848 """Returns the instance serial QMP socket name
851 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
854 def _SocatUnixConsoleParams():
855 """Returns the correct parameters for socat
857 If we have a new-enough socat we can use raw mode with an escape character.
860 if constants.SOCAT_USE_ESCAPE:
861 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
863 return "echo=0,icanon=0"
866 def _InstanceKVMRuntime(cls, instance_name):
867 """Returns the instance KVM runtime filename
870 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
873 def _InstanceChrootDir(cls, instance_name):
874 """Returns the name of the KVM chroot dir of the instance
877 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
880 def _InstanceNICDir(cls, instance_name):
881 """Returns the name of the directory holding the tap device files for a
885 return utils.PathJoin(cls._NICS_DIR, instance_name)
888 def _InstanceNICFile(cls, instance_name, seq):
889 """Returns the name of the file containing the tap device for a given NIC
892 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
895 def _InstanceKeymapFile(cls, instance_name):
896 """Returns the name of the file containing the keymap for a given instance
899 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
902 def _TryReadUidFile(cls, uid_file):
903 """Try to read a uid file
906 if os.path.exists(uid_file):
908 uid = int(utils.ReadOneLineFile(uid_file))
910 except EnvironmentError:
911 logging.warning("Can't read uid file", exc_info=True)
912 except (TypeError, ValueError):
913 logging.warning("Can't parse uid file contents", exc_info=True)
917 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
918 """Removes an instance's rutime sockets/files/dirs.
921 utils.RemoveFile(pidfile)
922 utils.RemoveFile(cls._InstanceMonitor(instance_name))
923 utils.RemoveFile(cls._InstanceSerial(instance_name))
924 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
925 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
926 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
927 uid_file = cls._InstanceUidFile(instance_name)
928 uid = cls._TryReadUidFile(uid_file)
929 utils.RemoveFile(uid_file)
931 uidpool.ReleaseUid(uid)
933 shutil.rmtree(cls._InstanceNICDir(instance_name))
935 if err.errno != errno.ENOENT:
938 chroot_dir = cls._InstanceChrootDir(instance_name)
939 utils.RemoveDir(chroot_dir)
941 if err.errno == errno.ENOTEMPTY:
942 # The chroot directory is expected to be empty, but it isn't.
943 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
946 utils.TimestampForFilename()))
947 logging.warning("The chroot directory of instance %s can not be"
948 " removed as it is not empty. Moving it to the"
949 " quarantine instead. Please investigate the"
950 " contents (%s) and clean up manually",
951 instance_name, new_chroot_dir)
952 utils.RenameFile(chroot_dir, new_chroot_dir)
957 def _ConfigureNIC(instance, seq, nic, tap):
958 """Run the network configuration script for a specified NIC
960 @param instance: instance we're acting on
961 @type instance: instance object
962 @param seq: nic sequence number
964 @param nic: nic we're acting on
965 @type nic: nic object
966 @param tap: the host's tap interface this NIC corresponds to
971 tags = " ".join(instance.tags)
976 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
977 "INSTANCE": instance.name,
979 "MODE": nic.nicparams[constants.NIC_MODE],
981 "INTERFACE_INDEX": str(seq),
988 if nic.nicparams[constants.NIC_LINK]:
989 env["LINK"] = nic.nicparams[constants.NIC_LINK]
992 n = objects.Network.FromDict(nic.netinfo)
993 env.update(n.HooksDict())
995 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
996 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
998 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1000 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1001 " network configuration script output: %s" %
1002 (tap, result.fail_reason, result.output))
1005 def _VerifyAffinityPackage():
1006 if affinity is None:
1007 raise errors.HypervisorError("affinity Python package not"
1008 " found; cannot use CPU pinning under KVM")
1011 def _BuildAffinityCpuMask(cpu_list):
1012 """Create a CPU mask suitable for sched_setaffinity from a list of
1015 See man taskset for more info on sched_setaffinity masks.
1016 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1018 @type cpu_list: list of int
1019 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1021 @return: a bit mask of CPU affinities
1024 if cpu_list == constants.CPU_PINNING_OFF:
1025 return constants.CPU_PINNING_ALL_KVM
1027 return sum(2 ** cpu for cpu in cpu_list)
1030 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1031 """Change CPU affinity for running VM according to given CPU mask.
1033 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1034 @type cpu_mask: string
1035 @param process_id: process ID of KVM process. Used to pin entire VM
1037 @type process_id: int
1038 @param thread_dict: map of virtual CPUs to KVM thread IDs
1039 @type thread_dict: dict int:int
1042 # Convert the string CPU mask to a list of list of int's
1043 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1045 if len(cpu_list) == 1:
1046 all_cpu_mapping = cpu_list[0]
1047 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1048 # If CPU pinning has 1 entry that's "all", then do nothing
1051 # If CPU pinning has one non-all entry, map the entire VM to
1052 # one set of physical CPUs
1053 cls._VerifyAffinityPackage()
1054 affinity.set_process_affinity_mask(
1055 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1057 # The number of vCPUs mapped should match the number of vCPUs
1058 # reported by KVM. This was already verified earlier, so
1059 # here only as a sanity check.
1060 assert len(thread_dict) == len(cpu_list)
1061 cls._VerifyAffinityPackage()
1063 # For each vCPU, map it to the proper list of physical CPUs
1064 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1065 affinity.set_process_affinity_mask(thread_dict[i],
1066 cls._BuildAffinityCpuMask(vcpu))
1068 def _GetVcpuThreadIds(self, instance_name):
1069 """Get a mapping of vCPU no. to thread IDs for the instance
1071 @type instance_name: string
1072 @param instance_name: instance in question
1073 @rtype: dictionary of int:int
1074 @return: a dictionary mapping vCPU numbers to thread IDs
1078 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1079 for line in output.stdout.splitlines():
1080 match = self._CPU_INFO_RE.search(line)
1083 grp = map(int, match.groups())
1084 result[grp[0]] = grp[1]
1088 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1089 """Complete CPU pinning.
1091 @type instance_name: string
1092 @param instance_name: name of instance
1093 @type cpu_mask: string
1094 @param cpu_mask: CPU pinning mask as entered by user
1097 # Get KVM process ID, to be used if need to pin entire VM
1098 _, pid, _ = self._InstancePidAlive(instance_name)
1099 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1100 thread_dict = self._GetVcpuThreadIds(instance_name)
1101 # Run CPU pinning, based on configured mask
1102 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1104 def ListInstances(self):
1105 """Get the list of running instances.
1107 We can do this by listing our live instances directory and
1108 checking whether the associated kvm process is still alive.
1112 for name in os.listdir(self._PIDS_DIR):
1113 if self._InstancePidAlive(name)[2]:
1117 def GetInstanceInfo(self, instance_name):
1118 """Get instance properties.
1120 @type instance_name: string
1121 @param instance_name: the instance name
1122 @rtype: tuple of strings
1123 @return: (name, id, memory, vcpus, stat, times)
1126 _, pid, alive = self._InstancePidAlive(instance_name)
1130 _, memory, vcpus = self._InstancePidInfo(pid)
1135 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1137 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1138 # Will fail if ballooning is not enabled, but we can then just resort to
1140 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1141 memory = mem_bytes / 1048576
1142 except errors.HypervisorError:
1145 return (instance_name, pid, memory, vcpus, istat, times)
1147 def GetAllInstancesInfo(self):
1148 """Get properties of all instances.
1150 @return: list of tuples (name, id, memory, vcpus, stat, times)
1154 for name in os.listdir(self._PIDS_DIR):
1156 info = self.GetInstanceInfo(name)
1157 except errors.HypervisorError:
1158 # Ignore exceptions due to instances being shut down
1164 def _GenerateKVMBlockDevicesOptions(self, instance, block_devices,
1166 """Generate KVM options regarding instance's block devices.
1168 @type instance: L{objects.Instance}
1169 @param instance: the instance object
1170 @type block_devices: list of tuples
1171 @param block_devices: list of tuples [(disk, link_name)..]
1172 @type kvmhelp: string
1173 @param kvmhelp: output of kvm --help
1174 @type devlist: string
1175 @param devlist: output of kvm -device ?
1177 @return: list of command line options eventually used by kvm executable
1180 hvp = instance.hvparams
1181 kernel_path = hvp[constants.HV_KERNEL_PATH]
1185 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1187 # whether this is an older KVM version that uses the boot=on flag
1189 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1192 device_driver = None
1193 disk_type = hvp[constants.HV_DISK_TYPE]
1194 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1195 if_val = ",if=%s" % self._VIRTIO
1197 if self._VIRTIO_BLK_RE.search(devlist):
1199 # will be passed in -device option as driver
1200 device_driver = self._VIRTIO_BLK_PCI
1201 except errors.HypervisorError, _:
1204 if_val = ",if=%s" % disk_type
1206 disk_cache = hvp[constants.HV_DISK_CACHE]
1207 if instance.disk_template in constants.DTS_EXT_MIRROR:
1208 if disk_cache != "none":
1209 # TODO: make this a hard error, instead of a silent overwrite
1210 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1211 " to prevent shared storage corruption on migration",
1213 cache_val = ",cache=none"
1214 elif disk_cache != constants.HT_CACHE_DEFAULT:
1215 cache_val = ",cache=%s" % disk_cache
1218 for cfdev, dev_path in block_devices:
1219 if cfdev.mode != constants.DISK_RDWR:
1220 raise errors.HypervisorError("Instance has read-only disks which"
1221 " are not supported by KVM")
1222 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1225 dev_opts.extend(["-boot", "c"])
1227 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1228 boot_val = ",boot=on"
1229 drive_val = "file=%s,format=raw%s%s%s" % \
1230 (dev_path, if_val, boot_val, cache_val)
1233 # block_devices are the 4th entry of runtime file that did not exist in
1234 # the past. That means that cfdev should always have pci slot and
1235 # _GenerateDeviceKVMId() will not raise a exception.
1236 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1237 drive_val += (",id=%s" % kvm_devid)
1238 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1239 dev_val = ("%s,drive=%s,id=%s" %
1240 (device_driver, kvm_devid, kvm_devid))
1241 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1242 dev_opts.extend(["-device", dev_val])
1244 dev_opts.extend(["-drive", drive_val])
1248 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1250 """Generate KVM information to start an instance.
1252 @type kvmhelp: string
1253 @param kvmhelp: output of kvm --help
1254 @attention: this function must not have any side-effects; for
1255 example, it must not write to the filesystem, or read values
1256 from the current system the are expected to differ between
1257 nodes, since it is only run once at instance startup;
1258 actions/kvm arguments that can vary between systems should be
1259 done in L{_ExecuteKVMRuntime}
1262 # pylint: disable=R0912,R0914,R0915
1263 hvp = instance.hvparams
1264 self.ValidateParameters(hvp)
1266 pidfile = self._InstancePidFile(instance.name)
1267 kvm = hvp[constants.HV_KVM_PATH]
1269 # used just by the vnc server, if enabled
1270 kvm_cmd.extend(["-name", instance.name])
1271 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1273 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1274 if hvp[constants.HV_CPU_CORES]:
1275 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1276 if hvp[constants.HV_CPU_THREADS]:
1277 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1278 if hvp[constants.HV_CPU_SOCKETS]:
1279 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1281 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1283 kvm_cmd.extend(["-pidfile", pidfile])
1284 kvm_cmd.extend(["-balloon", "virtio"])
1285 kvm_cmd.extend(["-daemonize"])
1286 if not instance.hvparams[constants.HV_ACPI]:
1287 kvm_cmd.extend(["-no-acpi"])
1288 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1289 constants.INSTANCE_REBOOT_EXIT:
1290 kvm_cmd.extend(["-no-reboot"])
1292 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1294 mversion = self._GetDefaultMachineVersion(kvm)
1295 if self._MACHINE_RE.search(kvmhelp):
1296 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1297 # extra hypervisor parameters. We should also investigate whether and how
1298 # shadow_mem should be considered for the resource model.
1299 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1300 specprop = ",accel=kvm"
1303 machinespec = "%s%s" % (mversion, specprop)
1304 kvm_cmd.extend(["-machine", machinespec])
1306 kvm_cmd.extend(["-M", mversion])
1307 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1308 self._ENABLE_KVM_RE.search(kvmhelp)):
1309 kvm_cmd.extend(["-enable-kvm"])
1310 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1311 self._DISABLE_KVM_RE.search(kvmhelp)):
1312 kvm_cmd.extend(["-disable-kvm"])
1314 kernel_path = hvp[constants.HV_KERNEL_PATH]
1316 boot_cdrom = boot_floppy = boot_network = False
1318 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1319 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1320 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1323 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1326 kvm_cmd.extend(["-boot", "n"])
1328 # whether this is an older KVM version that uses the boot=on flag
1330 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1332 disk_type = hvp[constants.HV_DISK_TYPE]
1334 #Now we can specify a different device type for CDROM devices.
1335 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1336 if not cdrom_disk_type:
1337 cdrom_disk_type = disk_type
1339 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1341 options = ",format=raw,media=cdrom"
1342 # set cdrom 'if' type
1344 actual_cdrom_type = constants.HT_DISK_IDE
1345 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1346 actual_cdrom_type = "virtio"
1348 actual_cdrom_type = cdrom_disk_type
1349 if_val = ",if=%s" % actual_cdrom_type
1350 # set boot flag, if needed
1353 kvm_cmd.extend(["-boot", "d"])
1355 boot_val = ",boot=on"
1356 # and finally build the entire '-drive' value
1357 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1358 kvm_cmd.extend(["-drive", drive_val])
1360 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1362 options = ",format=raw,media=cdrom"
1363 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1364 if_val = ",if=virtio"
1366 if_val = ",if=%s" % cdrom_disk_type
1367 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1368 kvm_cmd.extend(["-drive", drive_val])
1370 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1372 options = ",format=raw,media=disk"
1374 kvm_cmd.extend(["-boot", "a"])
1375 options = "%s,boot=on" % options
1376 if_val = ",if=floppy"
1377 options = "%s%s" % (options, if_val)
1378 drive_val = "file=%s%s" % (floppy_image, options)
1379 kvm_cmd.extend(["-drive", drive_val])
1382 kvm_cmd.extend(["-kernel", kernel_path])
1383 initrd_path = hvp[constants.HV_INITRD_PATH]
1385 kvm_cmd.extend(["-initrd", initrd_path])
1386 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1387 hvp[constants.HV_KERNEL_ARGS]]
1388 if hvp[constants.HV_SERIAL_CONSOLE]:
1389 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1390 root_append.append("console=ttyS0,%s" % serial_speed)
1391 kvm_cmd.extend(["-append", " ".join(root_append)])
1393 mem_path = hvp[constants.HV_MEM_PATH]
1395 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1397 monitor_dev = ("unix:%s,server,nowait" %
1398 self._InstanceMonitor(instance.name))
1399 kvm_cmd.extend(["-monitor", monitor_dev])
1400 if hvp[constants.HV_SERIAL_CONSOLE]:
1401 serial_dev = ("unix:%s,server,nowait" %
1402 self._InstanceSerial(instance.name))
1403 kvm_cmd.extend(["-serial", serial_dev])
1405 kvm_cmd.extend(["-serial", "none"])
1407 mouse_type = hvp[constants.HV_USB_MOUSE]
1408 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1409 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1410 spice_ip_version = None
1412 kvm_cmd.extend(["-usb"])
1415 kvm_cmd.extend(["-usbdevice", mouse_type])
1416 elif vnc_bind_address:
1417 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1419 if vnc_bind_address:
1420 if netutils.IP4Address.IsValid(vnc_bind_address):
1421 if instance.network_port > constants.VNC_BASE_PORT:
1422 display = instance.network_port - constants.VNC_BASE_PORT
1423 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1424 vnc_arg = ":%d" % (display)
1426 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1428 logging.error("Network port is not a valid VNC display (%d < %d),"
1429 " not starting VNC",
1430 instance.network_port, constants.VNC_BASE_PORT)
1433 # Only allow tls and other option when not binding to a file, for now.
1434 # kvm/qemu gets confused otherwise about the filename to use.
1436 if hvp[constants.HV_VNC_TLS]:
1437 vnc_append = "%s,tls" % vnc_append
1438 if hvp[constants.HV_VNC_X509_VERIFY]:
1439 vnc_append = "%s,x509verify=%s" % (vnc_append,
1440 hvp[constants.HV_VNC_X509])
1441 elif hvp[constants.HV_VNC_X509]:
1442 vnc_append = "%s,x509=%s" % (vnc_append,
1443 hvp[constants.HV_VNC_X509])
1444 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1445 vnc_append = "%s,password" % vnc_append
1447 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1450 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1452 kvm_cmd.extend(["-vnc", vnc_arg])
1454 # FIXME: this is wrong here; the iface ip address differs
1455 # between systems, so it should be done in _ExecuteKVMRuntime
1456 if netutils.IsValidInterface(spice_bind):
1457 # The user specified a network interface, we have to figure out the IP
1459 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1460 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1462 # if the user specified an IP version and the interface does not
1463 # have that kind of IP addresses, throw an exception
1464 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1465 if not addresses[spice_ip_version]:
1466 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1467 " for %s" % (spice_ip_version,
1470 # the user did not specify an IP version, we have to figure it out
1471 elif (addresses[constants.IP4_VERSION] and
1472 addresses[constants.IP6_VERSION]):
1473 # we have both ipv4 and ipv6, let's use the cluster default IP
1475 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1476 spice_ip_version = \
1477 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1478 elif addresses[constants.IP4_VERSION]:
1479 spice_ip_version = constants.IP4_VERSION
1480 elif addresses[constants.IP6_VERSION]:
1481 spice_ip_version = constants.IP6_VERSION
1483 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1484 " for %s" % (spice_bind))
1486 spice_address = addresses[spice_ip_version][0]
1489 # spice_bind is known to be a valid IP address, because
1490 # ValidateParameters checked it.
1491 spice_address = spice_bind
1493 spice_arg = "addr=%s" % spice_address
1494 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1495 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1496 (spice_arg, instance.network_port,
1497 pathutils.SPICE_CACERT_FILE))
1498 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1499 (spice_arg, pathutils.SPICE_CERT_FILE,
1500 pathutils.SPICE_CERT_FILE))
1501 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1503 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1505 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1507 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1508 spice_arg = "%s,disable-ticketing" % spice_arg
1510 if spice_ip_version:
1511 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1513 # Image compression options
1514 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1515 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1516 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1518 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1520 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1522 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1524 # Video stream detection
1525 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1527 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1529 # Audio compression, by default in qemu-kvm it is on
1530 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1531 spice_arg = "%s,playback-compression=off" % spice_arg
1532 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1533 spice_arg = "%s,agent-mouse=off" % spice_arg
1535 # Enable the spice agent communication channel between the host and the
1537 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1540 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1542 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1544 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1545 kvm_cmd.extend(["-spice", spice_arg])
1548 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1549 # also works in earlier versions though (tested with 1.1 and 1.3)
1550 if self._DISPLAY_RE.search(kvmhelp):
1551 kvm_cmd.extend(["-display", "none"])
1553 kvm_cmd.extend(["-nographic"])
1555 if hvp[constants.HV_USE_LOCALTIME]:
1556 kvm_cmd.extend(["-localtime"])
1558 if hvp[constants.HV_KVM_USE_CHROOT]:
1559 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1561 # Add qemu-KVM -cpu param
1562 if hvp[constants.HV_CPU_TYPE]:
1563 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1565 # As requested by music lovers
1566 if hvp[constants.HV_SOUNDHW]:
1567 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1569 # Pass a -vga option if requested, or if spice is used, for backwards
1571 if hvp[constants.HV_VGA]:
1572 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1574 kvm_cmd.extend(["-vga", "qxl"])
1576 # Various types of usb devices, comma separated
1577 if hvp[constants.HV_USB_DEVICES]:
1578 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1579 kvm_cmd.extend(["-usbdevice", dev])
1581 if hvp[constants.HV_KVM_EXTRA]:
1582 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1584 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1586 for disk, dev_path in block_devices:
1587 _UpdatePCISlots(disk, pci_reservations)
1588 kvm_disks.append((disk, dev_path))
1591 for nic in instance.nics:
1592 _UpdatePCISlots(nic, pci_reservations)
1593 kvm_nics.append(nic)
1597 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1599 def _WriteKVMRuntime(self, instance_name, data):
1600 """Write an instance's KVM runtime
1604 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1606 except EnvironmentError, err:
1607 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1609 def _ReadKVMRuntime(self, instance_name):
1610 """Read an instance's KVM runtime
1614 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1615 except EnvironmentError, err:
1616 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1619 def _SaveKVMRuntime(self, instance, kvm_runtime):
1620 """Save an instance's KVM runtime
1623 kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1625 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1626 serialized_blockdevs = [(blk.ToDict(), link) for blk, link in block_devices]
1627 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1628 serialized_blockdevs))
1630 self._WriteKVMRuntime(instance.name, serialized_form)
1632 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1633 """Load an instance's KVM runtime
1636 if not serialized_runtime:
1637 serialized_runtime = self._ReadKVMRuntime(instance.name)
1639 loaded_runtime = serializer.Load(serialized_runtime)
1640 if len(loaded_runtime) == 3:
1641 serialized_blockdevs = []
1642 kvm_cmd, serialized_nics, hvparams = loaded_runtime
1644 kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
1646 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1647 block_devices = [(objects.Disk.FromDict(sdisk), link)
1648 for sdisk, link in serialized_blockdevs]
1650 return (kvm_cmd, kvm_nics, hvparams, block_devices)
1652 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1653 """Run the KVM cmd and check for errors
1656 @param name: instance name
1657 @type kvm_cmd: list of strings
1658 @param kvm_cmd: runcmd input for kvm
1659 @type tap_fds: list of int
1660 @param tap_fds: fds of tap devices opened by Ganeti
1664 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1667 utils_wrapper.CloseFdNoError(fd)
1670 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1671 (name, result.fail_reason, result.output))
1672 if not self._InstancePidAlive(name)[2]:
1673 raise errors.HypervisorError("Failed to start instance %s" % name)
1675 # 52/50 local variables
1676 # pylint: disable=R0914
1677 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1678 """Execute a KVM cmd, after completing it with some last minute data.
1680 @type incoming: tuple of strings
1681 @param incoming: (target_host_ip, port)
1682 @type kvmhelp: string
1683 @param kvmhelp: output of kvm --help
1686 # Small _ExecuteKVMRuntime hv parameters programming howto:
1687 # - conf_hvp contains the parameters as configured on ganeti. they might
1688 # have changed since the instance started; only use them if the change
1689 # won't affect the inside of the instance (which hasn't been rebooted).
1690 # - up_hvp contains the parameters as they were when the instance was
1691 # started, plus any new parameter which has been added between ganeti
1692 # versions: it is paramount that those default to a value which won't
1693 # affect the inside of the instance as well.
1694 conf_hvp = instance.hvparams
1695 name = instance.name
1696 self._CheckDown(name)
1700 kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1701 # the first element of kvm_cmd is always the path to the kvm binary
1702 kvm_path = kvm_cmd[0]
1703 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1705 # We know it's safe to run as a different user upon migration, so we'll use
1706 # the latest conf, from conf_hvp.
1707 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1708 if security_model == constants.HT_SM_USER:
1709 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1711 keymap = conf_hvp[constants.HV_KEYMAP]
1713 keymap_path = self._InstanceKeymapFile(name)
1714 # If a keymap file is specified, KVM won't use its internal defaults. By
1715 # first including the "en-us" layout, an error on loading the actual
1716 # layout (e.g. because it can't be found) won't lead to a non-functional
1717 # keyboard. A keyboard with incorrect keys is still better than none.
1718 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1719 kvm_cmd.extend(["-k", keymap_path])
1721 # We have reasons to believe changing something like the nic driver/type
1722 # upon migration won't exactly fly with the instance kernel, so for nic
1723 # related parameters we'll use up_hvp
1726 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1728 kvm_cmd.extend(["-net", "none"])
1732 nic_type = up_hvp[constants.HV_NIC_TYPE]
1733 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1734 nic_model = self._VIRTIO
1736 if self._VIRTIO_NET_RE.search(devlist):
1737 nic_model = self._VIRTIO_NET_PCI
1738 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1739 except errors.HypervisorError, _:
1740 # Older versions of kvm don't support DEVICE_LIST, but they don't
1741 # have new virtio syntax either.
1744 if up_hvp[constants.HV_VHOST_NET]:
1745 # check for vhost_net support
1746 if self._VHOST_RE.search(kvmhelp):
1747 tap_extra = ",vhost=on"
1749 raise errors.HypervisorError("vhost_net is configured"
1750 " but it is not available")
1752 nic_model = nic_type
1754 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1756 for nic_seq, nic in enumerate(kvm_nics):
1757 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1758 tapfds.append(tapfd)
1759 taps.append(tapname)
1760 if kvm_supports_netdev:
1761 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1763 # kvm_nics already exist in old runtime files and thus there might
1764 # be some entries without pci slot (therefore try: except:)
1765 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1767 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1768 except errors.HotplugError:
1769 netdev = "netdev%d" % nic_seq
1770 nic_val += (",netdev=%s" % netdev)
1771 tap_val = ("type=tap,id=%s,fd=%d%s" %
1772 (netdev, tapfd, tap_extra))
1773 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1775 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1777 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1778 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1781 target, port = incoming
1782 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1784 # Changing the vnc password doesn't bother the guest that much. At most it
1785 # will surprise people who connect to it. Whether positively or negatively
1787 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1791 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1792 except EnvironmentError, err:
1793 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1794 % (vnc_pwd_file, err))
1796 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1797 utils.EnsureDirs([(self._InstanceChrootDir(name),
1798 constants.SECURE_DIR_MODE)])
1800 # Automatically enable QMP if version is >= 0.14
1801 if self._QMP_RE.search(kvmhelp):
1802 logging.debug("Enabling QMP")
1803 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1804 self._InstanceQmpMonitor(instance.name)])
1806 # Configure the network now for starting instances and bridged interfaces,
1807 # during FinalizeMigration for incoming instances' routed interfaces
1808 for nic_seq, nic in enumerate(kvm_nics):
1810 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1812 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1814 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1818 kvm_cmd.extend(bdev_opts)
1819 # CPU affinity requires kvm to start paused, so we set this flag if the
1820 # instance is not already paused and if we are not going to accept a
1821 # migrating instance. In the latter case, pausing is not needed.
1822 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1823 if start_kvm_paused:
1824 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1826 # Note: CPU pinning is using up_hvp since changes take effect
1827 # during instance startup anyway, and to avoid problems when soft
1828 # rebooting the instance.
1830 if up_hvp.get(constants.HV_CPU_MASK, None):
1833 if security_model == constants.HT_SM_POOL:
1834 ss = ssconf.SimpleStore()
1835 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1836 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1837 uid = uidpool.RequestUnusedUid(all_uids)
1839 username = pwd.getpwuid(uid.GetUid()).pw_name
1840 kvm_cmd.extend(["-runas", username])
1841 self._RunKVMCmd(name, kvm_cmd, tapfds)
1843 uidpool.ReleaseUid(uid)
1847 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1849 self._RunKVMCmd(name, kvm_cmd, tapfds)
1851 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1852 constants.RUN_DIRS_MODE)])
1853 for nic_seq, tap in enumerate(taps):
1854 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1858 change_cmd = "change vnc password %s" % vnc_pwd
1859 self._CallMonitorCommand(instance.name, change_cmd)
1861 # Setting SPICE password. We are not vulnerable to malicious passwordless
1862 # connection attempts because SPICE by default does not allow connections
1863 # if neither a password nor the "disable_ticketing" options are specified.
1864 # As soon as we send the password via QMP, that password is a valid ticket
1866 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1867 if spice_password_file:
1870 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1871 except EnvironmentError, err:
1872 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1873 % (spice_password_file, err))
1875 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1878 "protocol": "spice",
1879 "password": spice_pwd,
1881 qmp.Execute("set_password", arguments)
1883 for filename in temp_files:
1884 utils.RemoveFile(filename)
1886 # If requested, set CPU affinity and resume instance execution
1888 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1890 start_memory = self._InstanceStartupMemory(instance)
1891 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1892 self.BalloonInstanceMemory(instance, start_memory)
1894 if start_kvm_paused:
1895 # To control CPU pinning, ballooning, and vnc/spice passwords
1896 # the VM was started in a frozen state. If freezing was not
1897 # explicitly requested resume the vm status.
1898 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1900 def StartInstance(self, instance, block_devices, startup_paused):
1901 """Start an instance.
1904 self._CheckDown(instance.name)
1905 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1906 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1907 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1908 startup_paused, kvmhelp)
1909 self._SaveKVMRuntime(instance, kvm_runtime)
1910 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1912 def _CallMonitorCommand(self, instance_name, command):
1913 """Invoke a command on the instance monitor.
1916 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1917 # version. The monitor protocol is designed for human consumption, whereas
1918 # QMP is made for programmatic usage. In the worst case QMP can also
1919 # execute monitor commands. As it is, all calls to socat take at least
1920 # 500ms and likely more: socat can't detect the end of the reply and waits
1921 # for 500ms of no data received before exiting (500 ms is the default for
1922 # the "-t" parameter).
1923 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1924 (utils.ShellQuote(command),
1925 constants.SOCAT_PATH,
1926 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1927 result = utils.RunCmd(socat)
1929 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1931 (command, instance_name, result.fail_reason, result.output))
1932 raise errors.HypervisorError(msg)
1936 def _GetFreePCISlot(self, instance, dev):
1937 """Get the first available pci slot of a runnung instance.
1940 slots = bitarray(32)
1941 slots.setall(False) # pylint: disable=E1101
1942 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1943 for line in output.stdout.splitlines():
1944 match = self._INFO_PCI_RE.search(line)
1946 slot = int(match.group(1))
1949 [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1951 raise errors.HypervisorError("All PCI slots occupied")
1955 def VerifyHotplugSupport(self, instance, action, dev_type):
1956 """Check if hotplug is supported.
1958 Hotplug is *not* supported in case of:
1959 - security models and chroot (disk hotplug)
1960 - fdsend module is missing (nic hot-add)
1962 @raise errors.HypervisorError: in previous cases
1965 if dev_type == constants.HOTPLUG_TARGET_DISK:
1966 hvp = instance.hvparams
1967 security_model = hvp[constants.HV_SECURITY_MODEL]
1968 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
1970 raise errors.HotplugError("Disk hotplug is not supported"
1971 " in case of chroot.")
1972 if security_model != constants.HT_SM_NONE:
1973 raise errors.HotplugError("Disk Hotplug is not supported in case"
1974 " security models are used.")
1976 if (dev_type == constants.HOTPLUG_TARGET_NIC and
1977 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
1978 raise errors.HotplugError("Cannot hot-add NIC."
1979 " fdsend python module is missing.")
1982 def HotplugSupported(self, instance):
1983 """Checks if hotplug is generally supported.
1985 Hotplug is *not* supported in case of:
1986 - qemu versions < 1.0
1987 - for stopped instances
1989 @raise errors.HypervisorError: in one of the previous cases
1993 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1994 except errors.HypervisorError:
1995 raise errors.HotplugError("Instance is probably down")
1997 # TODO: search for netdev_add, drive_add, device_add.....
1998 match = self._INFO_VERSION_RE.search(output.stdout)
2000 raise errors.HotplugError("Cannot parse qemu version via monitor")
2002 v_major, v_min, _, _ = match.groups()
2003 if (int(v_major), int(v_min)) < (1, 0):
2004 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2006 def _CallHotplugCommand(self, name, cmd):
2007 output = self._CallMonitorCommand(name, cmd)
2008 # TODO: parse output and check if succeeded
2009 for line in output.stdout.splitlines():
2010 logging.info("%s", line)
2012 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2013 """ Helper method to hot-add a new device
2015 It gets free pci slot generates the device name and invokes the
2016 device specific method.
2019 # in case of hot-mod this is given
2020 if device.pci is None:
2021 self._GetFreePCISlot(instance, device)
2022 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2023 runtime = self._LoadKVMRuntime(instance)
2024 if dev_type == constants.HOTPLUG_TARGET_DISK:
2025 command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2027 command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2028 (hex(device.pci), kvm_devid, kvm_devid))
2029 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2030 (tap, fd) = _OpenTap()
2031 self._ConfigureNIC(instance, seq, device, tap)
2032 self._PassTapFd(instance, fd, device)
2033 command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2034 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2035 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2036 command += "device_add %s" % args
2037 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2039 self._CallHotplugCommand(instance.name, command)
2040 # update relevant entries in runtime file
2041 index = _DEVICE_RUNTIME_INDEX[dev_type]
2042 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2043 runtime[index].append(entry)
2044 self._SaveKVMRuntime(instance, runtime)
2046 def HotDelDevice(self, instance, dev_type, device, _, seq):
2047 """ Helper method for hot-del device
2049 It gets device info from runtime file, generates the device name and
2050 invokes the device specific method.
2053 runtime = self._LoadKVMRuntime(instance)
2054 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2055 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2056 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2057 if dev_type == constants.HOTPLUG_TARGET_DISK:
2058 command = "device_del %s\n" % kvm_devid
2059 command += "drive_del %s" % kvm_devid
2060 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2061 command = "device_del %s\n" % kvm_devid
2062 command += "netdev_del %s" % kvm_devid
2063 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2064 self._CallHotplugCommand(instance.name, command)
2065 index = _DEVICE_RUNTIME_INDEX[dev_type]
2066 runtime[index].remove(entry)
2067 self._SaveKVMRuntime(instance, runtime)
2069 return kvm_device.pci
2071 def HotModDevice(self, instance, dev_type, device, _, seq):
2072 """ Helper method for hot-mod device
2074 It gets device info from runtime file, generates the device name and
2075 invokes the device specific method. Currently only NICs support hot-mod
2078 if dev_type == constants.HOTPLUG_TARGET_NIC:
2079 # putting it back in the same pci slot
2080 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2081 # TODO: remove sleep when socat gets removed
2083 self.HotAddDevice(instance, dev_type, device, _, seq)
2085 def _PassTapFd(self, instance, fd, nic):
2086 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2089 # TODO: factor out code related to unix sockets.
2090 # squash common parts between monitor and qmp
2091 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2092 command = "getfd %s\n" % kvm_devid
2094 logging.info("%s", fds)
2096 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2098 fdsend.sendfds(monsock.sock, command, fds=fds)
2103 def _ParseKVMVersion(cls, text):
2104 """Parse the KVM version from the --help output.
2107 @param text: output of kvm --help
2108 @return: (version, v_maj, v_min, v_rev)
2109 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2112 match = cls._VERSION_RE.search(text.splitlines()[0])
2114 raise errors.HypervisorError("Unable to get KVM version")
2116 v_all = match.group(0)
2117 v_maj = int(match.group(1))
2118 v_min = int(match.group(2))
2120 v_rev = int(match.group(4))
2123 return (v_all, v_maj, v_min, v_rev)
2126 def _GetKVMOutput(cls, kvm_path, option):
2127 """Return the output of a kvm invocation
2129 @type kvm_path: string
2130 @param kvm_path: path to the kvm executable
2131 @type option: a key of _KVMOPTS_CMDS
2132 @param option: kvm option to fetch the output from
2133 @return: output a supported kvm invocation
2134 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2137 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2139 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2141 result = utils.RunCmd([kvm_path] + optlist)
2142 if result.failed and not can_fail:
2143 raise errors.HypervisorError("Unable to get KVM %s output" %
2144 " ".join(cls._KVMOPTS_CMDS[option]))
2145 return result.output
2148 def _GetKVMVersion(cls, kvm_path):
2149 """Return the installed KVM version.
2151 @return: (version, v_maj, v_min, v_rev)
2152 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2155 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2158 def _GetDefaultMachineVersion(cls, kvm_path):
2159 """Return the default hardware revision (e.g. pc-1.1)
2162 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2163 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2165 return match.group(1)
2169 def StopInstance(self, instance, force=False, retry=False, name=None):
2170 """Stop an instance.
2173 if name is not None and not force:
2174 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2176 name = instance.name
2177 acpi = instance.hvparams[constants.HV_ACPI]
2180 _, pid, alive = self._InstancePidAlive(name)
2181 if pid > 0 and alive:
2182 if force or not acpi:
2183 utils.KillProcess(pid)
2185 self._CallMonitorCommand(name, "system_powerdown")
2187 def CleanupInstance(self, instance_name):
2188 """Cleanup after a stopped instance
2191 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2192 if pid > 0 and alive:
2193 raise errors.HypervisorError("Cannot cleanup a live instance")
2194 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2196 def RebootInstance(self, instance):
2197 """Reboot an instance.
2200 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2201 # socket the instance will stop, but now power up again. So we'll resort
2202 # to shutdown and restart.
2203 _, _, alive = self._InstancePidAlive(instance.name)
2205 raise errors.HypervisorError("Failed to reboot instance %s:"
2206 " not running" % instance.name)
2207 # StopInstance will delete the saved KVM runtime so:
2208 # ...first load it...
2209 kvm_runtime = self._LoadKVMRuntime(instance)
2210 # ...now we can safely call StopInstance...
2211 if not self.StopInstance(instance):
2212 self.StopInstance(instance, force=True)
2213 # ...and finally we can save it again, and execute it...
2214 self._SaveKVMRuntime(instance, kvm_runtime)
2215 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2216 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2217 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2219 def MigrationInfo(self, instance):
2220 """Get instance information to perform a migration.
2222 @type instance: L{objects.Instance}
2223 @param instance: instance to be migrated
2225 @return: content of the KVM runtime file
2228 return self._ReadKVMRuntime(instance.name)
2230 def AcceptInstance(self, instance, info, target):
2231 """Prepare to accept an instance.
2233 @type instance: L{objects.Instance}
2234 @param instance: instance to be accepted
2236 @param info: content of the KVM runtime file on the source node
2237 @type target: string
2238 @param target: target host (usually ip), on this node
2241 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2242 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2243 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2244 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2245 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2246 incoming=incoming_address)
2248 def FinalizeMigrationDst(self, instance, info, success):
2249 """Finalize the instance migration on the target node.
2251 Stop the incoming mode KVM.
2253 @type instance: L{objects.Instance}
2254 @param instance: instance whose migration is being finalized
2258 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2259 kvm_nics = kvm_runtime[1]
2261 for nic_seq, nic in enumerate(kvm_nics):
2262 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2263 # Bridged interfaces have already been configured
2266 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2267 except EnvironmentError, err:
2268 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2269 instance.name, nic_seq, str(err))
2272 self._ConfigureNIC(instance, nic_seq, nic, tap)
2273 except errors.HypervisorError, err:
2274 logging.warning(str(err))
2276 self._WriteKVMRuntime(instance.name, info)
2278 self.StopInstance(instance, force=True)
2280 def MigrateInstance(self, instance, target, live):
2281 """Migrate an instance to a target node.
2283 The migration will not be attempted if the instance is not
2286 @type instance: L{objects.Instance}
2287 @param instance: the instance to be migrated
2288 @type target: string
2289 @param target: ip address of the target node
2291 @param live: perform a live migration
2294 instance_name = instance.name
2295 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2296 _, _, alive = self._InstancePidAlive(instance_name)
2298 raise errors.HypervisorError("Instance not running, cannot migrate")
2301 self._CallMonitorCommand(instance_name, "stop")
2303 migrate_command = ("migrate_set_speed %dm" %
2304 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2305 self._CallMonitorCommand(instance_name, migrate_command)
2307 migrate_command = ("migrate_set_downtime %dms" %
2308 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2309 self._CallMonitorCommand(instance_name, migrate_command)
2311 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2312 self._CallMonitorCommand(instance_name, migrate_command)
2314 def FinalizeMigrationSource(self, instance, success, live):
2315 """Finalize the instance migration on the source node.
2317 @type instance: L{objects.Instance}
2318 @param instance: the instance that was migrated
2320 @param success: whether the migration succeeded or not
2322 @param live: whether the user requested a live migration or not
2326 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2327 utils.KillProcess(pid)
2328 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2330 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2332 def GetMigrationStatus(self, instance):
2333 """Get the migration status
2335 @type instance: L{objects.Instance}
2336 @param instance: the instance that is being migrated
2337 @rtype: L{objects.MigrationStatus}
2338 @return: the status of the current migration (one of
2339 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2340 progress info that can be retrieved from the hypervisor
2343 info_command = "info migrate"
2344 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2345 result = self._CallMonitorCommand(instance.name, info_command)
2346 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2348 if not result.stdout:
2349 logging.info("KVM: empty 'info migrate' result")
2351 logging.warning("KVM: unknown 'info migrate' result: %s",
2354 status = match.group(1)
2355 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2356 migration_status = objects.MigrationStatus(status=status)
2357 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2359 migration_status.transferred_ram = match.group("transferred")
2360 migration_status.total_ram = match.group("total")
2362 return migration_status
2364 logging.warning("KVM: unknown migration status '%s'", status)
2366 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2368 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2370 def BalloonInstanceMemory(self, instance, mem):
2371 """Balloon an instance memory to a certain value.
2373 @type instance: L{objects.Instance}
2374 @param instance: instance to be accepted
2376 @param mem: actual memory size to use for instance runtime
2379 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2381 def GetNodeInfo(self):
2382 """Return information about the node.
2384 @return: a dict with the following keys (values in MiB):
2385 - memory_total: the total memory size on the node
2386 - memory_free: the available memory on the node for instances
2387 - memory_dom0: the memory used by the node itself, if available
2388 - hv_version: the hypervisor version in the form (major, minor,
2392 result = self.GetLinuxNodeInfo()
2393 # FIXME: this is the global kvm version, but the actual version can be
2394 # customized as an hv parameter. we should use the nodegroup's default kvm
2395 # path parameter here.
2396 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2397 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2401 def GetInstanceConsole(cls, instance, hvparams, beparams):
2402 """Return a command for connecting to the console of an instance.
2405 if hvparams[constants.HV_SERIAL_CONSOLE]:
2406 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2407 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2408 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2409 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2410 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2411 return objects.InstanceConsole(instance=instance.name,
2412 kind=constants.CONS_SSH,
2413 host=instance.primary_node,
2414 user=constants.SSH_CONSOLE_USER,
2417 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2418 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2419 display = instance.network_port - constants.VNC_BASE_PORT
2420 return objects.InstanceConsole(instance=instance.name,
2421 kind=constants.CONS_VNC,
2422 host=vnc_bind_address,
2423 port=instance.network_port,
2426 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2428 return objects.InstanceConsole(instance=instance.name,
2429 kind=constants.CONS_SPICE,
2431 port=instance.network_port)
2433 return objects.InstanceConsole(instance=instance.name,
2434 kind=constants.CONS_MESSAGE,
2435 message=("No serial shell for instance %s" %
2439 """Verify the hypervisor.
2441 Check that the required binaries exist.
2443 @return: Problem description if something is wrong, C{None} otherwise
2447 # FIXME: this is the global kvm binary, but the actual path can be
2448 # customized as an hv parameter; we should use the nodegroup's
2449 # default kvm path parameter here.
2450 if not os.path.exists(constants.KVM_PATH):
2451 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2452 if not os.path.exists(constants.SOCAT_PATH):
2453 msgs.append("The socat binary ('%s') does not exist" %
2454 constants.SOCAT_PATH)
2456 return self._FormatVerifyResults(msgs)
2459 def CheckParameterSyntax(cls, hvparams):
2460 """Check the given parameters for validity.
2462 @type hvparams: dict
2463 @param hvparams: dictionary with parameter names/value
2464 @raise errors.HypervisorError: when a parameter is not valid
2467 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2469 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2471 if not hvparams[constants.HV_ROOT_PATH]:
2472 raise errors.HypervisorError("Need a root partition for the instance,"
2473 " if a kernel is defined")
2475 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2476 not hvparams[constants.HV_VNC_X509]):
2477 raise errors.HypervisorError("%s must be defined, if %s is" %
2478 (constants.HV_VNC_X509,
2479 constants.HV_VNC_X509_VERIFY))
2481 if hvparams[constants.HV_SERIAL_CONSOLE]:
2482 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2483 valid_speeds = constants.VALID_SERIAL_SPEEDS
2484 if not serial_speed or serial_speed not in valid_speeds:
2485 raise errors.HypervisorError("Invalid serial console speed, must be"
2487 utils.CommaJoin(valid_speeds))
2489 boot_order = hvparams[constants.HV_BOOT_ORDER]
2490 if (boot_order == constants.HT_BO_CDROM and
2491 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2492 raise errors.HypervisorError("Cannot boot from cdrom without an"
2495 security_model = hvparams[constants.HV_SECURITY_MODEL]
2496 if security_model == constants.HT_SM_USER:
2497 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2498 raise errors.HypervisorError("A security domain (user to run kvm as)"
2499 " must be specified")
2500 elif (security_model == constants.HT_SM_NONE or
2501 security_model == constants.HT_SM_POOL):
2502 if hvparams[constants.HV_SECURITY_DOMAIN]:
2503 raise errors.HypervisorError("Cannot have a security domain when the"
2504 " security model is 'none' or 'pool'")
2506 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2507 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2509 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2510 # if an IP version is specified, the spice_bind parameter must be an
2512 if (netutils.IP4Address.IsValid(spice_bind) and
2513 spice_ip_version != constants.IP4_VERSION):
2514 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2515 " the specified IP version is %s" %
2516 (spice_bind, spice_ip_version))
2518 if (netutils.IP6Address.IsValid(spice_bind) and
2519 spice_ip_version != constants.IP6_VERSION):
2520 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2521 " the specified IP version is %s" %
2522 (spice_bind, spice_ip_version))
2524 # All the other SPICE parameters depend on spice_bind being set. Raise an
2525 # error if any of them is set without it.
2526 for param in _SPICE_ADDITIONAL_PARAMS:
2528 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2529 (param, constants.HV_KVM_SPICE_BIND))
2532 def ValidateParameters(cls, hvparams):
2533 """Check the given parameters for validity.
2535 @type hvparams: dict
2536 @param hvparams: dictionary with parameter names/value
2537 @raise errors.HypervisorError: when a parameter is not valid
2540 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2542 kvm_path = hvparams[constants.HV_KVM_PATH]
2544 security_model = hvparams[constants.HV_SECURITY_MODEL]
2545 if security_model == constants.HT_SM_USER:
2546 username = hvparams[constants.HV_SECURITY_DOMAIN]
2548 pwd.getpwnam(username)
2550 raise errors.HypervisorError("Unknown security domain user %s"
2553 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2555 # only one of VNC and SPICE can be used currently.
2556 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2557 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2558 " only one of them can be used at a"
2561 # check that KVM supports SPICE
2562 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2563 if not cls._SPICE_RE.search(kvmhelp):
2564 raise errors.HypervisorError("SPICE is configured, but it is not"
2565 " supported according to 'kvm --help'")
2567 # if spice_bind is not an IP address, it must be a valid interface
2568 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2569 netutils.IP6Address.IsValid(spice_bind))
2570 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2571 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2572 " a valid IP address or interface name" %
2573 constants.HV_KVM_SPICE_BIND)
2575 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2577 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2578 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2579 raise errors.HypervisorError("Unsupported machine version: %s" %
2583 def PowercycleNode(cls):
2584 """KVM powercycle, just a wrapper over Linux powercycle.
2587 cls.LinuxPowercycle()