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,
544 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
546 _MIGRATION_PROGRESS_RE = \
547 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
548 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
549 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
551 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
552 _MIGRATION_INFO_RETRY_DELAY = 2
554 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
556 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
557 _CPU_INFO_CMD = "info cpus"
560 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
562 _QMP_RE = re.compile(r"^-qmp\s", re.M)
563 _SPICE_RE = re.compile(r"^-spice\s", re.M)
564 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
565 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
566 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
567 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
568 # match -drive.*boot=on|off on different lines, but in between accept only
569 # dashes not preceeded by a new line (which would mean another option
570 # different than -drive is starting)
571 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
576 ANCILLARY_FILES_OPT = [
581 hv_base.BaseHypervisor.__init__(self)
582 # Let's make sure the directories we need exist, even if the RUN_DIR lives
583 # in a tmpfs filesystem or has been otherwise wiped out.
584 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
585 utils.EnsureDirs(dirs)
588 def _InstancePidFile(cls, instance_name):
589 """Returns the instance pidfile.
592 return utils.PathJoin(cls._PIDS_DIR, instance_name)
595 def _InstanceUidFile(cls, instance_name):
596 """Returns the instance uidfile.
599 return utils.PathJoin(cls._UIDS_DIR, instance_name)
602 def _InstancePidInfo(cls, pid):
603 """Check pid file for instance information.
605 Check that a pid file is associated with an instance, and retrieve
606 information from its command line.
608 @type pid: string or int
609 @param pid: process id of the instance to check
611 @return: (instance_name, memory, vcpus)
612 @raise errors.HypervisorError: when an instance cannot be found
615 alive = utils.IsProcessAlive(pid)
617 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
619 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
621 cmdline = utils.ReadFile(cmdline_file)
622 except EnvironmentError, err:
623 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
630 arg_list = cmdline.split("\x00")
632 arg = arg_list.pop(0)
634 instance = arg_list.pop(0)
636 memory = int(arg_list.pop(0))
638 vcpus = int(arg_list.pop(0).split(",")[0])
641 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
644 return (instance, memory, vcpus)
646 def _InstancePidAlive(self, instance_name):
647 """Returns the instance pidfile, pid, and liveness.
649 @type instance_name: string
650 @param instance_name: instance name
652 @return: (pid file name, pid, liveness)
655 pidfile = self._InstancePidFile(instance_name)
656 pid = utils.ReadPidFile(pidfile)
660 cmd_instance = self._InstancePidInfo(pid)[0]
661 alive = (cmd_instance == instance_name)
662 except errors.HypervisorError:
665 return (pidfile, pid, alive)
667 def _CheckDown(self, instance_name):
668 """Raises an error unless the given instance is down.
671 alive = self._InstancePidAlive(instance_name)[2]
673 raise errors.HypervisorError("Failed to start instance %s: %s" %
674 (instance_name, "already running"))
677 def _InstanceMonitor(cls, instance_name):
678 """Returns the instance monitor socket name
681 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
684 def _InstanceSerial(cls, instance_name):
685 """Returns the instance serial socket name
688 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
691 def _InstanceQmpMonitor(cls, instance_name):
692 """Returns the instance serial QMP socket name
695 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
698 def _SocatUnixConsoleParams():
699 """Returns the correct parameters for socat
701 If we have a new-enough socat we can use raw mode with an escape character.
704 if constants.SOCAT_USE_ESCAPE:
705 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
707 return "echo=0,icanon=0"
710 def _InstanceKVMRuntime(cls, instance_name):
711 """Returns the instance KVM runtime filename
714 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
717 def _InstanceChrootDir(cls, instance_name):
718 """Returns the name of the KVM chroot dir of the instance
721 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
724 def _InstanceNICDir(cls, instance_name):
725 """Returns the name of the directory holding the tap device files for a
729 return utils.PathJoin(cls._NICS_DIR, instance_name)
732 def _InstanceNICFile(cls, instance_name, seq):
733 """Returns the name of the file containing the tap device for a given NIC
736 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
739 def _InstanceKeymapFile(cls, instance_name):
740 """Returns the name of the file containing the keymap for a given instance
743 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
746 def _TryReadUidFile(cls, uid_file):
747 """Try to read a uid file
750 if os.path.exists(uid_file):
752 uid = int(utils.ReadOneLineFile(uid_file))
754 except EnvironmentError:
755 logging.warning("Can't read uid file", exc_info=True)
756 except (TypeError, ValueError):
757 logging.warning("Can't parse uid file contents", exc_info=True)
761 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
762 """Removes an instance's rutime sockets/files/dirs.
765 utils.RemoveFile(pidfile)
766 utils.RemoveFile(cls._InstanceMonitor(instance_name))
767 utils.RemoveFile(cls._InstanceSerial(instance_name))
768 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
769 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
770 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
771 uid_file = cls._InstanceUidFile(instance_name)
772 uid = cls._TryReadUidFile(uid_file)
773 utils.RemoveFile(uid_file)
775 uidpool.ReleaseUid(uid)
777 shutil.rmtree(cls._InstanceNICDir(instance_name))
779 if err.errno != errno.ENOENT:
782 chroot_dir = cls._InstanceChrootDir(instance_name)
783 utils.RemoveDir(chroot_dir)
785 if err.errno == errno.ENOTEMPTY:
786 # The chroot directory is expected to be empty, but it isn't.
787 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
790 utils.TimestampForFilename()))
791 logging.warning("The chroot directory of instance %s can not be"
792 " removed as it is not empty. Moving it to the"
793 " quarantine instead. Please investigate the"
794 " contents (%s) and clean up manually",
795 instance_name, new_chroot_dir)
796 utils.RenameFile(chroot_dir, new_chroot_dir)
801 def _ConfigureNIC(instance, seq, nic, tap):
802 """Run the network configuration script for a specified NIC
804 @param instance: instance we're acting on
805 @type instance: instance object
806 @param seq: nic sequence number
808 @param nic: nic we're acting on
809 @type nic: nic object
810 @param tap: the host's tap interface this NIC corresponds to
815 tags = " ".join(instance.tags)
820 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
821 "INSTANCE": instance.name,
823 "MODE": nic.nicparams[constants.NIC_MODE],
825 "INTERFACE_INDEX": str(seq),
832 if nic.nicparams[constants.NIC_LINK]:
833 env["LINK"] = nic.nicparams[constants.NIC_LINK]
836 n = objects.Network.FromDict(nic.netinfo)
837 _BuildNetworkEnv(nic.network, n.network, n.gateway,
838 n.network6, n.gateway6, n.network_type,
839 n.mac_prefix, n.tags, env)
841 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
842 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
844 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
846 raise errors.HypervisorError("Failed to configure interface %s: %s."
847 " Network configuration script output: %s" %
848 (tap, result.fail_reason, result.output))
851 def _VerifyAffinityPackage():
853 raise errors.HypervisorError("affinity Python package not"
854 " found; cannot use CPU pinning under KVM")
857 def _BuildAffinityCpuMask(cpu_list):
858 """Create a CPU mask suitable for sched_setaffinity from a list of
861 See man taskset for more info on sched_setaffinity masks.
862 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
864 @type cpu_list: list of int
865 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
867 @return: a bit mask of CPU affinities
870 if cpu_list == constants.CPU_PINNING_OFF:
871 return constants.CPU_PINNING_ALL_KVM
873 return sum(2 ** cpu for cpu in cpu_list)
876 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
877 """Change CPU affinity for running VM according to given CPU mask.
879 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
880 @type cpu_mask: string
881 @param process_id: process ID of KVM process. Used to pin entire VM
883 @type process_id: int
884 @param thread_dict: map of virtual CPUs to KVM thread IDs
885 @type thread_dict: dict int:int
888 # Convert the string CPU mask to a list of list of int's
889 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
891 if len(cpu_list) == 1:
892 all_cpu_mapping = cpu_list[0]
893 if all_cpu_mapping == constants.CPU_PINNING_OFF:
894 # If CPU pinning has 1 entry that's "all", then do nothing
897 # If CPU pinning has one non-all entry, map the entire VM to
898 # one set of physical CPUs
899 cls._VerifyAffinityPackage()
900 affinity.set_process_affinity_mask(
901 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
903 # The number of vCPUs mapped should match the number of vCPUs
904 # reported by KVM. This was already verified earlier, so
905 # here only as a sanity check.
906 assert len(thread_dict) == len(cpu_list)
907 cls._VerifyAffinityPackage()
909 # For each vCPU, map it to the proper list of physical CPUs
910 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
911 affinity.set_process_affinity_mask(thread_dict[i],
912 cls._BuildAffinityCpuMask(vcpu))
914 def _GetVcpuThreadIds(self, instance_name):
915 """Get a mapping of vCPU no. to thread IDs for the instance
917 @type instance_name: string
918 @param instance_name: instance in question
919 @rtype: dictionary of int:int
920 @return: a dictionary mapping vCPU numbers to thread IDs
924 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
925 for line in output.stdout.splitlines():
926 match = self._CPU_INFO_RE.search(line)
929 grp = map(int, match.groups())
930 result[grp[0]] = grp[1]
934 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
935 """Complete CPU pinning.
937 @type instance_name: string
938 @param instance_name: name of instance
939 @type cpu_mask: string
940 @param cpu_mask: CPU pinning mask as entered by user
943 # Get KVM process ID, to be used if need to pin entire VM
944 _, pid, _ = self._InstancePidAlive(instance_name)
945 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
946 thread_dict = self._GetVcpuThreadIds(instance_name)
947 # Run CPU pinning, based on configured mask
948 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
950 def ListInstances(self):
951 """Get the list of running instances.
953 We can do this by listing our live instances directory and
954 checking whether the associated kvm process is still alive.
958 for name in os.listdir(self._PIDS_DIR):
959 if self._InstancePidAlive(name)[2]:
963 def GetInstanceInfo(self, instance_name):
964 """Get instance properties.
966 @type instance_name: string
967 @param instance_name: the instance name
968 @rtype: tuple of strings
969 @return: (name, id, memory, vcpus, stat, times)
972 _, pid, alive = self._InstancePidAlive(instance_name)
976 _, memory, vcpus = self._InstancePidInfo(pid)
981 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
983 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
984 # Will fail if ballooning is not enabled, but we can then just resort to
986 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
987 memory = mem_bytes / 1048576
988 except errors.HypervisorError:
991 return (instance_name, pid, memory, vcpus, istat, times)
993 def GetAllInstancesInfo(self):
994 """Get properties of all instances.
996 @return: list of tuples (name, id, memory, vcpus, stat, times)
1000 for name in os.listdir(self._PIDS_DIR):
1002 info = self.GetInstanceInfo(name)
1003 except errors.HypervisorError:
1004 # Ignore exceptions due to instances being shut down
1010 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
1011 """Generate KVM information to start an instance.
1013 @attention: this function must not have any side-effects; for
1014 example, it must not write to the filesystem, or read values
1015 from the current system the are expected to differ between
1016 nodes, since it is only run once at instance startup;
1017 actions/kvm arguments that can vary between systems should be
1018 done in L{_ExecuteKVMRuntime}
1021 # pylint: disable=R0912,R0914,R0915
1022 kvmhelp = self._GetKVMHelpOutput()
1023 hvp = instance.hvparams
1025 pidfile = self._InstancePidFile(instance.name)
1026 kvm = constants.KVM_PATH
1028 kvm_cmd.extend(["-M", self._GetDefaultMachineVersion()])
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 kernel_path = hvp[constants.HV_KERNEL_PATH]
1054 boot_disk = boot_cdrom = boot_floppy = boot_network = False
1056 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1057 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1058 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1059 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1061 self.ValidateParameters(hvp)
1064 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1066 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1067 self._ENABLE_KVM_RE.search(kvmhelp)):
1068 kvm_cmd.extend(["-enable-kvm"])
1069 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1070 self._DISABLE_KVM_RE.search(kvmhelp)):
1071 kvm_cmd.extend(["-disable-kvm"])
1074 kvm_cmd.extend(["-boot", "n"])
1076 # whether this is an older KVM version that uses the boot=on flag
1078 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1080 disk_type = hvp[constants.HV_DISK_TYPE]
1081 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1082 if_val = ",if=virtio"
1084 if_val = ",if=%s" % disk_type
1086 disk_cache = hvp[constants.HV_DISK_CACHE]
1087 if instance.disk_template in constants.DTS_EXT_MIRROR:
1088 if disk_cache != "none":
1089 # TODO: make this a hard error, instead of a silent overwrite
1090 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1091 " to prevent shared storage corruption on migration",
1093 cache_val = ",cache=none"
1094 elif disk_cache != constants.HT_CACHE_DEFAULT:
1095 cache_val = ",cache=%s" % disk_cache
1098 for cfdev, dev_path in block_devices:
1099 if cfdev.mode != constants.DISK_RDWR:
1100 raise errors.HypervisorError("Instance has read-only disks which"
1101 " are not supported by KVM")
1102 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1105 kvm_cmd.extend(["-boot", "c"])
1107 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1108 boot_val = ",boot=on"
1110 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1112 kvm_cmd.extend(["-drive", drive_val])
1114 #Now we can specify a different device type for CDROM devices.
1115 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1116 if not cdrom_disk_type:
1117 cdrom_disk_type = disk_type
1119 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1121 options = ",format=raw,media=cdrom"
1122 # set cdrom 'if' type
1124 actual_cdrom_type = constants.HT_DISK_IDE
1125 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1126 actual_cdrom_type = "virtio"
1128 actual_cdrom_type = cdrom_disk_type
1129 if_val = ",if=%s" % actual_cdrom_type
1130 # set boot flag, if needed
1133 kvm_cmd.extend(["-boot", "d"])
1135 boot_val = ",boot=on"
1136 # and finally build the entire '-drive' value
1137 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1138 kvm_cmd.extend(["-drive", drive_val])
1140 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1142 options = ",format=raw,media=cdrom"
1143 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1144 if_val = ",if=virtio"
1146 if_val = ",if=%s" % cdrom_disk_type
1147 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1148 kvm_cmd.extend(["-drive", drive_val])
1150 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1152 options = ",format=raw,media=disk"
1154 kvm_cmd.extend(["-boot", "a"])
1155 options = "%s,boot=on" % options
1156 if_val = ",if=floppy"
1157 options = "%s%s" % (options, if_val)
1158 drive_val = "file=%s%s" % (floppy_image, options)
1159 kvm_cmd.extend(["-drive", drive_val])
1162 kvm_cmd.extend(["-kernel", kernel_path])
1163 initrd_path = hvp[constants.HV_INITRD_PATH]
1165 kvm_cmd.extend(["-initrd", initrd_path])
1166 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1167 hvp[constants.HV_KERNEL_ARGS]]
1168 if hvp[constants.HV_SERIAL_CONSOLE]:
1169 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1170 root_append.append("console=ttyS0,%s" % serial_speed)
1171 kvm_cmd.extend(["-append", " ".join(root_append)])
1173 mem_path = hvp[constants.HV_MEM_PATH]
1175 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1177 monitor_dev = ("unix:%s,server,nowait" %
1178 self._InstanceMonitor(instance.name))
1179 kvm_cmd.extend(["-monitor", monitor_dev])
1180 if hvp[constants.HV_SERIAL_CONSOLE]:
1181 serial_dev = ("unix:%s,server,nowait" %
1182 self._InstanceSerial(instance.name))
1183 kvm_cmd.extend(["-serial", serial_dev])
1185 kvm_cmd.extend(["-serial", "none"])
1187 mouse_type = hvp[constants.HV_USB_MOUSE]
1188 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1189 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1190 spice_ip_version = None
1192 kvm_cmd.extend(["-usb"])
1195 kvm_cmd.extend(["-usbdevice", mouse_type])
1196 elif vnc_bind_address:
1197 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1199 if vnc_bind_address:
1200 if netutils.IP4Address.IsValid(vnc_bind_address):
1201 if instance.network_port > constants.VNC_BASE_PORT:
1202 display = instance.network_port - constants.VNC_BASE_PORT
1203 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1204 vnc_arg = ":%d" % (display)
1206 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1208 logging.error("Network port is not a valid VNC display (%d < %d)."
1209 " Not starting VNC", instance.network_port,
1210 constants.VNC_BASE_PORT)
1213 # Only allow tls and other option when not binding to a file, for now.
1214 # kvm/qemu gets confused otherwise about the filename to use.
1216 if hvp[constants.HV_VNC_TLS]:
1217 vnc_append = "%s,tls" % vnc_append
1218 if hvp[constants.HV_VNC_X509_VERIFY]:
1219 vnc_append = "%s,x509verify=%s" % (vnc_append,
1220 hvp[constants.HV_VNC_X509])
1221 elif hvp[constants.HV_VNC_X509]:
1222 vnc_append = "%s,x509=%s" % (vnc_append,
1223 hvp[constants.HV_VNC_X509])
1224 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1225 vnc_append = "%s,password" % vnc_append
1227 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1230 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1232 kvm_cmd.extend(["-vnc", vnc_arg])
1234 # FIXME: this is wrong here; the iface ip address differs
1235 # between systems, so it should be done in _ExecuteKVMRuntime
1236 if netutils.IsValidInterface(spice_bind):
1237 # The user specified a network interface, we have to figure out the IP
1239 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1240 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1242 # if the user specified an IP version and the interface does not
1243 # have that kind of IP addresses, throw an exception
1244 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1245 if not addresses[spice_ip_version]:
1246 raise errors.HypervisorError("spice: unable to get an IPv%s address"
1247 " for %s" % (spice_ip_version,
1250 # the user did not specify an IP version, we have to figure it out
1251 elif (addresses[constants.IP4_VERSION] and
1252 addresses[constants.IP6_VERSION]):
1253 # we have both ipv4 and ipv6, let's use the cluster default IP
1255 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1256 spice_ip_version = \
1257 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1258 elif addresses[constants.IP4_VERSION]:
1259 spice_ip_version = constants.IP4_VERSION
1260 elif addresses[constants.IP6_VERSION]:
1261 spice_ip_version = constants.IP6_VERSION
1263 raise errors.HypervisorError("spice: unable to get an IP address"
1264 " for %s" % (spice_bind))
1266 spice_address = addresses[spice_ip_version][0]
1269 # spice_bind is known to be a valid IP address, because
1270 # ValidateParameters checked it.
1271 spice_address = spice_bind
1273 spice_arg = "addr=%s" % spice_address
1274 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1275 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1276 (spice_arg, instance.network_port,
1277 pathutils.SPICE_CACERT_FILE))
1278 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1279 (spice_arg, pathutils.SPICE_CERT_FILE,
1280 pathutils.SPICE_CERT_FILE))
1281 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1283 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1285 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1287 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1288 spice_arg = "%s,disable-ticketing" % spice_arg
1290 if spice_ip_version:
1291 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1293 # Image compression options
1294 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1295 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1296 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1298 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1300 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1302 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1304 # Video stream detection
1305 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1307 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1309 # Audio compression, by default in qemu-kvm it is on
1310 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1311 spice_arg = "%s,playback-compression=off" % spice_arg
1312 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1313 spice_arg = "%s,agent-mouse=off" % spice_arg
1315 # Enable the spice agent communication channel between the host and the
1317 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1318 kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1319 "name=com.redhat.spice.0"])
1320 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1322 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1323 kvm_cmd.extend(["-spice", spice_arg])
1326 kvm_cmd.extend(["-nographic"])
1328 if hvp[constants.HV_USE_LOCALTIME]:
1329 kvm_cmd.extend(["-localtime"])
1331 if hvp[constants.HV_KVM_USE_CHROOT]:
1332 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1334 # Add qemu-KVM -cpu param
1335 if hvp[constants.HV_CPU_TYPE]:
1336 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1338 # As requested by music lovers
1339 if hvp[constants.HV_SOUNDHW]:
1340 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1342 # Pass a -vga option if requested, or if spice is used, for backwards
1344 if hvp[constants.HV_VGA]:
1345 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1347 kvm_cmd.extend(["-vga", "qxl"])
1349 # Various types of usb devices, comma separated
1350 if hvp[constants.HV_USB_DEVICES]:
1351 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1352 kvm_cmd.extend(["-usbdevice", dev])
1354 if hvp[constants.HV_KVM_EXTRA]:
1355 kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1357 # Save the current instance nics, but defer their expansion as parameters,
1358 # as we'll need to generate executable temp files for them.
1359 kvm_nics = instance.nics
1362 return (kvm_cmd, kvm_nics, hvparams)
1364 def _WriteKVMRuntime(self, instance_name, data):
1365 """Write an instance's KVM runtime
1369 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1371 except EnvironmentError, err:
1372 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1374 def _ReadKVMRuntime(self, instance_name):
1375 """Read an instance's KVM runtime
1379 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1380 except EnvironmentError, err:
1381 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1384 def _SaveKVMRuntime(self, instance, kvm_runtime):
1385 """Save an instance's KVM runtime
1388 kvm_cmd, kvm_nics, hvparams = kvm_runtime
1389 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1390 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1391 self._WriteKVMRuntime(instance.name, serialized_form)
1393 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1394 """Load an instance's KVM runtime
1397 if not serialized_runtime:
1398 serialized_runtime = self._ReadKVMRuntime(instance.name)
1399 loaded_runtime = serializer.Load(serialized_runtime)
1400 kvm_cmd, serialized_nics, hvparams = loaded_runtime
1401 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1402 return (kvm_cmd, kvm_nics, hvparams)
1404 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1405 """Run the KVM cmd and check for errors
1408 @param name: instance name
1409 @type kvm_cmd: list of strings
1410 @param kvm_cmd: runcmd input for kvm
1411 @type tap_fds: list of int
1412 @param tap_fds: fds of tap devices opened by Ganeti
1416 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1419 utils_wrapper.CloseFdNoError(fd)
1422 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1423 (name, result.fail_reason, result.output))
1424 if not self._InstancePidAlive(name)[2]:
1425 raise errors.HypervisorError("Failed to start instance %s" % name)
1427 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
1428 """Execute a KVM cmd, after completing it with some last minute data.
1430 @type incoming: tuple of strings
1431 @param incoming: (target_host_ip, port)
1434 # Small _ExecuteKVMRuntime hv parameters programming howto:
1435 # - conf_hvp contains the parameters as configured on ganeti. they might
1436 # have changed since the instance started; only use them if the change
1437 # won't affect the inside of the instance (which hasn't been rebooted).
1438 # - up_hvp contains the parameters as they were when the instance was
1439 # started, plus any new parameter which has been added between ganeti
1440 # versions: it is paramount that those default to a value which won't
1441 # affect the inside of the instance as well.
1442 conf_hvp = instance.hvparams
1443 name = instance.name
1444 self._CheckDown(name)
1448 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1449 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1451 kvmhelp = self._GetKVMHelpOutput()
1452 _, v_major, v_min, _ = self._ParseKVMVersion(kvmhelp)
1454 # We know it's safe to run as a different user upon migration, so we'll use
1455 # the latest conf, from conf_hvp.
1456 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1457 if security_model == constants.HT_SM_USER:
1458 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1460 keymap = conf_hvp[constants.HV_KEYMAP]
1462 keymap_path = self._InstanceKeymapFile(name)
1463 # If a keymap file is specified, KVM won't use its internal defaults. By
1464 # first including the "en-us" layout, an error on loading the actual
1465 # layout (e.g. because it can't be found) won't lead to a non-functional
1466 # keyboard. A keyboard with incorrect keys is still better than none.
1467 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1468 kvm_cmd.extend(["-k", keymap_path])
1470 # We have reasons to believe changing something like the nic driver/type
1471 # upon migration won't exactly fly with the instance kernel, so for nic
1472 # related parameters we'll use up_hvp
1476 kvm_cmd.extend(["-net", "none"])
1480 nic_type = up_hvp[constants.HV_NIC_TYPE]
1481 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1482 # From version 0.12.0, kvm uses a new sintax for network configuration.
1483 if (v_major, v_min) >= (0, 12):
1484 nic_model = "virtio-net-pci"
1487 nic_model = "virtio"
1489 if up_hvp[constants.HV_VHOST_NET]:
1490 # vhost_net is only available from version 0.13.0 or newer
1491 if self._VHOST_RE.search(kvmhelp):
1492 tap_extra = ",vhost=on"
1494 raise errors.HypervisorError("vhost_net is configured"
1495 " but it is not available")
1497 nic_model = nic_type
1499 for nic_seq, nic in enumerate(kvm_nics):
1500 tapname, tapfd = _OpenTap(vnet_hdr)
1501 tapfds.append(tapfd)
1502 taps.append(tapname)
1503 if self._NETDEV_RE.search(kvmhelp):
1504 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1505 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1506 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1508 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1510 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1511 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1514 target, port = incoming
1515 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1517 # Changing the vnc password doesn't bother the guest that much. At most it
1518 # will surprise people who connect to it. Whether positively or negatively
1520 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1524 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1525 except EnvironmentError, err:
1526 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1527 % (vnc_pwd_file, err))
1529 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1530 utils.EnsureDirs([(self._InstanceChrootDir(name),
1531 constants.SECURE_DIR_MODE)])
1533 # Automatically enable QMP if version is >= 0.14
1534 if self._QMP_RE.search(kvmhelp):
1535 logging.debug("Enabling QMP")
1536 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1537 self._InstanceQmpMonitor(instance.name)])
1539 # Configure the network now for starting instances and bridged interfaces,
1540 # during FinalizeMigration for incoming instances' routed interfaces
1541 for nic_seq, nic in enumerate(kvm_nics):
1543 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1545 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1547 # CPU affinity requires kvm to start paused, so we set this flag if the
1548 # instance is not already paused and if we are not going to accept a
1549 # migrating instance. In the latter case, pausing is not needed.
1550 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1551 if start_kvm_paused:
1552 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1554 # Note: CPU pinning is using up_hvp since changes take effect
1555 # during instance startup anyway, and to avoid problems when soft
1556 # rebooting the instance.
1558 if up_hvp.get(constants.HV_CPU_MASK, None):
1561 if security_model == constants.HT_SM_POOL:
1562 ss = ssconf.SimpleStore()
1563 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1564 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1565 uid = uidpool.RequestUnusedUid(all_uids)
1567 username = pwd.getpwuid(uid.GetUid()).pw_name
1568 kvm_cmd.extend(["-runas", username])
1569 self._RunKVMCmd(name, kvm_cmd, tapfds)
1571 uidpool.ReleaseUid(uid)
1575 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1577 self._RunKVMCmd(name, kvm_cmd, tapfds)
1579 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1580 constants.RUN_DIRS_MODE)])
1581 for nic_seq, tap in enumerate(taps):
1582 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1586 change_cmd = "change vnc password %s" % vnc_pwd
1587 self._CallMonitorCommand(instance.name, change_cmd)
1589 # Setting SPICE password. We are not vulnerable to malicious passwordless
1590 # connection attempts because SPICE by default does not allow connections
1591 # if neither a password nor the "disable_ticketing" options are specified.
1592 # As soon as we send the password via QMP, that password is a valid ticket
1594 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1595 if spice_password_file:
1598 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1599 except EnvironmentError, err:
1600 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1601 % (spice_password_file, err))
1603 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1606 "protocol": "spice",
1607 "password": spice_pwd,
1609 qmp.Execute("set_password", arguments)
1611 for filename in temp_files:
1612 utils.RemoveFile(filename)
1614 # If requested, set CPU affinity and resume instance execution
1616 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1618 start_memory = self._InstanceStartupMemory(instance)
1619 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1620 self.BalloonInstanceMemory(instance, start_memory)
1622 if start_kvm_paused:
1623 # To control CPU pinning, ballooning, and vnc/spice passwords
1624 # the VM was started in a frozen state. If freezing was not
1625 # explicitly requested resume the vm status.
1626 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1628 def StartInstance(self, instance, block_devices, startup_paused):
1629 """Start an instance.
1632 self._CheckDown(instance.name)
1633 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1635 self._SaveKVMRuntime(instance, kvm_runtime)
1636 self._ExecuteKVMRuntime(instance, kvm_runtime)
1638 def _CallMonitorCommand(self, instance_name, command):
1639 """Invoke a command on the instance monitor.
1642 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1643 (utils.ShellQuote(command),
1644 constants.SOCAT_PATH,
1645 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1646 result = utils.RunCmd(socat)
1648 msg = ("Failed to send command '%s' to instance %s."
1649 " output: %s, error: %s, fail_reason: %s" %
1650 (command, instance_name,
1651 result.stdout, result.stderr, result.fail_reason))
1652 raise errors.HypervisorError(msg)
1657 def _ParseKVMVersion(cls, text):
1658 """Parse the KVM version from the --help output.
1661 @param text: output of kvm --help
1662 @return: (version, v_maj, v_min, v_rev)
1663 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1666 match = cls._VERSION_RE.search(text.splitlines()[0])
1668 raise errors.HypervisorError("Unable to get KVM version")
1670 v_all = match.group(0)
1671 v_maj = int(match.group(1))
1672 v_min = int(match.group(2))
1674 v_rev = int(match.group(4))
1677 return (v_all, v_maj, v_min, v_rev)
1680 def _GetKVMHelpOutput(cls):
1681 """Return the KVM help output.
1683 @return: output of kvm --help
1684 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1687 result = utils.RunCmd([constants.KVM_PATH, "--help"])
1689 raise errors.HypervisorError("Unable to get KVM help output")
1690 return result.output
1693 def _GetKVMVersion(cls):
1694 """Return the installed KVM version.
1696 @return: (version, v_maj, v_min, v_rev)
1697 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1700 return cls._ParseKVMVersion(cls._GetKVMHelpOutput())
1702 def StopInstance(self, instance, force=False, retry=False, name=None):
1703 """Stop an instance.
1706 if name is not None and not force:
1707 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1709 name = instance.name
1710 acpi = instance.hvparams[constants.HV_ACPI]
1713 _, pid, alive = self._InstancePidAlive(name)
1714 if pid > 0 and alive:
1715 if force or not acpi:
1716 utils.KillProcess(pid)
1718 self._CallMonitorCommand(name, "system_powerdown")
1721 def _GetDefaultMachineVersion(cls):
1722 """Return the default hardware revision (e.g. pc-1.1)
1725 result = utils.RunCmd([constants.KVM_PATH, "-M", "?"])
1727 raise errors.HypervisorError("Unable to get default hardware revision")
1728 match = cls._DEFAULT_MACHINE_VERSION_RE.search(result.output)
1730 return match.group(1)
1734 def CleanupInstance(self, instance_name):
1735 """Cleanup after a stopped instance
1738 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1739 if pid > 0 and alive:
1740 raise errors.HypervisorError("Cannot cleanup a live instance")
1741 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1743 def RebootInstance(self, instance):
1744 """Reboot an instance.
1747 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1748 # socket the instance will stop, but now power up again. So we'll resort
1749 # to shutdown and restart.
1750 _, _, alive = self._InstancePidAlive(instance.name)
1752 raise errors.HypervisorError("Failed to reboot instance %s:"
1753 " not running" % instance.name)
1754 # StopInstance will delete the saved KVM runtime so:
1755 # ...first load it...
1756 kvm_runtime = self._LoadKVMRuntime(instance)
1757 # ...now we can safely call StopInstance...
1758 if not self.StopInstance(instance):
1759 self.StopInstance(instance, force=True)
1760 # ...and finally we can save it again, and execute it...
1761 self._SaveKVMRuntime(instance, kvm_runtime)
1762 self._ExecuteKVMRuntime(instance, kvm_runtime)
1764 def MigrationInfo(self, instance):
1765 """Get instance information to perform a migration.
1767 @type instance: L{objects.Instance}
1768 @param instance: instance to be migrated
1770 @return: content of the KVM runtime file
1773 return self._ReadKVMRuntime(instance.name)
1775 def AcceptInstance(self, instance, info, target):
1776 """Prepare to accept an instance.
1778 @type instance: L{objects.Instance}
1779 @param instance: instance to be accepted
1781 @param info: content of the KVM runtime file on the source node
1782 @type target: string
1783 @param target: target host (usually ip), on this node
1786 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1787 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1788 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1790 def FinalizeMigrationDst(self, instance, info, success):
1791 """Finalize the instance migration on the target node.
1793 Stop the incoming mode KVM.
1795 @type instance: L{objects.Instance}
1796 @param instance: instance whose migration is being finalized
1800 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1801 kvm_nics = kvm_runtime[1]
1803 for nic_seq, nic in enumerate(kvm_nics):
1804 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1805 # Bridged interfaces have already been configured
1808 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1809 except EnvironmentError, err:
1810 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1811 instance.name, nic_seq, str(err))
1814 self._ConfigureNIC(instance, nic_seq, nic, tap)
1815 except errors.HypervisorError, err:
1816 logging.warning(str(err))
1818 self._WriteKVMRuntime(instance.name, info)
1820 self.StopInstance(instance, force=True)
1822 def MigrateInstance(self, instance, target, live):
1823 """Migrate an instance to a target node.
1825 The migration will not be attempted if the instance is not
1828 @type instance: L{objects.Instance}
1829 @param instance: the instance to be migrated
1830 @type target: string
1831 @param target: ip address of the target node
1833 @param live: perform a live migration
1836 instance_name = instance.name
1837 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1838 _, _, alive = self._InstancePidAlive(instance_name)
1840 raise errors.HypervisorError("Instance not running, cannot migrate")
1843 self._CallMonitorCommand(instance_name, "stop")
1845 migrate_command = ("migrate_set_speed %dm" %
1846 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1847 self._CallMonitorCommand(instance_name, migrate_command)
1849 migrate_command = ("migrate_set_downtime %dms" %
1850 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1851 self._CallMonitorCommand(instance_name, migrate_command)
1853 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1854 self._CallMonitorCommand(instance_name, migrate_command)
1856 def FinalizeMigrationSource(self, instance, success, live):
1857 """Finalize the instance migration on the source node.
1859 @type instance: L{objects.Instance}
1860 @param instance: the instance that was migrated
1862 @param success: whether the migration succeeded or not
1864 @param live: whether the user requested a live migration or not
1868 pidfile, pid, _ = self._InstancePidAlive(instance.name)
1869 utils.KillProcess(pid)
1870 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1872 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1874 def GetMigrationStatus(self, instance):
1875 """Get the migration status
1877 @type instance: L{objects.Instance}
1878 @param instance: the instance that is being migrated
1879 @rtype: L{objects.MigrationStatus}
1880 @return: the status of the current migration (one of
1881 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1882 progress info that can be retrieved from the hypervisor
1885 info_command = "info migrate"
1886 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1887 result = self._CallMonitorCommand(instance.name, info_command)
1888 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1890 if not result.stdout:
1891 logging.info("KVM: empty 'info migrate' result")
1893 logging.warning("KVM: unknown 'info migrate' result: %s",
1896 status = match.group(1)
1897 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1898 migration_status = objects.MigrationStatus(status=status)
1899 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1901 migration_status.transferred_ram = match.group("transferred")
1902 migration_status.total_ram = match.group("total")
1904 return migration_status
1906 logging.warning("KVM: unknown migration status '%s'", status)
1908 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1910 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1912 def BalloonInstanceMemory(self, instance, mem):
1913 """Balloon an instance memory to a certain value.
1915 @type instance: L{objects.Instance}
1916 @param instance: instance to be accepted
1918 @param mem: actual memory size to use for instance runtime
1921 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1923 def GetNodeInfo(self):
1924 """Return information about the node.
1926 @return: a dict with the following keys (values in MiB):
1927 - memory_total: the total memory size on the node
1928 - memory_free: the available memory on the node for instances
1929 - memory_dom0: the memory used by the node itself, if available
1930 - hv_version: the hypervisor version in the form (major, minor,
1934 result = self.GetLinuxNodeInfo()
1935 _, v_major, v_min, v_rev = self._GetKVMVersion()
1936 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1940 def GetInstanceConsole(cls, instance, hvparams, beparams):
1941 """Return a command for connecting to the console of an instance.
1944 if hvparams[constants.HV_SERIAL_CONSOLE]:
1945 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1946 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1947 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1948 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1949 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1950 return objects.InstanceConsole(instance=instance.name,
1951 kind=constants.CONS_SSH,
1952 host=instance.primary_node,
1953 user=constants.SSH_CONSOLE_USER,
1956 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1957 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1958 display = instance.network_port - constants.VNC_BASE_PORT
1959 return objects.InstanceConsole(instance=instance.name,
1960 kind=constants.CONS_VNC,
1961 host=vnc_bind_address,
1962 port=instance.network_port,
1965 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1967 return objects.InstanceConsole(instance=instance.name,
1968 kind=constants.CONS_SPICE,
1970 port=instance.network_port)
1972 return objects.InstanceConsole(instance=instance.name,
1973 kind=constants.CONS_MESSAGE,
1974 message=("No serial shell for instance %s" %
1978 """Verify the hypervisor.
1980 Check that the binary exists.
1983 if not os.path.exists(constants.KVM_PATH):
1984 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1985 if not os.path.exists(constants.SOCAT_PATH):
1986 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1989 def CheckParameterSyntax(cls, hvparams):
1990 """Check the given parameters for validity.
1992 @type hvparams: dict
1993 @param hvparams: dictionary with parameter names/value
1994 @raise errors.HypervisorError: when a parameter is not valid
1997 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1999 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2001 if not hvparams[constants.HV_ROOT_PATH]:
2002 raise errors.HypervisorError("Need a root partition for the instance,"
2003 " if a kernel is defined")
2005 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2006 not hvparams[constants.HV_VNC_X509]):
2007 raise errors.HypervisorError("%s must be defined, if %s is" %
2008 (constants.HV_VNC_X509,
2009 constants.HV_VNC_X509_VERIFY))
2011 if hvparams[constants.HV_SERIAL_CONSOLE]:
2012 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2013 valid_speeds = constants.VALID_SERIAL_SPEEDS
2014 if not serial_speed or serial_speed not in valid_speeds:
2015 raise errors.HypervisorError("Invalid serial console speed, must be"
2017 utils.CommaJoin(valid_speeds))
2019 boot_order = hvparams[constants.HV_BOOT_ORDER]
2020 if (boot_order == constants.HT_BO_CDROM and
2021 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2022 raise errors.HypervisorError("Cannot boot from cdrom without an"
2025 security_model = hvparams[constants.HV_SECURITY_MODEL]
2026 if security_model == constants.HT_SM_USER:
2027 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2028 raise errors.HypervisorError("A security domain (user to run kvm as)"
2029 " must be specified")
2030 elif (security_model == constants.HT_SM_NONE or
2031 security_model == constants.HT_SM_POOL):
2032 if hvparams[constants.HV_SECURITY_DOMAIN]:
2033 raise errors.HypervisorError("Cannot have a security domain when the"
2034 " security model is 'none' or 'pool'")
2036 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2037 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2039 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2040 # if an IP version is specified, the spice_bind parameter must be an
2042 if (netutils.IP4Address.IsValid(spice_bind) and
2043 spice_ip_version != constants.IP4_VERSION):
2044 raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2045 " the specified IP version is %s" %
2046 (spice_bind, spice_ip_version))
2048 if (netutils.IP6Address.IsValid(spice_bind) and
2049 spice_ip_version != constants.IP6_VERSION):
2050 raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2051 " the specified IP version is %s" %
2052 (spice_bind, spice_ip_version))
2054 # All the other SPICE parameters depend on spice_bind being set. Raise an
2055 # error if any of them is set without it.
2056 for param in _SPICE_ADDITIONAL_PARAMS:
2058 raise errors.HypervisorError("spice: %s requires %s to be set" %
2059 (param, constants.HV_KVM_SPICE_BIND))
2062 def ValidateParameters(cls, hvparams):
2063 """Check the given parameters for validity.
2065 @type hvparams: dict
2066 @param hvparams: dictionary with parameter names/value
2067 @raise errors.HypervisorError: when a parameter is not valid
2070 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2072 security_model = hvparams[constants.HV_SECURITY_MODEL]
2073 if security_model == constants.HT_SM_USER:
2074 username = hvparams[constants.HV_SECURITY_DOMAIN]
2076 pwd.getpwnam(username)
2078 raise errors.HypervisorError("Unknown security domain user %s"
2081 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2083 # only one of VNC and SPICE can be used currently.
2084 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2085 raise errors.HypervisorError("both SPICE and VNC are configured, but"
2086 " only one of them can be used at a"
2089 # KVM version should be >= 0.14.0
2090 kvmhelp = cls._GetKVMHelpOutput()
2091 if not cls._SPICE_RE.search(kvmhelp):
2092 raise errors.HypervisorError("spice is configured, but it is not"
2093 " supported according to kvm --help")
2095 # if spice_bind is not an IP address, it must be a valid interface
2096 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2097 or netutils.IP6Address.IsValid(spice_bind))
2098 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2099 raise errors.HypervisorError("spice: the %s parameter must be either"
2100 " a valid IP address or interface name" %
2101 constants.HV_KVM_SPICE_BIND)
2104 def PowercycleNode(cls):
2105 """KVM powercycle, just a wrapper over Linux powercycle.
2108 cls.LinuxPowercycle()