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,
53 constants.HV_INITRD_PATH,
54 constants.HV_ROOT_PATH,
55 constants.HV_KERNEL_ARGS,
57 constants.HV_SERIAL_CONSOLE,
58 constants.HV_VNC_BIND_ADDRESS,
60 constants.HV_VNC_X509,
61 constants.HV_VNC_X509_VERIFY,
62 constants.HV_CDROM_IMAGE_PATH,
63 constants.HV_BOOT_ORDER,
64 constants.HV_NIC_TYPE,
65 constants.HV_DISK_TYPE,
66 constants.HV_USB_MOUSE,
69 _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
73 hv_base.BaseHypervisor.__init__(self)
74 # Let's make sure the directories we need exist, even if the RUN_DIR lives
75 # in a tmpfs filesystem or has been otherwise wiped out.
76 dirs = [(dir, constants.RUN_DIRS_MODE) for dir in self._DIRS]
77 utils.EnsureDirs(dirs)
79 def _InstancePidAlive(self, instance_name):
80 """Returns the instance pid and pidfile
83 pidfile = "%s/%s" % (self._PIDS_DIR, instance_name)
84 pid = utils.ReadPidFile(pidfile)
85 alive = utils.IsProcessAlive(pid)
87 return (pidfile, pid, alive)
90 def _InstanceMonitor(cls, instance_name):
91 """Returns the instance monitor socket name
94 return '%s/%s.monitor' % (cls._CTRL_DIR, instance_name)
97 def _InstanceSerial(cls, instance_name):
98 """Returns the instance serial socket name
101 return '%s/%s.serial' % (cls._CTRL_DIR, instance_name)
104 def _InstanceKVMRuntime(cls, instance_name):
105 """Returns the instance KVM runtime filename
108 return '%s/%s.runtime' % (cls._CONF_DIR, instance_name)
110 def _WriteNetScript(self, instance, seq, nic):
111 """Write a script to connect a net interface to the proper bridge.
113 This can be used by any qemu-type hypervisor.
115 @param instance: instance we're acting on
116 @type instance: instance object
117 @param seq: nic sequence number
119 @param nic: nic we're acting on
120 @type nic: nic object
121 @return: netscript file name
126 script.write("#!/bin/sh\n")
127 script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
128 script.write("export INSTANCE=%s\n" % instance.name)
129 script.write("export MAC=%s\n" % nic.mac)
130 script.write("export IP=%s\n" % nic.ip)
131 script.write("export BRIDGE=%s\n" % nic.bridge)
132 script.write("export INTERFACE=$1\n")
133 # TODO: make this configurable at ./configure time
134 script.write("if [ -x /etc/ganeti/kvm-vif-bridge ]; then\n")
135 script.write(" # Execute the user-specific vif file\n")
136 script.write(" /etc/ganeti/kvm-vif-bridge\n")
137 script.write("else\n")
138 script.write(" # Connect the interface to the bridge\n")
139 script.write(" /sbin/ifconfig $INTERFACE 0.0.0.0 up\n")
140 script.write(" /usr/sbin/brctl addif $BRIDGE $INTERFACE\n")
141 script.write("fi\n\n")
142 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
143 # mounted noexec sometimes, so we'll have to find another place.
144 (tmpfd, tmpfile_name) = tempfile.mkstemp()
145 tmpfile = os.fdopen(tmpfd, 'w')
146 tmpfile.write(script.getvalue())
148 os.chmod(tmpfile_name, 0755)
151 def ListInstances(self):
152 """Get the list of running instances.
154 We can do this by listing our live instances directory and
155 checking whether the associated kvm process is still alive.
159 for name in os.listdir(self._PIDS_DIR):
160 filename = "%s/%s" % (self._PIDS_DIR, name)
161 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
165 def GetInstanceInfo(self, instance_name):
166 """Get instance properties.
168 @param instance_name: the instance name
170 @return: tuple (name, id, memory, vcpus, stat, times)
173 pidfile, pid, alive = self._InstancePidAlive(instance_name)
177 cmdline_file = "/proc/%s/cmdline" % pid
179 fh = open(cmdline_file, 'r')
184 except EnvironmentError, err:
185 raise errors.HypervisorError("Failed to list instance %s: %s" %
186 (instance_name, err))
193 arg_list = cmdline.split('\x00')
195 arg = arg_list.pop(0)
197 memory = int(arg_list.pop(0))
199 vcpus = int(arg_list.pop(0))
201 return (instance_name, pid, memory, vcpus, stat, times)
203 def GetAllInstancesInfo(self):
204 """Get properties of all instances.
206 @return: list of tuples (name, id, memory, vcpus, stat, times)
210 for name in os.listdir(self._PIDS_DIR):
211 filename = "%s/%s" % (self._PIDS_DIR, name)
212 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
214 info = self.GetInstanceInfo(name)
215 except errors.HypervisorError, err:
222 def _GenerateKVMRuntime(self, instance, block_devices):
223 """Generate KVM information to start an instance.
226 pidfile, pid, alive = self._InstancePidAlive(instance.name)
227 kvm = constants.KVM_PATH
229 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
230 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
231 kvm_cmd.extend(['-pidfile', pidfile])
232 # used just by the vnc server, if enabled
233 kvm_cmd.extend(['-name', instance.name])
234 kvm_cmd.extend(['-daemonize'])
235 if not instance.hvparams[constants.HV_ACPI]:
236 kvm_cmd.extend(['-no-acpi'])
238 hvp = instance.hvparams
239 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
240 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
241 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
244 kvm_cmd.extend(['-boot', 'n'])
246 disk_type = hvp[constants.HV_DISK_TYPE]
247 if disk_type == constants.HT_DISK_PARAVIRTUAL:
248 if_val = ',if=virtio'
250 if_val = ',if=%s' % disk_type
251 for cfdev, dev_path in block_devices:
252 if cfdev.mode != constants.DISK_RDWR:
253 raise errors.HypervisorError("Instance has read-only disks which"
254 " are not supported by KVM")
255 # TODO: handle FD_LOOP and FD_BLKTAP (?)
257 kvm_cmd.extend(['-boot', 'c'])
258 boot_val = ',boot=on'
259 # We only boot from the first disk
264 drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
265 kvm_cmd.extend(['-drive', drive_val])
267 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
269 options = ',format=raw,media=cdrom'
271 kvm_cmd.extend(['-boot', 'd'])
272 options = '%s,boot=on' % options
274 options = '%s,if=virtio' % options
275 drive_val = 'file=%s%s' % (iso_image, options)
276 kvm_cmd.extend(['-drive', drive_val])
278 kernel_path = hvp[constants.HV_KERNEL_PATH]
280 kvm_cmd.extend(['-kernel', kernel_path])
281 initrd_path = hvp[constants.HV_INITRD_PATH]
283 kvm_cmd.extend(['-initrd', initrd_path])
284 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
285 hvp[constants.HV_KERNEL_ARGS]]
286 if hvp[constants.HV_SERIAL_CONSOLE]:
287 root_append.append('console=ttyS0,38400')
288 kvm_cmd.extend(['-append', ' '.join(root_append)])
290 mouse_type = hvp[constants.HV_USB_MOUSE]
292 kvm_cmd.extend(['-usb'])
293 kvm_cmd.extend(['-usbdevice', mouse_type])
295 # FIXME: handle vnc password
296 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
298 if utils.IsValidIP(vnc_bind_address):
299 if instance.network_port > constants.VNC_BASE_PORT:
300 display = instance.network_port - constants.VNC_BASE_PORT
301 if vnc_bind_address == '0.0.0.0':
302 vnc_arg = ':%d' % (display)
304 vnc_arg = '%s:%d' % (vnc_bind_address, display)
306 logging.error("Network port is not a valid VNC display (%d < %d)."
307 " Not starting VNC" %
308 (instance.network_port,
309 constants.VNC_BASE_PORT))
312 # Only allow tls and other option when not binding to a file, for now.
313 # kvm/qemu gets confused otherwise about the filename to use.
315 if hvp[constants.HV_VNC_TLS]:
316 vnc_append = '%s,tls' % vnc_append
317 if hvp[constants.HV_VNC_X509_VERIFY]:
318 vnc_append = '%s,x509verify=%s' % (vnc_append,
319 hvp[constants.HV_VNC_X509])
320 elif hvp[constants.HV_VNC_X509]:
321 vnc_append = '%s,x509=%s' % (vnc_append,
322 hvp[constants.HV_VNC_X509])
323 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
326 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
328 kvm_cmd.extend(['-vnc', vnc_arg])
330 kvm_cmd.extend(['-nographic'])
332 monitor_dev = 'unix:%s,server,nowait' % \
333 self._InstanceMonitor(instance.name)
334 kvm_cmd.extend(['-monitor', monitor_dev])
335 if hvp[constants.HV_SERIAL_CONSOLE]:
336 serial_dev = ('unix:%s,server,nowait' %
337 self._InstanceSerial(instance.name))
338 kvm_cmd.extend(['-serial', serial_dev])
340 kvm_cmd.extend(['-serial', 'none'])
342 # Save the current instance nics, but defer their expansion as parameters,
343 # as we'll need to generate executable temp files for them.
344 kvm_nics = instance.nics
347 return (kvm_cmd, kvm_nics, hvparams)
349 def _WriteKVMRuntime(self, instance_name, data):
350 """Write an instance's KVM runtime
354 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
356 except EnvironmentError, err:
357 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
359 def _ReadKVMRuntime(self, instance_name):
360 """Read an instance's KVM runtime
364 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
365 except EnvironmentError, err:
366 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
369 def _SaveKVMRuntime(self, instance, kvm_runtime):
370 """Save an instance's KVM runtime
373 kvm_cmd, kvm_nics, hvparams = kvm_runtime
374 serialized_nics = [nic.ToDict() for nic in kvm_nics]
375 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
376 self._WriteKVMRuntime(instance.name, serialized_form)
378 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
379 """Load an instance's KVM runtime
382 if not serialized_runtime:
383 serialized_runtime = self._ReadKVMRuntime(instance.name)
384 loaded_runtime = serializer.Load(serialized_runtime)
385 kvm_cmd, serialized_nics, hvparams = loaded_runtime
386 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
387 return (kvm_cmd, kvm_nics, hvparams)
389 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
390 """Execute a KVM cmd, after completing it with some last minute data
392 @type incoming: tuple of strings
393 @param incoming: (target_host_ip, port)
396 pidfile, pid, alive = self._InstancePidAlive(instance.name)
398 raise errors.HypervisorError("Failed to start instance %s: %s" %
399 (instance.name, "already running"))
403 kvm_cmd, kvm_nics, hvparams = kvm_runtime
406 kvm_cmd.extend(['-net', 'none'])
408 nic_type = hvparams[constants.HV_NIC_TYPE]
409 if nic_type == constants.HT_NIC_PARAVIRTUAL:
410 nic_model = "model=virtio"
412 nic_model = "model=%s" % nic_type
414 for nic_seq, nic in enumerate(kvm_nics):
415 nic_val = "nic,macaddr=%s,%s" % (nic.mac, nic_model)
416 script = self._WriteNetScript(instance, nic_seq, nic)
417 kvm_cmd.extend(['-net', nic_val])
418 kvm_cmd.extend(['-net', 'tap,script=%s' % script])
419 temp_files.append(script)
422 target, port = incoming
423 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
425 result = utils.RunCmd(kvm_cmd)
427 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
428 (instance.name, result.fail_reason,
431 if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
432 raise errors.HypervisorError("Failed to start instance %s: %s" %
435 for filename in temp_files:
436 utils.RemoveFile(filename)
438 def StartInstance(self, instance, block_devices):
439 """Start an instance.
442 pidfile, pid, alive = self._InstancePidAlive(instance.name)
444 raise errors.HypervisorError("Failed to start instance %s: %s" %
445 (instance.name, "already running"))
447 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
448 self._SaveKVMRuntime(instance, kvm_runtime)
449 self._ExecuteKVMRuntime(instance, kvm_runtime)
451 def _CallMonitorCommand(self, instance_name, command):
452 """Invoke a command on the instance monitor.
455 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
456 (utils.ShellQuote(command),
457 constants.SOCAT_PATH,
458 utils.ShellQuote(self._InstanceMonitor(instance_name))))
459 result = utils.RunCmd(socat)
461 msg = ("Failed to send command '%s' to instance %s."
462 " output: %s, error: %s, fail_reason: %s" %
463 (command, instance_name,
464 result.stdout, result.stderr, result.fail_reason))
465 raise errors.HypervisorError(msg)
469 def _RetryInstancePowerdown(self, instance, pid, timeout=30):
470 """Wait for an instance to power down.
473 # Wait up to $timeout seconds
474 end = time.time() + timeout
476 while time.time() < end and utils.IsProcessAlive(pid):
477 self._CallMonitorCommand(instance.name, 'system_powerdown')
479 # Make wait time longer for next try
483 def StopInstance(self, instance, force=False):
487 pidfile, pid, alive = self._InstancePidAlive(instance.name)
488 if pid > 0 and alive:
489 if force or not instance.hvparams[constants.HV_ACPI]:
490 utils.KillProcess(pid)
492 self._RetryInstancePowerdown(instance, pid)
494 if not utils.IsProcessAlive(pid):
495 utils.RemoveFile(pidfile)
496 utils.RemoveFile(self._InstanceMonitor(instance.name))
497 utils.RemoveFile(self._InstanceSerial(instance.name))
498 utils.RemoveFile(self._InstanceKVMRuntime(instance.name))
503 def RebootInstance(self, instance):
504 """Reboot an instance.
507 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
508 # socket the instance will stop, but now power up again. So we'll resort
509 # to shutdown and restart.
510 pidfile, pid, alive = self._InstancePidAlive(instance.name)
512 raise errors.HypervisorError("Failed to reboot instance %s: not running" %
514 # StopInstance will delete the saved KVM runtime so:
515 # ...first load it...
516 kvm_runtime = self._LoadKVMRuntime(instance)
517 # ...now we can safely call StopInstance...
518 if not self.StopInstance(instance):
519 self.StopInstance(instance, force=True)
520 # ...and finally we can save it again, and execute it...
521 self._SaveKVMRuntime(instance, kvm_runtime)
522 self._ExecuteKVMRuntime(instance, kvm_runtime)
524 def MigrationInfo(self, instance):
525 """Get instance information to perform a migration.
527 @type instance: L{objects.Instance}
528 @param instance: instance to be migrated
530 @return: content of the KVM runtime file
533 return self._ReadKVMRuntime(instance.name)
535 def AcceptInstance(self, instance, info, target):
536 """Prepare to accept an instance.
538 @type instance: L{objects.Instance}
539 @param instance: instance to be accepted
541 @param info: content of the KVM runtime file on the source node
543 @param target: target host (usually ip), on this node
546 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
547 incoming_address = (target, constants.KVM_MIGRATION_PORT)
548 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
550 def FinalizeMigration(self, instance, info, success):
551 """Finalize an instance migration.
553 Stop the incoming mode KVM.
555 @type instance: L{objects.Instance}
556 @param instance: instance whose migration is being aborted
560 self._WriteKVMRuntime(instance.name, info)
562 self.StopInstance(instance, force=True)
564 def MigrateInstance(self, instance_name, target, live):
565 """Migrate an instance to a target node.
567 The migration will not be attempted if the instance is not
570 @type instance_name: string
571 @param instance_name: name of the instance to be migrated
573 @param target: ip address of the target node
575 @param live: perform a live migration
578 pidfile, pid, alive = self._InstancePidAlive(instance_name)
580 raise errors.HypervisorError("Instance not running, cannot migrate")
583 self._CallMonitorCommand(instance_name, 'stop')
585 migrate_command = ('migrate -d tcp:%s:%s' %
586 (target, constants.KVM_MIGRATION_PORT))
587 self._CallMonitorCommand(instance_name, migrate_command)
589 info_command = 'info migrate'
592 result = self._CallMonitorCommand(instance_name, info_command)
593 match = self._MIGRATION_STATUS_RE.search(result.stdout)
595 raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
598 status = match.group(1)
599 if status == 'completed':
601 elif status == 'active':
603 elif status == 'failed' or status == 'cancelled':
605 self._CallMonitorCommand(instance_name, 'cont')
606 raise errors.HypervisorError("Migration %s at the kvm level" %
609 logging.info("KVM: unknown migration status '%s'" % status)
612 utils.KillProcess(pid)
613 utils.RemoveFile(pidfile)
614 utils.RemoveFile(self._InstanceMonitor(instance_name))
615 utils.RemoveFile(self._InstanceSerial(instance_name))
616 utils.RemoveFile(self._InstanceKVMRuntime(instance_name))
618 def GetNodeInfo(self):
619 """Return information about the node.
621 This is just a wrapper over the base GetLinuxNodeInfo method.
623 @return: a dict with the following keys (values in MiB):
624 - memory_total: the total memory size on the node
625 - memory_free: the available memory on the node for instances
626 - memory_dom0: the memory used by the node itself, if available
629 return self.GetLinuxNodeInfo()
632 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
633 """Return a command for connecting to the console of an instance.
636 if hvparams[constants.HV_SERIAL_CONSOLE]:
637 # FIXME: The socat shell is not perfect. In particular the way we start
638 # it ctrl+c will close it, rather than being passed to the other end.
639 # On the other hand if we pass the option 'raw' (or ignbrk=1) there
640 # will be no way of exiting socat (except killing it from another shell)
641 # and ctrl+c doesn't work anyway, printing ^C rather than being
642 # interpreted by kvm. For now we'll leave it this way, which at least
643 # allows a minimal interaction and changes on the machine.
644 shell_command = ("%s STDIO,echo=0,icanon=0 UNIX-CONNECT:%s" %
645 (constants.SOCAT_PATH,
646 utils.ShellQuote(cls._InstanceSerial(instance.name))))
648 shell_command = "echo 'No serial shell for instance %s'" % instance.name
650 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
652 if instance.network_port > constants.VNC_BASE_PORT:
653 display = instance.network_port - constants.VNC_BASE_PORT
654 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
655 " (display: %d)'" % (vnc_bind_address,
656 instance.network_port,
658 shell_command = "%s; %s" % (vnc_command, shell_command)
663 """Verify the hypervisor.
665 Check that the binary exists.
668 if not os.path.exists(constants.KVM_PATH):
669 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
670 if not os.path.exists(constants.SOCAT_PATH):
671 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
675 def CheckParameterSyntax(cls, hvparams):
676 """Check the given parameters for validity.
679 @param hvparams: dictionary with parameter names/value
680 @raise errors.HypervisorError: when a parameter is not valid
683 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
685 kernel_path = hvparams[constants.HV_KERNEL_PATH]
687 if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
688 raise errors.HypervisorError("The kernel path must be an absolute path"
691 if not hvparams[constants.HV_ROOT_PATH]:
692 raise errors.HypervisorError("Need a root partition for the instance"
693 ", if a kernel is defined")
695 if hvparams[constants.HV_INITRD_PATH]:
696 if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
697 raise errors.HypervisorError("The initrd path must an absolute path"
700 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
702 if not utils.IsValidIP(vnc_bind_address):
703 if not os.path.isabs(vnc_bind_address):
704 raise errors.HypervisorError("The VNC bind address must be either"
705 " a valid IP address or an absolute"
706 " pathname. '%s' given" %
709 if hvparams[constants.HV_VNC_X509_VERIFY] and \
710 not hvparams[constants.HV_VNC_X509]:
711 raise errors.HypervisorError("%s must be defined, if %s is" %
712 (constants.HV_VNC_X509,
713 constants.HV_VNC_X509_VERIFY))
715 if hvparams[constants.HV_VNC_X509]:
716 if not os.path.isabs(hvparams[constants.HV_VNC_X509]):
717 raise errors.HypervisorError("The vnc x509 path must an absolute path"
720 iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
721 if iso_path and not os.path.isabs(iso_path):
722 raise errors.HypervisorError("The path to the CDROM image must be"
723 " an absolute path, if defined")
725 boot_order = hvparams[constants.HV_BOOT_ORDER]
726 if boot_order not in constants.HT_KVM_VALID_BO_TYPES:
727 raise errors.HypervisorError(\
728 "The boot order must be one of %s" %
729 utils.CommaJoin(constants.HT_KVM_VALID_BO_TYPES))
731 if boot_order == constants.HT_BO_CDROM and not iso_path:
732 raise errors.HypervisorError("Cannot boot from cdrom without an"
735 nic_type = hvparams[constants.HV_NIC_TYPE]
736 if nic_type not in constants.HT_KVM_VALID_NIC_TYPES:
737 raise errors.HypervisorError(\
738 "Invalid NIC type %s specified for the KVM"
739 " hypervisor. Please choose one of: %s" %
740 (nic_type, utils.CommaJoin(constants.HT_KVM_VALID_NIC_TYPES)))
741 elif (boot_order == constants.HT_BO_NETWORK and
742 nic_type == constants.HT_NIC_PARAVIRTUAL):
743 raise errors.HypervisorError("Cannot boot from a paravirtual NIC. Please"
744 " change the NIC type.")
746 disk_type = hvparams[constants.HV_DISK_TYPE]
747 if disk_type not in constants.HT_KVM_VALID_DISK_TYPES:
748 raise errors.HypervisorError(\
749 "Invalid disk type %s specified for the KVM"
750 " hypervisor. Please choose one of: %s" %
751 (disk_type, utils.CommaJoin(constants.HT_KVM_VALID_DISK_TYPES)))
753 mouse_type = hvparams[constants.HV_USB_MOUSE]
754 if mouse_type and mouse_type not in constants.HT_KVM_VALID_MOUSE_TYPES:
755 raise errors.HypervisorError(\
756 "Invalid usb mouse type %s specified for the KVM hypervisor. Please"
757 " choose one of %s" %
758 utils.CommaJoin(constants.HT_KVM_VALID_MOUSE_TYPES))
760 def ValidateParameters(self, hvparams):
761 """Check the given parameters for validity.
763 For the KVM hypervisor, this checks the existence of the
767 super(KVMHypervisor, self).ValidateParameters(hvparams)
769 kernel_path = hvparams[constants.HV_KERNEL_PATH]
770 if kernel_path and not os.path.isfile(kernel_path):
771 raise errors.HypervisorError("Instance kernel '%s' not found or"
772 " not a file" % kernel_path)
773 initrd_path = hvparams[constants.HV_INITRD_PATH]
774 if initrd_path and not os.path.isfile(initrd_path):
775 raise errors.HypervisorError("Instance initrd '%s' not found or"
776 " not a file" % initrd_path)
778 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
779 if vnc_bind_address and not utils.IsValidIP(vnc_bind_address) and \
780 not os.path.isdir(vnc_bind_address):
781 raise errors.HypervisorError("Instance vnc bind address must be either"
782 " an ip address or an existing directory")
784 vnc_x509 = hvparams[constants.HV_VNC_X509]
785 if vnc_x509 and not os.path.isdir(vnc_x509):
786 raise errors.HypervisorError("Instance vnc x509 path '%s' not found"
787 " or not a directory" % vnc_x509)
789 iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
790 if iso_path and not os.path.isfile(iso_path):
791 raise errors.HypervisorError("Instance cdrom image '%s' not found or"
792 " not a file" % iso_path)