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
34 from cStringIO import StringIO
36 from ganeti import utils
37 from ganeti import constants
38 from ganeti import errors
39 from ganeti import serializer
40 from ganeti import objects
41 from ganeti import uidpool
42 from ganeti import ssconf
43 from ganeti.hypervisor import hv_base
44 from ganeti import netutils
47 _KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
50 def _WriteNetScript(instance, nic, index):
51 """Write a script to connect a net interface to the proper bridge.
53 This can be used by any qemu-type hypervisor.
55 @type instance: L{objects.Instance}
56 @param instance: Instance object
57 @type nic: L{objects.NIC}
58 @param nic: NIC object
60 @param index: NIC index
66 tags = " ".join(instance.tags)
71 sw = utils.ShellWriter(buf)
73 sw.Write("# this is autogenerated by Ganeti, please do not edit")
74 sw.Write("export PATH=$PATH:/sbin:/usr/sbin")
75 sw.Write("export INSTANCE=%s", utils.ShellQuote(instance.name))
76 sw.Write("export MAC=%s", utils.ShellQuote(nic.mac))
77 sw.Write("export MODE=%s",
78 utils.ShellQuote(nic.nicparams[constants.NIC_MODE]))
79 sw.Write("export INTERFACE=\"$1\"")
80 sw.Write("export TAGS=%s", utils.ShellQuote(tags))
83 sw.Write("export IP=%s", utils.ShellQuote(nic.ip))
85 if nic.nicparams[constants.NIC_LINK]:
86 sw.Write("export LINK=%s",
87 utils.ShellQuote(nic.nicparams[constants.NIC_LINK]))
89 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
90 sw.Write("export BRIDGE=%s",
91 utils.ShellQuote(nic.nicparams[constants.NIC_LINK]))
93 # TODO: make this configurable at ./configure time
94 sw.Write("if [ -x %s ]; then", utils.ShellQuote(_KVM_NETWORK_SCRIPT))
97 sw.Write("# Execute the user-specific vif file")
98 sw.Write(_KVM_NETWORK_SCRIPT)
104 sw.Write("ifconfig $INTERFACE 0.0.0.0 up")
106 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
107 sw.Write("# Connect the interface to the bridge")
108 sw.Write("brctl addif $BRIDGE $INTERFACE")
110 elif nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED:
112 raise errors.HypervisorError("nic/%d is routed, but has no IP"
115 sw.Write("# Route traffic targeted at the IP to the interface")
116 if nic.nicparams[constants.NIC_LINK]:
117 sw.Write("while ip rule del dev $INTERFACE; do :; done")
118 sw.Write("ip rule add dev $INTERFACE table $LINK")
119 sw.Write("ip route replace $IP table $LINK proto static"
122 sw.Write("ip route replace $IP proto static dev $INTERFACE")
124 interface_v4_conf = "/proc/sys/net/ipv4/conf/$INTERFACE"
125 sw.Write(" if [ -d %s ]; then", interface_v4_conf)
128 sw.Write("echo 1 > %s/proxy_arp", interface_v4_conf)
129 sw.Write("echo 1 > %s/forwarding", interface_v4_conf)
134 interface_v6_conf = "/proc/sys/net/ipv6/conf/$INTERFACE"
135 sw.Write("if [ -d %s ]; then", interface_v6_conf)
138 sw.Write("echo 1 > %s/proxy_ndp", interface_v6_conf)
139 sw.Write("echo 1 > %s/forwarding", interface_v6_conf)
147 return buf.getvalue()
150 class KVMHypervisor(hv_base.BaseHypervisor):
151 """KVM hypervisor interface"""
154 _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
155 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
156 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
157 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
158 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
159 # KVM instances with chroot enabled are started in empty chroot directories.
160 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
161 # After an instance is stopped, its chroot directory is removed.
162 # If the chroot directory is not empty, it can't be removed.
163 # A non-empty chroot directory indicates a possible security incident.
164 # To support forensics, the non-empty chroot directory is quarantined in
165 # a separate directory, called 'chroot-quarantine'.
166 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
167 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR,
168 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR]
171 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
172 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
173 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
174 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
175 constants.HV_ACPI: hv_base.NO_CHECK,
176 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
177 constants.HV_VNC_BIND_ADDRESS:
178 (False, lambda x: (netutils.IP4Address.IsValid(x) or
179 utils.IsNormAbsPath(x)),
180 "the VNC bind address must be either a valid IP address or an absolute"
181 " pathname", None, None),
182 constants.HV_VNC_TLS: hv_base.NO_CHECK,
183 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
184 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
185 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
186 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
187 constants.HV_BOOT_ORDER:
188 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
189 constants.HV_NIC_TYPE:
190 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
191 constants.HV_DISK_TYPE:
192 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
193 constants.HV_USB_MOUSE:
194 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
195 constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
196 constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
197 constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
198 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
199 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
200 constants.HV_DISK_CACHE:
201 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
202 constants.HV_SECURITY_MODEL:
203 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
204 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
205 constants.HV_KVM_FLAG:
206 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
207 constants.HV_VHOST_NET: hv_base.NO_CHECK,
208 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
209 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
212 _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
214 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
215 _MIGRATION_INFO_RETRY_DELAY = 2
217 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)\.(\d+)\b")
224 hv_base.BaseHypervisor.__init__(self)
225 # Let's make sure the directories we need exist, even if the RUN_DIR lives
226 # in a tmpfs filesystem or has been otherwise wiped out.
227 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
228 utils.EnsureDirs(dirs)
231 def _InstancePidFile(cls, instance_name):
232 """Returns the instance pidfile.
235 return utils.PathJoin(cls._PIDS_DIR, instance_name)
238 def _InstanceUidFile(cls, instance_name):
239 """Returns the instance uidfile.
242 return utils.PathJoin(cls._UIDS_DIR, instance_name)
245 def _InstancePidInfo(cls, pid):
246 """Check pid file for instance information.
248 Check that a pid file is associated with an instance, and retrieve
249 information from its command line.
251 @type pid: string or int
252 @param pid: process id of the instance to check
254 @return: (instance_name, memory, vcpus)
255 @raise errors.HypervisorError: when an instance cannot be found
258 alive = utils.IsProcessAlive(pid)
260 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
262 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
264 cmdline = utils.ReadFile(cmdline_file)
265 except EnvironmentError, err:
266 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
273 arg_list = cmdline.split('\x00')
275 arg = arg_list.pop(0)
277 instance = arg_list.pop(0)
279 memory = int(arg_list.pop(0))
281 vcpus = int(arg_list.pop(0))
284 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
287 return (instance, memory, vcpus)
289 def _InstancePidAlive(self, instance_name):
290 """Returns the instance pidfile, pid, and liveness.
292 @type instance_name: string
293 @param instance_name: instance name
295 @return: (pid file name, pid, liveness)
298 pidfile = self._InstancePidFile(instance_name)
299 pid = utils.ReadPidFile(pidfile)
303 cmd_instance = self._InstancePidInfo(pid)[0]
304 alive = (cmd_instance == instance_name)
305 except errors.HypervisorError:
308 return (pidfile, pid, alive)
310 def _CheckDown(self, instance_name):
311 """Raises an error unless the given instance is down.
314 alive = self._InstancePidAlive(instance_name)[2]
316 raise errors.HypervisorError("Failed to start instance %s: %s" %
317 (instance_name, "already running"))
320 def _InstanceMonitor(cls, instance_name):
321 """Returns the instance monitor socket name
324 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
327 def _InstanceSerial(cls, instance_name):
328 """Returns the instance serial socket name
331 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
334 def _SocatUnixConsoleParams():
335 """Returns the correct parameters for socat
337 If we have a new-enough socat we can use raw mode with an escape character.
340 if constants.SOCAT_USE_ESCAPE:
341 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
343 return "echo=0,icanon=0"
346 def _InstanceKVMRuntime(cls, instance_name):
347 """Returns the instance KVM runtime filename
350 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
353 def _InstanceChrootDir(cls, instance_name):
354 """Returns the name of the KVM chroot dir of the instance
357 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
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 chroot_dir = cls._InstanceChrootDir(instance_name)
390 utils.RemoveDir(chroot_dir)
392 if err.errno == errno.ENOTEMPTY:
393 # The chroot directory is expected to be empty, but it isn't.
394 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
397 utils.TimestampForFilename()))
398 logging.warning("The chroot directory of instance %s can not be"
399 " removed as it is not empty. Moving it to the"
400 " quarantine instead. Please investigate the"
401 " contents (%s) and clean up manually",
402 instance_name, new_chroot_dir)
403 utils.RenameFile(chroot_dir, new_chroot_dir)
408 def _WriteNetScriptFile(instance, seq, nic):
409 """Write a script to connect a net interface to the proper bridge.
411 This can be used by any qemu-type hypervisor.
413 @param instance: instance we're acting on
414 @type instance: instance object
415 @param seq: nic sequence number
417 @param nic: nic we're acting on
418 @type nic: nic object
419 @return: netscript file name
423 script = _WriteNetScript(instance, nic, seq)
425 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
426 # mounted noexec sometimes, so we'll have to find another place.
427 (tmpfd, tmpfile_name) = tempfile.mkstemp()
428 tmpfile = os.fdopen(tmpfd, 'w')
430 tmpfile.write(script)
433 os.chmod(tmpfile_name, 0755)
436 def ListInstances(self):
437 """Get the list of running instances.
439 We can do this by listing our live instances directory and
440 checking whether the associated kvm process is still alive.
444 for name in os.listdir(self._PIDS_DIR):
445 if self._InstancePidAlive(name)[2]:
449 def GetInstanceInfo(self, instance_name):
450 """Get instance properties.
452 @type instance_name: string
453 @param instance_name: the instance name
454 @rtype: tuple of strings
455 @return: (name, id, memory, vcpus, stat, times)
458 _, pid, alive = self._InstancePidAlive(instance_name)
462 _, memory, vcpus = self._InstancePidInfo(pid)
466 return (instance_name, pid, memory, vcpus, stat, times)
468 def GetAllInstancesInfo(self):
469 """Get properties of all instances.
471 @return: list of tuples (name, id, memory, vcpus, stat, times)
475 for name in os.listdir(self._PIDS_DIR):
477 info = self.GetInstanceInfo(name)
478 except errors.HypervisorError:
484 def _GenerateKVMRuntime(self, instance, block_devices):
485 """Generate KVM information to start an instance.
488 pidfile = self._InstancePidFile(instance.name)
489 kvm = constants.KVM_PATH
491 # used just by the vnc server, if enabled
492 kvm_cmd.extend(['-name', instance.name])
493 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
494 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
495 kvm_cmd.extend(['-pidfile', pidfile])
496 kvm_cmd.extend(['-daemonize'])
497 if not instance.hvparams[constants.HV_ACPI]:
498 kvm_cmd.extend(['-no-acpi'])
500 hvp = instance.hvparams
501 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
502 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
503 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
505 if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
506 kvm_cmd.extend(["-enable-kvm"])
507 elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
508 kvm_cmd.extend(["-disable-kvm"])
511 kvm_cmd.extend(['-boot', 'n'])
513 disk_type = hvp[constants.HV_DISK_TYPE]
514 if disk_type == constants.HT_DISK_PARAVIRTUAL:
515 if_val = ',if=virtio'
517 if_val = ',if=%s' % disk_type
519 disk_cache = hvp[constants.HV_DISK_CACHE]
520 if disk_cache != constants.HT_CACHE_DEFAULT:
521 cache_val = ",cache=%s" % disk_cache
524 for cfdev, dev_path in block_devices:
525 if cfdev.mode != constants.DISK_RDWR:
526 raise errors.HypervisorError("Instance has read-only disks which"
527 " are not supported by KVM")
528 # TODO: handle FD_LOOP and FD_BLKTAP (?)
530 kvm_cmd.extend(['-boot', 'c'])
531 if disk_type != constants.HT_DISK_IDE:
532 boot_val = ',boot=on'
535 # We only boot from the first disk
540 drive_val = 'file=%s,format=raw%s%s%s' % (dev_path, if_val, boot_val,
542 kvm_cmd.extend(['-drive', drive_val])
544 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
546 options = ',format=raw,media=cdrom'
548 kvm_cmd.extend(['-boot', 'd'])
549 if disk_type != constants.HT_DISK_IDE:
550 options = '%s,boot=on' % options
552 if disk_type == constants.HT_DISK_PARAVIRTUAL:
553 if_val = ',if=virtio'
555 if_val = ',if=%s' % disk_type
556 options = '%s%s' % (options, if_val)
557 drive_val = 'file=%s%s' % (iso_image, options)
558 kvm_cmd.extend(['-drive', drive_val])
560 kernel_path = hvp[constants.HV_KERNEL_PATH]
562 kvm_cmd.extend(['-kernel', kernel_path])
563 initrd_path = hvp[constants.HV_INITRD_PATH]
565 kvm_cmd.extend(['-initrd', initrd_path])
566 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
567 hvp[constants.HV_KERNEL_ARGS]]
568 if hvp[constants.HV_SERIAL_CONSOLE]:
569 root_append.append('console=ttyS0,38400')
570 kvm_cmd.extend(['-append', ' '.join(root_append)])
572 mem_path = hvp[constants.HV_MEM_PATH]
574 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
576 mouse_type = hvp[constants.HV_USB_MOUSE]
577 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
580 kvm_cmd.extend(['-usb'])
581 kvm_cmd.extend(['-usbdevice', mouse_type])
582 elif vnc_bind_address:
583 kvm_cmd.extend(['-usbdevice', constants.HT_MOUSE_TABLET])
586 if netutils.IP4Address.IsValid(vnc_bind_address):
587 if instance.network_port > constants.VNC_BASE_PORT:
588 display = instance.network_port - constants.VNC_BASE_PORT
589 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
590 vnc_arg = ':%d' % (display)
592 vnc_arg = '%s:%d' % (vnc_bind_address, display)
594 logging.error("Network port is not a valid VNC display (%d < %d)."
595 " Not starting VNC", instance.network_port,
596 constants.VNC_BASE_PORT)
599 # Only allow tls and other option when not binding to a file, for now.
600 # kvm/qemu gets confused otherwise about the filename to use.
602 if hvp[constants.HV_VNC_TLS]:
603 vnc_append = '%s,tls' % vnc_append
604 if hvp[constants.HV_VNC_X509_VERIFY]:
605 vnc_append = '%s,x509verify=%s' % (vnc_append,
606 hvp[constants.HV_VNC_X509])
607 elif hvp[constants.HV_VNC_X509]:
608 vnc_append = '%s,x509=%s' % (vnc_append,
609 hvp[constants.HV_VNC_X509])
610 if hvp[constants.HV_VNC_PASSWORD_FILE]:
611 vnc_append = '%s,password' % vnc_append
613 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
616 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
618 kvm_cmd.extend(['-vnc', vnc_arg])
620 kvm_cmd.extend(['-nographic'])
622 monitor_dev = ("unix:%s,server,nowait" %
623 self._InstanceMonitor(instance.name))
624 kvm_cmd.extend(['-monitor', monitor_dev])
625 if hvp[constants.HV_SERIAL_CONSOLE]:
626 serial_dev = ('unix:%s,server,nowait' %
627 self._InstanceSerial(instance.name))
628 kvm_cmd.extend(['-serial', serial_dev])
630 kvm_cmd.extend(['-serial', 'none'])
632 if hvp[constants.HV_USE_LOCALTIME]:
633 kvm_cmd.extend(['-localtime'])
635 if hvp[constants.HV_KVM_USE_CHROOT]:
636 kvm_cmd.extend(['-chroot', self._InstanceChrootDir(instance.name)])
638 # Save the current instance nics, but defer their expansion as parameters,
639 # as we'll need to generate executable temp files for them.
640 kvm_nics = instance.nics
643 return (kvm_cmd, kvm_nics, hvparams)
645 def _WriteKVMRuntime(self, instance_name, data):
646 """Write an instance's KVM runtime
650 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
652 except EnvironmentError, err:
653 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
655 def _ReadKVMRuntime(self, instance_name):
656 """Read an instance's KVM runtime
660 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
661 except EnvironmentError, err:
662 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
665 def _SaveKVMRuntime(self, instance, kvm_runtime):
666 """Save an instance's KVM runtime
669 kvm_cmd, kvm_nics, hvparams = kvm_runtime
670 serialized_nics = [nic.ToDict() for nic in kvm_nics]
671 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
672 self._WriteKVMRuntime(instance.name, serialized_form)
674 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
675 """Load an instance's KVM runtime
678 if not serialized_runtime:
679 serialized_runtime = self._ReadKVMRuntime(instance.name)
680 loaded_runtime = serializer.Load(serialized_runtime)
681 kvm_cmd, serialized_nics, hvparams = loaded_runtime
682 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
683 return (kvm_cmd, kvm_nics, hvparams)
685 def _RunKVMCmd(self, name, kvm_cmd):
686 """Run the KVM cmd and check for errors
689 @param name: instance name
690 @type kvm_cmd: list of strings
691 @param kvm_cmd: runcmd input for kvm
694 result = utils.RunCmd(kvm_cmd)
696 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
697 (name, result.fail_reason, result.output))
698 if not self._InstancePidAlive(name)[2]:
699 raise errors.HypervisorError("Failed to start instance %s" % name)
701 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
702 """Execute a KVM cmd, after completing it with some last minute data
704 @type incoming: tuple of strings
705 @param incoming: (target_host_ip, port)
708 # Small _ExecuteKVMRuntime hv parameters programming howto:
709 # - conf_hvp contains the parameters as configured on ganeti. they might
710 # have changed since the instance started; only use them if the change
711 # won't affect the inside of the instance (which hasn't been rebooted).
712 # - up_hvp contains the parameters as they were when the instance was
713 # started, plus any new parameter which has been added between ganeti
714 # versions: it is paramount that those default to a value which won't
715 # affect the inside of the instance as well.
716 conf_hvp = instance.hvparams
718 self._CheckDown(name)
722 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
723 up_hvp = objects.FillDict(conf_hvp, up_hvp)
725 # We know it's safe to run as a different user upon migration, so we'll use
726 # the latest conf, from conf_hvp.
727 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
728 if security_model == constants.HT_SM_USER:
729 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
731 # We have reasons to believe changing something like the nic driver/type
732 # upon migration won't exactly fly with the instance kernel, so for nic
733 # related parameters we'll use up_hvp
735 kvm_cmd.extend(["-net", "none"])
738 nic_type = up_hvp[constants.HV_NIC_TYPE]
739 if nic_type == constants.HT_NIC_PARAVIRTUAL:
740 nic_model = "model=virtio"
741 if up_hvp[constants.HV_VHOST_NET]:
742 tap_extra = ",vhost=on"
744 nic_model = "model=%s" % nic_type
746 for nic_seq, nic in enumerate(kvm_nics):
747 nic_val = "nic,vlan=%s,macaddr=%s,%s" % (nic_seq, nic.mac, nic_model)
748 script = self._WriteNetScriptFile(instance, nic_seq, nic)
749 tap_val = "tap,vlan=%s,script=%s%s" % (nic_seq, script, tap_extra)
750 kvm_cmd.extend(["-net", nic_val])
751 kvm_cmd.extend(["-net", tap_val])
752 temp_files.append(script)
755 target, port = incoming
756 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
758 # Changing the vnc password doesn't bother the guest that much. At most it
759 # will surprise people who connect to it. Whether positively or negatively
761 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
765 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
766 except EnvironmentError, err:
767 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
768 % (vnc_pwd_file, err))
770 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
771 utils.EnsureDirs([(self._InstanceChrootDir(name),
772 constants.SECURE_DIR_MODE)])
774 if security_model == constants.HT_SM_POOL:
775 ss = ssconf.SimpleStore()
776 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
777 all_uids = set(uidpool.ExpandUidPool(uid_pool))
778 uid = uidpool.RequestUnusedUid(all_uids)
780 username = pwd.getpwuid(uid.GetUid()).pw_name
781 kvm_cmd.extend(["-runas", username])
782 self._RunKVMCmd(name, kvm_cmd)
784 uidpool.ReleaseUid(uid)
788 utils.WriteFile(self._InstanceUidFile(name), data=str(uid))
790 self._RunKVMCmd(name, kvm_cmd)
793 change_cmd = 'change vnc password %s' % vnc_pwd
794 self._CallMonitorCommand(instance.name, change_cmd)
796 for filename in temp_files:
797 utils.RemoveFile(filename)
799 def StartInstance(self, instance, block_devices):
800 """Start an instance.
803 self._CheckDown(instance.name)
804 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
805 self._SaveKVMRuntime(instance, kvm_runtime)
806 self._ExecuteKVMRuntime(instance, kvm_runtime)
808 def _CallMonitorCommand(self, instance_name, command):
809 """Invoke a command on the instance monitor.
812 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
813 (utils.ShellQuote(command),
814 constants.SOCAT_PATH,
815 utils.ShellQuote(self._InstanceMonitor(instance_name))))
816 result = utils.RunCmd(socat)
818 msg = ("Failed to send command '%s' to instance %s."
819 " output: %s, error: %s, fail_reason: %s" %
820 (command, instance_name,
821 result.stdout, result.stderr, result.fail_reason))
822 raise errors.HypervisorError(msg)
827 def _GetKVMVersion(cls):
828 """Return the installed KVM version
830 @return: (version, v_maj, v_min, v_rev), or None
833 result = utils.RunCmd([constants.KVM_PATH, "--help"])
836 match = cls._VERSION_RE.search(result.output.splitlines()[0])
839 return (match.group(0), match.group(1), match.group(2), match.group(3))
841 def StopInstance(self, instance, force=False, retry=False, name=None):
845 if name is not None and not force:
846 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
849 acpi = instance.hvparams[constants.HV_ACPI]
852 _, pid, alive = self._InstancePidAlive(name)
853 if pid > 0 and alive:
854 if force or not acpi:
855 utils.KillProcess(pid)
857 self._CallMonitorCommand(name, 'system_powerdown')
859 def CleanupInstance(self, instance_name):
860 """Cleanup after a stopped instance
863 pidfile, pid, alive = self._InstancePidAlive(instance_name)
864 if pid > 0 and alive:
865 raise errors.HypervisorError("Cannot cleanup a live instance")
866 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
868 def RebootInstance(self, instance):
869 """Reboot an instance.
872 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
873 # socket the instance will stop, but now power up again. So we'll resort
874 # to shutdown and restart.
875 _, _, alive = self._InstancePidAlive(instance.name)
877 raise errors.HypervisorError("Failed to reboot instance %s:"
878 " not running" % instance.name)
879 # StopInstance will delete the saved KVM runtime so:
880 # ...first load it...
881 kvm_runtime = self._LoadKVMRuntime(instance)
882 # ...now we can safely call StopInstance...
883 if not self.StopInstance(instance):
884 self.StopInstance(instance, force=True)
885 # ...and finally we can save it again, and execute it...
886 self._SaveKVMRuntime(instance, kvm_runtime)
887 self._ExecuteKVMRuntime(instance, kvm_runtime)
889 def MigrationInfo(self, instance):
890 """Get instance information to perform a migration.
892 @type instance: L{objects.Instance}
893 @param instance: instance to be migrated
895 @return: content of the KVM runtime file
898 return self._ReadKVMRuntime(instance.name)
900 def AcceptInstance(self, instance, info, target):
901 """Prepare to accept an instance.
903 @type instance: L{objects.Instance}
904 @param instance: instance to be accepted
906 @param info: content of the KVM runtime file on the source node
908 @param target: target host (usually ip), on this node
911 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
912 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
913 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
915 def FinalizeMigration(self, instance, info, success):
916 """Finalize an instance migration.
918 Stop the incoming mode KVM.
920 @type instance: L{objects.Instance}
921 @param instance: instance whose migration is being finalized
925 self._WriteKVMRuntime(instance.name, info)
927 self.StopInstance(instance, force=True)
929 def MigrateInstance(self, instance, target, live):
930 """Migrate an instance to a target node.
932 The migration will not be attempted if the instance is not
935 @type instance: L{objects.Instance}
936 @param instance: the instance to be migrated
938 @param target: ip address of the target node
940 @param live: perform a live migration
943 instance_name = instance.name
944 port = instance.hvparams[constants.HV_MIGRATION_PORT]
945 pidfile, pid, alive = self._InstancePidAlive(instance_name)
947 raise errors.HypervisorError("Instance not running, cannot migrate")
950 self._CallMonitorCommand(instance_name, 'stop')
952 migrate_command = ('migrate_set_speed %dm' %
953 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
954 self._CallMonitorCommand(instance_name, migrate_command)
956 migrate_command = ('migrate_set_downtime %dms' %
957 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
958 self._CallMonitorCommand(instance_name, migrate_command)
960 migrate_command = 'migrate -d tcp:%s:%s' % (target, port)
961 self._CallMonitorCommand(instance_name, migrate_command)
963 info_command = 'info migrate'
967 result = self._CallMonitorCommand(instance_name, info_command)
968 match = self._MIGRATION_STATUS_RE.search(result.stdout)
971 if not result.stdout:
972 logging.info("KVM: empty 'info migrate' result")
974 logging.warning("KVM: unknown 'info migrate' result: %s",
976 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
978 status = match.group(1)
979 if status == 'completed':
981 elif status == 'active':
982 # reset the broken answers count
984 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
985 elif status == 'failed' or status == 'cancelled':
987 self._CallMonitorCommand(instance_name, 'cont')
988 raise errors.HypervisorError("Migration %s at the kvm level" %
991 logging.warning("KVM: unknown migration status '%s'", status)
993 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
994 if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
995 raise errors.HypervisorError("Too many 'info migrate' broken answers")
997 utils.KillProcess(pid)
998 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
1000 def GetNodeInfo(self):
1001 """Return information about the node.
1003 This is just a wrapper over the base GetLinuxNodeInfo method.
1005 @return: a dict with the following keys (values in MiB):
1006 - memory_total: the total memory size on the node
1007 - memory_free: the available memory on the node for instances
1008 - memory_dom0: the memory used by the node itself, if available
1011 return self.GetLinuxNodeInfo()
1014 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
1015 """Return a command for connecting to the console of an instance.
1018 if hvparams[constants.HV_SERIAL_CONSOLE]:
1019 shell_command = ("%s STDIO,%s UNIX-CONNECT:%s" %
1020 (constants.SOCAT_PATH, cls._SocatUnixConsoleParams(),
1021 utils.ShellQuote(cls._InstanceSerial(instance.name))))
1023 shell_command = "echo 'No serial shell for instance %s'" % instance.name
1025 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1026 if vnc_bind_address:
1027 if instance.network_port > constants.VNC_BASE_PORT:
1028 display = instance.network_port - constants.VNC_BASE_PORT
1029 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
1030 " (display: %d)'" % (vnc_bind_address,
1031 instance.network_port,
1033 shell_command = "%s; %s" % (vnc_command, shell_command)
1035 return shell_command
1038 """Verify the hypervisor.
1040 Check that the binary exists.
1043 if not os.path.exists(constants.KVM_PATH):
1044 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1045 if not os.path.exists(constants.SOCAT_PATH):
1046 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1050 def CheckParameterSyntax(cls, hvparams):
1051 """Check the given parameters for validity.
1053 @type hvparams: dict
1054 @param hvparams: dictionary with parameter names/value
1055 @raise errors.HypervisorError: when a parameter is not valid
1058 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1060 kernel_path = hvparams[constants.HV_KERNEL_PATH]
1062 if not hvparams[constants.HV_ROOT_PATH]:
1063 raise errors.HypervisorError("Need a root partition for the instance,"
1064 " if a kernel is defined")
1066 if (hvparams[constants.HV_VNC_X509_VERIFY] and
1067 not hvparams[constants.HV_VNC_X509]):
1068 raise errors.HypervisorError("%s must be defined, if %s is" %
1069 (constants.HV_VNC_X509,
1070 constants.HV_VNC_X509_VERIFY))
1072 boot_order = hvparams[constants.HV_BOOT_ORDER]
1073 if (boot_order == constants.HT_BO_CDROM and
1074 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1075 raise errors.HypervisorError("Cannot boot from cdrom without an"
1078 security_model = hvparams[constants.HV_SECURITY_MODEL]
1079 if security_model == constants.HT_SM_USER:
1080 if not hvparams[constants.HV_SECURITY_DOMAIN]:
1081 raise errors.HypervisorError("A security domain (user to run kvm as)"
1082 " must be specified")
1083 elif (security_model == constants.HT_SM_NONE or
1084 security_model == constants.HT_SM_POOL):
1085 if hvparams[constants.HV_SECURITY_DOMAIN]:
1086 raise errors.HypervisorError("Cannot have a security domain when the"
1087 " security model is 'none' or 'pool'")
1090 def ValidateParameters(cls, hvparams):
1091 """Check the given parameters for validity.
1093 @type hvparams: dict
1094 @param hvparams: dictionary with parameter names/value
1095 @raise errors.HypervisorError: when a parameter is not valid
1098 super(KVMHypervisor, cls).ValidateParameters(hvparams)
1100 security_model = hvparams[constants.HV_SECURITY_MODEL]
1101 if security_model == constants.HT_SM_USER:
1102 username = hvparams[constants.HV_SECURITY_DOMAIN]
1104 pwd.getpwnam(username)
1106 raise errors.HypervisorError("Unknown security domain user %s"
1110 def PowercycleNode(cls):
1111 """KVM powercycle, just a wrapper over Linux powercycle.
1114 cls.LinuxPowercycle()