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 _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
553 # match -drive.*boot=on|off on different lines, but in between accept only
554 # dashes not preceeded by a new line (which would mean another option
555 # different than -drive is starting)
556 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
561 ANCILLARY_FILES_OPT = [
565 # Supported kvm options to get output from
566 _KVMOPT_HELP = "help"
567 _KVMOPT_MLIST = "mlist"
568 _KVMOPT_DEVICELIST = "devicelist"
570 # Command to execute to get the output from kvm, and whether to
571 # accept the output even on failure.
573 _KVMOPT_HELP: (["--help"], False),
574 _KVMOPT_MLIST: (["-M", "?"], False),
575 _KVMOPT_DEVICELIST: (["-device", "?"], True),
579 hv_base.BaseHypervisor.__init__(self)
580 # Let's make sure the directories we need exist, even if the RUN_DIR lives
581 # in a tmpfs filesystem or has been otherwise wiped out.
582 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
583 utils.EnsureDirs(dirs)
586 def _InstancePidFile(cls, instance_name):
587 """Returns the instance pidfile.
590 return utils.PathJoin(cls._PIDS_DIR, instance_name)
593 def _InstanceUidFile(cls, instance_name):
594 """Returns the instance uidfile.
597 return utils.PathJoin(cls._UIDS_DIR, instance_name)
600 def _InstancePidInfo(cls, pid):
601 """Check pid file for instance information.
603 Check that a pid file is associated with an instance, and retrieve
604 information from its command line.
606 @type pid: string or int
607 @param pid: process id of the instance to check
609 @return: (instance_name, memory, vcpus)
610 @raise errors.HypervisorError: when an instance cannot be found
613 alive = utils.IsProcessAlive(pid)
615 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
617 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
619 cmdline = utils.ReadFile(cmdline_file)
620 except EnvironmentError, err:
621 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
628 arg_list = cmdline.split("\x00")
630 arg = arg_list.pop(0)
632 instance = arg_list.pop(0)
634 memory = int(arg_list.pop(0))
636 vcpus = int(arg_list.pop(0).split(",")[0])
639 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
642 return (instance, memory, vcpus)
644 def _InstancePidAlive(self, instance_name):
645 """Returns the instance pidfile, pid, and liveness.
647 @type instance_name: string
648 @param instance_name: instance name
650 @return: (pid file name, pid, liveness)
653 pidfile = self._InstancePidFile(instance_name)
654 pid = utils.ReadPidFile(pidfile)
658 cmd_instance = self._InstancePidInfo(pid)[0]
659 alive = (cmd_instance == instance_name)
660 except errors.HypervisorError:
663 return (pidfile, pid, alive)
665 def _CheckDown(self, instance_name):
666 """Raises an error unless the given instance is down.
669 alive = self._InstancePidAlive(instance_name)[2]
671 raise errors.HypervisorError("Failed to start instance %s: %s" %
672 (instance_name, "already running"))
675 def _InstanceMonitor(cls, instance_name):
676 """Returns the instance monitor socket name
679 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
682 def _InstanceSerial(cls, instance_name):
683 """Returns the instance serial socket name
686 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
689 def _InstanceQmpMonitor(cls, instance_name):
690 """Returns the instance serial QMP socket name
693 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
696 def _SocatUnixConsoleParams():
697 """Returns the correct parameters for socat
699 If we have a new-enough socat we can use raw mode with an escape character.
702 if constants.SOCAT_USE_ESCAPE:
703 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
705 return "echo=0,icanon=0"
708 def _InstanceKVMRuntime(cls, instance_name):
709 """Returns the instance KVM runtime filename
712 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
715 def _InstanceChrootDir(cls, instance_name):
716 """Returns the name of the KVM chroot dir of the instance
719 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
722 def _InstanceNICDir(cls, instance_name):
723 """Returns the name of the directory holding the tap device files for a
727 return utils.PathJoin(cls._NICS_DIR, instance_name)
730 def _InstanceNICFile(cls, instance_name, seq):
731 """Returns the name of the file containing the tap device for a given NIC
734 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
737 def _InstanceKeymapFile(cls, instance_name):
738 """Returns the name of the file containing the keymap for a given instance
741 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
744 def _TryReadUidFile(cls, uid_file):
745 """Try to read a uid file
748 if os.path.exists(uid_file):
750 uid = int(utils.ReadOneLineFile(uid_file))
752 except EnvironmentError:
753 logging.warning("Can't read uid file", exc_info=True)
754 except (TypeError, ValueError):
755 logging.warning("Can't parse uid file contents", exc_info=True)
759 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
760 """Removes an instance's rutime sockets/files/dirs.
763 utils.RemoveFile(pidfile)
764 utils.RemoveFile(cls._InstanceMonitor(instance_name))
765 utils.RemoveFile(cls._InstanceSerial(instance_name))
766 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
767 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
768 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
769 uid_file = cls._InstanceUidFile(instance_name)
770 uid = cls._TryReadUidFile(uid_file)
771 utils.RemoveFile(uid_file)
773 uidpool.ReleaseUid(uid)
775 shutil.rmtree(cls._InstanceNICDir(instance_name))
777 if err.errno != errno.ENOENT:
780 chroot_dir = cls._InstanceChrootDir(instance_name)
781 utils.RemoveDir(chroot_dir)
783 if err.errno == errno.ENOTEMPTY:
784 # The chroot directory is expected to be empty, but it isn't.
785 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
788 utils.TimestampForFilename()))
789 logging.warning("The chroot directory of instance %s can not be"
790 " removed as it is not empty. Moving it to the"
791 " quarantine instead. Please investigate the"
792 " contents (%s) and clean up manually",
793 instance_name, new_chroot_dir)
794 utils.RenameFile(chroot_dir, new_chroot_dir)
799 def _ConfigureNIC(instance, seq, nic, tap):
800 """Run the network configuration script for a specified NIC
802 @param instance: instance we're acting on
803 @type instance: instance object
804 @param seq: nic sequence number
806 @param nic: nic we're acting on
807 @type nic: nic object
808 @param tap: the host's tap interface this NIC corresponds to
813 tags = " ".join(instance.tags)
818 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
819 "INSTANCE": instance.name,
821 "MODE": nic.nicparams[constants.NIC_MODE],
823 "INTERFACE_INDEX": str(seq),
830 if nic.nicparams[constants.NIC_LINK]:
831 env["LINK"] = nic.nicparams[constants.NIC_LINK]
834 n = objects.Network.FromDict(nic.netinfo)
835 env.update(n.HooksDict())
837 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
838 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
840 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
842 raise errors.HypervisorError("Failed to configure interface %s: %s."
843 " Network configuration script output: %s" %
844 (tap, result.fail_reason, result.output))
847 def _VerifyAffinityPackage():
849 raise errors.HypervisorError("affinity Python package not"
850 " found; cannot use CPU pinning under KVM")
853 def _BuildAffinityCpuMask(cpu_list):
854 """Create a CPU mask suitable for sched_setaffinity from a list of
857 See man taskset for more info on sched_setaffinity masks.
858 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
860 @type cpu_list: list of int
861 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
863 @return: a bit mask of CPU affinities
866 if cpu_list == constants.CPU_PINNING_OFF:
867 return constants.CPU_PINNING_ALL_KVM
869 return sum(2 ** cpu for cpu in cpu_list)
872 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
873 """Change CPU affinity for running VM according to given CPU mask.
875 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
876 @type cpu_mask: string
877 @param process_id: process ID of KVM process. Used to pin entire VM
879 @type process_id: int
880 @param thread_dict: map of virtual CPUs to KVM thread IDs
881 @type thread_dict: dict int:int
884 # Convert the string CPU mask to a list of list of int's
885 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
887 if len(cpu_list) == 1:
888 all_cpu_mapping = cpu_list[0]
889 if all_cpu_mapping == constants.CPU_PINNING_OFF:
890 # If CPU pinning has 1 entry that's "all", then do nothing
893 # If CPU pinning has one non-all entry, map the entire VM to
894 # one set of physical CPUs
895 cls._VerifyAffinityPackage()
896 affinity.set_process_affinity_mask(
897 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
899 # The number of vCPUs mapped should match the number of vCPUs
900 # reported by KVM. This was already verified earlier, so
901 # here only as a sanity check.
902 assert len(thread_dict) == len(cpu_list)
903 cls._VerifyAffinityPackage()
905 # For each vCPU, map it to the proper list of physical CPUs
906 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
907 affinity.set_process_affinity_mask(thread_dict[i],
908 cls._BuildAffinityCpuMask(vcpu))
910 def _GetVcpuThreadIds(self, instance_name):
911 """Get a mapping of vCPU no. to thread IDs for the instance
913 @type instance_name: string
914 @param instance_name: instance in question
915 @rtype: dictionary of int:int
916 @return: a dictionary mapping vCPU numbers to thread IDs
920 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
921 for line in output.stdout.splitlines():
922 match = self._CPU_INFO_RE.search(line)
925 grp = map(int, match.groups())
926 result[grp[0]] = grp[1]
930 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
931 """Complete CPU pinning.
933 @type instance_name: string
934 @param instance_name: name of instance
935 @type cpu_mask: string
936 @param cpu_mask: CPU pinning mask as entered by user
939 # Get KVM process ID, to be used if need to pin entire VM
940 _, pid, _ = self._InstancePidAlive(instance_name)
941 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
942 thread_dict = self._GetVcpuThreadIds(instance_name)
943 # Run CPU pinning, based on configured mask
944 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
946 def ListInstances(self):
947 """Get the list of running instances.
949 We can do this by listing our live instances directory and
950 checking whether the associated kvm process is still alive.
954 for name in os.listdir(self._PIDS_DIR):
955 if self._InstancePidAlive(name)[2]:
959 def GetInstanceInfo(self, instance_name):
960 """Get instance properties.
962 @type instance_name: string
963 @param instance_name: the instance name
964 @rtype: tuple of strings
965 @return: (name, id, memory, vcpus, stat, times)
968 _, pid, alive = self._InstancePidAlive(instance_name)
972 _, memory, vcpus = self._InstancePidInfo(pid)
977 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
979 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
980 # Will fail if ballooning is not enabled, but we can then just resort to
982 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
983 memory = mem_bytes / 1048576
984 except errors.HypervisorError:
987 return (instance_name, pid, memory, vcpus, istat, times)
989 def GetAllInstancesInfo(self):
990 """Get properties of all instances.
992 @return: list of tuples (name, id, memory, vcpus, stat, times)
996 for name in os.listdir(self._PIDS_DIR):
998 info = self.GetInstanceInfo(name)
999 except errors.HypervisorError:
1000 # Ignore exceptions due to instances being shut down
1006 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
1008 """Generate KVM information to start an instance.
1010 @type kvmhelp: string
1011 @param kvmhelp: output of kvm --help
1012 @attention: this function must not have any side-effects; for
1013 example, it must not write to the filesystem, or read values
1014 from the current system the are expected to differ between
1015 nodes, since it is only run once at instance startup;
1016 actions/kvm arguments that can vary between systems should be
1017 done in L{_ExecuteKVMRuntime}
1020 # pylint: disable=R0912,R0914,R0915
1021 hvp = instance.hvparams
1023 pidfile = self._InstancePidFile(instance.name)
1024 kvm = hvp[constants.HV_KVM_PATH]
1026 # used just by the vnc server, if enabled
1027 kvm_cmd.extend(["-name", instance.name])
1028 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1030 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1031 if hvp[constants.HV_CPU_CORES]:
1032 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1033 if hvp[constants.HV_CPU_THREADS]:
1034 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1035 if hvp[constants.HV_CPU_SOCKETS]:
1036 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1038 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1040 kvm_cmd.extend(["-pidfile", pidfile])
1041 kvm_cmd.extend(["-balloon", "virtio"])
1042 kvm_cmd.extend(["-daemonize"])
1043 if not instance.hvparams[constants.HV_ACPI]:
1044 kvm_cmd.extend(["-no-acpi"])
1045 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1046 constants.INSTANCE_REBOOT_EXIT:
1047 kvm_cmd.extend(["-no-reboot"])
1049 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1051 mversion = self._GetDefaultMachineVersion(kvm)
1052 kvm_cmd.extend(["-M", mversion])
1054 kernel_path = hvp[constants.HV_KERNEL_PATH]
1056 boot_disk = boot_cdrom = boot_floppy = boot_network = False
1058 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1059 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1060 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1061 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1063 self.ValidateParameters(hvp)
1066 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1068 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1069 self._ENABLE_KVM_RE.search(kvmhelp)):
1070 kvm_cmd.extend(["-enable-kvm"])
1071 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1072 self._DISABLE_KVM_RE.search(kvmhelp)):
1073 kvm_cmd.extend(["-disable-kvm"])
1076 kvm_cmd.extend(["-boot", "n"])
1078 # whether this is an older KVM version that uses the boot=on flag
1080 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1082 disk_type = hvp[constants.HV_DISK_TYPE]
1083 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1084 if_val = ",if=virtio"
1086 if_val = ",if=%s" % disk_type
1088 disk_cache = hvp[constants.HV_DISK_CACHE]
1089 if instance.disk_template in constants.DTS_EXT_MIRROR:
1090 if disk_cache != "none":
1091 # TODO: make this a hard error, instead of a silent overwrite
1092 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1093 " to prevent shared storage corruption on migration",
1095 cache_val = ",cache=none"
1096 elif disk_cache != constants.HT_CACHE_DEFAULT:
1097 cache_val = ",cache=%s" % disk_cache
1100 for cfdev, dev_path in block_devices:
1101 if cfdev.mode != constants.DISK_RDWR:
1102 raise errors.HypervisorError("Instance has read-only disks which"
1103 " are not supported by KVM")
1104 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1107 kvm_cmd.extend(["-boot", "c"])
1109 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1110 boot_val = ",boot=on"
1112 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1114 kvm_cmd.extend(["-drive", drive_val])
1116 #Now we can specify a different device type for CDROM devices.
1117 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1118 if not cdrom_disk_type:
1119 cdrom_disk_type = disk_type
1121 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1123 options = ",format=raw,media=cdrom"
1124 # set cdrom 'if' type
1126 actual_cdrom_type = constants.HT_DISK_IDE
1127 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1128 actual_cdrom_type = "virtio"
1130 actual_cdrom_type = cdrom_disk_type
1131 if_val = ",if=%s" % actual_cdrom_type
1132 # set boot flag, if needed
1135 kvm_cmd.extend(["-boot", "d"])
1137 boot_val = ",boot=on"
1138 # and finally build the entire '-drive' value
1139 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1140 kvm_cmd.extend(["-drive", drive_val])
1142 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1144 options = ",format=raw,media=cdrom"
1145 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1146 if_val = ",if=virtio"
1148 if_val = ",if=%s" % cdrom_disk_type
1149 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1150 kvm_cmd.extend(["-drive", drive_val])
1152 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1154 options = ",format=raw,media=disk"
1156 kvm_cmd.extend(["-boot", "a"])
1157 options = "%s,boot=on" % options
1158 if_val = ",if=floppy"
1159 options = "%s%s" % (options, if_val)
1160 drive_val = "file=%s%s" % (floppy_image, options)
1161 kvm_cmd.extend(["-drive", drive_val])
1164 kvm_cmd.extend(["-kernel", kernel_path])
1165 initrd_path = hvp[constants.HV_INITRD_PATH]
1167 kvm_cmd.extend(["-initrd", initrd_path])
1168 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1169 hvp[constants.HV_KERNEL_ARGS]]
1170 if hvp[constants.HV_SERIAL_CONSOLE]:
1171 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1172 root_append.append("console=ttyS0,%s" % serial_speed)
1173 kvm_cmd.extend(["-append", " ".join(root_append)])
1175 mem_path = hvp[constants.HV_MEM_PATH]
1177 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1179 monitor_dev = ("unix:%s,server,nowait" %
1180 self._InstanceMonitor(instance.name))
1181 kvm_cmd.extend(["-monitor", monitor_dev])
1182 if hvp[constants.HV_SERIAL_CONSOLE]:
1183 serial_dev = ("unix:%s,server,nowait" %
1184 self._InstanceSerial(instance.name))
1185 kvm_cmd.extend(["-serial", serial_dev])
1187 kvm_cmd.extend(["-serial", "none"])
1189 mouse_type = hvp[constants.HV_USB_MOUSE]
1190 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1191 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1192 spice_ip_version = None
1194 kvm_cmd.extend(["-usb"])
1197 kvm_cmd.extend(["-usbdevice", mouse_type])
1198 elif vnc_bind_address:
1199 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1201 if vnc_bind_address:
1202 if netutils.IP4Address.IsValid(vnc_bind_address):
1203 if instance.network_port > constants.VNC_BASE_PORT:
1204 display = instance.network_port - constants.VNC_BASE_PORT
1205 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1206 vnc_arg = ":%d" % (display)
1208 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1210 logging.error("Network port is not a valid VNC display (%d < %d)."
1211 " Not starting VNC", instance.network_port,
1212 constants.VNC_BASE_PORT)
1215 # Only allow tls and other option when not binding to a file, for now.
1216 # kvm/qemu gets confused otherwise about the filename to use.
1218 if hvp[constants.HV_VNC_TLS]:
1219 vnc_append = "%s,tls" % vnc_append
1220 if hvp[constants.HV_VNC_X509_VERIFY]:
1221 vnc_append = "%s,x509verify=%s" % (vnc_append,
1222 hvp[constants.HV_VNC_X509])
1223 elif hvp[constants.HV_VNC_X509]:
1224 vnc_append = "%s,x509=%s" % (vnc_append,
1225 hvp[constants.HV_VNC_X509])
1226 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1227 vnc_append = "%s,password" % vnc_append
1229 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1232 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1234 kvm_cmd.extend(["-vnc", vnc_arg])
1236 # FIXME: this is wrong here; the iface ip address differs
1237 # between systems, so it should be done in _ExecuteKVMRuntime
1238 if netutils.IsValidInterface(spice_bind):
1239 # The user specified a network interface, we have to figure out the IP
1241 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1242 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1244 # if the user specified an IP version and the interface does not
1245 # have that kind of IP addresses, throw an exception
1246 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1247 if not addresses[spice_ip_version]:
1248 raise errors.HypervisorError("spice: unable to get an IPv%s address"
1249 " for %s" % (spice_ip_version,
1252 # the user did not specify an IP version, we have to figure it out
1253 elif (addresses[constants.IP4_VERSION] and
1254 addresses[constants.IP6_VERSION]):
1255 # we have both ipv4 and ipv6, let's use the cluster default IP
1257 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1258 spice_ip_version = \
1259 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1260 elif addresses[constants.IP4_VERSION]:
1261 spice_ip_version = constants.IP4_VERSION
1262 elif addresses[constants.IP6_VERSION]:
1263 spice_ip_version = constants.IP6_VERSION
1265 raise errors.HypervisorError("spice: unable to get an IP address"
1266 " for %s" % (spice_bind))
1268 spice_address = addresses[spice_ip_version][0]
1271 # spice_bind is known to be a valid IP address, because
1272 # ValidateParameters checked it.
1273 spice_address = spice_bind
1275 spice_arg = "addr=%s" % spice_address
1276 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1277 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1278 (spice_arg, instance.network_port,
1279 pathutils.SPICE_CACERT_FILE))
1280 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1281 (spice_arg, pathutils.SPICE_CERT_FILE,
1282 pathutils.SPICE_CERT_FILE))
1283 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1285 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1287 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1289 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1290 spice_arg = "%s,disable-ticketing" % spice_arg
1292 if spice_ip_version:
1293 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1295 # Image compression options
1296 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1297 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1298 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1300 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1302 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1304 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1306 # Video stream detection
1307 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1309 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1311 # Audio compression, by default in qemu-kvm it is on
1312 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1313 spice_arg = "%s,playback-compression=off" % spice_arg
1314 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1315 spice_arg = "%s,agent-mouse=off" % spice_arg
1317 # Enable the spice agent communication channel between the host and the
1319 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1320 kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1321 "name=com.redhat.spice.0"])
1322 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1324 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1325 kvm_cmd.extend(["-spice", spice_arg])
1328 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
1329 # also works in earlier versions though (tested with 1.1 and 1.3)
1330 if self._DISPLAY_RE.search(kvmhelp):
1331 kvm_cmd.extend(["-display", "none"])
1333 kvm_cmd.extend(["-nographic"])
1335 if hvp[constants.HV_USE_LOCALTIME]:
1336 kvm_cmd.extend(["-localtime"])
1338 if hvp[constants.HV_KVM_USE_CHROOT]:
1339 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1341 # Add qemu-KVM -cpu param
1342 if hvp[constants.HV_CPU_TYPE]:
1343 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1345 # As requested by music lovers
1346 if hvp[constants.HV_SOUNDHW]:
1347 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1349 # Pass a -vga option if requested, or if spice is used, for backwards
1351 if hvp[constants.HV_VGA]:
1352 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1354 kvm_cmd.extend(["-vga", "qxl"])
1356 # Various types of usb devices, comma separated
1357 if hvp[constants.HV_USB_DEVICES]:
1358 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1359 kvm_cmd.extend(["-usbdevice", dev])
1361 if hvp[constants.HV_KVM_EXTRA]:
1362 kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1364 # Save the current instance nics, but defer their expansion as parameters,
1365 # as we'll need to generate executable temp files for them.
1366 kvm_nics = instance.nics
1369 return (kvm_cmd, kvm_nics, hvparams)
1371 def _WriteKVMRuntime(self, instance_name, data):
1372 """Write an instance's KVM runtime
1376 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1378 except EnvironmentError, err:
1379 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1381 def _ReadKVMRuntime(self, instance_name):
1382 """Read an instance's KVM runtime
1386 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1387 except EnvironmentError, err:
1388 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1391 def _SaveKVMRuntime(self, instance, kvm_runtime):
1392 """Save an instance's KVM runtime
1395 kvm_cmd, kvm_nics, hvparams = kvm_runtime
1396 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1397 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1398 self._WriteKVMRuntime(instance.name, serialized_form)
1400 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1401 """Load an instance's KVM runtime
1404 if not serialized_runtime:
1405 serialized_runtime = self._ReadKVMRuntime(instance.name)
1406 loaded_runtime = serializer.Load(serialized_runtime)
1407 kvm_cmd, serialized_nics, hvparams = loaded_runtime
1408 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1409 return (kvm_cmd, kvm_nics, hvparams)
1411 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1412 """Run the KVM cmd and check for errors
1415 @param name: instance name
1416 @type kvm_cmd: list of strings
1417 @param kvm_cmd: runcmd input for kvm
1418 @type tap_fds: list of int
1419 @param tap_fds: fds of tap devices opened by Ganeti
1423 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1426 utils_wrapper.CloseFdNoError(fd)
1429 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1430 (name, result.fail_reason, result.output))
1431 if not self._InstancePidAlive(name)[2]:
1432 raise errors.HypervisorError("Failed to start instance %s" % name)
1434 def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1435 """Execute a KVM cmd, after completing it with some last minute data.
1437 @type incoming: tuple of strings
1438 @param incoming: (target_host_ip, port)
1439 @type kvmhelp: string
1440 @param kvmhelp: output of kvm --help
1443 # Small _ExecuteKVMRuntime hv parameters programming howto:
1444 # - conf_hvp contains the parameters as configured on ganeti. they might
1445 # have changed since the instance started; only use them if the change
1446 # won't affect the inside of the instance (which hasn't been rebooted).
1447 # - up_hvp contains the parameters as they were when the instance was
1448 # started, plus any new parameter which has been added between ganeti
1449 # versions: it is paramount that those default to a value which won't
1450 # affect the inside of the instance as well.
1451 conf_hvp = instance.hvparams
1452 name = instance.name
1453 self._CheckDown(name)
1457 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1458 # the first element of kvm_cmd is always the path to the kvm binary
1459 kvm_path = kvm_cmd[0]
1460 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1462 # We know it's safe to run as a different user upon migration, so we'll use
1463 # the latest conf, from conf_hvp.
1464 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1465 if security_model == constants.HT_SM_USER:
1466 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1468 keymap = conf_hvp[constants.HV_KEYMAP]
1470 keymap_path = self._InstanceKeymapFile(name)
1471 # If a keymap file is specified, KVM won't use its internal defaults. By
1472 # first including the "en-us" layout, an error on loading the actual
1473 # layout (e.g. because it can't be found) won't lead to a non-functional
1474 # keyboard. A keyboard with incorrect keys is still better than none.
1475 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1476 kvm_cmd.extend(["-k", keymap_path])
1478 # We have reasons to believe changing something like the nic driver/type
1479 # upon migration won't exactly fly with the instance kernel, so for nic
1480 # related parameters we'll use up_hvp
1484 kvm_cmd.extend(["-net", "none"])
1488 nic_type = up_hvp[constants.HV_NIC_TYPE]
1489 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1490 nic_model = self._VIRTIO
1492 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1493 if self._NEW_VIRTIO_RE.search(devlist):
1494 nic_model = self._VIRTIO_NET_PCI
1496 except errors.HypervisorError, _:
1497 # Older versions of kvm don't support DEVICE_LIST, but they don't
1498 # have new virtio syntax either.
1501 if up_hvp[constants.HV_VHOST_NET]:
1502 # check for vhost_net support
1503 if self._VHOST_RE.search(kvmhelp):
1504 tap_extra = ",vhost=on"
1506 raise errors.HypervisorError("vhost_net is configured"
1507 " but it is not available")
1509 nic_model = nic_type
1511 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1513 for nic_seq, nic in enumerate(kvm_nics):
1514 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1515 tapfds.append(tapfd)
1516 taps.append(tapname)
1517 if kvm_supports_netdev:
1518 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1519 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1520 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1522 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1524 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1525 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1528 target, port = incoming
1529 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1531 # Changing the vnc password doesn't bother the guest that much. At most it
1532 # will surprise people who connect to it. Whether positively or negatively
1534 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1538 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1539 except EnvironmentError, err:
1540 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1541 % (vnc_pwd_file, err))
1543 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1544 utils.EnsureDirs([(self._InstanceChrootDir(name),
1545 constants.SECURE_DIR_MODE)])
1547 # Automatically enable QMP if version is >= 0.14
1548 if self._QMP_RE.search(kvmhelp):
1549 logging.debug("Enabling QMP")
1550 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1551 self._InstanceQmpMonitor(instance.name)])
1553 # Configure the network now for starting instances and bridged interfaces,
1554 # during FinalizeMigration for incoming instances' routed interfaces
1555 for nic_seq, nic in enumerate(kvm_nics):
1557 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1559 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1561 # CPU affinity requires kvm to start paused, so we set this flag if the
1562 # instance is not already paused and if we are not going to accept a
1563 # migrating instance. In the latter case, pausing is not needed.
1564 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1565 if start_kvm_paused:
1566 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1568 # Note: CPU pinning is using up_hvp since changes take effect
1569 # during instance startup anyway, and to avoid problems when soft
1570 # rebooting the instance.
1572 if up_hvp.get(constants.HV_CPU_MASK, None):
1575 if security_model == constants.HT_SM_POOL:
1576 ss = ssconf.SimpleStore()
1577 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1578 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1579 uid = uidpool.RequestUnusedUid(all_uids)
1581 username = pwd.getpwuid(uid.GetUid()).pw_name
1582 kvm_cmd.extend(["-runas", username])
1583 self._RunKVMCmd(name, kvm_cmd, tapfds)
1585 uidpool.ReleaseUid(uid)
1589 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1591 self._RunKVMCmd(name, kvm_cmd, tapfds)
1593 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1594 constants.RUN_DIRS_MODE)])
1595 for nic_seq, tap in enumerate(taps):
1596 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1600 change_cmd = "change vnc password %s" % vnc_pwd
1601 self._CallMonitorCommand(instance.name, change_cmd)
1603 # Setting SPICE password. We are not vulnerable to malicious passwordless
1604 # connection attempts because SPICE by default does not allow connections
1605 # if neither a password nor the "disable_ticketing" options are specified.
1606 # As soon as we send the password via QMP, that password is a valid ticket
1608 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1609 if spice_password_file:
1612 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1613 except EnvironmentError, err:
1614 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1615 % (spice_password_file, err))
1617 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1620 "protocol": "spice",
1621 "password": spice_pwd,
1623 qmp.Execute("set_password", arguments)
1625 for filename in temp_files:
1626 utils.RemoveFile(filename)
1628 # If requested, set CPU affinity and resume instance execution
1630 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1632 start_memory = self._InstanceStartupMemory(instance)
1633 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1634 self.BalloonInstanceMemory(instance, start_memory)
1636 if start_kvm_paused:
1637 # To control CPU pinning, ballooning, and vnc/spice passwords
1638 # the VM was started in a frozen state. If freezing was not
1639 # explicitly requested resume the vm status.
1640 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1642 def StartInstance(self, instance, block_devices, startup_paused):
1643 """Start an instance.
1646 self._CheckDown(instance.name)
1647 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1648 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1649 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1650 startup_paused, kvmhelp)
1651 self._SaveKVMRuntime(instance, kvm_runtime)
1652 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1654 def _CallMonitorCommand(self, instance_name, command):
1655 """Invoke a command on the instance monitor.
1658 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1659 (utils.ShellQuote(command),
1660 constants.SOCAT_PATH,
1661 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1662 result = utils.RunCmd(socat)
1664 msg = ("Failed to send command '%s' to instance %s."
1665 " output: %s, error: %s, fail_reason: %s" %
1666 (command, instance_name,
1667 result.stdout, result.stderr, result.fail_reason))
1668 raise errors.HypervisorError(msg)
1673 def _ParseKVMVersion(cls, text):
1674 """Parse the KVM version from the --help output.
1677 @param text: output of kvm --help
1678 @return: (version, v_maj, v_min, v_rev)
1679 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1682 match = cls._VERSION_RE.search(text.splitlines()[0])
1684 raise errors.HypervisorError("Unable to get KVM version")
1686 v_all = match.group(0)
1687 v_maj = int(match.group(1))
1688 v_min = int(match.group(2))
1690 v_rev = int(match.group(4))
1693 return (v_all, v_maj, v_min, v_rev)
1696 def _GetKVMOutput(cls, kvm_path, option):
1697 """Return the output of a kvm invocation
1699 @type kvm_path: string
1700 @param kvm_path: path to the kvm executable
1701 @type option: a key of _KVMOPTS_CMDS
1702 @param option: kvm option to fetch the output from
1703 @return: output a supported kvm invocation
1704 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1707 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1709 optlist, can_fail = cls._KVMOPTS_CMDS[option]
1711 result = utils.RunCmd([kvm_path] + optlist)
1712 if result.failed and not can_fail:
1713 raise errors.HypervisorError("Unable to get KVM %s output" %
1714 " ".join(cls._KVMOPTS_CMDS[option]))
1715 return result.output
1718 def _GetKVMVersion(cls, kvm_path):
1719 """Return the installed KVM version.
1721 @return: (version, v_maj, v_min, v_rev)
1722 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1725 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1728 def _GetDefaultMachineVersion(cls, kvm_path):
1729 """Return the default hardware revision (e.g. pc-1.1)
1732 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
1733 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output)
1735 return match.group(1)
1739 def StopInstance(self, instance, force=False, retry=False, name=None):
1740 """Stop an instance.
1743 if name is not None and not force:
1744 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1746 name = instance.name
1747 acpi = instance.hvparams[constants.HV_ACPI]
1750 _, pid, alive = self._InstancePidAlive(name)
1751 if pid > 0 and alive:
1752 if force or not acpi:
1753 utils.KillProcess(pid)
1755 self._CallMonitorCommand(name, "system_powerdown")
1757 def CleanupInstance(self, instance_name):
1758 """Cleanup after a stopped instance
1761 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1762 if pid > 0 and alive:
1763 raise errors.HypervisorError("Cannot cleanup a live instance")
1764 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1766 def RebootInstance(self, instance):
1767 """Reboot an instance.
1770 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1771 # socket the instance will stop, but now power up again. So we'll resort
1772 # to shutdown and restart.
1773 _, _, alive = self._InstancePidAlive(instance.name)
1775 raise errors.HypervisorError("Failed to reboot instance %s:"
1776 " not running" % instance.name)
1777 # StopInstance will delete the saved KVM runtime so:
1778 # ...first load it...
1779 kvm_runtime = self._LoadKVMRuntime(instance)
1780 # ...now we can safely call StopInstance...
1781 if not self.StopInstance(instance):
1782 self.StopInstance(instance, force=True)
1783 # ...and finally we can save it again, and execute it...
1784 self._SaveKVMRuntime(instance, kvm_runtime)
1785 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1786 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1787 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1789 def MigrationInfo(self, instance):
1790 """Get instance information to perform a migration.
1792 @type instance: L{objects.Instance}
1793 @param instance: instance to be migrated
1795 @return: content of the KVM runtime file
1798 return self._ReadKVMRuntime(instance.name)
1800 def AcceptInstance(self, instance, info, target):
1801 """Prepare to accept an instance.
1803 @type instance: L{objects.Instance}
1804 @param instance: instance to be accepted
1806 @param info: content of the KVM runtime file on the source node
1807 @type target: string
1808 @param target: target host (usually ip), on this node
1811 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1812 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1813 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1814 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1815 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1816 incoming=incoming_address)
1818 def FinalizeMigrationDst(self, instance, info, success):
1819 """Finalize the instance migration on the target node.
1821 Stop the incoming mode KVM.
1823 @type instance: L{objects.Instance}
1824 @param instance: instance whose migration is being finalized
1828 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1829 kvm_nics = kvm_runtime[1]
1831 for nic_seq, nic in enumerate(kvm_nics):
1832 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1833 # Bridged interfaces have already been configured
1836 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1837 except EnvironmentError, err:
1838 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1839 instance.name, nic_seq, str(err))
1842 self._ConfigureNIC(instance, nic_seq, nic, tap)
1843 except errors.HypervisorError, err:
1844 logging.warning(str(err))
1846 self._WriteKVMRuntime(instance.name, info)
1848 self.StopInstance(instance, force=True)
1850 def MigrateInstance(self, instance, target, live):
1851 """Migrate an instance to a target node.
1853 The migration will not be attempted if the instance is not
1856 @type instance: L{objects.Instance}
1857 @param instance: the instance to be migrated
1858 @type target: string
1859 @param target: ip address of the target node
1861 @param live: perform a live migration
1864 instance_name = instance.name
1865 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1866 _, _, alive = self._InstancePidAlive(instance_name)
1868 raise errors.HypervisorError("Instance not running, cannot migrate")
1871 self._CallMonitorCommand(instance_name, "stop")
1873 migrate_command = ("migrate_set_speed %dm" %
1874 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1875 self._CallMonitorCommand(instance_name, migrate_command)
1877 migrate_command = ("migrate_set_downtime %dms" %
1878 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1879 self._CallMonitorCommand(instance_name, migrate_command)
1881 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1882 self._CallMonitorCommand(instance_name, migrate_command)
1884 def FinalizeMigrationSource(self, instance, success, live):
1885 """Finalize the instance migration on the source node.
1887 @type instance: L{objects.Instance}
1888 @param instance: the instance that was migrated
1890 @param success: whether the migration succeeded or not
1892 @param live: whether the user requested a live migration or not
1896 pidfile, pid, _ = self._InstancePidAlive(instance.name)
1897 utils.KillProcess(pid)
1898 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1900 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1902 def GetMigrationStatus(self, instance):
1903 """Get the migration status
1905 @type instance: L{objects.Instance}
1906 @param instance: the instance that is being migrated
1907 @rtype: L{objects.MigrationStatus}
1908 @return: the status of the current migration (one of
1909 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1910 progress info that can be retrieved from the hypervisor
1913 info_command = "info migrate"
1914 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1915 result = self._CallMonitorCommand(instance.name, info_command)
1916 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1918 if not result.stdout:
1919 logging.info("KVM: empty 'info migrate' result")
1921 logging.warning("KVM: unknown 'info migrate' result: %s",
1924 status = match.group(1)
1925 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1926 migration_status = objects.MigrationStatus(status=status)
1927 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1929 migration_status.transferred_ram = match.group("transferred")
1930 migration_status.total_ram = match.group("total")
1932 return migration_status
1934 logging.warning("KVM: unknown migration status '%s'", status)
1936 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1938 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1940 def BalloonInstanceMemory(self, instance, mem):
1941 """Balloon an instance memory to a certain value.
1943 @type instance: L{objects.Instance}
1944 @param instance: instance to be accepted
1946 @param mem: actual memory size to use for instance runtime
1949 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1951 def GetNodeInfo(self):
1952 """Return information about the node.
1954 @return: a dict with the following keys (values in MiB):
1955 - memory_total: the total memory size on the node
1956 - memory_free: the available memory on the node for instances
1957 - memory_dom0: the memory used by the node itself, if available
1958 - hv_version: the hypervisor version in the form (major, minor,
1962 result = self.GetLinuxNodeInfo()
1963 # FIXME: this is the global kvm version, but the actual version can be
1964 # customized as an hv parameter. we should use the nodegroup's default kvm
1965 # path parameter here.
1966 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
1967 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1971 def GetInstanceConsole(cls, instance, hvparams, beparams):
1972 """Return a command for connecting to the console of an instance.
1975 if hvparams[constants.HV_SERIAL_CONSOLE]:
1976 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1977 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1978 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1979 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1980 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1981 return objects.InstanceConsole(instance=instance.name,
1982 kind=constants.CONS_SSH,
1983 host=instance.primary_node,
1984 user=constants.SSH_CONSOLE_USER,
1987 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1988 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1989 display = instance.network_port - constants.VNC_BASE_PORT
1990 return objects.InstanceConsole(instance=instance.name,
1991 kind=constants.CONS_VNC,
1992 host=vnc_bind_address,
1993 port=instance.network_port,
1996 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1998 return objects.InstanceConsole(instance=instance.name,
1999 kind=constants.CONS_SPICE,
2001 port=instance.network_port)
2003 return objects.InstanceConsole(instance=instance.name,
2004 kind=constants.CONS_MESSAGE,
2005 message=("No serial shell for instance %s" %
2009 """Verify the hypervisor.
2011 Check that the required binaries exist.
2013 @return: Problem description if something is wrong, C{None} otherwise
2017 # FIXME: this is the global kvm binary, but the actual path can be
2018 # customized as an hv parameter; we should use the nodegroup's
2019 # default kvm path parameter here.
2020 if not os.path.exists(constants.KVM_PATH):
2021 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2022 if not os.path.exists(constants.SOCAT_PATH):
2023 msgs.append("The socat binary ('%s') does not exist" %
2024 constants.SOCAT_PATH)
2026 return self._FormatVerifyResults(msgs)
2029 def CheckParameterSyntax(cls, hvparams):
2030 """Check the given parameters for validity.
2032 @type hvparams: dict
2033 @param hvparams: dictionary with parameter names/value
2034 @raise errors.HypervisorError: when a parameter is not valid
2037 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2039 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2041 if not hvparams[constants.HV_ROOT_PATH]:
2042 raise errors.HypervisorError("Need a root partition for the instance,"
2043 " if a kernel is defined")
2045 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2046 not hvparams[constants.HV_VNC_X509]):
2047 raise errors.HypervisorError("%s must be defined, if %s is" %
2048 (constants.HV_VNC_X509,
2049 constants.HV_VNC_X509_VERIFY))
2051 if hvparams[constants.HV_SERIAL_CONSOLE]:
2052 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2053 valid_speeds = constants.VALID_SERIAL_SPEEDS
2054 if not serial_speed or serial_speed not in valid_speeds:
2055 raise errors.HypervisorError("Invalid serial console speed, must be"
2057 utils.CommaJoin(valid_speeds))
2059 boot_order = hvparams[constants.HV_BOOT_ORDER]
2060 if (boot_order == constants.HT_BO_CDROM and
2061 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2062 raise errors.HypervisorError("Cannot boot from cdrom without an"
2065 security_model = hvparams[constants.HV_SECURITY_MODEL]
2066 if security_model == constants.HT_SM_USER:
2067 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2068 raise errors.HypervisorError("A security domain (user to run kvm as)"
2069 " must be specified")
2070 elif (security_model == constants.HT_SM_NONE or
2071 security_model == constants.HT_SM_POOL):
2072 if hvparams[constants.HV_SECURITY_DOMAIN]:
2073 raise errors.HypervisorError("Cannot have a security domain when the"
2074 " security model is 'none' or 'pool'")
2076 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2077 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2079 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2080 # if an IP version is specified, the spice_bind parameter must be an
2082 if (netutils.IP4Address.IsValid(spice_bind) and
2083 spice_ip_version != constants.IP4_VERSION):
2084 raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2085 " the specified IP version is %s" %
2086 (spice_bind, spice_ip_version))
2088 if (netutils.IP6Address.IsValid(spice_bind) and
2089 spice_ip_version != constants.IP6_VERSION):
2090 raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2091 " the specified IP version is %s" %
2092 (spice_bind, spice_ip_version))
2094 # All the other SPICE parameters depend on spice_bind being set. Raise an
2095 # error if any of them is set without it.
2096 for param in _SPICE_ADDITIONAL_PARAMS:
2098 raise errors.HypervisorError("spice: %s requires %s to be set" %
2099 (param, constants.HV_KVM_SPICE_BIND))
2102 def ValidateParameters(cls, hvparams):
2103 """Check the given parameters for validity.
2105 @type hvparams: dict
2106 @param hvparams: dictionary with parameter names/value
2107 @raise errors.HypervisorError: when a parameter is not valid
2110 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2112 kvm_path = hvparams[constants.HV_KVM_PATH]
2114 security_model = hvparams[constants.HV_SECURITY_MODEL]
2115 if security_model == constants.HT_SM_USER:
2116 username = hvparams[constants.HV_SECURITY_DOMAIN]
2118 pwd.getpwnam(username)
2120 raise errors.HypervisorError("Unknown security domain user %s"
2123 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2125 # only one of VNC and SPICE can be used currently.
2126 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2127 raise errors.HypervisorError("both SPICE and VNC are configured, but"
2128 " only one of them can be used at a"
2131 # check that KVM supports SPICE
2132 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP)
2133 if not cls._SPICE_RE.search(kvmhelp):
2134 raise errors.HypervisorError("spice is configured, but it is not"
2135 " supported according to kvm --help")
2137 # if spice_bind is not an IP address, it must be a valid interface
2138 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2139 or netutils.IP6Address.IsValid(spice_bind))
2140 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2141 raise errors.HypervisorError("spice: the %s parameter must be either"
2142 " a valid IP address or interface name" %
2143 constants.HV_KVM_SPICE_BIND)
2145 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION]
2147 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST)
2148 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output):
2149 raise errors.HypervisorError("Unsupported machine version: %s" %
2153 def PowercycleNode(cls):
2154 """KVM powercycle, just a wrapper over Linux powercycle.
2157 cls.LinuxPowercycle()