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"
761 _FIND_PCI_DEVICE_RE = \
762 staticmethod(lambda pci, devid:
763 re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' % (pci, devid),
767 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
768 _INFO_VERSION_CMD = "info version"
770 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
775 ANCILLARY_FILES_OPT = [
779 # Supported kvm options to get output from
780 _KVMOPT_HELP = "help"
781 _KVMOPT_MLIST = "mlist"
782 _KVMOPT_DEVICELIST = "devicelist"
784 # Command to execute to get the output from kvm, and whether to
785 # accept the output even on failure.
787 _KVMOPT_HELP: (["--help"], False),
788 _KVMOPT_MLIST: (["-M", "?"], False),
789 _KVMOPT_DEVICELIST: (["-device", "?"], True),
793 hv_base.BaseHypervisor.__init__(self)
794 # Let's make sure the directories we need exist, even if the RUN_DIR lives
795 # in a tmpfs filesystem or has been otherwise wiped out.
796 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
797 utils.EnsureDirs(dirs)
800 def _InstancePidFile(cls, instance_name):
801 """Returns the instance pidfile.
804 return utils.PathJoin(cls._PIDS_DIR, instance_name)
807 def _InstanceUidFile(cls, instance_name):
808 """Returns the instance uidfile.
811 return utils.PathJoin(cls._UIDS_DIR, instance_name)
814 def _InstancePidInfo(cls, pid):
815 """Check pid file for instance information.
817 Check that a pid file is associated with an instance, and retrieve
818 information from its command line.
820 @type pid: string or int
821 @param pid: process id of the instance to check
823 @return: (instance_name, memory, vcpus)
824 @raise errors.HypervisorError: when an instance cannot be found
827 alive = utils.IsProcessAlive(pid)
829 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
831 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
833 cmdline = utils.ReadFile(cmdline_file)
834 except EnvironmentError, err:
835 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
842 arg_list = cmdline.split("\x00")
844 arg = arg_list.pop(0)
846 instance = arg_list.pop(0)
848 memory = int(arg_list.pop(0))
850 vcpus = int(arg_list.pop(0).split(",")[0])
853 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
856 return (instance, memory, vcpus)
858 def _InstancePidAlive(self, instance_name):
859 """Returns the instance pidfile, pid, and liveness.
861 @type instance_name: string
862 @param instance_name: instance name
864 @return: (pid file name, pid, liveness)
867 pidfile = self._InstancePidFile(instance_name)
868 pid = utils.ReadPidFile(pidfile)
872 cmd_instance = self._InstancePidInfo(pid)[0]
873 alive = (cmd_instance == instance_name)
874 except errors.HypervisorError:
877 return (pidfile, pid, alive)
879 def _CheckDown(self, instance_name):
880 """Raises an error unless the given instance is down.
883 alive = self._InstancePidAlive(instance_name)[2]
885 raise errors.HypervisorError("Failed to start instance %s: %s" %
886 (instance_name, "already running"))
889 def _InstanceMonitor(cls, instance_name):
890 """Returns the instance monitor socket name
893 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
896 def _InstanceSerial(cls, instance_name):
897 """Returns the instance serial socket name
900 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
903 def _InstanceQmpMonitor(cls, instance_name):
904 """Returns the instance serial QMP socket name
907 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
910 def _SocatUnixConsoleParams():
911 """Returns the correct parameters for socat
913 If we have a new-enough socat we can use raw mode with an escape character.
916 if constants.SOCAT_USE_ESCAPE:
917 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
919 return "echo=0,icanon=0"
922 def _InstanceKVMRuntime(cls, instance_name):
923 """Returns the instance KVM runtime filename
926 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
929 def _InstanceChrootDir(cls, instance_name):
930 """Returns the name of the KVM chroot dir of the instance
933 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
936 def _InstanceNICDir(cls, instance_name):
937 """Returns the name of the directory holding the tap device files for a
941 return utils.PathJoin(cls._NICS_DIR, instance_name)
944 def _InstanceNICFile(cls, instance_name, seq):
945 """Returns the name of the file containing the tap device for a given NIC
948 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
951 def _InstanceKeymapFile(cls, instance_name):
952 """Returns the name of the file containing the keymap for a given instance
955 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
958 def _TryReadUidFile(cls, uid_file):
959 """Try to read a uid file
962 if os.path.exists(uid_file):
964 uid = int(utils.ReadOneLineFile(uid_file))
966 except EnvironmentError:
967 logging.warning("Can't read uid file", exc_info=True)
968 except (TypeError, ValueError):
969 logging.warning("Can't parse uid file contents", exc_info=True)
973 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
974 """Removes an instance's rutime sockets/files/dirs.
977 utils.RemoveFile(pidfile)
978 utils.RemoveFile(cls._InstanceMonitor(instance_name))
979 utils.RemoveFile(cls._InstanceSerial(instance_name))
980 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
981 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
982 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
983 uid_file = cls._InstanceUidFile(instance_name)
984 uid = cls._TryReadUidFile(uid_file)
985 utils.RemoveFile(uid_file)
987 uidpool.ReleaseUid(uid)
989 shutil.rmtree(cls._InstanceNICDir(instance_name))
991 if err.errno != errno.ENOENT:
994 chroot_dir = cls._InstanceChrootDir(instance_name)
995 utils.RemoveDir(chroot_dir)
997 if err.errno == errno.ENOTEMPTY:
998 # The chroot directory is expected to be empty, but it isn't.
999 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
1002 utils.TimestampForFilename()))
1003 logging.warning("The chroot directory of instance %s can not be"
1004 " removed as it is not empty. Moving it to the"
1005 " quarantine instead. Please investigate the"
1006 " contents (%s) and clean up manually",
1007 instance_name, new_chroot_dir)
1008 utils.RenameFile(chroot_dir, new_chroot_dir)
1013 def _ConfigureNIC(instance, seq, nic, tap):
1014 """Run the network configuration script for a specified NIC
1016 @param instance: instance we're acting on
1017 @type instance: instance object
1018 @param seq: nic sequence number
1020 @param nic: nic we're acting on
1021 @type nic: nic object
1022 @param tap: the host's tap interface this NIC corresponds to
1027 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1028 "INSTANCE": instance.name,
1030 "MODE": nic.nicparams[constants.NIC_MODE],
1032 "INTERFACE_INDEX": str(seq),
1033 "INTERFACE_UUID": nic.uuid,
1034 "TAGS": " ".join(instance.GetTags()),
1041 env["INTERFACE_NAME"] = nic.name
1043 if nic.nicparams[constants.NIC_LINK]:
1044 env["LINK"] = nic.nicparams[constants.NIC_LINK]
1047 n = objects.Network.FromDict(nic.netinfo)
1048 env.update(n.HooksDict())
1050 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1051 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1053 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1055 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1056 " network configuration script output: %s" %
1057 (tap, result.fail_reason, result.output))
1060 def _VerifyAffinityPackage():
1061 if affinity is None:
1062 raise errors.HypervisorError("affinity Python package not"
1063 " found; cannot use CPU pinning under KVM")
1066 def _BuildAffinityCpuMask(cpu_list):
1067 """Create a CPU mask suitable for sched_setaffinity from a list of
1070 See man taskset for more info on sched_setaffinity masks.
1071 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1073 @type cpu_list: list of int
1074 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1076 @return: a bit mask of CPU affinities
1079 if cpu_list == constants.CPU_PINNING_OFF:
1080 return constants.CPU_PINNING_ALL_KVM
1082 return sum(2 ** cpu for cpu in cpu_list)
1085 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1086 """Change CPU affinity for running VM according to given CPU mask.
1088 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1089 @type cpu_mask: string
1090 @param process_id: process ID of KVM process. Used to pin entire VM
1092 @type process_id: int
1093 @param thread_dict: map of virtual CPUs to KVM thread IDs
1094 @type thread_dict: dict int:int
1097 # Convert the string CPU mask to a list of list of int's
1098 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1100 if len(cpu_list) == 1:
1101 all_cpu_mapping = cpu_list[0]
1102 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1103 # If CPU pinning has 1 entry that's "all", then do nothing
1106 # If CPU pinning has one non-all entry, map the entire VM to
1107 # one set of physical CPUs
1108 cls._VerifyAffinityPackage()
1109 affinity.set_process_affinity_mask(
1110 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1112 # The number of vCPUs mapped should match the number of vCPUs
1113 # reported by KVM. This was already verified earlier, so
1114 # here only as a sanity check.
1115 assert len(thread_dict) == len(cpu_list)
1116 cls._VerifyAffinityPackage()
1118 # For each vCPU, map it to the proper list of physical CPUs
1119 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1120 affinity.set_process_affinity_mask(thread_dict[i],
1121 cls._BuildAffinityCpuMask(vcpu))
1123 def _GetVcpuThreadIds(self, instance_name):
1124 """Get a mapping of vCPU no. to thread IDs for the instance
1126 @type instance_name: string
1127 @param instance_name: instance in question
1128 @rtype: dictionary of int:int
1129 @return: a dictionary mapping vCPU numbers to thread IDs
1133 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1134 for line in output.stdout.splitlines():
1135 match = self._CPU_INFO_RE.search(line)
1138 grp = map(int, match.groups())
1139 result[grp[0]] = grp[1]
1143 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1144 """Complete CPU pinning.
1146 @type instance_name: string
1147 @param instance_name: name of instance
1148 @type cpu_mask: string
1149 @param cpu_mask: CPU pinning mask as entered by user
1152 # Get KVM process ID, to be used if need to pin entire VM
1153 _, pid, _ = self._InstancePidAlive(instance_name)
1154 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1155 thread_dict = self._GetVcpuThreadIds(instance_name)
1156 # Run CPU pinning, based on configured mask
1157 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1159 def ListInstances(self):
1160 """Get the list of running instances.
1162 We can do this by listing our live instances directory and
1163 checking whether the associated kvm process is still alive.
1167 for name in os.listdir(self._PIDS_DIR):
1168 if self._InstancePidAlive(name)[2]:
1172 def GetInstanceInfo(self, instance_name):
1173 """Get instance properties.
1175 @type instance_name: string
1176 @param instance_name: the instance name
1177 @rtype: tuple of strings
1178 @return: (name, id, memory, vcpus, stat, times)
1181 _, pid, alive = self._InstancePidAlive(instance_name)
1185 _, memory, vcpus = self._InstancePidInfo(pid)
1190 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1192 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1193 # Will fail if ballooning is not enabled, but we can then just resort to
1195 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1196 memory = mem_bytes / 1048576
1197 except errors.HypervisorError:
1200 return (instance_name, pid, memory, vcpus, istat, times)
1202 def GetAllInstancesInfo(self):
1203 """Get properties of all instances.
1205 @return: list of tuples (name, id, memory, vcpus, stat, times)
1209 for name in os.listdir(self._PIDS_DIR):
1211 info = self.GetInstanceInfo(name)
1212 except errors.HypervisorError:
1213 # Ignore exceptions due to instances being shut down
1219 def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1221 """Generate KVM options regarding instance's block devices.
1223 @type instance: L{objects.Instance}
1224 @param instance: the instance object
1225 @type kvm_disks: list of tuples
1226 @param kvm_disks: list of tuples [(disk, link_name)..]
1227 @type kvmhelp: string
1228 @param kvmhelp: output of kvm --help
1229 @type devlist: string
1230 @param devlist: output of kvm -device ?
1232 @return: list of command line options eventually used by kvm executable
1235 hvp = instance.hvparams
1236 kernel_path = hvp[constants.HV_KERNEL_PATH]
1240 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1242 # whether this is an older KVM version that uses the boot=on flag
1244 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1247 device_driver = None
1248 disk_type = hvp[constants.HV_DISK_TYPE]
1249 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1250 if_val = ",if=%s" % self._VIRTIO
1252 if self._VIRTIO_BLK_RE.search(devlist):
1254 # will be passed in -device option as driver
1255 device_driver = self._VIRTIO_BLK_PCI
1256 except errors.HypervisorError, _:
1259 if_val = ",if=%s" % disk_type
1261 disk_cache = hvp[constants.HV_DISK_CACHE]
1262 if instance.disk_template in constants.DTS_EXT_MIRROR:
1263 if disk_cache != "none":
1264 # TODO: make this a hard error, instead of a silent overwrite
1265 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1266 " to prevent shared storage corruption on migration",
1268 cache_val = ",cache=none"
1269 elif disk_cache != constants.HT_CACHE_DEFAULT:
1270 cache_val = ",cache=%s" % disk_cache
1273 for idx, (cfdev, link_name) in enumerate(kvm_disks):
1274 if cfdev.mode != constants.DISK_RDWR:
1275 raise errors.HypervisorError("Instance has read-only disks which"
1276 " are not supported by KVM")
1277 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1280 dev_opts.extend(["-boot", "c"])
1282 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1283 boot_val = ",boot=on"
1285 # For ext we allow overriding disk_cache hypervisor params per disk
1286 disk_cache = cfdev.params.get("cache", None)
1288 cache_val = ",cache=%s" % disk_cache
1289 drive_val = "file=%s,format=raw%s%s%s" % \
1290 (link_name, if_val, boot_val, cache_val)
1293 # kvm_disks are the 4th entry of runtime file that did not exist in
1294 # the past. That means that cfdev should always have pci slot and
1295 # _GenerateDeviceKVMId() will not raise a exception.
1296 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK,
1298 drive_val += (",id=%s" % kvm_devid)
1300 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1301 dev_val = ("%s,drive=%s,id=%s" %
1302 (device_driver, kvm_devid, kvm_devid))
1304 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1305 dev_opts.extend(["-device", dev_val])
1307 # TODO: export disk geometry in IDISK_PARAMS
1308 heads = cfdev.params.get('heads', None)
1309 secs = cfdev.params.get('secs', None)
1311 nr_sectors = cfdev.size * 1024 * 1024 / 512
1312 cyls = nr_sectors / (int(heads) * int(secs))
1317 if cyls and heads and secs:
1318 drive_val += (",cyls=%d,heads=%d,secs=%d" %
1319 (cyls, int(heads), int(secs)))
1321 dev_opts.extend(["-drive", drive_val])
1325 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1327 """Generate KVM information to start an instance.
1329 @type kvmhelp: string
1330 @param kvmhelp: output of kvm --help
1331 @attention: this function must not have any side-effects; for
1332 example, it must not write to the filesystem, or read values
1333 from the current system the are expected to differ between
1334 nodes, since it is only run once at instance startup;
1335 actions/kvm arguments that can vary between systems should be
1336 done in L{_ExecuteKVMRuntime}
1339 # pylint: disable=R0912,R0914,R0915
1340 hvp = instance.hvparams
1341 self.ValidateParameters(hvp)
1343 pidfile = self._InstancePidFile(instance.name)
1344 kvm = hvp[constants.HV_KVM_PATH]
1346 # used just by the vnc server, if enabled
1347 kvm_cmd.extend(["-name", instance.name])
1348 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1350 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1351 if hvp[constants.HV_CPU_CORES]:
1352 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1353 if hvp[constants.HV_CPU_THREADS]:
1354 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1355 if hvp[constants.HV_CPU_SOCKETS]:
1356 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1358 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1360 kvm_cmd.extend(["-pidfile", pidfile])
1361 kvm_cmd.extend(["-balloon", "virtio"])
1362 kvm_cmd.extend(["-daemonize"])
1363 if not instance.hvparams[constants.HV_ACPI]:
1364 kvm_cmd.extend(["-no-acpi"])
1365 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1366 constants.INSTANCE_REBOOT_EXIT:
1367 kvm_cmd.extend(["-no-reboot"])
1369 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1371 mversion = self._GetDefaultMachineVersion(kvm)
1372 if self._MACHINE_RE.search(kvmhelp):
1373 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1374 # extra hypervisor parameters. We should also investigate whether and how
1375 # shadow_mem should be considered for the resource model.
1376 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1377 specprop = ",accel=kvm"
1380 machinespec = "%s%s" % (mversion, specprop)
1381 kvm_cmd.extend(["-machine", machinespec])
1383 kvm_cmd.extend(["-M", mversion])
1384 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1385 self._ENABLE_KVM_RE.search(kvmhelp)):
1386 kvm_cmd.extend(["-enable-kvm"])
1387 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1388 self._DISABLE_KVM_RE.search(kvmhelp)):
1389 kvm_cmd.extend(["-disable-kvm"])
1391 kernel_path = hvp[constants.HV_KERNEL_PATH]
1393 boot_cdrom = boot_floppy = boot_network = False
1395 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1396 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1397 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1400 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1403 kvm_cmd.extend(["-boot", "n"])
1405 # whether this is an older KVM version that uses the boot=on flag
1407 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1409 disk_type = hvp[constants.HV_DISK_TYPE]
1411 #Now we can specify a different device type for CDROM devices.
1412 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1413 if not cdrom_disk_type:
1414 cdrom_disk_type = disk_type
1416 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1418 options = ",format=raw,media=cdrom"
1419 # set cdrom 'if' type
1421 actual_cdrom_type = constants.HT_DISK_IDE
1422 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1423 actual_cdrom_type = "virtio"
1425 actual_cdrom_type = cdrom_disk_type
1426 if_val = ",if=%s" % actual_cdrom_type
1427 # set boot flag, if needed
1430 kvm_cmd.extend(["-boot", "d"])
1432 boot_val = ",boot=on"
1433 # and finally build the entire '-drive' value
1434 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1435 kvm_cmd.extend(["-drive", drive_val])
1437 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1439 options = ",format=raw,media=cdrom"
1440 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1441 if_val = ",if=virtio"
1443 if_val = ",if=%s" % cdrom_disk_type
1444 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1445 kvm_cmd.extend(["-drive", drive_val])
1447 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1449 options = ",format=raw,media=disk"
1451 kvm_cmd.extend(["-boot", "a"])
1452 options = "%s,boot=on" % options
1453 if_val = ",if=floppy"
1454 options = "%s%s" % (options, if_val)
1455 drive_val = "file=%s%s" % (floppy_image, options)
1456 kvm_cmd.extend(["-drive", drive_val])
1459 kvm_cmd.extend(["-kernel", kernel_path])
1460 initrd_path = hvp[constants.HV_INITRD_PATH]
1462 kvm_cmd.extend(["-initrd", initrd_path])
1463 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1464 hvp[constants.HV_KERNEL_ARGS]]
1465 if hvp[constants.HV_SERIAL_CONSOLE]:
1466 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1467 root_append.append("console=ttyS0,%s" % serial_speed)
1468 kvm_cmd.extend(["-append", " ".join(root_append)])
1470 mem_path = hvp[constants.HV_MEM_PATH]
1472 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1474 monitor_dev = ("unix:%s,server,nowait" %
1475 self._InstanceMonitor(instance.name))
1476 kvm_cmd.extend(["-monitor", monitor_dev])
1477 if hvp[constants.HV_SERIAL_CONSOLE]:
1478 serial_dev = ("unix:%s,server,nowait" %
1479 self._InstanceSerial(instance.name))
1480 kvm_cmd.extend(["-serial", serial_dev])
1482 kvm_cmd.extend(["-serial", "none"])
1484 mouse_type = hvp[constants.HV_USB_MOUSE]
1485 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1486 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1487 spice_ip_version = None
1489 kvm_cmd.extend(["-usb"])
1492 kvm_cmd.extend(["-usbdevice", mouse_type])
1493 elif vnc_bind_address:
1494 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1496 if vnc_bind_address:
1497 if netutils.IP4Address.IsValid(vnc_bind_address):
1498 if instance.network_port > constants.VNC_BASE_PORT:
1499 display = instance.network_port - constants.VNC_BASE_PORT
1500 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1501 vnc_arg = ":%d" % (display)
1503 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1505 logging.error("Network port is not a valid VNC display (%d < %d),"
1506 " not starting VNC",
1507 instance.network_port, constants.VNC_BASE_PORT)
1510 # Only allow tls and other option when not binding to a file, for now.
1511 # kvm/qemu gets confused otherwise about the filename to use.
1513 if hvp[constants.HV_VNC_TLS]:
1514 vnc_append = "%s,tls" % vnc_append
1515 if hvp[constants.HV_VNC_X509_VERIFY]:
1516 vnc_append = "%s,x509verify=%s" % (vnc_append,
1517 hvp[constants.HV_VNC_X509])
1518 elif hvp[constants.HV_VNC_X509]:
1519 vnc_append = "%s,x509=%s" % (vnc_append,
1520 hvp[constants.HV_VNC_X509])
1521 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1522 vnc_append = "%s,password" % vnc_append
1524 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1527 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1529 kvm_cmd.extend(["-vnc", vnc_arg])
1531 # FIXME: this is wrong here; the iface ip address differs
1532 # between systems, so it should be done in _ExecuteKVMRuntime
1533 if netutils.IsValidInterface(spice_bind):
1534 # The user specified a network interface, we have to figure out the IP
1536 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1537 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1539 # if the user specified an IP version and the interface does not
1540 # have that kind of IP addresses, throw an exception
1541 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1542 if not addresses[spice_ip_version]:
1543 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1544 " for %s" % (spice_ip_version,
1547 # the user did not specify an IP version, we have to figure it out
1548 elif (addresses[constants.IP4_VERSION] and
1549 addresses[constants.IP6_VERSION]):
1550 # we have both ipv4 and ipv6, let's use the cluster default IP
1552 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1553 spice_ip_version = \
1554 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1555 elif addresses[constants.IP4_VERSION]:
1556 spice_ip_version = constants.IP4_VERSION
1557 elif addresses[constants.IP6_VERSION]:
1558 spice_ip_version = constants.IP6_VERSION
1560 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1561 " for %s" % (spice_bind))
1563 spice_address = addresses[spice_ip_version][0]
1566 # spice_bind is known to be a valid IP address, because
1567 # ValidateParameters checked it.
1568 spice_address = spice_bind
1570 spice_arg = "addr=%s" % spice_address
1571 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1572 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1573 (spice_arg, instance.network_port,
1574 pathutils.SPICE_CACERT_FILE))
1575 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1576 (spice_arg, pathutils.SPICE_CERT_FILE,
1577 pathutils.SPICE_CERT_FILE))
1578 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1580 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1582 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1584 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1585 spice_arg = "%s,disable-ticketing" % spice_arg
1587 if spice_ip_version:
1588 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1590 # Image compression options
1591 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1592 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1593 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1595 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1597 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1599 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1601 # Video stream detection
1602 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1604 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1606 # Audio compression, by default in qemu-kvm it is on
1607 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1608 spice_arg = "%s,playback-compression=off" % spice_arg
1609 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1610 spice_arg = "%s,agent-mouse=off" % spice_arg
1612 # Enable the spice agent communication channel between the host and the
1614 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1617 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1619 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1621 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1622 kvm_cmd.extend(["-spice", spice_arg])
1625 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1626 # also works in earlier versions though (tested with 1.1 and 1.3)
1627 if self._DISPLAY_RE.search(kvmhelp):
1628 kvm_cmd.extend(["-display", "none"])
1630 kvm_cmd.extend(["-nographic"])
1632 if hvp[constants.HV_USE_LOCALTIME]:
1633 kvm_cmd.extend(["-localtime"])
1635 if hvp[constants.HV_KVM_USE_CHROOT]:
1636 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1638 # Add qemu-KVM -cpu param
1639 if hvp[constants.HV_CPU_TYPE]:
1640 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1642 # As requested by music lovers
1643 if hvp[constants.HV_SOUNDHW]:
1644 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1646 # Pass a -vga option if requested, or if spice is used, for backwards
1648 if hvp[constants.HV_VGA]:
1649 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1651 kvm_cmd.extend(["-vga", "qxl"])
1653 # Various types of usb devices, comma separated
1654 if hvp[constants.HV_USB_DEVICES]:
1655 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1656 kvm_cmd.extend(["-usbdevice", dev])
1658 if hvp[constants.HV_KVM_EXTRA]:
1659 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1661 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1663 for disk, link_name in block_devices:
1664 _UpdatePCISlots(disk, pci_reservations)
1665 kvm_disks.append((disk, link_name))
1668 for nic in instance.nics:
1669 _UpdatePCISlots(nic, pci_reservations)
1670 kvm_nics.append(nic)
1674 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1676 def _WriteKVMRuntime(self, instance_name, data):
1677 """Write an instance's KVM runtime
1681 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1683 except EnvironmentError, err:
1684 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1686 def _ReadKVMRuntime(self, instance_name):
1687 """Read an instance's KVM runtime
1691 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1692 except EnvironmentError, err:
1693 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1696 def _SaveKVMRuntime(self, instance, kvm_runtime):
1697 """Save an instance's KVM runtime
1700 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1702 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1703 serialized_disks = [(blk.ToDict(), link)
1704 for blk, link in kvm_disks]
1705 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1708 self._WriteKVMRuntime(instance.name, serialized_form)
1710 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1711 """Load an instance's KVM runtime
1714 if not serialized_runtime:
1715 serialized_runtime = self._ReadKVMRuntime(instance.name)
1717 return _AnalyzeSerializedRuntime(serialized_runtime)
1719 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1720 """Run the KVM cmd and check for errors
1723 @param name: instance name
1724 @type kvm_cmd: list of strings
1725 @param kvm_cmd: runcmd input for kvm
1726 @type tap_fds: list of int
1727 @param tap_fds: fds of tap devices opened by Ganeti
1731 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1734 utils_wrapper.CloseFdNoError(fd)
1737 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1738 (name, result.fail_reason, result.output))
1739 if not self._InstancePidAlive(name)[2]:
1740 raise errors.HypervisorError("Failed to start instance %s" % name)
1742 # too many local variables
1743 # pylint: disable=R0914
1744 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1745 """Execute a KVM cmd, after completing it with some last minute data.
1747 @type incoming: tuple of strings
1748 @param incoming: (target_host_ip, port)
1749 @type kvmhelp: string
1750 @param kvmhelp: output of kvm --help
1753 # Small _ExecuteKVMRuntime hv parameters programming howto:
1754 # - conf_hvp contains the parameters as configured on ganeti. they might
1755 # have changed since the instance started; only use them if the change
1756 # won't affect the inside of the instance (which hasn't been rebooted).
1757 # - up_hvp contains the parameters as they were when the instance was
1758 # started, plus any new parameter which has been added between ganeti
1759 # versions: it is paramount that those default to a value which won't
1760 # affect the inside of the instance as well.
1761 conf_hvp = instance.hvparams
1762 name = instance.name
1763 self._CheckDown(name)
1767 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1768 # the first element of kvm_cmd is always the path to the kvm binary
1769 kvm_path = kvm_cmd[0]
1770 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1772 # We know it's safe to run as a different user upon migration, so we'll use
1773 # the latest conf, from conf_hvp.
1774 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1775 if security_model == constants.HT_SM_USER:
1776 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1778 keymap = conf_hvp[constants.HV_KEYMAP]
1780 keymap_path = self._InstanceKeymapFile(name)
1781 # If a keymap file is specified, KVM won't use its internal defaults. By
1782 # first including the "en-us" layout, an error on loading the actual
1783 # layout (e.g. because it can't be found) won't lead to a non-functional
1784 # keyboard. A keyboard with incorrect keys is still better than none.
1785 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1786 kvm_cmd.extend(["-k", keymap_path])
1788 # We have reasons to believe changing something like the nic driver/type
1789 # upon migration won't exactly fly with the instance kernel, so for nic
1790 # related parameters we'll use up_hvp
1793 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1795 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1799 kvm_cmd.extend(bdev_opts)
1802 kvm_cmd.extend(["-net", "none"])
1806 nic_type = up_hvp[constants.HV_NIC_TYPE]
1807 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1808 nic_model = self._VIRTIO
1810 if self._VIRTIO_NET_RE.search(devlist):
1811 nic_model = self._VIRTIO_NET_PCI
1812 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1813 except errors.HypervisorError, _:
1814 # Older versions of kvm don't support DEVICE_LIST, but they don't
1815 # have new virtio syntax either.
1818 if up_hvp[constants.HV_VHOST_NET]:
1819 # check for vhost_net support
1820 if self._VHOST_RE.search(kvmhelp):
1821 tap_extra = ",vhost=on"
1823 raise errors.HypervisorError("vhost_net is configured"
1824 " but it is not available")
1826 nic_model = nic_type
1828 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1830 for nic_seq, nic in enumerate(kvm_nics):
1831 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1832 tapfds.append(tapfd)
1833 taps.append(tapname)
1834 if kvm_supports_netdev:
1835 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1837 # kvm_nics already exist in old runtime files and thus there might
1838 # be some entries without pci slot (therefore try: except:)
1839 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1841 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1842 except errors.HotplugError:
1843 netdev = "netdev%d" % nic_seq
1844 nic_val += (",netdev=%s" % netdev)
1845 tap_val = ("type=tap,id=%s,fd=%d%s" %
1846 (netdev, tapfd, tap_extra))
1847 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1849 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1851 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1852 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1855 target, port = incoming
1856 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1858 # Changing the vnc password doesn't bother the guest that much. At most it
1859 # will surprise people who connect to it. Whether positively or negatively
1861 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1865 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1866 except EnvironmentError, err:
1867 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1868 % (vnc_pwd_file, err))
1870 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1871 utils.EnsureDirs([(self._InstanceChrootDir(name),
1872 constants.SECURE_DIR_MODE)])
1874 # Automatically enable QMP if version is >= 0.14
1875 if self._QMP_RE.search(kvmhelp):
1876 logging.debug("Enabling QMP")
1877 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1878 self._InstanceQmpMonitor(instance.name)])
1880 # Configure the network now for starting instances and bridged interfaces,
1881 # during FinalizeMigration for incoming instances' routed interfaces
1882 for nic_seq, nic in enumerate(kvm_nics):
1884 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1886 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1888 # CPU affinity requires kvm to start paused, so we set this flag if the
1889 # instance is not already paused and if we are not going to accept a
1890 # migrating instance. In the latter case, pausing is not needed.
1891 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1892 if start_kvm_paused:
1893 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1895 # Note: CPU pinning is using up_hvp since changes take effect
1896 # during instance startup anyway, and to avoid problems when soft
1897 # rebooting the instance.
1899 if up_hvp.get(constants.HV_CPU_MASK, None):
1902 if security_model == constants.HT_SM_POOL:
1903 ss = ssconf.SimpleStore()
1904 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1905 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1906 uid = uidpool.RequestUnusedUid(all_uids)
1908 username = pwd.getpwuid(uid.GetUid()).pw_name
1909 kvm_cmd.extend(["-runas", username])
1910 self._RunKVMCmd(name, kvm_cmd, tapfds)
1912 uidpool.ReleaseUid(uid)
1916 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1918 self._RunKVMCmd(name, kvm_cmd, tapfds)
1920 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1921 constants.RUN_DIRS_MODE)])
1922 for nic_seq, tap in enumerate(taps):
1923 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1927 change_cmd = "change vnc password %s" % vnc_pwd
1928 self._CallMonitorCommand(instance.name, change_cmd)
1930 # Setting SPICE password. We are not vulnerable to malicious passwordless
1931 # connection attempts because SPICE by default does not allow connections
1932 # if neither a password nor the "disable_ticketing" options are specified.
1933 # As soon as we send the password via QMP, that password is a valid ticket
1935 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1936 if spice_password_file:
1939 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1940 except EnvironmentError, err:
1941 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1942 % (spice_password_file, err))
1944 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1947 "protocol": "spice",
1948 "password": spice_pwd,
1950 qmp.Execute("set_password", arguments)
1952 for filename in temp_files:
1953 utils.RemoveFile(filename)
1955 # If requested, set CPU affinity and resume instance execution
1957 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1959 start_memory = self._InstanceStartupMemory(instance)
1960 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1961 self.BalloonInstanceMemory(instance, start_memory)
1963 if start_kvm_paused:
1964 # To control CPU pinning, ballooning, and vnc/spice passwords
1965 # the VM was started in a frozen state. If freezing was not
1966 # explicitly requested resume the vm status.
1967 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1969 def StartInstance(self, instance, block_devices, startup_paused):
1970 """Start an instance.
1973 self._CheckDown(instance.name)
1974 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1975 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1976 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1977 startup_paused, kvmhelp)
1978 self._SaveKVMRuntime(instance, kvm_runtime)
1979 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1981 def _CallMonitorCommand(self, instance_name, command, timeout=None):
1982 """Invoke a command on the instance monitor.
1985 if timeout is not None:
1986 timeout_cmd = "timeout %s" % (timeout, )
1990 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1991 # version. The monitor protocol is designed for human consumption, whereas
1992 # QMP is made for programmatic usage. In the worst case QMP can also
1993 # execute monitor commands. As it is, all calls to socat take at least
1994 # 500ms and likely more: socat can't detect the end of the reply and waits
1995 # for 500ms of no data received before exiting (500 ms is the default for
1996 # the "-t" parameter).
1997 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1998 (utils.ShellQuote(command),
2000 constants.SOCAT_PATH,
2001 utils.ShellQuote(self._InstanceMonitor(instance_name))))
2003 result = utils.RunCmd(socat)
2005 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2007 (command, instance_name, result.fail_reason, result.output))
2008 raise errors.HypervisorError(msg)
2012 def _GetFreePCISlot(self, instance, dev):
2013 """Get the first available pci slot of a runnung instance.
2016 slots = bitarray(32)
2017 slots.setall(False) # pylint: disable=E1101
2018 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2019 for line in output.stdout.splitlines():
2020 match = self._INFO_PCI_RE.search(line)
2022 slot = int(match.group(1))
2025 [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2027 raise errors.HypervisorError("All PCI slots occupied")
2031 def VerifyHotplugSupport(self, instance, action, dev_type):
2032 """Verifies that hotplug is supported.
2034 Hotplug is *not* supported in case of:
2035 - security models and chroot (disk hotplug)
2036 - fdsend module is missing (nic hot-add)
2038 @raise errors.HypervisorError: in one of the previous cases
2041 if dev_type == constants.HOTPLUG_TARGET_DISK:
2042 hvp = instance.hvparams
2043 security_model = hvp[constants.HV_SECURITY_MODEL]
2044 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2046 raise errors.HotplugError("Disk hotplug is not supported"
2047 " in case of chroot.")
2048 if security_model != constants.HT_SM_NONE:
2049 raise errors.HotplugError("Disk Hotplug is not supported in case"
2050 " security models are used.")
2052 if (dev_type == constants.HOTPLUG_TARGET_NIC and
2053 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2054 raise errors.HotplugError("Cannot hot-add NIC."
2055 " fdsend python module is missing.")
2057 def HotplugSupported(self, instance):
2058 """Checks if hotplug is generally supported.
2060 Hotplug is *not* supported in case of:
2061 - qemu versions < 1.0
2062 - for stopped instances
2064 @raise errors.HypervisorError: in one of the previous cases
2068 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2069 except errors.HypervisorError:
2070 raise errors.HotplugError("Instance is probably down")
2072 # TODO: search for netdev_add, drive_add, device_add.....
2073 match = self._INFO_VERSION_RE.search(output.stdout)
2075 raise errors.HotplugError("Cannot parse qemu version via monitor")
2077 v_major, v_min, _, _ = match.groups()
2078 if (int(v_major), int(v_min)) < (1, 0):
2079 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2081 def _CallHotplugCommands(self, name, cmds):
2083 self._CallMonitorCommand(name, c)
2086 def _VerifyHotplugCommand(self, instance_name, device, dev_type,
2088 """Checks if a previous hotplug command has succeeded.
2090 It issues info pci monitor command and checks depending on should_exist
2091 value if an entry with PCI slot and device ID is found or not.
2093 @raise errors.HypervisorError: if result is not the expected one
2096 output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
2097 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2099 self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
2100 if match and not should_exist:
2101 msg = "Device %s should have been removed but is still there" % kvm_devid
2102 raise errors.HypervisorError(msg)
2104 if not match and should_exist:
2105 msg = "Device %s should have been added but is missing" % kvm_devid
2106 raise errors.HypervisorError(msg)
2108 logging.info("Device %s has been correctly hot-plugged", kvm_devid)
2110 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2111 """ Helper method to hot-add a new device
2113 It gets free pci slot generates the device name and invokes the
2114 device specific method.
2117 # in case of hot-mod this is given
2118 if device.pci is None:
2119 self._GetFreePCISlot(instance, device)
2120 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2121 runtime = self._LoadKVMRuntime(instance)
2122 if dev_type == constants.HOTPLUG_TARGET_DISK:
2123 cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
2125 cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2126 (hex(device.pci), kvm_devid, kvm_devid)]
2127 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2128 (tap, fd) = _OpenTap()
2129 self._ConfigureNIC(instance, seq, device, tap)
2130 self._PassTapFd(instance, fd, device)
2131 cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
2132 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2133 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2134 cmds += ["device_add %s" % args]
2135 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2137 self._CallHotplugCommands(instance.name, cmds)
2138 self._VerifyHotplugCommand(instance.name, device, dev_type, True)
2139 # update relevant entries in runtime file
2140 index = _DEVICE_RUNTIME_INDEX[dev_type]
2141 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2142 runtime[index].append(entry)
2143 self._SaveKVMRuntime(instance, runtime)
2145 def HotDelDevice(self, instance, dev_type, device, _, seq):
2146 """ Helper method for hot-del device
2148 It gets device info from runtime file, generates the device name and
2149 invokes the device specific method.
2152 runtime = self._LoadKVMRuntime(instance)
2153 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2154 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2155 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2156 if dev_type == constants.HOTPLUG_TARGET_DISK:
2157 cmds = ["device_del %s" % kvm_devid]
2158 cmds += ["drive_del %s" % kvm_devid]
2159 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2160 cmds = ["device_del %s" % kvm_devid]
2161 cmds += ["netdev_del %s" % kvm_devid]
2162 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2163 self._CallHotplugCommands(instance.name, cmds)
2164 self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
2165 index = _DEVICE_RUNTIME_INDEX[dev_type]
2166 runtime[index].remove(entry)
2167 self._SaveKVMRuntime(instance, runtime)
2169 return kvm_device.pci
2171 def HotModDevice(self, instance, dev_type, device, _, seq):
2172 """ Helper method for hot-mod device
2174 It gets device info from runtime file, generates the device name and
2175 invokes the device specific method. Currently only NICs support hot-mod
2178 if dev_type == constants.HOTPLUG_TARGET_NIC:
2179 # putting it back in the same pci slot
2180 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2181 # TODO: remove sleep when socat gets removed
2182 self.HotAddDevice(instance, dev_type, device, _, seq)
2184 def _PassTapFd(self, instance, fd, nic):
2185 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2188 # TODO: factor out code related to unix sockets.
2189 # squash common parts between monitor and qmp
2190 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2191 command = "getfd %s\n" % kvm_devid
2193 logging.info("%s", fds)
2195 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2197 fdsend.sendfds(monsock.sock, command, fds=fds)
2202 def _ParseKVMVersion(cls, text):
2203 """Parse the KVM version from the --help output.
2206 @param text: output of kvm --help
2207 @return: (version, v_maj, v_min, v_rev)
2208 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2211 match = cls._VERSION_RE.search(text.splitlines()[0])
2213 raise errors.HypervisorError("Unable to get KVM version")
2215 v_all = match.group(0)
2216 v_maj = int(match.group(1))
2217 v_min = int(match.group(2))
2219 v_rev = int(match.group(4))
2222 return (v_all, v_maj, v_min, v_rev)
2225 def _GetKVMOutput(cls, kvm_path, option):
2226 """Return the output of a kvm invocation
2228 @type kvm_path: string
2229 @param kvm_path: path to the kvm executable
2230 @type option: a key of _KVMOPTS_CMDS
2231 @param option: kvm option to fetch the output from
2232 @return: output a supported kvm invocation
2233 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2236 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2238 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2240 result = utils.RunCmd([kvm_path] + optlist)
2241 if result.failed and not can_fail:
2242 raise errors.HypervisorError("Unable to get KVM %s output" %
2244 return result.output
2247 def _GetKVMVersion(cls, kvm_path):
2248 """Return the installed KVM version.
2250 @return: (version, v_maj, v_min, v_rev)
2251 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2254 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2257 def _GetDefaultMachineVersion(cls, kvm_path):
2258 """Return the default hardware revision (e.g. pc-1.1)
2261 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2262 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2264 return match.group(1)
2268 def StopInstance(self, instance, force=False, retry=False, name=None,
2270 """Stop an instance.
2273 assert(timeout is None or force is not None)
2275 if name is not None and not force:
2276 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2278 name = instance.name
2279 acpi = instance.hvparams[constants.HV_ACPI]
2282 _, pid, alive = self._InstancePidAlive(name)
2283 if pid > 0 and alive:
2284 if force or not acpi:
2285 utils.KillProcess(pid)
2287 self._CallMonitorCommand(name, "system_powerdown", timeout)
2289 def CleanupInstance(self, instance_name):
2290 """Cleanup after a stopped instance
2293 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2294 if pid > 0 and alive:
2295 raise errors.HypervisorError("Cannot cleanup a live instance")
2296 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2298 def RebootInstance(self, instance):
2299 """Reboot an instance.
2302 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2303 # socket the instance will stop, but now power up again. So we'll resort
2304 # to shutdown and restart.
2305 _, _, alive = self._InstancePidAlive(instance.name)
2307 raise errors.HypervisorError("Failed to reboot instance %s:"
2308 " not running" % instance.name)
2309 # StopInstance will delete the saved KVM runtime so:
2310 # ...first load it...
2311 kvm_runtime = self._LoadKVMRuntime(instance)
2312 # ...now we can safely call StopInstance...
2313 if not self.StopInstance(instance):
2314 self.StopInstance(instance, force=True)
2315 # ...and finally we can save it again, and execute it...
2316 self._SaveKVMRuntime(instance, kvm_runtime)
2317 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2318 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2319 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2321 def MigrationInfo(self, instance):
2322 """Get instance information to perform a migration.
2324 @type instance: L{objects.Instance}
2325 @param instance: instance to be migrated
2327 @return: content of the KVM runtime file
2330 return self._ReadKVMRuntime(instance.name)
2332 def AcceptInstance(self, instance, info, target):
2333 """Prepare to accept an instance.
2335 @type instance: L{objects.Instance}
2336 @param instance: instance to be accepted
2338 @param info: content of the KVM runtime file on the source node
2339 @type target: string
2340 @param target: target host (usually ip), on this node
2343 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2344 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2345 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2346 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2347 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2348 incoming=incoming_address)
2350 def FinalizeMigrationDst(self, instance, info, success):
2351 """Finalize the instance migration on the target node.
2353 Stop the incoming mode KVM.
2355 @type instance: L{objects.Instance}
2356 @param instance: instance whose migration is being finalized
2360 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2361 kvm_nics = kvm_runtime[1]
2363 for nic_seq, nic in enumerate(kvm_nics):
2364 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2365 # Bridged interfaces have already been configured
2368 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2369 except EnvironmentError, err:
2370 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2371 instance.name, nic_seq, str(err))
2374 self._ConfigureNIC(instance, nic_seq, nic, tap)
2375 except errors.HypervisorError, err:
2376 logging.warning(str(err))
2378 self._WriteKVMRuntime(instance.name, info)
2380 self.StopInstance(instance, force=True)
2382 def MigrateInstance(self, instance, target, live):
2383 """Migrate an instance to a target node.
2385 The migration will not be attempted if the instance is not
2388 @type instance: L{objects.Instance}
2389 @param instance: the instance to be migrated
2390 @type target: string
2391 @param target: ip address of the target node
2393 @param live: perform a live migration
2396 instance_name = instance.name
2397 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2398 _, _, alive = self._InstancePidAlive(instance_name)
2400 raise errors.HypervisorError("Instance not running, cannot migrate")
2403 self._CallMonitorCommand(instance_name, "stop")
2405 migrate_command = ("migrate_set_speed %dm" %
2406 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2407 self._CallMonitorCommand(instance_name, migrate_command)
2409 migrate_command = ("migrate_set_downtime %dms" %
2410 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2411 self._CallMonitorCommand(instance_name, migrate_command)
2413 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2414 self._CallMonitorCommand(instance_name, migrate_command)
2416 def FinalizeMigrationSource(self, instance, success, live):
2417 """Finalize the instance migration on the source node.
2419 @type instance: L{objects.Instance}
2420 @param instance: the instance that was migrated
2422 @param success: whether the migration succeeded or not
2424 @param live: whether the user requested a live migration or not
2428 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2429 utils.KillProcess(pid)
2430 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2432 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2434 def GetMigrationStatus(self, instance):
2435 """Get the migration status
2437 @type instance: L{objects.Instance}
2438 @param instance: the instance that is being migrated
2439 @rtype: L{objects.MigrationStatus}
2440 @return: the status of the current migration (one of
2441 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2442 progress info that can be retrieved from the hypervisor
2445 info_command = "info migrate"
2446 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2447 result = self._CallMonitorCommand(instance.name, info_command)
2448 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2450 if not result.stdout:
2451 logging.info("KVM: empty 'info migrate' result")
2453 logging.warning("KVM: unknown 'info migrate' result: %s",
2456 status = match.group(1)
2457 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2458 migration_status = objects.MigrationStatus(status=status)
2459 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2461 migration_status.transferred_ram = match.group("transferred")
2462 migration_status.total_ram = match.group("total")
2464 return migration_status
2466 logging.warning("KVM: unknown migration status '%s'", status)
2468 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2470 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2472 def BalloonInstanceMemory(self, instance, mem):
2473 """Balloon an instance memory to a certain value.
2475 @type instance: L{objects.Instance}
2476 @param instance: instance to be accepted
2478 @param mem: actual memory size to use for instance runtime
2481 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2483 def GetNodeInfo(self):
2484 """Return information about the node.
2486 @return: a dict with the following keys (values in MiB):
2487 - memory_total: the total memory size on the node
2488 - memory_free: the available memory on the node for instances
2489 - memory_dom0: the memory used by the node itself, if available
2490 - hv_version: the hypervisor version in the form (major, minor,
2494 result = self.GetLinuxNodeInfo()
2495 # FIXME: this is the global kvm version, but the actual version can be
2496 # customized as an hv parameter. we should use the nodegroup's default kvm
2497 # path parameter here.
2498 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2499 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2503 def GetInstanceConsole(cls, instance, hvparams, beparams):
2504 """Return a command for connecting to the console of an instance.
2507 if hvparams[constants.HV_SERIAL_CONSOLE]:
2508 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2509 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2510 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2511 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2512 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2513 return objects.InstanceConsole(instance=instance.name,
2514 kind=constants.CONS_SSH,
2515 host=instance.primary_node,
2516 user=constants.SSH_CONSOLE_USER,
2519 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2520 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2521 display = instance.network_port - constants.VNC_BASE_PORT
2522 return objects.InstanceConsole(instance=instance.name,
2523 kind=constants.CONS_VNC,
2524 host=vnc_bind_address,
2525 port=instance.network_port,
2528 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2530 return objects.InstanceConsole(instance=instance.name,
2531 kind=constants.CONS_SPICE,
2533 port=instance.network_port)
2535 return objects.InstanceConsole(instance=instance.name,
2536 kind=constants.CONS_MESSAGE,
2537 message=("No serial shell for instance %s" %
2541 """Verify the hypervisor.
2543 Check that the required binaries exist.
2545 @return: Problem description if something is wrong, C{None} otherwise
2549 # FIXME: this is the global kvm binary, but the actual path can be
2550 # customized as an hv parameter; we should use the nodegroup's
2551 # default kvm path parameter here.
2552 if not os.path.exists(constants.KVM_PATH):
2553 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2554 if not os.path.exists(constants.SOCAT_PATH):
2555 msgs.append("The socat binary ('%s') does not exist" %
2556 constants.SOCAT_PATH)
2558 return self._FormatVerifyResults(msgs)
2561 def CheckParameterSyntax(cls, hvparams):
2562 """Check the given parameters for validity.
2564 @type hvparams: dict
2565 @param hvparams: dictionary with parameter names/value
2566 @raise errors.HypervisorError: when a parameter is not valid
2569 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2571 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2573 if not hvparams[constants.HV_ROOT_PATH]:
2574 raise errors.HypervisorError("Need a root partition for the instance,"
2575 " if a kernel is defined")
2577 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2578 not hvparams[constants.HV_VNC_X509]):
2579 raise errors.HypervisorError("%s must be defined, if %s is" %
2580 (constants.HV_VNC_X509,
2581 constants.HV_VNC_X509_VERIFY))
2583 if hvparams[constants.HV_SERIAL_CONSOLE]:
2584 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2585 valid_speeds = constants.VALID_SERIAL_SPEEDS
2586 if not serial_speed or serial_speed not in valid_speeds:
2587 raise errors.HypervisorError("Invalid serial console speed, must be"
2589 utils.CommaJoin(valid_speeds))
2591 boot_order = hvparams[constants.HV_BOOT_ORDER]
2592 if (boot_order == constants.HT_BO_CDROM and
2593 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2594 raise errors.HypervisorError("Cannot boot from cdrom without an"
2597 security_model = hvparams[constants.HV_SECURITY_MODEL]
2598 if security_model == constants.HT_SM_USER:
2599 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2600 raise errors.HypervisorError("A security domain (user to run kvm as)"
2601 " must be specified")
2602 elif (security_model == constants.HT_SM_NONE or
2603 security_model == constants.HT_SM_POOL):
2604 if hvparams[constants.HV_SECURITY_DOMAIN]:
2605 raise errors.HypervisorError("Cannot have a security domain when the"
2606 " security model is 'none' or 'pool'")
2608 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2609 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2611 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2612 # if an IP version is specified, the spice_bind parameter must be an
2614 if (netutils.IP4Address.IsValid(spice_bind) and
2615 spice_ip_version != constants.IP4_VERSION):
2616 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2617 " the specified IP version is %s" %
2618 (spice_bind, spice_ip_version))
2620 if (netutils.IP6Address.IsValid(spice_bind) and
2621 spice_ip_version != constants.IP6_VERSION):
2622 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2623 " the specified IP version is %s" %
2624 (spice_bind, spice_ip_version))
2626 # All the other SPICE parameters depend on spice_bind being set. Raise an
2627 # error if any of them is set without it.
2628 for param in _SPICE_ADDITIONAL_PARAMS:
2630 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2631 (param, constants.HV_KVM_SPICE_BIND))
2634 def ValidateParameters(cls, hvparams):
2635 """Check the given parameters for validity.
2637 @type hvparams: dict
2638 @param hvparams: dictionary with parameter names/value
2639 @raise errors.HypervisorError: when a parameter is not valid
2642 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2644 kvm_path = hvparams[constants.HV_KVM_PATH]
2646 security_model = hvparams[constants.HV_SECURITY_MODEL]
2647 if security_model == constants.HT_SM_USER:
2648 username = hvparams[constants.HV_SECURITY_DOMAIN]
2650 pwd.getpwnam(username)
2652 raise errors.HypervisorError("Unknown security domain user %s"
2655 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2657 # only one of VNC and SPICE can be used currently.
2658 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2659 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2660 " only one of them can be used at a"
2663 # check that KVM supports SPICE
2664 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2665 if not cls._SPICE_RE.search(kvmhelp):
2666 raise errors.HypervisorError("SPICE is configured, but it is not"
2667 " supported according to 'kvm --help'")
2669 # if spice_bind is not an IP address, it must be a valid interface
2670 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2671 netutils.IP6Address.IsValid(spice_bind))
2672 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2673 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2674 " a valid IP address or interface name" %
2675 constants.HV_KVM_SPICE_BIND)
2677 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2679 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2680 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2681 raise errors.HypervisorError("Unsupported machine version: %s" %
2685 def PowercycleNode(cls):
2686 """KVM powercycle, just a wrapper over Linux powercycle.
2689 cls.LinuxPowercycle()