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
32 from cStringIO import StringIO
34 from ganeti import utils
35 from ganeti import constants
36 from ganeti import errors
37 from ganeti import serializer
38 from ganeti import objects
39 from ganeti.hypervisor import hv_base
42 class KVMHypervisor(hv_base.BaseHypervisor):
43 """KVM hypervisor interface"""
45 _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
46 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
47 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
48 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
49 _DIRS = [_ROOT_DIR, _PIDS_DIR, _CTRL_DIR, _CONF_DIR]
52 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
53 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
54 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
55 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
56 constants.HV_ACPI: hv_base.NO_CHECK,
57 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
58 constants.HV_VNC_BIND_ADDRESS:
59 (False, lambda x: (utils.IsValidIP(x) or utils.IsNormAbsPath(x)),
60 "the VNC bind address must be either a valid IP address or an absolute"
61 " pathname", None, None),
62 constants.HV_VNC_TLS: hv_base.NO_CHECK,
63 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
64 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
65 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
66 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
67 constants.HV_BOOT_ORDER:
68 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
69 constants.HV_NIC_TYPE:
70 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
71 constants.HV_DISK_TYPE:
72 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
73 constants.HV_USB_MOUSE:
74 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
75 constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
76 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
77 constants.HV_DISK_CACHE:
78 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
81 _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
84 _KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
91 hv_base.BaseHypervisor.__init__(self)
92 # Let's make sure the directories we need exist, even if the RUN_DIR lives
93 # in a tmpfs filesystem or has been otherwise wiped out.
94 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
95 utils.EnsureDirs(dirs)
97 def _InstancePidAlive(self, instance_name):
98 """Returns the instance pid and pidfile
101 pidfile = "%s/%s" % (self._PIDS_DIR, instance_name)
102 pid = utils.ReadPidFile(pidfile)
103 alive = utils.IsProcessAlive(pid)
105 return (pidfile, pid, alive)
108 def _InstanceMonitor(cls, instance_name):
109 """Returns the instance monitor socket name
112 return '%s/%s.monitor' % (cls._CTRL_DIR, instance_name)
115 def _InstanceSerial(cls, instance_name):
116 """Returns the instance serial socket name
119 return '%s/%s.serial' % (cls._CTRL_DIR, instance_name)
122 def _SocatUnixConsoleParams():
123 """Returns the correct parameters for socat
125 If we have a new-enough socat we can use raw mode with an escape character.
128 if constants.SOCAT_USE_ESCAPE:
129 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
131 return "echo=0,icanon=0"
134 def _InstanceKVMRuntime(cls, instance_name):
135 """Returns the instance KVM runtime filename
138 return '%s/%s.runtime' % (cls._CONF_DIR, instance_name)
141 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
142 """Removes an instance's rutime sockets/files.
145 utils.RemoveFile(pidfile)
146 utils.RemoveFile(cls._InstanceMonitor(instance_name))
147 utils.RemoveFile(cls._InstanceSerial(instance_name))
148 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
150 def _WriteNetScript(self, instance, seq, nic):
151 """Write a script to connect a net interface to the proper bridge.
153 This can be used by any qemu-type hypervisor.
155 @param instance: instance we're acting on
156 @type instance: instance object
157 @param seq: nic sequence number
159 @param nic: nic we're acting on
160 @type nic: nic object
161 @return: netscript file name
166 script.write("#!/bin/sh\n")
167 script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
168 script.write("export INSTANCE=%s\n" % instance.name)
169 script.write("export MAC=%s\n" % nic.mac)
171 script.write("export IP=%s\n" % nic.ip)
172 script.write("export MODE=%s\n" % nic.nicparams[constants.NIC_MODE])
173 if nic.nicparams[constants.NIC_LINK]:
174 script.write("export LINK=%s\n" % nic.nicparams[constants.NIC_LINK])
175 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
176 script.write("export BRIDGE=%s\n" % nic.nicparams[constants.NIC_LINK])
177 script.write("export INTERFACE=$1\n")
178 # TODO: make this configurable at ./configure time
179 script.write("if [ -x '%s' ]; then\n" % self._KVM_NETWORK_SCRIPT)
180 script.write(" # Execute the user-specific vif file\n")
181 script.write(" %s\n" % self._KVM_NETWORK_SCRIPT)
182 script.write("else\n")
183 script.write(" /sbin/ifconfig $INTERFACE 0.0.0.0 up\n")
184 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
185 script.write(" # Connect the interface to the bridge\n")
186 script.write(" /usr/sbin/brctl addif $BRIDGE $INTERFACE\n")
187 elif nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED:
188 script.write(" # Route traffic targeted at the IP to the interface\n")
189 if nic.nicparams[constants.NIC_LINK]:
190 script.write(" while /sbin/ip rule del dev $INTERFACE; do :; done\n")
191 script.write(" /sbin/ip rule add dev $INTERFACE table $LINK\n")
192 script.write(" /sbin/ip route replace $IP table $LINK proto static"
195 script.write(" /sbin/ip route replace $IP proto static"
197 interface_v4_conf = "/proc/sys/net/ipv4/conf/$INTERFACE"
198 interface_v6_conf = "/proc/sys/net/ipv6/conf/$INTERFACE"
199 script.write(" if [ -d %s ]; then\n" % interface_v4_conf)
200 script.write(" echo 1 > %s/proxy_arp\n" % interface_v4_conf)
201 script.write(" echo 1 > %s/forwarding\n" % interface_v4_conf)
202 script.write(" fi\n")
203 script.write(" if [ -d %s ]; then\n" % interface_v6_conf)
204 script.write(" echo 1 > %s/proxy_ndp\n" % interface_v6_conf)
205 script.write(" echo 1 > %s/forwarding\n" % interface_v6_conf)
206 script.write(" fi\n")
207 script.write("fi\n\n")
208 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
209 # mounted noexec sometimes, so we'll have to find another place.
210 (tmpfd, tmpfile_name) = tempfile.mkstemp()
211 tmpfile = os.fdopen(tmpfd, 'w')
213 tmpfile.write(script.getvalue())
216 os.chmod(tmpfile_name, 0755)
219 def ListInstances(self):
220 """Get the list of running instances.
222 We can do this by listing our live instances directory and
223 checking whether the associated kvm process is still alive.
227 for name in os.listdir(self._PIDS_DIR):
228 filename = "%s/%s" % (self._PIDS_DIR, name)
229 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
233 def GetInstanceInfo(self, instance_name):
234 """Get instance properties.
236 @param instance_name: the instance name
238 @return: tuple (name, id, memory, vcpus, stat, times)
241 pidfile, pid, alive = self._InstancePidAlive(instance_name)
245 cmdline_file = "/proc/%s/cmdline" % pid
247 cmdline = utils.ReadFile(cmdline_file)
248 except EnvironmentError, err:
249 raise errors.HypervisorError("Failed to list instance %s: %s" %
250 (instance_name, err))
257 arg_list = cmdline.split('\x00')
259 arg = arg_list.pop(0)
261 memory = int(arg_list.pop(0))
263 vcpus = int(arg_list.pop(0))
265 return (instance_name, pid, memory, vcpus, stat, times)
267 def GetAllInstancesInfo(self):
268 """Get properties of all instances.
270 @return: list of tuples (name, id, memory, vcpus, stat, times)
274 for name in os.listdir(self._PIDS_DIR):
275 filename = "%s/%s" % (self._PIDS_DIR, name)
276 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
278 info = self.GetInstanceInfo(name)
279 except errors.HypervisorError, err:
286 def _GenerateKVMRuntime(self, instance, block_devices):
287 """Generate KVM information to start an instance.
290 pidfile, pid, alive = self._InstancePidAlive(instance.name)
291 kvm = constants.KVM_PATH
293 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
294 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
295 kvm_cmd.extend(['-pidfile', pidfile])
296 # used just by the vnc server, if enabled
297 kvm_cmd.extend(['-name', instance.name])
298 kvm_cmd.extend(['-daemonize'])
299 if not instance.hvparams[constants.HV_ACPI]:
300 kvm_cmd.extend(['-no-acpi'])
302 hvp = instance.hvparams
303 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
304 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
305 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
308 kvm_cmd.extend(['-boot', 'n'])
310 disk_type = hvp[constants.HV_DISK_TYPE]
311 if disk_type == constants.HT_DISK_PARAVIRTUAL:
312 if_val = ',if=virtio'
314 if_val = ',if=%s' % disk_type
316 disk_cache = hvp[constants.HV_DISK_CACHE]
317 if disk_cache != constants.HT_CACHE_DEFAULT:
318 cache_val = ",cache=%s" % disk_cache
321 for cfdev, dev_path in block_devices:
322 if cfdev.mode != constants.DISK_RDWR:
323 raise errors.HypervisorError("Instance has read-only disks which"
324 " are not supported by KVM")
325 # TODO: handle FD_LOOP and FD_BLKTAP (?)
327 kvm_cmd.extend(['-boot', 'c'])
328 boot_val = ',boot=on'
329 # We only boot from the first disk
334 drive_val = 'file=%s,format=raw%s%s%s' % (dev_path, if_val, boot_val,
336 kvm_cmd.extend(['-drive', drive_val])
338 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
340 options = ',format=raw,media=cdrom'
342 kvm_cmd.extend(['-boot', 'd'])
343 options = '%s,boot=on' % options
345 options = '%s,if=virtio' % options
346 drive_val = 'file=%s%s' % (iso_image, options)
347 kvm_cmd.extend(['-drive', drive_val])
349 kernel_path = hvp[constants.HV_KERNEL_PATH]
351 kvm_cmd.extend(['-kernel', kernel_path])
352 initrd_path = hvp[constants.HV_INITRD_PATH]
354 kvm_cmd.extend(['-initrd', initrd_path])
355 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
356 hvp[constants.HV_KERNEL_ARGS]]
357 if hvp[constants.HV_SERIAL_CONSOLE]:
358 root_append.append('console=ttyS0,38400')
359 kvm_cmd.extend(['-append', ' '.join(root_append)])
361 mouse_type = hvp[constants.HV_USB_MOUSE]
363 kvm_cmd.extend(['-usb'])
364 kvm_cmd.extend(['-usbdevice', mouse_type])
366 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
368 if utils.IsValidIP(vnc_bind_address):
369 if instance.network_port > constants.VNC_BASE_PORT:
370 display = instance.network_port - constants.VNC_BASE_PORT
371 if vnc_bind_address == '0.0.0.0':
372 vnc_arg = ':%d' % (display)
374 vnc_arg = '%s:%d' % (vnc_bind_address, display)
376 logging.error("Network port is not a valid VNC display (%d < %d)."
377 " Not starting VNC" %
378 (instance.network_port,
379 constants.VNC_BASE_PORT))
382 # Only allow tls and other option when not binding to a file, for now.
383 # kvm/qemu gets confused otherwise about the filename to use.
385 if hvp[constants.HV_VNC_TLS]:
386 vnc_append = '%s,tls' % vnc_append
387 if hvp[constants.HV_VNC_X509_VERIFY]:
388 vnc_append = '%s,x509verify=%s' % (vnc_append,
389 hvp[constants.HV_VNC_X509])
390 elif hvp[constants.HV_VNC_X509]:
391 vnc_append = '%s,x509=%s' % (vnc_append,
392 hvp[constants.HV_VNC_X509])
393 if hvp[constants.HV_VNC_PASSWORD_FILE]:
394 vnc_append = '%s,password' % vnc_append
396 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
399 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
401 kvm_cmd.extend(['-vnc', vnc_arg])
403 kvm_cmd.extend(['-nographic'])
405 monitor_dev = ("unix:%s,server,nowait" %
406 self._InstanceMonitor(instance.name))
407 kvm_cmd.extend(['-monitor', monitor_dev])
408 if hvp[constants.HV_SERIAL_CONSOLE]:
409 serial_dev = ('unix:%s,server,nowait' %
410 self._InstanceSerial(instance.name))
411 kvm_cmd.extend(['-serial', serial_dev])
413 kvm_cmd.extend(['-serial', 'none'])
415 if hvp[constants.HV_USE_LOCALTIME]:
416 kvm_cmd.extend(['-localtime'])
418 # Save the current instance nics, but defer their expansion as parameters,
419 # as we'll need to generate executable temp files for them.
420 kvm_nics = instance.nics
423 return (kvm_cmd, kvm_nics, hvparams)
425 def _WriteKVMRuntime(self, instance_name, data):
426 """Write an instance's KVM runtime
430 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
432 except EnvironmentError, err:
433 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
435 def _ReadKVMRuntime(self, instance_name):
436 """Read an instance's KVM runtime
440 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
441 except EnvironmentError, err:
442 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
445 def _SaveKVMRuntime(self, instance, kvm_runtime):
446 """Save an instance's KVM runtime
449 kvm_cmd, kvm_nics, hvparams = kvm_runtime
450 serialized_nics = [nic.ToDict() for nic in kvm_nics]
451 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
452 self._WriteKVMRuntime(instance.name, serialized_form)
454 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
455 """Load an instance's KVM runtime
458 if not serialized_runtime:
459 serialized_runtime = self._ReadKVMRuntime(instance.name)
460 loaded_runtime = serializer.Load(serialized_runtime)
461 kvm_cmd, serialized_nics, hvparams = loaded_runtime
462 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
463 return (kvm_cmd, kvm_nics, hvparams)
465 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
466 """Execute a KVM cmd, after completing it with some last minute data
468 @type incoming: tuple of strings
469 @param incoming: (target_host_ip, port)
472 pidfile, pid, alive = self._InstancePidAlive(instance.name)
473 hvp = instance.hvparams
475 raise errors.HypervisorError("Failed to start instance %s: %s" %
476 (instance.name, "already running"))
480 kvm_cmd, kvm_nics, hvparams = kvm_runtime
483 kvm_cmd.extend(['-net', 'none'])
485 nic_type = hvparams[constants.HV_NIC_TYPE]
486 if nic_type == constants.HT_NIC_PARAVIRTUAL:
487 nic_model = "model=virtio"
489 nic_model = "model=%s" % nic_type
491 for nic_seq, nic in enumerate(kvm_nics):
492 nic_val = "nic,macaddr=%s,%s" % (nic.mac, nic_model)
493 script = self._WriteNetScript(instance, nic_seq, nic)
494 kvm_cmd.extend(['-net', nic_val])
495 kvm_cmd.extend(['-net', 'tap,script=%s' % script])
496 temp_files.append(script)
499 target, port = incoming
500 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
502 vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
506 vnc_pwd = utils.ReadFile(vnc_pwd_file)
507 except EnvironmentError, err:
508 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
509 % (vnc_pwd_file, err))
511 result = utils.RunCmd(kvm_cmd)
513 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
514 (instance.name, result.fail_reason,
517 if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
518 raise errors.HypervisorError("Failed to start instance %s" %
522 change_cmd = 'change vnc password %s' % vnc_pwd
523 self._CallMonitorCommand(instance.name, change_cmd)
525 for filename in temp_files:
526 utils.RemoveFile(filename)
528 def StartInstance(self, instance, block_devices):
529 """Start an instance.
532 pidfile, pid, alive = self._InstancePidAlive(instance.name)
534 raise errors.HypervisorError("Failed to start instance %s: %s" %
535 (instance.name, "already running"))
537 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
538 self._SaveKVMRuntime(instance, kvm_runtime)
539 self._ExecuteKVMRuntime(instance, kvm_runtime)
541 def _CallMonitorCommand(self, instance_name, command):
542 """Invoke a command on the instance monitor.
545 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
546 (utils.ShellQuote(command),
547 constants.SOCAT_PATH,
548 utils.ShellQuote(self._InstanceMonitor(instance_name))))
549 result = utils.RunCmd(socat)
551 msg = ("Failed to send command '%s' to instance %s."
552 " output: %s, error: %s, fail_reason: %s" %
553 (command, instance_name,
554 result.stdout, result.stderr, result.fail_reason))
555 raise errors.HypervisorError(msg)
559 def StopInstance(self, instance, force=False, retry=False):
563 pidfile, pid, alive = self._InstancePidAlive(instance.name)
564 if pid > 0 and alive:
565 if force or not instance.hvparams[constants.HV_ACPI]:
566 utils.KillProcess(pid)
568 self._CallMonitorCommand(instance.name, 'system_powerdown')
570 if not utils.IsProcessAlive(pid):
571 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
576 def RebootInstance(self, instance):
577 """Reboot an instance.
580 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
581 # socket the instance will stop, but now power up again. So we'll resort
582 # to shutdown and restart.
583 pidfile, pid, alive = self._InstancePidAlive(instance.name)
585 raise errors.HypervisorError("Failed to reboot instance %s:"
586 " not running" % instance.name)
587 # StopInstance will delete the saved KVM runtime so:
588 # ...first load it...
589 kvm_runtime = self._LoadKVMRuntime(instance)
590 # ...now we can safely call StopInstance...
591 if not self.StopInstance(instance):
592 self.StopInstance(instance, force=True)
593 # ...and finally we can save it again, and execute it...
594 self._SaveKVMRuntime(instance, kvm_runtime)
595 self._ExecuteKVMRuntime(instance, kvm_runtime)
597 def MigrationInfo(self, instance):
598 """Get instance information to perform a migration.
600 @type instance: L{objects.Instance}
601 @param instance: instance to be migrated
603 @return: content of the KVM runtime file
606 return self._ReadKVMRuntime(instance.name)
608 def AcceptInstance(self, instance, info, target):
609 """Prepare to accept an instance.
611 @type instance: L{objects.Instance}
612 @param instance: instance to be accepted
614 @param info: content of the KVM runtime file on the source node
616 @param target: target host (usually ip), on this node
619 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
620 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
621 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
623 def FinalizeMigration(self, instance, info, success):
624 """Finalize an instance migration.
626 Stop the incoming mode KVM.
628 @type instance: L{objects.Instance}
629 @param instance: instance whose migration is being aborted
633 self._WriteKVMRuntime(instance.name, info)
635 self.StopInstance(instance, force=True)
637 def MigrateInstance(self, instance, target, live):
638 """Migrate an instance to a target node.
640 The migration will not be attempted if the instance is not
643 @type instance: L{objects.Instance}
644 @param instance: the instance to be migrated
646 @param target: ip address of the target node
648 @param live: perform a live migration
651 instance_name = instance.name
652 port = instance.hvparams[constants.HV_MIGRATION_PORT]
653 pidfile, pid, alive = self._InstancePidAlive(instance_name)
655 raise errors.HypervisorError("Instance not running, cannot migrate")
657 if not utils.TcpPing(target, port, live_port_needed=True):
658 raise errors.HypervisorError("Remote host %s not listening on port"
659 " %s, cannot migrate" % (target, port))
662 self._CallMonitorCommand(instance_name, 'stop')
664 migrate_command = 'migrate -d tcp:%s:%s' % (target, port)
665 self._CallMonitorCommand(instance_name, migrate_command)
667 info_command = 'info migrate'
670 result = self._CallMonitorCommand(instance_name, info_command)
671 match = self._MIGRATION_STATUS_RE.search(result.stdout)
673 raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
676 status = match.group(1)
677 if status == 'completed':
679 elif status == 'active':
681 elif status == 'failed' or status == 'cancelled':
683 self._CallMonitorCommand(instance_name, 'cont')
684 raise errors.HypervisorError("Migration %s at the kvm level" %
687 logging.info("KVM: unknown migration status '%s'" % status)
690 utils.KillProcess(pid)
691 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
693 def GetNodeInfo(self):
694 """Return information about the node.
696 This is just a wrapper over the base GetLinuxNodeInfo method.
698 @return: a dict with the following keys (values in MiB):
699 - memory_total: the total memory size on the node
700 - memory_free: the available memory on the node for instances
701 - memory_dom0: the memory used by the node itself, if available
704 return self.GetLinuxNodeInfo()
707 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
708 """Return a command for connecting to the console of an instance.
711 if hvparams[constants.HV_SERIAL_CONSOLE]:
712 shell_command = ("%s STDIO,%s UNIX-CONNECT:%s" %
713 (constants.SOCAT_PATH, cls._SocatUnixConsoleParams(),
714 utils.ShellQuote(cls._InstanceSerial(instance.name))))
716 shell_command = "echo 'No serial shell for instance %s'" % instance.name
718 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
720 if instance.network_port > constants.VNC_BASE_PORT:
721 display = instance.network_port - constants.VNC_BASE_PORT
722 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
723 " (display: %d)'" % (vnc_bind_address,
724 instance.network_port,
726 shell_command = "%s; %s" % (vnc_command, shell_command)
731 """Verify the hypervisor.
733 Check that the binary exists.
736 if not os.path.exists(constants.KVM_PATH):
737 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
738 if not os.path.exists(constants.SOCAT_PATH):
739 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
743 def CheckParameterSyntax(cls, hvparams):
744 """Check the given parameters for validity.
747 @param hvparams: dictionary with parameter names/value
748 @raise errors.HypervisorError: when a parameter is not valid
751 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
753 kernel_path = hvparams[constants.HV_KERNEL_PATH]
755 if not hvparams[constants.HV_ROOT_PATH]:
756 raise errors.HypervisorError("Need a root partition for the instance,"
757 " if a kernel is defined")
759 if (hvparams[constants.HV_VNC_X509_VERIFY] and
760 not hvparams[constants.HV_VNC_X509]):
761 raise errors.HypervisorError("%s must be defined, if %s is" %
762 (constants.HV_VNC_X509,
763 constants.HV_VNC_X509_VERIFY))
765 boot_order = hvparams[constants.HV_BOOT_ORDER]
767 if (boot_order == constants.HT_BO_CDROM and
768 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
769 raise errors.HypervisorError("Cannot boot from cdrom without an"
771 if (boot_order == constants.HT_BO_NETWORK and
772 hvparams[constants.HV_NIC_TYPE] == constants.HT_NIC_PARAVIRTUAL):
773 raise errors.HypervisorError("Cannot boot from a paravirtual NIC. Please"
774 " change the NIC type.")
777 def PowercycleNode(cls):
778 """KVM powercycle, just a wrapper over Linux powercycle.
781 cls.LinuxPowercycle()