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,
63 constants.HV_NIC_TYPE,
64 constants.HV_DISK_TYPE,
67 _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
71 hv_base.BaseHypervisor.__init__(self)
72 # Let's make sure the directories we need exist, even if the RUN_DIR lives
73 # in a tmpfs filesystem or has been otherwise wiped out.
74 for mydir in self._DIRS:
75 if not os.path.exists(mydir):
78 def _InstancePidAlive(self, instance_name):
79 """Returns the instance pid and pidfile
82 pidfile = "%s/%s" % (self._PIDS_DIR, instance_name)
83 pid = utils.ReadPidFile(pidfile)
84 alive = utils.IsProcessAlive(pid)
86 return (pidfile, pid, alive)
89 def _InstanceMonitor(cls, instance_name):
90 """Returns the instance monitor socket name
93 return '%s/%s.monitor' % (cls._CTRL_DIR, instance_name)
96 def _InstanceSerial(cls, instance_name):
97 """Returns the instance serial socket name
100 return '%s/%s.serial' % (cls._CTRL_DIR, instance_name)
103 def _InstanceKVMRuntime(cls, instance_name):
104 """Returns the instance KVM runtime filename
107 return '%s/%s.runtime' % (cls._CONF_DIR, instance_name)
109 def _WriteNetScript(self, instance, seq, nic):
110 """Write a script to connect a net interface to the proper bridge.
112 This can be used by any qemu-type hypervisor.
114 @param instance: instance we're acting on
115 @type instance: instance object
116 @param seq: nic sequence number
118 @param nic: nic we're acting on
119 @type nic: nic object
120 @return: netscript file name
125 script.write("#!/bin/sh\n")
126 script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
127 script.write("export INSTANCE=%s\n" % instance.name)
128 script.write("export MAC=%s\n" % nic.mac)
129 script.write("export IP=%s\n" % nic.ip)
130 script.write("export BRIDGE=%s\n" % nic.bridge)
131 script.write("export INTERFACE=$1\n")
132 # TODO: make this configurable at ./configure time
133 script.write("if [ -x /etc/ganeti/kvm-vif-bridge ]; then\n")
134 script.write(" # Execute the user-specific vif file\n")
135 script.write(" /etc/ganeti/kvm-vif-bridge\n")
136 script.write("else\n")
137 script.write(" # Connect the interface to the bridge\n")
138 script.write(" /sbin/ifconfig $INTERFACE 0.0.0.0 up\n")
139 script.write(" /usr/sbin/brctl addif $BRIDGE $INTERFACE\n")
140 script.write("fi\n\n")
141 # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
142 # mounted noexec sometimes, so we'll have to find another place.
143 (tmpfd, tmpfile_name) = tempfile.mkstemp()
144 tmpfile = os.fdopen(tmpfd, 'w')
145 tmpfile.write(script.getvalue())
147 os.chmod(tmpfile_name, 0755)
150 def ListInstances(self):
151 """Get the list of running instances.
153 We can do this by listing our live instances directory and
154 checking whether the associated kvm process is still alive.
158 for name in os.listdir(self._PIDS_DIR):
159 filename = "%s/%s" % (self._PIDS_DIR, name)
160 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
164 def GetInstanceInfo(self, instance_name):
165 """Get instance properties.
167 @param instance_name: the instance name
169 @return: tuple (name, id, memory, vcpus, stat, times)
172 pidfile, pid, alive = self._InstancePidAlive(instance_name)
176 cmdline_file = "/proc/%s/cmdline" % pid
178 fh = open(cmdline_file, 'r')
183 except EnvironmentError, err:
184 raise errors.HypervisorError("Failed to list instance %s: %s" %
185 (instance_name, err))
192 arg_list = cmdline.split('\x00')
194 arg = arg_list.pop(0)
196 memory = arg_list.pop(0)
198 vcpus = arg_list.pop(0)
200 return (instance_name, pid, memory, vcpus, stat, times)
202 def GetAllInstancesInfo(self):
203 """Get properties of all instances.
205 @return: list of tuples (name, id, memory, vcpus, stat, times)
209 for name in os.listdir(self._PIDS_DIR):
210 filename = "%s/%s" % (self._PIDS_DIR, name)
211 if utils.IsProcessAlive(utils.ReadPidFile(filename)):
213 info = self.GetInstanceInfo(name)
214 except errors.HypervisorError, err:
221 def _GenerateKVMRuntime(self, instance, block_devices, extra_args):
222 """Generate KVM information to start an instance.
225 pidfile, pid, alive = self._InstancePidAlive(instance.name)
226 kvm = constants.KVM_PATH
228 kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
229 kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
230 kvm_cmd.extend(['-pidfile', pidfile])
231 # used just by the vnc server, if enabled
232 kvm_cmd.extend(['-name', instance.name])
233 kvm_cmd.extend(['-daemonize'])
234 if not instance.hvparams[constants.HV_ACPI]:
235 kvm_cmd.extend(['-no-acpi'])
237 boot_disk = (instance.hvparams[constants.HV_BOOT_ORDER] == "disk")
238 boot_cdrom = (instance.hvparams[constants.HV_BOOT_ORDER] == "cdrom")
240 disk_type = instance.hvparams[constants.HV_DISK_TYPE]
241 if disk_type == constants.HT_DISK_PARAVIRTUAL:
242 if_val = ',if=virtio'
244 if_val = ',if=%s' % disk_type
245 for cfdev, dev_path in block_devices:
246 if cfdev.mode != constants.DISK_RDWR:
247 raise errors.HypervisorError("Instance has read-only disks which"
248 " are not supported by KVM")
249 # TODO: handle FD_LOOP and FD_BLKTAP (?)
251 kvm_cmd.extend(['-boot', 'c'])
252 boot_val = ',boot=on'
257 drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
258 kvm_cmd.extend(['-drive', drive_val])
260 iso_image = instance.hvparams[constants.HV_CDROM_IMAGE_PATH]
262 options = ',format=raw,media=cdrom'
264 kvm_cmd.extend(['-boot', 'd'])
265 options = '%s,boot=on' % options
267 options = '%s,if=virtio' % options
268 drive_val = 'file=%s%s' % (iso_image, options)
269 kvm_cmd.extend(['-drive', drive_val])
271 kernel_path = instance.hvparams[constants.HV_KERNEL_PATH]
273 kvm_cmd.extend(['-kernel', kernel_path])
274 initrd_path = instance.hvparams[constants.HV_INITRD_PATH]
276 kvm_cmd.extend(['-initrd', initrd_path])
277 root_append = 'root=%s ro' % instance.hvparams[constants.HV_ROOT_PATH]
278 if instance.hvparams[constants.HV_SERIAL_CONSOLE]:
279 kvm_cmd.extend(['-append', 'console=ttyS0,38400 %s' % root_append])
281 kvm_cmd.extend(['-append', root_append])
283 # FIXME: handle vnc password
284 vnc_bind_address = instance.hvparams[constants.HV_VNC_BIND_ADDRESS]
286 kvm_cmd.extend(['-usbdevice', 'tablet'])
287 if utils.IsValidIP(vnc_bind_address):
288 if instance.network_port > constants.VNC_BASE_PORT:
289 display = instance.network_port - constants.VNC_BASE_PORT
290 if vnc_bind_address == '0.0.0.0':
291 vnc_arg = ':%d' % (display)
293 vnc_arg = '%s:%d' % (constants.HV_VNC_BIND_ADDRESS, display)
295 logging.error("Network port is not a valid VNC display (%d < %d)."
296 " Not starting VNC" %
297 (instance.network_port,
298 constants.VNC_BASE_PORT))
301 # Only allow tls and other option when not binding to a file, for now.
302 # kvm/qemu gets confused otherwise about the filename to use.
304 if instance.hvparams[constants.HV_VNC_TLS]:
305 vnc_append = '%s,tls' % vnc_append
306 if instance.hvparams[constants.HV_VNC_X509_VERIFY]:
307 vnc_append = '%s,x509verify=%s' % (vnc_append,
308 instance.hvparams[constants.HV_VNC_X509])
309 elif instance.hvparams[constants.HV_VNC_X509]:
310 vnc_append = '%s,x509=%s' % (vnc_append,
311 instance.hvparams[constants.HV_VNC_X509])
312 vnc_arg = '%s%s' % (vnc_arg, vnc_append)
315 vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
317 kvm_cmd.extend(['-vnc', vnc_arg])
319 kvm_cmd.extend(['-nographic'])
321 monitor_dev = 'unix:%s,server,nowait' % \
322 self._InstanceMonitor(instance.name)
323 kvm_cmd.extend(['-monitor', monitor_dev])
324 if instance.hvparams[constants.HV_SERIAL_CONSOLE]:
325 serial_dev = 'unix:%s,server,nowait' % self._InstanceSerial(instance.name)
326 kvm_cmd.extend(['-serial', serial_dev])
328 kvm_cmd.extend(['-serial', 'none'])
330 # Save the current instance nics, but defer their expansion as parameters,
331 # as we'll need to generate executable temp files for them.
332 kvm_nics = instance.nics
333 hvparams = instance.hvparams
335 return (kvm_cmd, kvm_nics, hvparams)
337 def _WriteKVMRuntime(self, instance_name, data):
338 """Write an instance's KVM runtime
342 utils.WriteFile(self._InstanceKVMRuntime(instance_name),
344 except EnvironmentError, err:
345 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
347 def _ReadKVMRuntime(self, instance_name):
348 """Read an instance's KVM runtime
352 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
353 except EnvironmentError, err:
354 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
357 def _SaveKVMRuntime(self, instance, kvm_runtime):
358 """Save an instance's KVM runtime
361 kvm_cmd, kvm_nics, hvparams = kvm_runtime
362 serialized_nics = [nic.ToDict() for nic in kvm_nics]
363 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
364 self._WriteKVMRuntime(instance.name, serialized_form)
366 def _LoadKVMRuntime(self, instance, serialized_runtime=None):
367 """Load an instance's KVM runtime
370 if not serialized_runtime:
371 serialized_runtime = self._ReadKVMRuntime(instance.name)
372 loaded_runtime = serializer.Load(serialized_runtime)
373 kvm_cmd, serialized_nics, hvparams = loaded_runtime
374 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
375 return (kvm_cmd, kvm_nics, hvparams)
377 def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
378 """Execute a KVM cmd, after completing it with some last minute data
380 @type incoming: tuple of strings
381 @param incoming: (target_host_ip, port)
384 pidfile, pid, alive = self._InstancePidAlive(instance.name)
386 raise errors.HypervisorError("Failed to start instance %s: %s" %
387 (instance.name, "already running"))
391 kvm_cmd, kvm_nics, hvparams = kvm_runtime
394 kvm_cmd.extend(['-net', 'none'])
396 for nic_seq, nic in enumerate(kvm_nics):
397 nic_val = "nic,macaddr=%s,model=virtio" % nic.mac
398 script = self._WriteNetScript(instance, nic_seq, nic)
399 kvm_cmd.extend(['-net', nic_val])
400 kvm_cmd.extend(['-net', 'tap,script=%s' % script])
401 temp_files.append(script)
404 target, port = incoming
405 kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
407 result = utils.RunCmd(kvm_cmd)
409 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
410 (instance.name, result.fail_reason,
413 if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
414 raise errors.HypervisorError("Failed to start instance %s: %s" %
417 for filename in temp_files:
418 utils.RemoveFile(filename)
420 def StartInstance(self, instance, block_devices, extra_args):
421 """Start an instance.
424 pidfile, pid, alive = self._InstancePidAlive(instance.name)
426 raise errors.HypervisorError("Failed to start instance %s: %s" %
427 (instance.name, "already running"))
429 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices, extra_args)
430 self._SaveKVMRuntime(instance, kvm_runtime)
431 self._ExecuteKVMRuntime(instance, kvm_runtime)
433 def _CallMonitorCommand(self, instance_name, command):
434 """Invoke a command on the instance monitor.
437 socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
438 (utils.ShellQuote(command),
439 constants.SOCAT_PATH,
440 utils.ShellQuote(self._InstanceMonitor(instance_name))))
441 result = utils.RunCmd(socat)
443 msg = ("Failed to send command '%s' to instance %s."
444 " output: %s, error: %s, fail_reason: %s" %
445 (instance.name, result.stdout, result.stderr, result.fail_reason))
446 raise errors.HypervisorError(msg)
450 def _RetryInstancePowerdown(self, instance, pid, timeout=30):
451 """Wait for an instance to power down.
454 # Wait up to $timeout seconds
455 end = time.time() + timeout
457 while time.time() < end and utils.IsProcessAlive(pid):
458 self._CallMonitorCommand(instance.name, 'system_powerdown')
460 # Make wait time longer for next try
464 def StopInstance(self, instance, force=False):
468 pidfile, pid, alive = self._InstancePidAlive(instance.name)
469 if pid > 0 and alive:
470 if force or not instance.hvparams[constants.HV_ACPI]:
471 utils.KillProcess(pid)
473 self._RetryInstancePowerdown(instance, pid)
475 if not utils.IsProcessAlive(pid):
476 utils.RemoveFile(pidfile)
477 utils.RemoveFile(self._InstanceMonitor(instance.name))
478 utils.RemoveFile(self._InstanceSerial(instance.name))
479 utils.RemoveFile(self._InstanceKVMRuntime(instance.name))
484 def RebootInstance(self, instance):
485 """Reboot an instance.
488 # For some reason if we do a 'send-key ctrl-alt-delete' to the control
489 # socket the instance will stop, but now power up again. So we'll resort
490 # to shutdown and restart.
491 pidfile, pid, alive = self._InstancePidAlive(instance.name)
493 raise errors.HypervisorError("Failed to reboot instance %s: not running" %
495 # StopInstance will delete the saved KVM runtime so:
496 # ...first load it...
497 kvm_runtime = self._LoadKVMRuntime(instance)
498 # ...now we can safely call StopInstance...
499 if not self.StopInstance(instance):
500 self.StopInstance(instance, force=True)
501 # ...and finally we can save it again, and execute it...
502 self._SaveKVMRuntime(instance, kvm_runtime)
503 self._ExecuteKVMRuntime(instance, kvm_runtime)
505 def MigrationInfo(self, instance):
506 """Get instance information to perform a migration.
508 @type instance: L{objects.Instance}
509 @param instance: instance to be migrated
511 @return: content of the KVM runtime file
514 return self._ReadKVMRuntime(instance.name)
516 def AcceptInstance(self, instance, info, target):
517 """Prepare to accept an instance.
519 @type instance: L{objects.Instance}
520 @param instance: instance to be accepted
522 @param info: content of the KVM runtime file on the source node
524 @param target: target host (usually ip), on this node
527 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
528 incoming_address = (target, constants.KVM_MIGRATION_PORT)
529 self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
531 def FinalizeMigration(self, instance, info, success):
532 """Finalize an instance migration.
534 Stop the incoming mode KVM.
536 @type instance: L{objects.Instance}
537 @param instance: instance whose migration is being aborted
541 self._WriteKVMRuntime(instance.name, info)
543 self.StopInstance(instance, force=True)
545 def MigrateInstance(self, instance_name, target, live):
546 """Migrate an instance to a target node.
548 The migration will not be attempted if the instance is not
551 @type instance_name: string
552 @param instance_name: name of the instance to be migrated
554 @param target: ip address of the target node
556 @param live: perform a live migration
559 pidfile, pid, alive = self._InstancePidAlive(instance_name)
561 raise errors.HypervisorError("Instance not running, cannot migrate")
564 self._CallMonitorCommand(instance_name, 'stop')
566 migrate_command = ('migrate -d tcp:%s:%s' %
567 (target, constants.KVM_MIGRATION_PORT))
568 self._CallMonitorCommand(instance_name, migrate_command)
570 info_command = 'info migrate'
573 result = self._CallMonitorCommand(instance_name, info_command)
574 match = self._MIGRATION_STATUS_RE.search(result.stdout)
576 raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
579 status = match.group(1)
580 if status == 'completed':
582 elif status == 'active':
584 elif status == 'failed' or status == 'cancelled':
586 self._CallMonitorCommand(instance_name, 'cont')
587 raise errors.HypervisorError("Migration %s at the kvm level" %
590 logging.info("KVM: unknown migration status '%s'" % status)
593 utils.KillProcess(pid)
594 utils.RemoveFile(pidfile)
595 utils.RemoveFile(self._InstanceMonitor(instance_name))
596 utils.RemoveFile(self._InstanceSerial(instance_name))
597 utils.RemoveFile(self._InstanceKVMRuntime(instance_name))
599 def GetNodeInfo(self):
600 """Return information about the node.
602 @return: a dict with the following keys (values in MiB):
603 - memory_total: the total memory size on the node
604 - memory_free: the available memory on the node for instances
605 - memory_dom0: the memory used by the node itself, if available
608 # global ram usage from the xm info command
611 # note: in xen 3, memory has changed to total_memory
613 fh = file("/proc/meminfo")
615 data = fh.readlines()
618 except EnvironmentError, err:
619 raise errors.HypervisorError("Failed to list node info: %s" % err)
624 splitfields = line.split(":", 1)
626 if len(splitfields) > 1:
627 key = splitfields[0].strip()
628 val = splitfields[1].strip()
629 if key == 'MemTotal':
630 result['memory_total'] = int(val.split()[0])/1024
631 elif key in ('MemFree', 'Buffers', 'Cached'):
632 sum_free += int(val.split()[0])/1024
633 elif key == 'Active':
634 result['memory_dom0'] = int(val.split()[0])/1024
635 result['memory_free'] = sum_free
639 fh = open("/proc/cpuinfo")
641 cpu_total = len(re.findall("(?m)^processor\s*:\s*[0-9]+\s*$",
645 except EnvironmentError, err:
646 raise errors.HypervisorError("Failed to list node info: %s" % err)
647 result['cpu_total'] = cpu_total
648 # FIXME: export correct data here
649 result['cpu_nodes'] = 1
650 result['cpu_sockets'] = 1
655 def GetShellCommandForConsole(cls, instance, hvparams, beparams):
656 """Return a command for connecting to the console of an instance.
659 if hvparams[constants.HV_SERIAL_CONSOLE]:
660 # FIXME: The socat shell is not perfect. In particular the way we start
661 # it ctrl+c will close it, rather than being passed to the other end.
662 # On the other hand if we pass the option 'raw' (or ignbrk=1) there
663 # will be no way of exiting socat (except killing it from another shell)
664 # and ctrl+c doesn't work anyway, printing ^C rather than being
665 # interpreted by kvm. For now we'll leave it this way, which at least
666 # allows a minimal interaction and changes on the machine.
667 shell_command = ("%s STDIO,echo=0,icanon=0 UNIX-CONNECT:%s" %
668 (constants.SOCAT_PATH,
669 utils.ShellQuote(cls._InstanceSerial(instance.name))))
671 shell_command = "echo 'No serial shell for instance %s'" % instance.name
673 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
675 if instance.network_port > constants.VNC_BASE_PORT:
676 display = instance.network_port - constants.VNC_BASE_PORT
677 vnc_command = ("echo 'Instance has VNC listening on %s:%d"
678 " (display: %d)'" % (vnc_bind_address,
679 instance.network_port,
681 shell_command = "%s; %s" % (vnc_command, shell_command)
686 """Verify the hypervisor.
688 Check that the binary exists.
691 if not os.path.exists(constants.KVM_PATH):
692 return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
693 if not os.path.exists(constants.SOCAT_PATH):
694 return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
698 def CheckParameterSyntax(cls, hvparams):
699 """Check the given parameters for validity.
701 For the KVM hypervisor, this only check the existence of the
705 @param hvparams: dictionary with parameter names/value
706 @raise errors.HypervisorError: when a parameter is not valid
709 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
711 kernel_path = hvparams[constants.HV_KERNEL_PATH]
713 if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
714 raise errors.HypervisorError("The kernel path must be an absolute path"
717 if not hvparams[constants.HV_ROOT_PATH]:
718 raise errors.HypervisorError("Need a root partition for the instance"
719 ", if a kernel is defined")
721 if hvparams[constants.HV_INITRD_PATH]:
722 if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
723 raise errors.HypervisorError("The initrd path must an absolute path"
726 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
728 if not utils.IsValidIP(vnc_bind_address):
729 if not os.path.isabs(vnc_bind_address):
730 raise errors.HypervisorError("The VNC bind address must be either"
731 " a valid IP address or an absolute"
732 " pathname. '%s' given" %
735 if hvparams[constants.HV_VNC_X509_VERIFY] and \
736 not hvparams[constants.HV_VNC_X509]:
737 raise errors.HypervisorError("%s must be defined, if %s is" %
738 (constants.HV_VNC_X509,
739 constants.HV_VNC_X509_VERIFY))
741 if hvparams[constants.HV_VNC_X509]:
742 if not os.path.isabs(hvparams[constants.HV_VNC_X509]):
743 raise errors.HypervisorError("The vnc x509 path must an absolute path"
746 iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
747 if iso_path and not os.path.isabs(iso_path):
748 raise errors.HypervisorError("The path to the CDROM image must be"
749 " an absolute path, if defined")
751 boot_order = hvparams[constants.HV_BOOT_ORDER]
752 if boot_order not in ('cdrom', 'disk'):
753 raise errors.HypervisorError("The boot order must be 'cdrom' or 'disk'")
755 if boot_order == 'cdrom' and not iso_path:
756 raise errors.HypervisorError("Cannot boot from cdrom without an ISO path")
758 nic_type = hvparams[constants.HV_NIC_TYPE]
759 if nic_type not in constants.HT_KVM_VALID_NIC_TYPES:
760 raise errors.HypervisorError("Invalid NIC type %s specified for the KVM"
761 " hypervisor. Please choose one of: %s" %
763 constants.HT_KVM_VALID_NIC_TYPES))
765 disk_type = hvparams[constants.HV_DISK_TYPE]
766 if disk_type not in constants.HT_KVM_VALID_DISK_TYPES:
767 raise errors.HypervisorError("Invalid disk type %s specified for the KVM"
768 " hypervisor. Please choose one of: %s" %
770 constants.HT_KVM_VALID_DISK_TYPES))
772 def ValidateParameters(self, hvparams):
773 """Check the given parameters for validity.
775 For the KVM hypervisor, this checks the existence of the
779 super(KVMHypervisor, self).ValidateParameters(hvparams)
781 kernel_path = hvparams[constants.HV_KERNEL_PATH]
782 if kernel_path and not os.path.isfile(kernel_path):
783 raise errors.HypervisorError("Instance kernel '%s' not found or"
784 " not a file" % kernel_path)
785 initrd_path = hvparams[constants.HV_INITRD_PATH]
786 if initrd_path and not os.path.isfile(initrd_path):
787 raise errors.HypervisorError("Instance initrd '%s' not found or"
788 " not a file" % initrd_path)
790 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
791 if vnc_bind_address and not utils.IsValidIP(vnc_bind_address) and \
792 not os.path.isdir(vnc_bind_address):
793 raise errors.HypervisorError("Instance vnc bind address must be either"
794 " an ip address or an existing directory")
796 vnc_x509 = hvparams[constants.HV_VNC_X509]
797 if vnc_x509 and not os.path.isdir(vnc_x509):
798 raise errors.HypervisorError("Instance vnc x509 path '%s' not found"
799 " or not a directory" % vnc_x509)
801 iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
802 if iso_path and not os.path.isfile(iso_path):
803 raise errors.HypervisorError("Instance cdrom image '%s' not found or"
804 " not a file" % iso_path)