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_DATA_KEY = "data"
460 _ERROR_DESC_KEY = "desc"
461 _EXECUTE_KEY = "execute"
462 _ARGUMENTS_KEY = "arguments"
463 _CAPABILITIES_COMMAND = "qmp_capabilities"
464 _MESSAGE_END_TOKEN = "\r\n"
466 def __init__(self, monitor_filename):
467 super(QmpConnection, self).__init__(monitor_filename)
471 """Connects to the QMP monitor.
473 Connects to the UNIX socket and makes sure that we can actually send and
474 receive data to the kvm instance via QMP.
476 @raise errors.HypervisorError: when there are communication errors
477 @raise errors.ProgrammerError: when there are data serialization errors
480 super(QmpConnection, self).connect()
481 # Check if we receive a correct greeting message from the server
482 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
483 greeting = self._Recv()
484 if not greeting[self._FIRST_MESSAGE_KEY]:
485 self._connected = False
486 raise errors.HypervisorError("kvm: QMP communication error (wrong"
489 # Let's put the monitor in command mode using the qmp_capabilities
490 # command, or else no command will be executable.
491 # (As per the QEMU Protocol Specification 0.1 - section 4)
492 self.Execute(self._CAPABILITIES_COMMAND)
494 def _ParseMessage(self, buf):
495 """Extract and parse a QMP message from the given buffer.
497 Seeks for a QMP message in the given buf. If found, it parses it and
498 returns it together with the rest of the characters in the buf.
499 If no message is found, returns None and the whole buffer.
501 @raise errors.ProgrammerError: when there are data serialization errors
505 # Check if we got the message end token (CRLF, as per the QEMU Protocol
506 # Specification 0.1 - Section 2.1.1)
507 pos = buf.find(self._MESSAGE_END_TOKEN)
510 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
511 except Exception, err:
512 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
515 return (message, buf)
518 """Receives a message from QMP and decodes the received JSON object.
521 @return: the received message
522 @raise errors.HypervisorError: when there are communication errors
523 @raise errors.ProgrammerError: when there are data serialization errors
526 self._check_connection()
528 # Check if there is already a message in the buffer
529 (message, self._buf) = self._ParseMessage(self._buf)
533 recv_buffer = StringIO.StringIO(self._buf)
534 recv_buffer.seek(len(self._buf))
537 data = self.sock.recv(4096)
540 recv_buffer.write(data)
542 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
546 except socket.timeout, err:
547 raise errors.HypervisorError("Timeout while receiving a QMP message: "
549 except socket.error, err:
550 raise errors.HypervisorError("Unable to receive data from KVM using the"
551 " QMP protocol: %s" % err)
553 def _Send(self, message):
554 """Encodes and sends a message to KVM using QMP.
556 @type message: QmpMessage
557 @param message: message to send to KVM
558 @raise errors.HypervisorError: when there are communication errors
559 @raise errors.ProgrammerError: when there are data serialization errors
562 self._check_connection()
564 message_str = str(message)
565 except Exception, err:
566 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
569 self.sock.sendall(message_str)
570 except socket.timeout, err:
571 raise errors.HypervisorError("Timeout while sending a QMP message: "
572 "%s (%s)" % (err.string, err.errno))
573 except socket.error, err:
574 raise errors.HypervisorError("Unable to send data from KVM using the"
575 " QMP protocol: %s" % err)
577 def Execute(self, command, arguments=None):
578 """Executes a QMP command and returns the response of the server.
581 @param command: the command to execute
582 @type arguments: dict
583 @param arguments: dictionary of arguments to be passed to the command
585 @return: dictionary representing the received JSON object
586 @raise errors.HypervisorError: when there are communication errors
587 @raise errors.ProgrammerError: when there are data serialization errors
590 self._check_connection()
591 message = QmpMessage({self._EXECUTE_KEY: command})
593 message[self._ARGUMENTS_KEY] = arguments
596 # Events can occur between the sending of the command and the reception
597 # of the response, so we need to filter out messages with the event key.
599 response = self._Recv()
600 err = response[self._ERROR_KEY]
602 raise errors.HypervisorError("kvm: error executing the %s"
603 " command: %s (%s, %s):" %
605 err[self._ERROR_DESC_KEY],
606 err[self._ERROR_CLASS_KEY],
607 err[self._ERROR_DATA_KEY]))
609 elif not response[self._EVENT_KEY]:
613 class KVMHypervisor(hv_base.BaseHypervisor):
614 """KVM hypervisor interface
619 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
620 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
621 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
622 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
623 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
624 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
625 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
626 # KVM instances with chroot enabled are started in empty chroot directories.
627 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
628 # After an instance is stopped, its chroot directory is removed.
629 # If the chroot directory is not empty, it can't be removed.
630 # A non-empty chroot directory indicates a possible security incident.
631 # To support forensics, the non-empty chroot directory is quarantined in
632 # a separate directory, called 'chroot-quarantine'.
633 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
634 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
635 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
638 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
639 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
640 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
641 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
642 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
643 constants.HV_ACPI: hv_base.NO_CHECK,
644 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
645 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
646 constants.HV_VNC_BIND_ADDRESS:
647 (False, lambda x: (netutils.IP4Address.IsValid(x) or
648 utils.IsNormAbsPath(x)),
649 "The VNC bind address must be either a valid IP address or an absolute"
650 " pathname", None, None),
651 constants.HV_VNC_TLS: hv_base.NO_CHECK,
652 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
653 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
654 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
655 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
656 constants.HV_KVM_SPICE_IP_VERSION:
657 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
658 x in constants.VALID_IP_VERSIONS),
659 "The SPICE IP version should be 4 or 6",
661 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
662 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
664 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
665 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
667 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
668 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
670 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
671 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
673 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
674 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
675 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
676 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
677 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
678 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
679 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
680 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
681 constants.HV_BOOT_ORDER:
682 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
683 constants.HV_NIC_TYPE:
684 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
685 constants.HV_DISK_TYPE:
686 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
687 constants.HV_KVM_CDROM_DISK_TYPE:
688 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
689 constants.HV_USB_MOUSE:
690 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
691 constants.HV_KEYMAP: hv_base.NO_CHECK,
692 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
693 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
694 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
695 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
696 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
697 constants.HV_DISK_CACHE:
698 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
699 constants.HV_SECURITY_MODEL:
700 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
701 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
702 constants.HV_KVM_FLAG:
703 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
704 constants.HV_VHOST_NET: hv_base.NO_CHECK,
705 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
706 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
707 constants.HV_REBOOT_BEHAVIOR:
708 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
709 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
710 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
711 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
712 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
713 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
714 constants.HV_SOUNDHW: hv_base.NO_CHECK,
715 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
716 constants.HV_VGA: hv_base.NO_CHECK,
717 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
718 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
719 constants.HV_VNET_HDR: hv_base.NO_CHECK,
723 _VIRTIO_NET_PCI = "virtio-net-pci"
724 _VIRTIO_BLK_PCI = "virtio-blk-pci"
726 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
728 _MIGRATION_PROGRESS_RE = \
729 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
730 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
731 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
733 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
734 _MIGRATION_INFO_RETRY_DELAY = 2
736 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
738 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
739 _CPU_INFO_CMD = "info cpus"
742 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
743 _CHECK_MACHINE_VERSION_RE = \
744 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
746 _QMP_RE = re.compile(r"^-qmp\s", re.M)
747 _SPICE_RE = re.compile(r"^-spice\s", re.M)
748 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
749 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
750 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
751 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
752 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
753 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
754 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
755 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
756 # match -drive.*boot=on|off on different lines, but in between accept only
757 # dashes not preceeded by a new line (which would mean another option
758 # different than -drive is starting)
759 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
761 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
762 _INFO_PCI_CMD = "info pci"
764 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
765 _INFO_VERSION_CMD = "info version"
767 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
772 ANCILLARY_FILES_OPT = [
776 # Supported kvm options to get output from
777 _KVMOPT_HELP = "help"
778 _KVMOPT_MLIST = "mlist"
779 _KVMOPT_DEVICELIST = "devicelist"
781 # Command to execute to get the output from kvm, and whether to
782 # accept the output even on failure.
784 _KVMOPT_HELP: (["--help"], False),
785 _KVMOPT_MLIST: (["-M", "?"], False),
786 _KVMOPT_DEVICELIST: (["-device", "?"], True),
790 hv_base.BaseHypervisor.__init__(self)
791 # Let's make sure the directories we need exist, even if the RUN_DIR lives
792 # in a tmpfs filesystem or has been otherwise wiped out.
793 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
794 utils.EnsureDirs(dirs)
797 def _InstancePidFile(cls, instance_name):
798 """Returns the instance pidfile.
801 return utils.PathJoin(cls._PIDS_DIR, instance_name)
804 def _InstanceUidFile(cls, instance_name):
805 """Returns the instance uidfile.
808 return utils.PathJoin(cls._UIDS_DIR, instance_name)
811 def _InstancePidInfo(cls, pid):
812 """Check pid file for instance information.
814 Check that a pid file is associated with an instance, and retrieve
815 information from its command line.
817 @type pid: string or int
818 @param pid: process id of the instance to check
820 @return: (instance_name, memory, vcpus)
821 @raise errors.HypervisorError: when an instance cannot be found
824 alive = utils.IsProcessAlive(pid)
826 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
828 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
830 cmdline = utils.ReadFile(cmdline_file)
831 except EnvironmentError, err:
832 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
839 arg_list = cmdline.split("\x00")
841 arg = arg_list.pop(0)
843 instance = arg_list.pop(0)
845 memory = int(arg_list.pop(0))
847 vcpus = int(arg_list.pop(0).split(",")[0])
850 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
853 return (instance, memory, vcpus)
855 def _InstancePidAlive(self, instance_name):
856 """Returns the instance pidfile, pid, and liveness.
858 @type instance_name: string
859 @param instance_name: instance name
861 @return: (pid file name, pid, liveness)
864 pidfile = self._InstancePidFile(instance_name)
865 pid = utils.ReadPidFile(pidfile)
869 cmd_instance = self._InstancePidInfo(pid)[0]
870 alive = (cmd_instance == instance_name)
871 except errors.HypervisorError:
874 return (pidfile, pid, alive)
876 def _CheckDown(self, instance_name):
877 """Raises an error unless the given instance is down.
880 alive = self._InstancePidAlive(instance_name)[2]
882 raise errors.HypervisorError("Failed to start instance %s: %s" %
883 (instance_name, "already running"))
886 def _InstanceMonitor(cls, instance_name):
887 """Returns the instance monitor socket name
890 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
893 def _InstanceSerial(cls, instance_name):
894 """Returns the instance serial socket name
897 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
900 def _InstanceQmpMonitor(cls, instance_name):
901 """Returns the instance serial QMP socket name
904 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
907 def _SocatUnixConsoleParams():
908 """Returns the correct parameters for socat
910 If we have a new-enough socat we can use raw mode with an escape character.
913 if constants.SOCAT_USE_ESCAPE:
914 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
916 return "echo=0,icanon=0"
919 def _InstanceKVMRuntime(cls, instance_name):
920 """Returns the instance KVM runtime filename
923 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
926 def _InstanceChrootDir(cls, instance_name):
927 """Returns the name of the KVM chroot dir of the instance
930 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
933 def _InstanceNICDir(cls, instance_name):
934 """Returns the name of the directory holding the tap device files for a
938 return utils.PathJoin(cls._NICS_DIR, instance_name)
941 def _InstanceNICFile(cls, instance_name, seq):
942 """Returns the name of the file containing the tap device for a given NIC
945 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
948 def _InstanceKeymapFile(cls, instance_name):
949 """Returns the name of the file containing the keymap for a given instance
952 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
955 def _TryReadUidFile(cls, uid_file):
956 """Try to read a uid file
959 if os.path.exists(uid_file):
961 uid = int(utils.ReadOneLineFile(uid_file))
963 except EnvironmentError:
964 logging.warning("Can't read uid file", exc_info=True)
965 except (TypeError, ValueError):
966 logging.warning("Can't parse uid file contents", exc_info=True)
970 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
971 """Removes an instance's rutime sockets/files/dirs.
974 utils.RemoveFile(pidfile)
975 utils.RemoveFile(cls._InstanceMonitor(instance_name))
976 utils.RemoveFile(cls._InstanceSerial(instance_name))
977 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
978 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
979 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
980 uid_file = cls._InstanceUidFile(instance_name)
981 uid = cls._TryReadUidFile(uid_file)
982 utils.RemoveFile(uid_file)
984 uidpool.ReleaseUid(uid)
986 shutil.rmtree(cls._InstanceNICDir(instance_name))
988 if err.errno != errno.ENOENT:
991 chroot_dir = cls._InstanceChrootDir(instance_name)
992 utils.RemoveDir(chroot_dir)
994 if err.errno == errno.ENOTEMPTY:
995 # The chroot directory is expected to be empty, but it isn't.
996 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
999 utils.TimestampForFilename()))
1000 logging.warning("The chroot directory of instance %s can not be"
1001 " removed as it is not empty. Moving it to the"
1002 " quarantine instead. Please investigate the"
1003 " contents (%s) and clean up manually",
1004 instance_name, new_chroot_dir)
1005 utils.RenameFile(chroot_dir, new_chroot_dir)
1010 def _ConfigureNIC(instance, seq, nic, tap):
1011 """Run the network configuration script for a specified NIC
1013 @param instance: instance we're acting on
1014 @type instance: instance object
1015 @param seq: nic sequence number
1017 @param nic: nic we're acting on
1018 @type nic: nic object
1019 @param tap: the host's tap interface this NIC corresponds to
1024 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1025 "INSTANCE": instance.name,
1027 "MODE": nic.nicparams[constants.NIC_MODE],
1029 "INTERFACE_INDEX": str(seq),
1030 "INTERFACE_UUID": nic.uuid,
1031 "TAGS": " ".join(instance.GetTags()),
1038 env["INTERFACE_NAME"] = nic.name
1040 if nic.nicparams[constants.NIC_LINK]:
1041 env["LINK"] = nic.nicparams[constants.NIC_LINK]
1044 n = objects.Network.FromDict(nic.netinfo)
1045 env.update(n.HooksDict())
1047 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1048 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1050 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1052 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1053 " network configuration script output: %s" %
1054 (tap, result.fail_reason, result.output))
1057 def _VerifyAffinityPackage():
1058 if affinity is None:
1059 raise errors.HypervisorError("affinity Python package not"
1060 " found; cannot use CPU pinning under KVM")
1063 def _BuildAffinityCpuMask(cpu_list):
1064 """Create a CPU mask suitable for sched_setaffinity from a list of
1067 See man taskset for more info on sched_setaffinity masks.
1068 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1070 @type cpu_list: list of int
1071 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1073 @return: a bit mask of CPU affinities
1076 if cpu_list == constants.CPU_PINNING_OFF:
1077 return constants.CPU_PINNING_ALL_KVM
1079 return sum(2 ** cpu for cpu in cpu_list)
1082 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1083 """Change CPU affinity for running VM according to given CPU mask.
1085 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1086 @type cpu_mask: string
1087 @param process_id: process ID of KVM process. Used to pin entire VM
1089 @type process_id: int
1090 @param thread_dict: map of virtual CPUs to KVM thread IDs
1091 @type thread_dict: dict int:int
1094 # Convert the string CPU mask to a list of list of int's
1095 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1097 if len(cpu_list) == 1:
1098 all_cpu_mapping = cpu_list[0]
1099 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1100 # If CPU pinning has 1 entry that's "all", then do nothing
1103 # If CPU pinning has one non-all entry, map the entire VM to
1104 # one set of physical CPUs
1105 cls._VerifyAffinityPackage()
1106 affinity.set_process_affinity_mask(
1107 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1109 # The number of vCPUs mapped should match the number of vCPUs
1110 # reported by KVM. This was already verified earlier, so
1111 # here only as a sanity check.
1112 assert len(thread_dict) == len(cpu_list)
1113 cls._VerifyAffinityPackage()
1115 # For each vCPU, map it to the proper list of physical CPUs
1116 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1117 affinity.set_process_affinity_mask(thread_dict[i],
1118 cls._BuildAffinityCpuMask(vcpu))
1120 def _GetVcpuThreadIds(self, instance_name):
1121 """Get a mapping of vCPU no. to thread IDs for the instance
1123 @type instance_name: string
1124 @param instance_name: instance in question
1125 @rtype: dictionary of int:int
1126 @return: a dictionary mapping vCPU numbers to thread IDs
1130 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1131 for line in output.stdout.splitlines():
1132 match = self._CPU_INFO_RE.search(line)
1135 grp = map(int, match.groups())
1136 result[grp[0]] = grp[1]
1140 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1141 """Complete CPU pinning.
1143 @type instance_name: string
1144 @param instance_name: name of instance
1145 @type cpu_mask: string
1146 @param cpu_mask: CPU pinning mask as entered by user
1149 # Get KVM process ID, to be used if need to pin entire VM
1150 _, pid, _ = self._InstancePidAlive(instance_name)
1151 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1152 thread_dict = self._GetVcpuThreadIds(instance_name)
1153 # Run CPU pinning, based on configured mask
1154 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1156 def ListInstances(self):
1157 """Get the list of running instances.
1159 We can do this by listing our live instances directory and
1160 checking whether the associated kvm process is still alive.
1164 for name in os.listdir(self._PIDS_DIR):
1165 if self._InstancePidAlive(name)[2]:
1169 def GetInstanceInfo(self, instance_name):
1170 """Get instance properties.
1172 @type instance_name: string
1173 @param instance_name: the instance name
1174 @rtype: tuple of strings
1175 @return: (name, id, memory, vcpus, stat, times)
1178 _, pid, alive = self._InstancePidAlive(instance_name)
1182 _, memory, vcpus = self._InstancePidInfo(pid)
1187 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1189 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1190 # Will fail if ballooning is not enabled, but we can then just resort to
1192 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1193 memory = mem_bytes / 1048576
1194 except errors.HypervisorError:
1197 return (instance_name, pid, memory, vcpus, istat, times)
1199 def GetAllInstancesInfo(self):
1200 """Get properties of all instances.
1202 @return: list of tuples (name, id, memory, vcpus, stat, times)
1206 for name in os.listdir(self._PIDS_DIR):
1208 info = self.GetInstanceInfo(name)
1209 except errors.HypervisorError:
1210 # Ignore exceptions due to instances being shut down
1216 def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1218 """Generate KVM options regarding instance's block devices.
1220 @type instance: L{objects.Instance}
1221 @param instance: the instance object
1222 @type kvm_disks: list of tuples
1223 @param kvm_disks: list of tuples [(disk, link_name)..]
1224 @type kvmhelp: string
1225 @param kvmhelp: output of kvm --help
1226 @type devlist: string
1227 @param devlist: output of kvm -device ?
1229 @return: list of command line options eventually used by kvm executable
1232 hvp = instance.hvparams
1233 kernel_path = hvp[constants.HV_KERNEL_PATH]
1237 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1239 # whether this is an older KVM version that uses the boot=on flag
1241 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1244 device_driver = None
1245 disk_type = hvp[constants.HV_DISK_TYPE]
1246 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1247 if_val = ",if=%s" % self._VIRTIO
1249 if self._VIRTIO_BLK_RE.search(devlist):
1251 # will be passed in -device option as driver
1252 device_driver = self._VIRTIO_BLK_PCI
1253 except errors.HypervisorError, _:
1256 if_val = ",if=%s" % disk_type
1258 disk_cache = hvp[constants.HV_DISK_CACHE]
1259 if instance.disk_template in constants.DTS_EXT_MIRROR:
1260 if disk_cache != "none":
1261 # TODO: make this a hard error, instead of a silent overwrite
1262 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1263 " to prevent shared storage corruption on migration",
1265 cache_val = ",cache=none"
1266 elif disk_cache != constants.HT_CACHE_DEFAULT:
1267 cache_val = ",cache=%s" % disk_cache
1270 for idx, (cfdev, link_name) in enumerate(kvm_disks):
1271 if cfdev.mode != constants.DISK_RDWR:
1272 raise errors.HypervisorError("Instance has read-only disks which"
1273 " are not supported by KVM")
1274 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1277 dev_opts.extend(["-boot", "c"])
1279 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1280 boot_val = ",boot=on"
1281 drive_val = "file=%s,format=raw%s%s%s" % \
1282 (link_name, if_val, boot_val, cache_val)
1285 # kvm_disks are the 4th entry of runtime file that did not exist in
1286 # the past. That means that cfdev should always have pci slot and
1287 # _GenerateDeviceKVMId() will not raise a exception.
1288 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK,
1290 drive_val += (",id=%s" % kvm_devid)
1292 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1293 dev_val = ("%s,drive=%s,id=%s" %
1294 (device_driver, kvm_devid, kvm_devid))
1296 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1297 dev_opts.extend(["-device", dev_val])
1299 # TODO: export disk geometry in IDISK_PARAMS
1300 heads = cfdev.params.get('heads', None)
1301 secs = cfdev.params.get('secs', None)
1303 nr_sectors = cfdev.size * 1024 * 1024 / 512
1304 cyls = nr_sectors / (int(heads) * int(secs))
1309 if cyls and heads and secs:
1310 drive_val += (",cyls=%d,heads=%d,secs=%d" %
1311 (cyls, int(heads), int(secs)))
1313 dev_opts.extend(["-drive", drive_val])
1317 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1319 """Generate KVM information to start an instance.
1321 @type kvmhelp: string
1322 @param kvmhelp: output of kvm --help
1323 @attention: this function must not have any side-effects; for
1324 example, it must not write to the filesystem, or read values
1325 from the current system the are expected to differ between
1326 nodes, since it is only run once at instance startup;
1327 actions/kvm arguments that can vary between systems should be
1328 done in L{_ExecuteKVMRuntime}
1331 # pylint: disable=R0912,R0914,R0915
1332 hvp = instance.hvparams
1333 self.ValidateParameters(hvp)
1335 pidfile = self._InstancePidFile(instance.name)
1336 kvm = hvp[constants.HV_KVM_PATH]
1338 # used just by the vnc server, if enabled
1339 kvm_cmd.extend(["-name", instance.name])
1340 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1342 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1343 if hvp[constants.HV_CPU_CORES]:
1344 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1345 if hvp[constants.HV_CPU_THREADS]:
1346 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1347 if hvp[constants.HV_CPU_SOCKETS]:
1348 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1350 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1352 kvm_cmd.extend(["-pidfile", pidfile])
1353 kvm_cmd.extend(["-balloon", "virtio"])
1354 kvm_cmd.extend(["-daemonize"])
1355 if not instance.hvparams[constants.HV_ACPI]:
1356 kvm_cmd.extend(["-no-acpi"])
1357 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1358 constants.INSTANCE_REBOOT_EXIT:
1359 kvm_cmd.extend(["-no-reboot"])
1361 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1363 mversion = self._GetDefaultMachineVersion(kvm)
1364 if self._MACHINE_RE.search(kvmhelp):
1365 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1366 # extra hypervisor parameters. We should also investigate whether and how
1367 # shadow_mem should be considered for the resource model.
1368 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1369 specprop = ",accel=kvm"
1372 machinespec = "%s%s" % (mversion, specprop)
1373 kvm_cmd.extend(["-machine", machinespec])
1375 kvm_cmd.extend(["-M", mversion])
1376 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1377 self._ENABLE_KVM_RE.search(kvmhelp)):
1378 kvm_cmd.extend(["-enable-kvm"])
1379 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1380 self._DISABLE_KVM_RE.search(kvmhelp)):
1381 kvm_cmd.extend(["-disable-kvm"])
1383 kernel_path = hvp[constants.HV_KERNEL_PATH]
1385 boot_cdrom = boot_floppy = boot_network = False
1387 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1388 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1389 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1392 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1395 kvm_cmd.extend(["-boot", "n"])
1397 # whether this is an older KVM version that uses the boot=on flag
1399 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1401 disk_type = hvp[constants.HV_DISK_TYPE]
1403 #Now we can specify a different device type for CDROM devices.
1404 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1405 if not cdrom_disk_type:
1406 cdrom_disk_type = disk_type
1408 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1410 options = ",format=raw,media=cdrom"
1411 # set cdrom 'if' type
1413 actual_cdrom_type = constants.HT_DISK_IDE
1414 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1415 actual_cdrom_type = "virtio"
1417 actual_cdrom_type = cdrom_disk_type
1418 if_val = ",if=%s" % actual_cdrom_type
1419 # set boot flag, if needed
1422 kvm_cmd.extend(["-boot", "d"])
1424 boot_val = ",boot=on"
1425 # and finally build the entire '-drive' value
1426 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1427 kvm_cmd.extend(["-drive", drive_val])
1429 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1431 options = ",format=raw,media=cdrom"
1432 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1433 if_val = ",if=virtio"
1435 if_val = ",if=%s" % cdrom_disk_type
1436 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1437 kvm_cmd.extend(["-drive", drive_val])
1439 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1441 options = ",format=raw,media=disk"
1443 kvm_cmd.extend(["-boot", "a"])
1444 options = "%s,boot=on" % options
1445 if_val = ",if=floppy"
1446 options = "%s%s" % (options, if_val)
1447 drive_val = "file=%s%s" % (floppy_image, options)
1448 kvm_cmd.extend(["-drive", drive_val])
1451 kvm_cmd.extend(["-kernel", kernel_path])
1452 initrd_path = hvp[constants.HV_INITRD_PATH]
1454 kvm_cmd.extend(["-initrd", initrd_path])
1455 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1456 hvp[constants.HV_KERNEL_ARGS]]
1457 if hvp[constants.HV_SERIAL_CONSOLE]:
1458 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1459 root_append.append("console=ttyS0,%s" % serial_speed)
1460 kvm_cmd.extend(["-append", " ".join(root_append)])
1462 mem_path = hvp[constants.HV_MEM_PATH]
1464 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1466 monitor_dev = ("unix:%s,server,nowait" %
1467 self._InstanceMonitor(instance.name))
1468 kvm_cmd.extend(["-monitor", monitor_dev])
1469 if hvp[constants.HV_SERIAL_CONSOLE]:
1470 serial_dev = ("unix:%s,server,nowait" %
1471 self._InstanceSerial(instance.name))
1472 kvm_cmd.extend(["-serial", serial_dev])
1474 kvm_cmd.extend(["-serial", "none"])
1476 mouse_type = hvp[constants.HV_USB_MOUSE]
1477 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1478 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1479 spice_ip_version = None
1481 kvm_cmd.extend(["-usb"])
1484 kvm_cmd.extend(["-usbdevice", mouse_type])
1485 elif vnc_bind_address:
1486 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1488 if vnc_bind_address:
1489 if netutils.IP4Address.IsValid(vnc_bind_address):
1490 if instance.network_port > constants.VNC_BASE_PORT:
1491 display = instance.network_port - constants.VNC_BASE_PORT
1492 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1493 vnc_arg = ":%d" % (display)
1495 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1497 logging.error("Network port is not a valid VNC display (%d < %d),"
1498 " not starting VNC",
1499 instance.network_port, constants.VNC_BASE_PORT)
1502 # Only allow tls and other option when not binding to a file, for now.
1503 # kvm/qemu gets confused otherwise about the filename to use.
1505 if hvp[constants.HV_VNC_TLS]:
1506 vnc_append = "%s,tls" % vnc_append
1507 if hvp[constants.HV_VNC_X509_VERIFY]:
1508 vnc_append = "%s,x509verify=%s" % (vnc_append,
1509 hvp[constants.HV_VNC_X509])
1510 elif hvp[constants.HV_VNC_X509]:
1511 vnc_append = "%s,x509=%s" % (vnc_append,
1512 hvp[constants.HV_VNC_X509])
1513 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1514 vnc_append = "%s,password" % vnc_append
1516 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1519 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1521 kvm_cmd.extend(["-vnc", vnc_arg])
1523 # FIXME: this is wrong here; the iface ip address differs
1524 # between systems, so it should be done in _ExecuteKVMRuntime
1525 if netutils.IsValidInterface(spice_bind):
1526 # The user specified a network interface, we have to figure out the IP
1528 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1529 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1531 # if the user specified an IP version and the interface does not
1532 # have that kind of IP addresses, throw an exception
1533 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1534 if not addresses[spice_ip_version]:
1535 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1536 " for %s" % (spice_ip_version,
1539 # the user did not specify an IP version, we have to figure it out
1540 elif (addresses[constants.IP4_VERSION] and
1541 addresses[constants.IP6_VERSION]):
1542 # we have both ipv4 and ipv6, let's use the cluster default IP
1544 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1545 spice_ip_version = \
1546 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1547 elif addresses[constants.IP4_VERSION]:
1548 spice_ip_version = constants.IP4_VERSION
1549 elif addresses[constants.IP6_VERSION]:
1550 spice_ip_version = constants.IP6_VERSION
1552 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1553 " for %s" % (spice_bind))
1555 spice_address = addresses[spice_ip_version][0]
1558 # spice_bind is known to be a valid IP address, because
1559 # ValidateParameters checked it.
1560 spice_address = spice_bind
1562 spice_arg = "addr=%s" % spice_address
1563 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1564 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1565 (spice_arg, instance.network_port,
1566 pathutils.SPICE_CACERT_FILE))
1567 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1568 (spice_arg, pathutils.SPICE_CERT_FILE,
1569 pathutils.SPICE_CERT_FILE))
1570 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1572 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1574 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1576 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1577 spice_arg = "%s,disable-ticketing" % spice_arg
1579 if spice_ip_version:
1580 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1582 # Image compression options
1583 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1584 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1585 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1587 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1589 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1591 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1593 # Video stream detection
1594 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1596 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1598 # Audio compression, by default in qemu-kvm it is on
1599 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1600 spice_arg = "%s,playback-compression=off" % spice_arg
1601 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1602 spice_arg = "%s,agent-mouse=off" % spice_arg
1604 # Enable the spice agent communication channel between the host and the
1606 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1609 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1611 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1613 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1614 kvm_cmd.extend(["-spice", spice_arg])
1617 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1618 # also works in earlier versions though (tested with 1.1 and 1.3)
1619 if self._DISPLAY_RE.search(kvmhelp):
1620 kvm_cmd.extend(["-display", "none"])
1622 kvm_cmd.extend(["-nographic"])
1624 if hvp[constants.HV_USE_LOCALTIME]:
1625 kvm_cmd.extend(["-localtime"])
1627 if hvp[constants.HV_KVM_USE_CHROOT]:
1628 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1630 # Add qemu-KVM -cpu param
1631 if hvp[constants.HV_CPU_TYPE]:
1632 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1634 # As requested by music lovers
1635 if hvp[constants.HV_SOUNDHW]:
1636 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1638 # Pass a -vga option if requested, or if spice is used, for backwards
1640 if hvp[constants.HV_VGA]:
1641 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1643 kvm_cmd.extend(["-vga", "qxl"])
1645 # Various types of usb devices, comma separated
1646 if hvp[constants.HV_USB_DEVICES]:
1647 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1648 kvm_cmd.extend(["-usbdevice", dev])
1650 if hvp[constants.HV_KVM_EXTRA]:
1651 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1653 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1655 for disk, link_name in block_devices:
1656 _UpdatePCISlots(disk, pci_reservations)
1657 kvm_disks.append((disk, link_name))
1660 for nic in instance.nics:
1661 _UpdatePCISlots(nic, pci_reservations)
1662 kvm_nics.append(nic)
1666 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1668 def _WriteKVMRuntime(self, instance_name, data):
1669 """Write an instance's KVM runtime
1673 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1675 except EnvironmentError, err:
1676 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1678 def _ReadKVMRuntime(self, instance_name):
1679 """Read an instance's KVM runtime
1683 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1684 except EnvironmentError, err:
1685 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1688 def _SaveKVMRuntime(self, instance, kvm_runtime):
1689 """Save an instance's KVM runtime
1692 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1694 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1695 serialized_disks = [(blk.ToDict(), link)
1696 for blk, link in kvm_disks]
1697 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1700 self._WriteKVMRuntime(instance.name, serialized_form)
1702 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1703 """Load an instance's KVM runtime
1706 if not serialized_runtime:
1707 serialized_runtime = self._ReadKVMRuntime(instance.name)
1709 return _AnalyzeSerializedRuntime(serialized_runtime)
1711 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1712 """Run the KVM cmd and check for errors
1715 @param name: instance name
1716 @type kvm_cmd: list of strings
1717 @param kvm_cmd: runcmd input for kvm
1718 @type tap_fds: list of int
1719 @param tap_fds: fds of tap devices opened by Ganeti
1723 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1726 utils_wrapper.CloseFdNoError(fd)
1729 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1730 (name, result.fail_reason, result.output))
1731 if not self._InstancePidAlive(name)[2]:
1732 raise errors.HypervisorError("Failed to start instance %s" % name)
1734 # too many local variables
1735 # pylint: disable=R0914
1736 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1737 """Execute a KVM cmd, after completing it with some last minute data.
1739 @type incoming: tuple of strings
1740 @param incoming: (target_host_ip, port)
1741 @type kvmhelp: string
1742 @param kvmhelp: output of kvm --help
1745 # Small _ExecuteKVMRuntime hv parameters programming howto:
1746 # - conf_hvp contains the parameters as configured on ganeti. they might
1747 # have changed since the instance started; only use them if the change
1748 # won't affect the inside of the instance (which hasn't been rebooted).
1749 # - up_hvp contains the parameters as they were when the instance was
1750 # started, plus any new parameter which has been added between ganeti
1751 # versions: it is paramount that those default to a value which won't
1752 # affect the inside of the instance as well.
1753 conf_hvp = instance.hvparams
1754 name = instance.name
1755 self._CheckDown(name)
1759 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1760 # the first element of kvm_cmd is always the path to the kvm binary
1761 kvm_path = kvm_cmd[0]
1762 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1764 # We know it's safe to run as a different user upon migration, so we'll use
1765 # the latest conf, from conf_hvp.
1766 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1767 if security_model == constants.HT_SM_USER:
1768 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1770 keymap = conf_hvp[constants.HV_KEYMAP]
1772 keymap_path = self._InstanceKeymapFile(name)
1773 # If a keymap file is specified, KVM won't use its internal defaults. By
1774 # first including the "en-us" layout, an error on loading the actual
1775 # layout (e.g. because it can't be found) won't lead to a non-functional
1776 # keyboard. A keyboard with incorrect keys is still better than none.
1777 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1778 kvm_cmd.extend(["-k", keymap_path])
1780 # We have reasons to believe changing something like the nic driver/type
1781 # upon migration won't exactly fly with the instance kernel, so for nic
1782 # related parameters we'll use up_hvp
1785 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1787 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1791 kvm_cmd.extend(bdev_opts)
1794 kvm_cmd.extend(["-net", "none"])
1798 nic_type = up_hvp[constants.HV_NIC_TYPE]
1799 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1800 nic_model = self._VIRTIO
1802 if self._VIRTIO_NET_RE.search(devlist):
1803 nic_model = self._VIRTIO_NET_PCI
1804 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1805 except errors.HypervisorError, _:
1806 # Older versions of kvm don't support DEVICE_LIST, but they don't
1807 # have new virtio syntax either.
1810 if up_hvp[constants.HV_VHOST_NET]:
1811 # check for vhost_net support
1812 if self._VHOST_RE.search(kvmhelp):
1813 tap_extra = ",vhost=on"
1815 raise errors.HypervisorError("vhost_net is configured"
1816 " but it is not available")
1818 nic_model = nic_type
1820 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1822 for nic_seq, nic in enumerate(kvm_nics):
1823 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1824 tapfds.append(tapfd)
1825 taps.append(tapname)
1826 if kvm_supports_netdev:
1827 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1829 # kvm_nics already exist in old runtime files and thus there might
1830 # be some entries without pci slot (therefore try: except:)
1831 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1833 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1834 except errors.HotplugError:
1835 netdev = "netdev%d" % nic_seq
1836 nic_val += (",netdev=%s" % netdev)
1837 tap_val = ("type=tap,id=%s,fd=%d%s" %
1838 (netdev, tapfd, tap_extra))
1839 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1841 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1843 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1844 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1847 target, port = incoming
1848 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1850 # Changing the vnc password doesn't bother the guest that much. At most it
1851 # will surprise people who connect to it. Whether positively or negatively
1853 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1857 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1858 except EnvironmentError, err:
1859 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1860 % (vnc_pwd_file, err))
1862 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1863 utils.EnsureDirs([(self._InstanceChrootDir(name),
1864 constants.SECURE_DIR_MODE)])
1866 # Automatically enable QMP if version is >= 0.14
1867 if self._QMP_RE.search(kvmhelp):
1868 logging.debug("Enabling QMP")
1869 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1870 self._InstanceQmpMonitor(instance.name)])
1872 # Configure the network now for starting instances and bridged interfaces,
1873 # during FinalizeMigration for incoming instances' routed interfaces
1874 for nic_seq, nic in enumerate(kvm_nics):
1876 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1878 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1880 # CPU affinity requires kvm to start paused, so we set this flag if the
1881 # instance is not already paused and if we are not going to accept a
1882 # migrating instance. In the latter case, pausing is not needed.
1883 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1884 if start_kvm_paused:
1885 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1887 # Note: CPU pinning is using up_hvp since changes take effect
1888 # during instance startup anyway, and to avoid problems when soft
1889 # rebooting the instance.
1891 if up_hvp.get(constants.HV_CPU_MASK, None):
1894 if security_model == constants.HT_SM_POOL:
1895 ss = ssconf.SimpleStore()
1896 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1897 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1898 uid = uidpool.RequestUnusedUid(all_uids)
1900 username = pwd.getpwuid(uid.GetUid()).pw_name
1901 kvm_cmd.extend(["-runas", username])
1902 self._RunKVMCmd(name, kvm_cmd, tapfds)
1904 uidpool.ReleaseUid(uid)
1908 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1910 self._RunKVMCmd(name, kvm_cmd, tapfds)
1912 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1913 constants.RUN_DIRS_MODE)])
1914 for nic_seq, tap in enumerate(taps):
1915 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1919 change_cmd = "change vnc password %s" % vnc_pwd
1920 self._CallMonitorCommand(instance.name, change_cmd)
1922 # Setting SPICE password. We are not vulnerable to malicious passwordless
1923 # connection attempts because SPICE by default does not allow connections
1924 # if neither a password nor the "disable_ticketing" options are specified.
1925 # As soon as we send the password via QMP, that password is a valid ticket
1927 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1928 if spice_password_file:
1931 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1932 except EnvironmentError, err:
1933 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1934 % (spice_password_file, err))
1936 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1939 "protocol": "spice",
1940 "password": spice_pwd,
1942 qmp.Execute("set_password", arguments)
1944 for filename in temp_files:
1945 utils.RemoveFile(filename)
1947 # If requested, set CPU affinity and resume instance execution
1949 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1951 start_memory = self._InstanceStartupMemory(instance)
1952 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1953 self.BalloonInstanceMemory(instance, start_memory)
1955 if start_kvm_paused:
1956 # To control CPU pinning, ballooning, and vnc/spice passwords
1957 # the VM was started in a frozen state. If freezing was not
1958 # explicitly requested resume the vm status.
1959 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1961 def StartInstance(self, instance, block_devices, startup_paused):
1962 """Start an instance.
1965 self._CheckDown(instance.name)
1966 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1967 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1968 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1969 startup_paused, kvmhelp)
1970 self._SaveKVMRuntime(instance, kvm_runtime)
1971 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1973 def _CallMonitorCommand(self, instance_name, command, timeout=None):
1974 """Invoke a command on the instance monitor.
1977 if timeout is not None:
1978 timeout_cmd = "timeout %s" % (timeout, )
1982 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1983 # version. The monitor protocol is designed for human consumption, whereas
1984 # QMP is made for programmatic usage. In the worst case QMP can also
1985 # execute monitor commands. As it is, all calls to socat take at least
1986 # 500ms and likely more: socat can't detect the end of the reply and waits
1987 # for 500ms of no data received before exiting (500 ms is the default for
1988 # the "-t" parameter).
1989 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1990 (utils.ShellQuote(command),
1992 constants.SOCAT_PATH,
1993 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1995 result = utils.RunCmd(socat)
1997 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1999 (command, instance_name, result.fail_reason, result.output))
2000 raise errors.HypervisorError(msg)
2004 def _GetFreePCISlot(self, instance, dev):
2005 """Get the first available pci slot of a runnung instance.
2008 slots = bitarray(32)
2009 slots.setall(False) # pylint: disable=E1101
2010 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2011 for line in output.stdout.splitlines():
2012 match = self._INFO_PCI_RE.search(line)
2014 slot = int(match.group(1))
2017 [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2019 raise errors.HypervisorError("All PCI slots occupied")
2023 def VerifyHotplugSupport(self, instance, action, dev_type):
2024 """Verifies that hotplug is supported.
2026 Hotplug is *not* supported in case of:
2027 - security models and chroot (disk hotplug)
2028 - fdsend module is missing (nic hot-add)
2030 @raise errors.HypervisorError: in one of the previous cases
2033 if dev_type == constants.HOTPLUG_TARGET_DISK:
2034 hvp = instance.hvparams
2035 security_model = hvp[constants.HV_SECURITY_MODEL]
2036 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2038 raise errors.HotplugError("Disk hotplug is not supported"
2039 " in case of chroot.")
2040 if security_model != constants.HT_SM_NONE:
2041 raise errors.HotplugError("Disk Hotplug is not supported in case"
2042 " security models are used.")
2044 if (dev_type == constants.HOTPLUG_TARGET_NIC and
2045 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2046 raise errors.HotplugError("Cannot hot-add NIC."
2047 " fdsend python module is missing.")
2049 def HotplugSupported(self, instance):
2050 """Checks if hotplug is generally supported.
2052 Hotplug is *not* supported in case of:
2053 - qemu versions < 1.0
2054 - for stopped instances
2056 @raise errors.HypervisorError: in one of the previous cases
2060 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2061 except errors.HypervisorError:
2062 raise errors.HotplugError("Instance is probably down")
2064 # TODO: search for netdev_add, drive_add, device_add.....
2065 match = self._INFO_VERSION_RE.search(output.stdout)
2067 raise errors.HotplugError("Cannot parse qemu version via monitor")
2069 v_major, v_min, _, _ = match.groups()
2070 if (int(v_major), int(v_min)) < (1, 0):
2071 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2073 def _CallHotplugCommand(self, name, cmd):
2074 output = self._CallMonitorCommand(name, cmd)
2075 # TODO: parse output and check if succeeded
2076 for line in output.stdout.splitlines():
2077 logging.info("%s", line)
2079 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2080 """ Helper method to hot-add a new device
2082 It gets free pci slot generates the device name and invokes the
2083 device specific method.
2086 # in case of hot-mod this is given
2087 if device.pci is None:
2088 self._GetFreePCISlot(instance, device)
2089 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2090 runtime = self._LoadKVMRuntime(instance)
2091 if dev_type == constants.HOTPLUG_TARGET_DISK:
2092 command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2094 command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2095 (hex(device.pci), kvm_devid, kvm_devid))
2096 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2097 (tap, fd) = _OpenTap()
2098 self._ConfigureNIC(instance, seq, device, tap)
2099 self._PassTapFd(instance, fd, device)
2100 command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2101 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2102 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2103 command += "device_add %s" % args
2104 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2106 self._CallHotplugCommand(instance.name, command)
2107 # update relevant entries in runtime file
2108 index = _DEVICE_RUNTIME_INDEX[dev_type]
2109 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2110 runtime[index].append(entry)
2111 self._SaveKVMRuntime(instance, runtime)
2113 def HotDelDevice(self, instance, dev_type, device, _, seq):
2114 """ Helper method for hot-del device
2116 It gets device info from runtime file, generates the device name and
2117 invokes the device specific method.
2120 runtime = self._LoadKVMRuntime(instance)
2121 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2122 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2123 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2124 if dev_type == constants.HOTPLUG_TARGET_DISK:
2125 command = "device_del %s\n" % kvm_devid
2126 command += "drive_del %s" % kvm_devid
2127 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2128 command = "device_del %s\n" % kvm_devid
2129 command += "netdev_del %s" % kvm_devid
2130 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2131 self._CallHotplugCommand(instance.name, command)
2132 index = _DEVICE_RUNTIME_INDEX[dev_type]
2133 runtime[index].remove(entry)
2134 self._SaveKVMRuntime(instance, runtime)
2136 return kvm_device.pci
2138 def HotModDevice(self, instance, dev_type, device, _, seq):
2139 """ Helper method for hot-mod device
2141 It gets device info from runtime file, generates the device name and
2142 invokes the device specific method. Currently only NICs support hot-mod
2145 if dev_type == constants.HOTPLUG_TARGET_NIC:
2146 # putting it back in the same pci slot
2147 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2148 # TODO: remove sleep when socat gets removed
2150 self.HotAddDevice(instance, dev_type, device, _, seq)
2152 def _PassTapFd(self, instance, fd, nic):
2153 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2156 # TODO: factor out code related to unix sockets.
2157 # squash common parts between monitor and qmp
2158 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2159 command = "getfd %s\n" % kvm_devid
2161 logging.info("%s", fds)
2163 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2165 fdsend.sendfds(monsock.sock, command, fds=fds)
2170 def _ParseKVMVersion(cls, text):
2171 """Parse the KVM version from the --help output.
2174 @param text: output of kvm --help
2175 @return: (version, v_maj, v_min, v_rev)
2176 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2179 match = cls._VERSION_RE.search(text.splitlines()[0])
2181 raise errors.HypervisorError("Unable to get KVM version")
2183 v_all = match.group(0)
2184 v_maj = int(match.group(1))
2185 v_min = int(match.group(2))
2187 v_rev = int(match.group(4))
2190 return (v_all, v_maj, v_min, v_rev)
2193 def _GetKVMOutput(cls, kvm_path, option):
2194 """Return the output of a kvm invocation
2196 @type kvm_path: string
2197 @param kvm_path: path to the kvm executable
2198 @type option: a key of _KVMOPTS_CMDS
2199 @param option: kvm option to fetch the output from
2200 @return: output a supported kvm invocation
2201 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2204 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2206 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2208 result = utils.RunCmd([kvm_path] + optlist)
2209 if result.failed and not can_fail:
2210 raise errors.HypervisorError("Unable to get KVM %s output" %
2212 return result.output
2215 def _GetKVMVersion(cls, kvm_path):
2216 """Return the installed KVM version.
2218 @return: (version, v_maj, v_min, v_rev)
2219 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2222 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2225 def _GetDefaultMachineVersion(cls, kvm_path):
2226 """Return the default hardware revision (e.g. pc-1.1)
2229 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2230 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2232 return match.group(1)
2236 def StopInstance(self, instance, force=False, retry=False, name=None,
2238 """Stop an instance.
2241 assert(timeout is None or force is not None)
2243 if name is not None and not force:
2244 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2246 name = instance.name
2247 acpi = instance.hvparams[constants.HV_ACPI]
2250 _, pid, alive = self._InstancePidAlive(name)
2251 if pid > 0 and alive:
2252 if force or not acpi:
2253 utils.KillProcess(pid)
2255 self._CallMonitorCommand(name, "system_powerdown", timeout)
2257 def CleanupInstance(self, instance_name):
2258 """Cleanup after a stopped instance
2261 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2262 if pid > 0 and alive:
2263 raise errors.HypervisorError("Cannot cleanup a live instance")
2264 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2266 def RebootInstance(self, instance):
2267 """Reboot an instance.
2270 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2271 # socket the instance will stop, but now power up again. So we'll resort
2272 # to shutdown and restart.
2273 _, _, alive = self._InstancePidAlive(instance.name)
2275 raise errors.HypervisorError("Failed to reboot instance %s:"
2276 " not running" % instance.name)
2277 # StopInstance will delete the saved KVM runtime so:
2278 # ...first load it...
2279 kvm_runtime = self._LoadKVMRuntime(instance)
2280 # ...now we can safely call StopInstance...
2281 if not self.StopInstance(instance):
2282 self.StopInstance(instance, force=True)
2283 # ...and finally we can save it again, and execute it...
2284 self._SaveKVMRuntime(instance, kvm_runtime)
2285 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2286 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2287 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2289 def MigrationInfo(self, instance):
2290 """Get instance information to perform a migration.
2292 @type instance: L{objects.Instance}
2293 @param instance: instance to be migrated
2295 @return: content of the KVM runtime file
2298 return self._ReadKVMRuntime(instance.name)
2300 def AcceptInstance(self, instance, info, target):
2301 """Prepare to accept an instance.
2303 @type instance: L{objects.Instance}
2304 @param instance: instance to be accepted
2306 @param info: content of the KVM runtime file on the source node
2307 @type target: string
2308 @param target: target host (usually ip), on this node
2311 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2312 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2313 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2314 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2315 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2316 incoming=incoming_address)
2318 def FinalizeMigrationDst(self, instance, info, success):
2319 """Finalize the instance migration on the target node.
2321 Stop the incoming mode KVM.
2323 @type instance: L{objects.Instance}
2324 @param instance: instance whose migration is being finalized
2328 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2329 kvm_nics = kvm_runtime[1]
2331 for nic_seq, nic in enumerate(kvm_nics):
2332 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2333 # Bridged interfaces have already been configured
2336 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2337 except EnvironmentError, err:
2338 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2339 instance.name, nic_seq, str(err))
2342 self._ConfigureNIC(instance, nic_seq, nic, tap)
2343 except errors.HypervisorError, err:
2344 logging.warning(str(err))
2346 self._WriteKVMRuntime(instance.name, info)
2348 self.StopInstance(instance, force=True)
2350 def MigrateInstance(self, instance, target, live):
2351 """Migrate an instance to a target node.
2353 The migration will not be attempted if the instance is not
2356 @type instance: L{objects.Instance}
2357 @param instance: the instance to be migrated
2358 @type target: string
2359 @param target: ip address of the target node
2361 @param live: perform a live migration
2364 instance_name = instance.name
2365 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2366 _, _, alive = self._InstancePidAlive(instance_name)
2368 raise errors.HypervisorError("Instance not running, cannot migrate")
2371 self._CallMonitorCommand(instance_name, "stop")
2373 migrate_command = ("migrate_set_speed %dm" %
2374 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2375 self._CallMonitorCommand(instance_name, migrate_command)
2377 migrate_command = ("migrate_set_downtime %dms" %
2378 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2379 self._CallMonitorCommand(instance_name, migrate_command)
2381 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2382 self._CallMonitorCommand(instance_name, migrate_command)
2384 def FinalizeMigrationSource(self, instance, success, live):
2385 """Finalize the instance migration on the source node.
2387 @type instance: L{objects.Instance}
2388 @param instance: the instance that was migrated
2390 @param success: whether the migration succeeded or not
2392 @param live: whether the user requested a live migration or not
2396 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2397 utils.KillProcess(pid)
2398 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2400 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2402 def GetMigrationStatus(self, instance):
2403 """Get the migration status
2405 @type instance: L{objects.Instance}
2406 @param instance: the instance that is being migrated
2407 @rtype: L{objects.MigrationStatus}
2408 @return: the status of the current migration (one of
2409 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2410 progress info that can be retrieved from the hypervisor
2413 info_command = "info migrate"
2414 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2415 result = self._CallMonitorCommand(instance.name, info_command)
2416 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2418 if not result.stdout:
2419 logging.info("KVM: empty 'info migrate' result")
2421 logging.warning("KVM: unknown 'info migrate' result: %s",
2424 status = match.group(1)
2425 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2426 migration_status = objects.MigrationStatus(status=status)
2427 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2429 migration_status.transferred_ram = match.group("transferred")
2430 migration_status.total_ram = match.group("total")
2432 return migration_status
2434 logging.warning("KVM: unknown migration status '%s'", status)
2436 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2438 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2440 def BalloonInstanceMemory(self, instance, mem):
2441 """Balloon an instance memory to a certain value.
2443 @type instance: L{objects.Instance}
2444 @param instance: instance to be accepted
2446 @param mem: actual memory size to use for instance runtime
2449 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2451 def GetNodeInfo(self):
2452 """Return information about the node.
2454 @return: a dict with the following keys (values in MiB):
2455 - memory_total: the total memory size on the node
2456 - memory_free: the available memory on the node for instances
2457 - memory_dom0: the memory used by the node itself, if available
2458 - hv_version: the hypervisor version in the form (major, minor,
2462 result = self.GetLinuxNodeInfo()
2463 # FIXME: this is the global kvm version, but the actual version can be
2464 # customized as an hv parameter. we should use the nodegroup's default kvm
2465 # path parameter here.
2466 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2467 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2471 def GetInstanceConsole(cls, instance, hvparams, beparams):
2472 """Return a command for connecting to the console of an instance.
2475 if hvparams[constants.HV_SERIAL_CONSOLE]:
2476 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2477 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2478 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2479 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2480 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2481 return objects.InstanceConsole(instance=instance.name,
2482 kind=constants.CONS_SSH,
2483 host=instance.primary_node,
2484 user=constants.SSH_CONSOLE_USER,
2487 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2488 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2489 display = instance.network_port - constants.VNC_BASE_PORT
2490 return objects.InstanceConsole(instance=instance.name,
2491 kind=constants.CONS_VNC,
2492 host=vnc_bind_address,
2493 port=instance.network_port,
2496 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2498 return objects.InstanceConsole(instance=instance.name,
2499 kind=constants.CONS_SPICE,
2501 port=instance.network_port)
2503 return objects.InstanceConsole(instance=instance.name,
2504 kind=constants.CONS_MESSAGE,
2505 message=("No serial shell for instance %s" %
2509 """Verify the hypervisor.
2511 Check that the required binaries exist.
2513 @return: Problem description if something is wrong, C{None} otherwise
2517 # FIXME: this is the global kvm binary, but the actual path can be
2518 # customized as an hv parameter; we should use the nodegroup's
2519 # default kvm path parameter here.
2520 if not os.path.exists(constants.KVM_PATH):
2521 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2522 if not os.path.exists(constants.SOCAT_PATH):
2523 msgs.append("The socat binary ('%s') does not exist" %
2524 constants.SOCAT_PATH)
2526 return self._FormatVerifyResults(msgs)
2529 def CheckParameterSyntax(cls, hvparams):
2530 """Check the given parameters for validity.
2532 @type hvparams: dict
2533 @param hvparams: dictionary with parameter names/value
2534 @raise errors.HypervisorError: when a parameter is not valid
2537 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2539 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2541 if not hvparams[constants.HV_ROOT_PATH]:
2542 raise errors.HypervisorError("Need a root partition for the instance,"
2543 " if a kernel is defined")
2545 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2546 not hvparams[constants.HV_VNC_X509]):
2547 raise errors.HypervisorError("%s must be defined, if %s is" %
2548 (constants.HV_VNC_X509,
2549 constants.HV_VNC_X509_VERIFY))
2551 if hvparams[constants.HV_SERIAL_CONSOLE]:
2552 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2553 valid_speeds = constants.VALID_SERIAL_SPEEDS
2554 if not serial_speed or serial_speed not in valid_speeds:
2555 raise errors.HypervisorError("Invalid serial console speed, must be"
2557 utils.CommaJoin(valid_speeds))
2559 boot_order = hvparams[constants.HV_BOOT_ORDER]
2560 if (boot_order == constants.HT_BO_CDROM and
2561 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2562 raise errors.HypervisorError("Cannot boot from cdrom without an"
2565 security_model = hvparams[constants.HV_SECURITY_MODEL]
2566 if security_model == constants.HT_SM_USER:
2567 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2568 raise errors.HypervisorError("A security domain (user to run kvm as)"
2569 " must be specified")
2570 elif (security_model == constants.HT_SM_NONE or
2571 security_model == constants.HT_SM_POOL):
2572 if hvparams[constants.HV_SECURITY_DOMAIN]:
2573 raise errors.HypervisorError("Cannot have a security domain when the"
2574 " security model is 'none' or 'pool'")
2576 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2577 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2579 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2580 # if an IP version is specified, the spice_bind parameter must be an
2582 if (netutils.IP4Address.IsValid(spice_bind) and
2583 spice_ip_version != constants.IP4_VERSION):
2584 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2585 " the specified IP version is %s" %
2586 (spice_bind, spice_ip_version))
2588 if (netutils.IP6Address.IsValid(spice_bind) and
2589 spice_ip_version != constants.IP6_VERSION):
2590 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2591 " the specified IP version is %s" %
2592 (spice_bind, spice_ip_version))
2594 # All the other SPICE parameters depend on spice_bind being set. Raise an
2595 # error if any of them is set without it.
2596 for param in _SPICE_ADDITIONAL_PARAMS:
2598 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2599 (param, constants.HV_KVM_SPICE_BIND))
2602 def ValidateParameters(cls, hvparams):
2603 """Check the given parameters for validity.
2605 @type hvparams: dict
2606 @param hvparams: dictionary with parameter names/value
2607 @raise errors.HypervisorError: when a parameter is not valid
2610 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2612 kvm_path = hvparams[constants.HV_KVM_PATH]
2614 security_model = hvparams[constants.HV_SECURITY_MODEL]
2615 if security_model == constants.HT_SM_USER:
2616 username = hvparams[constants.HV_SECURITY_DOMAIN]
2618 pwd.getpwnam(username)
2620 raise errors.HypervisorError("Unknown security domain user %s"
2623 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2625 # only one of VNC and SPICE can be used currently.
2626 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2627 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2628 " only one of them can be used at a"
2631 # check that KVM supports SPICE
2632 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2633 if not cls._SPICE_RE.search(kvmhelp):
2634 raise errors.HypervisorError("SPICE is configured, but it is not"
2635 " supported according to 'kvm --help'")
2637 # if spice_bind is not an IP address, it must be a valid interface
2638 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2639 netutils.IP6Address.IsValid(spice_bind))
2640 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2641 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2642 " a valid IP address or interface name" %
2643 constants.HV_KVM_SPICE_BIND)
2645 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2647 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2648 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2649 raise errors.HypervisorError("Unsupported machine version: %s" %
2653 def PowercycleNode(cls):
2654 """KVM powercycle, just a wrapper over Linux powercycle.
2657 cls.LinuxPowercycle()