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:
189 raise errors.HypervisorError("nic/%d is routed, but has no ip." % seq)
190 script.write(" # Route traffic targeted at the IP to the interface\n")
191 if nic.nicparams[constants.NIC_LINK]:
192 script.write(" while /sbin/ip rule del dev $INTERFACE; do :; done\n")
193 script.write(" /sbin/ip rule add dev $INTERFACE table $LINK\n")
194 script.write(" /sbin/ip route replace $IP table $LINK proto static"
197 script.write(" /sbin/ip route replace $IP proto static"
199 interface_v4_conf = "/proc/sys/net/ipv4/conf/$INTERFACE"
200 interface_v6_conf = "/proc/sys/net/ipv6/conf/$INTERFACE"
201 script.write(" if [ -d %s ]; then\n" % interface_v4_conf)
202 script.write(" echo 1 > %s/proxy_arp\n" % interface_v4_conf)
203 script.write(" echo 1 > %s/forwarding\n" % interface_v4_conf)
204 script.write(" fi\n")
205 script.write(" if [ -d %s ]; then\n" % interface_v6_conf)
206 script.write(" echo 1 > %s/proxy_ndp\n" % interface_v6_conf)
207 script.write(" echo 1 > %s/forwarding\n" % interface_v6_conf)
208 script.write(" fi\n")
209 script.write("fi\n\n")
210 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
211 # mounted noexec sometimes, so we'll have to find another place.
212 (tmpfd, tmpfile_name) = tempfile.mkstemp()
213 tmpfile = os.fdopen(tmpfd, 'w')
215 tmpfile.write(script.getvalue())
218 os.chmod(tmpfile_name, 0755)
221 def ListInstances(self):
222 """Get the list of running instances.
224 We can do this by listing our live instances directory and
225 checking whether the associated kvm process is still alive.
229 for name in os.listdir(self._PIDS_DIR):
230 filename = "%s/%s" % (self._PIDS_DIR, name)
231 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
235 def GetInstanceInfo(self, instance_name):
236 """Get instance properties.
238 @param instance_name: the instance name
240 @return: tuple (name, id, memory, vcpus, stat, times)
243 pidfile, pid, alive = self._InstancePidAlive(instance_name)
247 cmdline_file = "/proc/%s/cmdline" % pid
249 cmdline = utils.ReadFile(cmdline_file)
250 except EnvironmentError, err:
251 raise errors.HypervisorError("Failed to list instance %s: %s" %
252 (instance_name, err))
259 arg_list = cmdline.split('\x00')
261 arg = arg_list.pop(0)
263 memory = int(arg_list.pop(0))
265 vcpus = int(arg_list.pop(0))
267 return (instance_name, pid, memory, vcpus, stat, times)
269 def GetAllInstancesInfo(self):
270 """Get properties of all instances.
272 @return: list of tuples (name, id, memory, vcpus, stat, times)
276 for name in os.listdir(self._PIDS_DIR):
277 filename = "%s/%s" % (self._PIDS_DIR, name)
278 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
280 info = self.GetInstanceInfo(name)
281 except errors.HypervisorError, err:
288 def _GenerateKVMRuntime(self, instance, block_devices):
289 """Generate KVM information to start an instance.
292 pidfile, pid, alive = self._InstancePidAlive(instance.name)
293 kvm = constants.KVM_PATH
295 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
296 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
297 kvm_cmd.extend(['-pidfile', pidfile])
298 # used just by the vnc server, if enabled
299 kvm_cmd.extend(['-name', instance.name])
300 kvm_cmd.extend(['-daemonize'])
301 if not instance.hvparams[constants.HV_ACPI]:
302 kvm_cmd.extend(['-no-acpi'])
304 hvp = instance.hvparams
305 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
306 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
307 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
310 kvm_cmd.extend(['-boot', 'n'])
312 disk_type = hvp[constants.HV_DISK_TYPE]
313 if disk_type == constants.HT_DISK_PARAVIRTUAL:
314 if_val = ',if=virtio'
316 if_val = ',if=%s' % disk_type
318 disk_cache = hvp[constants.HV_DISK_CACHE]
319 if disk_cache != constants.HT_CACHE_DEFAULT:
320 cache_val = ",cache=%s" % disk_cache
323 for cfdev, dev_path in block_devices:
324 if cfdev.mode != constants.DISK_RDWR:
325 raise errors.HypervisorError("Instance has read-only disks which"
326 " are not supported by KVM")
327 # TODO: handle FD_LOOP and FD_BLKTAP (?)
329 kvm_cmd.extend(['-boot', 'c'])
330 boot_val = ',boot=on'
331 # We only boot from the first disk
336 drive_val = 'file=%s,format=raw%s%s%s' % (dev_path, if_val, boot_val,
338 kvm_cmd.extend(['-drive', drive_val])
340 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
342 options = ',format=raw,media=cdrom'
344 kvm_cmd.extend(['-boot', 'd'])
345 options = '%s,boot=on' % options
347 options = '%s,if=virtio' % options
348 drive_val = 'file=%s%s' % (iso_image, options)
349 kvm_cmd.extend(['-drive', drive_val])
351 kernel_path = hvp[constants.HV_KERNEL_PATH]
353 kvm_cmd.extend(['-kernel', kernel_path])
354 initrd_path = hvp[constants.HV_INITRD_PATH]
356 kvm_cmd.extend(['-initrd', initrd_path])
357 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
358 hvp[constants.HV_KERNEL_ARGS]]
359 if hvp[constants.HV_SERIAL_CONSOLE]:
360 root_append.append('console=ttyS0,38400')
361 kvm_cmd.extend(['-append', ' '.join(root_append)])
363 mouse_type = hvp[constants.HV_USB_MOUSE]
365 kvm_cmd.extend(['-usb'])
366 kvm_cmd.extend(['-usbdevice', mouse_type])
368 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
370 if utils.IsValidIP(vnc_bind_address):
371 if instance.network_port > constants.VNC_BASE_PORT:
372 display = instance.network_port - constants.VNC_BASE_PORT
373 if vnc_bind_address == '0.0.0.0':
374 vnc_arg = ':%d' % (display)
376 vnc_arg = '%s:%d' % (vnc_bind_address, display)
378 logging.error("Network port is not a valid VNC display (%d < %d)."
379 " Not starting VNC" %
380 (instance.network_port,
381 constants.VNC_BASE_PORT))
384 # Only allow tls and other option when not binding to a file, for now.
385 # kvm/qemu gets confused otherwise about the filename to use.
387 if hvp[constants.HV_VNC_TLS]:
388 vnc_append = '%s,tls' % vnc_append
389 if hvp[constants.HV_VNC_X509_VERIFY]:
390 vnc_append = '%s,x509verify=%s' % (vnc_append,
391 hvp[constants.HV_VNC_X509])
392 elif hvp[constants.HV_VNC_X509]:
393 vnc_append = '%s,x509=%s' % (vnc_append,
394 hvp[constants.HV_VNC_X509])
395 if hvp[constants.HV_VNC_PASSWORD_FILE]:
396 vnc_append = '%s,password' % vnc_append
398 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
401 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
403 kvm_cmd.extend(['-vnc', vnc_arg])
405 kvm_cmd.extend(['-nographic'])
407 monitor_dev = ("unix:%s,server,nowait" %
408 self._InstanceMonitor(instance.name))
409 kvm_cmd.extend(['-monitor', monitor_dev])
410 if hvp[constants.HV_SERIAL_CONSOLE]:
411 serial_dev = ('unix:%s,server,nowait' %
412 self._InstanceSerial(instance.name))
413 kvm_cmd.extend(['-serial', serial_dev])
415 kvm_cmd.extend(['-serial', 'none'])
417 if hvp[constants.HV_USE_LOCALTIME]:
418 kvm_cmd.extend(['-localtime'])
420 # Save the current instance nics, but defer their expansion as parameters,
421 # as we'll need to generate executable temp files for them.
422 kvm_nics = instance.nics
425 return (kvm_cmd, kvm_nics, hvparams)
427 def _WriteKVMRuntime(self, instance_name, data):
428 """Write an instance's KVM runtime
432 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
434 except EnvironmentError, err:
435 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
437 def _ReadKVMRuntime(self, instance_name):
438 """Read an instance's KVM runtime
442 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
443 except EnvironmentError, err:
444 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
447 def _SaveKVMRuntime(self, instance, kvm_runtime):
448 """Save an instance's KVM runtime
451 kvm_cmd, kvm_nics, hvparams = kvm_runtime
452 serialized_nics = [nic.ToDict() for nic in kvm_nics]
453 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
454 self._WriteKVMRuntime(instance.name, serialized_form)
456 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
457 """Load an instance's KVM runtime
460 if not serialized_runtime:
461 serialized_runtime = self._ReadKVMRuntime(instance.name)
462 loaded_runtime = serializer.Load(serialized_runtime)
463 kvm_cmd, serialized_nics, hvparams = loaded_runtime
464 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
465 return (kvm_cmd, kvm_nics, hvparams)
467 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
468 """Execute a KVM cmd, after completing it with some last minute data
470 @type incoming: tuple of strings
471 @param incoming: (target_host_ip, port)
474 pidfile, pid, alive = self._InstancePidAlive(instance.name)
475 hvp = instance.hvparams
477 raise errors.HypervisorError("Failed to start instance %s: %s" %
478 (instance.name, "already running"))
482 kvm_cmd, kvm_nics, hvparams = kvm_runtime
485 kvm_cmd.extend(['-net', 'none'])
487 nic_type = hvparams[constants.HV_NIC_TYPE]
488 if nic_type == constants.HT_NIC_PARAVIRTUAL:
489 nic_model = "model=virtio"
491 nic_model = "model=%s" % nic_type
493 for nic_seq, nic in enumerate(kvm_nics):
494 nic_val = "nic,macaddr=%s,%s" % (nic.mac, nic_model)
495 script = self._WriteNetScript(instance, nic_seq, nic)
496 kvm_cmd.extend(['-net', nic_val])
497 kvm_cmd.extend(['-net', 'tap,script=%s' % script])
498 temp_files.append(script)
501 target, port = incoming
502 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
504 vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
508 vnc_pwd = utils.ReadFile(vnc_pwd_file)
509 except EnvironmentError, err:
510 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
511 % (vnc_pwd_file, err))
513 result = utils.RunCmd(kvm_cmd)
515 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
516 (instance.name, result.fail_reason,
519 if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
520 raise errors.HypervisorError("Failed to start instance %s" %
524 change_cmd = 'change vnc password %s' % vnc_pwd
525 self._CallMonitorCommand(instance.name, change_cmd)
527 for filename in temp_files:
528 utils.RemoveFile(filename)
530 def StartInstance(self, instance, block_devices):
531 """Start an instance.
534 pidfile, pid, alive = self._InstancePidAlive(instance.name)
536 raise errors.HypervisorError("Failed to start instance %s: %s" %
537 (instance.name, "already running"))
539 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
540 self._SaveKVMRuntime(instance, kvm_runtime)
541 self._ExecuteKVMRuntime(instance, kvm_runtime)
543 def _CallMonitorCommand(self, instance_name, command):
544 """Invoke a command on the instance monitor.
547 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
548 (utils.ShellQuote(command),
549 constants.SOCAT_PATH,
550 utils.ShellQuote(self._InstanceMonitor(instance_name))))
551 result = utils.RunCmd(socat)
553 msg = ("Failed to send command '%s' to instance %s."
554 " output: %s, error: %s, fail_reason: %s" %
555 (command, instance_name,
556 result.stdout, result.stderr, result.fail_reason))
557 raise errors.HypervisorError(msg)
561 def StopInstance(self, instance, force=False, retry=False):
565 pidfile, pid, alive = self._InstancePidAlive(instance.name)
566 if pid > 0 and alive:
567 if force or not instance.hvparams[constants.HV_ACPI]:
568 utils.KillProcess(pid)
570 self._CallMonitorCommand(instance.name, 'system_powerdown')
572 if not utils.IsProcessAlive(pid):
573 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
578 def RebootInstance(self, instance):
579 """Reboot an instance.
582 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
583 # socket the instance will stop, but now power up again. So we'll resort
584 # to shutdown and restart.
585 pidfile, pid, alive = self._InstancePidAlive(instance.name)
587 raise errors.HypervisorError("Failed to reboot instance %s:"
588 " not running" % instance.name)
589 # StopInstance will delete the saved KVM runtime so:
590 # ...first load it...
591 kvm_runtime = self._LoadKVMRuntime(instance)
592 # ...now we can safely call StopInstance...
593 if not self.StopInstance(instance):
594 self.StopInstance(instance, force=True)
595 # ...and finally we can save it again, and execute it...
596 self._SaveKVMRuntime(instance, kvm_runtime)
597 self._ExecuteKVMRuntime(instance, kvm_runtime)
599 def MigrationInfo(self, instance):
600 """Get instance information to perform a migration.
602 @type instance: L{objects.Instance}
603 @param instance: instance to be migrated
605 @return: content of the KVM runtime file
608 return self._ReadKVMRuntime(instance.name)
610 def AcceptInstance(self, instance, info, target):
611 """Prepare to accept an instance.
613 @type instance: L{objects.Instance}
614 @param instance: instance to be accepted
616 @param info: content of the KVM runtime file on the source node
618 @param target: target host (usually ip), on this node
621 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
622 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
623 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
625 def FinalizeMigration(self, instance, info, success):
626 """Finalize an instance migration.
628 Stop the incoming mode KVM.
630 @type instance: L{objects.Instance}
631 @param instance: instance whose migration is being aborted
635 self._WriteKVMRuntime(instance.name, info)
637 self.StopInstance(instance, force=True)
639 def MigrateInstance(self, instance, target, live):
640 """Migrate an instance to a target node.
642 The migration will not be attempted if the instance is not
645 @type instance: L{objects.Instance}
646 @param instance: the instance to be migrated
648 @param target: ip address of the target node
650 @param live: perform a live migration
653 instance_name = instance.name
654 port = instance.hvparams[constants.HV_MIGRATION_PORT]
655 pidfile, pid, alive = self._InstancePidAlive(instance_name)
657 raise errors.HypervisorError("Instance not running, cannot migrate")
659 if not utils.TcpPing(target, port, live_port_needed=True):
660 raise errors.HypervisorError("Remote host %s not listening on port"
661 " %s, cannot migrate" % (target, port))
664 self._CallMonitorCommand(instance_name, 'stop')
666 migrate_command = 'migrate -d tcp:%s:%s' % (target, port)
667 self._CallMonitorCommand(instance_name, migrate_command)
669 info_command = 'info migrate'
672 result = self._CallMonitorCommand(instance_name, info_command)
673 match = self._MIGRATION_STATUS_RE.search(result.stdout)
675 raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
678 status = match.group(1)
679 if status == 'completed':
681 elif status == 'active':
683 elif status == 'failed' or status == 'cancelled':
685 self._CallMonitorCommand(instance_name, 'cont')
686 raise errors.HypervisorError("Migration %s at the kvm level" %
689 logging.info("KVM: unknown migration status '%s'" % status)
692 utils.KillProcess(pid)
693 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
695 def GetNodeInfo(self):
696 """Return information about the node.
698 This is just a wrapper over the base GetLinuxNodeInfo method.
700 @return: a dict with the following keys (values in MiB):
701 - memory_total: the total memory size on the node
702 - memory_free: the available memory on the node for instances
703 - memory_dom0: the memory used by the node itself, if available
706 return self.GetLinuxNodeInfo()
709 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
710 """Return a command for connecting to the console of an instance.
713 if hvparams[constants.HV_SERIAL_CONSOLE]:
714 shell_command = ("%s STDIO,%s UNIX-CONNECT:%s" %
715 (constants.SOCAT_PATH, cls._SocatUnixConsoleParams(),
716 utils.ShellQuote(cls._InstanceSerial(instance.name))))
718 shell_command = "echo 'No serial shell for instance %s'" % instance.name
720 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
722 if instance.network_port > constants.VNC_BASE_PORT:
723 display = instance.network_port - constants.VNC_BASE_PORT
724 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
725 " (display: %d)'" % (vnc_bind_address,
726 instance.network_port,
728 shell_command = "%s; %s" % (vnc_command, shell_command)
733 """Verify the hypervisor.
735 Check that the binary exists.
738 if not os.path.exists(constants.KVM_PATH):
739 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
740 if not os.path.exists(constants.SOCAT_PATH):
741 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
745 def CheckParameterSyntax(cls, hvparams):
746 """Check the given parameters for validity.
749 @param hvparams: dictionary with parameter names/value
750 @raise errors.HypervisorError: when a parameter is not valid
753 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
755 kernel_path = hvparams[constants.HV_KERNEL_PATH]
757 if not hvparams[constants.HV_ROOT_PATH]:
758 raise errors.HypervisorError("Need a root partition for the instance,"
759 " if a kernel is defined")
761 if (hvparams[constants.HV_VNC_X509_VERIFY] and
762 not hvparams[constants.HV_VNC_X509]):
763 raise errors.HypervisorError("%s must be defined, if %s is" %
764 (constants.HV_VNC_X509,
765 constants.HV_VNC_X509_VERIFY))
767 boot_order = hvparams[constants.HV_BOOT_ORDER]
769 if (boot_order == constants.HT_BO_CDROM and
770 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
771 raise errors.HypervisorError("Cannot boot from cdrom without an"
773 if (boot_order == constants.HT_BO_NETWORK and
774 hvparams[constants.HV_NIC_TYPE] == constants.HT_NIC_PARAVIRTUAL):
775 raise errors.HypervisorError("Cannot boot from a paravirtual NIC. Please"
776 " change the NIC type.")
779 def PowercycleNode(cls):
780 """KVM powercycle, just a wrapper over Linux powercycle.
783 cls.LinuxPowercycle()