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,
83 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
84 """Retrieves supported TUN features from file descriptor.
86 @see: L{_ProbeTapVnetHdr}
89 req = struct.pack("I", 0)
91 buf = _ioctl(fd, TUNGETFEATURES, req)
92 except EnvironmentError, err:
93 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
96 (flags, ) = struct.unpack("I", buf)
100 def _ProbeTapVnetHdr(fd, _features_fn=_GetTunFeatures):
101 """Check whether to enable the IFF_VNET_HDR flag.
103 To do this, _all_ of the following conditions must be met:
104 1. TUNGETFEATURES ioctl() *must* be implemented
105 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
106 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
107 drivers/net/tun.c there is no way to test this until after the tap device
108 has been created using TUNSETIFF, and there is no way to change the
109 IFF_VNET_HDR flag after creating the interface, catch-22! However both
110 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
111 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
114 @param fd: the file descriptor of /dev/net/tun
117 flags = _features_fn(fd)
123 result = bool(flags & IFF_VNET_HDR)
126 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
131 def _OpenTap(vnet_hdr=True):
132 """Open a new tap device and return its file descriptor.
134 This is intended to be used by a qemu-type hypervisor together with the -net
135 tap,fd=<fd> command line parameter.
137 @type vnet_hdr: boolean
138 @param vnet_hdr: Enable the VNET Header
139 @return: (ifname, tapfd)
144 tapfd = os.open("/dev/net/tun", os.O_RDWR)
145 except EnvironmentError:
146 raise errors.HypervisorError("Failed to open /dev/net/tun")
148 flags = IFF_TAP | IFF_NO_PI
150 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
151 flags |= IFF_VNET_HDR
153 # The struct ifreq ioctl request (see netdevice(7))
154 ifr = struct.pack("16sh", "", flags)
157 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
158 except EnvironmentError, err:
159 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
162 # Get the interface name from the ioctl
163 ifname = struct.unpack("16sh", res)[0].strip("\x00")
164 return (ifname, tapfd)
168 """QEMU Messaging Protocol (QMP) message.
171 def __init__(self, data):
172 """Creates a new QMP message based on the passed data.
175 if not isinstance(data, dict):
176 raise TypeError("QmpMessage must be initialized with a dict")
180 def __getitem__(self, field_name):
181 """Get the value of the required field if present, or None.
183 Overrides the [] operator to provide access to the message data,
184 returning None if the required item is not in the message
185 @return: the value of the field_name field, or None if field_name
186 is not contained in the message
189 return self.data.get(field_name, None)
191 def __setitem__(self, field_name, field_value):
192 """Set the value of the required field_name to field_value.
195 self.data[field_name] = field_value
198 def BuildFromJsonString(json_string):
199 """Build a QmpMessage from a JSON encoded string.
201 @type json_string: str
202 @param json_string: JSON string representing the message
203 @rtype: L{QmpMessage}
204 @return: a L{QmpMessage} built from json_string
208 data = serializer.LoadJson(json_string)
209 return QmpMessage(data)
212 # The protocol expects the JSON object to be sent as a single line.
213 return serializer.DumpJson(self.data)
215 def __eq__(self, other):
216 # When comparing two QmpMessages, we are interested in comparing
217 # their internal representation of the message data
218 return self.data == other.data
222 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
225 _FIRST_MESSAGE_KEY = "QMP"
228 _RETURN_KEY = RETURN_KEY = "return"
229 _ACTUAL_KEY = ACTUAL_KEY = "actual"
230 _ERROR_CLASS_KEY = "class"
231 _ERROR_DATA_KEY = "data"
232 _ERROR_DESC_KEY = "desc"
233 _EXECUTE_KEY = "execute"
234 _ARGUMENTS_KEY = "arguments"
235 _CAPABILITIES_COMMAND = "qmp_capabilities"
236 _MESSAGE_END_TOKEN = "\r\n"
239 def __init__(self, monitor_filename):
240 """Instantiates the QmpConnection object.
242 @type monitor_filename: string
243 @param monitor_filename: the filename of the UNIX raw socket on which the
244 QMP monitor is listening
247 self.monitor_filename = monitor_filename
248 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
249 # We want to fail if the server doesn't send a complete message
250 # in a reasonable amount of time
251 self.sock.settimeout(self._SOCKET_TIMEOUT)
252 self._connected = False
255 def _check_socket(self):
258 sock_stat = os.stat(self.monitor_filename)
259 except EnvironmentError, err:
260 if err.errno == errno.ENOENT:
261 raise errors.HypervisorError("No qmp socket found")
263 raise errors.HypervisorError("Error checking qmp socket: %s",
264 utils.ErrnoOrStr(err))
265 if not stat.S_ISSOCK(sock_stat.st_mode):
266 raise errors.HypervisorError("Qmp socket is not a socket")
268 def _check_connection(self):
269 """Make sure that the connection is established.
272 if not self._connected:
273 raise errors.ProgrammerError("To use a QmpConnection you need to first"
274 " invoke connect() on it")
277 """Connects to the QMP monitor.
279 Connects to the UNIX socket and makes sure that we can actually send and
280 receive data to the kvm instance via QMP.
282 @raise errors.HypervisorError: when there are communication errors
283 @raise errors.ProgrammerError: when there are data serialization errors
287 raise errors.ProgrammerError("Cannot connect twice")
291 # Check file existance/stuff
293 self.sock.connect(self.monitor_filename)
294 except EnvironmentError:
295 raise errors.HypervisorError("Can't connect to qmp socket")
296 self._connected = True
298 # Check if we receive a correct greeting message from the server
299 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
300 greeting = self._Recv()
301 if not greeting[self._FIRST_MESSAGE_KEY]:
302 self._connected = False
303 raise errors.HypervisorError("kvm: QMP communication error (wrong"
306 # Let's put the monitor in command mode using the qmp_capabilities
307 # command, or else no command will be executable.
308 # (As per the QEMU Protocol Specification 0.1 - section 4)
309 self.Execute(self._CAPABILITIES_COMMAND)
311 def _ParseMessage(self, buf):
312 """Extract and parse a QMP message from the given buffer.
314 Seeks for a QMP message in the given buf. If found, it parses it and
315 returns it together with the rest of the characters in the buf.
316 If no message is found, returns None and the whole buffer.
318 @raise errors.ProgrammerError: when there are data serialization errors
322 # Check if we got the message end token (CRLF, as per the QEMU Protocol
323 # Specification 0.1 - Section 2.1.1)
324 pos = buf.find(self._MESSAGE_END_TOKEN)
327 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
328 except Exception, err:
329 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
332 return (message, buf)
335 """Receives a message from QMP and decodes the received JSON object.
338 @return: the received message
339 @raise errors.HypervisorError: when there are communication errors
340 @raise errors.ProgrammerError: when there are data serialization errors
343 self._check_connection()
345 # Check if there is already a message in the buffer
346 (message, self._buf) = self._ParseMessage(self._buf)
350 recv_buffer = StringIO.StringIO(self._buf)
351 recv_buffer.seek(len(self._buf))
354 data = self.sock.recv(4096)
357 recv_buffer.write(data)
359 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
363 except socket.timeout, err:
364 raise errors.HypervisorError("Timeout while receiving a QMP message: "
366 except socket.error, err:
367 raise errors.HypervisorError("Unable to receive data from KVM using the"
368 " QMP protocol: %s" % err)
370 def _Send(self, message):
371 """Encodes and sends a message to KVM using QMP.
373 @type message: QmpMessage
374 @param message: message to send to KVM
375 @raise errors.HypervisorError: when there are communication errors
376 @raise errors.ProgrammerError: when there are data serialization errors
379 self._check_connection()
381 message_str = str(message)
382 except Exception, err:
383 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
386 self.sock.sendall(message_str)
387 except socket.timeout, err:
388 raise errors.HypervisorError("Timeout while sending a QMP message: "
389 "%s (%s)" % (err.string, err.errno))
390 except socket.error, err:
391 raise errors.HypervisorError("Unable to send data from KVM using the"
392 " QMP protocol: %s" % err)
394 def Execute(self, command, arguments=None):
395 """Executes a QMP command and returns the response of the server.
398 @param command: the command to execute
399 @type arguments: dict
400 @param arguments: dictionary of arguments to be passed to the command
402 @return: dictionary representing the received JSON object
403 @raise errors.HypervisorError: when there are communication errors
404 @raise errors.ProgrammerError: when there are data serialization errors
407 self._check_connection()
408 message = QmpMessage({self._EXECUTE_KEY: command})
410 message[self._ARGUMENTS_KEY] = arguments
413 # Events can occur between the sending of the command and the reception
414 # of the response, so we need to filter out messages with the event key.
416 response = self._Recv()
417 err = response[self._ERROR_KEY]
419 raise errors.HypervisorError("kvm: error executing the %s"
420 " command: %s (%s, %s):" %
422 err[self._ERROR_DESC_KEY],
423 err[self._ERROR_CLASS_KEY],
424 err[self._ERROR_DATA_KEY]))
426 elif not response[self._EVENT_KEY]:
430 class KVMHypervisor(hv_base.BaseHypervisor):
431 """KVM hypervisor interface
436 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
437 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
438 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
439 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
440 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
441 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
442 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
443 # KVM instances with chroot enabled are started in empty chroot directories.
444 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
445 # After an instance is stopped, its chroot directory is removed.
446 # If the chroot directory is not empty, it can't be removed.
447 # A non-empty chroot directory indicates a possible security incident.
448 # To support forensics, the non-empty chroot directory is quarantined in
449 # a separate directory, called 'chroot-quarantine'.
450 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
451 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
452 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
455 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
456 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
457 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
458 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
459 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
460 constants.HV_ACPI: hv_base.NO_CHECK,
461 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
462 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
463 constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later
464 constants.HV_VNC_TLS: hv_base.NO_CHECK,
465 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
466 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
467 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
468 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
469 constants.HV_KVM_SPICE_IP_VERSION:
470 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
471 x in constants.VALID_IP_VERSIONS),
472 "The SPICE IP version should be 4 or 6",
474 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
475 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
477 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
478 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
480 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
481 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
483 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
484 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
486 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
487 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
488 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
489 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
490 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
491 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
492 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
493 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
494 constants.HV_BOOT_ORDER:
495 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
496 constants.HV_NIC_TYPE:
497 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
498 constants.HV_DISK_TYPE:
499 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
500 constants.HV_KVM_CDROM_DISK_TYPE:
501 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
502 constants.HV_USB_MOUSE:
503 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
504 constants.HV_KEYMAP: hv_base.NO_CHECK,
505 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
506 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
507 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
508 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
509 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
510 constants.HV_DISK_CACHE:
511 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
512 constants.HV_SECURITY_MODEL:
513 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
514 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
515 constants.HV_KVM_FLAG:
516 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
517 constants.HV_VHOST_NET: hv_base.NO_CHECK,
518 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
519 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
520 constants.HV_REBOOT_BEHAVIOR:
521 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
522 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
523 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
524 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
525 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
526 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
527 constants.HV_SOUNDHW: hv_base.NO_CHECK,
528 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
529 constants.HV_VGA: hv_base.NO_CHECK,
530 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
531 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
532 constants.HV_VNET_HDR: hv_base.NO_CHECK,
536 _VIRTIO_NET_PCI = "virtio-net-pci"
538 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
540 _MIGRATION_PROGRESS_RE = \
541 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
542 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
543 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
545 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
546 _MIGRATION_INFO_RETRY_DELAY = 2
548 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
550 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
551 _CPU_INFO_CMD = "info cpus"
554 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
555 _CHECK_MACHINE_VERSION_RE = \
556 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
558 _QMP_RE = re.compile(r"^-qmp\s", re.M)
559 _SPICE_RE = re.compile(r"^-spice\s", re.M)
560 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
561 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
562 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
563 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
564 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
565 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
566 _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
567 # match -drive.*boot=on|off on different lines, but in between accept only
568 # dashes not preceeded by a new line (which would mean another option
569 # different than -drive is starting)
570 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
571 _UUID_RE = re.compile(r"^-uuid\s", re.M)
576 ANCILLARY_FILES_OPT = [
580 # Supported kvm options to get output from
581 _KVMOPT_HELP = "help"
582 _KVMOPT_MLIST = "mlist"
583 _KVMOPT_DEVICELIST = "devicelist"
585 # Command to execute to get the output from kvm, and whether to
586 # accept the output even on failure.
588 _KVMOPT_HELP: (["--help"], False),
589 _KVMOPT_MLIST: (["-M", "?"], False),
590 _KVMOPT_DEVICELIST: (["-device", "?"], True),
594 hv_base.BaseHypervisor.__init__(self)
595 # Let's make sure the directories we need exist, even if the RUN_DIR lives
596 # in a tmpfs filesystem or has been otherwise wiped out.
597 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
598 utils.EnsureDirs(dirs)
601 def _InstancePidFile(cls, instance_name):
602 """Returns the instance pidfile.
605 return utils.PathJoin(cls._PIDS_DIR, instance_name)
608 def _InstanceUidFile(cls, instance_name):
609 """Returns the instance uidfile.
612 return utils.PathJoin(cls._UIDS_DIR, instance_name)
615 def _InstancePidInfo(cls, pid):
616 """Check pid file for instance information.
618 Check that a pid file is associated with an instance, and retrieve
619 information from its command line.
621 @type pid: string or int
622 @param pid: process id of the instance to check
624 @return: (instance_name, memory, vcpus)
625 @raise errors.HypervisorError: when an instance cannot be found
628 alive = utils.IsProcessAlive(pid)
630 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
632 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
634 cmdline = utils.ReadFile(cmdline_file)
635 except EnvironmentError, err:
636 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
643 arg_list = cmdline.split("\x00")
645 arg = arg_list.pop(0)
647 instance = arg_list.pop(0)
649 memory = int(arg_list.pop(0))
651 vcpus = int(arg_list.pop(0).split(",")[0])
654 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
657 return (instance, memory, vcpus)
659 def _InstancePidAlive(self, instance_name):
660 """Returns the instance pidfile, pid, and liveness.
662 @type instance_name: string
663 @param instance_name: instance name
665 @return: (pid file name, pid, liveness)
668 pidfile = self._InstancePidFile(instance_name)
669 pid = utils.ReadPidFile(pidfile)
673 cmd_instance = self._InstancePidInfo(pid)[0]
674 alive = (cmd_instance == instance_name)
675 except errors.HypervisorError:
678 return (pidfile, pid, alive)
680 def _CheckDown(self, instance_name):
681 """Raises an error unless the given instance is down.
684 alive = self._InstancePidAlive(instance_name)[2]
686 raise errors.HypervisorError("Failed to start instance %s: %s" %
687 (instance_name, "already running"))
690 def _InstanceMonitor(cls, instance_name):
691 """Returns the instance monitor socket name
694 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
697 def _InstanceSerial(cls, instance_name):
698 """Returns the instance serial socket name
701 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
704 def _InstanceQmpMonitor(cls, instance_name):
705 """Returns the instance serial QMP socket name
708 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
711 def _SocatUnixConsoleParams():
712 """Returns the correct parameters for socat
714 If we have a new-enough socat we can use raw mode with an escape character.
717 if constants.SOCAT_USE_ESCAPE:
718 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
720 return "echo=0,icanon=0"
723 def _InstanceKVMRuntime(cls, instance_name):
724 """Returns the instance KVM runtime filename
727 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
730 def _InstanceChrootDir(cls, instance_name):
731 """Returns the name of the KVM chroot dir of the instance
734 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
737 def _InstanceNICDir(cls, instance_name):
738 """Returns the name of the directory holding the tap device files for a
742 return utils.PathJoin(cls._NICS_DIR, instance_name)
745 def _InstanceNICFile(cls, instance_name, seq):
746 """Returns the name of the file containing the tap device for a given NIC
749 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
752 def _InstanceKeymapFile(cls, instance_name):
753 """Returns the name of the file containing the keymap for a given instance
756 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
759 def _TryReadUidFile(cls, uid_file):
760 """Try to read a uid file
763 if os.path.exists(uid_file):
765 uid = int(utils.ReadOneLineFile(uid_file))
767 except EnvironmentError:
768 logging.warning("Can't read uid file", exc_info=True)
769 except (TypeError, ValueError):
770 logging.warning("Can't parse uid file contents", exc_info=True)
774 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
775 """Removes an instance's rutime sockets/files/dirs.
778 utils.RemoveFile(pidfile)
779 utils.RemoveFile(cls._InstanceMonitor(instance_name))
780 utils.RemoveFile(cls._InstanceSerial(instance_name))
781 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
782 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
783 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
784 uid_file = cls._InstanceUidFile(instance_name)
785 uid = cls._TryReadUidFile(uid_file)
786 utils.RemoveFile(uid_file)
788 uidpool.ReleaseUid(uid)
790 shutil.rmtree(cls._InstanceNICDir(instance_name))
792 if err.errno != errno.ENOENT:
795 chroot_dir = cls._InstanceChrootDir(instance_name)
796 utils.RemoveDir(chroot_dir)
798 if err.errno == errno.ENOTEMPTY:
799 # The chroot directory is expected to be empty, but it isn't.
800 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
803 utils.TimestampForFilename()))
804 logging.warning("The chroot directory of instance %s can not be"
805 " removed as it is not empty. Moving it to the"
806 " quarantine instead. Please investigate the"
807 " contents (%s) and clean up manually",
808 instance_name, new_chroot_dir)
809 utils.RenameFile(chroot_dir, new_chroot_dir)
814 def _ConfigureNIC(instance, seq, nic, tap):
815 """Run the network configuration script for a specified NIC
817 @param instance: instance we're acting on
818 @type instance: instance object
819 @param seq: nic sequence number
821 @param nic: nic we're acting on
822 @type nic: nic object
823 @param tap: the host's tap interface this NIC corresponds to
828 tags = " ".join(instance.tags)
833 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
834 "INSTANCE": instance.name,
836 "MODE": nic.nicparams[constants.NIC_MODE],
838 "INTERFACE_INDEX": str(seq),
845 if nic.nicparams[constants.NIC_LINK]:
846 env["LINK"] = nic.nicparams[constants.NIC_LINK]
849 n = objects.Network.FromDict(nic.netinfo)
850 env.update(n.HooksDict())
852 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
853 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
855 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
857 raise errors.HypervisorError("Failed to configure interface %s: %s;"
858 " network configuration script output: %s" %
859 (tap, result.fail_reason, result.output))
862 def _VerifyAffinityPackage():
864 raise errors.HypervisorError("affinity Python package not"
865 " found; cannot use CPU pinning under KVM")
868 def _BuildAffinityCpuMask(cpu_list):
869 """Create a CPU mask suitable for sched_setaffinity from a list of
872 See man taskset for more info on sched_setaffinity masks.
873 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
875 @type cpu_list: list of int
876 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
878 @return: a bit mask of CPU affinities
881 if cpu_list == constants.CPU_PINNING_OFF:
882 return constants.CPU_PINNING_ALL_KVM
884 return sum(2 ** cpu for cpu in cpu_list)
887 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
888 """Change CPU affinity for running VM according to given CPU mask.
890 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
891 @type cpu_mask: string
892 @param process_id: process ID of KVM process. Used to pin entire VM
894 @type process_id: int
895 @param thread_dict: map of virtual CPUs to KVM thread IDs
896 @type thread_dict: dict int:int
899 # Convert the string CPU mask to a list of list of int's
900 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
902 if len(cpu_list) == 1:
903 all_cpu_mapping = cpu_list[0]
904 if all_cpu_mapping == constants.CPU_PINNING_OFF:
905 # If CPU pinning has 1 entry that's "all", then do nothing
908 # If CPU pinning has one non-all entry, map the entire VM to
909 # one set of physical CPUs
910 cls._VerifyAffinityPackage()
911 affinity.set_process_affinity_mask(
912 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
914 # The number of vCPUs mapped should match the number of vCPUs
915 # reported by KVM. This was already verified earlier, so
916 # here only as a sanity check.
917 assert len(thread_dict) == len(cpu_list)
918 cls._VerifyAffinityPackage()
920 # For each vCPU, map it to the proper list of physical CPUs
921 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
922 affinity.set_process_affinity_mask(thread_dict[i],
923 cls._BuildAffinityCpuMask(vcpu))
925 def _GetVcpuThreadIds(self, instance_name):
926 """Get a mapping of vCPU no. to thread IDs for the instance
928 @type instance_name: string
929 @param instance_name: instance in question
930 @rtype: dictionary of int:int
931 @return: a dictionary mapping vCPU numbers to thread IDs
935 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
936 for line in output.stdout.splitlines():
937 match = self._CPU_INFO_RE.search(line)
940 grp = map(int, match.groups())
941 result[grp[0]] = grp[1]
945 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
946 """Complete CPU pinning.
948 @type instance_name: string
949 @param instance_name: name of instance
950 @type cpu_mask: string
951 @param cpu_mask: CPU pinning mask as entered by user
954 # Get KVM process ID, to be used if need to pin entire VM
955 _, pid, _ = self._InstancePidAlive(instance_name)
956 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
957 thread_dict = self._GetVcpuThreadIds(instance_name)
958 # Run CPU pinning, based on configured mask
959 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
961 def ListInstances(self, hvparams=None):
962 """Get the list of running instances.
964 We can do this by listing our live instances directory and
965 checking whether the associated kvm process is still alive.
969 for name in os.listdir(self._PIDS_DIR):
970 if self._InstancePidAlive(name)[2]:
974 def GetInstanceInfo(self, instance_name, hvparams=None):
975 """Get instance properties.
977 @type instance_name: string
978 @param instance_name: the instance name
979 @type hvparams: dict of strings
980 @param hvparams: hvparams to be used with this instance
981 @rtype: tuple of strings
982 @return: (name, id, memory, vcpus, stat, times)
985 _, pid, alive = self._InstancePidAlive(instance_name)
989 _, memory, vcpus = self._InstancePidInfo(pid)
994 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
996 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
997 # Will fail if ballooning is not enabled, but we can then just resort to
999 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1000 memory = mem_bytes / 1048576
1001 except errors.HypervisorError:
1004 return (instance_name, pid, memory, vcpus, istat, times)
1006 def GetAllInstancesInfo(self, hvparams=None):
1007 """Get properties of all instances.
1009 @type hvparams: dict of strings
1010 @param hvparams: hypervisor parameter
1011 @return: list of tuples (name, id, memory, vcpus, stat, times)
1015 for name in os.listdir(self._PIDS_DIR):
1017 info = self.GetInstanceInfo(name)
1018 except errors.HypervisorError:
1019 # Ignore exceptions due to instances being shut down
1025 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1027 """Generate KVM information to start an instance.
1029 @type kvmhelp: string
1030 @param kvmhelp: output of kvm --help
1031 @attention: this function must not have any side-effects; for
1032 example, it must not write to the filesystem, or read values
1033 from the current system the are expected to differ between
1034 nodes, since it is only run once at instance startup;
1035 actions/kvm arguments that can vary between systems should be
1036 done in L{_ExecuteKVMRuntime}
1039 # pylint: disable=R0912,R0914,R0915
1040 hvp = instance.hvparams
1041 self.ValidateParameters(hvp)
1043 pidfile = self._InstancePidFile(instance.name)
1044 kvm = hvp[constants.HV_KVM_PATH]
1046 # used just by the vnc server, if enabled
1047 kvm_cmd.extend(["-name", instance.name])
1048 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1050 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1051 if hvp[constants.HV_CPU_CORES]:
1052 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1053 if hvp[constants.HV_CPU_THREADS]:
1054 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1055 if hvp[constants.HV_CPU_SOCKETS]:
1056 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1058 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1060 kvm_cmd.extend(["-pidfile", pidfile])
1061 kvm_cmd.extend(["-balloon", "virtio"])
1062 kvm_cmd.extend(["-daemonize"])
1063 if not instance.hvparams[constants.HV_ACPI]:
1064 kvm_cmd.extend(["-no-acpi"])
1065 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1066 constants.INSTANCE_REBOOT_EXIT:
1067 kvm_cmd.extend(["-no-reboot"])
1069 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1071 mversion = self._GetDefaultMachineVersion(kvm)
1072 if self._MACHINE_RE.search(kvmhelp):
1073 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1074 # extra hypervisor parameters. We should also investigate whether and how
1075 # shadow_mem should be considered for the resource model.
1076 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1077 specprop = ",accel=kvm"
1080 machinespec = "%s%s" % (mversion, specprop)
1081 kvm_cmd.extend(["-machine", machinespec])
1083 kvm_cmd.extend(["-M", mversion])
1084 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1085 self._ENABLE_KVM_RE.search(kvmhelp)):
1086 kvm_cmd.extend(["-enable-kvm"])
1087 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1088 self._DISABLE_KVM_RE.search(kvmhelp)):
1089 kvm_cmd.extend(["-disable-kvm"])
1091 kernel_path = hvp[constants.HV_KERNEL_PATH]
1093 boot_disk = boot_cdrom = boot_floppy = boot_network = False
1095 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1096 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1097 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1098 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1101 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1104 kvm_cmd.extend(["-boot", "n"])
1106 # whether this is an older KVM version that uses the boot=on flag
1108 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1110 disk_type = hvp[constants.HV_DISK_TYPE]
1111 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1112 if_val = ",if=virtio"
1114 if_val = ",if=%s" % disk_type
1116 disk_cache = hvp[constants.HV_DISK_CACHE]
1117 if instance.disk_template in constants.DTS_EXT_MIRROR:
1118 if disk_cache != "none":
1119 # TODO: make this a hard error, instead of a silent overwrite
1120 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1121 " to prevent shared storage corruption on migration",
1123 cache_val = ",cache=none"
1124 elif disk_cache != constants.HT_CACHE_DEFAULT:
1125 cache_val = ",cache=%s" % disk_cache
1128 for cfdev, dev_path in block_devices:
1129 if cfdev.mode != constants.DISK_RDWR:
1130 raise errors.HypervisorError("Instance has read-only disks which"
1131 " are not supported by KVM")
1132 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1135 kvm_cmd.extend(["-boot", "c"])
1137 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1138 boot_val = ",boot=on"
1140 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1142 kvm_cmd.extend(["-drive", drive_val])
1144 #Now we can specify a different device type for CDROM devices.
1145 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1146 if not cdrom_disk_type:
1147 cdrom_disk_type = disk_type
1149 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1151 options = ",format=raw,media=cdrom"
1152 # set cdrom 'if' type
1154 actual_cdrom_type = constants.HT_DISK_IDE
1155 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1156 actual_cdrom_type = "virtio"
1158 actual_cdrom_type = cdrom_disk_type
1159 if_val = ",if=%s" % actual_cdrom_type
1160 # set boot flag, if needed
1163 kvm_cmd.extend(["-boot", "d"])
1165 boot_val = ",boot=on"
1166 # and finally build the entire '-drive' value
1167 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1168 kvm_cmd.extend(["-drive", drive_val])
1170 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1172 options = ",format=raw,media=cdrom"
1173 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1174 if_val = ",if=virtio"
1176 if_val = ",if=%s" % cdrom_disk_type
1177 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1178 kvm_cmd.extend(["-drive", drive_val])
1180 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1182 options = ",format=raw,media=disk"
1184 kvm_cmd.extend(["-boot", "a"])
1185 options = "%s,boot=on" % options
1186 if_val = ",if=floppy"
1187 options = "%s%s" % (options, if_val)
1188 drive_val = "file=%s%s" % (floppy_image, options)
1189 kvm_cmd.extend(["-drive", drive_val])
1192 kvm_cmd.extend(["-kernel", kernel_path])
1193 initrd_path = hvp[constants.HV_INITRD_PATH]
1195 kvm_cmd.extend(["-initrd", initrd_path])
1196 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1197 hvp[constants.HV_KERNEL_ARGS]]
1198 if hvp[constants.HV_SERIAL_CONSOLE]:
1199 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1200 root_append.append("console=ttyS0,%s" % serial_speed)
1201 kvm_cmd.extend(["-append", " ".join(root_append)])
1203 mem_path = hvp[constants.HV_MEM_PATH]
1205 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1207 monitor_dev = ("unix:%s,server,nowait" %
1208 self._InstanceMonitor(instance.name))
1209 kvm_cmd.extend(["-monitor", monitor_dev])
1210 if hvp[constants.HV_SERIAL_CONSOLE]:
1211 serial_dev = ("unix:%s,server,nowait" %
1212 self._InstanceSerial(instance.name))
1213 kvm_cmd.extend(["-serial", serial_dev])
1215 kvm_cmd.extend(["-serial", "none"])
1217 mouse_type = hvp[constants.HV_USB_MOUSE]
1218 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1219 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1220 spice_ip_version = None
1222 kvm_cmd.extend(["-usb"])
1225 kvm_cmd.extend(["-usbdevice", mouse_type])
1226 elif vnc_bind_address:
1227 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1229 if vnc_bind_address:
1230 if netutils.IsValidInterface(vnc_bind_address):
1231 if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
1232 if_ip4_addresses = if_addresses[constants.IP4_VERSION]
1233 if len(if_ip4_addresses) < 1:
1234 logging.error("Could not determine IPv4 address of interface %s",
1237 vnc_bind_address = if_ip4_addresses[0]
1238 if netutils.IP4Address.IsValid(vnc_bind_address):
1239 if instance.network_port > constants.VNC_BASE_PORT:
1240 display = instance.network_port - constants.VNC_BASE_PORT
1241 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1242 vnc_arg = ":%d" % (display)
1244 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1246 logging.error("Network port is not a valid VNC display (%d < %d),"
1247 " not starting VNC",
1248 instance.network_port, constants.VNC_BASE_PORT)
1251 # Only allow tls and other option when not binding to a file, for now.
1252 # kvm/qemu gets confused otherwise about the filename to use.
1254 if hvp[constants.HV_VNC_TLS]:
1255 vnc_append = "%s,tls" % vnc_append
1256 if hvp[constants.HV_VNC_X509_VERIFY]:
1257 vnc_append = "%s,x509verify=%s" % (vnc_append,
1258 hvp[constants.HV_VNC_X509])
1259 elif hvp[constants.HV_VNC_X509]:
1260 vnc_append = "%s,x509=%s" % (vnc_append,
1261 hvp[constants.HV_VNC_X509])
1262 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1263 vnc_append = "%s,password" % vnc_append
1265 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1268 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1270 kvm_cmd.extend(["-vnc", vnc_arg])
1272 # FIXME: this is wrong here; the iface ip address differs
1273 # between systems, so it should be done in _ExecuteKVMRuntime
1274 if netutils.IsValidInterface(spice_bind):
1275 # The user specified a network interface, we have to figure out the IP
1277 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1278 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1280 # if the user specified an IP version and the interface does not
1281 # have that kind of IP addresses, throw an exception
1282 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1283 if not addresses[spice_ip_version]:
1284 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1285 " for %s" % (spice_ip_version,
1288 # the user did not specify an IP version, we have to figure it out
1289 elif (addresses[constants.IP4_VERSION] and
1290 addresses[constants.IP6_VERSION]):
1291 # we have both ipv4 and ipv6, let's use the cluster default IP
1293 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1294 spice_ip_version = \
1295 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1296 elif addresses[constants.IP4_VERSION]:
1297 spice_ip_version = constants.IP4_VERSION
1298 elif addresses[constants.IP6_VERSION]:
1299 spice_ip_version = constants.IP6_VERSION
1301 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1302 " for %s" % (spice_bind))
1304 spice_address = addresses[spice_ip_version][0]
1307 # spice_bind is known to be a valid IP address, because
1308 # ValidateParameters checked it.
1309 spice_address = spice_bind
1311 spice_arg = "addr=%s" % spice_address
1312 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1313 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1314 (spice_arg, instance.network_port,
1315 pathutils.SPICE_CACERT_FILE))
1316 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1317 (spice_arg, pathutils.SPICE_CERT_FILE,
1318 pathutils.SPICE_CERT_FILE))
1319 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1321 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1323 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1325 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1326 spice_arg = "%s,disable-ticketing" % spice_arg
1328 if spice_ip_version:
1329 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1331 # Image compression options
1332 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1333 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1334 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1336 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1338 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1340 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1342 # Video stream detection
1343 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1345 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1347 # Audio compression, by default in qemu-kvm it is on
1348 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1349 spice_arg = "%s,playback-compression=off" % spice_arg
1350 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1351 spice_arg = "%s,agent-mouse=off" % spice_arg
1353 # Enable the spice agent communication channel between the host and the
1355 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1358 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1360 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1362 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1363 kvm_cmd.extend(["-spice", spice_arg])
1366 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1367 # also works in earlier versions though (tested with 1.1 and 1.3)
1368 if self._DISPLAY_RE.search(kvmhelp):
1369 kvm_cmd.extend(["-display", "none"])
1371 kvm_cmd.extend(["-nographic"])
1373 if hvp[constants.HV_USE_LOCALTIME]:
1374 kvm_cmd.extend(["-localtime"])
1376 if hvp[constants.HV_KVM_USE_CHROOT]:
1377 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1379 # Add qemu-KVM -cpu param
1380 if hvp[constants.HV_CPU_TYPE]:
1381 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1383 # As requested by music lovers
1384 if hvp[constants.HV_SOUNDHW]:
1385 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1387 # Pass a -vga option if requested, or if spice is used, for backwards
1389 if hvp[constants.HV_VGA]:
1390 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1392 kvm_cmd.extend(["-vga", "qxl"])
1394 # Various types of usb devices, comma separated
1395 if hvp[constants.HV_USB_DEVICES]:
1396 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1397 kvm_cmd.extend(["-usbdevice", dev])
1399 # Set system UUID to instance UUID
1400 if self._UUID_RE.search(kvmhelp):
1401 kvm_cmd.extend(["-uuid", instance.uuid])
1403 if hvp[constants.HV_KVM_EXTRA]:
1404 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1406 # Save the current instance nics, but defer their expansion as parameters,
1407 # as we'll need to generate executable temp files for them.
1408 kvm_nics = instance.nics
1411 return (kvm_cmd, kvm_nics, hvparams)
1413 def _WriteKVMRuntime(self, instance_name, data):
1414 """Write an instance's KVM runtime
1418 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1420 except EnvironmentError, err:
1421 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1423 def _ReadKVMRuntime(self, instance_name):
1424 """Read an instance's KVM runtime
1428 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1429 except EnvironmentError, err:
1430 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1433 def _SaveKVMRuntime(self, instance, kvm_runtime):
1434 """Save an instance's KVM runtime
1437 kvm_cmd, kvm_nics, hvparams = kvm_runtime
1438 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1439 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1440 self._WriteKVMRuntime(instance.name, serialized_form)
1442 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1443 """Load an instance's KVM runtime
1446 if not serialized_runtime:
1447 serialized_runtime = self._ReadKVMRuntime(instance.name)
1448 loaded_runtime = serializer.Load(serialized_runtime)
1449 kvm_cmd, serialized_nics, hvparams = loaded_runtime
1450 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1451 return (kvm_cmd, kvm_nics, hvparams)
1453 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1454 """Run the KVM cmd and check for errors
1457 @param name: instance name
1458 @type kvm_cmd: list of strings
1459 @param kvm_cmd: runcmd input for kvm
1460 @type tap_fds: list of int
1461 @param tap_fds: fds of tap devices opened by Ganeti
1465 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1468 utils_wrapper.CloseFdNoError(fd)
1471 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1472 (name, result.fail_reason, result.output))
1473 if not self._InstancePidAlive(name)[2]:
1474 raise errors.HypervisorError("Failed to start instance %s" % name)
1476 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1477 """Execute a KVM cmd, after completing it with some last minute data.
1479 @type incoming: tuple of strings
1480 @param incoming: (target_host_ip, port)
1481 @type kvmhelp: string
1482 @param kvmhelp: output of kvm --help
1485 # Small _ExecuteKVMRuntime hv parameters programming howto:
1486 # - conf_hvp contains the parameters as configured on ganeti. they might
1487 # have changed since the instance started; only use them if the change
1488 # won't affect the inside of the instance (which hasn't been rebooted).
1489 # - up_hvp contains the parameters as they were when the instance was
1490 # started, plus any new parameter which has been added between ganeti
1491 # versions: it is paramount that those default to a value which won't
1492 # affect the inside of the instance as well.
1493 conf_hvp = instance.hvparams
1494 name = instance.name
1495 self._CheckDown(name)
1499 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1500 # the first element of kvm_cmd is always the path to the kvm binary
1501 kvm_path = kvm_cmd[0]
1502 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1504 # We know it's safe to run as a different user upon migration, so we'll use
1505 # the latest conf, from conf_hvp.
1506 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1507 if security_model == constants.HT_SM_USER:
1508 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1510 keymap = conf_hvp[constants.HV_KEYMAP]
1512 keymap_path = self._InstanceKeymapFile(name)
1513 # If a keymap file is specified, KVM won't use its internal defaults. By
1514 # first including the "en-us" layout, an error on loading the actual
1515 # layout (e.g. because it can't be found) won't lead to a non-functional
1516 # keyboard. A keyboard with incorrect keys is still better than none.
1517 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1518 kvm_cmd.extend(["-k", keymap_path])
1520 # We have reasons to believe changing something like the nic driver/type
1521 # upon migration won't exactly fly with the instance kernel, so for nic
1522 # related parameters we'll use up_hvp
1526 kvm_cmd.extend(["-net", "none"])
1530 nic_type = up_hvp[constants.HV_NIC_TYPE]
1531 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1532 nic_model = self._VIRTIO
1534 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1535 if self._NEW_VIRTIO_RE.search(devlist):
1536 nic_model = self._VIRTIO_NET_PCI
1537 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1538 except errors.HypervisorError, _:
1539 # Older versions of kvm don't support DEVICE_LIST, but they don't
1540 # have new virtio syntax either.
1543 if up_hvp[constants.HV_VHOST_NET]:
1544 # check for vhost_net support
1545 if self._VHOST_RE.search(kvmhelp):
1546 tap_extra = ",vhost=on"
1548 raise errors.HypervisorError("vhost_net is configured"
1549 " but it is not available")
1551 nic_model = nic_type
1553 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1555 for nic_seq, nic in enumerate(kvm_nics):
1556 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1557 tapfds.append(tapfd)
1558 taps.append(tapname)
1559 if kvm_supports_netdev:
1560 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1561 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1562 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1564 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1566 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1567 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1570 target, port = incoming
1571 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1573 # Changing the vnc password doesn't bother the guest that much. At most it
1574 # will surprise people who connect to it. Whether positively or negatively
1576 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1580 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1581 except EnvironmentError, err:
1582 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1583 % (vnc_pwd_file, err))
1585 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1586 utils.EnsureDirs([(self._InstanceChrootDir(name),
1587 constants.SECURE_DIR_MODE)])
1589 # Automatically enable QMP if version is >= 0.14
1590 if self._QMP_RE.search(kvmhelp):
1591 logging.debug("Enabling QMP")
1592 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1593 self._InstanceQmpMonitor(instance.name)])
1595 # Configure the network now for starting instances and bridged interfaces,
1596 # during FinalizeMigration for incoming instances' routed interfaces
1597 for nic_seq, nic in enumerate(kvm_nics):
1599 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1601 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1603 # CPU affinity requires kvm to start paused, so we set this flag if the
1604 # instance is not already paused and if we are not going to accept a
1605 # migrating instance. In the latter case, pausing is not needed.
1606 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1607 if start_kvm_paused:
1608 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1610 # Note: CPU pinning is using up_hvp since changes take effect
1611 # during instance startup anyway, and to avoid problems when soft
1612 # rebooting the instance.
1614 if up_hvp.get(constants.HV_CPU_MASK, None):
1617 if security_model == constants.HT_SM_POOL:
1618 ss = ssconf.SimpleStore()
1619 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1620 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1621 uid = uidpool.RequestUnusedUid(all_uids)
1623 username = pwd.getpwuid(uid.GetUid()).pw_name
1624 kvm_cmd.extend(["-runas", username])
1625 self._RunKVMCmd(name, kvm_cmd, tapfds)
1627 uidpool.ReleaseUid(uid)
1631 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1633 self._RunKVMCmd(name, kvm_cmd, tapfds)
1635 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1636 constants.RUN_DIRS_MODE)])
1637 for nic_seq, tap in enumerate(taps):
1638 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1642 change_cmd = "change vnc password %s" % vnc_pwd
1643 self._CallMonitorCommand(instance.name, change_cmd)
1645 # Setting SPICE password. We are not vulnerable to malicious passwordless
1646 # connection attempts because SPICE by default does not allow connections
1647 # if neither a password nor the "disable_ticketing" options are specified.
1648 # As soon as we send the password via QMP, that password is a valid ticket
1650 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1651 if spice_password_file:
1654 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1655 except EnvironmentError, err:
1656 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1657 % (spice_password_file, err))
1659 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1662 "protocol": "spice",
1663 "password": spice_pwd,
1665 qmp.Execute("set_password", arguments)
1667 for filename in temp_files:
1668 utils.RemoveFile(filename)
1670 # If requested, set CPU affinity and resume instance execution
1672 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1674 start_memory = self._InstanceStartupMemory(instance)
1675 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1676 self.BalloonInstanceMemory(instance, start_memory)
1678 if start_kvm_paused:
1679 # To control CPU pinning, ballooning, and vnc/spice passwords
1680 # the VM was started in a frozen state. If freezing was not
1681 # explicitly requested resume the vm status.
1682 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1684 def StartInstance(self, instance, block_devices, startup_paused):
1685 """Start an instance.
1688 self._CheckDown(instance.name)
1689 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1690 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1691 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1692 startup_paused, kvmhelp)
1693 self._SaveKVMRuntime(instance, kvm_runtime)
1694 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1696 def _CallMonitorCommand(self, instance_name, command):
1697 """Invoke a command on the instance monitor.
1700 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1701 # version. The monitor protocol is designed for human consumption, whereas
1702 # QMP is made for programmatic usage. In the worst case QMP can also
1703 # execute monitor commands. As it is, all calls to socat take at least
1704 # 500ms and likely more: socat can't detect the end of the reply and waits
1705 # for 500ms of no data received before exiting (500 ms is the default for
1706 # the "-t" parameter).
1707 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1708 (utils.ShellQuote(command),
1709 constants.SOCAT_PATH,
1710 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1711 result = utils.RunCmd(socat)
1713 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1715 (command, instance_name, result.fail_reason, result.output))
1716 raise errors.HypervisorError(msg)
1721 def _ParseKVMVersion(cls, text):
1722 """Parse the KVM version from the --help output.
1725 @param text: output of kvm --help
1726 @return: (version, v_maj, v_min, v_rev)
1727 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1730 match = cls._VERSION_RE.search(text.splitlines()[0])
1732 raise errors.HypervisorError("Unable to get KVM version")
1734 v_all = match.group(0)
1735 v_maj = int(match.group(1))
1736 v_min = int(match.group(2))
1738 v_rev = int(match.group(4))
1741 return (v_all, v_maj, v_min, v_rev)
1744 def _GetKVMOutput(cls, kvm_path, option):
1745 """Return the output of a kvm invocation
1747 @type kvm_path: string
1748 @param kvm_path: path to the kvm executable
1749 @type option: a key of _KVMOPTS_CMDS
1750 @param option: kvm option to fetch the output from
1751 @return: output a supported kvm invocation
1752 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1755 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1757 optlist, can_fail = cls._KVMOPTS_CMDS[option]
1759 result = utils.RunCmd([kvm_path] + optlist)
1760 if result.failed and not can_fail:
1761 raise errors.HypervisorError("Unable to get KVM %s output" %
1762 " ".join(cls._KVMOPTS_CMDS[option]))
1763 return result.output
1766 def _GetKVMVersion(cls, kvm_path):
1767 """Return the installed KVM version.
1769 @return: (version, v_maj, v_min, v_rev)
1770 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1773 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1776 def _GetDefaultMachineVersion(cls, kvm_path):
1777 """Return the default hardware revision (e.g. pc-1.1)
1780 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1781 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1783 return match.group(1)
1787 def StopInstance(self, instance, force=False, retry=False, name=None):
1788 """Stop an instance.
1791 if name is not None and not force:
1792 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1794 name = instance.name
1795 acpi = instance.hvparams[constants.HV_ACPI]
1798 _, pid, alive = self._InstancePidAlive(name)
1799 if pid > 0 and alive:
1800 if force or not acpi:
1801 utils.KillProcess(pid)
1803 self._CallMonitorCommand(name, "system_powerdown")
1805 def CleanupInstance(self, instance_name):
1806 """Cleanup after a stopped instance
1809 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1810 if pid > 0 and alive:
1811 raise errors.HypervisorError("Cannot cleanup a live instance")
1812 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1814 def RebootInstance(self, instance):
1815 """Reboot an instance.
1818 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1819 # socket the instance will stop, but now power up again. So we'll resort
1820 # to shutdown and restart.
1821 _, _, alive = self._InstancePidAlive(instance.name)
1823 raise errors.HypervisorError("Failed to reboot instance %s:"
1824 " not running" % instance.name)
1825 # StopInstance will delete the saved KVM runtime so:
1826 # ...first load it...
1827 kvm_runtime = self._LoadKVMRuntime(instance)
1828 # ...now we can safely call StopInstance...
1829 if not self.StopInstance(instance):
1830 self.StopInstance(instance, force=True)
1831 # ...and finally we can save it again, and execute it...
1832 self._SaveKVMRuntime(instance, kvm_runtime)
1833 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1834 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1835 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1837 def MigrationInfo(self, instance):
1838 """Get instance information to perform a migration.
1840 @type instance: L{objects.Instance}
1841 @param instance: instance to be migrated
1843 @return: content of the KVM runtime file
1846 return self._ReadKVMRuntime(instance.name)
1848 def AcceptInstance(self, instance, info, target):
1849 """Prepare to accept an instance.
1851 @type instance: L{objects.Instance}
1852 @param instance: instance to be accepted
1854 @param info: content of the KVM runtime file on the source node
1855 @type target: string
1856 @param target: target host (usually ip), on this node
1859 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1860 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1861 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1862 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1863 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1864 incoming=incoming_address)
1866 def FinalizeMigrationDst(self, instance, info, success):
1867 """Finalize the instance migration on the target node.
1869 Stop the incoming mode KVM.
1871 @type instance: L{objects.Instance}
1872 @param instance: instance whose migration is being finalized
1876 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1877 kvm_nics = kvm_runtime[1]
1879 for nic_seq, nic in enumerate(kvm_nics):
1880 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1881 # Bridged interfaces have already been configured
1884 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1885 except EnvironmentError, err:
1886 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1887 instance.name, nic_seq, str(err))
1890 self._ConfigureNIC(instance, nic_seq, nic, tap)
1891 except errors.HypervisorError, err:
1892 logging.warning(str(err))
1894 self._WriteKVMRuntime(instance.name, info)
1896 self.StopInstance(instance, force=True)
1898 def MigrateInstance(self, cluster_name, instance, target, live):
1899 """Migrate an instance to a target node.
1901 The migration will not be attempted if the instance is not
1904 @type cluster_name: string
1905 @param cluster_name: name of the cluster
1906 @type instance: L{objects.Instance}
1907 @param instance: the instance to be migrated
1908 @type target: string
1909 @param target: ip address of the target node
1911 @param live: perform a live migration
1914 instance_name = instance.name
1915 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1916 _, _, alive = self._InstancePidAlive(instance_name)
1918 raise errors.HypervisorError("Instance not running, cannot migrate")
1921 self._CallMonitorCommand(instance_name, "stop")
1923 migrate_command = ("migrate_set_speed %dm" %
1924 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1925 self._CallMonitorCommand(instance_name, migrate_command)
1927 migrate_command = ("migrate_set_downtime %dms" %
1928 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1929 self._CallMonitorCommand(instance_name, migrate_command)
1931 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1932 self._CallMonitorCommand(instance_name, migrate_command)
1934 def FinalizeMigrationSource(self, instance, success, live):
1935 """Finalize the instance migration on the source node.
1937 @type instance: L{objects.Instance}
1938 @param instance: the instance that was migrated
1940 @param success: whether the migration succeeded or not
1942 @param live: whether the user requested a live migration or not
1946 pidfile, pid, _ = self._InstancePidAlive(instance.name)
1947 utils.KillProcess(pid)
1948 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1950 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1952 def GetMigrationStatus(self, instance):
1953 """Get the migration status
1955 @type instance: L{objects.Instance}
1956 @param instance: the instance that is being migrated
1957 @rtype: L{objects.MigrationStatus}
1958 @return: the status of the current migration (one of
1959 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1960 progress info that can be retrieved from the hypervisor
1963 info_command = "info migrate"
1964 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1965 result = self._CallMonitorCommand(instance.name, info_command)
1966 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1968 if not result.stdout:
1969 logging.info("KVM: empty 'info migrate' result")
1971 logging.warning("KVM: unknown 'info migrate' result: %s",
1974 status = match.group(1)
1975 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1976 migration_status = objects.MigrationStatus(status=status)
1977 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1979 migration_status.transferred_ram = match.group("transferred")
1980 migration_status.total_ram = match.group("total")
1982 return migration_status
1984 logging.warning("KVM: unknown migration status '%s'", status)
1986 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1988 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1990 def BalloonInstanceMemory(self, instance, mem):
1991 """Balloon an instance memory to a certain value.
1993 @type instance: L{objects.Instance}
1994 @param instance: instance to be accepted
1996 @param mem: actual memory size to use for instance runtime
1999 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2001 def GetNodeInfo(self, hvparams=None):
2002 """Return information about the node.
2004 @type hvparams: dict of strings
2005 @param hvparams: hypervisor parameters, not used in this class
2007 @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus
2009 - hv_version: the hypervisor version in the form (major, minor,
2013 result = self.GetLinuxNodeInfo()
2014 # FIXME: this is the global kvm version, but the actual version can be
2015 # customized as an hv parameter. we should use the nodegroup's default kvm
2016 # path parameter here.
2017 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2018 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2022 def GetInstanceConsole(cls, instance, primary_node, hvparams, beparams):
2023 """Return a command for connecting to the console of an instance.
2026 if hvparams[constants.HV_SERIAL_CONSOLE]:
2027 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2028 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2029 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2030 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2031 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2032 return objects.InstanceConsole(instance=instance.name,
2033 kind=constants.CONS_SSH,
2034 host=primary_node.name,
2035 user=constants.SSH_CONSOLE_USER,
2038 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2039 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2040 display = instance.network_port - constants.VNC_BASE_PORT
2041 return objects.InstanceConsole(instance=instance.name,
2042 kind=constants.CONS_VNC,
2043 host=vnc_bind_address,
2044 port=instance.network_port,
2047 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2049 return objects.InstanceConsole(instance=instance.name,
2050 kind=constants.CONS_SPICE,
2052 port=instance.network_port)
2054 return objects.InstanceConsole(instance=instance.name,
2055 kind=constants.CONS_MESSAGE,
2056 message=("No serial shell for instance %s" %
2059 def Verify(self, hvparams=None):
2060 """Verify the hypervisor.
2062 Check that the required binaries exist.
2064 @type hvparams: dict of strings
2065 @param hvparams: hypervisor parameters to be verified against, not used here
2067 @return: Problem description if something is wrong, C{None} otherwise
2071 # FIXME: this is the global kvm binary, but the actual path can be
2072 # customized as an hv parameter; we should use the nodegroup's
2073 # default kvm path parameter here.
2074 if not os.path.exists(constants.KVM_PATH):
2075 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2076 if not os.path.exists(constants.SOCAT_PATH):
2077 msgs.append("The socat binary ('%s') does not exist" %
2078 constants.SOCAT_PATH)
2080 return self._FormatVerifyResults(msgs)
2083 def CheckParameterSyntax(cls, hvparams):
2084 """Check the given parameters for validity.
2086 @type hvparams: dict
2087 @param hvparams: dictionary with parameter names/value
2088 @raise errors.HypervisorError: when a parameter is not valid
2091 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2093 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2095 if not hvparams[constants.HV_ROOT_PATH]:
2096 raise errors.HypervisorError("Need a root partition for the instance,"
2097 " if a kernel is defined")
2099 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2100 not hvparams[constants.HV_VNC_X509]):
2101 raise errors.HypervisorError("%s must be defined, if %s is" %
2102 (constants.HV_VNC_X509,
2103 constants.HV_VNC_X509_VERIFY))
2105 if hvparams[constants.HV_SERIAL_CONSOLE]:
2106 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2107 valid_speeds = constants.VALID_SERIAL_SPEEDS
2108 if not serial_speed or serial_speed not in valid_speeds:
2109 raise errors.HypervisorError("Invalid serial console speed, must be"
2111 utils.CommaJoin(valid_speeds))
2113 boot_order = hvparams[constants.HV_BOOT_ORDER]
2114 if (boot_order == constants.HT_BO_CDROM and
2115 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2116 raise errors.HypervisorError("Cannot boot from cdrom without an"
2119 security_model = hvparams[constants.HV_SECURITY_MODEL]
2120 if security_model == constants.HT_SM_USER:
2121 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2122 raise errors.HypervisorError("A security domain (user to run kvm as)"
2123 " must be specified")
2124 elif (security_model == constants.HT_SM_NONE or
2125 security_model == constants.HT_SM_POOL):
2126 if hvparams[constants.HV_SECURITY_DOMAIN]:
2127 raise errors.HypervisorError("Cannot have a security domain when the"
2128 " security model is 'none' or 'pool'")
2130 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2131 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2133 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2134 # if an IP version is specified, the spice_bind parameter must be an
2136 if (netutils.IP4Address.IsValid(spice_bind) and
2137 spice_ip_version != constants.IP4_VERSION):
2138 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2139 " the specified IP version is %s" %
2140 (spice_bind, spice_ip_version))
2142 if (netutils.IP6Address.IsValid(spice_bind) and
2143 spice_ip_version != constants.IP6_VERSION):
2144 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2145 " the specified IP version is %s" %
2146 (spice_bind, spice_ip_version))
2148 # All the other SPICE parameters depend on spice_bind being set. Raise an
2149 # error if any of them is set without it.
2150 for param in _SPICE_ADDITIONAL_PARAMS:
2152 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2153 (param, constants.HV_KVM_SPICE_BIND))
2156 def ValidateParameters(cls, hvparams):
2157 """Check the given parameters for validity.
2159 @type hvparams: dict
2160 @param hvparams: dictionary with parameter names/value
2161 @raise errors.HypervisorError: when a parameter is not valid
2164 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2166 kvm_path = hvparams[constants.HV_KVM_PATH]
2168 security_model = hvparams[constants.HV_SECURITY_MODEL]
2169 if security_model == constants.HT_SM_USER:
2170 username = hvparams[constants.HV_SECURITY_DOMAIN]
2172 pwd.getpwnam(username)
2174 raise errors.HypervisorError("Unknown security domain user %s"
2176 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2177 if vnc_bind_address:
2178 bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address)
2179 is_interface = netutils.IsValidInterface(vnc_bind_address)
2180 is_path = utils.IsNormAbsPath(vnc_bind_address)
2181 if not bound_to_addr and not is_interface and not is_path:
2182 raise errors.HypervisorError("VNC: The %s parameter must be either"
2183 " a valid IP address, an interface name,"
2184 " or an absolute path" %
2185 constants.HV_KVM_SPICE_BIND)
2187 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2189 # only one of VNC and SPICE can be used currently.
2190 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2191 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2192 " only one of them can be used at a"
2195 # check that KVM supports SPICE
2196 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2197 if not cls._SPICE_RE.search(kvmhelp):
2198 raise errors.HypervisorError("SPICE is configured, but it is not"
2199 " supported according to 'kvm --help'")
2201 # if spice_bind is not an IP address, it must be a valid interface
2202 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2203 netutils.IP6Address.IsValid(spice_bind))
2204 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2205 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2206 " a valid IP address or interface name" %
2207 constants.HV_KVM_SPICE_BIND)
2209 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2211 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2212 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2213 raise errors.HypervisorError("Unsupported machine version: %s" %
2217 def PowercycleNode(cls, hvparams=None):
2218 """KVM powercycle, just a wrapper over Linux powercycle.
2220 @type hvparams: dict of strings
2221 @param hvparams: hypervisor params to be used on this node
2224 cls.LinuxPowercycle()