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 kvm_cmd.extend(['-boot', 'c'])
244 boot_val = ',boot=on'
249 # TODO: handle different if= types
250 if_val = ',if=virtio'
252 drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
253 kvm_cmd.extend(['-drive', drive_val])
255 iso_image = instance.hvparams[constants.HV_CDROM_IMAGE_PATH]
257 options = ',format=raw,media=cdrom'
259 kvm_cmd.extend(['-boot', 'd'])
260 options = '%s,boot=on' % options
262 options = '%s,if=virtio' % options
263 drive_val = 'file=%s%s' % (iso_image, options)
264 kvm_cmd.extend(['-drive', drive_val])
266 kernel_path = instance.hvparams[constants.HV_KERNEL_PATH]
268 kvm_cmd.extend(['-kernel', kernel_path])
269 initrd_path = instance.hvparams[constants.HV_INITRD_PATH]
271 kvm_cmd.extend(['-initrd', initrd_path])
272 root_append = 'root=%s ro' % instance.hvparams[constants.HV_ROOT_PATH]
273 if instance.hvparams[constants.HV_SERIAL_CONSOLE]:
274 kvm_cmd.extend(['-append', 'console=ttyS0,38400 %s' % root_append])
276 kvm_cmd.extend(['-append', root_append])
278 # FIXME: handle vnc password
279 vnc_bind_address = instance.hvparams[constants.HV_VNC_BIND_ADDRESS]
281 kvm_cmd.extend(['-usbdevice', 'tablet'])
282 if utils.IsValidIP(vnc_bind_address):
283 if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
284 display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
285 if vnc_bind_address == '0.0.0.0':
286 vnc_arg = ':%d' % (display)
288 vnc_arg = '%s:%d' % (constants.HV_VNC_BIND_ADDRESS, display)
290 logging.error("Network port is not a valid VNC display (%d < %d)."
291 " Not starting VNC" %
292 (instance.network_port,
293 constants.HT_HVM_VNC_BASE_PORT))
296 # Only allow tls and other option when not binding to a file, for now.
297 # kvm/qemu gets confused otherwise about the filename to use.
299 if instance.hvparams[constants.HV_VNC_TLS]:
300 vnc_append = '%s,tls' % vnc_append
301 if instance.hvparams[constants.HV_VNC_X509_VERIFY]:
302 vnc_append = '%s,x509verify=%s' % (vnc_append,
303 instance.hvparams[constants.HV_VNC_X509])
304 elif instance.hvparams[constants.HV_VNC_X509]:
305 vnc_append = '%s,x509=%s' % (vnc_append,
306 instance.hvparams[constants.HV_VNC_X509])
307 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
310 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
312 kvm_cmd.extend(['-vnc', vnc_arg])
314 kvm_cmd.extend(['-nographic'])
316 monitor_dev = 'unix:%s,server,nowait' % \
317 self._InstanceMonitor(instance.name)
318 kvm_cmd.extend(['-monitor', monitor_dev])
319 if instance.hvparams[constants.HV_SERIAL_CONSOLE]:
320 serial_dev = 'unix:%s,server,nowait' % self._InstanceSerial(instance.name)
321 kvm_cmd.extend(['-serial', serial_dev])
323 kvm_cmd.extend(['-serial', 'none'])
325 # Save the current instance nics, but defer their expansion as parameters,
326 # as we'll need to generate executable temp files for them.
327 kvm_nics = instance.nics
329 return (kvm_cmd, kvm_nics)
331 def _WriteKVMRuntime(self, instance_name, data):
332 """Write an instance's KVM runtime
336 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
338 except EnvironmentError, err:
339 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
341 def _ReadKVMRuntime(self, instance_name):
342 """Read an instance's KVM runtime
346 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
347 except EnvironmentError, err:
348 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
351 def _SaveKVMRuntime(self, instance, kvm_runtime):
352 """Save an instance's KVM runtime
355 kvm_cmd, kvm_nics = kvm_runtime
356 serialized_nics = [nic.ToDict() for nic in kvm_nics]
357 serialized_form = serializer.Dump((kvm_cmd, serialized_nics))
358 self._WriteKVMRuntime(instance.name, serialized_form)
360 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
361 """Load an instance's KVM runtime
364 if not serialized_runtime:
365 serialized_runtime = self._ReadKVMRuntime(instance.name)
366 loaded_runtime = serializer.Load(serialized_runtime)
367 kvm_cmd, serialized_nics = loaded_runtime
368 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
369 return (kvm_cmd, kvm_nics)
371 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
372 """Execute a KVM cmd, after completing it with some last minute data
374 @type incoming: tuple of strings
375 @param incoming: (target_host_ip, port)
378 pidfile, pid, alive = self._InstancePidAlive(instance.name)
380 raise errors.HypervisorError("Failed to start instance %s: %s" %
381 (instance.name, "already running"))
385 kvm_cmd, kvm_nics = kvm_runtime
388 kvm_cmd.extend(['-net', 'none'])
390 for nic_seq, nic in enumerate(kvm_nics):
391 nic_val = "nic,macaddr=%s,model=virtio" % nic.mac
392 script = self._WriteNetScript(instance, nic_seq, nic)
393 kvm_cmd.extend(['-net', nic_val])
394 kvm_cmd.extend(['-net', 'tap,script=%s' % script])
395 temp_files.append(script)
398 target, port = incoming
399 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
401 result = utils.RunCmd(kvm_cmd)
403 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
404 (instance.name, result.fail_reason,
407 if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
408 raise errors.HypervisorError("Failed to start instance %s: %s" %
411 for filename in temp_files:
412 utils.RemoveFile(filename)
414 def StartInstance(self, instance, block_devices, extra_args):
415 """Start an instance.
418 pidfile, pid, alive = self._InstancePidAlive(instance.name)
420 raise errors.HypervisorError("Failed to start instance %s: %s" %
421 (instance.name, "already running"))
423 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices, extra_args)
424 self._SaveKVMRuntime(instance, kvm_runtime)
425 self._ExecuteKVMRuntime(instance, kvm_runtime)
427 def _CallMonitorCommand(self, instance_name, command):
428 """Invoke a command on the instance monitor.
431 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
432 (utils.ShellQuote(command),
433 constants.SOCAT_PATH,
434 utils.ShellQuote(self._InstanceMonitor(instance_name))))
435 result = utils.RunCmd(socat)
437 msg = ("Failed to send command '%s' to instance %s."
438 " output: %s, error: %s, fail_reason: %s" %
439 (instance.name, result.stdout, result.stderr, result.fail_reason))
440 raise errors.HypervisorError(msg)
444 def _RetryInstancePowerdown(self, instance, pid, timeout=30):
445 """Wait for an instance to power down.
448 # Wait up to $timeout seconds
449 end = time.time() + timeout
451 while time.time() < end and utils.IsProcessAlive(pid):
452 self._CallMonitorCommand(instance.name, 'system_powerdown')
454 # Make wait time longer for next try
458 def StopInstance(self, instance, force=False):
462 pidfile, pid, alive = self._InstancePidAlive(instance.name)
463 if pid > 0 and alive:
464 if force or not instance.hvparams[constants.HV_ACPI]:
465 utils.KillProcess(pid)
467 self._RetryInstancePowerdown(instance, pid)
469 if not utils.IsProcessAlive(pid):
470 utils.RemoveFile(pidfile)
471 utils.RemoveFile(self._InstanceMonitor(instance.name))
472 utils.RemoveFile(self._InstanceSerial(instance.name))
473 utils.RemoveFile(self._InstanceKVMRuntime(instance.name))
478 def RebootInstance(self, instance):
479 """Reboot an instance.
482 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
483 # socket the instance will stop, but now power up again. So we'll resort
484 # to shutdown and restart.
485 pidfile, pid, alive = self._InstancePidAlive(instance.name)
487 raise errors.HypervisorError("Failed to reboot instance %s: not running" %
489 # StopInstance will delete the saved KVM runtime so:
490 # ...first load it...
491 kvm_runtime = self._LoadKVMRuntime(instance)
492 # ...now we can safely call StopInstance...
493 if not self.StopInstance(instance):
494 self.StopInstance(instance, force=True)
495 # ...and finally we can save it again, and execute it...
496 self._SaveKVMRuntime(instance, kvm_runtime)
497 self._ExecuteKVMRuntime(instance, kvm_runtime)
499 def MigrationInfo(self, instance):
500 """Get instance information to perform a migration.
502 @type instance: L{objects.Instance}
503 @param instance: instance to be migrated
505 @return: content of the KVM runtime file
508 return self._ReadKVMRuntime(instance.name)
510 def AcceptInstance(self, instance, info, target):
511 """Prepare to accept an instance.
513 @type instance: L{objects.Instance}
514 @param instance: instance to be accepted
516 @param info: content of the KVM runtime file on the source node
518 @param target: target host (usually ip), on this node
521 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
522 incoming_address = (target, constants.KVM_MIGRATION_PORT)
523 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
525 def FinalizeMigration(self, instance, info, success):
526 """Finalize an instance migration.
528 Stop the incoming mode KVM.
530 @type instance: L{objects.Instance}
531 @param instance: instance whose migration is being aborted
535 self._WriteKVMRuntime(instance.name, info)
537 self.StopInstance(instance, force=True)
539 def MigrateInstance(self, instance_name, target, live):
540 """Migrate an instance to a target node.
542 The migration will not be attempted if the instance is not
545 @type instance_name: string
546 @param instance_name: name of the instance to be migrated
548 @param target: ip address of the target node
550 @param live: perform a live migration
553 pidfile, pid, alive = self._InstancePidAlive(instance_name)
555 raise errors.HypervisorError("Instance not running, cannot migrate")
558 self._CallMonitorCommand(instance_name, 'stop')
560 migrate_command = ('migrate -d tcp:%s:%s' %
561 (target, constants.KVM_MIGRATION_PORT))
562 self._CallMonitorCommand(instance_name, migrate_command)
564 info_command = 'info migrate'
567 result = self._CallMonitorCommand(instance_name, info_command)
568 match = self._MIGRATION_STATUS_RE.search(result.stdout)
570 raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
573 status = match.group(1)
574 if status == 'completed':
576 elif status == 'active':
578 elif status == 'failed' or status == 'cancelled':
580 self._CallMonitorCommand(instance_name, 'cont')
581 raise errors.HypervisorError("Migration %s at the kvm level" %
584 logging.info("KVM: unknown migration status '%s'" % status)
587 utils.KillProcess(pid)
588 utils.RemoveFile(pidfile)
589 utils.RemoveFile(self._InstanceMonitor(instance_name))
590 utils.RemoveFile(self._InstanceSerial(instance_name))
591 utils.RemoveFile(self._InstanceKVMRuntime(instance_name))
593 def GetNodeInfo(self):
594 """Return information about the node.
596 @return: a dict with the following keys (values in MiB):
597 - memory_total: the total memory size on the node
598 - memory_free: the available memory on the node for instances
599 - memory_dom0: the memory used by the node itself, if available
602 # global ram usage from the xm info command
605 # note: in xen 3, memory has changed to total_memory
607 fh = file("/proc/meminfo")
609 data = fh.readlines()
612 except EnvironmentError, err:
613 raise errors.HypervisorError("Failed to list node info: %s" % err)
618 splitfields = line.split(":", 1)
620 if len(splitfields) > 1:
621 key = splitfields[0].strip()
622 val = splitfields[1].strip()
623 if key == 'MemTotal':
624 result['memory_total'] = int(val.split()[0])/1024
625 elif key in ('MemFree', 'Buffers', 'Cached'):
626 sum_free += int(val.split()[0])/1024
627 elif key == 'Active':
628 result['memory_dom0'] = int(val.split()[0])/1024
629 result['memory_free'] = sum_free
633 fh = open("/proc/cpuinfo")
635 cpu_total = len(re.findall("(?m)^processor\s*:\s*[0-9]+\s*$",
639 except EnvironmentError, err:
640 raise errors.HypervisorError("Failed to list node info: %s" % err)
641 result['cpu_total'] = cpu_total
646 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
647 """Return a command for connecting to the console of an instance.
650 if hvparams[constants.HV_SERIAL_CONSOLE]:
651 # FIXME: The socat shell is not perfect. In particular the way we start
652 # it ctrl+c will close it, rather than being passed to the other end.
653 # On the other hand if we pass the option 'raw' (or ignbrk=1) there
654 # will be no way of exiting socat (except killing it from another shell)
655 # and ctrl+c doesn't work anyway, printing ^C rather than being
656 # interpreted by kvm. For now we'll leave it this way, which at least
657 # allows a minimal interaction and changes on the machine.
658 shell_command = ("%s STDIO,echo=0,icanon=0 UNIX-CONNECT:%s" %
659 (constants.SOCAT_PATH,
660 utils.ShellQuote(cls._InstanceSerial(instance.name))))
662 shell_command = "echo 'No serial shell for instance %s'" % instance.name
664 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
666 if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
667 display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
668 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
669 " (display: %d)'" % (vnc_bind_address,
670 instance.network_port,
672 shell_command = "%s; %s" % (vnc_command, shell_command)
677 """Verify the hypervisor.
679 Check that the binary exists.
682 if not os.path.exists(constants.KVM_PATH):
683 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
684 if not os.path.exists(constants.SOCAT_PATH):
685 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
689 def CheckParameterSyntax(cls, hvparams):
690 """Check the given parameters for validity.
692 For the KVM hypervisor, this only check the existence of the
696 @param hvparams: dictionary with parameter names/value
697 @raise errors.HypervisorError: when a parameter is not valid
700 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
702 kernel_path = hvparams[constants.HV_KERNEL_PATH]
704 if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
705 raise errors.HypervisorError("The kernel path must be an absolute path"
708 if not hvparams[constants.HV_ROOT_PATH]:
709 raise errors.HypervisorError("Need a root partition for the instance"
710 ", if a kernel is defined")
712 if hvparams[constants.HV_INITRD_PATH]:
713 if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
714 raise errors.HypervisorError("The initrd path must an absolute path"
717 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
719 if not utils.IsValidIP(vnc_bind_address):
720 if not os.path.isabs(vnc_bind_address):
721 raise errors.HypervisorError("The VNC bind address must be either"
722 " a valid IP address or an absolute"
723 " pathname. '%s' given" %
726 if hvparams[constants.HV_VNC_X509_VERIFY] and \
727 not hvparams[constants.HV_VNC_X509]:
728 raise errors.HypervisorError("%s must be defined, if %s is" %
729 (constants.HV_VNC_X509,
730 constants.HV_VNC_X509_VERIFY))
732 if hvparams[constants.HV_VNC_X509]:
733 if not os.path.isabs(hvparams[constants.HV_VNC_X509]):
734 raise errors.HypervisorError("The vnc x509 path must an absolute path"
737 iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
738 if iso_path and not os.path.isabs(iso_path):
739 raise errors.HypervisorError("The path to the CDROM image must be"
740 " an absolute path, if defined")
742 boot_order = hvparams[constants.HV_BOOT_ORDER]
743 if boot_order not in ('cdrom', 'disk'):
744 raise errors.HypervisorError("The boot order must be 'cdrom' or 'disk'")
746 if boot_order == 'cdrom' and not iso_path:
747 raise errors.HypervisorError("Cannot boot from cdrom without an ISO path")
749 def ValidateParameters(self, hvparams):
750 """Check the given parameters for validity.
752 For the KVM hypervisor, this checks the existence of the
756 super(KVMHypervisor, self).ValidateParameters(hvparams)
758 kernel_path = hvparams[constants.HV_KERNEL_PATH]
759 if kernel_path and not os.path.isfile(kernel_path):
760 raise errors.HypervisorError("Instance kernel '%s' not found or"
761 " not a file" % kernel_path)
762 initrd_path = hvparams[constants.HV_INITRD_PATH]
763 if initrd_path and not os.path.isfile(initrd_path):
764 raise errors.HypervisorError("Instance initrd '%s' not found or"
765 " not a file" % initrd_path)
767 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
768 if vnc_bind_address and not utils.IsValidIP(vnc_bind_address) and \
769 not os.path.isdir(vnc_bind_address):
770 raise errors.HypervisorError("Instance vnc bind address must be either"
771 " an ip address or an existing directory")
773 vnc_x509 = hvparams[constants.HV_VNC_X509]
774 if vnc_x509 and not os.path.isdir(vnc_x509):
775 raise errors.HypervisorError("Instance vnc x509 path '%s' not found"
776 " or not a directory" % vnc_x509)
778 iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
779 if iso_path and not os.path.isfile(iso_path):
780 raise errors.HypervisorError("Instance cdrom image '%s' not found or"
781 " not a file" % iso_path)