4 # Copyright (C) 2008, 2009, 2010, 2011, 2012 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:
143 raise errors.HypervisorError("Failed to allocate a new TAP device")
145 # Get the interface name from the ioctl
146 ifname = struct.unpack("16sh", res)[0].strip("\x00")
147 return (ifname, tapfd)
150 def _BuildNetworkEnv(name, network, gateway, network6, gateway6,
151 network_type, mac_prefix, tags, env):
152 """Build environment variables concerning a Network.
156 env["NETWORK_NAME"] = name
158 env["NETWORK_SUBNET"] = network
160 env["NETWORK_GATEWAY"] = gateway
162 env["NETWORK_SUBNET6"] = network6
164 env["NETWORK_GATEWAY6"] = gateway6
166 env["NETWORK_MAC_PREFIX"] = mac_prefix
168 env["NETWORK_TYPE"] = network_type
170 env["NETWORK_TAGS"] = " ".join(tags)
176 """QEMU Messaging Protocol (QMP) message.
179 def __init__(self, data):
180 """Creates a new QMP message based on the passed data.
183 if not isinstance(data, dict):
184 raise TypeError("QmpMessage must be initialized with a dict")
188 def __getitem__(self, field_name):
189 """Get the value of the required field if present, or None.
191 Overrides the [] operator to provide access to the message data,
192 returning None if the required item is not in the message
193 @return: the value of the field_name field, or None if field_name
194 is not contained in the message
197 return self.data.get(field_name, None)
199 def __setitem__(self, field_name, field_value):
200 """Set the value of the required field_name to field_value.
203 self.data[field_name] = field_value
206 def BuildFromJsonString(json_string):
207 """Build a QmpMessage from a JSON encoded string.
209 @type json_string: str
210 @param json_string: JSON string representing the message
211 @rtype: L{QmpMessage}
212 @return: a L{QmpMessage} built from json_string
216 data = serializer.LoadJson(json_string)
217 return QmpMessage(data)
220 # The protocol expects the JSON object to be sent as a single line.
221 return serializer.DumpJson(self.data)
223 def __eq__(self, other):
224 # When comparing two QmpMessages, we are interested in comparing
225 # their internal representation of the message data
226 return self.data == other.data
230 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
233 _FIRST_MESSAGE_KEY = "QMP"
236 _RETURN_KEY = RETURN_KEY = "return"
237 _ACTUAL_KEY = ACTUAL_KEY = "actual"
238 _ERROR_CLASS_KEY = "class"
239 _ERROR_DATA_KEY = "data"
240 _ERROR_DESC_KEY = "desc"
241 _EXECUTE_KEY = "execute"
242 _ARGUMENTS_KEY = "arguments"
243 _CAPABILITIES_COMMAND = "qmp_capabilities"
244 _MESSAGE_END_TOKEN = "\r\n"
247 def __init__(self, monitor_filename):
248 """Instantiates the QmpConnection object.
250 @type monitor_filename: string
251 @param monitor_filename: the filename of the UNIX raw socket on which the
252 QMP monitor is listening
255 self.monitor_filename = monitor_filename
256 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
257 # We want to fail if the server doesn't send a complete message
258 # in a reasonable amount of time
259 self.sock.settimeout(self._SOCKET_TIMEOUT)
260 self._connected = False
263 def _check_socket(self):
266 sock_stat = os.stat(self.monitor_filename)
267 except EnvironmentError, err:
268 if err.errno == errno.ENOENT:
269 raise errors.HypervisorError("No qmp socket found")
271 raise errors.HypervisorError("Error checking qmp socket: %s",
272 utils.ErrnoOrStr(err))
273 if not stat.S_ISSOCK(sock_stat.st_mode):
274 raise errors.HypervisorError("Qmp socket is not a socket")
276 def _check_connection(self):
277 """Make sure that the connection is established.
280 if not self._connected:
281 raise errors.ProgrammerError("To use a QmpConnection you need to first"
282 " invoke connect() on it")
285 """Connects to the QMP monitor.
287 Connects to the UNIX socket and makes sure that we can actually send and
288 receive data to the kvm instance via QMP.
290 @raise errors.HypervisorError: when there are communication errors
291 @raise errors.ProgrammerError: when there are data serialization errors
295 raise errors.ProgrammerError("Cannot connect twice")
299 # Check file existance/stuff
301 self.sock.connect(self.monitor_filename)
302 except EnvironmentError:
303 raise errors.HypervisorError("Can't connect to qmp socket")
304 self._connected = True
306 # Check if we receive a correct greeting message from the server
307 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
308 greeting = self._Recv()
309 if not greeting[self._FIRST_MESSAGE_KEY]:
310 self._connected = False
311 raise errors.HypervisorError("kvm: qmp communication error (wrong"
314 # Let's put the monitor in command mode using the qmp_capabilities
315 # command, or else no command will be executable.
316 # (As per the QEMU Protocol Specification 0.1 - section 4)
317 self.Execute(self._CAPABILITIES_COMMAND)
319 def _ParseMessage(self, buf):
320 """Extract and parse a QMP message from the given buffer.
322 Seeks for a QMP message in the given buf. If found, it parses it and
323 returns it together with the rest of the characters in the buf.
324 If no message is found, returns None and the whole buffer.
326 @raise errors.ProgrammerError: when there are data serialization errors
330 # Check if we got the message end token (CRLF, as per the QEMU Protocol
331 # Specification 0.1 - Section 2.1.1)
332 pos = buf.find(self._MESSAGE_END_TOKEN)
335 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
336 except Exception, err:
337 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
340 return (message, buf)
343 """Receives a message from QMP and decodes the received JSON object.
346 @return: the received message
347 @raise errors.HypervisorError: when there are communication errors
348 @raise errors.ProgrammerError: when there are data serialization errors
351 self._check_connection()
353 # Check if there is already a message in the buffer
354 (message, self._buf) = self._ParseMessage(self._buf)
358 recv_buffer = StringIO.StringIO(self._buf)
359 recv_buffer.seek(len(self._buf))
362 data = self.sock.recv(4096)
365 recv_buffer.write(data)
367 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
371 except socket.timeout, err:
372 raise errors.HypervisorError("Timeout while receiving a QMP message: "
374 except socket.error, err:
375 raise errors.HypervisorError("Unable to receive data from KVM using the"
376 " QMP protocol: %s" % err)
378 def _Send(self, message):
379 """Encodes and sends a message to KVM using QMP.
381 @type message: QmpMessage
382 @param message: message to send to KVM
383 @raise errors.HypervisorError: when there are communication errors
384 @raise errors.ProgrammerError: when there are data serialization errors
387 self._check_connection()
389 message_str = str(message)
390 except Exception, err:
391 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
394 self.sock.sendall(message_str)
395 except socket.timeout, err:
396 raise errors.HypervisorError("Timeout while sending a QMP message: "
397 "%s (%s)" % (err.string, err.errno))
398 except socket.error, err:
399 raise errors.HypervisorError("Unable to send data from KVM using the"
400 " QMP protocol: %s" % err)
402 def Execute(self, command, arguments=None):
403 """Executes a QMP command and returns the response of the server.
406 @param command: the command to execute
407 @type arguments: dict
408 @param arguments: dictionary of arguments to be passed to the command
410 @return: dictionary representing the received JSON object
411 @raise errors.HypervisorError: when there are communication errors
412 @raise errors.ProgrammerError: when there are data serialization errors
415 self._check_connection()
416 message = QmpMessage({self._EXECUTE_KEY: command})
418 message[self._ARGUMENTS_KEY] = arguments
421 # Events can occur between the sending of the command and the reception
422 # of the response, so we need to filter out messages with the event key.
424 response = self._Recv()
425 err = response[self._ERROR_KEY]
427 raise errors.HypervisorError("kvm: error executing the %s"
428 " command: %s (%s, %s):" %
430 err[self._ERROR_DESC_KEY],
431 err[self._ERROR_CLASS_KEY],
432 err[self._ERROR_DATA_KEY]))
434 elif not response[self._EVENT_KEY]:
438 class KVMHypervisor(hv_base.BaseHypervisor):
439 """KVM hypervisor interface
444 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
445 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
446 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
447 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
448 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
449 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
450 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
451 # KVM instances with chroot enabled are started in empty chroot directories.
452 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
453 # After an instance is stopped, its chroot directory is removed.
454 # If the chroot directory is not empty, it can't be removed.
455 # A non-empty chroot directory indicates a possible security incident.
456 # To support forensics, the non-empty chroot directory is quarantined in
457 # a separate directory, called 'chroot-quarantine'.
458 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
459 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
460 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
463 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
464 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
465 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
466 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
467 constants.HV_ACPI: hv_base.NO_CHECK,
468 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
469 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
470 constants.HV_VNC_BIND_ADDRESS:
471 (False, lambda x: (netutils.IP4Address.IsValid(x) or
472 utils.IsNormAbsPath(x)),
473 "the VNC bind address must be either a valid IP address or an absolute"
474 " pathname", None, None),
475 constants.HV_VNC_TLS: hv_base.NO_CHECK,
476 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
477 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
478 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
479 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
480 constants.HV_KVM_SPICE_IP_VERSION:
481 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
482 x in constants.VALID_IP_VERSIONS),
483 "the SPICE IP version should be 4 or 6",
485 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
486 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
488 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
489 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
491 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
492 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
494 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
495 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
497 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
498 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
499 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
500 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
501 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
502 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
503 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
504 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
505 constants.HV_BOOT_ORDER:
506 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
507 constants.HV_NIC_TYPE:
508 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
509 constants.HV_DISK_TYPE:
510 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
511 constants.HV_KVM_CDROM_DISK_TYPE:
512 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
513 constants.HV_USB_MOUSE:
514 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
515 constants.HV_KEYMAP: hv_base.NO_CHECK,
516 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
517 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
518 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
519 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
520 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
521 constants.HV_DISK_CACHE:
522 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
523 constants.HV_SECURITY_MODEL:
524 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
525 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
526 constants.HV_KVM_FLAG:
527 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
528 constants.HV_VHOST_NET: hv_base.NO_CHECK,
529 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
530 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
531 constants.HV_REBOOT_BEHAVIOR:
532 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
533 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
534 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
535 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
536 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
537 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
538 constants.HV_SOUNDHW: hv_base.NO_CHECK,
539 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
540 constants.HV_VGA: hv_base.NO_CHECK,
541 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
542 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
545 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
547 _MIGRATION_PROGRESS_RE = \
548 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
549 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
550 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
552 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
553 _MIGRATION_INFO_RETRY_DELAY = 2
555 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
557 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
558 _CPU_INFO_CMD = "info cpus"
561 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
563 _QMP_RE = re.compile(r"^-qmp\s", re.M)
564 _SPICE_RE = re.compile(r"^-spice\s", re.M)
565 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
566 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
567 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
568 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
569 # match -drive.*boot=on|off on different lines, but in between accept only
570 # dashes not preceeded by a new line (which would mean another option
571 # different than -drive is starting)
572 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
577 ANCILLARY_FILES_OPT = [
582 hv_base.BaseHypervisor.__init__(self)
583 # Let's make sure the directories we need exist, even if the RUN_DIR lives
584 # in a tmpfs filesystem or has been otherwise wiped out.
585 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
586 utils.EnsureDirs(dirs)
589 def _InstancePidFile(cls, instance_name):
590 """Returns the instance pidfile.
593 return utils.PathJoin(cls._PIDS_DIR, instance_name)
596 def _InstanceUidFile(cls, instance_name):
597 """Returns the instance uidfile.
600 return utils.PathJoin(cls._UIDS_DIR, instance_name)
603 def _InstancePidInfo(cls, pid):
604 """Check pid file for instance information.
606 Check that a pid file is associated with an instance, and retrieve
607 information from its command line.
609 @type pid: string or int
610 @param pid: process id of the instance to check
612 @return: (instance_name, memory, vcpus)
613 @raise errors.HypervisorError: when an instance cannot be found
616 alive = utils.IsProcessAlive(pid)
618 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
620 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
622 cmdline = utils.ReadFile(cmdline_file)
623 except EnvironmentError, err:
624 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
631 arg_list = cmdline.split("\x00")
633 arg = arg_list.pop(0)
635 instance = arg_list.pop(0)
637 memory = int(arg_list.pop(0))
639 vcpus = int(arg_list.pop(0).split(",")[0])
642 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
645 return (instance, memory, vcpus)
647 def _InstancePidAlive(self, instance_name):
648 """Returns the instance pidfile, pid, and liveness.
650 @type instance_name: string
651 @param instance_name: instance name
653 @return: (pid file name, pid, liveness)
656 pidfile = self._InstancePidFile(instance_name)
657 pid = utils.ReadPidFile(pidfile)
661 cmd_instance = self._InstancePidInfo(pid)[0]
662 alive = (cmd_instance == instance_name)
663 except errors.HypervisorError:
666 return (pidfile, pid, alive)
668 def _CheckDown(self, instance_name):
669 """Raises an error unless the given instance is down.
672 alive = self._InstancePidAlive(instance_name)[2]
674 raise errors.HypervisorError("Failed to start instance %s: %s" %
675 (instance_name, "already running"))
678 def _InstanceMonitor(cls, instance_name):
679 """Returns the instance monitor socket name
682 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
685 def _InstanceSerial(cls, instance_name):
686 """Returns the instance serial socket name
689 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
692 def _InstanceQmpMonitor(cls, instance_name):
693 """Returns the instance serial QMP socket name
696 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
699 def _SocatUnixConsoleParams():
700 """Returns the correct parameters for socat
702 If we have a new-enough socat we can use raw mode with an escape character.
705 if constants.SOCAT_USE_ESCAPE:
706 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
708 return "echo=0,icanon=0"
711 def _InstanceKVMRuntime(cls, instance_name):
712 """Returns the instance KVM runtime filename
715 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
718 def _InstanceChrootDir(cls, instance_name):
719 """Returns the name of the KVM chroot dir of the instance
722 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
725 def _InstanceNICDir(cls, instance_name):
726 """Returns the name of the directory holding the tap device files for a
730 return utils.PathJoin(cls._NICS_DIR, instance_name)
733 def _InstanceNICFile(cls, instance_name, seq):
734 """Returns the name of the file containing the tap device for a given NIC
737 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
740 def _InstanceKeymapFile(cls, instance_name):
741 """Returns the name of the file containing the keymap for a given instance
744 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
747 def _TryReadUidFile(cls, uid_file):
748 """Try to read a uid file
751 if os.path.exists(uid_file):
753 uid = int(utils.ReadOneLineFile(uid_file))
755 except EnvironmentError:
756 logging.warning("Can't read uid file", exc_info=True)
757 except (TypeError, ValueError):
758 logging.warning("Can't parse uid file contents", exc_info=True)
762 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
763 """Removes an instance's rutime sockets/files/dirs.
766 utils.RemoveFile(pidfile)
767 utils.RemoveFile(cls._InstanceMonitor(instance_name))
768 utils.RemoveFile(cls._InstanceSerial(instance_name))
769 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
770 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
771 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
772 uid_file = cls._InstanceUidFile(instance_name)
773 uid = cls._TryReadUidFile(uid_file)
774 utils.RemoveFile(uid_file)
776 uidpool.ReleaseUid(uid)
778 shutil.rmtree(cls._InstanceNICDir(instance_name))
780 if err.errno != errno.ENOENT:
783 chroot_dir = cls._InstanceChrootDir(instance_name)
784 utils.RemoveDir(chroot_dir)
786 if err.errno == errno.ENOTEMPTY:
787 # The chroot directory is expected to be empty, but it isn't.
788 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
791 utils.TimestampForFilename()))
792 logging.warning("The chroot directory of instance %s can not be"
793 " removed as it is not empty. Moving it to the"
794 " quarantine instead. Please investigate the"
795 " contents (%s) and clean up manually",
796 instance_name, new_chroot_dir)
797 utils.RenameFile(chroot_dir, new_chroot_dir)
802 def _ConfigureNIC(instance, seq, nic, tap):
803 """Run the network configuration script for a specified NIC
805 @param instance: instance we're acting on
806 @type instance: instance object
807 @param seq: nic sequence number
809 @param nic: nic we're acting on
810 @type nic: nic object
811 @param tap: the host's tap interface this NIC corresponds to
816 tags = " ".join(instance.tags)
821 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
822 "INSTANCE": instance.name,
824 "MODE": nic.nicparams[constants.NIC_MODE],
826 "INTERFACE_INDEX": str(seq),
833 if nic.nicparams[constants.NIC_LINK]:
834 env["LINK"] = nic.nicparams[constants.NIC_LINK]
837 n = objects.Network.FromDict(nic.netinfo)
838 _BuildNetworkEnv(nic.network, n.network, n.gateway,
839 n.network6, n.gateway6, n.network_type,
840 n.mac_prefix, n.tags, env)
842 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
843 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
845 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
847 raise errors.HypervisorError("Failed to configure interface %s: %s."
848 " Network configuration script output: %s" %
849 (tap, result.fail_reason, result.output))
852 def _VerifyAffinityPackage():
854 raise errors.HypervisorError("affinity Python package not"
855 " found; cannot use CPU pinning under KVM")
858 def _BuildAffinityCpuMask(cpu_list):
859 """Create a CPU mask suitable for sched_setaffinity from a list of
862 See man taskset for more info on sched_setaffinity masks.
863 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
865 @type cpu_list: list of int
866 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
868 @return: a bit mask of CPU affinities
871 if cpu_list == constants.CPU_PINNING_OFF:
872 return constants.CPU_PINNING_ALL_KVM
874 return sum(2 ** cpu for cpu in cpu_list)
877 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
878 """Change CPU affinity for running VM according to given CPU mask.
880 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
881 @type cpu_mask: string
882 @param process_id: process ID of KVM process. Used to pin entire VM
884 @type process_id: int
885 @param thread_dict: map of virtual CPUs to KVM thread IDs
886 @type thread_dict: dict int:int
889 # Convert the string CPU mask to a list of list of int's
890 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
892 if len(cpu_list) == 1:
893 all_cpu_mapping = cpu_list[0]
894 if all_cpu_mapping == constants.CPU_PINNING_OFF:
895 # If CPU pinning has 1 entry that's "all", then do nothing
898 # If CPU pinning has one non-all entry, map the entire VM to
899 # one set of physical CPUs
900 cls._VerifyAffinityPackage()
901 affinity.set_process_affinity_mask(
902 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
904 # The number of vCPUs mapped should match the number of vCPUs
905 # reported by KVM. This was already verified earlier, so
906 # here only as a sanity check.
907 assert len(thread_dict) == len(cpu_list)
908 cls._VerifyAffinityPackage()
910 # For each vCPU, map it to the proper list of physical CPUs
911 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
912 affinity.set_process_affinity_mask(thread_dict[i],
913 cls._BuildAffinityCpuMask(vcpu))
915 def _GetVcpuThreadIds(self, instance_name):
916 """Get a mapping of vCPU no. to thread IDs for the instance
918 @type instance_name: string
919 @param instance_name: instance in question
920 @rtype: dictionary of int:int
921 @return: a dictionary mapping vCPU numbers to thread IDs
925 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
926 for line in output.stdout.splitlines():
927 match = self._CPU_INFO_RE.search(line)
930 grp = map(int, match.groups())
931 result[grp[0]] = grp[1]
935 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
936 """Complete CPU pinning.
938 @type instance_name: string
939 @param instance_name: name of instance
940 @type cpu_mask: string
941 @param cpu_mask: CPU pinning mask as entered by user
944 # Get KVM process ID, to be used if need to pin entire VM
945 _, pid, _ = self._InstancePidAlive(instance_name)
946 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
947 thread_dict = self._GetVcpuThreadIds(instance_name)
948 # Run CPU pinning, based on configured mask
949 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
951 def ListInstances(self):
952 """Get the list of running instances.
954 We can do this by listing our live instances directory and
955 checking whether the associated kvm process is still alive.
959 for name in os.listdir(self._PIDS_DIR):
960 if self._InstancePidAlive(name)[2]:
964 def GetInstanceInfo(self, instance_name):
965 """Get instance properties.
967 @type instance_name: string
968 @param instance_name: the instance name
969 @rtype: tuple of strings
970 @return: (name, id, memory, vcpus, stat, times)
973 _, pid, alive = self._InstancePidAlive(instance_name)
977 _, memory, vcpus = self._InstancePidInfo(pid)
982 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
984 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
985 # Will fail if ballooning is not enabled, but we can then just resort to
987 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
988 memory = mem_bytes / 1048576
989 except errors.HypervisorError:
992 return (instance_name, pid, memory, vcpus, istat, times)
994 def GetAllInstancesInfo(self):
995 """Get properties of all instances.
997 @return: list of tuples (name, id, memory, vcpus, stat, times)
1001 for name in os.listdir(self._PIDS_DIR):
1003 info = self.GetInstanceInfo(name)
1004 except errors.HypervisorError:
1005 # Ignore exceptions due to instances being shut down
1011 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
1012 """Generate KVM information to start an instance.
1014 @attention: this function must not have any side-effects; for
1015 example, it must not write to the filesystem, or read values
1016 from the current system the are expected to differ between
1017 nodes, since it is only run once at instance startup;
1018 actions/kvm arguments that can vary between systems should be
1019 done in L{_ExecuteKVMRuntime}
1022 # pylint: disable=R0912,R0914,R0915
1023 kvmhelp = self._GetKVMHelpOutput()
1024 hvp = instance.hvparams
1026 pidfile = self._InstancePidFile(instance.name)
1027 kvm = constants.KVM_PATH
1029 # used just by the vnc server, if enabled
1030 kvm_cmd.extend(["-name", instance.name])
1031 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1033 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1034 if hvp[constants.HV_CPU_CORES]:
1035 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1036 if hvp[constants.HV_CPU_THREADS]:
1037 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1038 if hvp[constants.HV_CPU_SOCKETS]:
1039 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1041 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1043 kvm_cmd.extend(["-pidfile", pidfile])
1044 kvm_cmd.extend(["-balloon", "virtio"])
1045 kvm_cmd.extend(["-daemonize"])
1046 if not instance.hvparams[constants.HV_ACPI]:
1047 kvm_cmd.extend(["-no-acpi"])
1048 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1049 constants.INSTANCE_REBOOT_EXIT:
1050 kvm_cmd.extend(["-no-reboot"])
1052 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1054 mversion = self._GetDefaultMachineVersion()
1055 kvm_cmd.extend(["-M", mversion])
1057 kernel_path = hvp[constants.HV_KERNEL_PATH]
1059 boot_disk = boot_cdrom = boot_floppy = boot_network = False
1061 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1062 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1063 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1064 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1066 self.ValidateParameters(hvp)
1069 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1071 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1072 self._ENABLE_KVM_RE.search(kvmhelp)):
1073 kvm_cmd.extend(["-enable-kvm"])
1074 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1075 self._DISABLE_KVM_RE.search(kvmhelp)):
1076 kvm_cmd.extend(["-disable-kvm"])
1079 kvm_cmd.extend(["-boot", "n"])
1081 # whether this is an older KVM version that uses the boot=on flag
1083 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1085 disk_type = hvp[constants.HV_DISK_TYPE]
1086 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1087 if_val = ",if=virtio"
1089 if_val = ",if=%s" % disk_type
1091 disk_cache = hvp[constants.HV_DISK_CACHE]
1092 if instance.disk_template in constants.DTS_EXT_MIRROR:
1093 if disk_cache != "none":
1094 # TODO: make this a hard error, instead of a silent overwrite
1095 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1096 " to prevent shared storage corruption on migration",
1098 cache_val = ",cache=none"
1099 elif disk_cache != constants.HT_CACHE_DEFAULT:
1100 cache_val = ",cache=%s" % disk_cache
1103 for cfdev, dev_path in block_devices:
1104 if cfdev.mode != constants.DISK_RDWR:
1105 raise errors.HypervisorError("Instance has read-only disks which"
1106 " are not supported by KVM")
1107 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1110 kvm_cmd.extend(["-boot", "c"])
1112 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1113 boot_val = ",boot=on"
1115 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1117 kvm_cmd.extend(["-drive", drive_val])
1119 #Now we can specify a different device type for CDROM devices.
1120 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1121 if not cdrom_disk_type:
1122 cdrom_disk_type = disk_type
1124 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1126 options = ",format=raw,media=cdrom"
1127 # set cdrom 'if' type
1129 actual_cdrom_type = constants.HT_DISK_IDE
1130 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1131 actual_cdrom_type = "virtio"
1133 actual_cdrom_type = cdrom_disk_type
1134 if_val = ",if=%s" % actual_cdrom_type
1135 # set boot flag, if needed
1138 kvm_cmd.extend(["-boot", "d"])
1140 boot_val = ",boot=on"
1141 # and finally build the entire '-drive' value
1142 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1143 kvm_cmd.extend(["-drive", drive_val])
1145 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1147 options = ",format=raw,media=cdrom"
1148 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1149 if_val = ",if=virtio"
1151 if_val = ",if=%s" % cdrom_disk_type
1152 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1153 kvm_cmd.extend(["-drive", drive_val])
1155 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1157 options = ",format=raw,media=disk"
1159 kvm_cmd.extend(["-boot", "a"])
1160 options = "%s,boot=on" % options
1161 if_val = ",if=floppy"
1162 options = "%s%s" % (options, if_val)
1163 drive_val = "file=%s%s" % (floppy_image, options)
1164 kvm_cmd.extend(["-drive", drive_val])
1167 kvm_cmd.extend(["-kernel", kernel_path])
1168 initrd_path = hvp[constants.HV_INITRD_PATH]
1170 kvm_cmd.extend(["-initrd", initrd_path])
1171 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1172 hvp[constants.HV_KERNEL_ARGS]]
1173 if hvp[constants.HV_SERIAL_CONSOLE]:
1174 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1175 root_append.append("console=ttyS0,%s" % serial_speed)
1176 kvm_cmd.extend(["-append", " ".join(root_append)])
1178 mem_path = hvp[constants.HV_MEM_PATH]
1180 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1182 monitor_dev = ("unix:%s,server,nowait" %
1183 self._InstanceMonitor(instance.name))
1184 kvm_cmd.extend(["-monitor", monitor_dev])
1185 if hvp[constants.HV_SERIAL_CONSOLE]:
1186 serial_dev = ("unix:%s,server,nowait" %
1187 self._InstanceSerial(instance.name))
1188 kvm_cmd.extend(["-serial", serial_dev])
1190 kvm_cmd.extend(["-serial", "none"])
1192 mouse_type = hvp[constants.HV_USB_MOUSE]
1193 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1194 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1195 spice_ip_version = None
1197 kvm_cmd.extend(["-usb"])
1200 kvm_cmd.extend(["-usbdevice", mouse_type])
1201 elif vnc_bind_address:
1202 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1204 if vnc_bind_address:
1205 if netutils.IP4Address.IsValid(vnc_bind_address):
1206 if instance.network_port > constants.VNC_BASE_PORT:
1207 display = instance.network_port - constants.VNC_BASE_PORT
1208 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1209 vnc_arg = ":%d" % (display)
1211 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1213 logging.error("Network port is not a valid VNC display (%d < %d)."
1214 " Not starting VNC", instance.network_port,
1215 constants.VNC_BASE_PORT)
1218 # Only allow tls and other option when not binding to a file, for now.
1219 # kvm/qemu gets confused otherwise about the filename to use.
1221 if hvp[constants.HV_VNC_TLS]:
1222 vnc_append = "%s,tls" % vnc_append
1223 if hvp[constants.HV_VNC_X509_VERIFY]:
1224 vnc_append = "%s,x509verify=%s" % (vnc_append,
1225 hvp[constants.HV_VNC_X509])
1226 elif hvp[constants.HV_VNC_X509]:
1227 vnc_append = "%s,x509=%s" % (vnc_append,
1228 hvp[constants.HV_VNC_X509])
1229 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1230 vnc_append = "%s,password" % vnc_append
1232 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1235 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1237 kvm_cmd.extend(["-vnc", vnc_arg])
1239 # FIXME: this is wrong here; the iface ip address differs
1240 # between systems, so it should be done in _ExecuteKVMRuntime
1241 if netutils.IsValidInterface(spice_bind):
1242 # The user specified a network interface, we have to figure out the IP
1244 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1245 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1247 # if the user specified an IP version and the interface does not
1248 # have that kind of IP addresses, throw an exception
1249 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1250 if not addresses[spice_ip_version]:
1251 raise errors.HypervisorError("spice: unable to get an IPv%s address"
1252 " for %s" % (spice_ip_version,
1255 # the user did not specify an IP version, we have to figure it out
1256 elif (addresses[constants.IP4_VERSION] and
1257 addresses[constants.IP6_VERSION]):
1258 # we have both ipv4 and ipv6, let's use the cluster default IP
1260 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1261 spice_ip_version = \
1262 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1263 elif addresses[constants.IP4_VERSION]:
1264 spice_ip_version = constants.IP4_VERSION
1265 elif addresses[constants.IP6_VERSION]:
1266 spice_ip_version = constants.IP6_VERSION
1268 raise errors.HypervisorError("spice: unable to get an IP address"
1269 " for %s" % (spice_bind))
1271 spice_address = addresses[spice_ip_version][0]
1274 # spice_bind is known to be a valid IP address, because
1275 # ValidateParameters checked it.
1276 spice_address = spice_bind
1278 spice_arg = "addr=%s" % spice_address
1279 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1280 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1281 (spice_arg, instance.network_port,
1282 pathutils.SPICE_CACERT_FILE))
1283 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1284 (spice_arg, pathutils.SPICE_CERT_FILE,
1285 pathutils.SPICE_CERT_FILE))
1286 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1288 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1290 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1292 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1293 spice_arg = "%s,disable-ticketing" % spice_arg
1295 if spice_ip_version:
1296 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1298 # Image compression options
1299 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1300 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1301 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1303 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1305 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1307 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1309 # Video stream detection
1310 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1312 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1314 # Audio compression, by default in qemu-kvm it is on
1315 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1316 spice_arg = "%s,playback-compression=off" % spice_arg
1317 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1318 spice_arg = "%s,agent-mouse=off" % spice_arg
1320 # Enable the spice agent communication channel between the host and the
1322 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1323 kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1324 "name=com.redhat.spice.0"])
1325 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1327 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1328 kvm_cmd.extend(["-spice", spice_arg])
1331 kvm_cmd.extend(["-nographic"])
1333 if hvp[constants.HV_USE_LOCALTIME]:
1334 kvm_cmd.extend(["-localtime"])
1336 if hvp[constants.HV_KVM_USE_CHROOT]:
1337 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1339 # Add qemu-KVM -cpu param
1340 if hvp[constants.HV_CPU_TYPE]:
1341 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1343 # As requested by music lovers
1344 if hvp[constants.HV_SOUNDHW]:
1345 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1347 # Pass a -vga option if requested, or if spice is used, for backwards
1349 if hvp[constants.HV_VGA]:
1350 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1352 kvm_cmd.extend(["-vga", "qxl"])
1354 # Various types of usb devices, comma separated
1355 if hvp[constants.HV_USB_DEVICES]:
1356 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1357 kvm_cmd.extend(["-usbdevice", dev])
1359 if hvp[constants.HV_KVM_EXTRA]:
1360 kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1362 # Save the current instance nics, but defer their expansion as parameters,
1363 # as we'll need to generate executable temp files for them.
1364 kvm_nics = instance.nics
1367 return (kvm_cmd, kvm_nics, hvparams)
1369 def _WriteKVMRuntime(self, instance_name, data):
1370 """Write an instance's KVM runtime
1374 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1376 except EnvironmentError, err:
1377 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1379 def _ReadKVMRuntime(self, instance_name):
1380 """Read an instance's KVM runtime
1384 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1385 except EnvironmentError, err:
1386 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1389 def _SaveKVMRuntime(self, instance, kvm_runtime):
1390 """Save an instance's KVM runtime
1393 kvm_cmd, kvm_nics, hvparams = kvm_runtime
1394 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1395 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1396 self._WriteKVMRuntime(instance.name, serialized_form)
1398 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1399 """Load an instance's KVM runtime
1402 if not serialized_runtime:
1403 serialized_runtime = self._ReadKVMRuntime(instance.name)
1404 loaded_runtime = serializer.Load(serialized_runtime)
1405 kvm_cmd, serialized_nics, hvparams = loaded_runtime
1406 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1407 return (kvm_cmd, kvm_nics, hvparams)
1409 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1410 """Run the KVM cmd and check for errors
1413 @param name: instance name
1414 @type kvm_cmd: list of strings
1415 @param kvm_cmd: runcmd input for kvm
1416 @type tap_fds: list of int
1417 @param tap_fds: fds of tap devices opened by Ganeti
1421 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1424 utils_wrapper.CloseFdNoError(fd)
1427 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1428 (name, result.fail_reason, result.output))
1429 if not self._InstancePidAlive(name)[2]:
1430 raise errors.HypervisorError("Failed to start instance %s" % name)
1432 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
1433 """Execute a KVM cmd, after completing it with some last minute data.
1435 @type incoming: tuple of strings
1436 @param incoming: (target_host_ip, port)
1439 # Small _ExecuteKVMRuntime hv parameters programming howto:
1440 # - conf_hvp contains the parameters as configured on ganeti. they might
1441 # have changed since the instance started; only use them if the change
1442 # won't affect the inside of the instance (which hasn't been rebooted).
1443 # - up_hvp contains the parameters as they were when the instance was
1444 # started, plus any new parameter which has been added between ganeti
1445 # versions: it is paramount that those default to a value which won't
1446 # affect the inside of the instance as well.
1447 conf_hvp = instance.hvparams
1448 name = instance.name
1449 self._CheckDown(name)
1453 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1454 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1456 kvmhelp = self._GetKVMHelpOutput()
1457 _, v_major, v_min, _ = self._ParseKVMVersion(kvmhelp)
1459 # We know it's safe to run as a different user upon migration, so we'll use
1460 # the latest conf, from conf_hvp.
1461 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1462 if security_model == constants.HT_SM_USER:
1463 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1465 keymap = conf_hvp[constants.HV_KEYMAP]
1467 keymap_path = self._InstanceKeymapFile(name)
1468 # If a keymap file is specified, KVM won't use its internal defaults. By
1469 # first including the "en-us" layout, an error on loading the actual
1470 # layout (e.g. because it can't be found) won't lead to a non-functional
1471 # keyboard. A keyboard with incorrect keys is still better than none.
1472 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1473 kvm_cmd.extend(["-k", keymap_path])
1475 # We have reasons to believe changing something like the nic driver/type
1476 # upon migration won't exactly fly with the instance kernel, so for nic
1477 # related parameters we'll use up_hvp
1481 kvm_cmd.extend(["-net", "none"])
1485 nic_type = up_hvp[constants.HV_NIC_TYPE]
1486 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1487 # From version 0.12.0, kvm uses a new sintax for network configuration.
1488 if (v_major, v_min) >= (0, 12):
1489 nic_model = "virtio-net-pci"
1492 nic_model = "virtio"
1494 if up_hvp[constants.HV_VHOST_NET]:
1495 # vhost_net is only available from version 0.13.0 or newer
1496 if self._VHOST_RE.search(kvmhelp):
1497 tap_extra = ",vhost=on"
1499 raise errors.HypervisorError("vhost_net is configured"
1500 " but it is not available")
1502 nic_model = nic_type
1504 for nic_seq, nic in enumerate(kvm_nics):
1505 tapname, tapfd = _OpenTap(vnet_hdr)
1506 tapfds.append(tapfd)
1507 taps.append(tapname)
1508 if self._NETDEV_RE.search(kvmhelp):
1509 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1510 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1511 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1513 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1515 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1516 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1519 target, port = incoming
1520 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1522 # Changing the vnc password doesn't bother the guest that much. At most it
1523 # will surprise people who connect to it. Whether positively or negatively
1525 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1529 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1530 except EnvironmentError, err:
1531 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1532 % (vnc_pwd_file, err))
1534 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1535 utils.EnsureDirs([(self._InstanceChrootDir(name),
1536 constants.SECURE_DIR_MODE)])
1538 # Automatically enable QMP if version is >= 0.14
1539 if self._QMP_RE.search(kvmhelp):
1540 logging.debug("Enabling QMP")
1541 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1542 self._InstanceQmpMonitor(instance.name)])
1544 # Configure the network now for starting instances and bridged interfaces,
1545 # during FinalizeMigration for incoming instances' routed interfaces
1546 for nic_seq, nic in enumerate(kvm_nics):
1548 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1550 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1552 # CPU affinity requires kvm to start paused, so we set this flag if the
1553 # instance is not already paused and if we are not going to accept a
1554 # migrating instance. In the latter case, pausing is not needed.
1555 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1556 if start_kvm_paused:
1557 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1559 # Note: CPU pinning is using up_hvp since changes take effect
1560 # during instance startup anyway, and to avoid problems when soft
1561 # rebooting the instance.
1563 if up_hvp.get(constants.HV_CPU_MASK, None):
1566 if security_model == constants.HT_SM_POOL:
1567 ss = ssconf.SimpleStore()
1568 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1569 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1570 uid = uidpool.RequestUnusedUid(all_uids)
1572 username = pwd.getpwuid(uid.GetUid()).pw_name
1573 kvm_cmd.extend(["-runas", username])
1574 self._RunKVMCmd(name, kvm_cmd, tapfds)
1576 uidpool.ReleaseUid(uid)
1580 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1582 self._RunKVMCmd(name, kvm_cmd, tapfds)
1584 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1585 constants.RUN_DIRS_MODE)])
1586 for nic_seq, tap in enumerate(taps):
1587 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1591 change_cmd = "change vnc password %s" % vnc_pwd
1592 self._CallMonitorCommand(instance.name, change_cmd)
1594 # Setting SPICE password. We are not vulnerable to malicious passwordless
1595 # connection attempts because SPICE by default does not allow connections
1596 # if neither a password nor the "disable_ticketing" options are specified.
1597 # As soon as we send the password via QMP, that password is a valid ticket
1599 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1600 if spice_password_file:
1603 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1604 except EnvironmentError, err:
1605 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1606 % (spice_password_file, err))
1608 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1611 "protocol": "spice",
1612 "password": spice_pwd,
1614 qmp.Execute("set_password", arguments)
1616 for filename in temp_files:
1617 utils.RemoveFile(filename)
1619 # If requested, set CPU affinity and resume instance execution
1621 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1623 start_memory = self._InstanceStartupMemory(instance)
1624 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1625 self.BalloonInstanceMemory(instance, start_memory)
1627 if start_kvm_paused:
1628 # To control CPU pinning, ballooning, and vnc/spice passwords
1629 # the VM was started in a frozen state. If freezing was not
1630 # explicitly requested resume the vm status.
1631 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1633 def StartInstance(self, instance, block_devices, startup_paused):
1634 """Start an instance.
1637 self._CheckDown(instance.name)
1638 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1640 self._SaveKVMRuntime(instance, kvm_runtime)
1641 self._ExecuteKVMRuntime(instance, kvm_runtime)
1643 def _CallMonitorCommand(self, instance_name, command):
1644 """Invoke a command on the instance monitor.
1647 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1648 (utils.ShellQuote(command),
1649 constants.SOCAT_PATH,
1650 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1651 result = utils.RunCmd(socat)
1653 msg = ("Failed to send command '%s' to instance %s."
1654 " output: %s, error: %s, fail_reason: %s" %
1655 (command, instance_name,
1656 result.stdout, result.stderr, result.fail_reason))
1657 raise errors.HypervisorError(msg)
1662 def _ParseKVMVersion(cls, text):
1663 """Parse the KVM version from the --help output.
1666 @param text: output of kvm --help
1667 @return: (version, v_maj, v_min, v_rev)
1668 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1671 match = cls._VERSION_RE.search(text.splitlines()[0])
1673 raise errors.HypervisorError("Unable to get KVM version")
1675 v_all = match.group(0)
1676 v_maj = int(match.group(1))
1677 v_min = int(match.group(2))
1679 v_rev = int(match.group(4))
1682 return (v_all, v_maj, v_min, v_rev)
1685 def _GetKVMHelpOutput(cls):
1686 """Return the KVM help output.
1688 @return: output of kvm --help
1689 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1692 result = utils.RunCmd([constants.KVM_PATH, "--help"])
1694 raise errors.HypervisorError("Unable to get KVM help output")
1695 return result.output
1698 def _GetKVMVersion(cls):
1699 """Return the installed KVM version.
1701 @return: (version, v_maj, v_min, v_rev)
1702 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1705 return cls._ParseKVMVersion(cls._GetKVMHelpOutput())
1707 def StopInstance(self, instance, force=False, retry=False, name=None):
1708 """Stop an instance.
1711 if name is not None and not force:
1712 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1714 name = instance.name
1715 acpi = instance.hvparams[constants.HV_ACPI]
1718 _, pid, alive = self._InstancePidAlive(name)
1719 if pid > 0 and alive:
1720 if force or not acpi:
1721 utils.KillProcess(pid)
1723 self._CallMonitorCommand(name, "system_powerdown")
1726 def _GetDefaultMachineVersion(cls):
1727 """Return the default hardware revision (e.g. pc-1.1)
1730 result = utils.RunCmd([constants.KVM_PATH, "-M", "?"])
1732 raise errors.HypervisorError("Unable to get default hardware revision")
1733 match = cls._DEFAULT_MACHINE_VERSION_RE.search(result.output)
1735 return match.group(1)
1739 def CleanupInstance(self, instance_name):
1740 """Cleanup after a stopped instance
1743 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1744 if pid > 0 and alive:
1745 raise errors.HypervisorError("Cannot cleanup a live instance")
1746 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1748 def RebootInstance(self, instance):
1749 """Reboot an instance.
1752 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1753 # socket the instance will stop, but now power up again. So we'll resort
1754 # to shutdown and restart.
1755 _, _, alive = self._InstancePidAlive(instance.name)
1757 raise errors.HypervisorError("Failed to reboot instance %s:"
1758 " not running" % instance.name)
1759 # StopInstance will delete the saved KVM runtime so:
1760 # ...first load it...
1761 kvm_runtime = self._LoadKVMRuntime(instance)
1762 # ...now we can safely call StopInstance...
1763 if not self.StopInstance(instance):
1764 self.StopInstance(instance, force=True)
1765 # ...and finally we can save it again, and execute it...
1766 self._SaveKVMRuntime(instance, kvm_runtime)
1767 self._ExecuteKVMRuntime(instance, kvm_runtime)
1769 def MigrationInfo(self, instance):
1770 """Get instance information to perform a migration.
1772 @type instance: L{objects.Instance}
1773 @param instance: instance to be migrated
1775 @return: content of the KVM runtime file
1778 return self._ReadKVMRuntime(instance.name)
1780 def AcceptInstance(self, instance, info, target):
1781 """Prepare to accept an instance.
1783 @type instance: L{objects.Instance}
1784 @param instance: instance to be accepted
1786 @param info: content of the KVM runtime file on the source node
1787 @type target: string
1788 @param target: target host (usually ip), on this node
1791 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1792 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1793 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1795 def FinalizeMigrationDst(self, instance, info, success):
1796 """Finalize the instance migration on the target node.
1798 Stop the incoming mode KVM.
1800 @type instance: L{objects.Instance}
1801 @param instance: instance whose migration is being finalized
1805 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1806 kvm_nics = kvm_runtime[1]
1808 for nic_seq, nic in enumerate(kvm_nics):
1809 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1810 # Bridged interfaces have already been configured
1813 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1814 except EnvironmentError, err:
1815 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1816 instance.name, nic_seq, str(err))
1819 self._ConfigureNIC(instance, nic_seq, nic, tap)
1820 except errors.HypervisorError, err:
1821 logging.warning(str(err))
1823 self._WriteKVMRuntime(instance.name, info)
1825 self.StopInstance(instance, force=True)
1827 def MigrateInstance(self, instance, target, live):
1828 """Migrate an instance to a target node.
1830 The migration will not be attempted if the instance is not
1833 @type instance: L{objects.Instance}
1834 @param instance: the instance to be migrated
1835 @type target: string
1836 @param target: ip address of the target node
1838 @param live: perform a live migration
1841 instance_name = instance.name
1842 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1843 _, _, alive = self._InstancePidAlive(instance_name)
1845 raise errors.HypervisorError("Instance not running, cannot migrate")
1848 self._CallMonitorCommand(instance_name, "stop")
1850 migrate_command = ("migrate_set_speed %dm" %
1851 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1852 self._CallMonitorCommand(instance_name, migrate_command)
1854 migrate_command = ("migrate_set_downtime %dms" %
1855 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1856 self._CallMonitorCommand(instance_name, migrate_command)
1858 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1859 self._CallMonitorCommand(instance_name, migrate_command)
1861 def FinalizeMigrationSource(self, instance, success, live):
1862 """Finalize the instance migration on the source node.
1864 @type instance: L{objects.Instance}
1865 @param instance: the instance that was migrated
1867 @param success: whether the migration succeeded or not
1869 @param live: whether the user requested a live migration or not
1873 pidfile, pid, _ = self._InstancePidAlive(instance.name)
1874 utils.KillProcess(pid)
1875 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1877 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1879 def GetMigrationStatus(self, instance):
1880 """Get the migration status
1882 @type instance: L{objects.Instance}
1883 @param instance: the instance that is being migrated
1884 @rtype: L{objects.MigrationStatus}
1885 @return: the status of the current migration (one of
1886 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1887 progress info that can be retrieved from the hypervisor
1890 info_command = "info migrate"
1891 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1892 result = self._CallMonitorCommand(instance.name, info_command)
1893 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1895 if not result.stdout:
1896 logging.info("KVM: empty 'info migrate' result")
1898 logging.warning("KVM: unknown 'info migrate' result: %s",
1901 status = match.group(1)
1902 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1903 migration_status = objects.MigrationStatus(status=status)
1904 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1906 migration_status.transferred_ram = match.group("transferred")
1907 migration_status.total_ram = match.group("total")
1909 return migration_status
1911 logging.warning("KVM: unknown migration status '%s'", status)
1913 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1915 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1917 def BalloonInstanceMemory(self, instance, mem):
1918 """Balloon an instance memory to a certain value.
1920 @type instance: L{objects.Instance}
1921 @param instance: instance to be accepted
1923 @param mem: actual memory size to use for instance runtime
1926 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1928 def GetNodeInfo(self):
1929 """Return information about the node.
1931 @return: a dict with the following keys (values in MiB):
1932 - memory_total: the total memory size on the node
1933 - memory_free: the available memory on the node for instances
1934 - memory_dom0: the memory used by the node itself, if available
1935 - hv_version: the hypervisor version in the form (major, minor,
1939 result = self.GetLinuxNodeInfo()
1940 _, v_major, v_min, v_rev = self._GetKVMVersion()
1941 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1945 def GetInstanceConsole(cls, instance, hvparams, beparams):
1946 """Return a command for connecting to the console of an instance.
1949 if hvparams[constants.HV_SERIAL_CONSOLE]:
1950 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1951 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1952 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1953 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1954 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1955 return objects.InstanceConsole(instance=instance.name,
1956 kind=constants.CONS_SSH,
1957 host=instance.primary_node,
1958 user=constants.SSH_CONSOLE_USER,
1961 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1962 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1963 display = instance.network_port - constants.VNC_BASE_PORT
1964 return objects.InstanceConsole(instance=instance.name,
1965 kind=constants.CONS_VNC,
1966 host=vnc_bind_address,
1967 port=instance.network_port,
1970 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1972 return objects.InstanceConsole(instance=instance.name,
1973 kind=constants.CONS_SPICE,
1975 port=instance.network_port)
1977 return objects.InstanceConsole(instance=instance.name,
1978 kind=constants.CONS_MESSAGE,
1979 message=("No serial shell for instance %s" %
1983 """Verify the hypervisor.
1985 Check that the binary exists.
1988 if not os.path.exists(constants.KVM_PATH):
1989 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1990 if not os.path.exists(constants.SOCAT_PATH):
1991 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1994 def CheckParameterSyntax(cls, hvparams):
1995 """Check the given parameters for validity.
1997 @type hvparams: dict
1998 @param hvparams: dictionary with parameter names/value
1999 @raise errors.HypervisorError: when a parameter is not valid
2002 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2004 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2006 if not hvparams[constants.HV_ROOT_PATH]:
2007 raise errors.HypervisorError("Need a root partition for the instance,"
2008 " if a kernel is defined")
2010 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2011 not hvparams[constants.HV_VNC_X509]):
2012 raise errors.HypervisorError("%s must be defined, if %s is" %
2013 (constants.HV_VNC_X509,
2014 constants.HV_VNC_X509_VERIFY))
2016 if hvparams[constants.HV_SERIAL_CONSOLE]:
2017 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2018 valid_speeds = constants.VALID_SERIAL_SPEEDS
2019 if not serial_speed or serial_speed not in valid_speeds:
2020 raise errors.HypervisorError("Invalid serial console speed, must be"
2022 utils.CommaJoin(valid_speeds))
2024 boot_order = hvparams[constants.HV_BOOT_ORDER]
2025 if (boot_order == constants.HT_BO_CDROM and
2026 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2027 raise errors.HypervisorError("Cannot boot from cdrom without an"
2030 security_model = hvparams[constants.HV_SECURITY_MODEL]
2031 if security_model == constants.HT_SM_USER:
2032 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2033 raise errors.HypervisorError("A security domain (user to run kvm as)"
2034 " must be specified")
2035 elif (security_model == constants.HT_SM_NONE or
2036 security_model == constants.HT_SM_POOL):
2037 if hvparams[constants.HV_SECURITY_DOMAIN]:
2038 raise errors.HypervisorError("Cannot have a security domain when the"
2039 " security model is 'none' or 'pool'")
2041 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2042 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2044 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2045 # if an IP version is specified, the spice_bind parameter must be an
2047 if (netutils.IP4Address.IsValid(spice_bind) and
2048 spice_ip_version != constants.IP4_VERSION):
2049 raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2050 " the specified IP version is %s" %
2051 (spice_bind, spice_ip_version))
2053 if (netutils.IP6Address.IsValid(spice_bind) and
2054 spice_ip_version != constants.IP6_VERSION):
2055 raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2056 " the specified IP version is %s" %
2057 (spice_bind, spice_ip_version))
2059 # All the other SPICE parameters depend on spice_bind being set. Raise an
2060 # error if any of them is set without it.
2061 for param in _SPICE_ADDITIONAL_PARAMS:
2063 raise errors.HypervisorError("spice: %s requires %s to be set" %
2064 (param, constants.HV_KVM_SPICE_BIND))
2067 def ValidateParameters(cls, hvparams):
2068 """Check the given parameters for validity.
2070 @type hvparams: dict
2071 @param hvparams: dictionary with parameter names/value
2072 @raise errors.HypervisorError: when a parameter is not valid
2075 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2077 security_model = hvparams[constants.HV_SECURITY_MODEL]
2078 if security_model == constants.HT_SM_USER:
2079 username = hvparams[constants.HV_SECURITY_DOMAIN]
2081 pwd.getpwnam(username)
2083 raise errors.HypervisorError("Unknown security domain user %s"
2086 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2088 # only one of VNC and SPICE can be used currently.
2089 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2090 raise errors.HypervisorError("both SPICE and VNC are configured, but"
2091 " only one of them can be used at a"
2094 # KVM version should be >= 0.14.0
2095 kvmhelp = cls._GetKVMHelpOutput()
2096 if not cls._SPICE_RE.search(kvmhelp):
2097 raise errors.HypervisorError("spice is configured, but it is not"
2098 " supported according to kvm --help")
2100 # if spice_bind is not an IP address, it must be a valid interface
2101 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2102 or netutils.IP6Address.IsValid(spice_bind))
2103 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2104 raise errors.HypervisorError("spice: the %s parameter must be either"
2105 " a valid IP address or interface name" %
2106 constants.HV_KVM_SPICE_BIND)
2109 def PowercycleNode(cls):
2110 """KVM powercycle, just a wrapper over Linux powercycle.
2113 cls.LinuxPowercycle()