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.IsValidIP4(x) or utils.IsNormAbsPath(x)),
179 "the VNC bind address must be either a valid IP address or an absolute"
180 " pathname", None, None),
181 constants.HV_VNC_TLS: hv_base.NO_CHECK,
182 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
183 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
184 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
185 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
186 constants.HV_BOOT_ORDER:
187 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
188 constants.HV_NIC_TYPE:
189 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
190 constants.HV_DISK_TYPE:
191 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
192 constants.HV_USB_MOUSE:
193 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
194 constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
195 constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
196 constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
197 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
198 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
199 constants.HV_DISK_CACHE:
200 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
201 constants.HV_SECURITY_MODEL:
202 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
203 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
204 constants.HV_KVM_FLAG:
205 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
206 constants.HV_VHOST_NET: hv_base.NO_CHECK,
207 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
210 _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
212 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
213 _MIGRATION_INFO_RETRY_DELAY = 2
215 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)\.(\d+)\b")
222 hv_base.BaseHypervisor.__init__(self)
223 # Let's make sure the directories we need exist, even if the RUN_DIR lives
224 # in a tmpfs filesystem or has been otherwise wiped out.
225 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
226 utils.EnsureDirs(dirs)
229 def _InstancePidFile(cls, instance_name):
230 """Returns the instance pidfile.
233 return utils.PathJoin(cls._PIDS_DIR, instance_name)
236 def _InstanceUidFile(cls, instance_name):
237 """Returns the instance uidfile.
240 return utils.PathJoin(cls._UIDS_DIR, instance_name)
243 def _InstancePidInfo(cls, pid):
244 """Check pid file for instance information.
246 Check that a pid file is associated with an instance, and retrieve
247 information from its command line.
249 @type pid: string or int
250 @param pid: process id of the instance to check
252 @return: (instance_name, memory, vcpus)
253 @raise errors.HypervisorError: when an instance cannot be found
256 alive = utils.IsProcessAlive(pid)
258 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
260 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
262 cmdline = utils.ReadFile(cmdline_file)
263 except EnvironmentError, err:
264 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
271 arg_list = cmdline.split('\x00')
273 arg = arg_list.pop(0)
275 instance = arg_list.pop(0)
277 memory = int(arg_list.pop(0))
279 vcpus = int(arg_list.pop(0))
282 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
285 return (instance, memory, vcpus)
287 def _InstancePidAlive(self, instance_name):
288 """Returns the instance pidfile, pid, and liveness.
290 @type instance_name: string
291 @param instance_name: instance name
293 @return: (pid file name, pid, liveness)
296 pidfile = self._InstancePidFile(instance_name)
297 pid = utils.ReadPidFile(pidfile)
301 cmd_instance = self._InstancePidInfo(pid)[0]
302 alive = (cmd_instance == instance_name)
303 except errors.HypervisorError:
306 return (pidfile, pid, alive)
308 def _CheckDown(self, instance_name):
309 """Raises an error unless the given instance is down.
312 alive = self._InstancePidAlive(instance_name)[2]
314 raise errors.HypervisorError("Failed to start instance %s: %s" %
315 (instance_name, "already running"))
318 def _InstanceMonitor(cls, instance_name):
319 """Returns the instance monitor socket name
322 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
325 def _InstanceSerial(cls, instance_name):
326 """Returns the instance serial socket name
329 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
332 def _SocatUnixConsoleParams():
333 """Returns the correct parameters for socat
335 If we have a new-enough socat we can use raw mode with an escape character.
338 if constants.SOCAT_USE_ESCAPE:
339 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
341 return "echo=0,icanon=0"
344 def _InstanceKVMRuntime(cls, instance_name):
345 """Returns the instance KVM runtime filename
348 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
351 def _InstanceChrootDir(cls, instance_name):
352 """Returns the name of the KVM chroot dir of the instance
355 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
358 def _TryReadUidFile(cls, uid_file):
359 """Try to read a uid file
362 if os.path.exists(uid_file):
364 uid = int(utils.ReadOneLineFile(uid_file))
366 except EnvironmentError:
367 logging.warning("Can't read uid file", exc_info=True)
368 except (TypeError, ValueError):
369 logging.warning("Can't parse uid file contents", exc_info=True)
373 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
374 """Removes an instance's rutime sockets/files/dirs.
377 utils.RemoveFile(pidfile)
378 utils.RemoveFile(cls._InstanceMonitor(instance_name))
379 utils.RemoveFile(cls._InstanceSerial(instance_name))
380 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
381 uid_file = cls._InstanceUidFile(instance_name)
382 uid = cls._TryReadUidFile(uid_file)
383 utils.RemoveFile(uid_file)
385 uidpool.ReleaseUid(uid)
387 chroot_dir = cls._InstanceChrootDir(instance_name)
388 utils.RemoveDir(chroot_dir)
390 if err.errno == errno.ENOTEMPTY:
391 # The chroot directory is expected to be empty, but it isn't.
392 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
395 utils.TimestampForFilename()))
396 logging.warning("The chroot directory of instance %s can not be"
397 " removed as it is not empty. Moving it to the"
398 " quarantine instead. Please investigate the"
399 " contents (%s) and clean up manually",
400 instance_name, new_chroot_dir)
401 utils.RenameFile(chroot_dir, new_chroot_dir)
406 def _WriteNetScriptFile(instance, seq, nic):
407 """Write a script to connect a net interface to the proper bridge.
409 This can be used by any qemu-type hypervisor.
411 @param instance: instance we're acting on
412 @type instance: instance object
413 @param seq: nic sequence number
415 @param nic: nic we're acting on
416 @type nic: nic object
417 @return: netscript file name
421 script = _WriteNetScript(instance, nic, seq)
423 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
424 # mounted noexec sometimes, so we'll have to find another place.
425 (tmpfd, tmpfile_name) = tempfile.mkstemp()
426 tmpfile = os.fdopen(tmpfd, 'w')
428 tmpfile.write(script)
431 os.chmod(tmpfile_name, 0755)
434 def ListInstances(self):
435 """Get the list of running instances.
437 We can do this by listing our live instances directory and
438 checking whether the associated kvm process is still alive.
442 for name in os.listdir(self._PIDS_DIR):
443 if self._InstancePidAlive(name)[2]:
447 def GetInstanceInfo(self, instance_name):
448 """Get instance properties.
450 @type instance_name: string
451 @param instance_name: the instance name
452 @rtype: tuple of strings
453 @return: (name, id, memory, vcpus, stat, times)
456 _, pid, alive = self._InstancePidAlive(instance_name)
460 _, memory, vcpus = self._InstancePidInfo(pid)
464 return (instance_name, pid, memory, vcpus, stat, times)
466 def GetAllInstancesInfo(self):
467 """Get properties of all instances.
469 @return: list of tuples (name, id, memory, vcpus, stat, times)
473 for name in os.listdir(self._PIDS_DIR):
475 info = self.GetInstanceInfo(name)
476 except errors.HypervisorError:
482 def _GenerateKVMRuntime(self, instance, block_devices):
483 """Generate KVM information to start an instance.
486 pidfile = self._InstancePidFile(instance.name)
487 kvm = constants.KVM_PATH
489 # used just by the vnc server, if enabled
490 kvm_cmd.extend(['-name', instance.name])
491 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
492 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
493 kvm_cmd.extend(['-pidfile', pidfile])
494 kvm_cmd.extend(['-daemonize'])
495 if not instance.hvparams[constants.HV_ACPI]:
496 kvm_cmd.extend(['-no-acpi'])
498 hvp = instance.hvparams
499 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
500 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
501 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
503 if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
504 kvm_cmd.extend(["-enable-kvm"])
505 elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
506 kvm_cmd.extend(["-disable-kvm"])
509 kvm_cmd.extend(['-boot', 'n'])
511 disk_type = hvp[constants.HV_DISK_TYPE]
512 if disk_type == constants.HT_DISK_PARAVIRTUAL:
513 if_val = ',if=virtio'
515 if_val = ',if=%s' % disk_type
517 disk_cache = hvp[constants.HV_DISK_CACHE]
518 if disk_cache != constants.HT_CACHE_DEFAULT:
519 cache_val = ",cache=%s" % disk_cache
522 for cfdev, dev_path in block_devices:
523 if cfdev.mode != constants.DISK_RDWR:
524 raise errors.HypervisorError("Instance has read-only disks which"
525 " are not supported by KVM")
526 # TODO: handle FD_LOOP and FD_BLKTAP (?)
528 kvm_cmd.extend(['-boot', 'c'])
529 if disk_type != constants.HT_DISK_IDE:
530 boot_val = ',boot=on'
533 # We only boot from the first disk
538 drive_val = 'file=%s,format=raw%s%s%s' % (dev_path, if_val, boot_val,
540 kvm_cmd.extend(['-drive', drive_val])
542 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
544 options = ',format=raw,media=cdrom'
546 kvm_cmd.extend(['-boot', 'd'])
547 if disk_type != constants.HT_DISK_IDE:
548 options = '%s,boot=on' % options
550 if disk_type == constants.HT_DISK_PARAVIRTUAL:
551 if_val = ',if=virtio'
553 if_val = ',if=%s' % disk_type
554 options = '%s%s' % (options, if_val)
555 drive_val = 'file=%s%s' % (iso_image, options)
556 kvm_cmd.extend(['-drive', drive_val])
558 kernel_path = hvp[constants.HV_KERNEL_PATH]
560 kvm_cmd.extend(['-kernel', kernel_path])
561 initrd_path = hvp[constants.HV_INITRD_PATH]
563 kvm_cmd.extend(['-initrd', initrd_path])
564 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
565 hvp[constants.HV_KERNEL_ARGS]]
566 if hvp[constants.HV_SERIAL_CONSOLE]:
567 root_append.append('console=ttyS0,38400')
568 kvm_cmd.extend(['-append', ' '.join(root_append)])
570 mouse_type = hvp[constants.HV_USB_MOUSE]
571 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
574 kvm_cmd.extend(['-usb'])
575 kvm_cmd.extend(['-usbdevice', mouse_type])
576 elif vnc_bind_address:
577 kvm_cmd.extend(['-usbdevice', constants.HT_MOUSE_TABLET])
580 if netutils.IsValidIP4(vnc_bind_address):
581 if instance.network_port > constants.VNC_BASE_PORT:
582 display = instance.network_port - constants.VNC_BASE_PORT
583 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
584 vnc_arg = ':%d' % (display)
586 vnc_arg = '%s:%d' % (vnc_bind_address, display)
588 logging.error("Network port is not a valid VNC display (%d < %d)."
589 " Not starting VNC", instance.network_port,
590 constants.VNC_BASE_PORT)
593 # Only allow tls and other option when not binding to a file, for now.
594 # kvm/qemu gets confused otherwise about the filename to use.
596 if hvp[constants.HV_VNC_TLS]:
597 vnc_append = '%s,tls' % vnc_append
598 if hvp[constants.HV_VNC_X509_VERIFY]:
599 vnc_append = '%s,x509verify=%s' % (vnc_append,
600 hvp[constants.HV_VNC_X509])
601 elif hvp[constants.HV_VNC_X509]:
602 vnc_append = '%s,x509=%s' % (vnc_append,
603 hvp[constants.HV_VNC_X509])
604 if hvp[constants.HV_VNC_PASSWORD_FILE]:
605 vnc_append = '%s,password' % vnc_append
607 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
610 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
612 kvm_cmd.extend(['-vnc', vnc_arg])
614 kvm_cmd.extend(['-nographic'])
616 monitor_dev = ("unix:%s,server,nowait" %
617 self._InstanceMonitor(instance.name))
618 kvm_cmd.extend(['-monitor', monitor_dev])
619 if hvp[constants.HV_SERIAL_CONSOLE]:
620 serial_dev = ('unix:%s,server,nowait' %
621 self._InstanceSerial(instance.name))
622 kvm_cmd.extend(['-serial', serial_dev])
624 kvm_cmd.extend(['-serial', 'none'])
626 if hvp[constants.HV_USE_LOCALTIME]:
627 kvm_cmd.extend(['-localtime'])
629 if hvp[constants.HV_KVM_USE_CHROOT]:
630 kvm_cmd.extend(['-chroot', self._InstanceChrootDir(instance.name)])
632 # Save the current instance nics, but defer their expansion as parameters,
633 # as we'll need to generate executable temp files for them.
634 kvm_nics = instance.nics
637 return (kvm_cmd, kvm_nics, hvparams)
639 def _WriteKVMRuntime(self, instance_name, data):
640 """Write an instance's KVM runtime
644 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
646 except EnvironmentError, err:
647 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
649 def _ReadKVMRuntime(self, instance_name):
650 """Read an instance's KVM runtime
654 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
655 except EnvironmentError, err:
656 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
659 def _SaveKVMRuntime(self, instance, kvm_runtime):
660 """Save an instance's KVM runtime
663 kvm_cmd, kvm_nics, hvparams = kvm_runtime
664 serialized_nics = [nic.ToDict() for nic in kvm_nics]
665 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
666 self._WriteKVMRuntime(instance.name, serialized_form)
668 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
669 """Load an instance's KVM runtime
672 if not serialized_runtime:
673 serialized_runtime = self._ReadKVMRuntime(instance.name)
674 loaded_runtime = serializer.Load(serialized_runtime)
675 kvm_cmd, serialized_nics, hvparams = loaded_runtime
676 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
677 return (kvm_cmd, kvm_nics, hvparams)
679 def _RunKVMCmd(self, name, kvm_cmd):
680 """Run the KVM cmd and check for errors
683 @param name: instance name
684 @type kvm_cmd: list of strings
685 @param kvm_cmd: runcmd input for kvm
688 result = utils.RunCmd(kvm_cmd)
690 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
691 (name, result.fail_reason, result.output))
692 if not self._InstancePidAlive(name)[2]:
693 raise errors.HypervisorError("Failed to start instance %s" % name)
695 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
696 """Execute a KVM cmd, after completing it with some last minute data
698 @type incoming: tuple of strings
699 @param incoming: (target_host_ip, port)
702 # Small _ExecuteKVMRuntime hv parameters programming howto:
703 # - conf_hvp contains the parameters as configured on ganeti. they might
704 # have changed since the instance started; only use them if the change
705 # won't affect the inside of the instance (which hasn't been rebooted).
706 # - up_hvp contains the parameters as they were when the instance was
707 # started, plus any new parameter which has been added between ganeti
708 # versions: it is paramount that those default to a value which won't
709 # affect the inside of the instance as well.
710 conf_hvp = instance.hvparams
712 self._CheckDown(name)
716 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
717 up_hvp = objects.FillDict(conf_hvp, up_hvp)
719 # We know it's safe to run as a different user upon migration, so we'll use
720 # the latest conf, from conf_hvp.
721 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
722 if security_model == constants.HT_SM_USER:
723 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
725 # We have reasons to believe changing something like the nic driver/type
726 # upon migration won't exactly fly with the instance kernel, so for nic
727 # related parameters we'll use up_hvp
729 kvm_cmd.extend(["-net", "none"])
732 nic_type = up_hvp[constants.HV_NIC_TYPE]
733 if nic_type == constants.HT_NIC_PARAVIRTUAL:
734 nic_model = "model=virtio"
735 if up_hvp[constants.HV_VHOST_NET]:
736 tap_extra = ",vhost=on"
738 nic_model = "model=%s" % nic_type
740 for nic_seq, nic in enumerate(kvm_nics):
741 nic_val = "nic,vlan=%s,macaddr=%s,%s" % (nic_seq, nic.mac, nic_model)
742 script = self._WriteNetScriptFile(instance, nic_seq, nic)
743 tap_val = "tap,vlan=%s,script=%s%s" % (nic_seq, script, tap_extra)
744 kvm_cmd.extend(["-net", nic_val])
745 kvm_cmd.extend(["-net", tap_val])
746 temp_files.append(script)
749 target, port = incoming
750 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
752 # Changing the vnc password doesn't bother the guest that much. At most it
753 # will surprise people who connect to it. Whether positively or negatively
755 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
759 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
760 except EnvironmentError, err:
761 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
762 % (vnc_pwd_file, err))
764 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
765 utils.EnsureDirs([(self._InstanceChrootDir(name),
766 constants.SECURE_DIR_MODE)])
768 if security_model == constants.HT_SM_POOL:
769 ss = ssconf.SimpleStore()
770 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
771 all_uids = set(uidpool.ExpandUidPool(uid_pool))
772 uid = uidpool.RequestUnusedUid(all_uids)
774 username = pwd.getpwuid(uid.GetUid()).pw_name
775 kvm_cmd.extend(["-runas", username])
776 self._RunKVMCmd(name, kvm_cmd)
778 uidpool.ReleaseUid(uid)
782 utils.WriteFile(self._InstanceUidFile(name), data=str(uid))
784 self._RunKVMCmd(name, kvm_cmd)
787 change_cmd = 'change vnc password %s' % vnc_pwd
788 self._CallMonitorCommand(instance.name, change_cmd)
790 for filename in temp_files:
791 utils.RemoveFile(filename)
793 def StartInstance(self, instance, block_devices):
794 """Start an instance.
797 self._CheckDown(instance.name)
798 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
799 self._SaveKVMRuntime(instance, kvm_runtime)
800 self._ExecuteKVMRuntime(instance, kvm_runtime)
802 def _CallMonitorCommand(self, instance_name, command):
803 """Invoke a command on the instance monitor.
806 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
807 (utils.ShellQuote(command),
808 constants.SOCAT_PATH,
809 utils.ShellQuote(self._InstanceMonitor(instance_name))))
810 result = utils.RunCmd(socat)
812 msg = ("Failed to send command '%s' to instance %s."
813 " output: %s, error: %s, fail_reason: %s" %
814 (command, instance_name,
815 result.stdout, result.stderr, result.fail_reason))
816 raise errors.HypervisorError(msg)
821 def _GetKVMVersion(cls):
822 """Return the installed KVM version
824 @return: (version, v_maj, v_min, v_rev), or None
827 result = utils.RunCmd([constants.KVM_PATH, "--help"])
830 match = cls._VERSION_RE.search(result.output.splitlines()[0])
833 return (match.group(0), match.group(1), match.group(2), match.group(3))
835 def StopInstance(self, instance, force=False, retry=False, name=None):
839 if name is not None and not force:
840 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
843 acpi = instance.hvparams[constants.HV_ACPI]
846 _, pid, alive = self._InstancePidAlive(name)
847 if pid > 0 and alive:
848 if force or not acpi:
849 utils.KillProcess(pid)
851 self._CallMonitorCommand(name, 'system_powerdown')
853 def CleanupInstance(self, instance_name):
854 """Cleanup after a stopped instance
857 pidfile, pid, alive = self._InstancePidAlive(instance_name)
858 if pid > 0 and alive:
859 raise errors.HypervisorError("Cannot cleanup a live instance")
860 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
862 def RebootInstance(self, instance):
863 """Reboot an instance.
866 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
867 # socket the instance will stop, but now power up again. So we'll resort
868 # to shutdown and restart.
869 _, _, alive = self._InstancePidAlive(instance.name)
871 raise errors.HypervisorError("Failed to reboot instance %s:"
872 " not running" % instance.name)
873 # StopInstance will delete the saved KVM runtime so:
874 # ...first load it...
875 kvm_runtime = self._LoadKVMRuntime(instance)
876 # ...now we can safely call StopInstance...
877 if not self.StopInstance(instance):
878 self.StopInstance(instance, force=True)
879 # ...and finally we can save it again, and execute it...
880 self._SaveKVMRuntime(instance, kvm_runtime)
881 self._ExecuteKVMRuntime(instance, kvm_runtime)
883 def MigrationInfo(self, instance):
884 """Get instance information to perform a migration.
886 @type instance: L{objects.Instance}
887 @param instance: instance to be migrated
889 @return: content of the KVM runtime file
892 return self._ReadKVMRuntime(instance.name)
894 def AcceptInstance(self, instance, info, target):
895 """Prepare to accept an instance.
897 @type instance: L{objects.Instance}
898 @param instance: instance to be accepted
900 @param info: content of the KVM runtime file on the source node
902 @param target: target host (usually ip), on this node
905 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
906 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
907 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
909 def FinalizeMigration(self, instance, info, success):
910 """Finalize an instance migration.
912 Stop the incoming mode KVM.
914 @type instance: L{objects.Instance}
915 @param instance: instance whose migration is being finalized
919 self._WriteKVMRuntime(instance.name, info)
921 self.StopInstance(instance, force=True)
923 def MigrateInstance(self, instance, target, live):
924 """Migrate an instance to a target node.
926 The migration will not be attempted if the instance is not
929 @type instance: L{objects.Instance}
930 @param instance: the instance to be migrated
932 @param target: ip address of the target node
934 @param live: perform a live migration
937 instance_name = instance.name
938 port = instance.hvparams[constants.HV_MIGRATION_PORT]
939 pidfile, pid, alive = self._InstancePidAlive(instance_name)
941 raise errors.HypervisorError("Instance not running, cannot migrate")
944 self._CallMonitorCommand(instance_name, 'stop')
946 migrate_command = ('migrate_set_speed %dm' %
947 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
948 self._CallMonitorCommand(instance_name, migrate_command)
950 migrate_command = ('migrate_set_downtime %dms' %
951 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
952 self._CallMonitorCommand(instance_name, migrate_command)
954 migrate_command = 'migrate -d tcp:%s:%s' % (target, port)
955 self._CallMonitorCommand(instance_name, migrate_command)
957 info_command = 'info migrate'
961 result = self._CallMonitorCommand(instance_name, info_command)
962 match = self._MIGRATION_STATUS_RE.search(result.stdout)
965 if not result.stdout:
966 logging.info("KVM: empty 'info migrate' result")
968 logging.warning("KVM: unknown 'info migrate' result: %s",
970 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
972 status = match.group(1)
973 if status == 'completed':
975 elif status == 'active':
976 # reset the broken answers count
978 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
979 elif status == 'failed' or status == 'cancelled':
981 self._CallMonitorCommand(instance_name, 'cont')
982 raise errors.HypervisorError("Migration %s at the kvm level" %
985 logging.warning("KVM: unknown migration status '%s'", status)
987 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
988 if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
989 raise errors.HypervisorError("Too many 'info migrate' broken answers")
991 utils.KillProcess(pid)
992 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
994 def GetNodeInfo(self):
995 """Return information about the node.
997 This is just a wrapper over the base GetLinuxNodeInfo method.
999 @return: a dict with the following keys (values in MiB):
1000 - memory_total: the total memory size on the node
1001 - memory_free: the available memory on the node for instances
1002 - memory_dom0: the memory used by the node itself, if available
1005 return self.GetLinuxNodeInfo()
1008 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
1009 """Return a command for connecting to the console of an instance.
1012 if hvparams[constants.HV_SERIAL_CONSOLE]:
1013 shell_command = ("%s STDIO,%s UNIX-CONNECT:%s" %
1014 (constants.SOCAT_PATH, cls._SocatUnixConsoleParams(),
1015 utils.ShellQuote(cls._InstanceSerial(instance.name))))
1017 shell_command = "echo 'No serial shell for instance %s'" % instance.name
1019 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
1020 if vnc_bind_address:
1021 if instance.network_port > constants.VNC_BASE_PORT:
1022 display = instance.network_port - constants.VNC_BASE_PORT
1023 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
1024 " (display: %d)'" % (vnc_bind_address,
1025 instance.network_port,
1027 shell_command = "%s; %s" % (vnc_command, shell_command)
1029 return shell_command
1032 """Verify the hypervisor.
1034 Check that the binary exists.
1037 if not os.path.exists(constants.KVM_PATH):
1038 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
1039 if not os.path.exists(constants.SOCAT_PATH):
1040 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
1044 def CheckParameterSyntax(cls, hvparams):
1045 """Check the given parameters for validity.
1047 @type hvparams: dict
1048 @param hvparams: dictionary with parameter names/value
1049 @raise errors.HypervisorError: when a parameter is not valid
1052 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
1054 kernel_path = hvparams[constants.HV_KERNEL_PATH]
1056 if not hvparams[constants.HV_ROOT_PATH]:
1057 raise errors.HypervisorError("Need a root partition for the instance,"
1058 " if a kernel is defined")
1060 if (hvparams[constants.HV_VNC_X509_VERIFY] and
1061 not hvparams[constants.HV_VNC_X509]):
1062 raise errors.HypervisorError("%s must be defined, if %s is" %
1063 (constants.HV_VNC_X509,
1064 constants.HV_VNC_X509_VERIFY))
1066 boot_order = hvparams[constants.HV_BOOT_ORDER]
1067 if (boot_order == constants.HT_BO_CDROM and
1068 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
1069 raise errors.HypervisorError("Cannot boot from cdrom without an"
1072 security_model = hvparams[constants.HV_SECURITY_MODEL]
1073 if security_model == constants.HT_SM_USER:
1074 if not hvparams[constants.HV_SECURITY_DOMAIN]:
1075 raise errors.HypervisorError("A security domain (user to run kvm as)"
1076 " must be specified")
1077 elif (security_model == constants.HT_SM_NONE or
1078 security_model == constants.HT_SM_POOL):
1079 if hvparams[constants.HV_SECURITY_DOMAIN]:
1080 raise errors.HypervisorError("Cannot have a security domain when the"
1081 " security model is 'none' or 'pool'")
1084 def ValidateParameters(cls, hvparams):
1085 """Check the given parameters for validity.
1087 @type hvparams: dict
1088 @param hvparams: dictionary with parameter names/value
1089 @raise errors.HypervisorError: when a parameter is not valid
1092 super(KVMHypervisor, cls).ValidateParameters(hvparams)
1094 security_model = hvparams[constants.HV_SECURITY_MODEL]
1095 if security_model == constants.HT_SM_USER:
1096 username = hvparams[constants.HV_SECURITY_DOMAIN]
1098 pwd.getpwnam(username)
1100 raise errors.HypervisorError("Unknown security domain user %s"
1104 def PowercycleNode(cls):
1105 """KVM powercycle, just a wrapper over Linux powercycle.
1108 cls.LinuxPowercycle()