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-ifup-custom"
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 # This is needed because QMP can return more than one greetings
489 # see https://groups.google.com/d/msg/ganeti-devel/gZYcvHKDooU/SnukC8dgS5AJ
492 # Let's put the monitor in command mode using the qmp_capabilities
493 # command, or else no command will be executable.
494 # (As per the QEMU Protocol Specification 0.1 - section 4)
495 self.Execute(self._CAPABILITIES_COMMAND)
497 def _ParseMessage(self, buf):
498 """Extract and parse a QMP message from the given buffer.
500 Seeks for a QMP message in the given buf. If found, it parses it and
501 returns it together with the rest of the characters in the buf.
502 If no message is found, returns None and the whole buffer.
504 @raise errors.ProgrammerError: when there are data serialization errors
508 # Check if we got the message end token (CRLF, as per the QEMU Protocol
509 # Specification 0.1 - Section 2.1.1)
510 pos = buf.find(self._MESSAGE_END_TOKEN)
513 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
514 except Exception, err:
515 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
518 return (message, buf)
521 """Receives a message from QMP and decodes the received JSON object.
524 @return: the received message
525 @raise errors.HypervisorError: when there are communication errors
526 @raise errors.ProgrammerError: when there are data serialization errors
529 self._check_connection()
531 # Check if there is already a message in the buffer
532 (message, self._buf) = self._ParseMessage(self._buf)
536 recv_buffer = StringIO.StringIO(self._buf)
537 recv_buffer.seek(len(self._buf))
540 data = self.sock.recv(4096)
543 recv_buffer.write(data)
545 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
549 except socket.timeout, err:
550 raise errors.HypervisorError("Timeout while receiving a QMP message: "
552 except socket.error, err:
553 raise errors.HypervisorError("Unable to receive data from KVM using the"
554 " QMP protocol: %s" % err)
556 def _Send(self, message):
557 """Encodes and sends a message to KVM using QMP.
559 @type message: QmpMessage
560 @param message: message to send to KVM
561 @raise errors.HypervisorError: when there are communication errors
562 @raise errors.ProgrammerError: when there are data serialization errors
565 self._check_connection()
567 message_str = str(message)
568 except Exception, err:
569 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
572 self.sock.sendall(message_str)
573 except socket.timeout, err:
574 raise errors.HypervisorError("Timeout while sending a QMP message: "
575 "%s (%s)" % (err.string, err.errno))
576 except socket.error, err:
577 raise errors.HypervisorError("Unable to send data from KVM using the"
578 " QMP protocol: %s" % err)
580 def Execute(self, command, arguments=None):
581 """Executes a QMP command and returns the response of the server.
584 @param command: the command to execute
585 @type arguments: dict
586 @param arguments: dictionary of arguments to be passed to the command
588 @return: dictionary representing the received JSON object
589 @raise errors.HypervisorError: when there are communication errors
590 @raise errors.ProgrammerError: when there are data serialization errors
593 self._check_connection()
594 message = QmpMessage({self._EXECUTE_KEY: command})
596 message[self._ARGUMENTS_KEY] = arguments
599 # Events can occur between the sending of the command and the reception
600 # of the response, so we need to filter out messages with the event key.
602 response = self._Recv()
603 err = response[self._ERROR_KEY]
605 raise errors.HypervisorError("kvm: error executing the %s"
606 " command: %s (%s):" %
608 err[self._ERROR_DESC_KEY],
609 err[self._ERROR_CLASS_KEY]))
611 elif not response[self._EVENT_KEY]:
615 class KVMHypervisor(hv_base.BaseHypervisor):
616 """KVM hypervisor interface
621 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
622 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
623 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
624 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
625 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
626 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
627 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
628 # KVM instances with chroot enabled are started in empty chroot directories.
629 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
630 # After an instance is stopped, its chroot directory is removed.
631 # If the chroot directory is not empty, it can't be removed.
632 # A non-empty chroot directory indicates a possible security incident.
633 # To support forensics, the non-empty chroot directory is quarantined in
634 # a separate directory, called 'chroot-quarantine'.
635 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
636 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
637 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
640 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
641 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
642 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
643 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
644 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
645 constants.HV_ACPI: hv_base.NO_CHECK,
646 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
647 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
648 constants.HV_VNC_BIND_ADDRESS:
649 (False, lambda x: (netutils.IP4Address.IsValid(x) or
650 utils.IsNormAbsPath(x)),
651 "The VNC bind address must be either a valid IP address or an absolute"
652 " pathname", None, None),
653 constants.HV_VNC_TLS: hv_base.NO_CHECK,
654 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
655 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
656 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
657 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
658 constants.HV_KVM_SPICE_IP_VERSION:
659 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
660 x in constants.VALID_IP_VERSIONS),
661 "The SPICE IP version should be 4 or 6",
663 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
664 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
666 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
667 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
669 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
670 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
672 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
673 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
675 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
676 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
677 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
678 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
679 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
680 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
681 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
682 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
683 constants.HV_BOOT_ORDER:
684 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
685 constants.HV_NIC_TYPE:
686 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
687 constants.HV_DISK_TYPE:
688 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
689 constants.HV_KVM_CDROM_DISK_TYPE:
690 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
691 constants.HV_USB_MOUSE:
692 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
693 constants.HV_KEYMAP: hv_base.NO_CHECK,
694 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
695 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
696 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
697 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
698 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
699 constants.HV_DISK_CACHE:
700 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
701 constants.HV_SECURITY_MODEL:
702 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
703 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
704 constants.HV_KVM_FLAG:
705 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
706 constants.HV_VHOST_NET: hv_base.NO_CHECK,
707 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
708 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
709 constants.HV_REBOOT_BEHAVIOR:
710 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
711 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
712 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
713 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
714 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
715 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
716 constants.HV_SOUNDHW: hv_base.NO_CHECK,
717 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
718 constants.HV_VGA: hv_base.NO_CHECK,
719 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
720 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
721 constants.HV_VNET_HDR: hv_base.NO_CHECK,
725 _VIRTIO_NET_PCI = "virtio-net-pci"
726 _VIRTIO_BLK_PCI = "virtio-blk-pci"
728 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
730 _MIGRATION_PROGRESS_RE = \
731 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
732 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
733 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
735 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
736 _MIGRATION_INFO_RETRY_DELAY = 2
738 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
740 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
741 _CPU_INFO_CMD = "info cpus"
744 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
745 _CHECK_MACHINE_VERSION_RE = \
746 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
748 _QMP_RE = re.compile(r"^-qmp\s", re.M)
749 _SPICE_RE = re.compile(r"^-spice\s", re.M)
750 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
751 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
752 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
753 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
754 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
755 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
756 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
757 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
758 # match -drive.*boot=on|off on different lines, but in between accept only
759 # dashes not preceeded by a new line (which would mean another option
760 # different than -drive is starting)
761 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
763 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
764 _INFO_PCI_CMD = "info pci"
765 _FIND_PCI_DEVICE_RE = \
766 staticmethod(lambda pci, devid:
767 re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' % (pci, devid),
771 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
772 _INFO_VERSION_CMD = "info version"
774 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
779 ANCILLARY_FILES_OPT = [
783 # Supported kvm options to get output from
784 _KVMOPT_HELP = "help"
785 _KVMOPT_MLIST = "mlist"
786 _KVMOPT_DEVICELIST = "devicelist"
788 # Command to execute to get the output from kvm, and whether to
789 # accept the output even on failure.
791 _KVMOPT_HELP: (["--help"], False),
792 _KVMOPT_MLIST: (["-M", "?"], False),
793 _KVMOPT_DEVICELIST: (["-device", "?"], True),
797 hv_base.BaseHypervisor.__init__(self)
798 # Let's make sure the directories we need exist, even if the RUN_DIR lives
799 # in a tmpfs filesystem or has been otherwise wiped out.
800 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
801 utils.EnsureDirs(dirs)
804 def _InstancePidFile(cls, instance_name):
805 """Returns the instance pidfile.
808 return utils.PathJoin(cls._PIDS_DIR, instance_name)
811 def _InstanceUidFile(cls, instance_name):
812 """Returns the instance uidfile.
815 return utils.PathJoin(cls._UIDS_DIR, instance_name)
818 def _InstancePidInfo(cls, pid):
819 """Check pid file for instance information.
821 Check that a pid file is associated with an instance, and retrieve
822 information from its command line.
824 @type pid: string or int
825 @param pid: process id of the instance to check
827 @return: (instance_name, memory, vcpus)
828 @raise errors.HypervisorError: when an instance cannot be found
831 alive = utils.IsProcessAlive(pid)
833 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
835 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
837 cmdline = utils.ReadFile(cmdline_file)
838 except EnvironmentError, err:
839 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
846 arg_list = cmdline.split("\x00")
848 arg = arg_list.pop(0)
850 instance = arg_list.pop(0)
852 memory = int(arg_list.pop(0))
854 vcpus = int(arg_list.pop(0).split(",")[0])
857 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
860 return (instance, memory, vcpus)
862 def _InstancePidAlive(self, instance_name):
863 """Returns the instance pidfile, pid, and liveness.
865 @type instance_name: string
866 @param instance_name: instance name
868 @return: (pid file name, pid, liveness)
871 pidfile = self._InstancePidFile(instance_name)
872 pid = utils.ReadPidFile(pidfile)
876 cmd_instance = self._InstancePidInfo(pid)[0]
877 alive = (cmd_instance == instance_name)
878 except errors.HypervisorError:
881 return (pidfile, pid, alive)
883 def _CheckDown(self, instance_name):
884 """Raises an error unless the given instance is down.
887 alive = self._InstancePidAlive(instance_name)[2]
889 raise errors.HypervisorError("Failed to start instance %s: %s" %
890 (instance_name, "already running"))
893 def _InstanceMonitor(cls, instance_name):
894 """Returns the instance monitor socket name
897 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
900 def _InstanceSerial(cls, instance_name):
901 """Returns the instance serial socket name
904 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
907 def _InstanceQmpMonitor(cls, instance_name):
908 """Returns the instance serial QMP socket name
911 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
914 def _SocatUnixConsoleParams():
915 """Returns the correct parameters for socat
917 If we have a new-enough socat we can use raw mode with an escape character.
920 if constants.SOCAT_USE_ESCAPE:
921 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
923 return "echo=0,icanon=0"
926 def _InstanceKVMRuntime(cls, instance_name):
927 """Returns the instance KVM runtime filename
930 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
933 def _InstanceChrootDir(cls, instance_name):
934 """Returns the name of the KVM chroot dir of the instance
937 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
940 def _InstanceNICDir(cls, instance_name):
941 """Returns the name of the directory holding the tap device files for a
945 return utils.PathJoin(cls._NICS_DIR, instance_name)
948 def _InstanceNICFile(cls, instance_name, seq):
949 """Returns the name of the file containing the tap device for a given NIC
952 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
955 def _InstanceKeymapFile(cls, instance_name):
956 """Returns the name of the file containing the keymap for a given instance
959 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
962 def _TryReadUidFile(cls, uid_file):
963 """Try to read a uid file
966 if os.path.exists(uid_file):
968 uid = int(utils.ReadOneLineFile(uid_file))
970 except EnvironmentError:
971 logging.warning("Can't read uid file", exc_info=True)
972 except (TypeError, ValueError):
973 logging.warning("Can't parse uid file contents", exc_info=True)
977 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
978 """Removes an instance's rutime sockets/files/dirs.
981 utils.RemoveFile(pidfile)
982 utils.RemoveFile(cls._InstanceMonitor(instance_name))
983 utils.RemoveFile(cls._InstanceSerial(instance_name))
984 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
985 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
986 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
987 uid_file = cls._InstanceUidFile(instance_name)
988 uid = cls._TryReadUidFile(uid_file)
989 utils.RemoveFile(uid_file)
991 uidpool.ReleaseUid(uid)
993 shutil.rmtree(cls._InstanceNICDir(instance_name))
995 if err.errno != errno.ENOENT:
998 chroot_dir = cls._InstanceChrootDir(instance_name)
999 utils.RemoveDir(chroot_dir)
1000 except OSError, err:
1001 if err.errno == errno.ENOTEMPTY:
1002 # The chroot directory is expected to be empty, but it isn't.
1003 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
1006 utils.TimestampForFilename()))
1007 logging.warning("The chroot directory of instance %s can not be"
1008 " removed as it is not empty. Moving it to the"
1009 " quarantine instead. Please investigate the"
1010 " contents (%s) and clean up manually",
1011 instance_name, new_chroot_dir)
1012 utils.RenameFile(chroot_dir, new_chroot_dir)
1017 def _ConfigureNIC(instance, seq, nic, tap):
1018 """Run the network configuration script for a specified NIC
1020 @param instance: instance we're acting on
1021 @type instance: instance object
1022 @param seq: nic sequence number
1024 @param nic: nic we're acting on
1025 @type nic: nic object
1026 @param tap: the host's tap interface this NIC corresponds to
1031 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1032 "INSTANCE": instance.name,
1034 "MODE": nic.nicparams[constants.NIC_MODE],
1036 "INTERFACE_INDEX": str(seq),
1037 "INTERFACE_UUID": nic.uuid,
1038 "TAGS": " ".join(instance.GetTags()),
1045 env["INTERFACE_NAME"] = nic.name
1047 if nic.nicparams[constants.NIC_LINK]:
1048 env["LINK"] = nic.nicparams[constants.NIC_LINK]
1051 n = objects.Network.FromDict(nic.netinfo)
1052 env.update(n.HooksDict())
1054 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1055 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1057 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1059 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1060 " network configuration script output: %s" %
1061 (tap, result.fail_reason, result.output))
1064 def _VerifyAffinityPackage():
1065 if affinity is None:
1066 raise errors.HypervisorError("affinity Python package not"
1067 " found; cannot use CPU pinning under KVM")
1070 def _BuildAffinityCpuMask(cpu_list):
1071 """Create a CPU mask suitable for sched_setaffinity from a list of
1074 See man taskset for more info on sched_setaffinity masks.
1075 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1077 @type cpu_list: list of int
1078 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1080 @return: a bit mask of CPU affinities
1083 if cpu_list == constants.CPU_PINNING_OFF:
1084 return constants.CPU_PINNING_ALL_KVM
1086 return sum(2 ** cpu for cpu in cpu_list)
1089 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1090 """Change CPU affinity for running VM according to given CPU mask.
1092 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1093 @type cpu_mask: string
1094 @param process_id: process ID of KVM process. Used to pin entire VM
1096 @type process_id: int
1097 @param thread_dict: map of virtual CPUs to KVM thread IDs
1098 @type thread_dict: dict int:int
1101 # Convert the string CPU mask to a list of list of int's
1102 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1104 if len(cpu_list) == 1:
1105 all_cpu_mapping = cpu_list[0]
1106 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1107 # If CPU pinning has 1 entry that's "all", then do nothing
1110 # If CPU pinning has one non-all entry, map the entire VM to
1111 # one set of physical CPUs
1112 cls._VerifyAffinityPackage()
1113 affinity.set_process_affinity_mask(
1114 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1116 # The number of vCPUs mapped should match the number of vCPUs
1117 # reported by KVM. This was already verified earlier, so
1118 # here only as a sanity check.
1119 assert len(thread_dict) == len(cpu_list)
1120 cls._VerifyAffinityPackage()
1122 # For each vCPU, map it to the proper list of physical CPUs
1123 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1124 affinity.set_process_affinity_mask(thread_dict[i],
1125 cls._BuildAffinityCpuMask(vcpu))
1127 def _GetVcpuThreadIds(self, instance_name):
1128 """Get a mapping of vCPU no. to thread IDs for the instance
1130 @type instance_name: string
1131 @param instance_name: instance in question
1132 @rtype: dictionary of int:int
1133 @return: a dictionary mapping vCPU numbers to thread IDs
1137 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1138 for line in output.stdout.splitlines():
1139 match = self._CPU_INFO_RE.search(line)
1142 grp = map(int, match.groups())
1143 result[grp[0]] = grp[1]
1147 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1148 """Complete CPU pinning.
1150 @type instance_name: string
1151 @param instance_name: name of instance
1152 @type cpu_mask: string
1153 @param cpu_mask: CPU pinning mask as entered by user
1156 # Get KVM process ID, to be used if need to pin entire VM
1157 _, pid, _ = self._InstancePidAlive(instance_name)
1158 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1159 thread_dict = self._GetVcpuThreadIds(instance_name)
1160 # Run CPU pinning, based on configured mask
1161 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1163 def ListInstances(self):
1164 """Get the list of running instances.
1166 We can do this by listing our live instances directory and
1167 checking whether the associated kvm process is still alive.
1171 for name in os.listdir(self._PIDS_DIR):
1172 if self._InstancePidAlive(name)[2]:
1176 def GetInstanceInfo(self, instance_name):
1177 """Get instance properties.
1179 @type instance_name: string
1180 @param instance_name: the instance name
1181 @rtype: tuple of strings
1182 @return: (name, id, memory, vcpus, stat, times)
1185 _, pid, alive = self._InstancePidAlive(instance_name)
1189 _, memory, vcpus = self._InstancePidInfo(pid)
1194 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1196 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1197 # Will fail if ballooning is not enabled, but we can then just resort to
1199 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1200 memory = mem_bytes / 1048576
1201 except errors.HypervisorError:
1204 return (instance_name, pid, memory, vcpus, istat, times)
1206 def GetAllInstancesInfo(self):
1207 """Get properties of all instances.
1209 @return: list of tuples (name, id, memory, vcpus, stat, times)
1213 for name in os.listdir(self._PIDS_DIR):
1215 info = self.GetInstanceInfo(name)
1216 except errors.HypervisorError:
1217 # Ignore exceptions due to instances being shut down
1223 def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1225 """Generate KVM options regarding instance's block devices.
1227 @type instance: L{objects.Instance}
1228 @param instance: the instance object
1229 @type kvm_disks: list of tuples
1230 @param kvm_disks: list of tuples [(disk, link_name)..]
1231 @type kvmhelp: string
1232 @param kvmhelp: output of kvm --help
1233 @type devlist: string
1234 @param devlist: output of kvm -device ?
1236 @return: list of command line options eventually used by kvm executable
1239 hvp = instance.hvparams
1240 kernel_path = hvp[constants.HV_KERNEL_PATH]
1244 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1246 # whether this is an older KVM version that uses the boot=on flag
1248 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1251 device_driver = None
1252 disk_type = hvp[constants.HV_DISK_TYPE]
1253 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1254 if_val = ",if=%s" % self._VIRTIO
1256 if self._VIRTIO_BLK_RE.search(devlist):
1258 # will be passed in -device option as driver
1259 device_driver = self._VIRTIO_BLK_PCI
1260 except errors.HypervisorError, _:
1263 if_val = ",if=%s" % disk_type
1265 disk_cache = hvp[constants.HV_DISK_CACHE]
1266 if instance.disk_template in constants.DTS_EXT_MIRROR:
1267 if disk_cache != "none":
1268 # TODO: make this a hard error, instead of a silent overwrite
1269 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1270 " to prevent shared storage corruption on migration",
1272 cache_val = ",cache=none"
1273 elif disk_cache != constants.HT_CACHE_DEFAULT:
1274 cache_val = ",cache=%s" % disk_cache
1277 for idx, (cfdev, link_name) in enumerate(kvm_disks):
1278 if cfdev.mode != constants.DISK_RDWR:
1279 raise errors.HypervisorError("Instance has read-only disks which"
1280 " are not supported by KVM")
1281 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1284 dev_opts.extend(["-boot", "c"])
1286 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1287 boot_val = ",boot=on"
1289 # For ext we allow overriding disk_cache hypervisor params per disk
1290 disk_cache = cfdev.params.get("cache", None)
1292 cache_val = ",cache=%s" % disk_cache
1293 drive_val = "file=%s,format=raw%s%s%s" % \
1294 (link_name, if_val, boot_val, cache_val)
1297 # kvm_disks are the 4th entry of runtime file that did not exist in
1298 # the past. That means that cfdev should always have pci slot and
1299 # _GenerateDeviceKVMId() will not raise a exception.
1300 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK,
1302 drive_val += (",id=%s" % kvm_devid)
1304 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1305 dev_val = ("%s,drive=%s,id=%s" %
1306 (device_driver, kvm_devid, kvm_devid))
1308 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1309 dev_opts.extend(["-device", dev_val])
1311 # TODO: export disk geometry in IDISK_PARAMS
1312 heads = cfdev.params.get('heads', None)
1313 secs = cfdev.params.get('secs', None)
1315 nr_sectors = cfdev.size * 1024 * 1024 / 512
1316 cyls = nr_sectors / (int(heads) * int(secs))
1321 if cyls and heads and secs:
1322 drive_val += (",cyls=%d,heads=%d,secs=%d" %
1323 (cyls, int(heads), int(secs)))
1325 dev_opts.extend(["-drive", drive_val])
1329 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1331 """Generate KVM information to start an instance.
1333 @type kvmhelp: string
1334 @param kvmhelp: output of kvm --help
1335 @attention: this function must not have any side-effects; for
1336 example, it must not write to the filesystem, or read values
1337 from the current system the are expected to differ between
1338 nodes, since it is only run once at instance startup;
1339 actions/kvm arguments that can vary between systems should be
1340 done in L{_ExecuteKVMRuntime}
1343 # pylint: disable=R0912,R0914,R0915
1344 hvp = instance.hvparams
1345 self.ValidateParameters(hvp)
1347 pidfile = self._InstancePidFile(instance.name)
1348 kvm = hvp[constants.HV_KVM_PATH]
1350 # used just by the vnc server, if enabled
1351 kvm_cmd.extend(["-name", instance.name])
1352 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1354 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1355 if hvp[constants.HV_CPU_CORES]:
1356 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1357 if hvp[constants.HV_CPU_THREADS]:
1358 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1359 if hvp[constants.HV_CPU_SOCKETS]:
1360 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1362 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1364 kvm_cmd.extend(["-pidfile", pidfile])
1365 kvm_cmd.extend(["-balloon", "virtio"])
1366 kvm_cmd.extend(["-daemonize"])
1367 if not instance.hvparams[constants.HV_ACPI]:
1368 kvm_cmd.extend(["-no-acpi"])
1369 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1370 constants.INSTANCE_REBOOT_EXIT:
1371 kvm_cmd.extend(["-no-reboot"])
1373 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1375 mversion = self._GetDefaultMachineVersion(kvm)
1376 if self._MACHINE_RE.search(kvmhelp):
1377 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1378 # extra hypervisor parameters. We should also investigate whether and how
1379 # shadow_mem should be considered for the resource model.
1380 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1381 specprop = ",accel=kvm"
1384 machinespec = "%s%s" % (mversion, specprop)
1385 kvm_cmd.extend(["-machine", machinespec])
1387 kvm_cmd.extend(["-M", mversion])
1388 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1389 self._ENABLE_KVM_RE.search(kvmhelp)):
1390 kvm_cmd.extend(["-enable-kvm"])
1391 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1392 self._DISABLE_KVM_RE.search(kvmhelp)):
1393 kvm_cmd.extend(["-disable-kvm"])
1395 kernel_path = hvp[constants.HV_KERNEL_PATH]
1397 boot_cdrom = boot_floppy = boot_network = False
1399 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1400 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1401 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1404 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1407 kvm_cmd.extend(["-boot", "n"])
1409 # whether this is an older KVM version that uses the boot=on flag
1411 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1413 disk_type = hvp[constants.HV_DISK_TYPE]
1415 #Now we can specify a different device type for CDROM devices.
1416 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1417 if not cdrom_disk_type:
1418 cdrom_disk_type = disk_type
1420 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1422 options = ",format=raw,media=cdrom"
1423 # set cdrom 'if' type
1425 actual_cdrom_type = constants.HT_DISK_IDE
1426 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1427 actual_cdrom_type = "virtio"
1429 actual_cdrom_type = cdrom_disk_type
1430 if_val = ",if=%s" % actual_cdrom_type
1431 # set boot flag, if needed
1434 kvm_cmd.extend(["-boot", "d"])
1436 boot_val = ",boot=on"
1437 # and finally build the entire '-drive' value
1438 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1439 kvm_cmd.extend(["-drive", drive_val])
1441 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1443 options = ",format=raw,media=cdrom"
1444 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1445 if_val = ",if=virtio"
1447 if_val = ",if=%s" % cdrom_disk_type
1448 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1449 kvm_cmd.extend(["-drive", drive_val])
1451 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1453 options = ",format=raw,media=disk"
1455 kvm_cmd.extend(["-boot", "a"])
1456 options = "%s,boot=on" % options
1457 if_val = ",if=floppy"
1458 options = "%s%s" % (options, if_val)
1459 drive_val = "file=%s%s" % (floppy_image, options)
1460 kvm_cmd.extend(["-drive", drive_val])
1463 kvm_cmd.extend(["-kernel", kernel_path])
1464 initrd_path = hvp[constants.HV_INITRD_PATH]
1466 kvm_cmd.extend(["-initrd", initrd_path])
1467 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1468 hvp[constants.HV_KERNEL_ARGS]]
1469 if hvp[constants.HV_SERIAL_CONSOLE]:
1470 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1471 root_append.append("console=ttyS0,%s" % serial_speed)
1472 kvm_cmd.extend(["-append", " ".join(root_append)])
1474 mem_path = hvp[constants.HV_MEM_PATH]
1476 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1478 monitor_dev = ("unix:%s,server,nowait" %
1479 self._InstanceMonitor(instance.name))
1480 kvm_cmd.extend(["-monitor", monitor_dev])
1481 if hvp[constants.HV_SERIAL_CONSOLE]:
1482 serial_dev = ("unix:%s,server,nowait" %
1483 self._InstanceSerial(instance.name))
1484 kvm_cmd.extend(["-serial", serial_dev])
1486 kvm_cmd.extend(["-serial", "none"])
1488 mouse_type = hvp[constants.HV_USB_MOUSE]
1489 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1490 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1491 spice_ip_version = None
1493 kvm_cmd.extend(["-usb"])
1496 kvm_cmd.extend(["-usbdevice", mouse_type])
1497 elif vnc_bind_address:
1498 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1500 if vnc_bind_address:
1501 if netutils.IP4Address.IsValid(vnc_bind_address):
1502 if instance.network_port > constants.VNC_BASE_PORT:
1503 display = instance.network_port - constants.VNC_BASE_PORT
1504 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1505 vnc_arg = ":%d" % (display)
1507 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1509 logging.error("Network port is not a valid VNC display (%d < %d),"
1510 " not starting VNC",
1511 instance.network_port, constants.VNC_BASE_PORT)
1514 # Only allow tls and other option when not binding to a file, for now.
1515 # kvm/qemu gets confused otherwise about the filename to use.
1517 if hvp[constants.HV_VNC_TLS]:
1518 vnc_append = "%s,tls" % vnc_append
1519 if hvp[constants.HV_VNC_X509_VERIFY]:
1520 vnc_append = "%s,x509verify=%s" % (vnc_append,
1521 hvp[constants.HV_VNC_X509])
1522 elif hvp[constants.HV_VNC_X509]:
1523 vnc_append = "%s,x509=%s" % (vnc_append,
1524 hvp[constants.HV_VNC_X509])
1525 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1526 vnc_append = "%s,password" % vnc_append
1528 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1531 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1533 kvm_cmd.extend(["-vnc", vnc_arg])
1535 # FIXME: this is wrong here; the iface ip address differs
1536 # between systems, so it should be done in _ExecuteKVMRuntime
1537 if netutils.IsValidInterface(spice_bind):
1538 # The user specified a network interface, we have to figure out the IP
1540 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1541 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1543 # if the user specified an IP version and the interface does not
1544 # have that kind of IP addresses, throw an exception
1545 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1546 if not addresses[spice_ip_version]:
1547 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1548 " for %s" % (spice_ip_version,
1551 # the user did not specify an IP version, we have to figure it out
1552 elif (addresses[constants.IP4_VERSION] and
1553 addresses[constants.IP6_VERSION]):
1554 # we have both ipv4 and ipv6, let's use the cluster default IP
1556 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1557 spice_ip_version = \
1558 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1559 elif addresses[constants.IP4_VERSION]:
1560 spice_ip_version = constants.IP4_VERSION
1561 elif addresses[constants.IP6_VERSION]:
1562 spice_ip_version = constants.IP6_VERSION
1564 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1565 " for %s" % (spice_bind))
1567 spice_address = addresses[spice_ip_version][0]
1570 # spice_bind is known to be a valid IP address, because
1571 # ValidateParameters checked it.
1572 spice_address = spice_bind
1574 spice_arg = "addr=%s" % spice_address
1575 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1576 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1577 (spice_arg, instance.network_port,
1578 pathutils.SPICE_CACERT_FILE))
1579 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1580 (spice_arg, pathutils.SPICE_CERT_FILE,
1581 pathutils.SPICE_CERT_FILE))
1582 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1584 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1586 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1588 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1589 spice_arg = "%s,disable-ticketing" % spice_arg
1591 if spice_ip_version:
1592 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1594 # Image compression options
1595 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1596 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1597 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1599 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1601 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1603 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1605 # Video stream detection
1606 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1608 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1610 # Audio compression, by default in qemu-kvm it is on
1611 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1612 spice_arg = "%s,playback-compression=off" % spice_arg
1613 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1614 spice_arg = "%s,agent-mouse=off" % spice_arg
1616 # Enable the spice agent communication channel between the host and the
1618 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1621 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1623 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1625 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1626 kvm_cmd.extend(["-spice", spice_arg])
1629 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1630 # also works in earlier versions though (tested with 1.1 and 1.3)
1631 if self._DISPLAY_RE.search(kvmhelp):
1632 kvm_cmd.extend(["-display", "none"])
1634 kvm_cmd.extend(["-nographic"])
1636 if hvp[constants.HV_USE_LOCALTIME]:
1637 kvm_cmd.extend(["-localtime"])
1639 if hvp[constants.HV_KVM_USE_CHROOT]:
1640 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1642 # Add qemu-KVM -cpu param
1643 if hvp[constants.HV_CPU_TYPE]:
1644 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1646 # As requested by music lovers
1647 if hvp[constants.HV_SOUNDHW]:
1648 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1650 # Pass a -vga option if requested, or if spice is used, for backwards
1652 if hvp[constants.HV_VGA]:
1653 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1655 kvm_cmd.extend(["-vga", "qxl"])
1657 # Various types of usb devices, comma separated
1658 if hvp[constants.HV_USB_DEVICES]:
1659 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1660 kvm_cmd.extend(["-usbdevice", dev])
1662 if hvp[constants.HV_KVM_EXTRA]:
1663 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1665 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1667 for disk, link_name in block_devices:
1668 _UpdatePCISlots(disk, pci_reservations)
1669 kvm_disks.append((disk, link_name))
1672 for nic in instance.nics:
1673 _UpdatePCISlots(nic, pci_reservations)
1674 kvm_nics.append(nic)
1678 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1680 def _WriteKVMRuntime(self, instance_name, data):
1681 """Write an instance's KVM runtime
1685 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1687 except EnvironmentError, err:
1688 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1690 def _ReadKVMRuntime(self, instance_name):
1691 """Read an instance's KVM runtime
1695 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1696 except EnvironmentError, err:
1697 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1700 def _SaveKVMRuntime(self, instance, kvm_runtime):
1701 """Save an instance's KVM runtime
1704 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1706 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1707 serialized_disks = [(blk.ToDict(), link)
1708 for blk, link in kvm_disks]
1709 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1712 self._WriteKVMRuntime(instance.name, serialized_form)
1714 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1715 """Load an instance's KVM runtime
1718 if not serialized_runtime:
1719 serialized_runtime = self._ReadKVMRuntime(instance.name)
1721 return _AnalyzeSerializedRuntime(serialized_runtime)
1723 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1724 """Run the KVM cmd and check for errors
1727 @param name: instance name
1728 @type kvm_cmd: list of strings
1729 @param kvm_cmd: runcmd input for kvm
1730 @type tap_fds: list of int
1731 @param tap_fds: fds of tap devices opened by Ganeti
1735 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1738 utils_wrapper.CloseFdNoError(fd)
1741 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1742 (name, result.fail_reason, result.output))
1743 if not self._InstancePidAlive(name)[2]:
1744 raise errors.HypervisorError("Failed to start instance %s" % name)
1746 # too many local variables
1747 # pylint: disable=R0914
1748 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1749 """Execute a KVM cmd, after completing it with some last minute data.
1751 @type incoming: tuple of strings
1752 @param incoming: (target_host_ip, port)
1753 @type kvmhelp: string
1754 @param kvmhelp: output of kvm --help
1757 # Small _ExecuteKVMRuntime hv parameters programming howto:
1758 # - conf_hvp contains the parameters as configured on ganeti. they might
1759 # have changed since the instance started; only use them if the change
1760 # won't affect the inside of the instance (which hasn't been rebooted).
1761 # - up_hvp contains the parameters as they were when the instance was
1762 # started, plus any new parameter which has been added between ganeti
1763 # versions: it is paramount that those default to a value which won't
1764 # affect the inside of the instance as well.
1765 conf_hvp = instance.hvparams
1766 name = instance.name
1767 self._CheckDown(name)
1771 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1772 # the first element of kvm_cmd is always the path to the kvm binary
1773 kvm_path = kvm_cmd[0]
1774 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1776 # We know it's safe to run as a different user upon migration, so we'll use
1777 # the latest conf, from conf_hvp.
1778 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1779 if security_model == constants.HT_SM_USER:
1780 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1782 keymap = conf_hvp[constants.HV_KEYMAP]
1784 keymap_path = self._InstanceKeymapFile(name)
1785 # If a keymap file is specified, KVM won't use its internal defaults. By
1786 # first including the "en-us" layout, an error on loading the actual
1787 # layout (e.g. because it can't be found) won't lead to a non-functional
1788 # keyboard. A keyboard with incorrect keys is still better than none.
1789 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1790 kvm_cmd.extend(["-k", keymap_path])
1792 # We have reasons to believe changing something like the nic driver/type
1793 # upon migration won't exactly fly with the instance kernel, so for nic
1794 # related parameters we'll use up_hvp
1797 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1799 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1803 kvm_cmd.extend(bdev_opts)
1806 kvm_cmd.extend(["-net", "none"])
1810 nic_type = up_hvp[constants.HV_NIC_TYPE]
1811 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1812 nic_model = self._VIRTIO
1814 if self._VIRTIO_NET_RE.search(devlist):
1815 nic_model = self._VIRTIO_NET_PCI
1816 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1817 except errors.HypervisorError, _:
1818 # Older versions of kvm don't support DEVICE_LIST, but they don't
1819 # have new virtio syntax either.
1822 if up_hvp[constants.HV_VHOST_NET]:
1823 # check for vhost_net support
1824 if self._VHOST_RE.search(kvmhelp):
1825 tap_extra = ",vhost=on"
1827 raise errors.HypervisorError("vhost_net is configured"
1828 " but it is not available")
1830 nic_model = nic_type
1832 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1834 for nic_seq, nic in enumerate(kvm_nics):
1835 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1836 tapfds.append(tapfd)
1837 taps.append(tapname)
1838 if kvm_supports_netdev:
1839 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1841 # kvm_nics already exist in old runtime files and thus there might
1842 # be some entries without pci slot (therefore try: except:)
1843 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1845 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1846 except errors.HotplugError:
1847 netdev = "netdev%d" % nic_seq
1848 nic_val += (",netdev=%s" % netdev)
1849 tap_val = ("type=tap,id=%s,fd=%d%s" %
1850 (netdev, tapfd, tap_extra))
1851 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1853 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1855 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1856 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1859 target, port = incoming
1860 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1862 # Changing the vnc password doesn't bother the guest that much. At most it
1863 # will surprise people who connect to it. Whether positively or negatively
1865 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1869 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1870 except EnvironmentError, err:
1871 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1872 % (vnc_pwd_file, err))
1874 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1875 utils.EnsureDirs([(self._InstanceChrootDir(name),
1876 constants.SECURE_DIR_MODE)])
1878 # Automatically enable QMP if version is >= 0.14
1879 if self._QMP_RE.search(kvmhelp):
1880 logging.debug("Enabling QMP")
1881 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1882 self._InstanceQmpMonitor(instance.name)])
1884 # Configure the network now for starting instances and bridged interfaces,
1885 # during FinalizeMigration for incoming instances' routed interfaces
1886 for nic_seq, nic in enumerate(kvm_nics):
1888 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1890 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1892 # CPU affinity requires kvm to start paused, so we set this flag if the
1893 # instance is not already paused and if we are not going to accept a
1894 # migrating instance. In the latter case, pausing is not needed.
1895 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1896 if start_kvm_paused:
1897 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1899 # Note: CPU pinning is using up_hvp since changes take effect
1900 # during instance startup anyway, and to avoid problems when soft
1901 # rebooting the instance.
1903 if up_hvp.get(constants.HV_CPU_MASK, None):
1906 if security_model == constants.HT_SM_POOL:
1907 ss = ssconf.SimpleStore()
1908 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1909 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1910 uid = uidpool.RequestUnusedUid(all_uids)
1912 username = pwd.getpwuid(uid.GetUid()).pw_name
1913 kvm_cmd.extend(["-runas", username])
1914 self._RunKVMCmd(name, kvm_cmd, tapfds)
1916 uidpool.ReleaseUid(uid)
1920 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1922 self._RunKVMCmd(name, kvm_cmd, tapfds)
1924 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1925 constants.RUN_DIRS_MODE)])
1926 for nic_seq, tap in enumerate(taps):
1927 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1931 change_cmd = "change vnc password %s" % vnc_pwd
1932 self._CallMonitorCommand(instance.name, change_cmd)
1934 # Setting SPICE password. We are not vulnerable to malicious passwordless
1935 # connection attempts because SPICE by default does not allow connections
1936 # if neither a password nor the "disable_ticketing" options are specified.
1937 # As soon as we send the password via QMP, that password is a valid ticket
1939 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1940 if spice_password_file:
1943 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1944 except EnvironmentError, err:
1945 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1946 % (spice_password_file, err))
1948 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1951 "protocol": "spice",
1952 "password": spice_pwd,
1954 qmp.Execute("set_password", arguments)
1956 for filename in temp_files:
1957 utils.RemoveFile(filename)
1959 # If requested, set CPU affinity and resume instance execution
1961 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1963 start_memory = self._InstanceStartupMemory(instance)
1964 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1965 self.BalloonInstanceMemory(instance, start_memory)
1967 if start_kvm_paused:
1968 # To control CPU pinning, ballooning, and vnc/spice passwords
1969 # the VM was started in a frozen state. If freezing was not
1970 # explicitly requested resume the vm status.
1971 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1973 def StartInstance(self, instance, block_devices, startup_paused):
1974 """Start an instance.
1977 self._CheckDown(instance.name)
1978 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1979 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1980 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1981 startup_paused, kvmhelp)
1982 self._SaveKVMRuntime(instance, kvm_runtime)
1983 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1985 def _CallMonitorCommand(self, instance_name, command, timeout=None):
1986 """Invoke a command on the instance monitor.
1989 if timeout is not None:
1990 timeout_cmd = "timeout %s" % (timeout, )
1994 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1995 # version. The monitor protocol is designed for human consumption, whereas
1996 # QMP is made for programmatic usage. In the worst case QMP can also
1997 # execute monitor commands. As it is, all calls to socat take at least
1998 # 500ms and likely more: socat can't detect the end of the reply and waits
1999 # for 500ms of no data received before exiting (500 ms is the default for
2000 # the "-t" parameter).
2001 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
2002 (utils.ShellQuote(command),
2004 constants.SOCAT_PATH,
2005 utils.ShellQuote(self._InstanceMonitor(instance_name))))
2007 result = utils.RunCmd(socat)
2009 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2011 (command, instance_name, result.fail_reason, result.output))
2012 raise errors.HypervisorError(msg)
2016 def _GetFreePCISlot(self, instance, dev):
2017 """Get the first available pci slot of a runnung instance.
2020 slots = bitarray(32)
2021 slots.setall(False) # pylint: disable=E1101
2022 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2023 for line in output.stdout.splitlines():
2024 match = self._INFO_PCI_RE.search(line)
2026 slot = int(match.group(1))
2029 [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2031 raise errors.HypervisorError("All PCI slots occupied")
2035 def VerifyHotplugSupport(self, instance, action, dev_type):
2036 """Verifies that hotplug is supported.
2038 Hotplug is *not* supported in case of:
2039 - security models and chroot (disk hotplug)
2040 - fdsend module is missing (nic hot-add)
2042 @raise errors.HypervisorError: in one of the previous cases
2045 if dev_type == constants.HOTPLUG_TARGET_DISK:
2046 hvp = instance.hvparams
2047 security_model = hvp[constants.HV_SECURITY_MODEL]
2048 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2050 raise errors.HotplugError("Disk hotplug is not supported"
2051 " in case of chroot.")
2052 if security_model != constants.HT_SM_NONE:
2053 raise errors.HotplugError("Disk Hotplug is not supported in case"
2054 " security models are used.")
2056 if (dev_type == constants.HOTPLUG_TARGET_NIC and
2057 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2058 raise errors.HotplugError("Cannot hot-add NIC."
2059 " fdsend python module is missing.")
2061 def HotplugSupported(self, instance):
2062 """Checks if hotplug is generally supported.
2064 Hotplug is *not* supported in case of:
2065 - qemu versions < 1.0
2066 - for stopped instances
2068 @raise errors.HypervisorError: in one of the previous cases
2072 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2073 except errors.HypervisorError:
2074 raise errors.HotplugError("Instance is probably down")
2076 # TODO: search for netdev_add, drive_add, device_add.....
2077 match = self._INFO_VERSION_RE.search(output.stdout)
2079 raise errors.HotplugError("Cannot parse qemu version via monitor")
2081 v_major, v_min, _, _ = match.groups()
2082 if (int(v_major), int(v_min)) < (1, 0):
2083 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2085 def _CallHotplugCommands(self, name, cmds):
2087 self._CallMonitorCommand(name, c)
2090 def _VerifyHotplugCommand(self, instance_name, device, dev_type,
2092 """Checks if a previous hotplug command has succeeded.
2094 It issues info pci monitor command and checks depending on should_exist
2095 value if an entry with PCI slot and device ID is found or not.
2097 @raise errors.HypervisorError: if result is not the expected one
2100 output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
2101 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2103 self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
2104 if match and not should_exist:
2105 msg = "Device %s should have been removed but is still there" % kvm_devid
2106 raise errors.HypervisorError(msg)
2108 if not match and should_exist:
2109 msg = "Device %s should have been added but is missing" % kvm_devid
2110 raise errors.HypervisorError(msg)
2112 logging.info("Device %s has been correctly hot-plugged", kvm_devid)
2114 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2115 """ Helper method to hot-add a new device
2117 It gets free pci slot generates the device name and invokes the
2118 device specific method.
2121 # in case of hot-mod this is given
2122 if device.pci is None:
2123 self._GetFreePCISlot(instance, device)
2124 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2125 runtime = self._LoadKVMRuntime(instance)
2126 if dev_type == constants.HOTPLUG_TARGET_DISK:
2127 cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
2129 cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2130 (hex(device.pci), kvm_devid, kvm_devid)]
2131 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2132 (tap, fd) = _OpenTap()
2133 self._ConfigureNIC(instance, seq, device, tap)
2134 self._PassTapFd(instance, fd, device)
2135 cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
2136 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2137 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2138 cmds += ["device_add %s" % args]
2139 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2141 self._CallHotplugCommands(instance.name, cmds)
2142 self._VerifyHotplugCommand(instance.name, device, dev_type, True)
2143 # update relevant entries in runtime file
2144 index = _DEVICE_RUNTIME_INDEX[dev_type]
2145 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2146 runtime[index].append(entry)
2147 self._SaveKVMRuntime(instance, runtime)
2149 def HotDelDevice(self, instance, dev_type, device, _, seq):
2150 """ Helper method for hot-del device
2152 It gets device info from runtime file, generates the device name and
2153 invokes the device specific method.
2156 runtime = self._LoadKVMRuntime(instance)
2157 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2158 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2159 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2160 if dev_type == constants.HOTPLUG_TARGET_DISK:
2161 cmds = ["device_del %s" % kvm_devid]
2162 cmds += ["drive_del %s" % kvm_devid]
2163 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2164 cmds = ["device_del %s" % kvm_devid]
2165 cmds += ["netdev_del %s" % kvm_devid]
2166 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2167 self._CallHotplugCommands(instance.name, cmds)
2168 self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
2169 index = _DEVICE_RUNTIME_INDEX[dev_type]
2170 runtime[index].remove(entry)
2171 self._SaveKVMRuntime(instance, runtime)
2173 return kvm_device.pci
2175 def HotModDevice(self, instance, dev_type, device, _, seq):
2176 """ Helper method for hot-mod device
2178 It gets device info from runtime file, generates the device name and
2179 invokes the device specific method. Currently only NICs support hot-mod
2182 if dev_type == constants.HOTPLUG_TARGET_NIC:
2183 # putting it back in the same pci slot
2184 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2185 # TODO: remove sleep when socat gets removed
2186 self.HotAddDevice(instance, dev_type, device, _, seq)
2188 def _PassTapFd(self, instance, fd, nic):
2189 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2192 # TODO: factor out code related to unix sockets.
2193 # squash common parts between monitor and qmp
2194 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2195 command = "getfd %s\n" % kvm_devid
2197 logging.info("%s", fds)
2199 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2201 fdsend.sendfds(monsock.sock, command, fds=fds)
2206 def _ParseKVMVersion(cls, text):
2207 """Parse the KVM version from the --help output.
2210 @param text: output of kvm --help
2211 @return: (version, v_maj, v_min, v_rev)
2212 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2215 match = cls._VERSION_RE.search(text.splitlines()[0])
2217 raise errors.HypervisorError("Unable to get KVM version")
2219 v_all = match.group(0)
2220 v_maj = int(match.group(1))
2221 v_min = int(match.group(2))
2223 v_rev = int(match.group(4))
2226 return (v_all, v_maj, v_min, v_rev)
2229 def _GetKVMOutput(cls, kvm_path, option):
2230 """Return the output of a kvm invocation
2232 @type kvm_path: string
2233 @param kvm_path: path to the kvm executable
2234 @type option: a key of _KVMOPTS_CMDS
2235 @param option: kvm option to fetch the output from
2236 @return: output a supported kvm invocation
2237 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2240 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2242 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2244 result = utils.RunCmd([kvm_path] + optlist)
2245 if result.failed and not can_fail:
2246 raise errors.HypervisorError("Unable to get KVM %s output" %
2248 return result.output
2251 def _GetKVMVersion(cls, kvm_path):
2252 """Return the installed KVM version.
2254 @return: (version, v_maj, v_min, v_rev)
2255 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2258 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2261 def _GetDefaultMachineVersion(cls, kvm_path):
2262 """Return the default hardware revision (e.g. pc-1.1)
2265 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2266 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2268 return match.group(1)
2272 def StopInstance(self, instance, force=False, retry=False, name=None,
2274 """Stop an instance.
2277 assert(timeout is None or force is not None)
2279 if name is not None and not force:
2280 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2282 name = instance.name
2283 acpi = instance.hvparams[constants.HV_ACPI]
2286 _, pid, alive = self._InstancePidAlive(name)
2287 if pid > 0 and alive:
2288 if force or not acpi:
2289 utils.KillProcess(pid)
2291 self._CallMonitorCommand(name, "system_powerdown", timeout)
2293 def CleanupInstance(self, instance_name):
2294 """Cleanup after a stopped instance
2297 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2298 if pid > 0 and alive:
2299 raise errors.HypervisorError("Cannot cleanup a live instance")
2300 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2302 def RebootInstance(self, instance):
2303 """Reboot an instance.
2306 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2307 # socket the instance will stop, but now power up again. So we'll resort
2308 # to shutdown and restart.
2309 _, _, alive = self._InstancePidAlive(instance.name)
2311 raise errors.HypervisorError("Failed to reboot instance %s:"
2312 " not running" % instance.name)
2313 # StopInstance will delete the saved KVM runtime so:
2314 # ...first load it...
2315 kvm_runtime = self._LoadKVMRuntime(instance)
2316 # ...now we can safely call StopInstance...
2317 if not self.StopInstance(instance):
2318 self.StopInstance(instance, force=True)
2319 # ...and finally we can save it again, and execute it...
2320 self._SaveKVMRuntime(instance, kvm_runtime)
2321 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2322 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2323 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2325 def MigrationInfo(self, instance):
2326 """Get instance information to perform a migration.
2328 @type instance: L{objects.Instance}
2329 @param instance: instance to be migrated
2331 @return: content of the KVM runtime file
2334 return self._ReadKVMRuntime(instance.name)
2336 def AcceptInstance(self, instance, info, target):
2337 """Prepare to accept an instance.
2339 @type instance: L{objects.Instance}
2340 @param instance: instance to be accepted
2342 @param info: content of the KVM runtime file on the source node
2343 @type target: string
2344 @param target: target host (usually ip), on this node
2347 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2348 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2349 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2350 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2351 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2352 incoming=incoming_address)
2354 def FinalizeMigrationDst(self, instance, info, success):
2355 """Finalize the instance migration on the target node.
2357 Stop the incoming mode KVM.
2359 @type instance: L{objects.Instance}
2360 @param instance: instance whose migration is being finalized
2364 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2365 kvm_nics = kvm_runtime[1]
2367 for nic_seq, nic in enumerate(kvm_nics):
2368 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2369 # Bridged interfaces have already been configured
2372 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2373 except EnvironmentError, err:
2374 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2375 instance.name, nic_seq, str(err))
2378 self._ConfigureNIC(instance, nic_seq, nic, tap)
2379 except errors.HypervisorError, err:
2380 logging.warning(str(err))
2382 self._WriteKVMRuntime(instance.name, info)
2384 self.StopInstance(instance, force=True)
2386 def MigrateInstance(self, instance, target, live):
2387 """Migrate an instance to a target node.
2389 The migration will not be attempted if the instance is not
2392 @type instance: L{objects.Instance}
2393 @param instance: the instance to be migrated
2394 @type target: string
2395 @param target: ip address of the target node
2397 @param live: perform a live migration
2400 instance_name = instance.name
2401 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2402 _, _, alive = self._InstancePidAlive(instance_name)
2404 raise errors.HypervisorError("Instance not running, cannot migrate")
2407 self._CallMonitorCommand(instance_name, "stop")
2409 migrate_command = ("migrate_set_speed %dm" %
2410 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2411 self._CallMonitorCommand(instance_name, migrate_command)
2413 migrate_command = ("migrate_set_downtime %dms" %
2414 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2415 self._CallMonitorCommand(instance_name, migrate_command)
2417 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2418 self._CallMonitorCommand(instance_name, migrate_command)
2420 def FinalizeMigrationSource(self, instance, success, live):
2421 """Finalize the instance migration on the source node.
2423 @type instance: L{objects.Instance}
2424 @param instance: the instance that was migrated
2426 @param success: whether the migration succeeded or not
2428 @param live: whether the user requested a live migration or not
2432 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2433 utils.KillProcess(pid)
2434 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2436 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2438 def GetMigrationStatus(self, instance):
2439 """Get the migration status
2441 @type instance: L{objects.Instance}
2442 @param instance: the instance that is being migrated
2443 @rtype: L{objects.MigrationStatus}
2444 @return: the status of the current migration (one of
2445 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2446 progress info that can be retrieved from the hypervisor
2449 info_command = "info migrate"
2450 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2451 result = self._CallMonitorCommand(instance.name, info_command)
2452 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2454 if not result.stdout:
2455 logging.info("KVM: empty 'info migrate' result")
2457 logging.warning("KVM: unknown 'info migrate' result: %s",
2460 status = match.group(1)
2461 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2462 migration_status = objects.MigrationStatus(status=status)
2463 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2465 migration_status.transferred_ram = match.group("transferred")
2466 migration_status.total_ram = match.group("total")
2468 return migration_status
2470 logging.warning("KVM: unknown migration status '%s'", status)
2472 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2474 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2476 def BalloonInstanceMemory(self, instance, mem):
2477 """Balloon an instance memory to a certain value.
2479 @type instance: L{objects.Instance}
2480 @param instance: instance to be accepted
2482 @param mem: actual memory size to use for instance runtime
2485 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2487 def GetNodeInfo(self):
2488 """Return information about the node.
2490 @return: a dict with the following keys (values in MiB):
2491 - memory_total: the total memory size on the node
2492 - memory_free: the available memory on the node for instances
2493 - memory_dom0: the memory used by the node itself, if available
2494 - hv_version: the hypervisor version in the form (major, minor,
2498 result = self.GetLinuxNodeInfo()
2499 # FIXME: this is the global kvm version, but the actual version can be
2500 # customized as an hv parameter. we should use the nodegroup's default kvm
2501 # path parameter here.
2502 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2503 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2507 def GetInstanceConsole(cls, instance, hvparams, beparams):
2508 """Return a command for connecting to the console of an instance.
2511 if hvparams[constants.HV_SERIAL_CONSOLE]:
2512 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2513 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2514 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2515 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2516 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2517 return objects.InstanceConsole(instance=instance.name,
2518 kind=constants.CONS_SSH,
2519 host=instance.primary_node,
2520 user=constants.SSH_CONSOLE_USER,
2523 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2524 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2525 display = instance.network_port - constants.VNC_BASE_PORT
2526 return objects.InstanceConsole(instance=instance.name,
2527 kind=constants.CONS_VNC,
2528 host=vnc_bind_address,
2529 port=instance.network_port,
2532 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2534 return objects.InstanceConsole(instance=instance.name,
2535 kind=constants.CONS_SPICE,
2537 port=instance.network_port)
2539 return objects.InstanceConsole(instance=instance.name,
2540 kind=constants.CONS_MESSAGE,
2541 message=("No serial shell for instance %s" %
2545 """Verify the hypervisor.
2547 Check that the required binaries exist.
2549 @return: Problem description if something is wrong, C{None} otherwise
2553 # FIXME: this is the global kvm binary, but the actual path can be
2554 # customized as an hv parameter; we should use the nodegroup's
2555 # default kvm path parameter here.
2556 if not os.path.exists(constants.KVM_PATH):
2557 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2558 if not os.path.exists(constants.SOCAT_PATH):
2559 msgs.append("The socat binary ('%s') does not exist" %
2560 constants.SOCAT_PATH)
2562 return self._FormatVerifyResults(msgs)
2565 def CheckParameterSyntax(cls, hvparams):
2566 """Check the given parameters for validity.
2568 @type hvparams: dict
2569 @param hvparams: dictionary with parameter names/value
2570 @raise errors.HypervisorError: when a parameter is not valid
2573 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2575 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2577 if not hvparams[constants.HV_ROOT_PATH]:
2578 raise errors.HypervisorError("Need a root partition for the instance,"
2579 " if a kernel is defined")
2581 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2582 not hvparams[constants.HV_VNC_X509]):
2583 raise errors.HypervisorError("%s must be defined, if %s is" %
2584 (constants.HV_VNC_X509,
2585 constants.HV_VNC_X509_VERIFY))
2587 if hvparams[constants.HV_SERIAL_CONSOLE]:
2588 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2589 valid_speeds = constants.VALID_SERIAL_SPEEDS
2590 if not serial_speed or serial_speed not in valid_speeds:
2591 raise errors.HypervisorError("Invalid serial console speed, must be"
2593 utils.CommaJoin(valid_speeds))
2595 boot_order = hvparams[constants.HV_BOOT_ORDER]
2596 if (boot_order == constants.HT_BO_CDROM and
2597 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2598 raise errors.HypervisorError("Cannot boot from cdrom without an"
2601 security_model = hvparams[constants.HV_SECURITY_MODEL]
2602 if security_model == constants.HT_SM_USER:
2603 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2604 raise errors.HypervisorError("A security domain (user to run kvm as)"
2605 " must be specified")
2606 elif (security_model == constants.HT_SM_NONE or
2607 security_model == constants.HT_SM_POOL):
2608 if hvparams[constants.HV_SECURITY_DOMAIN]:
2609 raise errors.HypervisorError("Cannot have a security domain when the"
2610 " security model is 'none' or 'pool'")
2612 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2613 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2615 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2616 # if an IP version is specified, the spice_bind parameter must be an
2618 if (netutils.IP4Address.IsValid(spice_bind) and
2619 spice_ip_version != constants.IP4_VERSION):
2620 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2621 " the specified IP version is %s" %
2622 (spice_bind, spice_ip_version))
2624 if (netutils.IP6Address.IsValid(spice_bind) and
2625 spice_ip_version != constants.IP6_VERSION):
2626 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2627 " the specified IP version is %s" %
2628 (spice_bind, spice_ip_version))
2630 # All the other SPICE parameters depend on spice_bind being set. Raise an
2631 # error if any of them is set without it.
2632 for param in _SPICE_ADDITIONAL_PARAMS:
2634 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2635 (param, constants.HV_KVM_SPICE_BIND))
2638 def ValidateParameters(cls, hvparams):
2639 """Check the given parameters for validity.
2641 @type hvparams: dict
2642 @param hvparams: dictionary with parameter names/value
2643 @raise errors.HypervisorError: when a parameter is not valid
2646 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2648 kvm_path = hvparams[constants.HV_KVM_PATH]
2650 security_model = hvparams[constants.HV_SECURITY_MODEL]
2651 if security_model == constants.HT_SM_USER:
2652 username = hvparams[constants.HV_SECURITY_DOMAIN]
2654 pwd.getpwnam(username)
2656 raise errors.HypervisorError("Unknown security domain user %s"
2659 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2661 # only one of VNC and SPICE can be used currently.
2662 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2663 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2664 " only one of them can be used at a"
2667 # check that KVM supports SPICE
2668 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2669 if not cls._SPICE_RE.search(kvmhelp):
2670 raise errors.HypervisorError("SPICE is configured, but it is not"
2671 " supported according to 'kvm --help'")
2673 # if spice_bind is not an IP address, it must be a valid interface
2674 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2675 netutils.IP6Address.IsValid(spice_bind))
2676 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2677 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2678 " a valid IP address or interface name" %
2679 constants.HV_KVM_SPICE_BIND)
2681 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2683 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2684 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2685 raise errors.HypervisorError("Unsupported machine version: %s" %
2689 def PowercycleNode(cls):
2690 """KVM powercycle, just a wrapper over Linux powercycle.
2693 cls.LinuxPowercycle()