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
38 from ganeti import utils
39 from ganeti import constants
40 from ganeti import errors
41 from ganeti import serializer
42 from ganeti import objects
43 from ganeti import uidpool
44 from ganeti import ssconf
45 from ganeti.hypervisor import hv_base
46 from ganeti import netutils
47 from ganeti.utils import wrapper as utils_wrapper
50 _KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
52 # TUN/TAP driver constants, taken from <linux/if_tun.h>
53 # They are architecture-independent and already hardcoded in qemu-kvm source,
54 # so we can safely include them here.
55 TUNSETIFF = 0x400454ca
56 TUNGETIFF = 0x800454d2
57 TUNGETFEATURES = 0x800454cf
63 def _ProbeTapVnetHdr(fd):
64 """Check whether to enable the IFF_VNET_HDR flag.
66 To do this, _all_ of the following conditions must be met:
67 1. TUNGETFEATURES ioctl() *must* be implemented
68 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
69 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
70 drivers/net/tun.c there is no way to test this until after the tap device
71 has been created using TUNSETIFF, and there is no way to change the
72 IFF_VNET_HDR flag after creating the interface, catch-22! However both
73 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
74 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
77 @param fd: the file descriptor of /dev/net/tun
80 req = struct.pack("I", 0)
82 res = fcntl.ioctl(fd, TUNGETFEATURES, req)
83 except EnvironmentError:
84 logging.warning("TUNGETFEATURES ioctl() not implemented")
87 tunflags = struct.unpack("I", res)[0]
88 if tunflags & IFF_VNET_HDR:
91 logging.warning("Host does not support IFF_VNET_HDR, not enabling")
95 def _OpenTap(vnet_hdr=True):
96 """Open a new tap device and return its file descriptor.
98 This is intended to be used by a qemu-type hypervisor together with the -net
99 tap,fd=<fd> command line parameter.
101 @type vnet_hdr: boolean
102 @param vnet_hdr: Enable the VNET Header
103 @return: (ifname, tapfd)
108 tapfd = os.open("/dev/net/tun", os.O_RDWR)
109 except EnvironmentError:
110 raise errors.HypervisorError("Failed to open /dev/net/tun")
112 flags = IFF_TAP | IFF_NO_PI
114 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
115 flags |= IFF_VNET_HDR
117 # The struct ifreq ioctl request (see netdevice(7))
118 ifr = struct.pack("16sh", "", flags)
121 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
122 except EnvironmentError:
123 raise errors.HypervisorError("Failed to allocate a new TAP device")
125 # Get the interface name from the ioctl
126 ifname = struct.unpack("16sh", res)[0].strip("\x00")
127 return (ifname, tapfd)
130 class KVMHypervisor(hv_base.BaseHypervisor):
131 """KVM hypervisor interface"""
134 _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
135 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
136 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
137 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
138 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
139 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
140 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
141 # KVM instances with chroot enabled are started in empty chroot directories.
142 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
143 # After an instance is stopped, its chroot directory is removed.
144 # If the chroot directory is not empty, it can't be removed.
145 # A non-empty chroot directory indicates a possible security incident.
146 # To support forensics, the non-empty chroot directory is quarantined in
147 # a separate directory, called 'chroot-quarantine'.
148 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
149 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
150 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR]
153 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
154 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
155 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
156 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
157 constants.HV_ACPI: hv_base.NO_CHECK,
158 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
159 constants.HV_VNC_BIND_ADDRESS:
160 (False, lambda x: (netutils.IP4Address.IsValid(x) or
161 utils.IsNormAbsPath(x)),
162 "the VNC bind address must be either a valid IP address or an absolute"
163 " pathname", None, None),
164 constants.HV_VNC_TLS: hv_base.NO_CHECK,
165 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
166 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
167 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
168 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
169 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
170 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
171 constants.HV_BOOT_ORDER:
172 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
173 constants.HV_NIC_TYPE:
174 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
175 constants.HV_DISK_TYPE:
176 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
177 constants.HV_KVM_CDROM_DISK_TYPE:
178 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
179 constants.HV_USB_MOUSE:
180 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
181 constants.HV_KEYMAP: hv_base.NO_CHECK,
182 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
183 constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
184 constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
185 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
186 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
187 constants.HV_DISK_CACHE:
188 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
189 constants.HV_SECURITY_MODEL:
190 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
191 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
192 constants.HV_KVM_FLAG:
193 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
194 constants.HV_VHOST_NET: hv_base.NO_CHECK,
195 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
196 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
197 constants.HV_REBOOT_BEHAVIOR:
198 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS)
201 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
203 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
204 _MIGRATION_INFO_RETRY_DELAY = 2
206 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)\.(\d+)\b")
213 hv_base.BaseHypervisor.__init__(self)
214 # Let's make sure the directories we need exist, even if the RUN_DIR lives
215 # in a tmpfs filesystem or has been otherwise wiped out.
216 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
217 utils.EnsureDirs(dirs)
220 def _InstancePidFile(cls, instance_name):
221 """Returns the instance pidfile.
224 return utils.PathJoin(cls._PIDS_DIR, instance_name)
227 def _InstanceUidFile(cls, instance_name):
228 """Returns the instance uidfile.
231 return utils.PathJoin(cls._UIDS_DIR, instance_name)
234 def _InstancePidInfo(cls, pid):
235 """Check pid file for instance information.
237 Check that a pid file is associated with an instance, and retrieve
238 information from its command line.
240 @type pid: string or int
241 @param pid: process id of the instance to check
243 @return: (instance_name, memory, vcpus)
244 @raise errors.HypervisorError: when an instance cannot be found
247 alive = utils.IsProcessAlive(pid)
249 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
251 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
253 cmdline = utils.ReadFile(cmdline_file)
254 except EnvironmentError, err:
255 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
262 arg_list = cmdline.split("\x00")
264 arg = arg_list.pop(0)
266 instance = arg_list.pop(0)
268 memory = int(arg_list.pop(0))
270 vcpus = int(arg_list.pop(0))
273 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
276 return (instance, memory, vcpus)
278 def _InstancePidAlive(self, instance_name):
279 """Returns the instance pidfile, pid, and liveness.
281 @type instance_name: string
282 @param instance_name: instance name
284 @return: (pid file name, pid, liveness)
287 pidfile = self._InstancePidFile(instance_name)
288 pid = utils.ReadPidFile(pidfile)
292 cmd_instance = self._InstancePidInfo(pid)[0]
293 alive = (cmd_instance == instance_name)
294 except errors.HypervisorError:
297 return (pidfile, pid, alive)
299 def _CheckDown(self, instance_name):
300 """Raises an error unless the given instance is down.
303 alive = self._InstancePidAlive(instance_name)[2]
305 raise errors.HypervisorError("Failed to start instance %s: %s" %
306 (instance_name, "already running"))
309 def _InstanceMonitor(cls, instance_name):
310 """Returns the instance monitor socket name
313 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
316 def _InstanceSerial(cls, instance_name):
317 """Returns the instance serial socket name
320 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
323 def _SocatUnixConsoleParams():
324 """Returns the correct parameters for socat
326 If we have a new-enough socat we can use raw mode with an escape character.
329 if constants.SOCAT_USE_ESCAPE:
330 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
332 return "echo=0,icanon=0"
335 def _InstanceKVMRuntime(cls, instance_name):
336 """Returns the instance KVM runtime filename
339 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
342 def _InstanceChrootDir(cls, instance_name):
343 """Returns the name of the KVM chroot dir of the instance
346 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
349 def _InstanceNICDir(cls, instance_name):
350 """Returns the name of the directory holding the tap device files for a
354 return utils.PathJoin(cls._NICS_DIR, instance_name)
357 def _InstanceNICFile(cls, instance_name, seq):
358 """Returns the name of the file containing the tap device for a given NIC
361 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
364 def _InstanceKeymapFile(cls, instance_name):
365 """Returns the name of the file containing the keymap for a given instance
368 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
371 def _TryReadUidFile(cls, uid_file):
372 """Try to read a uid file
375 if os.path.exists(uid_file):
377 uid = int(utils.ReadOneLineFile(uid_file))
379 except EnvironmentError:
380 logging.warning("Can't read uid file", exc_info=True)
381 except (TypeError, ValueError):
382 logging.warning("Can't parse uid file contents", exc_info=True)
386 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
387 """Removes an instance's rutime sockets/files/dirs.
390 utils.RemoveFile(pidfile)
391 utils.RemoveFile(cls._InstanceMonitor(instance_name))
392 utils.RemoveFile(cls._InstanceSerial(instance_name))
393 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
394 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
395 uid_file = cls._InstanceUidFile(instance_name)
396 uid = cls._TryReadUidFile(uid_file)
397 utils.RemoveFile(uid_file)
399 uidpool.ReleaseUid(uid)
401 shutil.rmtree(cls._InstanceNICDir(instance_name))
403 if err.errno != errno.ENOENT:
406 chroot_dir = cls._InstanceChrootDir(instance_name)
407 utils.RemoveDir(chroot_dir)
409 if err.errno == errno.ENOTEMPTY:
410 # The chroot directory is expected to be empty, but it isn't.
411 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
414 utils.TimestampForFilename()))
415 logging.warning("The chroot directory of instance %s can not be"
416 " removed as it is not empty. Moving it to the"
417 " quarantine instead. Please investigate the"
418 " contents (%s) and clean up manually",
419 instance_name, new_chroot_dir)
420 utils.RenameFile(chroot_dir, new_chroot_dir)
425 def _ConfigureNIC(instance, seq, nic, tap):
426 """Run the network configuration script for a specified NIC
428 @param instance: instance we're acting on
429 @type instance: instance object
430 @param seq: nic sequence number
432 @param nic: nic we're acting on
433 @type nic: nic object
434 @param tap: the host's tap interface this NIC corresponds to
440 tags = " ".join(instance.tags)
445 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
446 "INSTANCE": instance.name,
448 "MODE": nic.nicparams[constants.NIC_MODE],
450 "INTERFACE_INDEX": str(seq),
457 if nic.nicparams[constants.NIC_LINK]:
458 env["LINK"] = nic.nicparams[constants.NIC_LINK]
460 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
461 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
463 result = utils.RunCmd([constants.KVM_IFUP, tap], env=env)
465 raise errors.HypervisorError("Failed to configure interface %s: %s."
466 " Network configuration script output: %s" %
467 (tap, result.fail_reason, result.output))
469 def ListInstances(self):
470 """Get the list of running instances.
472 We can do this by listing our live instances directory and
473 checking whether the associated kvm process is still alive.
477 for name in os.listdir(self._PIDS_DIR):
478 if self._InstancePidAlive(name)[2]:
482 def GetInstanceInfo(self, instance_name):
483 """Get instance properties.
485 @type instance_name: string
486 @param instance_name: the instance name
487 @rtype: tuple of strings
488 @return: (name, id, memory, vcpus, stat, times)
491 _, pid, alive = self._InstancePidAlive(instance_name)
495 _, memory, vcpus = self._InstancePidInfo(pid)
499 return (instance_name, pid, memory, vcpus, stat, times)
501 def GetAllInstancesInfo(self):
502 """Get properties of all instances.
504 @return: list of tuples (name, id, memory, vcpus, stat, times)
508 for name in os.listdir(self._PIDS_DIR):
510 info = self.GetInstanceInfo(name)
511 except errors.HypervisorError:
517 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
518 """Generate KVM information to start an instance.
521 kvm_version = self._GetKVMVersion()
523 _, v_major, v_min, _ = kvm_version
525 raise errors.HypervisorError("Unable to get KVM version")
527 pidfile = self._InstancePidFile(instance.name)
528 kvm = constants.KVM_PATH
530 # used just by the vnc server, if enabled
531 kvm_cmd.extend(["-name", instance.name])
532 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MEMORY]])
533 kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
534 kvm_cmd.extend(["-pidfile", pidfile])
535 kvm_cmd.extend(["-daemonize"])
536 if not instance.hvparams[constants.HV_ACPI]:
537 kvm_cmd.extend(["-no-acpi"])
539 kvm_cmd.extend(["-S"])
540 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
541 constants.INSTANCE_REBOOT_EXIT:
542 kvm_cmd.extend(["-no-reboot"])
544 hvp = instance.hvparams
545 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
546 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
547 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
548 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
550 if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
551 kvm_cmd.extend(["-enable-kvm"])
552 elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
553 kvm_cmd.extend(["-disable-kvm"])
556 kvm_cmd.extend(["-boot", "n"])
558 disk_type = hvp[constants.HV_DISK_TYPE]
559 if disk_type == constants.HT_DISK_PARAVIRTUAL:
560 if_val = ",if=virtio"
562 if_val = ",if=%s" % disk_type
564 disk_cache = hvp[constants.HV_DISK_CACHE]
565 if instance.disk_template in constants.DTS_EXT_MIRROR:
566 if disk_cache != "none":
567 # TODO: make this a hard error, instead of a silent overwrite
568 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
569 " to prevent shared storage corruption on migration",
571 cache_val = ",cache=none"
572 elif disk_cache != constants.HT_CACHE_DEFAULT:
573 cache_val = ",cache=%s" % disk_cache
576 for cfdev, dev_path in block_devices:
577 if cfdev.mode != constants.DISK_RDWR:
578 raise errors.HypervisorError("Instance has read-only disks which"
579 " are not supported by KVM")
580 # TODO: handle FD_LOOP and FD_BLKTAP (?)
583 kvm_cmd.extend(["-boot", "c"])
585 if (v_major, v_min) < (0, 14) and disk_type != constants.HT_DISK_IDE:
586 boot_val = ",boot=on"
588 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
590 kvm_cmd.extend(["-drive", drive_val])
592 #Now we can specify a different device type for CDROM devices.
593 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
594 if not cdrom_disk_type:
595 cdrom_disk_type = disk_type
597 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
599 options = ",format=raw,media=cdrom"
601 kvm_cmd.extend(["-boot", "d"])
602 if cdrom_disk_type != constants.HT_DISK_IDE:
603 options = "%s,boot=on,if=%s" % (options, constants.HT_DISK_IDE)
605 options = "%s,boot=on" % options
607 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
608 if_val = ",if=virtio"
610 if_val = ",if=%s" % cdrom_disk_type
611 options = "%s%s" % (options, if_val)
612 drive_val = "file=%s%s" % (iso_image, options)
613 kvm_cmd.extend(["-drive", drive_val])
615 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
617 options = ",format=raw,media=cdrom"
618 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
619 if_val = ",if=virtio"
621 if_val = ",if=%s" % cdrom_disk_type
622 options = "%s%s" % (options, if_val)
623 drive_val = "file=%s%s" % (iso_image2, options)
624 kvm_cmd.extend(["-drive", drive_val])
626 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
628 options = ",format=raw,media=disk"
630 kvm_cmd.extend(["-boot", "a"])
631 options = "%s,boot=on" % options
632 if_val = ",if=floppy"
633 options = "%s%s" % (options, if_val)
634 drive_val = "file=%s%s" % (floppy_image, options)
635 kvm_cmd.extend(["-drive", drive_val])
637 kernel_path = hvp[constants.HV_KERNEL_PATH]
639 kvm_cmd.extend(["-kernel", kernel_path])
640 initrd_path = hvp[constants.HV_INITRD_PATH]
642 kvm_cmd.extend(["-initrd", initrd_path])
643 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
644 hvp[constants.HV_KERNEL_ARGS]]
645 if hvp[constants.HV_SERIAL_CONSOLE]:
646 root_append.append("console=ttyS0,38400")
647 kvm_cmd.extend(["-append", " ".join(root_append)])
649 mem_path = hvp[constants.HV_MEM_PATH]
651 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
653 mouse_type = hvp[constants.HV_USB_MOUSE]
654 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
657 kvm_cmd.extend(["-usb"])
658 kvm_cmd.extend(["-usbdevice", mouse_type])
659 elif vnc_bind_address:
660 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
662 keymap = hvp[constants.HV_KEYMAP]
664 keymap_path = self._InstanceKeymapFile(instance.name)
665 # If a keymap file is specified, KVM won't use its internal defaults. By
666 # first including the "en-us" layout, an error on loading the actual
667 # layout (e.g. because it can't be found) won't lead to a non-functional
668 # keyboard. A keyboard with incorrect keys is still better than none.
669 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
670 kvm_cmd.extend(["-k", keymap_path])
673 if netutils.IP4Address.IsValid(vnc_bind_address):
674 if instance.network_port > constants.VNC_BASE_PORT:
675 display = instance.network_port - constants.VNC_BASE_PORT
676 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
677 vnc_arg = ":%d" % (display)
679 vnc_arg = "%s:%d" % (vnc_bind_address, display)
681 logging.error("Network port is not a valid VNC display (%d < %d)."
682 " Not starting VNC", instance.network_port,
683 constants.VNC_BASE_PORT)
686 # Only allow tls and other option when not binding to a file, for now.
687 # kvm/qemu gets confused otherwise about the filename to use.
689 if hvp[constants.HV_VNC_TLS]:
690 vnc_append = "%s,tls" % vnc_append
691 if hvp[constants.HV_VNC_X509_VERIFY]:
692 vnc_append = "%s,x509verify=%s" % (vnc_append,
693 hvp[constants.HV_VNC_X509])
694 elif hvp[constants.HV_VNC_X509]:
695 vnc_append = "%s,x509=%s" % (vnc_append,
696 hvp[constants.HV_VNC_X509])
697 if hvp[constants.HV_VNC_PASSWORD_FILE]:
698 vnc_append = "%s,password" % vnc_append
700 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
703 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
705 kvm_cmd.extend(["-vnc", vnc_arg])
707 kvm_cmd.extend(["-nographic"])
709 monitor_dev = ("unix:%s,server,nowait" %
710 self._InstanceMonitor(instance.name))
711 kvm_cmd.extend(["-monitor", monitor_dev])
712 if hvp[constants.HV_SERIAL_CONSOLE]:
713 serial_dev = ("unix:%s,server,nowait" %
714 self._InstanceSerial(instance.name))
715 kvm_cmd.extend(["-serial", serial_dev])
717 kvm_cmd.extend(["-serial", "none"])
719 if hvp[constants.HV_USE_LOCALTIME]:
720 kvm_cmd.extend(["-localtime"])
722 if hvp[constants.HV_KVM_USE_CHROOT]:
723 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
725 # Save the current instance nics, but defer their expansion as parameters,
726 # as we'll need to generate executable temp files for them.
727 kvm_nics = instance.nics
730 return (kvm_cmd, kvm_nics, hvparams)
732 def _WriteKVMRuntime(self, instance_name, data):
733 """Write an instance's KVM runtime
737 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
739 except EnvironmentError, err:
740 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
742 def _ReadKVMRuntime(self, instance_name):
743 """Read an instance's KVM runtime
747 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
748 except EnvironmentError, err:
749 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
752 def _SaveKVMRuntime(self, instance, kvm_runtime):
753 """Save an instance's KVM runtime
756 kvm_cmd, kvm_nics, hvparams = kvm_runtime
757 serialized_nics = [nic.ToDict() for nic in kvm_nics]
758 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
759 self._WriteKVMRuntime(instance.name, serialized_form)
761 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
762 """Load an instance's KVM runtime
765 if not serialized_runtime:
766 serialized_runtime = self._ReadKVMRuntime(instance.name)
767 loaded_runtime = serializer.Load(serialized_runtime)
768 kvm_cmd, serialized_nics, hvparams = loaded_runtime
769 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
770 return (kvm_cmd, kvm_nics, hvparams)
772 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
773 """Run the KVM cmd and check for errors
776 @param name: instance name
777 @type kvm_cmd: list of strings
778 @param kvm_cmd: runcmd input for kvm
779 @type tap_fds: list of int
780 @param tap_fds: fds of tap devices opened by Ganeti
784 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
787 utils_wrapper.CloseFdNoError(fd)
790 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
791 (name, result.fail_reason, result.output))
792 if not self._InstancePidAlive(name)[2]:
793 raise errors.HypervisorError("Failed to start instance %s" % name)
795 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
796 """Execute a KVM cmd, after completing it with some last minute data
798 @type incoming: tuple of strings
799 @param incoming: (target_host_ip, port)
802 # Small _ExecuteKVMRuntime hv parameters programming howto:
803 # - conf_hvp contains the parameters as configured on ganeti. they might
804 # have changed since the instance started; only use them if the change
805 # won't affect the inside of the instance (which hasn't been rebooted).
806 # - up_hvp contains the parameters as they were when the instance was
807 # started, plus any new parameter which has been added between ganeti
808 # versions: it is paramount that those default to a value which won't
809 # affect the inside of the instance as well.
810 conf_hvp = instance.hvparams
812 self._CheckDown(name)
816 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
817 up_hvp = objects.FillDict(conf_hvp, up_hvp)
819 kvm_version = self._GetKVMVersion()
821 _, v_major, v_min, _ = kvm_version
823 raise errors.HypervisorError("Unable to get KVM version")
825 # We know it's safe to run as a different user upon migration, so we'll use
826 # the latest conf, from conf_hvp.
827 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
828 if security_model == constants.HT_SM_USER:
829 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
831 # We have reasons to believe changing something like the nic driver/type
832 # upon migration won't exactly fly with the instance kernel, so for nic
833 # related parameters we'll use up_hvp
837 kvm_cmd.extend(["-net", "none"])
841 nic_type = up_hvp[constants.HV_NIC_TYPE]
842 if nic_type == constants.HT_NIC_PARAVIRTUAL:
843 # From version 0.12.0, kvm uses a new sintax for network configuration.
844 if (v_major, v_min) >= (0, 12):
845 nic_model = "virtio-net-pci"
850 if up_hvp[constants.HV_VHOST_NET]:
851 # vhost_net is only available from version 0.13.0 or newer
852 if (v_major, v_min) >= (0, 13):
853 tap_extra = ",vhost=on"
855 raise errors.HypervisorError("vhost_net is configured"
856 " but it is not available")
860 for nic_seq, nic in enumerate(kvm_nics):
861 tapname, tapfd = _OpenTap(vnet_hdr)
864 if (v_major, v_min) >= (0, 12):
865 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
866 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
867 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
869 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
871 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
872 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
875 target, port = incoming
876 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
878 # Changing the vnc password doesn't bother the guest that much. At most it
879 # will surprise people who connect to it. Whether positively or negatively
881 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
885 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
886 except EnvironmentError, err:
887 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
888 % (vnc_pwd_file, err))
890 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
891 utils.EnsureDirs([(self._InstanceChrootDir(name),
892 constants.SECURE_DIR_MODE)])
894 # Configure the network now for starting instances and bridged interfaces,
895 # during FinalizeMigration for incoming instances' routed interfaces
896 for nic_seq, nic in enumerate(kvm_nics):
898 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
900 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
902 if security_model == constants.HT_SM_POOL:
903 ss = ssconf.SimpleStore()
904 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
905 all_uids = set(uidpool.ExpandUidPool(uid_pool))
906 uid = uidpool.RequestUnusedUid(all_uids)
908 username = pwd.getpwuid(uid.GetUid()).pw_name
909 kvm_cmd.extend(["-runas", username])
910 self._RunKVMCmd(name, kvm_cmd, tapfds)
912 uidpool.ReleaseUid(uid)
916 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
918 self._RunKVMCmd(name, kvm_cmd, tapfds)
920 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
921 constants.RUN_DIRS_MODE)])
922 for nic_seq, tap in enumerate(taps):
923 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
927 change_cmd = "change vnc password %s" % vnc_pwd
928 self._CallMonitorCommand(instance.name, change_cmd)
930 for filename in temp_files:
931 utils.RemoveFile(filename)
933 def StartInstance(self, instance, block_devices, startup_paused):
934 """Start an instance.
937 self._CheckDown(instance.name)
938 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
940 self._SaveKVMRuntime(instance, kvm_runtime)
941 self._ExecuteKVMRuntime(instance, kvm_runtime)
943 def _CallMonitorCommand(self, instance_name, command):
944 """Invoke a command on the instance monitor.
947 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
948 (utils.ShellQuote(command),
949 constants.SOCAT_PATH,
950 utils.ShellQuote(self._InstanceMonitor(instance_name))))
951 result = utils.RunCmd(socat)
953 msg = ("Failed to send command '%s' to instance %s."
954 " output: %s, error: %s, fail_reason: %s" %
955 (command, instance_name,
956 result.stdout, result.stderr, result.fail_reason))
957 raise errors.HypervisorError(msg)
962 def _GetKVMVersion(cls):
963 """Return the installed KVM version
965 @return: (version, v_maj, v_min, v_rev), or None
968 result = utils.RunCmd([constants.KVM_PATH, "--help"])
971 match = cls._VERSION_RE.search(result.output.splitlines()[0])
975 return (match.group(0), int(match.group(1)), int(match.group(2)),
978 def StopInstance(self, instance, force=False, retry=False, name=None):
982 if name is not None and not force:
983 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
986 acpi = instance.hvparams[constants.HV_ACPI]
989 _, pid, alive = self._InstancePidAlive(name)
990 if pid > 0 and alive:
991 if force or not acpi:
992 utils.KillProcess(pid)
994 self._CallMonitorCommand(name, "system_powerdown")
996 def CleanupInstance(self, instance_name):
997 """Cleanup after a stopped instance
1000 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1001 if pid > 0 and alive:
1002 raise errors.HypervisorError("Cannot cleanup a live instance")
1003 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1005 def RebootInstance(self, instance):
1006 """Reboot an instance.
1009 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1010 # socket the instance will stop, but now power up again. So we'll resort
1011 # to shutdown and restart.
1012 _, _, alive = self._InstancePidAlive(instance.name)
1014 raise errors.HypervisorError("Failed to reboot instance %s:"
1015 " not running" % instance.name)
1016 # StopInstance will delete the saved KVM runtime so:
1017 # ...first load it...
1018 kvm_runtime = self._LoadKVMRuntime(instance)
1019 # ...now we can safely call StopInstance...
1020 if not self.StopInstance(instance):
1021 self.StopInstance(instance, force=True)
1022 # ...and finally we can save it again, and execute it...
1023 self._SaveKVMRuntime(instance, kvm_runtime)
1024 self._ExecuteKVMRuntime(instance, kvm_runtime)
1026 def MigrationInfo(self, instance):
1027 """Get instance information to perform a migration.
1029 @type instance: L{objects.Instance}
1030 @param instance: instance to be migrated
1032 @return: content of the KVM runtime file
1035 return self._ReadKVMRuntime(instance.name)
1037 def AcceptInstance(self, instance, info, target):
1038 """Prepare to accept an instance.
1040 @type instance: L{objects.Instance}
1041 @param instance: instance to be accepted
1043 @param info: content of the KVM runtime file on the source node
1044 @type target: string
1045 @param target: target host (usually ip), on this node
1048 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1049 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1050 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1052 def FinalizeMigration(self, instance, info, success):
1053 """Finalize an instance migration.
1055 Stop the incoming mode KVM.
1057 @type instance: L{objects.Instance}
1058 @param instance: instance whose migration is being finalized
1062 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1063 kvm_nics = kvm_runtime[1]
1065 for nic_seq, nic in enumerate(kvm_nics):
1066 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1067 # Bridged interfaces have already been configured
1070 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1071 except EnvironmentError, err:
1072 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1073 instance.name, nic_seq, str(err))
1076 self._ConfigureNIC(instance, nic_seq, nic, tap)
1077 except errors.HypervisorError, err:
1078 logging.warning(str(err))
1080 self._WriteKVMRuntime(instance.name, info)
1082 self.StopInstance(instance, force=True)
1084 def MigrateInstance(self, instance, target, live):
1085 """Migrate an instance to a target node.
1087 The migration will not be attempted if the instance is not
1090 @type instance: L{objects.Instance}
1091 @param instance: the instance to be migrated
1092 @type target: string
1093 @param target: ip address of the target node
1095 @param live: perform a live migration
1098 instance_name = instance.name
1099 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1100 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1102 raise errors.HypervisorError("Instance not running, cannot migrate")
1105 self._CallMonitorCommand(instance_name, "stop")
1107 migrate_command = ("migrate_set_speed %dm" %
1108 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1109 self._CallMonitorCommand(instance_name, migrate_command)
1111 migrate_command = ("migrate_set_downtime %dms" %
1112 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1113 self._CallMonitorCommand(instance_name, migrate_command)
1115 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1116 self._CallMonitorCommand(instance_name, migrate_command)
1118 info_command = "info migrate"
1122 result = self._CallMonitorCommand(instance_name, info_command)
1123 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1126 if not result.stdout:
1127 logging.info("KVM: empty 'info migrate' result")
1129 logging.warning("KVM: unknown 'info migrate' result: %s",
1131 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1133 status = match.group(1)
1134 if status == "completed":
1136 elif status == "active":
1137 # reset the broken answers count
1139 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1140 elif status == "failed" or status == "cancelled":
1142 self._CallMonitorCommand(instance_name, 'cont')
1143 raise errors.HypervisorError("Migration %s at the kvm level" %
1146 logging.warning("KVM: unknown migration status '%s'", status)
1148 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1149 if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
1150 raise errors.HypervisorError("Too many 'info migrate' broken answers")
1152 utils.KillProcess(pid)
1153 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1155 def GetNodeInfo(self):
1156 """Return information about the node.
1158 This is just a wrapper over the base GetLinuxNodeInfo method.
1160 @return: a dict with the following keys (values in MiB):
1161 - memory_total: the total memory size on the node
1162 - memory_free: the available memory on the node for instances
1163 - memory_dom0: the memory used by the node itself, if available
1166 return self.GetLinuxNodeInfo()
1169 def GetInstanceConsole(cls, instance, hvparams, beparams):
1170 """Return a command for connecting to the console of an instance.
1173 if hvparams[constants.HV_SERIAL_CONSOLE]:
1174 cmd = [constants.KVM_CONSOLE_WRAPPER,
1175 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1176 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1177 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1178 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1179 return objects.InstanceConsole(instance=instance.name,
1180 kind=constants.CONS_SSH,
1181 host=instance.primary_node,
1182 user=constants.GANETI_RUNAS,
1185 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1186 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1187 display = instance.network_port - constants.VNC_BASE_PORT
1188 return objects.InstanceConsole(instance=instance.name,
1189 kind=constants.CONS_VNC,
1190 host=vnc_bind_address,
1191 port=instance.network_port,
1194 return objects.InstanceConsole(instance=instance.name,
1195 kind=constants.CONS_MESSAGE,
1196 message=("No serial shell for instance %s" %
1200 """Verify the hypervisor.
1202 Check that the binary exists.
1205 if not os.path.exists(constants.KVM_PATH):
1206 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1207 if not os.path.exists(constants.SOCAT_PATH):
1208 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1211 def CheckParameterSyntax(cls, hvparams):
1212 """Check the given parameters for validity.
1214 @type hvparams: dict
1215 @param hvparams: dictionary with parameter names/value
1216 @raise errors.HypervisorError: when a parameter is not valid
1219 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1221 kernel_path = hvparams[constants.HV_KERNEL_PATH]
1223 if not hvparams[constants.HV_ROOT_PATH]:
1224 raise errors.HypervisorError("Need a root partition for the instance,"
1225 " if a kernel is defined")
1227 if (hvparams[constants.HV_VNC_X509_VERIFY] and
1228 not hvparams[constants.HV_VNC_X509]):
1229 raise errors.HypervisorError("%s must be defined, if %s is" %
1230 (constants.HV_VNC_X509,
1231 constants.HV_VNC_X509_VERIFY))
1233 boot_order = hvparams[constants.HV_BOOT_ORDER]
1234 if (boot_order == constants.HT_BO_CDROM and
1235 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1236 raise errors.HypervisorError("Cannot boot from cdrom without an"
1239 security_model = hvparams[constants.HV_SECURITY_MODEL]
1240 if security_model == constants.HT_SM_USER:
1241 if not hvparams[constants.HV_SECURITY_DOMAIN]:
1242 raise errors.HypervisorError("A security domain (user to run kvm as)"
1243 " must be specified")
1244 elif (security_model == constants.HT_SM_NONE or
1245 security_model == constants.HT_SM_POOL):
1246 if hvparams[constants.HV_SECURITY_DOMAIN]:
1247 raise errors.HypervisorError("Cannot have a security domain when the"
1248 " security model is 'none' or 'pool'")
1251 def ValidateParameters(cls, hvparams):
1252 """Check the given parameters for validity.
1254 @type hvparams: dict
1255 @param hvparams: dictionary with parameter names/value
1256 @raise errors.HypervisorError: when a parameter is not valid
1259 super(KVMHypervisor, cls).ValidateParameters(hvparams)
1261 security_model = hvparams[constants.HV_SECURITY_MODEL]
1262 if security_model == constants.HT_SM_USER:
1263 username = hvparams[constants.HV_SECURITY_DOMAIN]
1265 pwd.getpwnam(username)
1267 raise errors.HypervisorError("Unknown security domain user %s"
1271 def PowercycleNode(cls):
1272 """KVM powercycle, just a wrapper over Linux powercycle.
1275 cls.LinuxPowercycle()