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 _GetFreeSlot(slots, slot=None, reserve=False):
147 """Helper method to get first available slot in a bitarray
149 @type slots: bitarray
150 @param slots: the bitarray to operate on
152 @param slot: if given we check whether the slot is free
153 @type reserve: boolean
154 @param reserve: whether to reserve the first available slot or not
155 @return: the idx of the (first) available slot
156 @raise errors.HotplugError: If all slots in a bitarray are occupied
157 or the given slot is not free.
161 assert slot < len(slots)
163 raise errors.HypervisorError("Slots %d occupied" % slot)
166 avail = slots.search(_AVAILABLE_PCI_SLOT, 1)
168 raise errors.HypervisorError("All slots occupied")
178 def _GetExistingDeviceInfo(dev_type, device, runtime):
179 """Helper function to get an existing device inside the runtime file
181 Used when an instance is running. Load kvm runtime file and search
182 for a device based on its type and uuid.
184 @type dev_type: sting
185 @param dev_type: device type of param dev
186 @type device: L{objects.Disk} or L{objects.NIC}
187 @param device: the device object for which we generate a kvm name
188 @type runtime: tuple (cmd, nics, hvparams, disks)
189 @param runtime: the runtime data to search for the device
190 @raise errors.HotplugError: in case the requested device does not
191 exist (e.g. device has been added without --hotplug option) or
192 device info has not pci slot (e.g. old devices in the cluster)
195 index = _DEVICE_RUNTIME_INDEX[dev_type]
196 found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
198 raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
199 (dev_type, device.uuid))
204 def _UpgradeSerializedRuntime(serialized_runtime):
205 """Upgrade runtime data
207 Remove any deprecated fields or change the format of the data.
208 The runtime files are not upgraded when Ganeti is upgraded, so the required
209 modification have to be performed here.
211 @type serialized_runtime: string
212 @param serialized_runtime: raw text data read from actual runtime file
213 @return: (cmd, nic dicts, hvparams, bdev dicts)
217 loaded_runtime = serializer.Load(serialized_runtime)
218 kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
219 if len(loaded_runtime) >= 4:
220 serialized_disks = loaded_runtime[3]
222 serialized_disks = []
224 for nic in serialized_nics:
225 # Add a dummy uuid slot if an pre-2.8 NIC is found
226 if "uuid" not in nic:
227 nic["uuid"] = utils.NewUUID()
229 return kvm_cmd, serialized_nics, hvparams, serialized_disks
232 def _AnalyzeSerializedRuntime(serialized_runtime):
233 """Return runtime entries for a serialized runtime file
235 @type serialized_runtime: string
236 @param serialized_runtime: raw text data read from actual runtime file
237 @return: (cmd, nics, hvparams, bdevs)
241 kvm_cmd, serialized_nics, hvparams, serialized_disks = \
242 _UpgradeSerializedRuntime(serialized_runtime)
243 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
244 kvm_disks = [(objects.Disk.FromDict(sdisk), link)
245 for sdisk, link in serialized_disks]
247 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
250 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
251 """Retrieves supported TUN features from file descriptor.
253 @see: L{_ProbeTapVnetHdr}
256 req = struct.pack("I", 0)
258 buf = _ioctl(fd, TUNGETFEATURES, req)
259 except EnvironmentError, err:
260 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
263 (flags, ) = struct.unpack("I", buf)
267 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
268 """Check whether to enable the IFF_VNET_HDR flag.
270 To do this, _all_ of the following conditions must be met:
271 1. TUNGETFEATURES ioctl() *must* be implemented
272 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
273 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
274 drivers/net/tun.c there is no way to test this until after the tap device
275 has been created using TUNSETIFF, and there is no way to change the
276 IFF_VNET_HDR flag after creating the interface, catch-22! However both
277 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
278 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
281 @param fd: the file descriptor of /dev/net/tun
284 flags = _features_fn(fd)
290 result = bool(flags & IFF_VNET_HDR)
293 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
298 def _OpenTap(vnet_hdr=True):
299 """Open a new tap device and return its file descriptor.
301 This is intended to be used by a qemu-type hypervisor together with the -net
302 tap,fd=<fd> command line parameter.
304 @type vnet_hdr: boolean
305 @param vnet_hdr: Enable the VNET Header
306 @return: (ifname, tapfd)
311 tapfd = os.open("/dev/net/tun", os.O_RDWR)
312 except EnvironmentError:
313 raise errors.HypervisorError("Failed to open /dev/net/tun")
315 flags = IFF_TAP | IFF_NO_PI
317 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
318 flags |= IFF_VNET_HDR
320 # The struct ifreq ioctl request (see netdevice(7))
321 ifr = struct.pack("16sh", "", flags)
324 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
325 except EnvironmentError, err:
326 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
329 # Get the interface name from the ioctl
330 ifname = struct.unpack("16sh", res)[0].strip("\x00")
331 return (ifname, tapfd)
335 """QEMU Messaging Protocol (QMP) message.
338 def __init__(self, data):
339 """Creates a new QMP message based on the passed data.
342 if not isinstance(data, dict):
343 raise TypeError("QmpMessage must be initialized with a dict")
347 def __getitem__(self, field_name):
348 """Get the value of the required field if present, or None.
350 Overrides the [] operator to provide access to the message data,
351 returning None if the required item is not in the message
352 @return: the value of the field_name field, or None if field_name
353 is not contained in the message
356 return self.data.get(field_name, None)
358 def __setitem__(self, field_name, field_value):
359 """Set the value of the required field_name to field_value.
362 self.data[field_name] = field_value
365 def BuildFromJsonString(json_string):
366 """Build a QmpMessage from a JSON encoded string.
368 @type json_string: str
369 @param json_string: JSON string representing the message
370 @rtype: L{QmpMessage}
371 @return: a L{QmpMessage} built from json_string
375 data = serializer.LoadJson(json_string)
376 return QmpMessage(data)
379 # The protocol expects the JSON object to be sent as a single line.
380 return serializer.DumpJson(self.data)
382 def __eq__(self, other):
383 # When comparing two QmpMessages, we are interested in comparing
384 # their internal representation of the message data
385 return self.data == other.data
388 class MonitorSocket(object):
391 def __init__(self, monitor_filename):
392 """Instantiates the MonitorSocket object.
394 @type monitor_filename: string
395 @param monitor_filename: the filename of the UNIX raw socket on which the
396 monitor (QMP or simple one) is listening
399 self.monitor_filename = monitor_filename
400 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
401 # We want to fail if the server doesn't send a complete message
402 # in a reasonable amount of time
403 self.sock.settimeout(self._SOCKET_TIMEOUT)
404 self._connected = False
406 def _check_socket(self):
409 sock_stat = os.stat(self.monitor_filename)
410 except EnvironmentError, err:
411 if err.errno == errno.ENOENT:
412 raise errors.HypervisorError("No monitor socket found")
414 raise errors.HypervisorError("Error checking monitor socket: %s",
415 utils.ErrnoOrStr(err))
416 if not stat.S_ISSOCK(sock_stat.st_mode):
417 raise errors.HypervisorError("Monitor socket is not a socket")
419 def _check_connection(self):
420 """Make sure that the connection is established.
423 if not self._connected:
424 raise errors.ProgrammerError("To use a MonitorSocket you need to first"
425 " invoke connect() on it")
428 """Connects to the monitor.
430 Connects to the UNIX socket
432 @raise errors.HypervisorError: when there are communication errors
436 raise errors.ProgrammerError("Cannot connect twice")
440 # Check file existance/stuff
442 self.sock.connect(self.monitor_filename)
443 except EnvironmentError:
444 raise errors.HypervisorError("Can't connect to qmp socket")
445 self._connected = True
450 It cannot be used after this call.
456 class QmpConnection(MonitorSocket):
457 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
460 _FIRST_MESSAGE_KEY = "QMP"
463 _RETURN_KEY = RETURN_KEY = "return"
464 _ACTUAL_KEY = ACTUAL_KEY = "actual"
465 _ERROR_CLASS_KEY = "class"
466 _ERROR_DESC_KEY = "desc"
467 _EXECUTE_KEY = "execute"
468 _ARGUMENTS_KEY = "arguments"
469 _CAPABILITIES_COMMAND = "qmp_capabilities"
470 _MESSAGE_END_TOKEN = "\r\n"
472 def __init__(self, monitor_filename):
473 super(QmpConnection, self).__init__(monitor_filename)
477 """Connects to the QMP monitor.
479 Connects to the UNIX socket and makes sure that we can actually send and
480 receive data to the kvm instance via QMP.
482 @raise errors.HypervisorError: when there are communication errors
483 @raise errors.ProgrammerError: when there are data serialization errors
486 super(QmpConnection, self).connect()
487 # Check if we receive a correct greeting message from the server
488 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
489 greeting = self._Recv()
490 if not greeting[self._FIRST_MESSAGE_KEY]:
491 self._connected = False
492 raise errors.HypervisorError("kvm: QMP communication error (wrong"
495 # This is needed because QMP can return more than one greetings
496 # see https://groups.google.com/d/msg/ganeti-devel/gZYcvHKDooU/SnukC8dgS5AJ
499 # Let's put the monitor in command mode using the qmp_capabilities
500 # command, or else no command will be executable.
501 # (As per the QEMU Protocol Specification 0.1 - section 4)
502 self.Execute(self._CAPABILITIES_COMMAND)
504 def _ParseMessage(self, buf):
505 """Extract and parse a QMP message from the given buffer.
507 Seeks for a QMP message in the given buf. If found, it parses it and
508 returns it together with the rest of the characters in the buf.
509 If no message is found, returns None and the whole buffer.
511 @raise errors.ProgrammerError: when there are data serialization errors
515 # Check if we got the message end token (CRLF, as per the QEMU Protocol
516 # Specification 0.1 - Section 2.1.1)
517 pos = buf.find(self._MESSAGE_END_TOKEN)
520 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
521 except Exception, err:
522 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
525 return (message, buf)
528 """Receives a message from QMP and decodes the received JSON object.
531 @return: the received message
532 @raise errors.HypervisorError: when there are communication errors
533 @raise errors.ProgrammerError: when there are data serialization errors
536 self._check_connection()
538 # Check if there is already a message in the buffer
539 (message, self._buf) = self._ParseMessage(self._buf)
543 recv_buffer = StringIO.StringIO(self._buf)
544 recv_buffer.seek(len(self._buf))
547 data = self.sock.recv(4096)
550 recv_buffer.write(data)
552 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
556 except socket.timeout, err:
557 raise errors.HypervisorError("Timeout while receiving a QMP message: "
559 except socket.error, err:
560 raise errors.HypervisorError("Unable to receive data from KVM using the"
561 " QMP protocol: %s" % err)
563 def _Send(self, message):
564 """Encodes and sends a message to KVM using QMP.
566 @type message: QmpMessage
567 @param message: message to send to KVM
568 @raise errors.HypervisorError: when there are communication errors
569 @raise errors.ProgrammerError: when there are data serialization errors
572 self._check_connection()
574 message_str = str(message)
575 except Exception, err:
576 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
579 self.sock.sendall(message_str)
580 except socket.timeout, err:
581 raise errors.HypervisorError("Timeout while sending a QMP message: "
582 "%s (%s)" % (err.string, err.errno))
583 except socket.error, err:
584 raise errors.HypervisorError("Unable to send data from KVM using the"
585 " QMP protocol: %s" % err)
587 def Execute(self, command, arguments=None):
588 """Executes a QMP command and returns the response of the server.
591 @param command: the command to execute
592 @type arguments: dict
593 @param arguments: dictionary of arguments to be passed to the command
595 @return: dictionary representing the received JSON object
596 @raise errors.HypervisorError: when there are communication errors
597 @raise errors.ProgrammerError: when there are data serialization errors
600 self._check_connection()
601 message = QmpMessage({self._EXECUTE_KEY: command})
603 message[self._ARGUMENTS_KEY] = arguments
606 # Events can occur between the sending of the command and the reception
607 # of the response, so we need to filter out messages with the event key.
609 response = self._Recv()
610 err = response[self._ERROR_KEY]
612 raise errors.HypervisorError("kvm: error executing the %s"
613 " command: %s (%s):" %
615 err[self._ERROR_DESC_KEY],
616 err[self._ERROR_CLASS_KEY]))
618 elif not response[self._EVENT_KEY]:
622 class KVMHypervisor(hv_base.BaseHypervisor):
623 """KVM hypervisor interface
628 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
629 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
630 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
631 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
632 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
633 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
634 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
635 # KVM instances with chroot enabled are started in empty chroot directories.
636 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
637 # After an instance is stopped, its chroot directory is removed.
638 # If the chroot directory is not empty, it can't be removed.
639 # A non-empty chroot directory indicates a possible security incident.
640 # To support forensics, the non-empty chroot directory is quarantined in
641 # a separate directory, called 'chroot-quarantine'.
642 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
643 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
644 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
647 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
648 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
649 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
650 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
651 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
652 constants.HV_ACPI: hv_base.NO_CHECK,
653 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
654 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
655 constants.HV_VNC_BIND_ADDRESS:
656 (False, lambda x: (netutils.IP4Address.IsValid(x) or
657 utils.IsNormAbsPath(x)),
658 "The VNC bind address must be either a valid IP address or an absolute"
659 " pathname", None, None),
660 constants.HV_VNC_TLS: hv_base.NO_CHECK,
661 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
662 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
663 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
664 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
665 constants.HV_KVM_SPICE_IP_VERSION:
666 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
667 x in constants.VALID_IP_VERSIONS),
668 "The SPICE IP version should be 4 or 6",
670 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
671 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
673 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
674 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
676 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
677 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
679 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
680 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
682 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
683 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
684 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
685 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
686 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
687 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
688 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
689 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
690 constants.HV_BOOT_ORDER:
691 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
692 constants.HV_NIC_TYPE:
693 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
694 constants.HV_DISK_TYPE:
695 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
696 constants.HV_KVM_CDROM_DISK_TYPE:
697 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
698 constants.HV_USB_MOUSE:
699 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
700 constants.HV_KEYMAP: hv_base.NO_CHECK,
701 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
702 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
703 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
704 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
705 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
706 constants.HV_DISK_CACHE:
707 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
708 constants.HV_SECURITY_MODEL:
709 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
710 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
711 constants.HV_KVM_FLAG:
712 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
713 constants.HV_VHOST_NET: hv_base.NO_CHECK,
714 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
715 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
716 constants.HV_REBOOT_BEHAVIOR:
717 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
718 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
719 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
720 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
721 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
722 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
723 constants.HV_SOUNDHW: hv_base.NO_CHECK,
724 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
725 constants.HV_VGA: hv_base.NO_CHECK,
726 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
727 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
728 constants.HV_VNET_HDR: hv_base.NO_CHECK,
732 _VIRTIO_NET_PCI = "virtio-net-pci"
733 _VIRTIO_BLK_PCI = "virtio-blk-pci"
735 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
737 _MIGRATION_PROGRESS_RE = \
738 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
739 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
740 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
742 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
743 _MIGRATION_INFO_RETRY_DELAY = 2
745 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
747 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
748 _CPU_INFO_CMD = "info cpus"
751 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
752 _CHECK_MACHINE_VERSION_RE = \
753 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
755 _QMP_RE = re.compile(r"^-qmp\s", re.M)
756 _SPICE_RE = re.compile(r"^-spice\s", re.M)
757 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
758 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
759 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
760 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
761 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
762 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
763 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
764 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
765 # match -drive.*boot=on|off on different lines, but in between accept only
766 # dashes not preceeded by a new line (which would mean another option
767 # different than -drive is starting)
768 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
770 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
771 _INFO_PCI_CMD = "info pci"
772 _FIND_PCI_DEVICE_RE = \
773 staticmethod(lambda pci, devid:
774 re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' % (pci, devid),
778 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
779 _INFO_VERSION_CMD = "info version"
781 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
786 ANCILLARY_FILES_OPT = [
790 # Supported kvm options to get output from
791 _KVMOPT_HELP = "help"
792 _KVMOPT_MLIST = "mlist"
793 _KVMOPT_DEVICELIST = "devicelist"
795 # Command to execute to get the output from kvm, and whether to
796 # accept the output even on failure.
798 _KVMOPT_HELP: (["--help"], False),
799 _KVMOPT_MLIST: (["-M", "?"], False),
800 _KVMOPT_DEVICELIST: (["-device", "?"], True),
804 hv_base.BaseHypervisor.__init__(self)
805 # Let's make sure the directories we need exist, even if the RUN_DIR lives
806 # in a tmpfs filesystem or has been otherwise wiped out.
807 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
808 utils.EnsureDirs(dirs)
811 def _InstancePidFile(cls, instance_name):
812 """Returns the instance pidfile.
815 return utils.PathJoin(cls._PIDS_DIR, instance_name)
818 def _InstanceUidFile(cls, instance_name):
819 """Returns the instance uidfile.
822 return utils.PathJoin(cls._UIDS_DIR, instance_name)
825 def _InstancePidInfo(cls, pid):
826 """Check pid file for instance information.
828 Check that a pid file is associated with an instance, and retrieve
829 information from its command line.
831 @type pid: string or int
832 @param pid: process id of the instance to check
834 @return: (instance_name, memory, vcpus)
835 @raise errors.HypervisorError: when an instance cannot be found
838 alive = utils.IsProcessAlive(pid)
840 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
842 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
844 cmdline = utils.ReadFile(cmdline_file)
845 except EnvironmentError, err:
846 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
853 arg_list = cmdline.split("\x00")
855 arg = arg_list.pop(0)
857 instance = arg_list.pop(0)
859 memory = int(arg_list.pop(0))
861 vcpus = int(arg_list.pop(0).split(",")[0])
864 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
867 return (instance, memory, vcpus)
869 def _InstancePidAlive(self, instance_name):
870 """Returns the instance pidfile, pid, and liveness.
872 @type instance_name: string
873 @param instance_name: instance name
875 @return: (pid file name, pid, liveness)
878 pidfile = self._InstancePidFile(instance_name)
879 pid = utils.ReadPidFile(pidfile)
883 cmd_instance = self._InstancePidInfo(pid)[0]
884 alive = (cmd_instance == instance_name)
885 except errors.HypervisorError:
888 return (pidfile, pid, alive)
890 def _CheckDown(self, instance_name):
891 """Raises an error unless the given instance is down.
894 alive = self._InstancePidAlive(instance_name)[2]
896 raise errors.HypervisorError("Failed to start instance %s: %s" %
897 (instance_name, "already running"))
900 def _InstanceMonitor(cls, instance_name):
901 """Returns the instance monitor socket name
904 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
907 def _InstanceSerial(cls, instance_name):
908 """Returns the instance serial socket name
911 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
914 def _InstanceQmpMonitor(cls, instance_name):
915 """Returns the instance serial QMP socket name
918 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
921 def _SocatUnixConsoleParams():
922 """Returns the correct parameters for socat
924 If we have a new-enough socat we can use raw mode with an escape character.
927 if constants.SOCAT_USE_ESCAPE:
928 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
930 return "echo=0,icanon=0"
933 def _InstanceKVMRuntime(cls, instance_name):
934 """Returns the instance KVM runtime filename
937 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
940 def _InstanceChrootDir(cls, instance_name):
941 """Returns the name of the KVM chroot dir of the instance
944 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
947 def _InstanceNICDir(cls, instance_name):
948 """Returns the name of the directory holding the tap device files for a
952 return utils.PathJoin(cls._NICS_DIR, instance_name)
955 def _InstanceNICFile(cls, instance_name, seq_or_uuid):
956 """Returns the name of the file containing the tap device for a given NIC
959 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq_or_uuid))
962 def _GetInstanceNICTap(cls, instance_name, nic):
963 """Returns the tap for the corresponding nic
965 Search for tap file named after NIC's uuid.
966 For old instances without uuid indexed tap files returns nothing.
970 return utils.ReadFile(cls._InstanceNICFile(instance_name, nic.uuid))
971 except EnvironmentError:
975 def _WriteInstanceNICFiles(cls, instance_name, seq, nic, tap):
976 """Write tap name to both instance NIC files
979 for ident in [seq, nic.uuid]:
980 utils.WriteFile(cls._InstanceNICFile(instance_name, ident), data=tap)
983 def _RemoveInstanceNICFiles(cls, instance_name, seq, nic):
984 """Write tap name to both instance NIC files
987 for ident in [seq, nic.uuid]:
988 utils.RemoveFile(cls._InstanceNICFile(instance_name, ident))
991 def _InstanceKeymapFile(cls, instance_name):
992 """Returns the name of the file containing the keymap for a given instance
995 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
998 def _TryReadUidFile(cls, uid_file):
999 """Try to read a uid file
1002 if os.path.exists(uid_file):
1004 uid = int(utils.ReadOneLineFile(uid_file))
1006 except EnvironmentError:
1007 logging.warning("Can't read uid file", exc_info=True)
1008 except (TypeError, ValueError):
1009 logging.warning("Can't parse uid file contents", exc_info=True)
1013 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
1014 """Removes an instance's rutime sockets/files/dirs.
1017 # This takes info from NICDir and RuntimeFile
1018 cls._UnconfigureInstanceNICs(instance_name)
1019 utils.RemoveFile(pidfile)
1020 utils.RemoveFile(cls._InstanceMonitor(instance_name))
1021 utils.RemoveFile(cls._InstanceSerial(instance_name))
1022 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
1023 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
1024 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
1025 uid_file = cls._InstanceUidFile(instance_name)
1026 uid = cls._TryReadUidFile(uid_file)
1027 utils.RemoveFile(uid_file)
1029 uidpool.ReleaseUid(uid)
1031 shutil.rmtree(cls._InstanceNICDir(instance_name))
1032 except OSError, err:
1033 if err.errno != errno.ENOENT:
1036 chroot_dir = cls._InstanceChrootDir(instance_name)
1037 utils.RemoveDir(chroot_dir)
1038 except OSError, err:
1039 if err.errno == errno.ENOTEMPTY:
1040 # The chroot directory is expected to be empty, but it isn't.
1041 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
1044 utils.TimestampForFilename()))
1045 logging.warning("The chroot directory of instance %s can not be"
1046 " removed as it is not empty. Moving it to the"
1047 " quarantine instead. Please investigate the"
1048 " contents (%s) and clean up manually",
1049 instance_name, new_chroot_dir)
1050 utils.RenameFile(chroot_dir, new_chroot_dir)
1055 def _CreateNICEnv(instance_name, nic, tap, seq=None, instance_tags=None):
1056 """Create environment variables for a specific NIC
1058 This is needed during NIC ifup/ifdown scripts.
1059 Since instance tags may change during NIC creation and removal
1060 and because during cleanup instance object is not available we
1061 pass them only upon NIC creation (instance startup/NIC hot-plugging).
1065 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1066 "INSTANCE": instance_name,
1068 "MODE": nic.nicparams[constants.NIC_MODE],
1069 "INTERFACE_UUID": nic.uuid,
1073 env["TAGS"] = " ".join(instance_tags)
1075 # This should always be available except for old instances in the
1076 # cluster without uuid indexed tap files.
1078 env["INTERFACE"] = tap
1081 env["INTERFACE_INDEX"] = str(seq)
1087 env["INTERFACE_NAME"] = nic.name
1089 if nic.nicparams[constants.NIC_LINK]:
1090 env["LINK"] = nic.nicparams[constants.NIC_LINK]
1093 n = objects.Network.FromDict(nic.netinfo)
1094 env.update(n.HooksDict())
1096 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1097 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1102 def _ConfigureNIC(cls, instance, seq, nic, tap):
1103 """Run the network configuration script for a specified NIC
1105 @param instance: instance we're acting on
1106 @type instance: instance object
1107 @param seq: nic sequence number
1109 @param nic: nic we're acting on
1110 @type nic: nic object
1111 @param tap: the host's tap interface this NIC corresponds to
1115 env = cls._CreateNICEnv(instance.name, nic, tap, seq, instance.GetTags())
1116 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1118 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1119 " network configuration script output: %s" %
1120 (tap, result.fail_reason, result.output))
1123 def _UnconfigureNic(cls, instance_name, nic, only_local=True):
1124 """Run ifdown script for a specific NIC
1126 This is executed during instance cleanup and NIC hot-unplug
1128 @param instance: instance we're acting on
1129 @type instance: instance object
1130 @param nic: nic we're acting on
1131 @type nic: nic object
1132 @param localy: whether ifdown script should reset global conf (dns) or not
1133 @type localy: boolean
1136 tap = cls._GetInstanceNICTap(instance_name, nic)
1137 env = cls._CreateNICEnv(instance_name, nic, tap)
1138 arg2 = str(only_local).lower()
1139 result = utils.RunCmd([pathutils.KVM_IFDOWN, tap, arg2], env=env)
1141 raise errors.HypervisorError("Failed to unconfigure interface %s: %s;"
1142 " network configuration script output: %s" %
1143 (tap, result.fail_reason, result.output))
1146 def _VerifyAffinityPackage():
1147 if affinity is None:
1148 raise errors.HypervisorError("affinity Python package not"
1149 " found; cannot use CPU pinning under KVM")
1152 def _BuildAffinityCpuMask(cpu_list):
1153 """Create a CPU mask suitable for sched_setaffinity from a list of
1156 See man taskset for more info on sched_setaffinity masks.
1157 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1159 @type cpu_list: list of int
1160 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1162 @return: a bit mask of CPU affinities
1165 if cpu_list == constants.CPU_PINNING_OFF:
1166 return constants.CPU_PINNING_ALL_KVM
1168 return sum(2 ** cpu for cpu in cpu_list)
1171 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1172 """Change CPU affinity for running VM according to given CPU mask.
1174 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1175 @type cpu_mask: string
1176 @param process_id: process ID of KVM process. Used to pin entire VM
1178 @type process_id: int
1179 @param thread_dict: map of virtual CPUs to KVM thread IDs
1180 @type thread_dict: dict int:int
1183 # Convert the string CPU mask to a list of list of int's
1184 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1186 if len(cpu_list) == 1:
1187 all_cpu_mapping = cpu_list[0]
1188 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1189 # If CPU pinning has 1 entry that's "all", then do nothing
1192 # If CPU pinning has one non-all entry, map the entire VM to
1193 # one set of physical CPUs
1194 cls._VerifyAffinityPackage()
1195 affinity.set_process_affinity_mask(
1196 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1198 # The number of vCPUs mapped should match the number of vCPUs
1199 # reported by KVM. This was already verified earlier, so
1200 # here only as a sanity check.
1201 assert len(thread_dict) == len(cpu_list)
1202 cls._VerifyAffinityPackage()
1204 # For each vCPU, map it to the proper list of physical CPUs
1205 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1206 affinity.set_process_affinity_mask(thread_dict[i],
1207 cls._BuildAffinityCpuMask(vcpu))
1209 def _GetVcpuThreadIds(self, instance_name):
1210 """Get a mapping of vCPU no. to thread IDs for the instance
1212 @type instance_name: string
1213 @param instance_name: instance in question
1214 @rtype: dictionary of int:int
1215 @return: a dictionary mapping vCPU numbers to thread IDs
1219 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1220 for line in output.stdout.splitlines():
1221 match = self._CPU_INFO_RE.search(line)
1224 grp = map(int, match.groups())
1225 result[grp[0]] = grp[1]
1229 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1230 """Complete CPU pinning.
1232 @type instance_name: string
1233 @param instance_name: name of instance
1234 @type cpu_mask: string
1235 @param cpu_mask: CPU pinning mask as entered by user
1238 # Get KVM process ID, to be used if need to pin entire VM
1239 _, pid, _ = self._InstancePidAlive(instance_name)
1240 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1241 thread_dict = self._GetVcpuThreadIds(instance_name)
1242 # Run CPU pinning, based on configured mask
1243 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1245 def ListInstances(self):
1246 """Get the list of running instances.
1248 We can do this by listing our live instances directory and
1249 checking whether the associated kvm process is still alive.
1253 for name in os.listdir(self._PIDS_DIR):
1254 if self._InstancePidAlive(name)[2]:
1258 def GetInstanceInfo(self, instance_name):
1259 """Get instance properties.
1261 @type instance_name: string
1262 @param instance_name: the instance name
1263 @rtype: tuple of strings
1264 @return: (name, id, memory, vcpus, stat, times)
1267 _, pid, alive = self._InstancePidAlive(instance_name)
1271 _, memory, vcpus = self._InstancePidInfo(pid)
1276 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1278 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1279 # Will fail if ballooning is not enabled, but we can then just resort to
1281 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1282 memory = mem_bytes / 1048576
1283 except errors.HypervisorError:
1286 return (instance_name, pid, memory, vcpus, istat, times)
1288 def GetAllInstancesInfo(self):
1289 """Get properties of all instances.
1291 @return: list of tuples (name, id, memory, vcpus, stat, times)
1295 for name in os.listdir(self._PIDS_DIR):
1297 info = self.GetInstanceInfo(name)
1298 except errors.HypervisorError:
1299 # Ignore exceptions due to instances being shut down
1305 def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1307 """Generate KVM options regarding instance's block devices.
1309 @type instance: L{objects.Instance}
1310 @param instance: the instance object
1311 @type kvm_disks: list of tuples
1312 @param kvm_disks: list of tuples [(disk, link_name)..]
1313 @type kvmhelp: string
1314 @param kvmhelp: output of kvm --help
1315 @type devlist: string
1316 @param devlist: output of kvm -device ?
1318 @return: list of command line options eventually used by kvm executable
1321 hvp = instance.hvparams
1322 kernel_path = hvp[constants.HV_KERNEL_PATH]
1326 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1328 # whether this is an older KVM version that uses the boot=on flag
1330 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1333 device_driver = None
1334 disk_type = hvp[constants.HV_DISK_TYPE]
1335 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1336 if_val = ",if=%s" % self._VIRTIO
1338 if self._VIRTIO_BLK_RE.search(devlist):
1340 # will be passed in -device option as driver
1341 device_driver = self._VIRTIO_BLK_PCI
1342 except errors.HypervisorError, _:
1345 if_val = ",if=%s" % disk_type
1347 disk_cache = hvp[constants.HV_DISK_CACHE]
1348 if instance.disk_template in constants.DTS_EXT_MIRROR:
1349 if disk_cache != "none":
1350 # TODO: make this a hard error, instead of a silent overwrite
1351 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1352 " to prevent shared storage corruption on migration",
1354 cache_val = ",cache=none"
1355 elif disk_cache != constants.HT_CACHE_DEFAULT:
1356 cache_val = ",cache=%s" % disk_cache
1359 for idx, (cfdev, link_name) in enumerate(kvm_disks):
1360 if cfdev.mode != constants.DISK_RDWR:
1361 raise errors.HypervisorError("Instance has read-only disks which"
1362 " are not supported by KVM")
1363 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1366 dev_opts.extend(["-boot", "c"])
1368 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1369 boot_val = ",boot=on"
1371 # For ext we allow overriding disk_cache hypervisor params per disk
1372 disk_cache = cfdev.params.get("cache", None)
1374 cache_val = ",cache=%s" % disk_cache
1375 drive_val = "file=%s,format=raw%s%s%s" % \
1376 (link_name, if_val, boot_val, cache_val)
1379 # kvm_disks are the 4th entry of runtime file that did not exist in
1380 # the past. That means that cfdev should always have pci slot and
1381 # _GenerateDeviceKVMId() will not raise a exception.
1382 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK,
1384 drive_val += (",id=%s" % kvm_devid)
1386 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1387 dev_val = ("%s,drive=%s,id=%s" %
1388 (device_driver, kvm_devid, kvm_devid))
1390 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1391 dev_opts.extend(["-device", dev_val])
1393 # TODO: export disk geometry in IDISK_PARAMS
1394 heads = cfdev.params.get('heads', None)
1395 secs = cfdev.params.get('secs', None)
1397 nr_sectors = cfdev.size * 1024 * 1024 / 512
1398 cyls = nr_sectors / (int(heads) * int(secs))
1403 if cyls and heads and secs:
1404 drive_val += (",cyls=%d,heads=%d,secs=%d" %
1405 (cyls, int(heads), int(secs)))
1407 dev_opts.extend(["-drive", drive_val])
1411 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1413 """Generate KVM information to start an instance.
1415 @type kvmhelp: string
1416 @param kvmhelp: output of kvm --help
1417 @attention: this function must not have any side-effects; for
1418 example, it must not write to the filesystem, or read values
1419 from the current system the are expected to differ between
1420 nodes, since it is only run once at instance startup;
1421 actions/kvm arguments that can vary between systems should be
1422 done in L{_ExecuteKVMRuntime}
1425 # pylint: disable=R0912,R0914,R0915
1426 hvp = instance.hvparams
1427 self.ValidateParameters(hvp)
1429 pidfile = self._InstancePidFile(instance.name)
1430 kvm = hvp[constants.HV_KVM_PATH]
1432 # used just by the vnc server, if enabled
1433 kvm_cmd.extend(["-name", instance.name])
1434 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1436 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1437 if hvp[constants.HV_CPU_CORES]:
1438 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1439 if hvp[constants.HV_CPU_THREADS]:
1440 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1441 if hvp[constants.HV_CPU_SOCKETS]:
1442 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1444 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1446 kvm_cmd.extend(["-pidfile", pidfile])
1447 kvm_cmd.extend(["-balloon", "virtio"])
1448 kvm_cmd.extend(["-daemonize"])
1449 if not instance.hvparams[constants.HV_ACPI]:
1450 kvm_cmd.extend(["-no-acpi"])
1451 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1452 constants.INSTANCE_REBOOT_EXIT:
1453 kvm_cmd.extend(["-no-reboot"])
1455 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1457 mversion = self._GetDefaultMachineVersion(kvm)
1458 if self._MACHINE_RE.search(kvmhelp):
1459 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1460 # extra hypervisor parameters. We should also investigate whether and how
1461 # shadow_mem should be considered for the resource model.
1462 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1463 specprop = ",accel=kvm"
1466 machinespec = "%s%s" % (mversion, specprop)
1467 kvm_cmd.extend(["-machine", machinespec])
1469 kvm_cmd.extend(["-M", mversion])
1470 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1471 self._ENABLE_KVM_RE.search(kvmhelp)):
1472 kvm_cmd.extend(["-enable-kvm"])
1473 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1474 self._DISABLE_KVM_RE.search(kvmhelp)):
1475 kvm_cmd.extend(["-disable-kvm"])
1477 kernel_path = hvp[constants.HV_KERNEL_PATH]
1479 boot_cdrom = boot_floppy = boot_network = False
1481 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1482 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1483 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1486 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1489 kvm_cmd.extend(["-boot", "n"])
1491 # whether this is an older KVM version that uses the boot=on flag
1493 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1495 disk_type = hvp[constants.HV_DISK_TYPE]
1497 #Now we can specify a different device type for CDROM devices.
1498 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1499 if not cdrom_disk_type:
1500 cdrom_disk_type = disk_type
1502 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1504 options = ",format=raw,media=cdrom"
1505 # set cdrom 'if' type
1507 actual_cdrom_type = constants.HT_DISK_IDE
1508 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1509 actual_cdrom_type = "virtio"
1511 actual_cdrom_type = cdrom_disk_type
1512 if_val = ",if=%s" % actual_cdrom_type
1513 # set boot flag, if needed
1516 kvm_cmd.extend(["-boot", "d"])
1518 boot_val = ",boot=on"
1519 # and finally build the entire '-drive' value
1520 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1521 kvm_cmd.extend(["-drive", drive_val])
1523 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1525 options = ",format=raw,media=cdrom"
1526 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1527 if_val = ",if=virtio"
1529 if_val = ",if=%s" % cdrom_disk_type
1530 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1531 kvm_cmd.extend(["-drive", drive_val])
1533 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1535 options = ",format=raw,media=disk"
1537 kvm_cmd.extend(["-boot", "a"])
1538 options = "%s,boot=on" % options
1539 if_val = ",if=floppy"
1540 options = "%s%s" % (options, if_val)
1541 drive_val = "file=%s%s" % (floppy_image, options)
1542 kvm_cmd.extend(["-drive", drive_val])
1545 kvm_cmd.extend(["-kernel", kernel_path])
1546 initrd_path = hvp[constants.HV_INITRD_PATH]
1548 kvm_cmd.extend(["-initrd", initrd_path])
1549 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1550 hvp[constants.HV_KERNEL_ARGS]]
1551 if hvp[constants.HV_SERIAL_CONSOLE]:
1552 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1553 root_append.append("console=ttyS0,%s" % serial_speed)
1554 kvm_cmd.extend(["-append", " ".join(root_append)])
1556 mem_path = hvp[constants.HV_MEM_PATH]
1558 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1560 monitor_dev = ("unix:%s,server,nowait" %
1561 self._InstanceMonitor(instance.name))
1562 kvm_cmd.extend(["-monitor", monitor_dev])
1563 if hvp[constants.HV_SERIAL_CONSOLE]:
1564 serial_dev = ("unix:%s,server,nowait" %
1565 self._InstanceSerial(instance.name))
1566 kvm_cmd.extend(["-serial", serial_dev])
1568 kvm_cmd.extend(["-serial", "none"])
1570 mouse_type = hvp[constants.HV_USB_MOUSE]
1571 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1572 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1573 spice_ip_version = None
1575 kvm_cmd.extend(["-usb"])
1578 kvm_cmd.extend(["-usbdevice", mouse_type])
1579 elif vnc_bind_address:
1580 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1582 if vnc_bind_address:
1583 if netutils.IP4Address.IsValid(vnc_bind_address):
1584 if instance.network_port > constants.VNC_BASE_PORT:
1585 display = instance.network_port - constants.VNC_BASE_PORT
1586 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1587 vnc_arg = ":%d" % (display)
1589 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1591 logging.error("Network port is not a valid VNC display (%d < %d),"
1592 " not starting VNC",
1593 instance.network_port, constants.VNC_BASE_PORT)
1596 # Only allow tls and other option when not binding to a file, for now.
1597 # kvm/qemu gets confused otherwise about the filename to use.
1599 if hvp[constants.HV_VNC_TLS]:
1600 vnc_append = "%s,tls" % vnc_append
1601 if hvp[constants.HV_VNC_X509_VERIFY]:
1602 vnc_append = "%s,x509verify=%s" % (vnc_append,
1603 hvp[constants.HV_VNC_X509])
1604 elif hvp[constants.HV_VNC_X509]:
1605 vnc_append = "%s,x509=%s" % (vnc_append,
1606 hvp[constants.HV_VNC_X509])
1607 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1608 vnc_append = "%s,password" % vnc_append
1610 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1613 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1615 kvm_cmd.extend(["-vnc", vnc_arg])
1617 # FIXME: this is wrong here; the iface ip address differs
1618 # between systems, so it should be done in _ExecuteKVMRuntime
1619 if netutils.IsValidInterface(spice_bind):
1620 # The user specified a network interface, we have to figure out the IP
1622 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1623 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1625 # if the user specified an IP version and the interface does not
1626 # have that kind of IP addresses, throw an exception
1627 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1628 if not addresses[spice_ip_version]:
1629 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1630 " for %s" % (spice_ip_version,
1633 # the user did not specify an IP version, we have to figure it out
1634 elif (addresses[constants.IP4_VERSION] and
1635 addresses[constants.IP6_VERSION]):
1636 # we have both ipv4 and ipv6, let's use the cluster default IP
1638 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1639 spice_ip_version = \
1640 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1641 elif addresses[constants.IP4_VERSION]:
1642 spice_ip_version = constants.IP4_VERSION
1643 elif addresses[constants.IP6_VERSION]:
1644 spice_ip_version = constants.IP6_VERSION
1646 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1647 " for %s" % (spice_bind))
1649 spice_address = addresses[spice_ip_version][0]
1652 # spice_bind is known to be a valid IP address, because
1653 # ValidateParameters checked it.
1654 spice_address = spice_bind
1656 spice_arg = "addr=%s" % spice_address
1657 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1658 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1659 (spice_arg, instance.network_port,
1660 pathutils.SPICE_CACERT_FILE))
1661 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1662 (spice_arg, pathutils.SPICE_CERT_FILE,
1663 pathutils.SPICE_CERT_FILE))
1664 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1666 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1668 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1670 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1671 spice_arg = "%s,disable-ticketing" % spice_arg
1673 if spice_ip_version:
1674 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1676 # Image compression options
1677 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1678 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1679 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1681 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1683 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1685 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1687 # Video stream detection
1688 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1690 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1692 # Audio compression, by default in qemu-kvm it is on
1693 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1694 spice_arg = "%s,playback-compression=off" % spice_arg
1695 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1696 spice_arg = "%s,agent-mouse=off" % spice_arg
1698 # Enable the spice agent communication channel between the host and the
1700 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1703 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1705 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1707 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1708 kvm_cmd.extend(["-spice", spice_arg])
1711 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1712 # also works in earlier versions though (tested with 1.1 and 1.3)
1713 if self._DISPLAY_RE.search(kvmhelp):
1714 kvm_cmd.extend(["-display", "none"])
1716 kvm_cmd.extend(["-nographic"])
1718 if hvp[constants.HV_USE_LOCALTIME]:
1719 kvm_cmd.extend(["-localtime"])
1721 if hvp[constants.HV_KVM_USE_CHROOT]:
1722 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1724 # Add qemu-KVM -cpu param
1725 if hvp[constants.HV_CPU_TYPE]:
1726 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1728 # As requested by music lovers
1729 if hvp[constants.HV_SOUNDHW]:
1730 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1732 # Pass a -vga option if requested, or if spice is used, for backwards
1734 if hvp[constants.HV_VGA]:
1735 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1737 kvm_cmd.extend(["-vga", "qxl"])
1739 # Various types of usb devices, comma separated
1740 if hvp[constants.HV_USB_DEVICES]:
1741 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1742 kvm_cmd.extend(["-usbdevice", dev])
1744 if hvp[constants.HV_KVM_EXTRA]:
1745 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1747 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1749 for disk, link_name in block_devices:
1750 disk.pci = _GetFreeSlot(pci_reservations, disk.pci, True)
1751 kvm_disks.append((disk, link_name))
1754 for nic in instance.nics:
1755 nic.pci = _GetFreeSlot(pci_reservations, nic.pci, True)
1756 kvm_nics.append(nic)
1760 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1762 def _WriteKVMRuntime(self, instance_name, data):
1763 """Write an instance's KVM runtime
1767 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1769 except EnvironmentError, err:
1770 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1773 def _ReadKVMRuntime(cls, instance_name):
1774 """Read an instance's KVM runtime
1778 file_content = utils.ReadFile(cls._InstanceKVMRuntime(instance_name))
1779 except EnvironmentError, err:
1780 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1783 def _SaveKVMRuntime(self, instance, kvm_runtime):
1784 """Save an instance's KVM runtime
1787 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1789 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1790 serialized_disks = [(blk.ToDict(), link)
1791 for blk, link in kvm_disks]
1792 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1795 self._WriteKVMRuntime(instance.name, serialized_form)
1798 def _LoadKVMRuntime(cls, instance_name, serialized_runtime=None):
1799 """Load an instance's KVM runtime
1802 if not serialized_runtime:
1803 serialized_runtime = cls._ReadKVMRuntime(instance_name)
1805 return _AnalyzeSerializedRuntime(serialized_runtime)
1807 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1808 """Run the KVM cmd and check for errors
1811 @param name: instance name
1812 @type kvm_cmd: list of strings
1813 @param kvm_cmd: runcmd input for kvm
1814 @type tap_fds: list of int
1815 @param tap_fds: fds of tap devices opened by Ganeti
1819 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1822 utils_wrapper.CloseFdNoError(fd)
1825 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1826 (name, result.fail_reason, result.output))
1827 if not self._InstancePidAlive(name)[2]:
1828 raise errors.HypervisorError("Failed to start instance %s" % name)
1830 # too many local variables
1831 # pylint: disable=R0914
1832 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1833 """Execute a KVM cmd, after completing it with some last minute data.
1835 @type incoming: tuple of strings
1836 @param incoming: (target_host_ip, port)
1837 @type kvmhelp: string
1838 @param kvmhelp: output of kvm --help
1841 # Small _ExecuteKVMRuntime hv parameters programming howto:
1842 # - conf_hvp contains the parameters as configured on ganeti. they might
1843 # have changed since the instance started; only use them if the change
1844 # won't affect the inside of the instance (which hasn't been rebooted).
1845 # - up_hvp contains the parameters as they were when the instance was
1846 # started, plus any new parameter which has been added between ganeti
1847 # versions: it is paramount that those default to a value which won't
1848 # affect the inside of the instance as well.
1849 conf_hvp = instance.hvparams
1850 name = instance.name
1851 self._CheckDown(name)
1855 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1856 # the first element of kvm_cmd is always the path to the kvm binary
1857 kvm_path = kvm_cmd[0]
1858 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1860 # We know it's safe to run as a different user upon migration, so we'll use
1861 # the latest conf, from conf_hvp.
1862 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1863 if security_model == constants.HT_SM_USER:
1864 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1866 keymap = conf_hvp[constants.HV_KEYMAP]
1868 keymap_path = self._InstanceKeymapFile(name)
1869 # If a keymap file is specified, KVM won't use its internal defaults. By
1870 # first including the "en-us" layout, an error on loading the actual
1871 # layout (e.g. because it can't be found) won't lead to a non-functional
1872 # keyboard. A keyboard with incorrect keys is still better than none.
1873 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1874 kvm_cmd.extend(["-k", keymap_path])
1876 # We have reasons to believe changing something like the nic driver/type
1877 # upon migration won't exactly fly with the instance kernel, so for nic
1878 # related parameters we'll use up_hvp
1881 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1883 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1887 kvm_cmd.extend(bdev_opts)
1890 kvm_cmd.extend(["-net", "none"])
1894 nic_type = up_hvp[constants.HV_NIC_TYPE]
1895 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1896 nic_model = self._VIRTIO
1898 if self._VIRTIO_NET_RE.search(devlist):
1899 nic_model = self._VIRTIO_NET_PCI
1900 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1901 except errors.HypervisorError, _:
1902 # Older versions of kvm don't support DEVICE_LIST, but they don't
1903 # have new virtio syntax either.
1906 if up_hvp[constants.HV_VHOST_NET]:
1907 # check for vhost_net support
1908 if self._VHOST_RE.search(kvmhelp):
1909 tap_extra = ",vhost=on"
1911 raise errors.HypervisorError("vhost_net is configured"
1912 " but it is not available")
1914 nic_model = nic_type
1916 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1918 for nic_seq, nic in enumerate(kvm_nics):
1919 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1920 tapfds.append(tapfd)
1921 taps.append(tapname)
1922 if kvm_supports_netdev:
1923 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1925 # kvm_nics already exist in old runtime files and thus there might
1926 # be some entries without pci slot (therefore try: except:)
1927 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1929 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1930 except errors.HotplugError:
1931 netdev = "netdev%d" % nic_seq
1932 nic_val += (",netdev=%s" % netdev)
1933 tap_val = ("type=tap,id=%s,fd=%d%s" %
1934 (netdev, tapfd, tap_extra))
1935 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1937 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1939 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1940 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1943 target, port = incoming
1944 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1946 # Changing the vnc password doesn't bother the guest that much. At most it
1947 # will surprise people who connect to it. Whether positively or negatively
1949 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1953 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1954 except EnvironmentError, err:
1955 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1956 % (vnc_pwd_file, err))
1958 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1959 utils.EnsureDirs([(self._InstanceChrootDir(name),
1960 constants.SECURE_DIR_MODE)])
1962 # Automatically enable QMP if version is >= 0.14
1963 if self._QMP_RE.search(kvmhelp):
1964 logging.debug("Enabling QMP")
1965 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1966 self._InstanceQmpMonitor(instance.name)])
1968 # Configure the network now for starting instances and bridged interfaces,
1969 # during FinalizeMigration for incoming instances' routed interfaces
1970 for nic_seq, nic in enumerate(kvm_nics):
1972 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1974 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1976 # CPU affinity requires kvm to start paused, so we set this flag if the
1977 # instance is not already paused and if we are not going to accept a
1978 # migrating instance. In the latter case, pausing is not needed.
1979 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1980 if start_kvm_paused:
1981 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1983 # Note: CPU pinning is using up_hvp since changes take effect
1984 # during instance startup anyway, and to avoid problems when soft
1985 # rebooting the instance.
1987 if up_hvp.get(constants.HV_CPU_MASK, None):
1990 if security_model == constants.HT_SM_POOL:
1991 ss = ssconf.SimpleStore()
1992 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1993 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1994 uid = uidpool.RequestUnusedUid(all_uids)
1996 username = pwd.getpwuid(uid.GetUid()).pw_name
1997 kvm_cmd.extend(["-runas", username])
1998 self._RunKVMCmd(name, kvm_cmd, tapfds)
2000 uidpool.ReleaseUid(uid)
2004 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
2006 self._RunKVMCmd(name, kvm_cmd, tapfds)
2008 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
2009 constants.RUN_DIRS_MODE)])
2010 for nic_seq, tap in enumerate(taps):
2011 nic = kvm_nics[nic_seq]
2012 self._WriteInstanceNICFiles(instance.name, nic_seq, nic, tap)
2015 change_cmd = "change vnc password %s" % vnc_pwd
2016 self._CallMonitorCommand(instance.name, change_cmd)
2018 # Setting SPICE password. We are not vulnerable to malicious passwordless
2019 # connection attempts because SPICE by default does not allow connections
2020 # if neither a password nor the "disable_ticketing" options are specified.
2021 # As soon as we send the password via QMP, that password is a valid ticket
2023 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
2024 if spice_password_file:
2027 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
2028 except EnvironmentError, err:
2029 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
2030 % (spice_password_file, err))
2032 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
2035 "protocol": "spice",
2036 "password": spice_pwd,
2038 qmp.Execute("set_password", arguments)
2040 for filename in temp_files:
2041 utils.RemoveFile(filename)
2043 # If requested, set CPU affinity and resume instance execution
2045 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
2047 start_memory = self._InstanceStartupMemory(instance)
2048 if start_memory < instance.beparams[constants.BE_MAXMEM]:
2049 self.BalloonInstanceMemory(instance, start_memory)
2051 if start_kvm_paused:
2052 # To control CPU pinning, ballooning, and vnc/spice passwords
2053 # the VM was started in a frozen state. If freezing was not
2054 # explicitly requested resume the vm status.
2055 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2057 def StartInstance(self, instance, block_devices, startup_paused):
2058 """Start an instance.
2061 self._CheckDown(instance.name)
2062 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2063 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2064 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
2065 startup_paused, kvmhelp)
2066 self._SaveKVMRuntime(instance, kvm_runtime)
2067 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2069 def _CallMonitorCommand(self, instance_name, command, timeout=None):
2070 """Invoke a command on the instance monitor.
2073 if timeout is not None:
2074 timeout_cmd = "timeout %s" % (timeout, )
2078 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
2079 # version. The monitor protocol is designed for human consumption, whereas
2080 # QMP is made for programmatic usage. In the worst case QMP can also
2081 # execute monitor commands. As it is, all calls to socat take at least
2082 # 500ms and likely more: socat can't detect the end of the reply and waits
2083 # for 500ms of no data received before exiting (500 ms is the default for
2084 # the "-t" parameter).
2085 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
2086 (utils.ShellQuote(command),
2088 constants.SOCAT_PATH,
2089 utils.ShellQuote(self._InstanceMonitor(instance_name))))
2091 result = utils.RunCmd(socat)
2093 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
2095 (command, instance_name, result.fail_reason, result.output))
2096 raise errors.HypervisorError(msg)
2100 def _GetFreePCISlot(self, instance, dev):
2101 """Get the first available pci slot of a runnung instance.
2104 slots = bitarray(32)
2105 slots.setall(False) # pylint: disable=E1101
2106 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2107 for line in output.stdout.splitlines():
2108 match = self._INFO_PCI_RE.search(line)
2110 slot = int(match.group(1))
2113 dev.pci = _GetFreeSlot(slots)
2115 def VerifyHotplugSupport(self, instance, action, dev_type):
2116 """Verifies that hotplug is supported.
2118 Hotplug is *not* supported in case of:
2119 - security models and chroot (disk hotplug)
2120 - fdsend module is missing (nic hot-add)
2122 @raise errors.HypervisorError: in one of the previous cases
2125 if dev_type == constants.HOTPLUG_TARGET_DISK:
2126 hvp = instance.hvparams
2127 security_model = hvp[constants.HV_SECURITY_MODEL]
2128 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2130 raise errors.HotplugError("Disk hotplug is not supported"
2131 " in case of chroot.")
2132 if security_model != constants.HT_SM_NONE:
2133 raise errors.HotplugError("Disk Hotplug is not supported in case"
2134 " security models are used.")
2136 if (dev_type == constants.HOTPLUG_TARGET_NIC and
2137 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2138 raise errors.HotplugError("Cannot hot-add NIC."
2139 " fdsend python module is missing.")
2141 def HotplugSupported(self, instance):
2142 """Checks if hotplug is generally supported.
2144 Hotplug is *not* supported in case of:
2145 - qemu versions < 1.0
2146 - for stopped instances
2148 @raise errors.HypervisorError: in one of the previous cases
2152 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2153 except errors.HypervisorError:
2154 raise errors.HotplugError("Instance is probably down")
2156 # TODO: search for netdev_add, drive_add, device_add.....
2157 match = self._INFO_VERSION_RE.search(output.stdout)
2159 raise errors.HotplugError("Cannot parse qemu version via monitor")
2161 v_major, v_min, _, _ = match.groups()
2162 if (int(v_major), int(v_min)) < (1, 0):
2163 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2165 def _CallHotplugCommands(self, name, cmds):
2167 self._CallMonitorCommand(name, c)
2170 def _VerifyHotplugCommand(self, instance_name, device, dev_type,
2172 """Checks if a previous hotplug command has succeeded.
2174 It issues info pci monitor command and checks depending on should_exist
2175 value if an entry with PCI slot and device ID is found or not.
2177 @raise errors.HypervisorError: if result is not the expected one
2180 output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD)
2181 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2183 self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout)
2184 if match and not should_exist:
2185 msg = "Device %s should have been removed but is still there" % kvm_devid
2186 raise errors.HypervisorError(msg)
2188 if not match and should_exist:
2189 msg = "Device %s should have been added but is missing" % kvm_devid
2190 raise errors.HypervisorError(msg)
2192 logging.info("Device %s has been correctly hot-plugged", kvm_devid)
2194 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2195 """ Helper method to hot-add a new device
2197 It gets free pci slot generates the device name and invokes the
2198 device specific method.
2201 # in case of hot-mod this is given
2202 if device.pci is None:
2203 self._GetFreePCISlot(instance, device)
2204 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2205 runtime = self._LoadKVMRuntime(instance.name)
2206 if dev_type == constants.HOTPLUG_TARGET_DISK:
2207 cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" %
2209 cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2210 (hex(device.pci), kvm_devid, kvm_devid)]
2211 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2212 (tap, fd) = _OpenTap()
2213 self._ConfigureNIC(instance, seq, device, tap)
2214 self._PassTapFd(instance, fd, device)
2215 cmds = ["netdev_add tap,id=%s,fd=%s" % (kvm_devid, kvm_devid)]
2216 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2217 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2218 cmds += ["device_add %s" % args]
2219 self._WriteInstanceNICFiles(instance.name, seq, device, tap)
2221 self._CallHotplugCommands(instance.name, cmds)
2222 self._VerifyHotplugCommand(instance.name, device, dev_type, True)
2223 # update relevant entries in runtime file
2224 index = _DEVICE_RUNTIME_INDEX[dev_type]
2225 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2226 runtime[index].append(entry)
2227 self._SaveKVMRuntime(instance, runtime)
2229 def HotDelDevice(self, instance, dev_type, device, _, seq):
2230 """ Helper method for hot-del device
2232 It gets device info from runtime file, generates the device name and
2233 invokes the device specific method.
2236 runtime = self._LoadKVMRuntime(instance.name)
2237 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2238 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2239 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2240 if dev_type == constants.HOTPLUG_TARGET_DISK:
2241 cmds = ["device_del %s" % kvm_devid]
2242 cmds += ["drive_del %s" % kvm_devid]
2243 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2244 cmds = ["device_del %s" % kvm_devid]
2245 cmds += ["netdev_del %s" % kvm_devid]
2246 self._UnconfigureNic(instance.name, kvm_device, False)
2247 self._RemoveInstanceNICFiles(instance.name, seq, device)
2248 self._CallHotplugCommands(instance.name, cmds)
2249 self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False)
2250 index = _DEVICE_RUNTIME_INDEX[dev_type]
2251 runtime[index].remove(entry)
2252 self._SaveKVMRuntime(instance, runtime)
2254 return kvm_device.pci
2256 def HotModDevice(self, instance, dev_type, device, _, seq):
2257 """ Helper method for hot-mod device
2259 It gets device info from runtime file, generates the device name and
2260 invokes the device specific method. Currently only NICs support hot-mod
2263 if dev_type == constants.HOTPLUG_TARGET_NIC:
2264 # putting it back in the same pci slot
2265 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2266 # TODO: remove sleep when socat gets removed
2267 self.HotAddDevice(instance, dev_type, device, _, seq)
2269 def _PassTapFd(self, instance, fd, nic):
2270 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2273 # TODO: factor out code related to unix sockets.
2274 # squash common parts between monitor and qmp
2275 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2276 command = "getfd %s\n" % kvm_devid
2278 logging.info("%s", fds)
2280 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2282 fdsend.sendfds(monsock.sock, command, fds=fds)
2287 def _ParseKVMVersion(cls, text):
2288 """Parse the KVM version from the --help output.
2291 @param text: output of kvm --help
2292 @return: (version, v_maj, v_min, v_rev)
2293 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2296 match = cls._VERSION_RE.search(text.splitlines()[0])
2298 raise errors.HypervisorError("Unable to get KVM version")
2300 v_all = match.group(0)
2301 v_maj = int(match.group(1))
2302 v_min = int(match.group(2))
2304 v_rev = int(match.group(4))
2307 return (v_all, v_maj, v_min, v_rev)
2310 def _GetKVMOutput(cls, kvm_path, option):
2311 """Return the output of a kvm invocation
2313 @type kvm_path: string
2314 @param kvm_path: path to the kvm executable
2315 @type option: a key of _KVMOPTS_CMDS
2316 @param option: kvm option to fetch the output from
2317 @return: output a supported kvm invocation
2318 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2321 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2323 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2325 result = utils.RunCmd([kvm_path] + optlist)
2326 if result.failed and not can_fail:
2327 raise errors.HypervisorError("Unable to get KVM %s output" %
2329 return result.output
2332 def _GetKVMVersion(cls, kvm_path):
2333 """Return the installed KVM version.
2335 @return: (version, v_maj, v_min, v_rev)
2336 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2339 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2342 def _GetDefaultMachineVersion(cls, kvm_path):
2343 """Return the default hardware revision (e.g. pc-1.1)
2346 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2347 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2349 return match.group(1)
2353 def StopInstance(self, instance, force=False, retry=False, name=None,
2355 """Stop an instance.
2358 assert(timeout is None or force is not None)
2360 if name is not None and not force:
2361 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2363 name = instance.name
2364 acpi = instance.hvparams[constants.HV_ACPI]
2367 _, pid, alive = self._InstancePidAlive(name)
2368 if pid > 0 and alive:
2369 if force or not acpi:
2370 utils.KillProcess(pid)
2372 self._CallMonitorCommand(name, "system_powerdown", timeout)
2375 def _UnconfigureInstanceNICs(cls, instance_name, info=None):
2376 """Get runtime NICs of an instance and unconfigure them
2379 _, kvm_nics, __, ___ = cls._LoadKVMRuntime(instance_name, info)
2380 for nic in kvm_nics:
2381 cls._UnconfigureNic(instance_name, nic)
2383 def CleanupInstance(self, instance_name):
2384 """Cleanup after a stopped instance
2387 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2388 if pid > 0 and alive:
2389 raise errors.HypervisorError("Cannot cleanup a live instance")
2390 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2392 def RebootInstance(self, instance):
2393 """Reboot an instance.
2396 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2397 # socket the instance will stop, but now power up again. So we'll resort
2398 # to shutdown and restart.
2399 _, _, alive = self._InstancePidAlive(instance.name)
2401 raise errors.HypervisorError("Failed to reboot instance %s:"
2402 " not running" % instance.name)
2403 # StopInstance will delete the saved KVM runtime so:
2404 # ...first load it...
2405 kvm_runtime = self._LoadKVMRuntime(instance.name)
2406 # ...now we can safely call StopInstance...
2407 if not self.StopInstance(instance):
2408 self.StopInstance(instance, force=True)
2409 # ...and finally we can save it again, and execute it...
2410 self._SaveKVMRuntime(instance, kvm_runtime)
2411 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2412 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2413 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2415 def MigrationInfo(self, instance):
2416 """Get instance information to perform a migration.
2418 @type instance: L{objects.Instance}
2419 @param instance: instance to be migrated
2421 @return: content of the KVM runtime file
2424 return self._ReadKVMRuntime(instance.name)
2426 def AcceptInstance(self, instance, info, target):
2427 """Prepare to accept an instance.
2429 @type instance: L{objects.Instance}
2430 @param instance: instance to be accepted
2432 @param info: content of the KVM runtime file on the source node
2433 @type target: string
2434 @param target: target host (usually ip), on this node
2437 kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2438 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2439 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2440 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2441 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2442 incoming=incoming_address)
2444 def FinalizeMigrationDst(self, instance, info, success):
2445 """Finalize the instance migration on the target node.
2447 Stop the incoming mode KVM.
2449 @type instance: L{objects.Instance}
2450 @param instance: instance whose migration is being finalized
2454 kvm_runtime = self._LoadKVMRuntime(instance.name, serialized_runtime=info)
2455 kvm_nics = kvm_runtime[1]
2457 for nic_seq, nic in enumerate(kvm_nics):
2458 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2459 # Bridged interfaces have already been configured
2462 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2463 except EnvironmentError, err:
2464 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2465 instance.name, nic_seq, str(err))
2468 self._ConfigureNIC(instance, nic_seq, nic, tap)
2469 except errors.HypervisorError, err:
2470 logging.warning(str(err))
2472 self._WriteKVMRuntime(instance.name, info)
2474 self._UnconfigureInstanceNICs(instance.name, info)
2475 self.StopInstance(instance, force=True)
2477 def MigrateInstance(self, instance, target, live):
2478 """Migrate an instance to a target node.
2480 The migration will not be attempted if the instance is not
2483 @type instance: L{objects.Instance}
2484 @param instance: the instance to be migrated
2485 @type target: string
2486 @param target: ip address of the target node
2488 @param live: perform a live migration
2491 instance_name = instance.name
2492 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2493 _, _, alive = self._InstancePidAlive(instance_name)
2495 raise errors.HypervisorError("Instance not running, cannot migrate")
2498 self._CallMonitorCommand(instance_name, "stop")
2500 migrate_command = ("migrate_set_speed %dm" %
2501 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2502 self._CallMonitorCommand(instance_name, migrate_command)
2504 migrate_command = ("migrate_set_downtime %dms" %
2505 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2506 self._CallMonitorCommand(instance_name, migrate_command)
2508 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2509 self._CallMonitorCommand(instance_name, migrate_command)
2511 def FinalizeMigrationSource(self, instance, success, live):
2512 """Finalize the instance migration on the source node.
2514 @type instance: L{objects.Instance}
2515 @param instance: the instance that was migrated
2517 @param success: whether the migration succeeded or not
2519 @param live: whether the user requested a live migration or not
2523 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2524 utils.KillProcess(pid)
2525 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2527 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2529 def GetMigrationStatus(self, instance):
2530 """Get the migration status
2532 @type instance: L{objects.Instance}
2533 @param instance: the instance that is being migrated
2534 @rtype: L{objects.MigrationStatus}
2535 @return: the status of the current migration (one of
2536 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2537 progress info that can be retrieved from the hypervisor
2540 info_command = "info migrate"
2541 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2542 result = self._CallMonitorCommand(instance.name, info_command)
2543 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2545 if not result.stdout:
2546 logging.info("KVM: empty 'info migrate' result")
2548 logging.warning("KVM: unknown 'info migrate' result: %s",
2551 status = match.group(1)
2552 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2553 migration_status = objects.MigrationStatus(status=status)
2554 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2556 migration_status.transferred_ram = match.group("transferred")
2557 migration_status.total_ram = match.group("total")
2559 return migration_status
2561 logging.warning("KVM: unknown migration status '%s'", status)
2563 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2565 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2567 def BalloonInstanceMemory(self, instance, mem):
2568 """Balloon an instance memory to a certain value.
2570 @type instance: L{objects.Instance}
2571 @param instance: instance to be accepted
2573 @param mem: actual memory size to use for instance runtime
2576 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2578 def GetNodeInfo(self):
2579 """Return information about the node.
2581 @return: a dict with the following keys (values in MiB):
2582 - memory_total: the total memory size on the node
2583 - memory_free: the available memory on the node for instances
2584 - memory_dom0: the memory used by the node itself, if available
2585 - hv_version: the hypervisor version in the form (major, minor,
2589 result = self.GetLinuxNodeInfo()
2590 # FIXME: this is the global kvm version, but the actual version can be
2591 # customized as an hv parameter. we should use the nodegroup's default kvm
2592 # path parameter here.
2593 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2594 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2598 def GetInstanceConsole(cls, instance, hvparams, beparams):
2599 """Return a command for connecting to the console of an instance.
2602 if hvparams[constants.HV_SERIAL_CONSOLE]:
2603 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2604 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2605 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2606 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2607 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2608 return objects.InstanceConsole(instance=instance.name,
2609 kind=constants.CONS_SSH,
2610 host=instance.primary_node,
2611 user=constants.SSH_CONSOLE_USER,
2614 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2615 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2616 display = instance.network_port - constants.VNC_BASE_PORT
2617 return objects.InstanceConsole(instance=instance.name,
2618 kind=constants.CONS_VNC,
2619 host=vnc_bind_address,
2620 port=instance.network_port,
2623 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2625 return objects.InstanceConsole(instance=instance.name,
2626 kind=constants.CONS_SPICE,
2628 port=instance.network_port)
2630 return objects.InstanceConsole(instance=instance.name,
2631 kind=constants.CONS_MESSAGE,
2632 message=("No serial shell for instance %s" %
2636 """Verify the hypervisor.
2638 Check that the required binaries exist.
2640 @return: Problem description if something is wrong, C{None} otherwise
2644 # FIXME: this is the global kvm binary, but the actual path can be
2645 # customized as an hv parameter; we should use the nodegroup's
2646 # default kvm path parameter here.
2647 if not os.path.exists(constants.KVM_PATH):
2648 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2649 if not os.path.exists(constants.SOCAT_PATH):
2650 msgs.append("The socat binary ('%s') does not exist" %
2651 constants.SOCAT_PATH)
2653 return self._FormatVerifyResults(msgs)
2656 def CheckParameterSyntax(cls, hvparams):
2657 """Check the given parameters for validity.
2659 @type hvparams: dict
2660 @param hvparams: dictionary with parameter names/value
2661 @raise errors.HypervisorError: when a parameter is not valid
2664 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2666 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2668 if not hvparams[constants.HV_ROOT_PATH]:
2669 raise errors.HypervisorError("Need a root partition for the instance,"
2670 " if a kernel is defined")
2672 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2673 not hvparams[constants.HV_VNC_X509]):
2674 raise errors.HypervisorError("%s must be defined, if %s is" %
2675 (constants.HV_VNC_X509,
2676 constants.HV_VNC_X509_VERIFY))
2678 if hvparams[constants.HV_SERIAL_CONSOLE]:
2679 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2680 valid_speeds = constants.VALID_SERIAL_SPEEDS
2681 if not serial_speed or serial_speed not in valid_speeds:
2682 raise errors.HypervisorError("Invalid serial console speed, must be"
2684 utils.CommaJoin(valid_speeds))
2686 boot_order = hvparams[constants.HV_BOOT_ORDER]
2687 if (boot_order == constants.HT_BO_CDROM and
2688 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2689 raise errors.HypervisorError("Cannot boot from cdrom without an"
2692 security_model = hvparams[constants.HV_SECURITY_MODEL]
2693 if security_model == constants.HT_SM_USER:
2694 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2695 raise errors.HypervisorError("A security domain (user to run kvm as)"
2696 " must be specified")
2697 elif (security_model == constants.HT_SM_NONE or
2698 security_model == constants.HT_SM_POOL):
2699 if hvparams[constants.HV_SECURITY_DOMAIN]:
2700 raise errors.HypervisorError("Cannot have a security domain when the"
2701 " security model is 'none' or 'pool'")
2703 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2704 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2706 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2707 # if an IP version is specified, the spice_bind parameter must be an
2709 if (netutils.IP4Address.IsValid(spice_bind) and
2710 spice_ip_version != constants.IP4_VERSION):
2711 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2712 " the specified IP version is %s" %
2713 (spice_bind, spice_ip_version))
2715 if (netutils.IP6Address.IsValid(spice_bind) and
2716 spice_ip_version != constants.IP6_VERSION):
2717 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2718 " the specified IP version is %s" %
2719 (spice_bind, spice_ip_version))
2721 # All the other SPICE parameters depend on spice_bind being set. Raise an
2722 # error if any of them is set without it.
2723 for param in _SPICE_ADDITIONAL_PARAMS:
2725 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2726 (param, constants.HV_KVM_SPICE_BIND))
2729 def ValidateParameters(cls, hvparams):
2730 """Check the given parameters for validity.
2732 @type hvparams: dict
2733 @param hvparams: dictionary with parameter names/value
2734 @raise errors.HypervisorError: when a parameter is not valid
2737 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2739 kvm_path = hvparams[constants.HV_KVM_PATH]
2741 security_model = hvparams[constants.HV_SECURITY_MODEL]
2742 if security_model == constants.HT_SM_USER:
2743 username = hvparams[constants.HV_SECURITY_DOMAIN]
2745 pwd.getpwnam(username)
2747 raise errors.HypervisorError("Unknown security domain user %s"
2750 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2752 # only one of VNC and SPICE can be used currently.
2753 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2754 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2755 " only one of them can be used at a"
2758 # check that KVM supports SPICE
2759 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2760 if not cls._SPICE_RE.search(kvmhelp):
2761 raise errors.HypervisorError("SPICE is configured, but it is not"
2762 " supported according to 'kvm --help'")
2764 # if spice_bind is not an IP address, it must be a valid interface
2765 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2766 netutils.IP6Address.IsValid(spice_bind))
2767 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2768 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2769 " a valid IP address or interface name" %
2770 constants.HV_KVM_SPICE_BIND)
2772 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2774 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2775 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2776 raise errors.HypervisorError("Unsupported machine version: %s" %
2780 def PowercycleNode(cls):
2781 """KVM powercycle, just a wrapper over Linux powercycle.
2784 cls.LinuxPowercycle()