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.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,
199 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
201 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
202 _MIGRATION_INFO_RETRY_DELAY = 2
204 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)\.(\d+)\b")
211 hv_base.BaseHypervisor.__init__(self)
212 # Let's make sure the directories we need exist, even if the RUN_DIR lives
213 # in a tmpfs filesystem or has been otherwise wiped out.
214 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
215 utils.EnsureDirs(dirs)
218 def _InstancePidFile(cls, instance_name):
219 """Returns the instance pidfile.
222 return utils.PathJoin(cls._PIDS_DIR, instance_name)
225 def _InstanceUidFile(cls, instance_name):
226 """Returns the instance uidfile.
229 return utils.PathJoin(cls._UIDS_DIR, instance_name)
232 def _InstancePidInfo(cls, pid):
233 """Check pid file for instance information.
235 Check that a pid file is associated with an instance, and retrieve
236 information from its command line.
238 @type pid: string or int
239 @param pid: process id of the instance to check
241 @return: (instance_name, memory, vcpus)
242 @raise errors.HypervisorError: when an instance cannot be found
245 alive = utils.IsProcessAlive(pid)
247 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
249 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
251 cmdline = utils.ReadFile(cmdline_file)
252 except EnvironmentError, err:
253 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
260 arg_list = cmdline.split("\x00")
262 arg = arg_list.pop(0)
264 instance = arg_list.pop(0)
266 memory = int(arg_list.pop(0))
268 vcpus = int(arg_list.pop(0))
271 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
274 return (instance, memory, vcpus)
276 def _InstancePidAlive(self, instance_name):
277 """Returns the instance pidfile, pid, and liveness.
279 @type instance_name: string
280 @param instance_name: instance name
282 @return: (pid file name, pid, liveness)
285 pidfile = self._InstancePidFile(instance_name)
286 pid = utils.ReadPidFile(pidfile)
290 cmd_instance = self._InstancePidInfo(pid)[0]
291 alive = (cmd_instance == instance_name)
292 except errors.HypervisorError:
295 return (pidfile, pid, alive)
297 def _CheckDown(self, instance_name):
298 """Raises an error unless the given instance is down.
301 alive = self._InstancePidAlive(instance_name)[2]
303 raise errors.HypervisorError("Failed to start instance %s: %s" %
304 (instance_name, "already running"))
307 def _InstanceMonitor(cls, instance_name):
308 """Returns the instance monitor socket name
311 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
314 def _InstanceSerial(cls, instance_name):
315 """Returns the instance serial socket name
318 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
321 def _SocatUnixConsoleParams():
322 """Returns the correct parameters for socat
324 If we have a new-enough socat we can use raw mode with an escape character.
327 if constants.SOCAT_USE_ESCAPE:
328 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
330 return "echo=0,icanon=0"
333 def _InstanceKVMRuntime(cls, instance_name):
334 """Returns the instance KVM runtime filename
337 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
340 def _InstanceChrootDir(cls, instance_name):
341 """Returns the name of the KVM chroot dir of the instance
344 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
347 def _InstanceNICDir(cls, instance_name):
348 """Returns the name of the directory holding the tap device files for a
352 return utils.PathJoin(cls._NICS_DIR, instance_name)
355 def _InstanceNICFile(cls, instance_name, seq):
356 """Returns the name of the file containing the tap device for a given NIC
359 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
362 def _InstanceKeymapFile(cls, instance_name):
363 """Returns the name of the file containing the keymap for a given instance
366 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
369 def _TryReadUidFile(cls, uid_file):
370 """Try to read a uid file
373 if os.path.exists(uid_file):
375 uid = int(utils.ReadOneLineFile(uid_file))
377 except EnvironmentError:
378 logging.warning("Can't read uid file", exc_info=True)
379 except (TypeError, ValueError):
380 logging.warning("Can't parse uid file contents", exc_info=True)
384 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
385 """Removes an instance's rutime sockets/files/dirs.
388 utils.RemoveFile(pidfile)
389 utils.RemoveFile(cls._InstanceMonitor(instance_name))
390 utils.RemoveFile(cls._InstanceSerial(instance_name))
391 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
392 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
393 uid_file = cls._InstanceUidFile(instance_name)
394 uid = cls._TryReadUidFile(uid_file)
395 utils.RemoveFile(uid_file)
397 uidpool.ReleaseUid(uid)
399 shutil.rmtree(cls._InstanceNICDir(instance_name))
401 if err.errno != errno.ENOENT:
404 chroot_dir = cls._InstanceChrootDir(instance_name)
405 utils.RemoveDir(chroot_dir)
407 if err.errno == errno.ENOTEMPTY:
408 # The chroot directory is expected to be empty, but it isn't.
409 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
412 utils.TimestampForFilename()))
413 logging.warning("The chroot directory of instance %s can not be"
414 " removed as it is not empty. Moving it to the"
415 " quarantine instead. Please investigate the"
416 " contents (%s) and clean up manually",
417 instance_name, new_chroot_dir)
418 utils.RenameFile(chroot_dir, new_chroot_dir)
423 def _ConfigureNIC(instance, seq, nic, tap):
424 """Run the network configuration script for a specified NIC
426 @param instance: instance we're acting on
427 @type instance: instance object
428 @param seq: nic sequence number
430 @param nic: nic we're acting on
431 @type nic: nic object
432 @param tap: the host's tap interface this NIC corresponds to
438 tags = " ".join(instance.tags)
443 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
444 "INSTANCE": instance.name,
446 "MODE": nic.nicparams[constants.NIC_MODE],
448 "INTERFACE_INDEX": str(seq),
455 if nic.nicparams[constants.NIC_LINK]:
456 env["LINK"] = nic.nicparams[constants.NIC_LINK]
458 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
459 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
461 result = utils.RunCmd([constants.KVM_IFUP, tap], env=env)
463 raise errors.HypervisorError("Failed to configure interface %s: %s."
464 " Network configuration script output: %s" %
465 (tap, result.fail_reason, result.output))
467 def ListInstances(self):
468 """Get the list of running instances.
470 We can do this by listing our live instances directory and
471 checking whether the associated kvm process is still alive.
475 for name in os.listdir(self._PIDS_DIR):
476 if self._InstancePidAlive(name)[2]:
480 def GetInstanceInfo(self, instance_name):
481 """Get instance properties.
483 @type instance_name: string
484 @param instance_name: the instance name
485 @rtype: tuple of strings
486 @return: (name, id, memory, vcpus, stat, times)
489 _, pid, alive = self._InstancePidAlive(instance_name)
493 _, memory, vcpus = self._InstancePidInfo(pid)
497 return (instance_name, pid, memory, vcpus, stat, times)
499 def GetAllInstancesInfo(self):
500 """Get properties of all instances.
502 @return: list of tuples (name, id, memory, vcpus, stat, times)
506 for name in os.listdir(self._PIDS_DIR):
508 info = self.GetInstanceInfo(name)
509 except errors.HypervisorError:
515 def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
516 """Generate KVM information to start an instance.
519 kvm_version = self._GetKVMVersion()
521 _, v_major, v_min, _ = kvm_version
523 raise errors.HypervisorError("Unable to get KVM version")
525 pidfile = self._InstancePidFile(instance.name)
526 kvm = constants.KVM_PATH
528 # used just by the vnc server, if enabled
529 kvm_cmd.extend(["-name", instance.name])
530 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MEMORY]])
531 kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
532 kvm_cmd.extend(["-pidfile", pidfile])
533 kvm_cmd.extend(["-daemonize"])
534 if not instance.hvparams[constants.HV_ACPI]:
535 kvm_cmd.extend(["-no-acpi"])
537 kvm_cmd.extend(["-S"])
539 hvp = instance.hvparams
540 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
541 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
542 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
543 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
545 if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
546 kvm_cmd.extend(["-enable-kvm"])
547 elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
548 kvm_cmd.extend(["-disable-kvm"])
551 kvm_cmd.extend(["-boot", "n"])
553 disk_type = hvp[constants.HV_DISK_TYPE]
554 if disk_type == constants.HT_DISK_PARAVIRTUAL:
555 if_val = ",if=virtio"
557 if_val = ",if=%s" % disk_type
559 disk_cache = hvp[constants.HV_DISK_CACHE]
560 if instance.disk_template in constants.DTS_EXT_MIRROR:
561 if disk_cache != "none":
562 # TODO: make this a hard error, instead of a silent overwrite
563 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
564 " to prevent shared storage corruption on migration",
566 cache_val = ",cache=none"
567 elif disk_cache != constants.HT_CACHE_DEFAULT:
568 cache_val = ",cache=%s" % disk_cache
571 for cfdev, dev_path in block_devices:
572 if cfdev.mode != constants.DISK_RDWR:
573 raise errors.HypervisorError("Instance has read-only disks which"
574 " are not supported by KVM")
575 # TODO: handle FD_LOOP and FD_BLKTAP (?)
578 kvm_cmd.extend(["-boot", "c"])
580 if (v_major, v_min) < (0, 14) and disk_type != constants.HT_DISK_IDE:
581 boot_val = ",boot=on"
583 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
585 kvm_cmd.extend(["-drive", drive_val])
587 #Now we can specify a different device type for CDROM devices.
588 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
589 if not cdrom_disk_type:
590 cdrom_disk_type = disk_type
592 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
594 options = ",format=raw,media=cdrom"
596 kvm_cmd.extend(["-boot", "d"])
597 if cdrom_disk_type != constants.HT_DISK_IDE:
598 options = "%s,boot=on,if=%s" % (options, constants.HT_DISK_IDE)
600 options = "%s,boot=on" % options
602 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
603 if_val = ",if=virtio"
605 if_val = ",if=%s" % cdrom_disk_type
606 options = "%s%s" % (options, if_val)
607 drive_val = "file=%s%s" % (iso_image, options)
608 kvm_cmd.extend(["-drive", drive_val])
610 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
612 options = ",format=raw,media=cdrom"
613 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
614 if_val = ",if=virtio"
616 if_val = ",if=%s" % cdrom_disk_type
617 options = "%s%s" % (options, if_val)
618 drive_val = "file=%s%s" % (iso_image2, options)
619 kvm_cmd.extend(["-drive", drive_val])
621 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
623 options = ",format=raw,media=disk"
625 kvm_cmd.extend(["-boot", "a"])
626 options = "%s,boot=on" % options
627 if_val = ",if=floppy"
628 options = "%s%s" % (options, if_val)
629 drive_val = "file=%s%s" % (floppy_image, options)
630 kvm_cmd.extend(["-drive", drive_val])
632 kernel_path = hvp[constants.HV_KERNEL_PATH]
634 kvm_cmd.extend(["-kernel", kernel_path])
635 initrd_path = hvp[constants.HV_INITRD_PATH]
637 kvm_cmd.extend(["-initrd", initrd_path])
638 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
639 hvp[constants.HV_KERNEL_ARGS]]
640 if hvp[constants.HV_SERIAL_CONSOLE]:
641 root_append.append("console=ttyS0,38400")
642 kvm_cmd.extend(["-append", " ".join(root_append)])
644 mem_path = hvp[constants.HV_MEM_PATH]
646 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
648 mouse_type = hvp[constants.HV_USB_MOUSE]
649 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
652 kvm_cmd.extend(["-usb"])
653 kvm_cmd.extend(["-usbdevice", mouse_type])
654 elif vnc_bind_address:
655 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
657 keymap = hvp[constants.HV_KEYMAP]
659 keymap_path = self._InstanceKeymapFile(instance.name)
660 # If a keymap file is specified, KVM won't use its internal defaults. By
661 # first including the "en-us" layout, an error on loading the actual
662 # layout (e.g. because it can't be found) won't lead to a non-functional
663 # keyboard. A keyboard with incorrect keys is still better than none.
664 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
665 kvm_cmd.extend(["-k", keymap_path])
668 if netutils.IP4Address.IsValid(vnc_bind_address):
669 if instance.network_port > constants.VNC_BASE_PORT:
670 display = instance.network_port - constants.VNC_BASE_PORT
671 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
672 vnc_arg = ":%d" % (display)
674 vnc_arg = "%s:%d" % (vnc_bind_address, display)
676 logging.error("Network port is not a valid VNC display (%d < %d)."
677 " Not starting VNC", instance.network_port,
678 constants.VNC_BASE_PORT)
681 # Only allow tls and other option when not binding to a file, for now.
682 # kvm/qemu gets confused otherwise about the filename to use.
684 if hvp[constants.HV_VNC_TLS]:
685 vnc_append = "%s,tls" % vnc_append
686 if hvp[constants.HV_VNC_X509_VERIFY]:
687 vnc_append = "%s,x509verify=%s" % (vnc_append,
688 hvp[constants.HV_VNC_X509])
689 elif hvp[constants.HV_VNC_X509]:
690 vnc_append = "%s,x509=%s" % (vnc_append,
691 hvp[constants.HV_VNC_X509])
692 if hvp[constants.HV_VNC_PASSWORD_FILE]:
693 vnc_append = "%s,password" % vnc_append
695 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
698 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
700 kvm_cmd.extend(["-vnc", vnc_arg])
702 kvm_cmd.extend(["-nographic"])
704 monitor_dev = ("unix:%s,server,nowait" %
705 self._InstanceMonitor(instance.name))
706 kvm_cmd.extend(["-monitor", monitor_dev])
707 if hvp[constants.HV_SERIAL_CONSOLE]:
708 serial_dev = ("unix:%s,server,nowait" %
709 self._InstanceSerial(instance.name))
710 kvm_cmd.extend(["-serial", serial_dev])
712 kvm_cmd.extend(["-serial", "none"])
714 if hvp[constants.HV_USE_LOCALTIME]:
715 kvm_cmd.extend(["-localtime"])
717 if hvp[constants.HV_KVM_USE_CHROOT]:
718 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
720 # Save the current instance nics, but defer their expansion as parameters,
721 # as we'll need to generate executable temp files for them.
722 kvm_nics = instance.nics
725 return (kvm_cmd, kvm_nics, hvparams)
727 def _WriteKVMRuntime(self, instance_name, data):
728 """Write an instance's KVM runtime
732 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
734 except EnvironmentError, err:
735 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
737 def _ReadKVMRuntime(self, instance_name):
738 """Read an instance's KVM runtime
742 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
743 except EnvironmentError, err:
744 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
747 def _SaveKVMRuntime(self, instance, kvm_runtime):
748 """Save an instance's KVM runtime
751 kvm_cmd, kvm_nics, hvparams = kvm_runtime
752 serialized_nics = [nic.ToDict() for nic in kvm_nics]
753 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
754 self._WriteKVMRuntime(instance.name, serialized_form)
756 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
757 """Load an instance's KVM runtime
760 if not serialized_runtime:
761 serialized_runtime = self._ReadKVMRuntime(instance.name)
762 loaded_runtime = serializer.Load(serialized_runtime)
763 kvm_cmd, serialized_nics, hvparams = loaded_runtime
764 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
765 return (kvm_cmd, kvm_nics, hvparams)
767 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
768 """Run the KVM cmd and check for errors
771 @param name: instance name
772 @type kvm_cmd: list of strings
773 @param kvm_cmd: runcmd input for kvm
774 @type tap_fds: list of int
775 @param tap_fds: fds of tap devices opened by Ganeti
779 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
782 utils_wrapper.CloseFdNoError(fd)
785 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
786 (name, result.fail_reason, result.output))
787 if not self._InstancePidAlive(name)[2]:
788 raise errors.HypervisorError("Failed to start instance %s" % name)
790 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
791 """Execute a KVM cmd, after completing it with some last minute data
793 @type incoming: tuple of strings
794 @param incoming: (target_host_ip, port)
797 # Small _ExecuteKVMRuntime hv parameters programming howto:
798 # - conf_hvp contains the parameters as configured on ganeti. they might
799 # have changed since the instance started; only use them if the change
800 # won't affect the inside of the instance (which hasn't been rebooted).
801 # - up_hvp contains the parameters as they were when the instance was
802 # started, plus any new parameter which has been added between ganeti
803 # versions: it is paramount that those default to a value which won't
804 # affect the inside of the instance as well.
805 conf_hvp = instance.hvparams
807 self._CheckDown(name)
811 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
812 up_hvp = objects.FillDict(conf_hvp, up_hvp)
814 kvm_version = self._GetKVMVersion()
816 _, v_major, v_min, _ = kvm_version
818 raise errors.HypervisorError("Unable to get KVM version")
820 # We know it's safe to run as a different user upon migration, so we'll use
821 # the latest conf, from conf_hvp.
822 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
823 if security_model == constants.HT_SM_USER:
824 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
826 # We have reasons to believe changing something like the nic driver/type
827 # upon migration won't exactly fly with the instance kernel, so for nic
828 # related parameters we'll use up_hvp
832 kvm_cmd.extend(["-net", "none"])
836 nic_type = up_hvp[constants.HV_NIC_TYPE]
837 if nic_type == constants.HT_NIC_PARAVIRTUAL:
838 # From version 0.12.0, kvm uses a new sintax for network configuration.
839 if (v_major, v_min) >= (0, 12):
840 nic_model = "virtio-net-pci"
845 if up_hvp[constants.HV_VHOST_NET]:
846 # vhost_net is only available from version 0.13.0 or newer
847 if (v_major, v_min) >= (0, 13):
848 tap_extra = ",vhost=on"
850 raise errors.HypervisorError("vhost_net is configured"
851 " but it is not available")
855 for nic_seq, nic in enumerate(kvm_nics):
856 tapname, tapfd = _OpenTap(vnet_hdr)
859 if (v_major, v_min) >= (0, 12):
860 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
861 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
862 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
864 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
866 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
867 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
870 target, port = incoming
871 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
873 # Changing the vnc password doesn't bother the guest that much. At most it
874 # will surprise people who connect to it. Whether positively or negatively
876 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
880 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
881 except EnvironmentError, err:
882 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
883 % (vnc_pwd_file, err))
885 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
886 utils.EnsureDirs([(self._InstanceChrootDir(name),
887 constants.SECURE_DIR_MODE)])
889 # Configure the network now for starting instances and bridged interfaces,
890 # during FinalizeMigration for incoming instances' routed interfaces
891 for nic_seq, nic in enumerate(kvm_nics):
893 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
895 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
897 if security_model == constants.HT_SM_POOL:
898 ss = ssconf.SimpleStore()
899 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
900 all_uids = set(uidpool.ExpandUidPool(uid_pool))
901 uid = uidpool.RequestUnusedUid(all_uids)
903 username = pwd.getpwuid(uid.GetUid()).pw_name
904 kvm_cmd.extend(["-runas", username])
905 self._RunKVMCmd(name, kvm_cmd, tapfds)
907 uidpool.ReleaseUid(uid)
911 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
913 self._RunKVMCmd(name, kvm_cmd, tapfds)
915 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
916 constants.RUN_DIRS_MODE)])
917 for nic_seq, tap in enumerate(taps):
918 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
922 change_cmd = "change vnc password %s" % vnc_pwd
923 self._CallMonitorCommand(instance.name, change_cmd)
925 for filename in temp_files:
926 utils.RemoveFile(filename)
928 def StartInstance(self, instance, block_devices, startup_paused):
929 """Start an instance.
932 self._CheckDown(instance.name)
933 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
935 self._SaveKVMRuntime(instance, kvm_runtime)
936 self._ExecuteKVMRuntime(instance, kvm_runtime)
938 def _CallMonitorCommand(self, instance_name, command):
939 """Invoke a command on the instance monitor.
942 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
943 (utils.ShellQuote(command),
944 constants.SOCAT_PATH,
945 utils.ShellQuote(self._InstanceMonitor(instance_name))))
946 result = utils.RunCmd(socat)
948 msg = ("Failed to send command '%s' to instance %s."
949 " output: %s, error: %s, fail_reason: %s" %
950 (command, instance_name,
951 result.stdout, result.stderr, result.fail_reason))
952 raise errors.HypervisorError(msg)
957 def _GetKVMVersion(cls):
958 """Return the installed KVM version
960 @return: (version, v_maj, v_min, v_rev), or None
963 result = utils.RunCmd([constants.KVM_PATH, "--help"])
966 match = cls._VERSION_RE.search(result.output.splitlines()[0])
970 return (match.group(0), int(match.group(1)), int(match.group(2)),
973 def StopInstance(self, instance, force=False, retry=False, name=None):
977 if name is not None and not force:
978 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
981 acpi = instance.hvparams[constants.HV_ACPI]
984 _, pid, alive = self._InstancePidAlive(name)
985 if pid > 0 and alive:
986 if force or not acpi:
987 utils.KillProcess(pid)
989 self._CallMonitorCommand(name, "system_powerdown")
991 def CleanupInstance(self, instance_name):
992 """Cleanup after a stopped instance
995 pidfile, pid, alive = self._InstancePidAlive(instance_name)
996 if pid > 0 and alive:
997 raise errors.HypervisorError("Cannot cleanup a live instance")
998 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1000 def RebootInstance(self, instance):
1001 """Reboot an instance.
1004 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1005 # socket the instance will stop, but now power up again. So we'll resort
1006 # to shutdown and restart.
1007 _, _, alive = self._InstancePidAlive(instance.name)
1009 raise errors.HypervisorError("Failed to reboot instance %s:"
1010 " not running" % instance.name)
1011 # StopInstance will delete the saved KVM runtime so:
1012 # ...first load it...
1013 kvm_runtime = self._LoadKVMRuntime(instance)
1014 # ...now we can safely call StopInstance...
1015 if not self.StopInstance(instance):
1016 self.StopInstance(instance, force=True)
1017 # ...and finally we can save it again, and execute it...
1018 self._SaveKVMRuntime(instance, kvm_runtime)
1019 self._ExecuteKVMRuntime(instance, kvm_runtime)
1021 def MigrationInfo(self, instance):
1022 """Get instance information to perform a migration.
1024 @type instance: L{objects.Instance}
1025 @param instance: instance to be migrated
1027 @return: content of the KVM runtime file
1030 return self._ReadKVMRuntime(instance.name)
1032 def AcceptInstance(self, instance, info, target):
1033 """Prepare to accept an instance.
1035 @type instance: L{objects.Instance}
1036 @param instance: instance to be accepted
1038 @param info: content of the KVM runtime file on the source node
1039 @type target: string
1040 @param target: target host (usually ip), on this node
1043 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1044 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1045 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1047 def FinalizeMigration(self, instance, info, success):
1048 """Finalize an instance migration.
1050 Stop the incoming mode KVM.
1052 @type instance: L{objects.Instance}
1053 @param instance: instance whose migration is being finalized
1057 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1058 kvm_nics = kvm_runtime[1]
1060 for nic_seq, nic in enumerate(kvm_nics):
1061 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1062 # Bridged interfaces have already been configured
1065 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1066 except EnvironmentError, err:
1067 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1068 instance.name, nic_seq, str(err))
1071 self._ConfigureNIC(instance, nic_seq, nic, tap)
1072 except errors.HypervisorError, err:
1073 logging.warning(str(err))
1075 self._WriteKVMRuntime(instance.name, info)
1077 self.StopInstance(instance, force=True)
1079 def MigrateInstance(self, instance, target, live):
1080 """Migrate an instance to a target node.
1082 The migration will not be attempted if the instance is not
1085 @type instance: L{objects.Instance}
1086 @param instance: the instance to be migrated
1087 @type target: string
1088 @param target: ip address of the target node
1090 @param live: perform a live migration
1093 instance_name = instance.name
1094 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1095 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1097 raise errors.HypervisorError("Instance not running, cannot migrate")
1100 self._CallMonitorCommand(instance_name, "stop")
1102 migrate_command = ("migrate_set_speed %dm" %
1103 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1104 self._CallMonitorCommand(instance_name, migrate_command)
1106 migrate_command = ("migrate_set_downtime %dms" %
1107 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1108 self._CallMonitorCommand(instance_name, migrate_command)
1110 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1111 self._CallMonitorCommand(instance_name, migrate_command)
1113 info_command = "info migrate"
1117 result = self._CallMonitorCommand(instance_name, info_command)
1118 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1121 if not result.stdout:
1122 logging.info("KVM: empty 'info migrate' result")
1124 logging.warning("KVM: unknown 'info migrate' result: %s",
1126 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1128 status = match.group(1)
1129 if status == "completed":
1131 elif status == "active":
1132 # reset the broken answers count
1134 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1135 elif status == "failed" or status == "cancelled":
1137 self._CallMonitorCommand(instance_name, 'cont')
1138 raise errors.HypervisorError("Migration %s at the kvm level" %
1141 logging.warning("KVM: unknown migration status '%s'", status)
1143 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1144 if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
1145 raise errors.HypervisorError("Too many 'info migrate' broken answers")
1147 utils.KillProcess(pid)
1148 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1150 def GetNodeInfo(self):
1151 """Return information about the node.
1153 This is just a wrapper over the base GetLinuxNodeInfo method.
1155 @return: a dict with the following keys (values in MiB):
1156 - memory_total: the total memory size on the node
1157 - memory_free: the available memory on the node for instances
1158 - memory_dom0: the memory used by the node itself, if available
1161 return self.GetLinuxNodeInfo()
1164 def GetInstanceConsole(cls, instance, hvparams, beparams):
1165 """Return a command for connecting to the console of an instance.
1168 if hvparams[constants.HV_SERIAL_CONSOLE]:
1169 cmd = [constants.KVM_CONSOLE_WRAPPER,
1170 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1171 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1172 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1173 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1174 return objects.InstanceConsole(instance=instance.name,
1175 kind=constants.CONS_SSH,
1176 host=instance.primary_node,
1177 user=constants.GANETI_RUNAS,
1180 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1181 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1182 display = instance.network_port - constants.VNC_BASE_PORT
1183 return objects.InstanceConsole(instance=instance.name,
1184 kind=constants.CONS_VNC,
1185 host=vnc_bind_address,
1186 port=instance.network_port,
1189 return objects.InstanceConsole(instance=instance.name,
1190 kind=constants.CONS_MESSAGE,
1191 message=("No serial shell for instance %s" %
1195 """Verify the hypervisor.
1197 Check that the binary exists.
1200 if not os.path.exists(constants.KVM_PATH):
1201 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1202 if not os.path.exists(constants.SOCAT_PATH):
1203 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1206 def CheckParameterSyntax(cls, hvparams):
1207 """Check the given parameters for validity.
1209 @type hvparams: dict
1210 @param hvparams: dictionary with parameter names/value
1211 @raise errors.HypervisorError: when a parameter is not valid
1214 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1216 kernel_path = hvparams[constants.HV_KERNEL_PATH]
1218 if not hvparams[constants.HV_ROOT_PATH]:
1219 raise errors.HypervisorError("Need a root partition for the instance,"
1220 " if a kernel is defined")
1222 if (hvparams[constants.HV_VNC_X509_VERIFY] and
1223 not hvparams[constants.HV_VNC_X509]):
1224 raise errors.HypervisorError("%s must be defined, if %s is" %
1225 (constants.HV_VNC_X509,
1226 constants.HV_VNC_X509_VERIFY))
1228 boot_order = hvparams[constants.HV_BOOT_ORDER]
1229 if (boot_order == constants.HT_BO_CDROM and
1230 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1231 raise errors.HypervisorError("Cannot boot from cdrom without an"
1234 security_model = hvparams[constants.HV_SECURITY_MODEL]
1235 if security_model == constants.HT_SM_USER:
1236 if not hvparams[constants.HV_SECURITY_DOMAIN]:
1237 raise errors.HypervisorError("A security domain (user to run kvm as)"
1238 " must be specified")
1239 elif (security_model == constants.HT_SM_NONE or
1240 security_model == constants.HT_SM_POOL):
1241 if hvparams[constants.HV_SECURITY_DOMAIN]:
1242 raise errors.HypervisorError("Cannot have a security domain when the"
1243 " security model is 'none' or 'pool'")
1246 def ValidateParameters(cls, hvparams):
1247 """Check the given parameters for validity.
1249 @type hvparams: dict
1250 @param hvparams: dictionary with parameter names/value
1251 @raise errors.HypervisorError: when a parameter is not valid
1254 super(KVMHypervisor, cls).ValidateParameters(hvparams)
1256 security_model = hvparams[constants.HV_SECURITY_MODEL]
1257 if security_model == constants.HT_SM_USER:
1258 username = hvparams[constants.HV_SECURITY_DOMAIN]
1260 pwd.getpwnam(username)
1262 raise errors.HypervisorError("Unknown security domain user %s"
1266 def PowercycleNode(cls):
1267 """KVM powercycle, just a wrapper over Linux powercycle.
1270 cls.LinuxPowercycle()