4 # Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
40 from bitarray import bitarray
42 import affinity # pylint: disable=F0401
46 import fdsend # pylint: disable=F0401
50 from ganeti import utils
51 from ganeti import constants
52 from ganeti import errors
53 from ganeti import serializer
54 from ganeti import objects
55 from ganeti import uidpool
56 from ganeti import ssconf
57 from ganeti import netutils
58 from ganeti import pathutils
59 from ganeti.hypervisor import hv_base
60 from ganeti.utils import wrapper as utils_wrapper
63 _KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
64 _KVM_START_PAUSED_FLAG = "-S"
66 # TUN/TAP driver constants, taken from <linux/if_tun.h>
67 # They are architecture-independent and already hardcoded in qemu-kvm source,
68 # so we can safely include them here.
69 TUNSETIFF = 0x400454ca
70 TUNGETIFF = 0x800454d2
71 TUNGETFEATURES = 0x800454cf
76 #: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
77 _SPICE_ADDITIONAL_PARAMS = frozenset([
78 constants.HV_KVM_SPICE_IP_VERSION,
79 constants.HV_KVM_SPICE_PASSWORD_FILE,
80 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
81 constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
82 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
83 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
84 constants.HV_KVM_SPICE_USE_TLS,
87 # Constant bitarray that reflects to a free pci slot
88 # Use it with bitarray.search()
89 _AVAILABLE_PCI_SLOT = bitarray("0")
91 # below constants show the format of runtime file
92 # the nics are in second possition, while the disks in 4th (last)
93 # moreover disk entries are stored as a list of in tuples
94 # (L{objects.Disk}, link_name)
95 _KVM_NICS_RUNTIME_INDEX = 1
96 _KVM_DISKS_RUNTIME_INDEX = 3
97 _DEVICE_RUNTIME_INDEX = {
98 constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
99 constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
101 _FIND_RUNTIME_ENTRY = {
102 constants.HOTPLUG_TARGET_NIC:
103 lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
104 constants.HOTPLUG_TARGET_DISK:
105 lambda disk, kvm_disks: [(d, l) for (d, l) in kvm_disks
106 if d.uuid == disk.uuid]
109 constants.HOTPLUG_TARGET_NIC: lambda d: d,
110 constants.HOTPLUG_TARGET_DISK: lambda (d, e): d
113 constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
114 constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e)
118 def _GenerateDeviceKVMId(dev_type, dev):
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)
232 for sdisk, link 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 def BuildFromJsonString(json_string):
353 """Build a QmpMessage from a JSON encoded string.
355 @type json_string: str
356 @param json_string: JSON string representing the message
357 @rtype: L{QmpMessage}
358 @return: a L{QmpMessage} built from json_string
362 data = serializer.LoadJson(json_string)
363 return QmpMessage(data)
366 # The protocol expects the JSON object to be sent as a single line.
367 return serializer.DumpJson(self.data)
369 def __eq__(self, other):
370 # When comparing two QmpMessages, we are interested in comparing
371 # their internal representation of the message data
372 return self.data == other.data
375 class MonitorSocket(object):
378 def __init__(self, monitor_filename):
379 """Instantiates the MonitorSocket object.
381 @type monitor_filename: string
382 @param monitor_filename: the filename of the UNIX raw socket on which the
383 monitor (QMP or simple one) is listening
386 self.monitor_filename = monitor_filename
387 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
388 # We want to fail if the server doesn't send a complete message
389 # in a reasonable amount of time
390 self.sock.settimeout(self._SOCKET_TIMEOUT)
391 self._connected = False
393 def _check_socket(self):
396 sock_stat = os.stat(self.monitor_filename)
397 except EnvironmentError, err:
398 if err.errno == errno.ENOENT:
399 raise errors.HypervisorError("No monitor socket found")
401 raise errors.HypervisorError("Error checking monitor socket: %s",
402 utils.ErrnoOrStr(err))
403 if not stat.S_ISSOCK(sock_stat.st_mode):
404 raise errors.HypervisorError("Monitor socket is not a socket")
406 def _check_connection(self):
407 """Make sure that the connection is established.
410 if not self._connected:
411 raise errors.ProgrammerError("To use a MonitorSocket you need to first"
412 " invoke connect() on it")
415 """Connects to the monitor.
417 Connects to the UNIX socket
419 @raise errors.HypervisorError: when there are communication errors
423 raise errors.ProgrammerError("Cannot connect twice")
427 # Check file existance/stuff
429 self.sock.connect(self.monitor_filename)
430 except EnvironmentError:
431 raise errors.HypervisorError("Can't connect to qmp socket")
432 self._connected = True
437 It cannot be used after this call.
443 class QmpConnection(MonitorSocket):
444 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
447 _FIRST_MESSAGE_KEY = "QMP"
450 _RETURN_KEY = RETURN_KEY = "return"
451 _ACTUAL_KEY = ACTUAL_KEY = "actual"
452 _ERROR_CLASS_KEY = "class"
453 _ERROR_DATA_KEY = "data"
454 _ERROR_DESC_KEY = "desc"
455 _EXECUTE_KEY = "execute"
456 _ARGUMENTS_KEY = "arguments"
457 _CAPABILITIES_COMMAND = "qmp_capabilities"
458 _MESSAGE_END_TOKEN = "\r\n"
460 def __init__(self, monitor_filename):
461 super(QmpConnection, self).__init__(monitor_filename)
465 """Connects to the QMP monitor.
467 Connects to the UNIX socket and makes sure that we can actually send and
468 receive data to the kvm instance via QMP.
470 @raise errors.HypervisorError: when there are communication errors
471 @raise errors.ProgrammerError: when there are data serialization errors
474 super(QmpConnection, self).connect()
475 # Check if we receive a correct greeting message from the server
476 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
477 greeting = self._Recv()
478 if not greeting[self._FIRST_MESSAGE_KEY]:
479 self._connected = False
480 raise errors.HypervisorError("kvm: QMP communication error (wrong"
483 # Let's put the monitor in command mode using the qmp_capabilities
484 # command, or else no command will be executable.
485 # (As per the QEMU Protocol Specification 0.1 - section 4)
486 self.Execute(self._CAPABILITIES_COMMAND)
488 def _ParseMessage(self, buf):
489 """Extract and parse a QMP message from the given buffer.
491 Seeks for a QMP message in the given buf. If found, it parses it and
492 returns it together with the rest of the characters in the buf.
493 If no message is found, returns None and the whole buffer.
495 @raise errors.ProgrammerError: when there are data serialization errors
499 # Check if we got the message end token (CRLF, as per the QEMU Protocol
500 # Specification 0.1 - Section 2.1.1)
501 pos = buf.find(self._MESSAGE_END_TOKEN)
504 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
505 except Exception, err:
506 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
509 return (message, buf)
512 """Receives a message from QMP and decodes the received JSON object.
515 @return: the received message
516 @raise errors.HypervisorError: when there are communication errors
517 @raise errors.ProgrammerError: when there are data serialization errors
520 self._check_connection()
522 # Check if there is already a message in the buffer
523 (message, self._buf) = self._ParseMessage(self._buf)
527 recv_buffer = StringIO.StringIO(self._buf)
528 recv_buffer.seek(len(self._buf))
531 data = self.sock.recv(4096)
534 recv_buffer.write(data)
536 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
540 except socket.timeout, err:
541 raise errors.HypervisorError("Timeout while receiving a QMP message: "
543 except socket.error, err:
544 raise errors.HypervisorError("Unable to receive data from KVM using the"
545 " QMP protocol: %s" % err)
547 def _Send(self, message):
548 """Encodes and sends a message to KVM using QMP.
550 @type message: QmpMessage
551 @param message: message to send to KVM
552 @raise errors.HypervisorError: when there are communication errors
553 @raise errors.ProgrammerError: when there are data serialization errors
556 self._check_connection()
558 message_str = str(message)
559 except Exception, err:
560 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
563 self.sock.sendall(message_str)
564 except socket.timeout, err:
565 raise errors.HypervisorError("Timeout while sending a QMP message: "
566 "%s (%s)" % (err.string, err.errno))
567 except socket.error, err:
568 raise errors.HypervisorError("Unable to send data from KVM using the"
569 " QMP protocol: %s" % err)
571 def Execute(self, command, arguments=None):
572 """Executes a QMP command and returns the response of the server.
575 @param command: the command to execute
576 @type arguments: dict
577 @param arguments: dictionary of arguments to be passed to the command
579 @return: dictionary representing the received JSON object
580 @raise errors.HypervisorError: when there are communication errors
581 @raise errors.ProgrammerError: when there are data serialization errors
584 self._check_connection()
585 message = QmpMessage({self._EXECUTE_KEY: command})
587 message[self._ARGUMENTS_KEY] = arguments
590 # Events can occur between the sending of the command and the reception
591 # of the response, so we need to filter out messages with the event key.
593 response = self._Recv()
594 err = response[self._ERROR_KEY]
596 raise errors.HypervisorError("kvm: error executing the %s"
597 " command: %s (%s, %s):" %
599 err[self._ERROR_DESC_KEY],
600 err[self._ERROR_CLASS_KEY],
601 err[self._ERROR_DATA_KEY]))
603 elif not response[self._EVENT_KEY]:
607 class KVMHypervisor(hv_base.BaseHypervisor):
608 """KVM hypervisor interface
613 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
614 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
615 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
616 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
617 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
618 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
619 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
620 # KVM instances with chroot enabled are started in empty chroot directories.
621 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
622 # After an instance is stopped, its chroot directory is removed.
623 # If the chroot directory is not empty, it can't be removed.
624 # A non-empty chroot directory indicates a possible security incident.
625 # To support forensics, the non-empty chroot directory is quarantined in
626 # a separate directory, called 'chroot-quarantine'.
627 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
628 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
629 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
632 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
633 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
634 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
635 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
636 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
637 constants.HV_ACPI: hv_base.NO_CHECK,
638 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
639 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
640 constants.HV_VNC_BIND_ADDRESS:
641 (False, lambda x: (netutils.IP4Address.IsValid(x) or
642 utils.IsNormAbsPath(x)),
643 "The VNC bind address must be either a valid IP address or an absolute"
644 " pathname", None, None),
645 constants.HV_VNC_TLS: hv_base.NO_CHECK,
646 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
647 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
648 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
649 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
650 constants.HV_KVM_SPICE_IP_VERSION:
651 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
652 x in constants.VALID_IP_VERSIONS),
653 "The SPICE IP version should be 4 or 6",
655 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
656 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
658 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
659 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
661 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
662 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
664 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
665 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
667 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
668 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
669 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
670 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
671 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
672 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
673 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
674 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
675 constants.HV_BOOT_ORDER:
676 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
677 constants.HV_NIC_TYPE:
678 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
679 constants.HV_DISK_TYPE:
680 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
681 constants.HV_KVM_CDROM_DISK_TYPE:
682 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
683 constants.HV_USB_MOUSE:
684 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
685 constants.HV_KEYMAP: hv_base.NO_CHECK,
686 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
687 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
688 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
689 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
690 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
691 constants.HV_DISK_CACHE:
692 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
693 constants.HV_SECURITY_MODEL:
694 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
695 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
696 constants.HV_KVM_FLAG:
697 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
698 constants.HV_VHOST_NET: hv_base.NO_CHECK,
699 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
700 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
701 constants.HV_REBOOT_BEHAVIOR:
702 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
703 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
704 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
705 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
706 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
707 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
708 constants.HV_SOUNDHW: hv_base.NO_CHECK,
709 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
710 constants.HV_VGA: hv_base.NO_CHECK,
711 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
712 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
713 constants.HV_VNET_HDR: hv_base.NO_CHECK,
717 _VIRTIO_NET_PCI = "virtio-net-pci"
718 _VIRTIO_BLK_PCI = "virtio-blk-pci"
720 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
722 _MIGRATION_PROGRESS_RE = \
723 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
724 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
725 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
727 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
728 _MIGRATION_INFO_RETRY_DELAY = 2
730 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
732 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
733 _CPU_INFO_CMD = "info cpus"
736 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
737 _CHECK_MACHINE_VERSION_RE = \
738 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
740 _QMP_RE = re.compile(r"^-qmp\s", re.M)
741 _SPICE_RE = re.compile(r"^-spice\s", re.M)
742 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
743 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
744 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
745 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
746 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
747 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
748 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
749 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
750 # match -drive.*boot=on|off on different lines, but in between accept only
751 # dashes not preceeded by a new line (which would mean another option
752 # different than -drive is starting)
753 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
755 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
756 _INFO_PCI_CMD = "info pci"
758 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
759 _INFO_VERSION_CMD = "info version"
761 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
766 ANCILLARY_FILES_OPT = [
770 # Supported kvm options to get output from
771 _KVMOPT_HELP = "help"
772 _KVMOPT_MLIST = "mlist"
773 _KVMOPT_DEVICELIST = "devicelist"
775 # Command to execute to get the output from kvm, and whether to
776 # accept the output even on failure.
778 _KVMOPT_HELP: (["--help"], False),
779 _KVMOPT_MLIST: (["-M", "?"], False),
780 _KVMOPT_DEVICELIST: (["-device", "?"], True),
784 hv_base.BaseHypervisor.__init__(self)
785 # Let's make sure the directories we need exist, even if the RUN_DIR lives
786 # in a tmpfs filesystem or has been otherwise wiped out.
787 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
788 utils.EnsureDirs(dirs)
791 def _InstancePidFile(cls, instance_name):
792 """Returns the instance pidfile.
795 return utils.PathJoin(cls._PIDS_DIR, instance_name)
798 def _InstanceUidFile(cls, instance_name):
799 """Returns the instance uidfile.
802 return utils.PathJoin(cls._UIDS_DIR, instance_name)
805 def _InstancePidInfo(cls, pid):
806 """Check pid file for instance information.
808 Check that a pid file is associated with an instance, and retrieve
809 information from its command line.
811 @type pid: string or int
812 @param pid: process id of the instance to check
814 @return: (instance_name, memory, vcpus)
815 @raise errors.HypervisorError: when an instance cannot be found
818 alive = utils.IsProcessAlive(pid)
820 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
822 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
824 cmdline = utils.ReadFile(cmdline_file)
825 except EnvironmentError, err:
826 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
833 arg_list = cmdline.split("\x00")
835 arg = arg_list.pop(0)
837 instance = arg_list.pop(0)
839 memory = int(arg_list.pop(0))
841 vcpus = int(arg_list.pop(0).split(",")[0])
844 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
847 return (instance, memory, vcpus)
849 def _InstancePidAlive(self, instance_name):
850 """Returns the instance pidfile, pid, and liveness.
852 @type instance_name: string
853 @param instance_name: instance name
855 @return: (pid file name, pid, liveness)
858 pidfile = self._InstancePidFile(instance_name)
859 pid = utils.ReadPidFile(pidfile)
863 cmd_instance = self._InstancePidInfo(pid)[0]
864 alive = (cmd_instance == instance_name)
865 except errors.HypervisorError:
868 return (pidfile, pid, alive)
870 def _CheckDown(self, instance_name):
871 """Raises an error unless the given instance is down.
874 alive = self._InstancePidAlive(instance_name)[2]
876 raise errors.HypervisorError("Failed to start instance %s: %s" %
877 (instance_name, "already running"))
880 def _InstanceMonitor(cls, instance_name):
881 """Returns the instance monitor socket name
884 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
887 def _InstanceSerial(cls, instance_name):
888 """Returns the instance serial socket name
891 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
894 def _InstanceQmpMonitor(cls, instance_name):
895 """Returns the instance serial QMP socket name
898 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
901 def _SocatUnixConsoleParams():
902 """Returns the correct parameters for socat
904 If we have a new-enough socat we can use raw mode with an escape character.
907 if constants.SOCAT_USE_ESCAPE:
908 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
910 return "echo=0,icanon=0"
913 def _InstanceKVMRuntime(cls, instance_name):
914 """Returns the instance KVM runtime filename
917 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
920 def _InstanceChrootDir(cls, instance_name):
921 """Returns the name of the KVM chroot dir of the instance
924 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
927 def _InstanceNICDir(cls, instance_name):
928 """Returns the name of the directory holding the tap device files for a
932 return utils.PathJoin(cls._NICS_DIR, instance_name)
935 def _InstanceNICFile(cls, instance_name, seq):
936 """Returns the name of the file containing the tap device for a given NIC
939 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
942 def _InstanceKeymapFile(cls, instance_name):
943 """Returns the name of the file containing the keymap for a given instance
946 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
949 def _TryReadUidFile(cls, uid_file):
950 """Try to read a uid file
953 if os.path.exists(uid_file):
955 uid = int(utils.ReadOneLineFile(uid_file))
957 except EnvironmentError:
958 logging.warning("Can't read uid file", exc_info=True)
959 except (TypeError, ValueError):
960 logging.warning("Can't parse uid file contents", exc_info=True)
964 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
965 """Removes an instance's rutime sockets/files/dirs.
968 utils.RemoveFile(pidfile)
969 utils.RemoveFile(cls._InstanceMonitor(instance_name))
970 utils.RemoveFile(cls._InstanceSerial(instance_name))
971 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
972 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
973 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
974 uid_file = cls._InstanceUidFile(instance_name)
975 uid = cls._TryReadUidFile(uid_file)
976 utils.RemoveFile(uid_file)
978 uidpool.ReleaseUid(uid)
980 shutil.rmtree(cls._InstanceNICDir(instance_name))
982 if err.errno != errno.ENOENT:
985 chroot_dir = cls._InstanceChrootDir(instance_name)
986 utils.RemoveDir(chroot_dir)
988 if err.errno == errno.ENOTEMPTY:
989 # The chroot directory is expected to be empty, but it isn't.
990 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
993 utils.TimestampForFilename()))
994 logging.warning("The chroot directory of instance %s can not be"
995 " removed as it is not empty. Moving it to the"
996 " quarantine instead. Please investigate the"
997 " contents (%s) and clean up manually",
998 instance_name, new_chroot_dir)
999 utils.RenameFile(chroot_dir, new_chroot_dir)
1004 def _ConfigureNIC(instance, seq, nic, tap):
1005 """Run the network configuration script for a specified NIC
1007 @param instance: instance we're acting on
1008 @type instance: instance object
1009 @param seq: nic sequence number
1011 @param nic: nic we're acting on
1012 @type nic: nic object
1013 @param tap: the host's tap interface this NIC corresponds to
1018 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1019 "INSTANCE": instance.name,
1021 "MODE": nic.nicparams[constants.NIC_MODE],
1023 "INTERFACE_INDEX": str(seq),
1024 "INTERFACE_UUID": nic.uuid,
1025 "TAGS": " ".join(instance.GetTags()),
1032 env["INTERFACE_NAME"] = nic.name
1034 if nic.nicparams[constants.NIC_LINK]:
1035 env["LINK"] = nic.nicparams[constants.NIC_LINK]
1038 n = objects.Network.FromDict(nic.netinfo)
1039 env.update(n.HooksDict())
1041 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1042 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1044 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1046 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1047 " network configuration script output: %s" %
1048 (tap, result.fail_reason, result.output))
1051 def _VerifyAffinityPackage():
1052 if affinity is None:
1053 raise errors.HypervisorError("affinity Python package not"
1054 " found; cannot use CPU pinning under KVM")
1057 def _BuildAffinityCpuMask(cpu_list):
1058 """Create a CPU mask suitable for sched_setaffinity from a list of
1061 See man taskset for more info on sched_setaffinity masks.
1062 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1064 @type cpu_list: list of int
1065 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1067 @return: a bit mask of CPU affinities
1070 if cpu_list == constants.CPU_PINNING_OFF:
1071 return constants.CPU_PINNING_ALL_KVM
1073 return sum(2 ** cpu for cpu in cpu_list)
1076 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1077 """Change CPU affinity for running VM according to given CPU mask.
1079 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1080 @type cpu_mask: string
1081 @param process_id: process ID of KVM process. Used to pin entire VM
1083 @type process_id: int
1084 @param thread_dict: map of virtual CPUs to KVM thread IDs
1085 @type thread_dict: dict int:int
1088 # Convert the string CPU mask to a list of list of int's
1089 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1091 if len(cpu_list) == 1:
1092 all_cpu_mapping = cpu_list[0]
1093 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1094 # If CPU pinning has 1 entry that's "all", then do nothing
1097 # If CPU pinning has one non-all entry, map the entire VM to
1098 # one set of physical CPUs
1099 cls._VerifyAffinityPackage()
1100 affinity.set_process_affinity_mask(
1101 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1103 # The number of vCPUs mapped should match the number of vCPUs
1104 # reported by KVM. This was already verified earlier, so
1105 # here only as a sanity check.
1106 assert len(thread_dict) == len(cpu_list)
1107 cls._VerifyAffinityPackage()
1109 # For each vCPU, map it to the proper list of physical CPUs
1110 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1111 affinity.set_process_affinity_mask(thread_dict[i],
1112 cls._BuildAffinityCpuMask(vcpu))
1114 def _GetVcpuThreadIds(self, instance_name):
1115 """Get a mapping of vCPU no. to thread IDs for the instance
1117 @type instance_name: string
1118 @param instance_name: instance in question
1119 @rtype: dictionary of int:int
1120 @return: a dictionary mapping vCPU numbers to thread IDs
1124 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1125 for line in output.stdout.splitlines():
1126 match = self._CPU_INFO_RE.search(line)
1129 grp = map(int, match.groups())
1130 result[grp[0]] = grp[1]
1134 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1135 """Complete CPU pinning.
1137 @type instance_name: string
1138 @param instance_name: name of instance
1139 @type cpu_mask: string
1140 @param cpu_mask: CPU pinning mask as entered by user
1143 # Get KVM process ID, to be used if need to pin entire VM
1144 _, pid, _ = self._InstancePidAlive(instance_name)
1145 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1146 thread_dict = self._GetVcpuThreadIds(instance_name)
1147 # Run CPU pinning, based on configured mask
1148 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1150 def ListInstances(self):
1151 """Get the list of running instances.
1153 We can do this by listing our live instances directory and
1154 checking whether the associated kvm process is still alive.
1158 for name in os.listdir(self._PIDS_DIR):
1159 if self._InstancePidAlive(name)[2]:
1163 def GetInstanceInfo(self, instance_name):
1164 """Get instance properties.
1166 @type instance_name: string
1167 @param instance_name: the instance name
1168 @rtype: tuple of strings
1169 @return: (name, id, memory, vcpus, stat, times)
1172 _, pid, alive = self._InstancePidAlive(instance_name)
1176 _, memory, vcpus = self._InstancePidInfo(pid)
1181 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1183 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1184 # Will fail if ballooning is not enabled, but we can then just resort to
1186 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1187 memory = mem_bytes / 1048576
1188 except errors.HypervisorError:
1191 return (instance_name, pid, memory, vcpus, istat, times)
1193 def GetAllInstancesInfo(self):
1194 """Get properties of all instances.
1196 @return: list of tuples (name, id, memory, vcpus, stat, times)
1200 for name in os.listdir(self._PIDS_DIR):
1202 info = self.GetInstanceInfo(name)
1203 except errors.HypervisorError:
1204 # Ignore exceptions due to instances being shut down
1210 def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1212 """Generate KVM options regarding instance's block devices.
1214 @type instance: L{objects.Instance}
1215 @param instance: the instance object
1216 @type kvm_disks: list of tuples
1217 @param kvm_disks: list of tuples [(disk, link_name)..]
1218 @type kvmhelp: string
1219 @param kvmhelp: output of kvm --help
1220 @type devlist: string
1221 @param devlist: output of kvm -device ?
1223 @return: list of command line options eventually used by kvm executable
1226 hvp = instance.hvparams
1227 kernel_path = hvp[constants.HV_KERNEL_PATH]
1231 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1233 # whether this is an older KVM version that uses the boot=on flag
1235 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1238 device_driver = None
1239 disk_type = hvp[constants.HV_DISK_TYPE]
1240 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1241 if_val = ",if=%s" % self._VIRTIO
1243 if self._VIRTIO_BLK_RE.search(devlist):
1245 # will be passed in -device option as driver
1246 device_driver = self._VIRTIO_BLK_PCI
1247 except errors.HypervisorError, _:
1250 if_val = ",if=%s" % disk_type
1252 disk_cache = hvp[constants.HV_DISK_CACHE]
1253 if instance.disk_template in constants.DTS_EXT_MIRROR:
1254 if disk_cache != "none":
1255 # TODO: make this a hard error, instead of a silent overwrite
1256 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1257 " to prevent shared storage corruption on migration",
1259 cache_val = ",cache=none"
1260 elif disk_cache != constants.HT_CACHE_DEFAULT:
1261 cache_val = ",cache=%s" % disk_cache
1264 for cfdev, link_name in kvm_disks:
1265 if cfdev.mode != constants.DISK_RDWR:
1266 raise errors.HypervisorError("Instance has read-only disks which"
1267 " are not supported by KVM")
1268 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1271 dev_opts.extend(["-boot", "c"])
1273 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1274 boot_val = ",boot=on"
1275 drive_val = "file=%s,format=raw%s%s%s" % \
1276 (dev_path, if_val, boot_val, cache_val)
1279 # kvm_disks are the 4th entry of runtime file that did not exist in
1280 # the past. That means that cfdev should always have pci slot and
1281 # _GenerateDeviceKVMId() will not raise a exception.
1282 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1283 drive_val += (",id=%s" % kvm_devid)
1284 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1285 dev_val = ("%s,drive=%s,id=%s" %
1286 (device_driver, kvm_devid, kvm_devid))
1287 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1288 dev_opts.extend(["-device", dev_val])
1290 dev_opts.extend(["-drive", drive_val])
1294 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1296 """Generate KVM information to start an instance.
1298 @type kvmhelp: string
1299 @param kvmhelp: output of kvm --help
1300 @attention: this function must not have any side-effects; for
1301 example, it must not write to the filesystem, or read values
1302 from the current system the are expected to differ between
1303 nodes, since it is only run once at instance startup;
1304 actions/kvm arguments that can vary between systems should be
1305 done in L{_ExecuteKVMRuntime}
1308 # pylint: disable=R0912,R0914,R0915
1309 hvp = instance.hvparams
1310 self.ValidateParameters(hvp)
1312 pidfile = self._InstancePidFile(instance.name)
1313 kvm = hvp[constants.HV_KVM_PATH]
1315 # used just by the vnc server, if enabled
1316 kvm_cmd.extend(["-name", instance.name])
1317 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1319 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1320 if hvp[constants.HV_CPU_CORES]:
1321 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1322 if hvp[constants.HV_CPU_THREADS]:
1323 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1324 if hvp[constants.HV_CPU_SOCKETS]:
1325 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1327 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1329 kvm_cmd.extend(["-pidfile", pidfile])
1330 kvm_cmd.extend(["-balloon", "virtio"])
1331 kvm_cmd.extend(["-daemonize"])
1332 if not instance.hvparams[constants.HV_ACPI]:
1333 kvm_cmd.extend(["-no-acpi"])
1334 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1335 constants.INSTANCE_REBOOT_EXIT:
1336 kvm_cmd.extend(["-no-reboot"])
1338 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1340 mversion = self._GetDefaultMachineVersion(kvm)
1341 if self._MACHINE_RE.search(kvmhelp):
1342 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1343 # extra hypervisor parameters. We should also investigate whether and how
1344 # shadow_mem should be considered for the resource model.
1345 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1346 specprop = ",accel=kvm"
1349 machinespec = "%s%s" % (mversion, specprop)
1350 kvm_cmd.extend(["-machine", machinespec])
1352 kvm_cmd.extend(["-M", mversion])
1353 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1354 self._ENABLE_KVM_RE.search(kvmhelp)):
1355 kvm_cmd.extend(["-enable-kvm"])
1356 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1357 self._DISABLE_KVM_RE.search(kvmhelp)):
1358 kvm_cmd.extend(["-disable-kvm"])
1360 kernel_path = hvp[constants.HV_KERNEL_PATH]
1362 boot_cdrom = boot_floppy = boot_network = False
1364 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1365 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1366 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1369 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1372 kvm_cmd.extend(["-boot", "n"])
1374 # whether this is an older KVM version that uses the boot=on flag
1376 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1378 disk_type = hvp[constants.HV_DISK_TYPE]
1380 #Now we can specify a different device type for CDROM devices.
1381 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1382 if not cdrom_disk_type:
1383 cdrom_disk_type = disk_type
1385 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1387 options = ",format=raw,media=cdrom"
1388 # set cdrom 'if' type
1390 actual_cdrom_type = constants.HT_DISK_IDE
1391 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1392 actual_cdrom_type = "virtio"
1394 actual_cdrom_type = cdrom_disk_type
1395 if_val = ",if=%s" % actual_cdrom_type
1396 # set boot flag, if needed
1399 kvm_cmd.extend(["-boot", "d"])
1401 boot_val = ",boot=on"
1402 # and finally build the entire '-drive' value
1403 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1404 kvm_cmd.extend(["-drive", drive_val])
1406 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1408 options = ",format=raw,media=cdrom"
1409 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1410 if_val = ",if=virtio"
1412 if_val = ",if=%s" % cdrom_disk_type
1413 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1414 kvm_cmd.extend(["-drive", drive_val])
1416 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1418 options = ",format=raw,media=disk"
1420 kvm_cmd.extend(["-boot", "a"])
1421 options = "%s,boot=on" % options
1422 if_val = ",if=floppy"
1423 options = "%s%s" % (options, if_val)
1424 drive_val = "file=%s%s" % (floppy_image, options)
1425 kvm_cmd.extend(["-drive", drive_val])
1428 kvm_cmd.extend(["-kernel", kernel_path])
1429 initrd_path = hvp[constants.HV_INITRD_PATH]
1431 kvm_cmd.extend(["-initrd", initrd_path])
1432 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1433 hvp[constants.HV_KERNEL_ARGS]]
1434 if hvp[constants.HV_SERIAL_CONSOLE]:
1435 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1436 root_append.append("console=ttyS0,%s" % serial_speed)
1437 kvm_cmd.extend(["-append", " ".join(root_append)])
1439 mem_path = hvp[constants.HV_MEM_PATH]
1441 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1443 monitor_dev = ("unix:%s,server,nowait" %
1444 self._InstanceMonitor(instance.name))
1445 kvm_cmd.extend(["-monitor", monitor_dev])
1446 if hvp[constants.HV_SERIAL_CONSOLE]:
1447 serial_dev = ("unix:%s,server,nowait" %
1448 self._InstanceSerial(instance.name))
1449 kvm_cmd.extend(["-serial", serial_dev])
1451 kvm_cmd.extend(["-serial", "none"])
1453 mouse_type = hvp[constants.HV_USB_MOUSE]
1454 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1455 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1456 spice_ip_version = None
1458 kvm_cmd.extend(["-usb"])
1461 kvm_cmd.extend(["-usbdevice", mouse_type])
1462 elif vnc_bind_address:
1463 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1465 if vnc_bind_address:
1466 if netutils.IP4Address.IsValid(vnc_bind_address):
1467 if instance.network_port > constants.VNC_BASE_PORT:
1468 display = instance.network_port - constants.VNC_BASE_PORT
1469 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1470 vnc_arg = ":%d" % (display)
1472 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1474 logging.error("Network port is not a valid VNC display (%d < %d),"
1475 " not starting VNC",
1476 instance.network_port, constants.VNC_BASE_PORT)
1479 # Only allow tls and other option when not binding to a file, for now.
1480 # kvm/qemu gets confused otherwise about the filename to use.
1482 if hvp[constants.HV_VNC_TLS]:
1483 vnc_append = "%s,tls" % vnc_append
1484 if hvp[constants.HV_VNC_X509_VERIFY]:
1485 vnc_append = "%s,x509verify=%s" % (vnc_append,
1486 hvp[constants.HV_VNC_X509])
1487 elif hvp[constants.HV_VNC_X509]:
1488 vnc_append = "%s,x509=%s" % (vnc_append,
1489 hvp[constants.HV_VNC_X509])
1490 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1491 vnc_append = "%s,password" % vnc_append
1493 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1496 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1498 kvm_cmd.extend(["-vnc", vnc_arg])
1500 # FIXME: this is wrong here; the iface ip address differs
1501 # between systems, so it should be done in _ExecuteKVMRuntime
1502 if netutils.IsValidInterface(spice_bind):
1503 # The user specified a network interface, we have to figure out the IP
1505 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1506 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1508 # if the user specified an IP version and the interface does not
1509 # have that kind of IP addresses, throw an exception
1510 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1511 if not addresses[spice_ip_version]:
1512 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1513 " for %s" % (spice_ip_version,
1516 # the user did not specify an IP version, we have to figure it out
1517 elif (addresses[constants.IP4_VERSION] and
1518 addresses[constants.IP6_VERSION]):
1519 # we have both ipv4 and ipv6, let's use the cluster default IP
1521 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1522 spice_ip_version = \
1523 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1524 elif addresses[constants.IP4_VERSION]:
1525 spice_ip_version = constants.IP4_VERSION
1526 elif addresses[constants.IP6_VERSION]:
1527 spice_ip_version = constants.IP6_VERSION
1529 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1530 " for %s" % (spice_bind))
1532 spice_address = addresses[spice_ip_version][0]
1535 # spice_bind is known to be a valid IP address, because
1536 # ValidateParameters checked it.
1537 spice_address = spice_bind
1539 spice_arg = "addr=%s" % spice_address
1540 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1541 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1542 (spice_arg, instance.network_port,
1543 pathutils.SPICE_CACERT_FILE))
1544 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1545 (spice_arg, pathutils.SPICE_CERT_FILE,
1546 pathutils.SPICE_CERT_FILE))
1547 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1549 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1551 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1553 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1554 spice_arg = "%s,disable-ticketing" % spice_arg
1556 if spice_ip_version:
1557 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1559 # Image compression options
1560 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1561 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1562 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1564 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1566 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1568 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1570 # Video stream detection
1571 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1573 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1575 # Audio compression, by default in qemu-kvm it is on
1576 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1577 spice_arg = "%s,playback-compression=off" % spice_arg
1578 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1579 spice_arg = "%s,agent-mouse=off" % spice_arg
1581 # Enable the spice agent communication channel between the host and the
1583 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1586 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1588 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1590 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1591 kvm_cmd.extend(["-spice", spice_arg])
1594 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1595 # also works in earlier versions though (tested with 1.1 and 1.3)
1596 if self._DISPLAY_RE.search(kvmhelp):
1597 kvm_cmd.extend(["-display", "none"])
1599 kvm_cmd.extend(["-nographic"])
1601 if hvp[constants.HV_USE_LOCALTIME]:
1602 kvm_cmd.extend(["-localtime"])
1604 if hvp[constants.HV_KVM_USE_CHROOT]:
1605 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1607 # Add qemu-KVM -cpu param
1608 if hvp[constants.HV_CPU_TYPE]:
1609 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1611 # As requested by music lovers
1612 if hvp[constants.HV_SOUNDHW]:
1613 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1615 # Pass a -vga option if requested, or if spice is used, for backwards
1617 if hvp[constants.HV_VGA]:
1618 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1620 kvm_cmd.extend(["-vga", "qxl"])
1622 # Various types of usb devices, comma separated
1623 if hvp[constants.HV_USB_DEVICES]:
1624 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1625 kvm_cmd.extend(["-usbdevice", dev])
1627 if hvp[constants.HV_KVM_EXTRA]:
1628 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1630 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1632 for disk, link_name in block_devices:
1633 _UpdatePCISlots(disk, pci_reservations)
1634 kvm_disks.append((disk, link_name))
1637 for nic in instance.nics:
1638 _UpdatePCISlots(nic, pci_reservations)
1639 kvm_nics.append(nic)
1643 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1645 def _WriteKVMRuntime(self, instance_name, data):
1646 """Write an instance's KVM runtime
1650 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1652 except EnvironmentError, err:
1653 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1655 def _ReadKVMRuntime(self, instance_name):
1656 """Read an instance's KVM runtime
1660 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1661 except EnvironmentError, err:
1662 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1665 def _SaveKVMRuntime(self, instance, kvm_runtime):
1666 """Save an instance's KVM runtime
1669 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1671 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1672 serialized_disks = [(blk.ToDict(), link)
1673 for blk, link in kvm_disks]
1674 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1677 self._WriteKVMRuntime(instance.name, serialized_form)
1679 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1680 """Load an instance's KVM runtime
1683 if not serialized_runtime:
1684 serialized_runtime = self._ReadKVMRuntime(instance.name)
1686 return _AnalyzeSerializedRuntime(serialized_runtime)
1688 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1689 """Run the KVM cmd and check for errors
1692 @param name: instance name
1693 @type kvm_cmd: list of strings
1694 @param kvm_cmd: runcmd input for kvm
1695 @type tap_fds: list of int
1696 @param tap_fds: fds of tap devices opened by Ganeti
1700 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1703 utils_wrapper.CloseFdNoError(fd)
1706 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1707 (name, result.fail_reason, result.output))
1708 if not self._InstancePidAlive(name)[2]:
1709 raise errors.HypervisorError("Failed to start instance %s" % name)
1711 # too many local variables
1712 # pylint: disable=R0914
1713 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1714 """Execute a KVM cmd, after completing it with some last minute data.
1716 @type incoming: tuple of strings
1717 @param incoming: (target_host_ip, port)
1718 @type kvmhelp: string
1719 @param kvmhelp: output of kvm --help
1722 # Small _ExecuteKVMRuntime hv parameters programming howto:
1723 # - conf_hvp contains the parameters as configured on ganeti. they might
1724 # have changed since the instance started; only use them if the change
1725 # won't affect the inside of the instance (which hasn't been rebooted).
1726 # - up_hvp contains the parameters as they were when the instance was
1727 # started, plus any new parameter which has been added between ganeti
1728 # versions: it is paramount that those default to a value which won't
1729 # affect the inside of the instance as well.
1730 conf_hvp = instance.hvparams
1731 name = instance.name
1732 self._CheckDown(name)
1736 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1737 # the first element of kvm_cmd is always the path to the kvm binary
1738 kvm_path = kvm_cmd[0]
1739 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1741 # We know it's safe to run as a different user upon migration, so we'll use
1742 # the latest conf, from conf_hvp.
1743 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1744 if security_model == constants.HT_SM_USER:
1745 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1747 keymap = conf_hvp[constants.HV_KEYMAP]
1749 keymap_path = self._InstanceKeymapFile(name)
1750 # If a keymap file is specified, KVM won't use its internal defaults. By
1751 # first including the "en-us" layout, an error on loading the actual
1752 # layout (e.g. because it can't be found) won't lead to a non-functional
1753 # keyboard. A keyboard with incorrect keys is still better than none.
1754 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1755 kvm_cmd.extend(["-k", keymap_path])
1757 # We have reasons to believe changing something like the nic driver/type
1758 # upon migration won't exactly fly with the instance kernel, so for nic
1759 # related parameters we'll use up_hvp
1762 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1764 kvm_cmd.extend(["-net", "none"])
1768 nic_type = up_hvp[constants.HV_NIC_TYPE]
1769 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1770 nic_model = self._VIRTIO
1772 if self._VIRTIO_NET_RE.search(devlist):
1773 nic_model = self._VIRTIO_NET_PCI
1774 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1775 except errors.HypervisorError, _:
1776 # Older versions of kvm don't support DEVICE_LIST, but they don't
1777 # have new virtio syntax either.
1780 if up_hvp[constants.HV_VHOST_NET]:
1781 # check for vhost_net support
1782 if self._VHOST_RE.search(kvmhelp):
1783 tap_extra = ",vhost=on"
1785 raise errors.HypervisorError("vhost_net is configured"
1786 " but it is not available")
1788 nic_model = nic_type
1790 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1792 for nic_seq, nic in enumerate(kvm_nics):
1793 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1794 tapfds.append(tapfd)
1795 taps.append(tapname)
1796 if kvm_supports_netdev:
1797 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1799 # kvm_nics already exist in old runtime files and thus there might
1800 # be some entries without pci slot (therefore try: except:)
1801 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1803 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1804 except errors.HotplugError:
1805 netdev = "netdev%d" % nic_seq
1806 nic_val += (",netdev=%s" % netdev)
1807 tap_val = ("type=tap,id=%s,fd=%d%s" %
1808 (netdev, tapfd, tap_extra))
1809 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1811 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1813 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1814 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1817 target, port = incoming
1818 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1820 # Changing the vnc password doesn't bother the guest that much. At most it
1821 # will surprise people who connect to it. Whether positively or negatively
1823 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1827 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1828 except EnvironmentError, err:
1829 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1830 % (vnc_pwd_file, err))
1832 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1833 utils.EnsureDirs([(self._InstanceChrootDir(name),
1834 constants.SECURE_DIR_MODE)])
1836 # Automatically enable QMP if version is >= 0.14
1837 if self._QMP_RE.search(kvmhelp):
1838 logging.debug("Enabling QMP")
1839 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1840 self._InstanceQmpMonitor(instance.name)])
1842 # Configure the network now for starting instances and bridged interfaces,
1843 # during FinalizeMigration for incoming instances' routed interfaces
1844 for nic_seq, nic in enumerate(kvm_nics):
1846 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1848 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1850 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1854 kvm_cmd.extend(bdev_opts)
1855 # CPU affinity requires kvm to start paused, so we set this flag if the
1856 # instance is not already paused and if we are not going to accept a
1857 # migrating instance. In the latter case, pausing is not needed.
1858 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1859 if start_kvm_paused:
1860 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1862 # Note: CPU pinning is using up_hvp since changes take effect
1863 # during instance startup anyway, and to avoid problems when soft
1864 # rebooting the instance.
1866 if up_hvp.get(constants.HV_CPU_MASK, None):
1869 if security_model == constants.HT_SM_POOL:
1870 ss = ssconf.SimpleStore()
1871 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1872 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1873 uid = uidpool.RequestUnusedUid(all_uids)
1875 username = pwd.getpwuid(uid.GetUid()).pw_name
1876 kvm_cmd.extend(["-runas", username])
1877 self._RunKVMCmd(name, kvm_cmd, tapfds)
1879 uidpool.ReleaseUid(uid)
1883 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1885 self._RunKVMCmd(name, kvm_cmd, tapfds)
1887 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1888 constants.RUN_DIRS_MODE)])
1889 for nic_seq, tap in enumerate(taps):
1890 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1894 change_cmd = "change vnc password %s" % vnc_pwd
1895 self._CallMonitorCommand(instance.name, change_cmd)
1897 # Setting SPICE password. We are not vulnerable to malicious passwordless
1898 # connection attempts because SPICE by default does not allow connections
1899 # if neither a password nor the "disable_ticketing" options are specified.
1900 # As soon as we send the password via QMP, that password is a valid ticket
1902 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1903 if spice_password_file:
1906 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1907 except EnvironmentError, err:
1908 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1909 % (spice_password_file, err))
1911 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1914 "protocol": "spice",
1915 "password": spice_pwd,
1917 qmp.Execute("set_password", arguments)
1919 for filename in temp_files:
1920 utils.RemoveFile(filename)
1922 # If requested, set CPU affinity and resume instance execution
1924 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1926 start_memory = self._InstanceStartupMemory(instance)
1927 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1928 self.BalloonInstanceMemory(instance, start_memory)
1930 if start_kvm_paused:
1931 # To control CPU pinning, ballooning, and vnc/spice passwords
1932 # the VM was started in a frozen state. If freezing was not
1933 # explicitly requested resume the vm status.
1934 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1936 def StartInstance(self, instance, block_devices, startup_paused):
1937 """Start an instance.
1940 self._CheckDown(instance.name)
1941 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1942 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1943 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1944 startup_paused, kvmhelp)
1945 self._SaveKVMRuntime(instance, kvm_runtime)
1946 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1948 def _CallMonitorCommand(self, instance_name, command, timeout=None):
1949 """Invoke a command on the instance monitor.
1952 if timeout is not None:
1953 timeout_cmd = "timeout %s" % (timeout, )
1957 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1958 # version. The monitor protocol is designed for human consumption, whereas
1959 # QMP is made for programmatic usage. In the worst case QMP can also
1960 # execute monitor commands. As it is, all calls to socat take at least
1961 # 500ms and likely more: socat can't detect the end of the reply and waits
1962 # for 500ms of no data received before exiting (500 ms is the default for
1963 # the "-t" parameter).
1964 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1965 (utils.ShellQuote(command),
1967 constants.SOCAT_PATH,
1968 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1970 result = utils.RunCmd(socat)
1972 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1974 (command, instance_name, result.fail_reason, result.output))
1975 raise errors.HypervisorError(msg)
1979 def _GetFreePCISlot(self, instance, dev):
1980 """Get the first available pci slot of a runnung instance.
1983 slots = bitarray(32)
1984 slots.setall(False) # pylint: disable=E1101
1985 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1986 for line in output.stdout.splitlines():
1987 match = self._INFO_PCI_RE.search(line)
1989 slot = int(match.group(1))
1992 [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1994 raise errors.HypervisorError("All PCI slots occupied")
1998 def VerifyHotplugSupport(self, instance, action, dev_type):
1999 """Verifies that hotplug is supported.
2001 Hotplug is *not* supported in case of:
2002 - security models and chroot (disk hotplug)
2003 - fdsend module is missing (nic hot-add)
2005 @raise errors.HypervisorError: in one of the previous cases
2008 if dev_type == constants.HOTPLUG_TARGET_DISK:
2009 hvp = instance.hvparams
2010 security_model = hvp[constants.HV_SECURITY_MODEL]
2011 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2013 raise errors.HotplugError("Disk hotplug is not supported"
2014 " in case of chroot.")
2015 if security_model != constants.HT_SM_NONE:
2016 raise errors.HotplugError("Disk Hotplug is not supported in case"
2017 " security models are used.")
2019 if (dev_type == constants.HOTPLUG_TARGET_NIC and
2020 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2021 raise errors.HotplugError("Cannot hot-add NIC."
2022 " fdsend python module is missing.")
2024 def HotplugSupported(self, instance):
2025 """Checks if hotplug is generally supported.
2027 Hotplug is *not* supported in case of:
2028 - qemu versions < 1.0
2029 - for stopped instances
2031 @raise errors.HypervisorError: in one of the previous cases
2035 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2036 except errors.HypervisorError:
2037 raise errors.HotplugError("Instance is probably down")
2039 # TODO: search for netdev_add, drive_add, device_add.....
2040 match = self._INFO_VERSION_RE.search(output.stdout)
2042 raise errors.HotplugError("Cannot parse qemu version via monitor")
2044 v_major, v_min, _, _ = match.groups()
2045 if (int(v_major), int(v_min)) < (1, 0):
2046 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2048 def _CallHotplugCommand(self, name, cmd):
2049 output = self._CallMonitorCommand(name, cmd)
2050 # TODO: parse output and check if succeeded
2051 for line in output.stdout.splitlines():
2052 logging.info("%s", line)
2054 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2055 """ Helper method to hot-add a new device
2057 It gets free pci slot generates the device name and invokes the
2058 device specific method.
2061 # in case of hot-mod this is given
2062 if device.pci is None:
2063 self._GetFreePCISlot(instance, device)
2064 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2065 runtime = self._LoadKVMRuntime(instance)
2066 if dev_type == constants.HOTPLUG_TARGET_DISK:
2067 command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2069 command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2070 (hex(device.pci), kvm_devid, kvm_devid))
2071 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2072 (tap, fd) = _OpenTap()
2073 self._ConfigureNIC(instance, seq, device, tap)
2074 self._PassTapFd(instance, fd, device)
2075 command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2076 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2077 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2078 command += "device_add %s" % args
2079 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2081 self._CallHotplugCommand(instance.name, command)
2082 # update relevant entries in runtime file
2083 index = _DEVICE_RUNTIME_INDEX[dev_type]
2084 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2085 runtime[index].append(entry)
2086 self._SaveKVMRuntime(instance, runtime)
2088 def HotDelDevice(self, instance, dev_type, device, _, seq):
2089 """ Helper method for hot-del device
2091 It gets device info from runtime file, generates the device name and
2092 invokes the device specific method.
2095 runtime = self._LoadKVMRuntime(instance)
2096 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2097 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2098 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2099 if dev_type == constants.HOTPLUG_TARGET_DISK:
2100 command = "device_del %s\n" % kvm_devid
2101 command += "drive_del %s" % kvm_devid
2102 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2103 command = "device_del %s\n" % kvm_devid
2104 command += "netdev_del %s" % kvm_devid
2105 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2106 self._CallHotplugCommand(instance.name, command)
2107 index = _DEVICE_RUNTIME_INDEX[dev_type]
2108 runtime[index].remove(entry)
2109 self._SaveKVMRuntime(instance, runtime)
2111 return kvm_device.pci
2113 def HotModDevice(self, instance, dev_type, device, _, seq):
2114 """ Helper method for hot-mod device
2116 It gets device info from runtime file, generates the device name and
2117 invokes the device specific method. Currently only NICs support hot-mod
2120 if dev_type == constants.HOTPLUG_TARGET_NIC:
2121 # putting it back in the same pci slot
2122 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2123 # TODO: remove sleep when socat gets removed
2125 self.HotAddDevice(instance, dev_type, device, _, seq)
2127 def _PassTapFd(self, instance, fd, nic):
2128 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2131 # TODO: factor out code related to unix sockets.
2132 # squash common parts between monitor and qmp
2133 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2134 command = "getfd %s\n" % kvm_devid
2136 logging.info("%s", fds)
2138 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2140 fdsend.sendfds(monsock.sock, command, fds=fds)
2145 def _ParseKVMVersion(cls, text):
2146 """Parse the KVM version from the --help output.
2149 @param text: output of kvm --help
2150 @return: (version, v_maj, v_min, v_rev)
2151 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2154 match = cls._VERSION_RE.search(text.splitlines()[0])
2156 raise errors.HypervisorError("Unable to get KVM version")
2158 v_all = match.group(0)
2159 v_maj = int(match.group(1))
2160 v_min = int(match.group(2))
2162 v_rev = int(match.group(4))
2165 return (v_all, v_maj, v_min, v_rev)
2168 def _GetKVMOutput(cls, kvm_path, option):
2169 """Return the output of a kvm invocation
2171 @type kvm_path: string
2172 @param kvm_path: path to the kvm executable
2173 @type option: a key of _KVMOPTS_CMDS
2174 @param option: kvm option to fetch the output from
2175 @return: output a supported kvm invocation
2176 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2179 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2181 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2183 result = utils.RunCmd([kvm_path] + optlist)
2184 if result.failed and not can_fail:
2185 raise errors.HypervisorError("Unable to get KVM %s output" %
2187 return result.output
2190 def _GetKVMVersion(cls, kvm_path):
2191 """Return the installed KVM version.
2193 @return: (version, v_maj, v_min, v_rev)
2194 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2197 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2200 def _GetDefaultMachineVersion(cls, kvm_path):
2201 """Return the default hardware revision (e.g. pc-1.1)
2204 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2205 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2207 return match.group(1)
2211 def StopInstance(self, instance, force=False, retry=False, name=None,
2213 """Stop an instance.
2216 assert(timeout is None or force is not None)
2218 if name is not None and not force:
2219 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2221 name = instance.name
2222 acpi = instance.hvparams[constants.HV_ACPI]
2225 _, pid, alive = self._InstancePidAlive(name)
2226 if pid > 0 and alive:
2227 if force or not acpi:
2228 utils.KillProcess(pid)
2230 self._CallMonitorCommand(name, "system_powerdown", timeout)
2232 def CleanupInstance(self, instance_name):
2233 """Cleanup after a stopped instance
2236 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2237 if pid > 0 and alive:
2238 raise errors.HypervisorError("Cannot cleanup a live instance")
2239 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2241 def RebootInstance(self, instance):
2242 """Reboot an instance.
2245 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2246 # socket the instance will stop, but now power up again. So we'll resort
2247 # to shutdown and restart.
2248 _, _, alive = self._InstancePidAlive(instance.name)
2250 raise errors.HypervisorError("Failed to reboot instance %s:"
2251 " not running" % instance.name)
2252 # StopInstance will delete the saved KVM runtime so:
2253 # ...first load it...
2254 kvm_runtime = self._LoadKVMRuntime(instance)
2255 # ...now we can safely call StopInstance...
2256 if not self.StopInstance(instance):
2257 self.StopInstance(instance, force=True)
2258 # ...and finally we can save it again, and execute it...
2259 self._SaveKVMRuntime(instance, kvm_runtime)
2260 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2261 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2262 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2264 def MigrationInfo(self, instance):
2265 """Get instance information to perform a migration.
2267 @type instance: L{objects.Instance}
2268 @param instance: instance to be migrated
2270 @return: content of the KVM runtime file
2273 return self._ReadKVMRuntime(instance.name)
2275 def AcceptInstance(self, instance, info, target):
2276 """Prepare to accept an instance.
2278 @type instance: L{objects.Instance}
2279 @param instance: instance to be accepted
2281 @param info: content of the KVM runtime file on the source node
2282 @type target: string
2283 @param target: target host (usually ip), on this node
2286 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2287 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2288 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2289 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2290 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2291 incoming=incoming_address)
2293 def FinalizeMigrationDst(self, instance, info, success):
2294 """Finalize the instance migration on the target node.
2296 Stop the incoming mode KVM.
2298 @type instance: L{objects.Instance}
2299 @param instance: instance whose migration is being finalized
2303 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2304 kvm_nics = kvm_runtime[1]
2306 for nic_seq, nic in enumerate(kvm_nics):
2307 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2308 # Bridged interfaces have already been configured
2311 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2312 except EnvironmentError, err:
2313 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2314 instance.name, nic_seq, str(err))
2317 self._ConfigureNIC(instance, nic_seq, nic, tap)
2318 except errors.HypervisorError, err:
2319 logging.warning(str(err))
2321 self._WriteKVMRuntime(instance.name, info)
2323 self.StopInstance(instance, force=True)
2325 def MigrateInstance(self, instance, target, live):
2326 """Migrate an instance to a target node.
2328 The migration will not be attempted if the instance is not
2331 @type instance: L{objects.Instance}
2332 @param instance: the instance to be migrated
2333 @type target: string
2334 @param target: ip address of the target node
2336 @param live: perform a live migration
2339 instance_name = instance.name
2340 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2341 _, _, alive = self._InstancePidAlive(instance_name)
2343 raise errors.HypervisorError("Instance not running, cannot migrate")
2346 self._CallMonitorCommand(instance_name, "stop")
2348 migrate_command = ("migrate_set_speed %dm" %
2349 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2350 self._CallMonitorCommand(instance_name, migrate_command)
2352 migrate_command = ("migrate_set_downtime %dms" %
2353 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2354 self._CallMonitorCommand(instance_name, migrate_command)
2356 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2357 self._CallMonitorCommand(instance_name, migrate_command)
2359 def FinalizeMigrationSource(self, instance, success, live):
2360 """Finalize the instance migration on the source node.
2362 @type instance: L{objects.Instance}
2363 @param instance: the instance that was migrated
2365 @param success: whether the migration succeeded or not
2367 @param live: whether the user requested a live migration or not
2371 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2372 utils.KillProcess(pid)
2373 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2375 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2377 def GetMigrationStatus(self, instance):
2378 """Get the migration status
2380 @type instance: L{objects.Instance}
2381 @param instance: the instance that is being migrated
2382 @rtype: L{objects.MigrationStatus}
2383 @return: the status of the current migration (one of
2384 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2385 progress info that can be retrieved from the hypervisor
2388 info_command = "info migrate"
2389 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2390 result = self._CallMonitorCommand(instance.name, info_command)
2391 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2393 if not result.stdout:
2394 logging.info("KVM: empty 'info migrate' result")
2396 logging.warning("KVM: unknown 'info migrate' result: %s",
2399 status = match.group(1)
2400 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2401 migration_status = objects.MigrationStatus(status=status)
2402 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2404 migration_status.transferred_ram = match.group("transferred")
2405 migration_status.total_ram = match.group("total")
2407 return migration_status
2409 logging.warning("KVM: unknown migration status '%s'", status)
2411 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2413 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2415 def BalloonInstanceMemory(self, instance, mem):
2416 """Balloon an instance memory to a certain value.
2418 @type instance: L{objects.Instance}
2419 @param instance: instance to be accepted
2421 @param mem: actual memory size to use for instance runtime
2424 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2426 def GetNodeInfo(self):
2427 """Return information about the node.
2429 @return: a dict with the following keys (values in MiB):
2430 - memory_total: the total memory size on the node
2431 - memory_free: the available memory on the node for instances
2432 - memory_dom0: the memory used by the node itself, if available
2433 - hv_version: the hypervisor version in the form (major, minor,
2437 result = self.GetLinuxNodeInfo()
2438 # FIXME: this is the global kvm version, but the actual version can be
2439 # customized as an hv parameter. we should use the nodegroup's default kvm
2440 # path parameter here.
2441 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2442 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2446 def GetInstanceConsole(cls, instance, hvparams, beparams):
2447 """Return a command for connecting to the console of an instance.
2450 if hvparams[constants.HV_SERIAL_CONSOLE]:
2451 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2452 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2453 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2454 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2455 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2456 return objects.InstanceConsole(instance=instance.name,
2457 kind=constants.CONS_SSH,
2458 host=instance.primary_node,
2459 user=constants.SSH_CONSOLE_USER,
2462 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2463 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2464 display = instance.network_port - constants.VNC_BASE_PORT
2465 return objects.InstanceConsole(instance=instance.name,
2466 kind=constants.CONS_VNC,
2467 host=vnc_bind_address,
2468 port=instance.network_port,
2471 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2473 return objects.InstanceConsole(instance=instance.name,
2474 kind=constants.CONS_SPICE,
2476 port=instance.network_port)
2478 return objects.InstanceConsole(instance=instance.name,
2479 kind=constants.CONS_MESSAGE,
2480 message=("No serial shell for instance %s" %
2484 """Verify the hypervisor.
2486 Check that the required binaries exist.
2488 @return: Problem description if something is wrong, C{None} otherwise
2492 # FIXME: this is the global kvm binary, but the actual path can be
2493 # customized as an hv parameter; we should use the nodegroup's
2494 # default kvm path parameter here.
2495 if not os.path.exists(constants.KVM_PATH):
2496 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2497 if not os.path.exists(constants.SOCAT_PATH):
2498 msgs.append("The socat binary ('%s') does not exist" %
2499 constants.SOCAT_PATH)
2501 return self._FormatVerifyResults(msgs)
2504 def CheckParameterSyntax(cls, hvparams):
2505 """Check the given parameters for validity.
2507 @type hvparams: dict
2508 @param hvparams: dictionary with parameter names/value
2509 @raise errors.HypervisorError: when a parameter is not valid
2512 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2514 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2516 if not hvparams[constants.HV_ROOT_PATH]:
2517 raise errors.HypervisorError("Need a root partition for the instance,"
2518 " if a kernel is defined")
2520 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2521 not hvparams[constants.HV_VNC_X509]):
2522 raise errors.HypervisorError("%s must be defined, if %s is" %
2523 (constants.HV_VNC_X509,
2524 constants.HV_VNC_X509_VERIFY))
2526 if hvparams[constants.HV_SERIAL_CONSOLE]:
2527 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2528 valid_speeds = constants.VALID_SERIAL_SPEEDS
2529 if not serial_speed or serial_speed not in valid_speeds:
2530 raise errors.HypervisorError("Invalid serial console speed, must be"
2532 utils.CommaJoin(valid_speeds))
2534 boot_order = hvparams[constants.HV_BOOT_ORDER]
2535 if (boot_order == constants.HT_BO_CDROM and
2536 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2537 raise errors.HypervisorError("Cannot boot from cdrom without an"
2540 security_model = hvparams[constants.HV_SECURITY_MODEL]
2541 if security_model == constants.HT_SM_USER:
2542 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2543 raise errors.HypervisorError("A security domain (user to run kvm as)"
2544 " must be specified")
2545 elif (security_model == constants.HT_SM_NONE or
2546 security_model == constants.HT_SM_POOL):
2547 if hvparams[constants.HV_SECURITY_DOMAIN]:
2548 raise errors.HypervisorError("Cannot have a security domain when the"
2549 " security model is 'none' or 'pool'")
2551 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2552 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2554 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2555 # if an IP version is specified, the spice_bind parameter must be an
2557 if (netutils.IP4Address.IsValid(spice_bind) and
2558 spice_ip_version != constants.IP4_VERSION):
2559 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2560 " the specified IP version is %s" %
2561 (spice_bind, spice_ip_version))
2563 if (netutils.IP6Address.IsValid(spice_bind) and
2564 spice_ip_version != constants.IP6_VERSION):
2565 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2566 " the specified IP version is %s" %
2567 (spice_bind, spice_ip_version))
2569 # All the other SPICE parameters depend on spice_bind being set. Raise an
2570 # error if any of them is set without it.
2571 for param in _SPICE_ADDITIONAL_PARAMS:
2573 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2574 (param, constants.HV_KVM_SPICE_BIND))
2577 def ValidateParameters(cls, hvparams):
2578 """Check the given parameters for validity.
2580 @type hvparams: dict
2581 @param hvparams: dictionary with parameter names/value
2582 @raise errors.HypervisorError: when a parameter is not valid
2585 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2587 kvm_path = hvparams[constants.HV_KVM_PATH]
2589 security_model = hvparams[constants.HV_SECURITY_MODEL]
2590 if security_model == constants.HT_SM_USER:
2591 username = hvparams[constants.HV_SECURITY_DOMAIN]
2593 pwd.getpwnam(username)
2595 raise errors.HypervisorError("Unknown security domain user %s"
2598 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2600 # only one of VNC and SPICE can be used currently.
2601 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2602 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2603 " only one of them can be used at a"
2606 # check that KVM supports SPICE
2607 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2608 if not cls._SPICE_RE.search(kvmhelp):
2609 raise errors.HypervisorError("SPICE is configured, but it is not"
2610 " supported according to 'kvm --help'")
2612 # if spice_bind is not an IP address, it must be a valid interface
2613 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2614 netutils.IP6Address.IsValid(spice_bind))
2615 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2616 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2617 " a valid IP address or interface name" %
2618 constants.HV_KVM_SPICE_BIND)
2620 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2622 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2623 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2624 raise errors.HypervisorError("Unsupported machine version: %s" %
2628 def PowercycleNode(cls):
2629 """KVM powercycle, just a wrapper over Linux powercycle.
2632 cls.LinuxPowercycle()