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:
464 (False, lambda x: (netutils.IP4Address.IsValid(x) or
465 utils.IsNormAbsPath(x)),
466 "The VNC bind address must be either a valid IP address or an absolute"
467 " pathname", None, None),
468 constants.HV_VNC_TLS: hv_base.NO_CHECK,
469 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
470 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
471 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
472 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
473 constants.HV_KVM_SPICE_IP_VERSION:
474 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
475 x in constants.VALID_IP_VERSIONS),
476 "The SPICE IP version should be 4 or 6",
478 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
479 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
481 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
482 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
484 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
485 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
487 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
488 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
490 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
491 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
492 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
493 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
494 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
495 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
496 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
497 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
498 constants.HV_BOOT_ORDER:
499 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
500 constants.HV_NIC_TYPE:
501 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
502 constants.HV_DISK_TYPE:
503 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
504 constants.HV_KVM_CDROM_DISK_TYPE:
505 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
506 constants.HV_USB_MOUSE:
507 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
508 constants.HV_KEYMAP: hv_base.NO_CHECK,
509 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
510 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
511 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
512 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
513 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
514 constants.HV_DISK_CACHE:
515 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
516 constants.HV_SECURITY_MODEL:
517 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
518 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
519 constants.HV_KVM_FLAG:
520 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
521 constants.HV_VHOST_NET: hv_base.NO_CHECK,
522 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
523 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
524 constants.HV_REBOOT_BEHAVIOR:
525 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
526 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
527 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
528 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
529 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
530 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
531 constants.HV_SOUNDHW: hv_base.NO_CHECK,
532 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
533 constants.HV_VGA: hv_base.NO_CHECK,
534 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
535 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
539 _VIRTIO_NET_PCI = "virtio-net-pci"
541 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
543 _MIGRATION_PROGRESS_RE = \
544 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
545 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
546 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
548 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
549 _MIGRATION_INFO_RETRY_DELAY = 2
551 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
553 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
554 _CPU_INFO_CMD = "info cpus"
557 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
558 _CHECK_MACHINE_VERSION_RE = \
559 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
561 _QMP_RE = re.compile(r"^-qmp\s", re.M)
562 _SPICE_RE = re.compile(r"^-spice\s", re.M)
563 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
564 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
565 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
566 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
567 _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
568 # match -drive.*boot=on|off on different lines, but in between accept only
569 # dashes not preceeded by a new line (which would mean another option
570 # different than -drive is starting)
571 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
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):
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):
975 """Get instance properties.
977 @type instance_name: string
978 @param instance_name: the instance name
979 @rtype: tuple of strings
980 @return: (name, id, memory, vcpus, stat, times)
983 _, pid, alive = self._InstancePidAlive(instance_name)
987 _, memory, vcpus = self._InstancePidInfo(pid)
992 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
994 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
995 # Will fail if ballooning is not enabled, but we can then just resort to
997 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
998 memory = mem_bytes / 1048576
999 except errors.HypervisorError:
1002 return (instance_name, pid, memory, vcpus, istat, times)
1004 def GetAllInstancesInfo(self):
1005 """Get properties of all instances.
1007 @return: list of tuples (name, id, memory, vcpus, stat, times)
1011 for name in os.listdir(self._PIDS_DIR):
1013 info = self.GetInstanceInfo(name)
1014 except errors.HypervisorError:
1015 # Ignore exceptions due to instances being shut down
1021 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1023 """Generate KVM information to start an instance.
1025 @type kvmhelp: string
1026 @param kvmhelp: output of kvm --help
1027 @attention: this function must not have any side-effects; for
1028 example, it must not write to the filesystem, or read values
1029 from the current system the are expected to differ between
1030 nodes, since it is only run once at instance startup;
1031 actions/kvm arguments that can vary between systems should be
1032 done in L{_ExecuteKVMRuntime}
1035 # pylint: disable=R0912,R0914,R0915
1036 hvp = instance.hvparams
1038 pidfile = self._InstancePidFile(instance.name)
1039 kvm = hvp[constants.HV_KVM_PATH]
1041 # used just by the vnc server, if enabled
1042 kvm_cmd.extend(["-name", instance.name])
1043 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1045 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1046 if hvp[constants.HV_CPU_CORES]:
1047 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1048 if hvp[constants.HV_CPU_THREADS]:
1049 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1050 if hvp[constants.HV_CPU_SOCKETS]:
1051 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1053 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1055 kvm_cmd.extend(["-pidfile", pidfile])
1056 kvm_cmd.extend(["-balloon", "virtio"])
1057 kvm_cmd.extend(["-daemonize"])
1058 if not instance.hvparams[constants.HV_ACPI]:
1059 kvm_cmd.extend(["-no-acpi"])
1060 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1061 constants.INSTANCE_REBOOT_EXIT:
1062 kvm_cmd.extend(["-no-reboot"])
1064 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1066 mversion = self._GetDefaultMachineVersion(kvm)
1067 kvm_cmd.extend(["-M", mversion])
1069 kernel_path = hvp[constants.HV_KERNEL_PATH]
1071 boot_disk = boot_cdrom = boot_floppy = boot_network = False
1073 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1074 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1075 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1076 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1078 self.ValidateParameters(hvp)
1081 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1083 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1084 self._ENABLE_KVM_RE.search(kvmhelp)):
1085 kvm_cmd.extend(["-enable-kvm"])
1086 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1087 self._DISABLE_KVM_RE.search(kvmhelp)):
1088 kvm_cmd.extend(["-disable-kvm"])
1091 kvm_cmd.extend(["-boot", "n"])
1093 # whether this is an older KVM version that uses the boot=on flag
1095 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1097 disk_type = hvp[constants.HV_DISK_TYPE]
1098 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1099 if_val = ",if=virtio"
1101 if_val = ",if=%s" % disk_type
1103 disk_cache = hvp[constants.HV_DISK_CACHE]
1104 if instance.disk_template in constants.DTS_EXT_MIRROR:
1105 if disk_cache != "none":
1106 # TODO: make this a hard error, instead of a silent overwrite
1107 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1108 " to prevent shared storage corruption on migration",
1110 cache_val = ",cache=none"
1111 elif disk_cache != constants.HT_CACHE_DEFAULT:
1112 cache_val = ",cache=%s" % disk_cache
1115 for cfdev, dev_path in block_devices:
1116 if cfdev.mode != constants.DISK_RDWR:
1117 raise errors.HypervisorError("Instance has read-only disks which"
1118 " are not supported by KVM")
1119 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1122 kvm_cmd.extend(["-boot", "c"])
1124 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1125 boot_val = ",boot=on"
1127 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1129 kvm_cmd.extend(["-drive", drive_val])
1131 #Now we can specify a different device type for CDROM devices.
1132 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1133 if not cdrom_disk_type:
1134 cdrom_disk_type = disk_type
1136 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1138 options = ",format=raw,media=cdrom"
1139 # set cdrom 'if' type
1141 actual_cdrom_type = constants.HT_DISK_IDE
1142 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1143 actual_cdrom_type = "virtio"
1145 actual_cdrom_type = cdrom_disk_type
1146 if_val = ",if=%s" % actual_cdrom_type
1147 # set boot flag, if needed
1150 kvm_cmd.extend(["-boot", "d"])
1152 boot_val = ",boot=on"
1153 # and finally build the entire '-drive' value
1154 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1155 kvm_cmd.extend(["-drive", drive_val])
1157 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1159 options = ",format=raw,media=cdrom"
1160 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1161 if_val = ",if=virtio"
1163 if_val = ",if=%s" % cdrom_disk_type
1164 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1165 kvm_cmd.extend(["-drive", drive_val])
1167 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1169 options = ",format=raw,media=disk"
1171 kvm_cmd.extend(["-boot", "a"])
1172 options = "%s,boot=on" % options
1173 if_val = ",if=floppy"
1174 options = "%s%s" % (options, if_val)
1175 drive_val = "file=%s%s" % (floppy_image, options)
1176 kvm_cmd.extend(["-drive", drive_val])
1179 kvm_cmd.extend(["-kernel", kernel_path])
1180 initrd_path = hvp[constants.HV_INITRD_PATH]
1182 kvm_cmd.extend(["-initrd", initrd_path])
1183 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1184 hvp[constants.HV_KERNEL_ARGS]]
1185 if hvp[constants.HV_SERIAL_CONSOLE]:
1186 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1187 root_append.append("console=ttyS0,%s" % serial_speed)
1188 kvm_cmd.extend(["-append", " ".join(root_append)])
1190 mem_path = hvp[constants.HV_MEM_PATH]
1192 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1194 monitor_dev = ("unix:%s,server,nowait" %
1195 self._InstanceMonitor(instance.name))
1196 kvm_cmd.extend(["-monitor", monitor_dev])
1197 if hvp[constants.HV_SERIAL_CONSOLE]:
1198 serial_dev = ("unix:%s,server,nowait" %
1199 self._InstanceSerial(instance.name))
1200 kvm_cmd.extend(["-serial", serial_dev])
1202 kvm_cmd.extend(["-serial", "none"])
1204 mouse_type = hvp[constants.HV_USB_MOUSE]
1205 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1206 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1207 spice_ip_version = None
1209 kvm_cmd.extend(["-usb"])
1212 kvm_cmd.extend(["-usbdevice", mouse_type])
1213 elif vnc_bind_address:
1214 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1216 if vnc_bind_address:
1217 if netutils.IP4Address.IsValid(vnc_bind_address):
1218 if instance.network_port > constants.VNC_BASE_PORT:
1219 display = instance.network_port - constants.VNC_BASE_PORT
1220 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1221 vnc_arg = ":%d" % (display)
1223 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1225 logging.error("Network port is not a valid VNC display (%d < %d),"
1226 " not starting VNC",
1227 instance.network_port, constants.VNC_BASE_PORT)
1230 # Only allow tls and other option when not binding to a file, for now.
1231 # kvm/qemu gets confused otherwise about the filename to use.
1233 if hvp[constants.HV_VNC_TLS]:
1234 vnc_append = "%s,tls" % vnc_append
1235 if hvp[constants.HV_VNC_X509_VERIFY]:
1236 vnc_append = "%s,x509verify=%s" % (vnc_append,
1237 hvp[constants.HV_VNC_X509])
1238 elif hvp[constants.HV_VNC_X509]:
1239 vnc_append = "%s,x509=%s" % (vnc_append,
1240 hvp[constants.HV_VNC_X509])
1241 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1242 vnc_append = "%s,password" % vnc_append
1244 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1247 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1249 kvm_cmd.extend(["-vnc", vnc_arg])
1251 # FIXME: this is wrong here; the iface ip address differs
1252 # between systems, so it should be done in _ExecuteKVMRuntime
1253 if netutils.IsValidInterface(spice_bind):
1254 # The user specified a network interface, we have to figure out the IP
1256 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1257 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1259 # if the user specified an IP version and the interface does not
1260 # have that kind of IP addresses, throw an exception
1261 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1262 if not addresses[spice_ip_version]:
1263 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1264 " for %s" % (spice_ip_version,
1267 # the user did not specify an IP version, we have to figure it out
1268 elif (addresses[constants.IP4_VERSION] and
1269 addresses[constants.IP6_VERSION]):
1270 # we have both ipv4 and ipv6, let's use the cluster default IP
1272 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1273 spice_ip_version = \
1274 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1275 elif addresses[constants.IP4_VERSION]:
1276 spice_ip_version = constants.IP4_VERSION
1277 elif addresses[constants.IP6_VERSION]:
1278 spice_ip_version = constants.IP6_VERSION
1280 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1281 " for %s" % (spice_bind))
1283 spice_address = addresses[spice_ip_version][0]
1286 # spice_bind is known to be a valid IP address, because
1287 # ValidateParameters checked it.
1288 spice_address = spice_bind
1290 spice_arg = "addr=%s" % spice_address
1291 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1292 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1293 (spice_arg, instance.network_port,
1294 pathutils.SPICE_CACERT_FILE))
1295 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1296 (spice_arg, pathutils.SPICE_CERT_FILE,
1297 pathutils.SPICE_CERT_FILE))
1298 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1300 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1302 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1304 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1305 spice_arg = "%s,disable-ticketing" % spice_arg
1307 if spice_ip_version:
1308 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1310 # Image compression options
1311 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1312 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1313 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1315 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1317 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1319 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1321 # Video stream detection
1322 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1324 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1326 # Audio compression, by default in qemu-kvm it is on
1327 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1328 spice_arg = "%s,playback-compression=off" % spice_arg
1329 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1330 spice_arg = "%s,agent-mouse=off" % spice_arg
1332 # Enable the spice agent communication channel between the host and the
1334 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1337 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1339 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1341 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1342 kvm_cmd.extend(["-spice", spice_arg])
1345 kvm_cmd.extend(["-nographic"])
1347 if hvp[constants.HV_USE_LOCALTIME]:
1348 kvm_cmd.extend(["-localtime"])
1350 if hvp[constants.HV_KVM_USE_CHROOT]:
1351 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1353 # Add qemu-KVM -cpu param
1354 if hvp[constants.HV_CPU_TYPE]:
1355 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1357 # As requested by music lovers
1358 if hvp[constants.HV_SOUNDHW]:
1359 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1361 # Pass a -vga option if requested, or if spice is used, for backwards
1363 if hvp[constants.HV_VGA]:
1364 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1366 kvm_cmd.extend(["-vga", "qxl"])
1368 # Various types of usb devices, comma separated
1369 if hvp[constants.HV_USB_DEVICES]:
1370 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1371 kvm_cmd.extend(["-usbdevice", dev])
1373 if hvp[constants.HV_KVM_EXTRA]:
1374 kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1376 # Save the current instance nics, but defer their expansion as parameters,
1377 # as we'll need to generate executable temp files for them.
1378 kvm_nics = instance.nics
1381 return (kvm_cmd, kvm_nics, hvparams)
1383 def _WriteKVMRuntime(self, instance_name, data):
1384 """Write an instance's KVM runtime
1388 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1390 except EnvironmentError, err:
1391 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1393 def _ReadKVMRuntime(self, instance_name):
1394 """Read an instance's KVM runtime
1398 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1399 except EnvironmentError, err:
1400 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1403 def _SaveKVMRuntime(self, instance, kvm_runtime):
1404 """Save an instance's KVM runtime
1407 kvm_cmd, kvm_nics, hvparams = kvm_runtime
1408 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1409 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1410 self._WriteKVMRuntime(instance.name, serialized_form)
1412 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1413 """Load an instance's KVM runtime
1416 if not serialized_runtime:
1417 serialized_runtime = self._ReadKVMRuntime(instance.name)
1418 loaded_runtime = serializer.Load(serialized_runtime)
1419 kvm_cmd, serialized_nics, hvparams = loaded_runtime
1420 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1421 return (kvm_cmd, kvm_nics, hvparams)
1423 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1424 """Run the KVM cmd and check for errors
1427 @param name: instance name
1428 @type kvm_cmd: list of strings
1429 @param kvm_cmd: runcmd input for kvm
1430 @type tap_fds: list of int
1431 @param tap_fds: fds of tap devices opened by Ganeti
1435 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1438 utils_wrapper.CloseFdNoError(fd)
1441 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1442 (name, result.fail_reason, result.output))
1443 if not self._InstancePidAlive(name)[2]:
1444 raise errors.HypervisorError("Failed to start instance %s" % name)
1446 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1447 """Execute a KVM cmd, after completing it with some last minute data.
1449 @type incoming: tuple of strings
1450 @param incoming: (target_host_ip, port)
1451 @type kvmhelp: string
1452 @param kvmhelp: output of kvm --help
1455 # Small _ExecuteKVMRuntime hv parameters programming howto:
1456 # - conf_hvp contains the parameters as configured on ganeti. they might
1457 # have changed since the instance started; only use them if the change
1458 # won't affect the inside of the instance (which hasn't been rebooted).
1459 # - up_hvp contains the parameters as they were when the instance was
1460 # started, plus any new parameter which has been added between ganeti
1461 # versions: it is paramount that those default to a value which won't
1462 # affect the inside of the instance as well.
1463 conf_hvp = instance.hvparams
1464 name = instance.name
1465 self._CheckDown(name)
1469 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1470 # the first element of kvm_cmd is always the path to the kvm binary
1471 kvm_path = kvm_cmd[0]
1472 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1474 # We know it's safe to run as a different user upon migration, so we'll use
1475 # the latest conf, from conf_hvp.
1476 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1477 if security_model == constants.HT_SM_USER:
1478 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1480 keymap = conf_hvp[constants.HV_KEYMAP]
1482 keymap_path = self._InstanceKeymapFile(name)
1483 # If a keymap file is specified, KVM won't use its internal defaults. By
1484 # first including the "en-us" layout, an error on loading the actual
1485 # layout (e.g. because it can't be found) won't lead to a non-functional
1486 # keyboard. A keyboard with incorrect keys is still better than none.
1487 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1488 kvm_cmd.extend(["-k", keymap_path])
1490 # We have reasons to believe changing something like the nic driver/type
1491 # upon migration won't exactly fly with the instance kernel, so for nic
1492 # related parameters we'll use up_hvp
1496 kvm_cmd.extend(["-net", "none"])
1500 nic_type = up_hvp[constants.HV_NIC_TYPE]
1501 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1502 nic_model = self._VIRTIO
1504 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1505 if self._NEW_VIRTIO_RE.search(devlist):
1506 nic_model = self._VIRTIO_NET_PCI
1508 except errors.HypervisorError, _:
1509 # Older versions of kvm don't support DEVICE_LIST, but they don't
1510 # have new virtio syntax either.
1513 if up_hvp[constants.HV_VHOST_NET]:
1514 # check for vhost_net support
1515 if self._VHOST_RE.search(kvmhelp):
1516 tap_extra = ",vhost=on"
1518 raise errors.HypervisorError("vhost_net is configured"
1519 " but it is not available")
1521 nic_model = nic_type
1523 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1525 for nic_seq, nic in enumerate(kvm_nics):
1526 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1527 tapfds.append(tapfd)
1528 taps.append(tapname)
1529 if kvm_supports_netdev:
1530 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1531 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1532 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1534 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1536 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1537 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1540 target, port = incoming
1541 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1543 # Changing the vnc password doesn't bother the guest that much. At most it
1544 # will surprise people who connect to it. Whether positively or negatively
1546 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1550 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1551 except EnvironmentError, err:
1552 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1553 % (vnc_pwd_file, err))
1555 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1556 utils.EnsureDirs([(self._InstanceChrootDir(name),
1557 constants.SECURE_DIR_MODE)])
1559 # Automatically enable QMP if version is >= 0.14
1560 if self._QMP_RE.search(kvmhelp):
1561 logging.debug("Enabling QMP")
1562 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1563 self._InstanceQmpMonitor(instance.name)])
1565 # Configure the network now for starting instances and bridged interfaces,
1566 # during FinalizeMigration for incoming instances' routed interfaces
1567 for nic_seq, nic in enumerate(kvm_nics):
1569 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1571 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1573 # CPU affinity requires kvm to start paused, so we set this flag if the
1574 # instance is not already paused and if we are not going to accept a
1575 # migrating instance. In the latter case, pausing is not needed.
1576 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1577 if start_kvm_paused:
1578 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1580 # Note: CPU pinning is using up_hvp since changes take effect
1581 # during instance startup anyway, and to avoid problems when soft
1582 # rebooting the instance.
1584 if up_hvp.get(constants.HV_CPU_MASK, None):
1587 if security_model == constants.HT_SM_POOL:
1588 ss = ssconf.SimpleStore()
1589 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1590 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1591 uid = uidpool.RequestUnusedUid(all_uids)
1593 username = pwd.getpwuid(uid.GetUid()).pw_name
1594 kvm_cmd.extend(["-runas", username])
1595 self._RunKVMCmd(name, kvm_cmd, tapfds)
1597 uidpool.ReleaseUid(uid)
1601 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1603 self._RunKVMCmd(name, kvm_cmd, tapfds)
1605 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1606 constants.RUN_DIRS_MODE)])
1607 for nic_seq, tap in enumerate(taps):
1608 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1612 change_cmd = "change vnc password %s" % vnc_pwd
1613 self._CallMonitorCommand(instance.name, change_cmd)
1615 # Setting SPICE password. We are not vulnerable to malicious passwordless
1616 # connection attempts because SPICE by default does not allow connections
1617 # if neither a password nor the "disable_ticketing" options are specified.
1618 # As soon as we send the password via QMP, that password is a valid ticket
1620 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1621 if spice_password_file:
1624 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1625 except EnvironmentError, err:
1626 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1627 % (spice_password_file, err))
1629 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1632 "protocol": "spice",
1633 "password": spice_pwd,
1635 qmp.Execute("set_password", arguments)
1637 for filename in temp_files:
1638 utils.RemoveFile(filename)
1640 # If requested, set CPU affinity and resume instance execution
1642 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1644 start_memory = self._InstanceStartupMemory(instance)
1645 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1646 self.BalloonInstanceMemory(instance, start_memory)
1648 if start_kvm_paused:
1649 # To control CPU pinning, ballooning, and vnc/spice passwords
1650 # the VM was started in a frozen state. If freezing was not
1651 # explicitly requested resume the vm status.
1652 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1654 def StartInstance(self, instance, block_devices, startup_paused):
1655 """Start an instance.
1658 self._CheckDown(instance.name)
1659 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1660 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1661 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1662 startup_paused, kvmhelp)
1663 self._SaveKVMRuntime(instance, kvm_runtime)
1664 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1666 def _CallMonitorCommand(self, instance_name, command):
1667 """Invoke a command on the instance monitor.
1670 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum
1671 # version. The monitor protocol is designed for human consumption, whereas
1672 # QMP is made for programmatic usage. In the worst case QMP can also
1673 # execute monitor commands. As it is, all calls to socat take at least
1674 # 500ms and likely more: socat can't detect the end of the reply and waits
1675 # for 500ms of no data received before exiting (500 ms is the default for
1676 # the "-t" parameter).
1677 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1678 (utils.ShellQuote(command),
1679 constants.SOCAT_PATH,
1680 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1681 result = utils.RunCmd(socat)
1683 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1685 (command, instance_name, result.fail_reason, result.output))
1686 raise errors.HypervisorError(msg)
1691 def _ParseKVMVersion(cls, text):
1692 """Parse the KVM version from the --help output.
1695 @param text: output of kvm --help
1696 @return: (version, v_maj, v_min, v_rev)
1697 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1700 match = cls._VERSION_RE.search(text.splitlines()[0])
1702 raise errors.HypervisorError("Unable to get KVM version")
1704 v_all = match.group(0)
1705 v_maj = int(match.group(1))
1706 v_min = int(match.group(2))
1708 v_rev = int(match.group(4))
1711 return (v_all, v_maj, v_min, v_rev)
1714 def _GetKVMOutput(cls, kvm_path, option):
1715 """Return the output of a kvm invocation
1717 @type kvm_path: string
1718 @param kvm_path: path to the kvm executable
1719 @type option: a key of _KVMOPTS_CMDS
1720 @param option: kvm option to fetch the output from
1721 @return: output a supported kvm invocation
1722 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1725 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1727 optlist, can_fail = cls._KVMOPTS_CMDS[option]
1729 result = utils.RunCmd([kvm_path] + optlist)
1730 if result.failed and not can_fail:
1731 raise errors.HypervisorError("Unable to get KVM %s output" %
1732 " ".join(cls._KVMOPTS_CMDS[option]))
1733 return result.output
1736 def _GetKVMVersion(cls, kvm_path):
1737 """Return the installed KVM version.
1739 @return: (version, v_maj, v_min, v_rev)
1740 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1743 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1746 def _GetDefaultMachineVersion(cls, kvm_path):
1747 """Return the default hardware revision (e.g. pc-1.1)
1750 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1751 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1753 return match.group(1)
1757 def StopInstance(self, instance, force=False, retry=False, name=None):
1758 """Stop an instance.
1761 if name is not None and not force:
1762 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1764 name = instance.name
1765 acpi = instance.hvparams[constants.HV_ACPI]
1768 _, pid, alive = self._InstancePidAlive(name)
1769 if pid > 0 and alive:
1770 if force or not acpi:
1771 utils.KillProcess(pid)
1773 self._CallMonitorCommand(name, "system_powerdown")
1775 def CleanupInstance(self, instance_name):
1776 """Cleanup after a stopped instance
1779 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1780 if pid > 0 and alive:
1781 raise errors.HypervisorError("Cannot cleanup a live instance")
1782 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1784 def RebootInstance(self, instance):
1785 """Reboot an instance.
1788 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1789 # socket the instance will stop, but now power up again. So we'll resort
1790 # to shutdown and restart.
1791 _, _, alive = self._InstancePidAlive(instance.name)
1793 raise errors.HypervisorError("Failed to reboot instance %s:"
1794 " not running" % instance.name)
1795 # StopInstance will delete the saved KVM runtime so:
1796 # ...first load it...
1797 kvm_runtime = self._LoadKVMRuntime(instance)
1798 # ...now we can safely call StopInstance...
1799 if not self.StopInstance(instance):
1800 self.StopInstance(instance, force=True)
1801 # ...and finally we can save it again, and execute it...
1802 self._SaveKVMRuntime(instance, kvm_runtime)
1803 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1804 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1805 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1807 def MigrationInfo(self, instance):
1808 """Get instance information to perform a migration.
1810 @type instance: L{objects.Instance}
1811 @param instance: instance to be migrated
1813 @return: content of the KVM runtime file
1816 return self._ReadKVMRuntime(instance.name)
1818 def AcceptInstance(self, instance, info, target):
1819 """Prepare to accept an instance.
1821 @type instance: L{objects.Instance}
1822 @param instance: instance to be accepted
1824 @param info: content of the KVM runtime file on the source node
1825 @type target: string
1826 @param target: target host (usually ip), on this node
1829 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1830 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1831 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1832 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1833 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1834 incoming=incoming_address)
1836 def FinalizeMigrationDst(self, instance, info, success):
1837 """Finalize the instance migration on the target node.
1839 Stop the incoming mode KVM.
1841 @type instance: L{objects.Instance}
1842 @param instance: instance whose migration is being finalized
1846 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1847 kvm_nics = kvm_runtime[1]
1849 for nic_seq, nic in enumerate(kvm_nics):
1850 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1851 # Bridged interfaces have already been configured
1854 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1855 except EnvironmentError, err:
1856 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1857 instance.name, nic_seq, str(err))
1860 self._ConfigureNIC(instance, nic_seq, nic, tap)
1861 except errors.HypervisorError, err:
1862 logging.warning(str(err))
1864 self._WriteKVMRuntime(instance.name, info)
1866 self.StopInstance(instance, force=True)
1868 def MigrateInstance(self, instance, target, live):
1869 """Migrate an instance to a target node.
1871 The migration will not be attempted if the instance is not
1874 @type instance: L{objects.Instance}
1875 @param instance: the instance to be migrated
1876 @type target: string
1877 @param target: ip address of the target node
1879 @param live: perform a live migration
1882 instance_name = instance.name
1883 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1884 _, _, alive = self._InstancePidAlive(instance_name)
1886 raise errors.HypervisorError("Instance not running, cannot migrate")
1889 self._CallMonitorCommand(instance_name, "stop")
1891 migrate_command = ("migrate_set_speed %dm" %
1892 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1893 self._CallMonitorCommand(instance_name, migrate_command)
1895 migrate_command = ("migrate_set_downtime %dms" %
1896 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1897 self._CallMonitorCommand(instance_name, migrate_command)
1899 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1900 self._CallMonitorCommand(instance_name, migrate_command)
1902 def FinalizeMigrationSource(self, instance, success, live):
1903 """Finalize the instance migration on the source node.
1905 @type instance: L{objects.Instance}
1906 @param instance: the instance that was migrated
1908 @param success: whether the migration succeeded or not
1910 @param live: whether the user requested a live migration or not
1914 pidfile, pid, _ = self._InstancePidAlive(instance.name)
1915 utils.KillProcess(pid)
1916 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1918 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1920 def GetMigrationStatus(self, instance):
1921 """Get the migration status
1923 @type instance: L{objects.Instance}
1924 @param instance: the instance that is being migrated
1925 @rtype: L{objects.MigrationStatus}
1926 @return: the status of the current migration (one of
1927 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1928 progress info that can be retrieved from the hypervisor
1931 info_command = "info migrate"
1932 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1933 result = self._CallMonitorCommand(instance.name, info_command)
1934 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1936 if not result.stdout:
1937 logging.info("KVM: empty 'info migrate' result")
1939 logging.warning("KVM: unknown 'info migrate' result: %s",
1942 status = match.group(1)
1943 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1944 migration_status = objects.MigrationStatus(status=status)
1945 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1947 migration_status.transferred_ram = match.group("transferred")
1948 migration_status.total_ram = match.group("total")
1950 return migration_status
1952 logging.warning("KVM: unknown migration status '%s'", status)
1954 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1956 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1958 def BalloonInstanceMemory(self, instance, mem):
1959 """Balloon an instance memory to a certain value.
1961 @type instance: L{objects.Instance}
1962 @param instance: instance to be accepted
1964 @param mem: actual memory size to use for instance runtime
1967 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1969 def GetNodeInfo(self):
1970 """Return information about the node.
1972 @return: a dict with the following keys (values in MiB):
1973 - memory_total: the total memory size on the node
1974 - memory_free: the available memory on the node for instances
1975 - memory_dom0: the memory used by the node itself, if available
1976 - hv_version: the hypervisor version in the form (major, minor,
1980 result = self.GetLinuxNodeInfo()
1981 # FIXME: this is the global kvm version, but the actual version can be
1982 # customized as an hv parameter. we should use the nodegroup's default kvm
1983 # path parameter here.
1984 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
1985 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1989 def GetInstanceConsole(cls, instance, hvparams, beparams):
1990 """Return a command for connecting to the console of an instance.
1993 if hvparams[constants.HV_SERIAL_CONSOLE]:
1994 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1995 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1996 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1997 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1998 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1999 return objects.InstanceConsole(instance=instance.name,
2000 kind=constants.CONS_SSH,
2001 host=instance.primary_node,
2002 user=constants.SSH_CONSOLE_USER,
2005 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2006 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2007 display = instance.network_port - constants.VNC_BASE_PORT
2008 return objects.InstanceConsole(instance=instance.name,
2009 kind=constants.CONS_VNC,
2010 host=vnc_bind_address,
2011 port=instance.network_port,
2014 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2016 return objects.InstanceConsole(instance=instance.name,
2017 kind=constants.CONS_SPICE,
2019 port=instance.network_port)
2021 return objects.InstanceConsole(instance=instance.name,
2022 kind=constants.CONS_MESSAGE,
2023 message=("No serial shell for instance %s" %
2027 """Verify the hypervisor.
2029 Check that the required binaries exist.
2031 @return: Problem description if something is wrong, C{None} otherwise
2035 # FIXME: this is the global kvm binary, but the actual path can be
2036 # customized as an hv parameter; we should use the nodegroup's
2037 # default kvm path parameter here.
2038 if not os.path.exists(constants.KVM_PATH):
2039 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2040 if not os.path.exists(constants.SOCAT_PATH):
2041 msgs.append("The socat binary ('%s') does not exist" %
2042 constants.SOCAT_PATH)
2044 return self._FormatVerifyResults(msgs)
2047 def CheckParameterSyntax(cls, hvparams):
2048 """Check the given parameters for validity.
2050 @type hvparams: dict
2051 @param hvparams: dictionary with parameter names/value
2052 @raise errors.HypervisorError: when a parameter is not valid
2055 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2057 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2059 if not hvparams[constants.HV_ROOT_PATH]:
2060 raise errors.HypervisorError("Need a root partition for the instance,"
2061 " if a kernel is defined")
2063 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2064 not hvparams[constants.HV_VNC_X509]):
2065 raise errors.HypervisorError("%s must be defined, if %s is" %
2066 (constants.HV_VNC_X509,
2067 constants.HV_VNC_X509_VERIFY))
2069 if hvparams[constants.HV_SERIAL_CONSOLE]:
2070 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2071 valid_speeds = constants.VALID_SERIAL_SPEEDS
2072 if not serial_speed or serial_speed not in valid_speeds:
2073 raise errors.HypervisorError("Invalid serial console speed, must be"
2075 utils.CommaJoin(valid_speeds))
2077 boot_order = hvparams[constants.HV_BOOT_ORDER]
2078 if (boot_order == constants.HT_BO_CDROM and
2079 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2080 raise errors.HypervisorError("Cannot boot from cdrom without an"
2083 security_model = hvparams[constants.HV_SECURITY_MODEL]
2084 if security_model == constants.HT_SM_USER:
2085 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2086 raise errors.HypervisorError("A security domain (user to run kvm as)"
2087 " must be specified")
2088 elif (security_model == constants.HT_SM_NONE or
2089 security_model == constants.HT_SM_POOL):
2090 if hvparams[constants.HV_SECURITY_DOMAIN]:
2091 raise errors.HypervisorError("Cannot have a security domain when the"
2092 " security model is 'none' or 'pool'")
2094 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2095 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2097 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2098 # if an IP version is specified, the spice_bind parameter must be an
2100 if (netutils.IP4Address.IsValid(spice_bind) and
2101 spice_ip_version != constants.IP4_VERSION):
2102 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2103 " the specified IP version is %s" %
2104 (spice_bind, spice_ip_version))
2106 if (netutils.IP6Address.IsValid(spice_bind) and
2107 spice_ip_version != constants.IP6_VERSION):
2108 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2109 " the specified IP version is %s" %
2110 (spice_bind, spice_ip_version))
2112 # All the other SPICE parameters depend on spice_bind being set. Raise an
2113 # error if any of them is set without it.
2114 for param in _SPICE_ADDITIONAL_PARAMS:
2116 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2117 (param, constants.HV_KVM_SPICE_BIND))
2120 def ValidateParameters(cls, hvparams):
2121 """Check the given parameters for validity.
2123 @type hvparams: dict
2124 @param hvparams: dictionary with parameter names/value
2125 @raise errors.HypervisorError: when a parameter is not valid
2128 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2130 kvm_path = hvparams[constants.HV_KVM_PATH]
2132 security_model = hvparams[constants.HV_SECURITY_MODEL]
2133 if security_model == constants.HT_SM_USER:
2134 username = hvparams[constants.HV_SECURITY_DOMAIN]
2136 pwd.getpwnam(username)
2138 raise errors.HypervisorError("Unknown security domain user %s"
2141 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2143 # only one of VNC and SPICE can be used currently.
2144 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2145 raise errors.HypervisorError("Both SPICE and VNC are configured, but"
2146 " only one of them can be used at a"
2149 # check that KVM supports SPICE
2150 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2151 if not cls._SPICE_RE.search(kvmhelp):
2152 raise errors.HypervisorError("SPICE is configured, but it is not"
2153 " supported according to 'kvm --help'")
2155 # if spice_bind is not an IP address, it must be a valid interface
2156 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or
2157 netutils.IP6Address.IsValid(spice_bind))
2158 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2159 raise errors.HypervisorError("SPICE: The %s parameter must be either"
2160 " a valid IP address or interface name" %
2161 constants.HV_KVM_SPICE_BIND)
2163 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2165 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2166 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2167 raise errors.HypervisorError("Unsupported machine version: %s" %
2171 def PowercycleNode(cls):
2172 """KVM powercycle, just a wrapper over Linux powercycle.
2175 cls.LinuxPowercycle()