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)
117 _MIGRATION_CAPS_DELIM = ":"
120 def _GenerateDeviceKVMId(dev_type, dev, idx=None):
121 """Helper function to generate a unique device name used by KVM
123 QEMU monitor commands use names to identify devices. Here we use their pci
124 slot and a part of their UUID to name them. dev.pci might be None for old
125 devices in the cluster.
127 @type dev_type: sting
128 @param dev_type: device type of param dev
129 @type dev: L{objects.Disk} or L{objects.NIC}
130 @param dev: the device object for which we generate a kvm name
131 @raise errors.HotplugError: in case a device has no pci slot (old devices)
135 # proper device id - available in latest Ganeti versions
136 if dev.pci and dev.uuid:
137 return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
139 # dummy device id - returned only to _GenerateKVMBlockDevicesOptions
140 # This enables -device option for paravirtual disk_type
142 return "%s-%d" % (dev_type.lower(), idx)
144 raise errors.HotplugError("Hotplug is not supported for devices"
145 " without UUID or PCI info")
148 def _GetFreeSlot(slots, slot=None, reserve=False):
149 """Helper method to get first available slot in a bitarray
151 @type slots: bitarray
152 @param slots: the bitarray to operate on
154 @param slot: if given we check whether the slot is free
155 @type reserve: boolean
156 @param reserve: whether to reserve the first available slot or not
157 @return: the idx of the (first) available slot
158 @raise errors.HotplugError: If all slots in a bitarray are occupied
159 or the given slot is not free.
163 assert slot < len(slots)
165 raise errors.HypervisorError("Slots %d occupied" % slot)
168 avail = slots.search(_AVAILABLE_PCI_SLOT, 1)
170 raise errors.HypervisorError("All slots occupied")
180 def _GetExistingDeviceInfo(dev_type, device, runtime):
181 """Helper function to get an existing device inside the runtime file
183 Used when an instance is running. Load kvm runtime file and search
184 for a device based on its type and uuid.
186 @type dev_type: sting
187 @param dev_type: device type of param dev
188 @type device: L{objects.Disk} or L{objects.NIC}
189 @param device: the device object for which we generate a kvm name
190 @type runtime: tuple (cmd, nics, hvparams, disks)
191 @param runtime: the runtime data to search for the device
192 @raise errors.HotplugError: in case the requested device does not
193 exist (e.g. device has been added without --hotplug option) or
194 device info has not pci slot (e.g. old devices in the cluster)
197 index = _DEVICE_RUNTIME_INDEX[dev_type]
198 found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
200 raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
201 (dev_type, device.uuid))
206 def _UpgradeSerializedRuntime(serialized_runtime):
207 """Upgrade runtime data
209 Remove any deprecated fields or change the format of the data.
210 The runtime files are not upgraded when Ganeti is upgraded, so the required
211 modification have to be performed here.
213 @type serialized_runtime: string
214 @param serialized_runtime: raw text data read from actual runtime file
215 @return: (cmd, nic dicts, hvparams, bdev dicts)
219 loaded_runtime = serializer.Load(serialized_runtime)
220 kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
221 if len(loaded_runtime) >= 4:
222 serialized_disks = loaded_runtime[3]
224 serialized_disks = []
226 for nic in serialized_nics:
227 # Add a dummy uuid slot if an pre-2.8 NIC is found
228 if "uuid" not in nic:
229 nic["uuid"] = utils.NewUUID()
231 return kvm_cmd, serialized_nics, hvparams, serialized_disks
234 def _AnalyzeSerializedRuntime(serialized_runtime):
235 """Return runtime entries for a serialized runtime file
237 @type serialized_runtime: string
238 @param serialized_runtime: raw text data read from actual runtime file
239 @return: (cmd, nics, hvparams, bdevs)
243 kvm_cmd, serialized_nics, hvparams, serialized_disks = \
244 _UpgradeSerializedRuntime(serialized_runtime)
245 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
246 kvm_disks = [(objects.Disk.FromDict(sdisk), link)
247 for sdisk, link in serialized_disks]
249 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
252 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
253 """Retrieves supported TUN features from file descriptor.
255 @see: L{_ProbeTapVnetHdr}
258 req = struct.pack("I", 0)
260 buf = _ioctl(fd, TUNGETFEATURES, req)
261 except EnvironmentError, err:
262 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
265 (flags, ) = struct.unpack("I", buf)
269 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
270 """Check whether to enable the IFF_VNET_HDR flag.
272 To do this, _all_ of the following conditions must be met:
273 1. TUNGETFEATURES ioctl() *must* be implemented
274 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
275 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
276 drivers/net/tun.c there is no way to test this until after the tap device
277 has been created using TUNSETIFF, and there is no way to change the
278 IFF_VNET_HDR flag after creating the interface, catch-22! However both
279 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
280 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
283 @param fd: the file descriptor of /dev/net/tun
286 flags = _features_fn(fd)
292 result = bool(flags & IFF_VNET_HDR)
295 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
300 def _OpenTap(vnet_hdr=True):
301 """Open a new tap device and return its file descriptor.
303 This is intended to be used by a qemu-type hypervisor together with the -net
304 tap,fd=<fd> command line parameter.
306 @type vnet_hdr: boolean
307 @param vnet_hdr: Enable the VNET Header
308 @return: (ifname, tapfd)
313 tapfd = os.open("/dev/net/tun", os.O_RDWR)
314 except EnvironmentError:
315 raise errors.HypervisorError("Failed to open /dev/net/tun")
317 flags = IFF_TAP | IFF_NO_PI
319 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
320 flags |= IFF_VNET_HDR
322 # The struct ifreq ioctl request (see netdevice(7))
323 ifr = struct.pack("16sh", "", flags)
326 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
327 except EnvironmentError, err:
328 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
331 # Get the interface name from the ioctl
332 ifname = struct.unpack("16sh", res)[0].strip("\x00")
333 return (ifname, tapfd)
337 """QEMU Messaging Protocol (QMP) message.
340 def __init__(self, data):
341 """Creates a new QMP message based on the passed data.
344 if not isinstance(data, dict):
345 raise TypeError("QmpMessage must be initialized with a dict")
349 def __getitem__(self, field_name):
350 """Get the value of the required field if present, or None.
352 Overrides the [] operator to provide access to the message data,
353 returning None if the required item is not in the message
354 @return: the value of the field_name field, or None if field_name
355 is not contained in the message
358 return self.data.get(field_name, None)
360 def __setitem__(self, field_name, field_value):
361 """Set the value of the required field_name to field_value.
364 self.data[field_name] = field_value
367 def BuildFromJsonString(json_string):
368 """Build a QmpMessage from a JSON encoded string.
370 @type json_string: str
371 @param json_string: JSON string representing the message
372 @rtype: L{QmpMessage}
373 @return: a L{QmpMessage} built from json_string
377 data = serializer.LoadJson(json_string)
378 return QmpMessage(data)
381 # The protocol expects the JSON object to be sent as a single line.
382 return serializer.DumpJson(self.data)
384 def __eq__(self, other):
385 # When comparing two QmpMessages, we are interested in comparing
386 # their internal representation of the message data
387 return self.data == other.data
390 class MonitorSocket(object):
393 def __init__(self, monitor_filename):
394 """Instantiates the MonitorSocket object.
396 @type monitor_filename: string
397 @param monitor_filename: the filename of the UNIX raw socket on which the
398 monitor (QMP or simple one) is listening
401 self.monitor_filename = monitor_filename
402 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
403 # We want to fail if the server doesn't send a complete message
404 # in a reasonable amount of time
405 self.sock.settimeout(self._SOCKET_TIMEOUT)
406 self._connected = False
408 def _check_socket(self):
411 sock_stat = os.stat(self.monitor_filename)
412 except EnvironmentError, err:
413 if err.errno == errno.ENOENT:
414 raise errors.HypervisorError("No monitor socket found")
416 raise errors.HypervisorError("Error checking monitor socket: %s",
417 utils.ErrnoOrStr(err))
418 if not stat.S_ISSOCK(sock_stat.st_mode):
419 raise errors.HypervisorError("Monitor socket is not a socket")
421 def _check_connection(self):
422 """Make sure that the connection is established.
425 if not self._connected:
426 raise errors.ProgrammerError("To use a MonitorSocket you need to first"
427 " invoke connect() on it")
430 """Connects to the monitor.
432 Connects to the UNIX socket
434 @raise errors.HypervisorError: when there are communication errors
438 raise errors.ProgrammerError("Cannot connect twice")
442 # Check file existance/stuff
444 self.sock.connect(self.monitor_filename)
445 except EnvironmentError:
446 raise errors.HypervisorError("Can't connect to qmp socket")
447 self._connected = True
452 It cannot be used after this call.
458 class QmpConnection(MonitorSocket):
459 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
462 _FIRST_MESSAGE_KEY = "QMP"
465 _RETURN_KEY = RETURN_KEY = "return"
466 _ACTUAL_KEY = ACTUAL_KEY = "actual"
467 _ERROR_CLASS_KEY = "class"
468 _ERROR_DESC_KEY = "desc"
469 _EXECUTE_KEY = "execute"
470 _ARGUMENTS_KEY = "arguments"
471 _CAPABILITIES_COMMAND = "qmp_capabilities"
472 _MESSAGE_END_TOKEN = "\r\n"
474 def __init__(self, monitor_filename):
475 super(QmpConnection, self).__init__(monitor_filename)
479 """Connects to the QMP monitor.
481 Connects to the UNIX socket and makes sure that we can actually send and
482 receive data to the kvm instance via QMP.
484 @raise errors.HypervisorError: when there are communication errors
485 @raise errors.ProgrammerError: when there are data serialization errors
488 super(QmpConnection, self).connect()
489 # Check if we receive a correct greeting message from the server
490 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
491 greeting = self._Recv()
492 if not greeting[self._FIRST_MESSAGE_KEY]:
493 self._connected = False
494 raise errors.HypervisorError("kvm: QMP communication error (wrong"
497 # This is needed because QMP can return more than one greetings
498 # see https://groups.google.com/d/msg/ganeti-devel/gZYcvHKDooU/SnukC8dgS5AJ
501 # Let's put the monitor in command mode using the qmp_capabilities
502 # command, or else no command will be executable.
503 # (As per the QEMU Protocol Specification 0.1 - section 4)
504 self.Execute(self._CAPABILITIES_COMMAND)
506 def _ParseMessage(self, buf):
507 """Extract and parse a QMP message from the given buffer.
509 Seeks for a QMP message in the given buf. If found, it parses it and
510 returns it together with the rest of the characters in the buf.
511 If no message is found, returns None and the whole buffer.
513 @raise errors.ProgrammerError: when there are data serialization errors
517 # Check if we got the message end token (CRLF, as per the QEMU Protocol
518 # Specification 0.1 - Section 2.1.1)
519 pos = buf.find(self._MESSAGE_END_TOKEN)
522 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
523 except Exception, err:
524 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
527 return (message, buf)
530 """Receives a message from QMP and decodes the received JSON object.
533 @return: the received message
534 @raise errors.HypervisorError: when there are communication errors
535 @raise errors.ProgrammerError: when there are data serialization errors
538 self._check_connection()
540 # Check if there is already a message in the buffer
541 (message, self._buf) = self._ParseMessage(self._buf)
545 recv_buffer = StringIO.StringIO(self._buf)
546 recv_buffer.seek(len(self._buf))
549 data = self.sock.recv(4096)
552 recv_buffer.write(data)
554 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
558 except socket.timeout, err:
559 raise errors.HypervisorError("Timeout while receiving a QMP message: "
561 except socket.error, err:
562 raise errors.HypervisorError("Unable to receive data from KVM using the"
563 " QMP protocol: %s" % err)
565 def _Send(self, message):
566 """Encodes and sends a message to KVM using QMP.
568 @type message: QmpMessage
569 @param message: message to send to KVM
570 @raise errors.HypervisorError: when there are communication errors
571 @raise errors.ProgrammerError: when there are data serialization errors
574 self._check_connection()
576 message_str = str(message)
577 except Exception, err:
578 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
581 self.sock.sendall(message_str)
582 except socket.timeout, err:
583 raise errors.HypervisorError("Timeout while sending a QMP message: "
584 "%s (%s)" % (err.string, err.errno))
585 except socket.error, err:
586 raise errors.HypervisorError("Unable to send data from KVM using the"
587 " QMP protocol: %s" % err)
589 def Execute(self, command, arguments=None):
590 """Executes a QMP command and returns the response of the server.
593 @param command: the command to execute
594 @type arguments: dict
595 @param arguments: dictionary of arguments to be passed to the command
597 @return: dictionary representing the received JSON object
598 @raise errors.HypervisorError: when there are communication errors
599 @raise errors.ProgrammerError: when there are data serialization errors
602 self._check_connection()
603 message = QmpMessage({self._EXECUTE_KEY: command})
605 message[self._ARGUMENTS_KEY] = arguments
608 # Events can occur between the sending of the command and the reception
609 # of the response, so we need to filter out messages with the event key.
611 response = self._Recv()
612 err = response[self._ERROR_KEY]
614 raise errors.HypervisorError("kvm: error executing the %s"
615 " command: %s (%s):" %
617 err[self._ERROR_DESC_KEY],
618 err[self._ERROR_CLASS_KEY]))
620 elif not response[self._EVENT_KEY]:
624 class KVMHypervisor(hv_base.BaseHypervisor):
625 """KVM hypervisor interface
630 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
631 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
632 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
633 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
634 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
635 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
636 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
637 # KVM instances with chroot enabled are started in empty chroot directories.
638 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
639 # After an instance is stopped, its chroot directory is removed.
640 # If the chroot directory is not empty, it can't be removed.
641 # A non-empty chroot directory indicates a possible security incident.
642 # To support forensics, the non-empty chroot directory is quarantined in
643 # a separate directory, called 'chroot-quarantine'.
644 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
645 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
646 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
649 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
650 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
651 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
652 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
653 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
654 constants.HV_ACPI: hv_base.NO_CHECK,
655 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
656 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
657 constants.HV_VNC_BIND_ADDRESS:
658 (False, lambda x: (netutils.IP4Address.IsValid(x) or
659 utils.IsNormAbsPath(x)),
660 "The VNC bind address must be either a valid IP address or an absolute"
661 " pathname", None, None),
662 constants.HV_VNC_TLS: hv_base.NO_CHECK,
663 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
664 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
665 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
666 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
667 constants.HV_KVM_SPICE_IP_VERSION:
668 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
669 x in constants.VALID_IP_VERSIONS),
670 "The SPICE IP version should be 4 or 6",
672 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
673 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
675 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
676 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
678 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
679 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
681 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
682 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
684 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
685 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
686 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
687 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
688 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
689 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
690 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
691 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
692 constants.HV_BOOT_ORDER:
693 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
694 constants.HV_NIC_TYPE:
695 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
696 constants.HV_DISK_TYPE:
697 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
698 constants.HV_KVM_CDROM_DISK_TYPE:
699 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
700 constants.HV_USB_MOUSE:
701 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
702 constants.HV_KEYMAP: hv_base.NO_CHECK,
703 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
704 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
705 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
706 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
707 constants.HV_KVM_MIGRATION_CAPS: hv_base.NO_CHECK,
708 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
709 constants.HV_DISK_CACHE:
710 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
711 constants.HV_SECURITY_MODEL:
712 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
713 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
714 constants.HV_KVM_FLAG:
715 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
716 constants.HV_VHOST_NET: hv_base.NO_CHECK,
717 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
718 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
719 constants.HV_REBOOT_BEHAVIOR:
720 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
721 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
722 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
723 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
724 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
725 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
726 constants.HV_SOUNDHW: hv_base.NO_CHECK,
727 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
728 constants.HV_VGA: hv_base.NO_CHECK,
729 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
730 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
731 constants.HV_VNET_HDR: hv_base.NO_CHECK,
735 _VIRTIO_NET_PCI = "virtio-net-pci"
736 _VIRTIO_BLK_PCI = "virtio-blk-pci"
738 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
740 _MIGRATION_PROGRESS_RE = \
741 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
742 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
743 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
745 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
746 _MIGRATION_INFO_RETRY_DELAY = 2
748 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
750 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
751 _CPU_INFO_CMD = "info cpus"
754 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
755 _CHECK_MACHINE_VERSION_RE = \
756 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
758 _QMP_RE = re.compile(r"^-qmp\s", re.M)
759 _SPICE_RE = re.compile(r"^-spice\s", re.M)
760 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
761 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
762 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
763 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
764 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
765 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
766 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
767 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
768 # match -drive.*boot=on|off on different lines, but in between accept only
769 # dashes not preceeded by a new line (which would mean another option
770 # different than -drive is starting)
771 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
773 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
774 _INFO_PCI_CMD = "info pci"
775 _FIND_PCI_DEVICE_RE = \
776 staticmethod(lambda pci, devid:
777 re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' % (pci, devid),
781 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
782 _INFO_VERSION_CMD = "info version"
784 # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller
785 _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000"
786 _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"]
791 ANCILLARY_FILES_OPT = [
795 # Supported kvm options to get output from
796 _KVMOPT_HELP = "help"
797 _KVMOPT_MLIST = "mlist"
798 _KVMOPT_DEVICELIST = "devicelist"
800 # Command to execute to get the output from kvm, and whether to
801 # accept the output even on failure.
803 _KVMOPT_HELP: (["--help"], False),
804 _KVMOPT_MLIST: (["-M", "?"], False),
805 _KVMOPT_DEVICELIST: (["-device", "?"], True),
809 hv_base.BaseHypervisor.__init__(self)
810 # Let's make sure the directories we need exist, even if the RUN_DIR lives
811 # in a tmpfs filesystem or has been otherwise wiped out.
812 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
813 utils.EnsureDirs(dirs)
816 def _InstancePidFile(cls, instance_name):
817 """Returns the instance pidfile.
820 return utils.PathJoin(cls._PIDS_DIR, instance_name)
823 def _InstanceUidFile(cls, instance_name):
824 """Returns the instance uidfile.
827 return utils.PathJoin(cls._UIDS_DIR, instance_name)
830 def _InstancePidInfo(cls, pid):
831 """Check pid file for instance information.
833 Check that a pid file is associated with an instance, and retrieve
834 information from its command line.
836 @type pid: string or int
837 @param pid: process id of the instance to check
839 @return: (instance_name, memory, vcpus)
840 @raise errors.HypervisorError: when an instance cannot be found
843 alive = utils.IsProcessAlive(pid)
845 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
847 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
849 cmdline = utils.ReadFile(cmdline_file)
850 except EnvironmentError, err:
851 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
858 arg_list = cmdline.split("\x00")
860 arg = arg_list.pop(0)
862 instance = arg_list.pop(0)
864 memory = int(arg_list.pop(0))
866 vcpus = int(arg_list.pop(0).split(",")[0])
869 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
872 return (instance, memory, vcpus)
874 def _InstancePidAlive(self, instance_name):
875 """Returns the instance pidfile, pid, and liveness.
877 @type instance_name: string
878 @param instance_name: instance name
880 @return: (pid file name, pid, liveness)
883 pidfile = self._InstancePidFile(instance_name)
884 pid = utils.ReadPidFile(pidfile)
888 cmd_instance = self._InstancePidInfo(pid)[0]
889 alive = (cmd_instance == instance_name)
890 except errors.HypervisorError:
893 return (pidfile, pid, alive)
895 def _CheckDown(self, instance_name):
896 """Raises an error unless the given instance is down.
899 alive = self._InstancePidAlive(instance_name)[2]
901 raise errors.HypervisorError("Failed to start instance %s: %s" %
902 (instance_name, "already running"))
905 def _InstanceMonitor(cls, instance_name):
906 """Returns the instance monitor socket name
909 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
912 def _InstanceSerial(cls, instance_name):
913 """Returns the instance serial socket name
916 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
919 def _InstanceQmpMonitor(cls, instance_name):
920 """Returns the instance serial QMP socket name
923 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
926 def _SocatUnixConsoleParams():
927 """Returns the correct parameters for socat
929 If we have a new-enough socat we can use raw mode with an escape character.
932 if constants.SOCAT_USE_ESCAPE:
933 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
935 return "echo=0,icanon=0"
938 def _InstanceKVMRuntime(cls, instance_name):
939 """Returns the instance KVM runtime filename
942 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
945 def _InstanceChrootDir(cls, instance_name):
946 """Returns the name of the KVM chroot dir of the instance
949 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
952 def _InstanceNICDir(cls, instance_name):
953 """Returns the name of the directory holding the tap device files for a
957 return utils.PathJoin(cls._NICS_DIR, instance_name)
960 def _InstanceNICFile(cls, instance_name, seq_or_uuid):
961 """Returns the name of the file containing the tap device for a given NIC
964 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq_or_uuid))
967 def _GetInstanceNICTap(cls, instance_name, nic):
968 """Returns the tap for the corresponding nic
970 Search for tap file named after NIC's uuid.
971 For old instances without uuid indexed tap files returns nothing.
975 return utils.ReadFile(cls._InstanceNICFile(instance_name, nic.uuid))
976 except EnvironmentError:
980 def _WriteInstanceNICFiles(cls, instance_name, seq, nic, tap):
981 """Write tap name to both instance NIC files
984 for ident in [seq, nic.uuid]:
985 utils.WriteFile(cls._InstanceNICFile(instance_name, ident), data=tap)
988 def _RemoveInstanceNICFiles(cls, instance_name, seq, nic):
989 """Write tap name to both instance NIC files
992 for ident in [seq, nic.uuid]:
993 utils.RemoveFile(cls._InstanceNICFile(instance_name, ident))
996 def _InstanceKeymapFile(cls, instance_name):
997 """Returns the name of the file containing the keymap for a given instance
1000 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
1003 def _TryReadUidFile(cls, uid_file):
1004 """Try to read a uid file
1007 if os.path.exists(uid_file):
1009 uid = int(utils.ReadOneLineFile(uid_file))
1011 except EnvironmentError:
1012 logging.warning("Can't read uid file", exc_info=True)
1013 except (TypeError, ValueError):
1014 logging.warning("Can't parse uid file contents", exc_info=True)
1018 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
1019 """Removes an instance's rutime sockets/files/dirs.
1022 # This takes info from NICDir and RuntimeFile
1023 cls._UnconfigureInstanceNICs(instance_name)
1024 utils.RemoveFile(pidfile)
1025 utils.RemoveFile(cls._InstanceMonitor(instance_name))
1026 utils.RemoveFile(cls._InstanceSerial(instance_name))
1027 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
1028 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
1029 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
1030 uid_file = cls._InstanceUidFile(instance_name)
1031 uid = cls._TryReadUidFile(uid_file)
1032 utils.RemoveFile(uid_file)
1034 uidpool.ReleaseUid(uid)
1036 shutil.rmtree(cls._InstanceNICDir(instance_name))
1037 except OSError, err:
1038 if err.errno != errno.ENOENT:
1041 chroot_dir = cls._InstanceChrootDir(instance_name)
1042 utils.RemoveDir(chroot_dir)
1043 except OSError, err:
1044 if err.errno == errno.ENOTEMPTY:
1045 # The chroot directory is expected to be empty, but it isn't.
1046 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
1049 utils.TimestampForFilename()))
1050 logging.warning("The chroot directory of instance %s can not be"
1051 " removed as it is not empty. Moving it to the"
1052 " quarantine instead. Please investigate the"
1053 " contents (%s) and clean up manually",
1054 instance_name, new_chroot_dir)
1055 utils.RenameFile(chroot_dir, new_chroot_dir)
1060 def _CreateNICEnv(instance_name, nic, tap, seq=None, instance_tags=None):
1061 """Create environment variables for a specific NIC
1063 This is needed during NIC ifup/ifdown scripts.
1064 Since instance tags may change during NIC creation and removal
1065 and because during cleanup instance object is not available we
1066 pass them only upon NIC creation (instance startup/NIC hot-plugging).
1070 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1071 "INSTANCE": instance_name,
1073 "MODE": nic.nicparams[constants.NIC_MODE],
1074 "INTERFACE_UUID": nic.uuid,
1078 env["TAGS"] = " ".join(instance_tags)
1080 # This should always be available except for old instances in the
1081 # cluster without uuid indexed tap files.
1083 env["INTERFACE"] = tap
1086 env["INTERFACE_INDEX"] = str(seq)
1092 env["INTERFACE_NAME"] = nic.name
1094 if nic.nicparams[constants.NIC_LINK]:
1095 env["LINK"] = nic.nicparams[constants.NIC_LINK]
1098 n = objects.Network.FromDict(nic.netinfo)
1099 env.update(n.HooksDict())
1101 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1102 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1107 def _ConfigureNIC(cls, instance, seq, nic, tap):
1108 """Run the network configuration script for a specified NIC
1110 @param instance: instance we're acting on
1111 @type instance: instance object
1112 @param seq: nic sequence number
1114 @param nic: nic we're acting on
1115 @type nic: nic object
1116 @param tap: the host's tap interface this NIC corresponds to
1120 env = cls._CreateNICEnv(instance.name, nic, tap, seq, instance.GetTags())
1121 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1123 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1124 " network configuration script output: %s" %
1125 (tap, result.fail_reason, result.output))
1128 def _UnconfigureNic(cls, instance_name, nic, only_local=True):
1129 """Run ifdown script for a specific NIC
1131 This is executed during instance cleanup and NIC hot-unplug
1133 @param instance: instance we're acting on
1134 @type instance: instance object
1135 @param nic: nic we're acting on
1136 @type nic: nic object
1137 @param localy: whether ifdown script should reset global conf (dns) or not
1138 @type localy: boolean
1141 tap = cls._GetInstanceNICTap(instance_name, nic)
1142 env = cls._CreateNICEnv(instance_name, nic, tap)
1143 arg2 = str(only_local).lower()
1144 result = utils.RunCmd([pathutils.KVM_IFDOWN, tap, arg2], env=env)
1146 raise errors.HypervisorError("Failed to unconfigure interface %s: %s;"
1147 " network configuration script output: %s" %
1148 (tap, result.fail_reason, result.output))
1151 def _VerifyAffinityPackage():
1152 if affinity is None:
1153 raise errors.HypervisorError("affinity Python package not"
1154 " found; cannot use CPU pinning under KVM")
1157 def _BuildAffinityCpuMask(cpu_list):
1158 """Create a CPU mask suitable for sched_setaffinity from a list of
1161 See man taskset for more info on sched_setaffinity masks.
1162 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1164 @type cpu_list: list of int
1165 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1167 @return: a bit mask of CPU affinities
1170 if cpu_list == constants.CPU_PINNING_OFF:
1171 return constants.CPU_PINNING_ALL_KVM
1173 return sum(2 ** cpu for cpu in cpu_list)
1176 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1177 """Change CPU affinity for running VM according to given CPU mask.
1179 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1180 @type cpu_mask: string
1181 @param process_id: process ID of KVM process. Used to pin entire VM
1183 @type process_id: int
1184 @param thread_dict: map of virtual CPUs to KVM thread IDs
1185 @type thread_dict: dict int:int
1188 # Convert the string CPU mask to a list of list of int's
1189 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1191 if len(cpu_list) == 1:
1192 all_cpu_mapping = cpu_list[0]
1193 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1194 # If CPU pinning has 1 entry that's "all", then do nothing
1197 # If CPU pinning has one non-all entry, map the entire VM to
1198 # one set of physical CPUs
1199 cls._VerifyAffinityPackage()
1200 affinity.set_process_affinity_mask(
1201 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1203 # The number of vCPUs mapped should match the number of vCPUs
1204 # reported by KVM. This was already verified earlier, so
1205 # here only as a sanity check.
1206 assert len(thread_dict) == len(cpu_list)
1207 cls._VerifyAffinityPackage()
1209 # For each vCPU, map it to the proper list of physical CPUs
1210 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1211 affinity.set_process_affinity_mask(thread_dict[i],
1212 cls._BuildAffinityCpuMask(vcpu))
1214 def _GetVcpuThreadIds(self, instance_name):
1215 """Get a mapping of vCPU no. to thread IDs for the instance
1217 @type instance_name: string
1218 @param instance_name: instance in question
1219 @rtype: dictionary of int:int
1220 @return: a dictionary mapping vCPU numbers to thread IDs
1224 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1225 for line in output.stdout.splitlines():
1226 match = self._CPU_INFO_RE.search(line)
1229 grp = map(int, match.groups())
1230 result[grp[0]] = grp[1]
1234 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1235 """Complete CPU pinning.
1237 @type instance_name: string
1238 @param instance_name: name of instance
1239 @type cpu_mask: string
1240 @param cpu_mask: CPU pinning mask as entered by user
1243 # Get KVM process ID, to be used if need to pin entire VM
1244 _, pid, _ = self._InstancePidAlive(instance_name)
1245 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1246 thread_dict = self._GetVcpuThreadIds(instance_name)
1247 # Run CPU pinning, based on configured mask
1248 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1250 def ListInstances(self):
1251 """Get the list of running instances.
1253 We can do this by listing our live instances directory and
1254 checking whether the associated kvm process is still alive.
1258 for name in os.listdir(self._PIDS_DIR):
1259 if self._InstancePidAlive(name)[2]:
1263 def GetInstanceInfo(self, instance_name):
1264 """Get instance properties.
1266 @type instance_name: string
1267 @param instance_name: the instance name
1268 @rtype: tuple of strings
1269 @return: (name, id, memory, vcpus, stat, times)
1272 _, pid, alive = self._InstancePidAlive(instance_name)
1276 _, memory, vcpus = self._InstancePidInfo(pid)
1281 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1283 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1284 # Will fail if ballooning is not enabled, but we can then just resort to
1286 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1287 memory = mem_bytes / 1048576
1288 except errors.HypervisorError:
1291 return (instance_name, pid, memory, vcpus, istat, times)
1293 def GetAllInstancesInfo(self):
1294 """Get properties of all instances.
1296 @return: list of tuples (name, id, memory, vcpus, stat, times)
1300 for name in os.listdir(self._PIDS_DIR):
1302 info = self.GetInstanceInfo(name)
1303 except errors.HypervisorError:
1304 # Ignore exceptions due to instances being shut down
1310 def _GenerateKVMBlockDevicesOptions(self, instance, up_hvp, kvm_disks,
1312 """Generate KVM options regarding instance's block devices.
1314 @type instance: L{objects.Instance}
1315 @param instance: the instance object
1317 @param up_hvp: the instance's runtime hypervisor parameters
1318 @type kvm_disks: list of tuples
1319 @param kvm_disks: list of tuples [(disk, link_name)..]
1320 @type kvmhelp: string
1321 @param kvmhelp: output of kvm --help
1322 @type devlist: string
1323 @param devlist: output of kvm -device ?
1325 @return: list of command line options eventually used by kvm executable
1328 kernel_path = up_hvp[constants.HV_KERNEL_PATH]
1332 boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1334 # whether this is an older KVM version that uses the boot=on flag
1336 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1339 device_driver = None
1340 disk_type = up_hvp[constants.HV_DISK_TYPE]
1341 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1342 if_val = ",if=%s" % self._VIRTIO
1344 if self._VIRTIO_BLK_RE.search(devlist):
1346 # will be passed in -device option as driver
1347 device_driver = self._VIRTIO_BLK_PCI
1348 except errors.HypervisorError, _:
1351 if_val = ",if=%s" % disk_type
1353 disk_cache = up_hvp[constants.HV_DISK_CACHE]
1354 if instance.disk_template in constants.DTS_EXT_MIRROR:
1355 if disk_cache != "none":
1356 # TODO: make this a hard error, instead of a silent overwrite
1357 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1358 " to prevent shared storage corruption on migration",
1360 cache_val = ",cache=none"
1361 elif disk_cache != constants.HT_CACHE_DEFAULT:
1362 cache_val = ",cache=%s" % disk_cache
1365 for idx, (cfdev, link_name) in enumerate(kvm_disks):
1366 if cfdev.mode != constants.DISK_RDWR:
1367 raise errors.HypervisorError("Instance has read-only disks which"
1368 " are not supported by KVM")
1369 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1372 dev_opts.extend(["-boot", "c"])
1374 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1375 boot_val = ",boot=on"
1377 # For ext we allow overriding disk_cache hypervisor params per disk
1378 disk_cache = cfdev.params.get("cache", None)
1380 cache_val = ",cache=%s" % disk_cache
1381 drive_val = "file=%s,format=raw%s%s%s" % \
1382 (link_name, if_val, boot_val, cache_val)
1385 # kvm_disks are the 4th entry of runtime file that did not exist in
1386 # the past. That means that cfdev should always have pci slot and
1387 # _GenerateDeviceKVMId() will not raise a exception.
1388 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK,
1390 drive_val += (",id=%s" % kvm_devid)
1392 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1393 dev_val = ("%s,drive=%s,id=%s" %
1394 (device_driver, kvm_devid, kvm_devid))
1396 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1397 dev_opts.extend(["-device", dev_val])
1399 # TODO: export disk geometry in IDISK_PARAMS
1400 heads = cfdev.params.get('heads', None)
1401 secs = cfdev.params.get('secs', None)
1403 nr_sectors = cfdev.size * 1024 * 1024 / 512
1404 cyls = nr_sectors / (int(heads) * int(secs))
1409 if cyls and heads and secs:
1410 drive_val += (",cyls=%d,heads=%d,secs=%d" %
1411 (cyls, int(heads), int(secs)))
1413 dev_opts.extend(["-drive", drive_val])
1417 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1419 """Generate KVM information to start an instance.
1421 @type kvmhelp: string
1422 @param kvmhelp: output of kvm --help
1423 @attention: this function must not have any side-effects; for
1424 example, it must not write to the filesystem, or read values
1425 from the current system the are expected to differ between
1426 nodes, since it is only run once at instance startup;
1427 actions/kvm arguments that can vary between systems should be
1428 done in L{_ExecuteKVMRuntime}
1431 # pylint: disable=R0912,R0914,R0915
1432 hvp = instance.hvparams
1433 self.ValidateParameters(hvp)
1435 pidfile = self._InstancePidFile(instance.name)
1436 kvm = hvp[constants.HV_KVM_PATH]
1438 # used just by the vnc server, if enabled
1439 kvm_cmd.extend(["-name", instance.name])
1440 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1442 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1443 if hvp[constants.HV_CPU_CORES]:
1444 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1445 if hvp[constants.HV_CPU_THREADS]:
1446 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1447 if hvp[constants.HV_CPU_SOCKETS]:
1448 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1450 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1452 kvm_cmd.extend(["-pidfile", pidfile])
1454 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1456 # As requested by music lovers
1457 if hvp[constants.HV_SOUNDHW]:
1458 soundhw = hvp[constants.HV_SOUNDHW]
1459 # For some reason only few sound devices require a PCI slot
1460 # while the Audio controller *must* be in slot 3.
1461 # That's why we bridge this option early in command line
1462 if soundhw in self._SOUNDHW_WITH_PCI_SLOT:
1463 _ = _GetFreeSlot(pci_reservations, reserve=True)
1464 kvm_cmd.extend(["-soundhw", soundhw])
1466 if hvp[constants.HV_DISK_TYPE] == constants.HT_DISK_SCSI:
1467 # The SCSI controller requires another PCI slot.
1468 _ = _GetFreeSlot(pci_reservations, reserve=True)
1470 # Add id to ballon and place to the first available slot (3 or 4)
1471 addr = _GetFreeSlot(pci_reservations, reserve=True)
1472 pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1473 kvm_cmd.extend(["-balloon", "virtio,id=balloon%s" % pci_info])
1474 kvm_cmd.extend(["-daemonize"])
1475 if not instance.hvparams[constants.HV_ACPI]:
1476 kvm_cmd.extend(["-no-acpi"])
1477 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1478 constants.INSTANCE_REBOOT_EXIT:
1479 kvm_cmd.extend(["-no-reboot"])
1481 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1483 mversion = self._GetDefaultMachineVersion(kvm)
1484 if self._MACHINE_RE.search(kvmhelp):
1485 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1486 # extra hypervisor parameters. We should also investigate whether and how
1487 # shadow_mem should be considered for the resource model.
1488 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1489 specprop = ",accel=kvm"
1492 machinespec = "%s%s" % (mversion, specprop)
1493 kvm_cmd.extend(["-machine", machinespec])
1495 kvm_cmd.extend(["-M", mversion])
1496 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1497 self._ENABLE_KVM_RE.search(kvmhelp)):
1498 kvm_cmd.extend(["-enable-kvm"])
1499 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1500 self._DISABLE_KVM_RE.search(kvmhelp)):
1501 kvm_cmd.extend(["-disable-kvm"])
1503 kernel_path = hvp[constants.HV_KERNEL_PATH]
1505 boot_cdrom = boot_floppy = boot_network = False
1507 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1508 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1509 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1512 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1515 kvm_cmd.extend(["-boot", "n"])
1517 # whether this is an older KVM version that uses the boot=on flag
1519 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1521 disk_type = hvp[constants.HV_DISK_TYPE]
1523 #Now we can specify a different device type for CDROM devices.
1524 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1525 if not cdrom_disk_type:
1526 cdrom_disk_type = disk_type
1528 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1530 options = ",format=raw,media=cdrom"
1531 # set cdrom 'if' type
1533 actual_cdrom_type = constants.HT_DISK_IDE
1534 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1535 actual_cdrom_type = "virtio"
1537 actual_cdrom_type = cdrom_disk_type
1538 if_val = ",if=%s" % actual_cdrom_type
1539 # set boot flag, if needed
1542 kvm_cmd.extend(["-boot", "d"])
1544 boot_val = ",boot=on"
1545 # and finally build the entire '-drive' value
1546 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1547 kvm_cmd.extend(["-drive", drive_val])
1549 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1551 options = ",format=raw,media=cdrom"
1552 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1553 if_val = ",if=virtio"
1555 if_val = ",if=%s" % cdrom_disk_type
1556 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1557 kvm_cmd.extend(["-drive", drive_val])
1559 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1561 options = ",format=raw,media=disk"
1563 kvm_cmd.extend(["-boot", "a"])
1564 options = "%s,boot=on" % options
1565 if_val = ",if=floppy"
1566 options = "%s%s" % (options, if_val)
1567 drive_val = "file=%s%s" % (floppy_image, options)
1568 kvm_cmd.extend(["-drive", drive_val])
1571 kvm_cmd.extend(["-kernel", kernel_path])
1572 initrd_path = hvp[constants.HV_INITRD_PATH]
1574 kvm_cmd.extend(["-initrd", initrd_path])
1575 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1576 hvp[constants.HV_KERNEL_ARGS]]
1577 if hvp[constants.HV_SERIAL_CONSOLE]:
1578 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1579 root_append.append("console=ttyS0,%s" % serial_speed)
1580 kvm_cmd.extend(["-append", " ".join(root_append)])
1582 mem_path = hvp[constants.HV_MEM_PATH]
1584 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1586 monitor_dev = ("unix:%s,server,nowait" %
1587 self._InstanceMonitor(instance.name))
1588 kvm_cmd.extend(["-monitor", monitor_dev])
1589 if hvp[constants.HV_SERIAL_CONSOLE]:
1590 serial_dev = ("unix:%s,server,nowait" %
1591 self._InstanceSerial(instance.name))
1592 kvm_cmd.extend(["-serial", serial_dev])
1594 kvm_cmd.extend(["-serial", "none"])
1596 mouse_type = hvp[constants.HV_USB_MOUSE]
1597 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1598 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1599 spice_ip_version = None
1601 kvm_cmd.extend(["-usb"])
1604 kvm_cmd.extend(["-usbdevice", mouse_type])
1605 elif vnc_bind_address:
1606 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1608 if vnc_bind_address:
1609 if netutils.IP4Address.IsValid(vnc_bind_address):
1610 if instance.network_port > constants.VNC_BASE_PORT:
1611 display = instance.network_port - constants.VNC_BASE_PORT
1612 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1613 vnc_arg = ":%d" % (display)
1615 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1617 logging.error("Network port is not a valid VNC display (%d < %d),"
1618 " not starting VNC",
1619 instance.network_port, constants.VNC_BASE_PORT)
1622 # Only allow tls and other option when not binding to a file, for now.
1623 # kvm/qemu gets confused otherwise about the filename to use.
1625 if hvp[constants.HV_VNC_TLS]:
1626 vnc_append = "%s,tls" % vnc_append
1627 if hvp[constants.HV_VNC_X509_VERIFY]:
1628 vnc_append = "%s,x509verify=%s" % (vnc_append,
1629 hvp[constants.HV_VNC_X509])
1630 elif hvp[constants.HV_VNC_X509]:
1631 vnc_append = "%s,x509=%s" % (vnc_append,
1632 hvp[constants.HV_VNC_X509])
1633 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1634 vnc_append = "%s,password" % vnc_append
1636 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1639 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1641 kvm_cmd.extend(["-vnc", vnc_arg])
1643 # FIXME: this is wrong here; the iface ip address differs
1644 # between systems, so it should be done in _ExecuteKVMRuntime
1645 if netutils.IsValidInterface(spice_bind):
1646 # The user specified a network interface, we have to figure out the IP
1648 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1649 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1651 # if the user specified an IP version and the interface does not
1652 # have that kind of IP addresses, throw an exception
1653 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1654 if not addresses[spice_ip_version]:
1655 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1656 " for %s" % (spice_ip_version,
1659 # the user did not specify an IP version, we have to figure it out
1660 elif (addresses[constants.IP4_VERSION] and
1661 addresses[constants.IP6_VERSION]):
1662 # we have both ipv4 and ipv6, let's use the cluster default IP
1664 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1665 spice_ip_version = \
1666 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1667 elif addresses[constants.IP4_VERSION]:
1668 spice_ip_version = constants.IP4_VERSION
1669 elif addresses[constants.IP6_VERSION]:
1670 spice_ip_version = constants.IP6_VERSION
1672 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1673 " for %s" % (spice_bind))
1675 spice_address = addresses[spice_ip_version][0]
1678 # spice_bind is known to be a valid IP address, because
1679 # ValidateParameters checked it.
1680 spice_address = spice_bind
1682 spice_arg = "addr=%s" % spice_address
1683 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1684 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1685 (spice_arg, instance.network_port,
1686 pathutils.SPICE_CACERT_FILE))
1687 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1688 (spice_arg, pathutils.SPICE_CERT_FILE,
1689 pathutils.SPICE_CERT_FILE))
1690 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1692 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1694 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1696 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1697 spice_arg = "%s,disable-ticketing" % spice_arg
1699 if spice_ip_version:
1700 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1702 # Image compression options
1703 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1704 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1705 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1707 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1709 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1711 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1713 # Video stream detection
1714 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1716 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1718 # Audio compression, by default in qemu-kvm it is on
1719 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1720 spice_arg = "%s,playback-compression=off" % spice_arg
1721 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1722 spice_arg = "%s,agent-mouse=off" % spice_arg
1724 # Enable the spice agent communication channel between the host and the
1726 addr = _GetFreeSlot(pci_reservations, reserve=True)
1727 pci_info = ",bus=pci.0,addr=%s" % hex(addr)
1728 kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice%s" % pci_info])
1731 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1733 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1735 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1736 kvm_cmd.extend(["-spice", spice_arg])
1739 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1740 # also works in earlier versions though (tested with 1.1 and 1.3)
1741 if self._DISPLAY_RE.search(kvmhelp):
1742 kvm_cmd.extend(["-display", "none"])
1744 kvm_cmd.extend(["-nographic"])
1746 if hvp[constants.HV_USE_LOCALTIME]:
1747 kvm_cmd.extend(["-localtime"])
1749 if hvp[constants.HV_KVM_USE_CHROOT]:
1750 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1752 # Add qemu-KVM -cpu param
1753 if hvp[constants.HV_CPU_TYPE]:
1754 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1756 # Pass a -vga option if requested, or if spice is used, for backwards
1758 if hvp[constants.HV_VGA]:
1759 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1761 kvm_cmd.extend(["-vga", "qxl"])
1763 # Various types of usb devices, comma separated
1764 if hvp[constants.HV_USB_DEVICES]:
1765 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1766 kvm_cmd.extend(["-usbdevice", dev])
1768 if hvp[constants.HV_KVM_EXTRA]:
1769 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1772 for disk, link_name in block_devices:
1773 disk.pci = _GetFreeSlot(pci_reservations, disk.pci, True)
1774 kvm_disks.append((disk, link_name))
1777 for nic in instance.nics:
1778 nic.pci = _GetFreeSlot(pci_reservations, nic.pci, True)
1779 kvm_nics.append(nic)
1783 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1785 def _WriteKVMRuntime(self, instance_name, data):
1786 """Write an instance's KVM runtime
1790 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1792 except EnvironmentError, err:
1793 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1796 def _ReadKVMRuntime(cls, instance_name):
1797 """Read an instance's KVM runtime
1801 file_content = utils.ReadFile(cls._InstanceKVMRuntime(instance_name))
1802 except EnvironmentError, err:
1803 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1806 def _SaveKVMRuntime(self, instance, kvm_runtime):
1807 """Save an instance's KVM runtime
1810 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1812 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1813 serialized_disks = [(blk.ToDict(), link)
1814 for blk, link in kvm_disks]
1815 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1818 self._WriteKVMRuntime(instance.name, serialized_form)
1821 def _LoadKVMRuntime(cls, instance_name, serialized_runtime=None):
1822 """Load an instance's KVM runtime
1825 if not serialized_runtime:
1826 serialized_runtime = cls._ReadKVMRuntime(instance_name)
1828 return _AnalyzeSerializedRuntime(serialized_runtime)
1830 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1831 """Run the KVM cmd and check for errors
1834 @param name: instance name
1835 @type kvm_cmd: list of strings
1836 @param kvm_cmd: runcmd input for kvm
1837 @type tap_fds: list of int
1838 @param tap_fds: fds of tap devices opened by Ganeti
1842 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1845 utils_wrapper.CloseFdNoError(fd)
1848 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1849 (name, result.fail_reason, result.output))
1850 if not self._InstancePidAlive(name)[2]:
1851 raise errors.HypervisorError("Failed to start instance %s" % name)
1853 # too many local variables
1854 # pylint: disable=R0914
1855 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1856 """Execute a KVM cmd, after completing it with some last minute data.
1858 @type incoming: tuple of strings
1859 @param incoming: (target_host_ip, port)
1860 @type kvmhelp: string
1861 @param kvmhelp: output of kvm --help
1864 # Small _ExecuteKVMRuntime hv parameters programming howto:
1865 # - conf_hvp contains the parameters as configured on ganeti. they might
1866 # have changed since the instance started; only use them if the change
1867 # won't affect the inside of the instance (which hasn't been rebooted).
1868 # - up_hvp contains the parameters as they were when the instance was
1869 # started, plus any new parameter which has been added between ganeti
1870 # versions: it is paramount that those default to a value which won't
1871 # affect the inside of the instance as well.
1872 conf_hvp = instance.hvparams
1873 name = instance.name
1874 self._CheckDown(name)
1878 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1879 # the first element of kvm_cmd is always the path to the kvm binary
1880 kvm_path = kvm_cmd[0]
1881 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1883 # We know it's safe to run as a different user upon migration, so we'll use
1884 # the latest conf, from conf_hvp.
1885 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1886 if security_model == constants.HT_SM_USER:
1887 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1889 keymap = conf_hvp[constants.HV_KEYMAP]
1891 keymap_path = self._InstanceKeymapFile(name)
1892 # If a keymap file is specified, KVM won't use its internal defaults. By
1893 # first including the "en-us" layout, an error on loading the actual
1894 # layout (e.g. because it can't be found) won't lead to a non-functional
1895 # keyboard. A keyboard with incorrect keys is still better than none.
1896 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1897 kvm_cmd.extend(["-k", keymap_path])
1899 # We have reasons to believe changing something like the nic driver/type
1900 # upon migration won't exactly fly with the instance kernel, so for nic
1901 # related parameters we'll use up_hvp
1904 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1906 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1911 kvm_cmd.extend(bdev_opts)
1914 kvm_cmd.extend(["-net", "none"])
1918 nic_type = up_hvp[constants.HV_NIC_TYPE]
1919 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1920 nic_model = self._VIRTIO
1922 if self._VIRTIO_NET_RE.search(devlist):
1923 nic_model = self._VIRTIO_NET_PCI
1924 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1925 except errors.HypervisorError, _:
1926 # Older versions of kvm don't support DEVICE_LIST, but they don't
1927 # have new virtio syntax either.
1930 if up_hvp[constants.HV_VHOST_NET]:
1931 # check for vhost_net support
1932 if self._VHOST_RE.search(kvmhelp):
1933 tap_extra = ",vhost=on"
1935 raise errors.HypervisorError("vhost_net is configured"
1936 " but it is not available")
1938 nic_model = nic_type
1940 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1942 for nic_seq, nic in enumerate(kvm_nics):
1943 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1944 tapfds.append(tapfd)
1945 taps.append(tapname)
1946 if kvm_supports_netdev:
1947 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1949 # kvm_nics already exist in old runtime files and thus there might
1950 # be some entries without pci slot (therefore try: except:)
1951 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1953 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1954 except errors.HotplugError:
1955 netdev = "netdev%d" % nic_seq
1956 nic_val += (",netdev=%s" % netdev)
1957 tap_val = ("type=tap,id=%s,fd=%d%s" %
1958 (netdev, tapfd, tap_extra))
1959 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1961 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1963 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1964 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1967 target, port = incoming
1968 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1970 # Changing the vnc password doesn't bother the guest that much. At most it
1971 # will surprise people who connect to it. Whether positively or negatively
1973 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1977 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1978 except EnvironmentError, err:
1979 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1980 % (vnc_pwd_file, err))
1982 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1983 utils.EnsureDirs([(self._InstanceChrootDir(name),
1984 constants.SECURE_DIR_MODE)])
1986 # Automatically enable QMP if version is >= 0.14
1987 if self._QMP_RE.search(kvmhelp):
1988 logging.debug("Enabling QMP")
1989 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1990 self._InstanceQmpMonitor(instance.name)])
1992 # Configure the network now for starting instances and bridged interfaces,
1993 # during FinalizeMigration for incoming instances' routed interfaces
1994 for nic_seq, nic in enumerate(kvm_nics):
1996 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1998 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
2000 # CPU affinity requires kvm to start paused, so we set this flag if the
2001 # instance is not already paused and if we are not going to accept a
2002 # migrating instance. In the latter case, pausing is not needed.
2003 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
2004 if start_kvm_paused:
2005 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
2007 # Note: CPU pinning is using up_hvp since changes take effect
2008 # during instance startup anyway, and to avoid problems when soft
2009 # rebooting the instance.
2011 if up_hvp.get(constants.HV_CPU_MASK, None):
2014 if security_model == constants.HT_SM_POOL:
2015 ss = ssconf.SimpleStore()
2016 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
2017 all_uids = set(uidpool.ExpandUidPool(uid_pool))
2018 uid = uidpool.RequestUnusedUid(all_uids)
2020 username = pwd.getpwuid(uid.GetUid()).pw_name
2021 kvm_cmd.extend(["-runas", username])
2022 self._RunKVMCmd(name, kvm_cmd, tapfds)
2024 uidpool.ReleaseUid(uid)
2028 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
2030 self._RunKVMCmd(name, kvm_cmd, tapfds)
2032 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
2033 constants.RUN_DIRS_MODE)])
2034 for nic_seq, tap in enumerate(taps):
2035 nic = kvm_nics[nic_seq]
2036 self._WriteInstanceNICFiles(instance.name, nic_seq, nic, tap)
2039 change_cmd = "change vnc password %s" % vnc_pwd
2040 self._CallMonitorCommand(instance.name, change_cmd)
2042 # Setting SPICE password. We are not vulnerable to malicious passwordless
2043 # connection attempts because SPICE by default does not allow connections
2044 # if neither a password nor the "disable_ticketing" options are specified.
2045 # As soon as we send the password via QMP, that password is a valid ticket
2047 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
2048 if spice_password_file:
2051 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
2052 except EnvironmentError, err:
2053 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
2054 % (spice_password_file, err))
2056 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
2059 "protocol": "spice",
2060 "password": spice_pwd,
2062 qmp.Execute("set_password", arguments)
2064 for filename in temp_files:
2065 utils.RemoveFile(filename)
2067 # If requested, set CPU affinity and resume instance execution
2069 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
2071 start_memory = self._InstanceStartupMemory(instance)
2072 if start_memory < instance.beparams[constants.BE_MAXMEM]:
2073 self.BalloonInstanceMemory(instance, start_memory)
2075 if start_kvm_paused:
2076 # To control CPU pinning, ballooning, and vnc/spice passwords
2077 # the VM was started in a frozen state. If freezing was not
2078 # explicitly requested resume the vm status.
2079 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2081 def StartInstance(self, instance, block_devices, startup_paused):
2082 """Start an instance.
2085 self._CheckDown(instance.name)
2086 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2087 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2088 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
2089 startup_paused, kvmhelp)
2090 self._SaveKVMRuntime(instance, kvm_runtime)
2091 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2093 def _CallMonitorCommand(self, instance_name, command, timeout=None):
2094 """Invoke a command on the instance monitor.
2097 if timeout is not None:
2098 timeout_cmd = "timeout %s" % (timeout, )
2102 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
2103 # version. The monitor protocol is designed for human consumption, whereas
2104 # QMP is made for programmatic usage. In the worst case QMP can also
2105 # execute monitor commands. As it is, all calls to socat take at least
2106 # 500ms and likely more: socat can't detect the end of the reply and waits
2107 # for 500ms of no data received before exiting (500 ms is the default for
2108 # the "-t" parameter).
2109 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
2110 (utils.ShellQuote(command),
2112 constants.SOCAT_PATH,
2113 utils.ShellQuote(self._InstanceMonitor(instance_name))))
2115 result = utils.RunCmd(socat)
2117 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2119 (command, instance_name, result.fail_reason, result.output))
2120 raise errors.HypervisorError(msg)
2124 def _GetFreePCISlot(self, instance, dev):
2125 """Get the first available pci slot of a runnung instance.
2128 slots = bitarray(32)
2129 slots.setall(False) # pylint: disable=E1101
2130 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2131 for line in output.stdout.splitlines():
2132 match = self._INFO_PCI_RE.search(line)
2134 slot = int(match.group(1))
2137 dev.pci = _GetFreeSlot(slots)
2139 def VerifyHotplugSupport(self, instance, action, dev_type):
2140 """Verifies that hotplug is supported.
2142 Hotplug is *not* supported in case of:
2143 - security models and chroot (disk hotplug)
2144 - fdsend module is missing (nic hot-add)
2146 @raise errors.HypervisorError: in one of the previous cases
2149 if dev_type == constants.HOTPLUG_TARGET_DISK:
2150 hvp = instance.hvparams
2151 security_model = hvp[constants.HV_SECURITY_MODEL]
2152 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2154 raise errors.HotplugError("Disk hotplug is not supported"
2155 " in case of chroot.")
2156 if security_model != constants.HT_SM_NONE:
2157 raise errors.HotplugError("Disk Hotplug is not supported in case"
2158 " security models are used.")
2160 if (dev_type == constants.HOTPLUG_TARGET_NIC and
2161 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2162 raise errors.HotplugError("Cannot hot-add NIC."
2163 " fdsend python module is missing.")
2165 def HotplugSupported(self, instance):
2166 """Checks if hotplug is generally supported.
2168 Hotplug is *not* supported in case of:
2169 - qemu versions < 1.0
2170 - for stopped instances
2172 @raise errors.HypervisorError: in one of the previous cases
2176 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2177 except errors.HypervisorError:
2178 raise errors.HotplugError("Instance is probably down")
2180 # TODO: search for netdev_add, drive_add, device_add.....
2181 match = self._INFO_VERSION_RE.search(output.stdout)
2183 raise errors.HotplugError("Cannot parse qemu version via monitor")
2185 v_major, v_min, _, _ = match.groups()
2186 if (int(v_major), int(v_min)) < (1, 0):
2187 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2189 def _CallHotplugCommands(self, name, cmds):
2191 self._CallMonitorCommand(name, c)
2194 def _VerifyHotplugCommand(self, instance_name, device, dev_type,
2196 """Checks if a previous hotplug command has succeeded.
2198 It issues info pci monitor command and checks depending on should_exist
2199 value if an entry with PCI slot and device ID is found or not.
2201 @raise errors.HypervisorError: if result is not the expected one
2204 output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
2205 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2207 self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
2208 if match and not should_exist:
2209 msg = "Device %s should have been removed but is still there" % kvm_devid
2210 raise errors.HypervisorError(msg)
2212 if not match and should_exist:
2213 msg = "Device %s should have been added but is missing" % kvm_devid
2214 raise errors.HypervisorError(msg)
2216 logging.info("Device %s has been correctly hot-plugged", kvm_devid)
2218 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2219 """ Helper method to hot-add a new device
2221 It gets free pci slot generates the device name and invokes the
2222 device specific method.
2225 # in case of hot-mod this is given
2226 if device.pci is None:
2227 self._GetFreePCISlot(instance, device)
2228 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2229 runtime = self._LoadKVMRuntime(instance.name)
2230 if dev_type == constants.HOTPLUG_TARGET_DISK:
2231 cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
2233 cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2234 (hex(device.pci), kvm_devid, kvm_devid)]
2235 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2236 (tap, fd) = _OpenTap()
2237 self._ConfigureNIC(instance, seq, device, tap)
2238 self._PassTapFd(instance, fd, device)
2239 cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
2240 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2241 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2242 cmds += ["device_add %s" % args]
2243 self._WriteInstanceNICFiles(instance.name, seq, device, tap)
2245 self._CallHotplugCommands(instance.name, cmds)
2246 self._VerifyHotplugCommand(instance.name, device, dev_type, True)
2247 # update relevant entries in runtime file
2248 index = _DEVICE_RUNTIME_INDEX[dev_type]
2249 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2250 runtime[index].append(entry)
2251 self._SaveKVMRuntime(instance, runtime)
2253 def HotDelDevice(self, instance, dev_type, device, _, seq):
2254 """ Helper method for hot-del device
2256 It gets device info from runtime file, generates the device name and
2257 invokes the device specific method.
2260 runtime = self._LoadKVMRuntime(instance.name)
2261 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2262 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2263 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2264 if dev_type == constants.HOTPLUG_TARGET_DISK:
2265 cmds = ["device_del %s" % kvm_devid]
2266 cmds += ["drive_del %s" % kvm_devid]
2267 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2268 cmds = ["device_del %s" % kvm_devid]
2269 cmds += ["netdev_del %s" % kvm_devid]
2270 self._UnconfigureNic(instance.name, kvm_device, False)
2271 self._RemoveInstanceNICFiles(instance.name, seq, device)
2272 self._CallHotplugCommands(instance.name, cmds)
2273 self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
2274 index = _DEVICE_RUNTIME_INDEX[dev_type]
2275 runtime[index].remove(entry)
2276 self._SaveKVMRuntime(instance, runtime)
2278 return kvm_device.pci
2280 def HotModDevice(self, instance, dev_type, device, _, seq):
2281 """ Helper method for hot-mod device
2283 It gets device info from runtime file, generates the device name and
2284 invokes the device specific method. Currently only NICs support hot-mod
2287 if dev_type == constants.HOTPLUG_TARGET_NIC:
2288 # putting it back in the same pci slot
2289 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2290 # TODO: remove sleep when socat gets removed
2291 self.HotAddDevice(instance, dev_type, device, _, seq)
2293 def _PassTapFd(self, instance, fd, nic):
2294 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2297 # TODO: factor out code related to unix sockets.
2298 # squash common parts between monitor and qmp
2299 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2300 command = "getfd %s\n" % kvm_devid
2302 logging.info("%s", fds)
2304 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2306 fdsend.sendfds(monsock.sock, command, fds=fds)
2311 def _ParseKVMVersion(cls, text):
2312 """Parse the KVM version from the --help output.
2315 @param text: output of kvm --help
2316 @return: (version, v_maj, v_min, v_rev)
2317 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2320 match = cls._VERSION_RE.search(text.splitlines()[0])
2322 raise errors.HypervisorError("Unable to get KVM version")
2324 v_all = match.group(0)
2325 v_maj = int(match.group(1))
2326 v_min = int(match.group(2))
2328 v_rev = int(match.group(4))
2331 return (v_all, v_maj, v_min, v_rev)
2334 def _GetKVMOutput(cls, kvm_path, option):
2335 """Return the output of a kvm invocation
2337 @type kvm_path: string
2338 @param kvm_path: path to the kvm executable
2339 @type option: a key of _KVMOPTS_CMDS
2340 @param option: kvm option to fetch the output from
2341 @return: output a supported kvm invocation
2342 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2345 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2347 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2349 result = utils.RunCmd([kvm_path] + optlist)
2350 if result.failed and not can_fail:
2351 raise errors.HypervisorError("Unable to get KVM %s output" %
2353 return result.output
2356 def _GetKVMVersion(cls, kvm_path):
2357 """Return the installed KVM version.
2359 @return: (version, v_maj, v_min, v_rev)
2360 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2363 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2366 def _GetDefaultMachineVersion(cls, kvm_path):
2367 """Return the default hardware revision (e.g. pc-1.1)
2370 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2371 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2373 return match.group(1)
2377 def StopInstance(self, instance, force=False, retry=False, name=None,
2379 """Stop an instance.
2382 assert(timeout is None or force is not None)
2384 if name is not None and not force:
2385 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2387 name = instance.name
2388 acpi = instance.hvparams[constants.HV_ACPI]
2391 _, pid, alive = self._InstancePidAlive(name)
2392 if pid > 0 and alive:
2393 if force or not acpi:
2394 utils.KillProcess(pid)
2396 self._CallMonitorCommand(name, "system_powerdown", timeout)
2399 def _UnconfigureInstanceNICs(cls, instance_name, info=None):
2400 """Get runtime NICs of an instance and unconfigure them
2403 _, kvm_nics, __, ___ = cls._LoadKVMRuntime(instance_name, info)
2404 for nic in kvm_nics:
2405 cls._UnconfigureNic(instance_name, nic)
2407 def CleanupInstance(self, instance_name):
2408 """Cleanup after a stopped instance
2411 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2412 if pid > 0 and alive:
2413 raise errors.HypervisorError("Cannot cleanup a live instance")
2414 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2416 def RebootInstance(self, instance):
2417 """Reboot an instance.
2420 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2421 # socket the instance will stop, but now power up again. So we'll resort
2422 # to shutdown and restart.
2423 _, _, alive = self._InstancePidAlive(instance.name)
2425 raise errors.HypervisorError("Failed to reboot instance %s:"
2426 " not running" % instance.name)
2427 # StopInstance will delete the saved KVM runtime so:
2428 # ...first load it...
2429 kvm_runtime = self._LoadKVMRuntime(instance.name)
2430 # ...now we can safely call StopInstance...
2431 if not self.StopInstance(instance):
2432 self.StopInstance(instance, force=True)
2433 # ...and finally we can save it again, and execute it...
2434 self._SaveKVMRuntime(instance, kvm_runtime)
2435 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2436 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2437 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2439 def MigrationInfo(self, instance):
2440 """Get instance information to perform a migration.
2442 @type instance: L{objects.Instance}
2443 @param instance: instance to be migrated
2445 @return: content of the KVM runtime file
2448 return self._ReadKVMRuntime(instance.name)
2450 def AcceptInstance(self, instance, info, target):
2451 """Prepare to accept an instance.
2453 @type instance: L{objects.Instance}
2454 @param instance: instance to be accepted
2456 @param info: content of the KVM runtime file on the source node
2457 @type target: string
2458 @param target: target host (usually ip), on this node
2461 kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2462 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2463 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2464 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2465 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2466 incoming=incoming_address)
2468 def FinalizeMigrationDst(self, instance, info, success):
2469 """Finalize the instance migration on the target node.
2471 Stop the incoming mode KVM.
2473 @type instance: L{objects.Instance}
2474 @param instance: instance whose migration is being finalized
2478 kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2479 kvm_nics = kvm_runtime[1]
2481 for nic_seq, nic in enumerate(kvm_nics):
2482 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2483 # Bridged interfaces have already been configured
2486 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2487 except EnvironmentError, err:
2488 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2489 instance.name, nic_seq, str(err))
2492 self._ConfigureNIC(instance, nic_seq, nic, tap)
2493 except errors.HypervisorError, err:
2494 logging.warning(str(err))
2496 self._WriteKVMRuntime(instance.name, info)
2498 self._UnconfigureInstanceNICs(instance.name, info)
2499 self.StopInstance(instance, force=True)
2501 def MigrateInstance(self, instance, target, live):
2502 """Migrate an instance to a target node.
2504 The migration will not be attempted if the instance is not
2507 @type instance: L{objects.Instance}
2508 @param instance: the instance to be migrated
2509 @type target: string
2510 @param target: ip address of the target node
2512 @param live: perform a live migration
2515 instance_name = instance.name
2516 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2517 _, _, alive = self._InstancePidAlive(instance_name)
2519 raise errors.HypervisorError("Instance not running, cannot migrate")
2522 self._CallMonitorCommand(instance_name, "stop")
2524 migrate_command = ("migrate_set_speed %dm" %
2525 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2526 self._CallMonitorCommand(instance_name, migrate_command)
2528 migrate_command = ("migrate_set_downtime %dms" %
2529 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2530 self._CallMonitorCommand(instance_name, migrate_command)
2532 # These commands are supported in latest qemu versions.
2533 # Since _CallMonitorCommand does not catch monitor errors
2534 # this does not raise an exception in case command is not supported
2535 # TODO: either parse output of command or see if the command supported
2536 # via info help (see hotplug)
2537 migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
2539 for c in migration_caps.split(_MIGRATION_CAPS_DELIM):
2540 migrate_command = ("migrate_set_capability %s on" % c)
2541 self._CallMonitorCommand(instance_name, migrate_command)
2543 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2544 self._CallMonitorCommand(instance_name, migrate_command)
2546 def FinalizeMigrationSource(self, instance, success, live):
2547 """Finalize the instance migration on the source node.
2549 @type instance: L{objects.Instance}
2550 @param instance: the instance that was migrated
2552 @param success: whether the migration succeeded or not
2554 @param live: whether the user requested a live migration or not
2558 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2559 utils.KillProcess(pid)
2560 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2562 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2564 def GetMigrationStatus(self, instance):
2565 """Get the migration status
2567 @type instance: L{objects.Instance}
2568 @param instance: the instance that is being migrated
2569 @rtype: L{objects.MigrationStatus}
2570 @return: the status of the current migration (one of
2571 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2572 progress info that can be retrieved from the hypervisor
2575 info_command = "info migrate"
2576 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2577 result = self._CallMonitorCommand(instance.name, info_command)
2578 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2580 if not result.stdout:
2581 logging.info("KVM: empty 'info migrate' result")
2583 logging.warning("KVM: unknown 'info migrate' result: %s",
2586 status = match.group(1)
2587 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2588 migration_status = objects.MigrationStatus(status=status)
2589 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2591 migration_status.transferred_ram = match.group("transferred")
2592 migration_status.total_ram = match.group("total")
2594 return migration_status
2596 logging.warning("KVM: unknown migration status '%s'", status)
2598 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2600 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2602 def BalloonInstanceMemory(self, instance, mem):
2603 """Balloon an instance memory to a certain value.
2605 @type instance: L{objects.Instance}
2606 @param instance: instance to be accepted
2608 @param mem: actual memory size to use for instance runtime
2611 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2613 def GetNodeInfo(self):
2614 """Return information about the node.
2616 @return: a dict with the following keys (values in MiB):
2617 - memory_total: the total memory size on the node
2618 - memory_free: the available memory on the node for instances
2619 - memory_dom0: the memory used by the node itself, if available
2620 - hv_version: the hypervisor version in the form (major, minor,
2624 result = self.GetLinuxNodeInfo()
2625 # FIXME: this is the global kvm version, but the actual version can be
2626 # customized as an hv parameter. we should use the nodegroup's default kvm
2627 # path parameter here.
2628 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2629 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2633 def GetInstanceConsole(cls, instance, hvparams, beparams):
2634 """Return a command for connecting to the console of an instance.
2637 if hvparams[constants.HV_SERIAL_CONSOLE]:
2638 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2639 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2640 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2641 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2642 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2643 return objects.InstanceConsole(instance=instance.name,
2644 kind=constants.CONS_SSH,
2645 host=instance.primary_node,
2646 user=constants.SSH_CONSOLE_USER,
2649 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2650 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2651 display = instance.network_port - constants.VNC_BASE_PORT
2652 return objects.InstanceConsole(instance=instance.name,
2653 kind=constants.CONS_VNC,
2654 host=vnc_bind_address,
2655 port=instance.network_port,
2658 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2660 return objects.InstanceConsole(instance=instance.name,
2661 kind=constants.CONS_SPICE,
2663 port=instance.network_port)
2665 return objects.InstanceConsole(instance=instance.name,
2666 kind=constants.CONS_MESSAGE,
2667 message=("No serial shell for instance %s" %
2671 """Verify the hypervisor.
2673 Check that the required binaries exist.
2675 @return: Problem description if something is wrong, C{None} otherwise
2679 # FIXME: this is the global kvm binary, but the actual path can be
2680 # customized as an hv parameter; we should use the nodegroup's
2681 # default kvm path parameter here.
2682 if not os.path.exists(constants.KVM_PATH):
2683 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2684 if not os.path.exists(constants.SOCAT_PATH):
2685 msgs.append("The socat binary ('%s') does not exist" %
2686 constants.SOCAT_PATH)
2688 return self._FormatVerifyResults(msgs)
2691 def CheckParameterSyntax(cls, hvparams):
2692 """Check the given parameters for validity.
2694 @type hvparams: dict
2695 @param hvparams: dictionary with parameter names/value
2696 @raise errors.HypervisorError: when a parameter is not valid
2699 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2701 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2703 if not hvparams[constants.HV_ROOT_PATH]:
2704 raise errors.HypervisorError("Need a root partition for the instance,"
2705 " if a kernel is defined")
2707 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2708 not hvparams[constants.HV_VNC_X509]):
2709 raise errors.HypervisorError("%s must be defined, if %s is" %
2710 (constants.HV_VNC_X509,
2711 constants.HV_VNC_X509_VERIFY))
2713 if hvparams[constants.HV_SERIAL_CONSOLE]:
2714 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2715 valid_speeds = constants.VALID_SERIAL_SPEEDS
2716 if not serial_speed or serial_speed not in valid_speeds:
2717 raise errors.HypervisorError("Invalid serial console speed, must be"
2719 utils.CommaJoin(valid_speeds))
2721 boot_order = hvparams[constants.HV_BOOT_ORDER]
2722 if (boot_order == constants.HT_BO_CDROM and
2723 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2724 raise errors.HypervisorError("Cannot boot from cdrom without an"
2727 security_model = hvparams[constants.HV_SECURITY_MODEL]
2728 if security_model == constants.HT_SM_USER:
2729 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2730 raise errors.HypervisorError("A security domain (user to run kvm as)"
2731 " must be specified")
2732 elif (security_model == constants.HT_SM_NONE or
2733 security_model == constants.HT_SM_POOL):
2734 if hvparams[constants.HV_SECURITY_DOMAIN]:
2735 raise errors.HypervisorError("Cannot have a security domain when the"
2736 " security model is 'none' or 'pool'")
2738 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2739 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2741 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2742 # if an IP version is specified, the spice_bind parameter must be an
2744 if (netutils.IP4Address.IsValid(spice_bind) and
2745 spice_ip_version != constants.IP4_VERSION):
2746 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2747 " the specified IP version is %s" %
2748 (spice_bind, spice_ip_version))
2750 if (netutils.IP6Address.IsValid(spice_bind) and
2751 spice_ip_version != constants.IP6_VERSION):
2752 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2753 " the specified IP version is %s" %
2754 (spice_bind, spice_ip_version))
2756 # All the other SPICE parameters depend on spice_bind being set. Raise an
2757 # error if any of them is set without it.
2758 for param in _SPICE_ADDITIONAL_PARAMS:
2760 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2761 (param, constants.HV_KVM_SPICE_BIND))
2764 def ValidateParameters(cls, hvparams):
2765 """Check the given parameters for validity.
2767 @type hvparams: dict
2768 @param hvparams: dictionary with parameter names/value
2769 @raise errors.HypervisorError: when a parameter is not valid
2772 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2774 kvm_path = hvparams[constants.HV_KVM_PATH]
2776 security_model = hvparams[constants.HV_SECURITY_MODEL]
2777 if security_model == constants.HT_SM_USER:
2778 username = hvparams[constants.HV_SECURITY_DOMAIN]
2780 pwd.getpwnam(username)
2782 raise errors.HypervisorError("Unknown security domain user %s"
2785 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2787 # only one of VNC and SPICE can be used currently.
2788 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2789 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2790 " only one of them can be used at a"
2793 # check that KVM supports SPICE
2794 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2795 if not cls._SPICE_RE.search(kvmhelp):
2796 raise errors.HypervisorError("SPICE is configured, but it is not"
2797 " supported according to 'kvm --help'")
2799 # if spice_bind is not an IP address, it must be a valid interface
2800 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2801 netutils.IP6Address.IsValid(spice_bind))
2802 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2803 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2804 " a valid IP address or interface name" %
2805 constants.HV_KVM_SPICE_BIND)
2807 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2809 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2810 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2811 raise errors.HypervisorError("Unsupported machine version: %s" %
2815 def PowercycleNode(cls):
2816 """KVM powercycle, just a wrapper over Linux powercycle.
2819 cls.LinuxPowercycle()