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_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
66 constants.HV_BOOT_ORDER:
67 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
68 constants.HV_NIC_TYPE:
69 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
70 constants.HV_DISK_TYPE:
71 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
72 constants.HV_USB_MOUSE:
73 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
76 _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
79 _KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
86 hv_base.BaseHypervisor.__init__(self)
87 # Let's make sure the directories we need exist, even if the RUN_DIR lives
88 # in a tmpfs filesystem or has been otherwise wiped out.
89 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS]
90 utils.EnsureDirs(dirs)
92 def _InstancePidAlive(self, instance_name):
93 """Returns the instance pid and pidfile
96 pidfile = "%s/%s" % (self._PIDS_DIR, instance_name)
97 pid = utils.ReadPidFile(pidfile)
98 alive = utils.IsProcessAlive(pid)
100 return (pidfile, pid, alive)
103 def _InstanceMonitor(cls, instance_name):
104 """Returns the instance monitor socket name
107 return '%s/%s.monitor' % (cls._CTRL_DIR, instance_name)
110 def _InstanceSerial(cls, instance_name):
111 """Returns the instance serial socket name
114 return '%s/%s.serial' % (cls._CTRL_DIR, instance_name)
117 def _InstanceKVMRuntime(cls, instance_name):
118 """Returns the instance KVM runtime filename
121 return '%s/%s.runtime' % (cls._CONF_DIR, instance_name)
124 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
125 """Removes an instance's rutime sockets/files.
128 utils.RemoveFile(pidfile)
129 utils.RemoveFile(cls._InstanceMonitor(instance_name))
130 utils.RemoveFile(cls._InstanceSerial(instance_name))
131 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
133 def _WriteNetScript(self, instance, seq, nic):
134 """Write a script to connect a net interface to the proper bridge.
136 This can be used by any qemu-type hypervisor.
138 @param instance: instance we're acting on
139 @type instance: instance object
140 @param seq: nic sequence number
142 @param nic: nic we're acting on
143 @type nic: nic object
144 @return: netscript file name
149 script.write("#!/bin/sh\n")
150 script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
151 script.write("export INSTANCE=%s\n" % instance.name)
152 script.write("export MAC=%s\n" % nic.mac)
154 script.write("export IP=%s\n" % nic.ip)
155 script.write("export MODE=%s\n" % nic.nicparams[constants.NIC_MODE])
156 if nic.nicparams[constants.NIC_LINK]:
157 script.write("export LINK=%s\n" % nic.nicparams[constants.NIC_LINK])
158 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
159 script.write("export BRIDGE=%s\n" % nic.nicparams[constants.NIC_LINK])
160 script.write("export INTERFACE=$1\n")
161 # TODO: make this configurable at ./configure time
162 script.write("if [ -x '%s' ]; then\n" % self._KVM_NETWORK_SCRIPT)
163 script.write(" # Execute the user-specific vif file\n")
164 script.write(" %s\n" % self._KVM_NETWORK_SCRIPT)
165 script.write("else\n")
166 script.write(" /sbin/ifconfig $INTERFACE 0.0.0.0 up\n")
167 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
168 script.write(" # Connect the interface to the bridge\n")
169 script.write(" /usr/sbin/brctl addif $BRIDGE $INTERFACE\n")
170 elif nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED:
171 script.write(" # Route traffic targeted at the IP to the interface\n")
172 if nic.nicparams[constants.NIC_LINK]:
173 script.write(" /sbin/ip route replace $IP/32 table $LINK"
176 script.write(" /sbin/ip route replace $IP/32 dev $INTERFACE\n")
177 interface_proxy_arp = "/proc/sys/net/ipv4/conf/$INTERFACE/proxy_arp"
178 interface_forwarding = "/proc/sys/net/ipv4/conf/$INTERFACE/forwarding"
179 script.write(" /bin/echo 1 > %s\n" % interface_proxy_arp)
180 script.write(" /bin/echo 1 > %s\n" % interface_forwarding)
181 script.write("fi\n\n")
182 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
183 # mounted noexec sometimes, so we'll have to find another place.
184 (tmpfd, tmpfile_name) = tempfile.mkstemp()
185 tmpfile = os.fdopen(tmpfd, 'w')
187 tmpfile.write(script.getvalue())
190 os.chmod(tmpfile_name, 0755)
193 def ListInstances(self):
194 """Get the list of running instances.
196 We can do this by listing our live instances directory and
197 checking whether the associated kvm process is still alive.
201 for name in os.listdir(self._PIDS_DIR):
202 filename = "%s/%s" % (self._PIDS_DIR, name)
203 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
207 def GetInstanceInfo(self, instance_name):
208 """Get instance properties.
210 @param instance_name: the instance name
212 @return: tuple (name, id, memory, vcpus, stat, times)
215 pidfile, pid, alive = self._InstancePidAlive(instance_name)
219 cmdline_file = "/proc/%s/cmdline" % pid
221 cmdline = utils.ReadFile(cmdline_file)
222 except EnvironmentError, err:
223 raise errors.HypervisorError("Failed to list instance %s: %s" %
224 (instance_name, err))
231 arg_list = cmdline.split('\x00')
233 arg = arg_list.pop(0)
235 memory = int(arg_list.pop(0))
237 vcpus = int(arg_list.pop(0))
239 return (instance_name, pid, memory, vcpus, stat, times)
241 def GetAllInstancesInfo(self):
242 """Get properties of all instances.
244 @return: list of tuples (name, id, memory, vcpus, stat, times)
248 for name in os.listdir(self._PIDS_DIR):
249 filename = "%s/%s" % (self._PIDS_DIR, name)
250 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
252 info = self.GetInstanceInfo(name)
253 except errors.HypervisorError, err:
260 def _GenerateKVMRuntime(self, instance, block_devices):
261 """Generate KVM information to start an instance.
264 pidfile, pid, alive = self._InstancePidAlive(instance.name)
265 kvm = constants.KVM_PATH
267 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
268 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
269 kvm_cmd.extend(['-pidfile', pidfile])
270 # used just by the vnc server, if enabled
271 kvm_cmd.extend(['-name', instance.name])
272 kvm_cmd.extend(['-daemonize'])
273 if not instance.hvparams[constants.HV_ACPI]:
274 kvm_cmd.extend(['-no-acpi'])
276 hvp = instance.hvparams
277 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
278 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
279 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
282 kvm_cmd.extend(['-boot', 'n'])
284 disk_type = hvp[constants.HV_DISK_TYPE]
285 if disk_type == constants.HT_DISK_PARAVIRTUAL:
286 if_val = ',if=virtio'
288 if_val = ',if=%s' % disk_type
289 for cfdev, dev_path in block_devices:
290 if cfdev.mode != constants.DISK_RDWR:
291 raise errors.HypervisorError("Instance has read-only disks which"
292 " are not supported by KVM")
293 # TODO: handle FD_LOOP and FD_BLKTAP (?)
295 kvm_cmd.extend(['-boot', 'c'])
296 boot_val = ',boot=on'
297 # We only boot from the first disk
302 drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
303 kvm_cmd.extend(['-drive', drive_val])
305 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
307 options = ',format=raw,media=cdrom'
309 kvm_cmd.extend(['-boot', 'd'])
310 options = '%s,boot=on' % options
312 options = '%s,if=virtio' % options
313 drive_val = 'file=%s%s' % (iso_image, options)
314 kvm_cmd.extend(['-drive', drive_val])
316 kernel_path = hvp[constants.HV_KERNEL_PATH]
318 kvm_cmd.extend(['-kernel', kernel_path])
319 initrd_path = hvp[constants.HV_INITRD_PATH]
321 kvm_cmd.extend(['-initrd', initrd_path])
322 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
323 hvp[constants.HV_KERNEL_ARGS]]
324 if hvp[constants.HV_SERIAL_CONSOLE]:
325 root_append.append('console=ttyS0,38400')
326 kvm_cmd.extend(['-append', ' '.join(root_append)])
328 mouse_type = hvp[constants.HV_USB_MOUSE]
330 kvm_cmd.extend(['-usb'])
331 kvm_cmd.extend(['-usbdevice', mouse_type])
333 # FIXME: handle vnc password
334 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
336 if utils.IsValidIP(vnc_bind_address):
337 if instance.network_port > constants.VNC_BASE_PORT:
338 display = instance.network_port - constants.VNC_BASE_PORT
339 if vnc_bind_address == '0.0.0.0':
340 vnc_arg = ':%d' % (display)
342 vnc_arg = '%s:%d' % (vnc_bind_address, display)
344 logging.error("Network port is not a valid VNC display (%d < %d)."
345 " Not starting VNC" %
346 (instance.network_port,
347 constants.VNC_BASE_PORT))
350 # Only allow tls and other option when not binding to a file, for now.
351 # kvm/qemu gets confused otherwise about the filename to use.
353 if hvp[constants.HV_VNC_TLS]:
354 vnc_append = '%s,tls' % vnc_append
355 if hvp[constants.HV_VNC_X509_VERIFY]:
356 vnc_append = '%s,x509verify=%s' % (vnc_append,
357 hvp[constants.HV_VNC_X509])
358 elif hvp[constants.HV_VNC_X509]:
359 vnc_append = '%s,x509=%s' % (vnc_append,
360 hvp[constants.HV_VNC_X509])
361 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
364 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
366 kvm_cmd.extend(['-vnc', vnc_arg])
368 kvm_cmd.extend(['-nographic'])
370 monitor_dev = 'unix:%s,server,nowait' % \
371 self._InstanceMonitor(instance.name)
372 kvm_cmd.extend(['-monitor', monitor_dev])
373 if hvp[constants.HV_SERIAL_CONSOLE]:
374 serial_dev = ('unix:%s,server,nowait' %
375 self._InstanceSerial(instance.name))
376 kvm_cmd.extend(['-serial', serial_dev])
378 kvm_cmd.extend(['-serial', 'none'])
380 # Save the current instance nics, but defer their expansion as parameters,
381 # as we'll need to generate executable temp files for them.
382 kvm_nics = instance.nics
385 return (kvm_cmd, kvm_nics, hvparams)
387 def _WriteKVMRuntime(self, instance_name, data):
388 """Write an instance's KVM runtime
392 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
394 except EnvironmentError, err:
395 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
397 def _ReadKVMRuntime(self, instance_name):
398 """Read an instance's KVM runtime
402 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
403 except EnvironmentError, err:
404 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
407 def _SaveKVMRuntime(self, instance, kvm_runtime):
408 """Save an instance's KVM runtime
411 kvm_cmd, kvm_nics, hvparams = kvm_runtime
412 serialized_nics = [nic.ToDict() for nic in kvm_nics]
413 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
414 self._WriteKVMRuntime(instance.name, serialized_form)
416 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
417 """Load an instance's KVM runtime
420 if not serialized_runtime:
421 serialized_runtime = self._ReadKVMRuntime(instance.name)
422 loaded_runtime = serializer.Load(serialized_runtime)
423 kvm_cmd, serialized_nics, hvparams = loaded_runtime
424 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
425 return (kvm_cmd, kvm_nics, hvparams)
427 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
428 """Execute a KVM cmd, after completing it with some last minute data
430 @type incoming: tuple of strings
431 @param incoming: (target_host_ip, port)
434 pidfile, pid, alive = self._InstancePidAlive(instance.name)
436 raise errors.HypervisorError("Failed to start instance %s: %s" %
437 (instance.name, "already running"))
441 kvm_cmd, kvm_nics, hvparams = kvm_runtime
444 kvm_cmd.extend(['-net', 'none'])
446 nic_type = hvparams[constants.HV_NIC_TYPE]
447 if nic_type == constants.HT_NIC_PARAVIRTUAL:
448 nic_model = "model=virtio"
450 nic_model = "model=%s" % nic_type
452 for nic_seq, nic in enumerate(kvm_nics):
453 nic_val = "nic,macaddr=%s,%s" % (nic.mac, nic_model)
454 script = self._WriteNetScript(instance, nic_seq, nic)
455 kvm_cmd.extend(['-net', nic_val])
456 kvm_cmd.extend(['-net', 'tap,script=%s' % script])
457 temp_files.append(script)
460 target, port = incoming
461 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
463 result = utils.RunCmd(kvm_cmd)
465 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
466 (instance.name, result.fail_reason,
469 if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
470 raise errors.HypervisorError("Failed to start instance %s: %s" %
473 for filename in temp_files:
474 utils.RemoveFile(filename)
476 def StartInstance(self, instance, block_devices):
477 """Start an instance.
480 pidfile, pid, alive = self._InstancePidAlive(instance.name)
482 raise errors.HypervisorError("Failed to start instance %s: %s" %
483 (instance.name, "already running"))
485 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
486 self._SaveKVMRuntime(instance, kvm_runtime)
487 self._ExecuteKVMRuntime(instance, kvm_runtime)
489 def _CallMonitorCommand(self, instance_name, command):
490 """Invoke a command on the instance monitor.
493 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
494 (utils.ShellQuote(command),
495 constants.SOCAT_PATH,
496 utils.ShellQuote(self._InstanceMonitor(instance_name))))
497 result = utils.RunCmd(socat)
499 msg = ("Failed to send command '%s' to instance %s."
500 " output: %s, error: %s, fail_reason: %s" %
501 (command, instance_name,
502 result.stdout, result.stderr, result.fail_reason))
503 raise errors.HypervisorError(msg)
507 def _RetryInstancePowerdown(self, instance, pid, timeout=30):
508 """Wait for an instance to power down.
511 # Wait up to $timeout seconds
512 end = time.time() + timeout
514 while time.time() < end and utils.IsProcessAlive(pid):
515 self._CallMonitorCommand(instance.name, 'system_powerdown')
517 # Make wait time longer for next try
521 def StopInstance(self, instance, force=False):
525 pidfile, pid, alive = self._InstancePidAlive(instance.name)
526 if pid > 0 and alive:
527 if force or not instance.hvparams[constants.HV_ACPI]:
528 utils.KillProcess(pid)
530 self._RetryInstancePowerdown(instance, pid)
532 if not utils.IsProcessAlive(pid):
533 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
538 def RebootInstance(self, instance):
539 """Reboot an instance.
542 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
543 # socket the instance will stop, but now power up again. So we'll resort
544 # to shutdown and restart.
545 pidfile, pid, alive = self._InstancePidAlive(instance.name)
547 raise errors.HypervisorError("Failed to reboot instance %s: not running" %
549 # StopInstance will delete the saved KVM runtime so:
550 # ...first load it...
551 kvm_runtime = self._LoadKVMRuntime(instance)
552 # ...now we can safely call StopInstance...
553 if not self.StopInstance(instance):
554 self.StopInstance(instance, force=True)
555 # ...and finally we can save it again, and execute it...
556 self._SaveKVMRuntime(instance, kvm_runtime)
557 self._ExecuteKVMRuntime(instance, kvm_runtime)
559 def MigrationInfo(self, instance):
560 """Get instance information to perform a migration.
562 @type instance: L{objects.Instance}
563 @param instance: instance to be migrated
565 @return: content of the KVM runtime file
568 return self._ReadKVMRuntime(instance.name)
570 def AcceptInstance(self, instance, info, target):
571 """Prepare to accept an instance.
573 @type instance: L{objects.Instance}
574 @param instance: instance to be accepted
576 @param info: content of the KVM runtime file on the source node
578 @param target: target host (usually ip), on this node
581 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
582 incoming_address = (target, constants.KVM_MIGRATION_PORT)
583 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
585 def FinalizeMigration(self, instance, info, success):
586 """Finalize an instance migration.
588 Stop the incoming mode KVM.
590 @type instance: L{objects.Instance}
591 @param instance: instance whose migration is being aborted
595 self._WriteKVMRuntime(instance.name, info)
597 self.StopInstance(instance, force=True)
599 def MigrateInstance(self, instance_name, target, live):
600 """Migrate an instance to a target node.
602 The migration will not be attempted if the instance is not
605 @type instance_name: string
606 @param instance_name: name of the instance to be migrated
608 @param target: ip address of the target node
610 @param live: perform a live migration
613 pidfile, pid, alive = self._InstancePidAlive(instance_name)
615 raise errors.HypervisorError("Instance not running, cannot migrate")
618 self._CallMonitorCommand(instance_name, 'stop')
620 migrate_command = ('migrate -d tcp:%s:%s' %
621 (target, constants.KVM_MIGRATION_PORT))
622 self._CallMonitorCommand(instance_name, migrate_command)
624 info_command = 'info migrate'
627 result = self._CallMonitorCommand(instance_name, info_command)
628 match = self._MIGRATION_STATUS_RE.search(result.stdout)
630 raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
633 status = match.group(1)
634 if status == 'completed':
636 elif status == 'active':
638 elif status == 'failed' or status == 'cancelled':
640 self._CallMonitorCommand(instance_name, 'cont')
641 raise errors.HypervisorError("Migration %s at the kvm level" %
644 logging.info("KVM: unknown migration status '%s'" % status)
647 utils.KillProcess(pid)
648 self._RemoveInstanceRuntimeFiles(pidfile, instance_name)
650 def GetNodeInfo(self):
651 """Return information about the node.
653 This is just a wrapper over the base GetLinuxNodeInfo method.
655 @return: a dict with the following keys (values in MiB):
656 - memory_total: the total memory size on the node
657 - memory_free: the available memory on the node for instances
658 - memory_dom0: the memory used by the node itself, if available
661 return self.GetLinuxNodeInfo()
664 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
665 """Return a command for connecting to the console of an instance.
668 if hvparams[constants.HV_SERIAL_CONSOLE]:
669 # FIXME: The socat shell is not perfect. In particular the way we start
670 # it ctrl+c will close it, rather than being passed to the other end.
671 # On the other hand if we pass the option 'raw' (or ignbrk=1) there
672 # will be no way of exiting socat (except killing it from another shell)
673 # and ctrl+c doesn't work anyway, printing ^C rather than being
674 # interpreted by kvm. For now we'll leave it this way, which at least
675 # allows a minimal interaction and changes on the machine.
676 shell_command = ("%s STDIO,echo=0,icanon=0 UNIX-CONNECT:%s" %
677 (constants.SOCAT_PATH,
678 utils.ShellQuote(cls._InstanceSerial(instance.name))))
680 shell_command = "echo 'No serial shell for instance %s'" % instance.name
682 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
684 if instance.network_port > constants.VNC_BASE_PORT:
685 display = instance.network_port - constants.VNC_BASE_PORT
686 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
687 " (display: %d)'" % (vnc_bind_address,
688 instance.network_port,
690 shell_command = "%s; %s" % (vnc_command, shell_command)
695 """Verify the hypervisor.
697 Check that the binary exists.
700 if not os.path.exists(constants.KVM_PATH):
701 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
702 if not os.path.exists(constants.SOCAT_PATH):
703 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
707 def CheckParameterSyntax(cls, hvparams):
708 """Check the given parameters for validity.
711 @param hvparams: dictionary with parameter names/value
712 @raise errors.HypervisorError: when a parameter is not valid
715 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
717 kernel_path = hvparams[constants.HV_KERNEL_PATH]
719 if not hvparams[constants.HV_ROOT_PATH]:
720 raise errors.HypervisorError("Need a root partition for the instance,"
721 " if a kernel is defined")
723 if (hvparams[constants.HV_VNC_X509_VERIFY] and
724 not hvparams[constants.HV_VNC_X509]):
725 raise errors.HypervisorError("%s must be defined, if %s is" %
726 (constants.HV_VNC_X509,
727 constants.HV_VNC_X509_VERIFY))
729 boot_order = hvparams[constants.HV_BOOT_ORDER]
731 if (boot_order == constants.HT_BO_CDROM and
732 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
733 raise errors.HypervisorError("Cannot boot from cdrom without an"
735 if (boot_order == constants.HT_BO_NETWORK and
736 hvparams[constants.HV_NIC_TYPE] == constants.HT_NIC_PARAVIRTUAL):
737 raise errors.HypervisorError("Cannot boot from a paravirtual NIC. Please"
738 " change the NIC type.")
741 def PowercycleNode(cls):
742 """KVM powercycle, just a wrapper over Linux powercycle.
745 cls.LinuxPowercycle()