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 # 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 instance.disk_template in constants.DTS_EXT_MIRROR:
543 if disk_cache != "none":
544 # TODO: make this a hard error, instead of a silent overwrite
545 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
546 " to prevent shared storage corruption on migration",
548 cache_val = ",cache=none"
549 elif disk_cache != constants.HT_CACHE_DEFAULT:
550 cache_val = ",cache=%s" % disk_cache
553 for cfdev, dev_path in block_devices:
554 if cfdev.mode != constants.DISK_RDWR:
555 raise errors.HypervisorError("Instance has read-only disks which"
556 " are not supported by KVM")
557 # TODO: handle FD_LOOP and FD_BLKTAP (?)
559 kvm_cmd.extend(['-boot', 'c'])
560 if disk_type != constants.HT_DISK_IDE:
561 boot_val = ',boot=on'
564 # We only boot from the first disk
569 drive_val = 'file=%s,format=raw%s%s%s' % (dev_path, if_val, boot_val,
571 kvm_cmd.extend(['-drive', drive_val])
573 #Now we can specify a different device type for CDROM devices.
574 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
575 if not cdrom_disk_type:
576 cdrom_disk_type = disk_type
578 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
580 options = ',format=raw,media=cdrom'
582 kvm_cmd.extend(['-boot', 'd'])
583 if cdrom_disk_type != constants.HT_DISK_IDE:
584 options = '%s,boot=on,if=%s' % (options, constants.HT_DISK_IDE)
586 options = '%s,boot=on' % options
588 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
589 if_val = ',if=virtio'
591 if_val = ',if=%s' % cdrom_disk_type
592 options = '%s%s' % (options, if_val)
593 drive_val = 'file=%s%s' % (iso_image, options)
594 kvm_cmd.extend(['-drive', drive_val])
596 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
598 options = ',format=raw,media=cdrom'
599 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
600 if_val = ',if=virtio'
602 if_val = ',if=%s' % cdrom_disk_type
603 options = '%s%s' % (options, if_val)
604 drive_val = 'file=%s%s' % (iso_image2, options)
605 kvm_cmd.extend(['-drive', drive_val])
607 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
609 options = ',format=raw,media=disk'
611 kvm_cmd.extend(['-boot', 'a'])
612 options = '%s,boot=on' % options
613 if_val = ',if=floppy'
614 options = '%s%s' % (options, if_val)
615 drive_val = 'file=%s%s' % (floppy_image, options)
616 kvm_cmd.extend(['-drive', drive_val])
618 kernel_path = hvp[constants.HV_KERNEL_PATH]
620 kvm_cmd.extend(['-kernel', kernel_path])
621 initrd_path = hvp[constants.HV_INITRD_PATH]
623 kvm_cmd.extend(['-initrd', initrd_path])
624 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
625 hvp[constants.HV_KERNEL_ARGS]]
626 if hvp[constants.HV_SERIAL_CONSOLE]:
627 root_append.append('console=ttyS0,38400')
628 kvm_cmd.extend(['-append', ' '.join(root_append)])
630 mem_path = hvp[constants.HV_MEM_PATH]
632 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
634 mouse_type = hvp[constants.HV_USB_MOUSE]
635 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
638 kvm_cmd.extend(['-usb'])
639 kvm_cmd.extend(['-usbdevice', mouse_type])
640 elif vnc_bind_address:
641 kvm_cmd.extend(['-usbdevice', constants.HT_MOUSE_TABLET])
644 if netutils.IP4Address.IsValid(vnc_bind_address):
645 if instance.network_port > constants.VNC_BASE_PORT:
646 display = instance.network_port - constants.VNC_BASE_PORT
647 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
648 vnc_arg = ':%d' % (display)
650 vnc_arg = '%s:%d' % (vnc_bind_address, display)
652 logging.error("Network port is not a valid VNC display (%d < %d)."
653 " Not starting VNC", instance.network_port,
654 constants.VNC_BASE_PORT)
657 # Only allow tls and other option when not binding to a file, for now.
658 # kvm/qemu gets confused otherwise about the filename to use.
660 if hvp[constants.HV_VNC_TLS]:
661 vnc_append = '%s,tls' % vnc_append
662 if hvp[constants.HV_VNC_X509_VERIFY]:
663 vnc_append = '%s,x509verify=%s' % (vnc_append,
664 hvp[constants.HV_VNC_X509])
665 elif hvp[constants.HV_VNC_X509]:
666 vnc_append = '%s,x509=%s' % (vnc_append,
667 hvp[constants.HV_VNC_X509])
668 if hvp[constants.HV_VNC_PASSWORD_FILE]:
669 vnc_append = '%s,password' % vnc_append
671 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
674 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
676 kvm_cmd.extend(['-vnc', vnc_arg])
678 kvm_cmd.extend(['-nographic'])
680 monitor_dev = ("unix:%s,server,nowait" %
681 self._InstanceMonitor(instance.name))
682 kvm_cmd.extend(['-monitor', monitor_dev])
683 if hvp[constants.HV_SERIAL_CONSOLE]:
684 serial_dev = ('unix:%s,server,nowait' %
685 self._InstanceSerial(instance.name))
686 kvm_cmd.extend(['-serial', serial_dev])
688 kvm_cmd.extend(['-serial', 'none'])
690 if hvp[constants.HV_USE_LOCALTIME]:
691 kvm_cmd.extend(['-localtime'])
693 if hvp[constants.HV_KVM_USE_CHROOT]:
694 kvm_cmd.extend(['-chroot', self._InstanceChrootDir(instance.name)])
696 # Save the current instance nics, but defer their expansion as parameters,
697 # as we'll need to generate executable temp files for them.
698 kvm_nics = instance.nics
701 return (kvm_cmd, kvm_nics, hvparams)
703 def _WriteKVMRuntime(self, instance_name, data):
704 """Write an instance's KVM runtime
708 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
710 except EnvironmentError, err:
711 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
713 def _ReadKVMRuntime(self, instance_name):
714 """Read an instance's KVM runtime
718 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
719 except EnvironmentError, err:
720 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
723 def _SaveKVMRuntime(self, instance, kvm_runtime):
724 """Save an instance's KVM runtime
727 kvm_cmd, kvm_nics, hvparams = kvm_runtime
728 serialized_nics = [nic.ToDict() for nic in kvm_nics]
729 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
730 self._WriteKVMRuntime(instance.name, serialized_form)
732 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
733 """Load an instance's KVM runtime
736 if not serialized_runtime:
737 serialized_runtime = self._ReadKVMRuntime(instance.name)
738 loaded_runtime = serializer.Load(serialized_runtime)
739 kvm_cmd, serialized_nics, hvparams = loaded_runtime
740 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
741 return (kvm_cmd, kvm_nics, hvparams)
743 def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
744 """Run the KVM cmd and check for errors
747 @param name: instance name
748 @type kvm_cmd: list of strings
749 @param kvm_cmd: runcmd input for kvm
750 @type tap_fds: list of int
751 @param tap_fds: fds of tap devices opened by Ganeti
755 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
758 utils_wrapper.CloseFdNoError(fd)
761 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
762 (name, result.fail_reason, result.output))
763 if not self._InstancePidAlive(name)[2]:
764 raise errors.HypervisorError("Failed to start instance %s" % name)
766 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
767 """Execute a KVM cmd, after completing it with some last minute data
769 @type incoming: tuple of strings
770 @param incoming: (target_host_ip, port)
773 # Small _ExecuteKVMRuntime hv parameters programming howto:
774 # - conf_hvp contains the parameters as configured on ganeti. they might
775 # have changed since the instance started; only use them if the change
776 # won't affect the inside of the instance (which hasn't been rebooted).
777 # - up_hvp contains the parameters as they were when the instance was
778 # started, plus any new parameter which has been added between ganeti
779 # versions: it is paramount that those default to a value which won't
780 # affect the inside of the instance as well.
781 conf_hvp = instance.hvparams
783 self._CheckDown(name)
787 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
788 up_hvp = objects.FillDict(conf_hvp, up_hvp)
790 kvm_version = self._GetKVMVersion()
792 _, v_major, v_min, _ = kvm_version
794 raise errors.HypervisorError("Unable to get KVM version")
796 # We know it's safe to run as a different user upon migration, so we'll use
797 # the latest conf, from conf_hvp.
798 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
799 if security_model == constants.HT_SM_USER:
800 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
802 # We have reasons to believe changing something like the nic driver/type
803 # upon migration won't exactly fly with the instance kernel, so for nic
804 # related parameters we'll use up_hvp
808 kvm_cmd.extend(["-net", "none"])
812 nic_type = up_hvp[constants.HV_NIC_TYPE]
813 if nic_type == constants.HT_NIC_PARAVIRTUAL:
814 # From version 0.12.0, kvm uses a new sintax for network configuration.
815 if (v_major, v_min) >= (0, 12):
816 nic_model = "virtio-net-pci"
821 if up_hvp[constants.HV_VHOST_NET]:
822 # vhost_net is only available from version 0.13.0 or newer
823 if (v_major, v_min) >= (0, 13):
824 tap_extra = ",vhost=on"
826 raise errors.HypervisorError("vhost_net is configured"
827 " but it is not available")
831 for nic_seq, nic in enumerate(kvm_nics):
832 tapname, tapfd = _OpenTap(vnet_hdr)
835 if (v_major, v_min) >= (0, 12):
836 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
837 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
838 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
840 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
842 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
843 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
846 target, port = incoming
847 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
849 # Changing the vnc password doesn't bother the guest that much. At most it
850 # will surprise people who connect to it. Whether positively or negatively
852 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
856 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
857 except EnvironmentError, err:
858 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
859 % (vnc_pwd_file, err))
861 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
862 utils.EnsureDirs([(self._InstanceChrootDir(name),
863 constants.SECURE_DIR_MODE)])
866 # Configure the network now for starting instances, during
867 # FinalizeMigration for incoming instances
868 for nic_seq, nic in enumerate(kvm_nics):
869 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
871 if security_model == constants.HT_SM_POOL:
872 ss = ssconf.SimpleStore()
873 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
874 all_uids = set(uidpool.ExpandUidPool(uid_pool))
875 uid = uidpool.RequestUnusedUid(all_uids)
877 username = pwd.getpwuid(uid.GetUid()).pw_name
878 kvm_cmd.extend(["-runas", username])
879 self._RunKVMCmd(name, kvm_cmd, tapfds)
881 uidpool.ReleaseUid(uid)
885 utils.WriteFile(self._InstanceUidFile(name), data=str(uid))
887 self._RunKVMCmd(name, kvm_cmd, tapfds)
889 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
890 constants.RUN_DIRS_MODE)])
891 for nic_seq, tap in enumerate(taps):
892 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
896 change_cmd = 'change vnc password %s' % vnc_pwd
897 self._CallMonitorCommand(instance.name, change_cmd)
899 for filename in temp_files:
900 utils.RemoveFile(filename)
902 def StartInstance(self, instance, block_devices):
903 """Start an instance.
906 self._CheckDown(instance.name)
907 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
908 self._SaveKVMRuntime(instance, kvm_runtime)
909 self._ExecuteKVMRuntime(instance, kvm_runtime)
911 def _CallMonitorCommand(self, instance_name, command):
912 """Invoke a command on the instance monitor.
915 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
916 (utils.ShellQuote(command),
917 constants.SOCAT_PATH,
918 utils.ShellQuote(self._InstanceMonitor(instance_name))))
919 result = utils.RunCmd(socat)
921 msg = ("Failed to send command '%s' to instance %s."
922 " output: %s, error: %s, fail_reason: %s" %
923 (command, instance_name,
924 result.stdout, result.stderr, result.fail_reason))
925 raise errors.HypervisorError(msg)
930 def _GetKVMVersion(cls):
931 """Return the installed KVM version
933 @return: (version, v_maj, v_min, v_rev), or None
936 result = utils.RunCmd([constants.KVM_PATH, "--help"])
939 match = cls._VERSION_RE.search(result.output.splitlines()[0])
943 return (match.group(0), int(match.group(1)), int(match.group(2)),
946 def StopInstance(self, instance, force=False, retry=False, name=None):
950 if name is not None and not force:
951 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
954 acpi = instance.hvparams[constants.HV_ACPI]
957 _, pid, alive = self._InstancePidAlive(name)
958 if pid > 0 and alive:
959 if force or not acpi:
960 utils.KillProcess(pid)
962 self._CallMonitorCommand(name, 'system_powerdown')
964 def CleanupInstance(self, instance_name):
965 """Cleanup after a stopped instance
968 pidfile, pid, alive = self._InstancePidAlive(instance_name)
969 if pid > 0 and alive:
970 raise errors.HypervisorError("Cannot cleanup a live instance")
971 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
973 def RebootInstance(self, instance):
974 """Reboot an instance.
977 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
978 # socket the instance will stop, but now power up again. So we'll resort
979 # to shutdown and restart.
980 _, _, alive = self._InstancePidAlive(instance.name)
982 raise errors.HypervisorError("Failed to reboot instance %s:"
983 " not running" % instance.name)
984 # StopInstance will delete the saved KVM runtime so:
985 # ...first load it...
986 kvm_runtime = self._LoadKVMRuntime(instance)
987 # ...now we can safely call StopInstance...
988 if not self.StopInstance(instance):
989 self.StopInstance(instance, force=True)
990 # ...and finally we can save it again, and execute it...
991 self._SaveKVMRuntime(instance, kvm_runtime)
992 self._ExecuteKVMRuntime(instance, kvm_runtime)
994 def MigrationInfo(self, instance):
995 """Get instance information to perform a migration.
997 @type instance: L{objects.Instance}
998 @param instance: instance to be migrated
1000 @return: content of the KVM runtime file
1003 return self._ReadKVMRuntime(instance.name)
1005 def AcceptInstance(self, instance, info, target):
1006 """Prepare to accept an instance.
1008 @type instance: L{objects.Instance}
1009 @param instance: instance to be accepted
1011 @param info: content of the KVM runtime file on the source node
1012 @type target: string
1013 @param target: target host (usually ip), on this node
1016 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1017 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1018 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
1020 def FinalizeMigration(self, instance, info, success):
1021 """Finalize an instance migration.
1023 Stop the incoming mode KVM.
1025 @type instance: L{objects.Instance}
1026 @param instance: instance whose migration is being finalized
1030 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1031 kvm_nics = kvm_runtime[1]
1033 for nic_seq, nic in enumerate(kvm_nics):
1035 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1036 except EnvironmentError, err:
1037 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1038 instance.name, nic_seq, str(err))
1041 self._ConfigureNIC(instance, nic_seq, nic, tap)
1042 except errors.HypervisorError, err:
1043 logging.warning(str(err))
1045 self._WriteKVMRuntime(instance.name, info)
1047 self.StopInstance(instance, force=True)
1049 def MigrateInstance(self, instance, target, live):
1050 """Migrate an instance to a target node.
1052 The migration will not be attempted if the instance is not
1055 @type instance: L{objects.Instance}
1056 @param instance: the instance to be migrated
1057 @type target: string
1058 @param target: ip address of the target node
1060 @param live: perform a live migration
1063 instance_name = instance.name
1064 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1065 pidfile, pid, alive = self._InstancePidAlive(instance_name)
1067 raise errors.HypervisorError("Instance not running, cannot migrate")
1070 self._CallMonitorCommand(instance_name, 'stop')
1072 migrate_command = ('migrate_set_speed %dm' %
1073 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1074 self._CallMonitorCommand(instance_name, migrate_command)
1076 migrate_command = ('migrate_set_downtime %dms' %
1077 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1078 self._CallMonitorCommand(instance_name, migrate_command)
1080 migrate_command = 'migrate -d tcp:%s:%s' % (target, port)
1081 self._CallMonitorCommand(instance_name, migrate_command)
1083 info_command = 'info migrate'
1087 result = self._CallMonitorCommand(instance_name, info_command)
1088 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1091 if not result.stdout:
1092 logging.info("KVM: empty 'info migrate' result")
1094 logging.warning("KVM: unknown 'info migrate' result: %s",
1096 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1098 status = match.group(1)
1099 if status == 'completed':
1101 elif status == 'active':
1102 # reset the broken answers count
1104 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1105 elif status == 'failed' or status == 'cancelled':
1107 self._CallMonitorCommand(instance_name, 'cont')
1108 raise errors.HypervisorError("Migration %s at the kvm level" %
1111 logging.warning("KVM: unknown migration status '%s'", status)
1113 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1114 if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
1115 raise errors.HypervisorError("Too many 'info migrate' broken answers")
1117 utils.KillProcess(pid)
1118 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1120 def GetNodeInfo(self):
1121 """Return information about the node.
1123 This is just a wrapper over the base GetLinuxNodeInfo method.
1125 @return: a dict with the following keys (values in MiB):
1126 - memory_total: the total memory size on the node
1127 - memory_free: the available memory on the node for instances
1128 - memory_dom0: the memory used by the node itself, if available
1131 return self.GetLinuxNodeInfo()
1134 def GetInstanceConsole(cls, instance, hvparams, beparams):
1135 """Return a command for connecting to the console of an instance.
1138 if hvparams[constants.HV_SERIAL_CONSOLE]:
1139 cmd = [constants.SOCAT_PATH,
1140 "STDIO,%s" % cls._SocatUnixConsoleParams(),
1141 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
1142 return objects.InstanceConsole(instance=instance.name,
1143 kind=constants.CONS_SSH,
1144 host=instance.primary_node,
1145 user=constants.GANETI_RUNAS,
1148 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1149 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
1150 display = instance.network_port - constants.VNC_BASE_PORT
1151 return objects.InstanceConsole(instance=instance.name,
1152 kind=constants.CONS_VNC,
1153 host=vnc_bind_address,
1154 port=instance.network_port,
1157 return objects.InstanceConsole(instance=instance.name,
1158 kind=constants.CONS_MESSAGE,
1159 message=("No serial shell for instance %s" %
1163 """Verify the hypervisor.
1165 Check that the binary exists.
1168 if not os.path.exists(constants.KVM_PATH):
1169 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1170 if not os.path.exists(constants.SOCAT_PATH):
1171 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1174 def CheckParameterSyntax(cls, hvparams):
1175 """Check the given parameters for validity.
1177 @type hvparams: dict
1178 @param hvparams: dictionary with parameter names/value
1179 @raise errors.HypervisorError: when a parameter is not valid
1182 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1184 kernel_path = hvparams[constants.HV_KERNEL_PATH]
1186 if not hvparams[constants.HV_ROOT_PATH]:
1187 raise errors.HypervisorError("Need a root partition for the instance,"
1188 " if a kernel is defined")
1190 if (hvparams[constants.HV_VNC_X509_VERIFY] and
1191 not hvparams[constants.HV_VNC_X509]):
1192 raise errors.HypervisorError("%s must be defined, if %s is" %
1193 (constants.HV_VNC_X509,
1194 constants.HV_VNC_X509_VERIFY))
1196 boot_order = hvparams[constants.HV_BOOT_ORDER]
1197 if (boot_order == constants.HT_BO_CDROM and
1198 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1199 raise errors.HypervisorError("Cannot boot from cdrom without an"
1202 security_model = hvparams[constants.HV_SECURITY_MODEL]
1203 if security_model == constants.HT_SM_USER:
1204 if not hvparams[constants.HV_SECURITY_DOMAIN]:
1205 raise errors.HypervisorError("A security domain (user to run kvm as)"
1206 " must be specified")
1207 elif (security_model == constants.HT_SM_NONE or
1208 security_model == constants.HT_SM_POOL):
1209 if hvparams[constants.HV_SECURITY_DOMAIN]:
1210 raise errors.HypervisorError("Cannot have a security domain when the"
1211 " security model is 'none' or 'pool'")
1214 def ValidateParameters(cls, hvparams):
1215 """Check the given parameters for validity.
1217 @type hvparams: dict
1218 @param hvparams: dictionary with parameter names/value
1219 @raise errors.HypervisorError: when a parameter is not valid
1222 super(KVMHypervisor, cls).ValidateParameters(hvparams)
1224 security_model = hvparams[constants.HV_SECURITY_MODEL]
1225 if security_model == constants.HT_SM_USER:
1226 username = hvparams[constants.HV_SECURITY_DOMAIN]
1228 pwd.getpwnam(username)
1230 raise errors.HypervisorError("Unknown security domain user %s"
1234 def PowercycleNode(cls):
1235 """KVM powercycle, just a wrapper over Linux powercycle.
1238 cls.LinuxPowercycle()