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)
111 def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
112 """Removes an instance's rutime sockets/files.
115 utils.RemoveFile(pidfile)
116 utils.RemoveFile(cls._InstanceMonitor(instance_name))
117 utils.RemoveFile(cls._InstanceSerial(instance_name))
118 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
120 def _WriteNetScript(self, instance, seq, nic):
121 """Write a script to connect a net interface to the proper bridge.
123 This can be used by any qemu-type hypervisor.
125 @param instance: instance we're acting on
126 @type instance: instance object
127 @param seq: nic sequence number
129 @param nic: nic we're acting on
130 @type nic: nic object
131 @return: netscript file name
136 script.write("#!/bin/sh\n")
137 script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
138 script.write("export INSTANCE=%s\n" % instance.name)
139 script.write("export MAC=%s\n" % nic.mac)
140 script.write("export IP=%s\n" % nic.ip)
141 script.write("export BRIDGE=%s\n" % nic.bridge)
142 script.write("export INTERFACE=$1\n")
143 # TODO: make this configurable at ./configure time
144 script.write("if [ -x /etc/ganeti/kvm-vif-bridge ]; then\n")
145 script.write(" # Execute the user-specific vif file\n")
146 script.write(" /etc/ganeti/kvm-vif-bridge\n")
147 script.write("else\n")
148 script.write(" # Connect the interface to the bridge\n")
149 script.write(" /sbin/ifconfig $INTERFACE 0.0.0.0 up\n")
150 script.write(" /usr/sbin/brctl addif $BRIDGE $INTERFACE\n")
151 script.write("fi\n\n")
152 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
153 # mounted noexec sometimes, so we'll have to find another place.
154 (tmpfd, tmpfile_name) = tempfile.mkstemp()
155 tmpfile = os.fdopen(tmpfd, 'w')
156 tmpfile.write(script.getvalue())
158 os.chmod(tmpfile_name, 0755)
161 def ListInstances(self):
162 """Get the list of running instances.
164 We can do this by listing our live instances directory and
165 checking whether the associated kvm process is still alive.
169 for name in os.listdir(self._PIDS_DIR):
170 filename = "%s/%s" % (self._PIDS_DIR, name)
171 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
175 def GetInstanceInfo(self, instance_name):
176 """Get instance properties.
178 @param instance_name: the instance name
180 @return: tuple (name, id, memory, vcpus, stat, times)
183 pidfile, pid, alive = self._InstancePidAlive(instance_name)
187 cmdline_file = "/proc/%s/cmdline" % pid
189 fh = open(cmdline_file, 'r')
194 except EnvironmentError, err:
195 raise errors.HypervisorError("Failed to list instance %s: %s" %
196 (instance_name, err))
203 arg_list = cmdline.split('\x00')
205 arg = arg_list.pop(0)
207 memory = arg_list.pop(0)
209 vcpus = arg_list.pop(0)
211 return (instance_name, pid, memory, vcpus, stat, times)
213 def GetAllInstancesInfo(self):
214 """Get properties of all instances.
216 @return: list of tuples (name, id, memory, vcpus, stat, times)
220 for name in os.listdir(self._PIDS_DIR):
221 filename = "%s/%s" % (self._PIDS_DIR, name)
222 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
224 info = self.GetInstanceInfo(name)
225 except errors.HypervisorError, err:
232 def _GenerateKVMRuntime(self, instance, block_devices):
233 """Generate KVM information to start an instance.
236 pidfile, pid, alive = self._InstancePidAlive(instance.name)
237 kvm = constants.KVM_PATH
239 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
240 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
241 kvm_cmd.extend(['-pidfile', pidfile])
242 # used just by the vnc server, if enabled
243 kvm_cmd.extend(['-name', instance.name])
244 kvm_cmd.extend(['-daemonize'])
245 if not instance.hvparams[constants.HV_ACPI]:
246 kvm_cmd.extend(['-no-acpi'])
248 hvp = instance.hvparams
249 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
250 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
251 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
254 kvm_cmd.extend(['-boot', 'n'])
256 disk_type = hvp[constants.HV_DISK_TYPE]
257 if disk_type == constants.HT_DISK_PARAVIRTUAL:
258 if_val = ',if=virtio'
260 if_val = ',if=%s' % disk_type
261 for cfdev, dev_path in block_devices:
262 if cfdev.mode != constants.DISK_RDWR:
263 raise errors.HypervisorError("Instance has read-only disks which"
264 " are not supported by KVM")
265 # TODO: handle FD_LOOP and FD_BLKTAP (?)
267 kvm_cmd.extend(['-boot', 'c'])
268 boot_val = ',boot=on'
269 # We only boot from the first disk
274 drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
275 kvm_cmd.extend(['-drive', drive_val])
277 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
279 options = ',format=raw,media=cdrom'
281 kvm_cmd.extend(['-boot', 'd'])
282 options = '%s,boot=on' % options
284 options = '%s,if=virtio' % options
285 drive_val = 'file=%s%s' % (iso_image, options)
286 kvm_cmd.extend(['-drive', drive_val])
288 kernel_path = hvp[constants.HV_KERNEL_PATH]
290 kvm_cmd.extend(['-kernel', kernel_path])
291 initrd_path = hvp[constants.HV_INITRD_PATH]
293 kvm_cmd.extend(['-initrd', initrd_path])
294 root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
295 hvp[constants.HV_KERNEL_ARGS]]
296 if hvp[constants.HV_SERIAL_CONSOLE]:
297 root_append.append('console=ttyS0,38400')
298 kvm_cmd.extend(['-append', ' '.join(root_append)])
300 mouse_type = hvp[constants.HV_USB_MOUSE]
302 kvm_cmd.extend(['-usb'])
303 kvm_cmd.extend(['-usbdevice', mouse_type])
305 # FIXME: handle vnc password
306 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
308 if utils.IsValidIP(vnc_bind_address):
309 if instance.network_port > constants.VNC_BASE_PORT:
310 display = instance.network_port - constants.VNC_BASE_PORT
311 if vnc_bind_address == '0.0.0.0':
312 vnc_arg = ':%d' % (display)
314 vnc_arg = '%s:%d' % (vnc_bind_address, display)
316 logging.error("Network port is not a valid VNC display (%d < %d)."
317 " Not starting VNC" %
318 (instance.network_port,
319 constants.VNC_BASE_PORT))
322 # Only allow tls and other option when not binding to a file, for now.
323 # kvm/qemu gets confused otherwise about the filename to use.
325 if hvp[constants.HV_VNC_TLS]:
326 vnc_append = '%s,tls' % vnc_append
327 if hvp[constants.HV_VNC_X509_VERIFY]:
328 vnc_append = '%s,x509verify=%s' % (vnc_append,
329 hvp[constants.HV_VNC_X509])
330 elif hvp[constants.HV_VNC_X509]:
331 vnc_append = '%s,x509=%s' % (vnc_append,
332 hvp[constants.HV_VNC_X509])
333 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
336 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
338 kvm_cmd.extend(['-vnc', vnc_arg])
340 kvm_cmd.extend(['-nographic'])
342 monitor_dev = 'unix:%s,server,nowait' % \
343 self._InstanceMonitor(instance.name)
344 kvm_cmd.extend(['-monitor', monitor_dev])
345 if hvp[constants.HV_SERIAL_CONSOLE]:
346 serial_dev = ('unix:%s,server,nowait' %
347 self._InstanceSerial(instance.name))
348 kvm_cmd.extend(['-serial', serial_dev])
350 kvm_cmd.extend(['-serial', 'none'])
352 # Save the current instance nics, but defer their expansion as parameters,
353 # as we'll need to generate executable temp files for them.
354 kvm_nics = instance.nics
357 return (kvm_cmd, kvm_nics, hvparams)
359 def _WriteKVMRuntime(self, instance_name, data):
360 """Write an instance's KVM runtime
364 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
366 except EnvironmentError, err:
367 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
369 def _ReadKVMRuntime(self, instance_name):
370 """Read an instance's KVM runtime
374 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
375 except EnvironmentError, err:
376 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
379 def _SaveKVMRuntime(self, instance, kvm_runtime):
380 """Save an instance's KVM runtime
383 kvm_cmd, kvm_nics, hvparams = kvm_runtime
384 serialized_nics = [nic.ToDict() for nic in kvm_nics]
385 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
386 self._WriteKVMRuntime(instance.name, serialized_form)
388 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
389 """Load an instance's KVM runtime
392 if not serialized_runtime:
393 serialized_runtime = self._ReadKVMRuntime(instance.name)
394 loaded_runtime = serializer.Load(serialized_runtime)
395 kvm_cmd, serialized_nics, hvparams = loaded_runtime
396 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
397 return (kvm_cmd, kvm_nics, hvparams)
399 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
400 """Execute a KVM cmd, after completing it with some last minute data
402 @type incoming: tuple of strings
403 @param incoming: (target_host_ip, port)
406 pidfile, pid, alive = self._InstancePidAlive(instance.name)
408 raise errors.HypervisorError("Failed to start instance %s: %s" %
409 (instance.name, "already running"))
413 kvm_cmd, kvm_nics, hvparams = kvm_runtime
416 kvm_cmd.extend(['-net', 'none'])
418 nic_type = hvparams[constants.HV_NIC_TYPE]
419 if nic_type == constants.HT_NIC_PARAVIRTUAL:
420 nic_model = "model=virtio"
422 nic_model = "model=%s" % nic_type
424 for nic_seq, nic in enumerate(kvm_nics):
425 nic_val = "nic,macaddr=%s,%s" % (nic.mac, nic_model)
426 script = self._WriteNetScript(instance, nic_seq, nic)
427 kvm_cmd.extend(['-net', nic_val])
428 kvm_cmd.extend(['-net', 'tap,script=%s' % script])
429 temp_files.append(script)
432 target, port = incoming
433 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
435 result = utils.RunCmd(kvm_cmd)
437 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
438 (instance.name, result.fail_reason,
441 if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
442 raise errors.HypervisorError("Failed to start instance %s: %s" %
445 for filename in temp_files:
446 utils.RemoveFile(filename)
448 def StartInstance(self, instance, block_devices):
449 """Start an instance.
452 pidfile, pid, alive = self._InstancePidAlive(instance.name)
454 raise errors.HypervisorError("Failed to start instance %s: %s" %
455 (instance.name, "already running"))
457 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
458 self._SaveKVMRuntime(instance, kvm_runtime)
459 self._ExecuteKVMRuntime(instance, kvm_runtime)
461 def _CallMonitorCommand(self, instance_name, command):
462 """Invoke a command on the instance monitor.
465 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
466 (utils.ShellQuote(command),
467 constants.SOCAT_PATH,
468 utils.ShellQuote(self._InstanceMonitor(instance_name))))
469 result = utils.RunCmd(socat)
471 msg = ("Failed to send command '%s' to instance %s."
472 " output: %s, error: %s, fail_reason: %s" %
473 (command, instance_name,
474 result.stdout, result.stderr, result.fail_reason))
475 raise errors.HypervisorError(msg)
479 def _RetryInstancePowerdown(self, instance, pid, timeout=30):
480 """Wait for an instance to power down.
483 # Wait up to $timeout seconds
484 end = time.time() + timeout
486 while time.time() < end and utils.IsProcessAlive(pid):
487 self._CallMonitorCommand(instance.name, 'system_powerdown')
489 # Make wait time longer for next try
493 def StopInstance(self, instance, force=False):
497 pidfile, pid, alive = self._InstancePidAlive(instance.name)
498 if pid > 0 and alive:
499 if force or not instance.hvparams[constants.HV_ACPI]:
500 utils.KillProcess(pid)
502 self._RetryInstancePowerdown(instance, pid)
504 if not utils.IsProcessAlive(pid):
505 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
510 def RebootInstance(self, instance):
511 """Reboot an instance.
514 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
515 # socket the instance will stop, but now power up again. So we'll resort
516 # to shutdown and restart.
517 pidfile, pid, alive = self._InstancePidAlive(instance.name)
519 raise errors.HypervisorError("Failed to reboot instance %s: not running" %
521 # StopInstance will delete the saved KVM runtime so:
522 # ...first load it...
523 kvm_runtime = self._LoadKVMRuntime(instance)
524 # ...now we can safely call StopInstance...
525 if not self.StopInstance(instance):
526 self.StopInstance(instance, force=True)
527 # ...and finally we can save it again, and execute it...
528 self._SaveKVMRuntime(instance, kvm_runtime)
529 self._ExecuteKVMRuntime(instance, kvm_runtime)
531 def MigrationInfo(self, instance):
532 """Get instance information to perform a migration.
534 @type instance: L{objects.Instance}
535 @param instance: instance to be migrated
537 @return: content of the KVM runtime file
540 return self._ReadKVMRuntime(instance.name)
542 def AcceptInstance(self, instance, info, target):
543 """Prepare to accept an instance.
545 @type instance: L{objects.Instance}
546 @param instance: instance to be accepted
548 @param info: content of the KVM runtime file on the source node
550 @param target: target host (usually ip), on this node
553 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
554 incoming_address = (target, constants.KVM_MIGRATION_PORT)
555 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
557 def FinalizeMigration(self, instance, info, success):
558 """Finalize an instance migration.
560 Stop the incoming mode KVM.
562 @type instance: L{objects.Instance}
563 @param instance: instance whose migration is being aborted
567 self._WriteKVMRuntime(instance.name, info)
569 self.StopInstance(instance, force=True)
571 def MigrateInstance(self, instance_name, target, live):
572 """Migrate an instance to a target node.
574 The migration will not be attempted if the instance is not
577 @type instance_name: string
578 @param instance_name: name of the instance to be migrated
580 @param target: ip address of the target node
582 @param live: perform a live migration
585 pidfile, pid, alive = self._InstancePidAlive(instance_name)
587 raise errors.HypervisorError("Instance not running, cannot migrate")
590 self._CallMonitorCommand(instance_name, 'stop')
592 migrate_command = ('migrate -d tcp:%s:%s' %
593 (target, constants.KVM_MIGRATION_PORT))
594 self._CallMonitorCommand(instance_name, migrate_command)
596 info_command = 'info migrate'
599 result = self._CallMonitorCommand(instance_name, info_command)
600 match = self._MIGRATION_STATUS_RE.search(result.stdout)
602 raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
605 status = match.group(1)
606 if status == 'completed':
608 elif status == 'active':
610 elif status == 'failed' or status == 'cancelled':
612 self._CallMonitorCommand(instance_name, 'cont')
613 raise errors.HypervisorError("Migration %s at the kvm level" %
616 logging.info("KVM: unknown migration status '%s'" % status)
619 utils.KillProcess(pid)
620 self._RemoveInstanceRuntimeFiles(pidfile, instance.name)
622 def GetNodeInfo(self):
623 """Return information about the node.
625 This is just a wrapper over the base GetLinuxNodeInfo method.
627 @return: a dict with the following keys (values in MiB):
628 - memory_total: the total memory size on the node
629 - memory_free: the available memory on the node for instances
630 - memory_dom0: the memory used by the node itself, if available
633 return self.GetLinuxNodeInfo()
636 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
637 """Return a command for connecting to the console of an instance.
640 if hvparams[constants.HV_SERIAL_CONSOLE]:
641 # FIXME: The socat shell is not perfect. In particular the way we start
642 # it ctrl+c will close it, rather than being passed to the other end.
643 # On the other hand if we pass the option 'raw' (or ignbrk=1) there
644 # will be no way of exiting socat (except killing it from another shell)
645 # and ctrl+c doesn't work anyway, printing ^C rather than being
646 # interpreted by kvm. For now we'll leave it this way, which at least
647 # allows a minimal interaction and changes on the machine.
648 shell_command = ("%s STDIO,echo=0,icanon=0 UNIX-CONNECT:%s" %
649 (constants.SOCAT_PATH,
650 utils.ShellQuote(cls._InstanceSerial(instance.name))))
652 shell_command = "echo 'No serial shell for instance %s'" % instance.name
654 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
656 if instance.network_port > constants.VNC_BASE_PORT:
657 display = instance.network_port - constants.VNC_BASE_PORT
658 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
659 " (display: %d)'" % (vnc_bind_address,
660 instance.network_port,
662 shell_command = "%s; %s" % (vnc_command, shell_command)
667 """Verify the hypervisor.
669 Check that the binary exists.
672 if not os.path.exists(constants.KVM_PATH):
673 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
674 if not os.path.exists(constants.SOCAT_PATH):
675 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
679 def CheckParameterSyntax(cls, hvparams):
680 """Check the given parameters for validity.
683 @param hvparams: dictionary with parameter names/value
684 @raise errors.HypervisorError: when a parameter is not valid
687 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
689 kernel_path = hvparams[constants.HV_KERNEL_PATH]
691 if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
692 raise errors.HypervisorError("The kernel path must be an absolute path"
695 if not hvparams[constants.HV_ROOT_PATH]:
696 raise errors.HypervisorError("Need a root partition for the instance"
697 ", if a kernel is defined")
699 if hvparams[constants.HV_INITRD_PATH]:
700 if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
701 raise errors.HypervisorError("The initrd path must an absolute path"
704 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
706 if not utils.IsValidIP(vnc_bind_address):
707 if not os.path.isabs(vnc_bind_address):
708 raise errors.HypervisorError("The VNC bind address must be either"
709 " a valid IP address or an absolute"
710 " pathname. '%s' given" %
713 if hvparams[constants.HV_VNC_X509_VERIFY] and \
714 not hvparams[constants.HV_VNC_X509]:
715 raise errors.HypervisorError("%s must be defined, if %s is" %
716 (constants.HV_VNC_X509,
717 constants.HV_VNC_X509_VERIFY))
719 if hvparams[constants.HV_VNC_X509]:
720 if not os.path.isabs(hvparams[constants.HV_VNC_X509]):
721 raise errors.HypervisorError("The vnc x509 path must an absolute path"
724 iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
725 if iso_path and not os.path.isabs(iso_path):
726 raise errors.HypervisorError("The path to the CDROM image must be"
727 " an absolute path, if defined")
729 boot_order = hvparams[constants.HV_BOOT_ORDER]
730 if boot_order not in constants.HT_KVM_VALID_BO_TYPES:
731 raise errors.HypervisorError(\
732 "The boot order must be one of %s" %
733 utils.CommaJoin(constants.HT_KVM_VALID_BO_TYPES))
735 if boot_order == constants.HT_BO_CDROM and not iso_path:
736 raise errors.HypervisorError("Cannot boot from cdrom without an"
739 nic_type = hvparams[constants.HV_NIC_TYPE]
740 if nic_type not in constants.HT_KVM_VALID_NIC_TYPES:
741 raise errors.HypervisorError(\
742 "Invalid NIC type %s specified for the KVM"
743 " hypervisor. Please choose one of: %s" %
744 (nic_type, utils.CommaJoin(constants.HT_KVM_VALID_NIC_TYPES)))
745 elif (boot_order == constants.HT_BO_NETWORK and
746 nic_type == constants.HT_NIC_PARAVIRTUAL):
747 raise errors.HypervisorError("Cannot boot from a paravirtual NIC. Please"
748 " change the NIC type.")
750 disk_type = hvparams[constants.HV_DISK_TYPE]
751 if disk_type not in constants.HT_KVM_VALID_DISK_TYPES:
752 raise errors.HypervisorError(\
753 "Invalid disk type %s specified for the KVM"
754 " hypervisor. Please choose one of: %s" %
755 (disk_type, utils.CommaJoin(constants.HT_KVM_VALID_DISK_TYPES)))
757 mouse_type = hvparams[constants.HV_USB_MOUSE]
758 if mouse_type and mouse_type not in constants.HT_KVM_VALID_MOUSE_TYPES:
759 raise errors.HypervisorError(\
760 "Invalid usb mouse type %s specified for the KVM hypervisor. Please"
761 " choose one of %s" %
762 utils.CommaJoin(constants.HT_KVM_VALID_MOUSE_TYPES))
764 def ValidateParameters(self, hvparams):
765 """Check the given parameters for validity.
767 For the KVM hypervisor, this checks the existence of the
771 super(KVMHypervisor, self).ValidateParameters(hvparams)
773 kernel_path = hvparams[constants.HV_KERNEL_PATH]
774 if kernel_path and not os.path.isfile(kernel_path):
775 raise errors.HypervisorError("Instance kernel '%s' not found or"
776 " not a file" % kernel_path)
777 initrd_path = hvparams[constants.HV_INITRD_PATH]
778 if initrd_path and not os.path.isfile(initrd_path):
779 raise errors.HypervisorError("Instance initrd '%s' not found or"
780 " not a file" % initrd_path)
782 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
783 if vnc_bind_address and not utils.IsValidIP(vnc_bind_address) and \
784 not os.path.isdir(vnc_bind_address):
785 raise errors.HypervisorError("Instance vnc bind address must be either"
786 " an ip address or an existing directory")
788 vnc_x509 = hvparams[constants.HV_VNC_X509]
789 if vnc_x509 and not os.path.isdir(vnc_x509):
790 raise errors.HypervisorError("Instance vnc x509 path '%s' not found"
791 " or not a directory" % vnc_x509)
793 iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
794 if iso_path and not os.path.isfile(iso_path):
795 raise errors.HypervisorError("Instance cdrom image '%s' not found or"
796 " not a file" % iso_path)