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
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_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
441 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
442 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
443 constants.HV_BOOT_ORDER:
444 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
445 constants.HV_NIC_TYPE:
446 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
447 constants.HV_DISK_TYPE:
448 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
449 constants.HV_KVM_CDROM_DISK_TYPE:
450 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
451 constants.HV_USB_MOUSE:
452 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
453 constants.HV_KEYMAP: hv_base.NO_CHECK,
454 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
455 constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
456 constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
457 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
458 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
459 constants.HV_DISK_CACHE:
460 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
461 constants.HV_SECURITY_MODEL:
462 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
463 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
464 constants.HV_KVM_FLAG:
465 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
466 constants.HV_VHOST_NET: hv_base.NO_CHECK,
467 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
468 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
469 constants.HV_REBOOT_BEHAVIOR:
470 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
471 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
474 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
476 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
477 _MIGRATION_INFO_RETRY_DELAY = 2
479 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)\.(\d+)\b")
481 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
482 _CPU_INFO_CMD = "info cpus"
490 hv_base.BaseHypervisor.__init__(self)
491 # Let's make sure the directories we need exist, even if the RUN_DIR lives
492 # in a tmpfs filesystem or has been otherwise wiped out.
493 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
494 utils.EnsureDirs(dirs)
497 def _InstancePidFile(cls, instance_name):
498 """Returns the instance pidfile.
501 return utils.PathJoin(cls._PIDS_DIR, instance_name)
504 def _InstanceUidFile(cls, instance_name):
505 """Returns the instance uidfile.
508 return utils.PathJoin(cls._UIDS_DIR, instance_name)
511 def _InstancePidInfo(cls, pid):
512 """Check pid file for instance information.
514 Check that a pid file is associated with an instance, and retrieve
515 information from its command line.
517 @type pid: string or int
518 @param pid: process id of the instance to check
520 @return: (instance_name, memory, vcpus)
521 @raise errors.HypervisorError: when an instance cannot be found
524 alive = utils.IsProcessAlive(pid)
526 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
528 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
530 cmdline = utils.ReadFile(cmdline_file)
531 except EnvironmentError, err:
532 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
539 arg_list = cmdline.split("\x00")
541 arg = arg_list.pop(0)
543 instance = arg_list.pop(0)
545 memory = int(arg_list.pop(0))
547 vcpus = int(arg_list.pop(0))
550 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
553 return (instance, memory, vcpus)
555 def _InstancePidAlive(self, instance_name):
556 """Returns the instance pidfile, pid, and liveness.
558 @type instance_name: string
559 @param instance_name: instance name
561 @return: (pid file name, pid, liveness)
564 pidfile = self._InstancePidFile(instance_name)
565 pid = utils.ReadPidFile(pidfile)
569 cmd_instance = self._InstancePidInfo(pid)[0]
570 alive = (cmd_instance == instance_name)
571 except errors.HypervisorError:
574 return (pidfile, pid, alive)
576 def _CheckDown(self, instance_name):
577 """Raises an error unless the given instance is down.
580 alive = self._InstancePidAlive(instance_name)[2]
582 raise errors.HypervisorError("Failed to start instance %s: %s" %
583 (instance_name, "already running"))
586 def _InstanceMonitor(cls, instance_name):
587 """Returns the instance monitor socket name
590 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
593 def _InstanceSerial(cls, instance_name):
594 """Returns the instance serial socket name
597 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
600 def _InstanceQmpMonitor(cls, instance_name):
601 """Returns the instance serial QMP socket name
604 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
607 def _SocatUnixConsoleParams():
608 """Returns the correct parameters for socat
610 If we have a new-enough socat we can use raw mode with an escape character.
613 if constants.SOCAT_USE_ESCAPE:
614 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
616 return "echo=0,icanon=0"
619 def _InstanceKVMRuntime(cls, instance_name):
620 """Returns the instance KVM runtime filename
623 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
626 def _InstanceChrootDir(cls, instance_name):
627 """Returns the name of the KVM chroot dir of the instance
630 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
633 def _InstanceNICDir(cls, instance_name):
634 """Returns the name of the directory holding the tap device files for a
638 return utils.PathJoin(cls._NICS_DIR, instance_name)
641 def _InstanceNICFile(cls, instance_name, seq):
642 """Returns the name of the file containing the tap device for a given NIC
645 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
648 def _InstanceKeymapFile(cls, instance_name):
649 """Returns the name of the file containing the keymap for a given instance
652 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
655 def _TryReadUidFile(cls, uid_file):
656 """Try to read a uid file
659 if os.path.exists(uid_file):
661 uid = int(utils.ReadOneLineFile(uid_file))
663 except EnvironmentError:
664 logging.warning("Can't read uid file", exc_info=True)
665 except (TypeError, ValueError):
666 logging.warning("Can't parse uid file contents", exc_info=True)
670 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
671 """Removes an instance's rutime sockets/files/dirs.
674 utils.RemoveFile(pidfile)
675 utils.RemoveFile(cls._InstanceMonitor(instance_name))
676 utils.RemoveFile(cls._InstanceSerial(instance_name))
677 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
678 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
679 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
680 uid_file = cls._InstanceUidFile(instance_name)
681 uid = cls._TryReadUidFile(uid_file)
682 utils.RemoveFile(uid_file)
684 uidpool.ReleaseUid(uid)
686 shutil.rmtree(cls._InstanceNICDir(instance_name))
688 if err.errno != errno.ENOENT:
691 chroot_dir = cls._InstanceChrootDir(instance_name)
692 utils.RemoveDir(chroot_dir)
694 if err.errno == errno.ENOTEMPTY:
695 # The chroot directory is expected to be empty, but it isn't.
696 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
699 utils.TimestampForFilename()))
700 logging.warning("The chroot directory of instance %s can not be"
701 " removed as it is not empty. Moving it to the"
702 " quarantine instead. Please investigate the"
703 " contents (%s) and clean up manually",
704 instance_name, new_chroot_dir)
705 utils.RenameFile(chroot_dir, new_chroot_dir)
710 def _ConfigureNIC(instance, seq, nic, tap):
711 """Run the network configuration script for a specified NIC
713 @param instance: instance we're acting on
714 @type instance: instance object
715 @param seq: nic sequence number
717 @param nic: nic we're acting on
718 @type nic: nic object
719 @param tap: the host's tap interface this NIC corresponds to
725 tags = " ".join(instance.tags)
730 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
731 "INSTANCE": instance.name,
733 "MODE": nic.nicparams[constants.NIC_MODE],
735 "INTERFACE_INDEX": str(seq),
742 if nic.nicparams[constants.NIC_LINK]:
743 env["LINK"] = nic.nicparams[constants.NIC_LINK]
745 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
746 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
748 result = utils.RunCmd([constants.KVM_IFUP, tap], env=env)
750 raise errors.HypervisorError("Failed to configure interface %s: %s."
751 " Network configuration script output: %s" %
752 (tap, result.fail_reason, result.output))
755 def _VerifyAffinityPackage():
757 raise errors.HypervisorError("affinity Python package not"
758 " found; cannot use CPU pinning under KVM")
761 def _BuildAffinityCpuMask(cpu_list):
762 """Create a CPU mask suitable for sched_setaffinity from a list of
765 See man taskset for more info on sched_setaffinity masks.
766 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
768 @type cpu_list: list of int
769 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
771 @return: a bit mask of CPU affinities
774 if cpu_list == constants.CPU_PINNING_OFF:
775 return constants.CPU_PINNING_ALL_KVM
777 return sum(2 ** cpu for cpu in cpu_list)
780 def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
781 """Change CPU affinity for running VM according to given CPU mask.
783 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
784 @type cpu_mask: string
785 @param process_id: process ID of KVM process. Used to pin entire VM
787 @type process_id: int
788 @param thread_dict: map of virtual CPUs to KVM thread IDs
789 @type thread_dict: dict int:int
793 # Convert the string CPU mask to a list of list of int's
794 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
796 if len(cpu_list) == 1:
797 all_cpu_mapping = cpu_list[0]
798 if all_cpu_mapping == constants.CPU_PINNING_OFF:
799 # If CPU pinning has 1 entry that's "all", then do nothing
802 # If CPU pinning has one non-all entry, map the entire VM to
803 # one set of physical CPUs
804 cls._VerifyAffinityPackage()
805 affinity.set_process_affinity_mask(process_id,
806 cls._BuildAffinityCpuMask(all_cpu_mapping))
808 # The number of vCPUs mapped should match the number of vCPUs
809 # reported by KVM. This was already verified earlier, so
810 # here only as a sanity check.
811 assert len(thread_dict) == len(cpu_list)
812 cls._VerifyAffinityPackage()
814 # For each vCPU, map it to the proper list of physical CPUs
815 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
816 affinity.set_process_affinity_mask(thread_dict[i],
817 cls._BuildAffinityCpuMask(vcpu))
819 def _GetVcpuThreadIds(self, instance_name):
820 """Get a mapping of vCPU no. to thread IDs for the instance
822 @type instance_name: string
823 @param instance_name: instance in question
824 @rtype: dictionary of int:int
825 @return: a dictionary mapping vCPU numbers to thread IDs
829 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
830 for line in output.stdout.splitlines():
831 match = self._CPU_INFO_RE.search(line)
834 grp = map(int, match.groups())
835 result[grp[0]] = grp[1]
839 def _ExecuteCpuAffinity(self, instance_name, cpu_mask, startup_paused):
840 """Complete CPU pinning and resume instance execution if needed.
842 @type instance_name: string
843 @param instance_name: name of instance
844 @type cpu_mask: string
845 @param cpu_mask: CPU pinning mask as entered by user
846 @type startup_paused: bool
847 @param startup_paused: was instance requested to pause before startup
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)
859 # To control CPU pinning, the VM was started frozen, so we need
860 # to resume its execution, but only if freezing was not
861 # explicitly requested.
862 # Note: this is done even when an exception occurred so the VM
863 # is not unintentionally frozen.
864 if not startup_paused:
865 self._CallMonitorCommand(instance_name, self._CONT_CMD)
867 def ListInstances(self):
868 """Get the list of running instances.
870 We can do this by listing our live instances directory and
871 checking whether the associated kvm process is still alive.
875 for name in os.listdir(self._PIDS_DIR):
876 if self._InstancePidAlive(name)[2]:
880 def GetInstanceInfo(self, instance_name):
881 """Get instance properties.
883 @type instance_name: string
884 @param instance_name: the instance name
885 @rtype: tuple of strings
886 @return: (name, id, memory, vcpus, stat, times)
889 _, pid, alive = self._InstancePidAlive(instance_name)
893 _, memory, vcpus = self._InstancePidInfo(pid)
897 return (instance_name, pid, memory, vcpus, stat, times)
899 def GetAllInstancesInfo(self):
900 """Get properties of all instances.
902 @return: list of tuples (name, id, memory, vcpus, stat, times)
906 for name in os.listdir(self._PIDS_DIR):
908 info = self.GetInstanceInfo(name)
909 except errors.HypervisorError:
915 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
916 """Generate KVM information to start an instance.
919 # pylint: disable=R0914
920 _, v_major, v_min, _ = self._GetKVMVersion()
922 pidfile = self._InstancePidFile(instance.name)
923 kvm = constants.KVM_PATH
925 # used just by the vnc server, if enabled
926 kvm_cmd.extend(["-name", instance.name])
927 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MEMORY]])
928 kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
929 kvm_cmd.extend(["-pidfile", pidfile])
930 kvm_cmd.extend(["-daemonize"])
931 if not instance.hvparams[constants.HV_ACPI]:
932 kvm_cmd.extend(["-no-acpi"])
933 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
934 constants.INSTANCE_REBOOT_EXIT:
935 kvm_cmd.extend(["-no-reboot"])
937 hvp = instance.hvparams
938 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
939 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
940 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
941 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
943 self.ValidateParameters(hvp)
946 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
948 if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
949 kvm_cmd.extend(["-enable-kvm"])
950 elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
951 kvm_cmd.extend(["-disable-kvm"])
954 kvm_cmd.extend(["-boot", "n"])
956 disk_type = hvp[constants.HV_DISK_TYPE]
957 if disk_type == constants.HT_DISK_PARAVIRTUAL:
958 if_val = ",if=virtio"
960 if_val = ",if=%s" % disk_type
962 disk_cache = hvp[constants.HV_DISK_CACHE]
963 if instance.disk_template in constants.DTS_EXT_MIRROR:
964 if disk_cache != "none":
965 # TODO: make this a hard error, instead of a silent overwrite
966 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
967 " to prevent shared storage corruption on migration",
969 cache_val = ",cache=none"
970 elif disk_cache != constants.HT_CACHE_DEFAULT:
971 cache_val = ",cache=%s" % disk_cache
974 for cfdev, dev_path in block_devices:
975 if cfdev.mode != constants.DISK_RDWR:
976 raise errors.HypervisorError("Instance has read-only disks which"
977 " are not supported by KVM")
978 # TODO: handle FD_LOOP and FD_BLKTAP (?)
981 kvm_cmd.extend(["-boot", "c"])
983 if (v_major, v_min) < (0, 14) and disk_type != constants.HT_DISK_IDE:
984 boot_val = ",boot=on"
986 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
988 kvm_cmd.extend(["-drive", drive_val])
990 #Now we can specify a different device type for CDROM devices.
991 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
992 if not cdrom_disk_type:
993 cdrom_disk_type = disk_type
995 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
997 options = ",format=raw,media=cdrom"
999 kvm_cmd.extend(["-boot", "d"])
1000 if cdrom_disk_type != constants.HT_DISK_IDE:
1001 options = "%s,boot=on,if=%s" % (options, constants.HT_DISK_IDE)
1003 options = "%s,boot=on" % options
1005 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1006 if_val = ",if=virtio"
1008 if_val = ",if=%s" % cdrom_disk_type
1009 options = "%s%s" % (options, if_val)
1010 drive_val = "file=%s%s" % (iso_image, options)
1011 kvm_cmd.extend(["-drive", drive_val])
1013 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1015 options = ",format=raw,media=cdrom"
1016 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1017 if_val = ",if=virtio"
1019 if_val = ",if=%s" % cdrom_disk_type
1020 options = "%s%s" % (options, if_val)
1021 drive_val = "file=%s%s" % (iso_image2, options)
1022 kvm_cmd.extend(["-drive", drive_val])
1024 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1026 options = ",format=raw,media=disk"
1028 kvm_cmd.extend(["-boot", "a"])
1029 options = "%s,boot=on" % options
1030 if_val = ",if=floppy"
1031 options = "%s%s" % (options, if_val)
1032 drive_val = "file=%s%s" % (floppy_image, options)
1033 kvm_cmd.extend(["-drive", drive_val])
1035 kernel_path = hvp[constants.HV_KERNEL_PATH]
1037 kvm_cmd.extend(["-kernel", kernel_path])
1038 initrd_path = hvp[constants.HV_INITRD_PATH]
1040 kvm_cmd.extend(["-initrd", initrd_path])
1041 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1042 hvp[constants.HV_KERNEL_ARGS]]
1043 if hvp[constants.HV_SERIAL_CONSOLE]:
1044 root_append.append("console=ttyS0,38400")
1045 kvm_cmd.extend(["-append", " ".join(root_append)])
1047 mem_path = hvp[constants.HV_MEM_PATH]
1049 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1051 mouse_type = hvp[constants.HV_USB_MOUSE]
1052 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1055 kvm_cmd.extend(["-usb"])
1056 kvm_cmd.extend(["-usbdevice", mouse_type])
1057 elif vnc_bind_address:
1058 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1060 keymap = hvp[constants.HV_KEYMAP]
1062 keymap_path = self._InstanceKeymapFile(instance.name)
1063 # If a keymap file is specified, KVM won't use its internal defaults. By
1064 # first including the "en-us" layout, an error on loading the actual
1065 # layout (e.g. because it can't be found) won't lead to a non-functional
1066 # keyboard. A keyboard with incorrect keys is still better than none.
1067 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1068 kvm_cmd.extend(["-k", keymap_path])
1070 if vnc_bind_address:
1071 if netutils.IP4Address.IsValid(vnc_bind_address):
1072 if instance.network_port > constants.VNC_BASE_PORT:
1073 display = instance.network_port - constants.VNC_BASE_PORT
1074 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1075 vnc_arg = ":%d" % (display)
1077 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1079 logging.error("Network port is not a valid VNC display (%d < %d)."
1080 " Not starting VNC", instance.network_port,
1081 constants.VNC_BASE_PORT)
1084 # Only allow tls and other option when not binding to a file, for now.
1085 # kvm/qemu gets confused otherwise about the filename to use.
1087 if hvp[constants.HV_VNC_TLS]:
1088 vnc_append = "%s,tls" % vnc_append
1089 if hvp[constants.HV_VNC_X509_VERIFY]:
1090 vnc_append = "%s,x509verify=%s" % (vnc_append,
1091 hvp[constants.HV_VNC_X509])
1092 elif hvp[constants.HV_VNC_X509]:
1093 vnc_append = "%s,x509=%s" % (vnc_append,
1094 hvp[constants.HV_VNC_X509])
1095 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1096 vnc_append = "%s,password" % vnc_append
1098 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1101 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1103 kvm_cmd.extend(["-vnc", vnc_arg])
1105 kvm_cmd.extend(["-nographic"])
1107 monitor_dev = ("unix:%s,server,nowait" %
1108 self._InstanceMonitor(instance.name))
1109 kvm_cmd.extend(["-monitor", monitor_dev])
1110 if hvp[constants.HV_SERIAL_CONSOLE]:
1111 serial_dev = ("unix:%s,server,nowait" %
1112 self._InstanceSerial(instance.name))
1113 kvm_cmd.extend(["-serial", serial_dev])
1115 kvm_cmd.extend(["-serial", "none"])
1117 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1118 spice_ip_version = None
1120 if netutils.IsValidInterface(spice_bind):
1121 # The user specified a network interface, we have to figure out the IP
1123 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1124 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1126 # if the user specified an IP version and the interface does not
1127 # have that kind of IP addresses, throw an exception
1128 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1129 if not addresses[spice_ip_version]:
1130 raise errors.HypervisorError("spice: unable to get an IPv%s address"
1131 " for %s" % (spice_ip_version,
1134 # the user did not specify an IP version, we have to figure it out
1135 elif (addresses[constants.IP4_VERSION] and
1136 addresses[constants.IP6_VERSION]):
1137 # we have both ipv4 and ipv6, let's use the cluster default IP
1139 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1140 spice_ip_version = netutils.IPAddress.GetVersionFromAddressFamily(
1142 elif addresses[constants.IP4_VERSION]:
1143 spice_ip_version = constants.IP4_VERSION
1144 elif addresses[constants.IP6_VERSION]:
1145 spice_ip_version = constants.IP6_VERSION
1147 raise errors.HypervisorError("spice: unable to get an IP address"
1148 " for %s" % (spice_bind))
1150 spice_address = addresses[spice_ip_version][0]
1153 # spice_bind is known to be a valid IP address, because
1154 # ValidateParameters checked it.
1155 spice_address = spice_bind
1157 spice_arg = "addr=%s,port=%s" % (spice_address, instance.network_port)
1158 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1159 spice_arg = "%s,disable-ticketing" % spice_arg
1161 if spice_ip_version:
1162 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1164 # Image compression options
1165 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1166 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1167 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1169 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1171 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1173 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1175 # Video stream detection
1176 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1178 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1180 # Audio compression, by default in qemu-kvm it is on
1181 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1182 spice_arg = "%s,playback-compression=off" % spice_arg
1184 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1185 kvm_cmd.extend(["-spice", spice_arg])
1187 # Tell kvm to use the paravirtualized graphic card, optimized for SPICE
1188 kvm_cmd.extend(["-vga", "qxl"])
1190 if hvp[constants.HV_USE_LOCALTIME]:
1191 kvm_cmd.extend(["-localtime"])
1193 if hvp[constants.HV_KVM_USE_CHROOT]:
1194 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1196 # Save the current instance nics, but defer their expansion as parameters,
1197 # as we'll need to generate executable temp files for them.
1198 kvm_nics = instance.nics
1201 return (kvm_cmd, kvm_nics, hvparams)
1203 def _WriteKVMRuntime(self, instance_name, data):
1204 """Write an instance's KVM runtime
1208 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
1210 except EnvironmentError, err:
1211 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1213 def _ReadKVMRuntime(self, instance_name):
1214 """Read an instance's KVM runtime
1218 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1219 except EnvironmentError, err:
1220 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1223 def _SaveKVMRuntime(self, instance, kvm_runtime):
1224 """Save an instance's KVM runtime
1227 kvm_cmd, kvm_nics, hvparams = kvm_runtime
1228 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1229 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1230 self._WriteKVMRuntime(instance.name, serialized_form)
1232 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1233 """Load an instance's KVM runtime
1236 if not serialized_runtime:
1237 serialized_runtime = self._ReadKVMRuntime(instance.name)
1238 loaded_runtime = serializer.Load(serialized_runtime)
1239 kvm_cmd, serialized_nics, hvparams = loaded_runtime
1240 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1241 return (kvm_cmd, kvm_nics, hvparams)
1243 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1244 """Run the KVM cmd and check for errors
1247 @param name: instance name
1248 @type kvm_cmd: list of strings
1249 @param kvm_cmd: runcmd input for kvm
1250 @type tap_fds: list of int
1251 @param tap_fds: fds of tap devices opened by Ganeti
1255 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1258 utils_wrapper.CloseFdNoError(fd)
1261 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1262 (name, result.fail_reason, result.output))
1263 if not self._InstancePidAlive(name)[2]:
1264 raise errors.HypervisorError("Failed to start instance %s" % name)
1266 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
1267 """Execute a KVM cmd, after completing it with some last minute data
1269 @type incoming: tuple of strings
1270 @param incoming: (target_host_ip, port)
1273 # Small _ExecuteKVMRuntime hv parameters programming howto:
1274 # - conf_hvp contains the parameters as configured on ganeti. they might
1275 # have changed since the instance started; only use them if the change
1276 # won't affect the inside of the instance (which hasn't been rebooted).
1277 # - up_hvp contains the parameters as they were when the instance was
1278 # started, plus any new parameter which has been added between ganeti
1279 # versions: it is paramount that those default to a value which won't
1280 # affect the inside of the instance as well.
1281 conf_hvp = instance.hvparams
1282 name = instance.name
1283 self._CheckDown(name)
1287 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1288 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1290 _, v_major, v_min, _ = self._GetKVMVersion()
1292 # We know it's safe to run as a different user upon migration, so we'll use
1293 # the latest conf, from conf_hvp.
1294 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1295 if security_model == constants.HT_SM_USER:
1296 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1298 # We have reasons to believe changing something like the nic driver/type
1299 # upon migration won't exactly fly with the instance kernel, so for nic
1300 # related parameters we'll use up_hvp
1304 kvm_cmd.extend(["-net", "none"])
1308 nic_type = up_hvp[constants.HV_NIC_TYPE]
1309 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1310 # From version 0.12.0, kvm uses a new sintax for network configuration.
1311 if (v_major, v_min) >= (0, 12):
1312 nic_model = "virtio-net-pci"
1315 nic_model = "virtio"
1317 if up_hvp[constants.HV_VHOST_NET]:
1318 # vhost_net is only available from version 0.13.0 or newer
1319 if (v_major, v_min) >= (0, 13):
1320 tap_extra = ",vhost=on"
1322 raise errors.HypervisorError("vhost_net is configured"
1323 " but it is not available")
1325 nic_model = nic_type
1327 for nic_seq, nic in enumerate(kvm_nics):
1328 tapname, tapfd = _OpenTap(vnet_hdr)
1329 tapfds.append(tapfd)
1330 taps.append(tapname)
1331 if (v_major, v_min) >= (0, 12):
1332 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1333 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1334 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1336 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1338 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1339 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1342 target, port = incoming
1343 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1345 # Changing the vnc password doesn't bother the guest that much. At most it
1346 # will surprise people who connect to it. Whether positively or negatively
1348 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1352 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1353 except EnvironmentError, err:
1354 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1355 % (vnc_pwd_file, err))
1357 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1358 utils.EnsureDirs([(self._InstanceChrootDir(name),
1359 constants.SECURE_DIR_MODE)])
1361 # Automatically enable QMP if version is >= 0.14
1362 if (v_major, v_min) >= (0, 14):
1363 logging.debug("Enabling QMP")
1364 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1365 self._InstanceQmpMonitor(instance.name)])
1367 # Configure the network now for starting instances and bridged interfaces,
1368 # during FinalizeMigration for incoming instances' routed interfaces
1369 for nic_seq, nic in enumerate(kvm_nics):
1371 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1373 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1375 # Before running the KVM command, capture wether the instance is
1376 # supposed to start paused. This is used later when changing CPU
1377 # affinity in order to know whether to resume instance execution.
1378 startup_paused = _KVM_START_PAUSED_FLAG in kvm_cmd
1380 # Note: CPU pinning is using up_hvp since changes take effect
1381 # during instance startup anyway, and to avoid problems when soft
1382 # rebooting the instance.
1384 if up_hvp.get(constants.HV_CPU_MASK, None):
1386 if not startup_paused:
1387 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1389 if security_model == constants.HT_SM_POOL:
1390 ss = ssconf.SimpleStore()
1391 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1392 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1393 uid = uidpool.RequestUnusedUid(all_uids)
1395 username = pwd.getpwuid(uid.GetUid()).pw_name
1396 kvm_cmd.extend(["-runas", username])
1397 self._RunKVMCmd(name, kvm_cmd, tapfds)
1399 uidpool.ReleaseUid(uid)
1403 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1405 self._RunKVMCmd(name, kvm_cmd, tapfds)
1407 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1408 constants.RUN_DIRS_MODE)])
1409 for nic_seq, tap in enumerate(taps):
1410 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1414 change_cmd = "change vnc password %s" % vnc_pwd
1415 self._CallMonitorCommand(instance.name, change_cmd)
1417 # Setting SPICE password. We are not vulnerable to malicious passwordless
1418 # connection attempts because SPICE by default does not allow connections
1419 # if neither a password nor the "disable_ticketing" options are specified.
1420 # As soon as we send the password via QMP, that password is a valid ticket
1422 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1423 if spice_password_file:
1425 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1426 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1429 "protocol": "spice",
1430 "password": spice_pwd,
1432 qmp.Execute("set_password", arguments)
1433 except EnvironmentError, err:
1434 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1435 % (spice_password_file, err))
1437 for filename in temp_files:
1438 utils.RemoveFile(filename)
1440 # If requested, set CPU affinity and resume instance execution
1442 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK],
1445 def StartInstance(self, instance, block_devices, startup_paused):
1446 """Start an instance.
1449 self._CheckDown(instance.name)
1450 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
1452 self._SaveKVMRuntime(instance, kvm_runtime)
1453 self._ExecuteKVMRuntime(instance, kvm_runtime)
1455 def _CallMonitorCommand(self, instance_name, command):
1456 """Invoke a command on the instance monitor.
1459 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
1460 (utils.ShellQuote(command),
1461 constants.SOCAT_PATH,
1462 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1463 result = utils.RunCmd(socat)
1465 msg = ("Failed to send command '%s' to instance %s."
1466 " output: %s, error: %s, fail_reason: %s" %
1467 (command, instance_name,
1468 result.stdout, result.stderr, result.fail_reason))
1469 raise errors.HypervisorError(msg)
1474 def _GetKVMVersion(cls):
1475 """Return the installed KVM version.
1477 @return: (version, v_maj, v_min, v_rev)
1478 @raise L{errors.HypervisorError}: when the KVM version cannot be retrieved
1481 result = utils.RunCmd([constants.KVM_PATH, "--help"])
1483 raise errors.HypervisorError("Unable to get KVM version")
1484 match = cls._VERSION_RE.search(result.output.splitlines()[0])
1486 raise errors.HypervisorError("Unable to get KVM version")
1488 return (match.group(0), int(match.group(1)), int(match.group(2)),
1489 int(match.group(3)))
1491 def StopInstance(self, instance, force=False, retry=False, name=None):
1492 """Stop an instance.
1495 if name is not None and not force:
1496 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
1498 name = instance.name
1499 acpi = instance.hvparams[constants.HV_ACPI]
1502 _, pid, alive = self._InstancePidAlive(name)
1503 if pid > 0 and alive:
1504 if force or not acpi:
1505 utils.KillProcess(pid)
1507 self._CallMonitorCommand(name, "system_powerdown")
1509 def CleanupInstance(self, instance_name):
1510 """Cleanup after a stopped instance
1513 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1514 if pid > 0 and alive:
1515 raise errors.HypervisorError("Cannot cleanup a live instance")
1516 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1518 def RebootInstance(self, instance):
1519 """Reboot an instance.
1522 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1523 # socket the instance will stop, but now power up again. So we'll resort
1524 # to shutdown and restart.
1525 _, _, alive = self._InstancePidAlive(instance.name)
1527 raise errors.HypervisorError("Failed to reboot instance %s:"
1528 " not running" % instance.name)
1529 # StopInstance will delete the saved KVM runtime so:
1530 # ...first load it...
1531 kvm_runtime = self._LoadKVMRuntime(instance)
1532 # ...now we can safely call StopInstance...
1533 if not self.StopInstance(instance):
1534 self.StopInstance(instance, force=True)
1535 # ...and finally we can save it again, and execute it...
1536 self._SaveKVMRuntime(instance, kvm_runtime)
1537 self._ExecuteKVMRuntime(instance, kvm_runtime)
1539 def MigrationInfo(self, instance):
1540 """Get instance information to perform a migration.
1542 @type instance: L{objects.Instance}
1543 @param instance: instance to be migrated
1545 @return: content of the KVM runtime file
1548 return self._ReadKVMRuntime(instance.name)
1550 def AcceptInstance(self, instance, info, target):
1551 """Prepare to accept an instance.
1553 @type instance: L{objects.Instance}
1554 @param instance: instance to be accepted
1556 @param info: content of the KVM runtime file on the source node
1557 @type target: string
1558 @param target: target host (usually ip), on this node
1561 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1562 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1563 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1565 def FinalizeMigration(self, instance, info, success):
1566 """Finalize an instance migration.
1568 Stop the incoming mode KVM.
1570 @type instance: L{objects.Instance}
1571 @param instance: instance whose migration is being finalized
1575 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1576 kvm_nics = kvm_runtime[1]
1578 for nic_seq, nic in enumerate(kvm_nics):
1579 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1580 # Bridged interfaces have already been configured
1583 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1584 except EnvironmentError, err:
1585 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1586 instance.name, nic_seq, str(err))
1589 self._ConfigureNIC(instance, nic_seq, nic, tap)
1590 except errors.HypervisorError, err:
1591 logging.warning(str(err))
1593 self._WriteKVMRuntime(instance.name, info)
1595 self.StopInstance(instance, force=True)
1597 def MigrateInstance(self, instance, target, live):
1598 """Migrate an instance to a target node.
1600 The migration will not be attempted if the instance is not
1603 @type instance: L{objects.Instance}
1604 @param instance: the instance to be migrated
1605 @type target: string
1606 @param target: ip address of the target node
1608 @param live: perform a live migration
1611 instance_name = instance.name
1612 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1613 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1615 raise errors.HypervisorError("Instance not running, cannot migrate")
1618 self._CallMonitorCommand(instance_name, "stop")
1620 migrate_command = ("migrate_set_speed %dm" %
1621 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1622 self._CallMonitorCommand(instance_name, migrate_command)
1624 migrate_command = ("migrate_set_downtime %dms" %
1625 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1626 self._CallMonitorCommand(instance_name, migrate_command)
1628 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1629 self._CallMonitorCommand(instance_name, migrate_command)
1631 info_command = "info migrate"
1635 result = self._CallMonitorCommand(instance_name, info_command)
1636 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1639 if not result.stdout:
1640 logging.info("KVM: empty 'info migrate' result")
1642 logging.warning("KVM: unknown 'info migrate' result: %s",
1644 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1646 status = match.group(1)
1647 if status == "completed":
1649 elif status == "active":
1650 # reset the broken answers count
1652 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1653 elif status == "failed" or status == "cancelled":
1655 self._CallMonitorCommand(instance_name, self._CONT_CMD)
1656 raise errors.HypervisorError("Migration %s at the kvm level" %
1659 logging.warning("KVM: unknown migration status '%s'", status)
1661 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1662 if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
1663 raise errors.HypervisorError("Too many 'info migrate' broken answers")
1665 utils.KillProcess(pid)
1666 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1668 def GetNodeInfo(self):
1669 """Return information about the node.
1671 This is just a wrapper over the base GetLinuxNodeInfo method.
1673 @return: a dict with the following keys (values in MiB):
1674 - memory_total: the total memory size on the node
1675 - memory_free: the available memory on the node for instances
1676 - memory_dom0: the memory used by the node itself, if available
1679 return self.GetLinuxNodeInfo()
1682 def GetInstanceConsole(cls, instance, hvparams, beparams):
1683 """Return a command for connecting to the console of an instance.
1686 if hvparams[constants.HV_SERIAL_CONSOLE]:
1687 cmd = [constants.KVM_CONSOLE_WRAPPER,
1688 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1689 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1690 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1691 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1692 return objects.InstanceConsole(instance=instance.name,
1693 kind=constants.CONS_SSH,
1694 host=instance.primary_node,
1695 user=constants.GANETI_RUNAS,
1698 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1699 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1700 display = instance.network_port - constants.VNC_BASE_PORT
1701 return objects.InstanceConsole(instance=instance.name,
1702 kind=constants.CONS_VNC,
1703 host=vnc_bind_address,
1704 port=instance.network_port,
1707 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1709 return objects.InstanceConsole(instance=instance.name,
1710 kind=constants.CONS_SPICE,
1712 port=instance.network_port)
1714 return objects.InstanceConsole(instance=instance.name,
1715 kind=constants.CONS_MESSAGE,
1716 message=("No serial shell for instance %s" %
1720 """Verify the hypervisor.
1722 Check that the binary exists.
1725 if not os.path.exists(constants.KVM_PATH):
1726 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1727 if not os.path.exists(constants.SOCAT_PATH):
1728 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1731 def CheckParameterSyntax(cls, hvparams):
1732 """Check the given parameters for validity.
1734 @type hvparams: dict
1735 @param hvparams: dictionary with parameter names/value
1736 @raise errors.HypervisorError: when a parameter is not valid
1739 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1741 kernel_path = hvparams[constants.HV_KERNEL_PATH]
1743 if not hvparams[constants.HV_ROOT_PATH]:
1744 raise errors.HypervisorError("Need a root partition for the instance,"
1745 " if a kernel is defined")
1747 if (hvparams[constants.HV_VNC_X509_VERIFY] and
1748 not hvparams[constants.HV_VNC_X509]):
1749 raise errors.HypervisorError("%s must be defined, if %s is" %
1750 (constants.HV_VNC_X509,
1751 constants.HV_VNC_X509_VERIFY))
1753 boot_order = hvparams[constants.HV_BOOT_ORDER]
1754 if (boot_order == constants.HT_BO_CDROM and
1755 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1756 raise errors.HypervisorError("Cannot boot from cdrom without an"
1759 security_model = hvparams[constants.HV_SECURITY_MODEL]
1760 if security_model == constants.HT_SM_USER:
1761 if not hvparams[constants.HV_SECURITY_DOMAIN]:
1762 raise errors.HypervisorError("A security domain (user to run kvm as)"
1763 " must be specified")
1764 elif (security_model == constants.HT_SM_NONE or
1765 security_model == constants.HT_SM_POOL):
1766 if hvparams[constants.HV_SECURITY_DOMAIN]:
1767 raise errors.HypervisorError("Cannot have a security domain when the"
1768 " security model is 'none' or 'pool'")
1770 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1771 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
1773 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1774 # if an IP version is specified, the spice_bind parameter must be an
1776 if (netutils.IP4Address.IsValid(spice_bind) and
1777 spice_ip_version != constants.IP4_VERSION):
1778 raise errors.HypervisorError("spice: got an IPv4 address (%s), but"
1779 " the specified IP version is %s" %
1780 (spice_bind, spice_ip_version))
1782 if (netutils.IP6Address.IsValid(spice_bind) and
1783 spice_ip_version != constants.IP6_VERSION):
1784 raise errors.HypervisorError("spice: got an IPv6 address (%s), but"
1785 " the specified IP version is %s" %
1786 (spice_bind, spice_ip_version))
1788 # All the other SPICE parameters depend on spice_bind being set. Raise an
1789 # error if any of them is set without it.
1790 spice_additional_params = frozenset([
1791 constants.HV_KVM_SPICE_IP_VERSION,
1792 constants.HV_KVM_SPICE_PASSWORD_FILE,
1793 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
1794 constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
1795 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
1796 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
1798 for param in spice_additional_params:
1800 raise errors.HypervisorError("spice: %s requires %s to be set" %
1801 (param, constants.HV_KVM_SPICE_BIND))
1804 def ValidateParameters(cls, hvparams):
1805 """Check the given parameters for validity.
1807 @type hvparams: dict
1808 @param hvparams: dictionary with parameter names/value
1809 @raise errors.HypervisorError: when a parameter is not valid
1812 super(KVMHypervisor, cls).ValidateParameters(hvparams)
1814 security_model = hvparams[constants.HV_SECURITY_MODEL]
1815 if security_model == constants.HT_SM_USER:
1816 username = hvparams[constants.HV_SECURITY_DOMAIN]
1818 pwd.getpwnam(username)
1820 raise errors.HypervisorError("Unknown security domain user %s"
1823 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
1825 # only one of VNC and SPICE can be used currently.
1826 if hvparams[constants.HV_VNC_BIND_ADDRESS]:
1827 raise errors.HypervisorError("both SPICE and VNC are configured, but"
1828 " only one of them can be used at a"
1831 # KVM version should be >= 0.14.0
1832 _, v_major, v_min, _ = cls._GetKVMVersion()
1833 if (v_major, v_min) < (0, 14):
1834 raise errors.HypervisorError("spice is configured, but it is not"
1835 " available in versions of KVM < 0.14")
1837 # if spice_bind is not an IP address, it must be a valid interface
1838 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
1839 or netutils.IP6Address.IsValid(spice_bind))
1840 if not bound_to_addr and not netutils.IsValidInterface(spice_bind):
1841 raise errors.HypervisorError("spice: the %s parameter must be either"
1842 " a valid IP address or interface name" %
1843 constants.HV_KVM_SPICE_BIND)
1846 def PowercycleNode(cls):
1847 """KVM powercycle, just a wrapper over Linux powercycle.
1850 cls.LinuxPowercycle()