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_KVM_EXTRA: hv_base.NO_CHECK,
543 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
545 _MIGRATION_PROGRESS_RE = \
546 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
547 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
548 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
550 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
551 _MIGRATION_INFO_RETRY_DELAY = 2
553 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
555 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
556 _CPU_INFO_CMD = "info cpus"
559 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
561 _QMP_RE = re.compile(r"^-qmp\s", re.M)
562 _SPICE_RE = re.compile(r"^-spice\s", re.M)
563 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
564 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
565 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
566 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
567 # match -drive.*boot=on|off on different lines, but in between accept only
568 # dashes not preceeded by a new line (which would mean another option
569 # different than -drive is starting)
570 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
575 ANCILLARY_FILES_OPT = [
580 hv_base.BaseHypervisor.__init__(self)
581 # Let's make sure the directories we need exist, even if the RUN_DIR lives
582 # in a tmpfs filesystem or has been otherwise wiped out.
583 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
584 utils.EnsureDirs(dirs)
587 def _InstancePidFile(cls, instance_name):
588 """Returns the instance pidfile.
591 return utils.PathJoin(cls._PIDS_DIR, instance_name)
594 def _InstanceUidFile(cls, instance_name):
595 """Returns the instance uidfile.
598 return utils.PathJoin(cls._UIDS_DIR, instance_name)
601 def _InstancePidInfo(cls, pid):
602 """Check pid file for instance information.
604 Check that a pid file is associated with an instance, and retrieve
605 information from its command line.
607 @type pid: string or int
608 @param pid: process id of the instance to check
610 @return: (instance_name, memory, vcpus)
611 @raise errors.HypervisorError: when an instance cannot be found
614 alive = utils.IsProcessAlive(pid)
616 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
618 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
620 cmdline = utils.ReadFile(cmdline_file)
621 except EnvironmentError, err:
622 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
629 arg_list = cmdline.split("\x00")
631 arg = arg_list.pop(0)
633 instance = arg_list.pop(0)
635 memory = int(arg_list.pop(0))
637 vcpus = int(arg_list.pop(0).split(",")[0])
640 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
643 return (instance, memory, vcpus)
645 def _InstancePidAlive(self, instance_name):
646 """Returns the instance pidfile, pid, and liveness.
648 @type instance_name: string
649 @param instance_name: instance name
651 @return: (pid file name, pid, liveness)
654 pidfile = self._InstancePidFile(instance_name)
655 pid = utils.ReadPidFile(pidfile)
659 cmd_instance = self._InstancePidInfo(pid)[0]
660 alive = (cmd_instance == instance_name)
661 except errors.HypervisorError:
664 return (pidfile, pid, alive)
666 def _CheckDown(self, instance_name):
667 """Raises an error unless the given instance is down.
670 alive = self._InstancePidAlive(instance_name)[2]
672 raise errors.HypervisorError("Failed to start instance %s: %s" %
673 (instance_name, "already running"))
676 def _InstanceMonitor(cls, instance_name):
677 """Returns the instance monitor socket name
680 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
683 def _InstanceSerial(cls, instance_name):
684 """Returns the instance serial socket name
687 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
690 def _InstanceQmpMonitor(cls, instance_name):
691 """Returns the instance serial QMP socket name
694 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
697 def _SocatUnixConsoleParams():
698 """Returns the correct parameters for socat
700 If we have a new-enough socat we can use raw mode with an escape character.
703 if constants.SOCAT_USE_ESCAPE:
704 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
706 return "echo=0,icanon=0"
709 def _InstanceKVMRuntime(cls, instance_name):
710 """Returns the instance KVM runtime filename
713 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
716 def _InstanceChrootDir(cls, instance_name):
717 """Returns the name of the KVM chroot dir of the instance
720 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
723 def _InstanceNICDir(cls, instance_name):
724 """Returns the name of the directory holding the tap device files for a
728 return utils.PathJoin(cls._NICS_DIR, instance_name)
731 def _InstanceNICFile(cls, instance_name, seq):
732 """Returns the name of the file containing the tap device for a given NIC
735 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
738 def _InstanceKeymapFile(cls, instance_name):
739 """Returns the name of the file containing the keymap for a given instance
742 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
745 def _TryReadUidFile(cls, uid_file):
746 """Try to read a uid file
749 if os.path.exists(uid_file):
751 uid = int(utils.ReadOneLineFile(uid_file))
753 except EnvironmentError:
754 logging.warning("Can't read uid file", exc_info=True)
755 except (TypeError, ValueError):
756 logging.warning("Can't parse uid file contents", exc_info=True)
760 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
761 """Removes an instance's rutime sockets/files/dirs.
764 utils.RemoveFile(pidfile)
765 utils.RemoveFile(cls._InstanceMonitor(instance_name))
766 utils.RemoveFile(cls._InstanceSerial(instance_name))
767 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
768 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
769 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
770 uid_file = cls._InstanceUidFile(instance_name)
771 uid = cls._TryReadUidFile(uid_file)
772 utils.RemoveFile(uid_file)
774 uidpool.ReleaseUid(uid)
776 shutil.rmtree(cls._InstanceNICDir(instance_name))
778 if err.errno != errno.ENOENT:
781 chroot_dir = cls._InstanceChrootDir(instance_name)
782 utils.RemoveDir(chroot_dir)
784 if err.errno == errno.ENOTEMPTY:
785 # The chroot directory is expected to be empty, but it isn't.
786 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
789 utils.TimestampForFilename()))
790 logging.warning("The chroot directory of instance %s can not be"
791 " removed as it is not empty. Moving it to the"
792 " quarantine instead. Please investigate the"
793 " contents (%s) and clean up manually",
794 instance_name, new_chroot_dir)
795 utils.RenameFile(chroot_dir, new_chroot_dir)
800 def _ConfigureNIC(instance, seq, nic, tap):
801 """Run the network configuration script for a specified NIC
803 @param instance: instance we're acting on
804 @type instance: instance object
805 @param seq: nic sequence number
807 @param nic: nic we're acting on
808 @type nic: nic object
809 @param tap: the host's tap interface this NIC corresponds to
814 tags = " ".join(instance.tags)
819 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
820 "INSTANCE": instance.name,
822 "MODE": nic.nicparams[constants.NIC_MODE],
824 "INTERFACE_INDEX": str(seq),
831 if nic.nicparams[constants.NIC_LINK]:
832 env["LINK"] = nic.nicparams[constants.NIC_LINK]
835 n = objects.Network.FromDict(nic.netinfo)
836 _BuildNetworkEnv(nic.network, n.network, n.gateway,
837 n.network6, n.gateway6, n.network_type,
838 n.mac_prefix, n.tags, env)
840 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
841 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
843 result = utils.RunCmd([pathutils.KVM_IFUP, tap], env=env)
845 raise errors.HypervisorError("Failed to configure interface %s: %s."
846 " Network configuration script output: %s" %
847 (tap, result.fail_reason, result.output))
850 def _VerifyAffinityPackage():
852 raise errors.HypervisorError("affinity Python package not"
853 " found; cannot use CPU pinning under KVM")
856 def _BuildAffinityCpuMask(cpu_list):
857 """Create a CPU mask suitable for sched_setaffinity from a list of
860 See man taskset for more info on sched_setaffinity masks.
861 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
863 @type cpu_list: list of int
864 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
866 @return: a bit mask of CPU affinities
869 if cpu_list == constants.CPU_PINNING_OFF:
870 return constants.CPU_PINNING_ALL_KVM
872 return sum(2 ** cpu for cpu in cpu_list)
875 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
876 """Change CPU affinity for running VM according to given CPU mask.
878 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
879 @type cpu_mask: string
880 @param process_id: process ID of KVM process. Used to pin entire VM
882 @type process_id: int
883 @param thread_dict: map of virtual CPUs to KVM thread IDs
884 @type thread_dict: dict int:int
887 # Convert the string CPU mask to a list of list of int's
888 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
890 if len(cpu_list) == 1:
891 all_cpu_mapping = cpu_list[0]
892 if all_cpu_mapping == constants.CPU_PINNING_OFF:
893 # If CPU pinning has 1 entry that's "all", then do nothing
896 # If CPU pinning has one non-all entry, map the entire VM to
897 # one set of physical CPUs
898 cls._VerifyAffinityPackage()
899 affinity.set_process_affinity_mask(
900 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
902 # The number of vCPUs mapped should match the number of vCPUs
903 # reported by KVM. This was already verified earlier, so
904 # here only as a sanity check.
905 assert len(thread_dict) == len(cpu_list)
906 cls._VerifyAffinityPackage()
908 # For each vCPU, map it to the proper list of physical CPUs
909 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
910 affinity.set_process_affinity_mask(thread_dict[i],
911 cls._BuildAffinityCpuMask(vcpu))
913 def _GetVcpuThreadIds(self, instance_name):
914 """Get a mapping of vCPU no. to thread IDs for the instance
916 @type instance_name: string
917 @param instance_name: instance in question
918 @rtype: dictionary of int:int
919 @return: a dictionary mapping vCPU numbers to thread IDs
923 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
924 for line in output.stdout.splitlines():
925 match = self._CPU_INFO_RE.search(line)
928 grp = map(int, match.groups())
929 result[grp[0]] = grp[1]
933 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
934 """Complete CPU pinning.
936 @type instance_name: string
937 @param instance_name: name of instance
938 @type cpu_mask: string
939 @param cpu_mask: CPU pinning mask as entered by user
942 # Get KVM process ID, to be used if need to pin entire VM
943 _, pid, _ = self._InstancePidAlive(instance_name)
944 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
945 thread_dict = self._GetVcpuThreadIds(instance_name)
946 # Run CPU pinning, based on configured mask
947 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
949 def ListInstances(self):
950 """Get the list of running instances.
952 We can do this by listing our live instances directory and
953 checking whether the associated kvm process is still alive.
957 for name in os.listdir(self._PIDS_DIR):
958 if self._InstancePidAlive(name)[2]:
962 def GetInstanceInfo(self, instance_name):
963 """Get instance properties.
965 @type instance_name: string
966 @param instance_name: the instance name
967 @rtype: tuple of strings
968 @return: (name, id, memory, vcpus, stat, times)
971 _, pid, alive = self._InstancePidAlive(instance_name)
975 _, memory, vcpus = self._InstancePidInfo(pid)
980 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
982 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
983 # Will fail if ballooning is not enabled, but we can then just resort to
985 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
986 memory = mem_bytes / 1048576
987 except errors.HypervisorError:
990 return (instance_name, pid, memory, vcpus, istat, times)
992 def GetAllInstancesInfo(self):
993 """Get properties of all instances.
995 @return: list of tuples (name, id, memory, vcpus, stat, times)
999 for name in os.listdir(self._PIDS_DIR):
1001 info = self.GetInstanceInfo(name)
1002 except errors.HypervisorError:
1003 # Ignore exceptions due to instances being shut down
1009 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
1010 """Generate KVM information to start an instance.
1012 @attention: this function must not have any side-effects; for
1013 example, it must not write to the filesystem, or read values
1014 from the current system the are expected to differ between
1015 nodes, since it is only run once at instance startup;
1016 actions/kvm arguments that can vary between systems should be
1017 done in L{_ExecuteKVMRuntime}
1020 # pylint: disable=R0912,R0914,R0915
1021 kvmhelp = self._GetKVMHelpOutput()
1022 hvp = instance.hvparams
1024 pidfile = self._InstancePidFile(instance.name)
1025 kvm = constants.KVM_PATH
1027 kvm_cmd.extend(["-M", self._GetDefaultMachineVersion()])
1028 # used just by the vnc server, if enabled
1029 kvm_cmd.extend(["-name", instance.name])
1030 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1032 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1033 if hvp[constants.HV_CPU_CORES]:
1034 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1035 if hvp[constants.HV_CPU_THREADS]:
1036 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1037 if hvp[constants.HV_CPU_SOCKETS]:
1038 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1040 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1042 kvm_cmd.extend(["-pidfile", pidfile])
1043 kvm_cmd.extend(["-balloon", "virtio"])
1044 kvm_cmd.extend(["-daemonize"])
1045 if not instance.hvparams[constants.HV_ACPI]:
1046 kvm_cmd.extend(["-no-acpi"])
1047 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1048 constants.INSTANCE_REBOOT_EXIT:
1049 kvm_cmd.extend(["-no-reboot"])
1051 kernel_path = hvp[constants.HV_KERNEL_PATH]
1053 boot_disk = boot_cdrom = boot_floppy = boot_network = False
1055 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1056 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1057 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1058 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1060 self.ValidateParameters(hvp)
1063 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1065 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1066 self._ENABLE_KVM_RE.search(kvmhelp)):
1067 kvm_cmd.extend(["-enable-kvm"])
1068 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1069 self._DISABLE_KVM_RE.search(kvmhelp)):
1070 kvm_cmd.extend(["-disable-kvm"])
1073 kvm_cmd.extend(["-boot", "n"])
1075 # whether this is an older KVM version that uses the boot=on flag
1077 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1079 disk_type = hvp[constants.HV_DISK_TYPE]
1080 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1081 if_val = ",if=virtio"
1083 if_val = ",if=%s" % disk_type
1085 disk_cache = hvp[constants.HV_DISK_CACHE]
1086 if instance.disk_template in constants.DTS_EXT_MIRROR:
1087 if disk_cache != "none":
1088 # TODO: make this a hard error, instead of a silent overwrite
1089 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1090 " to prevent shared storage corruption on migration",
1092 cache_val = ",cache=none"
1093 elif disk_cache != constants.HT_CACHE_DEFAULT:
1094 cache_val = ",cache=%s" % disk_cache
1097 for cfdev, dev_path in block_devices:
1098 if cfdev.mode != constants.DISK_RDWR:
1099 raise errors.HypervisorError("Instance has read-only disks which"
1100 " are not supported by KVM")
1101 # TODO: handle FD_LOOP and FD_BLKTAP (?)
1104 kvm_cmd.extend(["-boot", "c"])
1106 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1107 boot_val = ",boot=on"
1109 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1111 kvm_cmd.extend(["-drive", drive_val])
1113 #Now we can specify a different device type for CDROM devices.
1114 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1115 if not cdrom_disk_type:
1116 cdrom_disk_type = disk_type
1118 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1120 options = ",format=raw,media=cdrom"
1121 # set cdrom 'if' type
1123 actual_cdrom_type = constants.HT_DISK_IDE
1124 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1125 actual_cdrom_type = "virtio"
1127 actual_cdrom_type = cdrom_disk_type
1128 if_val = ",if=%s" % actual_cdrom_type
1129 # set boot flag, if needed
1132 kvm_cmd.extend(["-boot", "d"])
1134 boot_val = ",boot=on"
1135 # and finally build the entire '-drive' value
1136 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1137 kvm_cmd.extend(["-drive", drive_val])
1139 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1141 options = ",format=raw,media=cdrom"
1142 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1143 if_val = ",if=virtio"
1145 if_val = ",if=%s" % cdrom_disk_type
1146 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1147 kvm_cmd.extend(["-drive", drive_val])
1149 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1151 options = ",format=raw,media=disk"
1153 kvm_cmd.extend(["-boot", "a"])
1154 options = "%s,boot=on" % options
1155 if_val = ",if=floppy"
1156 options = "%s%s" % (options, if_val)
1157 drive_val = "file=%s%s" % (floppy_image, options)
1158 kvm_cmd.extend(["-drive", drive_val])
1161 kvm_cmd.extend(["-kernel", kernel_path])
1162 initrd_path = hvp[constants.HV_INITRD_PATH]
1164 kvm_cmd.extend(["-initrd", initrd_path])
1165 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1166 hvp[constants.HV_KERNEL_ARGS]]
1167 if hvp[constants.HV_SERIAL_CONSOLE]:
1168 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1169 root_append.append("console=ttyS0,%s" % serial_speed)
1170 kvm_cmd.extend(["-append", " ".join(root_append)])
1172 mem_path = hvp[constants.HV_MEM_PATH]
1174 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1176 monitor_dev = ("unix:%s,server,nowait" %
1177 self._InstanceMonitor(instance.name))
1178 kvm_cmd.extend(["-monitor", monitor_dev])
1179 if hvp[constants.HV_SERIAL_CONSOLE]:
1180 serial_dev = ("unix:%s,server,nowait" %
1181 self._InstanceSerial(instance.name))
1182 kvm_cmd.extend(["-serial", serial_dev])
1184 kvm_cmd.extend(["-serial", "none"])
1186 mouse_type = hvp[constants.HV_USB_MOUSE]
1187 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1188 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1189 spice_ip_version = None
1191 kvm_cmd.extend(["-usb"])
1194 kvm_cmd.extend(["-usbdevice", mouse_type])
1195 elif vnc_bind_address:
1196 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1198 if vnc_bind_address:
1199 if netutils.IP4Address.IsValid(vnc_bind_address):
1200 if instance.network_port > constants.VNC_BASE_PORT:
1201 display = instance.network_port - constants.VNC_BASE_PORT
1202 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1203 vnc_arg = ":%d" % (display)
1205 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1207 logging.error("Network port is not a valid VNC display (%d < %d)."
1208 " Not starting VNC", instance.network_port,
1209 constants.VNC_BASE_PORT)
1212 # Only allow tls and other option when not binding to a file, for now.
1213 # kvm/qemu gets confused otherwise about the filename to use.
1215 if hvp[constants.HV_VNC_TLS]:
1216 vnc_append = "%s,tls" % vnc_append
1217 if hvp[constants.HV_VNC_X509_VERIFY]:
1218 vnc_append = "%s,x509verify=%s" % (vnc_append,
1219 hvp[constants.HV_VNC_X509])
1220 elif hvp[constants.HV_VNC_X509]:
1221 vnc_append = "%s,x509=%s" % (vnc_append,
1222 hvp[constants.HV_VNC_X509])
1223 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1224 vnc_append = "%s,password" % vnc_append
1226 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1229 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1231 kvm_cmd.extend(["-vnc", vnc_arg])
1233 # FIXME: this is wrong here; the iface ip address differs
1234 # between systems, so it should be done in _ExecuteKVMRuntime
1235 if netutils.IsValidInterface(spice_bind):
1236 # The user specified a network interface, we have to figure out the IP
1238 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1239 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1241 # if the user specified an IP version and the interface does not
1242 # have that kind of IP addresses, throw an exception
1243 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1244 if not addresses[spice_ip_version]:
1245 raise errors.HypervisorError("spice: unable to get an IPv%s address"
1246 " for %s" % (spice_ip_version,
1249 # the user did not specify an IP version, we have to figure it out
1250 elif (addresses[constants.IP4_VERSION] and
1251 addresses[constants.IP6_VERSION]):
1252 # we have both ipv4 and ipv6, let's use the cluster default IP
1254 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1255 spice_ip_version = \
1256 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1257 elif addresses[constants.IP4_VERSION]:
1258 spice_ip_version = constants.IP4_VERSION
1259 elif addresses[constants.IP6_VERSION]:
1260 spice_ip_version = constants.IP6_VERSION
1262 raise errors.HypervisorError("spice: unable to get an IP address"
1263 " for %s" % (spice_bind))
1265 spice_address = addresses[spice_ip_version][0]
1268 # spice_bind is known to be a valid IP address, because
1269 # ValidateParameters checked it.
1270 spice_address = spice_bind
1272 spice_arg = "addr=%s" % spice_address
1273 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1274 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1275 (spice_arg, instance.network_port,
1276 pathutils.SPICE_CACERT_FILE))
1277 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1278 (spice_arg, pathutils.SPICE_CERT_FILE,
1279 pathutils.SPICE_CERT_FILE))
1280 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1282 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1284 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1286 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1287 spice_arg = "%s,disable-ticketing" % spice_arg
1289 if spice_ip_version:
1290 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1292 # Image compression options
1293 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1294 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1295 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1297 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1299 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1301 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1303 # Video stream detection
1304 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1306 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1308 # Audio compression, by default in qemu-kvm it is on
1309 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1310 spice_arg = "%s,playback-compression=off" % spice_arg
1311 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1312 spice_arg = "%s,agent-mouse=off" % spice_arg
1314 # Enable the spice agent communication channel between the host and the
1316 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1317 kvm_cmd.extend(["-device", "virtserialport,chardev=spicechannel0,"
1318 "name=com.redhat.spice.0"])
1319 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1321 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1322 kvm_cmd.extend(["-spice", spice_arg])
1324 # Tell kvm to use the paravirtualized graphic card, optimized for SPICE
1325 kvm_cmd.extend(["-vga", "qxl"])
1328 kvm_cmd.extend(["-nographic"])
1330 if hvp[constants.HV_USE_LOCALTIME]:
1331 kvm_cmd.extend(["-localtime"])
1333 if hvp[constants.HV_KVM_USE_CHROOT]:
1334 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1336 # Add qemu-KVM -cpu param
1337 if hvp[constants.HV_CPU_TYPE]:
1338 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1340 # As requested by music lovers
1341 if hvp[constants.HV_SOUNDHW]:
1342 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1344 # Various types of usb devices, comma separated
1345 if hvp[constants.HV_USB_DEVICES]:
1346 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1347 kvm_cmd.extend(["-usbdevice", dev])
1349 if hvp[constants.HV_KVM_EXTRA]:
1350 kvm_cmd.extend([hvp[constants.HV_KVM_EXTRA]])
1352 # Save the current instance nics, but defer their expansion as parameters,
1353 # as we'll need to generate executable temp files for them.
1354 kvm_nics = instance.nics
1357 return (kvm_cmd, kvm_nics, hvparams)
1359 def _WriteKVMRuntime(self, instance_name, data):
1360 """Write an instance's KVM runtime
1364 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1366 except EnvironmentError, err:
1367 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1369 def _ReadKVMRuntime(self, instance_name):
1370 """Read an instance's KVM runtime
1374 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1375 except EnvironmentError, err:
1376 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1379 def _SaveKVMRuntime(self, instance, kvm_runtime):
1380 """Save an instance's KVM runtime
1383 kvm_cmd, kvm_nics, hvparams = kvm_runtime
1384 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1385 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1386 self._WriteKVMRuntime(instance.name, serialized_form)
1388 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1389 """Load an instance's KVM runtime
1392 if not serialized_runtime:
1393 serialized_runtime = self._ReadKVMRuntime(instance.name)
1394 loaded_runtime = serializer.Load(serialized_runtime)
1395 kvm_cmd, serialized_nics, hvparams = loaded_runtime
1396 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1397 return (kvm_cmd, kvm_nics, hvparams)
1399 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1400 """Run the KVM cmd and check for errors
1403 @param name: instance name
1404 @type kvm_cmd: list of strings
1405 @param kvm_cmd: runcmd input for kvm
1406 @type tap_fds: list of int
1407 @param tap_fds: fds of tap devices opened by Ganeti
1411 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1414 utils_wrapper.CloseFdNoError(fd)
1417 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1418 (name, result.fail_reason, result.output))
1419 if not self._InstancePidAlive(name)[2]:
1420 raise errors.HypervisorError("Failed to start instance %s" % name)
1422 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
1423 """Execute a KVM cmd, after completing it with some last minute data.
1425 @type incoming: tuple of strings
1426 @param incoming: (target_host_ip, port)
1429 # Small _ExecuteKVMRuntime hv parameters programming howto:
1430 # - conf_hvp contains the parameters as configured on ganeti. they might
1431 # have changed since the instance started; only use them if the change
1432 # won't affect the inside of the instance (which hasn't been rebooted).
1433 # - up_hvp contains the parameters as they were when the instance was
1434 # started, plus any new parameter which has been added between ganeti
1435 # versions: it is paramount that those default to a value which won't
1436 # affect the inside of the instance as well.
1437 conf_hvp = instance.hvparams
1438 name = instance.name
1439 self._CheckDown(name)
1443 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1444 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1446 kvmhelp = self._GetKVMHelpOutput()
1447 _, v_major, v_min, _ = self._ParseKVMVersion(kvmhelp)
1449 # We know it's safe to run as a different user upon migration, so we'll use
1450 # the latest conf, from conf_hvp.
1451 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1452 if security_model == constants.HT_SM_USER:
1453 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1455 keymap = conf_hvp[constants.HV_KEYMAP]
1457 keymap_path = self._InstanceKeymapFile(name)
1458 # If a keymap file is specified, KVM won't use its internal defaults. By
1459 # first including the "en-us" layout, an error on loading the actual
1460 # layout (e.g. because it can't be found) won't lead to a non-functional
1461 # keyboard. A keyboard with incorrect keys is still better than none.
1462 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1463 kvm_cmd.extend(["-k", keymap_path])
1465 # We have reasons to believe changing something like the nic driver/type
1466 # upon migration won't exactly fly with the instance kernel, so for nic
1467 # related parameters we'll use up_hvp
1471 kvm_cmd.extend(["-net", "none"])
1475 nic_type = up_hvp[constants.HV_NIC_TYPE]
1476 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1477 # From version 0.12.0, kvm uses a new sintax for network configuration.
1478 if (v_major, v_min) >= (0, 12):
1479 nic_model = "virtio-net-pci"
1482 nic_model = "virtio"
1484 if up_hvp[constants.HV_VHOST_NET]:
1485 # vhost_net is only available from version 0.13.0 or newer
1486 if self._VHOST_RE.search(kvmhelp):
1487 tap_extra = ",vhost=on"
1489 raise errors.HypervisorError("vhost_net is configured"
1490 " but it is not available")
1492 nic_model = nic_type
1494 for nic_seq, nic in enumerate(kvm_nics):
1495 tapname, tapfd = _OpenTap(vnet_hdr)
1496 tapfds.append(tapfd)
1497 taps.append(tapname)
1498 if self._NETDEV_RE.search(kvmhelp):
1499 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1500 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1501 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1503 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1505 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1506 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1509 target, port = incoming
1510 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1512 # Changing the vnc password doesn't bother the guest that much. At most it
1513 # will surprise people who connect to it. Whether positively or negatively
1515 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1519 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1520 except EnvironmentError, err:
1521 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1522 % (vnc_pwd_file, err))
1524 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1525 utils.EnsureDirs([(self._InstanceChrootDir(name),
1526 constants.SECURE_DIR_MODE)])
1528 # Automatically enable QMP if version is >= 0.14
1529 if self._QMP_RE.search(kvmhelp):
1530 logging.debug("Enabling QMP")
1531 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1532 self._InstanceQmpMonitor(instance.name)])
1534 # Configure the network now for starting instances and bridged interfaces,
1535 # during FinalizeMigration for incoming instances' routed interfaces
1536 for nic_seq, nic in enumerate(kvm_nics):
1538 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1540 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1542 # CPU affinity requires kvm to start paused, so we set this flag if the
1543 # instance is not already paused and if we are not going to accept a
1544 # migrating instance. In the latter case, pausing is not needed.
1545 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1546 if start_kvm_paused:
1547 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1549 # Note: CPU pinning is using up_hvp since changes take effect
1550 # during instance startup anyway, and to avoid problems when soft
1551 # rebooting the instance.
1553 if up_hvp.get(constants.HV_CPU_MASK, None):
1556 if security_model == constants.HT_SM_POOL:
1557 ss = ssconf.SimpleStore()
1558 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1559 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1560 uid = uidpool.RequestUnusedUid(all_uids)
1562 username = pwd.getpwuid(uid.GetUid()).pw_name
1563 kvm_cmd.extend(["-runas", username])
1564 self._RunKVMCmd(name, kvm_cmd, tapfds)
1566 uidpool.ReleaseUid(uid)
1570 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1572 self._RunKVMCmd(name, kvm_cmd, tapfds)
1574 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1575 constants.RUN_DIRS_MODE)])
1576 for nic_seq, tap in enumerate(taps):
1577 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1581 change_cmd = "change vnc password %s" % vnc_pwd
1582 self._CallMonitorCommand(instance.name, change_cmd)
1584 # Setting SPICE password. We are not vulnerable to malicious passwordless
1585 # connection attempts because SPICE by default does not allow connections
1586 # if neither a password nor the "disable_ticketing" options are specified.
1587 # As soon as we send the password via QMP, that password is a valid ticket
1589 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1590 if spice_password_file:
1593 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1594 except EnvironmentError, err:
1595 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1596 % (spice_password_file, err))
1598 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1601 "protocol": "spice",
1602 "password": spice_pwd,
1604 qmp.Execute("set_password", arguments)
1606 for filename in temp_files:
1607 utils.RemoveFile(filename)
1609 # If requested, set CPU affinity and resume instance execution
1611 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1613 start_memory = self._InstanceStartupMemory(instance)
1614 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1615 self.BalloonInstanceMemory(instance, start_memory)
1617 if start_kvm_paused:
1618 # To control CPU pinning, ballooning, and vnc/spice passwords
1619 # the VM was started in a frozen state. If freezing was not
1620 # explicitly requested resume the vm status.
1621 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1623 def StartInstance(self, instance, block_devices, startup_paused):
1624 """Start an instance.
1627 self._CheckDown(instance.name)
1628 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1630 self._SaveKVMRuntime(instance, kvm_runtime)
1631 self._ExecuteKVMRuntime(instance, kvm_runtime)
1633 def _CallMonitorCommand(self, instance_name, command):
1634 """Invoke a command on the instance monitor.
1637 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1638 (utils.ShellQuote(command),
1639 constants.SOCAT_PATH,
1640 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1641 result = utils.RunCmd(socat)
1643 msg = ("Failed to send command '%s' to instance %s."
1644 " output: %s, error: %s, fail_reason: %s" %
1645 (command, instance_name,
1646 result.stdout, result.stderr, result.fail_reason))
1647 raise errors.HypervisorError(msg)
1652 def _ParseKVMVersion(cls, text):
1653 """Parse the KVM version from the --help output.
1656 @param text: output of kvm --help
1657 @return: (version, v_maj, v_min, v_rev)
1658 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1661 match = cls._VERSION_RE.search(text.splitlines()[0])
1663 raise errors.HypervisorError("Unable to get KVM version")
1665 v_all = match.group(0)
1666 v_maj = int(match.group(1))
1667 v_min = int(match.group(2))
1669 v_rev = int(match.group(4))
1672 return (v_all, v_maj, v_min, v_rev)
1675 def _GetKVMHelpOutput(cls):
1676 """Return the KVM help output.
1678 @return: output of kvm --help
1679 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1682 result = utils.RunCmd([constants.KVM_PATH, "--help"])
1684 raise errors.HypervisorError("Unable to get KVM help output")
1685 return result.output
1688 def _GetKVMVersion(cls):
1689 """Return the installed KVM version.
1691 @return: (version, v_maj, v_min, v_rev)
1692 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1695 return cls._ParseKVMVersion(cls._GetKVMHelpOutput())
1697 def StopInstance(self, instance, force=False, retry=False, name=None):
1698 """Stop an instance.
1701 if name is not None and not force:
1702 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1704 name = instance.name
1705 acpi = instance.hvparams[constants.HV_ACPI]
1708 _, pid, alive = self._InstancePidAlive(name)
1709 if pid > 0 and alive:
1710 if force or not acpi:
1711 utils.KillProcess(pid)
1713 self._CallMonitorCommand(name, "system_powerdown")
1716 def _GetDefaultMachineVersion(cls):
1717 """Return the default hardware revision (e.g. pc-1.1)
1720 result = utils.RunCmd([constants.KVM_PATH, "-M", "?"])
1722 raise errors.HypervisorError("Unable to get default hardware revision")
1723 match = cls._DEFAULT_MACHINE_VERSION_RE.search(result.output)
1725 return match.group(1)
1729 def CleanupInstance(self, instance_name):
1730 """Cleanup after a stopped instance
1733 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1734 if pid > 0 and alive:
1735 raise errors.HypervisorError("Cannot cleanup a live instance")
1736 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1738 def RebootInstance(self, instance):
1739 """Reboot an instance.
1742 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1743 # socket the instance will stop, but now power up again. So we'll resort
1744 # to shutdown and restart.
1745 _, _, alive = self._InstancePidAlive(instance.name)
1747 raise errors.HypervisorError("Failed to reboot instance %s:"
1748 " not running" % instance.name)
1749 # StopInstance will delete the saved KVM runtime so:
1750 # ...first load it...
1751 kvm_runtime = self._LoadKVMRuntime(instance)
1752 # ...now we can safely call StopInstance...
1753 if not self.StopInstance(instance):
1754 self.StopInstance(instance, force=True)
1755 # ...and finally we can save it again, and execute it...
1756 self._SaveKVMRuntime(instance, kvm_runtime)
1757 self._ExecuteKVMRuntime(instance, kvm_runtime)
1759 def MigrationInfo(self, instance):
1760 """Get instance information to perform a migration.
1762 @type instance: L{objects.Instance}
1763 @param instance: instance to be migrated
1765 @return: content of the KVM runtime file
1768 return self._ReadKVMRuntime(instance.name)
1770 def AcceptInstance(self, instance, info, target):
1771 """Prepare to accept an instance.
1773 @type instance: L{objects.Instance}
1774 @param instance: instance to be accepted
1776 @param info: content of the KVM runtime file on the source node
1777 @type target: string
1778 @param target: target host (usually ip), on this node
1781 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1782 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1783 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1785 def FinalizeMigrationDst(self, instance, info, success):
1786 """Finalize the instance migration on the target node.
1788 Stop the incoming mode KVM.
1790 @type instance: L{objects.Instance}
1791 @param instance: instance whose migration is being finalized
1795 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1796 kvm_nics = kvm_runtime[1]
1798 for nic_seq, nic in enumerate(kvm_nics):
1799 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1800 # Bridged interfaces have already been configured
1803 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1804 except EnvironmentError, err:
1805 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1806 instance.name, nic_seq, str(err))
1809 self._ConfigureNIC(instance, nic_seq, nic, tap)
1810 except errors.HypervisorError, err:
1811 logging.warning(str(err))
1813 self._WriteKVMRuntime(instance.name, info)
1815 self.StopInstance(instance, force=True)
1817 def MigrateInstance(self, instance, target, live):
1818 """Migrate an instance to a target node.
1820 The migration will not be attempted if the instance is not
1823 @type instance: L{objects.Instance}
1824 @param instance: the instance to be migrated
1825 @type target: string
1826 @param target: ip address of the target node
1828 @param live: perform a live migration
1831 instance_name = instance.name
1832 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1833 _, _, alive = self._InstancePidAlive(instance_name)
1835 raise errors.HypervisorError("Instance not running, cannot migrate")
1838 self._CallMonitorCommand(instance_name, "stop")
1840 migrate_command = ("migrate_set_speed %dm" %
1841 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1842 self._CallMonitorCommand(instance_name, migrate_command)
1844 migrate_command = ("migrate_set_downtime %dms" %
1845 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1846 self._CallMonitorCommand(instance_name, migrate_command)
1848 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1849 self._CallMonitorCommand(instance_name, migrate_command)
1851 def FinalizeMigrationSource(self, instance, success, live):
1852 """Finalize the instance migration on the source node.
1854 @type instance: L{objects.Instance}
1855 @param instance: the instance that was migrated
1857 @param success: whether the migration succeeded or not
1859 @param live: whether the user requested a live migration or not
1863 pidfile, pid, _ = self._InstancePidAlive(instance.name)
1864 utils.KillProcess(pid)
1865 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
1867 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1869 def GetMigrationStatus(self, instance):
1870 """Get the migration status
1872 @type instance: L{objects.Instance}
1873 @param instance: the instance that is being migrated
1874 @rtype: L{objects.MigrationStatus}
1875 @return: the status of the current migration (one of
1876 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1877 progress info that can be retrieved from the hypervisor
1880 info_command = "info migrate"
1881 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1882 result = self._CallMonitorCommand(instance.name, info_command)
1883 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1885 if not result.stdout:
1886 logging.info("KVM: empty 'info migrate' result")
1888 logging.warning("KVM: unknown 'info migrate' result: %s",
1891 status = match.group(1)
1892 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1893 migration_status = objects.MigrationStatus(status=status)
1894 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1896 migration_status.transferred_ram = match.group("transferred")
1897 migration_status.total_ram = match.group("total")
1899 return migration_status
1901 logging.warning("KVM: unknown migration status '%s'", status)
1903 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1905 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1907 def BalloonInstanceMemory(self, instance, mem):
1908 """Balloon an instance memory to a certain value.
1910 @type instance: L{objects.Instance}
1911 @param instance: instance to be accepted
1913 @param mem: actual memory size to use for instance runtime
1916 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1918 def GetNodeInfo(self):
1919 """Return information about the node.
1921 @return: a dict with the following keys (values in MiB):
1922 - memory_total: the total memory size on the node
1923 - memory_free: the available memory on the node for instances
1924 - memory_dom0: the memory used by the node itself, if available
1925 - hv_version: the hypervisor version in the form (major, minor,
1929 result = self.GetLinuxNodeInfo()
1930 _, v_major, v_min, v_rev = self._GetKVMVersion()
1931 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
1935 def GetInstanceConsole(cls, instance, hvparams, beparams):
1936 """Return a command for connecting to the console of an instance.
1939 if hvparams[constants.HV_SERIAL_CONSOLE]:
1940 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
1941 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1942 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1943 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1944 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1945 return objects.InstanceConsole(instance=instance.name,
1946 kind=constants.CONS_SSH,
1947 host=instance.primary_node,
1948 user=constants.SSH_CONSOLE_USER,
1951 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1952 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1953 display = instance.network_port - constants.VNC_BASE_PORT
1954 return objects.InstanceConsole(instance=instance.name,
1955 kind=constants.CONS_VNC,
1956 host=vnc_bind_address,
1957 port=instance.network_port,
1960 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1962 return objects.InstanceConsole(instance=instance.name,
1963 kind=constants.CONS_SPICE,
1965 port=instance.network_port)
1967 return objects.InstanceConsole(instance=instance.name,
1968 kind=constants.CONS_MESSAGE,
1969 message=("No serial shell for instance %s" %
1973 """Verify the hypervisor.
1975 Check that the binary exists.
1978 if not os.path.exists(constants.KVM_PATH):
1979 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1980 if not os.path.exists(constants.SOCAT_PATH):
1981 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1984 def CheckParameterSyntax(cls, hvparams):
1985 """Check the given parameters for validity.
1987 @type hvparams: dict
1988 @param hvparams: dictionary with parameter names/value
1989 @raise errors.HypervisorError: when a parameter is not valid
1992 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1994 kernel_path = hvparams[constants.HV_KERNEL_PATH]
1996 if not hvparams[constants.HV_ROOT_PATH]:
1997 raise errors.HypervisorError("Need a root partition for the instance,"
1998 " if a kernel is defined")
2000 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2001 not hvparams[constants.HV_VNC_X509]):
2002 raise errors.HypervisorError("%s must be defined, if %s is" %
2003 (constants.HV_VNC_X509,
2004 constants.HV_VNC_X509_VERIFY))
2006 if hvparams[constants.HV_SERIAL_CONSOLE]:
2007 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2008 valid_speeds = constants.VALID_SERIAL_SPEEDS
2009 if not serial_speed or serial_speed not in valid_speeds:
2010 raise errors.HypervisorError("Invalid serial console speed, must be"
2012 utils.CommaJoin(valid_speeds))
2014 boot_order = hvparams[constants.HV_BOOT_ORDER]
2015 if (boot_order == constants.HT_BO_CDROM and
2016 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2017 raise errors.HypervisorError("Cannot boot from cdrom without an"
2020 security_model = hvparams[constants.HV_SECURITY_MODEL]
2021 if security_model == constants.HT_SM_USER:
2022 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2023 raise errors.HypervisorError("A security domain (user to run kvm as)"
2024 " must be specified")
2025 elif (security_model == constants.HT_SM_NONE or
2026 security_model == constants.HT_SM_POOL):
2027 if hvparams[constants.HV_SECURITY_DOMAIN]:
2028 raise errors.HypervisorError("Cannot have a security domain when the"
2029 " security model is 'none' or 'pool'")
2031 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2032 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2034 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2035 # if an IP version is specified, the spice_bind parameter must be an
2037 if (netutils.IP4Address.IsValid(spice_bind) and
2038 spice_ip_version != constants.IP4_VERSION):
2039 raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
2040 " the specified IP version is %s" %
2041 (spice_bind, spice_ip_version))
2043 if (netutils.IP6Address.IsValid(spice_bind) and
2044 spice_ip_version != constants.IP6_VERSION):
2045 raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
2046 " the specified IP version is %s" %
2047 (spice_bind, spice_ip_version))
2049 # All the other SPICE parameters depend on spice_bind being set. Raise an
2050 # error if any of them is set without it.
2051 for param in _SPICE_ADDITIONAL_PARAMS:
2053 raise errors.HypervisorError("spice: %s requires %s to be set" %
2054 (param, constants.HV_KVM_SPICE_BIND))
2057 def ValidateParameters(cls, hvparams):
2058 """Check the given parameters for validity.
2060 @type hvparams: dict
2061 @param hvparams: dictionary with parameter names/value
2062 @raise errors.HypervisorError: when a parameter is not valid
2065 super(KVMHypervisor, cls).ValidateParameters(hvparams)
2067 security_model = hvparams[constants.HV_SECURITY_MODEL]
2068 if security_model == constants.HT_SM_USER:
2069 username = hvparams[constants.HV_SECURITY_DOMAIN]
2071 pwd.getpwnam(username)
2073 raise errors.HypervisorError("Unknown security domain user %s"
2076 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2078 # only one of VNC and SPICE can be used currently.
2079 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
2080 raise errors.HypervisorError("both SPICE and VNC are configured, but"
2081 " only one of them can be used at a"
2084 # KVM version should be >= 0.14.0
2085 kvmhelp = cls._GetKVMHelpOutput()
2086 if not cls._SPICE_RE.search(kvmhelp):
2087 raise errors.HypervisorError("spice is configured, but it is not"
2088 " supported according to kvm --help")
2090 # if spice_bind is not an IP address, it must be a valid interface
2091 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
2092 or netutils.IP6Address.IsValid(spice_bind))
2093 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
2094 raise errors.HypervisorError("spice: the %s parameter must be either"
2095 " a valid IP address or interface name" %
2096 constants.HV_KVM_SPICE_BIND)
2099 def PowercycleNode(cls):
2100 """KVM powercycle, just a wrapper over Linux powercycle.
2103 cls.LinuxPowercycle()