4 # Copyright (C) 2008 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
46 class KVMHypervisor(hv_base.BaseHypervisor):
47 """KVM hypervisor interface"""
50 _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
51 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
52 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids
53 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
54 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
55 # KVM instances with chroot enabled are started in empty chroot directories.
56 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
57 # After an instance is stopped, its chroot directory is removed.
58 # If the chroot directory is not empty, it can't be removed.
59 # A non-empty chroot directory indicates a possible security incident.
60 # To support forensics, the non-empty chroot directory is quarantined in
61 # a separate directory, called 'chroot-quarantine'.
62 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
63 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR,
64 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR]
67 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
68 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
69 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
70 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
71 constants.HV_ACPI: hv_base.NO_CHECK,
72 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
73 constants.HV_VNC_BIND_ADDRESS:
74 (False, lambda x: (utils.IsValidIP(x) or utils.IsNormAbsPath(x)),
75 "the VNC bind address must be either a valid IP address or an absolute"
76 " pathname", None, None),
77 constants.HV_VNC_TLS: hv_base.NO_CHECK,
78 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
79 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
80 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
81 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
82 constants.HV_BOOT_ORDER:
83 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
84 constants.HV_NIC_TYPE:
85 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
86 constants.HV_DISK_TYPE:
87 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
88 constants.HV_USB_MOUSE:
89 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
90 constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
91 constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
92 constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
93 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
94 constants.HV_DISK_CACHE:
95 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
96 constants.HV_SECURITY_MODEL:
97 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
98 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
99 constants.HV_KVM_FLAG:
100 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
101 constants.HV_VHOST_NET: hv_base.NO_CHECK,
102 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
105 _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
107 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
108 _MIGRATION_INFO_RETRY_DELAY = 2
110 _KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
117 hv_base.BaseHypervisor.__init__(self)
118 # Let's make sure the directories we need exist, even if the RUN_DIR lives
119 # in a tmpfs filesystem or has been otherwise wiped out.
120 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
121 utils.EnsureDirs(dirs)
124 def _InstancePidFile(cls, instance_name):
125 """Returns the instance pidfile.
128 return utils.PathJoin(cls._PIDS_DIR, instance_name)
131 def _InstanceUidFile(cls, instance_name):
132 """Returns the instance uidfile.
135 return utils.PathJoin(cls._UIDS_DIR, instance_name)
138 def _InstancePidInfo(cls, pid):
139 """Check pid file for instance information.
141 Check that a pid file is associated with an instance, and retrieve
142 information from its command line.
144 @type pid: string or int
145 @param pid: process id of the instance to check
147 @return: (instance_name, memory, vcpus)
148 @raise errors.HypervisorError: when an instance cannot be found
151 alive = utils.IsProcessAlive(pid)
153 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
155 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
157 cmdline = utils.ReadFile(cmdline_file)
158 except EnvironmentError, err:
159 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
166 arg_list = cmdline.split('\x00')
168 arg = arg_list.pop(0)
170 instance = arg_list.pop(0)
172 memory = int(arg_list.pop(0))
174 vcpus = int(arg_list.pop(0))
177 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
180 return (instance, memory, vcpus)
182 def _InstancePidAlive(self, instance_name):
183 """Returns the instance pidfile, pid, and liveness.
185 @type instance_name: string
186 @param instance_name: instance name
188 @return: (pid file name, pid, liveness)
191 pidfile = self._InstancePidFile(instance_name)
192 pid = utils.ReadPidFile(pidfile)
196 cmd_instance = self._InstancePidInfo(pid)[0]
197 alive = (cmd_instance == instance_name)
198 except errors.HypervisorError:
201 return (pidfile, pid, alive)
203 def _CheckDown(self, instance_name):
204 """Raises an error unless the given instance is down.
207 alive = self._InstancePidAlive(instance_name)[2]
209 raise errors.HypervisorError("Failed to start instance %s: %s" %
210 (instance_name, "already running"))
213 def _InstanceMonitor(cls, instance_name):
214 """Returns the instance monitor socket name
217 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
220 def _InstanceSerial(cls, instance_name):
221 """Returns the instance serial socket name
224 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
227 def _SocatUnixConsoleParams():
228 """Returns the correct parameters for socat
230 If we have a new-enough socat we can use raw mode with an escape character.
233 if constants.SOCAT_USE_ESCAPE:
234 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
236 return "echo=0,icanon=0"
239 def _InstanceKVMRuntime(cls, instance_name):
240 """Returns the instance KVM runtime filename
243 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
246 def _InstanceChrootDir(cls, instance_name):
247 """Returns the name of the KVM chroot dir of the instance
250 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
253 def _TryReadUidFile(cls, uid_file):
254 """Try to read a uid file
257 if os.path.exists(uid_file):
259 uid = int(utils.ReadOneLineFile(uid_file))
261 except EnvironmentError:
262 logging.warning("Can't read uid file", exc_info=True)
263 except (TypeError, ValueError):
264 logging.warning("Can't parse uid file contents", exc_info=True)
268 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
269 """Removes an instance's rutime sockets/files/dirs.
272 utils.RemoveFile(pidfile)
273 utils.RemoveFile(cls._InstanceMonitor(instance_name))
274 utils.RemoveFile(cls._InstanceSerial(instance_name))
275 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
276 uid_file = cls._InstanceUidFile(instance_name)
277 uid = cls._TryReadUidFile(uid_file)
278 utils.RemoveFile(uid_file)
280 uidpool.ReleaseUid(uid)
282 chroot_dir = cls._InstanceChrootDir(instance_name)
283 utils.RemoveDir(chroot_dir)
285 if err.errno == errno.ENOTEMPTY:
286 # The chroot directory is expected to be empty, but it isn't.
287 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
290 utils.TimestampForFilename()))
291 logging.warning("The chroot directory of instance %s can not be"
292 " removed as it is not empty. Moving it to the"
293 " quarantine instead. Please investigate the"
294 " contents (%s) and clean up manually",
295 instance_name, new_chroot_dir)
296 utils.RenameFile(chroot_dir, new_chroot_dir)
300 def _WriteNetScript(self, instance, seq, nic):
301 """Write a script to connect a net interface to the proper bridge.
303 This can be used by any qemu-type hypervisor.
305 @param instance: instance we're acting on
306 @type instance: instance object
307 @param seq: nic sequence number
309 @param nic: nic we're acting on
310 @type nic: nic object
311 @return: netscript file name
316 script.write("#!/bin/sh\n")
317 script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
318 script.write("PATH=$PATH:/sbin:/usr/sbin\n")
319 script.write("export INSTANCE=%s\n" % instance.name)
320 script.write("export MAC=%s\n" % nic.mac)
322 script.write("export IP=%s\n" % nic.ip)
323 script.write("export MODE=%s\n" % nic.nicparams[constants.NIC_MODE])
324 if nic.nicparams[constants.NIC_LINK]:
325 script.write("export LINK=%s\n" % nic.nicparams[constants.NIC_LINK])
326 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
327 script.write("export BRIDGE=%s\n" % nic.nicparams[constants.NIC_LINK])
328 script.write("export INTERFACE=$1\n")
330 script.write("export TAGS=\"%s\"\n" % " ".join(instance.tags))
331 # TODO: make this configurable at ./configure time
332 script.write("if [ -x '%s' ]; then\n" % self._KVM_NETWORK_SCRIPT)
333 script.write(" # Execute the user-specific vif file\n")
334 script.write(" %s\n" % self._KVM_NETWORK_SCRIPT)
335 script.write("else\n")
336 script.write(" ifconfig $INTERFACE 0.0.0.0 up\n")
337 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
338 script.write(" # Connect the interface to the bridge\n")
339 script.write(" brctl addif $BRIDGE $INTERFACE\n")
340 elif nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED:
342 raise errors.HypervisorError("nic/%d is routed, but has no ip." % seq)
343 script.write(" # Route traffic targeted at the IP to the interface\n")
344 if nic.nicparams[constants.NIC_LINK]:
345 script.write(" while ip rule del dev $INTERFACE; do :; done\n")
346 script.write(" ip rule add dev $INTERFACE table $LINK\n")
347 script.write(" ip route replace $IP table $LINK proto static"
350 script.write(" ip route replace $IP proto static"
352 interface_v4_conf = "/proc/sys/net/ipv4/conf/$INTERFACE"
353 interface_v6_conf = "/proc/sys/net/ipv6/conf/$INTERFACE"
354 script.write(" if [ -d %s ]; then\n" % interface_v4_conf)
355 script.write(" echo 1 > %s/proxy_arp\n" % interface_v4_conf)
356 script.write(" echo 1 > %s/forwarding\n" % interface_v4_conf)
357 script.write(" fi\n")
358 script.write(" if [ -d %s ]; then\n" % interface_v6_conf)
359 script.write(" echo 1 > %s/proxy_ndp\n" % interface_v6_conf)
360 script.write(" echo 1 > %s/forwarding\n" % interface_v6_conf)
361 script.write(" fi\n")
362 script.write("fi\n\n")
363 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
364 # mounted noexec sometimes, so we'll have to find another place.
365 (tmpfd, tmpfile_name) = tempfile.mkstemp()
366 tmpfile = os.fdopen(tmpfd, 'w')
368 tmpfile.write(script.getvalue())
371 os.chmod(tmpfile_name, 0755)
374 def ListInstances(self):
375 """Get the list of running instances.
377 We can do this by listing our live instances directory and
378 checking whether the associated kvm process is still alive.
382 for name in os.listdir(self._PIDS_DIR):
383 if self._InstancePidAlive(name)[2]:
387 def GetInstanceInfo(self, instance_name):
388 """Get instance properties.
390 @type instance_name: string
391 @param instance_name: the instance name
392 @rtype: tuple of strings
393 @return: (name, id, memory, vcpus, stat, times)
396 _, pid, alive = self._InstancePidAlive(instance_name)
400 _, memory, vcpus = self._InstancePidInfo(pid)
404 return (instance_name, pid, memory, vcpus, stat, times)
406 def GetAllInstancesInfo(self):
407 """Get properties of all instances.
409 @return: list of tuples (name, id, memory, vcpus, stat, times)
413 for name in os.listdir(self._PIDS_DIR):
415 info = self.GetInstanceInfo(name)
416 except errors.HypervisorError:
422 def _GenerateKVMRuntime(self, instance, block_devices):
423 """Generate KVM information to start an instance.
426 pidfile = self._InstancePidFile(instance.name)
427 kvm = constants.KVM_PATH
429 # used just by the vnc server, if enabled
430 kvm_cmd.extend(['-name', instance.name])
431 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
432 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
433 kvm_cmd.extend(['-pidfile', pidfile])
434 kvm_cmd.extend(['-daemonize'])
435 if not instance.hvparams[constants.HV_ACPI]:
436 kvm_cmd.extend(['-no-acpi'])
438 hvp = instance.hvparams
439 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
440 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
441 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
443 if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
444 kvm_cmd.extend(["-enable-kvm"])
445 elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
446 kvm_cmd.extend(["-disable-kvm"])
449 kvm_cmd.extend(['-boot', 'n'])
451 disk_type = hvp[constants.HV_DISK_TYPE]
452 if disk_type == constants.HT_DISK_PARAVIRTUAL:
453 if_val = ',if=virtio'
455 if_val = ',if=%s' % disk_type
457 disk_cache = hvp[constants.HV_DISK_CACHE]
458 if disk_cache != constants.HT_CACHE_DEFAULT:
459 cache_val = ",cache=%s" % disk_cache
462 for cfdev, dev_path in block_devices:
463 if cfdev.mode != constants.DISK_RDWR:
464 raise errors.HypervisorError("Instance has read-only disks which"
465 " are not supported by KVM")
466 # TODO: handle FD_LOOP and FD_BLKTAP (?)
468 kvm_cmd.extend(['-boot', 'c'])
469 if disk_type != constants.HT_DISK_IDE:
470 boot_val = ',boot=on'
473 # We only boot from the first disk
478 drive_val = 'file=%s,format=raw%s%s%s' % (dev_path, if_val, boot_val,
480 kvm_cmd.extend(['-drive', drive_val])
482 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
484 options = ',format=raw,media=cdrom'
486 kvm_cmd.extend(['-boot', 'd'])
487 if disk_type != constants.HT_DISK_IDE:
488 options = '%s,boot=on' % options
490 if disk_type == constants.HT_DISK_PARAVIRTUAL:
491 if_val = ',if=virtio'
493 if_val = ',if=%s' % disk_type
494 options = '%s%s' % (options, if_val)
495 drive_val = 'file=%s%s' % (iso_image, options)
496 kvm_cmd.extend(['-drive', drive_val])
498 kernel_path = hvp[constants.HV_KERNEL_PATH]
500 kvm_cmd.extend(['-kernel', kernel_path])
501 initrd_path = hvp[constants.HV_INITRD_PATH]
503 kvm_cmd.extend(['-initrd', initrd_path])
504 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
505 hvp[constants.HV_KERNEL_ARGS]]
506 if hvp[constants.HV_SERIAL_CONSOLE]:
507 root_append.append('console=ttyS0,38400')
508 kvm_cmd.extend(['-append', ' '.join(root_append)])
510 mouse_type = hvp[constants.HV_USB_MOUSE]
511 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
514 kvm_cmd.extend(['-usb'])
515 kvm_cmd.extend(['-usbdevice', mouse_type])
516 elif vnc_bind_address:
517 kvm_cmd.extend(['-usbdevice', constants.HT_MOUSE_TABLET])
520 if utils.IsValidIP(vnc_bind_address):
521 if instance.network_port > constants.VNC_BASE_PORT:
522 display = instance.network_port - constants.VNC_BASE_PORT
523 if vnc_bind_address == '0.0.0.0':
524 vnc_arg = ':%d' % (display)
526 vnc_arg = '%s:%d' % (vnc_bind_address, display)
528 logging.error("Network port is not a valid VNC display (%d < %d)."
529 " Not starting VNC", instance.network_port,
530 constants.VNC_BASE_PORT)
533 # Only allow tls and other option when not binding to a file, for now.
534 # kvm/qemu gets confused otherwise about the filename to use.
536 if hvp[constants.HV_VNC_TLS]:
537 vnc_append = '%s,tls' % vnc_append
538 if hvp[constants.HV_VNC_X509_VERIFY]:
539 vnc_append = '%s,x509verify=%s' % (vnc_append,
540 hvp[constants.HV_VNC_X509])
541 elif hvp[constants.HV_VNC_X509]:
542 vnc_append = '%s,x509=%s' % (vnc_append,
543 hvp[constants.HV_VNC_X509])
544 if hvp[constants.HV_VNC_PASSWORD_FILE]:
545 vnc_append = '%s,password' % vnc_append
547 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
550 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
552 kvm_cmd.extend(['-vnc', vnc_arg])
554 kvm_cmd.extend(['-nographic'])
556 monitor_dev = ("unix:%s,server,nowait" %
557 self._InstanceMonitor(instance.name))
558 kvm_cmd.extend(['-monitor', monitor_dev])
559 if hvp[constants.HV_SERIAL_CONSOLE]:
560 serial_dev = ('unix:%s,server,nowait' %
561 self._InstanceSerial(instance.name))
562 kvm_cmd.extend(['-serial', serial_dev])
564 kvm_cmd.extend(['-serial', 'none'])
566 if hvp[constants.HV_USE_LOCALTIME]:
567 kvm_cmd.extend(['-localtime'])
569 if hvp[constants.HV_KVM_USE_CHROOT]:
570 kvm_cmd.extend(['-chroot', self._InstanceChrootDir(instance.name)])
572 # Save the current instance nics, but defer their expansion as parameters,
573 # as we'll need to generate executable temp files for them.
574 kvm_nics = instance.nics
577 return (kvm_cmd, kvm_nics, hvparams)
579 def _WriteKVMRuntime(self, instance_name, data):
580 """Write an instance's KVM runtime
584 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
586 except EnvironmentError, err:
587 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
589 def _ReadKVMRuntime(self, instance_name):
590 """Read an instance's KVM runtime
594 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
595 except EnvironmentError, err:
596 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
599 def _SaveKVMRuntime(self, instance, kvm_runtime):
600 """Save an instance's KVM runtime
603 kvm_cmd, kvm_nics, hvparams = kvm_runtime
604 serialized_nics = [nic.ToDict() for nic in kvm_nics]
605 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
606 self._WriteKVMRuntime(instance.name, serialized_form)
608 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
609 """Load an instance's KVM runtime
612 if not serialized_runtime:
613 serialized_runtime = self._ReadKVMRuntime(instance.name)
614 loaded_runtime = serializer.Load(serialized_runtime)
615 kvm_cmd, serialized_nics, hvparams = loaded_runtime
616 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
617 return (kvm_cmd, kvm_nics, hvparams)
619 def _RunKVMCmd(self, name, kvm_cmd):
620 """Run the KVM cmd and check for errors
623 @param name: instance name
624 @type kvm_cmd: list of strings
625 @param kvm_cmd: runcmd input for kvm
628 result = utils.RunCmd(kvm_cmd)
630 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
631 (name, result.fail_reason, result.output))
632 if not self._InstancePidAlive(name)[2]:
633 raise errors.HypervisorError("Failed to start instance %s" % name)
635 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
636 """Execute a KVM cmd, after completing it with some last minute data
638 @type incoming: tuple of strings
639 @param incoming: (target_host_ip, port)
642 # Small _ExecuteKVMRuntime hv parameters programming howto:
643 # - conf_hvp contains the parameters as configured on ganeti. they might
644 # have changed since the instance started; only use them if the change
645 # won't affect the inside of the instance (which hasn't been rebooted).
646 # - up_hvp contains the parameters as they were when the instance was
647 # started, plus any new parameter which has been added between ganeti
648 # versions: it is paramount that those default to a value which won't
649 # affect the inside of the instance as well.
650 conf_hvp = instance.hvparams
652 self._CheckDown(name)
656 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
657 up_hvp = objects.FillDict(conf_hvp, up_hvp)
659 # We know it's safe to run as a different user upon migration, so we'll use
660 # the latest conf, from conf_hvp.
661 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
662 if security_model == constants.HT_SM_USER:
663 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
665 # We have reasons to believe changing something like the nic driver/type
666 # upon migration won't exactly fly with the instance kernel, so for nic
667 # related parameters we'll use up_hvp
669 kvm_cmd.extend(["-net", "none"])
672 nic_type = up_hvp[constants.HV_NIC_TYPE]
673 if nic_type == constants.HT_NIC_PARAVIRTUAL:
674 nic_model = "model=virtio"
675 if up_hvp[constants.HV_VHOST_NET]:
676 tap_extra = ",vhost=on"
678 nic_model = "model=%s" % nic_type
680 for nic_seq, nic in enumerate(kvm_nics):
681 nic_val = "nic,vlan=%s,macaddr=%s,%s" % (nic_seq, nic.mac, nic_model)
682 script = self._WriteNetScript(instance, nic_seq, nic)
683 tap_val = "tap,vlan=%s,script=%s%s" % (nic_seq, script, tap_extra)
684 kvm_cmd.extend(["-net", nic_val])
685 kvm_cmd.extend(["-net", tap_val])
686 temp_files.append(script)
689 target, port = incoming
690 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
692 # Changing the vnc password doesn't bother the guest that much. At most it
693 # will surprise people who connect to it. Whether positively or negatively
695 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
699 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
700 except EnvironmentError, err:
701 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
702 % (vnc_pwd_file, err))
704 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
705 utils.EnsureDirs([(self._InstanceChrootDir(name),
706 constants.SECURE_DIR_MODE)])
708 if security_model == constants.HT_SM_POOL:
709 ss = ssconf.SimpleStore()
710 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
711 all_uids = set(uidpool.ExpandUidPool(uid_pool))
712 uid = uidpool.RequestUnusedUid(all_uids)
714 username = pwd.getpwuid(uid.GetUid()).pw_name
715 kvm_cmd.extend(["-runas", username])
716 self._RunKVMCmd(name, kvm_cmd)
718 uidpool.ReleaseUid(uid)
722 utils.WriteFile(self._InstanceUidFile(name), data=str(uid))
724 self._RunKVMCmd(name, kvm_cmd)
727 change_cmd = 'change vnc password %s' % vnc_pwd
728 self._CallMonitorCommand(instance.name, change_cmd)
730 for filename in temp_files:
731 utils.RemoveFile(filename)
733 def StartInstance(self, instance, block_devices):
734 """Start an instance.
737 self._CheckDown(instance.name)
738 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
739 self._SaveKVMRuntime(instance, kvm_runtime)
740 self._ExecuteKVMRuntime(instance, kvm_runtime)
742 def _CallMonitorCommand(self, instance_name, command):
743 """Invoke a command on the instance monitor.
746 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
747 (utils.ShellQuote(command),
748 constants.SOCAT_PATH,
749 utils.ShellQuote(self._InstanceMonitor(instance_name))))
750 result = utils.RunCmd(socat)
752 msg = ("Failed to send command '%s' to instance %s."
753 " output: %s, error: %s, fail_reason: %s" %
754 (command, instance_name,
755 result.stdout, result.stderr, result.fail_reason))
756 raise errors.HypervisorError(msg)
760 def StopInstance(self, instance, force=False, retry=False, name=None):
764 if name is not None and not force:
765 raise errors.HypervisorError("Cannot shutdown cleanly by name only")
768 acpi = instance.hvparams[constants.HV_ACPI]
771 _, pid, alive = self._InstancePidAlive(name)
772 if pid > 0 and alive:
773 if force or not acpi:
774 utils.KillProcess(pid)
776 self._CallMonitorCommand(name, 'system_powerdown')
778 def CleanupInstance(self, instance_name):
779 """Cleanup after a stopped instance
782 pidfile, pid, alive = self._InstancePidAlive(instance_name)
783 if pid > 0 and alive:
784 raise errors.HypervisorError("Cannot cleanup a live instance")
785 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
787 def RebootInstance(self, instance):
788 """Reboot an instance.
791 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
792 # socket the instance will stop, but now power up again. So we'll resort
793 # to shutdown and restart.
794 _, _, alive = self._InstancePidAlive(instance.name)
796 raise errors.HypervisorError("Failed to reboot instance %s:"
797 " not running" % instance.name)
798 # StopInstance will delete the saved KVM runtime so:
799 # ...first load it...
800 kvm_runtime = self._LoadKVMRuntime(instance)
801 # ...now we can safely call StopInstance...
802 if not self.StopInstance(instance):
803 self.StopInstance(instance, force=True)
804 # ...and finally we can save it again, and execute it...
805 self._SaveKVMRuntime(instance, kvm_runtime)
806 self._ExecuteKVMRuntime(instance, kvm_runtime)
808 def MigrationInfo(self, instance):
809 """Get instance information to perform a migration.
811 @type instance: L{objects.Instance}
812 @param instance: instance to be migrated
814 @return: content of the KVM runtime file
817 return self._ReadKVMRuntime(instance.name)
819 def AcceptInstance(self, instance, info, target):
820 """Prepare to accept an instance.
822 @type instance: L{objects.Instance}
823 @param instance: instance to be accepted
825 @param info: content of the KVM runtime file on the source node
827 @param target: target host (usually ip), on this node
830 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
831 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
832 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
834 def FinalizeMigration(self, instance, info, success):
835 """Finalize an instance migration.
837 Stop the incoming mode KVM.
839 @type instance: L{objects.Instance}
840 @param instance: instance whose migration is being finalized
844 self._WriteKVMRuntime(instance.name, info)
846 self.StopInstance(instance, force=True)
848 def MigrateInstance(self, instance, target, live):
849 """Migrate an instance to a target node.
851 The migration will not be attempted if the instance is not
854 @type instance: L{objects.Instance}
855 @param instance: the instance to be migrated
857 @param target: ip address of the target node
859 @param live: perform a live migration
862 instance_name = instance.name
863 port = instance.hvparams[constants.HV_MIGRATION_PORT]
864 pidfile, pid, alive = self._InstancePidAlive(instance_name)
866 raise errors.HypervisorError("Instance not running, cannot migrate")
868 if not utils.TcpPing(target, port, live_port_needed=True):
869 raise errors.HypervisorError("Remote host %s not listening on port"
870 " %s, cannot migrate" % (target, port))
873 self._CallMonitorCommand(instance_name, 'stop')
875 migrate_command = ('migrate_set_speed %dm' %
876 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
877 self._CallMonitorCommand(instance_name, migrate_command)
879 migrate_command = ('migrate_set_downtime %dms' %
880 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
881 self._CallMonitorCommand(instance_name, migrate_command)
883 migrate_command = 'migrate -d tcp:%s:%s' % (target, port)
884 self._CallMonitorCommand(instance_name, migrate_command)
886 info_command = 'info migrate'
890 result = self._CallMonitorCommand(instance_name, info_command)
891 match = self._MIGRATION_STATUS_RE.search(result.stdout)
894 if not result.stdout:
895 logging.info("KVM: empty 'info migrate' result")
897 logging.warning("KVM: unknown 'info migrate' result: %s",
899 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
901 status = match.group(1)
902 if status == 'completed':
904 elif status == 'active':
905 # reset the broken answers count
907 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
908 elif status == 'failed' or status == 'cancelled':
910 self._CallMonitorCommand(instance_name, 'cont')
911 raise errors.HypervisorError("Migration %s at the kvm level" %
914 logging.warning("KVM: unknown migration status '%s'", status)
916 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
917 if broken_answers >= self._MIGRATION_INFO_MAX_BAD_ANSWERS:
918 raise errors.HypervisorError("Too many 'info migrate' broken answers")
920 utils.KillProcess(pid)
921 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
923 def GetNodeInfo(self):
924 """Return information about the node.
926 This is just a wrapper over the base GetLinuxNodeInfo method.
928 @return: a dict with the following keys (values in MiB):
929 - memory_total: the total memory size on the node
930 - memory_free: the available memory on the node for instances
931 - memory_dom0: the memory used by the node itself, if available
934 return self.GetLinuxNodeInfo()
937 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
938 """Return a command for connecting to the console of an instance.
941 if hvparams[constants.HV_SERIAL_CONSOLE]:
942 shell_command = ("%s STDIO,%s UNIX-CONNECT:%s" %
943 (constants.SOCAT_PATH, cls._SocatUnixConsoleParams(),
944 utils.ShellQuote(cls._InstanceSerial(instance.name))))
946 shell_command = "echo 'No serial shell for instance %s'" % instance.name
948 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
950 if instance.network_port > constants.VNC_BASE_PORT:
951 display = instance.network_port - constants.VNC_BASE_PORT
952 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
953 " (display: %d)'" % (vnc_bind_address,
954 instance.network_port,
956 shell_command = "%s; %s" % (vnc_command, shell_command)
961 """Verify the hypervisor.
963 Check that the binary exists.
966 if not os.path.exists(constants.KVM_PATH):
967 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
968 if not os.path.exists(constants.SOCAT_PATH):
969 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
973 def CheckParameterSyntax(cls, hvparams):
974 """Check the given parameters for validity.
977 @param hvparams: dictionary with parameter names/value
978 @raise errors.HypervisorError: when a parameter is not valid
981 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
983 kernel_path = hvparams[constants.HV_KERNEL_PATH]
985 if not hvparams[constants.HV_ROOT_PATH]:
986 raise errors.HypervisorError("Need a root partition for the instance,"
987 " if a kernel is defined")
989 if (hvparams[constants.HV_VNC_X509_VERIFY] and
990 not hvparams[constants.HV_VNC_X509]):
991 raise errors.HypervisorError("%s must be defined, if %s is" %
992 (constants.HV_VNC_X509,
993 constants.HV_VNC_X509_VERIFY))
995 boot_order = hvparams[constants.HV_BOOT_ORDER]
996 if (boot_order == constants.HT_BO_CDROM and
997 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
998 raise errors.HypervisorError("Cannot boot from cdrom without an"
1001 security_model = hvparams[constants.HV_SECURITY_MODEL]
1002 if security_model == constants.HT_SM_USER:
1003 if not hvparams[constants.HV_SECURITY_DOMAIN]:
1004 raise errors.HypervisorError("A security domain (user to run kvm as)"
1005 " must be specified")
1006 elif (security_model == constants.HT_SM_NONE or
1007 security_model == constants.HT_SM_POOL):
1008 if hvparams[constants.HV_SECURITY_DOMAIN]:
1009 raise errors.HypervisorError("Cannot have a security domain when the"
1010 " security model is 'none' or 'pool'")
1013 def ValidateParameters(cls, hvparams):
1014 """Check the given parameters for validity.
1016 @type hvparams: dict
1017 @param hvparams: dictionary with parameter names/value
1018 @raise errors.HypervisorError: when a parameter is not valid
1021 super(KVMHypervisor, cls).ValidateParameters(hvparams)
1023 security_model = hvparams[constants.HV_SECURITY_MODEL]
1024 if security_model == constants.HT_SM_USER:
1025 username = hvparams[constants.HV_SECURITY_DOMAIN]
1027 pwd.getpwnam(username)
1029 raise errors.HypervisorError("Unknown security domain user %s"
1033 def PowercycleNode(cls):
1034 """KVM powercycle, just a wrapper over Linux powercycle.
1037 cls.LinuxPowercycle()