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 as a list of in tuples
94 # (L{objects.Disk}, link_name)
95 _KVM_NICS_RUNTIME_INDEX = 1
96 _KVM_DISKS_RUNTIME_INDEX = 3
97 _DEVICE_RUNTIME_INDEX = {
98 constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
99 constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
101 _FIND_RUNTIME_ENTRY = {
102 constants.HOTPLUG_TARGET_NIC:
103 lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
104 constants.HOTPLUG_TARGET_DISK:
105 lambda disk, kvm_disks: [(d, l) for (d, l) in kvm_disks
106 if d.uuid == disk.uuid]
109 constants.HOTPLUG_TARGET_NIC: lambda d: d,
110 constants.HOTPLUG_TARGET_DISK: lambda (d, e): d
113 constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
114 constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e)
118 def _GenerateDeviceKVMId(dev_type, dev):
119 """Helper function to generate a unique device name used by KVM
121 QEMU monitor commands use names to identify devices. Here we use their pci
122 slot and a part of their UUID to name them. dev.pci might be None for old
123 devices in the cluster.
125 @type dev_type: sting
126 @param dev_type: device type of param dev
127 @type dev: L{objects.Disk} or L{objects.NIC}
128 @param dev: the device object for which we generate a kvm name
129 @raise errors.HotplugError: in case a device has no pci slot (old devices)
134 raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
135 (dev_type, dev.uuid))
137 return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
140 def _UpdatePCISlots(dev, pci_reservations):
141 """Update pci configuration for a stopped instance
143 If dev has a pci slot then reserve it, else find first available
144 in pci_reservations bitarray. It acts on the same objects passed
145 as params so there is no need to return anything.
147 @type dev: L{objects.Disk} or L{objects.NIC}
148 @param dev: the device object for which we update its pci slot
149 @type pci_reservations: bitarray
150 @param pci_reservations: existing pci reservations for an instance
151 @raise errors.HotplugError: in case an instance has all its slot occupied
156 else: # pylint: disable=E1103
157 [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
159 raise errors.HypervisorError("All PCI slots occupied")
162 pci_reservations[free] = True
165 def _GetExistingDeviceInfo(dev_type, device, runtime):
166 """Helper function to get an existing device inside the runtime file
168 Used when an instance is running. Load kvm runtime file and search
169 for a device based on its type and uuid.
171 @type dev_type: sting
172 @param dev_type: device type of param dev
173 @type device: L{objects.Disk} or L{objects.NIC}
174 @param device: the device object for which we generate a kvm name
175 @type runtime: tuple (cmd, nics, hvparams, disks)
176 @param runtime: the runtime data to search for the device
177 @raise errors.HotplugError: in case the requested device does not
178 exist (e.g. device has been added without --hotplug option) or
179 device info has not pci slot (e.g. old devices in the cluster)
182 index = _DEVICE_RUNTIME_INDEX[dev_type]
183 found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
185 raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
186 (dev_type, device.uuid))
191 def _AnalyzeSerializedRuntime(serialized_runtime):
192 """Return runtime entries for a serialized runtime file
194 @type serialized_runtime: string
195 @param serialized_runtime: raw text data read from actual runtime file
196 @return: (cmd, nics, hvparams, bdevs)
200 loaded_runtime = serializer.Load(serialized_runtime)
201 if len(loaded_runtime) == 3:
202 serialized_disks = []
203 kvm_cmd, serialized_nics, hvparams = loaded_runtime
205 kvm_cmd, serialized_nics, hvparams, serialized_disks = loaded_runtime
207 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
208 kvm_disks = [(objects.Disk.FromDict(sdisk), link)
209 for sdisk, link in serialized_disks]
211 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
214 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
215 """Retrieves supported TUN features from file descriptor.
217 @see: L{_ProbeTapVnetHdr}
220 req = struct.pack("I", 0)
222 buf = _ioctl(fd, TUNGETFEATURES, req)
223 except EnvironmentError, err:
224 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
227 (flags, ) = struct.unpack("I", buf)
231 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
232 """Check whether to enable the IFF_VNET_HDR flag.
234 To do this, _all_ of the following conditions must be met:
235 1. TUNGETFEATURES ioctl() *must* be implemented
236 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
237 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
238 drivers/net/tun.c there is no way to test this until after the tap device
239 has been created using TUNSETIFF, and there is no way to change the
240 IFF_VNET_HDR flag after creating the interface, catch-22! However both
241 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
242 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
245 @param fd: the file descriptor of /dev/net/tun
248 flags = _features_fn(fd)
254 result = bool(flags & IFF_VNET_HDR)
257 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
262 def _OpenTap(vnet_hdr=True):
263 """Open a new tap device and return its file descriptor.
265 This is intended to be used by a qemu-type hypervisor together with the -net
266 tap,fd=<fd> command line parameter.
268 @type vnet_hdr: boolean
269 @param vnet_hdr: Enable the VNET Header
270 @return: (ifname, tapfd)
275 tapfd = os.open("/dev/net/tun", os.O_RDWR)
276 except EnvironmentError:
277 raise errors.HypervisorError("Failed to open /dev/net/tun")
279 flags = IFF_TAP | IFF_NO_PI
281 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
282 flags |= IFF_VNET_HDR
284 # The struct ifreq ioctl request (see netdevice(7))
285 ifr = struct.pack("16sh", "", flags)
288 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
289 except EnvironmentError, err:
290 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
293 # Get the interface name from the ioctl
294 ifname = struct.unpack("16sh", res)[0].strip("\x00")
295 return (ifname, tapfd)
299 """QEMU Messaging Protocol (QMP) message.
302 def __init__(self, data):
303 """Creates a new QMP message based on the passed data.
306 if not isinstance(data, dict):
307 raise TypeError("QmpMessage must be initialized with a dict")
311 def __getitem__(self, field_name):
312 """Get the value of the required field if present, or None.
314 Overrides the [] operator to provide access to the message data,
315 returning None if the required item is not in the message
316 @return: the value of the field_name field, or None if field_name
317 is not contained in the message
320 return self.data.get(field_name, None)
322 def __setitem__(self, field_name, field_value):
323 """Set the value of the required field_name to field_value.
326 self.data[field_name] = field_value
329 def BuildFromJsonString(json_string):
330 """Build a QmpMessage from a JSON encoded string.
332 @type json_string: str
333 @param json_string: JSON string representing the message
334 @rtype: L{QmpMessage}
335 @return: a L{QmpMessage} built from json_string
339 data = serializer.LoadJson(json_string)
340 return QmpMessage(data)
343 # The protocol expects the JSON object to be sent as a single line.
344 return serializer.DumpJson(self.data)
346 def __eq__(self, other):
347 # When comparing two QmpMessages, we are interested in comparing
348 # their internal representation of the message data
349 return self.data == other.data
352 class MonitorSocket(object):
355 def __init__(self, monitor_filename):
356 """Instantiates the MonitorSocket object.
358 @type monitor_filename: string
359 @param monitor_filename: the filename of the UNIX raw socket on which the
360 monitor (QMP or simple one) is listening
363 self.monitor_filename = monitor_filename
364 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
365 # We want to fail if the server doesn't send a complete message
366 # in a reasonable amount of time
367 self.sock.settimeout(self._SOCKET_TIMEOUT)
368 self._connected = False
370 def _check_socket(self):
373 sock_stat = os.stat(self.monitor_filename)
374 except EnvironmentError, err:
375 if err.errno == errno.ENOENT:
376 raise errors.HypervisorError("No monitor socket found")
378 raise errors.HypervisorError("Error checking monitor socket: %s",
379 utils.ErrnoOrStr(err))
380 if not stat.S_ISSOCK(sock_stat.st_mode):
381 raise errors.HypervisorError("Monitor socket is not a socket")
383 def _check_connection(self):
384 """Make sure that the connection is established.
387 if not self._connected:
388 raise errors.ProgrammerError("To use a MonitorSocket you need to first"
389 " invoke connect() on it")
392 """Connects to the monitor.
394 Connects to the UNIX socket
396 @raise errors.HypervisorError: when there are communication errors
400 raise errors.ProgrammerError("Cannot connect twice")
404 # Check file existance/stuff
406 self.sock.connect(self.monitor_filename)
407 except EnvironmentError:
408 raise errors.HypervisorError("Can't connect to qmp socket")
409 self._connected = True
414 It cannot be used after this call.
420 class QmpConnection(MonitorSocket):
421 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
424 _FIRST_MESSAGE_KEY = "QMP"
427 _RETURN_KEY = RETURN_KEY = "return"
428 _ACTUAL_KEY = ACTUAL_KEY = "actual"
429 _ERROR_CLASS_KEY = "class"
430 _ERROR_DATA_KEY = "data"
431 _ERROR_DESC_KEY = "desc"
432 _EXECUTE_KEY = "execute"
433 _ARGUMENTS_KEY = "arguments"
434 _CAPABILITIES_COMMAND = "qmp_capabilities"
435 _MESSAGE_END_TOKEN = "\r\n"
437 def __init__(self, monitor_filename):
438 super(QmpConnection, self).__init__(monitor_filename)
442 """Connects to the QMP monitor.
444 Connects to the UNIX socket and makes sure that we can actually send and
445 receive data to the kvm instance via QMP.
447 @raise errors.HypervisorError: when there are communication errors
448 @raise errors.ProgrammerError: when there are data serialization errors
451 super(QmpConnection, self).connect()
452 # Check if we receive a correct greeting message from the server
453 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
454 greeting = self._Recv()
455 if not greeting[self._FIRST_MESSAGE_KEY]:
456 self._connected = False
457 raise errors.HypervisorError("kvm: QMP communication error (wrong"
460 # Let's put the monitor in command mode using the qmp_capabilities
461 # command, or else no command will be executable.
462 # (As per the QEMU Protocol Specification 0.1 - section 4)
463 self.Execute(self._CAPABILITIES_COMMAND)
465 def _ParseMessage(self, buf):
466 """Extract and parse a QMP message from the given buffer.
468 Seeks for a QMP message in the given buf. If found, it parses it and
469 returns it together with the rest of the characters in the buf.
470 If no message is found, returns None and the whole buffer.
472 @raise errors.ProgrammerError: when there are data serialization errors
476 # Check if we got the message end token (CRLF, as per the QEMU Protocol
477 # Specification 0.1 - Section 2.1.1)
478 pos = buf.find(self._MESSAGE_END_TOKEN)
481 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
482 except Exception, err:
483 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
486 return (message, buf)
489 """Receives a message from QMP and decodes the received JSON object.
492 @return: the received message
493 @raise errors.HypervisorError: when there are communication errors
494 @raise errors.ProgrammerError: when there are data serialization errors
497 self._check_connection()
499 # Check if there is already a message in the buffer
500 (message, self._buf) = self._ParseMessage(self._buf)
504 recv_buffer = StringIO.StringIO(self._buf)
505 recv_buffer.seek(len(self._buf))
508 data = self.sock.recv(4096)
511 recv_buffer.write(data)
513 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
517 except socket.timeout, err:
518 raise errors.HypervisorError("Timeout while receiving a QMP message: "
520 except socket.error, err:
521 raise errors.HypervisorError("Unable to receive data from KVM using the"
522 " QMP protocol: %s" % err)
524 def _Send(self, message):
525 """Encodes and sends a message to KVM using QMP.
527 @type message: QmpMessage
528 @param message: message to send to KVM
529 @raise errors.HypervisorError: when there are communication errors
530 @raise errors.ProgrammerError: when there are data serialization errors
533 self._check_connection()
535 message_str = str(message)
536 except Exception, err:
537 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
540 self.sock.sendall(message_str)
541 except socket.timeout, err:
542 raise errors.HypervisorError("Timeout while sending a QMP message: "
543 "%s (%s)" % (err.string, err.errno))
544 except socket.error, err:
545 raise errors.HypervisorError("Unable to send data from KVM using the"
546 " QMP protocol: %s" % err)
548 def Execute(self, command, arguments=None):
549 """Executes a QMP command and returns the response of the server.
552 @param command: the command to execute
553 @type arguments: dict
554 @param arguments: dictionary of arguments to be passed to the command
556 @return: dictionary representing the received JSON object
557 @raise errors.HypervisorError: when there are communication errors
558 @raise errors.ProgrammerError: when there are data serialization errors
561 self._check_connection()
562 message = QmpMessage({self._EXECUTE_KEY: command})
564 message[self._ARGUMENTS_KEY] = arguments
567 # Events can occur between the sending of the command and the reception
568 # of the response, so we need to filter out messages with the event key.
570 response = self._Recv()
571 err = response[self._ERROR_KEY]
573 raise errors.HypervisorError("kvm: error executing the %s"
574 " command: %s (%s, %s):" %
576 err[self._ERROR_DESC_KEY],
577 err[self._ERROR_CLASS_KEY],
578 err[self._ERROR_DATA_KEY]))
580 elif not response[self._EVENT_KEY]:
584 class KVMHypervisor(hv_base.BaseHypervisor):
585 """KVM hypervisor interface
590 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
591 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
592 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
593 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
594 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
595 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
596 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
597 # KVM instances with chroot enabled are started in empty chroot directories.
598 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
599 # After an instance is stopped, its chroot directory is removed.
600 # If the chroot directory is not empty, it can't be removed.
601 # A non-empty chroot directory indicates a possible security incident.
602 # To support forensics, the non-empty chroot directory is quarantined in
603 # a separate directory, called 'chroot-quarantine'.
604 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
605 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
606 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
609 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
610 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
611 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
612 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
613 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
614 constants.HV_ACPI: hv_base.NO_CHECK,
615 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
616 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
617 constants.HV_VNC_BIND_ADDRESS:
618 (False, lambda x: (netutils.IP4Address.IsValid(x) or
619 utils.IsNormAbsPath(x)),
620 "The VNC bind address must be either a valid IP address or an absolute"
621 " pathname", None, None),
622 constants.HV_VNC_TLS: hv_base.NO_CHECK,
623 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
624 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
625 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
626 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
627 constants.HV_KVM_SPICE_IP_VERSION:
628 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
629 x in constants.VALID_IP_VERSIONS),
630 "The SPICE IP version should be 4 or 6",
632 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
633 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
635 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
636 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
638 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
639 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
641 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
642 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
644 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
645 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
646 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
647 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
648 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
649 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
650 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
651 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
652 constants.HV_BOOT_ORDER:
653 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
654 constants.HV_NIC_TYPE:
655 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
656 constants.HV_DISK_TYPE:
657 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
658 constants.HV_KVM_CDROM_DISK_TYPE:
659 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
660 constants.HV_USB_MOUSE:
661 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
662 constants.HV_KEYMAP: hv_base.NO_CHECK,
663 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
664 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
665 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
666 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
667 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
668 constants.HV_DISK_CACHE:
669 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
670 constants.HV_SECURITY_MODEL:
671 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
672 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
673 constants.HV_KVM_FLAG:
674 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
675 constants.HV_VHOST_NET: hv_base.NO_CHECK,
676 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
677 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
678 constants.HV_REBOOT_BEHAVIOR:
679 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
680 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
681 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
682 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
683 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
684 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
685 constants.HV_SOUNDHW: hv_base.NO_CHECK,
686 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
687 constants.HV_VGA: hv_base.NO_CHECK,
688 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
689 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
690 constants.HV_VNET_HDR: hv_base.NO_CHECK,
694 _VIRTIO_NET_PCI = "virtio-net-pci"
695 _VIRTIO_BLK_PCI = "virtio-blk-pci"
697 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
699 _MIGRATION_PROGRESS_RE = \
700 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
701 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
702 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
704 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
705 _MIGRATION_INFO_RETRY_DELAY = 2
707 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
709 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
710 _CPU_INFO_CMD = "info cpus"
713 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
714 _CHECK_MACHINE_VERSION_RE = \
715 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
717 _QMP_RE = re.compile(r"^-qmp\s", re.M)
718 _SPICE_RE = re.compile(r"^-spice\s", re.M)
719 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
720 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
721 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
722 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
723 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
724 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
725 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
726 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
727 # match -drive.*boot=on|off on different lines, but in between accept only
728 # dashes not preceeded by a new line (which would mean another option
729 # different than -drive is starting)
730 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
732 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
733 _INFO_PCI_CMD = "info pci"
735 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
736 _INFO_VERSION_CMD = "info version"
738 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
743 ANCILLARY_FILES_OPT = [
747 # Supported kvm options to get output from
748 _KVMOPT_HELP = "help"
749 _KVMOPT_MLIST = "mlist"
750 _KVMOPT_DEVICELIST = "devicelist"
752 # Command to execute to get the output from kvm, and whether to
753 # accept the output even on failure.
755 _KVMOPT_HELP: (["--help"], False),
756 _KVMOPT_MLIST: (["-M", "?"], False),
757 _KVMOPT_DEVICELIST: (["-device", "?"], True),
761 hv_base.BaseHypervisor.__init__(self)
762 # Let's make sure the directories we need exist, even if the RUN_DIR lives
763 # in a tmpfs filesystem or has been otherwise wiped out.
764 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
765 utils.EnsureDirs(dirs)
768 def _InstancePidFile(cls, instance_name):
769 """Returns the instance pidfile.
772 return utils.PathJoin(cls._PIDS_DIR, instance_name)
775 def _InstanceUidFile(cls, instance_name):
776 """Returns the instance uidfile.
779 return utils.PathJoin(cls._UIDS_DIR, instance_name)
782 def _InstancePidInfo(cls, pid):
783 """Check pid file for instance information.
785 Check that a pid file is associated with an instance, and retrieve
786 information from its command line.
788 @type pid: string or int
789 @param pid: process id of the instance to check
791 @return: (instance_name, memory, vcpus)
792 @raise errors.HypervisorError: when an instance cannot be found
795 alive = utils.IsProcessAlive(pid)
797 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
799 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
801 cmdline = utils.ReadFile(cmdline_file)
802 except EnvironmentError, err:
803 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
810 arg_list = cmdline.split("\x00")
812 arg = arg_list.pop(0)
814 instance = arg_list.pop(0)
816 memory = int(arg_list.pop(0))
818 vcpus = int(arg_list.pop(0).split(",")[0])
821 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
824 return (instance, memory, vcpus)
826 def _InstancePidAlive(self, instance_name):
827 """Returns the instance pidfile, pid, and liveness.
829 @type instance_name: string
830 @param instance_name: instance name
832 @return: (pid file name, pid, liveness)
835 pidfile = self._InstancePidFile(instance_name)
836 pid = utils.ReadPidFile(pidfile)
840 cmd_instance = self._InstancePidInfo(pid)[0]
841 alive = (cmd_instance == instance_name)
842 except errors.HypervisorError:
845 return (pidfile, pid, alive)
847 def _CheckDown(self, instance_name):
848 """Raises an error unless the given instance is down.
851 alive = self._InstancePidAlive(instance_name)[2]
853 raise errors.HypervisorError("Failed to start instance %s: %s" %
854 (instance_name, "already running"))
857 def _InstanceMonitor(cls, instance_name):
858 """Returns the instance monitor socket name
861 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
864 def _InstanceSerial(cls, instance_name):
865 """Returns the instance serial socket name
868 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
871 def _InstanceQmpMonitor(cls, instance_name):
872 """Returns the instance serial QMP socket name
875 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
878 def _SocatUnixConsoleParams():
879 """Returns the correct parameters for socat
881 If we have a new-enough socat we can use raw mode with an escape character.
884 if constants.SOCAT_USE_ESCAPE:
885 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
887 return "echo=0,icanon=0"
890 def _InstanceKVMRuntime(cls, instance_name):
891 """Returns the instance KVM runtime filename
894 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
897 def _InstanceChrootDir(cls, instance_name):
898 """Returns the name of the KVM chroot dir of the instance
901 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
904 def _InstanceNICDir(cls, instance_name):
905 """Returns the name of the directory holding the tap device files for a
909 return utils.PathJoin(cls._NICS_DIR, instance_name)
912 def _InstanceNICFile(cls, instance_name, seq):
913 """Returns the name of the file containing the tap device for a given NIC
916 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
919 def _InstanceKeymapFile(cls, instance_name):
920 """Returns the name of the file containing the keymap for a given instance
923 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
926 def _TryReadUidFile(cls, uid_file):
927 """Try to read a uid file
930 if os.path.exists(uid_file):
932 uid = int(utils.ReadOneLineFile(uid_file))
934 except EnvironmentError:
935 logging.warning("Can't read uid file", exc_info=True)
936 except (TypeError, ValueError):
937 logging.warning("Can't parse uid file contents", exc_info=True)
941 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
942 """Removes an instance's rutime sockets/files/dirs.
945 utils.RemoveFile(pidfile)
946 utils.RemoveFile(cls._InstanceMonitor(instance_name))
947 utils.RemoveFile(cls._InstanceSerial(instance_name))
948 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
949 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
950 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
951 uid_file = cls._InstanceUidFile(instance_name)
952 uid = cls._TryReadUidFile(uid_file)
953 utils.RemoveFile(uid_file)
955 uidpool.ReleaseUid(uid)
957 shutil.rmtree(cls._InstanceNICDir(instance_name))
959 if err.errno != errno.ENOENT:
962 chroot_dir = cls._InstanceChrootDir(instance_name)
963 utils.RemoveDir(chroot_dir)
965 if err.errno == errno.ENOTEMPTY:
966 # The chroot directory is expected to be empty, but it isn't.
967 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
970 utils.TimestampForFilename()))
971 logging.warning("The chroot directory of instance %s can not be"
972 " removed as it is not empty. Moving it to the"
973 " quarantine instead. Please investigate the"
974 " contents (%s) and clean up manually",
975 instance_name, new_chroot_dir)
976 utils.RenameFile(chroot_dir, new_chroot_dir)
981 def _ConfigureNIC(instance, seq, nic, tap):
982 """Run the network configuration script for a specified NIC
984 @param instance: instance we're acting on
985 @type instance: instance object
986 @param seq: nic sequence number
988 @param nic: nic we're acting on
989 @type nic: nic object
990 @param tap: the host's tap interface this NIC corresponds to
995 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
996 "INSTANCE": instance.name,
998 "MODE": nic.nicparams[constants.NIC_MODE],
1000 "INTERFACE_INDEX": str(seq),
1001 "INTERFACE_UUID": nic.uuid,
1002 "TAGS": " ".join(instance.GetTags()),
1009 env["INTERFACE_NAME"] = nic.name
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, kvm_disks,
1189 """Generate KVM options regarding instance's block devices.
1191 @type instance: L{objects.Instance}
1192 @param instance: the instance object
1193 @type kvm_disks: list of tuples
1194 @param kvm_disks: list of tuples [(disk, link_name)..]
1195 @type kvmhelp: string
1196 @param kvmhelp: output of kvm --help
1197 @type devlist: string
1198 @param devlist: output of kvm -device ?
1200 @return: list of command line options eventually used by kvm executable
1203 hvp = instance.hvparams
1204 kernel_path = hvp[constants.HV_KERNEL_PATH]
1208 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1210 # whether this is an older KVM version that uses the boot=on flag
1212 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1215 device_driver = None
1216 disk_type = hvp[constants.HV_DISK_TYPE]
1217 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1218 if_val = ",if=%s" % self._VIRTIO
1220 if self._VIRTIO_BLK_RE.search(devlist):
1222 # will be passed in -device option as driver
1223 device_driver = self._VIRTIO_BLK_PCI
1224 except errors.HypervisorError, _:
1227 if_val = ",if=%s" % disk_type
1229 disk_cache = hvp[constants.HV_DISK_CACHE]
1230 if instance.disk_template in constants.DTS_EXT_MIRROR:
1231 if disk_cache != "none":
1232 # TODO: make this a hard error, instead of a silent overwrite
1233 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1234 " to prevent shared storage corruption on migration",
1236 cache_val = ",cache=none"
1237 elif disk_cache != constants.HT_CACHE_DEFAULT:
1238 cache_val = ",cache=%s" % disk_cache
1241 for cfdev, link_name in kvm_disks:
1242 if cfdev.mode != constants.DISK_RDWR:
1243 raise errors.HypervisorError("Instance has read-only disks which"
1244 " are not supported by KVM")
1245 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1248 dev_opts.extend(["-boot", "c"])
1250 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1251 boot_val = ",boot=on"
1252 drive_val = "file=%s,format=raw%s%s%s" % \
1253 (dev_path, if_val, boot_val, cache_val)
1256 # kvm_disks are the 4th entry of runtime file that did not exist in
1257 # the past. That means that cfdev should always have pci slot and
1258 # _GenerateDeviceKVMId() will not raise a exception.
1259 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1260 drive_val += (",id=%s" % kvm_devid)
1261 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1262 dev_val = ("%s,drive=%s,id=%s" %
1263 (device_driver, kvm_devid, kvm_devid))
1264 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1265 dev_opts.extend(["-device", dev_val])
1267 dev_opts.extend(["-drive", drive_val])
1271 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1273 """Generate KVM information to start an instance.
1275 @type kvmhelp: string
1276 @param kvmhelp: output of kvm --help
1277 @attention: this function must not have any side-effects; for
1278 example, it must not write to the filesystem, or read values
1279 from the current system the are expected to differ between
1280 nodes, since it is only run once at instance startup;
1281 actions/kvm arguments that can vary between systems should be
1282 done in L{_ExecuteKVMRuntime}
1285 # pylint: disable=R0912,R0914,R0915
1286 hvp = instance.hvparams
1287 self.ValidateParameters(hvp)
1289 pidfile = self._InstancePidFile(instance.name)
1290 kvm = hvp[constants.HV_KVM_PATH]
1292 # used just by the vnc server, if enabled
1293 kvm_cmd.extend(["-name", instance.name])
1294 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1296 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1297 if hvp[constants.HV_CPU_CORES]:
1298 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1299 if hvp[constants.HV_CPU_THREADS]:
1300 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1301 if hvp[constants.HV_CPU_SOCKETS]:
1302 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1304 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1306 kvm_cmd.extend(["-pidfile", pidfile])
1307 kvm_cmd.extend(["-balloon", "virtio"])
1308 kvm_cmd.extend(["-daemonize"])
1309 if not instance.hvparams[constants.HV_ACPI]:
1310 kvm_cmd.extend(["-no-acpi"])
1311 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1312 constants.INSTANCE_REBOOT_EXIT:
1313 kvm_cmd.extend(["-no-reboot"])
1315 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1317 mversion = self._GetDefaultMachineVersion(kvm)
1318 if self._MACHINE_RE.search(kvmhelp):
1319 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1320 # extra hypervisor parameters. We should also investigate whether and how
1321 # shadow_mem should be considered for the resource model.
1322 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1323 specprop = ",accel=kvm"
1326 machinespec = "%s%s" % (mversion, specprop)
1327 kvm_cmd.extend(["-machine", machinespec])
1329 kvm_cmd.extend(["-M", mversion])
1330 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1331 self._ENABLE_KVM_RE.search(kvmhelp)):
1332 kvm_cmd.extend(["-enable-kvm"])
1333 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1334 self._DISABLE_KVM_RE.search(kvmhelp)):
1335 kvm_cmd.extend(["-disable-kvm"])
1337 kernel_path = hvp[constants.HV_KERNEL_PATH]
1339 boot_cdrom = boot_floppy = boot_network = False
1341 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1342 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1343 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1346 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1349 kvm_cmd.extend(["-boot", "n"])
1351 # whether this is an older KVM version that uses the boot=on flag
1353 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1355 disk_type = hvp[constants.HV_DISK_TYPE]
1357 #Now we can specify a different device type for CDROM devices.
1358 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1359 if not cdrom_disk_type:
1360 cdrom_disk_type = disk_type
1362 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1364 options = ",format=raw,media=cdrom"
1365 # set cdrom 'if' type
1367 actual_cdrom_type = constants.HT_DISK_IDE
1368 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1369 actual_cdrom_type = "virtio"
1371 actual_cdrom_type = cdrom_disk_type
1372 if_val = ",if=%s" % actual_cdrom_type
1373 # set boot flag, if needed
1376 kvm_cmd.extend(["-boot", "d"])
1378 boot_val = ",boot=on"
1379 # and finally build the entire '-drive' value
1380 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1381 kvm_cmd.extend(["-drive", drive_val])
1383 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1385 options = ",format=raw,media=cdrom"
1386 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1387 if_val = ",if=virtio"
1389 if_val = ",if=%s" % cdrom_disk_type
1390 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1391 kvm_cmd.extend(["-drive", drive_val])
1393 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1395 options = ",format=raw,media=disk"
1397 kvm_cmd.extend(["-boot", "a"])
1398 options = "%s,boot=on" % options
1399 if_val = ",if=floppy"
1400 options = "%s%s" % (options, if_val)
1401 drive_val = "file=%s%s" % (floppy_image, options)
1402 kvm_cmd.extend(["-drive", drive_val])
1405 kvm_cmd.extend(["-kernel", kernel_path])
1406 initrd_path = hvp[constants.HV_INITRD_PATH]
1408 kvm_cmd.extend(["-initrd", initrd_path])
1409 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1410 hvp[constants.HV_KERNEL_ARGS]]
1411 if hvp[constants.HV_SERIAL_CONSOLE]:
1412 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1413 root_append.append("console=ttyS0,%s" % serial_speed)
1414 kvm_cmd.extend(["-append", " ".join(root_append)])
1416 mem_path = hvp[constants.HV_MEM_PATH]
1418 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1420 monitor_dev = ("unix:%s,server,nowait" %
1421 self._InstanceMonitor(instance.name))
1422 kvm_cmd.extend(["-monitor", monitor_dev])
1423 if hvp[constants.HV_SERIAL_CONSOLE]:
1424 serial_dev = ("unix:%s,server,nowait" %
1425 self._InstanceSerial(instance.name))
1426 kvm_cmd.extend(["-serial", serial_dev])
1428 kvm_cmd.extend(["-serial", "none"])
1430 mouse_type = hvp[constants.HV_USB_MOUSE]
1431 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1432 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1433 spice_ip_version = None
1435 kvm_cmd.extend(["-usb"])
1438 kvm_cmd.extend(["-usbdevice", mouse_type])
1439 elif vnc_bind_address:
1440 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1442 if vnc_bind_address:
1443 if netutils.IP4Address.IsValid(vnc_bind_address):
1444 if instance.network_port > constants.VNC_BASE_PORT:
1445 display = instance.network_port - constants.VNC_BASE_PORT
1446 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1447 vnc_arg = ":%d" % (display)
1449 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1451 logging.error("Network port is not a valid VNC display (%d < %d),"
1452 " not starting VNC",
1453 instance.network_port, constants.VNC_BASE_PORT)
1456 # Only allow tls and other option when not binding to a file, for now.
1457 # kvm/qemu gets confused otherwise about the filename to use.
1459 if hvp[constants.HV_VNC_TLS]:
1460 vnc_append = "%s,tls" % vnc_append
1461 if hvp[constants.HV_VNC_X509_VERIFY]:
1462 vnc_append = "%s,x509verify=%s" % (vnc_append,
1463 hvp[constants.HV_VNC_X509])
1464 elif hvp[constants.HV_VNC_X509]:
1465 vnc_append = "%s,x509=%s" % (vnc_append,
1466 hvp[constants.HV_VNC_X509])
1467 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1468 vnc_append = "%s,password" % vnc_append
1470 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1473 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1475 kvm_cmd.extend(["-vnc", vnc_arg])
1477 # FIXME: this is wrong here; the iface ip address differs
1478 # between systems, so it should be done in _ExecuteKVMRuntime
1479 if netutils.IsValidInterface(spice_bind):
1480 # The user specified a network interface, we have to figure out the IP
1482 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1483 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1485 # if the user specified an IP version and the interface does not
1486 # have that kind of IP addresses, throw an exception
1487 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1488 if not addresses[spice_ip_version]:
1489 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1490 " for %s" % (spice_ip_version,
1493 # the user did not specify an IP version, we have to figure it out
1494 elif (addresses[constants.IP4_VERSION] and
1495 addresses[constants.IP6_VERSION]):
1496 # we have both ipv4 and ipv6, let's use the cluster default IP
1498 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1499 spice_ip_version = \
1500 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1501 elif addresses[constants.IP4_VERSION]:
1502 spice_ip_version = constants.IP4_VERSION
1503 elif addresses[constants.IP6_VERSION]:
1504 spice_ip_version = constants.IP6_VERSION
1506 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1507 " for %s" % (spice_bind))
1509 spice_address = addresses[spice_ip_version][0]
1512 # spice_bind is known to be a valid IP address, because
1513 # ValidateParameters checked it.
1514 spice_address = spice_bind
1516 spice_arg = "addr=%s" % spice_address
1517 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1518 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1519 (spice_arg, instance.network_port,
1520 pathutils.SPICE_CACERT_FILE))
1521 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1522 (spice_arg, pathutils.SPICE_CERT_FILE,
1523 pathutils.SPICE_CERT_FILE))
1524 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1526 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1528 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1530 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1531 spice_arg = "%s,disable-ticketing" % spice_arg
1533 if spice_ip_version:
1534 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1536 # Image compression options
1537 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1538 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1539 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1541 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1543 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1545 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1547 # Video stream detection
1548 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1550 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1552 # Audio compression, by default in qemu-kvm it is on
1553 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1554 spice_arg = "%s,playback-compression=off" % spice_arg
1555 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1556 spice_arg = "%s,agent-mouse=off" % spice_arg
1558 # Enable the spice agent communication channel between the host and the
1560 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1563 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1565 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1567 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1568 kvm_cmd.extend(["-spice", spice_arg])
1571 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1572 # also works in earlier versions though (tested with 1.1 and 1.3)
1573 if self._DISPLAY_RE.search(kvmhelp):
1574 kvm_cmd.extend(["-display", "none"])
1576 kvm_cmd.extend(["-nographic"])
1578 if hvp[constants.HV_USE_LOCALTIME]:
1579 kvm_cmd.extend(["-localtime"])
1581 if hvp[constants.HV_KVM_USE_CHROOT]:
1582 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1584 # Add qemu-KVM -cpu param
1585 if hvp[constants.HV_CPU_TYPE]:
1586 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1588 # As requested by music lovers
1589 if hvp[constants.HV_SOUNDHW]:
1590 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1592 # Pass a -vga option if requested, or if spice is used, for backwards
1594 if hvp[constants.HV_VGA]:
1595 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1597 kvm_cmd.extend(["-vga", "qxl"])
1599 # Various types of usb devices, comma separated
1600 if hvp[constants.HV_USB_DEVICES]:
1601 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1602 kvm_cmd.extend(["-usbdevice", dev])
1604 if hvp[constants.HV_KVM_EXTRA]:
1605 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1607 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1609 for disk, link_name in block_devices:
1610 _UpdatePCISlots(disk, pci_reservations)
1611 kvm_disks.append((disk, link_name))
1614 for nic in instance.nics:
1615 _UpdatePCISlots(nic, pci_reservations)
1616 kvm_nics.append(nic)
1620 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1622 def _WriteKVMRuntime(self, instance_name, data):
1623 """Write an instance's KVM runtime
1627 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1629 except EnvironmentError, err:
1630 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1632 def _ReadKVMRuntime(self, instance_name):
1633 """Read an instance's KVM runtime
1637 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1638 except EnvironmentError, err:
1639 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1642 def _SaveKVMRuntime(self, instance, kvm_runtime):
1643 """Save an instance's KVM runtime
1646 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1648 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1649 serialized_disks = [(blk.ToDict(), link)
1650 for blk, link in kvm_disks]
1651 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1654 self._WriteKVMRuntime(instance.name, serialized_form)
1656 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1657 """Load an instance's KVM runtime
1660 if not serialized_runtime:
1661 serialized_runtime = self._ReadKVMRuntime(instance.name)
1663 return _AnalyzeSerializedRuntime(serialized_runtime)
1665 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1666 """Run the KVM cmd and check for errors
1669 @param name: instance name
1670 @type kvm_cmd: list of strings
1671 @param kvm_cmd: runcmd input for kvm
1672 @type tap_fds: list of int
1673 @param tap_fds: fds of tap devices opened by Ganeti
1677 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1680 utils_wrapper.CloseFdNoError(fd)
1683 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1684 (name, result.fail_reason, result.output))
1685 if not self._InstancePidAlive(name)[2]:
1686 raise errors.HypervisorError("Failed to start instance %s" % name)
1688 # too many local variables
1689 # pylint: disable=R0914
1690 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1691 """Execute a KVM cmd, after completing it with some last minute data.
1693 @type incoming: tuple of strings
1694 @param incoming: (target_host_ip, port)
1695 @type kvmhelp: string
1696 @param kvmhelp: output of kvm --help
1699 # Small _ExecuteKVMRuntime hv parameters programming howto:
1700 # - conf_hvp contains the parameters as configured on ganeti. they might
1701 # have changed since the instance started; only use them if the change
1702 # won't affect the inside of the instance (which hasn't been rebooted).
1703 # - up_hvp contains the parameters as they were when the instance was
1704 # started, plus any new parameter which has been added between ganeti
1705 # versions: it is paramount that those default to a value which won't
1706 # affect the inside of the instance as well.
1707 conf_hvp = instance.hvparams
1708 name = instance.name
1709 self._CheckDown(name)
1713 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1714 # the first element of kvm_cmd is always the path to the kvm binary
1715 kvm_path = kvm_cmd[0]
1716 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1718 # We know it's safe to run as a different user upon migration, so we'll use
1719 # the latest conf, from conf_hvp.
1720 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1721 if security_model == constants.HT_SM_USER:
1722 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1724 keymap = conf_hvp[constants.HV_KEYMAP]
1726 keymap_path = self._InstanceKeymapFile(name)
1727 # If a keymap file is specified, KVM won't use its internal defaults. By
1728 # first including the "en-us" layout, an error on loading the actual
1729 # layout (e.g. because it can't be found) won't lead to a non-functional
1730 # keyboard. A keyboard with incorrect keys is still better than none.
1731 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1732 kvm_cmd.extend(["-k", keymap_path])
1734 # We have reasons to believe changing something like the nic driver/type
1735 # upon migration won't exactly fly with the instance kernel, so for nic
1736 # related parameters we'll use up_hvp
1739 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1741 kvm_cmd.extend(["-net", "none"])
1745 nic_type = up_hvp[constants.HV_NIC_TYPE]
1746 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1747 nic_model = self._VIRTIO
1749 if self._VIRTIO_NET_RE.search(devlist):
1750 nic_model = self._VIRTIO_NET_PCI
1751 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1752 except errors.HypervisorError, _:
1753 # Older versions of kvm don't support DEVICE_LIST, but they don't
1754 # have new virtio syntax either.
1757 if up_hvp[constants.HV_VHOST_NET]:
1758 # check for vhost_net support
1759 if self._VHOST_RE.search(kvmhelp):
1760 tap_extra = ",vhost=on"
1762 raise errors.HypervisorError("vhost_net is configured"
1763 " but it is not available")
1765 nic_model = nic_type
1767 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1769 for nic_seq, nic in enumerate(kvm_nics):
1770 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1771 tapfds.append(tapfd)
1772 taps.append(tapname)
1773 if kvm_supports_netdev:
1774 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1776 # kvm_nics already exist in old runtime files and thus there might
1777 # be some entries without pci slot (therefore try: except:)
1778 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1780 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1781 except errors.HotplugError:
1782 netdev = "netdev%d" % nic_seq
1783 nic_val += (",netdev=%s" % netdev)
1784 tap_val = ("type=tap,id=%s,fd=%d%s" %
1785 (netdev, tapfd, tap_extra))
1786 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1788 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1790 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1791 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1794 target, port = incoming
1795 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1797 # Changing the vnc password doesn't bother the guest that much. At most it
1798 # will surprise people who connect to it. Whether positively or negatively
1800 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1804 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1805 except EnvironmentError, err:
1806 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1807 % (vnc_pwd_file, err))
1809 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1810 utils.EnsureDirs([(self._InstanceChrootDir(name),
1811 constants.SECURE_DIR_MODE)])
1813 # Automatically enable QMP if version is >= 0.14
1814 if self._QMP_RE.search(kvmhelp):
1815 logging.debug("Enabling QMP")
1816 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1817 self._InstanceQmpMonitor(instance.name)])
1819 # Configure the network now for starting instances and bridged interfaces,
1820 # during FinalizeMigration for incoming instances' routed interfaces
1821 for nic_seq, nic in enumerate(kvm_nics):
1823 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1825 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1827 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1831 kvm_cmd.extend(bdev_opts)
1832 # CPU affinity requires kvm to start paused, so we set this flag if the
1833 # instance is not already paused and if we are not going to accept a
1834 # migrating instance. In the latter case, pausing is not needed.
1835 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1836 if start_kvm_paused:
1837 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1839 # Note: CPU pinning is using up_hvp since changes take effect
1840 # during instance startup anyway, and to avoid problems when soft
1841 # rebooting the instance.
1843 if up_hvp.get(constants.HV_CPU_MASK, None):
1846 if security_model == constants.HT_SM_POOL:
1847 ss = ssconf.SimpleStore()
1848 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1849 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1850 uid = uidpool.RequestUnusedUid(all_uids)
1852 username = pwd.getpwuid(uid.GetUid()).pw_name
1853 kvm_cmd.extend(["-runas", username])
1854 self._RunKVMCmd(name, kvm_cmd, tapfds)
1856 uidpool.ReleaseUid(uid)
1860 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1862 self._RunKVMCmd(name, kvm_cmd, tapfds)
1864 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1865 constants.RUN_DIRS_MODE)])
1866 for nic_seq, tap in enumerate(taps):
1867 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1871 change_cmd = "change vnc password %s" % vnc_pwd
1872 self._CallMonitorCommand(instance.name, change_cmd)
1874 # Setting SPICE password. We are not vulnerable to malicious passwordless
1875 # connection attempts because SPICE by default does not allow connections
1876 # if neither a password nor the "disable_ticketing" options are specified.
1877 # As soon as we send the password via QMP, that password is a valid ticket
1879 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1880 if spice_password_file:
1883 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1884 except EnvironmentError, err:
1885 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1886 % (spice_password_file, err))
1888 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1891 "protocol": "spice",
1892 "password": spice_pwd,
1894 qmp.Execute("set_password", arguments)
1896 for filename in temp_files:
1897 utils.RemoveFile(filename)
1899 # If requested, set CPU affinity and resume instance execution
1901 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1903 start_memory = self._InstanceStartupMemory(instance)
1904 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1905 self.BalloonInstanceMemory(instance, start_memory)
1907 if start_kvm_paused:
1908 # To control CPU pinning, ballooning, and vnc/spice passwords
1909 # the VM was started in a frozen state. If freezing was not
1910 # explicitly requested resume the vm status.
1911 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1913 def StartInstance(self, instance, block_devices, startup_paused):
1914 """Start an instance.
1917 self._CheckDown(instance.name)
1918 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1919 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1920 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1921 startup_paused, kvmhelp)
1922 self._SaveKVMRuntime(instance, kvm_runtime)
1923 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1925 def _CallMonitorCommand(self, instance_name, command, timeout=None):
1926 """Invoke a command on the instance monitor.
1929 if timeout is not None:
1930 timeout_cmd = "timeout %s" % (timeout, )
1934 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1935 # version. The monitor protocol is designed for human consumption, whereas
1936 # QMP is made for programmatic usage. In the worst case QMP can also
1937 # execute monitor commands. As it is, all calls to socat take at least
1938 # 500ms and likely more: socat can't detect the end of the reply and waits
1939 # for 500ms of no data received before exiting (500 ms is the default for
1940 # the "-t" parameter).
1941 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1942 (utils.ShellQuote(command),
1944 constants.SOCAT_PATH,
1945 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1947 result = utils.RunCmd(socat)
1949 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1951 (command, instance_name, result.fail_reason, result.output))
1952 raise errors.HypervisorError(msg)
1956 def _GetFreePCISlot(self, instance, dev):
1957 """Get the first available pci slot of a runnung instance.
1960 slots = bitarray(32)
1961 slots.setall(False) # pylint: disable=E1101
1962 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1963 for line in output.stdout.splitlines():
1964 match = self._INFO_PCI_RE.search(line)
1966 slot = int(match.group(1))
1969 [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1971 raise errors.HypervisorError("All PCI slots occupied")
1975 def VerifyHotplugSupport(self, instance, action, dev_type):
1976 """Verifies that hotplug is supported.
1978 Hotplug is *not* supported in case of:
1979 - security models and chroot (disk hotplug)
1980 - fdsend module is missing (nic hot-add)
1982 @raise errors.HypervisorError: in one of the previous cases
1985 if dev_type == constants.HOTPLUG_TARGET_DISK:
1986 hvp = instance.hvparams
1987 security_model = hvp[constants.HV_SECURITY_MODEL]
1988 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
1990 raise errors.HotplugError("Disk hotplug is not supported"
1991 " in case of chroot.")
1992 if security_model != constants.HT_SM_NONE:
1993 raise errors.HotplugError("Disk Hotplug is not supported in case"
1994 " security models are used.")
1996 if (dev_type == constants.HOTPLUG_TARGET_NIC and
1997 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
1998 raise errors.HotplugError("Cannot hot-add NIC."
1999 " fdsend python module is missing.")
2001 def HotplugSupported(self, instance):
2002 """Checks if hotplug is generally supported.
2004 Hotplug is *not* supported in case of:
2005 - qemu versions < 1.0
2006 - for stopped instances
2008 @raise errors.HypervisorError: in one of the previous cases
2012 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2013 except errors.HypervisorError:
2014 raise errors.HotplugError("Instance is probably down")
2016 # TODO: search for netdev_add, drive_add, device_add.....
2017 match = self._INFO_VERSION_RE.search(output.stdout)
2019 raise errors.HotplugError("Cannot parse qemu version via monitor")
2021 v_major, v_min, _, _ = match.groups()
2022 if (int(v_major), int(v_min)) < (1, 0):
2023 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2025 def _CallHotplugCommand(self, name, cmd):
2026 output = self._CallMonitorCommand(name, cmd)
2027 # TODO: parse output and check if succeeded
2028 for line in output.stdout.splitlines():
2029 logging.info("%s", line)
2031 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2032 """ Helper method to hot-add a new device
2034 It gets free pci slot generates the device name and invokes the
2035 device specific method.
2038 # in case of hot-mod this is given
2039 if device.pci is None:
2040 self._GetFreePCISlot(instance, device)
2041 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2042 runtime = self._LoadKVMRuntime(instance)
2043 if dev_type == constants.HOTPLUG_TARGET_DISK:
2044 command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2046 command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2047 (hex(device.pci), kvm_devid, kvm_devid))
2048 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2049 (tap, fd) = _OpenTap()
2050 self._ConfigureNIC(instance, seq, device, tap)
2051 self._PassTapFd(instance, fd, device)
2052 command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2053 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2054 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2055 command += "device_add %s" % args
2056 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2058 self._CallHotplugCommand(instance.name, command)
2059 # update relevant entries in runtime file
2060 index = _DEVICE_RUNTIME_INDEX[dev_type]
2061 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2062 runtime[index].append(entry)
2063 self._SaveKVMRuntime(instance, runtime)
2065 def HotDelDevice(self, instance, dev_type, device, _, seq):
2066 """ Helper method for hot-del device
2068 It gets device info from runtime file, generates the device name and
2069 invokes the device specific method.
2072 runtime = self._LoadKVMRuntime(instance)
2073 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2074 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2075 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2076 if dev_type == constants.HOTPLUG_TARGET_DISK:
2077 command = "device_del %s\n" % kvm_devid
2078 command += "drive_del %s" % kvm_devid
2079 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2080 command = "device_del %s\n" % kvm_devid
2081 command += "netdev_del %s" % kvm_devid
2082 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2083 self._CallHotplugCommand(instance.name, command)
2084 index = _DEVICE_RUNTIME_INDEX[dev_type]
2085 runtime[index].remove(entry)
2086 self._SaveKVMRuntime(instance, runtime)
2088 return kvm_device.pci
2090 def HotModDevice(self, instance, dev_type, device, _, seq):
2091 """ Helper method for hot-mod device
2093 It gets device info from runtime file, generates the device name and
2094 invokes the device specific method. Currently only NICs support hot-mod
2097 if dev_type == constants.HOTPLUG_TARGET_NIC:
2098 # putting it back in the same pci slot
2099 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2100 # TODO: remove sleep when socat gets removed
2102 self.HotAddDevice(instance, dev_type, device, _, seq)
2104 def _PassTapFd(self, instance, fd, nic):
2105 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2108 # TODO: factor out code related to unix sockets.
2109 # squash common parts between monitor and qmp
2110 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2111 command = "getfd %s\n" % kvm_devid
2113 logging.info("%s", fds)
2115 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2117 fdsend.sendfds(monsock.sock, command, fds=fds)
2122 def _ParseKVMVersion(cls, text):
2123 """Parse the KVM version from the --help output.
2126 @param text: output of kvm --help
2127 @return: (version, v_maj, v_min, v_rev)
2128 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2131 match = cls._VERSION_RE.search(text.splitlines()[0])
2133 raise errors.HypervisorError("Unable to get KVM version")
2135 v_all = match.group(0)
2136 v_maj = int(match.group(1))
2137 v_min = int(match.group(2))
2139 v_rev = int(match.group(4))
2142 return (v_all, v_maj, v_min, v_rev)
2145 def _GetKVMOutput(cls, kvm_path, option):
2146 """Return the output of a kvm invocation
2148 @type kvm_path: string
2149 @param kvm_path: path to the kvm executable
2150 @type option: a key of _KVMOPTS_CMDS
2151 @param option: kvm option to fetch the output from
2152 @return: output a supported kvm invocation
2153 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2156 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2158 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2160 result = utils.RunCmd([kvm_path] + optlist)
2161 if result.failed and not can_fail:
2162 raise errors.HypervisorError("Unable to get KVM %s output" %
2164 return result.output
2167 def _GetKVMVersion(cls, kvm_path):
2168 """Return the installed KVM version.
2170 @return: (version, v_maj, v_min, v_rev)
2171 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2174 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2177 def _GetDefaultMachineVersion(cls, kvm_path):
2178 """Return the default hardware revision (e.g. pc-1.1)
2181 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2182 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2184 return match.group(1)
2188 def StopInstance(self, instance, force=False, retry=False, name=None,
2190 """Stop an instance.
2193 assert(timeout is None or force is not None)
2195 if name is not None and not force:
2196 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2198 name = instance.name
2199 acpi = instance.hvparams[constants.HV_ACPI]
2202 _, pid, alive = self._InstancePidAlive(name)
2203 if pid > 0 and alive:
2204 if force or not acpi:
2205 utils.KillProcess(pid)
2207 self._CallMonitorCommand(name, "system_powerdown", timeout)
2209 def CleanupInstance(self, instance_name):
2210 """Cleanup after a stopped instance
2213 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2214 if pid > 0 and alive:
2215 raise errors.HypervisorError("Cannot cleanup a live instance")
2216 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2218 def RebootInstance(self, instance):
2219 """Reboot an instance.
2222 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2223 # socket the instance will stop, but now power up again. So we'll resort
2224 # to shutdown and restart.
2225 _, _, alive = self._InstancePidAlive(instance.name)
2227 raise errors.HypervisorError("Failed to reboot instance %s:"
2228 " not running" % instance.name)
2229 # StopInstance will delete the saved KVM runtime so:
2230 # ...first load it...
2231 kvm_runtime = self._LoadKVMRuntime(instance)
2232 # ...now we can safely call StopInstance...
2233 if not self.StopInstance(instance):
2234 self.StopInstance(instance, force=True)
2235 # ...and finally we can save it again, and execute it...
2236 self._SaveKVMRuntime(instance, kvm_runtime)
2237 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2238 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2239 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2241 def MigrationInfo(self, instance):
2242 """Get instance information to perform a migration.
2244 @type instance: L{objects.Instance}
2245 @param instance: instance to be migrated
2247 @return: content of the KVM runtime file
2250 return self._ReadKVMRuntime(instance.name)
2252 def AcceptInstance(self, instance, info, target):
2253 """Prepare to accept an instance.
2255 @type instance: L{objects.Instance}
2256 @param instance: instance to be accepted
2258 @param info: content of the KVM runtime file on the source node
2259 @type target: string
2260 @param target: target host (usually ip), on this node
2263 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2264 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2265 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2266 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2267 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2268 incoming=incoming_address)
2270 def FinalizeMigrationDst(self, instance, info, success):
2271 """Finalize the instance migration on the target node.
2273 Stop the incoming mode KVM.
2275 @type instance: L{objects.Instance}
2276 @param instance: instance whose migration is being finalized
2280 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2281 kvm_nics = kvm_runtime[1]
2283 for nic_seq, nic in enumerate(kvm_nics):
2284 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2285 # Bridged interfaces have already been configured
2288 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2289 except EnvironmentError, err:
2290 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2291 instance.name, nic_seq, str(err))
2294 self._ConfigureNIC(instance, nic_seq, nic, tap)
2295 except errors.HypervisorError, err:
2296 logging.warning(str(err))
2298 self._WriteKVMRuntime(instance.name, info)
2300 self.StopInstance(instance, force=True)
2302 def MigrateInstance(self, instance, target, live):
2303 """Migrate an instance to a target node.
2305 The migration will not be attempted if the instance is not
2308 @type instance: L{objects.Instance}
2309 @param instance: the instance to be migrated
2310 @type target: string
2311 @param target: ip address of the target node
2313 @param live: perform a live migration
2316 instance_name = instance.name
2317 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2318 _, _, alive = self._InstancePidAlive(instance_name)
2320 raise errors.HypervisorError("Instance not running, cannot migrate")
2323 self._CallMonitorCommand(instance_name, "stop")
2325 migrate_command = ("migrate_set_speed %dm" %
2326 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2327 self._CallMonitorCommand(instance_name, migrate_command)
2329 migrate_command = ("migrate_set_downtime %dms" %
2330 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2331 self._CallMonitorCommand(instance_name, migrate_command)
2333 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2334 self._CallMonitorCommand(instance_name, migrate_command)
2336 def FinalizeMigrationSource(self, instance, success, live):
2337 """Finalize the instance migration on the source node.
2339 @type instance: L{objects.Instance}
2340 @param instance: the instance that was migrated
2342 @param success: whether the migration succeeded or not
2344 @param live: whether the user requested a live migration or not
2348 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2349 utils.KillProcess(pid)
2350 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2352 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2354 def GetMigrationStatus(self, instance):
2355 """Get the migration status
2357 @type instance: L{objects.Instance}
2358 @param instance: the instance that is being migrated
2359 @rtype: L{objects.MigrationStatus}
2360 @return: the status of the current migration (one of
2361 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2362 progress info that can be retrieved from the hypervisor
2365 info_command = "info migrate"
2366 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2367 result = self._CallMonitorCommand(instance.name, info_command)
2368 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2370 if not result.stdout:
2371 logging.info("KVM: empty 'info migrate' result")
2373 logging.warning("KVM: unknown 'info migrate' result: %s",
2376 status = match.group(1)
2377 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2378 migration_status = objects.MigrationStatus(status=status)
2379 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2381 migration_status.transferred_ram = match.group("transferred")
2382 migration_status.total_ram = match.group("total")
2384 return migration_status
2386 logging.warning("KVM: unknown migration status '%s'", status)
2388 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2390 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2392 def BalloonInstanceMemory(self, instance, mem):
2393 """Balloon an instance memory to a certain value.
2395 @type instance: L{objects.Instance}
2396 @param instance: instance to be accepted
2398 @param mem: actual memory size to use for instance runtime
2401 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2403 def GetNodeInfo(self):
2404 """Return information about the node.
2406 @return: a dict with the following keys (values in MiB):
2407 - memory_total: the total memory size on the node
2408 - memory_free: the available memory on the node for instances
2409 - memory_dom0: the memory used by the node itself, if available
2410 - hv_version: the hypervisor version in the form (major, minor,
2414 result = self.GetLinuxNodeInfo()
2415 # FIXME: this is the global kvm version, but the actual version can be
2416 # customized as an hv parameter. we should use the nodegroup's default kvm
2417 # path parameter here.
2418 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2419 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2423 def GetInstanceConsole(cls, instance, hvparams, beparams):
2424 """Return a command for connecting to the console of an instance.
2427 if hvparams[constants.HV_SERIAL_CONSOLE]:
2428 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2429 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2430 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2431 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2432 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2433 return objects.InstanceConsole(instance=instance.name,
2434 kind=constants.CONS_SSH,
2435 host=instance.primary_node,
2436 user=constants.SSH_CONSOLE_USER,
2439 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2440 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2441 display = instance.network_port - constants.VNC_BASE_PORT
2442 return objects.InstanceConsole(instance=instance.name,
2443 kind=constants.CONS_VNC,
2444 host=vnc_bind_address,
2445 port=instance.network_port,
2448 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2450 return objects.InstanceConsole(instance=instance.name,
2451 kind=constants.CONS_SPICE,
2453 port=instance.network_port)
2455 return objects.InstanceConsole(instance=instance.name,
2456 kind=constants.CONS_MESSAGE,
2457 message=("No serial shell for instance %s" %
2461 """Verify the hypervisor.
2463 Check that the required binaries exist.
2465 @return: Problem description if something is wrong, C{None} otherwise
2469 # FIXME: this is the global kvm binary, but the actual path can be
2470 # customized as an hv parameter; we should use the nodegroup's
2471 # default kvm path parameter here.
2472 if not os.path.exists(constants.KVM_PATH):
2473 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2474 if not os.path.exists(constants.SOCAT_PATH):
2475 msgs.append("The socat binary ('%s') does not exist" %
2476 constants.SOCAT_PATH)
2478 return self._FormatVerifyResults(msgs)
2481 def CheckParameterSyntax(cls, hvparams):
2482 """Check the given parameters for validity.
2484 @type hvparams: dict
2485 @param hvparams: dictionary with parameter names/value
2486 @raise errors.HypervisorError: when a parameter is not valid
2489 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2491 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2493 if not hvparams[constants.HV_ROOT_PATH]:
2494 raise errors.HypervisorError("Need a root partition for the instance,"
2495 " if a kernel is defined")
2497 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2498 not hvparams[constants.HV_VNC_X509]):
2499 raise errors.HypervisorError("%s must be defined, if %s is" %
2500 (constants.HV_VNC_X509,
2501 constants.HV_VNC_X509_VERIFY))
2503 if hvparams[constants.HV_SERIAL_CONSOLE]:
2504 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2505 valid_speeds = constants.VALID_SERIAL_SPEEDS
2506 if not serial_speed or serial_speed not in valid_speeds:
2507 raise errors.HypervisorError("Invalid serial console speed, must be"
2509 utils.CommaJoin(valid_speeds))
2511 boot_order = hvparams[constants.HV_BOOT_ORDER]
2512 if (boot_order == constants.HT_BO_CDROM and
2513 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2514 raise errors.HypervisorError("Cannot boot from cdrom without an"
2517 security_model = hvparams[constants.HV_SECURITY_MODEL]
2518 if security_model == constants.HT_SM_USER:
2519 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2520 raise errors.HypervisorError("A security domain (user to run kvm as)"
2521 " must be specified")
2522 elif (security_model == constants.HT_SM_NONE or
2523 security_model == constants.HT_SM_POOL):
2524 if hvparams[constants.HV_SECURITY_DOMAIN]:
2525 raise errors.HypervisorError("Cannot have a security domain when the"
2526 " security model is 'none' or 'pool'")
2528 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2529 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2531 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2532 # if an IP version is specified, the spice_bind parameter must be an
2534 if (netutils.IP4Address.IsValid(spice_bind) and
2535 spice_ip_version != constants.IP4_VERSION):
2536 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2537 " the specified IP version is %s" %
2538 (spice_bind, spice_ip_version))
2540 if (netutils.IP6Address.IsValid(spice_bind) and
2541 spice_ip_version != constants.IP6_VERSION):
2542 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2543 " the specified IP version is %s" %
2544 (spice_bind, spice_ip_version))
2546 # All the other SPICE parameters depend on spice_bind being set. Raise an
2547 # error if any of them is set without it.
2548 for param in _SPICE_ADDITIONAL_PARAMS:
2550 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2551 (param, constants.HV_KVM_SPICE_BIND))
2554 def ValidateParameters(cls, hvparams):
2555 """Check the given parameters for validity.
2557 @type hvparams: dict
2558 @param hvparams: dictionary with parameter names/value
2559 @raise errors.HypervisorError: when a parameter is not valid
2562 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2564 kvm_path = hvparams[constants.HV_KVM_PATH]
2566 security_model = hvparams[constants.HV_SECURITY_MODEL]
2567 if security_model == constants.HT_SM_USER:
2568 username = hvparams[constants.HV_SECURITY_DOMAIN]
2570 pwd.getpwnam(username)
2572 raise errors.HypervisorError("Unknown security domain user %s"
2575 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2577 # only one of VNC and SPICE can be used currently.
2578 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2579 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2580 " only one of them can be used at a"
2583 # check that KVM supports SPICE
2584 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2585 if not cls._SPICE_RE.search(kvmhelp):
2586 raise errors.HypervisorError("SPICE is configured, but it is not"
2587 " supported according to 'kvm --help'")
2589 # if spice_bind is not an IP address, it must be a valid interface
2590 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2591 netutils.IP6Address.IsValid(spice_bind))
2592 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2593 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2594 " a valid IP address or interface name" %
2595 constants.HV_KVM_SPICE_BIND)
2597 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2599 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2600 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2601 raise errors.HypervisorError("Unsupported machine version: %s" %
2605 def PowercycleNode(cls):
2606 """KVM powercycle, just a wrapper over Linux powercycle.
2609 cls.LinuxPowercycle()