4 # Copyright (C) 2008, 2009, 2010, 2011 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
40 import affinity # pylint: disable=F0401
44 from ganeti import utils
45 from ganeti import constants
46 from ganeti import errors
47 from ganeti import serializer
48 from ganeti import objects
49 from ganeti import uidpool
50 from ganeti import ssconf
51 from ganeti.hypervisor import hv_base
52 from ganeti import netutils
53 from ganeti.utils import wrapper as utils_wrapper
56 _KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
57 _KVM_START_PAUSED_FLAG = "-S"
59 # TUN/TAP driver constants, taken from <linux/if_tun.h>
60 # They are architecture-independent and already hardcoded in qemu-kvm source,
61 # so we can safely include them here.
62 TUNSETIFF = 0x400454ca
63 TUNGETIFF = 0x800454d2
64 TUNGETFEATURES = 0x800454cf
70 def _ProbeTapVnetHdr(fd):
71 """Check whether to enable the IFF_VNET_HDR flag.
73 To do this, _all_ of the following conditions must be met:
74 1. TUNGETFEATURES ioctl() *must* be implemented
75 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
76 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
77 drivers/net/tun.c there is no way to test this until after the tap device
78 has been created using TUNSETIFF, and there is no way to change the
79 IFF_VNET_HDR flag after creating the interface, catch-22! However both
80 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
81 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
84 @param fd: the file descriptor of /dev/net/tun
87 req = struct.pack("I", 0)
89 res = fcntl.ioctl(fd, TUNGETFEATURES, req)
90 except EnvironmentError:
91 logging.warning("TUNGETFEATURES ioctl() not implemented")
94 tunflags = struct.unpack("I", res)[0]
95 if tunflags & IFF_VNET_HDR:
98 logging.warning("Host does not support IFF_VNET_HDR, not enabling")
102 def _OpenTap(vnet_hdr=True):
103 """Open a new tap device and return its file descriptor.
105 This is intended to be used by a qemu-type hypervisor together with the -net
106 tap,fd=<fd> command line parameter.
108 @type vnet_hdr: boolean
109 @param vnet_hdr: Enable the VNET Header
110 @return: (ifname, tapfd)
115 tapfd = os.open("/dev/net/tun", os.O_RDWR)
116 except EnvironmentError:
117 raise errors.HypervisorError("Failed to open /dev/net/tun")
119 flags = IFF_TAP | IFF_NO_PI
121 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
122 flags |= IFF_VNET_HDR
124 # The struct ifreq ioctl request (see netdevice(7))
125 ifr = struct.pack("16sh", "", flags)
128 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
129 except EnvironmentError:
130 raise errors.HypervisorError("Failed to allocate a new TAP device")
132 # Get the interface name from the ioctl
133 ifname = struct.unpack("16sh", res)[0].strip("\x00")
134 return (ifname, tapfd)
138 """QEMU Messaging Protocol (QMP) message.
142 def __init__(self, data):
143 """Creates a new QMP message based on the passed data.
146 if not isinstance(data, dict):
147 raise TypeError("QmpMessage must be initialized with a dict")
151 def __getitem__(self, field_name):
152 """Get the value of the required field if present, or None.
154 Overrides the [] operator to provide access to the message data,
155 returning None if the required item is not in the message
156 @return: the value of the field_name field, or None if field_name
157 is not contained in the message
161 if field_name in self.data:
162 return self.data[field_name]
166 def __setitem__(self, field_name, field_value):
167 """Set the value of the required field_name to field_value.
170 self.data[field_name] = field_value
173 def BuildFromJsonString(json_string):
174 """Build a QmpMessage from a JSON encoded string.
176 @type json_string: str
177 @param json_string: JSON string representing the message
178 @rtype: L{QmpMessage}
179 @return: a L{QmpMessage} built from json_string
183 data = serializer.LoadJson(json_string)
184 return QmpMessage(data)
187 # The protocol expects the JSON object to be sent as a single
188 # line, hence the need for indent=False.
189 return serializer.DumpJson(self.data, indent=False)
191 def __eq__(self, other):
192 # When comparing two QmpMessages, we are interested in comparing
193 # their internal representation of the message data
194 return self.data == other.data
198 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
201 _FIRST_MESSAGE_KEY = "QMP"
204 _ERROR_CLASS_KEY = "class"
205 _ERROR_DATA_KEY = "data"
206 _ERROR_DESC_KEY = "desc"
207 _EXECUTE_KEY = "execute"
208 _ARGUMENTS_KEY = "arguments"
209 _CAPABILITIES_COMMAND = "qmp_capabilities"
210 _MESSAGE_END_TOKEN = "\r\n"
213 def __init__(self, monitor_filename):
214 """Instantiates the QmpConnection object.
216 @type monitor_filename: string
217 @param monitor_filename: the filename of the UNIX raw socket on which the
218 QMP monitor is listening
221 self.monitor_filename = monitor_filename
222 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
223 # We want to fail if the server doesn't send a complete message
224 # in a reasonable amount of time
225 self.sock.settimeout(self._SOCKET_TIMEOUT)
226 self._connected = False
229 def _check_connection(self):
230 """Make sure that the connection is established.
233 if not self._connected:
234 raise errors.ProgrammerError("To use a QmpConnection you need to first"
235 " invoke connect() on it")
238 """Connects to the QMP monitor.
240 Connects to the UNIX socket and makes sure that we can actually send and
241 receive data to the kvm instance via QMP.
243 @raise errors.HypervisorError: when there are communication errors
244 @raise errors.ProgrammerError: when there are data serialization errors
247 self.sock.connect(self.monitor_filename)
248 self._connected = True
250 # Check if we receive a correct greeting message from the server
251 # (As per the QEMU Protocol Specification 0.1 - section 2.2)
252 greeting = self._Recv()
253 if not greeting[self._FIRST_MESSAGE_KEY]:
254 self._connected = False
255 raise errors.HypervisorError("kvm: qmp communication error (wrong"
258 # Let's put the monitor in command mode using the qmp_capabilities
259 # command, or else no command will be executable.
260 # (As per the QEMU Protocol Specification 0.1 - section 4)
261 self.Execute(self._CAPABILITIES_COMMAND)
263 def _ParseMessage(self, buf):
264 """Extract and parse a QMP message from the given buffer.
266 Seeks for a QMP message in the given buf. If found, it parses it and
267 returns it together with the rest of the characters in the buf.
268 If no message is found, returns None and the whole buffer.
270 @raise errors.ProgrammerError: when there are data serialization errors
274 # Check if we got the message end token (CRLF, as per the QEMU Protocol
275 # Specification 0.1 - Section 2.1.1)
276 pos = buf.find(self._MESSAGE_END_TOKEN)
279 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
280 except Exception, err:
281 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
284 return (message, buf)
287 """Receives a message from QMP and decodes the received JSON object.
290 @return: the received message
291 @raise errors.HypervisorError: when there are communication errors
292 @raise errors.ProgrammerError: when there are data serialization errors
295 self._check_connection()
297 # Check if there is already a message in the buffer
298 (message, self._buf) = self._ParseMessage(self._buf)
302 recv_buffer = StringIO.StringIO(self._buf)
303 recv_buffer.seek(len(self._buf))
306 data = self.sock.recv(4096)
309 recv_buffer.write(data)
311 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
315 except socket.timeout, err:
316 raise errors.HypervisorError("Timeout while receiving a QMP message: "
318 except socket.error, err:
319 raise errors.HypervisorError("Unable to receive data from KVM using the"
320 " QMP protocol: %s" % err)
322 def _Send(self, message):
323 """Encodes and sends a message to KVM using QMP.
325 @type message: QmpMessage
326 @param message: message to send to KVM
327 @raise errors.HypervisorError: when there are communication errors
328 @raise errors.ProgrammerError: when there are data serialization errors
331 self._check_connection()
333 message_str = str(message)
334 except Exception, err:
335 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
338 self.sock.sendall(message_str)
339 except socket.timeout, err:
340 raise errors.HypervisorError("Timeout while sending a QMP message: "
341 "%s (%s)" % (err.string, err.errno))
342 except socket.error, err:
343 raise errors.HypervisorError("Unable to send data from KVM using the"
344 " QMP protocol: %s" % err)
346 def Execute(self, command, arguments=None):
347 """Executes a QMP command and returns the response of the server.
350 @param command: the command to execute
351 @type arguments: dict
352 @param arguments: dictionary of arguments to be passed to the command
354 @return: dictionary representing the received JSON object
355 @raise errors.HypervisorError: when there are communication errors
356 @raise errors.ProgrammerError: when there are data serialization errors
359 self._check_connection()
360 message = QmpMessage({self._EXECUTE_KEY: command})
362 message[self._ARGUMENTS_KEY] = arguments
365 # Events can occur between the sending of the command and the reception
366 # of the response, so we need to filter out messages with the event key.
368 response = self._Recv()
369 err = response[self._ERROR_KEY]
371 raise errors.HypervisorError("kvm: error executing the %s"
372 " command: %s (%s, %s):" %
374 err[self._ERROR_DESC_KEY],
375 err[self._ERROR_CLASS_KEY],
376 err[self._ERROR_DATA_KEY]))
378 elif not response[self._EVENT_KEY]:
382 class KVMHypervisor(hv_base.BaseHypervisor):
383 """KVM hypervisor interface"""
386 _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
387 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
388 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
389 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
390 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
391 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
392 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
393 # KVM instances with chroot enabled are started in empty chroot directories.
394 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
395 # After an instance is stopped, its chroot directory is removed.
396 # If the chroot directory is not empty, it can't be removed.
397 # A non-empty chroot directory indicates a possible security incident.
398 # To support forensics, the non-empty chroot directory is quarantined in
399 # a separate directory, called 'chroot-quarantine'.
400 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
401 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
402 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR]
405 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
406 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
407 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
408 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
409 constants.HV_ACPI: hv_base.NO_CHECK,
410 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
411 constants.HV_VNC_BIND_ADDRESS:
412 (False, lambda x: (netutils.IP4Address.IsValid(x) or
413 utils.IsNormAbsPath(x)),
414 "the VNC bind address must be either a valid IP address or an absolute"
415 " pathname", None, None),
416 constants.HV_VNC_TLS: hv_base.NO_CHECK,
417 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
418 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
419 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
420 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later
421 constants.HV_KVM_SPICE_IP_VERSION:
422 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
423 x in constants.VALID_IP_VERSIONS),
424 "the SPICE IP version should be 4 or 6",
426 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
427 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
428 hv_base.ParamInSet(False,
429 constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
430 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
431 hv_base.ParamInSet(False,
432 constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
433 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
434 hv_base.ParamInSet(False,
435 constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
436 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
437 hv_base.ParamInSet(False,
438 constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
439 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
440 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
441 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
442 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
443 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
444 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
445 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
446 constants.HV_BOOT_ORDER:
447 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
448 constants.HV_NIC_TYPE:
449 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
450 constants.HV_DISK_TYPE:
451 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
452 constants.HV_KVM_CDROM_DISK_TYPE:
453 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
454 constants.HV_USB_MOUSE:
455 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
456 constants.HV_KEYMAP: hv_base.NO_CHECK,
457 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
458 constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
459 constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
460 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
461 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
462 constants.HV_DISK_CACHE:
463 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
464 constants.HV_SECURITY_MODEL:
465 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
466 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
467 constants.HV_KVM_FLAG:
468 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
469 constants.HV_VHOST_NET: hv_base.NO_CHECK,
470 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
471 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
472 constants.HV_REBOOT_BEHAVIOR:
473 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
474 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
477 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
479 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
480 _MIGRATION_INFO_RETRY_DELAY = 2
482 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)\.(\d+)\b")
484 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
485 _CPU_INFO_CMD = "info cpus"
493 hv_base.BaseHypervisor.__init__(self)
494 # Let's make sure the directories we need exist, even if the RUN_DIR lives
495 # in a tmpfs filesystem or has been otherwise wiped out.
496 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
497 utils.EnsureDirs(dirs)
500 def _InstancePidFile(cls, instance_name):
501 """Returns the instance pidfile.
504 return utils.PathJoin(cls._PIDS_DIR, instance_name)
507 def _InstanceUidFile(cls, instance_name):
508 """Returns the instance uidfile.
511 return utils.PathJoin(cls._UIDS_DIR, instance_name)
514 def _InstancePidInfo(cls, pid):
515 """Check pid file for instance information.
517 Check that a pid file is associated with an instance, and retrieve
518 information from its command line.
520 @type pid: string or int
521 @param pid: process id of the instance to check
523 @return: (instance_name, memory, vcpus)
524 @raise errors.HypervisorError: when an instance cannot be found
527 alive = utils.IsProcessAlive(pid)
529 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
531 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
533 cmdline = utils.ReadFile(cmdline_file)
534 except EnvironmentError, err:
535 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
542 arg_list = cmdline.split("\x00")
544 arg = arg_list.pop(0)
546 instance = arg_list.pop(0)
548 memory = int(arg_list.pop(0))
550 vcpus = int(arg_list.pop(0))
553 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
556 return (instance, memory, vcpus)
558 def _InstancePidAlive(self, instance_name):
559 """Returns the instance pidfile, pid, and liveness.
561 @type instance_name: string
562 @param instance_name: instance name
564 @return: (pid file name, pid, liveness)
567 pidfile = self._InstancePidFile(instance_name)
568 pid = utils.ReadPidFile(pidfile)
572 cmd_instance = self._InstancePidInfo(pid)[0]
573 alive = (cmd_instance == instance_name)
574 except errors.HypervisorError:
577 return (pidfile, pid, alive)
579 def _CheckDown(self, instance_name):
580 """Raises an error unless the given instance is down.
583 alive = self._InstancePidAlive(instance_name)[2]
585 raise errors.HypervisorError("Failed to start instance %s: %s" %
586 (instance_name, "already running"))
589 def _InstanceMonitor(cls, instance_name):
590 """Returns the instance monitor socket name
593 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
596 def _InstanceSerial(cls, instance_name):
597 """Returns the instance serial socket name
600 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
603 def _InstanceQmpMonitor(cls, instance_name):
604 """Returns the instance serial QMP socket name
607 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
610 def _SocatUnixConsoleParams():
611 """Returns the correct parameters for socat
613 If we have a new-enough socat we can use raw mode with an escape character.
616 if constants.SOCAT_USE_ESCAPE:
617 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
619 return "echo=0,icanon=0"
622 def _InstanceKVMRuntime(cls, instance_name):
623 """Returns the instance KVM runtime filename
626 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
629 def _InstanceChrootDir(cls, instance_name):
630 """Returns the name of the KVM chroot dir of the instance
633 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
636 def _InstanceNICDir(cls, instance_name):
637 """Returns the name of the directory holding the tap device files for a
641 return utils.PathJoin(cls._NICS_DIR, instance_name)
644 def _InstanceNICFile(cls, instance_name, seq):
645 """Returns the name of the file containing the tap device for a given NIC
648 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
651 def _InstanceKeymapFile(cls, instance_name):
652 """Returns the name of the file containing the keymap for a given instance
655 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
658 def _TryReadUidFile(cls, uid_file):
659 """Try to read a uid file
662 if os.path.exists(uid_file):
664 uid = int(utils.ReadOneLineFile(uid_file))
666 except EnvironmentError:
667 logging.warning("Can't read uid file", exc_info=True)
668 except (TypeError, ValueError):
669 logging.warning("Can't parse uid file contents", exc_info=True)
673 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
674 """Removes an instance's rutime sockets/files/dirs.
677 utils.RemoveFile(pidfile)
678 utils.RemoveFile(cls._InstanceMonitor(instance_name))
679 utils.RemoveFile(cls._InstanceSerial(instance_name))
680 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
681 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
682 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
683 uid_file = cls._InstanceUidFile(instance_name)
684 uid = cls._TryReadUidFile(uid_file)
685 utils.RemoveFile(uid_file)
687 uidpool.ReleaseUid(uid)
689 shutil.rmtree(cls._InstanceNICDir(instance_name))
691 if err.errno != errno.ENOENT:
694 chroot_dir = cls._InstanceChrootDir(instance_name)
695 utils.RemoveDir(chroot_dir)
697 if err.errno == errno.ENOTEMPTY:
698 # The chroot directory is expected to be empty, but it isn't.
699 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
702 utils.TimestampForFilename()))
703 logging.warning("The chroot directory of instance %s can not be"
704 " removed as it is not empty. Moving it to the"
705 " quarantine instead. Please investigate the"
706 " contents (%s) and clean up manually",
707 instance_name, new_chroot_dir)
708 utils.RenameFile(chroot_dir, new_chroot_dir)
713 def _ConfigureNIC(instance, seq, nic, tap):
714 """Run the network configuration script for a specified NIC
716 @param instance: instance we're acting on
717 @type instance: instance object
718 @param seq: nic sequence number
720 @param nic: nic we're acting on
721 @type nic: nic object
722 @param tap: the host's tap interface this NIC corresponds to
728 tags = " ".join(instance.tags)
733 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
734 "INSTANCE": instance.name,
736 "MODE": nic.nicparams[constants.NIC_MODE],
738 "INTERFACE_INDEX": str(seq),
745 if nic.nicparams[constants.NIC_LINK]:
746 env["LINK"] = nic.nicparams[constants.NIC_LINK]
748 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
749 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
751 result = utils.RunCmd([constants.KVM_IFUP, tap], env=env)
753 raise errors.HypervisorError("Failed to configure interface %s: %s."
754 " Network configuration script output: %s" %
755 (tap, result.fail_reason, result.output))
758 def _VerifyAffinityPackage():
760 raise errors.HypervisorError("affinity Python package not"
761 " found; cannot use CPU pinning under KVM")
764 def _BuildAffinityCpuMask(cpu_list):
765 """Create a CPU mask suitable for sched_setaffinity from a list of
768 See man taskset for more info on sched_setaffinity masks.
769 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
771 @type cpu_list: list of int
772 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
774 @return: a bit mask of CPU affinities
777 if cpu_list == constants.CPU_PINNING_OFF:
778 return constants.CPU_PINNING_ALL_KVM
780 return sum(2 ** cpu for cpu in cpu_list)
783 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
784 """Change CPU affinity for running VM according to given CPU mask.
786 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
787 @type cpu_mask: string
788 @param process_id: process ID of KVM process. Used to pin entire VM
790 @type process_id: int
791 @param thread_dict: map of virtual CPUs to KVM thread IDs
792 @type thread_dict: dict int:int
796 # Convert the string CPU mask to a list of list of int's
797 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
799 if len(cpu_list) == 1:
800 all_cpu_mapping = cpu_list[0]
801 if all_cpu_mapping == constants.CPU_PINNING_OFF:
802 # If CPU pinning has 1 entry that's "all", then do nothing
805 # If CPU pinning has one non-all entry, map the entire VM to
806 # one set of physical CPUs
807 cls._VerifyAffinityPackage()
808 affinity.set_process_affinity_mask(process_id,
809 cls._BuildAffinityCpuMask(all_cpu_mapping))
811 # The number of vCPUs mapped should match the number of vCPUs
812 # reported by KVM. This was already verified earlier, so
813 # here only as a sanity check.
814 assert len(thread_dict) == len(cpu_list)
815 cls._VerifyAffinityPackage()
817 # For each vCPU, map it to the proper list of physical CPUs
818 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
819 affinity.set_process_affinity_mask(thread_dict[i],
820 cls._BuildAffinityCpuMask(vcpu))
822 def _GetVcpuThreadIds(self, instance_name):
823 """Get a mapping of vCPU no. to thread IDs for the instance
825 @type instance_name: string
826 @param instance_name: instance in question
827 @rtype: dictionary of int:int
828 @return: a dictionary mapping vCPU numbers to thread IDs
832 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
833 for line in output.stdout.splitlines():
834 match = self._CPU_INFO_RE.search(line)
837 grp = map(int, match.groups())
838 result[grp[0]] = grp[1]
842 def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
843 """Complete CPU pinning.
845 @type instance_name: string
846 @param instance_name: name of instance
847 @type cpu_mask: string
848 @param cpu_mask: CPU pinning mask as entered by user
851 # Get KVM process ID, to be used if need to pin entire VM
852 _, pid, _ = self._InstancePidAlive(instance_name)
853 # Get vCPU thread IDs, to be used if need to pin vCPUs separately
854 thread_dict = self._GetVcpuThreadIds(instance_name)
855 # Run CPU pinning, based on configured mask
856 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
858 def ListInstances(self):
859 """Get the list of running instances.
861 We can do this by listing our live instances directory and
862 checking whether the associated kvm process is still alive.
866 for name in os.listdir(self._PIDS_DIR):
867 if self._InstancePidAlive(name)[2]:
871 def GetInstanceInfo(self, instance_name):
872 """Get instance properties.
874 @type instance_name: string
875 @param instance_name: the instance name
876 @rtype: tuple of strings
877 @return: (name, id, memory, vcpus, stat, times)
880 _, pid, alive = self._InstancePidAlive(instance_name)
884 _, memory, vcpus = self._InstancePidInfo(pid)
888 return (instance_name, pid, memory, vcpus, stat, times)
890 def GetAllInstancesInfo(self):
891 """Get properties of all instances.
893 @return: list of tuples (name, id, memory, vcpus, stat, times)
897 for name in os.listdir(self._PIDS_DIR):
899 info = self.GetInstanceInfo(name)
900 except errors.HypervisorError:
906 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
907 """Generate KVM information to start an instance.
910 # pylint: disable=R0914,R0915
911 _, v_major, v_min, _ = self._GetKVMVersion()
913 pidfile = self._InstancePidFile(instance.name)
914 kvm = constants.KVM_PATH
916 # used just by the vnc server, if enabled
917 kvm_cmd.extend(["-name", instance.name])
918 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MEMORY]])
919 kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
920 kvm_cmd.extend(["-pidfile", pidfile])
921 kvm_cmd.extend(["-daemonize"])
922 if not instance.hvparams[constants.HV_ACPI]:
923 kvm_cmd.extend(["-no-acpi"])
924 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
925 constants.INSTANCE_REBOOT_EXIT:
926 kvm_cmd.extend(["-no-reboot"])
928 hvp = instance.hvparams
929 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
930 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
931 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
932 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
934 self.ValidateParameters(hvp)
937 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
939 if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
940 kvm_cmd.extend(["-enable-kvm"])
941 elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
942 kvm_cmd.extend(["-disable-kvm"])
945 kvm_cmd.extend(["-boot", "n"])
947 disk_type = hvp[constants.HV_DISK_TYPE]
948 if disk_type == constants.HT_DISK_PARAVIRTUAL:
949 if_val = ",if=virtio"
951 if_val = ",if=%s" % disk_type
953 disk_cache = hvp[constants.HV_DISK_CACHE]
954 if instance.disk_template in constants.DTS_EXT_MIRROR:
955 if disk_cache != "none":
956 # TODO: make this a hard error, instead of a silent overwrite
957 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
958 " to prevent shared storage corruption on migration",
960 cache_val = ",cache=none"
961 elif disk_cache != constants.HT_CACHE_DEFAULT:
962 cache_val = ",cache=%s" % disk_cache
965 for cfdev, dev_path in block_devices:
966 if cfdev.mode != constants.DISK_RDWR:
967 raise errors.HypervisorError("Instance has read-only disks which"
968 " are not supported by KVM")
969 # TODO: handle FD_LOOP and FD_BLKTAP (?)
972 kvm_cmd.extend(["-boot", "c"])
974 if (v_major, v_min) < (0, 14) and disk_type != constants.HT_DISK_IDE:
975 boot_val = ",boot=on"
977 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
979 kvm_cmd.extend(["-drive", drive_val])
981 #Now we can specify a different device type for CDROM devices.
982 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
983 if not cdrom_disk_type:
984 cdrom_disk_type = disk_type
986 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
988 options = ",format=raw,media=cdrom"
990 kvm_cmd.extend(["-boot", "d"])
991 if cdrom_disk_type != constants.HT_DISK_IDE:
992 options = "%s,boot=on,if=%s" % (options, constants.HT_DISK_IDE)
994 options = "%s,boot=on" % options
996 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
997 if_val = ",if=virtio"
999 if_val = ",if=%s" % cdrom_disk_type
1000 options = "%s%s" % (options, if_val)
1001 drive_val = "file=%s%s" % (iso_image, options)
1002 kvm_cmd.extend(["-drive", drive_val])
1004 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1006 options = ",format=raw,media=cdrom"
1007 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1008 if_val = ",if=virtio"
1010 if_val = ",if=%s" % cdrom_disk_type
1011 options = "%s%s" % (options, if_val)
1012 drive_val = "file=%s%s" % (iso_image2, options)
1013 kvm_cmd.extend(["-drive", drive_val])
1015 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1017 options = ",format=raw,media=disk"
1019 kvm_cmd.extend(["-boot", "a"])
1020 options = "%s,boot=on" % options
1021 if_val = ",if=floppy"
1022 options = "%s%s" % (options, if_val)
1023 drive_val = "file=%s%s" % (floppy_image, options)
1024 kvm_cmd.extend(["-drive", drive_val])
1026 kernel_path = hvp[constants.HV_KERNEL_PATH]
1028 kvm_cmd.extend(["-kernel", kernel_path])
1029 initrd_path = hvp[constants.HV_INITRD_PATH]
1031 kvm_cmd.extend(["-initrd", initrd_path])
1032 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1033 hvp[constants.HV_KERNEL_ARGS]]
1034 if hvp[constants.HV_SERIAL_CONSOLE]:
1035 root_append.append("console=ttyS0,38400")
1036 kvm_cmd.extend(["-append", " ".join(root_append)])
1038 mem_path = hvp[constants.HV_MEM_PATH]
1040 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1042 mouse_type = hvp[constants.HV_USB_MOUSE]
1043 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1046 kvm_cmd.extend(["-usb"])
1047 kvm_cmd.extend(["-usbdevice", mouse_type])
1048 elif vnc_bind_address:
1049 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1051 keymap = hvp[constants.HV_KEYMAP]
1053 keymap_path = self._InstanceKeymapFile(instance.name)
1054 # If a keymap file is specified, KVM won't use its internal defaults. By
1055 # first including the "en-us" layout, an error on loading the actual
1056 # layout (e.g. because it can't be found) won't lead to a non-functional
1057 # keyboard. A keyboard with incorrect keys is still better than none.
1058 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1059 kvm_cmd.extend(["-k", keymap_path])
1061 if vnc_bind_address:
1062 if netutils.IP4Address.IsValid(vnc_bind_address):
1063 if instance.network_port > constants.VNC_BASE_PORT:
1064 display = instance.network_port - constants.VNC_BASE_PORT
1065 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1066 vnc_arg = ":%d" % (display)
1068 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1070 logging.error("Network port is not a valid VNC display (%d < %d)."
1071 " Not starting VNC", instance.network_port,
1072 constants.VNC_BASE_PORT)
1075 # Only allow tls and other option when not binding to a file, for now.
1076 # kvm/qemu gets confused otherwise about the filename to use.
1078 if hvp[constants.HV_VNC_TLS]:
1079 vnc_append = "%s,tls" % vnc_append
1080 if hvp[constants.HV_VNC_X509_VERIFY]:
1081 vnc_append = "%s,x509verify=%s" % (vnc_append,
1082 hvp[constants.HV_VNC_X509])
1083 elif hvp[constants.HV_VNC_X509]:
1084 vnc_append = "%s,x509=%s" % (vnc_append,
1085 hvp[constants.HV_VNC_X509])
1086 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1087 vnc_append = "%s,password" % vnc_append
1089 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1092 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1094 kvm_cmd.extend(["-vnc", vnc_arg])
1096 kvm_cmd.extend(["-nographic"])
1098 monitor_dev = ("unix:%s,server,nowait" %
1099 self._InstanceMonitor(instance.name))
1100 kvm_cmd.extend(["-monitor", monitor_dev])
1101 if hvp[constants.HV_SERIAL_CONSOLE]:
1102 serial_dev = ("unix:%s,server,nowait" %
1103 self._InstanceSerial(instance.name))
1104 kvm_cmd.extend(["-serial", serial_dev])
1106 kvm_cmd.extend(["-serial", "none"])
1108 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1109 spice_ip_version = None
1111 if netutils.IsValidInterface(spice_bind):
1112 # The user specified a network interface, we have to figure out the IP
1114 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1115 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1117 # if the user specified an IP version and the interface does not
1118 # have that kind of IP addresses, throw an exception
1119 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1120 if not addresses[spice_ip_version]:
1121 raise errors.HypervisorError("spice: unable to get an IPv%s address"
1122 " for %s" % (spice_ip_version,
1125 # the user did not specify an IP version, we have to figure it out
1126 elif (addresses[constants.IP4_VERSION] and
1127 addresses[constants.IP6_VERSION]):
1128 # we have both ipv4 and ipv6, let's use the cluster default IP
1130 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1131 spice_ip_version = netutils.IPAddress.GetVersionFromAddressFamily(
1133 elif addresses[constants.IP4_VERSION]:
1134 spice_ip_version = constants.IP4_VERSION
1135 elif addresses[constants.IP6_VERSION]:
1136 spice_ip_version = constants.IP6_VERSION
1138 raise errors.HypervisorError("spice: unable to get an IP address"
1139 " for %s" % (spice_bind))
1141 spice_address = addresses[spice_ip_version][0]
1144 # spice_bind is known to be a valid IP address, because
1145 # ValidateParameters checked it.
1146 spice_address = spice_bind
1148 spice_arg = "addr=%s" % spice_address
1149 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1150 spice_arg = "%s,tls-port=%s,x509-cacert-file=%s" % (spice_arg,
1151 instance.network_port, constants.SPICE_CACERT_FILE)
1152 spice_arg = "%s,x509-key-file=%s,x509-cert-file=%s" % (spice_arg,
1153 constants.SPICE_CERT_FILE, constants.SPICE_CERT_FILE)
1154 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1156 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1158 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1160 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1161 spice_arg = "%s,disable-ticketing" % spice_arg
1163 if spice_ip_version:
1164 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1166 # Image compression options
1167 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1168 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1169 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1171 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1173 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1175 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1177 # Video stream detection
1178 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1180 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1182 # Audio compression, by default in qemu-kvm it is on
1183 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1184 spice_arg = "%s,playback-compression=off" % spice_arg
1185 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1186 spice_arg = "%s,agent-mouse=off" % spice_arg
1188 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1189 kvm_cmd.extend(["-spice", spice_arg])
1191 # Tell kvm to use the paravirtualized graphic card, optimized for SPICE
1192 kvm_cmd.extend(["-vga", "qxl"])
1194 if hvp[constants.HV_USE_LOCALTIME]:
1195 kvm_cmd.extend(["-localtime"])
1197 if hvp[constants.HV_KVM_USE_CHROOT]:
1198 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1200 # Save the current instance nics, but defer their expansion as parameters,
1201 # as we'll need to generate executable temp files for them.
1202 kvm_nics = instance.nics
1205 return (kvm_cmd, kvm_nics, hvparams)
1207 def _WriteKVMRuntime(self, instance_name, data):
1208 """Write an instance's KVM runtime
1212 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1214 except EnvironmentError, err:
1215 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1217 def _ReadKVMRuntime(self, instance_name):
1218 """Read an instance's KVM runtime
1222 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1223 except EnvironmentError, err:
1224 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1227 def _SaveKVMRuntime(self, instance, kvm_runtime):
1228 """Save an instance's KVM runtime
1231 kvm_cmd, kvm_nics, hvparams = kvm_runtime
1232 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1233 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1234 self._WriteKVMRuntime(instance.name, serialized_form)
1236 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1237 """Load an instance's KVM runtime
1240 if not serialized_runtime:
1241 serialized_runtime = self._ReadKVMRuntime(instance.name)
1242 loaded_runtime = serializer.Load(serialized_runtime)
1243 kvm_cmd, serialized_nics, hvparams = loaded_runtime
1244 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1245 return (kvm_cmd, kvm_nics, hvparams)
1247 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1248 """Run the KVM cmd and check for errors
1251 @param name: instance name
1252 @type kvm_cmd: list of strings
1253 @param kvm_cmd: runcmd input for kvm
1254 @type tap_fds: list of int
1255 @param tap_fds: fds of tap devices opened by Ganeti
1259 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1262 utils_wrapper.CloseFdNoError(fd)
1265 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1266 (name, result.fail_reason, result.output))
1267 if not self._InstancePidAlive(name)[2]:
1268 raise errors.HypervisorError("Failed to start instance %s" % name)
1270 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
1271 """Execute a KVM cmd, after completing it with some last minute data
1273 @type incoming: tuple of strings
1274 @param incoming: (target_host_ip, port)
1277 # Small _ExecuteKVMRuntime hv parameters programming howto:
1278 # - conf_hvp contains the parameters as configured on ganeti. they might
1279 # have changed since the instance started; only use them if the change
1280 # won't affect the inside of the instance (which hasn't been rebooted).
1281 # - up_hvp contains the parameters as they were when the instance was
1282 # started, plus any new parameter which has been added between ganeti
1283 # versions: it is paramount that those default to a value which won't
1284 # affect the inside of the instance as well.
1285 conf_hvp = instance.hvparams
1286 name = instance.name
1287 self._CheckDown(name)
1291 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1292 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1294 _, v_major, v_min, _ = self._GetKVMVersion()
1296 # We know it's safe to run as a different user upon migration, so we'll use
1297 # the latest conf, from conf_hvp.
1298 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1299 if security_model == constants.HT_SM_USER:
1300 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1302 # We have reasons to believe changing something like the nic driver/type
1303 # upon migration won't exactly fly with the instance kernel, so for nic
1304 # related parameters we'll use up_hvp
1308 kvm_cmd.extend(["-net", "none"])
1312 nic_type = up_hvp[constants.HV_NIC_TYPE]
1313 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1314 # From version 0.12.0, kvm uses a new sintax for network configuration.
1315 if (v_major, v_min) >= (0, 12):
1316 nic_model = "virtio-net-pci"
1319 nic_model = "virtio"
1321 if up_hvp[constants.HV_VHOST_NET]:
1322 # vhost_net is only available from version 0.13.0 or newer
1323 if (v_major, v_min) >= (0, 13):
1324 tap_extra = ",vhost=on"
1326 raise errors.HypervisorError("vhost_net is configured"
1327 " but it is not available")
1329 nic_model = nic_type
1331 for nic_seq, nic in enumerate(kvm_nics):
1332 tapname, tapfd = _OpenTap(vnet_hdr)
1333 tapfds.append(tapfd)
1334 taps.append(tapname)
1335 if (v_major, v_min) >= (0, 12):
1336 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1337 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1338 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1340 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1342 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1343 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1346 target, port = incoming
1347 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1349 # Changing the vnc password doesn't bother the guest that much. At most it
1350 # will surprise people who connect to it. Whether positively or negatively
1352 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1356 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1357 except EnvironmentError, err:
1358 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1359 % (vnc_pwd_file, err))
1361 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1362 utils.EnsureDirs([(self._InstanceChrootDir(name),
1363 constants.SECURE_DIR_MODE)])
1365 # Automatically enable QMP if version is >= 0.14
1366 if (v_major, v_min) >= (0, 14):
1367 logging.debug("Enabling QMP")
1368 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1369 self._InstanceQmpMonitor(instance.name)])
1371 # Configure the network now for starting instances and bridged interfaces,
1372 # during FinalizeMigration for incoming instances' routed interfaces
1373 for nic_seq, nic in enumerate(kvm_nics):
1375 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1377 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1379 # CPU affinity requires kvm to start paused, so we set this flag if the
1380 # instance is not already paused and if we are not going to accept a
1381 # migrating instance. In the latter case, pausing is not needed.
1382 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1384 # Note: CPU pinning is using up_hvp since changes take effect
1385 # during instance startup anyway, and to avoid problems when soft
1386 # rebooting the instance.
1388 if up_hvp.get(constants.HV_CPU_MASK, None):
1390 if start_kvm_paused:
1391 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1393 if security_model == constants.HT_SM_POOL:
1394 ss = ssconf.SimpleStore()
1395 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1396 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1397 uid = uidpool.RequestUnusedUid(all_uids)
1399 username = pwd.getpwuid(uid.GetUid()).pw_name
1400 kvm_cmd.extend(["-runas", username])
1401 self._RunKVMCmd(name, kvm_cmd, tapfds)
1403 uidpool.ReleaseUid(uid)
1407 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1409 self._RunKVMCmd(name, kvm_cmd, tapfds)
1411 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1412 constants.RUN_DIRS_MODE)])
1413 for nic_seq, tap in enumerate(taps):
1414 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1418 change_cmd = "change vnc password %s" % vnc_pwd
1419 self._CallMonitorCommand(instance.name, change_cmd)
1421 # Setting SPICE password. We are not vulnerable to malicious passwordless
1422 # connection attempts because SPICE by default does not allow connections
1423 # if neither a password nor the "disable_ticketing" options are specified.
1424 # As soon as we send the password via QMP, that password is a valid ticket
1426 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1427 if spice_password_file:
1429 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1430 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1433 "protocol": "spice",
1434 "password": spice_pwd,
1436 qmp.Execute("set_password", arguments)
1437 except EnvironmentError, err:
1438 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1439 % (spice_password_file, err))
1441 for filename in temp_files:
1442 utils.RemoveFile(filename)
1444 # If requested, set CPU affinity and resume instance execution
1447 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1449 if start_kvm_paused:
1450 # To control CPU pinning, the VM was started frozen, so we need
1451 # to resume its execution, but only if freezing was not
1452 # explicitly requested.
1453 # Note: this is done even when an exception occurred so the VM
1454 # is not unintentionally frozen.
1455 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1457 def StartInstance(self, instance, block_devices, startup_paused):
1458 """Start an instance.
1461 self._CheckDown(instance.name)
1462 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1464 self._SaveKVMRuntime(instance, kvm_runtime)
1465 self._ExecuteKVMRuntime(instance, kvm_runtime)
1467 def _CallMonitorCommand(self, instance_name, command):
1468 """Invoke a command on the instance monitor.
1471 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1472 (utils.ShellQuote(command),
1473 constants.SOCAT_PATH,
1474 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1475 result = utils.RunCmd(socat)
1477 msg = ("Failed to send command '%s' to instance %s."
1478 " output: %s, error: %s, fail_reason: %s" %
1479 (command, instance_name,
1480 result.stdout, result.stderr, result.fail_reason))
1481 raise errors.HypervisorError(msg)
1486 def _GetKVMVersion(cls):
1487 """Return the installed KVM version.
1489 @return: (version, v_maj, v_min, v_rev)
1490 @raise L{errors.HypervisorError}: when the KVM version cannot be retrieved
1493 result = utils.RunCmd([constants.KVM_PATH, "--help"])
1495 raise errors.HypervisorError("Unable to get KVM version")
1496 match = cls._VERSION_RE.search(result.output.splitlines()[0])
1498 raise errors.HypervisorError("Unable to get KVM version")
1500 return (match.group(0), int(match.group(1)), int(match.group(2)),
1501 int(match.group(3)))
1503 def StopInstance(self, instance, force=False, retry=False, name=None):
1504 """Stop an instance.
1507 if name is not None and not force:
1508 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1510 name = instance.name
1511 acpi = instance.hvparams[constants.HV_ACPI]
1514 _, pid, alive = self._InstancePidAlive(name)
1515 if pid > 0 and alive:
1516 if force or not acpi:
1517 utils.KillProcess(pid)
1519 self._CallMonitorCommand(name, "system_powerdown")
1521 def CleanupInstance(self, instance_name):
1522 """Cleanup after a stopped instance
1525 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1526 if pid > 0 and alive:
1527 raise errors.HypervisorError("Cannot cleanup a live instance")
1528 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1530 def RebootInstance(self, instance):
1531 """Reboot an instance.
1534 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1535 # socket the instance will stop, but now power up again. So we'll resort
1536 # to shutdown and restart.
1537 _, _, alive = self._InstancePidAlive(instance.name)
1539 raise errors.HypervisorError("Failed to reboot instance %s:"
1540 " not running" % instance.name)
1541 # StopInstance will delete the saved KVM runtime so:
1542 # ...first load it...
1543 kvm_runtime = self._LoadKVMRuntime(instance)
1544 # ...now we can safely call StopInstance...
1545 if not self.StopInstance(instance):
1546 self.StopInstance(instance, force=True)
1547 # ...and finally we can save it again, and execute it...
1548 self._SaveKVMRuntime(instance, kvm_runtime)
1549 self._ExecuteKVMRuntime(instance, kvm_runtime)
1551 def MigrationInfo(self, instance):
1552 """Get instance information to perform a migration.
1554 @type instance: L{objects.Instance}
1555 @param instance: instance to be migrated
1557 @return: content of the KVM runtime file
1560 return self._ReadKVMRuntime(instance.name)
1562 def AcceptInstance(self, instance, info, target):
1563 """Prepare to accept an instance.
1565 @type instance: L{objects.Instance}
1566 @param instance: instance to be accepted
1568 @param info: content of the KVM runtime file on the source node
1569 @type target: string
1570 @param target: target host (usually ip), on this node
1573 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1574 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1575 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1577 def FinalizeMigration(self, instance, info, success):
1578 """Finalize an instance migration.
1580 Stop the incoming mode KVM.
1582 @type instance: L{objects.Instance}
1583 @param instance: instance whose migration is being finalized
1587 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1588 kvm_nics = kvm_runtime[1]
1590 for nic_seq, nic in enumerate(kvm_nics):
1591 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1592 # Bridged interfaces have already been configured
1595 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1596 except EnvironmentError, err:
1597 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1598 instance.name, nic_seq, str(err))
1601 self._ConfigureNIC(instance, nic_seq, nic, tap)
1602 except errors.HypervisorError, err:
1603 logging.warning(str(err))
1605 self._WriteKVMRuntime(instance.name, info)
1607 self.StopInstance(instance, force=True)
1609 def MigrateInstance(self, instance, target, live):
1610 """Migrate an instance to a target node.
1612 The migration will not be attempted if the instance is not
1615 @type instance: L{objects.Instance}
1616 @param instance: the instance to be migrated
1617 @type target: string
1618 @param target: ip address of the target node
1620 @param live: perform a live migration
1623 instance_name = instance.name
1624 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1625 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1627 raise errors.HypervisorError("Instance not running, cannot migrate")
1630 self._CallMonitorCommand(instance_name, "stop")
1632 migrate_command = ("migrate_set_speed %dm" %
1633 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1634 self._CallMonitorCommand(instance_name, migrate_command)
1636 migrate_command = ("migrate_set_downtime %dms" %
1637 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1638 self._CallMonitorCommand(instance_name, migrate_command)
1640 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1641 self._CallMonitorCommand(instance_name, migrate_command)
1643 info_command = "info migrate"
1647 result = self._CallMonitorCommand(instance_name, info_command)
1648 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1651 if not result.stdout:
1652 logging.info("KVM: empty 'info migrate' result")
1654 logging.warning("KVM: unknown 'info migrate' result: %s",
1656 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1658 status = match.group(1)
1659 if status == "completed":
1661 elif status == "active":
1662 # reset the broken answers count
1664 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1665 elif status == "failed" or status == "cancelled":
1667 self._CallMonitorCommand(instance_name, self._CONT_CMD)
1668 raise errors.HypervisorError("Migration %s at the kvm level" %
1671 logging.warning("KVM: unknown migration status '%s'", status)
1673 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1674 if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
1675 raise errors.HypervisorError("Too many 'info migrate' broken answers")
1677 utils.KillProcess(pid)
1678 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1680 def GetNodeInfo(self):
1681 """Return information about the node.
1683 This is just a wrapper over the base GetLinuxNodeInfo method.
1685 @return: a dict with the following keys (values in MiB):
1686 - memory_total: the total memory size on the node
1687 - memory_free: the available memory on the node for instances
1688 - memory_dom0: the memory used by the node itself, if available
1691 return self.GetLinuxNodeInfo()
1694 def GetInstanceConsole(cls, instance, hvparams, beparams):
1695 """Return a command for connecting to the console of an instance.
1698 if hvparams[constants.HV_SERIAL_CONSOLE]:
1699 cmd = [constants.KVM_CONSOLE_WRAPPER,
1700 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1701 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1702 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1703 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1704 return objects.InstanceConsole(instance=instance.name,
1705 kind=constants.CONS_SSH,
1706 host=instance.primary_node,
1707 user=constants.GANETI_RUNAS,
1710 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1711 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1712 display = instance.network_port - constants.VNC_BASE_PORT
1713 return objects.InstanceConsole(instance=instance.name,
1714 kind=constants.CONS_VNC,
1715 host=vnc_bind_address,
1716 port=instance.network_port,
1719 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1721 return objects.InstanceConsole(instance=instance.name,
1722 kind=constants.CONS_SPICE,
1724 port=instance.network_port)
1726 return objects.InstanceConsole(instance=instance.name,
1727 kind=constants.CONS_MESSAGE,
1728 message=("No serial shell for instance %s" %
1732 """Verify the hypervisor.
1734 Check that the binary exists.
1737 if not os.path.exists(constants.KVM_PATH):
1738 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1739 if not os.path.exists(constants.SOCAT_PATH):
1740 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1743 def CheckParameterSyntax(cls, hvparams):
1744 """Check the given parameters for validity.
1746 @type hvparams: dict
1747 @param hvparams: dictionary with parameter names/value
1748 @raise errors.HypervisorError: when a parameter is not valid
1751 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1753 kernel_path = hvparams[constants.HV_KERNEL_PATH]
1755 if not hvparams[constants.HV_ROOT_PATH]:
1756 raise errors.HypervisorError("Need a root partition for the instance,"
1757 " if a kernel is defined")
1759 if (hvparams[constants.HV_VNC_X509_VERIFY] and
1760 not hvparams[constants.HV_VNC_X509]):
1761 raise errors.HypervisorError("%s must be defined, if %s is" %
1762 (constants.HV_VNC_X509,
1763 constants.HV_VNC_X509_VERIFY))
1765 boot_order = hvparams[constants.HV_BOOT_ORDER]
1766 if (boot_order == constants.HT_BO_CDROM and
1767 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1768 raise errors.HypervisorError("Cannot boot from cdrom without an"
1771 security_model = hvparams[constants.HV_SECURITY_MODEL]
1772 if security_model == constants.HT_SM_USER:
1773 if not hvparams[constants.HV_SECURITY_DOMAIN]:
1774 raise errors.HypervisorError("A security domain (user to run kvm as)"
1775 " must be specified")
1776 elif (security_model == constants.HT_SM_NONE or
1777 security_model == constants.HT_SM_POOL):
1778 if hvparams[constants.HV_SECURITY_DOMAIN]:
1779 raise errors.HypervisorError("Cannot have a security domain when the"
1780 " security model is 'none' or 'pool'")
1782 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1783 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1785 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1786 # if an IP version is specified, the spice_bind parameter must be an
1788 if (netutils.IP4Address.IsValid(spice_bind) and
1789 spice_ip_version != constants.IP4_VERSION):
1790 raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1791 " the specified IP version is %s" %
1792 (spice_bind, spice_ip_version))
1794 if (netutils.IP6Address.IsValid(spice_bind) and
1795 spice_ip_version != constants.IP6_VERSION):
1796 raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1797 " the specified IP version is %s" %
1798 (spice_bind, spice_ip_version))
1800 # All the other SPICE parameters depend on spice_bind being set. Raise an
1801 # error if any of them is set without it.
1802 spice_additional_params = frozenset([
1803 constants.HV_KVM_SPICE_IP_VERSION,
1804 constants.HV_KVM_SPICE_PASSWORD_FILE,
1805 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
1806 constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
1807 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
1808 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
1809 constants.HV_KVM_SPICE_USE_TLS,
1811 for param in spice_additional_params:
1813 raise errors.HypervisorError("spice: %s requires %s to be set" %
1814 (param, constants.HV_KVM_SPICE_BIND))
1817 def ValidateParameters(cls, hvparams):
1818 """Check the given parameters for validity.
1820 @type hvparams: dict
1821 @param hvparams: dictionary with parameter names/value
1822 @raise errors.HypervisorError: when a parameter is not valid
1825 super(KVMHypervisor, cls).ValidateParameters(hvparams)
1827 security_model = hvparams[constants.HV_SECURITY_MODEL]
1828 if security_model == constants.HT_SM_USER:
1829 username = hvparams[constants.HV_SECURITY_DOMAIN]
1831 pwd.getpwnam(username)
1833 raise errors.HypervisorError("Unknown security domain user %s"
1836 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1838 # only one of VNC and SPICE can be used currently.
1839 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
1840 raise errors.HypervisorError("both SPICE and VNC are configured, but"
1841 " only one of them can be used at a"
1844 # KVM version should be >= 0.14.0
1845 _, v_major, v_min, _ = cls._GetKVMVersion()
1846 if (v_major, v_min) < (0, 14):
1847 raise errors.HypervisorError("spice is configured, but it is not"
1848 " available in versions of KVM < 0.14")
1850 # if spice_bind is not an IP address, it must be a valid interface
1851 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
1852 or netutils.IP6Address.IsValid(spice_bind))
1853 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
1854 raise errors.HypervisorError("spice: the %s parameter must be either"
1855 " a valid IP address or interface name" %
1856 constants.HV_KVM_SPICE_BIND)
1859 def PowercycleNode(cls):
1860 """KVM powercycle, just a wrapper over Linux powercycle.
1863 cls.LinuxPowercycle()