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,
56 constants.HV_SERIAL_CONSOLE,
57 constants.HV_VNC_BIND_ADDRESS,
59 constants.HV_VNC_X509,
60 constants.HV_VNC_X509_VERIFY,
61 constants.HV_CDROM_IMAGE_PATH,
62 constants.HV_BOOT_ORDER,
65 _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
69 hv_base.BaseHypervisor.__init__(self)
70 # Let's make sure the directories we need exist, even if the RUN_DIR lives
71 # in a tmpfs filesystem or has been otherwise wiped out.
72 for mydir in self._DIRS:
73 if not os.path.exists(mydir):
76 def _InstancePidAlive(self, instance_name):
77 """Returns the instance pid and pidfile
80 pidfile = "%s/%s" % (self._PIDS_DIR, instance_name)
81 pid = utils.ReadPidFile(pidfile)
82 alive = utils.IsProcessAlive(pid)
84 return (pidfile, pid, alive)
87 def _InstanceMonitor(cls, instance_name):
88 """Returns the instance monitor socket name
91 return '%s/%s.monitor' % (cls._CTRL_DIR, instance_name)
94 def _InstanceSerial(cls, instance_name):
95 """Returns the instance serial socket name
98 return '%s/%s.serial' % (cls._CTRL_DIR, instance_name)
101 def _InstanceKVMRuntime(cls, instance_name):
102 """Returns the instance KVM runtime filename
105 return '%s/%s.runtime' % (cls._CONF_DIR, instance_name)
107 def _WriteNetScript(self, instance, seq, nic):
108 """Write a script to connect a net interface to the proper bridge.
110 This can be used by any qemu-type hypervisor.
112 @param instance: instance we're acting on
113 @type instance: instance object
114 @param seq: nic sequence number
116 @param nic: nic we're acting on
117 @type nic: nic object
118 @return: netscript file name
123 script.write("#!/bin/sh\n")
124 script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
125 script.write("export INSTANCE=%s\n" % instance.name)
126 script.write("export MAC=%s\n" % nic.mac)
127 script.write("export IP=%s\n" % nic.ip)
128 script.write("export BRIDGE=%s\n" % nic.bridge)
129 script.write("export INTERFACE=$1\n")
130 # TODO: make this configurable at ./configure time
131 script.write("if [ -x /etc/ganeti/kvm-vif-bridge ]; then\n")
132 script.write(" # Execute the user-specific vif file\n")
133 script.write(" /etc/ganeti/kvm-vif-bridge\n")
134 script.write("else\n")
135 script.write(" # Connect the interface to the bridge\n")
136 script.write(" /sbin/ifconfig $INTERFACE 0.0.0.0 up\n")
137 script.write(" /usr/sbin/brctl addif $BRIDGE $INTERFACE\n")
138 script.write("fi\n\n")
139 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
140 # mounted noexec sometimes, so we'll have to find another place.
141 (tmpfd, tmpfile_name) = tempfile.mkstemp()
142 tmpfile = os.fdopen(tmpfd, 'w')
143 tmpfile.write(script.getvalue())
145 os.chmod(tmpfile_name, 0755)
148 def ListInstances(self):
149 """Get the list of running instances.
151 We can do this by listing our live instances directory and
152 checking whether the associated kvm process is still alive.
156 for name in os.listdir(self._PIDS_DIR):
157 filename = "%s/%s" % (self._PIDS_DIR, name)
158 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
162 def GetInstanceInfo(self, instance_name):
163 """Get instance properties.
165 @param instance_name: the instance name
167 @return: tuple (name, id, memory, vcpus, stat, times)
170 pidfile, pid, alive = self._InstancePidAlive(instance_name)
174 cmdline_file = "/proc/%s/cmdline" % pid
176 fh = open(cmdline_file, 'r')
181 except EnvironmentError, err:
182 raise errors.HypervisorError("Failed to list instance %s: %s" %
183 (instance_name, err))
190 arg_list = cmdline.split('\x00')
192 arg = arg_list.pop(0)
194 memory = arg_list.pop(0)
196 vcpus = arg_list.pop(0)
198 return (instance_name, pid, memory, vcpus, stat, times)
200 def GetAllInstancesInfo(self):
201 """Get properties of all instances.
203 @return: list of tuples (name, id, memory, vcpus, stat, times)
207 for name in os.listdir(self._PIDS_DIR):
208 filename = "%s/%s" % (self._PIDS_DIR, name)
209 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
211 info = self.GetInstanceInfo(name)
212 except errors.HypervisorError, err:
219 def _GenerateKVMRuntime(self, instance, block_devices, extra_args):
220 """Generate KVM information to start an instance.
223 pidfile, pid, alive = self._InstancePidAlive(instance.name)
224 kvm = constants.KVM_PATH
226 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
227 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
228 kvm_cmd.extend(['-pidfile', pidfile])
229 # used just by the vnc server, if enabled
230 kvm_cmd.extend(['-name', instance.name])
231 kvm_cmd.extend(['-daemonize'])
232 if not instance.hvparams[constants.HV_ACPI]:
233 kvm_cmd.extend(['-no-acpi'])
235 boot_disk = (instance.hvparams[constants.HV_BOOT_ORDER] == "disk")
236 boot_cdrom = (instance.hvparams[constants.HV_BOOT_ORDER] == "cdrom")
237 for cfdev, dev_path in block_devices:
238 if cfdev.mode != constants.DISK_RDWR:
239 raise errors.HypervisorError("Instance has read-only disks which"
240 " are not supported by KVM")
241 # TODO: handle FD_LOOP and FD_BLKTAP (?)
243 boot_val = ',boot=on'
248 # TODO: handle different if= types
249 if_val = ',if=virtio'
251 drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
252 kvm_cmd.extend(['-drive', drive_val])
254 iso_image = instance.hvparams[constants.HV_CDROM_IMAGE_PATH]
256 options = ',format=raw,if=virtio,media=cdrom'
258 options = '%s,boot=on' % options
259 drive_val = 'file=%s%s' % (iso_image, options)
260 kvm_cmd.extend(['-drive', drive_val])
262 kernel_path = instance.hvparams[constants.HV_KERNEL_PATH]
264 kvm_cmd.extend(['-kernel', kernel_path])
265 initrd_path = instance.hvparams[constants.HV_INITRD_PATH]
267 kvm_cmd.extend(['-initrd', initrd_path])
268 root_append = 'root=%s ro' % instance.hvparams[constants.HV_ROOT_PATH]
269 if instance.hvparams[constants.HV_SERIAL_CONSOLE]:
270 kvm_cmd.extend(['-append', 'console=ttyS0,38400 %s' % root_append])
272 kvm_cmd.extend(['-append', root_append])
274 # FIXME: handle vnc password
275 vnc_bind_address = instance.hvparams[constants.HV_VNC_BIND_ADDRESS]
277 kvm_cmd.extend(['-usbdevice', 'tablet'])
278 if utils.IsValidIP(vnc_bind_address):
279 if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
280 display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
281 if vnc_bind_address == '0.0.0.0':
282 vnc_arg = ':%d' % (display)
284 vnc_arg = '%s:%d' % (constants.HV_VNC_BIND_ADDRESS, display)
286 logging.error("Network port is not a valid VNC display (%d < %d)."
287 " Not starting VNC" %
288 (instance.network_port,
289 constants.HT_HVM_VNC_BASE_PORT))
292 # Only allow tls and other option when not binding to a file, for now.
293 # kvm/qemu gets confused otherwise about the filename to use.
295 if instance.hvparams[constants.HV_VNC_TLS]:
296 vnc_append = '%s,tls' % vnc_append
297 if instance.hvparams[constants.HV_VNC_X509_VERIFY]:
298 vnc_append = '%s,x509verify=%s' % (vnc_append,
299 instance.hvparams[constants.HV_VNC_X509])
300 elif instance.hvparams[constants.HV_VNC_X509]:
301 vnc_append = '%s,x509=%s' % (vnc_append,
302 instance.hvparams[constants.HV_VNC_X509])
303 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
306 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
308 kvm_cmd.extend(['-vnc', vnc_arg])
310 kvm_cmd.extend(['-nographic'])
312 monitor_dev = 'unix:%s,server,nowait' % \
313 self._InstanceMonitor(instance.name)
314 kvm_cmd.extend(['-monitor', monitor_dev])
315 if instance.hvparams[constants.HV_SERIAL_CONSOLE]:
316 serial_dev = 'unix:%s,server,nowait' % self._InstanceSerial(instance.name)
317 kvm_cmd.extend(['-serial', serial_dev])
319 kvm_cmd.extend(['-serial', 'none'])
321 # Save the current instance nics, but defer their expansion as parameters,
322 # as we'll need to generate executable temp files for them.
323 kvm_nics = instance.nics
325 return (kvm_cmd, kvm_nics)
327 def _WriteKVMRuntime(self, instance_name, data):
328 """Write an instance's KVM runtime
332 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
334 except EnvironmentError, err:
335 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
337 def _ReadKVMRuntime(self, instance_name):
338 """Read an instance's KVM runtime
342 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
343 except EnvironmentError, err:
344 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
347 def _SaveKVMRuntime(self, instance, kvm_runtime):
348 """Save an instance's KVM runtime
351 kvm_cmd, kvm_nics = kvm_runtime
352 serialized_nics = [nic.ToDict() for nic in kvm_nics]
353 serialized_form = serializer.Dump((kvm_cmd, serialized_nics))
354 self._WriteKVMRuntime(instance.name, serialized_form)
356 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
357 """Load an instance's KVM runtime
360 if not serialized_runtime:
361 serialized_runtime = self._ReadKVMRuntime(instance.name)
362 loaded_runtime = serializer.Load(serialized_runtime)
363 kvm_cmd, serialized_nics = loaded_runtime
364 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
365 return (kvm_cmd, kvm_nics)
367 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
368 """Execute a KVM cmd, after completing it with some last minute data
370 @type incoming: tuple of strings
371 @param incoming: (target_host_ip, port)
374 pidfile, pid, alive = self._InstancePidAlive(instance.name)
376 raise errors.HypervisorError("Failed to start instance %s: %s" %
377 (instance.name, "already running"))
381 kvm_cmd, kvm_nics = kvm_runtime
384 kvm_cmd.extend(['-net', 'none'])
386 for nic_seq, nic in enumerate(kvm_nics):
387 nic_val = "nic,macaddr=%s,model=virtio" % nic.mac
388 script = self._WriteNetScript(instance, nic_seq, nic)
389 kvm_cmd.extend(['-net', nic_val])
390 kvm_cmd.extend(['-net', 'tap,script=%s' % script])
391 temp_files.append(script)
394 target, port = incoming
395 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
397 result = utils.RunCmd(kvm_cmd)
399 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
400 (instance.name, result.fail_reason,
403 if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
404 raise errors.HypervisorError("Failed to start instance %s: %s" %
407 for filename in temp_files:
408 utils.RemoveFile(filename)
410 def StartInstance(self, instance, block_devices, extra_args):
411 """Start an instance.
414 pidfile, pid, alive = self._InstancePidAlive(instance.name)
416 raise errors.HypervisorError("Failed to start instance %s: %s" %
417 (instance.name, "already running"))
419 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices, extra_args)
420 self._SaveKVMRuntime(instance, kvm_runtime)
421 self._ExecuteKVMRuntime(instance, kvm_runtime)
423 def _CallMonitorCommand(self, instance_name, command):
424 """Invoke a command on the instance monitor.
427 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
428 (utils.ShellQuote(command),
429 constants.SOCAT_PATH,
430 utils.ShellQuote(self._InstanceMonitor(instance_name))))
431 result = utils.RunCmd(socat)
433 msg = ("Failed to send command '%s' to instance %s."
434 " output: %s, error: %s, fail_reason: %s" %
435 (instance.name, result.stdout, result.stderr, result.fail_reason))
436 raise errors.HypervisorError(msg)
440 def _RetryInstancePowerdown(self, instance, pid, timeout=30):
441 """Wait for an instance to power down.
444 # Wait up to $timeout seconds
445 end = time.time() + timeout
447 while time.time() < end and utils.IsProcessAlive(pid):
448 self._CallMonitorCommand(instance.name, 'system_powerdown')
450 # Make wait time longer for next try
454 def StopInstance(self, instance, force=False):
458 pidfile, pid, alive = self._InstancePidAlive(instance.name)
459 if pid > 0 and alive:
460 if force or not instance.hvparams[constants.HV_ACPI]:
461 utils.KillProcess(pid)
463 self._RetryInstancePowerdown(instance, pid)
465 if not utils.IsProcessAlive(pid):
466 utils.RemoveFile(pidfile)
467 utils.RemoveFile(self._InstanceMonitor(instance.name))
468 utils.RemoveFile(self._InstanceSerial(instance.name))
469 utils.RemoveFile(self._InstanceKVMRuntime(instance.name))
474 def RebootInstance(self, instance):
475 """Reboot an instance.
478 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
479 # socket the instance will stop, but now power up again. So we'll resort
480 # to shutdown and restart.
481 pidfile, pid, alive = self._InstancePidAlive(instance.name)
483 raise errors.HypervisorError("Failed to reboot instance %s: not running" %
485 # StopInstance will delete the saved KVM runtime so:
486 # ...first load it...
487 kvm_runtime = self._LoadKVMRuntime(instance)
488 # ...now we can safely call StopInstance...
489 if not self.StopInstance(instance):
490 self.StopInstance(instance, force=True)
491 # ...and finally we can save it again, and execute it...
492 self._SaveKVMRuntime(instance, kvm_runtime)
493 self._ExecuteKVMRuntime(instance, kvm_runtime)
495 def MigrationInfo(self, instance):
496 """Get instance information to perform a migration.
498 @type instance: L{objects.Instance}
499 @param instance: instance to be migrated
501 @return: content of the KVM runtime file
504 return self._ReadKVMRuntime(instance.name)
506 def AcceptInstance(self, instance, info, target):
507 """Prepare to accept an instance.
509 @type instance: L{objects.Instance}
510 @param instance: instance to be accepted
512 @param info: content of the KVM runtime file on the source node
514 @param target: target host (usually ip), on this node
517 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
518 incoming_address = (target, constants.KVM_MIGRATION_PORT)
519 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
521 def FinalizeMigration(self, instance, info, success):
522 """Finalize an instance migration.
524 Stop the incoming mode KVM.
526 @type instance: L{objects.Instance}
527 @param instance: instance whose migration is being aborted
531 self._WriteKVMRuntime(instance.name, info)
533 self.StopInstance(instance, force=True)
535 def MigrateInstance(self, instance_name, target, live):
536 """Migrate an instance to a target node.
538 The migration will not be attempted if the instance is not
541 @type instance_name: string
542 @param instance_name: name of the instance to be migrated
544 @param target: ip address of the target node
546 @param live: perform a live migration
549 pidfile, pid, alive = self._InstancePidAlive(instance_name)
551 raise errors.HypervisorError("Instance not running, cannot migrate")
554 self._CallMonitorCommand(instance_name, 'stop')
556 migrate_command = ('migrate -d tcp:%s:%s' %
557 (target, constants.KVM_MIGRATION_PORT))
558 self._CallMonitorCommand(instance_name, migrate_command)
560 info_command = 'info migrate'
563 result = self._CallMonitorCommand(instance_name, info_command)
564 match = self._MIGRATION_STATUS_RE.search(result.stdout)
566 raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
569 status = match.group(1)
570 if status == 'completed':
572 elif status == 'active':
574 elif status == 'failed' or status == 'cancelled':
576 self._CallMonitorCommand(instance_name, 'cont')
577 raise errors.HypervisorError("Migration %s at the kvm level" %
580 logging.info("KVM: unknown migration status '%s'" % status)
583 utils.KillProcess(pid)
584 utils.RemoveFile(pidfile)
585 utils.RemoveFile(self._InstanceMonitor(instance_name))
586 utils.RemoveFile(self._InstanceSerial(instance_name))
587 utils.RemoveFile(self._InstanceKVMRuntime(instance_name))
589 def GetNodeInfo(self):
590 """Return information about the node.
592 @return: a dict with the following keys (values in MiB):
593 - memory_total: the total memory size on the node
594 - memory_free: the available memory on the node for instances
595 - memory_dom0: the memory used by the node itself, if available
598 # global ram usage from the xm info command
601 # note: in xen 3, memory has changed to total_memory
603 fh = file("/proc/meminfo")
605 data = fh.readlines()
608 except EnvironmentError, err:
609 raise errors.HypervisorError("Failed to list node info: %s" % err)
614 splitfields = line.split(":", 1)
616 if len(splitfields) > 1:
617 key = splitfields[0].strip()
618 val = splitfields[1].strip()
619 if key == 'MemTotal':
620 result['memory_total'] = int(val.split()[0])/1024
621 elif key in ('MemFree', 'Buffers', 'Cached'):
622 sum_free += int(val.split()[0])/1024
623 elif key == 'Active':
624 result['memory_dom0'] = int(val.split()[0])/1024
625 result['memory_free'] = sum_free
629 fh = open("/proc/cpuinfo")
631 cpu_total = len(re.findall("(?m)^processor\s*:\s*[0-9]+\s*$",
635 except EnvironmentError, err:
636 raise errors.HypervisorError("Failed to list node info: %s" % err)
637 result['cpu_total'] = cpu_total
642 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
643 """Return a command for connecting to the console of an instance.
646 if hvparams[constants.HV_SERIAL_CONSOLE]:
647 # FIXME: The socat shell is not perfect. In particular the way we start
648 # it ctrl+c will close it, rather than being passed to the other end.
649 # On the other hand if we pass the option 'raw' (or ignbrk=1) there
650 # will be no way of exiting socat (except killing it from another shell)
651 # and ctrl+c doesn't work anyway, printing ^C rather than being
652 # interpreted by kvm. For now we'll leave it this way, which at least
653 # allows a minimal interaction and changes on the machine.
654 shell_command = ("%s STDIO,echo=0,icanon=0 UNIX-CONNECT:%s" %
655 (constants.SOCAT_PATH,
656 utils.ShellQuote(cls._InstanceSerial(instance.name))))
658 shell_command = "echo 'No serial shell for instance %s'" % instance.name
660 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
662 if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
663 display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
664 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
665 " (display: %d)'" % (vnc_bind_address,
666 instance.network_port,
668 shell_command = "%s; %s" % (vnc_command, shell_command)
673 """Verify the hypervisor.
675 Check that the binary exists.
678 if not os.path.exists(constants.KVM_PATH):
679 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
680 if not os.path.exists(constants.SOCAT_PATH):
681 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
685 def CheckParameterSyntax(cls, hvparams):
686 """Check the given parameters for validity.
688 For the KVM hypervisor, this only check the existence of the
692 @param hvparams: dictionary with parameter names/value
693 @raise errors.HypervisorError: when a parameter is not valid
696 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
698 kernel_path = hvparams[constants.HV_KERNEL_PATH]
700 if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
701 raise errors.HypervisorError("The kernel path must be an absolute path"
704 if not hvparams[constants.HV_ROOT_PATH]:
705 raise errors.HypervisorError("Need a root partition for the instance"
706 ", if a kernel is defined")
708 if hvparams[constants.HV_INITRD_PATH]:
709 if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
710 raise errors.HypervisorError("The initrd path must an absolute path"
713 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
715 if not utils.IsValidIP(vnc_bind_address):
716 if not os.path.isabs(vnc_bind_address):
717 raise errors.HypervisorError("The VNC bind address must be either"
718 " a valid IP address or an absolute"
719 " pathname. '%s' given" %
722 if hvparams[constants.HV_VNC_X509_VERIFY] and \
723 not hvparams[constants.HV_VNC_X509]:
724 raise errors.HypervisorError("%s must be defined, if %s is" %
725 (constants.HV_VNC_X509,
726 constants.HV_VNC_X509_VERIFY))
728 if hvparams[constants.HV_VNC_X509]:
729 if not os.path.isabs(hvparams[constants.HV_VNC_X509]):
730 raise errors.HypervisorError("The vnc x509 path must an absolute path"
733 iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
734 if iso_path and not os.path.isabs(iso_path):
735 raise errors.HypervisorError("The path to the CDROM image must be"
736 " an absolute path, if defined")
738 boot_order = hvparams[constants.HV_BOOT_ORDER]
739 if boot_order not in ('cdrom', 'disk'):
740 raise errors.HypervisorError("The boot order must be 'cdrom' or 'disk'")
742 if boot_order == 'cdrom' and not iso_path:
743 raise errors.HypervisorError("Cannot boot from cdrom without an ISO path")
745 def ValidateParameters(self, hvparams):
746 """Check the given parameters for validity.
748 For the KVM hypervisor, this checks the existence of the
752 super(KVMHypervisor, self).ValidateParameters(hvparams)
754 kernel_path = hvparams[constants.HV_KERNEL_PATH]
755 if kernel_path and not os.path.isfile(kernel_path):
756 raise errors.HypervisorError("Instance kernel '%s' not found or"
757 " not a file" % kernel_path)
758 initrd_path = hvparams[constants.HV_INITRD_PATH]
759 if initrd_path and not os.path.isfile(initrd_path):
760 raise errors.HypervisorError("Instance initrd '%s' not found or"
761 " not a file" % initrd_path)
763 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
764 if vnc_bind_address and not utils.IsValidIP(vnc_bind_address) and \
765 not os.path.isdir(vnc_bind_address):
766 raise errors.HypervisorError("Instance vnc bind address must be either"
767 " an ip address or an existing directory")
769 vnc_x509 = hvparams[constants.HV_VNC_X509]
770 if vnc_x509 and not os.path.isdir(vnc_x509):
771 raise errors.HypervisorError("Instance vnc x509 path '%s' not found"
772 " or not a directory" % vnc_x509)
774 iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
775 if iso_path and not os.path.isfile(iso_path):
776 raise errors.HypervisorError("Instance cdrom image '%s' not found or"
777 " not a file" % iso_path)