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 _ProbeTapVnetHdr(fd):
84 """Check whether to enable the IFF_VNET_HDR flag.
86 To do this, _all_ of the following conditions must be met:
87 1. TUNGETFEATURES ioctl() *must* be implemented
88 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
89 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
90 drivers/net/tun.c there is no way to test this until after the tap device
91 has been created using TUNSETIFF, and there is no way to change the
92 IFF_VNET_HDR flag after creating the interface, catch-22! However both
93 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
94 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
97 @param fd: the file descriptor of /dev/net/tun
100 req = struct.pack("I", 0)
102 res = fcntl.ioctl(fd, TUNGETFEATURES, req)
103 except EnvironmentError:
104 logging.warning("TUNGETFEATURES ioctl() not implemented")
107 tunflags = struct.unpack("I", res)[0]
108 if tunflags & IFF_VNET_HDR:
111 logging.warning("Host does not support IFF_VNET_HDR, not enabling")
115 def _OpenTap(vnet_hdr=True):
116 """Open a new tap device and return its file descriptor.
118 This is intended to be used by a qemu-type hypervisor together with the -net
119 tap,fd=<fd> command line parameter.
121 @type vnet_hdr: boolean
122 @param vnet_hdr: Enable the VNET Header
123 @return: (ifname, tapfd)
128 tapfd = os.open("/dev/net/tun", os.O_RDWR)
129 except EnvironmentError:
130 raise errors.HypervisorError("Failed to open /dev/net/tun")
132 flags = IFF_TAP | IFF_NO_PI
134 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
135 flags |= IFF_VNET_HDR
137 # The struct ifreq ioctl request (see netdevice(7))
138 ifr = struct.pack("16sh", "", flags)
141 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
142 except EnvironmentError, err:
143 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
146 # Get the interface name from the ioctl
147 ifname = struct.unpack("16sh", res)[0].strip("\x00")
148 return (ifname, tapfd)
152 """QEMU Messaging Protocol (QMP) message.
155 def __init__(self, data):
156 """Creates a new QMP message based on the passed data.
159 if not isinstance(data, dict):
160 raise TypeError("QmpMessage must be initialized with a dict")
164 def __getitem__(self, field_name):
165 """Get the value of the required field if present, or None.
167 Overrides the [] operator to provide access to the message data,
168 returning None if the required item is not in the message
169 @return: the value of the field_name field, or None if field_name
170 is not contained in the message
173 return self.data.get(field_name, None)
175 def __setitem__(self, field_name, field_value):
176 """Set the value of the required field_name to field_value.
179 self.data[field_name] = field_value
182 def BuildFromJsonString(json_string):
183 """Build a QmpMessage from a JSON encoded string.
185 @type json_string: str
186 @param json_string: JSON string representing the message
187 @rtype: L{QmpMessage}
188 @return: a L{QmpMessage} built from json_string
192 data = serializer.LoadJson(json_string)
193 return QmpMessage(data)
196 # The protocol expects the JSON object to be sent as a single line.
197 return serializer.DumpJson(self.data)
199 def __eq__(self, other):
200 # When comparing two QmpMessages, we are interested in comparing
201 # their internal representation of the message data
202 return self.data == other.data
206 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
209 _FIRST_MESSAGE_KEY = "QMP"
212 _RETURN_KEY = RETURN_KEY = "return"
213 _ACTUAL_KEY = ACTUAL_KEY = "actual"
214 _ERROR_CLASS_KEY = "class"
215 _ERROR_DATA_KEY = "data"
216 _ERROR_DESC_KEY = "desc"
217 _EXECUTE_KEY = "execute"
218 _ARGUMENTS_KEY = "arguments"
219 _CAPABILITIES_COMMAND = "qmp_capabilities"
220 _MESSAGE_END_TOKEN = "\r\n"
223 def __init__(self, monitor_filename):
224 """Instantiates the QmpConnection object.
226 @type monitor_filename: string
227 @param monitor_filename: the filename of the UNIX raw socket on which the
228 QMP monitor is listening
231 self.monitor_filename = monitor_filename
232 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
233 # We want to fail if the server doesn't send a complete message
234 # in a reasonable amount of time
235 self.sock.settimeout(self._SOCKET_TIMEOUT)
236 self._connected = False
239 def _check_socket(self):
242 sock_stat = os.stat(self.monitor_filename)
243 except EnvironmentError, err:
244 if err.errno == errno.ENOENT:
245 raise errors.HypervisorError("No qmp socket found")
247 raise errors.HypervisorError("Error checking qmp socket: %s",
248 utils.ErrnoOrStr(err))
249 if not stat.S_ISSOCK(sock_stat.st_mode):
250 raise errors.HypervisorError("Qmp socket is not a socket")
252 def _check_connection(self):
253 """Make sure that the connection is established.
256 if not self._connected:
257 raise errors.ProgrammerError("To use a QmpConnection you need to first"
258 " invoke connect() on it")
261 """Connects to the QMP monitor.
263 Connects to the UNIX socket and makes sure that we can actually send and
264 receive data to the kvm instance via QMP.
266 @raise errors.HypervisorError: when there are communication errors
267 @raise errors.ProgrammerError: when there are data serialization errors
271 raise errors.ProgrammerError("Cannot connect twice")
275 # Check file existance/stuff
277 self.sock.connect(self.monitor_filename)
278 except EnvironmentError:
279 raise errors.HypervisorError("Can't connect to qmp socket")
280 self._connected = True
282 # Check if we receive a correct greeting message from the server
283 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
284 greeting = self._Recv()
285 if not greeting[self._FIRST_MESSAGE_KEY]:
286 self._connected = False
287 raise errors.HypervisorError("kvm: qmp communication error (wrong"
290 # Let's put the monitor in command mode using the qmp_capabilities
291 # command, or else no command will be executable.
292 # (As per the QEMU Protocol Specification 0.1 - section 4)
293 self.Execute(self._CAPABILITIES_COMMAND)
295 def _ParseMessage(self, buf):
296 """Extract and parse a QMP message from the given buffer.
298 Seeks for a QMP message in the given buf. If found, it parses it and
299 returns it together with the rest of the characters in the buf.
300 If no message is found, returns None and the whole buffer.
302 @raise errors.ProgrammerError: when there are data serialization errors
306 # Check if we got the message end token (CRLF, as per the QEMU Protocol
307 # Specification 0.1 - Section 2.1.1)
308 pos = buf.find(self._MESSAGE_END_TOKEN)
311 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
312 except Exception, err:
313 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
316 return (message, buf)
319 """Receives a message from QMP and decodes the received JSON object.
322 @return: the received message
323 @raise errors.HypervisorError: when there are communication errors
324 @raise errors.ProgrammerError: when there are data serialization errors
327 self._check_connection()
329 # Check if there is already a message in the buffer
330 (message, self._buf) = self._ParseMessage(self._buf)
334 recv_buffer = StringIO.StringIO(self._buf)
335 recv_buffer.seek(len(self._buf))
338 data = self.sock.recv(4096)
341 recv_buffer.write(data)
343 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
347 except socket.timeout, err:
348 raise errors.HypervisorError("Timeout while receiving a QMP message: "
350 except socket.error, err:
351 raise errors.HypervisorError("Unable to receive data from KVM using the"
352 " QMP protocol: %s" % err)
354 def _Send(self, message):
355 """Encodes and sends a message to KVM using QMP.
357 @type message: QmpMessage
358 @param message: message to send to KVM
359 @raise errors.HypervisorError: when there are communication errors
360 @raise errors.ProgrammerError: when there are data serialization errors
363 self._check_connection()
365 message_str = str(message)
366 except Exception, err:
367 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
370 self.sock.sendall(message_str)
371 except socket.timeout, err:
372 raise errors.HypervisorError("Timeout while sending a QMP message: "
373 "%s (%s)" % (err.string, err.errno))
374 except socket.error, err:
375 raise errors.HypervisorError("Unable to send data from KVM using the"
376 " QMP protocol: %s" % err)
378 def Execute(self, command, arguments=None):
379 """Executes a QMP command and returns the response of the server.
382 @param command: the command to execute
383 @type arguments: dict
384 @param arguments: dictionary of arguments to be passed to the command
386 @return: dictionary representing the received JSON object
387 @raise errors.HypervisorError: when there are communication errors
388 @raise errors.ProgrammerError: when there are data serialization errors
391 self._check_connection()
392 message = QmpMessage({self._EXECUTE_KEY: command})
394 message[self._ARGUMENTS_KEY] = arguments
397 # Events can occur between the sending of the command and the reception
398 # of the response, so we need to filter out messages with the event key.
400 response = self._Recv()
401 err = response[self._ERROR_KEY]
403 raise errors.HypervisorError("kvm: error executing the %s"
404 " command: %s (%s, %s):" %
406 err[self._ERROR_DESC_KEY],
407 err[self._ERROR_CLASS_KEY],
408 err[self._ERROR_DATA_KEY]))
410 elif not response[self._EVENT_KEY]:
414 class KVMHypervisor(hv_base.BaseHypervisor):
415 """KVM hypervisor interface
420 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
421 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
422 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
423 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
424 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
425 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
426 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
427 # KVM instances with chroot enabled are started in empty chroot directories.
428 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
429 # After an instance is stopped, its chroot directory is removed.
430 # If the chroot directory is not empty, it can't be removed.
431 # A non-empty chroot directory indicates a possible security incident.
432 # To support forensics, the non-empty chroot directory is quarantined in
433 # a separate directory, called 'chroot-quarantine'.
434 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
435 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
436 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
439 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
440 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
441 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
442 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
443 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
444 constants.HV_ACPI: hv_base.NO_CHECK,
445 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
446 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
447 constants.HV_VNC_BIND_ADDRESS:
448 (False, lambda x: (netutils.IP4Address.IsValid(x) or
449 utils.IsNormAbsPath(x)),
450 "the VNC bind address must be either a valid IP address or an absolute"
451 " pathname", None, None),
452 constants.HV_VNC_TLS: hv_base.NO_CHECK,
453 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
454 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
455 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
456 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
457 constants.HV_KVM_SPICE_IP_VERSION:
458 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
459 x in constants.VALID_IP_VERSIONS),
460 "the SPICE IP version should be 4 or 6",
462 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
463 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
465 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
466 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
468 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
469 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
471 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
472 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
474 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
475 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
476 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
477 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
478 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
479 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
480 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
481 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
482 constants.HV_BOOT_ORDER:
483 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
484 constants.HV_NIC_TYPE:
485 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
486 constants.HV_DISK_TYPE:
487 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
488 constants.HV_KVM_CDROM_DISK_TYPE:
489 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
490 constants.HV_USB_MOUSE:
491 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
492 constants.HV_KEYMAP: hv_base.NO_CHECK,
493 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
494 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
495 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
496 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
497 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
498 constants.HV_DISK_CACHE:
499 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
500 constants.HV_SECURITY_MODEL:
501 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
502 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
503 constants.HV_KVM_FLAG:
504 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
505 constants.HV_VHOST_NET: hv_base.NO_CHECK,
506 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
507 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
508 constants.HV_REBOOT_BEHAVIOR:
509 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
510 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
511 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
512 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
513 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
514 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
515 constants.HV_SOUNDHW: hv_base.NO_CHECK,
516 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
517 constants.HV_VGA: hv_base.NO_CHECK,
518 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
519 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
523 _VIRTIO_NET_PCI = "virtio-net-pci"
525 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
527 _MIGRATION_PROGRESS_RE = \
528 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
529 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
530 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
532 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
533 _MIGRATION_INFO_RETRY_DELAY = 2
535 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
537 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
538 _CPU_INFO_CMD = "info cpus"
541 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
542 _CHECK_MACHINE_VERSION_RE = \
543 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
545 _QMP_RE = re.compile(r"^-qmp\s", re.M)
546 _SPICE_RE = re.compile(r"^-spice\s", re.M)
547 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
548 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
549 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
550 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
551 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
552 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
553 _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
554 # match -drive.*boot=on|off on different lines, but in between accept only
555 # dashes not preceeded by a new line (which would mean another option
556 # different than -drive is starting)
557 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
562 ANCILLARY_FILES_OPT = [
566 # Supported kvm options to get output from
567 _KVMOPT_HELP = "help"
568 _KVMOPT_MLIST = "mlist"
569 _KVMOPT_DEVICELIST = "devicelist"
571 # Command to execute to get the output from kvm, and whether to
572 # accept the output even on failure.
574 _KVMOPT_HELP: (["--help"], False),
575 _KVMOPT_MLIST: (["-M", "?"], False),
576 _KVMOPT_DEVICELIST: (["-device", "?"], True),
580 hv_base.BaseHypervisor.__init__(self)
581 # Let's make sure the directories we need exist, even if the RUN_DIR lives
582 # in a tmpfs filesystem or has been otherwise wiped out.
583 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
584 utils.EnsureDirs(dirs)
587 def _InstancePidFile(cls, instance_name):
588 """Returns the instance pidfile.
591 return utils.PathJoin(cls._PIDS_DIR, instance_name)
594 def _InstanceUidFile(cls, instance_name):
595 """Returns the instance uidfile.
598 return utils.PathJoin(cls._UIDS_DIR, instance_name)
601 def _InstancePidInfo(cls, pid):
602 """Check pid file for instance information.
604 Check that a pid file is associated with an instance, and retrieve
605 information from its command line.
607 @type pid: string or int
608 @param pid: process id of the instance to check
610 @return: (instance_name, memory, vcpus)
611 @raise errors.HypervisorError: when an instance cannot be found
614 alive = utils.IsProcessAlive(pid)
616 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
618 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
620 cmdline = utils.ReadFile(cmdline_file)
621 except EnvironmentError, err:
622 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
629 arg_list = cmdline.split("\x00")
631 arg = arg_list.pop(0)
633 instance = arg_list.pop(0)
635 memory = int(arg_list.pop(0))
637 vcpus = int(arg_list.pop(0).split(",")[0])
640 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
643 return (instance, memory, vcpus)
645 def _InstancePidAlive(self, instance_name):
646 """Returns the instance pidfile, pid, and liveness.
648 @type instance_name: string
649 @param instance_name: instance name
651 @return: (pid file name, pid, liveness)
654 pidfile = self._InstancePidFile(instance_name)
655 pid = utils.ReadPidFile(pidfile)
659 cmd_instance = self._InstancePidInfo(pid)[0]
660 alive = (cmd_instance == instance_name)
661 except errors.HypervisorError:
664 return (pidfile, pid, alive)
666 def _CheckDown(self, instance_name):
667 """Raises an error unless the given instance is down.
670 alive = self._InstancePidAlive(instance_name)[2]
672 raise errors.HypervisorError("Failed to start instance %s: %s" %
673 (instance_name, "already running"))
676 def _InstanceMonitor(cls, instance_name):
677 """Returns the instance monitor socket name
680 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
683 def _InstanceSerial(cls, instance_name):
684 """Returns the instance serial socket name
687 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
690 def _InstanceQmpMonitor(cls, instance_name):
691 """Returns the instance serial QMP socket name
694 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
697 def _SocatUnixConsoleParams():
698 """Returns the correct parameters for socat
700 If we have a new-enough socat we can use raw mode with an escape character.
703 if constants.SOCAT_USE_ESCAPE:
704 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
706 return "echo=0,icanon=0"
709 def _InstanceKVMRuntime(cls, instance_name):
710 """Returns the instance KVM runtime filename
713 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
716 def _InstanceChrootDir(cls, instance_name):
717 """Returns the name of the KVM chroot dir of the instance
720 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
723 def _InstanceNICDir(cls, instance_name):
724 """Returns the name of the directory holding the tap device files for a
728 return utils.PathJoin(cls._NICS_DIR, instance_name)
731 def _InstanceNICFile(cls, instance_name, seq):
732 """Returns the name of the file containing the tap device for a given NIC
735 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
738 def _InstanceKeymapFile(cls, instance_name):
739 """Returns the name of the file containing the keymap for a given instance
742 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
745 def _TryReadUidFile(cls, uid_file):
746 """Try to read a uid file
749 if os.path.exists(uid_file):
751 uid = int(utils.ReadOneLineFile(uid_file))
753 except EnvironmentError:
754 logging.warning("Can't read uid file", exc_info=True)
755 except (TypeError, ValueError):
756 logging.warning("Can't parse uid file contents", exc_info=True)
760 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
761 """Removes an instance's rutime sockets/files/dirs.
764 utils.RemoveFile(pidfile)
765 utils.RemoveFile(cls._InstanceMonitor(instance_name))
766 utils.RemoveFile(cls._InstanceSerial(instance_name))
767 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
768 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
769 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
770 uid_file = cls._InstanceUidFile(instance_name)
771 uid = cls._TryReadUidFile(uid_file)
772 utils.RemoveFile(uid_file)
774 uidpool.ReleaseUid(uid)
776 shutil.rmtree(cls._InstanceNICDir(instance_name))
778 if err.errno != errno.ENOENT:
781 chroot_dir = cls._InstanceChrootDir(instance_name)
782 utils.RemoveDir(chroot_dir)
784 if err.errno == errno.ENOTEMPTY:
785 # The chroot directory is expected to be empty, but it isn't.
786 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
789 utils.TimestampForFilename()))
790 logging.warning("The chroot directory of instance %s can not be"
791 " removed as it is not empty. Moving it to the"
792 " quarantine instead. Please investigate the"
793 " contents (%s) and clean up manually",
794 instance_name, new_chroot_dir)
795 utils.RenameFile(chroot_dir, new_chroot_dir)
800 def _ConfigureNIC(instance, seq, nic, tap):
801 """Run the network configuration script for a specified NIC
803 @param instance: instance we're acting on
804 @type instance: instance object
805 @param seq: nic sequence number
807 @param nic: nic we're acting on
808 @type nic: nic object
809 @param tap: the host's tap interface this NIC corresponds to
814 tags = " ".join(instance.tags)
819 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
820 "INSTANCE": instance.name,
822 "MODE": nic.nicparams[constants.NIC_MODE],
824 "INTERFACE_INDEX": str(seq),
831 if nic.nicparams[constants.NIC_LINK]:
832 env["LINK"] = nic.nicparams[constants.NIC_LINK]
835 n = objects.Network.FromDict(nic.netinfo)
836 env.update(n.HooksDict())
838 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
839 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
841 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
843 raise errors.HypervisorError("Failed to configure interface %s: %s."
844 " Network configuration script output: %s" %
845 (tap, result.fail_reason, result.output))
848 def _VerifyAffinityPackage():
850 raise errors.HypervisorError("affinity Python package not"
851 " found; cannot use CPU pinning under KVM")
854 def _BuildAffinityCpuMask(cpu_list):
855 """Create a CPU mask suitable for sched_setaffinity from a list of
858 See man taskset for more info on sched_setaffinity masks.
859 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
861 @type cpu_list: list of int
862 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
864 @return: a bit mask of CPU affinities
867 if cpu_list == constants.CPU_PINNING_OFF:
868 return constants.CPU_PINNING_ALL_KVM
870 return sum(2 ** cpu for cpu in cpu_list)
873 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
874 """Change CPU affinity for running VM according to given CPU mask.
876 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
877 @type cpu_mask: string
878 @param process_id: process ID of KVM process. Used to pin entire VM
880 @type process_id: int
881 @param thread_dict: map of virtual CPUs to KVM thread IDs
882 @type thread_dict: dict int:int
885 # Convert the string CPU mask to a list of list of int's
886 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
888 if len(cpu_list) == 1:
889 all_cpu_mapping = cpu_list[0]
890 if all_cpu_mapping == constants.CPU_PINNING_OFF:
891 # If CPU pinning has 1 entry that's "all", then do nothing
894 # If CPU pinning has one non-all entry, map the entire VM to
895 # one set of physical CPUs
896 cls._VerifyAffinityPackage()
897 affinity.set_process_affinity_mask(
898 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
900 # The number of vCPUs mapped should match the number of vCPUs
901 # reported by KVM. This was already verified earlier, so
902 # here only as a sanity check.
903 assert len(thread_dict) == len(cpu_list)
904 cls._VerifyAffinityPackage()
906 # For each vCPU, map it to the proper list of physical CPUs
907 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
908 affinity.set_process_affinity_mask(thread_dict[i],
909 cls._BuildAffinityCpuMask(vcpu))
911 def _GetVcpuThreadIds(self, instance_name):
912 """Get a mapping of vCPU no. to thread IDs for the instance
914 @type instance_name: string
915 @param instance_name: instance in question
916 @rtype: dictionary of int:int
917 @return: a dictionary mapping vCPU numbers to thread IDs
921 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
922 for line in output.stdout.splitlines():
923 match = self._CPU_INFO_RE.search(line)
926 grp = map(int, match.groups())
927 result[grp[0]] = grp[1]
931 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
932 """Complete CPU pinning.
934 @type instance_name: string
935 @param instance_name: name of instance
936 @type cpu_mask: string
937 @param cpu_mask: CPU pinning mask as entered by user
940 # Get KVM process ID, to be used if need to pin entire VM
941 _, pid, _ = self._InstancePidAlive(instance_name)
942 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
943 thread_dict = self._GetVcpuThreadIds(instance_name)
944 # Run CPU pinning, based on configured mask
945 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
947 def ListInstances(self):
948 """Get the list of running instances.
950 We can do this by listing our live instances directory and
951 checking whether the associated kvm process is still alive.
955 for name in os.listdir(self._PIDS_DIR):
956 if self._InstancePidAlive(name)[2]:
960 def GetInstanceInfo(self, instance_name):
961 """Get instance properties.
963 @type instance_name: string
964 @param instance_name: the instance name
965 @rtype: tuple of strings
966 @return: (name, id, memory, vcpus, stat, times)
969 _, pid, alive = self._InstancePidAlive(instance_name)
973 _, memory, vcpus = self._InstancePidInfo(pid)
978 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
980 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
981 # Will fail if ballooning is not enabled, but we can then just resort to
983 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
984 memory = mem_bytes / 1048576
985 except errors.HypervisorError:
988 return (instance_name, pid, memory, vcpus, istat, times)
990 def GetAllInstancesInfo(self):
991 """Get properties of all instances.
993 @return: list of tuples (name, id, memory, vcpus, stat, times)
997 for name in os.listdir(self._PIDS_DIR):
999 info = self.GetInstanceInfo(name)
1000 except errors.HypervisorError:
1001 # Ignore exceptions due to instances being shut down
1007 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1009 """Generate KVM information to start an instance.
1011 @type kvmhelp: string
1012 @param kvmhelp: output of kvm --help
1013 @attention: this function must not have any side-effects; for
1014 example, it must not write to the filesystem, or read values
1015 from the current system the are expected to differ between
1016 nodes, since it is only run once at instance startup;
1017 actions/kvm arguments that can vary between systems should be
1018 done in L{_ExecuteKVMRuntime}
1021 # pylint: disable=R0912,R0914,R0915
1022 hvp = instance.hvparams
1023 self.ValidateParameters(hvp)
1025 pidfile = self._InstancePidFile(instance.name)
1026 kvm = hvp[constants.HV_KVM_PATH]
1028 # used just by the vnc server, if enabled
1029 kvm_cmd.extend(["-name", instance.name])
1030 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1032 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1033 if hvp[constants.HV_CPU_CORES]:
1034 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1035 if hvp[constants.HV_CPU_THREADS]:
1036 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1037 if hvp[constants.HV_CPU_SOCKETS]:
1038 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1040 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1042 kvm_cmd.extend(["-pidfile", pidfile])
1043 kvm_cmd.extend(["-balloon", "virtio"])
1044 kvm_cmd.extend(["-daemonize"])
1045 if not instance.hvparams[constants.HV_ACPI]:
1046 kvm_cmd.extend(["-no-acpi"])
1047 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1048 constants.INSTANCE_REBOOT_EXIT:
1049 kvm_cmd.extend(["-no-reboot"])
1051 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1053 mversion = self._GetDefaultMachineVersion(kvm)
1054 if self._MACHINE_RE.search(kvmhelp):
1055 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
1056 # extra hypervisor parameters. We should also investigate whether and how
1057 # shadow_mem should be considered for the resource model.
1058 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1059 specprop = ",accel=kvm"
1062 machinespec = "%s%s" % (mversion, specprop)
1063 kvm_cmd.extend(["-machine", machinespec])
1065 kvm_cmd.extend(["-M", mversion])
1066 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1067 self._ENABLE_KVM_RE.search(kvmhelp)):
1068 kvm_cmd.extend(["-enable-kvm"])
1069 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1070 self._DISABLE_KVM_RE.search(kvmhelp)):
1071 kvm_cmd.extend(["-disable-kvm"])
1073 kernel_path = hvp[constants.HV_KERNEL_PATH]
1075 boot_disk = boot_cdrom = boot_floppy = boot_network = False
1077 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1078 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1079 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1080 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1083 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1086 kvm_cmd.extend(["-boot", "n"])
1088 # whether this is an older KVM version that uses the boot=on flag
1090 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1092 disk_type = hvp[constants.HV_DISK_TYPE]
1093 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1094 if_val = ",if=virtio"
1096 if_val = ",if=%s" % disk_type
1098 disk_cache = hvp[constants.HV_DISK_CACHE]
1099 if instance.disk_template in constants.DTS_EXT_MIRROR:
1100 if disk_cache != "none":
1101 # TODO: make this a hard error, instead of a silent overwrite
1102 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1103 " to prevent shared storage corruption on migration",
1105 cache_val = ",cache=none"
1106 elif disk_cache != constants.HT_CACHE_DEFAULT:
1107 cache_val = ",cache=%s" % disk_cache
1110 for cfdev, dev_path in block_devices:
1111 if cfdev.mode != constants.DISK_RDWR:
1112 raise errors.HypervisorError("Instance has read-only disks which"
1113 " are not supported by KVM")
1114 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1117 kvm_cmd.extend(["-boot", "c"])
1119 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1120 boot_val = ",boot=on"
1122 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1124 kvm_cmd.extend(["-drive", drive_val])
1126 #Now we can specify a different device type for CDROM devices.
1127 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1128 if not cdrom_disk_type:
1129 cdrom_disk_type = disk_type
1131 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1133 options = ",format=raw,media=cdrom"
1134 # set cdrom 'if' type
1136 actual_cdrom_type = constants.HT_DISK_IDE
1137 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1138 actual_cdrom_type = "virtio"
1140 actual_cdrom_type = cdrom_disk_type
1141 if_val = ",if=%s" % actual_cdrom_type
1142 # set boot flag, if needed
1145 kvm_cmd.extend(["-boot", "d"])
1147 boot_val = ",boot=on"
1148 # and finally build the entire '-drive' value
1149 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1150 kvm_cmd.extend(["-drive", drive_val])
1152 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1154 options = ",format=raw,media=cdrom"
1155 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1156 if_val = ",if=virtio"
1158 if_val = ",if=%s" % cdrom_disk_type
1159 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1160 kvm_cmd.extend(["-drive", drive_val])
1162 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1164 options = ",format=raw,media=disk"
1166 kvm_cmd.extend(["-boot", "a"])
1167 options = "%s,boot=on" % options
1168 if_val = ",if=floppy"
1169 options = "%s%s" % (options, if_val)
1170 drive_val = "file=%s%s" % (floppy_image, options)
1171 kvm_cmd.extend(["-drive", drive_val])
1174 kvm_cmd.extend(["-kernel", kernel_path])
1175 initrd_path = hvp[constants.HV_INITRD_PATH]
1177 kvm_cmd.extend(["-initrd", initrd_path])
1178 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1179 hvp[constants.HV_KERNEL_ARGS]]
1180 if hvp[constants.HV_SERIAL_CONSOLE]:
1181 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1182 root_append.append("console=ttyS0,%s" % serial_speed)
1183 kvm_cmd.extend(["-append", " ".join(root_append)])
1185 mem_path = hvp[constants.HV_MEM_PATH]
1187 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1189 monitor_dev = ("unix:%s,server,nowait" %
1190 self._InstanceMonitor(instance.name))
1191 kvm_cmd.extend(["-monitor", monitor_dev])
1192 if hvp[constants.HV_SERIAL_CONSOLE]:
1193 serial_dev = ("unix:%s,server,nowait" %
1194 self._InstanceSerial(instance.name))
1195 kvm_cmd.extend(["-serial", serial_dev])
1197 kvm_cmd.extend(["-serial", "none"])
1199 mouse_type = hvp[constants.HV_USB_MOUSE]
1200 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1201 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1202 spice_ip_version = None
1204 kvm_cmd.extend(["-usb"])
1207 kvm_cmd.extend(["-usbdevice", mouse_type])
1208 elif vnc_bind_address:
1209 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1211 if vnc_bind_address:
1212 if netutils.IP4Address.IsValid(vnc_bind_address):
1213 if instance.network_port > constants.VNC_BASE_PORT:
1214 display = instance.network_port - constants.VNC_BASE_PORT
1215 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1216 vnc_arg = ":%d" % (display)
1218 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1220 logging.error("Network port is not a valid VNC display (%d < %d)."
1221 " Not starting VNC", instance.network_port,
1222 constants.VNC_BASE_PORT)
1225 # Only allow tls and other option when not binding to a file, for now.
1226 # kvm/qemu gets confused otherwise about the filename to use.
1228 if hvp[constants.HV_VNC_TLS]:
1229 vnc_append = "%s,tls" % vnc_append
1230 if hvp[constants.HV_VNC_X509_VERIFY]:
1231 vnc_append = "%s,x509verify=%s" % (vnc_append,
1232 hvp[constants.HV_VNC_X509])
1233 elif hvp[constants.HV_VNC_X509]:
1234 vnc_append = "%s,x509=%s" % (vnc_append,
1235 hvp[constants.HV_VNC_X509])
1236 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1237 vnc_append = "%s,password" % vnc_append
1239 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1242 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1244 kvm_cmd.extend(["-vnc", vnc_arg])
1246 # FIXME: this is wrong here; the iface ip address differs
1247 # between systems, so it should be done in _ExecuteKVMRuntime
1248 if netutils.IsValidInterface(spice_bind):
1249 # The user specified a network interface, we have to figure out the IP
1251 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1252 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1254 # if the user specified an IP version and the interface does not
1255 # have that kind of IP addresses, throw an exception
1256 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1257 if not addresses[spice_ip_version]:
1258 raise errors.HypervisorError("spice: unable to get an IPv%s address"
1259 " for %s" % (spice_ip_version,
1262 # the user did not specify an IP version, we have to figure it out
1263 elif (addresses[constants.IP4_VERSION] and
1264 addresses[constants.IP6_VERSION]):
1265 # we have both ipv4 and ipv6, let's use the cluster default IP
1267 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1268 spice_ip_version = \
1269 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1270 elif addresses[constants.IP4_VERSION]:
1271 spice_ip_version = constants.IP4_VERSION
1272 elif addresses[constants.IP6_VERSION]:
1273 spice_ip_version = constants.IP6_VERSION
1275 raise errors.HypervisorError("spice: unable to get an IP address"
1276 " for %s" % (spice_bind))
1278 spice_address = addresses[spice_ip_version][0]
1281 # spice_bind is known to be a valid IP address, because
1282 # ValidateParameters checked it.
1283 spice_address = spice_bind
1285 spice_arg = "addr=%s" % spice_address
1286 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1287 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1288 (spice_arg, instance.network_port,
1289 pathutils.SPICE_CACERT_FILE))
1290 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1291 (spice_arg, pathutils.SPICE_CERT_FILE,
1292 pathutils.SPICE_CERT_FILE))
1293 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1295 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1297 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1299 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1300 spice_arg = "%s,disable-ticketing" % spice_arg
1302 if spice_ip_version:
1303 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1305 # Image compression options
1306 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1307 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1308 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1310 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1312 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1314 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1316 # Video stream detection
1317 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1319 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1321 # Audio compression, by default in qemu-kvm it is on
1322 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1323 spice_arg = "%s,playback-compression=off" % spice_arg
1324 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1325 spice_arg = "%s,agent-mouse=off" % spice_arg
1327 # Enable the spice agent communication channel between the host and the
1329 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1330 kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1331 "name=com.redhat.spice.0"])
1332 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1334 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1335 kvm_cmd.extend(["-spice", spice_arg])
1338 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1339 # also works in earlier versions though (tested with 1.1 and 1.3)
1340 if self._DISPLAY_RE.search(kvmhelp):
1341 kvm_cmd.extend(["-display", "none"])
1343 kvm_cmd.extend(["-nographic"])
1345 if hvp[constants.HV_USE_LOCALTIME]:
1346 kvm_cmd.extend(["-localtime"])
1348 if hvp[constants.HV_KVM_USE_CHROOT]:
1349 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1351 # Add qemu-KVM -cpu param
1352 if hvp[constants.HV_CPU_TYPE]:
1353 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1355 # As requested by music lovers
1356 if hvp[constants.HV_SOUNDHW]:
1357 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1359 # Pass a -vga option if requested, or if spice is used, for backwards
1361 if hvp[constants.HV_VGA]:
1362 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1364 kvm_cmd.extend(["-vga", "qxl"])
1366 # Various types of usb devices, comma separated
1367 if hvp[constants.HV_USB_DEVICES]:
1368 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1369 kvm_cmd.extend(["-usbdevice", dev])
1371 if hvp[constants.HV_KVM_EXTRA]:
1372 kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA].split(" ")])
1374 # Save the current instance nics, but defer their expansion as parameters,
1375 # as we'll need to generate executable temp files for them.
1376 kvm_nics = instance.nics
1379 return (kvm_cmd, kvm_nics, hvparams)
1381 def _WriteKVMRuntime(self, instance_name, data):
1382 """Write an instance's KVM runtime
1386 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1388 except EnvironmentError, err:
1389 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1391 def _ReadKVMRuntime(self, instance_name):
1392 """Read an instance's KVM runtime
1396 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1397 except EnvironmentError, err:
1398 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1401 def _SaveKVMRuntime(self, instance, kvm_runtime):
1402 """Save an instance's KVM runtime
1405 kvm_cmd, kvm_nics, hvparams = kvm_runtime
1406 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1407 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1408 self._WriteKVMRuntime(instance.name, serialized_form)
1410 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1411 """Load an instance's KVM runtime
1414 if not serialized_runtime:
1415 serialized_runtime = self._ReadKVMRuntime(instance.name)
1416 loaded_runtime = serializer.Load(serialized_runtime)
1417 kvm_cmd, serialized_nics, hvparams = loaded_runtime
1418 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1419 return (kvm_cmd, kvm_nics, hvparams)
1421 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1422 """Run the KVM cmd and check for errors
1425 @param name: instance name
1426 @type kvm_cmd: list of strings
1427 @param kvm_cmd: runcmd input for kvm
1428 @type tap_fds: list of int
1429 @param tap_fds: fds of tap devices opened by Ganeti
1433 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1436 utils_wrapper.CloseFdNoError(fd)
1439 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1440 (name, result.fail_reason, result.output))
1441 if not self._InstancePidAlive(name)[2]:
1442 raise errors.HypervisorError("Failed to start instance %s" % name)
1444 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1445 """Execute a KVM cmd, after completing it with some last minute data.
1447 @type incoming: tuple of strings
1448 @param incoming: (target_host_ip, port)
1449 @type kvmhelp: string
1450 @param kvmhelp: output of kvm --help
1453 # Small _ExecuteKVMRuntime hv parameters programming howto:
1454 # - conf_hvp contains the parameters as configured on ganeti. they might
1455 # have changed since the instance started; only use them if the change
1456 # won't affect the inside of the instance (which hasn't been rebooted).
1457 # - up_hvp contains the parameters as they were when the instance was
1458 # started, plus any new parameter which has been added between ganeti
1459 # versions: it is paramount that those default to a value which won't
1460 # affect the inside of the instance as well.
1461 conf_hvp = instance.hvparams
1462 name = instance.name
1463 self._CheckDown(name)
1467 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1468 # the first element of kvm_cmd is always the path to the kvm binary
1469 kvm_path = kvm_cmd[0]
1470 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1472 # We know it's safe to run as a different user upon migration, so we'll use
1473 # the latest conf, from conf_hvp.
1474 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1475 if security_model == constants.HT_SM_USER:
1476 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1478 keymap = conf_hvp[constants.HV_KEYMAP]
1480 keymap_path = self._InstanceKeymapFile(name)
1481 # If a keymap file is specified, KVM won't use its internal defaults. By
1482 # first including the "en-us" layout, an error on loading the actual
1483 # layout (e.g. because it can't be found) won't lead to a non-functional
1484 # keyboard. A keyboard with incorrect keys is still better than none.
1485 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1486 kvm_cmd.extend(["-k", keymap_path])
1488 # We have reasons to believe changing something like the nic driver/type
1489 # upon migration won't exactly fly with the instance kernel, so for nic
1490 # related parameters we'll use up_hvp
1494 kvm_cmd.extend(["-net", "none"])
1498 nic_type = up_hvp[constants.HV_NIC_TYPE]
1499 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1500 nic_model = self._VIRTIO
1502 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1503 if self._NEW_VIRTIO_RE.search(devlist):
1504 nic_model = self._VIRTIO_NET_PCI
1506 except errors.HypervisorError, _:
1507 # Older versions of kvm don't support DEVICE_LIST, but they don't
1508 # have new virtio syntax either.
1511 if up_hvp[constants.HV_VHOST_NET]:
1512 # check for vhost_net support
1513 if self._VHOST_RE.search(kvmhelp):
1514 tap_extra = ",vhost=on"
1516 raise errors.HypervisorError("vhost_net is configured"
1517 " but it is not available")
1519 nic_model = nic_type
1521 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1523 for nic_seq, nic in enumerate(kvm_nics):
1524 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1525 tapfds.append(tapfd)
1526 taps.append(tapname)
1527 if kvm_supports_netdev:
1528 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1529 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1530 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1532 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1534 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1535 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1538 target, port = incoming
1539 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1541 # Changing the vnc password doesn't bother the guest that much. At most it
1542 # will surprise people who connect to it. Whether positively or negatively
1544 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1548 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1549 except EnvironmentError, err:
1550 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1551 % (vnc_pwd_file, err))
1553 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1554 utils.EnsureDirs([(self._InstanceChrootDir(name),
1555 constants.SECURE_DIR_MODE)])
1557 # Automatically enable QMP if version is >= 0.14
1558 if self._QMP_RE.search(kvmhelp):
1559 logging.debug("Enabling QMP")
1560 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1561 self._InstanceQmpMonitor(instance.name)])
1563 # Configure the network now for starting instances and bridged interfaces,
1564 # during FinalizeMigration for incoming instances' routed interfaces
1565 for nic_seq, nic in enumerate(kvm_nics):
1567 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1569 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1571 # CPU affinity requires kvm to start paused, so we set this flag if the
1572 # instance is not already paused and if we are not going to accept a
1573 # migrating instance. In the latter case, pausing is not needed.
1574 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1575 if start_kvm_paused:
1576 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1578 # Note: CPU pinning is using up_hvp since changes take effect
1579 # during instance startup anyway, and to avoid problems when soft
1580 # rebooting the instance.
1582 if up_hvp.get(constants.HV_CPU_MASK, None):
1585 if security_model == constants.HT_SM_POOL:
1586 ss = ssconf.SimpleStore()
1587 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1588 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1589 uid = uidpool.RequestUnusedUid(all_uids)
1591 username = pwd.getpwuid(uid.GetUid()).pw_name
1592 kvm_cmd.extend(["-runas", username])
1593 self._RunKVMCmd(name, kvm_cmd, tapfds)
1595 uidpool.ReleaseUid(uid)
1599 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1601 self._RunKVMCmd(name, kvm_cmd, tapfds)
1603 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1604 constants.RUN_DIRS_MODE)])
1605 for nic_seq, tap in enumerate(taps):
1606 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1610 change_cmd = "change vnc password %s" % vnc_pwd
1611 self._CallMonitorCommand(instance.name, change_cmd)
1613 # Setting SPICE password. We are not vulnerable to malicious passwordless
1614 # connection attempts because SPICE by default does not allow connections
1615 # if neither a password nor the "disable_ticketing" options are specified.
1616 # As soon as we send the password via QMP, that password is a valid ticket
1618 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1619 if spice_password_file:
1622 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1623 except EnvironmentError, err:
1624 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1625 % (spice_password_file, err))
1627 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1630 "protocol": "spice",
1631 "password": spice_pwd,
1633 qmp.Execute("set_password", arguments)
1635 for filename in temp_files:
1636 utils.RemoveFile(filename)
1638 # If requested, set CPU affinity and resume instance execution
1640 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1642 start_memory = self._InstanceStartupMemory(instance)
1643 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1644 self.BalloonInstanceMemory(instance, start_memory)
1646 if start_kvm_paused:
1647 # To control CPU pinning, ballooning, and vnc/spice passwords
1648 # the VM was started in a frozen state. If freezing was not
1649 # explicitly requested resume the vm status.
1650 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1652 def StartInstance(self, instance, block_devices, startup_paused):
1653 """Start an instance.
1656 self._CheckDown(instance.name)
1657 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1658 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1659 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1660 startup_paused, kvmhelp)
1661 self._SaveKVMRuntime(instance, kvm_runtime)
1662 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1664 def _CallMonitorCommand(self, instance_name, command):
1665 """Invoke a command on the instance monitor.
1668 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1669 (utils.ShellQuote(command),
1670 constants.SOCAT_PATH,
1671 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1672 result = utils.RunCmd(socat)
1674 msg = ("Failed to send command '%s' to instance %s."
1675 " output: %s, error: %s, fail_reason: %s" %
1676 (command, instance_name,
1677 result.stdout, result.stderr, result.fail_reason))
1678 raise errors.HypervisorError(msg)
1683 def _ParseKVMVersion(cls, text):
1684 """Parse the KVM version from the --help output.
1687 @param text: output of kvm --help
1688 @return: (version, v_maj, v_min, v_rev)
1689 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1692 match = cls._VERSION_RE.search(text.splitlines()[0])
1694 raise errors.HypervisorError("Unable to get KVM version")
1696 v_all = match.group(0)
1697 v_maj = int(match.group(1))
1698 v_min = int(match.group(2))
1700 v_rev = int(match.group(4))
1703 return (v_all, v_maj, v_min, v_rev)
1706 def _GetKVMOutput(cls, kvm_path, option):
1707 """Return the output of a kvm invocation
1709 @type kvm_path: string
1710 @param kvm_path: path to the kvm executable
1711 @type option: a key of _KVMOPTS_CMDS
1712 @param option: kvm option to fetch the output from
1713 @return: output a supported kvm invocation
1714 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1717 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1719 optlist, can_fail = cls._KVMOPTS_CMDS[option]
1721 result = utils.RunCmd([kvm_path] + optlist)
1722 if result.failed and not can_fail:
1723 raise errors.HypervisorError("Unable to get KVM %s output" %
1724 " ".join(cls._KVMOPTS_CMDS[option]))
1725 return result.output
1728 def _GetKVMVersion(cls, kvm_path):
1729 """Return the installed KVM version.
1731 @return: (version, v_maj, v_min, v_rev)
1732 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1735 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1738 def _GetDefaultMachineVersion(cls, kvm_path):
1739 """Return the default hardware revision (e.g. pc-1.1)
1742 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1743 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1745 return match.group(1)
1749 def StopInstance(self, instance, force=False, retry=False, name=None):
1750 """Stop an instance.
1753 if name is not None and not force:
1754 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1756 name = instance.name
1757 acpi = instance.hvparams[constants.HV_ACPI]
1760 _, pid, alive = self._InstancePidAlive(name)
1761 if pid > 0 and alive:
1762 if force or not acpi:
1763 utils.KillProcess(pid)
1765 self._CallMonitorCommand(name, "system_powerdown")
1767 def CleanupInstance(self, instance_name):
1768 """Cleanup after a stopped instance
1771 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1772 if pid > 0 and alive:
1773 raise errors.HypervisorError("Cannot cleanup a live instance")
1774 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1776 def RebootInstance(self, instance):
1777 """Reboot an instance.
1780 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1781 # socket the instance will stop, but now power up again. So we'll resort
1782 # to shutdown and restart.
1783 _, _, alive = self._InstancePidAlive(instance.name)
1785 raise errors.HypervisorError("Failed to reboot instance %s:"
1786 " not running" % instance.name)
1787 # StopInstance will delete the saved KVM runtime so:
1788 # ...first load it...
1789 kvm_runtime = self._LoadKVMRuntime(instance)
1790 # ...now we can safely call StopInstance...
1791 if not self.StopInstance(instance):
1792 self.StopInstance(instance, force=True)
1793 # ...and finally we can save it again, and execute it...
1794 self._SaveKVMRuntime(instance, kvm_runtime)
1795 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1796 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1797 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1799 def MigrationInfo(self, instance):
1800 """Get instance information to perform a migration.
1802 @type instance: L{objects.Instance}
1803 @param instance: instance to be migrated
1805 @return: content of the KVM runtime file
1808 return self._ReadKVMRuntime(instance.name)
1810 def AcceptInstance(self, instance, info, target):
1811 """Prepare to accept an instance.
1813 @type instance: L{objects.Instance}
1814 @param instance: instance to be accepted
1816 @param info: content of the KVM runtime file on the source node
1817 @type target: string
1818 @param target: target host (usually ip), on this node
1821 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1822 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1823 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1824 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1825 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1826 incoming=incoming_address)
1828 def FinalizeMigrationDst(self, instance, info, success):
1829 """Finalize the instance migration on the target node.
1831 Stop the incoming mode KVM.
1833 @type instance: L{objects.Instance}
1834 @param instance: instance whose migration is being finalized
1838 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1839 kvm_nics = kvm_runtime[1]
1841 for nic_seq, nic in enumerate(kvm_nics):
1842 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1843 # Bridged interfaces have already been configured
1846 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1847 except EnvironmentError, err:
1848 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1849 instance.name, nic_seq, str(err))
1852 self._ConfigureNIC(instance, nic_seq, nic, tap)
1853 except errors.HypervisorError, err:
1854 logging.warning(str(err))
1856 self._WriteKVMRuntime(instance.name, info)
1858 self.StopInstance(instance, force=True)
1860 def MigrateInstance(self, instance, target, live):
1861 """Migrate an instance to a target node.
1863 The migration will not be attempted if the instance is not
1866 @type instance: L{objects.Instance}
1867 @param instance: the instance to be migrated
1868 @type target: string
1869 @param target: ip address of the target node
1871 @param live: perform a live migration
1874 instance_name = instance.name
1875 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1876 _, _, alive = self._InstancePidAlive(instance_name)
1878 raise errors.HypervisorError("Instance not running, cannot migrate")
1881 self._CallMonitorCommand(instance_name, "stop")
1883 migrate_command = ("migrate_set_speed %dm" %
1884 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1885 self._CallMonitorCommand(instance_name, migrate_command)
1887 migrate_command = ("migrate_set_downtime %dms" %
1888 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1889 self._CallMonitorCommand(instance_name, migrate_command)
1891 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1892 self._CallMonitorCommand(instance_name, migrate_command)
1894 def FinalizeMigrationSource(self, instance, success, live):
1895 """Finalize the instance migration on the source node.
1897 @type instance: L{objects.Instance}
1898 @param instance: the instance that was migrated
1900 @param success: whether the migration succeeded or not
1902 @param live: whether the user requested a live migration or not
1906 pidfile, pid, _ = self._InstancePidAlive(instance.name)
1907 utils.KillProcess(pid)
1908 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1910 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1912 def GetMigrationStatus(self, instance):
1913 """Get the migration status
1915 @type instance: L{objects.Instance}
1916 @param instance: the instance that is being migrated
1917 @rtype: L{objects.MigrationStatus}
1918 @return: the status of the current migration (one of
1919 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1920 progress info that can be retrieved from the hypervisor
1923 info_command = "info migrate"
1924 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1925 result = self._CallMonitorCommand(instance.name, info_command)
1926 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1928 if not result.stdout:
1929 logging.info("KVM: empty 'info migrate' result")
1931 logging.warning("KVM: unknown 'info migrate' result: %s",
1934 status = match.group(1)
1935 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1936 migration_status = objects.MigrationStatus(status=status)
1937 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1939 migration_status.transferred_ram = match.group("transferred")
1940 migration_status.total_ram = match.group("total")
1942 return migration_status
1944 logging.warning("KVM: unknown migration status '%s'", status)
1946 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1948 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1950 def BalloonInstanceMemory(self, instance, mem):
1951 """Balloon an instance memory to a certain value.
1953 @type instance: L{objects.Instance}
1954 @param instance: instance to be accepted
1956 @param mem: actual memory size to use for instance runtime
1959 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1961 def GetNodeInfo(self):
1962 """Return information about the node.
1964 @return: a dict with the following keys (values in MiB):
1965 - memory_total: the total memory size on the node
1966 - memory_free: the available memory on the node for instances
1967 - memory_dom0: the memory used by the node itself, if available
1968 - hv_version: the hypervisor version in the form (major, minor,
1972 result = self.GetLinuxNodeInfo()
1973 # FIXME: this is the global kvm version, but the actual version can be
1974 # customized as an hv parameter. we should use the nodegroup's default kvm
1975 # path parameter here.
1976 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
1977 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1981 def GetInstanceConsole(cls, instance, hvparams, beparams):
1982 """Return a command for connecting to the console of an instance.
1985 if hvparams[constants.HV_SERIAL_CONSOLE]:
1986 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1987 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1988 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1989 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1990 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1991 return objects.InstanceConsole(instance=instance.name,
1992 kind=constants.CONS_SSH,
1993 host=instance.primary_node,
1994 user=constants.SSH_CONSOLE_USER,
1997 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1998 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1999 display = instance.network_port - constants.VNC_BASE_PORT
2000 return objects.InstanceConsole(instance=instance.name,
2001 kind=constants.CONS_VNC,
2002 host=vnc_bind_address,
2003 port=instance.network_port,
2006 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2008 return objects.InstanceConsole(instance=instance.name,
2009 kind=constants.CONS_SPICE,
2011 port=instance.network_port)
2013 return objects.InstanceConsole(instance=instance.name,
2014 kind=constants.CONS_MESSAGE,
2015 message=("No serial shell for instance %s" %
2019 """Verify the hypervisor.
2021 Check that the required binaries exist.
2023 @return: Problem description if something is wrong, C{None} otherwise
2027 # FIXME: this is the global kvm binary, but the actual path can be
2028 # customized as an hv parameter; we should use the nodegroup's
2029 # default kvm path parameter here.
2030 if not os.path.exists(constants.KVM_PATH):
2031 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2032 if not os.path.exists(constants.SOCAT_PATH):
2033 msgs.append("The socat binary ('%s') does not exist" %
2034 constants.SOCAT_PATH)
2036 return self._FormatVerifyResults(msgs)
2039 def CheckParameterSyntax(cls, hvparams):
2040 """Check the given parameters for validity.
2042 @type hvparams: dict
2043 @param hvparams: dictionary with parameter names/value
2044 @raise errors.HypervisorError: when a parameter is not valid
2047 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2049 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2051 if not hvparams[constants.HV_ROOT_PATH]:
2052 raise errors.HypervisorError("Need a root partition for the instance,"
2053 " if a kernel is defined")
2055 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2056 not hvparams[constants.HV_VNC_X509]):
2057 raise errors.HypervisorError("%s must be defined, if %s is" %
2058 (constants.HV_VNC_X509,
2059 constants.HV_VNC_X509_VERIFY))
2061 if hvparams[constants.HV_SERIAL_CONSOLE]:
2062 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2063 valid_speeds = constants.VALID_SERIAL_SPEEDS
2064 if not serial_speed or serial_speed not in valid_speeds:
2065 raise errors.HypervisorError("Invalid serial console speed, must be"
2067 utils.CommaJoin(valid_speeds))
2069 boot_order = hvparams[constants.HV_BOOT_ORDER]
2070 if (boot_order == constants.HT_BO_CDROM and
2071 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2072 raise errors.HypervisorError("Cannot boot from cdrom without an"
2075 security_model = hvparams[constants.HV_SECURITY_MODEL]
2076 if security_model == constants.HT_SM_USER:
2077 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2078 raise errors.HypervisorError("A security domain (user to run kvm as)"
2079 " must be specified")
2080 elif (security_model == constants.HT_SM_NONE or
2081 security_model == constants.HT_SM_POOL):
2082 if hvparams[constants.HV_SECURITY_DOMAIN]:
2083 raise errors.HypervisorError("Cannot have a security domain when the"
2084 " security model is 'none' or 'pool'")
2086 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2087 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2089 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2090 # if an IP version is specified, the spice_bind parameter must be an
2092 if (netutils.IP4Address.IsValid(spice_bind) and
2093 spice_ip_version != constants.IP4_VERSION):
2094 raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2095 " the specified IP version is %s" %
2096 (spice_bind, spice_ip_version))
2098 if (netutils.IP6Address.IsValid(spice_bind) and
2099 spice_ip_version != constants.IP6_VERSION):
2100 raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2101 " the specified IP version is %s" %
2102 (spice_bind, spice_ip_version))
2104 # All the other SPICE parameters depend on spice_bind being set. Raise an
2105 # error if any of them is set without it.
2106 for param in _SPICE_ADDITIONAL_PARAMS:
2108 raise errors.HypervisorError("spice: %s requires %s to be set" %
2109 (param, constants.HV_KVM_SPICE_BIND))
2112 def ValidateParameters(cls, hvparams):
2113 """Check the given parameters for validity.
2115 @type hvparams: dict
2116 @param hvparams: dictionary with parameter names/value
2117 @raise errors.HypervisorError: when a parameter is not valid
2120 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2122 kvm_path = hvparams[constants.HV_KVM_PATH]
2124 security_model = hvparams[constants.HV_SECURITY_MODEL]
2125 if security_model == constants.HT_SM_USER:
2126 username = hvparams[constants.HV_SECURITY_DOMAIN]
2128 pwd.getpwnam(username)
2130 raise errors.HypervisorError("Unknown security domain user %s"
2133 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2135 # only one of VNC and SPICE can be used currently.
2136 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2137 raise errors.HypervisorError("both SPICE and VNC are configured, but"
2138 " only one of them can be used at a"
2141 # check that KVM supports SPICE
2142 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2143 if not cls._SPICE_RE.search(kvmhelp):
2144 raise errors.HypervisorError("spice is configured, but it is not"
2145 " supported according to kvm --help")
2147 # if spice_bind is not an IP address, it must be a valid interface
2148 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2149 or netutils.IP6Address.IsValid(spice_bind))
2150 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2151 raise errors.HypervisorError("spice: the %s parameter must be either"
2152 " a valid IP address or interface name" %
2153 constants.HV_KVM_SPICE_BIND)
2155 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2157 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2158 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2159 raise errors.HypervisorError("Unsupported machine version: %s" %
2163 def PowercycleNode(cls):
2164 """KVM powercycle, just a wrapper over Linux powercycle.
2167 cls.LinuxPowercycle()