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
41 import affinity # pylint: disable=F0401
45 from ganeti import utils
46 from ganeti import constants
47 from ganeti import errors
48 from ganeti import serializer
49 from ganeti import objects
50 from ganeti import uidpool
51 from ganeti import ssconf
52 from ganeti import netutils
53 from ganeti import pathutils
54 from ganeti.hypervisor import hv_base
55 from ganeti.utils import wrapper as utils_wrapper
58 _KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
59 _KVM_START_PAUSED_FLAG = "-S"
61 # TUN/TAP driver constants, taken from <linux/if_tun.h>
62 # They are architecture-independent and already hardcoded in qemu-kvm source,
63 # so we can safely include them here.
64 TUNSETIFF = 0x400454ca
65 TUNGETIFF = 0x800454d2
66 TUNGETFEATURES = 0x800454cf
71 #: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND}
72 _SPICE_ADDITIONAL_PARAMS = frozenset([
73 constants.HV_KVM_SPICE_IP_VERSION,
74 constants.HV_KVM_SPICE_PASSWORD_FILE,
75 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
76 constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
77 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
78 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
79 constants.HV_KVM_SPICE_USE_TLS,
82 # below constants show the format of runtime file
83 # the nics are in second possition, while the disks in 4th (last)
84 # moreover disk entries are stored in tupples of L{objects.Disk}, dev_path
85 _KVM_NICS_RUNTIME_INDEX = 1
86 _KVM_DISKS_RUNTIME_INDEX = 3
87 _DEVICE_RUNTIME_INDEX = {
88 constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
89 constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
91 _FIND_RUNTIME_ENTRY = {
92 constants.HOTPLUG_TARGET_NIC:
93 lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
94 constants.HOTPLUG_TARGET_DISK:
95 lambda disk, kvm_disks: [(d, l) for (d, l) in kvm_disks
96 if d.uuid == disk.uuid]
99 constants.HOTPLUG_TARGET_NIC: lambda d: d,
100 constants.HOTPLUG_TARGET_DISK: lambda (d, e): d
103 constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
104 constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e)
108 def _GetExistingDeviceInfo(dev_type, device, runtime):
109 """Helper function to get an existing device inside the runtime file
111 Used when an instance is running. Load kvm runtime file and search
112 for a device based on its type and uuid.
114 @type dev_type: sting
115 @param dev_type: device type of param dev
116 @type device: L{objects.Disk} or L{objects.NIC}
117 @param device: the device object for which we generate a kvm name
118 @type runtime: tuple (cmd, nics, hvparams, disks)
119 @param runtime: the runtime data to search for the device
120 @raise errors.HotplugError: in case the requested device does not
121 exist (e.g. device has been added without --hotplug option) or
122 device info has not pci slot (e.g. old devices in the cluster)
125 index = _DEVICE_RUNTIME_INDEX[dev_type]
126 found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
128 raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
129 (dev_type, device.uuid))
134 def _AnalyzeSerializedRuntime(serialized_runtime):
135 """Return runtime entries for a serialized runtime file
137 @type serialized_runtime: string
138 @param serialized_runtime: raw text data read from actual runtime file
139 @return: (cmd, nics, hvparams, bdevs)
143 loaded_runtime = serializer.Load(serialized_runtime)
144 if len(loaded_runtime) == 3:
145 serialized_blockdevs = []
146 kvm_cmd, serialized_nics, hvparams = loaded_runtime
148 kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
150 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
151 block_devices = [(objects.Disk.FromDict(sdisk), link)
152 for sdisk, link in serialized_blockdevs]
154 return (kvm_cmd, kvm_nics, hvparams, block_devices)
157 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
158 """Retrieves supported TUN features from file descriptor.
160 @see: L{_ProbeTapVnetHdr}
163 req = struct.pack("I", 0)
165 buf = _ioctl(fd, TUNGETFEATURES, req)
166 except EnvironmentError, err:
167 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
170 (flags, ) = struct.unpack("I", buf)
174 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
175 """Check whether to enable the IFF_VNET_HDR flag.
177 To do this, _all_ of the following conditions must be met:
178 1. TUNGETFEATURES ioctl() *must* be implemented
179 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
180 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
181 drivers/net/tun.c there is no way to test this until after the tap device
182 has been created using TUNSETIFF, and there is no way to change the
183 IFF_VNET_HDR flag after creating the interface, catch-22! However both
184 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
185 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
188 @param fd: the file descriptor of /dev/net/tun
191 flags = _features_fn(fd)
197 result = bool(flags & IFF_VNET_HDR)
200 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
205 def _OpenTap(vnet_hdr=True):
206 """Open a new tap device and return its file descriptor.
208 This is intended to be used by a qemu-type hypervisor together with the -net
209 tap,fd=<fd> command line parameter.
211 @type vnet_hdr: boolean
212 @param vnet_hdr: Enable the VNET Header
213 @return: (ifname, tapfd)
218 tapfd = os.open("/dev/net/tun", os.O_RDWR)
219 except EnvironmentError:
220 raise errors.HypervisorError("Failed to open /dev/net/tun")
222 flags = IFF_TAP | IFF_NO_PI
224 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
225 flags |= IFF_VNET_HDR
227 # The struct ifreq ioctl request (see netdevice(7))
228 ifr = struct.pack("16sh", "", flags)
231 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
232 except EnvironmentError, err:
233 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
236 # Get the interface name from the ioctl
237 ifname = struct.unpack("16sh", res)[0].strip("\x00")
238 return (ifname, tapfd)
242 """QEMU Messaging Protocol (QMP) message.
245 def __init__(self, data):
246 """Creates a new QMP message based on the passed data.
249 if not isinstance(data, dict):
250 raise TypeError("QmpMessage must be initialized with a dict")
254 def __getitem__(self, field_name):
255 """Get the value of the required field if present, or None.
257 Overrides the [] operator to provide access to the message data,
258 returning None if the required item is not in the message
259 @return: the value of the field_name field, or None if field_name
260 is not contained in the message
263 return self.data.get(field_name, None)
265 def __setitem__(self, field_name, field_value):
266 """Set the value of the required field_name to field_value.
269 self.data[field_name] = field_value
272 def BuildFromJsonString(json_string):
273 """Build a QmpMessage from a JSON encoded string.
275 @type json_string: str
276 @param json_string: JSON string representing the message
277 @rtype: L{QmpMessage}
278 @return: a L{QmpMessage} built from json_string
282 data = serializer.LoadJson(json_string)
283 return QmpMessage(data)
286 # The protocol expects the JSON object to be sent as a single line.
287 return serializer.DumpJson(self.data)
289 def __eq__(self, other):
290 # When comparing two QmpMessages, we are interested in comparing
291 # their internal representation of the message data
292 return self.data == other.data
296 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
299 _FIRST_MESSAGE_KEY = "QMP"
302 _RETURN_KEY = RETURN_KEY = "return"
303 _ACTUAL_KEY = ACTUAL_KEY = "actual"
304 _ERROR_CLASS_KEY = "class"
305 _ERROR_DATA_KEY = "data"
306 _ERROR_DESC_KEY = "desc"
307 _EXECUTE_KEY = "execute"
308 _ARGUMENTS_KEY = "arguments"
309 _CAPABILITIES_COMMAND = "qmp_capabilities"
310 _MESSAGE_END_TOKEN = "\r\n"
313 def __init__(self, monitor_filename):
314 """Instantiates the QmpConnection object.
316 @type monitor_filename: string
317 @param monitor_filename: the filename of the UNIX raw socket on which the
318 QMP monitor is listening
321 self.monitor_filename = monitor_filename
322 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
323 # We want to fail if the server doesn't send a complete message
324 # in a reasonable amount of time
325 self.sock.settimeout(self._SOCKET_TIMEOUT)
326 self._connected = False
329 def _check_socket(self):
332 sock_stat = os.stat(self.monitor_filename)
333 except EnvironmentError, err:
334 if err.errno == errno.ENOENT:
335 raise errors.HypervisorError("No qmp socket found")
337 raise errors.HypervisorError("Error checking qmp socket: %s",
338 utils.ErrnoOrStr(err))
339 if not stat.S_ISSOCK(sock_stat.st_mode):
340 raise errors.HypervisorError("Qmp socket is not a socket")
342 def _check_connection(self):
343 """Make sure that the connection is established.
346 if not self._connected:
347 raise errors.ProgrammerError("To use a QmpConnection you need to first"
348 " invoke connect() on it")
351 """Connects to the QMP monitor.
353 Connects to the UNIX socket and makes sure that we can actually send and
354 receive data to the kvm instance via QMP.
356 @raise errors.HypervisorError: when there are communication errors
357 @raise errors.ProgrammerError: when there are data serialization errors
361 raise errors.ProgrammerError("Cannot connect twice")
365 # Check file existance/stuff
367 self.sock.connect(self.monitor_filename)
368 except EnvironmentError:
369 raise errors.HypervisorError("Can't connect to qmp socket")
370 self._connected = True
372 # Check if we receive a correct greeting message from the server
373 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
374 greeting = self._Recv()
375 if not greeting[self._FIRST_MESSAGE_KEY]:
376 self._connected = False
377 raise errors.HypervisorError("kvm: QMP communication error (wrong"
380 # Let's put the monitor in command mode using the qmp_capabilities
381 # command, or else no command will be executable.
382 # (As per the QEMU Protocol Specification 0.1 - section 4)
383 self.Execute(self._CAPABILITIES_COMMAND)
385 def _ParseMessage(self, buf):
386 """Extract and parse a QMP message from the given buffer.
388 Seeks for a QMP message in the given buf. If found, it parses it and
389 returns it together with the rest of the characters in the buf.
390 If no message is found, returns None and the whole buffer.
392 @raise errors.ProgrammerError: when there are data serialization errors
396 # Check if we got the message end token (CRLF, as per the QEMU Protocol
397 # Specification 0.1 - Section 2.1.1)
398 pos = buf.find(self._MESSAGE_END_TOKEN)
401 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
402 except Exception, err:
403 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
406 return (message, buf)
409 """Receives a message from QMP and decodes the received JSON object.
412 @return: the received message
413 @raise errors.HypervisorError: when there are communication errors
414 @raise errors.ProgrammerError: when there are data serialization errors
417 self._check_connection()
419 # Check if there is already a message in the buffer
420 (message, self._buf) = self._ParseMessage(self._buf)
424 recv_buffer = StringIO.StringIO(self._buf)
425 recv_buffer.seek(len(self._buf))
428 data = self.sock.recv(4096)
431 recv_buffer.write(data)
433 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
437 except socket.timeout, err:
438 raise errors.HypervisorError("Timeout while receiving a QMP message: "
440 except socket.error, err:
441 raise errors.HypervisorError("Unable to receive data from KVM using the"
442 " QMP protocol: %s" % err)
444 def _Send(self, message):
445 """Encodes and sends a message to KVM using QMP.
447 @type message: QmpMessage
448 @param message: message to send to KVM
449 @raise errors.HypervisorError: when there are communication errors
450 @raise errors.ProgrammerError: when there are data serialization errors
453 self._check_connection()
455 message_str = str(message)
456 except Exception, err:
457 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
460 self.sock.sendall(message_str)
461 except socket.timeout, err:
462 raise errors.HypervisorError("Timeout while sending a QMP message: "
463 "%s (%s)" % (err.string, err.errno))
464 except socket.error, err:
465 raise errors.HypervisorError("Unable to send data from KVM using the"
466 " QMP protocol: %s" % err)
468 def Execute(self, command, arguments=None):
469 """Executes a QMP command and returns the response of the server.
472 @param command: the command to execute
473 @type arguments: dict
474 @param arguments: dictionary of arguments to be passed to the command
476 @return: dictionary representing the received JSON object
477 @raise errors.HypervisorError: when there are communication errors
478 @raise errors.ProgrammerError: when there are data serialization errors
481 self._check_connection()
482 message = QmpMessage({self._EXECUTE_KEY: command})
484 message[self._ARGUMENTS_KEY] = arguments
487 # Events can occur between the sending of the command and the reception
488 # of the response, so we need to filter out messages with the event key.
490 response = self._Recv()
491 err = response[self._ERROR_KEY]
493 raise errors.HypervisorError("kvm: error executing the %s"
494 " command: %s (%s, %s):" %
496 err[self._ERROR_DESC_KEY],
497 err[self._ERROR_CLASS_KEY],
498 err[self._ERROR_DATA_KEY]))
500 elif not response[self._EVENT_KEY]:
504 class KVMHypervisor(hv_base.BaseHypervisor):
505 """KVM hypervisor interface
510 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
511 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
512 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
513 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
514 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
515 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
516 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
517 # KVM instances with chroot enabled are started in empty chroot directories.
518 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
519 # After an instance is stopped, its chroot directory is removed.
520 # If the chroot directory is not empty, it can't be removed.
521 # A non-empty chroot directory indicates a possible security incident.
522 # To support forensics, the non-empty chroot directory is quarantined in
523 # a separate directory, called 'chroot-quarantine'.
524 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
525 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
526 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
529 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
530 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
531 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
532 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
533 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
534 constants.HV_ACPI: hv_base.NO_CHECK,
535 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
536 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
537 constants.HV_VNC_BIND_ADDRESS:
538 (False, lambda x: (netutils.IP4Address.IsValid(x) or
539 utils.IsNormAbsPath(x)),
540 "The VNC bind address must be either a valid IP address or an absolute"
541 " pathname", None, None),
542 constants.HV_VNC_TLS: hv_base.NO_CHECK,
543 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
544 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
545 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
546 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
547 constants.HV_KVM_SPICE_IP_VERSION:
548 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
549 x in constants.VALID_IP_VERSIONS),
550 "The SPICE IP version should be 4 or 6",
552 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
553 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
555 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
556 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
558 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
559 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
561 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
562 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
564 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
565 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
566 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
567 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
568 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
569 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
570 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
571 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
572 constants.HV_BOOT_ORDER:
573 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
574 constants.HV_NIC_TYPE:
575 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
576 constants.HV_DISK_TYPE:
577 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
578 constants.HV_KVM_CDROM_DISK_TYPE:
579 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
580 constants.HV_USB_MOUSE:
581 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
582 constants.HV_KEYMAP: hv_base.NO_CHECK,
583 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
584 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
585 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
586 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
587 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
588 constants.HV_DISK_CACHE:
589 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
590 constants.HV_SECURITY_MODEL:
591 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
592 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
593 constants.HV_KVM_FLAG:
594 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
595 constants.HV_VHOST_NET: hv_base.NO_CHECK,
596 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
597 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
598 constants.HV_REBOOT_BEHAVIOR:
599 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
600 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
601 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
602 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
603 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
604 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
605 constants.HV_SOUNDHW: hv_base.NO_CHECK,
606 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
607 constants.HV_VGA: hv_base.NO_CHECK,
608 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
609 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
610 constants.HV_VNET_HDR: hv_base.NO_CHECK,
614 _VIRTIO_NET_PCI = "virtio-net-pci"
615 _VIRTIO_BLK_PCI = "virtio-blk-pci"
617 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
619 _MIGRATION_PROGRESS_RE = \
620 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
621 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
622 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
624 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
625 _MIGRATION_INFO_RETRY_DELAY = 2
627 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
629 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
630 _CPU_INFO_CMD = "info cpus"
633 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
634 _CHECK_MACHINE_VERSION_RE = \
635 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
637 _QMP_RE = re.compile(r"^-qmp\s", re.M)
638 _SPICE_RE = re.compile(r"^-spice\s", re.M)
639 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
640 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
641 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
642 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
643 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
644 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
645 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
646 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M)
647 # match -drive.*boot=on|off on different lines, but in between accept only
648 # dashes not preceeded by a new line (which would mean another option
649 # different than -drive is starting)
650 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
655 ANCILLARY_FILES_OPT = [
659 # Supported kvm options to get output from
660 _KVMOPT_HELP = "help"
661 _KVMOPT_MLIST = "mlist"
662 _KVMOPT_DEVICELIST = "devicelist"
664 # Command to execute to get the output from kvm, and whether to
665 # accept the output even on failure.
667 _KVMOPT_HELP: (["--help"], False),
668 _KVMOPT_MLIST: (["-M", "?"], False),
669 _KVMOPT_DEVICELIST: (["-device", "?"], True),
673 hv_base.BaseHypervisor.__init__(self)
674 # Let's make sure the directories we need exist, even if the RUN_DIR lives
675 # in a tmpfs filesystem or has been otherwise wiped out.
676 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
677 utils.EnsureDirs(dirs)
680 def _InstancePidFile(cls, instance_name):
681 """Returns the instance pidfile.
684 return utils.PathJoin(cls._PIDS_DIR, instance_name)
687 def _InstanceUidFile(cls, instance_name):
688 """Returns the instance uidfile.
691 return utils.PathJoin(cls._UIDS_DIR, instance_name)
694 def _InstancePidInfo(cls, pid):
695 """Check pid file for instance information.
697 Check that a pid file is associated with an instance, and retrieve
698 information from its command line.
700 @type pid: string or int
701 @param pid: process id of the instance to check
703 @return: (instance_name, memory, vcpus)
704 @raise errors.HypervisorError: when an instance cannot be found
707 alive = utils.IsProcessAlive(pid)
709 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
711 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
713 cmdline = utils.ReadFile(cmdline_file)
714 except EnvironmentError, err:
715 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
722 arg_list = cmdline.split("\x00")
724 arg = arg_list.pop(0)
726 instance = arg_list.pop(0)
728 memory = int(arg_list.pop(0))
730 vcpus = int(arg_list.pop(0).split(",")[0])
733 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
736 return (instance, memory, vcpus)
738 def _InstancePidAlive(self, instance_name):
739 """Returns the instance pidfile, pid, and liveness.
741 @type instance_name: string
742 @param instance_name: instance name
744 @return: (pid file name, pid, liveness)
747 pidfile = self._InstancePidFile(instance_name)
748 pid = utils.ReadPidFile(pidfile)
752 cmd_instance = self._InstancePidInfo(pid)[0]
753 alive = (cmd_instance == instance_name)
754 except errors.HypervisorError:
757 return (pidfile, pid, alive)
759 def _CheckDown(self, instance_name):
760 """Raises an error unless the given instance is down.
763 alive = self._InstancePidAlive(instance_name)[2]
765 raise errors.HypervisorError("Failed to start instance %s: %s" %
766 (instance_name, "already running"))
769 def _InstanceMonitor(cls, instance_name):
770 """Returns the instance monitor socket name
773 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
776 def _InstanceSerial(cls, instance_name):
777 """Returns the instance serial socket name
780 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
783 def _InstanceQmpMonitor(cls, instance_name):
784 """Returns the instance serial QMP socket name
787 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
790 def _SocatUnixConsoleParams():
791 """Returns the correct parameters for socat
793 If we have a new-enough socat we can use raw mode with an escape character.
796 if constants.SOCAT_USE_ESCAPE:
797 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
799 return "echo=0,icanon=0"
802 def _InstanceKVMRuntime(cls, instance_name):
803 """Returns the instance KVM runtime filename
806 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
809 def _InstanceChrootDir(cls, instance_name):
810 """Returns the name of the KVM chroot dir of the instance
813 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
816 def _InstanceNICDir(cls, instance_name):
817 """Returns the name of the directory holding the tap device files for a
821 return utils.PathJoin(cls._NICS_DIR, instance_name)
824 def _InstanceNICFile(cls, instance_name, seq):
825 """Returns the name of the file containing the tap device for a given NIC
828 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
831 def _InstanceKeymapFile(cls, instance_name):
832 """Returns the name of the file containing the keymap for a given instance
835 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
838 def _TryReadUidFile(cls, uid_file):
839 """Try to read a uid file
842 if os.path.exists(uid_file):
844 uid = int(utils.ReadOneLineFile(uid_file))
846 except EnvironmentError:
847 logging.warning("Can't read uid file", exc_info=True)
848 except (TypeError, ValueError):
849 logging.warning("Can't parse uid file contents", exc_info=True)
853 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
854 """Removes an instance's rutime sockets/files/dirs.
857 utils.RemoveFile(pidfile)
858 utils.RemoveFile(cls._InstanceMonitor(instance_name))
859 utils.RemoveFile(cls._InstanceSerial(instance_name))
860 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
861 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
862 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
863 uid_file = cls._InstanceUidFile(instance_name)
864 uid = cls._TryReadUidFile(uid_file)
865 utils.RemoveFile(uid_file)
867 uidpool.ReleaseUid(uid)
869 shutil.rmtree(cls._InstanceNICDir(instance_name))
871 if err.errno != errno.ENOENT:
874 chroot_dir = cls._InstanceChrootDir(instance_name)
875 utils.RemoveDir(chroot_dir)
877 if err.errno == errno.ENOTEMPTY:
878 # The chroot directory is expected to be empty, but it isn't.
879 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
882 utils.TimestampForFilename()))
883 logging.warning("The chroot directory of instance %s can not be"
884 " removed as it is not empty. Moving it to the"
885 " quarantine instead. Please investigate the"
886 " contents (%s) and clean up manually",
887 instance_name, new_chroot_dir)
888 utils.RenameFile(chroot_dir, new_chroot_dir)
893 def _ConfigureNIC(instance, seq, nic, tap):
894 """Run the network configuration script for a specified NIC
896 @param instance: instance we're acting on
897 @type instance: instance object
898 @param seq: nic sequence number
900 @param nic: nic we're acting on
901 @type nic: nic object
902 @param tap: the host's tap interface this NIC corresponds to
907 tags = " ".join(instance.tags)
912 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
913 "INSTANCE": instance.name,
915 "MODE": nic.nicparams[constants.NIC_MODE],
917 "INTERFACE_INDEX": str(seq),
924 if nic.nicparams[constants.NIC_LINK]:
925 env["LINK"] = nic.nicparams[constants.NIC_LINK]
928 n = objects.Network.FromDict(nic.netinfo)
929 env.update(n.HooksDict())
931 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
932 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
934 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
936 raise errors.HypervisorError("Failed to configure interface %s: %s;"
937 " network configuration script output: %s" %
938 (tap, result.fail_reason, result.output))
941 def _VerifyAffinityPackage():
943 raise errors.HypervisorError("affinity Python package not"
944 " found; cannot use CPU pinning under KVM")
947 def _BuildAffinityCpuMask(cpu_list):
948 """Create a CPU mask suitable for sched_setaffinity from a list of
951 See man taskset for more info on sched_setaffinity masks.
952 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
954 @type cpu_list: list of int
955 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
957 @return: a bit mask of CPU affinities
960 if cpu_list == constants.CPU_PINNING_OFF:
961 return constants.CPU_PINNING_ALL_KVM
963 return sum(2 ** cpu for cpu in cpu_list)
966 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
967 """Change CPU affinity for running VM according to given CPU mask.
969 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
970 @type cpu_mask: string
971 @param process_id: process ID of KVM process. Used to pin entire VM
973 @type process_id: int
974 @param thread_dict: map of virtual CPUs to KVM thread IDs
975 @type thread_dict: dict int:int
978 # Convert the string CPU mask to a list of list of int's
979 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
981 if len(cpu_list) == 1:
982 all_cpu_mapping = cpu_list[0]
983 if all_cpu_mapping == constants.CPU_PINNING_OFF:
984 # If CPU pinning has 1 entry that's "all", then do nothing
987 # If CPU pinning has one non-all entry, map the entire VM to
988 # one set of physical CPUs
989 cls._VerifyAffinityPackage()
990 affinity.set_process_affinity_mask(
991 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
993 # The number of vCPUs mapped should match the number of vCPUs
994 # reported by KVM. This was already verified earlier, so
995 # here only as a sanity check.
996 assert len(thread_dict) == len(cpu_list)
997 cls._VerifyAffinityPackage()
999 # For each vCPU, map it to the proper list of physical CPUs
1000 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
1001 affinity.set_process_affinity_mask(thread_dict[i],
1002 cls._BuildAffinityCpuMask(vcpu))
1004 def _GetVcpuThreadIds(self, instance_name):
1005 """Get a mapping of vCPU no. to thread IDs for the instance
1007 @type instance_name: string
1008 @param instance_name: instance in question
1009 @rtype: dictionary of int:int
1010 @return: a dictionary mapping vCPU numbers to thread IDs
1014 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
1015 for line in output.stdout.splitlines():
1016 match = self._CPU_INFO_RE.search(line)
1019 grp = map(int, match.groups())
1020 result[grp[0]] = grp[1]
1024 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
1025 """Complete CPU pinning.
1027 @type instance_name: string
1028 @param instance_name: name of instance
1029 @type cpu_mask: string
1030 @param cpu_mask: CPU pinning mask as entered by user
1033 # Get KVM process ID, to be used if need to pin entire VM
1034 _, pid, _ = self._InstancePidAlive(instance_name)
1035 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
1036 thread_dict = self._GetVcpuThreadIds(instance_name)
1037 # Run CPU pinning, based on configured mask
1038 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
1040 def ListInstances(self):
1041 """Get the list of running instances.
1043 We can do this by listing our live instances directory and
1044 checking whether the associated kvm process is still alive.
1048 for name in os.listdir(self._PIDS_DIR):
1049 if self._InstancePidAlive(name)[2]:
1053 def GetInstanceInfo(self, instance_name):
1054 """Get instance properties.
1056 @type instance_name: string
1057 @param instance_name: the instance name
1058 @rtype: tuple of strings
1059 @return: (name, id, memory, vcpus, stat, times)
1062 _, pid, alive = self._InstancePidAlive(instance_name)
1066 _, memory, vcpus = self._InstancePidInfo(pid)
1071 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
1073 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
1074 # Will fail if ballooning is not enabled, but we can then just resort to
1076 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1077 memory = mem_bytes / 1048576
1078 except errors.HypervisorError:
1081 return (instance_name, pid, memory, vcpus, istat, times)
1083 def GetAllInstancesInfo(self):
1084 """Get properties of all instances.
1086 @return: list of tuples (name, id, memory, vcpus, stat, times)
1090 for name in os.listdir(self._PIDS_DIR):
1092 info = self.GetInstanceInfo(name)
1093 except errors.HypervisorError:
1094 # Ignore exceptions due to instances being shut down
1100 def _GenerateKVMBlockDevicesOptions(self, instance, block_devices, kvmhelp):
1102 hvp = instance.hvparams
1103 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1104 kvm_path = hvp[constants.HV_KVM_PATH]
1106 # whether this is an older KVM version that uses the boot=on flag
1108 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1111 device_driver = None
1112 disk_type = hvp[constants.HV_DISK_TYPE]
1113 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1114 if_val = ",if=%s" % self._VIRTIO
1116 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1117 if self._VIRTIO_BLK_RE.search(devlist):
1118 # TODO: uncomment when -device is used
1119 # if_val = ",if=none"
1120 # will be passed in -device option as driver
1121 device_driver = self._VIRTIO_BLK_PCI
1122 except errors.HypervisorError, _:
1125 if_val = ",if=%s" % disk_type
1127 disk_cache = hvp[constants.HV_DISK_CACHE]
1128 if instance.disk_template in constants.DTS_EXT_MIRROR:
1129 if disk_cache != "none":
1130 # TODO: make this a hard error, instead of a silent overwrite
1131 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1132 " to prevent shared storage corruption on migration",
1134 cache_val = ",cache=none"
1135 elif disk_cache != constants.HT_CACHE_DEFAULT:
1136 cache_val = ",cache=%s" % disk_cache
1139 for cfdev, dev_path in block_devices:
1140 if cfdev.mode != constants.DISK_RDWR:
1141 raise errors.HypervisorError("Instance has read-only disks which"
1142 " are not supported by KVM")
1143 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1146 dev_opts.extend(["-boot", "c"])
1148 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1149 boot_val = ",boot=on"
1150 drive_val = "file=%s,format=raw%s%s%s" % \
1151 (dev_path, if_val, boot_val, cache_val)
1155 dev_opts.extend(["-drive", drive_val])
1159 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1161 """Generate KVM information to start an instance.
1163 @type kvmhelp: string
1164 @param kvmhelp: output of kvm --help
1165 @attention: this function must not have any side-effects; for
1166 example, it must not write to the filesystem, or read values
1167 from the current system the are expected to differ between
1168 nodes, since it is only run once at instance startup;
1169 actions/kvm arguments that can vary between systems should be
1170 done in L{_ExecuteKVMRuntime}
1173 # pylint: disable=R0912,R0914,R0915
1174 hvp = instance.hvparams
1175 self.ValidateParameters(hvp)
1177 pidfile = self._InstancePidFile(instance.name)
1178 kvm = hvp[constants.HV_KVM_PATH]
1180 # used just by the vnc server, if enabled
1181 kvm_cmd.extend(["-name", instance.name])
1182 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1184 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1185 if hvp[constants.HV_CPU_CORES]:
1186 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1187 if hvp[constants.HV_CPU_THREADS]:
1188 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1189 if hvp[constants.HV_CPU_SOCKETS]:
1190 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1192 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1194 kvm_cmd.extend(["-pidfile", pidfile])
1195 kvm_cmd.extend(["-balloon", "virtio"])
1196 kvm_cmd.extend(["-daemonize"])
1197 if not instance.hvparams[constants.HV_ACPI]:
1198 kvm_cmd.extend(["-no-acpi"])
1199 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1200 constants.INSTANCE_REBOOT_EXIT:
1201 kvm_cmd.extend(["-no-reboot"])
1203 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1205 mversion = self._GetDefaultMachineVersion(kvm)
1206 if self._MACHINE_RE.search(kvmhelp):
1207 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1208 # extra hypervisor parameters. We should also investigate whether and how
1209 # shadow_mem should be considered for the resource model.
1210 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1211 specprop = ",accel=kvm"
1214 machinespec = "%s%s" % (mversion, specprop)
1215 kvm_cmd.extend(["-machine", machinespec])
1217 kvm_cmd.extend(["-M", mversion])
1218 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1219 self._ENABLE_KVM_RE.search(kvmhelp)):
1220 kvm_cmd.extend(["-enable-kvm"])
1221 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1222 self._DISABLE_KVM_RE.search(kvmhelp)):
1223 kvm_cmd.extend(["-disable-kvm"])
1225 kernel_path = hvp[constants.HV_KERNEL_PATH]
1227 boot_cdrom = boot_floppy = boot_network = False
1229 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1230 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1231 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1234 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1237 kvm_cmd.extend(["-boot", "n"])
1239 # whether this is an older KVM version that uses the boot=on flag
1241 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1243 disk_type = hvp[constants.HV_DISK_TYPE]
1245 #Now we can specify a different device type for CDROM devices.
1246 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1247 if not cdrom_disk_type:
1248 cdrom_disk_type = disk_type
1250 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1252 options = ",format=raw,media=cdrom"
1253 # set cdrom 'if' type
1255 actual_cdrom_type = constants.HT_DISK_IDE
1256 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1257 actual_cdrom_type = "virtio"
1259 actual_cdrom_type = cdrom_disk_type
1260 if_val = ",if=%s" % actual_cdrom_type
1261 # set boot flag, if needed
1264 kvm_cmd.extend(["-boot", "d"])
1266 boot_val = ",boot=on"
1267 # and finally build the entire '-drive' value
1268 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1269 kvm_cmd.extend(["-drive", drive_val])
1271 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1273 options = ",format=raw,media=cdrom"
1274 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1275 if_val = ",if=virtio"
1277 if_val = ",if=%s" % cdrom_disk_type
1278 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1279 kvm_cmd.extend(["-drive", drive_val])
1281 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1283 options = ",format=raw,media=disk"
1285 kvm_cmd.extend(["-boot", "a"])
1286 options = "%s,boot=on" % options
1287 if_val = ",if=floppy"
1288 options = "%s%s" % (options, if_val)
1289 drive_val = "file=%s%s" % (floppy_image, options)
1290 kvm_cmd.extend(["-drive", drive_val])
1293 kvm_cmd.extend(["-kernel", kernel_path])
1294 initrd_path = hvp[constants.HV_INITRD_PATH]
1296 kvm_cmd.extend(["-initrd", initrd_path])
1297 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1298 hvp[constants.HV_KERNEL_ARGS]]
1299 if hvp[constants.HV_SERIAL_CONSOLE]:
1300 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1301 root_append.append("console=ttyS0,%s" % serial_speed)
1302 kvm_cmd.extend(["-append", " ".join(root_append)])
1304 mem_path = hvp[constants.HV_MEM_PATH]
1306 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1308 monitor_dev = ("unix:%s,server,nowait" %
1309 self._InstanceMonitor(instance.name))
1310 kvm_cmd.extend(["-monitor", monitor_dev])
1311 if hvp[constants.HV_SERIAL_CONSOLE]:
1312 serial_dev = ("unix:%s,server,nowait" %
1313 self._InstanceSerial(instance.name))
1314 kvm_cmd.extend(["-serial", serial_dev])
1316 kvm_cmd.extend(["-serial", "none"])
1318 mouse_type = hvp[constants.HV_USB_MOUSE]
1319 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1320 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1321 spice_ip_version = None
1323 kvm_cmd.extend(["-usb"])
1326 kvm_cmd.extend(["-usbdevice", mouse_type])
1327 elif vnc_bind_address:
1328 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1330 if vnc_bind_address:
1331 if netutils.IP4Address.IsValid(vnc_bind_address):
1332 if instance.network_port > constants.VNC_BASE_PORT:
1333 display = instance.network_port - constants.VNC_BASE_PORT
1334 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1335 vnc_arg = ":%d" % (display)
1337 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1339 logging.error("Network port is not a valid VNC display (%d < %d),"
1340 " not starting VNC",
1341 instance.network_port, constants.VNC_BASE_PORT)
1344 # Only allow tls and other option when not binding to a file, for now.
1345 # kvm/qemu gets confused otherwise about the filename to use.
1347 if hvp[constants.HV_VNC_TLS]:
1348 vnc_append = "%s,tls" % vnc_append
1349 if hvp[constants.HV_VNC_X509_VERIFY]:
1350 vnc_append = "%s,x509verify=%s" % (vnc_append,
1351 hvp[constants.HV_VNC_X509])
1352 elif hvp[constants.HV_VNC_X509]:
1353 vnc_append = "%s,x509=%s" % (vnc_append,
1354 hvp[constants.HV_VNC_X509])
1355 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1356 vnc_append = "%s,password" % vnc_append
1358 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1361 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1363 kvm_cmd.extend(["-vnc", vnc_arg])
1365 # FIXME: this is wrong here; the iface ip address differs
1366 # between systems, so it should be done in _ExecuteKVMRuntime
1367 if netutils.IsValidInterface(spice_bind):
1368 # The user specified a network interface, we have to figure out the IP
1370 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1371 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1373 # if the user specified an IP version and the interface does not
1374 # have that kind of IP addresses, throw an exception
1375 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1376 if not addresses[spice_ip_version]:
1377 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1378 " for %s" % (spice_ip_version,
1381 # the user did not specify an IP version, we have to figure it out
1382 elif (addresses[constants.IP4_VERSION] and
1383 addresses[constants.IP6_VERSION]):
1384 # we have both ipv4 and ipv6, let's use the cluster default IP
1386 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1387 spice_ip_version = \
1388 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1389 elif addresses[constants.IP4_VERSION]:
1390 spice_ip_version = constants.IP4_VERSION
1391 elif addresses[constants.IP6_VERSION]:
1392 spice_ip_version = constants.IP6_VERSION
1394 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1395 " for %s" % (spice_bind))
1397 spice_address = addresses[spice_ip_version][0]
1400 # spice_bind is known to be a valid IP address, because
1401 # ValidateParameters checked it.
1402 spice_address = spice_bind
1404 spice_arg = "addr=%s" % spice_address
1405 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1406 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1407 (spice_arg, instance.network_port,
1408 pathutils.SPICE_CACERT_FILE))
1409 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1410 (spice_arg, pathutils.SPICE_CERT_FILE,
1411 pathutils.SPICE_CERT_FILE))
1412 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1414 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1416 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1418 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1419 spice_arg = "%s,disable-ticketing" % spice_arg
1421 if spice_ip_version:
1422 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1424 # Image compression options
1425 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1426 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1427 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1429 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1431 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1433 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1435 # Video stream detection
1436 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1438 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1440 # Audio compression, by default in qemu-kvm it is on
1441 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1442 spice_arg = "%s,playback-compression=off" % spice_arg
1443 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1444 spice_arg = "%s,agent-mouse=off" % spice_arg
1446 # Enable the spice agent communication channel between the host and the
1448 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1451 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1453 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1455 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1456 kvm_cmd.extend(["-spice", spice_arg])
1459 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1460 # also works in earlier versions though (tested with 1.1 and 1.3)
1461 if self._DISPLAY_RE.search(kvmhelp):
1462 kvm_cmd.extend(["-display", "none"])
1464 kvm_cmd.extend(["-nographic"])
1466 if hvp[constants.HV_USE_LOCALTIME]:
1467 kvm_cmd.extend(["-localtime"])
1469 if hvp[constants.HV_KVM_USE_CHROOT]:
1470 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1472 # Add qemu-KVM -cpu param
1473 if hvp[constants.HV_CPU_TYPE]:
1474 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1476 # As requested by music lovers
1477 if hvp[constants.HV_SOUNDHW]:
1478 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1480 # Pass a -vga option if requested, or if spice is used, for backwards
1482 if hvp[constants.HV_VGA]:
1483 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1485 kvm_cmd.extend(["-vga", "qxl"])
1487 # Various types of usb devices, comma separated
1488 if hvp[constants.HV_USB_DEVICES]:
1489 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1490 kvm_cmd.extend(["-usbdevice", dev])
1492 if hvp[constants.HV_KVM_EXTRA]:
1493 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1496 for disk, dev_path in block_devices:
1497 kvm_disks.append((disk, dev_path))
1500 for nic in instance.nics:
1501 kvm_nics.append(nic)
1505 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1507 def _WriteKVMRuntime(self, instance_name, data):
1508 """Write an instance's KVM runtime
1512 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1514 except EnvironmentError, err:
1515 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1517 def _ReadKVMRuntime(self, instance_name):
1518 """Read an instance's KVM runtime
1522 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1523 except EnvironmentError, err:
1524 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1527 def _SaveKVMRuntime(self, instance, kvm_runtime):
1528 """Save an instance's KVM runtime
1531 kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1533 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1534 serialized_blockdevs = [(blk.ToDict(), link)
1535 for blk, link in block_devices]
1536 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1537 serialized_blockdevs))
1539 self._WriteKVMRuntime(instance.name, serialized_form)
1541 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1542 """Load an instance's KVM runtime
1545 if not serialized_runtime:
1546 serialized_runtime = self._ReadKVMRuntime(instance.name)
1548 return _AnalyzeSerializedRuntime(serialized_runtime)
1550 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1551 """Run the KVM cmd and check for errors
1554 @param name: instance name
1555 @type kvm_cmd: list of strings
1556 @param kvm_cmd: runcmd input for kvm
1557 @type tap_fds: list of int
1558 @param tap_fds: fds of tap devices opened by Ganeti
1562 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1565 utils_wrapper.CloseFdNoError(fd)
1568 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1569 (name, result.fail_reason, result.output))
1570 if not self._InstancePidAlive(name)[2]:
1571 raise errors.HypervisorError("Failed to start instance %s" % name)
1573 # 52/50 local variables
1574 # pylint: disable=R0914
1575 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1576 """Execute a KVM cmd, after completing it with some last minute data.
1578 @type incoming: tuple of strings
1579 @param incoming: (target_host_ip, port)
1580 @type kvmhelp: string
1581 @param kvmhelp: output of kvm --help
1584 # Small _ExecuteKVMRuntime hv parameters programming howto:
1585 # - conf_hvp contains the parameters as configured on ganeti. they might
1586 # have changed since the instance started; only use them if the change
1587 # won't affect the inside of the instance (which hasn't been rebooted).
1588 # - up_hvp contains the parameters as they were when the instance was
1589 # started, plus any new parameter which has been added between ganeti
1590 # versions: it is paramount that those default to a value which won't
1591 # affect the inside of the instance as well.
1592 conf_hvp = instance.hvparams
1593 name = instance.name
1594 self._CheckDown(name)
1598 kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1599 # the first element of kvm_cmd is always the path to the kvm binary
1600 kvm_path = kvm_cmd[0]
1601 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1603 # We know it's safe to run as a different user upon migration, so we'll use
1604 # the latest conf, from conf_hvp.
1605 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1606 if security_model == constants.HT_SM_USER:
1607 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1609 keymap = conf_hvp[constants.HV_KEYMAP]
1611 keymap_path = self._InstanceKeymapFile(name)
1612 # If a keymap file is specified, KVM won't use its internal defaults. By
1613 # first including the "en-us" layout, an error on loading the actual
1614 # layout (e.g. because it can't be found) won't lead to a non-functional
1615 # keyboard. A keyboard with incorrect keys is still better than none.
1616 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1617 kvm_cmd.extend(["-k", keymap_path])
1619 # We have reasons to believe changing something like the nic driver/type
1620 # upon migration won't exactly fly with the instance kernel, so for nic
1621 # related parameters we'll use up_hvp
1625 kvm_cmd.extend(["-net", "none"])
1629 nic_type = up_hvp[constants.HV_NIC_TYPE]
1630 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1631 nic_model = self._VIRTIO
1633 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1634 if self._VIRTIO_NET_RE.search(devlist):
1635 nic_model = self._VIRTIO_NET_PCI
1636 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1637 except errors.HypervisorError, _:
1638 # Older versions of kvm don't support DEVICE_LIST, but they don't
1639 # have new virtio syntax either.
1642 if up_hvp[constants.HV_VHOST_NET]:
1643 # check for vhost_net support
1644 if self._VHOST_RE.search(kvmhelp):
1645 tap_extra = ",vhost=on"
1647 raise errors.HypervisorError("vhost_net is configured"
1648 " but it is not available")
1650 nic_model = nic_type
1652 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1654 for nic_seq, nic in enumerate(kvm_nics):
1655 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1656 tapfds.append(tapfd)
1657 taps.append(tapname)
1658 if kvm_supports_netdev:
1659 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1660 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1661 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1663 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1665 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1666 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1669 target, port = incoming
1670 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1672 # Changing the vnc password doesn't bother the guest that much. At most it
1673 # will surprise people who connect to it. Whether positively or negatively
1675 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1679 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1680 except EnvironmentError, err:
1681 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1682 % (vnc_pwd_file, err))
1684 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1685 utils.EnsureDirs([(self._InstanceChrootDir(name),
1686 constants.SECURE_DIR_MODE)])
1688 # Automatically enable QMP if version is >= 0.14
1689 if self._QMP_RE.search(kvmhelp):
1690 logging.debug("Enabling QMP")
1691 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1692 self._InstanceQmpMonitor(instance.name)])
1694 # Configure the network now for starting instances and bridged interfaces,
1695 # during FinalizeMigration for incoming instances' routed interfaces
1696 for nic_seq, nic in enumerate(kvm_nics):
1698 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1700 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1702 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1705 kvm_cmd.extend(bdev_opts)
1706 # CPU affinity requires kvm to start paused, so we set this flag if the
1707 # instance is not already paused and if we are not going to accept a
1708 # migrating instance. In the latter case, pausing is not needed.
1709 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1710 if start_kvm_paused:
1711 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1713 # Note: CPU pinning is using up_hvp since changes take effect
1714 # during instance startup anyway, and to avoid problems when soft
1715 # rebooting the instance.
1717 if up_hvp.get(constants.HV_CPU_MASK, None):
1720 if security_model == constants.HT_SM_POOL:
1721 ss = ssconf.SimpleStore()
1722 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1723 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1724 uid = uidpool.RequestUnusedUid(all_uids)
1726 username = pwd.getpwuid(uid.GetUid()).pw_name
1727 kvm_cmd.extend(["-runas", username])
1728 self._RunKVMCmd(name, kvm_cmd, tapfds)
1730 uidpool.ReleaseUid(uid)
1734 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1736 self._RunKVMCmd(name, kvm_cmd, tapfds)
1738 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1739 constants.RUN_DIRS_MODE)])
1740 for nic_seq, tap in enumerate(taps):
1741 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1745 change_cmd = "change vnc password %s" % vnc_pwd
1746 self._CallMonitorCommand(instance.name, change_cmd)
1748 # Setting SPICE password. We are not vulnerable to malicious passwordless
1749 # connection attempts because SPICE by default does not allow connections
1750 # if neither a password nor the "disable_ticketing" options are specified.
1751 # As soon as we send the password via QMP, that password is a valid ticket
1753 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1754 if spice_password_file:
1757 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1758 except EnvironmentError, err:
1759 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1760 % (spice_password_file, err))
1762 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1765 "protocol": "spice",
1766 "password": spice_pwd,
1768 qmp.Execute("set_password", arguments)
1770 for filename in temp_files:
1771 utils.RemoveFile(filename)
1773 # If requested, set CPU affinity and resume instance execution
1775 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1777 start_memory = self._InstanceStartupMemory(instance)
1778 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1779 self.BalloonInstanceMemory(instance, start_memory)
1781 if start_kvm_paused:
1782 # To control CPU pinning, ballooning, and vnc/spice passwords
1783 # the VM was started in a frozen state. If freezing was not
1784 # explicitly requested resume the vm status.
1785 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1787 def StartInstance(self, instance, block_devices, startup_paused):
1788 """Start an instance.
1791 self._CheckDown(instance.name)
1792 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1793 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1794 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1795 startup_paused, kvmhelp)
1796 self._SaveKVMRuntime(instance, kvm_runtime)
1797 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1799 def _CallMonitorCommand(self, instance_name, command, timeout=None):
1800 """Invoke a command on the instance monitor.
1803 if timeout is not None:
1804 timeout_cmd = "timeout %s" % (timeout, )
1808 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1809 # version. The monitor protocol is designed for human consumption, whereas
1810 # QMP is made for programmatic usage. In the worst case QMP can also
1811 # execute monitor commands. As it is, all calls to socat take at least
1812 # 500ms and likely more: socat can't detect the end of the reply and waits
1813 # for 500ms of no data received before exiting (500 ms is the default for
1814 # the "-t" parameter).
1815 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1816 (utils.ShellQuote(command),
1818 constants.SOCAT_PATH,
1819 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1821 result = utils.RunCmd(socat)
1823 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1825 (command, instance_name, result.fail_reason, result.output))
1826 raise errors.HypervisorError(msg)
1831 def _ParseKVMVersion(cls, text):
1832 """Parse the KVM version from the --help output.
1835 @param text: output of kvm --help
1836 @return: (version, v_maj, v_min, v_rev)
1837 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1840 match = cls._VERSION_RE.search(text.splitlines()[0])
1842 raise errors.HypervisorError("Unable to get KVM version")
1844 v_all = match.group(0)
1845 v_maj = int(match.group(1))
1846 v_min = int(match.group(2))
1848 v_rev = int(match.group(4))
1851 return (v_all, v_maj, v_min, v_rev)
1854 def _GetKVMOutput(cls, kvm_path, option):
1855 """Return the output of a kvm invocation
1857 @type kvm_path: string
1858 @param kvm_path: path to the kvm executable
1859 @type option: a key of _KVMOPTS_CMDS
1860 @param option: kvm option to fetch the output from
1861 @return: output a supported kvm invocation
1862 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1865 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1867 optlist, can_fail = cls._KVMOPTS_CMDS[option]
1869 result = utils.RunCmd([kvm_path] + optlist)
1870 if result.failed and not can_fail:
1871 raise errors.HypervisorError("Unable to get KVM %s output" %
1873 return result.output
1876 def _GetKVMVersion(cls, kvm_path):
1877 """Return the installed KVM version.
1879 @return: (version, v_maj, v_min, v_rev)
1880 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1883 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1886 def _GetDefaultMachineVersion(cls, kvm_path):
1887 """Return the default hardware revision (e.g. pc-1.1)
1890 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1891 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1893 return match.group(1)
1897 def StopInstance(self, instance, force=False, retry=False, name=None,
1899 """Stop an instance.
1902 assert(timeout is None or force is not None)
1904 if name is not None and not force:
1905 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1907 name = instance.name
1908 acpi = instance.hvparams[constants.HV_ACPI]
1911 _, pid, alive = self._InstancePidAlive(name)
1912 if pid > 0 and alive:
1913 if force or not acpi:
1914 utils.KillProcess(pid)
1916 self._CallMonitorCommand(name, "system_powerdown", timeout)
1918 def CleanupInstance(self, instance_name):
1919 """Cleanup after a stopped instance
1922 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1923 if pid > 0 and alive:
1924 raise errors.HypervisorError("Cannot cleanup a live instance")
1925 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1927 def RebootInstance(self, instance):
1928 """Reboot an instance.
1931 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1932 # socket the instance will stop, but now power up again. So we'll resort
1933 # to shutdown and restart.
1934 _, _, alive = self._InstancePidAlive(instance.name)
1936 raise errors.HypervisorError("Failed to reboot instance %s:"
1937 " not running" % instance.name)
1938 # StopInstance will delete the saved KVM runtime so:
1939 # ...first load it...
1940 kvm_runtime = self._LoadKVMRuntime(instance)
1941 # ...now we can safely call StopInstance...
1942 if not self.StopInstance(instance):
1943 self.StopInstance(instance, force=True)
1944 # ...and finally we can save it again, and execute it...
1945 self._SaveKVMRuntime(instance, kvm_runtime)
1946 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1947 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1948 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1950 def MigrationInfo(self, instance):
1951 """Get instance information to perform a migration.
1953 @type instance: L{objects.Instance}
1954 @param instance: instance to be migrated
1956 @return: content of the KVM runtime file
1959 return self._ReadKVMRuntime(instance.name)
1961 def AcceptInstance(self, instance, info, target):
1962 """Prepare to accept an instance.
1964 @type instance: L{objects.Instance}
1965 @param instance: instance to be accepted
1967 @param info: content of the KVM runtime file on the source node
1968 @type target: string
1969 @param target: target host (usually ip), on this node
1972 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1973 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1974 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1975 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1976 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1977 incoming=incoming_address)
1979 def FinalizeMigrationDst(self, instance, info, success):
1980 """Finalize the instance migration on the target node.
1982 Stop the incoming mode KVM.
1984 @type instance: L{objects.Instance}
1985 @param instance: instance whose migration is being finalized
1989 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1990 kvm_nics = kvm_runtime[1]
1992 for nic_seq, nic in enumerate(kvm_nics):
1993 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1994 # Bridged interfaces have already been configured
1997 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1998 except EnvironmentError, err:
1999 logging.warning("Failed to find host interface for %s NIC #%d: %s",
2000 instance.name, nic_seq, str(err))
2003 self._ConfigureNIC(instance, nic_seq, nic, tap)
2004 except errors.HypervisorError, err:
2005 logging.warning(str(err))
2007 self._WriteKVMRuntime(instance.name, info)
2009 self.StopInstance(instance, force=True)
2011 def MigrateInstance(self, instance, target, live):
2012 """Migrate an instance to a target node.
2014 The migration will not be attempted if the instance is not
2017 @type instance: L{objects.Instance}
2018 @param instance: the instance to be migrated
2019 @type target: string
2020 @param target: ip address of the target node
2022 @param live: perform a live migration
2025 instance_name = instance.name
2026 port = instance.hvparams[constants.HV_MIGRATION_PORT]
2027 _, _, alive = self._InstancePidAlive(instance_name)
2029 raise errors.HypervisorError("Instance not running, cannot migrate")
2032 self._CallMonitorCommand(instance_name, "stop")
2034 migrate_command = ("migrate_set_speed %dm" %
2035 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
2036 self._CallMonitorCommand(instance_name, migrate_command)
2038 migrate_command = ("migrate_set_downtime %dms" %
2039 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
2040 self._CallMonitorCommand(instance_name, migrate_command)
2042 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
2043 self._CallMonitorCommand(instance_name, migrate_command)
2045 def FinalizeMigrationSource(self, instance, success, live):
2046 """Finalize the instance migration on the source node.
2048 @type instance: L{objects.Instance}
2049 @param instance: the instance that was migrated
2051 @param success: whether the migration succeeded or not
2053 @param live: whether the user requested a live migration or not
2057 pidfile, pid, _ = self._InstancePidAlive(instance.name)
2058 utils.KillProcess(pid)
2059 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
2061 self._CallMonitorCommand(instance.name, self._CONT_CMD)
2063 def GetMigrationStatus(self, instance):
2064 """Get the migration status
2066 @type instance: L{objects.Instance}
2067 @param instance: the instance that is being migrated
2068 @rtype: L{objects.MigrationStatus}
2069 @return: the status of the current migration (one of
2070 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
2071 progress info that can be retrieved from the hypervisor
2074 info_command = "info migrate"
2075 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
2076 result = self._CallMonitorCommand(instance.name, info_command)
2077 match = self._MIGRATION_STATUS_RE.search(result.stdout)
2079 if not result.stdout:
2080 logging.info("KVM: empty 'info migrate' result")
2082 logging.warning("KVM: unknown 'info migrate' result: %s",
2085 status = match.group(1)
2086 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
2087 migration_status = objects.MigrationStatus(status=status)
2088 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
2090 migration_status.transferred_ram = match.group("transferred")
2091 migration_status.total_ram = match.group("total")
2093 return migration_status
2095 logging.warning("KVM: unknown migration status '%s'", status)
2097 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
2099 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2101 def BalloonInstanceMemory(self, instance, mem):
2102 """Balloon an instance memory to a certain value.
2104 @type instance: L{objects.Instance}
2105 @param instance: instance to be accepted
2107 @param mem: actual memory size to use for instance runtime
2110 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2112 def GetNodeInfo(self):
2113 """Return information about the node.
2115 @return: a dict with the following keys (values in MiB):
2116 - memory_total: the total memory size on the node
2117 - memory_free: the available memory on the node for instances
2118 - memory_dom0: the memory used by the node itself, if available
2119 - hv_version: the hypervisor version in the form (major, minor,
2123 result = self.GetLinuxNodeInfo()
2124 # FIXME: this is the global kvm version, but the actual version can be
2125 # customized as an hv parameter. we should use the nodegroup's default kvm
2126 # path parameter here.
2127 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2128 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2132 def GetInstanceConsole(cls, instance, hvparams, beparams):
2133 """Return a command for connecting to the console of an instance.
2136 if hvparams[constants.HV_SERIAL_CONSOLE]:
2137 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2138 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2139 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2140 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2141 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2142 return objects.InstanceConsole(instance=instance.name,
2143 kind=constants.CONS_SSH,
2144 host=instance.primary_node,
2145 user=constants.SSH_CONSOLE_USER,
2148 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2149 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2150 display = instance.network_port - constants.VNC_BASE_PORT
2151 return objects.InstanceConsole(instance=instance.name,
2152 kind=constants.CONS_VNC,
2153 host=vnc_bind_address,
2154 port=instance.network_port,
2157 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2159 return objects.InstanceConsole(instance=instance.name,
2160 kind=constants.CONS_SPICE,
2162 port=instance.network_port)
2164 return objects.InstanceConsole(instance=instance.name,
2165 kind=constants.CONS_MESSAGE,
2166 message=("No serial shell for instance %s" %
2170 """Verify the hypervisor.
2172 Check that the required binaries exist.
2174 @return: Problem description if something is wrong, C{None} otherwise
2178 # FIXME: this is the global kvm binary, but the actual path can be
2179 # customized as an hv parameter; we should use the nodegroup's
2180 # default kvm path parameter here.
2181 if not os.path.exists(constants.KVM_PATH):
2182 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2183 if not os.path.exists(constants.SOCAT_PATH):
2184 msgs.append("The socat binary ('%s') does not exist" %
2185 constants.SOCAT_PATH)
2187 return self._FormatVerifyResults(msgs)
2190 def CheckParameterSyntax(cls, hvparams):
2191 """Check the given parameters for validity.
2193 @type hvparams: dict
2194 @param hvparams: dictionary with parameter names/value
2195 @raise errors.HypervisorError: when a parameter is not valid
2198 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2200 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2202 if not hvparams[constants.HV_ROOT_PATH]:
2203 raise errors.HypervisorError("Need a root partition for the instance,"
2204 " if a kernel is defined")
2206 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2207 not hvparams[constants.HV_VNC_X509]):
2208 raise errors.HypervisorError("%s must be defined, if %s is" %
2209 (constants.HV_VNC_X509,
2210 constants.HV_VNC_X509_VERIFY))
2212 if hvparams[constants.HV_SERIAL_CONSOLE]:
2213 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2214 valid_speeds = constants.VALID_SERIAL_SPEEDS
2215 if not serial_speed or serial_speed not in valid_speeds:
2216 raise errors.HypervisorError("Invalid serial console speed, must be"
2218 utils.CommaJoin(valid_speeds))
2220 boot_order = hvparams[constants.HV_BOOT_ORDER]
2221 if (boot_order == constants.HT_BO_CDROM and
2222 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2223 raise errors.HypervisorError("Cannot boot from cdrom without an"
2226 security_model = hvparams[constants.HV_SECURITY_MODEL]
2227 if security_model == constants.HT_SM_USER:
2228 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2229 raise errors.HypervisorError("A security domain (user to run kvm as)"
2230 " must be specified")
2231 elif (security_model == constants.HT_SM_NONE or
2232 security_model == constants.HT_SM_POOL):
2233 if hvparams[constants.HV_SECURITY_DOMAIN]:
2234 raise errors.HypervisorError("Cannot have a security domain when the"
2235 " security model is 'none' or 'pool'")
2237 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2238 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2240 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2241 # if an IP version is specified, the spice_bind parameter must be an
2243 if (netutils.IP4Address.IsValid(spice_bind) and
2244 spice_ip_version != constants.IP4_VERSION):
2245 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2246 " the specified IP version is %s" %
2247 (spice_bind, spice_ip_version))
2249 if (netutils.IP6Address.IsValid(spice_bind) and
2250 spice_ip_version != constants.IP6_VERSION):
2251 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2252 " the specified IP version is %s" %
2253 (spice_bind, spice_ip_version))
2255 # All the other SPICE parameters depend on spice_bind being set. Raise an
2256 # error if any of them is set without it.
2257 for param in _SPICE_ADDITIONAL_PARAMS:
2259 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2260 (param, constants.HV_KVM_SPICE_BIND))
2263 def ValidateParameters(cls, hvparams):
2264 """Check the given parameters for validity.
2266 @type hvparams: dict
2267 @param hvparams: dictionary with parameter names/value
2268 @raise errors.HypervisorError: when a parameter is not valid
2271 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2273 kvm_path = hvparams[constants.HV_KVM_PATH]
2275 security_model = hvparams[constants.HV_SECURITY_MODEL]
2276 if security_model == constants.HT_SM_USER:
2277 username = hvparams[constants.HV_SECURITY_DOMAIN]
2279 pwd.getpwnam(username)
2281 raise errors.HypervisorError("Unknown security domain user %s"
2284 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2286 # only one of VNC and SPICE can be used currently.
2287 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2288 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2289 " only one of them can be used at a"
2292 # check that KVM supports SPICE
2293 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2294 if not cls._SPICE_RE.search(kvmhelp):
2295 raise errors.HypervisorError("SPICE is configured, but it is not"
2296 " supported according to 'kvm --help'")
2298 # if spice_bind is not an IP address, it must be a valid interface
2299 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2300 netutils.IP6Address.IsValid(spice_bind))
2301 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2302 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2303 " a valid IP address or interface name" %
2304 constants.HV_KVM_SPICE_BIND)
2306 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2308 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2309 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2310 raise errors.HypervisorError("Unsupported machine version: %s" %
2314 def PowercycleNode(cls):
2315 """KVM powercycle, just a wrapper over Linux powercycle.
2318 cls.LinuxPowercycle()