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 _, v_major, v_min, _ = self._GetKVMVersion()
523 pidfile = self._InstancePidFile(instance.name)
524 kvm = constants.KVM_PATH
526 # used just by the vnc server, if enabled
527 kvm_cmd.extend(["-name", instance.name])
528 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MEMORY]])
529 kvm_cmd.extend(["-smp", instance.beparams[constants.BE_VCPUS]])
530 kvm_cmd.extend(["-pidfile", pidfile])
531 kvm_cmd.extend(["-daemonize"])
532 if not instance.hvparams[constants.HV_ACPI]:
533 kvm_cmd.extend(["-no-acpi"])
535 kvm_cmd.extend(["-S"])
536 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
537 constants.INSTANCE_REBOOT_EXIT:
538 kvm_cmd.extend(["-no-reboot"])
540 hvp = instance.hvparams
541 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
542 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
543 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
544 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
546 if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
547 kvm_cmd.extend(["-enable-kvm"])
548 elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
549 kvm_cmd.extend(["-disable-kvm"])
552 kvm_cmd.extend(["-boot", "n"])
554 disk_type = hvp[constants.HV_DISK_TYPE]
555 if disk_type == constants.HT_DISK_PARAVIRTUAL:
556 if_val = ",if=virtio"
558 if_val = ",if=%s" % disk_type
560 disk_cache = hvp[constants.HV_DISK_CACHE]
561 if instance.disk_template in constants.DTS_EXT_MIRROR:
562 if disk_cache != "none":
563 # TODO: make this a hard error, instead of a silent overwrite
564 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
565 " to prevent shared storage corruption on migration",
567 cache_val = ",cache=none"
568 elif disk_cache != constants.HT_CACHE_DEFAULT:
569 cache_val = ",cache=%s" % disk_cache
572 for cfdev, dev_path in block_devices:
573 if cfdev.mode != constants.DISK_RDWR:
574 raise errors.HypervisorError("Instance has read-only disks which"
575 " are not supported by KVM")
576 # TODO: handle FD_LOOP and FD_BLKTAP (?)
579 kvm_cmd.extend(["-boot", "c"])
581 if (v_major, v_min) < (0, 14) and disk_type != constants.HT_DISK_IDE:
582 boot_val = ",boot=on"
584 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
586 kvm_cmd.extend(["-drive", drive_val])
588 #Now we can specify a different device type for CDROM devices.
589 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
590 if not cdrom_disk_type:
591 cdrom_disk_type = disk_type
593 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
595 options = ",format=raw,media=cdrom"
597 kvm_cmd.extend(["-boot", "d"])
598 if cdrom_disk_type != constants.HT_DISK_IDE:
599 options = "%s,boot=on,if=%s" % (options, constants.HT_DISK_IDE)
601 options = "%s,boot=on" % options
603 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
604 if_val = ",if=virtio"
606 if_val = ",if=%s" % cdrom_disk_type
607 options = "%s%s" % (options, if_val)
608 drive_val = "file=%s%s" % (iso_image, options)
609 kvm_cmd.extend(["-drive", drive_val])
611 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
613 options = ",format=raw,media=cdrom"
614 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
615 if_val = ",if=virtio"
617 if_val = ",if=%s" % cdrom_disk_type
618 options = "%s%s" % (options, if_val)
619 drive_val = "file=%s%s" % (iso_image2, options)
620 kvm_cmd.extend(["-drive", drive_val])
622 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
624 options = ",format=raw,media=disk"
626 kvm_cmd.extend(["-boot", "a"])
627 options = "%s,boot=on" % options
628 if_val = ",if=floppy"
629 options = "%s%s" % (options, if_val)
630 drive_val = "file=%s%s" % (floppy_image, options)
631 kvm_cmd.extend(["-drive", drive_val])
633 kernel_path = hvp[constants.HV_KERNEL_PATH]
635 kvm_cmd.extend(["-kernel", kernel_path])
636 initrd_path = hvp[constants.HV_INITRD_PATH]
638 kvm_cmd.extend(["-initrd", initrd_path])
639 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
640 hvp[constants.HV_KERNEL_ARGS]]
641 if hvp[constants.HV_SERIAL_CONSOLE]:
642 root_append.append("console=ttyS0,38400")
643 kvm_cmd.extend(["-append", " ".join(root_append)])
645 mem_path = hvp[constants.HV_MEM_PATH]
647 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
649 mouse_type = hvp[constants.HV_USB_MOUSE]
650 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
653 kvm_cmd.extend(["-usb"])
654 kvm_cmd.extend(["-usbdevice", mouse_type])
655 elif vnc_bind_address:
656 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
658 keymap = hvp[constants.HV_KEYMAP]
660 keymap_path = self._InstanceKeymapFile(instance.name)
661 # If a keymap file is specified, KVM won't use its internal defaults. By
662 # first including the "en-us" layout, an error on loading the actual
663 # layout (e.g. because it can't be found) won't lead to a non-functional
664 # keyboard. A keyboard with incorrect keys is still better than none.
665 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
666 kvm_cmd.extend(["-k", keymap_path])
669 if netutils.IP4Address.IsValid(vnc_bind_address):
670 if instance.network_port > constants.VNC_BASE_PORT:
671 display = instance.network_port - constants.VNC_BASE_PORT
672 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
673 vnc_arg = ":%d" % (display)
675 vnc_arg = "%s:%d" % (vnc_bind_address, display)
677 logging.error("Network port is not a valid VNC display (%d < %d)."
678 " Not starting VNC", instance.network_port,
679 constants.VNC_BASE_PORT)
682 # Only allow tls and other option when not binding to a file, for now.
683 # kvm/qemu gets confused otherwise about the filename to use.
685 if hvp[constants.HV_VNC_TLS]:
686 vnc_append = "%s,tls" % vnc_append
687 if hvp[constants.HV_VNC_X509_VERIFY]:
688 vnc_append = "%s,x509verify=%s" % (vnc_append,
689 hvp[constants.HV_VNC_X509])
690 elif hvp[constants.HV_VNC_X509]:
691 vnc_append = "%s,x509=%s" % (vnc_append,
692 hvp[constants.HV_VNC_X509])
693 if hvp[constants.HV_VNC_PASSWORD_FILE]:
694 vnc_append = "%s,password" % vnc_append
696 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
699 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
701 kvm_cmd.extend(["-vnc", vnc_arg])
703 kvm_cmd.extend(["-nographic"])
705 monitor_dev = ("unix:%s,server,nowait" %
706 self._InstanceMonitor(instance.name))
707 kvm_cmd.extend(["-monitor", monitor_dev])
708 if hvp[constants.HV_SERIAL_CONSOLE]:
709 serial_dev = ("unix:%s,server,nowait" %
710 self._InstanceSerial(instance.name))
711 kvm_cmd.extend(["-serial", serial_dev])
713 kvm_cmd.extend(["-serial", "none"])
715 if hvp[constants.HV_USE_LOCALTIME]:
716 kvm_cmd.extend(["-localtime"])
718 if hvp[constants.HV_KVM_USE_CHROOT]:
719 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
721 # Save the current instance nics, but defer their expansion as parameters,
722 # as we'll need to generate executable temp files for them.
723 kvm_nics = instance.nics
726 return (kvm_cmd, kvm_nics, hvparams)
728 def _WriteKVMRuntime(self, instance_name, data):
729 """Write an instance's KVM runtime
733 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
735 except EnvironmentError, err:
736 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
738 def _ReadKVMRuntime(self, instance_name):
739 """Read an instance's KVM runtime
743 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
744 except EnvironmentError, err:
745 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
748 def _SaveKVMRuntime(self, instance, kvm_runtime):
749 """Save an instance's KVM runtime
752 kvm_cmd, kvm_nics, hvparams = kvm_runtime
753 serialized_nics = [nic.ToDict() for nic in kvm_nics]
754 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
755 self._WriteKVMRuntime(instance.name, serialized_form)
757 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
758 """Load an instance's KVM runtime
761 if not serialized_runtime:
762 serialized_runtime = self._ReadKVMRuntime(instance.name)
763 loaded_runtime = serializer.Load(serialized_runtime)
764 kvm_cmd, serialized_nics, hvparams = loaded_runtime
765 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
766 return (kvm_cmd, kvm_nics, hvparams)
768 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
769 """Run the KVM cmd and check for errors
772 @param name: instance name
773 @type kvm_cmd: list of strings
774 @param kvm_cmd: runcmd input for kvm
775 @type tap_fds: list of int
776 @param tap_fds: fds of tap devices opened by Ganeti
780 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
783 utils_wrapper.CloseFdNoError(fd)
786 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
787 (name, result.fail_reason, result.output))
788 if not self._InstancePidAlive(name)[2]:
789 raise errors.HypervisorError("Failed to start instance %s" % name)
791 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
792 """Execute a KVM cmd, after completing it with some last minute data
794 @type incoming: tuple of strings
795 @param incoming: (target_host_ip, port)
798 # Small _ExecuteKVMRuntime hv parameters programming howto:
799 # - conf_hvp contains the parameters as configured on ganeti. they might
800 # have changed since the instance started; only use them if the change
801 # won't affect the inside of the instance (which hasn't been rebooted).
802 # - up_hvp contains the parameters as they were when the instance was
803 # started, plus any new parameter which has been added between ganeti
804 # versions: it is paramount that those default to a value which won't
805 # affect the inside of the instance as well.
806 conf_hvp = instance.hvparams
808 self._CheckDown(name)
812 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
813 up_hvp = objects.FillDict(conf_hvp, up_hvp)
815 _, v_major, v_min, _ = self._GetKVMVersion()
817 # We know it's safe to run as a different user upon migration, so we'll use
818 # the latest conf, from conf_hvp.
819 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
820 if security_model == constants.HT_SM_USER:
821 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
823 # We have reasons to believe changing something like the nic driver/type
824 # upon migration won't exactly fly with the instance kernel, so for nic
825 # related parameters we'll use up_hvp
829 kvm_cmd.extend(["-net", "none"])
833 nic_type = up_hvp[constants.HV_NIC_TYPE]
834 if nic_type == constants.HT_NIC_PARAVIRTUAL:
835 # From version 0.12.0, kvm uses a new sintax for network configuration.
836 if (v_major, v_min) >= (0, 12):
837 nic_model = "virtio-net-pci"
842 if up_hvp[constants.HV_VHOST_NET]:
843 # vhost_net is only available from version 0.13.0 or newer
844 if (v_major, v_min) >= (0, 13):
845 tap_extra = ",vhost=on"
847 raise errors.HypervisorError("vhost_net is configured"
848 " but it is not available")
852 for nic_seq, nic in enumerate(kvm_nics):
853 tapname, tapfd = _OpenTap(vnet_hdr)
856 if (v_major, v_min) >= (0, 12):
857 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
858 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
859 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
861 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
863 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
864 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
867 target, port = incoming
868 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
870 # Changing the vnc password doesn't bother the guest that much. At most it
871 # will surprise people who connect to it. Whether positively or negatively
873 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
877 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
878 except EnvironmentError, err:
879 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
880 % (vnc_pwd_file, err))
882 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
883 utils.EnsureDirs([(self._InstanceChrootDir(name),
884 constants.SECURE_DIR_MODE)])
886 # Configure the network now for starting instances and bridged interfaces,
887 # during FinalizeMigration for incoming instances' routed interfaces
888 for nic_seq, nic in enumerate(kvm_nics):
890 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
892 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
894 if security_model == constants.HT_SM_POOL:
895 ss = ssconf.SimpleStore()
896 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
897 all_uids = set(uidpool.ExpandUidPool(uid_pool))
898 uid = uidpool.RequestUnusedUid(all_uids)
900 username = pwd.getpwuid(uid.GetUid()).pw_name
901 kvm_cmd.extend(["-runas", username])
902 self._RunKVMCmd(name, kvm_cmd, tapfds)
904 uidpool.ReleaseUid(uid)
908 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
910 self._RunKVMCmd(name, kvm_cmd, tapfds)
912 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
913 constants.RUN_DIRS_MODE)])
914 for nic_seq, tap in enumerate(taps):
915 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
919 change_cmd = "change vnc password %s" % vnc_pwd
920 self._CallMonitorCommand(instance.name, change_cmd)
922 for filename in temp_files:
923 utils.RemoveFile(filename)
925 def StartInstance(self, instance, block_devices, startup_paused):
926 """Start an instance.
929 self._CheckDown(instance.name)
930 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices,
932 self._SaveKVMRuntime(instance, kvm_runtime)
933 self._ExecuteKVMRuntime(instance, kvm_runtime)
935 def _CallMonitorCommand(self, instance_name, command):
936 """Invoke a command on the instance monitor.
939 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
940 (utils.ShellQuote(command),
941 constants.SOCAT_PATH,
942 utils.ShellQuote(self._InstanceMonitor(instance_name))))
943 result = utils.RunCmd(socat)
945 msg = ("Failed to send command '%s' to instance %s."
946 " output: %s, error: %s, fail_reason: %s" %
947 (command, instance_name,
948 result.stdout, result.stderr, result.fail_reason))
949 raise errors.HypervisorError(msg)
954 def _GetKVMVersion(cls):
955 """Return the installed KVM version
957 @return: (version, v_maj, v_min, v_rev)
958 @raise: L{errors.HypervisorError}
961 result = utils.RunCmd([constants.KVM_PATH, "--help"])
963 raise errors.HypervisorError("Unable to get KVM version")
964 match = cls._VERSION_RE.search(result.output.splitlines()[0])
966 raise errors.HypervisorError("Unable to get KVM version")
968 return (match.group(0), int(match.group(1)), int(match.group(2)),
971 def StopInstance(self, instance, force=False, retry=False, name=None):
975 if name is not None and not force:
976 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
979 acpi = instance.hvparams[constants.HV_ACPI]
982 _, pid, alive = self._InstancePidAlive(name)
983 if pid > 0 and alive:
984 if force or not acpi:
985 utils.KillProcess(pid)
987 self._CallMonitorCommand(name, "system_powerdown")
989 def CleanupInstance(self, instance_name):
990 """Cleanup after a stopped instance
993 pidfile, pid, alive = self._InstancePidAlive(instance_name)
994 if pid > 0 and alive:
995 raise errors.HypervisorError("Cannot cleanup a live instance")
996 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
998 def RebootInstance(self, instance):
999 """Reboot an instance.
1002 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
1003 # socket the instance will stop, but now power up again. So we'll resort
1004 # to shutdown and restart.
1005 _, _, alive = self._InstancePidAlive(instance.name)
1007 raise errors.HypervisorError("Failed to reboot instance %s:"
1008 " not running" % instance.name)
1009 # StopInstance will delete the saved KVM runtime so:
1010 # ...first load it...
1011 kvm_runtime = self._LoadKVMRuntime(instance)
1012 # ...now we can safely call StopInstance...
1013 if not self.StopInstance(instance):
1014 self.StopInstance(instance, force=True)
1015 # ...and finally we can save it again, and execute it...
1016 self._SaveKVMRuntime(instance, kvm_runtime)
1017 self._ExecuteKVMRuntime(instance, kvm_runtime)
1019 def MigrationInfo(self, instance):
1020 """Get instance information to perform a migration.
1022 @type instance: L{objects.Instance}
1023 @param instance: instance to be migrated
1025 @return: content of the KVM runtime file
1028 return self._ReadKVMRuntime(instance.name)
1030 def AcceptInstance(self, instance, info, target):
1031 """Prepare to accept an instance.
1033 @type instance: L{objects.Instance}
1034 @param instance: instance to be accepted
1036 @param info: content of the KVM runtime file on the source node
1037 @type target: string
1038 @param target: target host (usually ip), on this node
1041 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1042 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1043 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1045 def FinalizeMigration(self, instance, info, success):
1046 """Finalize an instance migration.
1048 Stop the incoming mode KVM.
1050 @type instance: L{objects.Instance}
1051 @param instance: instance whose migration is being finalized
1055 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1056 kvm_nics = kvm_runtime[1]
1058 for nic_seq, nic in enumerate(kvm_nics):
1059 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1060 # Bridged interfaces have already been configured
1063 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1064 except EnvironmentError, err:
1065 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1066 instance.name, nic_seq, str(err))
1069 self._ConfigureNIC(instance, nic_seq, nic, tap)
1070 except errors.HypervisorError, err:
1071 logging.warning(str(err))
1073 self._WriteKVMRuntime(instance.name, info)
1075 self.StopInstance(instance, force=True)
1077 def MigrateInstance(self, instance, target, live):
1078 """Migrate an instance to a target node.
1080 The migration will not be attempted if the instance is not
1083 @type instance: L{objects.Instance}
1084 @param instance: the instance to be migrated
1085 @type target: string
1086 @param target: ip address of the target node
1088 @param live: perform a live migration
1091 instance_name = instance.name
1092 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1093 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1095 raise errors.HypervisorError("Instance not running, cannot migrate")
1098 self._CallMonitorCommand(instance_name, "stop")
1100 migrate_command = ("migrate_set_speed %dm" %
1101 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1102 self._CallMonitorCommand(instance_name, migrate_command)
1104 migrate_command = ("migrate_set_downtime %dms" %
1105 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1106 self._CallMonitorCommand(instance_name, migrate_command)
1108 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1109 self._CallMonitorCommand(instance_name, migrate_command)
1111 info_command = "info migrate"
1115 result = self._CallMonitorCommand(instance_name, info_command)
1116 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1119 if not result.stdout:
1120 logging.info("KVM: empty 'info migrate' result")
1122 logging.warning("KVM: unknown 'info migrate' result: %s",
1124 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1126 status = match.group(1)
1127 if status == "completed":
1129 elif status == "active":
1130 # reset the broken answers count
1132 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1133 elif status == "failed" or status == "cancelled":
1135 self._CallMonitorCommand(instance_name, 'cont')
1136 raise errors.HypervisorError("Migration %s at the kvm level" %
1139 logging.warning("KVM: unknown migration status '%s'", status)
1141 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1142 if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
1143 raise errors.HypervisorError("Too many 'info migrate' broken answers")
1145 utils.KillProcess(pid)
1146 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1148 def GetNodeInfo(self):
1149 """Return information about the node.
1151 This is just a wrapper over the base GetLinuxNodeInfo method.
1153 @return: a dict with the following keys (values in MiB):
1154 - memory_total: the total memory size on the node
1155 - memory_free: the available memory on the node for instances
1156 - memory_dom0: the memory used by the node itself, if available
1159 return self.GetLinuxNodeInfo()
1162 def GetInstanceConsole(cls, instance, hvparams, beparams):
1163 """Return a command for connecting to the console of an instance.
1166 if hvparams[constants.HV_SERIAL_CONSOLE]:
1167 cmd = [constants.KVM_CONSOLE_WRAPPER,
1168 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
1169 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
1170 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1171 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1172 return objects.InstanceConsole(instance=instance.name,
1173 kind=constants.CONS_SSH,
1174 host=instance.primary_node,
1175 user=constants.GANETI_RUNAS,
1178 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1179 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1180 display = instance.network_port - constants.VNC_BASE_PORT
1181 return objects.InstanceConsole(instance=instance.name,
1182 kind=constants.CONS_VNC,
1183 host=vnc_bind_address,
1184 port=instance.network_port,
1187 return objects.InstanceConsole(instance=instance.name,
1188 kind=constants.CONS_MESSAGE,
1189 message=("No serial shell for instance %s" %
1193 """Verify the hypervisor.
1195 Check that the binary exists.
1198 if not os.path.exists(constants.KVM_PATH):
1199 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1200 if not os.path.exists(constants.SOCAT_PATH):
1201 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1204 def CheckParameterSyntax(cls, hvparams):
1205 """Check the given parameters for validity.
1207 @type hvparams: dict
1208 @param hvparams: dictionary with parameter names/value
1209 @raise errors.HypervisorError: when a parameter is not valid
1212 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1214 kernel_path = hvparams[constants.HV_KERNEL_PATH]
1216 if not hvparams[constants.HV_ROOT_PATH]:
1217 raise errors.HypervisorError("Need a root partition for the instance,"
1218 " if a kernel is defined")
1220 if (hvparams[constants.HV_VNC_X509_VERIFY] and
1221 not hvparams[constants.HV_VNC_X509]):
1222 raise errors.HypervisorError("%s must be defined, if %s is" %
1223 (constants.HV_VNC_X509,
1224 constants.HV_VNC_X509_VERIFY))
1226 boot_order = hvparams[constants.HV_BOOT_ORDER]
1227 if (boot_order == constants.HT_BO_CDROM and
1228 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1229 raise errors.HypervisorError("Cannot boot from cdrom without an"
1232 security_model = hvparams[constants.HV_SECURITY_MODEL]
1233 if security_model == constants.HT_SM_USER:
1234 if not hvparams[constants.HV_SECURITY_DOMAIN]:
1235 raise errors.HypervisorError("A security domain (user to run kvm as)"
1236 " must be specified")
1237 elif (security_model == constants.HT_SM_NONE or
1238 security_model == constants.HT_SM_POOL):
1239 if hvparams[constants.HV_SECURITY_DOMAIN]:
1240 raise errors.HypervisorError("Cannot have a security domain when the"
1241 " security model is 'none' or 'pool'")
1244 def ValidateParameters(cls, hvparams):
1245 """Check the given parameters for validity.
1247 @type hvparams: dict
1248 @param hvparams: dictionary with parameter names/value
1249 @raise errors.HypervisorError: when a parameter is not valid
1252 super(KVMHypervisor, cls).ValidateParameters(hvparams)
1254 security_model = hvparams[constants.HV_SECURITY_MODEL]
1255 if security_model == constants.HT_SM_USER:
1256 username = hvparams[constants.HV_SECURITY_DOMAIN]
1258 pwd.getpwnam(username)
1260 raise errors.HypervisorError("Unknown security domain user %s"
1264 def PowercycleNode(cls):
1265 """KVM powercycle, just a wrapper over Linux powercycle.
1268 cls.LinuxPowercycle()