4 # Copyright (C) 2008, 2009, 2010 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 # KVM instances with chroot enabled are started in empty chroot directories.
141 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
142 # After an instance is stopped, its chroot directory is removed.
143 # If the chroot directory is not empty, it can't be removed.
144 # A non-empty chroot directory indicates a possible security incident.
145 # To support forensics, the non-empty chroot directory is quarantined in
146 # a separate directory, called 'chroot-quarantine'.
147 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
148 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
149 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR]
152 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
153 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
154 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
155 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
156 constants.HV_ACPI: hv_base.NO_CHECK,
157 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
158 constants.HV_VNC_BIND_ADDRESS:
159 (False, lambda x: (netutils.IP4Address.IsValid(x) or
160 utils.IsNormAbsPath(x)),
161 "the VNC bind address must be either a valid IP address or an absolute"
162 " pathname", None, None),
163 constants.HV_VNC_TLS: hv_base.NO_CHECK,
164 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
165 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
166 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
167 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
168 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
169 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
170 constants.HV_BOOT_ORDER:
171 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
172 constants.HV_NIC_TYPE:
173 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
174 constants.HV_DISK_TYPE:
175 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
176 constants.HV_KVM_CDROM_DISK_TYPE:
177 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
178 constants.HV_USB_MOUSE:
179 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
180 constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
181 constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
182 constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
183 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
184 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
185 constants.HV_DISK_CACHE:
186 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
187 constants.HV_SECURITY_MODEL:
188 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
189 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
190 constants.HV_KVM_FLAG:
191 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
192 constants.HV_VHOST_NET: hv_base.NO_CHECK,
193 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
194 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
197 _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
199 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
200 _MIGRATION_INFO_RETRY_DELAY = 2
202 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)\.(\d+)\b")
209 hv_base.BaseHypervisor.__init__(self)
210 # Let's make sure the directories we need exist, even if the RUN_DIR lives
211 # in a tmpfs filesystem or has been otherwise wiped out.
212 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
213 utils.EnsureDirs(dirs)
216 def _InstancePidFile(cls, instance_name):
217 """Returns the instance pidfile.
220 return utils.PathJoin(cls._PIDS_DIR, instance_name)
223 def _InstanceUidFile(cls, instance_name):
224 """Returns the instance uidfile.
227 return utils.PathJoin(cls._UIDS_DIR, instance_name)
230 def _InstancePidInfo(cls, pid):
231 """Check pid file for instance information.
233 Check that a pid file is associated with an instance, and retrieve
234 information from its command line.
236 @type pid: string or int
237 @param pid: process id of the instance to check
239 @return: (instance_name, memory, vcpus)
240 @raise errors.HypervisorError: when an instance cannot be found
243 alive = utils.IsProcessAlive(pid)
245 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
247 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
249 cmdline = utils.ReadFile(cmdline_file)
250 except EnvironmentError, err:
251 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
258 arg_list = cmdline.split('\x00')
260 arg = arg_list.pop(0)
262 instance = arg_list.pop(0)
264 memory = int(arg_list.pop(0))
266 vcpus = int(arg_list.pop(0))
269 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
272 return (instance, memory, vcpus)
274 def _InstancePidAlive(self, instance_name):
275 """Returns the instance pidfile, pid, and liveness.
277 @type instance_name: string
278 @param instance_name: instance name
280 @return: (pid file name, pid, liveness)
283 pidfile = self._InstancePidFile(instance_name)
284 pid = utils.ReadPidFile(pidfile)
288 cmd_instance = self._InstancePidInfo(pid)[0]
289 alive = (cmd_instance == instance_name)
290 except errors.HypervisorError:
293 return (pidfile, pid, alive)
295 def _CheckDown(self, instance_name):
296 """Raises an error unless the given instance is down.
299 alive = self._InstancePidAlive(instance_name)[2]
301 raise errors.HypervisorError("Failed to start instance %s: %s" %
302 (instance_name, "already running"))
305 def _InstanceMonitor(cls, instance_name):
306 """Returns the instance monitor socket name
309 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
312 def _InstanceSerial(cls, instance_name):
313 """Returns the instance serial socket name
316 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
319 def _SocatUnixConsoleParams():
320 """Returns the correct parameters for socat
322 If we have a new-enough socat we can use raw mode with an escape character.
325 if constants.SOCAT_USE_ESCAPE:
326 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
328 return "echo=0,icanon=0"
331 def _InstanceKVMRuntime(cls, instance_name):
332 """Returns the instance KVM runtime filename
335 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
338 def _InstanceChrootDir(cls, instance_name):
339 """Returns the name of the KVM chroot dir of the instance
342 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
345 def _InstanceNICDir(cls, instance_name):
346 """Returns the name of the directory holding the tap device files for a
350 return utils.PathJoin(cls._NICS_DIR, instance_name)
353 def _InstanceNICFile(cls, instance_name, seq):
354 """Returns the name of the file containing the tap device for a given NIC
357 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
360 def _TryReadUidFile(cls, uid_file):
361 """Try to read a uid file
364 if os.path.exists(uid_file):
366 uid = int(utils.ReadOneLineFile(uid_file))
368 except EnvironmentError:
369 logging.warning("Can't read uid file", exc_info=True)
370 except (TypeError, ValueError):
371 logging.warning("Can't parse uid file contents", exc_info=True)
375 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
376 """Removes an instance's rutime sockets/files/dirs.
379 utils.RemoveFile(pidfile)
380 utils.RemoveFile(cls._InstanceMonitor(instance_name))
381 utils.RemoveFile(cls._InstanceSerial(instance_name))
382 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
383 uid_file = cls._InstanceUidFile(instance_name)
384 uid = cls._TryReadUidFile(uid_file)
385 utils.RemoveFile(uid_file)
387 uidpool.ReleaseUid(uid)
389 shutil.rmtree(cls._InstanceNICDir(instance_name))
391 if err.errno != errno.ENOENT:
394 chroot_dir = cls._InstanceChrootDir(instance_name)
395 utils.RemoveDir(chroot_dir)
397 if err.errno == errno.ENOTEMPTY:
398 # The chroot directory is expected to be empty, but it isn't.
399 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
402 utils.TimestampForFilename()))
403 logging.warning("The chroot directory of instance %s can not be"
404 " removed as it is not empty. Moving it to the"
405 " quarantine instead. Please investigate the"
406 " contents (%s) and clean up manually",
407 instance_name, new_chroot_dir)
408 utils.RenameFile(chroot_dir, new_chroot_dir)
413 def _ConfigureNIC(instance, seq, nic, tap):
414 """Run the network configuration script for a specified NIC
416 @param instance: instance we're acting on
417 @type instance: instance object
418 @param seq: nic sequence number
420 @param nic: nic we're acting on
421 @type nic: nic object
422 @param tap: the host's tap interface this NIC corresponds to
428 tags = " ".join(instance.tags)
433 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
434 "INSTANCE": instance.name,
436 "MODE": nic.nicparams[constants.NIC_MODE],
438 "INTERFACE_INDEX": str(seq),
445 if nic.nicparams[constants.NIC_LINK]:
446 env["LINK"] = nic.nicparams[constants.NIC_LINK]
448 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
449 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
451 result = utils.RunCmd([constants.KVM_IFUP, tap], env=env)
453 raise errors.HypervisorError("Failed to configure interface %s: %s."
454 " Network configuration script output: %s" %
455 (tap, result.fail_reason, result.output))
457 def ListInstances(self):
458 """Get the list of running instances.
460 We can do this by listing our live instances directory and
461 checking whether the associated kvm process is still alive.
465 for name in os.listdir(self._PIDS_DIR):
466 if self._InstancePidAlive(name)[2]:
470 def GetInstanceInfo(self, instance_name):
471 """Get instance properties.
473 @type instance_name: string
474 @param instance_name: the instance name
475 @rtype: tuple of strings
476 @return: (name, id, memory, vcpus, stat, times)
479 _, pid, alive = self._InstancePidAlive(instance_name)
483 _, memory, vcpus = self._InstancePidInfo(pid)
487 return (instance_name, pid, memory, vcpus, stat, times)
489 def GetAllInstancesInfo(self):
490 """Get properties of all instances.
492 @return: list of tuples (name, id, memory, vcpus, stat, times)
496 for name in os.listdir(self._PIDS_DIR):
498 info = self.GetInstanceInfo(name)
499 except errors.HypervisorError:
505 def _GenerateKVMRuntime(self, instance, block_devices):
506 """Generate KVM information to start an instance.
509 pidfile = self._InstancePidFile(instance.name)
510 kvm = constants.KVM_PATH
512 # used just by the vnc server, if enabled
513 kvm_cmd.extend(['-name', instance.name])
514 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
515 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
516 kvm_cmd.extend(['-pidfile', pidfile])
517 kvm_cmd.extend(['-daemonize'])
518 if not instance.hvparams[constants.HV_ACPI]:
519 kvm_cmd.extend(['-no-acpi'])
521 hvp = instance.hvparams
522 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
523 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
524 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
525 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
527 if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
528 kvm_cmd.extend(["-enable-kvm"])
529 elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
530 kvm_cmd.extend(["-disable-kvm"])
533 kvm_cmd.extend(['-boot', 'n'])
535 disk_type = hvp[constants.HV_DISK_TYPE]
536 if disk_type == constants.HT_DISK_PARAVIRTUAL:
537 if_val = ',if=virtio'
539 if_val = ',if=%s' % disk_type
541 disk_cache = hvp[constants.HV_DISK_CACHE]
542 if disk_cache != constants.HT_CACHE_DEFAULT:
543 cache_val = ",cache=%s" % disk_cache
546 for cfdev, dev_path in block_devices:
547 if cfdev.mode != constants.DISK_RDWR:
548 raise errors.HypervisorError("Instance has read-only disks which"
549 " are not supported by KVM")
550 # TODO: handle FD_LOOP and FD_BLKTAP (?)
552 kvm_cmd.extend(['-boot', 'c'])
553 if disk_type != constants.HT_DISK_IDE:
554 boot_val = ',boot=on'
557 # We only boot from the first disk
562 drive_val = 'file=%s,format=raw%s%s%s' % (dev_path, if_val, boot_val,
564 kvm_cmd.extend(['-drive', drive_val])
566 #Now we can specify a different device type for CDROM devices.
567 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
568 if not cdrom_disk_type:
569 cdrom_disk_type = disk_type
571 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
573 options = ',format=raw,media=cdrom'
575 kvm_cmd.extend(['-boot', 'd'])
576 if cdrom_disk_type != constants.HT_DISK_IDE:
577 options = '%s,boot=on,if=%s' % (options, constants.HT_DISK_IDE)
579 options = '%s,boot=on' % options
581 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
582 if_val = ',if=virtio'
584 if_val = ',if=%s' % cdrom_disk_type
585 options = '%s%s' % (options, if_val)
586 drive_val = 'file=%s%s' % (iso_image, options)
587 kvm_cmd.extend(['-drive', drive_val])
589 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
591 options = ',format=raw,media=cdrom'
592 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
593 if_val = ',if=virtio'
595 if_val = ',if=%s' % cdrom_disk_type
596 options = '%s%s' % (options, if_val)
597 drive_val = 'file=%s%s' % (iso_image2, options)
598 kvm_cmd.extend(['-drive', drive_val])
600 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
602 options = ',format=raw,media=disk'
604 kvm_cmd.extend(['-boot', 'a'])
605 options = '%s,boot=on' % options
606 if_val = ',if=floppy'
607 options = '%s%s' % (options, if_val)
608 drive_val = 'file=%s%s' % (floppy_image, options)
609 kvm_cmd.extend(['-drive', drive_val])
611 kernel_path = hvp[constants.HV_KERNEL_PATH]
613 kvm_cmd.extend(['-kernel', kernel_path])
614 initrd_path = hvp[constants.HV_INITRD_PATH]
616 kvm_cmd.extend(['-initrd', initrd_path])
617 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
618 hvp[constants.HV_KERNEL_ARGS]]
619 if hvp[constants.HV_SERIAL_CONSOLE]:
620 root_append.append('console=ttyS0,38400')
621 kvm_cmd.extend(['-append', ' '.join(root_append)])
623 mem_path = hvp[constants.HV_MEM_PATH]
625 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
627 mouse_type = hvp[constants.HV_USB_MOUSE]
628 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
631 kvm_cmd.extend(['-usb'])
632 kvm_cmd.extend(['-usbdevice', mouse_type])
633 elif vnc_bind_address:
634 kvm_cmd.extend(['-usbdevice', constants.HT_MOUSE_TABLET])
637 if netutils.IP4Address.IsValid(vnc_bind_address):
638 if instance.network_port > constants.VNC_BASE_PORT:
639 display = instance.network_port - constants.VNC_BASE_PORT
640 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
641 vnc_arg = ':%d' % (display)
643 vnc_arg = '%s:%d' % (vnc_bind_address, display)
645 logging.error("Network port is not a valid VNC display (%d < %d)."
646 " Not starting VNC", instance.network_port,
647 constants.VNC_BASE_PORT)
650 # Only allow tls and other option when not binding to a file, for now.
651 # kvm/qemu gets confused otherwise about the filename to use.
653 if hvp[constants.HV_VNC_TLS]:
654 vnc_append = '%s,tls' % vnc_append
655 if hvp[constants.HV_VNC_X509_VERIFY]:
656 vnc_append = '%s,x509verify=%s' % (vnc_append,
657 hvp[constants.HV_VNC_X509])
658 elif hvp[constants.HV_VNC_X509]:
659 vnc_append = '%s,x509=%s' % (vnc_append,
660 hvp[constants.HV_VNC_X509])
661 if hvp[constants.HV_VNC_PASSWORD_FILE]:
662 vnc_append = '%s,password' % vnc_append
664 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
667 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
669 kvm_cmd.extend(['-vnc', vnc_arg])
671 kvm_cmd.extend(['-nographic'])
673 monitor_dev = ("unix:%s,server,nowait" %
674 self._InstanceMonitor(instance.name))
675 kvm_cmd.extend(['-monitor', monitor_dev])
676 if hvp[constants.HV_SERIAL_CONSOLE]:
677 serial_dev = ('unix:%s,server,nowait' %
678 self._InstanceSerial(instance.name))
679 kvm_cmd.extend(['-serial', serial_dev])
681 kvm_cmd.extend(['-serial', 'none'])
683 if hvp[constants.HV_USE_LOCALTIME]:
684 kvm_cmd.extend(['-localtime'])
686 if hvp[constants.HV_KVM_USE_CHROOT]:
687 kvm_cmd.extend(['-chroot', self._InstanceChrootDir(instance.name)])
689 # Save the current instance nics, but defer their expansion as parameters,
690 # as we'll need to generate executable temp files for them.
691 kvm_nics = instance.nics
694 return (kvm_cmd, kvm_nics, hvparams)
696 def _WriteKVMRuntime(self, instance_name, data):
697 """Write an instance's KVM runtime
701 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
703 except EnvironmentError, err:
704 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
706 def _ReadKVMRuntime(self, instance_name):
707 """Read an instance's KVM runtime
711 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
712 except EnvironmentError, err:
713 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
716 def _SaveKVMRuntime(self, instance, kvm_runtime):
717 """Save an instance's KVM runtime
720 kvm_cmd, kvm_nics, hvparams = kvm_runtime
721 serialized_nics = [nic.ToDict() for nic in kvm_nics]
722 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
723 self._WriteKVMRuntime(instance.name, serialized_form)
725 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
726 """Load an instance's KVM runtime
729 if not serialized_runtime:
730 serialized_runtime = self._ReadKVMRuntime(instance.name)
731 loaded_runtime = serializer.Load(serialized_runtime)
732 kvm_cmd, serialized_nics, hvparams = loaded_runtime
733 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
734 return (kvm_cmd, kvm_nics, hvparams)
736 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
737 """Run the KVM cmd and check for errors
740 @param name: instance name
741 @type kvm_cmd: list of strings
742 @param kvm_cmd: runcmd input for kvm
743 @type tap_fds: list of int
744 @param tap_fds: fds of tap devices opened by Ganeti
748 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
751 utils_wrapper.CloseFdNoError(fd)
754 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
755 (name, result.fail_reason, result.output))
756 if not self._InstancePidAlive(name)[2]:
757 raise errors.HypervisorError("Failed to start instance %s" % name)
759 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
760 """Execute a KVM cmd, after completing it with some last minute data
762 @type incoming: tuple of strings
763 @param incoming: (target_host_ip, port)
766 # Small _ExecuteKVMRuntime hv parameters programming howto:
767 # - conf_hvp contains the parameters as configured on ganeti. they might
768 # have changed since the instance started; only use them if the change
769 # won't affect the inside of the instance (which hasn't been rebooted).
770 # - up_hvp contains the parameters as they were when the instance was
771 # started, plus any new parameter which has been added between ganeti
772 # versions: it is paramount that those default to a value which won't
773 # affect the inside of the instance as well.
774 conf_hvp = instance.hvparams
776 self._CheckDown(name)
780 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
781 up_hvp = objects.FillDict(conf_hvp, up_hvp)
783 kvm_version = self._GetKVMVersion()
785 _, v_major, v_min, _ = kvm_version
787 raise errors.HypervisorError("Unable to get KVM version")
789 # We know it's safe to run as a different user upon migration, so we'll use
790 # the latest conf, from conf_hvp.
791 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
792 if security_model == constants.HT_SM_USER:
793 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
795 # We have reasons to believe changing something like the nic driver/type
796 # upon migration won't exactly fly with the instance kernel, so for nic
797 # related parameters we'll use up_hvp
801 kvm_cmd.extend(["-net", "none"])
805 nic_type = up_hvp[constants.HV_NIC_TYPE]
806 if nic_type == constants.HT_NIC_PARAVIRTUAL:
807 # From version 0.12.0, kvm uses a new sintax for network configuration.
808 if (v_major, v_min) >= (0, 12):
809 nic_model = "virtio-net-pci"
814 if up_hvp[constants.HV_VHOST_NET]:
815 # vhost_net is only available from version 0.13.0 or newer
816 if (v_major, v_min) >= (0, 13):
817 tap_extra = ",vhost=on"
819 raise errors.HypervisorError("vhost_net is configured"
820 " but it is not available")
824 for nic_seq, nic in enumerate(kvm_nics):
825 tapname, tapfd = _OpenTap(vnet_hdr)
828 if (v_major, v_min) >= (0, 12):
829 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
830 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
831 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
833 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
835 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
836 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
839 target, port = incoming
840 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
842 # Changing the vnc password doesn't bother the guest that much. At most it
843 # will surprise people who connect to it. Whether positively or negatively
845 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
849 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
850 except EnvironmentError, err:
851 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
852 % (vnc_pwd_file, err))
854 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
855 utils.EnsureDirs([(self._InstanceChrootDir(name),
856 constants.SECURE_DIR_MODE)])
859 # Configure the network now for starting instances, during
860 # FinalizeMigration for incoming instances
861 for nic_seq, nic in enumerate(kvm_nics):
862 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
864 if security_model == constants.HT_SM_POOL:
865 ss = ssconf.SimpleStore()
866 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
867 all_uids = set(uidpool.ExpandUidPool(uid_pool))
868 uid = uidpool.RequestUnusedUid(all_uids)
870 username = pwd.getpwuid(uid.GetUid()).pw_name
871 kvm_cmd.extend(["-runas", username])
872 self._RunKVMCmd(name, kvm_cmd, tapfds)
874 uidpool.ReleaseUid(uid)
878 utils.WriteFile(self._InstanceUidFile(name), data=str(uid))
880 self._RunKVMCmd(name, kvm_cmd, tapfds)
882 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
883 constants.RUN_DIRS_MODE)])
884 for nic_seq, tap in enumerate(taps):
885 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
889 change_cmd = 'change vnc password %s' % vnc_pwd
890 self._CallMonitorCommand(instance.name, change_cmd)
892 for filename in temp_files:
893 utils.RemoveFile(filename)
895 def StartInstance(self, instance, block_devices):
896 """Start an instance.
899 self._CheckDown(instance.name)
900 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
901 self._SaveKVMRuntime(instance, kvm_runtime)
902 self._ExecuteKVMRuntime(instance, kvm_runtime)
904 def _CallMonitorCommand(self, instance_name, command):
905 """Invoke a command on the instance monitor.
908 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
909 (utils.ShellQuote(command),
910 constants.SOCAT_PATH,
911 utils.ShellQuote(self._InstanceMonitor(instance_name))))
912 result = utils.RunCmd(socat)
914 msg = ("Failed to send command '%s' to instance %s."
915 " output: %s, error: %s, fail_reason: %s" %
916 (command, instance_name,
917 result.stdout, result.stderr, result.fail_reason))
918 raise errors.HypervisorError(msg)
923 def _GetKVMVersion(cls):
924 """Return the installed KVM version
926 @return: (version, v_maj, v_min, v_rev), or None
929 result = utils.RunCmd([constants.KVM_PATH, "--help"])
932 match = cls._VERSION_RE.search(result.output.splitlines()[0])
936 return (match.group(0), int(match.group(1)), int(match.group(2)),
939 def StopInstance(self, instance, force=False, retry=False, name=None):
943 if name is not None and not force:
944 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
947 acpi = instance.hvparams[constants.HV_ACPI]
950 _, pid, alive = self._InstancePidAlive(name)
951 if pid > 0 and alive:
952 if force or not acpi:
953 utils.KillProcess(pid)
955 self._CallMonitorCommand(name, 'system_powerdown')
957 def CleanupInstance(self, instance_name):
958 """Cleanup after a stopped instance
961 pidfile, pid, alive = self._InstancePidAlive(instance_name)
962 if pid > 0 and alive:
963 raise errors.HypervisorError("Cannot cleanup a live instance")
964 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
966 def RebootInstance(self, instance):
967 """Reboot an instance.
970 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
971 # socket the instance will stop, but now power up again. So we'll resort
972 # to shutdown and restart.
973 _, _, alive = self._InstancePidAlive(instance.name)
975 raise errors.HypervisorError("Failed to reboot instance %s:"
976 " not running" % instance.name)
977 # StopInstance will delete the saved KVM runtime so:
978 # ...first load it...
979 kvm_runtime = self._LoadKVMRuntime(instance)
980 # ...now we can safely call StopInstance...
981 if not self.StopInstance(instance):
982 self.StopInstance(instance, force=True)
983 # ...and finally we can save it again, and execute it...
984 self._SaveKVMRuntime(instance, kvm_runtime)
985 self._ExecuteKVMRuntime(instance, kvm_runtime)
987 def MigrationInfo(self, instance):
988 """Get instance information to perform a migration.
990 @type instance: L{objects.Instance}
991 @param instance: instance to be migrated
993 @return: content of the KVM runtime file
996 return self._ReadKVMRuntime(instance.name)
998 def AcceptInstance(self, instance, info, target):
999 """Prepare to accept an instance.
1001 @type instance: L{objects.Instance}
1002 @param instance: instance to be accepted
1004 @param info: content of the KVM runtime file on the source node
1005 @type target: string
1006 @param target: target host (usually ip), on this node
1009 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1010 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1011 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1013 def FinalizeMigration(self, instance, info, success):
1014 """Finalize an instance migration.
1016 Stop the incoming mode KVM.
1018 @type instance: L{objects.Instance}
1019 @param instance: instance whose migration is being finalized
1023 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1024 kvm_nics = kvm_runtime[1]
1026 for nic_seq, nic in enumerate(kvm_nics):
1028 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1029 except EnvironmentError, err:
1030 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1031 instance.name, nic_seq, str(err))
1034 self._ConfigureNIC(instance, nic_seq, nic, tap)
1035 except errors.HypervisorError, err:
1036 logging.warning(str(err))
1038 self._WriteKVMRuntime(instance.name, info)
1040 self.StopInstance(instance, force=True)
1042 def MigrateInstance(self, instance, target, live):
1043 """Migrate an instance to a target node.
1045 The migration will not be attempted if the instance is not
1048 @type instance: L{objects.Instance}
1049 @param instance: the instance to be migrated
1050 @type target: string
1051 @param target: ip address of the target node
1053 @param live: perform a live migration
1056 instance_name = instance.name
1057 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1058 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1060 raise errors.HypervisorError("Instance not running, cannot migrate")
1063 self._CallMonitorCommand(instance_name, 'stop')
1065 migrate_command = ('migrate_set_speed %dm' %
1066 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1067 self._CallMonitorCommand(instance_name, migrate_command)
1069 migrate_command = ('migrate_set_downtime %dms' %
1070 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1071 self._CallMonitorCommand(instance_name, migrate_command)
1073 migrate_command = 'migrate -d tcp:%s:%s' % (target, port)
1074 self._CallMonitorCommand(instance_name, migrate_command)
1076 info_command = 'info migrate'
1080 result = self._CallMonitorCommand(instance_name, info_command)
1081 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1084 if not result.stdout:
1085 logging.info("KVM: empty 'info migrate' result")
1087 logging.warning("KVM: unknown 'info migrate' result: %s",
1089 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1091 status = match.group(1)
1092 if status == 'completed':
1094 elif status == 'active':
1095 # reset the broken answers count
1097 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1098 elif status == 'failed' or status == 'cancelled':
1100 self._CallMonitorCommand(instance_name, 'cont')
1101 raise errors.HypervisorError("Migration %s at the kvm level" %
1104 logging.warning("KVM: unknown migration status '%s'", status)
1106 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1107 if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
1108 raise errors.HypervisorError("Too many 'info migrate' broken answers")
1110 utils.KillProcess(pid)
1111 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1113 def GetNodeInfo(self):
1114 """Return information about the node.
1116 This is just a wrapper over the base GetLinuxNodeInfo method.
1118 @return: a dict with the following keys (values in MiB):
1119 - memory_total: the total memory size on the node
1120 - memory_free: the available memory on the node for instances
1121 - memory_dom0: the memory used by the node itself, if available
1124 return self.GetLinuxNodeInfo()
1127 def GetInstanceConsole(cls, instance, hvparams, beparams):
1128 """Return a command for connecting to the console of an instance.
1131 if hvparams[constants.HV_SERIAL_CONSOLE]:
1132 cmd = [constants.SOCAT_PATH,
1133 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1134 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1135 return objects.InstanceConsole(instance=instance.name,
1136 kind=constants.CONS_SSH,
1137 host=instance.primary_node,
1138 user=constants.GANETI_RUNAS,
1141 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1142 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1143 display = instance.network_port - constants.VNC_BASE_PORT
1144 return objects.InstanceConsole(instance=instance.name,
1145 kind=constants.CONS_VNC,
1146 host=vnc_bind_address,
1147 port=instance.network_port,
1150 return objects.InstanceConsole(instance=instance.name,
1151 kind=constants.CONS_MESSAGE,
1152 message=("No serial shell for instance %s" %
1156 """Verify the hypervisor.
1158 Check that the binary exists.
1161 if not os.path.exists(constants.KVM_PATH):
1162 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1163 if not os.path.exists(constants.SOCAT_PATH):
1164 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1167 def CheckParameterSyntax(cls, hvparams):
1168 """Check the given parameters for validity.
1170 @type hvparams: dict
1171 @param hvparams: dictionary with parameter names/value
1172 @raise errors.HypervisorError: when a parameter is not valid
1175 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1177 kernel_path = hvparams[constants.HV_KERNEL_PATH]
1179 if not hvparams[constants.HV_ROOT_PATH]:
1180 raise errors.HypervisorError("Need a root partition for the instance,"
1181 " if a kernel is defined")
1183 if (hvparams[constants.HV_VNC_X509_VERIFY] and
1184 not hvparams[constants.HV_VNC_X509]):
1185 raise errors.HypervisorError("%s must be defined, if %s is" %
1186 (constants.HV_VNC_X509,
1187 constants.HV_VNC_X509_VERIFY))
1189 boot_order = hvparams[constants.HV_BOOT_ORDER]
1190 if (boot_order == constants.HT_BO_CDROM and
1191 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1192 raise errors.HypervisorError("Cannot boot from cdrom without an"
1195 security_model = hvparams[constants.HV_SECURITY_MODEL]
1196 if security_model == constants.HT_SM_USER:
1197 if not hvparams[constants.HV_SECURITY_DOMAIN]:
1198 raise errors.HypervisorError("A security domain (user to run kvm as)"
1199 " must be specified")
1200 elif (security_model == constants.HT_SM_NONE or
1201 security_model == constants.HT_SM_POOL):
1202 if hvparams[constants.HV_SECURITY_DOMAIN]:
1203 raise errors.HypervisorError("Cannot have a security domain when the"
1204 " security model is 'none' or 'pool'")
1207 def ValidateParameters(cls, hvparams):
1208 """Check the given parameters for validity.
1210 @type hvparams: dict
1211 @param hvparams: dictionary with parameter names/value
1212 @raise errors.HypervisorError: when a parameter is not valid
1215 super(KVMHypervisor, cls).ValidateParameters(hvparams)
1217 security_model = hvparams[constants.HV_SECURITY_MODEL]
1218 if security_model == constants.HT_SM_USER:
1219 username = hvparams[constants.HV_SECURITY_DOMAIN]
1221 pwd.getpwnam(username)
1223 raise errors.HypervisorError("Unknown security domain user %s"
1227 def PowercycleNode(cls):
1228 """KVM powercycle, just a wrapper over Linux powercycle.
1231 cls.LinuxPowercycle()