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 then 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 _AnalyzeSerializedRuntime(serialized_runtime):
191 """Return runtime entries for a serialized runtime file
193 @type serialized_runtime: string
194 @param serialized_runtime: raw text data read from actual runtime file
195 @return: (cmd, nics, hvparams, bdevs)
199 loaded_runtime = serializer.Load(serialized_runtime)
200 if len(loaded_runtime) == 3:
201 serialized_blockdevs = []
202 kvm_cmd, serialized_nics, hvparams = loaded_runtime
204 kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
206 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
207 block_devices = [(objects.Disk.FromDict(sdisk), link)
208 for sdisk, link in serialized_blockdevs]
210 return (kvm_cmd, kvm_nics, hvparams, block_devices)
213 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
214 """Retrieves supported TUN features from file descriptor.
216 @see: L{_ProbeTapVnetHdr}
219 req = struct.pack("I", 0)
221 buf = _ioctl(fd, TUNGETFEATURES, req)
222 except EnvironmentError, err:
223 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
226 (flags, ) = struct.unpack("I", buf)
230 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
231 """Check whether to enable the IFF_VNET_HDR flag.
233 To do this, _all_ of the following conditions must be met:
234 1. TUNGETFEATURES ioctl() *must* be implemented
235 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
236 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
237 drivers/net/tun.c there is no way to test this until after the tap device
238 has been created using TUNSETIFF, and there is no way to change the
239 IFF_VNET_HDR flag after creating the interface, catch-22! However both
240 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
241 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
244 @param fd: the file descriptor of /dev/net/tun
247 flags = _features_fn(fd)
253 result = bool(flags & IFF_VNET_HDR)
256 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
261 def _OpenTap(vnet_hdr=True):
262 """Open a new tap device and return its file descriptor.
264 This is intended to be used by a qemu-type hypervisor together with the -net
265 tap,fd=<fd> command line parameter.
267 @type vnet_hdr: boolean
268 @param vnet_hdr: Enable the VNET Header
269 @return: (ifname, tapfd)
274 tapfd = os.open("/dev/net/tun", os.O_RDWR)
275 except EnvironmentError:
276 raise errors.HypervisorError("Failed to open /dev/net/tun")
278 flags = IFF_TAP | IFF_NO_PI
280 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
281 flags |= IFF_VNET_HDR
283 # The struct ifreq ioctl request (see netdevice(7))
284 ifr = struct.pack("16sh", "", flags)
287 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
288 except EnvironmentError, err:
289 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
292 # Get the interface name from the ioctl
293 ifname = struct.unpack("16sh", res)[0].strip("\x00")
294 return (ifname, tapfd)
298 """QEMU Messaging Protocol (QMP) message.
301 def __init__(self, data):
302 """Creates a new QMP message based on the passed data.
305 if not isinstance(data, dict):
306 raise TypeError("QmpMessage must be initialized with a dict")
310 def __getitem__(self, field_name):
311 """Get the value of the required field if present, or None.
313 Overrides the [] operator to provide access to the message data,
314 returning None if the required item is not in the message
315 @return: the value of the field_name field, or None if field_name
316 is not contained in the message
319 return self.data.get(field_name, None)
321 def __setitem__(self, field_name, field_value):
322 """Set the value of the required field_name to field_value.
325 self.data[field_name] = field_value
328 def BuildFromJsonString(json_string):
329 """Build a QmpMessage from a JSON encoded string.
331 @type json_string: str
332 @param json_string: JSON string representing the message
333 @rtype: L{QmpMessage}
334 @return: a L{QmpMessage} built from json_string
338 data = serializer.LoadJson(json_string)
339 return QmpMessage(data)
342 # The protocol expects the JSON object to be sent as a single line.
343 return serializer.DumpJson(self.data)
345 def __eq__(self, other):
346 # When comparing two QmpMessages, we are interested in comparing
347 # their internal representation of the message data
348 return self.data == other.data
351 class MonitorSocket(object):
354 def __init__(self, monitor_filename):
355 """Instantiates the MonitorSocket object.
357 @type monitor_filename: string
358 @param monitor_filename: the filename of the UNIX raw socket on which the
359 monitor (QMP or simple one) is listening
362 self.monitor_filename = monitor_filename
363 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
364 # We want to fail if the server doesn't send a complete message
365 # in a reasonable amount of time
366 self.sock.settimeout(self._SOCKET_TIMEOUT)
367 self._connected = False
369 def _check_socket(self):
372 sock_stat = os.stat(self.monitor_filename)
373 except EnvironmentError, err:
374 if err.errno == errno.ENOENT:
375 raise errors.HypervisorError("No monitor socket found")
377 raise errors.HypervisorError("Error checking monitor socket: %s",
378 utils.ErrnoOrStr(err))
379 if not stat.S_ISSOCK(sock_stat.st_mode):
380 raise errors.HypervisorError("Monitor socket is not a socket")
382 def _check_connection(self):
383 """Make sure that the connection is established.
386 if not self._connected:
387 raise errors.ProgrammerError("To use a MonitorSocket you need to first"
388 " invoke connect() on it")
391 """Connects to the monitor.
393 Connects to the UNIX socket
395 @raise errors.HypervisorError: when there are communication errors
399 raise errors.ProgrammerError("Cannot connect twice")
403 # Check file existance/stuff
405 self.sock.connect(self.monitor_filename)
406 except EnvironmentError:
407 raise errors.HypervisorError("Can't connect to qmp socket")
408 self._connected = True
413 It cannot be used after this call.
419 class QmpConnection(MonitorSocket):
420 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
423 _FIRST_MESSAGE_KEY = "QMP"
426 _RETURN_KEY = RETURN_KEY = "return"
427 _ACTUAL_KEY = ACTUAL_KEY = "actual"
428 _ERROR_CLASS_KEY = "class"
429 _ERROR_DATA_KEY = "data"
430 _ERROR_DESC_KEY = "desc"
431 _EXECUTE_KEY = "execute"
432 _ARGUMENTS_KEY = "arguments"
433 _CAPABILITIES_COMMAND = "qmp_capabilities"
434 _MESSAGE_END_TOKEN = "\r\n"
436 def __init__(self, monitor_filename):
437 super(QmpConnection, self).__init__(monitor_filename)
441 """Connects to the QMP monitor.
443 Connects to the UNIX socket and makes sure that we can actually send and
444 receive data to the kvm instance via QMP.
446 @raise errors.HypervisorError: when there are communication errors
447 @raise errors.ProgrammerError: when there are data serialization errors
450 super(QmpConnection, self).connect()
451 # Check if we receive a correct greeting message from the server
452 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
453 greeting = self._Recv()
454 if not greeting[self._FIRST_MESSAGE_KEY]:
455 self._connected = False
456 raise errors.HypervisorError("kvm: QMP communication error (wrong"
459 # Let's put the monitor in command mode using the qmp_capabilities
460 # command, or else no command will be executable.
461 # (As per the QEMU Protocol Specification 0.1 - section 4)
462 self.Execute(self._CAPABILITIES_COMMAND)
464 def _ParseMessage(self, buf):
465 """Extract and parse a QMP message from the given buffer.
467 Seeks for a QMP message in the given buf. If found, it parses it and
468 returns it together with the rest of the characters in the buf.
469 If no message is found, returns None and the whole buffer.
471 @raise errors.ProgrammerError: when there are data serialization errors
475 # Check if we got the message end token (CRLF, as per the QEMU Protocol
476 # Specification 0.1 - Section 2.1.1)
477 pos = buf.find(self._MESSAGE_END_TOKEN)
480 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
481 except Exception, err:
482 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
485 return (message, buf)
488 """Receives a message from QMP and decodes the received JSON object.
491 @return: the received message
492 @raise errors.HypervisorError: when there are communication errors
493 @raise errors.ProgrammerError: when there are data serialization errors
496 self._check_connection()
498 # Check if there is already a message in the buffer
499 (message, self._buf) = self._ParseMessage(self._buf)
503 recv_buffer = StringIO.StringIO(self._buf)
504 recv_buffer.seek(len(self._buf))
507 data = self.sock.recv(4096)
510 recv_buffer.write(data)
512 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
516 except socket.timeout, err:
517 raise errors.HypervisorError("Timeout while receiving a QMP message: "
519 except socket.error, err:
520 raise errors.HypervisorError("Unable to receive data from KVM using the"
521 " QMP protocol: %s" % err)
523 def _Send(self, message):
524 """Encodes and sends a message to KVM using QMP.
526 @type message: QmpMessage
527 @param message: message to send to KVM
528 @raise errors.HypervisorError: when there are communication errors
529 @raise errors.ProgrammerError: when there are data serialization errors
532 self._check_connection()
534 message_str = str(message)
535 except Exception, err:
536 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
539 self.sock.sendall(message_str)
540 except socket.timeout, err:
541 raise errors.HypervisorError("Timeout while sending a QMP message: "
542 "%s (%s)" % (err.string, err.errno))
543 except socket.error, err:
544 raise errors.HypervisorError("Unable to send data from KVM using the"
545 " QMP protocol: %s" % err)
547 def Execute(self, command, arguments=None):
548 """Executes a QMP command and returns the response of the server.
551 @param command: the command to execute
552 @type arguments: dict
553 @param arguments: dictionary of arguments to be passed to the command
555 @return: dictionary representing the received JSON object
556 @raise errors.HypervisorError: when there are communication errors
557 @raise errors.ProgrammerError: when there are data serialization errors
560 self._check_connection()
561 message = QmpMessage({self._EXECUTE_KEY: command})
563 message[self._ARGUMENTS_KEY] = arguments
566 # Events can occur between the sending of the command and the reception
567 # of the response, so we need to filter out messages with the event key.
569 response = self._Recv()
570 err = response[self._ERROR_KEY]
572 raise errors.HypervisorError("kvm: error executing the %s"
573 " command: %s (%s, %s):" %
575 err[self._ERROR_DESC_KEY],
576 err[self._ERROR_CLASS_KEY],
577 err[self._ERROR_DATA_KEY]))
579 elif not response[self._EVENT_KEY]:
583 class KVMHypervisor(hv_base.BaseHypervisor):
584 """KVM hypervisor interface
589 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
590 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
591 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
592 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
593 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
594 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
595 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
596 # KVM instances with chroot enabled are started in empty chroot directories.
597 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
598 # After an instance is stopped, its chroot directory is removed.
599 # If the chroot directory is not empty, it can't be removed.
600 # A non-empty chroot directory indicates a possible security incident.
601 # To support forensics, the non-empty chroot directory is quarantined in
602 # a separate directory, called 'chroot-quarantine'.
603 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
604 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
605 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
608 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
609 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
610 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
611 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
612 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
613 constants.HV_ACPI: hv_base.NO_CHECK,
614 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
615 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
616 constants.HV_VNC_BIND_ADDRESS:
617 (False, lambda x: (netutils.IP4Address.IsValid(x) or
618 utils.IsNormAbsPath(x)),
619 "The VNC bind address must be either a valid IP address or an absolute"
620 " pathname", None, None),
621 constants.HV_VNC_TLS: hv_base.NO_CHECK,
622 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
623 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
624 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
625 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
626 constants.HV_KVM_SPICE_IP_VERSION:
627 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
628 x in constants.VALID_IP_VERSIONS),
629 "The SPICE IP version should be 4 or 6",
631 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
632 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
634 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
635 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
637 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
638 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
640 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
641 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
643 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
644 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
645 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
646 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
647 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
648 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
649 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
650 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
651 constants.HV_BOOT_ORDER:
652 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
653 constants.HV_NIC_TYPE:
654 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
655 constants.HV_DISK_TYPE:
656 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
657 constants.HV_KVM_CDROM_DISK_TYPE:
658 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
659 constants.HV_USB_MOUSE:
660 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
661 constants.HV_KEYMAP: hv_base.NO_CHECK,
662 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
663 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
664 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
665 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
666 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
667 constants.HV_DISK_CACHE:
668 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
669 constants.HV_SECURITY_MODEL:
670 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
671 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
672 constants.HV_KVM_FLAG:
673 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
674 constants.HV_VHOST_NET: hv_base.NO_CHECK,
675 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
676 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
677 constants.HV_REBOOT_BEHAVIOR:
678 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
679 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
680 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
681 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
682 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
683 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
684 constants.HV_SOUNDHW: hv_base.NO_CHECK,
685 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
686 constants.HV_VGA: hv_base.NO_CHECK,
687 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
688 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
689 constants.HV_VNET_HDR: hv_base.NO_CHECK,
693 _VIRTIO_NET_PCI = "virtio-net-pci"
694 _VIRTIO_BLK_PCI = "virtio-blk-pci"
696 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
698 _MIGRATION_PROGRESS_RE = \
699 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
700 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
701 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
703 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
704 _MIGRATION_INFO_RETRY_DELAY = 2
706 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
708 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
709 _CPU_INFO_CMD = "info cpus"
712 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
713 _CHECK_MACHINE_VERSION_RE = \
714 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
716 _QMP_RE = re.compile(r"^-qmp\s", re.M)
717 _SPICE_RE = re.compile(r"^-spice\s", re.M)
718 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
719 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
720 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
721 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
722 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
723 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
724 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
725 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
726 # match -drive.*boot=on|off on different lines, but in between accept only
727 # dashes not preceeded by a new line (which would mean another option
728 # different than -drive is starting)
729 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
731 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
732 _INFO_PCI_CMD = "info pci"
734 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
735 _INFO_VERSION_CMD = "info version"
737 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
742 ANCILLARY_FILES_OPT = [
746 # Supported kvm options to get output from
747 _KVMOPT_HELP = "help"
748 _KVMOPT_MLIST = "mlist"
749 _KVMOPT_DEVICELIST = "devicelist"
751 # Command to execute to get the output from kvm, and whether to
752 # accept the output even on failure.
754 _KVMOPT_HELP: (["--help"], False),
755 _KVMOPT_MLIST: (["-M", "?"], False),
756 _KVMOPT_DEVICELIST: (["-device", "?"], True),
760 hv_base.BaseHypervisor.__init__(self)
761 # Let's make sure the directories we need exist, even if the RUN_DIR lives
762 # in a tmpfs filesystem or has been otherwise wiped out.
763 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
764 utils.EnsureDirs(dirs)
767 def _InstancePidFile(cls, instance_name):
768 """Returns the instance pidfile.
771 return utils.PathJoin(cls._PIDS_DIR, instance_name)
774 def _InstanceUidFile(cls, instance_name):
775 """Returns the instance uidfile.
778 return utils.PathJoin(cls._UIDS_DIR, instance_name)
781 def _InstancePidInfo(cls, pid):
782 """Check pid file for instance information.
784 Check that a pid file is associated with an instance, and retrieve
785 information from its command line.
787 @type pid: string or int
788 @param pid: process id of the instance to check
790 @return: (instance_name, memory, vcpus)
791 @raise errors.HypervisorError: when an instance cannot be found
794 alive = utils.IsProcessAlive(pid)
796 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
798 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
800 cmdline = utils.ReadFile(cmdline_file)
801 except EnvironmentError, err:
802 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
809 arg_list = cmdline.split("\x00")
811 arg = arg_list.pop(0)
813 instance = arg_list.pop(0)
815 memory = int(arg_list.pop(0))
817 vcpus = int(arg_list.pop(0).split(",")[0])
820 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
823 return (instance, memory, vcpus)
825 def _InstancePidAlive(self, instance_name):
826 """Returns the instance pidfile, pid, and liveness.
828 @type instance_name: string
829 @param instance_name: instance name
831 @return: (pid file name, pid, liveness)
834 pidfile = self._InstancePidFile(instance_name)
835 pid = utils.ReadPidFile(pidfile)
839 cmd_instance = self._InstancePidInfo(pid)[0]
840 alive = (cmd_instance == instance_name)
841 except errors.HypervisorError:
844 return (pidfile, pid, alive)
846 def _CheckDown(self, instance_name):
847 """Raises an error unless the given instance is down.
850 alive = self._InstancePidAlive(instance_name)[2]
852 raise errors.HypervisorError("Failed to start instance %s: %s" %
853 (instance_name, "already running"))
856 def _InstanceMonitor(cls, instance_name):
857 """Returns the instance monitor socket name
860 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
863 def _InstanceSerial(cls, instance_name):
864 """Returns the instance serial socket name
867 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
870 def _InstanceQmpMonitor(cls, instance_name):
871 """Returns the instance serial QMP socket name
874 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
877 def _SocatUnixConsoleParams():
878 """Returns the correct parameters for socat
880 If we have a new-enough socat we can use raw mode with an escape character.
883 if constants.SOCAT_USE_ESCAPE:
884 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
886 return "echo=0,icanon=0"
889 def _InstanceKVMRuntime(cls, instance_name):
890 """Returns the instance KVM runtime filename
893 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
896 def _InstanceChrootDir(cls, instance_name):
897 """Returns the name of the KVM chroot dir of the instance
900 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
903 def _InstanceNICDir(cls, instance_name):
904 """Returns the name of the directory holding the tap device files for a
908 return utils.PathJoin(cls._NICS_DIR, instance_name)
911 def _InstanceNICFile(cls, instance_name, seq):
912 """Returns the name of the file containing the tap device for a given NIC
915 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
918 def _InstanceKeymapFile(cls, instance_name):
919 """Returns the name of the file containing the keymap for a given instance
922 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
925 def _TryReadUidFile(cls, uid_file):
926 """Try to read a uid file
929 if os.path.exists(uid_file):
931 uid = int(utils.ReadOneLineFile(uid_file))
933 except EnvironmentError:
934 logging.warning("Can't read uid file", exc_info=True)
935 except (TypeError, ValueError):
936 logging.warning("Can't parse uid file contents", exc_info=True)
940 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
941 """Removes an instance's rutime sockets/files/dirs.
944 utils.RemoveFile(pidfile)
945 utils.RemoveFile(cls._InstanceMonitor(instance_name))
946 utils.RemoveFile(cls._InstanceSerial(instance_name))
947 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
948 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
949 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
950 uid_file = cls._InstanceUidFile(instance_name)
951 uid = cls._TryReadUidFile(uid_file)
952 utils.RemoveFile(uid_file)
954 uidpool.ReleaseUid(uid)
956 shutil.rmtree(cls._InstanceNICDir(instance_name))
958 if err.errno != errno.ENOENT:
961 chroot_dir = cls._InstanceChrootDir(instance_name)
962 utils.RemoveDir(chroot_dir)
964 if err.errno == errno.ENOTEMPTY:
965 # The chroot directory is expected to be empty, but it isn't.
966 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
969 utils.TimestampForFilename()))
970 logging.warning("The chroot directory of instance %s can not be"
971 " removed as it is not empty. Moving it to the"
972 " quarantine instead. Please investigate the"
973 " contents (%s) and clean up manually",
974 instance_name, new_chroot_dir)
975 utils.RenameFile(chroot_dir, new_chroot_dir)
980 def _ConfigureNIC(instance, seq, nic, tap):
981 """Run the network configuration script for a specified NIC
983 @param instance: instance we're acting on
984 @type instance: instance object
985 @param seq: nic sequence number
987 @param nic: nic we're acting on
988 @type nic: nic object
989 @param tap: the host's tap interface this NIC corresponds to
994 tags = " ".join(instance.tags)
999 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1000 "INSTANCE": instance.name,
1002 "MODE": nic.nicparams[constants.NIC_MODE],
1004 "INTERFACE_INDEX": str(seq),
1011 if nic.nicparams[constants.NIC_LINK]:
1012 env["LINK"] = nic.nicparams[constants.NIC_LINK]
1015 n = objects.Network.FromDict(nic.netinfo)
1016 env.update(n.HooksDict())
1018 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1019 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1021 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1023 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1024 " network configuration script output: %s" %
1025 (tap, result.fail_reason, result.output))
1028 def _VerifyAffinityPackage():
1029 if affinity is None:
1030 raise errors.HypervisorError("affinity Python package not"
1031 " found; cannot use CPU pinning under KVM")
1034 def _BuildAffinityCpuMask(cpu_list):
1035 """Create a CPU mask suitable for sched_setaffinity from a list of
1038 See man taskset for more info on sched_setaffinity masks.
1039 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1041 @type cpu_list: list of int
1042 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1044 @return: a bit mask of CPU affinities
1047 if cpu_list == constants.CPU_PINNING_OFF:
1048 return constants.CPU_PINNING_ALL_KVM
1050 return sum(2 ** cpu for cpu in cpu_list)
1053 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1054 """Change CPU affinity for running VM according to given CPU mask.
1056 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1057 @type cpu_mask: string
1058 @param process_id: process ID of KVM process. Used to pin entire VM
1060 @type process_id: int
1061 @param thread_dict: map of virtual CPUs to KVM thread IDs
1062 @type thread_dict: dict int:int
1065 # Convert the string CPU mask to a list of list of int's
1066 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1068 if len(cpu_list) == 1:
1069 all_cpu_mapping = cpu_list[0]
1070 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1071 # If CPU pinning has 1 entry that's "all", then do nothing
1074 # If CPU pinning has one non-all entry, map the entire VM to
1075 # one set of physical CPUs
1076 cls._VerifyAffinityPackage()
1077 affinity.set_process_affinity_mask(
1078 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1080 # The number of vCPUs mapped should match the number of vCPUs
1081 # reported by KVM. This was already verified earlier, so
1082 # here only as a sanity check.
1083 assert len(thread_dict) == len(cpu_list)
1084 cls._VerifyAffinityPackage()
1086 # For each vCPU, map it to the proper list of physical CPUs
1087 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1088 affinity.set_process_affinity_mask(thread_dict[i],
1089 cls._BuildAffinityCpuMask(vcpu))
1091 def _GetVcpuThreadIds(self, instance_name):
1092 """Get a mapping of vCPU no. to thread IDs for the instance
1094 @type instance_name: string
1095 @param instance_name: instance in question
1096 @rtype: dictionary of int:int
1097 @return: a dictionary mapping vCPU numbers to thread IDs
1101 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1102 for line in output.stdout.splitlines():
1103 match = self._CPU_INFO_RE.search(line)
1106 grp = map(int, match.groups())
1107 result[grp[0]] = grp[1]
1111 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1112 """Complete CPU pinning.
1114 @type instance_name: string
1115 @param instance_name: name of instance
1116 @type cpu_mask: string
1117 @param cpu_mask: CPU pinning mask as entered by user
1120 # Get KVM process ID, to be used if need to pin entire VM
1121 _, pid, _ = self._InstancePidAlive(instance_name)
1122 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1123 thread_dict = self._GetVcpuThreadIds(instance_name)
1124 # Run CPU pinning, based on configured mask
1125 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1127 def ListInstances(self):
1128 """Get the list of running instances.
1130 We can do this by listing our live instances directory and
1131 checking whether the associated kvm process is still alive.
1135 for name in os.listdir(self._PIDS_DIR):
1136 if self._InstancePidAlive(name)[2]:
1140 def GetInstanceInfo(self, instance_name):
1141 """Get instance properties.
1143 @type instance_name: string
1144 @param instance_name: the instance name
1145 @rtype: tuple of strings
1146 @return: (name, id, memory, vcpus, stat, times)
1149 _, pid, alive = self._InstancePidAlive(instance_name)
1153 _, memory, vcpus = self._InstancePidInfo(pid)
1158 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1160 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1161 # Will fail if ballooning is not enabled, but we can then just resort to
1163 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1164 memory = mem_bytes / 1048576
1165 except errors.HypervisorError:
1168 return (instance_name, pid, memory, vcpus, istat, times)
1170 def GetAllInstancesInfo(self):
1171 """Get properties of all instances.
1173 @return: list of tuples (name, id, memory, vcpus, stat, times)
1177 for name in os.listdir(self._PIDS_DIR):
1179 info = self.GetInstanceInfo(name)
1180 except errors.HypervisorError:
1181 # Ignore exceptions due to instances being shut down
1187 def _GenerateKVMBlockDevicesOptions(self, instance, block_devices, kvmhelp):
1189 hvp = instance.hvparams
1190 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1191 kvm_path = hvp[constants.HV_KVM_PATH]
1193 # whether this is an older KVM version that uses the boot=on flag
1195 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1198 device_driver = None
1199 disk_type = hvp[constants.HV_DISK_TYPE]
1200 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1201 if_val = ",if=%s" % self._VIRTIO
1203 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1204 if self._VIRTIO_BLK_RE.search(devlist):
1206 # will be passed in -device option as driver
1207 device_driver = self._VIRTIO_BLK_PCI
1208 except errors.HypervisorError, _:
1211 if_val = ",if=%s" % disk_type
1213 disk_cache = hvp[constants.HV_DISK_CACHE]
1214 if instance.disk_template in constants.DTS_EXT_MIRROR:
1215 if disk_cache != "none":
1216 # TODO: make this a hard error, instead of a silent overwrite
1217 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1218 " to prevent shared storage corruption on migration",
1220 cache_val = ",cache=none"
1221 elif disk_cache != constants.HT_CACHE_DEFAULT:
1222 cache_val = ",cache=%s" % disk_cache
1225 for cfdev, dev_path in block_devices:
1226 if cfdev.mode != constants.DISK_RDWR:
1227 raise errors.HypervisorError("Instance has read-only disks which"
1228 " are not supported by KVM")
1229 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1232 dev_opts.extend(["-boot", "c"])
1234 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1235 boot_val = ",boot=on"
1236 drive_val = "file=%s,format=raw%s%s%s" % \
1237 (dev_path, if_val, boot_val, cache_val)
1240 # block_devices are the 4th entry of runtime file that did not exist in
1241 # the past. That means that cfdev should always have pci slot and
1242 # _GenerateDeviceKVMId() will not raise a exception.
1243 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1244 drive_val += (",id=%s" % kvm_devid)
1245 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1246 dev_val = ("%s,drive=%s,id=%s" %
1247 (device_driver, kvm_devid, kvm_devid))
1248 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1249 dev_opts.extend(["-device", dev_val])
1251 dev_opts.extend(["-drive", drive_val])
1255 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1257 """Generate KVM information to start an instance.
1259 @type kvmhelp: string
1260 @param kvmhelp: output of kvm --help
1261 @attention: this function must not have any side-effects; for
1262 example, it must not write to the filesystem, or read values
1263 from the current system the are expected to differ between
1264 nodes, since it is only run once at instance startup;
1265 actions/kvm arguments that can vary between systems should be
1266 done in L{_ExecuteKVMRuntime}
1269 # pylint: disable=R0912,R0914,R0915
1270 hvp = instance.hvparams
1271 self.ValidateParameters(hvp)
1273 pidfile = self._InstancePidFile(instance.name)
1274 kvm = hvp[constants.HV_KVM_PATH]
1276 # used just by the vnc server, if enabled
1277 kvm_cmd.extend(["-name", instance.name])
1278 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1280 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1281 if hvp[constants.HV_CPU_CORES]:
1282 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1283 if hvp[constants.HV_CPU_THREADS]:
1284 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1285 if hvp[constants.HV_CPU_SOCKETS]:
1286 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1288 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1290 kvm_cmd.extend(["-pidfile", pidfile])
1291 kvm_cmd.extend(["-balloon", "virtio"])
1292 kvm_cmd.extend(["-daemonize"])
1293 if not instance.hvparams[constants.HV_ACPI]:
1294 kvm_cmd.extend(["-no-acpi"])
1295 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1296 constants.INSTANCE_REBOOT_EXIT:
1297 kvm_cmd.extend(["-no-reboot"])
1299 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1301 mversion = self._GetDefaultMachineVersion(kvm)
1302 if self._MACHINE_RE.search(kvmhelp):
1303 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1304 # extra hypervisor parameters. We should also investigate whether and how
1305 # shadow_mem should be considered for the resource model.
1306 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1307 specprop = ",accel=kvm"
1310 machinespec = "%s%s" % (mversion, specprop)
1311 kvm_cmd.extend(["-machine", machinespec])
1313 kvm_cmd.extend(["-M", mversion])
1314 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1315 self._ENABLE_KVM_RE.search(kvmhelp)):
1316 kvm_cmd.extend(["-enable-kvm"])
1317 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1318 self._DISABLE_KVM_RE.search(kvmhelp)):
1319 kvm_cmd.extend(["-disable-kvm"])
1321 kernel_path = hvp[constants.HV_KERNEL_PATH]
1323 boot_cdrom = boot_floppy = boot_network = False
1325 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1326 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1327 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1330 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1333 kvm_cmd.extend(["-boot", "n"])
1335 # whether this is an older KVM version that uses the boot=on flag
1337 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1339 disk_type = hvp[constants.HV_DISK_TYPE]
1341 #Now we can specify a different device type for CDROM devices.
1342 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1343 if not cdrom_disk_type:
1344 cdrom_disk_type = disk_type
1346 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1348 options = ",format=raw,media=cdrom"
1349 # set cdrom 'if' type
1351 actual_cdrom_type = constants.HT_DISK_IDE
1352 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1353 actual_cdrom_type = "virtio"
1355 actual_cdrom_type = cdrom_disk_type
1356 if_val = ",if=%s" % actual_cdrom_type
1357 # set boot flag, if needed
1360 kvm_cmd.extend(["-boot", "d"])
1362 boot_val = ",boot=on"
1363 # and finally build the entire '-drive' value
1364 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1365 kvm_cmd.extend(["-drive", drive_val])
1367 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1369 options = ",format=raw,media=cdrom"
1370 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1371 if_val = ",if=virtio"
1373 if_val = ",if=%s" % cdrom_disk_type
1374 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1375 kvm_cmd.extend(["-drive", drive_val])
1377 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1379 options = ",format=raw,media=disk"
1381 kvm_cmd.extend(["-boot", "a"])
1382 options = "%s,boot=on" % options
1383 if_val = ",if=floppy"
1384 options = "%s%s" % (options, if_val)
1385 drive_val = "file=%s%s" % (floppy_image, options)
1386 kvm_cmd.extend(["-drive", drive_val])
1389 kvm_cmd.extend(["-kernel", kernel_path])
1390 initrd_path = hvp[constants.HV_INITRD_PATH]
1392 kvm_cmd.extend(["-initrd", initrd_path])
1393 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1394 hvp[constants.HV_KERNEL_ARGS]]
1395 if hvp[constants.HV_SERIAL_CONSOLE]:
1396 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1397 root_append.append("console=ttyS0,%s" % serial_speed)
1398 kvm_cmd.extend(["-append", " ".join(root_append)])
1400 mem_path = hvp[constants.HV_MEM_PATH]
1402 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1404 monitor_dev = ("unix:%s,server,nowait" %
1405 self._InstanceMonitor(instance.name))
1406 kvm_cmd.extend(["-monitor", monitor_dev])
1407 if hvp[constants.HV_SERIAL_CONSOLE]:
1408 serial_dev = ("unix:%s,server,nowait" %
1409 self._InstanceSerial(instance.name))
1410 kvm_cmd.extend(["-serial", serial_dev])
1412 kvm_cmd.extend(["-serial", "none"])
1414 mouse_type = hvp[constants.HV_USB_MOUSE]
1415 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1416 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1417 spice_ip_version = None
1419 kvm_cmd.extend(["-usb"])
1422 kvm_cmd.extend(["-usbdevice", mouse_type])
1423 elif vnc_bind_address:
1424 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1426 if vnc_bind_address:
1427 if netutils.IP4Address.IsValid(vnc_bind_address):
1428 if instance.network_port > constants.VNC_BASE_PORT:
1429 display = instance.network_port - constants.VNC_BASE_PORT
1430 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1431 vnc_arg = ":%d" % (display)
1433 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1435 logging.error("Network port is not a valid VNC display (%d < %d),"
1436 " not starting VNC",
1437 instance.network_port, constants.VNC_BASE_PORT)
1440 # Only allow tls and other option when not binding to a file, for now.
1441 # kvm/qemu gets confused otherwise about the filename to use.
1443 if hvp[constants.HV_VNC_TLS]:
1444 vnc_append = "%s,tls" % vnc_append
1445 if hvp[constants.HV_VNC_X509_VERIFY]:
1446 vnc_append = "%s,x509verify=%s" % (vnc_append,
1447 hvp[constants.HV_VNC_X509])
1448 elif hvp[constants.HV_VNC_X509]:
1449 vnc_append = "%s,x509=%s" % (vnc_append,
1450 hvp[constants.HV_VNC_X509])
1451 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1452 vnc_append = "%s,password" % vnc_append
1454 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1457 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1459 kvm_cmd.extend(["-vnc", vnc_arg])
1461 # FIXME: this is wrong here; the iface ip address differs
1462 # between systems, so it should be done in _ExecuteKVMRuntime
1463 if netutils.IsValidInterface(spice_bind):
1464 # The user specified a network interface, we have to figure out the IP
1466 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1467 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1469 # if the user specified an IP version and the interface does not
1470 # have that kind of IP addresses, throw an exception
1471 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1472 if not addresses[spice_ip_version]:
1473 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1474 " for %s" % (spice_ip_version,
1477 # the user did not specify an IP version, we have to figure it out
1478 elif (addresses[constants.IP4_VERSION] and
1479 addresses[constants.IP6_VERSION]):
1480 # we have both ipv4 and ipv6, let's use the cluster default IP
1482 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1483 spice_ip_version = \
1484 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1485 elif addresses[constants.IP4_VERSION]:
1486 spice_ip_version = constants.IP4_VERSION
1487 elif addresses[constants.IP6_VERSION]:
1488 spice_ip_version = constants.IP6_VERSION
1490 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1491 " for %s" % (spice_bind))
1493 spice_address = addresses[spice_ip_version][0]
1496 # spice_bind is known to be a valid IP address, because
1497 # ValidateParameters checked it.
1498 spice_address = spice_bind
1500 spice_arg = "addr=%s" % spice_address
1501 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1502 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1503 (spice_arg, instance.network_port,
1504 pathutils.SPICE_CACERT_FILE))
1505 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1506 (spice_arg, pathutils.SPICE_CERT_FILE,
1507 pathutils.SPICE_CERT_FILE))
1508 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1510 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1512 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1514 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1515 spice_arg = "%s,disable-ticketing" % spice_arg
1517 if spice_ip_version:
1518 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1520 # Image compression options
1521 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1522 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1523 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1525 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1527 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1529 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1531 # Video stream detection
1532 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1534 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1536 # Audio compression, by default in qemu-kvm it is on
1537 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1538 spice_arg = "%s,playback-compression=off" % spice_arg
1539 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1540 spice_arg = "%s,agent-mouse=off" % spice_arg
1542 # Enable the spice agent communication channel between the host and the
1544 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1547 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1549 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1551 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1552 kvm_cmd.extend(["-spice", spice_arg])
1555 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1556 # also works in earlier versions though (tested with 1.1 and 1.3)
1557 if self._DISPLAY_RE.search(kvmhelp):
1558 kvm_cmd.extend(["-display", "none"])
1560 kvm_cmd.extend(["-nographic"])
1562 if hvp[constants.HV_USE_LOCALTIME]:
1563 kvm_cmd.extend(["-localtime"])
1565 if hvp[constants.HV_KVM_USE_CHROOT]:
1566 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1568 # Add qemu-KVM -cpu param
1569 if hvp[constants.HV_CPU_TYPE]:
1570 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1572 # As requested by music lovers
1573 if hvp[constants.HV_SOUNDHW]:
1574 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1576 # Pass a -vga option if requested, or if spice is used, for backwards
1578 if hvp[constants.HV_VGA]:
1579 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1581 kvm_cmd.extend(["-vga", "qxl"])
1583 # Various types of usb devices, comma separated
1584 if hvp[constants.HV_USB_DEVICES]:
1585 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1586 kvm_cmd.extend(["-usbdevice", dev])
1588 if hvp[constants.HV_KVM_EXTRA]:
1589 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1591 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1593 for disk, link_name in block_devices:
1594 _UpdatePCISlots(disk, pci_reservations)
1595 kvm_disks.append((disk, link_name))
1598 for nic in instance.nics:
1599 _UpdatePCISlots(nic, pci_reservations)
1600 kvm_nics.append(nic)
1604 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1606 def _WriteKVMRuntime(self, instance_name, data):
1607 """Write an instance's KVM runtime
1611 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1613 except EnvironmentError, err:
1614 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1616 def _ReadKVMRuntime(self, instance_name):
1617 """Read an instance's KVM runtime
1621 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1622 except EnvironmentError, err:
1623 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1626 def _SaveKVMRuntime(self, instance, kvm_runtime):
1627 """Save an instance's KVM runtime
1630 kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1632 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1633 serialized_blockdevs = [(blk.ToDict(), link)
1634 for blk, link in block_devices]
1635 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1636 serialized_blockdevs))
1638 self._WriteKVMRuntime(instance.name, serialized_form)
1640 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1641 """Load an instance's KVM runtime
1644 if not serialized_runtime:
1645 serialized_runtime = self._ReadKVMRuntime(instance.name)
1647 return _AnalyzeSerializedRuntime(serialized_runtime)
1649 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1650 """Run the KVM cmd and check for errors
1653 @param name: instance name
1654 @type kvm_cmd: list of strings
1655 @param kvm_cmd: runcmd input for kvm
1656 @type tap_fds: list of int
1657 @param tap_fds: fds of tap devices opened by Ganeti
1661 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1664 utils_wrapper.CloseFdNoError(fd)
1667 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1668 (name, result.fail_reason, result.output))
1669 if not self._InstancePidAlive(name)[2]:
1670 raise errors.HypervisorError("Failed to start instance %s" % name)
1672 # 52/50 local variables
1673 # pylint: disable=R0914
1674 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1675 """Execute a KVM cmd, after completing it with some last minute data.
1677 @type incoming: tuple of strings
1678 @param incoming: (target_host_ip, port)
1679 @type kvmhelp: string
1680 @param kvmhelp: output of kvm --help
1683 # Small _ExecuteKVMRuntime hv parameters programming howto:
1684 # - conf_hvp contains the parameters as configured on ganeti. they might
1685 # have changed since the instance started; only use them if the change
1686 # won't affect the inside of the instance (which hasn't been rebooted).
1687 # - up_hvp contains the parameters as they were when the instance was
1688 # started, plus any new parameter which has been added between ganeti
1689 # versions: it is paramount that those default to a value which won't
1690 # affect the inside of the instance as well.
1691 conf_hvp = instance.hvparams
1692 name = instance.name
1693 self._CheckDown(name)
1697 kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1698 # the first element of kvm_cmd is always the path to the kvm binary
1699 kvm_path = kvm_cmd[0]
1700 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1702 # We know it's safe to run as a different user upon migration, so we'll use
1703 # the latest conf, from conf_hvp.
1704 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1705 if security_model == constants.HT_SM_USER:
1706 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1708 keymap = conf_hvp[constants.HV_KEYMAP]
1710 keymap_path = self._InstanceKeymapFile(name)
1711 # If a keymap file is specified, KVM won't use its internal defaults. By
1712 # first including the "en-us" layout, an error on loading the actual
1713 # layout (e.g. because it can't be found) won't lead to a non-functional
1714 # keyboard. A keyboard with incorrect keys is still better than none.
1715 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1716 kvm_cmd.extend(["-k", keymap_path])
1718 # We have reasons to believe changing something like the nic driver/type
1719 # upon migration won't exactly fly with the instance kernel, so for nic
1720 # related parameters we'll use up_hvp
1724 kvm_cmd.extend(["-net", "none"])
1728 nic_type = up_hvp[constants.HV_NIC_TYPE]
1729 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1730 nic_model = self._VIRTIO
1732 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1733 if self._VIRTIO_NET_RE.search(devlist):
1734 nic_model = self._VIRTIO_NET_PCI
1735 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1736 except errors.HypervisorError, _:
1737 # Older versions of kvm don't support DEVICE_LIST, but they don't
1738 # have new virtio syntax either.
1741 if up_hvp[constants.HV_VHOST_NET]:
1742 # check for vhost_net support
1743 if self._VHOST_RE.search(kvmhelp):
1744 tap_extra = ",vhost=on"
1746 raise errors.HypervisorError("vhost_net is configured"
1747 " but it is not available")
1749 nic_model = nic_type
1751 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1753 for nic_seq, nic in enumerate(kvm_nics):
1754 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1755 tapfds.append(tapfd)
1756 taps.append(tapname)
1757 if kvm_supports_netdev:
1758 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1760 # kvm_nics already exist in old runtime files and thus there might
1761 # be some entries without pci slot (therefore try: except:)
1762 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1764 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1765 except errors.HotplugError:
1766 netdev = "netdev%d" % nic_seq
1767 nic_val += (",netdev=%s" % netdev)
1768 tap_val = ("type=tap,id=%s,fd=%d%s" %
1769 (netdev, tapfd, tap_extra))
1770 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1772 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1774 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1775 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1778 target, port = incoming
1779 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1781 # Changing the vnc password doesn't bother the guest that much. At most it
1782 # will surprise people who connect to it. Whether positively or negatively
1784 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1788 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1789 except EnvironmentError, err:
1790 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1791 % (vnc_pwd_file, err))
1793 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1794 utils.EnsureDirs([(self._InstanceChrootDir(name),
1795 constants.SECURE_DIR_MODE)])
1797 # Automatically enable QMP if version is >= 0.14
1798 if self._QMP_RE.search(kvmhelp):
1799 logging.debug("Enabling QMP")
1800 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1801 self._InstanceQmpMonitor(instance.name)])
1803 # Configure the network now for starting instances and bridged interfaces,
1804 # during FinalizeMigration for incoming instances' routed interfaces
1805 for nic_seq, nic in enumerate(kvm_nics):
1807 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1809 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1811 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1814 kvm_cmd.extend(bdev_opts)
1815 # CPU affinity requires kvm to start paused, so we set this flag if the
1816 # instance is not already paused and if we are not going to accept a
1817 # migrating instance. In the latter case, pausing is not needed.
1818 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1819 if start_kvm_paused:
1820 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1822 # Note: CPU pinning is using up_hvp since changes take effect
1823 # during instance startup anyway, and to avoid problems when soft
1824 # rebooting the instance.
1826 if up_hvp.get(constants.HV_CPU_MASK, None):
1829 if security_model == constants.HT_SM_POOL:
1830 ss = ssconf.SimpleStore()
1831 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1832 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1833 uid = uidpool.RequestUnusedUid(all_uids)
1835 username = pwd.getpwuid(uid.GetUid()).pw_name
1836 kvm_cmd.extend(["-runas", username])
1837 self._RunKVMCmd(name, kvm_cmd, tapfds)
1839 uidpool.ReleaseUid(uid)
1843 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1845 self._RunKVMCmd(name, kvm_cmd, tapfds)
1847 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1848 constants.RUN_DIRS_MODE)])
1849 for nic_seq, tap in enumerate(taps):
1850 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1854 change_cmd = "change vnc password %s" % vnc_pwd
1855 self._CallMonitorCommand(instance.name, change_cmd)
1857 # Setting SPICE password. We are not vulnerable to malicious passwordless
1858 # connection attempts because SPICE by default does not allow connections
1859 # if neither a password nor the "disable_ticketing" options are specified.
1860 # As soon as we send the password via QMP, that password is a valid ticket
1862 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1863 if spice_password_file:
1866 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1867 except EnvironmentError, err:
1868 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1869 % (spice_password_file, err))
1871 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1874 "protocol": "spice",
1875 "password": spice_pwd,
1877 qmp.Execute("set_password", arguments)
1879 for filename in temp_files:
1880 utils.RemoveFile(filename)
1882 # If requested, set CPU affinity and resume instance execution
1884 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1886 start_memory = self._InstanceStartupMemory(instance)
1887 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1888 self.BalloonInstanceMemory(instance, start_memory)
1890 if start_kvm_paused:
1891 # To control CPU pinning, ballooning, and vnc/spice passwords
1892 # the VM was started in a frozen state. If freezing was not
1893 # explicitly requested resume the vm status.
1894 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1896 def StartInstance(self, instance, block_devices, startup_paused):
1897 """Start an instance.
1900 self._CheckDown(instance.name)
1901 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1902 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1903 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1904 startup_paused, kvmhelp)
1905 self._SaveKVMRuntime(instance, kvm_runtime)
1906 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1908 def _CallMonitorCommand(self, instance_name, command, timeout=None):
1909 """Invoke a command on the instance monitor.
1912 if timeout is not None:
1913 timeout_cmd = "timeout %s" % (timeout, )
1917 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1918 # version. The monitor protocol is designed for human consumption, whereas
1919 # QMP is made for programmatic usage. In the worst case QMP can also
1920 # execute monitor commands. As it is, all calls to socat take at least
1921 # 500ms and likely more: socat can't detect the end of the reply and waits
1922 # for 500ms of no data received before exiting (500 ms is the default for
1923 # the "-t" parameter).
1924 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1925 (utils.ShellQuote(command),
1927 constants.SOCAT_PATH,
1928 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1930 result = utils.RunCmd(socat)
1932 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1934 (command, instance_name, result.fail_reason, result.output))
1935 raise errors.HypervisorError(msg)
1939 def _GetFreePCISlot(self, instance, dev):
1940 """Get the first available pci slot of a runnung instance.
1943 slots = bitarray(32)
1944 slots.setall(False) # pylint: disable=E1101
1945 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1946 for line in output.stdout.splitlines():
1947 match = self._INFO_PCI_RE.search(line)
1949 slot = int(match.group(1))
1952 [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1954 raise errors.HypervisorError("All PCI slots occupied")
1958 def HotplugSupported(self, instance, action, dev_type):
1959 """Check if hotplug is supported.
1961 Hotplug is *not* supported in case of:
1962 - qemu versions < 1.0
1963 - security models and chroot (disk hotplug)
1964 - fdsend module is missing (nic hot-add)
1966 @raise errors.HypervisorError: in previous cases
1969 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
1970 # TODO: search for netdev_add, drive_add, device_add.....
1971 match = self._INFO_VERSION_RE.search(output.stdout)
1973 raise errors.HotplugError("Try hotplug only in running instances.")
1974 v_major, v_min, _, _ = match.groups()
1975 if (int(v_major), int(v_min)) < (1, 0):
1976 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
1978 if dev_type == constants.HOTPLUG_TARGET_DISK:
1979 hvp = instance.hvparams
1980 security_model = hvp[constants.HV_SECURITY_MODEL]
1981 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
1983 raise errors.HotplugError("Disk hotplug is not supported"
1984 " in case of chroot.")
1985 if security_model != constants.HT_SM_NONE:
1986 raise errors.HotplugError("Disk Hotplug is not supported in case"
1987 " security models are used.")
1989 if (dev_type == constants.HOTPLUG_TARGET_NIC and
1990 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
1991 raise errors.HotplugError("Cannot hot-add NIC."
1992 " fdsend python module is missing.")
1995 def _CallHotplugCommand(self, name, cmd):
1996 output = self._CallMonitorCommand(name, cmd)
1997 # TODO: parse output and check if succeeded
1998 for line in output.stdout.splitlines():
1999 logging.info("%s", line)
2001 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2002 """ Helper method to hot-add a new device
2004 It gets free pci slot generates the device name and invokes the
2005 device specific method.
2008 # in case of hot-mod this is given
2009 if device.pci is None:
2010 self._GetFreePCISlot(instance, device)
2011 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2012 runtime = self._LoadKVMRuntime(instance)
2013 if dev_type == constants.HOTPLUG_TARGET_DISK:
2014 command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2016 command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2017 (hex(device.pci), kvm_devid, kvm_devid))
2018 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2019 (tap, fd) = _OpenTap()
2020 self._ConfigureNIC(instance, seq, device, tap)
2021 self._PassTapFd(instance, fd, device)
2022 command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2023 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2024 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2025 command += "device_add %s" % args
2026 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2028 self._CallHotplugCommand(instance.name, command)
2029 # update relevant entries in runtime file
2030 index = _DEVICE_RUNTIME_INDEX[dev_type]
2031 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2032 runtime[index].append(entry)
2033 self._SaveKVMRuntime(instance, runtime)
2035 def HotDelDevice(self, instance, dev_type, device, _, seq):
2036 """ Helper method for hot-del device
2038 It gets device info from runtime file, generates the device name and
2039 invokes the device specific method.
2042 runtime = self._LoadKVMRuntime(instance)
2043 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2044 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2045 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2046 if dev_type == constants.HOTPLUG_TARGET_DISK:
2047 command = "device_del %s" % kvm_devid
2048 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2049 command = "device_del %s\n" % kvm_devid
2050 command += "netdev_del %s" % kvm_devid
2051 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2052 self._CallHotplugCommand(instance.name, command)
2053 index = _DEVICE_RUNTIME_INDEX[dev_type]
2054 runtime[index].remove(entry)
2055 self._SaveKVMRuntime(instance, runtime)
2057 return kvm_device.pci
2059 def HotModDevice(self, instance, dev_type, device, _, seq):
2060 """ Helper method for hot-mod device
2062 It gets device info from runtime file, generates the device name and
2063 invokes the device specific method. Currently only NICs support hot-mod
2066 if dev_type == constants.HOTPLUG_TARGET_NIC:
2067 # putting it back in the same pci slot
2068 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2069 # TODO: remove sleep when socat gets removed
2071 self.HotAddDevice(instance, dev_type, device, _, seq)
2073 def _PassTapFd(self, instance, fd, nic):
2074 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2077 # TODO: factor out code related to unix sockets.
2078 # squash common parts between monitor and qmp
2079 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2080 command = "getfd %s\n" % kvm_devid
2082 logging.info("%s", fds)
2084 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2086 fdsend.sendfds(monsock.sock, command, fds=fds)
2091 def _ParseKVMVersion(cls, text):
2092 """Parse the KVM version from the --help output.
2095 @param text: output of kvm --help
2096 @return: (version, v_maj, v_min, v_rev)
2097 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2100 match = cls._VERSION_RE.search(text.splitlines()[0])
2102 raise errors.HypervisorError("Unable to get KVM version")
2104 v_all = match.group(0)
2105 v_maj = int(match.group(1))
2106 v_min = int(match.group(2))
2108 v_rev = int(match.group(4))
2111 return (v_all, v_maj, v_min, v_rev)
2114 def _GetKVMOutput(cls, kvm_path, option):
2115 """Return the output of a kvm invocation
2117 @type kvm_path: string
2118 @param kvm_path: path to the kvm executable
2119 @type option: a key of _KVMOPTS_CMDS
2120 @param option: kvm option to fetch the output from
2121 @return: output a supported kvm invocation
2122 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2125 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2127 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2129 result = utils.RunCmd([kvm_path] + optlist)
2130 if result.failed and not can_fail:
2131 raise errors.HypervisorError("Unable to get KVM %s output" %
2133 return result.output
2136 def _GetKVMVersion(cls, kvm_path):
2137 """Return the installed KVM version.
2139 @return: (version, v_maj, v_min, v_rev)
2140 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2143 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2146 def _GetDefaultMachineVersion(cls, kvm_path):
2147 """Return the default hardware revision (e.g. pc-1.1)
2150 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2151 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2153 return match.group(1)
2157 def StopInstance(self, instance, force=False, retry=False, name=None,
2159 """Stop an instance.
2162 assert(timeout is None or force is not None)
2164 if name is not None and not force:
2165 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2167 name = instance.name
2168 acpi = instance.hvparams[constants.HV_ACPI]
2171 _, pid, alive = self._InstancePidAlive(name)
2172 if pid > 0 and alive:
2173 if force or not acpi:
2174 utils.KillProcess(pid)
2176 self._CallMonitorCommand(name, "system_powerdown", timeout)
2178 def CleanupInstance(self, instance_name):
2179 """Cleanup after a stopped instance
2182 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2183 if pid > 0 and alive:
2184 raise errors.HypervisorError("Cannot cleanup a live instance")
2185 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2187 def RebootInstance(self, instance):
2188 """Reboot an instance.
2191 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2192 # socket the instance will stop, but now power up again. So we'll resort
2193 # to shutdown and restart.
2194 _, _, alive = self._InstancePidAlive(instance.name)
2196 raise errors.HypervisorError("Failed to reboot instance %s:"
2197 " not running" % instance.name)
2198 # StopInstance will delete the saved KVM runtime so:
2199 # ...first load it...
2200 kvm_runtime = self._LoadKVMRuntime(instance)
2201 # ...now we can safely call StopInstance...
2202 if not self.StopInstance(instance):
2203 self.StopInstance(instance, force=True)
2204 # ...and finally we can save it again, and execute it...
2205 self._SaveKVMRuntime(instance, kvm_runtime)
2206 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2207 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2208 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2210 def MigrationInfo(self, instance):
2211 """Get instance information to perform a migration.
2213 @type instance: L{objects.Instance}
2214 @param instance: instance to be migrated
2216 @return: content of the KVM runtime file
2219 return self._ReadKVMRuntime(instance.name)
2221 def AcceptInstance(self, instance, info, target):
2222 """Prepare to accept an instance.
2224 @type instance: L{objects.Instance}
2225 @param instance: instance to be accepted
2227 @param info: content of the KVM runtime file on the source node
2228 @type target: string
2229 @param target: target host (usually ip), on this node
2232 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2233 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2234 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2235 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2236 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2237 incoming=incoming_address)
2239 def FinalizeMigrationDst(self, instance, info, success):
2240 """Finalize the instance migration on the target node.
2242 Stop the incoming mode KVM.
2244 @type instance: L{objects.Instance}
2245 @param instance: instance whose migration is being finalized
2249 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2250 kvm_nics = kvm_runtime[1]
2252 for nic_seq, nic in enumerate(kvm_nics):
2253 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2254 # Bridged interfaces have already been configured
2257 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2258 except EnvironmentError, err:
2259 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2260 instance.name, nic_seq, str(err))
2263 self._ConfigureNIC(instance, nic_seq, nic, tap)
2264 except errors.HypervisorError, err:
2265 logging.warning(str(err))
2267 self._WriteKVMRuntime(instance.name, info)
2269 self.StopInstance(instance, force=True)
2271 def MigrateInstance(self, instance, target, live):
2272 """Migrate an instance to a target node.
2274 The migration will not be attempted if the instance is not
2277 @type instance: L{objects.Instance}
2278 @param instance: the instance to be migrated
2279 @type target: string
2280 @param target: ip address of the target node
2282 @param live: perform a live migration
2285 instance_name = instance.name
2286 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2287 _, _, alive = self._InstancePidAlive(instance_name)
2289 raise errors.HypervisorError("Instance not running, cannot migrate")
2292 self._CallMonitorCommand(instance_name, "stop")
2294 migrate_command = ("migrate_set_speed %dm" %
2295 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2296 self._CallMonitorCommand(instance_name, migrate_command)
2298 migrate_command = ("migrate_set_downtime %dms" %
2299 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2300 self._CallMonitorCommand(instance_name, migrate_command)
2302 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2303 self._CallMonitorCommand(instance_name, migrate_command)
2305 def FinalizeMigrationSource(self, instance, success, live):
2306 """Finalize the instance migration on the source node.
2308 @type instance: L{objects.Instance}
2309 @param instance: the instance that was migrated
2311 @param success: whether the migration succeeded or not
2313 @param live: whether the user requested a live migration or not
2317 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2318 utils.KillProcess(pid)
2319 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2321 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2323 def GetMigrationStatus(self, instance):
2324 """Get the migration status
2326 @type instance: L{objects.Instance}
2327 @param instance: the instance that is being migrated
2328 @rtype: L{objects.MigrationStatus}
2329 @return: the status of the current migration (one of
2330 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2331 progress info that can be retrieved from the hypervisor
2334 info_command = "info migrate"
2335 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2336 result = self._CallMonitorCommand(instance.name, info_command)
2337 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2339 if not result.stdout:
2340 logging.info("KVM: empty 'info migrate' result")
2342 logging.warning("KVM: unknown 'info migrate' result: %s",
2345 status = match.group(1)
2346 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2347 migration_status = objects.MigrationStatus(status=status)
2348 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2350 migration_status.transferred_ram = match.group("transferred")
2351 migration_status.total_ram = match.group("total")
2353 return migration_status
2355 logging.warning("KVM: unknown migration status '%s'", status)
2357 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2359 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2361 def BalloonInstanceMemory(self, instance, mem):
2362 """Balloon an instance memory to a certain value.
2364 @type instance: L{objects.Instance}
2365 @param instance: instance to be accepted
2367 @param mem: actual memory size to use for instance runtime
2370 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2372 def GetNodeInfo(self):
2373 """Return information about the node.
2375 @return: a dict with the following keys (values in MiB):
2376 - memory_total: the total memory size on the node
2377 - memory_free: the available memory on the node for instances
2378 - memory_dom0: the memory used by the node itself, if available
2379 - hv_version: the hypervisor version in the form (major, minor,
2383 result = self.GetLinuxNodeInfo()
2384 # FIXME: this is the global kvm version, but the actual version can be
2385 # customized as an hv parameter. we should use the nodegroup's default kvm
2386 # path parameter here.
2387 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2388 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2392 def GetInstanceConsole(cls, instance, hvparams, beparams):
2393 """Return a command for connecting to the console of an instance.
2396 if hvparams[constants.HV_SERIAL_CONSOLE]:
2397 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2398 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2399 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2400 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2401 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2402 return objects.InstanceConsole(instance=instance.name,
2403 kind=constants.CONS_SSH,
2404 host=instance.primary_node,
2405 user=constants.SSH_CONSOLE_USER,
2408 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2409 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2410 display = instance.network_port - constants.VNC_BASE_PORT
2411 return objects.InstanceConsole(instance=instance.name,
2412 kind=constants.CONS_VNC,
2413 host=vnc_bind_address,
2414 port=instance.network_port,
2417 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2419 return objects.InstanceConsole(instance=instance.name,
2420 kind=constants.CONS_SPICE,
2422 port=instance.network_port)
2424 return objects.InstanceConsole(instance=instance.name,
2425 kind=constants.CONS_MESSAGE,
2426 message=("No serial shell for instance %s" %
2430 """Verify the hypervisor.
2432 Check that the required binaries exist.
2434 @return: Problem description if something is wrong, C{None} otherwise
2438 # FIXME: this is the global kvm binary, but the actual path can be
2439 # customized as an hv parameter; we should use the nodegroup's
2440 # default kvm path parameter here.
2441 if not os.path.exists(constants.KVM_PATH):
2442 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2443 if not os.path.exists(constants.SOCAT_PATH):
2444 msgs.append("The socat binary ('%s') does not exist" %
2445 constants.SOCAT_PATH)
2447 return self._FormatVerifyResults(msgs)
2450 def CheckParameterSyntax(cls, hvparams):
2451 """Check the given parameters for validity.
2453 @type hvparams: dict
2454 @param hvparams: dictionary with parameter names/value
2455 @raise errors.HypervisorError: when a parameter is not valid
2458 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2460 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2462 if not hvparams[constants.HV_ROOT_PATH]:
2463 raise errors.HypervisorError("Need a root partition for the instance,"
2464 " if a kernel is defined")
2466 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2467 not hvparams[constants.HV_VNC_X509]):
2468 raise errors.HypervisorError("%s must be defined, if %s is" %
2469 (constants.HV_VNC_X509,
2470 constants.HV_VNC_X509_VERIFY))
2472 if hvparams[constants.HV_SERIAL_CONSOLE]:
2473 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2474 valid_speeds = constants.VALID_SERIAL_SPEEDS
2475 if not serial_speed or serial_speed not in valid_speeds:
2476 raise errors.HypervisorError("Invalid serial console speed, must be"
2478 utils.CommaJoin(valid_speeds))
2480 boot_order = hvparams[constants.HV_BOOT_ORDER]
2481 if (boot_order == constants.HT_BO_CDROM and
2482 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2483 raise errors.HypervisorError("Cannot boot from cdrom without an"
2486 security_model = hvparams[constants.HV_SECURITY_MODEL]
2487 if security_model == constants.HT_SM_USER:
2488 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2489 raise errors.HypervisorError("A security domain (user to run kvm as)"
2490 " must be specified")
2491 elif (security_model == constants.HT_SM_NONE or
2492 security_model == constants.HT_SM_POOL):
2493 if hvparams[constants.HV_SECURITY_DOMAIN]:
2494 raise errors.HypervisorError("Cannot have a security domain when the"
2495 " security model is 'none' or 'pool'")
2497 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2498 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2500 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2501 # if an IP version is specified, the spice_bind parameter must be an
2503 if (netutils.IP4Address.IsValid(spice_bind) and
2504 spice_ip_version != constants.IP4_VERSION):
2505 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2506 " the specified IP version is %s" %
2507 (spice_bind, spice_ip_version))
2509 if (netutils.IP6Address.IsValid(spice_bind) and
2510 spice_ip_version != constants.IP6_VERSION):
2511 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2512 " the specified IP version is %s" %
2513 (spice_bind, spice_ip_version))
2515 # All the other SPICE parameters depend on spice_bind being set. Raise an
2516 # error if any of them is set without it.
2517 for param in _SPICE_ADDITIONAL_PARAMS:
2519 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2520 (param, constants.HV_KVM_SPICE_BIND))
2523 def ValidateParameters(cls, hvparams):
2524 """Check the given parameters for validity.
2526 @type hvparams: dict
2527 @param hvparams: dictionary with parameter names/value
2528 @raise errors.HypervisorError: when a parameter is not valid
2531 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2533 kvm_path = hvparams[constants.HV_KVM_PATH]
2535 security_model = hvparams[constants.HV_SECURITY_MODEL]
2536 if security_model == constants.HT_SM_USER:
2537 username = hvparams[constants.HV_SECURITY_DOMAIN]
2539 pwd.getpwnam(username)
2541 raise errors.HypervisorError("Unknown security domain user %s"
2544 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2546 # only one of VNC and SPICE can be used currently.
2547 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2548 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2549 " only one of them can be used at a"
2552 # check that KVM supports SPICE
2553 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2554 if not cls._SPICE_RE.search(kvmhelp):
2555 raise errors.HypervisorError("SPICE is configured, but it is not"
2556 " supported according to 'kvm --help'")
2558 # if spice_bind is not an IP address, it must be a valid interface
2559 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2560 netutils.IP6Address.IsValid(spice_bind))
2561 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2562 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2563 " a valid IP address or interface name" %
2564 constants.HV_KVM_SPICE_BIND)
2566 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2568 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2569 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2570 raise errors.HypervisorError("Unsupported machine version: %s" %
2574 def PowercycleNode(cls):
2575 """KVM powercycle, just a wrapper over Linux powercycle.
2578 cls.LinuxPowercycle()