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 _AnalyzeSerializedRuntime(serialized_runtime):
192 """Return runtime entries for a serialized runtime file
194 @type serialized_runtime: string
195 @param serialized_runtime: raw text data read from actual runtime file
196 @return: (cmd, nics, hvparams, bdevs)
200 loaded_runtime = serializer.Load(serialized_runtime)
201 if len(loaded_runtime) == 3:
202 serialized_disks = []
203 kvm_cmd, serialized_nics, hvparams = loaded_runtime
205 kvm_cmd, serialized_nics, hvparams, serialized_disks = loaded_runtime
207 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
208 kvm_disks = [(objects.Disk.FromDict(sdisk), link, uri)
209 for sdisk, link, uri in serialized_disks]
211 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
214 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
215 """Retrieves supported TUN features from file descriptor.
217 @see: L{_ProbeTapVnetHdr}
220 req = struct.pack("I", 0)
222 buf = _ioctl(fd, TUNGETFEATURES, req)
223 except EnvironmentError, err:
224 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
227 (flags, ) = struct.unpack("I", buf)
231 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
232 """Check whether to enable the IFF_VNET_HDR flag.
234 To do this, _all_ of the following conditions must be met:
235 1. TUNGETFEATURES ioctl() *must* be implemented
236 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
237 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
238 drivers/net/tun.c there is no way to test this until after the tap device
239 has been created using TUNSETIFF, and there is no way to change the
240 IFF_VNET_HDR flag after creating the interface, catch-22! However both
241 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
242 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
245 @param fd: the file descriptor of /dev/net/tun
248 flags = _features_fn(fd)
254 result = bool(flags & IFF_VNET_HDR)
257 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
262 def _OpenTap(vnet_hdr=True):
263 """Open a new tap device and return its file descriptor.
265 This is intended to be used by a qemu-type hypervisor together with the -net
266 tap,fd=<fd> command line parameter.
268 @type vnet_hdr: boolean
269 @param vnet_hdr: Enable the VNET Header
270 @return: (ifname, tapfd)
275 tapfd = os.open("/dev/net/tun", os.O_RDWR)
276 except EnvironmentError:
277 raise errors.HypervisorError("Failed to open /dev/net/tun")
279 flags = IFF_TAP | IFF_NO_PI
281 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
282 flags |= IFF_VNET_HDR
284 # The struct ifreq ioctl request (see netdevice(7))
285 ifr = struct.pack("16sh", "", flags)
288 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
289 except EnvironmentError, err:
290 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
293 # Get the interface name from the ioctl
294 ifname = struct.unpack("16sh", res)[0].strip("\x00")
295 return (ifname, tapfd)
299 """QEMU Messaging Protocol (QMP) message.
302 def __init__(self, data):
303 """Creates a new QMP message based on the passed data.
306 if not isinstance(data, dict):
307 raise TypeError("QmpMessage must be initialized with a dict")
311 def __getitem__(self, field_name):
312 """Get the value of the required field if present, or None.
314 Overrides the [] operator to provide access to the message data,
315 returning None if the required item is not in the message
316 @return: the value of the field_name field, or None if field_name
317 is not contained in the message
320 return self.data.get(field_name, None)
322 def __setitem__(self, field_name, field_value):
323 """Set the value of the required field_name to field_value.
326 self.data[field_name] = field_value
329 """Return the number of fields stored in this QmpMessage.
332 return len(self.data)
334 def __delitem__(self, key):
335 """Delete the specified element from the QmpMessage.
341 def BuildFromJsonString(json_string):
342 """Build a QmpMessage from a JSON encoded string.
344 @type json_string: str
345 @param json_string: JSON string representing the message
346 @rtype: L{QmpMessage}
347 @return: a L{QmpMessage} built from json_string
351 data = serializer.LoadJson(json_string)
352 return QmpMessage(data)
355 # The protocol expects the JSON object to be sent as a single line.
356 return serializer.DumpJson(self.data)
358 def __eq__(self, other):
359 # When comparing two QmpMessages, we are interested in comparing
360 # their internal representation of the message data
361 return self.data == other.data
364 class MonitorSocket(object):
367 def __init__(self, monitor_filename):
368 """Instantiates the MonitorSocket object.
370 @type monitor_filename: string
371 @param monitor_filename: the filename of the UNIX raw socket on which the
372 monitor (QMP or simple one) is listening
375 self.monitor_filename = monitor_filename
376 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
377 # We want to fail if the server doesn't send a complete message
378 # in a reasonable amount of time
379 self.sock.settimeout(self._SOCKET_TIMEOUT)
380 self._connected = False
382 def _check_socket(self):
385 sock_stat = os.stat(self.monitor_filename)
386 except EnvironmentError, err:
387 if err.errno == errno.ENOENT:
388 raise errors.HypervisorError("No monitor socket found")
390 raise errors.HypervisorError("Error checking monitor socket: %s",
391 utils.ErrnoOrStr(err))
392 if not stat.S_ISSOCK(sock_stat.st_mode):
393 raise errors.HypervisorError("Monitor socket is not a socket")
395 def _check_connection(self):
396 """Make sure that the connection is established.
399 if not self._connected:
400 raise errors.ProgrammerError("To use a MonitorSocket you need to first"
401 " invoke connect() on it")
404 """Connects to the monitor.
406 Connects to the UNIX socket
408 @raise errors.HypervisorError: when there are communication errors
412 raise errors.ProgrammerError("Cannot connect twice")
416 # Check file existance/stuff
418 self.sock.connect(self.monitor_filename)
419 except EnvironmentError:
420 raise errors.HypervisorError("Can't connect to qmp socket")
421 self._connected = True
426 It cannot be used after this call.
432 class QmpConnection(MonitorSocket):
433 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
436 _FIRST_MESSAGE_KEY = "QMP"
439 _RETURN_KEY = RETURN_KEY = "return"
440 _ACTUAL_KEY = ACTUAL_KEY = "actual"
441 _ERROR_CLASS_KEY = "class"
442 _ERROR_DATA_KEY = "data"
443 _ERROR_DESC_KEY = "desc"
444 _EXECUTE_KEY = "execute"
445 _ARGUMENTS_KEY = "arguments"
446 _CAPABILITIES_COMMAND = "qmp_capabilities"
447 _MESSAGE_END_TOKEN = "\r\n"
449 def __init__(self, monitor_filename):
450 super(QmpConnection, self).__init__(monitor_filename)
454 """Connects to the QMP monitor.
456 Connects to the UNIX socket and makes sure that we can actually send and
457 receive data to the kvm instance via QMP.
459 @raise errors.HypervisorError: when there are communication errors
460 @raise errors.ProgrammerError: when there are data serialization errors
463 super(QmpConnection, self).connect()
464 # Check if we receive a correct greeting message from the server
465 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
466 greeting = self._Recv()
467 if not greeting[self._FIRST_MESSAGE_KEY]:
468 self._connected = False
469 raise errors.HypervisorError("kvm: QMP communication error (wrong"
472 # Let's put the monitor in command mode using the qmp_capabilities
473 # command, or else no command will be executable.
474 # (As per the QEMU Protocol Specification 0.1 - section 4)
475 self.Execute(self._CAPABILITIES_COMMAND)
477 def _ParseMessage(self, buf):
478 """Extract and parse a QMP message from the given buffer.
480 Seeks for a QMP message in the given buf. If found, it parses it and
481 returns it together with the rest of the characters in the buf.
482 If no message is found, returns None and the whole buffer.
484 @raise errors.ProgrammerError: when there are data serialization errors
488 # Check if we got the message end token (CRLF, as per the QEMU Protocol
489 # Specification 0.1 - Section 2.1.1)
490 pos = buf.find(self._MESSAGE_END_TOKEN)
493 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
494 except Exception, err:
495 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
498 return (message, buf)
501 """Receives a message from QMP and decodes the received JSON object.
504 @return: the received message
505 @raise errors.HypervisorError: when there are communication errors
506 @raise errors.ProgrammerError: when there are data serialization errors
509 self._check_connection()
511 # Check if there is already a message in the buffer
512 (message, self._buf) = self._ParseMessage(self._buf)
516 recv_buffer = StringIO.StringIO(self._buf)
517 recv_buffer.seek(len(self._buf))
520 data = self.sock.recv(4096)
523 recv_buffer.write(data)
525 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
529 except socket.timeout, err:
530 raise errors.HypervisorError("Timeout while receiving a QMP message: "
532 except socket.error, err:
533 raise errors.HypervisorError("Unable to receive data from KVM using the"
534 " QMP protocol: %s" % err)
536 def _Send(self, message):
537 """Encodes and sends a message to KVM using QMP.
539 @type message: QmpMessage
540 @param message: message to send to KVM
541 @raise errors.HypervisorError: when there are communication errors
542 @raise errors.ProgrammerError: when there are data serialization errors
545 self._check_connection()
547 message_str = str(message)
548 except Exception, err:
549 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
552 self.sock.sendall(message_str)
553 except socket.timeout, err:
554 raise errors.HypervisorError("Timeout while sending a QMP message: "
555 "%s (%s)" % (err.string, err.errno))
556 except socket.error, err:
557 raise errors.HypervisorError("Unable to send data from KVM using the"
558 " QMP protocol: %s" % err)
560 def Execute(self, command, arguments=None):
561 """Executes a QMP command and returns the response of the server.
564 @param command: the command to execute
565 @type arguments: dict
566 @param arguments: dictionary of arguments to be passed to the command
568 @return: dictionary representing the received JSON object
569 @raise errors.HypervisorError: when there are communication errors
570 @raise errors.ProgrammerError: when there are data serialization errors
573 self._check_connection()
574 message = QmpMessage({self._EXECUTE_KEY: command})
576 message[self._ARGUMENTS_KEY] = arguments
579 # Events can occur between the sending of the command and the reception
580 # of the response, so we need to filter out messages with the event key.
582 response = self._Recv()
583 err = response[self._ERROR_KEY]
585 raise errors.HypervisorError("kvm: error executing the %s"
586 " command: %s (%s, %s):" %
588 err[self._ERROR_DESC_KEY],
589 err[self._ERROR_CLASS_KEY],
590 err[self._ERROR_DATA_KEY]))
592 elif not response[self._EVENT_KEY]:
596 class KVMHypervisor(hv_base.BaseHypervisor):
597 """KVM hypervisor interface
602 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
603 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
604 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
605 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
606 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
607 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
608 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
609 # KVM instances with chroot enabled are started in empty chroot directories.
610 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
611 # After an instance is stopped, its chroot directory is removed.
612 # If the chroot directory is not empty, it can't be removed.
613 # A non-empty chroot directory indicates a possible security incident.
614 # To support forensics, the non-empty chroot directory is quarantined in
615 # a separate directory, called 'chroot-quarantine'.
616 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
617 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
618 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
621 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
622 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
623 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
624 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
625 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
626 constants.HV_ACPI: hv_base.NO_CHECK,
627 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
628 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
629 constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
630 constants.HV_VNC_TLS: hv_base.NO_CHECK,
631 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
632 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
633 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
634 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
635 constants.HV_KVM_SPICE_IP_VERSION:
636 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
637 x in constants.VALID_IP_VERSIONS),
638 "The SPICE IP version should be 4 or 6",
640 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
641 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
643 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
644 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
646 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
647 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
649 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
650 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
652 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
653 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
654 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
655 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
656 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
657 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
658 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
659 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
660 constants.HV_BOOT_ORDER:
661 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
662 constants.HV_NIC_TYPE:
663 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
664 constants.HV_DISK_TYPE:
665 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
666 constants.HV_KVM_CDROM_DISK_TYPE:
667 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
668 constants.HV_USB_MOUSE:
669 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
670 constants.HV_KEYMAP: hv_base.NO_CHECK,
671 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
672 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
673 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
674 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
675 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
676 constants.HV_DISK_CACHE:
677 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
678 constants.HV_SECURITY_MODEL:
679 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
680 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
681 constants.HV_KVM_FLAG:
682 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
683 constants.HV_VHOST_NET: hv_base.NO_CHECK,
684 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
685 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
686 constants.HV_REBOOT_BEHAVIOR:
687 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
688 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
689 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
690 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
691 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
692 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
693 constants.HV_SOUNDHW: hv_base.NO_CHECK,
694 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
695 constants.HV_VGA: hv_base.NO_CHECK,
696 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
697 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
698 constants.HV_VNET_HDR: hv_base.NO_CHECK,
702 _VIRTIO_NET_PCI = "virtio-net-pci"
703 _VIRTIO_BLK_PCI = "virtio-blk-pci"
705 _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)",
707 _MIGRATION_PROGRESS_RE = \
708 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
709 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
710 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
712 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
713 _MIGRATION_INFO_RETRY_DELAY = 2
715 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
717 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
718 _CPU_INFO_CMD = "info cpus"
721 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
722 _CHECK_MACHINE_VERSION_RE = \
723 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
725 _QMP_RE = re.compile(r"^-qmp\s", re.M)
726 _SPICE_RE = re.compile(r"^-spice\s", re.M)
727 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
728 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
729 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
730 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
731 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
732 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
733 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
734 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
735 # match -drive.*boot=on|off on different lines, but in between accept only
736 # dashes not preceeded by a new line (which would mean another option
737 # different than -drive is starting)
738 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
739 _UUID_RE = re.compile(r"^-uuid\s", re.M)
741 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
742 _INFO_PCI_CMD = "info pci"
744 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
745 _INFO_VERSION_CMD = "info version"
747 _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
752 ANCILLARY_FILES_OPT = [
756 # Supported kvm options to get output from
757 _KVMOPT_HELP = "help"
758 _KVMOPT_MLIST = "mlist"
759 _KVMOPT_DEVICELIST = "devicelist"
761 # Command to execute to get the output from kvm, and whether to
762 # accept the output even on failure.
764 _KVMOPT_HELP: (["--help"], False),
765 _KVMOPT_MLIST: (["-M", "?"], False),
766 _KVMOPT_DEVICELIST: (["-device", "?"], True),
770 hv_base.BaseHypervisor.__init__(self)
771 # Let's make sure the directories we need exist, even if the RUN_DIR lives
772 # in a tmpfs filesystem or has been otherwise wiped out.
773 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
774 utils.EnsureDirs(dirs)
777 def _InstancePidFile(cls, instance_name):
778 """Returns the instance pidfile.
781 return utils.PathJoin(cls._PIDS_DIR, instance_name)
784 def _InstanceUidFile(cls, instance_name):
785 """Returns the instance uidfile.
788 return utils.PathJoin(cls._UIDS_DIR, instance_name)
791 def _InstancePidInfo(cls, pid):
792 """Check pid file for instance information.
794 Check that a pid file is associated with an instance, and retrieve
795 information from its command line.
797 @type pid: string or int
798 @param pid: process id of the instance to check
800 @return: (instance_name, memory, vcpus)
801 @raise errors.HypervisorError: when an instance cannot be found
804 alive = utils.IsProcessAlive(pid)
806 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
808 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
810 cmdline = utils.ReadFile(cmdline_file)
811 except EnvironmentError, err:
812 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
819 arg_list = cmdline.split("\x00")
821 arg = arg_list.pop(0)
823 instance = arg_list.pop(0)
825 memory = int(arg_list.pop(0))
827 vcpus = int(arg_list.pop(0).split(",")[0])
830 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
833 return (instance, memory, vcpus)
835 def _InstancePidAlive(self, instance_name):
836 """Returns the instance pidfile, pid, and liveness.
838 @type instance_name: string
839 @param instance_name: instance name
841 @return: (pid file name, pid, liveness)
844 pidfile = self._InstancePidFile(instance_name)
845 pid = utils.ReadPidFile(pidfile)
849 cmd_instance = self._InstancePidInfo(pid)[0]
850 alive = (cmd_instance == instance_name)
851 except errors.HypervisorError:
854 return (pidfile, pid, alive)
856 def _CheckDown(self, instance_name):
857 """Raises an error unless the given instance is down.
860 alive = self._InstancePidAlive(instance_name)[2]
862 raise errors.HypervisorError("Failed to start instance %s: %s" %
863 (instance_name, "already running"))
866 def _InstanceMonitor(cls, instance_name):
867 """Returns the instance monitor socket name
870 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
873 def _InstanceSerial(cls, instance_name):
874 """Returns the instance serial socket name
877 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
880 def _InstanceQmpMonitor(cls, instance_name):
881 """Returns the instance serial QMP socket name
884 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
887 def _SocatUnixConsoleParams():
888 """Returns the correct parameters for socat
890 If we have a new-enough socat we can use raw mode with an escape character.
893 if constants.SOCAT_USE_ESCAPE:
894 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
896 return "echo=0,icanon=0"
899 def _InstanceKVMRuntime(cls, instance_name):
900 """Returns the instance KVM runtime filename
903 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
906 def _InstanceChrootDir(cls, instance_name):
907 """Returns the name of the KVM chroot dir of the instance
910 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
913 def _InstanceNICDir(cls, instance_name):
914 """Returns the name of the directory holding the tap device files for a
918 return utils.PathJoin(cls._NICS_DIR, instance_name)
921 def _InstanceNICFile(cls, instance_name, seq):
922 """Returns the name of the file containing the tap device for a given NIC
925 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
928 def _InstanceKeymapFile(cls, instance_name):
929 """Returns the name of the file containing the keymap for a given instance
932 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
935 def _TryReadUidFile(cls, uid_file):
936 """Try to read a uid file
939 if os.path.exists(uid_file):
941 uid = int(utils.ReadOneLineFile(uid_file))
943 except EnvironmentError:
944 logging.warning("Can't read uid file", exc_info=True)
945 except (TypeError, ValueError):
946 logging.warning("Can't parse uid file contents", exc_info=True)
950 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
951 """Removes an instance's rutime sockets/files/dirs.
954 utils.RemoveFile(pidfile)
955 utils.RemoveFile(cls._InstanceMonitor(instance_name))
956 utils.RemoveFile(cls._InstanceSerial(instance_name))
957 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
958 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
959 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
960 uid_file = cls._InstanceUidFile(instance_name)
961 uid = cls._TryReadUidFile(uid_file)
962 utils.RemoveFile(uid_file)
964 uidpool.ReleaseUid(uid)
966 shutil.rmtree(cls._InstanceNICDir(instance_name))
968 if err.errno != errno.ENOENT:
971 chroot_dir = cls._InstanceChrootDir(instance_name)
972 utils.RemoveDir(chroot_dir)
974 if err.errno == errno.ENOTEMPTY:
975 # The chroot directory is expected to be empty, but it isn't.
976 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
979 utils.TimestampForFilename()))
980 logging.warning("The chroot directory of instance %s can not be"
981 " removed as it is not empty. Moving it to the"
982 " quarantine instead. Please investigate the"
983 " contents (%s) and clean up manually",
984 instance_name, new_chroot_dir)
985 utils.RenameFile(chroot_dir, new_chroot_dir)
990 def _ConfigureNIC(instance, seq, nic, tap):
991 """Run the network configuration script for a specified NIC
993 @param instance: instance we're acting on
994 @type instance: instance object
995 @param seq: nic sequence number
997 @param nic: nic we're acting on
998 @type nic: nic object
999 @param tap: the host's tap interface this NIC corresponds to
1004 tags = " ".join(instance.tags)
1009 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
1010 "INSTANCE": instance.name,
1012 "MODE": nic.nicparams[constants.NIC_MODE],
1014 "INTERFACE_INDEX": str(seq),
1021 if nic.nicparams[constants.NIC_LINK]:
1022 env["LINK"] = nic.nicparams[constants.NIC_LINK]
1025 n = objects.Network.FromDict(nic.netinfo)
1026 env.update(n.HooksDict())
1028 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1029 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
1031 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
1033 raise errors.HypervisorError("Failed to configure interface %s: %s;"
1034 " network configuration script output: %s" %
1035 (tap, result.fail_reason, result.output))
1038 def _VerifyAffinityPackage():
1039 if affinity is None:
1040 raise errors.HypervisorError("affinity Python package not"
1041 " found; cannot use CPU pinning under KVM")
1044 def _BuildAffinityCpuMask(cpu_list):
1045 """Create a CPU mask suitable for sched_setaffinity from a list of
1048 See man taskset for more info on sched_setaffinity masks.
1049 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
1051 @type cpu_list: list of int
1052 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
1054 @return: a bit mask of CPU affinities
1057 if cpu_list == constants.CPU_PINNING_OFF:
1058 return constants.CPU_PINNING_ALL_KVM
1060 return sum(2 ** cpu for cpu in cpu_list)
1063 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
1064 """Change CPU affinity for running VM according to given CPU mask.
1066 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
1067 @type cpu_mask: string
1068 @param process_id: process ID of KVM process. Used to pin entire VM
1070 @type process_id: int
1071 @param thread_dict: map of virtual CPUs to KVM thread IDs
1072 @type thread_dict: dict int:int
1075 # Convert the string CPU mask to a list of list of int's
1076 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
1078 if len(cpu_list) == 1:
1079 all_cpu_mapping = cpu_list[0]
1080 if all_cpu_mapping == constants.CPU_PINNING_OFF:
1081 # If CPU pinning has 1 entry that's "all", then do nothing
1084 # If CPU pinning has one non-all entry, map the entire VM to
1085 # one set of physical CPUs
1086 cls._VerifyAffinityPackage()
1087 affinity.set_process_affinity_mask(
1088 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
1090 # The number of vCPUs mapped should match the number of vCPUs
1091 # reported by KVM. This was already verified earlier, so
1092 # here only as a sanity check.
1093 assert len(thread_dict) == len(cpu_list)
1094 cls._VerifyAffinityPackage()
1096 # For each vCPU, map it to the proper list of physical CPUs
1097 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1098 affinity.set_process_affinity_mask(thread_dict[i],
1099 cls._BuildAffinityCpuMask(vcpu))
1101 def _GetVcpuThreadIds(self, instance_name):
1102 """Get a mapping of vCPU no. to thread IDs for the instance
1104 @type instance_name: string
1105 @param instance_name: instance in question
1106 @rtype: dictionary of int:int
1107 @return: a dictionary mapping vCPU numbers to thread IDs
1111 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1112 for line in output.stdout.splitlines():
1113 match = self._CPU_INFO_RE.search(line)
1116 grp = map(int, match.groups())
1117 result[grp[0]] = grp[1]
1121 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1122 """Complete CPU pinning.
1124 @type instance_name: string
1125 @param instance_name: name of instance
1126 @type cpu_mask: string
1127 @param cpu_mask: CPU pinning mask as entered by user
1130 # Get KVM process ID, to be used if need to pin entire VM
1131 _, pid, _ = self._InstancePidAlive(instance_name)
1132 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1133 thread_dict = self._GetVcpuThreadIds(instance_name)
1134 # Run CPU pinning, based on configured mask
1135 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1137 def ListInstances(self, hvparams=None):
1138 """Get the list of running instances.
1140 We can do this by listing our live instances directory and
1141 checking whether the associated kvm process is still alive.
1145 for name in os.listdir(self._PIDS_DIR):
1146 if self._InstancePidAlive(name)[2]:
1150 def GetInstanceInfo(self, instance_name, hvparams=None):
1151 """Get instance properties.
1153 @type instance_name: string
1154 @param instance_name: the instance name
1155 @type hvparams: dict of strings
1156 @param hvparams: hvparams to be used with this instance
1157 @rtype: tuple of strings
1158 @return: (name, id, memory, vcpus, stat, times)
1161 _, pid, alive = self._InstancePidAlive(instance_name)
1165 _, memory, vcpus = self._InstancePidInfo(pid)
1170 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1172 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1173 # Will fail if ballooning is not enabled, but we can then just resort to
1175 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1176 memory = mem_bytes / 1048576
1177 except errors.HypervisorError:
1180 return (instance_name, pid, memory, vcpus, istat, times)
1182 def GetAllInstancesInfo(self, hvparams=None):
1183 """Get properties of all instances.
1185 @type hvparams: dict of strings
1186 @param hvparams: hypervisor parameter
1187 @return: list of tuples (name, id, memory, vcpus, stat, times)
1191 for name in os.listdir(self._PIDS_DIR):
1193 info = self.GetInstanceInfo(name)
1194 except errors.HypervisorError:
1195 # Ignore exceptions due to instances being shut down
1201 def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
1203 """Generate KVM options regarding instance's block devices.
1205 @type instance: L{objects.Instance}
1206 @param instance: the instance object
1207 @type kvm_disks: list of tuples
1208 @param kvm_disks: list of tuples [(disk, link_name, uri)..]
1209 @type kvmhelp: string
1210 @param kvmhelp: output of kvm --help
1211 @type devlist: string
1212 @param devlist: output of kvm -device ?
1214 @return: list of command line options eventually used by kvm executable
1217 hvp = instance.hvparams
1218 kernel_path = hvp[constants.HV_KERNEL_PATH]
1222 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1224 # whether this is an older KVM version that uses the boot=on flag
1226 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1229 device_driver = None
1230 disk_type = hvp[constants.HV_DISK_TYPE]
1231 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1232 if_val = ",if=%s" % self._VIRTIO
1234 if self._VIRTIO_BLK_RE.search(devlist):
1236 # will be passed in -device option as driver
1237 device_driver = self._VIRTIO_BLK_PCI
1238 except errors.HypervisorError, _:
1241 if_val = ",if=%s" % disk_type
1243 disk_cache = hvp[constants.HV_DISK_CACHE]
1244 if instance.disk_template in constants.DTS_EXT_MIRROR:
1245 if disk_cache != "none":
1246 # TODO: make this a hard error, instead of a silent overwrite
1247 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1248 " to prevent shared storage corruption on migration",
1250 cache_val = ",cache=none"
1251 elif disk_cache != constants.HT_CACHE_DEFAULT:
1252 cache_val = ",cache=%s" % disk_cache
1255 for cfdev, link_name, uri in kvm_disks:
1256 if cfdev.mode != constants.DISK_RDWR:
1257 raise errors.HypervisorError("Instance has read-only disks which"
1258 " are not supported by KVM")
1259 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1262 dev_opts.extend(["-boot", "c"])
1264 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1265 boot_val = ",boot=on"
1267 access_mode = cfdev.params.get(constants.LDP_ACCESS,
1268 constants.DISK_KERNELSPACE)
1269 if (uri and access_mode == constants.DISK_USERSPACE):
1272 drive_uri = link_name
1274 drive_val = "file=%s,format=raw%s%s%s" % \
1275 (drive_uri, if_val, boot_val, cache_val)
1278 # kvm_disks are the 4th entry of runtime file that did not exist in
1279 # the past. That means that cfdev should always have pci slot and
1280 # _GenerateDeviceKVMId() will not raise a exception.
1281 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
1282 drive_val += (",id=%s" % kvm_devid)
1283 drive_val += (",bus=0,unit=%d" % cfdev.pci)
1284 dev_val = ("%s,drive=%s,id=%s" %
1285 (device_driver, kvm_devid, kvm_devid))
1286 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci)
1287 dev_opts.extend(["-device", dev_val])
1289 dev_opts.extend(["-drive", drive_val])
1293 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1295 """Generate KVM information to start an instance.
1297 @type kvmhelp: string
1298 @param kvmhelp: output of kvm --help
1299 @attention: this function must not have any side-effects; for
1300 example, it must not write to the filesystem, or read values
1301 from the current system the are expected to differ between
1302 nodes, since it is only run once at instance startup;
1303 actions/kvm arguments that can vary between systems should be
1304 done in L{_ExecuteKVMRuntime}
1307 # pylint: disable=R0912,R0914,R0915
1308 hvp = instance.hvparams
1309 self.ValidateParameters(hvp)
1311 pidfile = self._InstancePidFile(instance.name)
1312 kvm = hvp[constants.HV_KVM_PATH]
1314 # used just by the vnc server, if enabled
1315 kvm_cmd.extend(["-name", instance.name])
1316 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1318 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1319 if hvp[constants.HV_CPU_CORES]:
1320 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1321 if hvp[constants.HV_CPU_THREADS]:
1322 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1323 if hvp[constants.HV_CPU_SOCKETS]:
1324 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1326 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1328 kvm_cmd.extend(["-pidfile", pidfile])
1329 kvm_cmd.extend(["-balloon", "virtio"])
1330 kvm_cmd.extend(["-daemonize"])
1331 if not instance.hvparams[constants.HV_ACPI]:
1332 kvm_cmd.extend(["-no-acpi"])
1333 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1334 constants.INSTANCE_REBOOT_EXIT:
1335 kvm_cmd.extend(["-no-reboot"])
1337 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1339 mversion = self._GetDefaultMachineVersion(kvm)
1340 if self._MACHINE_RE.search(kvmhelp):
1341 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1342 # extra hypervisor parameters. We should also investigate whether and how
1343 # shadow_mem should be considered for the resource model.
1344 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1345 specprop = ",accel=kvm"
1348 machinespec = "%s%s" % (mversion, specprop)
1349 kvm_cmd.extend(["-machine", machinespec])
1351 kvm_cmd.extend(["-M", mversion])
1352 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1353 self._ENABLE_KVM_RE.search(kvmhelp)):
1354 kvm_cmd.extend(["-enable-kvm"])
1355 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1356 self._DISABLE_KVM_RE.search(kvmhelp)):
1357 kvm_cmd.extend(["-disable-kvm"])
1359 kernel_path = hvp[constants.HV_KERNEL_PATH]
1361 boot_cdrom = boot_floppy = boot_network = False
1363 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1364 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1365 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1368 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1371 kvm_cmd.extend(["-boot", "n"])
1373 # whether this is an older KVM version that uses the boot=on flag
1375 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1377 disk_type = hvp[constants.HV_DISK_TYPE]
1379 #Now we can specify a different device type for CDROM devices.
1380 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1381 if not cdrom_disk_type:
1382 cdrom_disk_type = disk_type
1384 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1386 options = ",format=raw,media=cdrom"
1387 # set cdrom 'if' type
1389 actual_cdrom_type = constants.HT_DISK_IDE
1390 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1391 actual_cdrom_type = "virtio"
1393 actual_cdrom_type = cdrom_disk_type
1394 if_val = ",if=%s" % actual_cdrom_type
1395 # set boot flag, if needed
1398 kvm_cmd.extend(["-boot", "d"])
1400 boot_val = ",boot=on"
1401 # and finally build the entire '-drive' value
1402 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1403 kvm_cmd.extend(["-drive", drive_val])
1405 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1407 options = ",format=raw,media=cdrom"
1408 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1409 if_val = ",if=virtio"
1411 if_val = ",if=%s" % cdrom_disk_type
1412 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1413 kvm_cmd.extend(["-drive", drive_val])
1415 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1417 options = ",format=raw,media=disk"
1419 kvm_cmd.extend(["-boot", "a"])
1420 options = "%s,boot=on" % options
1421 if_val = ",if=floppy"
1422 options = "%s%s" % (options, if_val)
1423 drive_val = "file=%s%s" % (floppy_image, options)
1424 kvm_cmd.extend(["-drive", drive_val])
1427 kvm_cmd.extend(["-kernel", kernel_path])
1428 initrd_path = hvp[constants.HV_INITRD_PATH]
1430 kvm_cmd.extend(["-initrd", initrd_path])
1431 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1432 hvp[constants.HV_KERNEL_ARGS]]
1433 if hvp[constants.HV_SERIAL_CONSOLE]:
1434 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1435 root_append.append("console=ttyS0,%s" % serial_speed)
1436 kvm_cmd.extend(["-append", " ".join(root_append)])
1438 mem_path = hvp[constants.HV_MEM_PATH]
1440 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1442 monitor_dev = ("unix:%s,server,nowait" %
1443 self._InstanceMonitor(instance.name))
1444 kvm_cmd.extend(["-monitor", monitor_dev])
1445 if hvp[constants.HV_SERIAL_CONSOLE]:
1446 serial_dev = ("unix:%s,server,nowait" %
1447 self._InstanceSerial(instance.name))
1448 kvm_cmd.extend(["-serial", serial_dev])
1450 kvm_cmd.extend(["-serial", "none"])
1452 mouse_type = hvp[constants.HV_USB_MOUSE]
1453 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1454 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1455 spice_ip_version = None
1457 kvm_cmd.extend(["-usb"])
1460 kvm_cmd.extend(["-usbdevice", mouse_type])
1461 elif vnc_bind_address:
1462 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1464 if vnc_bind_address:
1465 if netutils.IsValidInterface(vnc_bind_address):
1466 if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1467 if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1468 if len(if_ip4_addresses) < 1:
1469 logging.error("Could not determine IPv4 address of interface %s",
1472 vnc_bind_address = if_ip4_addresses[0]
1473 if netutils.IP4Address.IsValid(vnc_bind_address):
1474 if instance.network_port > constants.VNC_BASE_PORT:
1475 display = instance.network_port - constants.VNC_BASE_PORT
1476 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1477 vnc_arg = ":%d" % (display)
1479 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1481 logging.error("Network port is not a valid VNC display (%d < %d),"
1482 " not starting VNC",
1483 instance.network_port, constants.VNC_BASE_PORT)
1486 # Only allow tls and other option when not binding to a file, for now.
1487 # kvm/qemu gets confused otherwise about the filename to use.
1489 if hvp[constants.HV_VNC_TLS]:
1490 vnc_append = "%s,tls" % vnc_append
1491 if hvp[constants.HV_VNC_X509_VERIFY]:
1492 vnc_append = "%s,x509verify=%s" % (vnc_append,
1493 hvp[constants.HV_VNC_X509])
1494 elif hvp[constants.HV_VNC_X509]:
1495 vnc_append = "%s,x509=%s" % (vnc_append,
1496 hvp[constants.HV_VNC_X509])
1497 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1498 vnc_append = "%s,password" % vnc_append
1500 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1503 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1505 kvm_cmd.extend(["-vnc", vnc_arg])
1507 # FIXME: this is wrong here; the iface ip address differs
1508 # between systems, so it should be done in _ExecuteKVMRuntime
1509 if netutils.IsValidInterface(spice_bind):
1510 # The user specified a network interface, we have to figure out the IP
1512 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1513 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1515 # if the user specified an IP version and the interface does not
1516 # have that kind of IP addresses, throw an exception
1517 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1518 if not addresses[spice_ip_version]:
1519 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1520 " for %s" % (spice_ip_version,
1523 # the user did not specify an IP version, we have to figure it out
1524 elif (addresses[constants.IP4_VERSION] and
1525 addresses[constants.IP6_VERSION]):
1526 # we have both ipv4 and ipv6, let's use the cluster default IP
1528 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1529 spice_ip_version = \
1530 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1531 elif addresses[constants.IP4_VERSION]:
1532 spice_ip_version = constants.IP4_VERSION
1533 elif addresses[constants.IP6_VERSION]:
1534 spice_ip_version = constants.IP6_VERSION
1536 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1537 " for %s" % (spice_bind))
1539 spice_address = addresses[spice_ip_version][0]
1542 # spice_bind is known to be a valid IP address, because
1543 # ValidateParameters checked it.
1544 spice_address = spice_bind
1546 spice_arg = "addr=%s" % spice_address
1547 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1548 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1549 (spice_arg, instance.network_port,
1550 pathutils.SPICE_CACERT_FILE))
1551 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1552 (spice_arg, pathutils.SPICE_CERT_FILE,
1553 pathutils.SPICE_CERT_FILE))
1554 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1556 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1558 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1560 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1561 spice_arg = "%s,disable-ticketing" % spice_arg
1563 if spice_ip_version:
1564 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1566 # Image compression options
1567 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1568 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1569 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1571 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1573 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1575 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1577 # Video stream detection
1578 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1580 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1582 # Audio compression, by default in qemu-kvm it is on
1583 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1584 spice_arg = "%s,playback-compression=off" % spice_arg
1585 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1586 spice_arg = "%s,agent-mouse=off" % spice_arg
1588 # Enable the spice agent communication channel between the host and the
1590 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1593 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1595 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1597 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1598 kvm_cmd.extend(["-spice", spice_arg])
1601 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1602 # also works in earlier versions though (tested with 1.1 and 1.3)
1603 if self._DISPLAY_RE.search(kvmhelp):
1604 kvm_cmd.extend(["-display", "none"])
1606 kvm_cmd.extend(["-nographic"])
1608 if hvp[constants.HV_USE_LOCALTIME]:
1609 kvm_cmd.extend(["-localtime"])
1611 if hvp[constants.HV_KVM_USE_CHROOT]:
1612 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1614 # Add qemu-KVM -cpu param
1615 if hvp[constants.HV_CPU_TYPE]:
1616 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1618 # As requested by music lovers
1619 if hvp[constants.HV_SOUNDHW]:
1620 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1622 # Pass a -vga option if requested, or if spice is used, for backwards
1624 if hvp[constants.HV_VGA]:
1625 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1627 kvm_cmd.extend(["-vga", "qxl"])
1629 # Various types of usb devices, comma separated
1630 if hvp[constants.HV_USB_DEVICES]:
1631 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1632 kvm_cmd.extend(["-usbdevice", dev])
1634 # Set system UUID to instance UUID
1635 if self._UUID_RE.search(kvmhelp):
1636 kvm_cmd.extend(["-uuid", instance.uuid])
1638 if hvp[constants.HV_KVM_EXTRA]:
1639 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1641 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
1643 for disk, link_name, uri in block_devices:
1644 _UpdatePCISlots(disk, pci_reservations)
1645 kvm_disks.append((disk, link_name, uri))
1648 for nic in instance.nics:
1649 _UpdatePCISlots(nic, pci_reservations)
1650 kvm_nics.append(nic)
1654 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1656 def _WriteKVMRuntime(self, instance_name, data):
1657 """Write an instance's KVM runtime
1661 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1663 except EnvironmentError, err:
1664 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1666 def _ReadKVMRuntime(self, instance_name):
1667 """Read an instance's KVM runtime
1671 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1672 except EnvironmentError, err:
1673 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1676 def _SaveKVMRuntime(self, instance, kvm_runtime):
1677 """Save an instance's KVM runtime
1680 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
1682 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1683 serialized_disks = [(blk.ToDict(), link, uri)
1684 for blk, link, uri in kvm_disks]
1685 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1688 self._WriteKVMRuntime(instance.name, serialized_form)
1690 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1691 """Load an instance's KVM runtime
1694 if not serialized_runtime:
1695 serialized_runtime = self._ReadKVMRuntime(instance.name)
1697 return _AnalyzeSerializedRuntime(serialized_runtime)
1699 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1700 """Run the KVM cmd and check for errors
1703 @param name: instance name
1704 @type kvm_cmd: list of strings
1705 @param kvm_cmd: runcmd input for kvm
1706 @type tap_fds: list of int
1707 @param tap_fds: fds of tap devices opened by Ganeti
1711 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1714 utils_wrapper.CloseFdNoError(fd)
1717 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1718 (name, result.fail_reason, result.output))
1719 if not self._InstancePidAlive(name)[2]:
1720 raise errors.HypervisorError("Failed to start instance %s" % name)
1722 # too many local variables
1723 # pylint: disable=R0914
1724 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1725 """Execute a KVM cmd, after completing it with some last minute data.
1727 @type incoming: tuple of strings
1728 @param incoming: (target_host_ip, port)
1729 @type kvmhelp: string
1730 @param kvmhelp: output of kvm --help
1733 # Small _ExecuteKVMRuntime hv parameters programming howto:
1734 # - conf_hvp contains the parameters as configured on ganeti. they might
1735 # have changed since the instance started; only use them if the change
1736 # won't affect the inside of the instance (which hasn't been rebooted).
1737 # - up_hvp contains the parameters as they were when the instance was
1738 # started, plus any new parameter which has been added between ganeti
1739 # versions: it is paramount that those default to a value which won't
1740 # affect the inside of the instance as well.
1741 conf_hvp = instance.hvparams
1742 name = instance.name
1743 self._CheckDown(name)
1747 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
1748 # the first element of kvm_cmd is always the path to the kvm binary
1749 kvm_path = kvm_cmd[0]
1750 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1752 # We know it's safe to run as a different user upon migration, so we'll use
1753 # the latest conf, from conf_hvp.
1754 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1755 if security_model == constants.HT_SM_USER:
1756 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1758 keymap = conf_hvp[constants.HV_KEYMAP]
1760 keymap_path = self._InstanceKeymapFile(name)
1761 # If a keymap file is specified, KVM won't use its internal defaults. By
1762 # first including the "en-us" layout, an error on loading the actual
1763 # layout (e.g. because it can't be found) won't lead to a non-functional
1764 # keyboard. A keyboard with incorrect keys is still better than none.
1765 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1766 kvm_cmd.extend(["-k", keymap_path])
1768 # We have reasons to believe changing something like the nic driver/type
1769 # upon migration won't exactly fly with the instance kernel, so for nic
1770 # related parameters we'll use up_hvp
1773 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1775 kvm_cmd.extend(["-net", "none"])
1779 nic_type = up_hvp[constants.HV_NIC_TYPE]
1780 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1781 nic_model = self._VIRTIO
1783 if self._VIRTIO_NET_RE.search(devlist):
1784 nic_model = self._VIRTIO_NET_PCI
1785 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1786 except errors.HypervisorError, _:
1787 # Older versions of kvm don't support DEVICE_LIST, but they don't
1788 # have new virtio syntax either.
1791 if up_hvp[constants.HV_VHOST_NET]:
1792 # check for vhost_net support
1793 if self._VHOST_RE.search(kvmhelp):
1794 tap_extra = ",vhost=on"
1796 raise errors.HypervisorError("vhost_net is configured"
1797 " but it is not available")
1799 nic_model = nic_type
1801 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1803 for nic_seq, nic in enumerate(kvm_nics):
1804 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1805 tapfds.append(tapfd)
1806 taps.append(tapname)
1807 if kvm_supports_netdev:
1808 nic_val = "%s,mac=%s" % (nic_model, nic.mac)
1810 # kvm_nics already exist in old runtime files and thus there might
1811 # be some entries without pci slot (therefore try: except:)
1812 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
1814 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci)))
1815 except errors.HotplugError:
1816 netdev = "netdev%d" % nic_seq
1817 nic_val += (",netdev=%s" % netdev)
1818 tap_val = ("type=tap,id=%s,fd=%d%s" %
1819 (netdev, tapfd, tap_extra))
1820 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1822 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1824 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1825 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1828 target, port = incoming
1829 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1831 # Changing the vnc password doesn't bother the guest that much. At most it
1832 # will surprise people who connect to it. Whether positively or negatively
1834 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1838 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1839 except EnvironmentError, err:
1840 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1841 % (vnc_pwd_file, err))
1843 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1844 utils.EnsureDirs([(self._InstanceChrootDir(name),
1845 constants.SECURE_DIR_MODE)])
1847 # Automatically enable QMP if version is >= 0.14
1848 if self._QMP_RE.search(kvmhelp):
1849 logging.debug("Enabling QMP")
1850 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1851 self._InstanceQmpMonitor(instance.name)])
1853 # Configure the network now for starting instances and bridged interfaces,
1854 # during FinalizeMigration for incoming instances' routed interfaces
1855 for nic_seq, nic in enumerate(kvm_nics):
1857 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1859 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1861 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1865 kvm_cmd.extend(bdev_opts)
1866 # CPU affinity requires kvm to start paused, so we set this flag if the
1867 # instance is not already paused and if we are not going to accept a
1868 # migrating instance. In the latter case, pausing is not needed.
1869 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1870 if start_kvm_paused:
1871 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1873 # Note: CPU pinning is using up_hvp since changes take effect
1874 # during instance startup anyway, and to avoid problems when soft
1875 # rebooting the instance.
1877 if up_hvp.get(constants.HV_CPU_MASK, None):
1880 if security_model == constants.HT_SM_POOL:
1881 ss = ssconf.SimpleStore()
1882 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1883 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1884 uid = uidpool.RequestUnusedUid(all_uids)
1886 username = pwd.getpwuid(uid.GetUid()).pw_name
1887 kvm_cmd.extend(["-runas", username])
1888 self._RunKVMCmd(name, kvm_cmd, tapfds)
1890 uidpool.ReleaseUid(uid)
1894 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1896 self._RunKVMCmd(name, kvm_cmd, tapfds)
1898 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1899 constants.RUN_DIRS_MODE)])
1900 for nic_seq, tap in enumerate(taps):
1901 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1905 change_cmd = "change vnc password %s" % vnc_pwd
1906 self._CallMonitorCommand(instance.name, change_cmd)
1908 # Setting SPICE password. We are not vulnerable to malicious passwordless
1909 # connection attempts because SPICE by default does not allow connections
1910 # if neither a password nor the "disable_ticketing" options are specified.
1911 # As soon as we send the password via QMP, that password is a valid ticket
1913 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1914 if spice_password_file:
1917 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1918 except EnvironmentError, err:
1919 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1920 % (spice_password_file, err))
1922 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1925 "protocol": "spice",
1926 "password": spice_pwd,
1928 qmp.Execute("set_password", arguments)
1930 for filename in temp_files:
1931 utils.RemoveFile(filename)
1933 # If requested, set CPU affinity and resume instance execution
1935 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1937 start_memory = self._InstanceStartupMemory(instance)
1938 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1939 self.BalloonInstanceMemory(instance, start_memory)
1941 if start_kvm_paused:
1942 # To control CPU pinning, ballooning, and vnc/spice passwords
1943 # the VM was started in a frozen state. If freezing was not
1944 # explicitly requested resume the vm status.
1945 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1947 def StartInstance(self, instance, block_devices, startup_paused):
1948 """Start an instance.
1951 self._CheckDown(instance.name)
1952 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1953 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1954 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1955 startup_paused, kvmhelp)
1956 self._SaveKVMRuntime(instance, kvm_runtime)
1957 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1959 def _CallMonitorCommand(self, instance_name, command):
1960 """Invoke a command on the instance monitor.
1963 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1964 # version. The monitor protocol is designed for human consumption, whereas
1965 # QMP is made for programmatic usage. In the worst case QMP can also
1966 # execute monitor commands. As it is, all calls to socat take at least
1967 # 500ms and likely more: socat can't detect the end of the reply and waits
1968 # for 500ms of no data received before exiting (500 ms is the default for
1969 # the "-t" parameter).
1970 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1971 (utils.ShellQuote(command),
1972 constants.SOCAT_PATH,
1973 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1974 result = utils.RunCmd(socat)
1976 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1978 (command, instance_name, result.fail_reason, result.output))
1979 raise errors.HypervisorError(msg)
1983 def _GetFreePCISlot(self, instance, dev):
1984 """Get the first available pci slot of a runnung instance.
1987 slots = bitarray(32)
1988 slots.setall(False) # pylint: disable=E1101
1989 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1990 for line in output.stdout.splitlines():
1991 match = self._INFO_PCI_RE.search(line)
1993 slot = int(match.group(1))
1996 [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1998 raise errors.HypervisorError("All PCI slots occupied")
2002 def VerifyHotplugSupport(self, instance, action, dev_type):
2003 """Verifies that hotplug is supported.
2005 Hotplug is *not* supported in case of:
2006 - qemu versions < 1.0
2007 - security models and chroot (disk hotplug)
2008 - fdsend module is missing (nic hot-add)
2010 @raise errors.HypervisorError: in one of the previous cases
2013 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2014 # TODO: search for netdev_add, drive_add, device_add.....
2015 match = self._INFO_VERSION_RE.search(output.stdout)
2017 raise errors.HotplugError("Try hotplug only in running instances.")
2018 v_major, v_min, _, _ = match.groups()
2019 if (int(v_major), int(v_min)) < (1, 0):
2020 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2022 if dev_type == constants.HOTPLUG_TARGET_DISK:
2023 hvp = instance.hvparams
2024 security_model = hvp[constants.HV_SECURITY_MODEL]
2025 use_chroot = hvp[constants.HV_KVM_USE_CHROOT]
2027 raise errors.HotplugError("Disk hotplug is not supported"
2028 " in case of chroot.")
2029 if security_model != constants.HT_SM_NONE:
2030 raise errors.HotplugError("Disk Hotplug is not supported in case"
2031 " security models are used.")
2033 if (dev_type == constants.HOTPLUG_TARGET_NIC and
2034 action == constants.HOTPLUG_ACTION_ADD and not fdsend):
2035 raise errors.HotplugError("Cannot hot-add NIC."
2036 " fdsend python module is missing.")
2038 def _CallHotplugCommand(self, name, cmd):
2039 output = self._CallMonitorCommand(name, cmd)
2040 # TODO: parse output and check if succeeded
2041 for line in output.stdout.splitlines():
2042 logging.info("%s", line)
2044 def HotAddDevice(self, instance, dev_type, device, extra, seq):
2045 """ Helper method to hot-add a new device
2047 It gets free pci slot generates the device name and invokes the
2048 device specific method.
2051 # in case of hot-mod this is given
2052 if device.pci is None:
2053 self._GetFreePCISlot(instance, device)
2054 kvm_devid = _GenerateDeviceKVMId(dev_type, device)
2055 runtime = self._LoadKVMRuntime(instance)
2056 if dev_type == constants.HOTPLUG_TARGET_DISK:
2057 command = "drive_add dummy file=%s,if=none,id=%s,format=raw\n" % \
2059 command += ("device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" %
2060 (hex(device.pci), kvm_devid, kvm_devid))
2061 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2062 (tap, fd) = _OpenTap()
2063 self._ConfigureNIC(instance, seq, device, tap)
2064 self._PassTapFd(instance, fd, device)
2065 command = "netdev_add tap,id=%s,fd=%s\n" % (kvm_devid, kvm_devid)
2066 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s" % \
2067 (hex(device.pci), device.mac, kvm_devid, kvm_devid)
2068 command += "device_add %s" % args
2069 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap)
2071 self._CallHotplugCommand(instance.name, command)
2072 # update relevant entries in runtime file
2073 index = _DEVICE_RUNTIME_INDEX[dev_type]
2074 entry = _RUNTIME_ENTRY[dev_type](device, extra)
2075 runtime[index].append(entry)
2076 self._SaveKVMRuntime(instance, runtime)
2078 def HotDelDevice(self, instance, dev_type, device, _, seq):
2079 """ Helper method for hot-del device
2081 It gets device info from runtime file, generates the device name and
2082 invokes the device specific method.
2085 runtime = self._LoadKVMRuntime(instance)
2086 entry = _GetExistingDeviceInfo(dev_type, device, runtime)
2087 kvm_device = _RUNTIME_DEVICE[dev_type](entry)
2088 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
2089 if dev_type == constants.HOTPLUG_TARGET_DISK:
2090 command = "device_del %s\n" % kvm_devid
2091 command += "drive_del %s" % kvm_devid
2092 elif dev_type == constants.HOTPLUG_TARGET_NIC:
2093 command = "device_del %s\n" % kvm_devid
2094 command += "netdev_del %s" % kvm_devid
2095 utils.RemoveFile(self._InstanceNICFile(instance.name, seq))
2096 self._CallHotplugCommand(instance.name, command)
2097 index = _DEVICE_RUNTIME_INDEX[dev_type]
2098 runtime[index].remove(entry)
2099 self._SaveKVMRuntime(instance, runtime)
2101 return kvm_device.pci
2103 def HotModDevice(self, instance, dev_type, device, _, seq):
2104 """ Helper method for hot-mod device
2106 It gets device info from runtime file, generates the device name and
2107 invokes the device specific method. Currently only NICs support hot-mod
2110 if dev_type == constants.HOTPLUG_TARGET_NIC:
2111 # putting it back in the same pci slot
2112 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq)
2113 # TODO: remove sleep when socat gets removed
2115 self.HotAddDevice(instance, dev_type, device, _, seq)
2117 def _PassTapFd(self, instance, fd, nic):
2118 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS
2121 # TODO: factor out code related to unix sockets.
2122 # squash common parts between monitor and qmp
2123 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic)
2124 command = "getfd %s\n" % kvm_devid
2126 logging.info("%s", fds)
2128 monsock = MonitorSocket(self._InstanceMonitor(instance.name))
2130 fdsend.sendfds(monsock.sock, command, fds=fds)
2135 def _ParseKVMVersion(cls, text):
2136 """Parse the KVM version from the --help output.
2139 @param text: output of kvm --help
2140 @return: (version, v_maj, v_min, v_rev)
2141 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2144 match = cls._VERSION_RE.search(text.splitlines()[0])
2146 raise errors.HypervisorError("Unable to get KVM version")
2148 v_all = match.group(0)
2149 v_maj = int(match.group(1))
2150 v_min = int(match.group(2))
2152 v_rev = int(match.group(4))
2155 return (v_all, v_maj, v_min, v_rev)
2158 def _GetKVMOutput(cls, kvm_path, option):
2159 """Return the output of a kvm invocation
2161 @type kvm_path: string
2162 @param kvm_path: path to the kvm executable
2163 @type option: a key of _KVMOPTS_CMDS
2164 @param option: kvm option to fetch the output from
2165 @return: output a supported kvm invocation
2166 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
2169 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
2171 optlist, can_fail = cls._KVMOPTS_CMDS[option]
2173 result = utils.RunCmd([kvm_path] + optlist)
2174 if result.failed and not can_fail:
2175 raise errors.HypervisorError("Unable to get KVM %s output" %
2176 " ".join(cls._KVMOPTS_CMDS[option]))
2177 return result.output
2180 def _GetKVMVersion(cls, kvm_path):
2181 """Return the installed KVM version.
2183 @return: (version, v_maj, v_min, v_rev)
2184 @raise errors.HypervisorError: when the KVM version cannot be retrieved
2187 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2190 def _GetDefaultMachineVersion(cls, kvm_path):
2191 """Return the default hardware revision (e.g. pc-1.1)
2194 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2195 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
2197 return match.group(1)
2201 def StopInstance(self, instance, force=False, retry=False, name=None):
2202 """Stop an instance.
2205 if name is not None and not force:
2206 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
2208 name = instance.name
2209 acpi = instance.hvparams[constants.HV_ACPI]
2212 _, pid, alive = self._InstancePidAlive(name)
2213 if pid > 0 and alive:
2214 if force or not acpi:
2215 utils.KillProcess(pid)
2217 self._CallMonitorCommand(name, "system_powerdown")
2219 def CleanupInstance(self, instance_name):
2220 """Cleanup after a stopped instance
2223 pidfile, pid, alive = self._InstancePidAlive(instance_name)
2224 if pid > 0 and alive:
2225 raise errors.HypervisorError("Cannot cleanup a live instance")
2226 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
2228 def RebootInstance(self, instance):
2229 """Reboot an instance.
2232 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
2233 # socket the instance will stop, but now power up again. So we'll resort
2234 # to shutdown and restart.
2235 _, _, alive = self._InstancePidAlive(instance.name)
2237 raise errors.HypervisorError("Failed to reboot instance %s:"
2238 " not running" % instance.name)
2239 # StopInstance will delete the saved KVM runtime so:
2240 # ...first load it...
2241 kvm_runtime = self._LoadKVMRuntime(instance)
2242 # ...now we can safely call StopInstance...
2243 if not self.StopInstance(instance):
2244 self.StopInstance(instance, force=True)
2245 # ...and finally we can save it again, and execute it...
2246 self._SaveKVMRuntime(instance, kvm_runtime)
2247 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2248 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2249 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2251 def MigrationInfo(self, instance):
2252 """Get instance information to perform a migration.
2254 @type instance: L{objects.Instance}
2255 @param instance: instance to be migrated
2257 @return: content of the KVM runtime file
2260 return self._ReadKVMRuntime(instance.name)
2262 def AcceptInstance(self, instance, info, target):
2263 """Prepare to accept an instance.
2265 @type instance: L{objects.Instance}
2266 @param instance: instance to be accepted
2268 @param info: content of the KVM runtime file on the source node
2269 @type target: string
2270 @param target: target host (usually ip), on this node
2273 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2274 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
2275 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
2276 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
2277 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
2278 incoming=incoming_address)
2280 def FinalizeMigrationDst(self, instance, info, success):
2281 """Finalize the instance migration on the target node.
2283 Stop the incoming mode KVM.
2285 @type instance: L{objects.Instance}
2286 @param instance: instance whose migration is being finalized
2290 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
2291 kvm_nics = kvm_runtime[1]
2293 for nic_seq, nic in enumerate(kvm_nics):
2294 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
2295 # Bridged interfaces have already been configured
2298 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
2299 except EnvironmentError, err:
2300 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2301 instance.name, nic_seq, str(err))
2304 self._ConfigureNIC(instance, nic_seq, nic, tap)
2305 except errors.HypervisorError, err:
2306 logging.warning(str(err))
2308 self._WriteKVMRuntime(instance.name, info)
2310 self.StopInstance(instance, force=True)
2312 def MigrateInstance(self, cluster_name, instance, target, live):
2313 """Migrate an instance to a target node.
2315 The migration will not be attempted if the instance is not
2318 @type cluster_name: string
2319 @param cluster_name: name of the cluster
2320 @type instance: L{objects.Instance}
2321 @param instance: the instance to be migrated
2322 @type target: string
2323 @param target: ip address of the target node
2325 @param live: perform a live migration
2328 instance_name = instance.name
2329 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2330 _, _, alive = self._InstancePidAlive(instance_name)
2332 raise errors.HypervisorError("Instance not running, cannot migrate")
2335 self._CallMonitorCommand(instance_name, "stop")
2337 migrate_command = ("migrate_set_speed %dm" %
2338 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2339 self._CallMonitorCommand(instance_name, migrate_command)
2341 migrate_command = ("migrate_set_downtime %dms" %
2342 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2343 self._CallMonitorCommand(instance_name, migrate_command)
2345 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2346 self._CallMonitorCommand(instance_name, migrate_command)
2348 def FinalizeMigrationSource(self, instance, success, live):
2349 """Finalize the instance migration on the source node.
2351 @type instance: L{objects.Instance}
2352 @param instance: the instance that was migrated
2354 @param success: whether the migration succeeded or not
2356 @param live: whether the user requested a live migration or not
2360 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2361 utils.KillProcess(pid)
2362 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2364 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2366 def GetMigrationStatus(self, instance):
2367 """Get the migration status
2369 @type instance: L{objects.Instance}
2370 @param instance: the instance that is being migrated
2371 @rtype: L{objects.MigrationStatus}
2372 @return: the status of the current migration (one of
2373 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2374 progress info that can be retrieved from the hypervisor
2377 info_command = "info migrate"
2378 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2379 result = self._CallMonitorCommand(instance.name, info_command)
2380 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2382 if not result.stdout:
2383 logging.info("KVM: empty 'info migrate' result")
2385 logging.warning("KVM: unknown 'info migrate' result: %s",
2388 status = match.group(1)
2389 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2390 migration_status = objects.MigrationStatus(status=status)
2391 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2393 migration_status.transferred_ram = match.group("transferred")
2394 migration_status.total_ram = match.group("total")
2396 return migration_status
2398 logging.warning("KVM: unknown migration status '%s'", status)
2400 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2402 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2404 def BalloonInstanceMemory(self, instance, mem):
2405 """Balloon an instance memory to a certain value.
2407 @type instance: L{objects.Instance}
2408 @param instance: instance to be accepted
2410 @param mem: actual memory size to use for instance runtime
2413 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2415 def GetNodeInfo(self, hvparams=None):
2416 """Return information about the node.
2418 @type hvparams: dict of strings
2419 @param hvparams: hypervisor parameters, not used in this class
2421 @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2423 - hv_version: the hypervisor version in the form (major, minor,
2427 result = self.GetLinuxNodeInfo()
2428 # FIXME: this is the global kvm version, but the actual version can be
2429 # customized as an hv parameter. we should use the nodegroup's default kvm
2430 # path parameter here.
2431 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2432 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2436 def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2437 """Return a command for connecting to the console of an instance.
2440 if hvparams[constants.HV_SERIAL_CONSOLE]:
2441 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2442 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2443 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2444 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2445 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2446 return objects.InstanceConsole(instance=instance.name,
2447 kind=constants.CONS_SSH,
2448 host=primary_node.name,
2449 user=constants.SSH_CONSOLE_USER,
2452 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2453 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2454 display = instance.network_port - constants.VNC_BASE_PORT
2455 return objects.InstanceConsole(instance=instance.name,
2456 kind=constants.CONS_VNC,
2457 host=vnc_bind_address,
2458 port=instance.network_port,
2461 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2463 return objects.InstanceConsole(instance=instance.name,
2464 kind=constants.CONS_SPICE,
2466 port=instance.network_port)
2468 return objects.InstanceConsole(instance=instance.name,
2469 kind=constants.CONS_MESSAGE,
2470 message=("No serial shell for instance %s" %
2473 def Verify(self, hvparams=None):
2474 """Verify the hypervisor.
2476 Check that the required binaries exist.
2478 @type hvparams: dict of strings
2479 @param hvparams: hypervisor parameters to be verified against, not used here
2481 @return: Problem description if something is wrong, C{None} otherwise
2485 # FIXME: this is the global kvm binary, but the actual path can be
2486 # customized as an hv parameter; we should use the nodegroup's
2487 # default kvm path parameter here.
2488 if not os.path.exists(constants.KVM_PATH):
2489 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2490 if not os.path.exists(constants.SOCAT_PATH):
2491 msgs.append("The socat binary ('%s') does not exist" %
2492 constants.SOCAT_PATH)
2494 return self._FormatVerifyResults(msgs)
2497 def CheckParameterSyntax(cls, hvparams):
2498 """Check the given parameters for validity.
2500 @type hvparams: dict
2501 @param hvparams: dictionary with parameter names/value
2502 @raise errors.HypervisorError: when a parameter is not valid
2505 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2507 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2509 if not hvparams[constants.HV_ROOT_PATH]:
2510 raise errors.HypervisorError("Need a root partition for the instance,"
2511 " if a kernel is defined")
2513 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2514 not hvparams[constants.HV_VNC_X509]):
2515 raise errors.HypervisorError("%s must be defined, if %s is" %
2516 (constants.HV_VNC_X509,
2517 constants.HV_VNC_X509_VERIFY))
2519 if hvparams[constants.HV_SERIAL_CONSOLE]:
2520 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2521 valid_speeds = constants.VALID_SERIAL_SPEEDS
2522 if not serial_speed or serial_speed not in valid_speeds:
2523 raise errors.HypervisorError("Invalid serial console speed, must be"
2525 utils.CommaJoin(valid_speeds))
2527 boot_order = hvparams[constants.HV_BOOT_ORDER]
2528 if (boot_order == constants.HT_BO_CDROM and
2529 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2530 raise errors.HypervisorError("Cannot boot from cdrom without an"
2533 security_model = hvparams[constants.HV_SECURITY_MODEL]
2534 if security_model == constants.HT_SM_USER:
2535 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2536 raise errors.HypervisorError("A security domain (user to run kvm as)"
2537 " must be specified")
2538 elif (security_model == constants.HT_SM_NONE or
2539 security_model == constants.HT_SM_POOL):
2540 if hvparams[constants.HV_SECURITY_DOMAIN]:
2541 raise errors.HypervisorError("Cannot have a security domain when the"
2542 " security model is 'none' or 'pool'")
2544 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2545 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2547 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2548 # if an IP version is specified, the spice_bind parameter must be an
2550 if (netutils.IP4Address.IsValid(spice_bind) and
2551 spice_ip_version != constants.IP4_VERSION):
2552 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2553 " the specified IP version is %s" %
2554 (spice_bind, spice_ip_version))
2556 if (netutils.IP6Address.IsValid(spice_bind) and
2557 spice_ip_version != constants.IP6_VERSION):
2558 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2559 " the specified IP version is %s" %
2560 (spice_bind, spice_ip_version))
2562 # All the other SPICE parameters depend on spice_bind being set. Raise an
2563 # error if any of them is set without it.
2564 for param in _SPICE_ADDITIONAL_PARAMS:
2566 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2567 (param, constants.HV_KVM_SPICE_BIND))
2570 def ValidateParameters(cls, hvparams):
2571 """Check the given parameters for validity.
2573 @type hvparams: dict
2574 @param hvparams: dictionary with parameter names/value
2575 @raise errors.HypervisorError: when a parameter is not valid
2578 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2580 kvm_path = hvparams[constants.HV_KVM_PATH]
2582 security_model = hvparams[constants.HV_SECURITY_MODEL]
2583 if security_model == constants.HT_SM_USER:
2584 username = hvparams[constants.HV_SECURITY_DOMAIN]
2586 pwd.getpwnam(username)
2588 raise errors.HypervisorError("Unknown security domain user %s"
2590 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2591 if vnc_bind_address:
2592 bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2593 is_interface = netutils.IsValidInterface(vnc_bind_address)
2594 is_path = utils.IsNormAbsPath(vnc_bind_address)
2595 if not bound_to_addr and not is_interface and not is_path:
2596 raise errors.HypervisorError("VNC: The %s parameter must be either"
2597 " a valid IP address, an interface name,"
2598 " or an absolute path" %
2599 constants.HV_KVM_SPICE_BIND)
2601 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2603 # only one of VNC and SPICE can be used currently.
2604 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2605 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2606 " only one of them can be used at a"
2609 # check that KVM supports SPICE
2610 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2611 if not cls._SPICE_RE.search(kvmhelp):
2612 raise errors.HypervisorError("SPICE is configured, but it is not"
2613 " supported according to 'kvm --help'")
2615 # if spice_bind is not an IP address, it must be a valid interface
2616 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2617 netutils.IP6Address.IsValid(spice_bind))
2618 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2619 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2620 " a valid IP address or interface name" %
2621 constants.HV_KVM_SPICE_BIND)
2623 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2625 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2626 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2627 raise errors.HypervisorError("Unsupported machine version: %s" %
2631 def PowercycleNode(cls, hvparams=None):
2632 """KVM powercycle, just a wrapper over Linux powercycle.
2634 @type hvparams: dict of strings
2635 @param hvparams: hypervisor params to be used on this node
2638 cls.LinuxPowercycle()