4 # Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
40 from bitarray import bitarray
42 import affinity # pylint: disable=F0401
46 import fdsend # pylint: disable=F0401
50 from ganeti import utils
51 from ganeti import constants
52 from ganeti import errors
53 from ganeti import serializer
54 from ganeti import objects
55 from ganeti import uidpool
56 from ganeti import ssconf
57 from ganeti import netutils
58 from ganeti import pathutils
59 from ganeti.hypervisor import hv_base
60 from ganeti.utils import wrapper as utils_wrapper
63 _KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-ifup-custom"
64 _KVM_START_PAUSED_FLAG = "-S"
66 # TUN/TAP driver constants, taken from <linux/if_tun.h>
67 # They are architecture-independent and already hardcoded in qemu-kvm source,
68 # so we can safely include them here.
69 TUNSETIFF = 0x400454ca
70 TUNGETIFF = 0x800454d2
71 TUNGETFEATURES = 0x800454cf
76 #: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
77 _SPICE_ADDITIONAL_PARAMS = frozenset([
78 constants.HV_KVM_SPICE_IP_VERSION,
79 constants.HV_KVM_SPICE_PASSWORD_FILE,
80 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
81 constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
82 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
83 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
84 constants.HV_KVM_SPICE_USE_TLS,
87 # Constant bitarray that reflects to a free pci slot
88 # Use it with bitarray.search()
89 _AVAILABLE_PCI_SLOT = bitarray("0")
91 # below constants show the format of runtime file
92 # the nics are in second possition, while the disks in 4th (last)
93 # moreover disk entries are stored as a list of in tuples
94 # (L{objects.Disk}, link_name)
95 _KVM_NICS_RUNTIME_INDEX = 1
96 _KVM_DISKS_RUNTIME_INDEX = 3
97 _DEVICE_RUNTIME_INDEX = {
98 constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
99 constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
101 _FIND_RUNTIME_ENTRY = {
102 constants.HOTPLUG_TARGET_NIC:
103 lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
104 constants.HOTPLUG_TARGET_DISK:
105 lambda disk, kvm_disks: [(d, l) for (d, l) in kvm_disks
106 if d.uuid == disk.uuid]
109 constants.HOTPLUG_TARGET_NIC: lambda d: d,
110 constants.HOTPLUG_TARGET_DISK: lambda (d, e): d
113 constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
114 constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e)
118 def _GenerateDeviceKVMId(dev_type, dev, idx=None):
119 """Helper function to generate a unique device name used by KVM
121 QEMU monitor commands use names to identify devices. Here we use their pci
122 slot and a part of their UUID to name them. dev.pci might be None for old
123 devices in the cluster.
125 @type dev_type: sting
126 @param dev_type: device type of param dev
127 @type dev: L{objects.Disk} or L{objects.NIC}
128 @param dev: the device object for which we generate a kvm name
129 @raise errors.HotplugError: in case a device has no pci slot (old devices)
133 # proper device id - available in latest Ganeti versions
134 if dev.pci and dev.uuid:
135 return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
137 # dummy device id - returned only to _GenerateKVMBlockDevicesOptions
138 # This enables -device option for paravirtual disk_type
140 return "%s-%d" % (dev_type.lower(), idx)
142 raise errors.HotplugError("Hotplug is not supported for devices"
143 " without UUID or PCI info")
146 def _UpdatePCISlots(dev, pci_reservations):
147 """Update pci configuration for a stopped instance
149 If dev has a pci slot then reserve it, else find first available
150 in pci_reservations bitarray. It acts on the same objects passed
151 as params so there is no need to return anything.
153 @type dev: L{objects.Disk} or L{objects.NIC}
154 @param dev: the device object for which we update its pci slot
155 @type pci_reservations: bitarray
156 @param pci_reservations: existing pci reservations for an instance
157 @raise errors.HotplugError: in case an instance has all its slot occupied
162 else: # pylint: disable=E1103
163 [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
165 raise errors.HypervisorError("All PCI slots occupied")
168 pci_reservations[free] = True
171 def _GetExistingDeviceInfo(dev_type, device, runtime):
172 """Helper function to get an existing device inside the runtime file
174 Used when an instance is running. Load kvm runtime file and search
175 for a device based on its type and uuid.
177 @type dev_type: sting
178 @param dev_type: device type of param dev
179 @type device: L{objects.Disk} or L{objects.NIC}
180 @param device: the device object for which we generate a kvm name
181 @type runtime: tuple (cmd, nics, hvparams, disks)
182 @param runtime: the runtime data to search for the device
183 @raise errors.HotplugError: in case the requested device does not
184 exist (e.g. device has been added without --hotplug option) or
185 device info has not pci slot (e.g. old devices in the cluster)
188 index = _DEVICE_RUNTIME_INDEX[dev_type]
189 found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
191 raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
192 (dev_type, device.uuid))
197 def _UpgradeSerializedRuntime(serialized_runtime):
198 """Upgrade runtime data
200 Remove any deprecated fields or change the format of the data.
201 The runtime files are not upgraded when Ganeti is upgraded, so the required
202 modification have to be performed here.
204 @type serialized_runtime: string
205 @param serialized_runtime: raw text data read from actual runtime file
206 @return: (cmd, nic dicts, hvparams, bdev dicts)
210 loaded_runtime = serializer.Load(serialized_runtime)
211 kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
212 if len(loaded_runtime) >= 4:
213 serialized_disks = loaded_runtime[3]
215 serialized_disks = []
217 for nic in serialized_nics:
218 # Add a dummy uuid slot if an pre-2.8 NIC is found
219 if "uuid" not in nic:
220 nic["uuid"] = utils.NewUUID()
222 return kvm_cmd, serialized_nics, hvparams, serialized_disks
225 def _AnalyzeSerializedRuntime(serialized_runtime):
226 """Return runtime entries for a serialized runtime file
228 @type serialized_runtime: string
229 @param serialized_runtime: raw text data read from actual runtime file
230 @return: (cmd, nics, hvparams, bdevs)
234 kvm_cmd, serialized_nics, hvparams, serialized_disks = \
235 _UpgradeSerializedRuntime(serialized_runtime)
236 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
237 kvm_disks = [(objects.Disk.FromDict(sdisk), link)
238 for sdisk, link in serialized_disks]
240 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
243 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
244 """Retrieves supported TUN features from file descriptor.
246 @see: L{_ProbeTapVnetHdr}
249 req = struct.pack("I", 0)
251 buf = _ioctl(fd, TUNGETFEATURES, req)
252 except EnvironmentError, err:
253 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
256 (flags, ) = struct.unpack("I", buf)
260 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
261 """Check whether to enable the IFF_VNET_HDR flag.
263 To do this, _all_ of the following conditions must be met:
264 1. TUNGETFEATURES ioctl() *must* be implemented
265 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
266 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
267 drivers/net/tun.c there is no way to test this until after the tap device
268 has been created using TUNSETIFF, and there is no way to change the
269 IFF_VNET_HDR flag after creating the interface, catch-22! However both
270 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
271 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
274 @param fd: the file descriptor of /dev/net/tun
277 flags = _features_fn(fd)
283 result = bool(flags & IFF_VNET_HDR)
286 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
291 def _OpenTap(vnet_hdr=True):
292 """Open a new tap device and return its file descriptor.
294 This is intended to be used by a qemu-type hypervisor together with the -net
295 tap,fd=<fd> command line parameter.
297 @type vnet_hdr: boolean
298 @param vnet_hdr: Enable the VNET Header
299 @return: (ifname, tapfd)
304 tapfd = os.open("/dev/net/tun", os.O_RDWR)
305 except EnvironmentError:
306 raise errors.HypervisorError("Failed to open /dev/net/tun")
308 flags = IFF_TAP | IFF_NO_PI
310 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
311 flags |= IFF_VNET_HDR
313 # The struct ifreq ioctl request (see netdevice(7))
314 ifr = struct.pack("16sh", "", flags)
317 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
318 except EnvironmentError, err:
319 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
322 # Get the interface name from the ioctl
323 ifname = struct.unpack("16sh", res)[0].strip("\x00")
324 return (ifname, tapfd)
328 """QEMU Messaging Protocol (QMP) message.
331 def __init__(self, data):
332 """Creates a new QMP message based on the passed data.
335 if not isinstance(data, dict):
336 raise TypeError("QmpMessage must be initialized with a dict")
340 def __getitem__(self, field_name):
341 """Get the value of the required field if present, or None.
343 Overrides the [] operator to provide access to the message data,
344 returning None if the required item is not in the message
345 @return: the value of the field_name field, or None if field_name
346 is not contained in the message
349 return self.data.get(field_name, None)
351 def __setitem__(self, field_name, field_value):
352 """Set the value of the required field_name to field_value.
355 self.data[field_name] = field_value
358 def BuildFromJsonString(json_string):
359 """Build a QmpMessage from a JSON encoded string.
361 @type json_string: str
362 @param json_string: JSON string representing the message
363 @rtype: L{QmpMessage}
364 @return: a L{QmpMessage} built from json_string
368 data = serializer.LoadJson(json_string)
369 return QmpMessage(data)
372 # The protocol expects the JSON object to be sent as a single line.
373 return serializer.DumpJson(self.data)
375 def __eq__(self, other):
376 # When comparing two QmpMessages, we are interested in comparing
377 # their internal representation of the message data
378 return self.data == other.data
381 class MonitorSocket(object):
384 def __init__(self, monitor_filename):
385 """Instantiates the MonitorSocket object.
387 @type monitor_filename: string
388 @param monitor_filename: the filename of the UNIX raw socket on which the
389 monitor (QMP or simple one) is listening
392 self.monitor_filename = monitor_filename
393 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
394 # We want to fail if the server doesn't send a complete message
395 # in a reasonable amount of time
396 self.sock.settimeout(self._SOCKET_TIMEOUT)
397 self._connected = False
399 def _check_socket(self):
402 sock_stat = os.stat(self.monitor_filename)
403 except EnvironmentError, err:
404 if err.errno == errno.ENOENT:
405 raise errors.HypervisorError("No monitor socket found")
407 raise errors.HypervisorError("Error checking monitor socket: %s",
408 utils.ErrnoOrStr(err))
409 if not stat.S_ISSOCK(sock_stat.st_mode):
410 raise errors.HypervisorError("Monitor socket is not a socket")
412 def _check_connection(self):
413 """Make sure that the connection is established.
416 if not self._connected:
417 raise errors.ProgrammerError("To use a MonitorSocket you need to first"
418 " invoke connect() on it")
421 """Connects to the monitor.
423 Connects to the UNIX socket
425 @raise errors.HypervisorError: when there are communication errors
429 raise errors.ProgrammerError("Cannot connect twice")
433 # Check file existance/stuff
435 self.sock.connect(self.monitor_filename)
436 except EnvironmentError:
437 raise errors.HypervisorError("Can't connect to qmp socket")
438 self._connected = True
443 It cannot be used after this call.
449 class QmpConnection(MonitorSocket):
450 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
453 _FIRST_MESSAGE_KEY = "QMP"
456 _RETURN_KEY = RETURN_KEY = "return"
457 _ACTUAL_KEY = ACTUAL_KEY = "actual"
458 _ERROR_CLASS_KEY = "class"
459 _ERROR_DESC_KEY = "desc"
460 _EXECUTE_KEY = "execute"
461 _ARGUMENTS_KEY = "arguments"
462 _CAPABILITIES_COMMAND = "qmp_capabilities"
463 _MESSAGE_END_TOKEN = "\r\n"
465 def __init__(self, monitor_filename):
466 super(QmpConnection, self).__init__(monitor_filename)
470 """Connects to the QMP monitor.
472 Connects to the UNIX socket and makes sure that we can actually send and
473 receive data to the kvm instance via QMP.
475 @raise errors.HypervisorError: when there are communication errors
476 @raise errors.ProgrammerError: when there are data serialization errors
479 super(QmpConnection, self).connect()
480 # Check if we receive a correct greeting message from the server
481 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
482 greeting = self._Recv()
483 if not greeting[self._FIRST_MESSAGE_KEY]:
484 self._connected = False
485 raise errors.HypervisorError("kvm: QMP communication error (wrong"
488 # This is needed because QMP can return more than one greetings
489 # see https://groups.google.com/d/msg/ganeti-devel/gZYcvHKDooU/SnukC8dgS5AJ
492 # Let's put the monitor in command mode using the qmp_capabilities
493 # command, or else no command will be executable.
494 # (As per the QEMU Protocol Specification 0.1 - section 4)
495 self.Execute(self._CAPABILITIES_COMMAND)
497 def _ParseMessage(self, buf):
498 """Extract and parse a QMP message from the given buffer.
500 Seeks for a QMP message in the given buf. If found, it parses it and
501 returns it together with the rest of the characters in the buf.
502 If no message is found, returns None and the whole buffer.
504 @raise errors.ProgrammerError: when there are data serialization errors
508 # Check if we got the message end token (CRLF, as per the QEMU Protocol
509 # Specification 0.1 - Section 2.1.1)
510 pos = buf.find(self._MESSAGE_END_TOKEN)
513 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
514 except Exception, err:
515 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
518 return (message, buf)
521 """Receives a message from QMP and decodes the received JSON object.
524 @return: the received message
525 @raise errors.HypervisorError: when there are communication errors
526 @raise errors.ProgrammerError: when there are data serialization errors
529 self._check_connection()
531 # Check if there is already a message in the buffer
532 (message, self._buf) = self._ParseMessage(self._buf)
536 recv_buffer = StringIO.StringIO(self._buf)
537 recv_buffer.seek(len(self._buf))
540 data = self.sock.recv(4096)
543 recv_buffer.write(data)
545 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
549 except socket.timeout, err:
550 raise errors.HypervisorError("Timeout while receiving a QMP message: "
552 except socket.error, err:
553 raise errors.HypervisorError("Unable to receive data from KVM using the"
554 " QMP protocol: %s" % err)
556 def _Send(self, message):
557 """Encodes and sends a message to KVM using QMP.
559 @type message: QmpMessage
560 @param message: message to send to KVM
561 @raise errors.HypervisorError: when there are communication errors
562 @raise errors.ProgrammerError: when there are data serialization errors
565 self._check_connection()
567 message_str = str(message)
568 except Exception, err:
569 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
572 self.sock.sendall(message_str)
573 except socket.timeout, err:
574 raise errors.HypervisorError("Timeout while sending a QMP message: "
575 "%s (%s)" % (err.string, err.errno))
576 except socket.error, err:
577 raise errors.HypervisorError("Unable to send data from KVM using the"
578 " QMP protocol: %s" % err)
580 def Execute(self, command, arguments=None):
581 """Executes a QMP command and returns the response of the server.
584 @param command: the command to execute
585 @type arguments: dict
586 @param arguments: dictionary of arguments to be passed to the command
588 @return: dictionary representing the received JSON object
589 @raise errors.HypervisorError: when there are communication errors
590 @raise errors.ProgrammerError: when there are data serialization errors
593 self._check_connection()
594 message = QmpMessage({self._EXECUTE_KEY: command})
596 message[self._ARGUMENTS_KEY] = arguments
599 # Events can occur between the sending of the command and the reception
600 # of the response, so we need to filter out messages with the event key.
602 response = self._Recv()
603 err = response[self._ERROR_KEY]
605 raise errors.HypervisorError("kvm: error executing the %s"
606 " command: %s (%s):" %
608 err[self._ERROR_DESC_KEY],
609 err[self._ERROR_CLASS_KEY]))
611 elif not response[self._EVENT_KEY]:
615 class KVMHypervisor(hv_base.BaseHypervisor):
616 """KVM hypervisor interface
621 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
622 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
623 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
624 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
625 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
626 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
627 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
628 # KVM instances with chroot enabled are started in empty chroot directories.
629 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
630 # After an instance is stopped, its chroot directory is removed.
631 # If the chroot directory is not empty, it can't be removed.
632 # A non-empty chroot directory indicates a possible security incident.
633 # To support forensics, the non-empty chroot directory is quarantined in
634 # a separate directory, called 'chroot-quarantine'.
635 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
636 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
637 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
640 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
641 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
642 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
643 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
644 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
645 constants.HV_ACPI: hv_base.NO_CHECK,
646 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
647 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
648 constants.HV_VNC_BIND_ADDRESS:
649 (False, lambda x: (netutils.IP4Address.IsValid(x) or
650 utils.IsNormAbsPath(x)),
651 "The VNC bind address must be either a valid IP address or an absolute"
652 " pathname", None, None),
653 constants.HV_VNC_TLS: hv_base.NO_CHECK,
654 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
655 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
656 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
657 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
658 constants.HV_KVM_SPICE_IP_VERSION:
659 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
660 x in constants.VALID_IP_VERSIONS),
661 "The SPICE IP version should be 4 or 6",
663 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
664 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
666 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
667 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
669 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
670 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
672 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
673 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
675 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
676 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
677 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
678 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
679 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
680 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
681 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
682 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
683 constants.HV_BOOT_ORDER:
684 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
685 constants.HV_NIC_TYPE:
686 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
687 constants.HV_DISK_TYPE:
688 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
689 constants.HV_KVM_CDROM_DISK_TYPE:
690 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
691 constants.HV_USB_MOUSE:
692 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
693 constants.HV_KEYMAP: hv_base.NO_CHECK,
694 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
695 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
696 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
697 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
698 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
699 constants.HV_DISK_CACHE:
700 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
701 constants.HV_SECURITY_MODEL:
702 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
703 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
704 constants.HV_KVM_FLAG:
705 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
706 constants.HV_VHOST_NET: hv_base.NO_CHECK,
707 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
708 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
709 constants.HV_REBOOT_BEHAVIOR:
710 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
711 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
712 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
713 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
714 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
715 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
716 constants.HV_SOUNDHW: hv_base.NO_CHECK,
717 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
718 constants.HV_VGA: hv_base.NO_CHECK,
719 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
720 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
721 constants.HV_VNET_HDR: hv_base.NO_CHECK,
725 _VIRTIO_NET_PCI = "virtio-net-pci"
726 _VIRTIO_BLK_PCI = "virtio-blk-pci"
728 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
730 _MIGRATION_PROGRESS_RE = \
731 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
732 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
733 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
735 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
736 _MIGRATION_INFO_RETRY_DELAY = 2
738 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
740 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
741 _CPU_INFO_CMD = "info cpus"
744 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
745 _CHECK_MACHINE_VERSION_RE = \
746 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
748 _QMP_RE = re.compile(r"^-qmp\s", re.M)
749 _SPICE_RE = re.compile(r"^-spice\s", re.M)
750 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
751 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
752 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
753 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
754 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
755 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
756 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
757 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
758 # match -drive.*boot=on|off on different lines, but in between accept only
759 # dashes not preceeded by a new line (which would mean another option
760 # different than -drive is starting)
761 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
763 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
764 _INFO_PCI_CMD = "info pci"
765 _FIND_PCI_DEVICE_RE = \
766 staticmethod(lambda pci, devid:
767 re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' % (pci, devid),
771 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
772 _INFO_VERSION_CMD = "info version"
774 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
779 ANCILLARY_FILES_OPT = [
783 # Supported kvm options to get output from
784 _KVMOPT_HELP = "help"
785 _KVMOPT_MLIST = "mlist"
786 _KVMOPT_DEVICELIST = "devicelist"
788 # Command to execute to get the output from kvm, and whether to
789 # accept the output even on failure.
791 _KVMOPT_HELP: (["--help"], False),
792 _KVMOPT_MLIST: (["-M", "?"], False),
793 _KVMOPT_DEVICELIST: (["-device", "?"], True),
797 hv_base.BaseHypervisor.__init__(self)
798 # Let's make sure the directories we need exist, even if the RUN_DIR lives
799 # in a tmpfs filesystem or has been otherwise wiped out.
800 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
801 utils.EnsureDirs(dirs)
804 def _InstancePidFile(cls, instance_name):
805 """Returns the instance pidfile.
808 return utils.PathJoin(cls._PIDS_DIR, instance_name)
811 def _InstanceUidFile(cls, instance_name):
812 """Returns the instance uidfile.
815 return utils.PathJoin(cls._UIDS_DIR, instance_name)
818 def _InstancePidInfo(cls, pid):
819 """Check pid file for instance information.
821 Check that a pid file is associated with an instance, and retrieve
822 information from its command line.
824 @type pid: string or int
825 @param pid: process id of the instance to check
827 @return: (instance_name, memory, vcpus)
828 @raise errors.HypervisorError: when an instance cannot be found
831 alive = utils.IsProcessAlive(pid)
833 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
835 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
837 cmdline = utils.ReadFile(cmdline_file)
838 except EnvironmentError, err:
839 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
846 arg_list = cmdline.split("\x00")
848 arg = arg_list.pop(0)
850 instance = arg_list.pop(0)
852 memory = int(arg_list.pop(0))
854 vcpus = int(arg_list.pop(0).split(",")[0])
857 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
860 return (instance, memory, vcpus)
862 def _InstancePidAlive(self, instance_name):
863 """Returns the instance pidfile, pid, and liveness.
865 @type instance_name: string
866 @param instance_name: instance name
868 @return: (pid file name, pid, liveness)
871 pidfile = self._InstancePidFile(instance_name)
872 pid = utils.ReadPidFile(pidfile)
876 cmd_instance = self._InstancePidInfo(pid)[0]
877 alive = (cmd_instance == instance_name)
878 except errors.HypervisorError:
881 return (pidfile, pid, alive)
883 def _CheckDown(self, instance_name):
884 """Raises an error unless the given instance is down.
887 alive = self._InstancePidAlive(instance_name)[2]
889 raise errors.HypervisorError("Failed to start instance %s: %s" %
890 (instance_name, "already running"))
893 def _InstanceMonitor(cls, instance_name):
894 """Returns the instance monitor socket name
897 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
900 def _InstanceSerial(cls, instance_name):
901 """Returns the instance serial socket name
904 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
907 def _InstanceQmpMonitor(cls, instance_name):
908 """Returns the instance serial QMP socket name
911 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
914 def _SocatUnixConsoleParams():
915 """Returns the correct parameters for socat
917 If we have a new-enough socat we can use raw mode with an escape character.
920 if constants.SOCAT_USE_ESCAPE:
921 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
923 return "echo=0,icanon=0"
926 def _InstanceKVMRuntime(cls, instance_name):
927 """Returns the instance KVM runtime filename
930 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
933 def _InstanceChrootDir(cls, instance_name):
934 """Returns the name of the KVM chroot dir of the instance
937 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
940 def _InstanceNICDir(cls, instance_name):
941 """Returns the name of the directory holding the tap device files for a
945 return utils.PathJoin(cls._NICS_DIR, instance_name)
948 def _InstanceNICFile(cls, instance_name, seq_or_uuid):
949 """Returns the name of the file containing the tap device for a given NIC
952 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq_or_uuid))
955 def _GetInstanceNICTap(cls, instance_name, nic):
956 """Returns the tap for the corresponding nic
958 Search for tap file named after NIC's uuid.
959 For old instances without uuid indexed tap files returns nothing.
963 return utils.ReadFile(cls._InstanceNICFile(instance_name, nic.uuid))
964 except EnvironmentError:
968 def _WriteInstanceNICFiles(cls, instance_name, seq, nic, tap):
969 """Write tap name to both instance NIC files
972 for ident in [seq, nic.uuid]:
973 utils.WriteFile(cls._InstanceNICFile(instance_name, ident), data=tap)
976 def _RemoveInstanceNICFiles(cls, instance_name, seq, nic):
977 """Write tap name to both instance NIC files
980 for ident in [seq, nic.uuid]:
981 utils.RemoveFile(cls._InstanceNICFile(instance_name, ident))
984 def _InstanceKeymapFile(cls, instance_name):
985 """Returns the name of the file containing the keymap for a given instance
988 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
991 def _TryReadUidFile(cls, uid_file):
992 """Try to read a uid file
995 if os.path.exists(uid_file):
997 uid = int(utils.ReadOneLineFile(uid_file))
999 except EnvironmentError:
1000 logging.warning("Can't read uid file", exc_info=True)
1001 except (TypeError, ValueError):
1002 logging.warning("Can't parse uid file contents", exc_info=True)
1006 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
1007 """Removes an instance's rutime sockets/files/dirs.
1010 # This takes info from NICDir and RuntimeFile
1011 cls._UnconfigureInstanceNICs(instance_name)
1012 utils.RemoveFile(pidfile)
1013 utils.RemoveFile(cls._InstanceMonitor(instance_name))
1014 utils.RemoveFile(cls._InstanceSerial(instance_name))
1015 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
1016 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
1017 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
1018 uid_file = cls._InstanceUidFile(instance_name)
1019 uid = cls._TryReadUidFile(uid_file)
1020 utils.RemoveFile(uid_file)
1022 uidpool.ReleaseUid(uid)
1024 shutil.rmtree(cls._InstanceNICDir(instance_name))
1025 except OSError, err:
1026 if err.errno != errno.ENOENT:
1029 chroot_dir = cls._InstanceChrootDir(instance_name)
1030 utils.RemoveDir(chroot_dir)
1031 except OSError, err:
1032 if err.errno == errno.ENOTEMPTY:
1033 # The chroot directory is expected to be empty, but it isn't.
1034 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
1037 utils.TimestampForFilename()))
1038 logging.warning("The chroot directory of instance %s can not be"
1039 " removed as it is not empty. Moving it to the"
1040 " quarantine instead. Please investigate the"
1041 " contents (%s) and clean up manually",
1042 instance_name, new_chroot_dir)
1043 utils.RenameFile(chroot_dir, new_chroot_dir)
1048 def _CreateNICEnv(instance_name, nic, tap, seq=None, instance_tags=None):
1049 """Create environment variables for a specific NIC
1051 This is needed during NIC ifup/ifdown scripts.
1052 Since instance tags may change during NIC creation and removal
1053 and because during cleanup instance object is not available we
1054 pass them only upon NIC creation (instance startup/NIC hot-plugging).
1058 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1059 "INSTANCE": instance_name,
1061 "MODE": nic.nicparams[constants.NIC_MODE],
1062 "INTERFACE_UUID": nic.uuid,
1066 env["TAGS"] = " ".join(instance_tags)
1068 # This should always be available except for old instances in the
1069 # cluster without uuid indexed tap files.
1071 env["INTERFACE"] = tap
1074 env["INTERFACE_INDEX"] = str(seq)
1080 env["INTERFACE_NAME"] = nic.name
1082 if nic.nicparams[constants.NIC_LINK]:
1083 env["LINK"] = nic.nicparams[constants.NIC_LINK]
1086 n = objects.Network.FromDict(nic.netinfo)
1087 env.update(n.HooksDict())
1089 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1090 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1095 def _ConfigureNIC(cls, instance, seq, nic, tap):
1096 """Run the network configuration script for a specified NIC
1098 @param instance: instance we're acting on
1099 @type instance: instance object
1100 @param seq: nic sequence number
1102 @param nic: nic we're acting on
1103 @type nic: nic object
1104 @param tap: the host's tap interface this NIC corresponds to
1108 env = cls._CreateNICEnv(instance.name, nic, tap, seq, instance.GetTags())
1109 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1111 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1112 " network configuration script output: %s" %
1113 (tap, result.fail_reason, result.output))
1116 def _UnconfigureNic(cls, instance_name, nic, only_local=True):
1117 """Run ifdown script for a specific NIC
1119 This is executed during instance cleanup and NIC hot-unplug
1121 @param instance: instance we're acting on
1122 @type instance: instance object
1123 @param nic: nic we're acting on
1124 @type nic: nic object
1125 @param localy: whether ifdown script should reset global conf (dns) or not
1126 @type localy: boolean
1129 tap = cls._GetInstanceNICTap(instance_name, nic)
1130 env = cls._CreateNICEnv(instance_name, nic, tap)
1131 arg2 = str(only_local).lower()
1132 result = utils.RunCmd([pathutils.KVM_IFDOWN, tap, arg2], env=env)
1134 raise errors.HypervisorError("Failed to unconfigure interface %s: %s;"
1135 " network configuration script output: %s" %
1136 (tap, result.fail_reason, result.output))
1139 def _VerifyAffinityPackage():
1140 if affinity is None:
1141 raise errors.HypervisorError("affinity Python package not"
1142 " found; cannot use CPU pinning under KVM")
1145 def _BuildAffinityCpuMask(cpu_list):
1146 """Create a CPU mask suitable for sched_setaffinity from a list of
1149 See man taskset for more info on sched_setaffinity masks.
1150 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1152 @type cpu_list: list of int
1153 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1155 @return: a bit mask of CPU affinities
1158 if cpu_list == constants.CPU_PINNING_OFF:
1159 return constants.CPU_PINNING_ALL_KVM
1161 return sum(2 ** cpu for cpu in cpu_list)
1164 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1165 """Change CPU affinity for running VM according to given CPU mask.
1167 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1168 @type cpu_mask: string
1169 @param process_id: process ID of KVM process. Used to pin entire VM
1171 @type process_id: int
1172 @param thread_dict: map of virtual CPUs to KVM thread IDs
1173 @type thread_dict: dict int:int
1176 # Convert the string CPU mask to a list of list of int's
1177 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1179 if len(cpu_list) == 1:
1180 all_cpu_mapping = cpu_list[0]
1181 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1182 # If CPU pinning has 1 entry that's "all", then do nothing
1185 # If CPU pinning has one non-all entry, map the entire VM to
1186 # one set of physical CPUs
1187 cls._VerifyAffinityPackage()
1188 affinity.set_process_affinity_mask(
1189 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1191 # The number of vCPUs mapped should match the number of vCPUs
1192 # reported by KVM. This was already verified earlier, so
1193 # here only as a sanity check.
1194 assert len(thread_dict) == len(cpu_list)
1195 cls._VerifyAffinityPackage()
1197 # For each vCPU, map it to the proper list of physical CPUs
1198 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1199 affinity.set_process_affinity_mask(thread_dict[i],
1200 cls._BuildAffinityCpuMask(vcpu))
1202 def _GetVcpuThreadIds(self, instance_name):
1203 """Get a mapping of vCPU no. to thread IDs for the instance
1205 @type instance_name: string
1206 @param instance_name: instance in question
1207 @rtype: dictionary of int:int
1208 @return: a dictionary mapping vCPU numbers to thread IDs
1212 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1213 for line in output.stdout.splitlines():
1214 match = self._CPU_INFO_RE.search(line)
1217 grp = map(int, match.groups())
1218 result[grp[0]] = grp[1]
1222 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1223 """Complete CPU pinning.
1225 @type instance_name: string
1226 @param instance_name: name of instance
1227 @type cpu_mask: string
1228 @param cpu_mask: CPU pinning mask as entered by user
1231 # Get KVM process ID, to be used if need to pin entire VM
1232 _, pid, _ = self._InstancePidAlive(instance_name)
1233 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1234 thread_dict = self._GetVcpuThreadIds(instance_name)
1235 # Run CPU pinning, based on configured mask
1236 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1238 def ListInstances(self):
1239 """Get the list of running instances.
1241 We can do this by listing our live instances directory and
1242 checking whether the associated kvm process is still alive.
1246 for name in os.listdir(self._PIDS_DIR):
1247 if self._InstancePidAlive(name)[2]:
1251 def GetInstanceInfo(self, instance_name):
1252 """Get instance properties.
1254 @type instance_name: string
1255 @param instance_name: the instance name
1256 @rtype: tuple of strings
1257 @return: (name, id, memory, vcpus, stat, times)
1260 _, pid, alive = self._InstancePidAlive(instance_name)
1264 _, memory, vcpus = self._InstancePidInfo(pid)
1269 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1271 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1272 # Will fail if ballooning is not enabled, but we can then just resort to
1274 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1275 memory = mem_bytes / 1048576
1276 except errors.HypervisorError:
1279 return (instance_name, pid, memory, vcpus, istat, times)
1281 def GetAllInstancesInfo(self):
1282 """Get properties of all instances.
1284 @return: list of tuples (name, id, memory, vcpus, stat, times)
1288 for name in os.listdir(self._PIDS_DIR):
1290 info = self.GetInstanceInfo(name)
1291 except errors.HypervisorError:
1292 # Ignore exceptions due to instances being shut down
1298 def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1300 """Generate KVM options regarding instance's block devices.
1302 @type instance: L{objects.Instance}
1303 @param instance: the instance object
1304 @type kvm_disks: list of tuples
1305 @param kvm_disks: list of tuples [(disk, link_name)..]
1306 @type kvmhelp: string
1307 @param kvmhelp: output of kvm --help
1308 @type devlist: string
1309 @param devlist: output of kvm -device ?
1311 @return: list of command line options eventually used by kvm executable
1314 hvp = instance.hvparams
1315 kernel_path = hvp[constants.HV_KERNEL_PATH]
1319 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1321 # whether this is an older KVM version that uses the boot=on flag
1323 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1326 device_driver = None
1327 disk_type = hvp[constants.HV_DISK_TYPE]
1328 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1329 if_val = ",if=%s" % self._VIRTIO
1331 if self._VIRTIO_BLK_RE.search(devlist):
1333 # will be passed in -device option as driver
1334 device_driver = self._VIRTIO_BLK_PCI
1335 except errors.HypervisorError, _:
1338 if_val = ",if=%s" % disk_type
1340 disk_cache = hvp[constants.HV_DISK_CACHE]
1341 if instance.disk_template in constants.DTS_EXT_MIRROR:
1342 if disk_cache != "none":
1343 # TODO: make this a hard error, instead of a silent overwrite
1344 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1345 " to prevent shared storage corruption on migration",
1347 cache_val = ",cache=none"
1348 elif disk_cache != constants.HT_CACHE_DEFAULT:
1349 cache_val = ",cache=%s" % disk_cache
1352 for idx, (cfdev, link_name) in enumerate(kvm_disks):
1353 if cfdev.mode != constants.DISK_RDWR:
1354 raise errors.HypervisorError("Instance has read-only disks which"
1355 " are not supported by KVM")
1356 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1359 dev_opts.extend(["-boot", "c"])
1361 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1362 boot_val = ",boot=on"
1364 # For ext we allow overriding disk_cache hypervisor params per disk
1365 disk_cache = cfdev.params.get("cache", None)
1367 cache_val = ",cache=%s" % disk_cache
1368 drive_val = "file=%s,format=raw%s%s%s" % \
1369 (link_name, if_val, boot_val, cache_val)
1372 # kvm_disks are the 4th entry of runtime file that did not exist in
1373 # the past. That means that cfdev should always have pci slot and
1374 # _GenerateDeviceKVMId() will not raise a exception.
1375 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK,
1377 drive_val += (",id=%s" % kvm_devid)
1379 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1380 dev_val = ("%s,drive=%s,id=%s" %
1381 (device_driver, kvm_devid, kvm_devid))
1383 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1384 dev_opts.extend(["-device", dev_val])
1386 # TODO: export disk geometry in IDISK_PARAMS
1387 heads = cfdev.params.get('heads', None)
1388 secs = cfdev.params.get('secs', None)
1390 nr_sectors = cfdev.size * 1024 * 1024 / 512
1391 cyls = nr_sectors / (int(heads) * int(secs))
1396 if cyls and heads and secs:
1397 drive_val += (",cyls=%d,heads=%d,secs=%d" %
1398 (cyls, int(heads), int(secs)))
1400 dev_opts.extend(["-drive", drive_val])
1404 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1406 """Generate KVM information to start an instance.
1408 @type kvmhelp: string
1409 @param kvmhelp: output of kvm --help
1410 @attention: this function must not have any side-effects; for
1411 example, it must not write to the filesystem, or read values
1412 from the current system the are expected to differ between
1413 nodes, since it is only run once at instance startup;
1414 actions/kvm arguments that can vary between systems should be
1415 done in L{_ExecuteKVMRuntime}
1418 # pylint: disable=R0912,R0914,R0915
1419 hvp = instance.hvparams
1420 self.ValidateParameters(hvp)
1422 pidfile = self._InstancePidFile(instance.name)
1423 kvm = hvp[constants.HV_KVM_PATH]
1425 # used just by the vnc server, if enabled
1426 kvm_cmd.extend(["-name", instance.name])
1427 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1429 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1430 if hvp[constants.HV_CPU_CORES]:
1431 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1432 if hvp[constants.HV_CPU_THREADS]:
1433 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1434 if hvp[constants.HV_CPU_SOCKETS]:
1435 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1437 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1439 kvm_cmd.extend(["-pidfile", pidfile])
1440 kvm_cmd.extend(["-balloon", "virtio"])
1441 kvm_cmd.extend(["-daemonize"])
1442 if not instance.hvparams[constants.HV_ACPI]:
1443 kvm_cmd.extend(["-no-acpi"])
1444 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1445 constants.INSTANCE_REBOOT_EXIT:
1446 kvm_cmd.extend(["-no-reboot"])
1448 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1450 mversion = self._GetDefaultMachineVersion(kvm)
1451 if self._MACHINE_RE.search(kvmhelp):
1452 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1453 # extra hypervisor parameters. We should also investigate whether and how
1454 # shadow_mem should be considered for the resource model.
1455 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1456 specprop = ",accel=kvm"
1459 machinespec = "%s%s" % (mversion, specprop)
1460 kvm_cmd.extend(["-machine", machinespec])
1462 kvm_cmd.extend(["-M", mversion])
1463 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1464 self._ENABLE_KVM_RE.search(kvmhelp)):
1465 kvm_cmd.extend(["-enable-kvm"])
1466 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1467 self._DISABLE_KVM_RE.search(kvmhelp)):
1468 kvm_cmd.extend(["-disable-kvm"])
1470 kernel_path = hvp[constants.HV_KERNEL_PATH]
1472 boot_cdrom = boot_floppy = boot_network = False
1474 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1475 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1476 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1479 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1482 kvm_cmd.extend(["-boot", "n"])
1484 # whether this is an older KVM version that uses the boot=on flag
1486 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1488 disk_type = hvp[constants.HV_DISK_TYPE]
1490 #Now we can specify a different device type for CDROM devices.
1491 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1492 if not cdrom_disk_type:
1493 cdrom_disk_type = disk_type
1495 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1497 options = ",format=raw,media=cdrom"
1498 # set cdrom 'if' type
1500 actual_cdrom_type = constants.HT_DISK_IDE
1501 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1502 actual_cdrom_type = "virtio"
1504 actual_cdrom_type = cdrom_disk_type
1505 if_val = ",if=%s" % actual_cdrom_type
1506 # set boot flag, if needed
1509 kvm_cmd.extend(["-boot", "d"])
1511 boot_val = ",boot=on"
1512 # and finally build the entire '-drive' value
1513 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1514 kvm_cmd.extend(["-drive", drive_val])
1516 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1518 options = ",format=raw,media=cdrom"
1519 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1520 if_val = ",if=virtio"
1522 if_val = ",if=%s" % cdrom_disk_type
1523 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1524 kvm_cmd.extend(["-drive", drive_val])
1526 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1528 options = ",format=raw,media=disk"
1530 kvm_cmd.extend(["-boot", "a"])
1531 options = "%s,boot=on" % options
1532 if_val = ",if=floppy"
1533 options = "%s%s" % (options, if_val)
1534 drive_val = "file=%s%s" % (floppy_image, options)
1535 kvm_cmd.extend(["-drive", drive_val])
1538 kvm_cmd.extend(["-kernel", kernel_path])
1539 initrd_path = hvp[constants.HV_INITRD_PATH]
1541 kvm_cmd.extend(["-initrd", initrd_path])
1542 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1543 hvp[constants.HV_KERNEL_ARGS]]
1544 if hvp[constants.HV_SERIAL_CONSOLE]:
1545 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1546 root_append.append("console=ttyS0,%s" % serial_speed)
1547 kvm_cmd.extend(["-append", " ".join(root_append)])
1549 mem_path = hvp[constants.HV_MEM_PATH]
1551 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1553 monitor_dev = ("unix:%s,server,nowait" %
1554 self._InstanceMonitor(instance.name))
1555 kvm_cmd.extend(["-monitor", monitor_dev])
1556 if hvp[constants.HV_SERIAL_CONSOLE]:
1557 serial_dev = ("unix:%s,server,nowait" %
1558 self._InstanceSerial(instance.name))
1559 kvm_cmd.extend(["-serial", serial_dev])
1561 kvm_cmd.extend(["-serial", "none"])
1563 mouse_type = hvp[constants.HV_USB_MOUSE]
1564 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1565 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1566 spice_ip_version = None
1568 kvm_cmd.extend(["-usb"])
1571 kvm_cmd.extend(["-usbdevice", mouse_type])
1572 elif vnc_bind_address:
1573 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1575 if vnc_bind_address:
1576 if netutils.IP4Address.IsValid(vnc_bind_address):
1577 if instance.network_port > constants.VNC_BASE_PORT:
1578 display = instance.network_port - constants.VNC_BASE_PORT
1579 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1580 vnc_arg = ":%d" % (display)
1582 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1584 logging.error("Network port is not a valid VNC display (%d < %d),"
1585 " not starting VNC",
1586 instance.network_port, constants.VNC_BASE_PORT)
1589 # Only allow tls and other option when not binding to a file, for now.
1590 # kvm/qemu gets confused otherwise about the filename to use.
1592 if hvp[constants.HV_VNC_TLS]:
1593 vnc_append = "%s,tls" % vnc_append
1594 if hvp[constants.HV_VNC_X509_VERIFY]:
1595 vnc_append = "%s,x509verify=%s" % (vnc_append,
1596 hvp[constants.HV_VNC_X509])
1597 elif hvp[constants.HV_VNC_X509]:
1598 vnc_append = "%s,x509=%s" % (vnc_append,
1599 hvp[constants.HV_VNC_X509])
1600 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1601 vnc_append = "%s,password" % vnc_append
1603 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1606 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1608 kvm_cmd.extend(["-vnc", vnc_arg])
1610 # FIXME: this is wrong here; the iface ip address differs
1611 # between systems, so it should be done in _ExecuteKVMRuntime
1612 if netutils.IsValidInterface(spice_bind):
1613 # The user specified a network interface, we have to figure out the IP
1615 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1616 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1618 # if the user specified an IP version and the interface does not
1619 # have that kind of IP addresses, throw an exception
1620 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1621 if not addresses[spice_ip_version]:
1622 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1623 " for %s" % (spice_ip_version,
1626 # the user did not specify an IP version, we have to figure it out
1627 elif (addresses[constants.IP4_VERSION] and
1628 addresses[constants.IP6_VERSION]):
1629 # we have both ipv4 and ipv6, let's use the cluster default IP
1631 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1632 spice_ip_version = \
1633 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1634 elif addresses[constants.IP4_VERSION]:
1635 spice_ip_version = constants.IP4_VERSION
1636 elif addresses[constants.IP6_VERSION]:
1637 spice_ip_version = constants.IP6_VERSION
1639 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1640 " for %s" % (spice_bind))
1642 spice_address = addresses[spice_ip_version][0]
1645 # spice_bind is known to be a valid IP address, because
1646 # ValidateParameters checked it.
1647 spice_address = spice_bind
1649 spice_arg = "addr=%s" % spice_address
1650 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1651 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1652 (spice_arg, instance.network_port,
1653 pathutils.SPICE_CACERT_FILE))
1654 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1655 (spice_arg, pathutils.SPICE_CERT_FILE,
1656 pathutils.SPICE_CERT_FILE))
1657 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1659 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1661 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1663 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1664 spice_arg = "%s,disable-ticketing" % spice_arg
1666 if spice_ip_version:
1667 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1669 # Image compression options
1670 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1671 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1672 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1674 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1676 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1678 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1680 # Video stream detection
1681 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1683 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1685 # Audio compression, by default in qemu-kvm it is on
1686 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1687 spice_arg = "%s,playback-compression=off" % spice_arg
1688 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1689 spice_arg = "%s,agent-mouse=off" % spice_arg
1691 # Enable the spice agent communication channel between the host and the
1693 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1696 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1698 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1700 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1701 kvm_cmd.extend(["-spice", spice_arg])
1704 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1705 # also works in earlier versions though (tested with 1.1 and 1.3)
1706 if self._DISPLAY_RE.search(kvmhelp):
1707 kvm_cmd.extend(["-display", "none"])
1709 kvm_cmd.extend(["-nographic"])
1711 if hvp[constants.HV_USE_LOCALTIME]:
1712 kvm_cmd.extend(["-localtime"])
1714 if hvp[constants.HV_KVM_USE_CHROOT]:
1715 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1717 # Add qemu-KVM -cpu param
1718 if hvp[constants.HV_CPU_TYPE]:
1719 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1721 # As requested by music lovers
1722 if hvp[constants.HV_SOUNDHW]:
1723 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1725 # Pass a -vga option if requested, or if spice is used, for backwards
1727 if hvp[constants.HV_VGA]:
1728 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1730 kvm_cmd.extend(["-vga", "qxl"])
1732 # Various types of usb devices, comma separated
1733 if hvp[constants.HV_USB_DEVICES]:
1734 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1735 kvm_cmd.extend(["-usbdevice", dev])
1737 if hvp[constants.HV_KVM_EXTRA]:
1738 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1740 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1742 for disk, link_name in block_devices:
1743 _UpdatePCISlots(disk, pci_reservations)
1744 kvm_disks.append((disk, link_name))
1747 for nic in instance.nics:
1748 _UpdatePCISlots(nic, pci_reservations)
1749 kvm_nics.append(nic)
1753 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1755 def _WriteKVMRuntime(self, instance_name, data):
1756 """Write an instance's KVM runtime
1760 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1762 except EnvironmentError, err:
1763 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1766 def _ReadKVMRuntime(cls, instance_name):
1767 """Read an instance's KVM runtime
1771 file_content = utils.ReadFile(cls._InstanceKVMRuntime(instance_name))
1772 except EnvironmentError, err:
1773 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1776 def _SaveKVMRuntime(self, instance, kvm_runtime):
1777 """Save an instance's KVM runtime
1780 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1782 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1783 serialized_disks = [(blk.ToDict(), link)
1784 for blk, link in kvm_disks]
1785 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1788 self._WriteKVMRuntime(instance.name, serialized_form)
1791 def _LoadKVMRuntime(cls, instance_name, serialized_runtime=None):
1792 """Load an instance's KVM runtime
1795 if not serialized_runtime:
1796 serialized_runtime = cls._ReadKVMRuntime(instance_name)
1798 return _AnalyzeSerializedRuntime(serialized_runtime)
1800 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1801 """Run the KVM cmd and check for errors
1804 @param name: instance name
1805 @type kvm_cmd: list of strings
1806 @param kvm_cmd: runcmd input for kvm
1807 @type tap_fds: list of int
1808 @param tap_fds: fds of tap devices opened by Ganeti
1812 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1815 utils_wrapper.CloseFdNoError(fd)
1818 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1819 (name, result.fail_reason, result.output))
1820 if not self._InstancePidAlive(name)[2]:
1821 raise errors.HypervisorError("Failed to start instance %s" % name)
1823 # too many local variables
1824 # pylint: disable=R0914
1825 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1826 """Execute a KVM cmd, after completing it with some last minute data.
1828 @type incoming: tuple of strings
1829 @param incoming: (target_host_ip, port)
1830 @type kvmhelp: string
1831 @param kvmhelp: output of kvm --help
1834 # Small _ExecuteKVMRuntime hv parameters programming howto:
1835 # - conf_hvp contains the parameters as configured on ganeti. they might
1836 # have changed since the instance started; only use them if the change
1837 # won't affect the inside of the instance (which hasn't been rebooted).
1838 # - up_hvp contains the parameters as they were when the instance was
1839 # started, plus any new parameter which has been added between ganeti
1840 # versions: it is paramount that those default to a value which won't
1841 # affect the inside of the instance as well.
1842 conf_hvp = instance.hvparams
1843 name = instance.name
1844 self._CheckDown(name)
1848 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1849 # the first element of kvm_cmd is always the path to the kvm binary
1850 kvm_path = kvm_cmd[0]
1851 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1853 # We know it's safe to run as a different user upon migration, so we'll use
1854 # the latest conf, from conf_hvp.
1855 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1856 if security_model == constants.HT_SM_USER:
1857 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1859 keymap = conf_hvp[constants.HV_KEYMAP]
1861 keymap_path = self._InstanceKeymapFile(name)
1862 # If a keymap file is specified, KVM won't use its internal defaults. By
1863 # first including the "en-us" layout, an error on loading the actual
1864 # layout (e.g. because it can't be found) won't lead to a non-functional
1865 # keyboard. A keyboard with incorrect keys is still better than none.
1866 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1867 kvm_cmd.extend(["-k", keymap_path])
1869 # We have reasons to believe changing something like the nic driver/type
1870 # upon migration won't exactly fly with the instance kernel, so for nic
1871 # related parameters we'll use up_hvp
1874 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1876 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1880 kvm_cmd.extend(bdev_opts)
1883 kvm_cmd.extend(["-net", "none"])
1887 nic_type = up_hvp[constants.HV_NIC_TYPE]
1888 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1889 nic_model = self._VIRTIO
1891 if self._VIRTIO_NET_RE.search(devlist):
1892 nic_model = self._VIRTIO_NET_PCI
1893 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1894 except errors.HypervisorError, _:
1895 # Older versions of kvm don't support DEVICE_LIST, but they don't
1896 # have new virtio syntax either.
1899 if up_hvp[constants.HV_VHOST_NET]:
1900 # check for vhost_net support
1901 if self._VHOST_RE.search(kvmhelp):
1902 tap_extra = ",vhost=on"
1904 raise errors.HypervisorError("vhost_net is configured"
1905 " but it is not available")
1907 nic_model = nic_type
1909 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1911 for nic_seq, nic in enumerate(kvm_nics):
1912 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1913 tapfds.append(tapfd)
1914 taps.append(tapname)
1915 if kvm_supports_netdev:
1916 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1918 # kvm_nics already exist in old runtime files and thus there might
1919 # be some entries without pci slot (therefore try: except:)
1920 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1922 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1923 except errors.HotplugError:
1924 netdev = "netdev%d" % nic_seq
1925 nic_val += (",netdev=%s" % netdev)
1926 tap_val = ("type=tap,id=%s,fd=%d%s" %
1927 (netdev, tapfd, tap_extra))
1928 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1930 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1932 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1933 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1936 target, port = incoming
1937 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1939 # Changing the vnc password doesn't bother the guest that much. At most it
1940 # will surprise people who connect to it. Whether positively or negatively
1942 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1946 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1947 except EnvironmentError, err:
1948 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1949 % (vnc_pwd_file, err))
1951 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1952 utils.EnsureDirs([(self._InstanceChrootDir(name),
1953 constants.SECURE_DIR_MODE)])
1955 # Automatically enable QMP if version is >= 0.14
1956 if self._QMP_RE.search(kvmhelp):
1957 logging.debug("Enabling QMP")
1958 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1959 self._InstanceQmpMonitor(instance.name)])
1961 # Configure the network now for starting instances and bridged interfaces,
1962 # during FinalizeMigration for incoming instances' routed interfaces
1963 for nic_seq, nic in enumerate(kvm_nics):
1965 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1967 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1969 # CPU affinity requires kvm to start paused, so we set this flag if the
1970 # instance is not already paused and if we are not going to accept a
1971 # migrating instance. In the latter case, pausing is not needed.
1972 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1973 if start_kvm_paused:
1974 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1976 # Note: CPU pinning is using up_hvp since changes take effect
1977 # during instance startup anyway, and to avoid problems when soft
1978 # rebooting the instance.
1980 if up_hvp.get(constants.HV_CPU_MASK, None):
1983 if security_model == constants.HT_SM_POOL:
1984 ss = ssconf.SimpleStore()
1985 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1986 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1987 uid = uidpool.RequestUnusedUid(all_uids)
1989 username = pwd.getpwuid(uid.GetUid()).pw_name
1990 kvm_cmd.extend(["-runas", username])
1991 self._RunKVMCmd(name, kvm_cmd, tapfds)
1993 uidpool.ReleaseUid(uid)
1997 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1999 self._RunKVMCmd(name, kvm_cmd, tapfds)
2001 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
2002 constants.RUN_DIRS_MODE)])
2003 for nic_seq, tap in enumerate(taps):
2004 nic = kvm_nics[nic_seq]
2005 self._WriteInstanceNICFiles(instance.name, nic_seq, nic, tap)
2008 change_cmd = "change vnc password %s" % vnc_pwd
2009 self._CallMonitorCommand(instance.name, change_cmd)
2011 # Setting SPICE password. We are not vulnerable to malicious passwordless
2012 # connection attempts because SPICE by default does not allow connections
2013 # if neither a password nor the "disable_ticketing" options are specified.
2014 # As soon as we send the password via QMP, that password is a valid ticket
2016 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
2017 if spice_password_file:
2020 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
2021 except EnvironmentError, err:
2022 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
2023 % (spice_password_file, err))
2025 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
2028 "protocol": "spice",
2029 "password": spice_pwd,
2031 qmp.Execute("set_password", arguments)
2033 for filename in temp_files:
2034 utils.RemoveFile(filename)
2036 # If requested, set CPU affinity and resume instance execution
2038 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
2040 start_memory = self._InstanceStartupMemory(instance)
2041 if start_memory < instance.beparams[constants.BE_MAXMEM]:
2042 self.BalloonInstanceMemory(instance, start_memory)
2044 if start_kvm_paused:
2045 # To control CPU pinning, ballooning, and vnc/spice passwords
2046 # the VM was started in a frozen state. If freezing was not
2047 # explicitly requested resume the vm status.
2048 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2050 def StartInstance(self, instance, block_devices, startup_paused):
2051 """Start an instance.
2054 self._CheckDown(instance.name)
2055 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2056 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2057 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
2058 startup_paused, kvmhelp)
2059 self._SaveKVMRuntime(instance, kvm_runtime)
2060 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2062 def _CallMonitorCommand(self, instance_name, command, timeout=None):
2063 """Invoke a command on the instance monitor.
2066 if timeout is not None:
2067 timeout_cmd = "timeout %s" % (timeout, )
2071 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
2072 # version. The monitor protocol is designed for human consumption, whereas
2073 # QMP is made for programmatic usage. In the worst case QMP can also
2074 # execute monitor commands. As it is, all calls to socat take at least
2075 # 500ms and likely more: socat can't detect the end of the reply and waits
2076 # for 500ms of no data received before exiting (500 ms is the default for
2077 # the "-t" parameter).
2078 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
2079 (utils.ShellQuote(command),
2081 constants.SOCAT_PATH,
2082 utils.ShellQuote(self._InstanceMonitor(instance_name))))
2084 result = utils.RunCmd(socat)
2086 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2088 (command, instance_name, result.fail_reason, result.output))
2089 raise errors.HypervisorError(msg)
2093 def _GetFreePCISlot(self, instance, dev):
2094 """Get the first available pci slot of a runnung instance.
2097 slots = bitarray(32)
2098 slots.setall(False) # pylint: disable=E1101
2099 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2100 for line in output.stdout.splitlines():
2101 match = self._INFO_PCI_RE.search(line)
2103 slot = int(match.group(1))
2106 [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2108 raise errors.HypervisorError("All PCI slots occupied")
2112 def VerifyHotplugSupport(self, instance, action, dev_type):
2113 """Verifies that hotplug is supported.
2115 Hotplug is *not* supported in case of:
2116 - security models and chroot (disk hotplug)
2117 - fdsend module is missing (nic hot-add)
2119 @raise errors.HypervisorError: in one of the previous cases
2122 if dev_type == constants.HOTPLUG_TARGET_DISK:
2123 hvp = instance.hvparams
2124 security_model = hvp[constants.HV_SECURITY_MODEL]
2125 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2127 raise errors.HotplugError("Disk hotplug is not supported"
2128 " in case of chroot.")
2129 if security_model != constants.HT_SM_NONE:
2130 raise errors.HotplugError("Disk Hotplug is not supported in case"
2131 " security models are used.")
2133 if (dev_type == constants.HOTPLUG_TARGET_NIC and
2134 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2135 raise errors.HotplugError("Cannot hot-add NIC."
2136 " fdsend python module is missing.")
2138 def HotplugSupported(self, instance):
2139 """Checks if hotplug is generally supported.
2141 Hotplug is *not* supported in case of:
2142 - qemu versions < 1.0
2143 - for stopped instances
2145 @raise errors.HypervisorError: in one of the previous cases
2149 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2150 except errors.HypervisorError:
2151 raise errors.HotplugError("Instance is probably down")
2153 # TODO: search for netdev_add, drive_add, device_add.....
2154 match = self._INFO_VERSION_RE.search(output.stdout)
2156 raise errors.HotplugError("Cannot parse qemu version via monitor")
2158 v_major, v_min, _, _ = match.groups()
2159 if (int(v_major), int(v_min)) < (1, 0):
2160 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2162 def _CallHotplugCommands(self, name, cmds):
2164 self._CallMonitorCommand(name, c)
2167 def _VerifyHotplugCommand(self, instance_name, device, dev_type,
2169 """Checks if a previous hotplug command has succeeded.
2171 It issues info pci monitor command and checks depending on should_exist
2172 value if an entry with PCI slot and device ID is found or not.
2174 @raise errors.HypervisorError: if result is not the expected one
2177 output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
2178 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2180 self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
2181 if match and not should_exist:
2182 msg = "Device %s should have been removed but is still there" % kvm_devid
2183 raise errors.HypervisorError(msg)
2185 if not match and should_exist:
2186 msg = "Device %s should have been added but is missing" % kvm_devid
2187 raise errors.HypervisorError(msg)
2189 logging.info("Device %s has been correctly hot-plugged", kvm_devid)
2191 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2192 """ Helper method to hot-add a new device
2194 It gets free pci slot generates the device name and invokes the
2195 device specific method.
2198 # in case of hot-mod this is given
2199 if device.pci is None:
2200 self._GetFreePCISlot(instance, device)
2201 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2202 runtime = self._LoadKVMRuntime(instance.name)
2203 if dev_type == constants.HOTPLUG_TARGET_DISK:
2204 cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
2206 cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2207 (hex(device.pci), kvm_devid, kvm_devid)]
2208 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2209 (tap, fd) = _OpenTap()
2210 self._ConfigureNIC(instance, seq, device, tap)
2211 self._PassTapFd(instance, fd, device)
2212 cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
2213 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2214 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2215 cmds += ["device_add %s" % args]
2216 self._WriteInstanceNICFiles(instance.name, seq, device, tap)
2218 self._CallHotplugCommands(instance.name, cmds)
2219 self._VerifyHotplugCommand(instance.name, device, dev_type, True)
2220 # update relevant entries in runtime file
2221 index = _DEVICE_RUNTIME_INDEX[dev_type]
2222 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2223 runtime[index].append(entry)
2224 self._SaveKVMRuntime(instance, runtime)
2226 def HotDelDevice(self, instance, dev_type, device, _, seq):
2227 """ Helper method for hot-del device
2229 It gets device info from runtime file, generates the device name and
2230 invokes the device specific method.
2233 runtime = self._LoadKVMRuntime(instance.name)
2234 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2235 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2236 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2237 if dev_type == constants.HOTPLUG_TARGET_DISK:
2238 cmds = ["device_del %s" % kvm_devid]
2239 cmds += ["drive_del %s" % kvm_devid]
2240 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2241 cmds = ["device_del %s" % kvm_devid]
2242 cmds += ["netdev_del %s" % kvm_devid]
2243 self._UnconfigureNic(instance.name, kvm_device, False)
2244 self._RemoveInstanceNICFiles(instance.name, seq, device)
2245 self._CallHotplugCommands(instance.name, cmds)
2246 self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
2247 index = _DEVICE_RUNTIME_INDEX[dev_type]
2248 runtime[index].remove(entry)
2249 self._SaveKVMRuntime(instance, runtime)
2251 return kvm_device.pci
2253 def HotModDevice(self, instance, dev_type, device, _, seq):
2254 """ Helper method for hot-mod device
2256 It gets device info from runtime file, generates the device name and
2257 invokes the device specific method. Currently only NICs support hot-mod
2260 if dev_type == constants.HOTPLUG_TARGET_NIC:
2261 # putting it back in the same pci slot
2262 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2263 # TODO: remove sleep when socat gets removed
2264 self.HotAddDevice(instance, dev_type, device, _, seq)
2266 def _PassTapFd(self, instance, fd, nic):
2267 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2270 # TODO: factor out code related to unix sockets.
2271 # squash common parts between monitor and qmp
2272 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2273 command = "getfd %s\n" % kvm_devid
2275 logging.info("%s", fds)
2277 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2279 fdsend.sendfds(monsock.sock, command, fds=fds)
2284 def _ParseKVMVersion(cls, text):
2285 """Parse the KVM version from the --help output.
2288 @param text: output of kvm --help
2289 @return: (version, v_maj, v_min, v_rev)
2290 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2293 match = cls._VERSION_RE.search(text.splitlines()[0])
2295 raise errors.HypervisorError("Unable to get KVM version")
2297 v_all = match.group(0)
2298 v_maj = int(match.group(1))
2299 v_min = int(match.group(2))
2301 v_rev = int(match.group(4))
2304 return (v_all, v_maj, v_min, v_rev)
2307 def _GetKVMOutput(cls, kvm_path, option):
2308 """Return the output of a kvm invocation
2310 @type kvm_path: string
2311 @param kvm_path: path to the kvm executable
2312 @type option: a key of _KVMOPTS_CMDS
2313 @param option: kvm option to fetch the output from
2314 @return: output a supported kvm invocation
2315 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2318 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2320 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2322 result = utils.RunCmd([kvm_path] + optlist)
2323 if result.failed and not can_fail:
2324 raise errors.HypervisorError("Unable to get KVM %s output" %
2326 return result.output
2329 def _GetKVMVersion(cls, kvm_path):
2330 """Return the installed KVM version.
2332 @return: (version, v_maj, v_min, v_rev)
2333 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2336 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2339 def _GetDefaultMachineVersion(cls, kvm_path):
2340 """Return the default hardware revision (e.g. pc-1.1)
2343 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2344 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2346 return match.group(1)
2350 def StopInstance(self, instance, force=False, retry=False, name=None,
2352 """Stop an instance.
2355 assert(timeout is None or force is not None)
2357 if name is not None and not force:
2358 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2360 name = instance.name
2361 acpi = instance.hvparams[constants.HV_ACPI]
2364 _, pid, alive = self._InstancePidAlive(name)
2365 if pid > 0 and alive:
2366 if force or not acpi:
2367 utils.KillProcess(pid)
2369 self._CallMonitorCommand(name, "system_powerdown", timeout)
2372 def _UnconfigureInstanceNICs(cls, instance_name, info=None):
2373 """Get runtime NICs of an instance and unconfigure them
2376 _, kvm_nics, __, ___ = cls._LoadKVMRuntime(instance_name, info)
2377 for nic in kvm_nics:
2378 cls._UnconfigureNic(instance_name, nic)
2380 def CleanupInstance(self, instance_name):
2381 """Cleanup after a stopped instance
2384 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2385 if pid > 0 and alive:
2386 raise errors.HypervisorError("Cannot cleanup a live instance")
2387 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2389 def RebootInstance(self, instance):
2390 """Reboot an instance.
2393 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2394 # socket the instance will stop, but now power up again. So we'll resort
2395 # to shutdown and restart.
2396 _, _, alive = self._InstancePidAlive(instance.name)
2398 raise errors.HypervisorError("Failed to reboot instance %s:"
2399 " not running" % instance.name)
2400 # StopInstance will delete the saved KVM runtime so:
2401 # ...first load it...
2402 kvm_runtime = self._LoadKVMRuntime(instance.name)
2403 # ...now we can safely call StopInstance...
2404 if not self.StopInstance(instance):
2405 self.StopInstance(instance, force=True)
2406 # ...and finally we can save it again, and execute it...
2407 self._SaveKVMRuntime(instance, kvm_runtime)
2408 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2409 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2410 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2412 def MigrationInfo(self, instance):
2413 """Get instance information to perform a migration.
2415 @type instance: L{objects.Instance}
2416 @param instance: instance to be migrated
2418 @return: content of the KVM runtime file
2421 return self._ReadKVMRuntime(instance.name)
2423 def AcceptInstance(self, instance, info, target):
2424 """Prepare to accept an instance.
2426 @type instance: L{objects.Instance}
2427 @param instance: instance to be accepted
2429 @param info: content of the KVM runtime file on the source node
2430 @type target: string
2431 @param target: target host (usually ip), on this node
2434 kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2435 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2436 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2437 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2438 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2439 incoming=incoming_address)
2441 def FinalizeMigrationDst(self, instance, info, success):
2442 """Finalize the instance migration on the target node.
2444 Stop the incoming mode KVM.
2446 @type instance: L{objects.Instance}
2447 @param instance: instance whose migration is being finalized
2451 kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2452 kvm_nics = kvm_runtime[1]
2454 for nic_seq, nic in enumerate(kvm_nics):
2455 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2456 # Bridged interfaces have already been configured
2459 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2460 except EnvironmentError, err:
2461 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2462 instance.name, nic_seq, str(err))
2465 self._ConfigureNIC(instance, nic_seq, nic, tap)
2466 except errors.HypervisorError, err:
2467 logging.warning(str(err))
2469 self._WriteKVMRuntime(instance.name, info)
2471 self._UnconfigureInstanceNICs(instance.name, info)
2472 self.StopInstance(instance, force=True)
2474 def MigrateInstance(self, instance, target, live):
2475 """Migrate an instance to a target node.
2477 The migration will not be attempted if the instance is not
2480 @type instance: L{objects.Instance}
2481 @param instance: the instance to be migrated
2482 @type target: string
2483 @param target: ip address of the target node
2485 @param live: perform a live migration
2488 instance_name = instance.name
2489 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2490 _, _, alive = self._InstancePidAlive(instance_name)
2492 raise errors.HypervisorError("Instance not running, cannot migrate")
2495 self._CallMonitorCommand(instance_name, "stop")
2497 migrate_command = ("migrate_set_speed %dm" %
2498 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2499 self._CallMonitorCommand(instance_name, migrate_command)
2501 migrate_command = ("migrate_set_downtime %dms" %
2502 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2503 self._CallMonitorCommand(instance_name, migrate_command)
2505 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2506 self._CallMonitorCommand(instance_name, migrate_command)
2508 def FinalizeMigrationSource(self, instance, success, live):
2509 """Finalize the instance migration on the source node.
2511 @type instance: L{objects.Instance}
2512 @param instance: the instance that was migrated
2514 @param success: whether the migration succeeded or not
2516 @param live: whether the user requested a live migration or not
2520 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2521 utils.KillProcess(pid)
2522 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2524 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2526 def GetMigrationStatus(self, instance):
2527 """Get the migration status
2529 @type instance: L{objects.Instance}
2530 @param instance: the instance that is being migrated
2531 @rtype: L{objects.MigrationStatus}
2532 @return: the status of the current migration (one of
2533 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2534 progress info that can be retrieved from the hypervisor
2537 info_command = "info migrate"
2538 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2539 result = self._CallMonitorCommand(instance.name, info_command)
2540 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2542 if not result.stdout:
2543 logging.info("KVM: empty 'info migrate' result")
2545 logging.warning("KVM: unknown 'info migrate' result: %s",
2548 status = match.group(1)
2549 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2550 migration_status = objects.MigrationStatus(status=status)
2551 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2553 migration_status.transferred_ram = match.group("transferred")
2554 migration_status.total_ram = match.group("total")
2556 return migration_status
2558 logging.warning("KVM: unknown migration status '%s'", status)
2560 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2562 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2564 def BalloonInstanceMemory(self, instance, mem):
2565 """Balloon an instance memory to a certain value.
2567 @type instance: L{objects.Instance}
2568 @param instance: instance to be accepted
2570 @param mem: actual memory size to use for instance runtime
2573 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2575 def GetNodeInfo(self):
2576 """Return information about the node.
2578 @return: a dict with the following keys (values in MiB):
2579 - memory_total: the total memory size on the node
2580 - memory_free: the available memory on the node for instances
2581 - memory_dom0: the memory used by the node itself, if available
2582 - hv_version: the hypervisor version in the form (major, minor,
2586 result = self.GetLinuxNodeInfo()
2587 # FIXME: this is the global kvm version, but the actual version can be
2588 # customized as an hv parameter. we should use the nodegroup's default kvm
2589 # path parameter here.
2590 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2591 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2595 def GetInstanceConsole(cls, instance, hvparams, beparams):
2596 """Return a command for connecting to the console of an instance.
2599 if hvparams[constants.HV_SERIAL_CONSOLE]:
2600 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2601 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2602 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2603 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2604 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2605 return objects.InstanceConsole(instance=instance.name,
2606 kind=constants.CONS_SSH,
2607 host=instance.primary_node,
2608 user=constants.SSH_CONSOLE_USER,
2611 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2612 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2613 display = instance.network_port - constants.VNC_BASE_PORT
2614 return objects.InstanceConsole(instance=instance.name,
2615 kind=constants.CONS_VNC,
2616 host=vnc_bind_address,
2617 port=instance.network_port,
2620 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2622 return objects.InstanceConsole(instance=instance.name,
2623 kind=constants.CONS_SPICE,
2625 port=instance.network_port)
2627 return objects.InstanceConsole(instance=instance.name,
2628 kind=constants.CONS_MESSAGE,
2629 message=("No serial shell for instance %s" %
2633 """Verify the hypervisor.
2635 Check that the required binaries exist.
2637 @return: Problem description if something is wrong, C{None} otherwise
2641 # FIXME: this is the global kvm binary, but the actual path can be
2642 # customized as an hv parameter; we should use the nodegroup's
2643 # default kvm path parameter here.
2644 if not os.path.exists(constants.KVM_PATH):
2645 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2646 if not os.path.exists(constants.SOCAT_PATH):
2647 msgs.append("The socat binary ('%s') does not exist" %
2648 constants.SOCAT_PATH)
2650 return self._FormatVerifyResults(msgs)
2653 def CheckParameterSyntax(cls, hvparams):
2654 """Check the given parameters for validity.
2656 @type hvparams: dict
2657 @param hvparams: dictionary with parameter names/value
2658 @raise errors.HypervisorError: when a parameter is not valid
2661 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2663 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2665 if not hvparams[constants.HV_ROOT_PATH]:
2666 raise errors.HypervisorError("Need a root partition for the instance,"
2667 " if a kernel is defined")
2669 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2670 not hvparams[constants.HV_VNC_X509]):
2671 raise errors.HypervisorError("%s must be defined, if %s is" %
2672 (constants.HV_VNC_X509,
2673 constants.HV_VNC_X509_VERIFY))
2675 if hvparams[constants.HV_SERIAL_CONSOLE]:
2676 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2677 valid_speeds = constants.VALID_SERIAL_SPEEDS
2678 if not serial_speed or serial_speed not in valid_speeds:
2679 raise errors.HypervisorError("Invalid serial console speed, must be"
2681 utils.CommaJoin(valid_speeds))
2683 boot_order = hvparams[constants.HV_BOOT_ORDER]
2684 if (boot_order == constants.HT_BO_CDROM and
2685 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2686 raise errors.HypervisorError("Cannot boot from cdrom without an"
2689 security_model = hvparams[constants.HV_SECURITY_MODEL]
2690 if security_model == constants.HT_SM_USER:
2691 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2692 raise errors.HypervisorError("A security domain (user to run kvm as)"
2693 " must be specified")
2694 elif (security_model == constants.HT_SM_NONE or
2695 security_model == constants.HT_SM_POOL):
2696 if hvparams[constants.HV_SECURITY_DOMAIN]:
2697 raise errors.HypervisorError("Cannot have a security domain when the"
2698 " security model is 'none' or 'pool'")
2700 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2701 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2703 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2704 # if an IP version is specified, the spice_bind parameter must be an
2706 if (netutils.IP4Address.IsValid(spice_bind) and
2707 spice_ip_version != constants.IP4_VERSION):
2708 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2709 " the specified IP version is %s" %
2710 (spice_bind, spice_ip_version))
2712 if (netutils.IP6Address.IsValid(spice_bind) and
2713 spice_ip_version != constants.IP6_VERSION):
2714 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2715 " the specified IP version is %s" %
2716 (spice_bind, spice_ip_version))
2718 # All the other SPICE parameters depend on spice_bind being set. Raise an
2719 # error if any of them is set without it.
2720 for param in _SPICE_ADDITIONAL_PARAMS:
2722 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2723 (param, constants.HV_KVM_SPICE_BIND))
2726 def ValidateParameters(cls, hvparams):
2727 """Check the given parameters for validity.
2729 @type hvparams: dict
2730 @param hvparams: dictionary with parameter names/value
2731 @raise errors.HypervisorError: when a parameter is not valid
2734 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2736 kvm_path = hvparams[constants.HV_KVM_PATH]
2738 security_model = hvparams[constants.HV_SECURITY_MODEL]
2739 if security_model == constants.HT_SM_USER:
2740 username = hvparams[constants.HV_SECURITY_DOMAIN]
2742 pwd.getpwnam(username)
2744 raise errors.HypervisorError("Unknown security domain user %s"
2747 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2749 # only one of VNC and SPICE can be used currently.
2750 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2751 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2752 " only one of them can be used at a"
2755 # check that KVM supports SPICE
2756 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2757 if not cls._SPICE_RE.search(kvmhelp):
2758 raise errors.HypervisorError("SPICE is configured, but it is not"
2759 " supported according to 'kvm --help'")
2761 # if spice_bind is not an IP address, it must be a valid interface
2762 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2763 netutils.IP6Address.IsValid(spice_bind))
2764 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2765 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2766 " a valid IP address or interface name" %
2767 constants.HV_KVM_SPICE_BIND)
2769 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2771 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2772 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2773 raise errors.HypervisorError("Unsupported machine version: %s" %
2777 def PowercycleNode(cls):
2778 """KVM powercycle, just a wrapper over Linux powercycle.
2781 cls.LinuxPowercycle()