4 # Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
40 from bitarray import bitarray
42 import affinity # pylint: disable=F0401
46 import fdsend # pylint: disable=F0401
50 from ganeti import utils
51 from ganeti import constants
52 from ganeti import errors
53 from ganeti import serializer
54 from ganeti import objects
55 from ganeti import uidpool
56 from ganeti import ssconf
57 from ganeti import netutils
58 from ganeti import pathutils
59 from ganeti.hypervisor import hv_base
60 from ganeti.utils import wrapper as utils_wrapper
63 _KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
64 _KVM_START_PAUSED_FLAG = "-S"
66 # TUN/TAP driver constants, taken from <linux/if_tun.h>
67 # They are architecture-independent and already hardcoded in qemu-kvm source,
68 # so we can safely include them here.
69 TUNSETIFF = 0x400454ca
70 TUNGETIFF = 0x800454d2
71 TUNGETFEATURES = 0x800454cf
76 #: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
77 _SPICE_ADDITIONAL_PARAMS = frozenset([
78 constants.HV_KVM_SPICE_IP_VERSION,
79 constants.HV_KVM_SPICE_PASSWORD_FILE,
80 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
81 constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
82 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
83 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
84 constants.HV_KVM_SPICE_USE_TLS,
87 # Constant bitarray that reflects to a free pci slot
88 # Use it with bitarray.search()
89 _AVAILABLE_PCI_SLOT = bitarray("0")
91 # below constants show the format of runtime file
92 # the nics are in second possition, while the disks in 4th (last)
93 # moreover disk entries are stored as a list of in tuples
94 # (L{objects.Disk}, link_name, uri)
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, u) for (d, l, u) 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, None)
118 def _GenerateDeviceKVMId(dev_type, dev):
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)
134 raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
135 (dev_type, dev.uuid))
137 return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
140 def _UpdatePCISlots(dev, pci_reservations):
141 """Update pci configuration for a stopped instance
143 If dev has a pci slot then reserve it, else find first available
144 in pci_reservations bitarray. It acts on the same objects passed
145 as params so there is no need to return anything.
147 @type dev: L{objects.Disk} or L{objects.NIC}
148 @param dev: the device object for which we update its pci slot
149 @type pci_reservations: bitarray
150 @param pci_reservations: existing pci reservations for an instance
151 @raise errors.HotplugError: in case an instance has all its slot occupied
156 else: # pylint: disable=E1103
157 [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
159 raise errors.HypervisorError("All PCI slots occupied")
162 pci_reservations[free] = True
165 def _GetExistingDeviceInfo(dev_type, device, runtime):
166 """Helper function to get an existing device inside the runtime file
168 Used when an instance is running. Load kvm runtime file and search
169 for a device based on its type and uuid.
171 @type dev_type: sting
172 @param dev_type: device type of param dev
173 @type device: L{objects.Disk} or L{objects.NIC}
174 @param device: the device object for which we generate a kvm name
175 @type runtime: tuple (cmd, nics, hvparams, disks)
176 @param runtime: the runtime data to search for the device
177 @raise errors.HotplugError: in case the requested device does not
178 exist (e.g. device has been added without --hotplug option) or
179 device info has not pci slot (e.g. old devices in the cluster)
182 index = _DEVICE_RUNTIME_INDEX[dev_type]
183 found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
185 raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
186 (dev_type, device.uuid))
191 def _UpgradeSerializedRuntime(serialized_runtime):
192 """Upgrade runtime data
194 Remove any deprecated fields or change the format of the data.
195 The runtime files are not upgraded when Ganeti is upgraded, so the required
196 modification have to be performed here.
198 @type serialized_runtime: string
199 @param serialized_runtime: raw text data read from actual runtime file
200 @return: (cmd, nic dicts, hvparams, bdev dicts)
204 loaded_runtime = serializer.Load(serialized_runtime)
205 kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3]
206 if len(loaded_runtime) >= 4:
207 serialized_disks = loaded_runtime[3]
209 serialized_disks = []
211 for nic in serialized_nics:
212 # Add a dummy uuid slot if an pre-2.8 NIC is found
213 if "uuid" not in nic:
214 nic["uuid"] = utils.NewUUID()
216 return kvm_cmd, serialized_nics, hvparams, serialized_disks
219 def _AnalyzeSerializedRuntime(serialized_runtime):
220 """Return runtime entries for a serialized runtime file
222 @type serialized_runtime: string
223 @param serialized_runtime: raw text data read from actual runtime file
224 @return: (cmd, nics, hvparams, bdevs)
228 kvm_cmd, serialized_nics, hvparams, serialized_disks = \
229 _UpgradeSerializedRuntime(serialized_runtime)
230 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
231 kvm_disks = [(objects.Disk.FromDict(sdisk), link, uri)
232 for sdisk, link, uri in serialized_disks]
234 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
237 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
238 """Retrieves supported TUN features from file descriptor.
240 @see: L{_ProbeTapVnetHdr}
243 req = struct.pack("I", 0)
245 buf = _ioctl(fd, TUNGETFEATURES, req)
246 except EnvironmentError, err:
247 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
250 (flags, ) = struct.unpack("I", buf)
254 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
255 """Check whether to enable the IFF_VNET_HDR flag.
257 To do this, _all_ of the following conditions must be met:
258 1. TUNGETFEATURES ioctl() *must* be implemented
259 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
260 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
261 drivers/net/tun.c there is no way to test this until after the tap device
262 has been created using TUNSETIFF, and there is no way to change the
263 IFF_VNET_HDR flag after creating the interface, catch-22! However both
264 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
265 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
268 @param fd: the file descriptor of /dev/net/tun
271 flags = _features_fn(fd)
277 result = bool(flags & IFF_VNET_HDR)
280 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
285 def _OpenTap(vnet_hdr=True):
286 """Open a new tap device and return its file descriptor.
288 This is intended to be used by a qemu-type hypervisor together with the -net
289 tap,fd=<fd> command line parameter.
291 @type vnet_hdr: boolean
292 @param vnet_hdr: Enable the VNET Header
293 @return: (ifname, tapfd)
298 tapfd = os.open("/dev/net/tun", os.O_RDWR)
299 except EnvironmentError:
300 raise errors.HypervisorError("Failed to open /dev/net/tun")
302 flags = IFF_TAP | IFF_NO_PI
304 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
305 flags |= IFF_VNET_HDR
307 # The struct ifreq ioctl request (see netdevice(7))
308 ifr = struct.pack("16sh", "", flags)
311 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
312 except EnvironmentError, err:
313 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
316 # Get the interface name from the ioctl
317 ifname = struct.unpack("16sh", res)[0].strip("\x00")
318 return (ifname, tapfd)
322 """QEMU Messaging Protocol (QMP) message.
325 def __init__(self, data):
326 """Creates a new QMP message based on the passed data.
329 if not isinstance(data, dict):
330 raise TypeError("QmpMessage must be initialized with a dict")
334 def __getitem__(self, field_name):
335 """Get the value of the required field if present, or None.
337 Overrides the [] operator to provide access to the message data,
338 returning None if the required item is not in the message
339 @return: the value of the field_name field, or None if field_name
340 is not contained in the message
343 return self.data.get(field_name, None)
345 def __setitem__(self, field_name, field_value):
346 """Set the value of the required field_name to field_value.
349 self.data[field_name] = field_value
352 """Return the number of fields stored in this QmpMessage.
355 return len(self.data)
357 def __delitem__(self, key):
358 """Delete the specified element from the QmpMessage.
364 def BuildFromJsonString(json_string):
365 """Build a QmpMessage from a JSON encoded string.
367 @type json_string: str
368 @param json_string: JSON string representing the message
369 @rtype: L{QmpMessage}
370 @return: a L{QmpMessage} built from json_string
374 data = serializer.LoadJson(json_string)
375 return QmpMessage(data)
378 # The protocol expects the JSON object to be sent as a single line.
379 return serializer.DumpJson(self.data)
381 def __eq__(self, other):
382 # When comparing two QmpMessages, we are interested in comparing
383 # their internal representation of the message data
384 return self.data == other.data
387 class MonitorSocket(object):
390 def __init__(self, monitor_filename):
391 """Instantiates the MonitorSocket object.
393 @type monitor_filename: string
394 @param monitor_filename: the filename of the UNIX raw socket on which the
395 monitor (QMP or simple one) is listening
398 self.monitor_filename = monitor_filename
399 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
400 # We want to fail if the server doesn't send a complete message
401 # in a reasonable amount of time
402 self.sock.settimeout(self._SOCKET_TIMEOUT)
403 self._connected = False
405 def _check_socket(self):
408 sock_stat = os.stat(self.monitor_filename)
409 except EnvironmentError, err:
410 if err.errno == errno.ENOENT:
411 raise errors.HypervisorError("No monitor socket found")
413 raise errors.HypervisorError("Error checking monitor socket: %s",
414 utils.ErrnoOrStr(err))
415 if not stat.S_ISSOCK(sock_stat.st_mode):
416 raise errors.HypervisorError("Monitor socket is not a socket")
418 def _check_connection(self):
419 """Make sure that the connection is established.
422 if not self._connected:
423 raise errors.ProgrammerError("To use a MonitorSocket you need to first"
424 " invoke connect() on it")
427 """Connects to the monitor.
429 Connects to the UNIX socket
431 @raise errors.HypervisorError: when there are communication errors
435 raise errors.ProgrammerError("Cannot connect twice")
439 # Check file existance/stuff
441 self.sock.connect(self.monitor_filename)
442 except EnvironmentError:
443 raise errors.HypervisorError("Can't connect to qmp socket")
444 self._connected = True
449 It cannot be used after this call.
455 class QmpConnection(MonitorSocket):
456 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
459 _FIRST_MESSAGE_KEY = "QMP"
462 _RETURN_KEY = RETURN_KEY = "return"
463 _ACTUAL_KEY = ACTUAL_KEY = "actual"
464 _ERROR_CLASS_KEY = "class"
465 _ERROR_DESC_KEY = "desc"
466 _EXECUTE_KEY = "execute"
467 _ARGUMENTS_KEY = "arguments"
468 _CAPABILITIES_COMMAND = "qmp_capabilities"
469 _MESSAGE_END_TOKEN = "\r\n"
471 def __init__(self, monitor_filename):
472 super(QmpConnection, self).__init__(monitor_filename)
476 """Connects to the QMP monitor.
478 Connects to the UNIX socket and makes sure that we can actually send and
479 receive data to the kvm instance via QMP.
481 @raise errors.HypervisorError: when there are communication errors
482 @raise errors.ProgrammerError: when there are data serialization errors
485 super(QmpConnection, self).connect()
486 # Check if we receive a correct greeting message from the server
487 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
488 greeting = self._Recv()
489 if not greeting[self._FIRST_MESSAGE_KEY]:
490 self._connected = False
491 raise errors.HypervisorError("kvm: QMP communication error (wrong"
494 # Let's put the monitor in command mode using the qmp_capabilities
495 # command, or else no command will be executable.
496 # (As per the QEMU Protocol Specification 0.1 - section 4)
497 self.Execute(self._CAPABILITIES_COMMAND)
499 def _ParseMessage(self, buf):
500 """Extract and parse a QMP message from the given buffer.
502 Seeks for a QMP message in the given buf. If found, it parses it and
503 returns it together with the rest of the characters in the buf.
504 If no message is found, returns None and the whole buffer.
506 @raise errors.ProgrammerError: when there are data serialization errors
510 # Check if we got the message end token (CRLF, as per the QEMU Protocol
511 # Specification 0.1 - Section 2.1.1)
512 pos = buf.find(self._MESSAGE_END_TOKEN)
515 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
516 except Exception, err:
517 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
520 return (message, buf)
523 """Receives a message from QMP and decodes the received JSON object.
526 @return: the received message
527 @raise errors.HypervisorError: when there are communication errors
528 @raise errors.ProgrammerError: when there are data serialization errors
531 self._check_connection()
533 # Check if there is already a message in the buffer
534 (message, self._buf) = self._ParseMessage(self._buf)
538 recv_buffer = StringIO.StringIO(self._buf)
539 recv_buffer.seek(len(self._buf))
542 data = self.sock.recv(4096)
545 recv_buffer.write(data)
547 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
551 except socket.timeout, err:
552 raise errors.HypervisorError("Timeout while receiving a QMP message: "
554 except socket.error, err:
555 raise errors.HypervisorError("Unable to receive data from KVM using the"
556 " QMP protocol: %s" % err)
558 def _Send(self, message):
559 """Encodes and sends a message to KVM using QMP.
561 @type message: QmpMessage
562 @param message: message to send to KVM
563 @raise errors.HypervisorError: when there are communication errors
564 @raise errors.ProgrammerError: when there are data serialization errors
567 self._check_connection()
569 message_str = str(message)
570 except Exception, err:
571 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
574 self.sock.sendall(message_str)
575 except socket.timeout, err:
576 raise errors.HypervisorError("Timeout while sending a QMP message: "
577 "%s (%s)" % (err.string, err.errno))
578 except socket.error, err:
579 raise errors.HypervisorError("Unable to send data from KVM using the"
580 " QMP protocol: %s" % err)
582 def Execute(self, command, arguments=None):
583 """Executes a QMP command and returns the response of the server.
586 @param command: the command to execute
587 @type arguments: dict
588 @param arguments: dictionary of arguments to be passed to the command
590 @return: dictionary representing the received JSON object
591 @raise errors.HypervisorError: when there are communication errors
592 @raise errors.ProgrammerError: when there are data serialization errors
595 self._check_connection()
596 message = QmpMessage({self._EXECUTE_KEY: command})
598 message[self._ARGUMENTS_KEY] = arguments
601 # Events can occur between the sending of the command and the reception
602 # of the response, so we need to filter out messages with the event key.
604 response = self._Recv()
605 err = response[self._ERROR_KEY]
607 raise errors.HypervisorError("kvm: error executing the %s"
608 " command: %s (%s):" %
610 err[self._ERROR_DESC_KEY],
611 err[self._ERROR_CLASS_KEY]))
613 elif not response[self._EVENT_KEY]:
617 class KVMHypervisor(hv_base.BaseHypervisor):
618 """KVM hypervisor interface
623 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
624 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
625 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
626 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
627 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
628 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
629 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
630 # KVM instances with chroot enabled are started in empty chroot directories.
631 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
632 # After an instance is stopped, its chroot directory is removed.
633 # If the chroot directory is not empty, it can't be removed.
634 # A non-empty chroot directory indicates a possible security incident.
635 # To support forensics, the non-empty chroot directory is quarantined in
636 # a separate directory, called 'chroot-quarantine'.
637 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
638 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
639 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
642 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
643 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
644 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
645 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
646 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
647 constants.HV_ACPI: hv_base.NO_CHECK,
648 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
649 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
650 constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
651 constants.HV_VNC_TLS: hv_base.NO_CHECK,
652 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
653 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
654 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
655 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
656 constants.HV_KVM_SPICE_IP_VERSION:
657 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
658 x in constants.VALID_IP_VERSIONS),
659 "The SPICE IP version should be 4 or 6",
661 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
662 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
664 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
665 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
667 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
668 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
670 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
671 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
673 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
674 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
675 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
676 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
677 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
678 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
679 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
680 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
681 constants.HV_BOOT_ORDER:
682 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
683 constants.HV_NIC_TYPE:
684 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
685 constants.HV_DISK_TYPE:
686 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
687 constants.HV_KVM_CDROM_DISK_TYPE:
688 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
689 constants.HV_USB_MOUSE:
690 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
691 constants.HV_KEYMAP: hv_base.NO_CHECK,
692 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
693 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
694 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
695 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
696 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
697 constants.HV_DISK_CACHE:
698 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
699 constants.HV_SECURITY_MODEL:
700 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
701 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
702 constants.HV_KVM_FLAG:
703 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
704 constants.HV_VHOST_NET: hv_base.NO_CHECK,
705 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
706 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
707 constants.HV_REBOOT_BEHAVIOR:
708 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
709 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
710 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
711 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
712 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
713 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
714 constants.HV_SOUNDHW: hv_base.NO_CHECK,
715 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
716 constants.HV_VGA: hv_base.NO_CHECK,
717 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
718 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
719 constants.HV_VNET_HDR: hv_base.NO_CHECK,
723 _VIRTIO_NET_PCI = "virtio-net-pci"
724 _VIRTIO_BLK_PCI = "virtio-blk-pci"
726 _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
728 _MIGRATION_PROGRESS_RE = \
729 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
730 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
731 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
733 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
734 _MIGRATION_INFO_RETRY_DELAY = 2
736 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
738 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
739 _CPU_INFO_CMD = "info cpus"
742 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
743 _CHECK_MACHINE_VERSION_RE = \
744 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
746 _QMP_RE = re.compile(r"^-qmp\s", re.M)
747 _SPICE_RE = re.compile(r"^-spice\s", re.M)
748 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
749 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
750 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
751 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
752 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
753 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
754 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
755 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
756 # match -drive.*boot=on|off on different lines, but in between accept only
757 # dashes not preceeded by a new line (which would mean another option
758 # different than -drive is starting)
759 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
760 _UUID_RE = re.compile(r"^-uuid\s", re.M)
762 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
763 _INFO_PCI_CMD = "info pci"
765 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
766 _INFO_VERSION_CMD = "info version"
768 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
773 ANCILLARY_FILES_OPT = [
777 # Supported kvm options to get output from
778 _KVMOPT_HELP = "help"
779 _KVMOPT_MLIST = "mlist"
780 _KVMOPT_DEVICELIST = "devicelist"
782 # Command to execute to get the output from kvm, and whether to
783 # accept the output even on failure.
785 _KVMOPT_HELP: (["--help"], False),
786 _KVMOPT_MLIST: (["-M", "?"], False),
787 _KVMOPT_DEVICELIST: (["-device", "?"], True),
791 hv_base.BaseHypervisor.__init__(self)
792 # Let's make sure the directories we need exist, even if the RUN_DIR lives
793 # in a tmpfs filesystem or has been otherwise wiped out.
794 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
795 utils.EnsureDirs(dirs)
798 def _InstancePidFile(cls, instance_name):
799 """Returns the instance pidfile.
802 return utils.PathJoin(cls._PIDS_DIR, instance_name)
805 def _InstanceUidFile(cls, instance_name):
806 """Returns the instance uidfile.
809 return utils.PathJoin(cls._UIDS_DIR, instance_name)
812 def _InstancePidInfo(cls, pid):
813 """Check pid file for instance information.
815 Check that a pid file is associated with an instance, and retrieve
816 information from its command line.
818 @type pid: string or int
819 @param pid: process id of the instance to check
821 @return: (instance_name, memory, vcpus)
822 @raise errors.HypervisorError: when an instance cannot be found
825 alive = utils.IsProcessAlive(pid)
827 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
829 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
831 cmdline = utils.ReadFile(cmdline_file)
832 except EnvironmentError, err:
833 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
840 arg_list = cmdline.split("\x00")
842 arg = arg_list.pop(0)
844 instance = arg_list.pop(0)
846 memory = int(arg_list.pop(0))
848 vcpus = int(arg_list.pop(0).split(",")[0])
851 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
854 return (instance, memory, vcpus)
856 def _InstancePidAlive(self, instance_name):
857 """Returns the instance pidfile, pid, and liveness.
859 @type instance_name: string
860 @param instance_name: instance name
862 @return: (pid file name, pid, liveness)
865 pidfile = self._InstancePidFile(instance_name)
866 pid = utils.ReadPidFile(pidfile)
870 cmd_instance = self._InstancePidInfo(pid)[0]
871 alive = (cmd_instance == instance_name)
872 except errors.HypervisorError:
875 return (pidfile, pid, alive)
877 def _CheckDown(self, instance_name):
878 """Raises an error unless the given instance is down.
881 alive = self._InstancePidAlive(instance_name)[2]
883 raise errors.HypervisorError("Failed to start instance %s: %s" %
884 (instance_name, "already running"))
887 def _InstanceMonitor(cls, instance_name):
888 """Returns the instance monitor socket name
891 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
894 def _InstanceSerial(cls, instance_name):
895 """Returns the instance serial socket name
898 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
901 def _InstanceQmpMonitor(cls, instance_name):
902 """Returns the instance serial QMP socket name
905 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
908 def _SocatUnixConsoleParams():
909 """Returns the correct parameters for socat
911 If we have a new-enough socat we can use raw mode with an escape character.
914 if constants.SOCAT_USE_ESCAPE:
915 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
917 return "echo=0,icanon=0"
920 def _InstanceKVMRuntime(cls, instance_name):
921 """Returns the instance KVM runtime filename
924 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
927 def _InstanceChrootDir(cls, instance_name):
928 """Returns the name of the KVM chroot dir of the instance
931 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
934 def _InstanceNICDir(cls, instance_name):
935 """Returns the name of the directory holding the tap device files for a
939 return utils.PathJoin(cls._NICS_DIR, instance_name)
942 def _InstanceNICFile(cls, instance_name, seq):
943 """Returns the name of the file containing the tap device for a given NIC
946 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
949 def _InstanceKeymapFile(cls, instance_name):
950 """Returns the name of the file containing the keymap for a given instance
953 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
956 def _TryReadUidFile(cls, uid_file):
957 """Try to read a uid file
960 if os.path.exists(uid_file):
962 uid = int(utils.ReadOneLineFile(uid_file))
964 except EnvironmentError:
965 logging.warning("Can't read uid file", exc_info=True)
966 except (TypeError, ValueError):
967 logging.warning("Can't parse uid file contents", exc_info=True)
971 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
972 """Removes an instance's rutime sockets/files/dirs.
975 utils.RemoveFile(pidfile)
976 utils.RemoveFile(cls._InstanceMonitor(instance_name))
977 utils.RemoveFile(cls._InstanceSerial(instance_name))
978 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
979 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
980 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
981 uid_file = cls._InstanceUidFile(instance_name)
982 uid = cls._TryReadUidFile(uid_file)
983 utils.RemoveFile(uid_file)
985 uidpool.ReleaseUid(uid)
987 shutil.rmtree(cls._InstanceNICDir(instance_name))
989 if err.errno != errno.ENOENT:
992 chroot_dir = cls._InstanceChrootDir(instance_name)
993 utils.RemoveDir(chroot_dir)
995 if err.errno == errno.ENOTEMPTY:
996 # The chroot directory is expected to be empty, but it isn't.
997 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
1000 utils.TimestampForFilename()))
1001 logging.warning("The chroot directory of instance %s can not be"
1002 " removed as it is not empty. Moving it to the"
1003 " quarantine instead. Please investigate the"
1004 " contents (%s) and clean up manually",
1005 instance_name, new_chroot_dir)
1006 utils.RenameFile(chroot_dir, new_chroot_dir)
1011 def _ConfigureNIC(instance, seq, nic, tap):
1012 """Run the network configuration script for a specified NIC
1014 @param instance: instance we're acting on
1015 @type instance: instance object
1016 @param seq: nic sequence number
1018 @param nic: nic we're acting on
1019 @type nic: nic object
1020 @param tap: the host's tap interface this NIC corresponds to
1025 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1026 "INSTANCE": instance.name,
1028 "MODE": nic.nicparams[constants.NIC_MODE],
1030 "INTERFACE_INDEX": str(seq),
1031 "INTERFACE_UUID": nic.uuid,
1032 "TAGS": " ".join(instance.GetTags()),
1039 env["INTERFACE_NAME"] = nic.name
1041 if nic.nicparams[constants.NIC_LINK]:
1042 env["LINK"] = nic.nicparams[constants.NIC_LINK]
1045 n = objects.Network.FromDict(nic.netinfo)
1046 env.update(n.HooksDict())
1048 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1049 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1051 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1053 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1054 " network configuration script output: %s" %
1055 (tap, result.fail_reason, result.output))
1058 def _VerifyAffinityPackage():
1059 if affinity is None:
1060 raise errors.HypervisorError("affinity Python package not"
1061 " found; cannot use CPU pinning under KVM")
1064 def _BuildAffinityCpuMask(cpu_list):
1065 """Create a CPU mask suitable for sched_setaffinity from a list of
1068 See man taskset for more info on sched_setaffinity masks.
1069 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1071 @type cpu_list: list of int
1072 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1074 @return: a bit mask of CPU affinities
1077 if cpu_list == constants.CPU_PINNING_OFF:
1078 return constants.CPU_PINNING_ALL_KVM
1080 return sum(2 ** cpu for cpu in cpu_list)
1083 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1084 """Change CPU affinity for running VM according to given CPU mask.
1086 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1087 @type cpu_mask: string
1088 @param process_id: process ID of KVM process. Used to pin entire VM
1090 @type process_id: int
1091 @param thread_dict: map of virtual CPUs to KVM thread IDs
1092 @type thread_dict: dict int:int
1095 # Convert the string CPU mask to a list of list of int's
1096 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1098 if len(cpu_list) == 1:
1099 all_cpu_mapping = cpu_list[0]
1100 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1101 # If CPU pinning has 1 entry that's "all", then do nothing
1104 # If CPU pinning has one non-all entry, map the entire VM to
1105 # one set of physical CPUs
1106 cls._VerifyAffinityPackage()
1107 affinity.set_process_affinity_mask(
1108 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1110 # The number of vCPUs mapped should match the number of vCPUs
1111 # reported by KVM. This was already verified earlier, so
1112 # here only as a sanity check.
1113 assert len(thread_dict) == len(cpu_list)
1114 cls._VerifyAffinityPackage()
1116 # For each vCPU, map it to the proper list of physical CPUs
1117 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1118 affinity.set_process_affinity_mask(thread_dict[i],
1119 cls._BuildAffinityCpuMask(vcpu))
1121 def _GetVcpuThreadIds(self, instance_name):
1122 """Get a mapping of vCPU no. to thread IDs for the instance
1124 @type instance_name: string
1125 @param instance_name: instance in question
1126 @rtype: dictionary of int:int
1127 @return: a dictionary mapping vCPU numbers to thread IDs
1131 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1132 for line in output.stdout.splitlines():
1133 match = self._CPU_INFO_RE.search(line)
1136 grp = map(int, match.groups())
1137 result[grp[0]] = grp[1]
1141 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1142 """Complete CPU pinning.
1144 @type instance_name: string
1145 @param instance_name: name of instance
1146 @type cpu_mask: string
1147 @param cpu_mask: CPU pinning mask as entered by user
1150 # Get KVM process ID, to be used if need to pin entire VM
1151 _, pid, _ = self._InstancePidAlive(instance_name)
1152 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1153 thread_dict = self._GetVcpuThreadIds(instance_name)
1154 # Run CPU pinning, based on configured mask
1155 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1157 def ListInstances(self, hvparams=None):
1158 """Get the list of running instances.
1160 We can do this by listing our live instances directory and
1161 checking whether the associated kvm process is still alive.
1165 for name in os.listdir(self._PIDS_DIR):
1166 if self._InstancePidAlive(name)[2]:
1170 def GetInstanceInfo(self, instance_name, hvparams=None):
1171 """Get instance properties.
1173 @type instance_name: string
1174 @param instance_name: the instance name
1175 @type hvparams: dict of strings
1176 @param hvparams: hvparams to be used with this instance
1177 @rtype: tuple of strings
1178 @return: (name, id, memory, vcpus, stat, times)
1181 _, pid, alive = self._InstancePidAlive(instance_name)
1185 _, memory, vcpus = self._InstancePidInfo(pid)
1190 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1192 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1193 # Will fail if ballooning is not enabled, but we can then just resort to
1195 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1196 memory = mem_bytes / 1048576
1197 except errors.HypervisorError:
1200 return (instance_name, pid, memory, vcpus, istat, times)
1202 def GetAllInstancesInfo(self, hvparams=None):
1203 """Get properties of all instances.
1205 @type hvparams: dict of strings
1206 @param hvparams: hypervisor parameter
1207 @return: list of tuples (name, id, memory, vcpus, stat, times)
1211 for name in os.listdir(self._PIDS_DIR):
1213 info = self.GetInstanceInfo(name)
1214 except errors.HypervisorError:
1215 # Ignore exceptions due to instances being shut down
1221 def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1223 """Generate KVM options regarding instance's block devices.
1225 @type instance: L{objects.Instance}
1226 @param instance: the instance object
1227 @type kvm_disks: list of tuples
1228 @param kvm_disks: list of tuples [(disk, link_name, uri)..]
1229 @type kvmhelp: string
1230 @param kvmhelp: output of kvm --help
1231 @type devlist: string
1232 @param devlist: output of kvm -device ?
1234 @return: list of command line options eventually used by kvm executable
1237 hvp = instance.hvparams
1238 kernel_path = hvp[constants.HV_KERNEL_PATH]
1242 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1244 # whether this is an older KVM version that uses the boot=on flag
1246 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1249 device_driver = None
1250 disk_type = hvp[constants.HV_DISK_TYPE]
1251 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1252 if_val = ",if=%s" % self._VIRTIO
1254 if self._VIRTIO_BLK_RE.search(devlist):
1256 # will be passed in -device option as driver
1257 device_driver = self._VIRTIO_BLK_PCI
1258 except errors.HypervisorError, _:
1261 if_val = ",if=%s" % disk_type
1263 disk_cache = hvp[constants.HV_DISK_CACHE]
1264 if instance.disk_template in constants.DTS_EXT_MIRROR:
1265 if disk_cache != "none":
1266 # TODO: make this a hard error, instead of a silent overwrite
1267 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1268 " to prevent shared storage corruption on migration",
1270 cache_val = ",cache=none"
1271 elif disk_cache != constants.HT_CACHE_DEFAULT:
1272 cache_val = ",cache=%s" % disk_cache
1275 for cfdev, link_name, uri in kvm_disks:
1276 if cfdev.mode != constants.DISK_RDWR:
1277 raise errors.HypervisorError("Instance has read-only disks which"
1278 " are not supported by KVM")
1279 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1282 dev_opts.extend(["-boot", "c"])
1284 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1285 boot_val = ",boot=on"
1287 access_mode = cfdev.params.get(constants.LDP_ACCESS,
1288 constants.DISK_KERNELSPACE)
1289 if (uri and access_mode == constants.DISK_USERSPACE):
1292 drive_uri = link_name
1294 drive_val = "file=%s,format=raw%s%s%s" % \
1295 (drive_uri, if_val, boot_val, cache_val)
1298 # kvm_disks are the 4th entry of runtime file that did not exist in
1299 # the past. That means that cfdev should always have pci slot and
1300 # _GenerateDeviceKVMId() will not raise a exception.
1301 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1302 drive_val += (",id=%s" % kvm_devid)
1303 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1304 dev_val = ("%s,drive=%s,id=%s" %
1305 (device_driver, kvm_devid, kvm_devid))
1306 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1307 dev_opts.extend(["-device", dev_val])
1309 dev_opts.extend(["-drive", drive_val])
1313 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1315 """Generate KVM information to start an instance.
1317 @type kvmhelp: string
1318 @param kvmhelp: output of kvm --help
1319 @attention: this function must not have any side-effects; for
1320 example, it must not write to the filesystem, or read values
1321 from the current system the are expected to differ between
1322 nodes, since it is only run once at instance startup;
1323 actions/kvm arguments that can vary between systems should be
1324 done in L{_ExecuteKVMRuntime}
1327 # pylint: disable=R0912,R0914,R0915
1328 hvp = instance.hvparams
1329 self.ValidateParameters(hvp)
1331 pidfile = self._InstancePidFile(instance.name)
1332 kvm = hvp[constants.HV_KVM_PATH]
1334 # used just by the vnc server, if enabled
1335 kvm_cmd.extend(["-name", instance.name])
1336 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1338 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1339 if hvp[constants.HV_CPU_CORES]:
1340 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1341 if hvp[constants.HV_CPU_THREADS]:
1342 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1343 if hvp[constants.HV_CPU_SOCKETS]:
1344 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1346 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1348 kvm_cmd.extend(["-pidfile", pidfile])
1349 kvm_cmd.extend(["-balloon", "virtio"])
1350 kvm_cmd.extend(["-daemonize"])
1351 if not instance.hvparams[constants.HV_ACPI]:
1352 kvm_cmd.extend(["-no-acpi"])
1353 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1354 constants.INSTANCE_REBOOT_EXIT:
1355 kvm_cmd.extend(["-no-reboot"])
1357 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1359 mversion = self._GetDefaultMachineVersion(kvm)
1360 if self._MACHINE_RE.search(kvmhelp):
1361 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1362 # extra hypervisor parameters. We should also investigate whether and how
1363 # shadow_mem should be considered for the resource model.
1364 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1365 specprop = ",accel=kvm"
1368 machinespec = "%s%s" % (mversion, specprop)
1369 kvm_cmd.extend(["-machine", machinespec])
1371 kvm_cmd.extend(["-M", mversion])
1372 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1373 self._ENABLE_KVM_RE.search(kvmhelp)):
1374 kvm_cmd.extend(["-enable-kvm"])
1375 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1376 self._DISABLE_KVM_RE.search(kvmhelp)):
1377 kvm_cmd.extend(["-disable-kvm"])
1379 kernel_path = hvp[constants.HV_KERNEL_PATH]
1381 boot_cdrom = boot_floppy = boot_network = False
1383 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1384 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1385 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1388 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1391 kvm_cmd.extend(["-boot", "n"])
1393 # whether this is an older KVM version that uses the boot=on flag
1395 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1397 disk_type = hvp[constants.HV_DISK_TYPE]
1399 #Now we can specify a different device type for CDROM devices.
1400 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1401 if not cdrom_disk_type:
1402 cdrom_disk_type = disk_type
1404 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1406 options = ",format=raw,media=cdrom"
1407 # set cdrom 'if' type
1409 actual_cdrom_type = constants.HT_DISK_IDE
1410 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1411 actual_cdrom_type = "virtio"
1413 actual_cdrom_type = cdrom_disk_type
1414 if_val = ",if=%s" % actual_cdrom_type
1415 # set boot flag, if needed
1418 kvm_cmd.extend(["-boot", "d"])
1420 boot_val = ",boot=on"
1421 # and finally build the entire '-drive' value
1422 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1423 kvm_cmd.extend(["-drive", drive_val])
1425 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1427 options = ",format=raw,media=cdrom"
1428 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1429 if_val = ",if=virtio"
1431 if_val = ",if=%s" % cdrom_disk_type
1432 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1433 kvm_cmd.extend(["-drive", drive_val])
1435 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1437 options = ",format=raw,media=disk"
1439 kvm_cmd.extend(["-boot", "a"])
1440 options = "%s,boot=on" % options
1441 if_val = ",if=floppy"
1442 options = "%s%s" % (options, if_val)
1443 drive_val = "file=%s%s" % (floppy_image, options)
1444 kvm_cmd.extend(["-drive", drive_val])
1447 kvm_cmd.extend(["-kernel", kernel_path])
1448 initrd_path = hvp[constants.HV_INITRD_PATH]
1450 kvm_cmd.extend(["-initrd", initrd_path])
1451 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1452 hvp[constants.HV_KERNEL_ARGS]]
1453 if hvp[constants.HV_SERIAL_CONSOLE]:
1454 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1455 root_append.append("console=ttyS0,%s" % serial_speed)
1456 kvm_cmd.extend(["-append", " ".join(root_append)])
1458 mem_path = hvp[constants.HV_MEM_PATH]
1460 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1462 monitor_dev = ("unix:%s,server,nowait" %
1463 self._InstanceMonitor(instance.name))
1464 kvm_cmd.extend(["-monitor", monitor_dev])
1465 if hvp[constants.HV_SERIAL_CONSOLE]:
1466 serial_dev = ("unix:%s,server,nowait" %
1467 self._InstanceSerial(instance.name))
1468 kvm_cmd.extend(["-serial", serial_dev])
1470 kvm_cmd.extend(["-serial", "none"])
1472 mouse_type = hvp[constants.HV_USB_MOUSE]
1473 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1474 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1475 spice_ip_version = None
1477 kvm_cmd.extend(["-usb"])
1480 kvm_cmd.extend(["-usbdevice", mouse_type])
1481 elif vnc_bind_address:
1482 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1484 if vnc_bind_address:
1485 if netutils.IsValidInterface(vnc_bind_address):
1486 if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1487 if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1488 if len(if_ip4_addresses) < 1:
1489 logging.error("Could not determine IPv4 address of interface %s",
1492 vnc_bind_address = if_ip4_addresses[0]
1493 if netutils.IP4Address.IsValid(vnc_bind_address):
1494 if instance.network_port > constants.VNC_BASE_PORT:
1495 display = instance.network_port - constants.VNC_BASE_PORT
1496 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1497 vnc_arg = ":%d" % (display)
1499 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1501 logging.error("Network port is not a valid VNC display (%d < %d),"
1502 " not starting VNC",
1503 instance.network_port, constants.VNC_BASE_PORT)
1506 # Only allow tls and other option when not binding to a file, for now.
1507 # kvm/qemu gets confused otherwise about the filename to use.
1509 if hvp[constants.HV_VNC_TLS]:
1510 vnc_append = "%s,tls" % vnc_append
1511 if hvp[constants.HV_VNC_X509_VERIFY]:
1512 vnc_append = "%s,x509verify=%s" % (vnc_append,
1513 hvp[constants.HV_VNC_X509])
1514 elif hvp[constants.HV_VNC_X509]:
1515 vnc_append = "%s,x509=%s" % (vnc_append,
1516 hvp[constants.HV_VNC_X509])
1517 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1518 vnc_append = "%s,password" % vnc_append
1520 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1523 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1525 kvm_cmd.extend(["-vnc", vnc_arg])
1527 # FIXME: this is wrong here; the iface ip address differs
1528 # between systems, so it should be done in _ExecuteKVMRuntime
1529 if netutils.IsValidInterface(spice_bind):
1530 # The user specified a network interface, we have to figure out the IP
1532 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1533 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1535 # if the user specified an IP version and the interface does not
1536 # have that kind of IP addresses, throw an exception
1537 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1538 if not addresses[spice_ip_version]:
1539 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1540 " for %s" % (spice_ip_version,
1543 # the user did not specify an IP version, we have to figure it out
1544 elif (addresses[constants.IP4_VERSION] and
1545 addresses[constants.IP6_VERSION]):
1546 # we have both ipv4 and ipv6, let's use the cluster default IP
1548 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1549 spice_ip_version = \
1550 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1551 elif addresses[constants.IP4_VERSION]:
1552 spice_ip_version = constants.IP4_VERSION
1553 elif addresses[constants.IP6_VERSION]:
1554 spice_ip_version = constants.IP6_VERSION
1556 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1557 " for %s" % (spice_bind))
1559 spice_address = addresses[spice_ip_version][0]
1562 # spice_bind is known to be a valid IP address, because
1563 # ValidateParameters checked it.
1564 spice_address = spice_bind
1566 spice_arg = "addr=%s" % spice_address
1567 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1568 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1569 (spice_arg, instance.network_port,
1570 pathutils.SPICE_CACERT_FILE))
1571 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1572 (spice_arg, pathutils.SPICE_CERT_FILE,
1573 pathutils.SPICE_CERT_FILE))
1574 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1576 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1578 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1580 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1581 spice_arg = "%s,disable-ticketing" % spice_arg
1583 if spice_ip_version:
1584 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1586 # Image compression options
1587 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1588 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1589 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1591 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1593 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1595 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1597 # Video stream detection
1598 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1600 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1602 # Audio compression, by default in qemu-kvm it is on
1603 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1604 spice_arg = "%s,playback-compression=off" % spice_arg
1605 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1606 spice_arg = "%s,agent-mouse=off" % spice_arg
1608 # Enable the spice agent communication channel between the host and the
1610 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1613 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1615 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1617 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1618 kvm_cmd.extend(["-spice", spice_arg])
1621 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1622 # also works in earlier versions though (tested with 1.1 and 1.3)
1623 if self._DISPLAY_RE.search(kvmhelp):
1624 kvm_cmd.extend(["-display", "none"])
1626 kvm_cmd.extend(["-nographic"])
1628 if hvp[constants.HV_USE_LOCALTIME]:
1629 kvm_cmd.extend(["-localtime"])
1631 if hvp[constants.HV_KVM_USE_CHROOT]:
1632 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1634 # Add qemu-KVM -cpu param
1635 if hvp[constants.HV_CPU_TYPE]:
1636 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1638 # As requested by music lovers
1639 if hvp[constants.HV_SOUNDHW]:
1640 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1642 # Pass a -vga option if requested, or if spice is used, for backwards
1644 if hvp[constants.HV_VGA]:
1645 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1647 kvm_cmd.extend(["-vga", "qxl"])
1649 # Various types of usb devices, comma separated
1650 if hvp[constants.HV_USB_DEVICES]:
1651 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1652 kvm_cmd.extend(["-usbdevice", dev])
1654 # Set system UUID to instance UUID
1655 if self._UUID_RE.search(kvmhelp):
1656 kvm_cmd.extend(["-uuid", instance.uuid])
1658 if hvp[constants.HV_KVM_EXTRA]:
1659 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1661 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1663 for disk, link_name, uri in block_devices:
1664 _UpdatePCISlots(disk, pci_reservations)
1665 kvm_disks.append((disk, link_name, uri))
1668 for nic in instance.nics:
1669 _UpdatePCISlots(nic, pci_reservations)
1670 kvm_nics.append(nic)
1674 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1676 def _WriteKVMRuntime(self, instance_name, data):
1677 """Write an instance's KVM runtime
1681 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1683 except EnvironmentError, err:
1684 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1686 def _ReadKVMRuntime(self, instance_name):
1687 """Read an instance's KVM runtime
1691 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1692 except EnvironmentError, err:
1693 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1696 def _SaveKVMRuntime(self, instance, kvm_runtime):
1697 """Save an instance's KVM runtime
1700 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1702 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1703 serialized_disks = [(blk.ToDict(), link, uri)
1704 for blk, link, uri in kvm_disks]
1705 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1708 self._WriteKVMRuntime(instance.name, serialized_form)
1710 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1711 """Load an instance's KVM runtime
1714 if not serialized_runtime:
1715 serialized_runtime = self._ReadKVMRuntime(instance.name)
1717 return _AnalyzeSerializedRuntime(serialized_runtime)
1719 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1720 """Run the KVM cmd and check for errors
1723 @param name: instance name
1724 @type kvm_cmd: list of strings
1725 @param kvm_cmd: runcmd input for kvm
1726 @type tap_fds: list of int
1727 @param tap_fds: fds of tap devices opened by Ganeti
1731 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1734 utils_wrapper.CloseFdNoError(fd)
1737 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1738 (name, result.fail_reason, result.output))
1739 if not self._InstancePidAlive(name)[2]:
1740 raise errors.HypervisorError("Failed to start instance %s" % name)
1742 # too many local variables
1743 # pylint: disable=R0914
1744 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1745 """Execute a KVM cmd, after completing it with some last minute data.
1747 @type incoming: tuple of strings
1748 @param incoming: (target_host_ip, port)
1749 @type kvmhelp: string
1750 @param kvmhelp: output of kvm --help
1753 # Small _ExecuteKVMRuntime hv parameters programming howto:
1754 # - conf_hvp contains the parameters as configured on ganeti. they might
1755 # have changed since the instance started; only use them if the change
1756 # won't affect the inside of the instance (which hasn't been rebooted).
1757 # - up_hvp contains the parameters as they were when the instance was
1758 # started, plus any new parameter which has been added between ganeti
1759 # versions: it is paramount that those default to a value which won't
1760 # affect the inside of the instance as well.
1761 conf_hvp = instance.hvparams
1762 name = instance.name
1763 self._CheckDown(name)
1767 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1768 # the first element of kvm_cmd is always the path to the kvm binary
1769 kvm_path = kvm_cmd[0]
1770 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1772 # We know it's safe to run as a different user upon migration, so we'll use
1773 # the latest conf, from conf_hvp.
1774 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1775 if security_model == constants.HT_SM_USER:
1776 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1778 keymap = conf_hvp[constants.HV_KEYMAP]
1780 keymap_path = self._InstanceKeymapFile(name)
1781 # If a keymap file is specified, KVM won't use its internal defaults. By
1782 # first including the "en-us" layout, an error on loading the actual
1783 # layout (e.g. because it can't be found) won't lead to a non-functional
1784 # keyboard. A keyboard with incorrect keys is still better than none.
1785 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1786 kvm_cmd.extend(["-k", keymap_path])
1788 # We have reasons to believe changing something like the nic driver/type
1789 # upon migration won't exactly fly with the instance kernel, so for nic
1790 # related parameters we'll use up_hvp
1793 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1795 kvm_cmd.extend(["-net", "none"])
1799 nic_type = up_hvp[constants.HV_NIC_TYPE]
1800 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1801 nic_model = self._VIRTIO
1803 if self._VIRTIO_NET_RE.search(devlist):
1804 nic_model = self._VIRTIO_NET_PCI
1805 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1806 except errors.HypervisorError, _:
1807 # Older versions of kvm don't support DEVICE_LIST, but they don't
1808 # have new virtio syntax either.
1811 if up_hvp[constants.HV_VHOST_NET]:
1812 # check for vhost_net support
1813 if self._VHOST_RE.search(kvmhelp):
1814 tap_extra = ",vhost=on"
1816 raise errors.HypervisorError("vhost_net is configured"
1817 " but it is not available")
1819 nic_model = nic_type
1821 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1823 for nic_seq, nic in enumerate(kvm_nics):
1824 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1825 tapfds.append(tapfd)
1826 taps.append(tapname)
1827 if kvm_supports_netdev:
1828 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1830 # kvm_nics already exist in old runtime files and thus there might
1831 # be some entries without pci slot (therefore try: except:)
1832 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1834 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1835 except errors.HotplugError:
1836 netdev = "netdev%d" % nic_seq
1837 nic_val += (",netdev=%s" % netdev)
1838 tap_val = ("type=tap,id=%s,fd=%d%s" %
1839 (netdev, tapfd, tap_extra))
1840 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1842 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1844 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1845 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1848 target, port = incoming
1849 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1851 # Changing the vnc password doesn't bother the guest that much. At most it
1852 # will surprise people who connect to it. Whether positively or negatively
1854 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1858 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1859 except EnvironmentError, err:
1860 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1861 % (vnc_pwd_file, err))
1863 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1864 utils.EnsureDirs([(self._InstanceChrootDir(name),
1865 constants.SECURE_DIR_MODE)])
1867 # Automatically enable QMP if version is >= 0.14
1868 if self._QMP_RE.search(kvmhelp):
1869 logging.debug("Enabling QMP")
1870 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1871 self._InstanceQmpMonitor(instance.name)])
1873 # Configure the network now for starting instances and bridged interfaces,
1874 # during FinalizeMigration for incoming instances' routed interfaces
1875 for nic_seq, nic in enumerate(kvm_nics):
1877 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1879 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1881 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1885 kvm_cmd.extend(bdev_opts)
1886 # CPU affinity requires kvm to start paused, so we set this flag if the
1887 # instance is not already paused and if we are not going to accept a
1888 # migrating instance. In the latter case, pausing is not needed.
1889 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1890 if start_kvm_paused:
1891 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1893 # Note: CPU pinning is using up_hvp since changes take effect
1894 # during instance startup anyway, and to avoid problems when soft
1895 # rebooting the instance.
1897 if up_hvp.get(constants.HV_CPU_MASK, None):
1900 if security_model == constants.HT_SM_POOL:
1901 ss = ssconf.SimpleStore()
1902 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1903 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1904 uid = uidpool.RequestUnusedUid(all_uids)
1906 username = pwd.getpwuid(uid.GetUid()).pw_name
1907 kvm_cmd.extend(["-runas", username])
1908 self._RunKVMCmd(name, kvm_cmd, tapfds)
1910 uidpool.ReleaseUid(uid)
1914 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1916 self._RunKVMCmd(name, kvm_cmd, tapfds)
1918 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1919 constants.RUN_DIRS_MODE)])
1920 for nic_seq, tap in enumerate(taps):
1921 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1925 change_cmd = "change vnc password %s" % vnc_pwd
1926 self._CallMonitorCommand(instance.name, change_cmd)
1928 # Setting SPICE password. We are not vulnerable to malicious passwordless
1929 # connection attempts because SPICE by default does not allow connections
1930 # if neither a password nor the "disable_ticketing" options are specified.
1931 # As soon as we send the password via QMP, that password is a valid ticket
1933 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1934 if spice_password_file:
1937 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1938 except EnvironmentError, err:
1939 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1940 % (spice_password_file, err))
1942 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1945 "protocol": "spice",
1946 "password": spice_pwd,
1948 qmp.Execute("set_password", arguments)
1950 for filename in temp_files:
1951 utils.RemoveFile(filename)
1953 # If requested, set CPU affinity and resume instance execution
1955 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1957 start_memory = self._InstanceStartupMemory(instance)
1958 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1959 self.BalloonInstanceMemory(instance, start_memory)
1961 if start_kvm_paused:
1962 # To control CPU pinning, ballooning, and vnc/spice passwords
1963 # the VM was started in a frozen state. If freezing was not
1964 # explicitly requested resume the vm status.
1965 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1967 def StartInstance(self, instance, block_devices, startup_paused):
1968 """Start an instance.
1971 self._CheckDown(instance.name)
1972 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1973 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1974 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1975 startup_paused, kvmhelp)
1976 self._SaveKVMRuntime(instance, kvm_runtime)
1977 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1979 def _CallMonitorCommand(self, instance_name, command):
1980 """Invoke a command on the instance monitor.
1983 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1984 # version. The monitor protocol is designed for human consumption, whereas
1985 # QMP is made for programmatic usage. In the worst case QMP can also
1986 # execute monitor commands. As it is, all calls to socat take at least
1987 # 500ms and likely more: socat can't detect the end of the reply and waits
1988 # for 500ms of no data received before exiting (500 ms is the default for
1989 # the "-t" parameter).
1990 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1991 (utils.ShellQuote(command),
1992 constants.SOCAT_PATH,
1993 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1994 result = utils.RunCmd(socat)
1996 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1998 (command, instance_name, result.fail_reason, result.output))
1999 raise errors.HypervisorError(msg)
2003 def _GetFreePCISlot(self, instance, dev):
2004 """Get the first available pci slot of a runnung instance.
2007 slots = bitarray(32)
2008 slots.setall(False) # pylint: disable=E1101
2009 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
2010 for line in output.stdout.splitlines():
2011 match = self._INFO_PCI_RE.search(line)
2013 slot = int(match.group(1))
2016 [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
2018 raise errors.HypervisorError("All PCI slots occupied")
2022 def VerifyHotplugSupport(self, instance, action, dev_type):
2023 """Verifies that hotplug is supported.
2025 Hotplug is *not* supported in case of:
2026 - security models and chroot (disk hotplug)
2027 - fdsend module is missing (nic hot-add)
2029 @raise errors.HypervisorError: in one of the previous cases
2032 if dev_type == constants.HOTPLUG_TARGET_DISK:
2033 hvp = instance.hvparams
2034 security_model = hvp[constants.HV_SECURITY_MODEL]
2035 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2037 raise errors.HotplugError("Disk hotplug is not supported"
2038 " in case of chroot.")
2039 if security_model != constants.HT_SM_NONE:
2040 raise errors.HotplugError("Disk Hotplug is not supported in case"
2041 " security models are used.")
2043 if (dev_type == constants.HOTPLUG_TARGET_NIC and
2044 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2045 raise errors.HotplugError("Cannot hot-add NIC."
2046 " fdsend python module is missing.")
2048 def HotplugSupported(self, instance):
2049 """Checks if hotplug is generally supported.
2051 Hotplug is *not* supported in case of:
2052 - qemu versions < 1.0
2053 - for stopped instances
2055 @raise errors.HypervisorError: in one of the previous cases
2059 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2060 except errors.HypervisorError:
2061 raise errors.HotplugError("Instance is probably down")
2063 # TODO: search for netdev_add, drive_add, device_add.....
2064 match = self._INFO_VERSION_RE.search(output.stdout)
2066 raise errors.HotplugError("Cannot parse qemu version via monitor")
2068 v_major, v_min, _, _ = match.groups()
2069 if (int(v_major), int(v_min)) < (1, 0):
2070 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2072 def _CallHotplugCommand(self, name, cmd):
2073 output = self._CallMonitorCommand(name, cmd)
2074 # TODO: parse output and check if succeeded
2075 for line in output.stdout.splitlines():
2076 logging.info("%s", line)
2078 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2079 """ Helper method to hot-add a new device
2081 It gets free pci slot generates the device name and invokes the
2082 device specific method.
2085 # in case of hot-mod this is given
2086 if device.pci is None:
2087 self._GetFreePCISlot(instance, device)
2088 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2089 runtime = self._LoadKVMRuntime(instance)
2090 if dev_type == constants.HOTPLUG_TARGET_DISK:
2091 command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2093 command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2094 (hex(device.pci), kvm_devid, kvm_devid))
2095 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2096 (tap, fd) = _OpenTap()
2097 self._ConfigureNIC(instance, seq, device, tap)
2098 self._PassTapFd(instance, fd, device)
2099 command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2100 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2101 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2102 command += "device_add %s" % args
2103 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2105 self._CallHotplugCommand(instance.name, command)
2106 # update relevant entries in runtime file
2107 index = _DEVICE_RUNTIME_INDEX[dev_type]
2108 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2109 runtime[index].append(entry)
2110 self._SaveKVMRuntime(instance, runtime)
2112 def HotDelDevice(self, instance, dev_type, device, _, seq):
2113 """ Helper method for hot-del device
2115 It gets device info from runtime file, generates the device name and
2116 invokes the device specific method.
2119 runtime = self._LoadKVMRuntime(instance)
2120 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2121 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2122 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2123 if dev_type == constants.HOTPLUG_TARGET_DISK:
2124 command = "device_del %s\n" % kvm_devid
2125 command += "drive_del %s" % kvm_devid
2126 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2127 command = "device_del %s\n" % kvm_devid
2128 command += "netdev_del %s" % kvm_devid
2129 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2130 self._CallHotplugCommand(instance.name, command)
2131 index = _DEVICE_RUNTIME_INDEX[dev_type]
2132 runtime[index].remove(entry)
2133 self._SaveKVMRuntime(instance, runtime)
2135 return kvm_device.pci
2137 def HotModDevice(self, instance, dev_type, device, _, seq):
2138 """ Helper method for hot-mod device
2140 It gets device info from runtime file, generates the device name and
2141 invokes the device specific method. Currently only NICs support hot-mod
2144 if dev_type == constants.HOTPLUG_TARGET_NIC:
2145 # putting it back in the same pci slot
2146 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2147 # TODO: remove sleep when socat gets removed
2149 self.HotAddDevice(instance, dev_type, device, _, seq)
2151 def _PassTapFd(self, instance, fd, nic):
2152 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2155 # TODO: factor out code related to unix sockets.
2156 # squash common parts between monitor and qmp
2157 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2158 command = "getfd %s\n" % kvm_devid
2160 logging.info("%s", fds)
2162 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2164 fdsend.sendfds(monsock.sock, command, fds=fds)
2169 def _ParseKVMVersion(cls, text):
2170 """Parse the KVM version from the --help output.
2173 @param text: output of kvm --help
2174 @return: (version, v_maj, v_min, v_rev)
2175 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2178 match = cls._VERSION_RE.search(text.splitlines()[0])
2180 raise errors.HypervisorError("Unable to get KVM version")
2182 v_all = match.group(0)
2183 v_maj = int(match.group(1))
2184 v_min = int(match.group(2))
2186 v_rev = int(match.group(4))
2189 return (v_all, v_maj, v_min, v_rev)
2192 def _GetKVMOutput(cls, kvm_path, option):
2193 """Return the output of a kvm invocation
2195 @type kvm_path: string
2196 @param kvm_path: path to the kvm executable
2197 @type option: a key of _KVMOPTS_CMDS
2198 @param option: kvm option to fetch the output from
2199 @return: output a supported kvm invocation
2200 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2203 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2205 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2207 result = utils.RunCmd([kvm_path] + optlist)
2208 if result.failed and not can_fail:
2209 raise errors.HypervisorError("Unable to get KVM %s output" %
2211 return result.output
2214 def _GetKVMVersion(cls, kvm_path):
2215 """Return the installed KVM version.
2217 @return: (version, v_maj, v_min, v_rev)
2218 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2221 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2224 def _GetDefaultMachineVersion(cls, kvm_path):
2225 """Return the default hardware revision (e.g. pc-1.1)
2228 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2229 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2231 return match.group(1)
2235 def StopInstance(self, instance, force=False, retry=False, name=None):
2236 """Stop an instance.
2239 if name is not None and not force:
2240 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2242 name = instance.name
2243 acpi = instance.hvparams[constants.HV_ACPI]
2246 _, pid, alive = self._InstancePidAlive(name)
2247 if pid > 0 and alive:
2248 if force or not acpi:
2249 utils.KillProcess(pid)
2251 self._CallMonitorCommand(name, "system_powerdown")
2253 def CleanupInstance(self, instance_name):
2254 """Cleanup after a stopped instance
2257 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2258 if pid > 0 and alive:
2259 raise errors.HypervisorError("Cannot cleanup a live instance")
2260 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2262 def RebootInstance(self, instance):
2263 """Reboot an instance.
2266 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2267 # socket the instance will stop, but now power up again. So we'll resort
2268 # to shutdown and restart.
2269 _, _, alive = self._InstancePidAlive(instance.name)
2271 raise errors.HypervisorError("Failed to reboot instance %s:"
2272 " not running" % instance.name)
2273 # StopInstance will delete the saved KVM runtime so:
2274 # ...first load it...
2275 kvm_runtime = self._LoadKVMRuntime(instance)
2276 # ...now we can safely call StopInstance...
2277 if not self.StopInstance(instance):
2278 self.StopInstance(instance, force=True)
2279 # ...and finally we can save it again, and execute it...
2280 self._SaveKVMRuntime(instance, kvm_runtime)
2281 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2282 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2283 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2285 def MigrationInfo(self, instance):
2286 """Get instance information to perform a migration.
2288 @type instance: L{objects.Instance}
2289 @param instance: instance to be migrated
2291 @return: content of the KVM runtime file
2294 return self._ReadKVMRuntime(instance.name)
2296 def AcceptInstance(self, instance, info, target):
2297 """Prepare to accept an instance.
2299 @type instance: L{objects.Instance}
2300 @param instance: instance to be accepted
2302 @param info: content of the KVM runtime file on the source node
2303 @type target: string
2304 @param target: target host (usually ip), on this node
2307 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2308 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2309 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2310 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2311 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2312 incoming=incoming_address)
2314 def FinalizeMigrationDst(self, instance, info, success):
2315 """Finalize the instance migration on the target node.
2317 Stop the incoming mode KVM.
2319 @type instance: L{objects.Instance}
2320 @param instance: instance whose migration is being finalized
2324 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2325 kvm_nics = kvm_runtime[1]
2327 for nic_seq, nic in enumerate(kvm_nics):
2328 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2329 # Bridged interfaces have already been configured
2332 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2333 except EnvironmentError, err:
2334 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2335 instance.name, nic_seq, str(err))
2338 self._ConfigureNIC(instance, nic_seq, nic, tap)
2339 except errors.HypervisorError, err:
2340 logging.warning(str(err))
2342 self._WriteKVMRuntime(instance.name, info)
2344 self.StopInstance(instance, force=True)
2346 def MigrateInstance(self, cluster_name, instance, target, live):
2347 """Migrate an instance to a target node.
2349 The migration will not be attempted if the instance is not
2352 @type cluster_name: string
2353 @param cluster_name: name of the cluster
2354 @type instance: L{objects.Instance}
2355 @param instance: the instance to be migrated
2356 @type target: string
2357 @param target: ip address of the target node
2359 @param live: perform a live migration
2362 instance_name = instance.name
2363 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2364 _, _, alive = self._InstancePidAlive(instance_name)
2366 raise errors.HypervisorError("Instance not running, cannot migrate")
2369 self._CallMonitorCommand(instance_name, "stop")
2371 migrate_command = ("migrate_set_speed %dm" %
2372 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2373 self._CallMonitorCommand(instance_name, migrate_command)
2375 migrate_command = ("migrate_set_downtime %dms" %
2376 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2377 self._CallMonitorCommand(instance_name, migrate_command)
2379 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2380 self._CallMonitorCommand(instance_name, migrate_command)
2382 def FinalizeMigrationSource(self, instance, success, live):
2383 """Finalize the instance migration on the source node.
2385 @type instance: L{objects.Instance}
2386 @param instance: the instance that was migrated
2388 @param success: whether the migration succeeded or not
2390 @param live: whether the user requested a live migration or not
2394 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2395 utils.KillProcess(pid)
2396 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2398 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2400 def GetMigrationStatus(self, instance):
2401 """Get the migration status
2403 @type instance: L{objects.Instance}
2404 @param instance: the instance that is being migrated
2405 @rtype: L{objects.MigrationStatus}
2406 @return: the status of the current migration (one of
2407 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2408 progress info that can be retrieved from the hypervisor
2411 info_command = "info migrate"
2412 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2413 result = self._CallMonitorCommand(instance.name, info_command)
2414 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2416 if not result.stdout:
2417 logging.info("KVM: empty 'info migrate' result")
2419 logging.warning("KVM: unknown 'info migrate' result: %s",
2422 status = match.group(1)
2423 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2424 migration_status = objects.MigrationStatus(status=status)
2425 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2427 migration_status.transferred_ram = match.group("transferred")
2428 migration_status.total_ram = match.group("total")
2430 return migration_status
2432 logging.warning("KVM: unknown migration status '%s'", status)
2434 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2436 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2438 def BalloonInstanceMemory(self, instance, mem):
2439 """Balloon an instance memory to a certain value.
2441 @type instance: L{objects.Instance}
2442 @param instance: instance to be accepted
2444 @param mem: actual memory size to use for instance runtime
2447 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2449 def GetNodeInfo(self, hvparams=None):
2450 """Return information about the node.
2452 @type hvparams: dict of strings
2453 @param hvparams: hypervisor parameters, not used in this class
2455 @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2457 - hv_version: the hypervisor version in the form (major, minor,
2461 result = self.GetLinuxNodeInfo()
2462 kvmpath = constants.KVM_PATH
2463 if hvparams is not None:
2464 kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2465 _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath)
2466 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2470 def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2471 """Return a command for connecting to the console of an instance.
2474 if hvparams[constants.HV_SERIAL_CONSOLE]:
2475 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2476 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2477 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2478 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2479 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2480 return objects.InstanceConsole(instance=instance.name,
2481 kind=constants.CONS_SSH,
2482 host=primary_node.name,
2483 user=constants.SSH_CONSOLE_USER,
2486 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2487 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2488 display = instance.network_port - constants.VNC_BASE_PORT
2489 return objects.InstanceConsole(instance=instance.name,
2490 kind=constants.CONS_VNC,
2491 host=vnc_bind_address,
2492 port=instance.network_port,
2495 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2497 return objects.InstanceConsole(instance=instance.name,
2498 kind=constants.CONS_SPICE,
2500 port=instance.network_port)
2502 return objects.InstanceConsole(instance=instance.name,
2503 kind=constants.CONS_MESSAGE,
2504 message=("No serial shell for instance %s" %
2507 def Verify(self, hvparams=None):
2508 """Verify the hypervisor.
2510 Check that the required binaries exist.
2512 @type hvparams: dict of strings
2513 @param hvparams: hypervisor parameters to be verified against, not used here
2515 @return: Problem description if something is wrong, C{None} otherwise
2519 kvmpath = constants.KVM_PATH
2520 if hvparams is not None:
2521 kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH)
2522 if not os.path.exists(kvmpath):
2523 msgs.append("The KVM binary ('%s') does not exist" % kvmpath)
2524 if not os.path.exists(constants.SOCAT_PATH):
2525 msgs.append("The socat binary ('%s') does not exist" %
2526 constants.SOCAT_PATH)
2528 return self._FormatVerifyResults(msgs)
2531 def CheckParameterSyntax(cls, hvparams):
2532 """Check the given parameters for validity.
2534 @type hvparams: dict
2535 @param hvparams: dictionary with parameter names/value
2536 @raise errors.HypervisorError: when a parameter is not valid
2539 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2541 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2543 if not hvparams[constants.HV_ROOT_PATH]:
2544 raise errors.HypervisorError("Need a root partition for the instance,"
2545 " if a kernel is defined")
2547 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2548 not hvparams[constants.HV_VNC_X509]):
2549 raise errors.HypervisorError("%s must be defined, if %s is" %
2550 (constants.HV_VNC_X509,
2551 constants.HV_VNC_X509_VERIFY))
2553 if hvparams[constants.HV_SERIAL_CONSOLE]:
2554 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2555 valid_speeds = constants.VALID_SERIAL_SPEEDS
2556 if not serial_speed or serial_speed not in valid_speeds:
2557 raise errors.HypervisorError("Invalid serial console speed, must be"
2559 utils.CommaJoin(valid_speeds))
2561 boot_order = hvparams[constants.HV_BOOT_ORDER]
2562 if (boot_order == constants.HT_BO_CDROM and
2563 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2564 raise errors.HypervisorError("Cannot boot from cdrom without an"
2567 security_model = hvparams[constants.HV_SECURITY_MODEL]
2568 if security_model == constants.HT_SM_USER:
2569 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2570 raise errors.HypervisorError("A security domain (user to run kvm as)"
2571 " must be specified")
2572 elif (security_model == constants.HT_SM_NONE or
2573 security_model == constants.HT_SM_POOL):
2574 if hvparams[constants.HV_SECURITY_DOMAIN]:
2575 raise errors.HypervisorError("Cannot have a security domain when the"
2576 " security model is 'none' or 'pool'")
2578 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2579 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2581 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2582 # if an IP version is specified, the spice_bind parameter must be an
2584 if (netutils.IP4Address.IsValid(spice_bind) and
2585 spice_ip_version != constants.IP4_VERSION):
2586 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2587 " the specified IP version is %s" %
2588 (spice_bind, spice_ip_version))
2590 if (netutils.IP6Address.IsValid(spice_bind) and
2591 spice_ip_version != constants.IP6_VERSION):
2592 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2593 " the specified IP version is %s" %
2594 (spice_bind, spice_ip_version))
2596 # All the other SPICE parameters depend on spice_bind being set. Raise an
2597 # error if any of them is set without it.
2598 for param in _SPICE_ADDITIONAL_PARAMS:
2600 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2601 (param, constants.HV_KVM_SPICE_BIND))
2604 def ValidateParameters(cls, hvparams):
2605 """Check the given parameters for validity.
2607 @type hvparams: dict
2608 @param hvparams: dictionary with parameter names/value
2609 @raise errors.HypervisorError: when a parameter is not valid
2612 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2614 kvm_path = hvparams[constants.HV_KVM_PATH]
2616 security_model = hvparams[constants.HV_SECURITY_MODEL]
2617 if security_model == constants.HT_SM_USER:
2618 username = hvparams[constants.HV_SECURITY_DOMAIN]
2620 pwd.getpwnam(username)
2622 raise errors.HypervisorError("Unknown security domain user %s"
2624 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2625 if vnc_bind_address:
2626 bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2627 is_interface = netutils.IsValidInterface(vnc_bind_address)
2628 is_path = utils.IsNormAbsPath(vnc_bind_address)
2629 if not bound_to_addr and not is_interface and not is_path:
2630 raise errors.HypervisorError("VNC: The %s parameter must be either"
2631 " a valid IP address, an interface name,"
2632 " or an absolute path" %
2633 constants.HV_KVM_SPICE_BIND)
2635 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2637 # only one of VNC and SPICE can be used currently.
2638 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2639 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2640 " only one of them can be used at a"
2643 # check that KVM supports SPICE
2644 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2645 if not cls._SPICE_RE.search(kvmhelp):
2646 raise errors.HypervisorError("SPICE is configured, but it is not"
2647 " supported according to 'kvm --help'")
2649 # if spice_bind is not an IP address, it must be a valid interface
2650 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2651 netutils.IP6Address.IsValid(spice_bind))
2652 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2653 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2654 " a valid IP address or interface name" %
2655 constants.HV_KVM_SPICE_BIND)
2657 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2659 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2660 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2661 raise errors.HypervisorError("Unsupported machine version: %s" %
2665 def PowercycleNode(cls, hvparams=None):
2666 """KVM powercycle, just a wrapper over Linux powercycle.
2668 @type hvparams: dict of strings
2669 @param hvparams: hypervisor params to be used on this node
2672 cls.LinuxPowercycle()