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, idx=None):
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)
133 # proper device id - available in latest Ganeti versions
134 if dev.pci and dev.uuid:
135 return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
137 # dummy device id - returned only to _GenerateKVMBlockDevicesOptions
138 # This enables -device option for paravirtual disk_type
140 return "%s-%d" % (dev_type.lower(), idx)
142 raise errors.HotplugError("Hotplug is not supported for devices"
143 " without UUID or PCI info")
146 def _UpdatePCISlots(dev, pci_reservations):
147 """Update pci configuration for a stopped instance
149 If dev has a pci slot then reserve it, else find first available
150 in pci_reservations bitarray. It acts on the same objects passed
151 as params so there is no need to return anything.
153 @type dev: L{objects.Disk} or L{objects.NIC}
154 @param dev: the device object for which we update its pci slot
155 @type pci_reservations: bitarray
156 @param pci_reservations: existing pci reservations for an instance
157 @raise errors.HotplugError: in case an instance has all its slot occupied
162 else: # pylint: disable=E1103
163 [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
165 raise errors.HypervisorError("All PCI slots occupied")
168 pci_reservations[free] = True
171 def _GetExistingDeviceInfo(dev_type, device, runtime):
172 """Helper function to get an existing device inside the runtime file
174 Used when an instance is running. Load kvm runtime file and search
175 for a device based on its type and uuid.
177 @type dev_type: sting
178 @param dev_type: device type of param dev
179 @type device: L{objects.Disk} or L{objects.NIC}
180 @param device: the device object for which we generate a kvm name
181 @type runtime: tuple (cmd, nics, hvparams, disks)
182 @param runtime: the runtime data to search for the device
183 @raise errors.HotplugError: in case the requested device does not
184 exist (e.g. device has been added without --hotplug option) or
185 device info has not pci slot (e.g. old devices in the cluster)
188 index = _DEVICE_RUNTIME_INDEX[dev_type]
189 found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
191 raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
192 (dev_type, device.uuid))
197 def _UpgradeSerializedRuntime(serialized_runtime):
198 """Upgrade runtime data
200 Remove any deprecated fields or change the format of the data.
201 The runtime files are not upgraded when Ganeti is upgraded, so the required
202 modification have to be performed here.
204 @type serialized_runtime: string
205 @param serialized_runtime: raw text data read from actual runtime file
206 @return: (cmd, nic dicts, hvparams, bdev dicts)
210 loaded_runtime = serializer.Load(serialized_runtime)
211 kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
212 if len(loaded_runtime) >= 4:
213 serialized_disks = loaded_runtime[3]
215 serialized_disks = []
217 for nic in serialized_nics:
218 # Add a dummy uuid slot if an pre-2.8 NIC is found
219 if "uuid" not in nic:
220 nic["uuid"] = utils.NewUUID()
222 return kvm_cmd, serialized_nics, hvparams, serialized_disks
225 def _AnalyzeSerializedRuntime(serialized_runtime):
226 """Return runtime entries for a serialized runtime file
228 @type serialized_runtime: string
229 @param serialized_runtime: raw text data read from actual runtime file
230 @return: (cmd, nics, hvparams, bdevs)
234 kvm_cmd, serialized_nics, hvparams, serialized_disks = \
235 _UpgradeSerializedRuntime(serialized_runtime)
236 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
237 kvm_disks = [(objects.Disk.FromDict(sdisk), link)
238 for sdisk, link in serialized_disks]
240 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
243 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
244 """Retrieves supported TUN features from file descriptor.
246 @see: L{_ProbeTapVnetHdr}
249 req = struct.pack("I", 0)
251 buf = _ioctl(fd, TUNGETFEATURES, req)
252 except EnvironmentError, err:
253 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
256 (flags, ) = struct.unpack("I", buf)
260 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
261 """Check whether to enable the IFF_VNET_HDR flag.
263 To do this, _all_ of the following conditions must be met:
264 1. TUNGETFEATURES ioctl() *must* be implemented
265 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
266 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
267 drivers/net/tun.c there is no way to test this until after the tap device
268 has been created using TUNSETIFF, and there is no way to change the
269 IFF_VNET_HDR flag after creating the interface, catch-22! However both
270 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
271 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
274 @param fd: the file descriptor of /dev/net/tun
277 flags = _features_fn(fd)
283 result = bool(flags & IFF_VNET_HDR)
286 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
291 def _OpenTap(vnet_hdr=True):
292 """Open a new tap device and return its file descriptor.
294 This is intended to be used by a qemu-type hypervisor together with the -net
295 tap,fd=<fd> command line parameter.
297 @type vnet_hdr: boolean
298 @param vnet_hdr: Enable the VNET Header
299 @return: (ifname, tapfd)
304 tapfd = os.open("/dev/net/tun", os.O_RDWR)
305 except EnvironmentError:
306 raise errors.HypervisorError("Failed to open /dev/net/tun")
308 flags = IFF_TAP | IFF_NO_PI
310 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
311 flags |= IFF_VNET_HDR
313 # The struct ifreq ioctl request (see netdevice(7))
314 ifr = struct.pack("16sh", "", flags)
317 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
318 except EnvironmentError, err:
319 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
322 # Get the interface name from the ioctl
323 ifname = struct.unpack("16sh", res)[0].strip("\x00")
324 return (ifname, tapfd)
328 """QEMU Messaging Protocol (QMP) message.
331 def __init__(self, data):
332 """Creates a new QMP message based on the passed data.
335 if not isinstance(data, dict):
336 raise TypeError("QmpMessage must be initialized with a dict")
340 def __getitem__(self, field_name):
341 """Get the value of the required field if present, or None.
343 Overrides the [] operator to provide access to the message data,
344 returning None if the required item is not in the message
345 @return: the value of the field_name field, or None if field_name
346 is not contained in the message
349 return self.data.get(field_name, None)
351 def __setitem__(self, field_name, field_value):
352 """Set the value of the required field_name to field_value.
355 self.data[field_name] = field_value
358 def BuildFromJsonString(json_string):
359 """Build a QmpMessage from a JSON encoded string.
361 @type json_string: str
362 @param json_string: JSON string representing the message
363 @rtype: L{QmpMessage}
364 @return: a L{QmpMessage} built from json_string
368 data = serializer.LoadJson(json_string)
369 return QmpMessage(data)
372 # The protocol expects the JSON object to be sent as a single line.
373 return serializer.DumpJson(self.data)
375 def __eq__(self, other):
376 # When comparing two QmpMessages, we are interested in comparing
377 # their internal representation of the message data
378 return self.data == other.data
381 class MonitorSocket(object):
384 def __init__(self, monitor_filename):
385 """Instantiates the MonitorSocket object.
387 @type monitor_filename: string
388 @param monitor_filename: the filename of the UNIX raw socket on which the
389 monitor (QMP or simple one) is listening
392 self.monitor_filename = monitor_filename
393 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
394 # We want to fail if the server doesn't send a complete message
395 # in a reasonable amount of time
396 self.sock.settimeout(self._SOCKET_TIMEOUT)
397 self._connected = False
399 def _check_socket(self):
402 sock_stat = os.stat(self.monitor_filename)
403 except EnvironmentError, err:
404 if err.errno == errno.ENOENT:
405 raise errors.HypervisorError("No monitor socket found")
407 raise errors.HypervisorError("Error checking monitor socket: %s",
408 utils.ErrnoOrStr(err))
409 if not stat.S_ISSOCK(sock_stat.st_mode):
410 raise errors.HypervisorError("Monitor socket is not a socket")
412 def _check_connection(self):
413 """Make sure that the connection is established.
416 if not self._connected:
417 raise errors.ProgrammerError("To use a MonitorSocket you need to first"
418 " invoke connect() on it")
421 """Connects to the monitor.
423 Connects to the UNIX socket
425 @raise errors.HypervisorError: when there are communication errors
429 raise errors.ProgrammerError("Cannot connect twice")
433 # Check file existance/stuff
435 self.sock.connect(self.monitor_filename)
436 except EnvironmentError:
437 raise errors.HypervisorError("Can't connect to qmp socket")
438 self._connected = True
443 It cannot be used after this call.
449 class QmpConnection(MonitorSocket):
450 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
453 _FIRST_MESSAGE_KEY = "QMP"
456 _RETURN_KEY = RETURN_KEY = "return"
457 _ACTUAL_KEY = ACTUAL_KEY = "actual"
458 _ERROR_CLASS_KEY = "class"
459 _ERROR_DESC_KEY = "desc"
460 _EXECUTE_KEY = "execute"
461 _ARGUMENTS_KEY = "arguments"
462 _CAPABILITIES_COMMAND = "qmp_capabilities"
463 _MESSAGE_END_TOKEN = "\r\n"
465 def __init__(self, monitor_filename):
466 super(QmpConnection, self).__init__(monitor_filename)
470 """Connects to the QMP monitor.
472 Connects to the UNIX socket and makes sure that we can actually send and
473 receive data to the kvm instance via QMP.
475 @raise errors.HypervisorError: when there are communication errors
476 @raise errors.ProgrammerError: when there are data serialization errors
479 super(QmpConnection, self).connect()
480 # Check if we receive a correct greeting message from the server
481 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
482 greeting = self._Recv()
483 if not greeting[self._FIRST_MESSAGE_KEY]:
484 self._connected = False
485 raise errors.HypervisorError("kvm: QMP communication error (wrong"
488 # Let's put the monitor in command mode using the qmp_capabilities
489 # command, or else no command will be executable.
490 # (As per the QEMU Protocol Specification 0.1 - section 4)
491 self.Execute(self._CAPABILITIES_COMMAND)
493 def _ParseMessage(self, buf):
494 """Extract and parse a QMP message from the given buffer.
496 Seeks for a QMP message in the given buf. If found, it parses it and
497 returns it together with the rest of the characters in the buf.
498 If no message is found, returns None and the whole buffer.
500 @raise errors.ProgrammerError: when there are data serialization errors
504 # Check if we got the message end token (CRLF, as per the QEMU Protocol
505 # Specification 0.1 - Section 2.1.1)
506 pos = buf.find(self._MESSAGE_END_TOKEN)
509 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
510 except Exception, err:
511 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
514 return (message, buf)
517 """Receives a message from QMP and decodes the received JSON object.
520 @return: the received message
521 @raise errors.HypervisorError: when there are communication errors
522 @raise errors.ProgrammerError: when there are data serialization errors
525 self._check_connection()
527 # Check if there is already a message in the buffer
528 (message, self._buf) = self._ParseMessage(self._buf)
532 recv_buffer = StringIO.StringIO(self._buf)
533 recv_buffer.seek(len(self._buf))
536 data = self.sock.recv(4096)
539 recv_buffer.write(data)
541 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
545 except socket.timeout, err:
546 raise errors.HypervisorError("Timeout while receiving a QMP message: "
548 except socket.error, err:
549 raise errors.HypervisorError("Unable to receive data from KVM using the"
550 " QMP protocol: %s" % err)
552 def _Send(self, message):
553 """Encodes and sends a message to KVM using QMP.
555 @type message: QmpMessage
556 @param message: message to send to KVM
557 @raise errors.HypervisorError: when there are communication errors
558 @raise errors.ProgrammerError: when there are data serialization errors
561 self._check_connection()
563 message_str = str(message)
564 except Exception, err:
565 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
568 self.sock.sendall(message_str)
569 except socket.timeout, err:
570 raise errors.HypervisorError("Timeout while sending a QMP message: "
571 "%s (%s)" % (err.string, err.errno))
572 except socket.error, err:
573 raise errors.HypervisorError("Unable to send data from KVM using the"
574 " QMP protocol: %s" % err)
576 def Execute(self, command, arguments=None):
577 """Executes a QMP command and returns the response of the server.
580 @param command: the command to execute
581 @type arguments: dict
582 @param arguments: dictionary of arguments to be passed to the command
584 @return: dictionary representing the received JSON object
585 @raise errors.HypervisorError: when there are communication errors
586 @raise errors.ProgrammerError: when there are data serialization errors
589 self._check_connection()
590 message = QmpMessage({self._EXECUTE_KEY: command})
592 message[self._ARGUMENTS_KEY] = arguments
595 # Events can occur between the sending of the command and the reception
596 # of the response, so we need to filter out messages with the event key.
598 response = self._Recv()
599 err = response[self._ERROR_KEY]
601 raise errors.HypervisorError("kvm: error executing the %s"
602 " command: %s (%s):" %
604 err[self._ERROR_DESC_KEY],
605 err[self._ERROR_CLASS_KEY]))
607 elif not response[self._EVENT_KEY]:
611 class KVMHypervisor(hv_base.BaseHypervisor):
612 """KVM hypervisor interface
617 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
618 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
619 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
620 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
621 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
622 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
623 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
624 # KVM instances with chroot enabled are started in empty chroot directories.
625 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
626 # After an instance is stopped, its chroot directory is removed.
627 # If the chroot directory is not empty, it can't be removed.
628 # A non-empty chroot directory indicates a possible security incident.
629 # To support forensics, the non-empty chroot directory is quarantined in
630 # a separate directory, called 'chroot-quarantine'.
631 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
632 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
633 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
636 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
637 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
638 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
639 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
640 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
641 constants.HV_ACPI: hv_base.NO_CHECK,
642 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
643 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
644 constants.HV_VNC_BIND_ADDRESS:
645 (False, lambda x: (netutils.IP4Address.IsValid(x) or
646 utils.IsNormAbsPath(x)),
647 "The VNC bind address must be either a valid IP address or an absolute"
648 " pathname", None, None),
649 constants.HV_VNC_TLS: hv_base.NO_CHECK,
650 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
651 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
652 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
653 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
654 constants.HV_KVM_SPICE_IP_VERSION:
655 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
656 x in constants.VALID_IP_VERSIONS),
657 "The SPICE IP version should be 4 or 6",
659 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
660 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
662 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
663 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
665 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
666 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
668 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
669 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
671 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
672 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
673 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
674 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
675 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
676 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
677 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
678 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
679 constants.HV_BOOT_ORDER:
680 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
681 constants.HV_NIC_TYPE:
682 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
683 constants.HV_DISK_TYPE:
684 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
685 constants.HV_KVM_CDROM_DISK_TYPE:
686 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
687 constants.HV_USB_MOUSE:
688 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
689 constants.HV_KEYMAP: hv_base.NO_CHECK,
690 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
691 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
692 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
693 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
694 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
695 constants.HV_DISK_CACHE:
696 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
697 constants.HV_SECURITY_MODEL:
698 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
699 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
700 constants.HV_KVM_FLAG:
701 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
702 constants.HV_VHOST_NET: hv_base.NO_CHECK,
703 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
704 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
705 constants.HV_REBOOT_BEHAVIOR:
706 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
707 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
708 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
709 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
710 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
711 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
712 constants.HV_SOUNDHW: hv_base.NO_CHECK,
713 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
714 constants.HV_VGA: hv_base.NO_CHECK,
715 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
716 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
717 constants.HV_VNET_HDR: hv_base.NO_CHECK,
721 _VIRTIO_NET_PCI = "virtio-net-pci"
722 _VIRTIO_BLK_PCI = "virtio-blk-pci"
724 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
726 _MIGRATION_PROGRESS_RE = \
727 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
728 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
729 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
731 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
732 _MIGRATION_INFO_RETRY_DELAY = 2
734 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
736 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
737 _CPU_INFO_CMD = "info cpus"
740 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
741 _CHECK_MACHINE_VERSION_RE = \
742 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
744 _QMP_RE = re.compile(r"^-qmp\s", re.M)
745 _SPICE_RE = re.compile(r"^-spice\s", re.M)
746 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
747 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
748 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
749 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
750 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
751 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
752 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
753 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
754 # match -drive.*boot=on|off on different lines, but in between accept only
755 # dashes not preceeded by a new line (which would mean another option
756 # different than -drive is starting)
757 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
759 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
760 _INFO_PCI_CMD = "info pci"
762 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
763 _INFO_VERSION_CMD = "info version"
765 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
770 ANCILLARY_FILES_OPT = [
774 # Supported kvm options to get output from
775 _KVMOPT_HELP = "help"
776 _KVMOPT_MLIST = "mlist"
777 _KVMOPT_DEVICELIST = "devicelist"
779 # Command to execute to get the output from kvm, and whether to
780 # accept the output even on failure.
782 _KVMOPT_HELP: (["--help"], False),
783 _KVMOPT_MLIST: (["-M", "?"], False),
784 _KVMOPT_DEVICELIST: (["-device", "?"], True),
788 hv_base.BaseHypervisor.__init__(self)
789 # Let's make sure the directories we need exist, even if the RUN_DIR lives
790 # in a tmpfs filesystem or has been otherwise wiped out.
791 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
792 utils.EnsureDirs(dirs)
795 def _InstancePidFile(cls, instance_name):
796 """Returns the instance pidfile.
799 return utils.PathJoin(cls._PIDS_DIR, instance_name)
802 def _InstanceUidFile(cls, instance_name):
803 """Returns the instance uidfile.
806 return utils.PathJoin(cls._UIDS_DIR, instance_name)
809 def _InstancePidInfo(cls, pid):
810 """Check pid file for instance information.
812 Check that a pid file is associated with an instance, and retrieve
813 information from its command line.
815 @type pid: string or int
816 @param pid: process id of the instance to check
818 @return: (instance_name, memory, vcpus)
819 @raise errors.HypervisorError: when an instance cannot be found
822 alive = utils.IsProcessAlive(pid)
824 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
826 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
828 cmdline = utils.ReadFile(cmdline_file)
829 except EnvironmentError, err:
830 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
837 arg_list = cmdline.split("\x00")
839 arg = arg_list.pop(0)
841 instance = arg_list.pop(0)
843 memory = int(arg_list.pop(0))
845 vcpus = int(arg_list.pop(0).split(",")[0])
848 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
851 return (instance, memory, vcpus)
853 def _InstancePidAlive(self, instance_name):
854 """Returns the instance pidfile, pid, and liveness.
856 @type instance_name: string
857 @param instance_name: instance name
859 @return: (pid file name, pid, liveness)
862 pidfile = self._InstancePidFile(instance_name)
863 pid = utils.ReadPidFile(pidfile)
867 cmd_instance = self._InstancePidInfo(pid)[0]
868 alive = (cmd_instance == instance_name)
869 except errors.HypervisorError:
872 return (pidfile, pid, alive)
874 def _CheckDown(self, instance_name):
875 """Raises an error unless the given instance is down.
878 alive = self._InstancePidAlive(instance_name)[2]
880 raise errors.HypervisorError("Failed to start instance %s: %s" %
881 (instance_name, "already running"))
884 def _InstanceMonitor(cls, instance_name):
885 """Returns the instance monitor socket name
888 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
891 def _InstanceSerial(cls, instance_name):
892 """Returns the instance serial socket name
895 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
898 def _InstanceQmpMonitor(cls, instance_name):
899 """Returns the instance serial QMP socket name
902 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
905 def _SocatUnixConsoleParams():
906 """Returns the correct parameters for socat
908 If we have a new-enough socat we can use raw mode with an escape character.
911 if constants.SOCAT_USE_ESCAPE:
912 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
914 return "echo=0,icanon=0"
917 def _InstanceKVMRuntime(cls, instance_name):
918 """Returns the instance KVM runtime filename
921 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
924 def _InstanceChrootDir(cls, instance_name):
925 """Returns the name of the KVM chroot dir of the instance
928 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
931 def _InstanceNICDir(cls, instance_name):
932 """Returns the name of the directory holding the tap device files for a
936 return utils.PathJoin(cls._NICS_DIR, instance_name)
939 def _InstanceNICFile(cls, instance_name, seq):
940 """Returns the name of the file containing the tap device for a given NIC
943 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
946 def _InstanceKeymapFile(cls, instance_name):
947 """Returns the name of the file containing the keymap for a given instance
950 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
953 def _TryReadUidFile(cls, uid_file):
954 """Try to read a uid file
957 if os.path.exists(uid_file):
959 uid = int(utils.ReadOneLineFile(uid_file))
961 except EnvironmentError:
962 logging.warning("Can't read uid file", exc_info=True)
963 except (TypeError, ValueError):
964 logging.warning("Can't parse uid file contents", exc_info=True)
968 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
969 """Removes an instance's rutime sockets/files/dirs.
972 utils.RemoveFile(pidfile)
973 utils.RemoveFile(cls._InstanceMonitor(instance_name))
974 utils.RemoveFile(cls._InstanceSerial(instance_name))
975 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
976 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
977 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
978 uid_file = cls._InstanceUidFile(instance_name)
979 uid = cls._TryReadUidFile(uid_file)
980 utils.RemoveFile(uid_file)
982 uidpool.ReleaseUid(uid)
984 shutil.rmtree(cls._InstanceNICDir(instance_name))
986 if err.errno != errno.ENOENT:
989 chroot_dir = cls._InstanceChrootDir(instance_name)
990 utils.RemoveDir(chroot_dir)
992 if err.errno == errno.ENOTEMPTY:
993 # The chroot directory is expected to be empty, but it isn't.
994 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
997 utils.TimestampForFilename()))
998 logging.warning("The chroot directory of instance %s can not be"
999 " removed as it is not empty. Moving it to the"
1000 " quarantine instead. Please investigate the"
1001 " contents (%s) and clean up manually",
1002 instance_name, new_chroot_dir)
1003 utils.RenameFile(chroot_dir, new_chroot_dir)
1008 def _ConfigureNIC(instance, seq, nic, tap):
1009 """Run the network configuration script for a specified NIC
1011 @param instance: instance we're acting on
1012 @type instance: instance object
1013 @param seq: nic sequence number
1015 @param nic: nic we're acting on
1016 @type nic: nic object
1017 @param tap: the host's tap interface this NIC corresponds to
1022 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1023 "INSTANCE": instance.name,
1025 "MODE": nic.nicparams[constants.NIC_MODE],
1027 "INTERFACE_INDEX": str(seq),
1028 "INTERFACE_UUID": nic.uuid,
1029 "TAGS": " ".join(instance.GetTags()),
1036 env["INTERFACE_NAME"] = nic.name
1038 if nic.nicparams[constants.NIC_LINK]:
1039 env["LINK"] = nic.nicparams[constants.NIC_LINK]
1042 n = objects.Network.FromDict(nic.netinfo)
1043 env.update(n.HooksDict())
1045 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1046 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1048 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1050 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1051 " network configuration script output: %s" %
1052 (tap, result.fail_reason, result.output))
1055 def _VerifyAffinityPackage():
1056 if affinity is None:
1057 raise errors.HypervisorError("affinity Python package not"
1058 " found; cannot use CPU pinning under KVM")
1061 def _BuildAffinityCpuMask(cpu_list):
1062 """Create a CPU mask suitable for sched_setaffinity from a list of
1065 See man taskset for more info on sched_setaffinity masks.
1066 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1068 @type cpu_list: list of int
1069 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1071 @return: a bit mask of CPU affinities
1074 if cpu_list == constants.CPU_PINNING_OFF:
1075 return constants.CPU_PINNING_ALL_KVM
1077 return sum(2 ** cpu for cpu in cpu_list)
1080 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1081 """Change CPU affinity for running VM according to given CPU mask.
1083 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1084 @type cpu_mask: string
1085 @param process_id: process ID of KVM process. Used to pin entire VM
1087 @type process_id: int
1088 @param thread_dict: map of virtual CPUs to KVM thread IDs
1089 @type thread_dict: dict int:int
1092 # Convert the string CPU mask to a list of list of int's
1093 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1095 if len(cpu_list) == 1:
1096 all_cpu_mapping = cpu_list[0]
1097 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1098 # If CPU pinning has 1 entry that's "all", then do nothing
1101 # If CPU pinning has one non-all entry, map the entire VM to
1102 # one set of physical CPUs
1103 cls._VerifyAffinityPackage()
1104 affinity.set_process_affinity_mask(
1105 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1107 # The number of vCPUs mapped should match the number of vCPUs
1108 # reported by KVM. This was already verified earlier, so
1109 # here only as a sanity check.
1110 assert len(thread_dict) == len(cpu_list)
1111 cls._VerifyAffinityPackage()
1113 # For each vCPU, map it to the proper list of physical CPUs
1114 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1115 affinity.set_process_affinity_mask(thread_dict[i],
1116 cls._BuildAffinityCpuMask(vcpu))
1118 def _GetVcpuThreadIds(self, instance_name):
1119 """Get a mapping of vCPU no. to thread IDs for the instance
1121 @type instance_name: string
1122 @param instance_name: instance in question
1123 @rtype: dictionary of int:int
1124 @return: a dictionary mapping vCPU numbers to thread IDs
1128 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1129 for line in output.stdout.splitlines():
1130 match = self._CPU_INFO_RE.search(line)
1133 grp = map(int, match.groups())
1134 result[grp[0]] = grp[1]
1138 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1139 """Complete CPU pinning.
1141 @type instance_name: string
1142 @param instance_name: name of instance
1143 @type cpu_mask: string
1144 @param cpu_mask: CPU pinning mask as entered by user
1147 # Get KVM process ID, to be used if need to pin entire VM
1148 _, pid, _ = self._InstancePidAlive(instance_name)
1149 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1150 thread_dict = self._GetVcpuThreadIds(instance_name)
1151 # Run CPU pinning, based on configured mask
1152 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1154 def ListInstances(self):
1155 """Get the list of running instances.
1157 We can do this by listing our live instances directory and
1158 checking whether the associated kvm process is still alive.
1162 for name in os.listdir(self._PIDS_DIR):
1163 if self._InstancePidAlive(name)[2]:
1167 def GetInstanceInfo(self, instance_name):
1168 """Get instance properties.
1170 @type instance_name: string
1171 @param instance_name: the instance name
1172 @rtype: tuple of strings
1173 @return: (name, id, memory, vcpus, stat, times)
1176 _, pid, alive = self._InstancePidAlive(instance_name)
1180 _, memory, vcpus = self._InstancePidInfo(pid)
1185 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1187 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1188 # Will fail if ballooning is not enabled, but we can then just resort to
1190 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1191 memory = mem_bytes / 1048576
1192 except errors.HypervisorError:
1195 return (instance_name, pid, memory, vcpus, istat, times)
1197 def GetAllInstancesInfo(self):
1198 """Get properties of all instances.
1200 @return: list of tuples (name, id, memory, vcpus, stat, times)
1204 for name in os.listdir(self._PIDS_DIR):
1206 info = self.GetInstanceInfo(name)
1207 except errors.HypervisorError:
1208 # Ignore exceptions due to instances being shut down
1214 def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1216 """Generate KVM options regarding instance's block devices.
1218 @type instance: L{objects.Instance}
1219 @param instance: the instance object
1220 @type kvm_disks: list of tuples
1221 @param kvm_disks: list of tuples [(disk, link_name)..]
1222 @type kvmhelp: string
1223 @param kvmhelp: output of kvm --help
1224 @type devlist: string
1225 @param devlist: output of kvm -device ?
1227 @return: list of command line options eventually used by kvm executable
1230 hvp = instance.hvparams
1231 kernel_path = hvp[constants.HV_KERNEL_PATH]
1235 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1237 # whether this is an older KVM version that uses the boot=on flag
1239 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1242 device_driver = None
1243 disk_type = hvp[constants.HV_DISK_TYPE]
1244 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1245 if_val = ",if=%s" % self._VIRTIO
1247 if self._VIRTIO_BLK_RE.search(devlist):
1249 # will be passed in -device option as driver
1250 device_driver = self._VIRTIO_BLK_PCI
1251 except errors.HypervisorError, _:
1254 if_val = ",if=%s" % disk_type
1256 disk_cache = hvp[constants.HV_DISK_CACHE]
1257 if instance.disk_template in constants.DTS_EXT_MIRROR:
1258 if disk_cache != "none":
1259 # TODO: make this a hard error, instead of a silent overwrite
1260 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1261 " to prevent shared storage corruption on migration",
1263 cache_val = ",cache=none"
1264 elif disk_cache != constants.HT_CACHE_DEFAULT:
1265 cache_val = ",cache=%s" % disk_cache
1268 for idx, (cfdev, link_name) in enumerate(kvm_disks):
1269 if cfdev.mode != constants.DISK_RDWR:
1270 raise errors.HypervisorError("Instance has read-only disks which"
1271 " are not supported by KVM")
1272 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1275 dev_opts.extend(["-boot", "c"])
1277 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1278 boot_val = ",boot=on"
1280 # For ext we allow overriding disk_cache hypervisor params per disk
1281 disk_cache = cfdev.params.get("cache", None)
1283 cache_val = ",cache=%s" % disk_cache
1284 drive_val = "file=%s,format=raw%s%s%s" % \
1285 (link_name, if_val, boot_val, cache_val)
1288 # kvm_disks are the 4th entry of runtime file that did not exist in
1289 # the past. That means that cfdev should always have pci slot and
1290 # _GenerateDeviceKVMId() will not raise a exception.
1291 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK,
1293 drive_val += (",id=%s" % kvm_devid)
1295 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1296 dev_val = ("%s,drive=%s,id=%s" %
1297 (device_driver, kvm_devid, kvm_devid))
1299 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1300 dev_opts.extend(["-device", dev_val])
1302 # TODO: export disk geometry in IDISK_PARAMS
1303 heads = cfdev.params.get('heads', None)
1304 secs = cfdev.params.get('secs', None)
1306 nr_sectors = cfdev.size * 1024 * 1024 / 512
1307 cyls = nr_sectors / (int(heads) * int(secs))
1312 if cyls and heads and secs:
1313 drive_val += (",cyls=%d,heads=%d,secs=%d" %
1314 (cyls, int(heads), int(secs)))
1316 dev_opts.extend(["-drive", drive_val])
1320 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1322 """Generate KVM information to start an instance.
1324 @type kvmhelp: string
1325 @param kvmhelp: output of kvm --help
1326 @attention: this function must not have any side-effects; for
1327 example, it must not write to the filesystem, or read values
1328 from the current system the are expected to differ between
1329 nodes, since it is only run once at instance startup;
1330 actions/kvm arguments that can vary between systems should be
1331 done in L{_ExecuteKVMRuntime}
1334 # pylint: disable=R0912,R0914,R0915
1335 hvp = instance.hvparams
1336 self.ValidateParameters(hvp)
1338 pidfile = self._InstancePidFile(instance.name)
1339 kvm = hvp[constants.HV_KVM_PATH]
1341 # used just by the vnc server, if enabled
1342 kvm_cmd.extend(["-name", instance.name])
1343 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1345 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1346 if hvp[constants.HV_CPU_CORES]:
1347 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1348 if hvp[constants.HV_CPU_THREADS]:
1349 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1350 if hvp[constants.HV_CPU_SOCKETS]:
1351 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1353 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1355 kvm_cmd.extend(["-pidfile", pidfile])
1356 kvm_cmd.extend(["-balloon", "virtio"])
1357 kvm_cmd.extend(["-daemonize"])
1358 if not instance.hvparams[constants.HV_ACPI]:
1359 kvm_cmd.extend(["-no-acpi"])
1360 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1361 constants.INSTANCE_REBOOT_EXIT:
1362 kvm_cmd.extend(["-no-reboot"])
1364 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1366 mversion = self._GetDefaultMachineVersion(kvm)
1367 if self._MACHINE_RE.search(kvmhelp):
1368 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1369 # extra hypervisor parameters. We should also investigate whether and how
1370 # shadow_mem should be considered for the resource model.
1371 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1372 specprop = ",accel=kvm"
1375 machinespec = "%s%s" % (mversion, specprop)
1376 kvm_cmd.extend(["-machine", machinespec])
1378 kvm_cmd.extend(["-M", mversion])
1379 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1380 self._ENABLE_KVM_RE.search(kvmhelp)):
1381 kvm_cmd.extend(["-enable-kvm"])
1382 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1383 self._DISABLE_KVM_RE.search(kvmhelp)):
1384 kvm_cmd.extend(["-disable-kvm"])
1386 kernel_path = hvp[constants.HV_KERNEL_PATH]
1388 boot_cdrom = boot_floppy = boot_network = False
1390 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1391 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1392 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1395 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1398 kvm_cmd.extend(["-boot", "n"])
1400 # whether this is an older KVM version that uses the boot=on flag
1402 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1404 disk_type = hvp[constants.HV_DISK_TYPE]
1406 #Now we can specify a different device type for CDROM devices.
1407 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1408 if not cdrom_disk_type:
1409 cdrom_disk_type = disk_type
1411 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1413 options = ",format=raw,media=cdrom"
1414 # set cdrom 'if' type
1416 actual_cdrom_type = constants.HT_DISK_IDE
1417 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1418 actual_cdrom_type = "virtio"
1420 actual_cdrom_type = cdrom_disk_type
1421 if_val = ",if=%s" % actual_cdrom_type
1422 # set boot flag, if needed
1425 kvm_cmd.extend(["-boot", "d"])
1427 boot_val = ",boot=on"
1428 # and finally build the entire '-drive' value
1429 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1430 kvm_cmd.extend(["-drive", drive_val])
1432 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1434 options = ",format=raw,media=cdrom"
1435 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1436 if_val = ",if=virtio"
1438 if_val = ",if=%s" % cdrom_disk_type
1439 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1440 kvm_cmd.extend(["-drive", drive_val])
1442 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1444 options = ",format=raw,media=disk"
1446 kvm_cmd.extend(["-boot", "a"])
1447 options = "%s,boot=on" % options
1448 if_val = ",if=floppy"
1449 options = "%s%s" % (options, if_val)
1450 drive_val = "file=%s%s" % (floppy_image, options)
1451 kvm_cmd.extend(["-drive", drive_val])
1454 kvm_cmd.extend(["-kernel", kernel_path])
1455 initrd_path = hvp[constants.HV_INITRD_PATH]
1457 kvm_cmd.extend(["-initrd", initrd_path])
1458 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1459 hvp[constants.HV_KERNEL_ARGS]]
1460 if hvp[constants.HV_SERIAL_CONSOLE]:
1461 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1462 root_append.append("console=ttyS0,%s" % serial_speed)
1463 kvm_cmd.extend(["-append", " ".join(root_append)])
1465 mem_path = hvp[constants.HV_MEM_PATH]
1467 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1469 monitor_dev = ("unix:%s,server,nowait" %
1470 self._InstanceMonitor(instance.name))
1471 kvm_cmd.extend(["-monitor", monitor_dev])
1472 if hvp[constants.HV_SERIAL_CONSOLE]:
1473 serial_dev = ("unix:%s,server,nowait" %
1474 self._InstanceSerial(instance.name))
1475 kvm_cmd.extend(["-serial", serial_dev])
1477 kvm_cmd.extend(["-serial", "none"])
1479 mouse_type = hvp[constants.HV_USB_MOUSE]
1480 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1481 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1482 spice_ip_version = None
1484 kvm_cmd.extend(["-usb"])
1487 kvm_cmd.extend(["-usbdevice", mouse_type])
1488 elif vnc_bind_address:
1489 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1491 if vnc_bind_address:
1492 if netutils.IP4Address.IsValid(vnc_bind_address):
1493 if instance.network_port > constants.VNC_BASE_PORT:
1494 display = instance.network_port - constants.VNC_BASE_PORT
1495 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1496 vnc_arg = ":%d" % (display)
1498 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1500 logging.error("Network port is not a valid VNC display (%d < %d),"
1501 " not starting VNC",
1502 instance.network_port, constants.VNC_BASE_PORT)
1505 # Only allow tls and other option when not binding to a file, for now.
1506 # kvm/qemu gets confused otherwise about the filename to use.
1508 if hvp[constants.HV_VNC_TLS]:
1509 vnc_append = "%s,tls" % vnc_append
1510 if hvp[constants.HV_VNC_X509_VERIFY]:
1511 vnc_append = "%s,x509verify=%s" % (vnc_append,
1512 hvp[constants.HV_VNC_X509])
1513 elif hvp[constants.HV_VNC_X509]:
1514 vnc_append = "%s,x509=%s" % (vnc_append,
1515 hvp[constants.HV_VNC_X509])
1516 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1517 vnc_append = "%s,password" % vnc_append
1519 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1522 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1524 kvm_cmd.extend(["-vnc", vnc_arg])
1526 # FIXME: this is wrong here; the iface ip address differs
1527 # between systems, so it should be done in _ExecuteKVMRuntime
1528 if netutils.IsValidInterface(spice_bind):
1529 # The user specified a network interface, we have to figure out the IP
1531 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1532 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1534 # if the user specified an IP version and the interface does not
1535 # have that kind of IP addresses, throw an exception
1536 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1537 if not addresses[spice_ip_version]:
1538 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1539 " for %s" % (spice_ip_version,
1542 # the user did not specify an IP version, we have to figure it out
1543 elif (addresses[constants.IP4_VERSION] and
1544 addresses[constants.IP6_VERSION]):
1545 # we have both ipv4 and ipv6, let's use the cluster default IP
1547 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1548 spice_ip_version = \
1549 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1550 elif addresses[constants.IP4_VERSION]:
1551 spice_ip_version = constants.IP4_VERSION
1552 elif addresses[constants.IP6_VERSION]:
1553 spice_ip_version = constants.IP6_VERSION
1555 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1556 " for %s" % (spice_bind))
1558 spice_address = addresses[spice_ip_version][0]
1561 # spice_bind is known to be a valid IP address, because
1562 # ValidateParameters checked it.
1563 spice_address = spice_bind
1565 spice_arg = "addr=%s" % spice_address
1566 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1567 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1568 (spice_arg, instance.network_port,
1569 pathutils.SPICE_CACERT_FILE))
1570 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1571 (spice_arg, pathutils.SPICE_CERT_FILE,
1572 pathutils.SPICE_CERT_FILE))
1573 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1575 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1577 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1579 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1580 spice_arg = "%s,disable-ticketing" % spice_arg
1582 if spice_ip_version:
1583 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1585 # Image compression options
1586 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1587 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1588 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1590 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1592 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1594 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1596 # Video stream detection
1597 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1599 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1601 # Audio compression, by default in qemu-kvm it is on
1602 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1603 spice_arg = "%s,playback-compression=off" % spice_arg
1604 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1605 spice_arg = "%s,agent-mouse=off" % spice_arg
1607 # Enable the spice agent communication channel between the host and the
1609 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1612 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1614 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1616 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1617 kvm_cmd.extend(["-spice", spice_arg])
1620 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1621 # also works in earlier versions though (tested with 1.1 and 1.3)
1622 if self._DISPLAY_RE.search(kvmhelp):
1623 kvm_cmd.extend(["-display", "none"])
1625 kvm_cmd.extend(["-nographic"])
1627 if hvp[constants.HV_USE_LOCALTIME]:
1628 kvm_cmd.extend(["-localtime"])
1630 if hvp[constants.HV_KVM_USE_CHROOT]:
1631 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1633 # Add qemu-KVM -cpu param
1634 if hvp[constants.HV_CPU_TYPE]:
1635 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1637 # As requested by music lovers
1638 if hvp[constants.HV_SOUNDHW]:
1639 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1641 # Pass a -vga option if requested, or if spice is used, for backwards
1643 if hvp[constants.HV_VGA]:
1644 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1646 kvm_cmd.extend(["-vga", "qxl"])
1648 # Various types of usb devices, comma separated
1649 if hvp[constants.HV_USB_DEVICES]:
1650 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1651 kvm_cmd.extend(["-usbdevice", dev])
1653 if hvp[constants.HV_KVM_EXTRA]:
1654 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1656 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1658 for disk, link_name in block_devices:
1659 _UpdatePCISlots(disk, pci_reservations)
1660 kvm_disks.append((disk, link_name))
1663 for nic in instance.nics:
1664 _UpdatePCISlots(nic, pci_reservations)
1665 kvm_nics.append(nic)
1669 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1671 def _WriteKVMRuntime(self, instance_name, data):
1672 """Write an instance's KVM runtime
1676 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1678 except EnvironmentError, err:
1679 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1681 def _ReadKVMRuntime(self, instance_name):
1682 """Read an instance's KVM runtime
1686 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1687 except EnvironmentError, err:
1688 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1691 def _SaveKVMRuntime(self, instance, kvm_runtime):
1692 """Save an instance's KVM runtime
1695 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1697 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1698 serialized_disks = [(blk.ToDict(), link)
1699 for blk, link in kvm_disks]
1700 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1703 self._WriteKVMRuntime(instance.name, serialized_form)
1705 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1706 """Load an instance's KVM runtime
1709 if not serialized_runtime:
1710 serialized_runtime = self._ReadKVMRuntime(instance.name)
1712 return _AnalyzeSerializedRuntime(serialized_runtime)
1714 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1715 """Run the KVM cmd and check for errors
1718 @param name: instance name
1719 @type kvm_cmd: list of strings
1720 @param kvm_cmd: runcmd input for kvm
1721 @type tap_fds: list of int
1722 @param tap_fds: fds of tap devices opened by Ganeti
1726 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1729 utils_wrapper.CloseFdNoError(fd)
1732 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1733 (name, result.fail_reason, result.output))
1734 if not self._InstancePidAlive(name)[2]:
1735 raise errors.HypervisorError("Failed to start instance %s" % name)
1737 # too many local variables
1738 # pylint: disable=R0914
1739 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1740 """Execute a KVM cmd, after completing it with some last minute data.
1742 @type incoming: tuple of strings
1743 @param incoming: (target_host_ip, port)
1744 @type kvmhelp: string
1745 @param kvmhelp: output of kvm --help
1748 # Small _ExecuteKVMRuntime hv parameters programming howto:
1749 # - conf_hvp contains the parameters as configured on ganeti. they might
1750 # have changed since the instance started; only use them if the change
1751 # won't affect the inside of the instance (which hasn't been rebooted).
1752 # - up_hvp contains the parameters as they were when the instance was
1753 # started, plus any new parameter which has been added between ganeti
1754 # versions: it is paramount that those default to a value which won't
1755 # affect the inside of the instance as well.
1756 conf_hvp = instance.hvparams
1757 name = instance.name
1758 self._CheckDown(name)
1762 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1763 # the first element of kvm_cmd is always the path to the kvm binary
1764 kvm_path = kvm_cmd[0]
1765 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1767 # We know it's safe to run as a different user upon migration, so we'll use
1768 # the latest conf, from conf_hvp.
1769 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1770 if security_model == constants.HT_SM_USER:
1771 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1773 keymap = conf_hvp[constants.HV_KEYMAP]
1775 keymap_path = self._InstanceKeymapFile(name)
1776 # If a keymap file is specified, KVM won't use its internal defaults. By
1777 # first including the "en-us" layout, an error on loading the actual
1778 # layout (e.g. because it can't be found) won't lead to a non-functional
1779 # keyboard. A keyboard with incorrect keys is still better than none.
1780 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1781 kvm_cmd.extend(["-k", keymap_path])
1783 # We have reasons to believe changing something like the nic driver/type
1784 # upon migration won't exactly fly with the instance kernel, so for nic
1785 # related parameters we'll use up_hvp
1788 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1790 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1794 kvm_cmd.extend(bdev_opts)
1797 kvm_cmd.extend(["-net", "none"])
1801 nic_type = up_hvp[constants.HV_NIC_TYPE]
1802 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1803 nic_model = self._VIRTIO
1805 if self._VIRTIO_NET_RE.search(devlist):
1806 nic_model = self._VIRTIO_NET_PCI
1807 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1808 except errors.HypervisorError, _:
1809 # Older versions of kvm don't support DEVICE_LIST, but they don't
1810 # have new virtio syntax either.
1813 if up_hvp[constants.HV_VHOST_NET]:
1814 # check for vhost_net support
1815 if self._VHOST_RE.search(kvmhelp):
1816 tap_extra = ",vhost=on"
1818 raise errors.HypervisorError("vhost_net is configured"
1819 " but it is not available")
1821 nic_model = nic_type
1823 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1825 for nic_seq, nic in enumerate(kvm_nics):
1826 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1827 tapfds.append(tapfd)
1828 taps.append(tapname)
1829 if kvm_supports_netdev:
1830 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1832 # kvm_nics already exist in old runtime files and thus there might
1833 # be some entries without pci slot (therefore try: except:)
1834 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1836 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1837 except errors.HotplugError:
1838 netdev = "netdev%d" % nic_seq
1839 nic_val += (",netdev=%s" % netdev)
1840 tap_val = ("type=tap,id=%s,fd=%d%s" %
1841 (netdev, tapfd, tap_extra))
1842 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1844 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1846 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1847 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1850 target, port = incoming
1851 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1853 # Changing the vnc password doesn't bother the guest that much. At most it
1854 # will surprise people who connect to it. Whether positively or negatively
1856 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1860 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1861 except EnvironmentError, err:
1862 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1863 % (vnc_pwd_file, err))
1865 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1866 utils.EnsureDirs([(self._InstanceChrootDir(name),
1867 constants.SECURE_DIR_MODE)])
1869 # Automatically enable QMP if version is >= 0.14
1870 if self._QMP_RE.search(kvmhelp):
1871 logging.debug("Enabling QMP")
1872 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1873 self._InstanceQmpMonitor(instance.name)])
1875 # Configure the network now for starting instances and bridged interfaces,
1876 # during FinalizeMigration for incoming instances' routed interfaces
1877 for nic_seq, nic in enumerate(kvm_nics):
1879 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1881 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1883 # CPU affinity requires kvm to start paused, so we set this flag if the
1884 # instance is not already paused and if we are not going to accept a
1885 # migrating instance. In the latter case, pausing is not needed.
1886 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1887 if start_kvm_paused:
1888 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1890 # Note: CPU pinning is using up_hvp since changes take effect
1891 # during instance startup anyway, and to avoid problems when soft
1892 # rebooting the instance.
1894 if up_hvp.get(constants.HV_CPU_MASK, None):
1897 if security_model == constants.HT_SM_POOL:
1898 ss = ssconf.SimpleStore()
1899 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1900 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1901 uid = uidpool.RequestUnusedUid(all_uids)
1903 username = pwd.getpwuid(uid.GetUid()).pw_name
1904 kvm_cmd.extend(["-runas", username])
1905 self._RunKVMCmd(name, kvm_cmd, tapfds)
1907 uidpool.ReleaseUid(uid)
1911 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1913 self._RunKVMCmd(name, kvm_cmd, tapfds)
1915 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1916 constants.RUN_DIRS_MODE)])
1917 for nic_seq, tap in enumerate(taps):
1918 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1922 change_cmd = "change vnc password %s" % vnc_pwd
1923 self._CallMonitorCommand(instance.name, change_cmd)
1925 # Setting SPICE password. We are not vulnerable to malicious passwordless
1926 # connection attempts because SPICE by default does not allow connections
1927 # if neither a password nor the "disable_ticketing" options are specified.
1928 # As soon as we send the password via QMP, that password is a valid ticket
1930 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1931 if spice_password_file:
1934 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1935 except EnvironmentError, err:
1936 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1937 % (spice_password_file, err))
1939 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1942 "protocol": "spice",
1943 "password": spice_pwd,
1945 qmp.Execute("set_password", arguments)
1947 for filename in temp_files:
1948 utils.RemoveFile(filename)
1950 # If requested, set CPU affinity and resume instance execution
1952 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1954 start_memory = self._InstanceStartupMemory(instance)
1955 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1956 self.BalloonInstanceMemory(instance, start_memory)
1958 if start_kvm_paused:
1959 # To control CPU pinning, ballooning, and vnc/spice passwords
1960 # the VM was started in a frozen state. If freezing was not
1961 # explicitly requested resume the vm status.
1962 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1964 def StartInstance(self, instance, block_devices, startup_paused):
1965 """Start an instance.
1968 self._CheckDown(instance.name)
1969 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1970 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1971 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1972 startup_paused, kvmhelp)
1973 self._SaveKVMRuntime(instance, kvm_runtime)
1974 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1976 def _CallMonitorCommand(self, instance_name, command, timeout=None):
1977 """Invoke a command on the instance monitor.
1980 if timeout is not None:
1981 timeout_cmd = "timeout %s" % (timeout, )
1985 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1986 # version. The monitor protocol is designed for human consumption, whereas
1987 # QMP is made for programmatic usage. In the worst case QMP can also
1988 # execute monitor commands. As it is, all calls to socat take at least
1989 # 500ms and likely more: socat can't detect the end of the reply and waits
1990 # for 500ms of no data received before exiting (500 ms is the default for
1991 # the "-t" parameter).
1992 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1993 (utils.ShellQuote(command),
1995 constants.SOCAT_PATH,
1996 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1998 result = utils.RunCmd(socat)
2000 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2002 (command, instance_name, result.fail_reason, result.output))
2003 raise errors.HypervisorError(msg)
2007 def _GetFreePCISlot(self, instance, dev):
2008 """Get the first available pci slot of a runnung instance.
2011 slots = bitarray(32)
2012 slots.setall(False) # pylint: disable=E1101
2013 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2014 for line in output.stdout.splitlines():
2015 match = self._INFO_PCI_RE.search(line)
2017 slot = int(match.group(1))
2020 [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2022 raise errors.HypervisorError("All PCI slots occupied")
2026 def VerifyHotplugSupport(self, instance, action, dev_type):
2027 """Verifies that hotplug is supported.
2029 Hotplug is *not* supported in case of:
2030 - security models and chroot (disk hotplug)
2031 - fdsend module is missing (nic hot-add)
2033 @raise errors.HypervisorError: in one of the previous cases
2036 if dev_type == constants.HOTPLUG_TARGET_DISK:
2037 hvp = instance.hvparams
2038 security_model = hvp[constants.HV_SECURITY_MODEL]
2039 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2041 raise errors.HotplugError("Disk hotplug is not supported"
2042 " in case of chroot.")
2043 if security_model != constants.HT_SM_NONE:
2044 raise errors.HotplugError("Disk Hotplug is not supported in case"
2045 " security models are used.")
2047 if (dev_type == constants.HOTPLUG_TARGET_NIC and
2048 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2049 raise errors.HotplugError("Cannot hot-add NIC."
2050 " fdsend python module is missing.")
2052 def HotplugSupported(self, instance):
2053 """Checks if hotplug is generally supported.
2055 Hotplug is *not* supported in case of:
2056 - qemu versions < 1.0
2057 - for stopped instances
2059 @raise errors.HypervisorError: in one of the previous cases
2063 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2064 except errors.HypervisorError:
2065 raise errors.HotplugError("Instance is probably down")
2067 # TODO: search for netdev_add, drive_add, device_add.....
2068 match = self._INFO_VERSION_RE.search(output.stdout)
2070 raise errors.HotplugError("Cannot parse qemu version via monitor")
2072 v_major, v_min, _, _ = match.groups()
2073 if (int(v_major), int(v_min)) < (1, 0):
2074 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2076 def _CallHotplugCommand(self, name, cmd):
2077 output = self._CallMonitorCommand(name, cmd)
2078 # TODO: parse output and check if succeeded
2079 for line in output.stdout.splitlines():
2080 logging.info("%s", line)
2082 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2083 """ Helper method to hot-add a new device
2085 It gets free pci slot generates the device name and invokes the
2086 device specific method.
2089 # in case of hot-mod this is given
2090 if device.pci is None:
2091 self._GetFreePCISlot(instance, device)
2092 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2093 runtime = self._LoadKVMRuntime(instance)
2094 if dev_type == constants.HOTPLUG_TARGET_DISK:
2095 command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2097 command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2098 (hex(device.pci), kvm_devid, kvm_devid))
2099 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2100 (tap, fd) = _OpenTap()
2101 self._ConfigureNIC(instance, seq, device, tap)
2102 self._PassTapFd(instance, fd, device)
2103 command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2104 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2105 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2106 command += "device_add %s" % args
2107 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2109 self._CallHotplugCommand(instance.name, command)
2110 # update relevant entries in runtime file
2111 index = _DEVICE_RUNTIME_INDEX[dev_type]
2112 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2113 runtime[index].append(entry)
2114 self._SaveKVMRuntime(instance, runtime)
2116 def HotDelDevice(self, instance, dev_type, device, _, seq):
2117 """ Helper method for hot-del device
2119 It gets device info from runtime file, generates the device name and
2120 invokes the device specific method.
2123 runtime = self._LoadKVMRuntime(instance)
2124 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2125 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2126 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2127 if dev_type == constants.HOTPLUG_TARGET_DISK:
2128 command = "device_del %s\n" % kvm_devid
2129 command += "drive_del %s" % kvm_devid
2130 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2131 command = "device_del %s\n" % kvm_devid
2132 command += "netdev_del %s" % kvm_devid
2133 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2134 self._CallHotplugCommand(instance.name, command)
2135 index = _DEVICE_RUNTIME_INDEX[dev_type]
2136 runtime[index].remove(entry)
2137 self._SaveKVMRuntime(instance, runtime)
2139 return kvm_device.pci
2141 def HotModDevice(self, instance, dev_type, device, _, seq):
2142 """ Helper method for hot-mod device
2144 It gets device info from runtime file, generates the device name and
2145 invokes the device specific method. Currently only NICs support hot-mod
2148 if dev_type == constants.HOTPLUG_TARGET_NIC:
2149 # putting it back in the same pci slot
2150 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2151 # TODO: remove sleep when socat gets removed
2153 self.HotAddDevice(instance, dev_type, device, _, seq)
2155 def _PassTapFd(self, instance, fd, nic):
2156 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2159 # TODO: factor out code related to unix sockets.
2160 # squash common parts between monitor and qmp
2161 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2162 command = "getfd %s\n" % kvm_devid
2164 logging.info("%s", fds)
2166 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2168 fdsend.sendfds(monsock.sock, command, fds=fds)
2173 def _ParseKVMVersion(cls, text):
2174 """Parse the KVM version from the --help output.
2177 @param text: output of kvm --help
2178 @return: (version, v_maj, v_min, v_rev)
2179 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2182 match = cls._VERSION_RE.search(text.splitlines()[0])
2184 raise errors.HypervisorError("Unable to get KVM version")
2186 v_all = match.group(0)
2187 v_maj = int(match.group(1))
2188 v_min = int(match.group(2))
2190 v_rev = int(match.group(4))
2193 return (v_all, v_maj, v_min, v_rev)
2196 def _GetKVMOutput(cls, kvm_path, option):
2197 """Return the output of a kvm invocation
2199 @type kvm_path: string
2200 @param kvm_path: path to the kvm executable
2201 @type option: a key of _KVMOPTS_CMDS
2202 @param option: kvm option to fetch the output from
2203 @return: output a supported kvm invocation
2204 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2207 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2209 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2211 result = utils.RunCmd([kvm_path] + optlist)
2212 if result.failed and not can_fail:
2213 raise errors.HypervisorError("Unable to get KVM %s output" %
2215 return result.output
2218 def _GetKVMVersion(cls, kvm_path):
2219 """Return the installed KVM version.
2221 @return: (version, v_maj, v_min, v_rev)
2222 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2225 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2228 def _GetDefaultMachineVersion(cls, kvm_path):
2229 """Return the default hardware revision (e.g. pc-1.1)
2232 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2233 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2235 return match.group(1)
2239 def StopInstance(self, instance, force=False, retry=False, name=None,
2241 """Stop an instance.
2244 assert(timeout is None or force is not None)
2246 if name is not None and not force:
2247 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2249 name = instance.name
2250 acpi = instance.hvparams[constants.HV_ACPI]
2253 _, pid, alive = self._InstancePidAlive(name)
2254 if pid > 0 and alive:
2255 if force or not acpi:
2256 utils.KillProcess(pid)
2258 self._CallMonitorCommand(name, "system_powerdown", timeout)
2260 def CleanupInstance(self, instance_name):
2261 """Cleanup after a stopped instance
2264 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2265 if pid > 0 and alive:
2266 raise errors.HypervisorError("Cannot cleanup a live instance")
2267 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2269 def RebootInstance(self, instance):
2270 """Reboot an instance.
2273 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2274 # socket the instance will stop, but now power up again. So we'll resort
2275 # to shutdown and restart.
2276 _, _, alive = self._InstancePidAlive(instance.name)
2278 raise errors.HypervisorError("Failed to reboot instance %s:"
2279 " not running" % instance.name)
2280 # StopInstance will delete the saved KVM runtime so:
2281 # ...first load it...
2282 kvm_runtime = self._LoadKVMRuntime(instance)
2283 # ...now we can safely call StopInstance...
2284 if not self.StopInstance(instance):
2285 self.StopInstance(instance, force=True)
2286 # ...and finally we can save it again, and execute it...
2287 self._SaveKVMRuntime(instance, kvm_runtime)
2288 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2289 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2290 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2292 def MigrationInfo(self, instance):
2293 """Get instance information to perform a migration.
2295 @type instance: L{objects.Instance}
2296 @param instance: instance to be migrated
2298 @return: content of the KVM runtime file
2301 return self._ReadKVMRuntime(instance.name)
2303 def AcceptInstance(self, instance, info, target):
2304 """Prepare to accept an instance.
2306 @type instance: L{objects.Instance}
2307 @param instance: instance to be accepted
2309 @param info: content of the KVM runtime file on the source node
2310 @type target: string
2311 @param target: target host (usually ip), on this node
2314 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2315 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2316 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2317 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2318 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2319 incoming=incoming_address)
2321 def FinalizeMigrationDst(self, instance, info, success):
2322 """Finalize the instance migration on the target node.
2324 Stop the incoming mode KVM.
2326 @type instance: L{objects.Instance}
2327 @param instance: instance whose migration is being finalized
2331 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2332 kvm_nics = kvm_runtime[1]
2334 for nic_seq, nic in enumerate(kvm_nics):
2335 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2336 # Bridged interfaces have already been configured
2339 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2340 except EnvironmentError, err:
2341 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2342 instance.name, nic_seq, str(err))
2345 self._ConfigureNIC(instance, nic_seq, nic, tap)
2346 except errors.HypervisorError, err:
2347 logging.warning(str(err))
2349 self._WriteKVMRuntime(instance.name, info)
2351 self.StopInstance(instance, force=True)
2353 def MigrateInstance(self, instance, target, live):
2354 """Migrate an instance to a target node.
2356 The migration will not be attempted if the instance is not
2359 @type instance: L{objects.Instance}
2360 @param instance: the instance to be migrated
2361 @type target: string
2362 @param target: ip address of the target node
2364 @param live: perform a live migration
2367 instance_name = instance.name
2368 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2369 _, _, alive = self._InstancePidAlive(instance_name)
2371 raise errors.HypervisorError("Instance not running, cannot migrate")
2374 self._CallMonitorCommand(instance_name, "stop")
2376 migrate_command = ("migrate_set_speed %dm" %
2377 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2378 self._CallMonitorCommand(instance_name, migrate_command)
2380 migrate_command = ("migrate_set_downtime %dms" %
2381 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2382 self._CallMonitorCommand(instance_name, migrate_command)
2384 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2385 self._CallMonitorCommand(instance_name, migrate_command)
2387 def FinalizeMigrationSource(self, instance, success, live):
2388 """Finalize the instance migration on the source node.
2390 @type instance: L{objects.Instance}
2391 @param instance: the instance that was migrated
2393 @param success: whether the migration succeeded or not
2395 @param live: whether the user requested a live migration or not
2399 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2400 utils.KillProcess(pid)
2401 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2403 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2405 def GetMigrationStatus(self, instance):
2406 """Get the migration status
2408 @type instance: L{objects.Instance}
2409 @param instance: the instance that is being migrated
2410 @rtype: L{objects.MigrationStatus}
2411 @return: the status of the current migration (one of
2412 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2413 progress info that can be retrieved from the hypervisor
2416 info_command = "info migrate"
2417 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2418 result = self._CallMonitorCommand(instance.name, info_command)
2419 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2421 if not result.stdout:
2422 logging.info("KVM: empty 'info migrate' result")
2424 logging.warning("KVM: unknown 'info migrate' result: %s",
2427 status = match.group(1)
2428 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2429 migration_status = objects.MigrationStatus(status=status)
2430 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2432 migration_status.transferred_ram = match.group("transferred")
2433 migration_status.total_ram = match.group("total")
2435 return migration_status
2437 logging.warning("KVM: unknown migration status '%s'", status)
2439 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2441 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2443 def BalloonInstanceMemory(self, instance, mem):
2444 """Balloon an instance memory to a certain value.
2446 @type instance: L{objects.Instance}
2447 @param instance: instance to be accepted
2449 @param mem: actual memory size to use for instance runtime
2452 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2454 def GetNodeInfo(self):
2455 """Return information about the node.
2457 @return: a dict with the following keys (values in MiB):
2458 - memory_total: the total memory size on the node
2459 - memory_free: the available memory on the node for instances
2460 - memory_dom0: the memory used by the node itself, if available
2461 - hv_version: the hypervisor version in the form (major, minor,
2465 result = self.GetLinuxNodeInfo()
2466 # FIXME: this is the global kvm version, but the actual version can be
2467 # customized as an hv parameter. we should use the nodegroup's default kvm
2468 # path parameter here.
2469 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2470 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2474 def GetInstanceConsole(cls, instance, hvparams, beparams):
2475 """Return a command for connecting to the console of an instance.
2478 if hvparams[constants.HV_SERIAL_CONSOLE]:
2479 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2480 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2481 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2482 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2483 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2484 return objects.InstanceConsole(instance=instance.name,
2485 kind=constants.CONS_SSH,
2486 host=instance.primary_node,
2487 user=constants.SSH_CONSOLE_USER,
2490 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2491 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2492 display = instance.network_port - constants.VNC_BASE_PORT
2493 return objects.InstanceConsole(instance=instance.name,
2494 kind=constants.CONS_VNC,
2495 host=vnc_bind_address,
2496 port=instance.network_port,
2499 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2501 return objects.InstanceConsole(instance=instance.name,
2502 kind=constants.CONS_SPICE,
2504 port=instance.network_port)
2506 return objects.InstanceConsole(instance=instance.name,
2507 kind=constants.CONS_MESSAGE,
2508 message=("No serial shell for instance %s" %
2512 """Verify the hypervisor.
2514 Check that the required binaries exist.
2516 @return: Problem description if something is wrong, C{None} otherwise
2520 # FIXME: this is the global kvm binary, but the actual path can be
2521 # customized as an hv parameter; we should use the nodegroup's
2522 # default kvm path parameter here.
2523 if not os.path.exists(constants.KVM_PATH):
2524 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2525 if not os.path.exists(constants.SOCAT_PATH):
2526 msgs.append("The socat binary ('%s') does not exist" %
2527 constants.SOCAT_PATH)
2529 return self._FormatVerifyResults(msgs)
2532 def CheckParameterSyntax(cls, hvparams):
2533 """Check the given parameters for validity.
2535 @type hvparams: dict
2536 @param hvparams: dictionary with parameter names/value
2537 @raise errors.HypervisorError: when a parameter is not valid
2540 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2542 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2544 if not hvparams[constants.HV_ROOT_PATH]:
2545 raise errors.HypervisorError("Need a root partition for the instance,"
2546 " if a kernel is defined")
2548 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2549 not hvparams[constants.HV_VNC_X509]):
2550 raise errors.HypervisorError("%s must be defined, if %s is" %
2551 (constants.HV_VNC_X509,
2552 constants.HV_VNC_X509_VERIFY))
2554 if hvparams[constants.HV_SERIAL_CONSOLE]:
2555 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2556 valid_speeds = constants.VALID_SERIAL_SPEEDS
2557 if not serial_speed or serial_speed not in valid_speeds:
2558 raise errors.HypervisorError("Invalid serial console speed, must be"
2560 utils.CommaJoin(valid_speeds))
2562 boot_order = hvparams[constants.HV_BOOT_ORDER]
2563 if (boot_order == constants.HT_BO_CDROM and
2564 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2565 raise errors.HypervisorError("Cannot boot from cdrom without an"
2568 security_model = hvparams[constants.HV_SECURITY_MODEL]
2569 if security_model == constants.HT_SM_USER:
2570 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2571 raise errors.HypervisorError("A security domain (user to run kvm as)"
2572 " must be specified")
2573 elif (security_model == constants.HT_SM_NONE or
2574 security_model == constants.HT_SM_POOL):
2575 if hvparams[constants.HV_SECURITY_DOMAIN]:
2576 raise errors.HypervisorError("Cannot have a security domain when the"
2577 " security model is 'none' or 'pool'")
2579 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2580 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2582 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2583 # if an IP version is specified, the spice_bind parameter must be an
2585 if (netutils.IP4Address.IsValid(spice_bind) and
2586 spice_ip_version != constants.IP4_VERSION):
2587 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2588 " the specified IP version is %s" %
2589 (spice_bind, spice_ip_version))
2591 if (netutils.IP6Address.IsValid(spice_bind) and
2592 spice_ip_version != constants.IP6_VERSION):
2593 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2594 " the specified IP version is %s" %
2595 (spice_bind, spice_ip_version))
2597 # All the other SPICE parameters depend on spice_bind being set. Raise an
2598 # error if any of them is set without it.
2599 for param in _SPICE_ADDITIONAL_PARAMS:
2601 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2602 (param, constants.HV_KVM_SPICE_BIND))
2605 def ValidateParameters(cls, hvparams):
2606 """Check the given parameters for validity.
2608 @type hvparams: dict
2609 @param hvparams: dictionary with parameter names/value
2610 @raise errors.HypervisorError: when a parameter is not valid
2613 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2615 kvm_path = hvparams[constants.HV_KVM_PATH]
2617 security_model = hvparams[constants.HV_SECURITY_MODEL]
2618 if security_model == constants.HT_SM_USER:
2619 username = hvparams[constants.HV_SECURITY_DOMAIN]
2621 pwd.getpwnam(username)
2623 raise errors.HypervisorError("Unknown security domain user %s"
2626 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2628 # only one of VNC and SPICE can be used currently.
2629 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2630 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2631 " only one of them can be used at a"
2634 # check that KVM supports SPICE
2635 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2636 if not cls._SPICE_RE.search(kvmhelp):
2637 raise errors.HypervisorError("SPICE is configured, but it is not"
2638 " supported according to 'kvm --help'")
2640 # if spice_bind is not an IP address, it must be a valid interface
2641 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2642 netutils.IP6Address.IsValid(spice_bind))
2643 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2644 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2645 " a valid IP address or interface name" %
2646 constants.HV_KVM_SPICE_BIND)
2648 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2650 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2651 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2652 raise errors.HypervisorError("Unsupported machine version: %s" %
2656 def PowercycleNode(cls):
2657 """KVM powercycle, just a wrapper over Linux powercycle.
2660 cls.LinuxPowercycle()